fix(smolmachines): stop VM before pack commit, with confirm prompt

smolvm pack create --from-vm requires the VM to be stopped. Add
machine_is_running() to smolvm.py (via machine ls --json state field),
and add the same confirm-stop flow to SmolmachinesFreezer that was
originally designed for macos-container: if running, prompt the user,
stop the VM, then pack. Already-stopped VMs are packed directly.
This commit is contained in:
2026-06-23 08:42:03 +00:00
committed by didericis
parent a32c0c7865
commit d11e3940fa
3 changed files with 89 additions and 6 deletions
+29 -3
View File
@@ -2,15 +2,31 @@
from __future__ import annotations
import sys
from .. import ActiveAgent
from ..freeze import Freezer
from .smolvm import pack_create_from_vm
from ..freeze import CommitCancelled, Freezer
from .smolvm import machine_is_running, machine_stop, pack_create_from_vm
from ...bottle_state import bottle_state_dir
from ...log import info
def _read_tty_line() -> str:
"""Read one line from /dev/tty, falling back to stdin."""
try:
with open("/dev/tty", "r", encoding="utf-8") as tty:
return tty.readline().rstrip("\n")
except OSError:
return sys.stdin.readline().rstrip("\n")
class SmolmachinesFreezer(Freezer):
"""Freezes a smolmachines bottle via `smolvm pack create --from-vm`."""
"""Freezes a smolmachines bottle via `smolvm pack create --from-vm`.
`smolvm pack create --from-vm` requires the VM to be stopped first.
If the VM is running the freezer prompts the user to confirm the stop
before proceeding. The VM remains stopped after commit; use
`./cli.py resume` to restart."""
backend_name = "smolmachines"
@@ -18,6 +34,16 @@ class SmolmachinesFreezer(Freezer):
machine = f"bot-bottle-{agent.slug}"
output = bottle_state_dir(agent.slug) / "committed-smolmachine"
output.parent.mkdir(parents=True, exist_ok=True)
if machine_is_running(machine):
sys.stderr.write(
f"bot-bottle: bottle {agent.slug!r} is running; "
"commit will stop it. Continue? [y/N] "
)
sys.stderr.flush()
reply = _read_tty_line().strip().lower()
if reply not in ("y", "yes"):
raise CommitCancelled
machine_stop(machine)
pack_create_from_vm(machine, output)
artifact = output.with_name(f"{output.name}.smolmachine")
return str(artifact)
+16
View File
@@ -25,6 +25,7 @@ smolvm binary."""
from __future__ import annotations
import json
import shutil
import subprocess
import time
@@ -153,6 +154,21 @@ def machine_create(
_smolvm(*args)
def machine_is_running(name: str) -> bool:
"""Return True if the named VM is in the 'running' state."""
result = _smolvm("machine", "ls", "--json", check=False)
if result.returncode != 0:
return False
try:
machines = json.loads(result.stdout or "[]")
except ValueError:
return False
return any(
isinstance(m, dict) and m.get("name") == name and m.get("state") == "running"
for m in machines
)
def machine_start(name: str) -> None:
"""`smolvm machine start --name NAME`."""
_smolvm("machine", "start", "--name", name)