From 47b882f6346d2cc381653bb99b05bd4034b97876 Mon Sep 17 00:00:00 2001 From: didericis Date: Sun, 10 May 2026 23:19:22 -0400 Subject: [PATCH] refactor(bottles): move 'list active' onto DockerBottlePlatform MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add list_active() abstract method on BottlePlatform; DockerBottlePlatform implements it with the existing docker ps logic. cli/list.py no longer calls docker directly — it just dispatches the active branch to the platform. --- claude_bottle/bottles/__init__.py | 5 +++++ claude_bottle/bottles/docker.py | 25 +++++++++++++++++++++++++ claude_bottle/cli/list.py | 26 +++----------------------- 3 files changed, 33 insertions(+), 23 deletions(-) diff --git a/claude_bottle/bottles/__init__.py b/claude_bottle/bottles/__init__.py index 2589640..740a3f2 100644 --- a/claude_bottle/bottles/__init__.py +++ b/claude_bottle/bottles/__init__.py @@ -122,6 +122,11 @@ class BottlePlatform(ABC): def cleanup(self, plan: BottleCleanupPlan) -> None: """Remove everything described by the cleanup plan.""" + @abstractmethod + def list_active(self) -> None: + """Print every currently-running bottle on this platform to + stderr (name + status).""" + # Import concrete platform classes AFTER the base types are defined, so # each platform module can pull BottleSpec / BottlePlan / BottlePlatform diff --git a/claude_bottle/bottles/docker.py b/claude_bottle/bottles/docker.py index 0278a2d..f08af61 100644 --- a/claude_bottle/bottles/docker.py +++ b/claude_bottle/bottles/docker.py @@ -527,3 +527,28 @@ class DockerBottlePlatform(BottlePlatform): stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, ) + + # --- List --- + + def list_active(self) -> None: + """Print all running claude-bottle containers (name + status). + Prints a single-line banner if there are none.""" + docker_mod.require_docker() + result = subprocess.run( + [ + "docker", "ps", + "--filter", "name=^claude-bottle-", + "--format", "{{.Names}}\t{{.Status}}", + ], + capture_output=True, + text=True, + ) + containers = (result.stdout or "").strip() + if not containers: + info("no active claude-bottle containers") + return + print() + for line in containers.splitlines(): + name, _, status = line.partition("\t") + info(f"container: {name} status: {status}") + print() diff --git a/claude_bottle/cli/list.py b/claude_bottle/cli/list.py index a60143b..af40292 100644 --- a/claude_bottle/cli/list.py +++ b/claude_bottle/cli/list.py @@ -1,12 +1,10 @@ -"""list: list available agents or active containers.""" +"""list: list available agents or active bottles.""" from __future__ import annotations import argparse -import subprocess -from .. import docker as docker_mod -from ..log import info +from ..bottles import get_bottle_platform from ..manifest import Manifest from ._common import PROG, USER_CWD @@ -22,23 +20,5 @@ def cmd_list(argv: list[str]) -> int: print(name) return 0 - docker_mod.require_docker() - result = subprocess.run( - [ - "docker", "ps", - "--filter", "name=^claude-bottle-", - "--format", "{{.Names}}\t{{.Status}}", - ], - capture_output=True, - text=True, - ) - containers = (result.stdout or "").strip() - if not containers: - info("no active claude-bottle containers") - return 0 - print() - for line in containers.splitlines(): - name, _, status = line.partition("\t") - info(f"container: {name} status: {status}") - print() + get_bottle_platform().list_active() return 0