Refactor cockpit to use claude-code-tools-local package

Architecture improvements:
- Import TmuxCLIController from installed claude-code-tools-local
- DockerTmuxAdapter extends TmuxCLIController for Docker execution
- Override _run_tmux_command() to prepend 'docker exec' to commands
- Backward compatibility alias: DockerTmuxController = DockerTmuxAdapter

This enables:
- Pulling upstream improvements from claude-code-tools
- Maintaining Docker-specific functionality
- Clean inheritance-based architecture

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
admin
2026-01-14 10:53:01 -03:00
parent ec33ac1936
commit 88cb7156e9

View File

@@ -9,7 +9,10 @@ Key features:
- tmux for human attachment when needed
- Multi-turn conversation support
Uses claude-code-tools TmuxCLIController pattern for robust session management.
Architecture:
Imports TmuxCLIController from claude-code-tools-local package and extends
it with DockerTmuxAdapter for Docker-containerized tmux sessions.
This enables importing upstream improvements while adding Docker support.
Usage:
luzia cockpit start <project> Start cockpit container
@@ -31,40 +34,57 @@ import re
from pathlib import Path
from typing import Dict, Optional, Tuple, List
# Import TmuxCLIController from installed claude-code-tools-local package
from claude_code_tools.tmux_cli_controller import TmuxCLIController
class DockerTmuxController:
class DockerTmuxAdapter(TmuxCLIController):
"""
Tmux controller that executes commands inside a Docker container.
Docker adapter for TmuxCLIController.
Based on claude-code-tools TmuxCLIController pattern, adapted for
Docker containerized tmux sessions.
Extends TmuxCLIController to execute tmux commands inside a Docker container
rather than on the host system. This enables:
- Inheriting all TmuxCLIController methods automatically
- Pulling upstream improvements from claude-code-tools
- Adding Docker-specific functionality
The key override is _run_tmux_command() which prepends 'docker exec' to all
tmux commands.
"""
def __init__(self, container_name: str, tmux_session: str = "agent", tmux_window: str = "main"):
"""
Initialize controller for a Docker container's tmux session.
Initialize adapter for a Docker container's tmux session.
Args:
container_name: Docker container name
tmux_session: tmux session name inside container (default: agent)
tmux_window: tmux window name (default: main)
"""
super().__init__(session_name=tmux_session, window_name=tmux_window)
self.container_name = container_name
self.tmux_session = tmux_session
self.tmux_window = tmux_window
self.target = f"{tmux_session}:{tmux_window}"
def _run_tmux(self, args: List[str]) -> Tuple[str, int]:
def _run_tmux_command(self, command: List[str]) -> Tuple[str, int]:
"""
Run a tmux command inside the Docker container.
Override: Run tmux command inside the Docker container.
This is the key override that makes all inherited TmuxCLIController
methods work inside Docker. Instead of running 'tmux <cmd>', we run
'docker exec <container> tmux <cmd>'.
Args:
args: tmux command arguments (without 'tmux' prefix)
command: List of command components (without 'tmux' prefix)
Returns:
Tuple of (stdout, return_code)
Tuple of (output, exit_code)
"""
cmd = ["docker", "exec", self.container_name, "tmux"] + args
if not self.is_container_running():
return "", 1
cmd = ["docker", "exec", self.container_name, "tmux"] + command
result = subprocess.run(cmd, capture_output=True, text=True)
return result.stdout.strip(), result.returncode
@@ -92,14 +112,14 @@ class DockerTmuxController:
return False
# Send text first
_, code = self._run_tmux(["send-keys", "-t", self.target, text])
_, code = self._run_tmux_command(["send-keys", "-t", self.target, text])
if code != 0:
return False
if enter:
if delay_enter > 0:
time.sleep(delay_enter)
self._run_tmux(["send-keys", "-t", self.target, "Enter"])
self._run_tmux_command(["send-keys", "-t", self.target, "Enter"])
return True
@@ -116,7 +136,7 @@ class DockerTmuxController:
if not self.is_container_running():
return ""
output, code = self._run_tmux([
output, code = self._run_tmux_command([
"capture-pane", "-t", self.target, "-p", "-S", f"-{lines}"
])
return output if code == 0 else ""
@@ -265,16 +285,20 @@ class DockerTmuxController:
"""Send Ctrl+C to interrupt running command."""
if not self.is_container_running():
return False
_, code = self._run_tmux(["send-keys", "-t", self.target, "C-c"])
_, code = self._run_tmux_command(["send-keys", "-t", self.target, "C-c"])
return code == 0
def clear_pane(self) -> bool:
"""Clear the pane screen."""
if not self.is_container_running():
return False
_, code = self._run_tmux(["send-keys", "-t", self.target, "C-l"])
_, code = self._run_tmux_command(["send-keys", "-t", self.target, "C-l"])
return code == 0
# Backward compatibility alias
DockerTmuxController = DockerTmuxAdapter
# Constants
COCKPIT_IMAGE = "luzia-cockpit:latest"
COCKPIT_PREFIX = "luzia-cockpit-"