0efc07ba67
Closes #178. The backend provision functions now receive a Bottle handle with exec / cp_in methods instead of a raw target string. Provisioner modules use bottle.exec and bottle.cp_in in place of inlined subprocess.run(["docker", "exec"/"cp", ...]) and direct _smolvm.machine_cp / machine_exec calls. This decouples the provisioners from backend-specific runtime primitives so future refactors (e.g. the supervise rework) can swap the bottle's exec implementation without touching every provisioner. Each launch.py constructs the Bottle handle before calling provision so it can be passed in; provision_prompt's return value is wired back onto the bottle's prompt path attribute after the fact.
99 lines
3.2 KiB
Python
99 lines
3.2 KiB
Python
"""SmolmachinesBottleBackend — the smolmachines implementation of
|
|
BottleBackend (PRD 0023)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from contextlib import contextmanager
|
|
from pathlib import Path
|
|
from typing import Generator, Sequence
|
|
|
|
from .. import ActiveAgent, Bottle, BottleBackend, BottleSpec
|
|
from . import cleanup as _cleanup
|
|
from . import enumerate as _enumerate
|
|
from . import launch as _launch
|
|
from . import prepare as _prepare
|
|
from . import smolvm as _smolvm
|
|
from .bottle import SmolmachinesBottle
|
|
from .bottle_cleanup_plan import SmolmachinesBottleCleanupPlan
|
|
from .bottle_plan import SmolmachinesBottlePlan
|
|
from .provision import ca as _ca
|
|
from .provision import git as _git
|
|
from .provision import prompt as _prompt
|
|
from .provision import provider_auth as _provider_auth
|
|
from .provision import skills as _skills
|
|
from .provision import supervise as _supervise
|
|
from .provision import workspace as _workspace
|
|
|
|
|
|
class SmolmachinesBottleBackend(
|
|
BottleBackend["SmolmachinesBottlePlan", "SmolmachinesBottleCleanupPlan"]
|
|
):
|
|
"""smolmachines backend. Selected by
|
|
`BOT_BOTTLE_BACKEND=smolmachines`."""
|
|
|
|
name = "smolmachines"
|
|
|
|
@classmethod
|
|
def is_available(cls) -> bool:
|
|
"""`smolvm` on PATH. The backend additionally needs macOS
|
|
for libkrun + TSI, but `enumerate_active` / `cleanup` are
|
|
host-shell ops that gracefully no-op on Linux too — the
|
|
runtime check happens at `prepare`."""
|
|
return _smolvm.is_available()
|
|
|
|
def _resolve_plan(
|
|
self, spec: BottleSpec, *, stage_dir: Path
|
|
) -> SmolmachinesBottlePlan:
|
|
return _prepare.resolve_plan(spec, stage_dir=stage_dir)
|
|
|
|
@contextmanager
|
|
def launch(
|
|
self, plan: SmolmachinesBottlePlan
|
|
) -> Generator[SmolmachinesBottle, None, None]:
|
|
with _launch.launch(plan, provision=self.provision) as bottle:
|
|
yield bottle
|
|
|
|
def provision_ca(
|
|
self, plan: SmolmachinesBottlePlan, bottle: Bottle
|
|
) -> None:
|
|
_ca.provision_ca(plan, bottle)
|
|
|
|
def provision_prompt(
|
|
self, plan: SmolmachinesBottlePlan, bottle: Bottle
|
|
) -> str | None:
|
|
return _prompt.provision_prompt(plan, bottle)
|
|
|
|
def provision_provider_auth(
|
|
self, plan: SmolmachinesBottlePlan, bottle: Bottle
|
|
) -> None:
|
|
_provider_auth.provision_provider_auth(plan, bottle)
|
|
|
|
def provision_skills(
|
|
self, plan: SmolmachinesBottlePlan, bottle: Bottle
|
|
) -> None:
|
|
_skills.provision_skills(plan, bottle)
|
|
|
|
def provision_workspace(
|
|
self, plan: SmolmachinesBottlePlan, bottle: Bottle
|
|
) -> None:
|
|
_workspace.provision_workspace(plan, bottle)
|
|
|
|
def provision_git(
|
|
self, plan: SmolmachinesBottlePlan, bottle: Bottle
|
|
) -> None:
|
|
_git.provision_git(plan, bottle)
|
|
|
|
def provision_supervise(
|
|
self, plan: SmolmachinesBottlePlan, bottle: Bottle
|
|
) -> None:
|
|
_supervise.provision_supervise(plan, bottle)
|
|
|
|
def prepare_cleanup(self) -> SmolmachinesBottleCleanupPlan:
|
|
return _cleanup.prepare_cleanup()
|
|
|
|
def cleanup(self, plan: SmolmachinesBottleCleanupPlan) -> None:
|
|
_cleanup.cleanup(plan)
|
|
|
|
def enumerate_active(self) -> Sequence[ActiveAgent]:
|
|
return _enumerate.enumerate_active()
|