Add tests for all exception paths (Die/ManifestError from resolve, Die
from _launch_bottle, Die from freezer) plus the macos-container
fall-through branch in destroy. Add TestDestroyDocker and
TestDestroySmolmachines to exercise the backend helpers directly.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Cast Die.code (_ExitCode) to int before passing to BottleError — Die
always holds an int but SystemExit.code is typed as str|int|None in
typeshed. Replace untyped lambda with str() as identity for
_uniquify_label_headless mock (fixes reportUnknownLambdaType).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add bot_bottle/api.py with four public functions the orchestrator uses:
start_headless, resume_headless, freeze, and destroy. These let a
ProgrammaticBottleRunner call directly into bot_bottle instead of
shelling out to the CLI; call sites in lifecycle.py stay unchanged.
Key changes:
- BottleSpec gains forge_env field for forge sidecar credentials
- _launch_bottle returns (slug, exit_code) instead of int so start_headless
can return the slug to callers
- All four API functions convert Die and non-zero exits to BottleError
- 27 new unit tests; existing tests updated for the new return type
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>