Files
bot-bottle/claude_bottle/bottles/docker/bottle.py
T
didericis aaed390953
test / run tests/run_tests.py (pull_request) Successful in 14s
refactor(bottles): Bottle becomes an ABC; DockerBottle inherits
Bottle was the only Protocol in an otherwise-ABC family
(BottlePlan, BottleCleanupPlan, BottlePlatform are all ABCs).
Convert to an ABC with abstract exec_claude / cp_in / close,
matching the rest of the hierarchy.

Rename _DockerBottle -> DockerBottle: the underscore was a
default-Python-private instinct that doesn't match the sibling
plan classes (DockerBottlePlan, DockerBottleCleanupPlan), all of
which are equally "only constructed by the platform" and yet
public-by-name.

Re-export DockerBottle from claude_bottle.bottles.docker.
2026-05-10 23:32:33 -04:00

47 lines
1.4 KiB
Python

"""DockerBottle — concrete Bottle handle yielded by
DockerBottlePlatform.launch.
Holds the container name plus the in-container prompt path so
exec_claude can transparently add --append-system-prompt-file when a
prompt was provisioned.
"""
from __future__ import annotations
import subprocess
from .. import Bottle
class DockerBottle(Bottle):
"""Concrete Bottle for Docker."""
def __init__(self, container: str, teardown, prompt_path_in_container: str | None):
self.name = container
self._teardown = teardown
self._prompt_path = prompt_path_in_container
self._closed = False
def exec_claude(self, argv: list[str], *, tty: bool = True) -> int:
full_argv = list(argv)
if self._prompt_path:
full_argv.extend(["--append-system-prompt-file", self._prompt_path])
cmd = ["docker", "exec"]
if tty:
cmd.append("-it")
cmd.extend([self.name, "claude", *full_argv])
return subprocess.run(cmd).returncode
def cp_in(self, host_path: str, container_path: str) -> None:
subprocess.run(
["docker", "cp", host_path, f"{self.name}:{container_path}"],
stdout=subprocess.DEVNULL,
check=True,
)
def close(self) -> None:
if self._closed:
return
self._closed = True
self._teardown()