feat(local-service): allow exact worktree migration

This commit is contained in:
DCCONSTRUCTIONS
2026-08-30 23:23:36 +03:00
parent 2a5763d3fb
commit 177be8869f
5 changed files with 421 additions and 25 deletions
+101 -13
View File
@@ -3,10 +3,12 @@
from __future__ import annotations
import hashlib
import os
import plistlib
import stat
from dataclasses import dataclass
from pathlib import Path
from typing import Final
from typing import Final, cast
MISSION_CORE_LAUNCH_AGENT_LABEL: Final = "com.nodedc.mission-core.local"
MISSION_CORE_LAUNCH_AGENT_SCHEMA: Final = "missioncore.local-launch-agent-plan/v1"
@@ -21,6 +23,9 @@ class MissionCoreLaunchAgentPlan:
agent_path: Path
current_sha256: str
desired_sha256: str
current_working_directory: Path
desired_working_directory: Path
preserved_data_directory: Path | None
current_program_arguments: tuple[str, ...]
desired_program_arguments: tuple[str, ...]
desired_payload: bytes
@@ -32,9 +37,24 @@ class MissionCoreLaunchAgentPlan:
"agent_path": str(self.agent_path),
"current_sha256": self.current_sha256,
"desired_sha256": self.desired_sha256,
"current_working_directory": str(self.current_working_directory),
"desired_working_directory": str(self.desired_working_directory),
"preserved_data_directory": (
str(self.preserved_data_directory)
if self.preserved_data_directory is not None
else None
),
"current_program_arguments": list(self.current_program_arguments),
"desired_program_arguments": list(self.desired_program_arguments),
"changes": {
"repository_migration": self.current_working_directory
!= self.desired_working_directory,
"data_directory_preserved": self.preserved_data_directory is not None,
"preserved_data_directory": (
str(self.preserved_data_directory)
if self.preserved_data_directory is not None
else None
),
"dependency_sync_disabled": "--no-sync"
in self.desired_program_arguments,
"self_health_watchdog": True,
@@ -49,8 +69,14 @@ def plan_mission_core_launch_agent(
*,
repository_root: Path,
agent_path: Path,
expected_current_repository_root: Path | None = None,
) -> MissionCoreLaunchAgentPlan:
repository = repository_root.expanduser().resolve(strict=True)
expected_current_repository = (
expected_current_repository_root.expanduser().resolve(strict=True)
if expected_current_repository_root is not None
else None
)
path = agent_path.expanduser().absolute()
current_payload = _read_private_regular_file(path)
try:
@@ -61,14 +87,24 @@ def plan_mission_core_launch_agent(
raise MissionCoreLaunchAgentError("current launch agent identity changed")
current_arguments = _program_arguments(current)
current_working_directory = current.get("WorkingDirectory")
if current_working_directory != str(repository):
if not isinstance(current_working_directory, str):
raise MissionCoreLaunchAgentError("current launch agent working directory is invalid")
if expected_current_repository is None and current_working_directory != str(repository):
raise MissionCoreLaunchAgentError("current launch agent targets another repository")
environment = current.get("EnvironmentVariables")
if not isinstance(environment, dict) or any(
if (
expected_current_repository is not None
and current_working_directory != str(expected_current_repository)
):
raise MissionCoreLaunchAgentError(
"current launch agent does not target the expected current repository"
)
environment_document = current.get("EnvironmentVariables")
if not isinstance(environment_document, dict) or any(
not isinstance(key, str) or not isinstance(value, str)
for key, value in environment.items()
for key, value in environment_document.items()
):
raise MissionCoreLaunchAgentError("current launch agent environment is invalid")
environment = cast(dict[str, str], environment_document)
# A LaunchAgent started directly from this repository's venv is denied
# access to ``.venv/pyvenv.cfg`` by macOS privacy controls because the
# checkout is below Downloads. The Homebrew uv launcher is already the
@@ -81,18 +117,31 @@ def plan_mission_core_launch_agent(
or not uv_entrypoint.exists()
):
raise MissionCoreLaunchAgentError("Mission Core uv entrypoint is unavailable")
current_repository = Path(current_working_directory)
repository_migration = current_repository != repository
preserved_data_directory = (
_preserved_migration_data_directory(
current_repository=current_repository,
environment=environment,
)
if repository_migration
else None
)
desired_environment = dict(environment)
desired_environment["MISSIONCORE_SERVICE_WATCHDOG"] = "1"
if preserved_data_directory is not None:
desired_environment["MISSIONCORE_DATA_DIR"] = str(preserved_data_directory)
log_path = repository / ".runtime/mission-core/k1link-serve-launchd.log"
desired_program_arguments = (
str(uv_entrypoint),
"run",
"--no-sync",
"k1link",
"serve",
)
desired: dict[str, object] = {
"Label": MISSION_CORE_LAUNCH_AGENT_LABEL,
"ProgramArguments": [
str(uv_entrypoint),
"run",
"--no-sync",
"k1link",
"serve",
],
"ProgramArguments": list(desired_program_arguments),
"WorkingDirectory": str(repository),
"EnvironmentVariables": desired_environment,
"KeepAlive": True,
@@ -109,8 +158,11 @@ def plan_mission_core_launch_agent(
agent_path=path,
current_sha256=_sha256(current_payload),
desired_sha256=_sha256(desired_payload),
current_working_directory=current_repository,
desired_working_directory=repository,
preserved_data_directory=preserved_data_directory,
current_program_arguments=current_arguments,
desired_program_arguments=tuple(desired["ProgramArguments"]),
desired_program_arguments=desired_program_arguments,
desired_payload=desired_payload,
)
@@ -122,6 +174,42 @@ def _program_arguments(document: dict[str, object]) -> tuple[str, ...]:
return tuple(value)
def _preserved_migration_data_directory(
*,
current_repository: Path,
environment: dict[str, str],
) -> Path:
configured = environment.get("MISSIONCORE_DATA_DIR", "")
if configured.strip():
if configured != configured.strip():
raise MissionCoreLaunchAgentError(
"current Mission Core data directory is not a canonical absolute path"
)
candidate = Path(configured)
else:
candidate = current_repository / ".runtime" / "mission-core"
if not candidate.is_absolute():
raise MissionCoreLaunchAgentError(
"current Mission Core data directory is not a canonical absolute path"
)
try:
resolved = candidate.resolve(strict=True)
metadata = candidate.lstat()
except OSError as exc:
raise MissionCoreLaunchAgentError(
"current Mission Core data directory is unavailable"
) from exc
if resolved != candidate or (
not stat.S_ISDIR(metadata.st_mode)
or stat.S_IMODE(metadata.st_mode) != 0o700
or metadata.st_uid != os.getuid()
):
raise MissionCoreLaunchAgentError(
"current Mission Core data directory is not a private canonical directory"
)
return resolved
def _read_private_regular_file(path: Path) -> bytes:
if path.is_symlink() or not path.is_file():
raise MissionCoreLaunchAgentError("Mission Core launch agent is unavailable")