Files
zk-data-agent/src/setup.py
T

153 lines
4.8 KiB
Python

from __future__ import annotations
import platform
import sys
from dataclasses import dataclass, field
from pathlib import Path
from .deferred_init import DeferredInitResult, run_deferred_init
from .prefetch import PrefetchResult, start_keychain_prefetch, start_mdm_raw_read, start_project_scan
from .release_notes import check_for_release_notes
MIN_PYTHON_VERSION: tuple[int, int] = (3, 10)
@dataclass(frozen=True)
class RuntimeRequirementCheck:
name: str
ok: bool
detail: str
def check_runtime_requirements() -> tuple[RuntimeRequirementCheck, ...]:
checks: list[RuntimeRequirementCheck] = []
py_major, py_minor = sys.version_info[:2]
py_ok = (py_major, py_minor) >= MIN_PYTHON_VERSION
checks.append(RuntimeRequirementCheck(
name='python_version',
ok=py_ok,
detail=(
f'Python {py_major}.{py_minor} >= {MIN_PYTHON_VERSION[0]}.{MIN_PYTHON_VERSION[1]}'
if py_ok
else f'Python {py_major}.{py_minor} is below required '
f'{MIN_PYTHON_VERSION[0]}.{MIN_PYTHON_VERSION[1]}'
),
))
impl = platform.python_implementation()
checks.append(RuntimeRequirementCheck(
name='python_implementation',
ok=True,
detail=impl,
))
machine = platform.machine() or 'unknown'
system = platform.system() or 'unknown'
checks.append(RuntimeRequirementCheck(
name='platform',
ok=True,
detail=f'{system} on {machine}',
))
return tuple(checks)
def _read_package_version() -> str:
try:
from importlib.metadata import version
return version('claw-code-agent')
except Exception:
return '0.0.0'
@dataclass(frozen=True)
class WorkspaceSetup:
python_version: str
implementation: str
platform_name: str
test_command: str = 'python3 -m unittest discover -s tests -v'
def startup_steps(self) -> tuple[str, ...]:
return (
'start top-level prefetch side effects',
'build workspace context',
'load mirrored command snapshot',
'load mirrored tool snapshot',
'prepare parity audit hooks',
'apply trust-gated deferred init',
)
@dataclass(frozen=True)
class SetupReport:
setup: WorkspaceSetup
prefetches: tuple[PrefetchResult, ...]
deferred_init: DeferredInitResult
trusted: bool
cwd: Path
runtime_checks: tuple[RuntimeRequirementCheck, ...] = field(default_factory=tuple)
release_notes: tuple[str, ...] = field(default_factory=tuple)
def has_blocking_issues(self) -> bool:
return any(not check.ok for check in self.runtime_checks)
def as_markdown(self) -> str:
lines = [
'# Setup Report',
'',
f'- Python: {self.setup.python_version} ({self.setup.implementation})',
f'- Platform: {self.setup.platform_name}',
f'- Trusted mode: {self.trusted}',
f'- CWD: {self.cwd}',
'',
'Runtime checks:',
*(
f'- {check.name}: {"ok" if check.ok else "FAIL"}{check.detail}'
for check in self.runtime_checks
),
'',
'Prefetches:',
*(f'- {prefetch.name}: {prefetch.detail}' for prefetch in self.prefetches),
'',
'Deferred init:',
*self.deferred_init.as_lines(),
]
if self.release_notes:
lines.extend(['', 'Release notes (newer than last seen):'])
lines.extend(f'- {note}' for note in self.release_notes)
return '\n'.join(lines)
def build_workspace_setup() -> WorkspaceSetup:
return WorkspaceSetup(
python_version='.'.join(str(part) for part in sys.version_info[:3]),
implementation=platform.python_implementation(),
platform_name=platform.platform(),
)
def run_setup(
cwd: Path | None = None,
trusted: bool = True,
last_seen_version: str | None = None,
) -> SetupReport:
root = cwd or Path(__file__).resolve().parent.parent
prefetches = [
start_mdm_raw_read(),
start_keychain_prefetch(),
start_project_scan(root),
]
release_notes_payload = check_for_release_notes(
current_version=_read_package_version(),
last_seen_version=last_seen_version,
cwd=root,
)
return SetupReport(
setup=build_workspace_setup(),
prefetches=tuple(prefetches),
deferred_init=run_deferred_init(trusted=trusted),
trusted=trusted,
cwd=root,
runtime_checks=check_runtime_requirements(),
release_notes=tuple(release_notes_payload['releaseNotes']),
)