diff --git a/bot_bottle/agent_provider.py b/bot_bottle/agent_provider.py index 594085b..67e14f2 100644 --- a/bot_bottle/agent_provider.py +++ b/bot_bottle/agent_provider.py @@ -103,6 +103,7 @@ class AgentProvisionPlan: prompt_mode: PromptMode image: str dockerfile: str + guest_home: str guest_env: dict[str, str] env_vars: dict[str, str] = field(default_factory=dict) dirs: tuple[AgentProvisionDir, ...] = () diff --git a/bot_bottle/backend/__init__.py b/bot_bottle/backend/__init__.py index 348ab40..1abde4d 100644 --- a/bot_bottle/backend/__init__.py +++ b/bot_bottle/backend/__init__.py @@ -78,9 +78,12 @@ class BottlePlan(ABC): spec: BottleSpec stage_dir: Path - guest_home: str git_gate_plan: GitGatePlan + @property + def guest_home(self) -> str: + return self.agent_provision.guest_home + @property def git_gate_insteadof_host(self) -> str: """Host (and optional port) used in git-gate insteadOf URLs. diff --git a/bot_bottle/backend/docker/resolve_plan.py b/bot_bottle/backend/docker/resolve_plan.py index 3eff0ef..d702933 100644 --- a/bot_bottle/backend/docker/resolve_plan.py +++ b/bot_bottle/backend/docker/resolve_plan.py @@ -169,7 +169,6 @@ def resolve_plan( return DockerBottlePlan( spec=spec, stage_dir=stage_dir, - guest_home=guest_home, slug=slug, container_name=container_name, container_name_pinned=container_name_pinned, diff --git a/bot_bottle/backend/smolmachines/resolve_plan.py b/bot_bottle/backend/smolmachines/resolve_plan.py index 2db756f..7e1e252 100644 --- a/bot_bottle/backend/smolmachines/resolve_plan.py +++ b/bot_bottle/backend/smolmachines/resolve_plan.py @@ -114,7 +114,6 @@ def resolve_plan( return SmolmachinesBottlePlan( spec=spec, stage_dir=stage_dir, - guest_home=guest_home, slug=slug, bundle_subnet=subnet, bundle_gateway=gateway, diff --git a/bot_bottle/contrib/claude/agent_provider.py b/bot_bottle/contrib/claude/agent_provider.py index b15ae43..9efc9db 100644 --- a/bot_bottle/contrib/claude/agent_provider.py +++ b/bot_bottle/contrib/claude/agent_provider.py @@ -110,6 +110,7 @@ class ClaudeAgentProvider(AgentProvider): prompt_mode=_RUNTIME.prompt_mode, image=_RUNTIME.image, dockerfile=dockerfile, + guest_home=guest_home, env_vars=env_vars, guest_env=resolved_guest_env, files=files, diff --git a/bot_bottle/contrib/codex/agent_provider.py b/bot_bottle/contrib/codex/agent_provider.py index 5e16eab..fa9143e 100644 --- a/bot_bottle/contrib/codex/agent_provider.py +++ b/bot_bottle/contrib/codex/agent_provider.py @@ -147,6 +147,7 @@ class CodexAgentProvider(AgentProvider): prompt_mode=_RUNTIME.prompt_mode, image=_RUNTIME.image, dockerfile=dockerfile, + guest_home=guest_home, env_vars=env_vars, guest_env=resolved_guest_env, dirs=tuple(dirs), diff --git a/tests/unit/test_compose.py b/tests/unit/test_compose.py index 251221c..8dd6472 100644 --- a/tests/unit/test_compose.py +++ b/tests/unit/test_compose.py @@ -149,7 +149,6 @@ def _plan( spec = _spec(supervise=supervise, with_git=with_git, with_egress=with_egress) return DockerBottlePlan( - guest_home="/home/node", spec=spec, stage_dir=STAGE, slug=SLUG, @@ -172,6 +171,7 @@ def _plan( prompt_mode="append_file", image="bot-bottle-claude:latest", dockerfile="", + guest_home="/home/node", guest_env={}, ), workspace_plan=workspace_plan(spec, guest_home="/home/node"), @@ -252,6 +252,7 @@ class TestAgentAlwaysPresent(unittest.TestCase): prompt_mode="read_prompt_file", image="bot-bottle-codex:latest", dockerfile="", + guest_home="/home/node", guest_env={"CODEX_HOME": "/home/node/.codex"}, ) plan = type(plan)(**{**vars(plan), "agent_provision": provision}) # type: ignore diff --git a/tests/unit/test_contrib_claude_provider.py b/tests/unit/test_contrib_claude_provider.py index a53a51b..fd665ae 100644 --- a/tests/unit/test_contrib_claude_provider.py +++ b/tests/unit/test_contrib_claude_provider.py @@ -76,7 +76,6 @@ def _plan( current_config_dir=Path("/tmp/current-config"), ) return DockerBottlePlan( - guest_home="/home/node", spec=spec, stage_dir=Path("/tmp/stage"), slug="demo-abc12", @@ -106,7 +105,7 @@ def _plan( use_runsc=False, agent_provision=agent_provision or AgentProvisionPlan( template="claude", command="claude", prompt_mode="append_file", - image="", dockerfile="", guest_env={}, + image="", dockerfile="", guest_home="/home/node", guest_env={}, ), workspace_plan=workspace_plan(spec, guest_home="/home/node"), ) @@ -211,7 +210,7 @@ class TestClaudeProvision(unittest.TestCase): def test_copies_files_and_chowns(self): provision = AgentProvisionPlan( template="claude", command="claude", prompt_mode="append_file", - image="", dockerfile="", guest_env={}, + image="", dockerfile="", guest_home="/home/node", guest_env={}, files=(AgentProvisionFile( Path("/tmp/claude.json"), "/home/node/.claude.json", ),), @@ -234,7 +233,7 @@ class TestClaudeProvision(unittest.TestCase): def test_dies_when_file_chown_fails(self): provision = AgentProvisionPlan( template="claude", command="claude", prompt_mode="append_file", - image="", dockerfile="", guest_env={}, + image="", dockerfile="", guest_home="/home/node", guest_env={}, files=(AgentProvisionFile( Path("/tmp/claude.json"), "/home/node/.claude.json", ),), @@ -250,7 +249,7 @@ class TestClaudeProvision(unittest.TestCase): def test_runs_verify_commands(self): provision = AgentProvisionPlan( template="claude", command="claude", prompt_mode="append_file", - image="", dockerfile="", guest_env={}, + image="", dockerfile="", guest_home="/home/node", guest_env={}, verify=(AgentProvisionCommand( ("/usr/bin/true",), "verify failed", ),), diff --git a/tests/unit/test_contrib_codex_provider.py b/tests/unit/test_contrib_codex_provider.py index db9f4a2..1400241 100644 --- a/tests/unit/test_contrib_codex_provider.py +++ b/tests/unit/test_contrib_codex_provider.py @@ -77,7 +77,6 @@ def _plan( current_config_dir=Path("/tmp/current-config"), ) return DockerBottlePlan( - guest_home="/home/node", spec=spec, stage_dir=Path("/tmp/stage"), slug="demo-abc12", @@ -107,7 +106,7 @@ def _plan( use_runsc=False, agent_provision=agent_provision or AgentProvisionPlan( template="codex", command="codex", prompt_mode="read_prompt_file", - image="", dockerfile="", guest_env={}, + image="", dockerfile="", guest_home="/home/node", guest_env={}, ), workspace_plan=workspace_plan(spec, guest_home="/home/node"), ) @@ -177,7 +176,7 @@ class TestCodexProvision(unittest.TestCase): provision = AgentProvisionPlan( template="codex", command="codex", prompt_mode="read_prompt_file", - image="", dockerfile="", guest_env={}, + image="", dockerfile="", guest_home="/home/node", guest_env={}, dirs=(AgentProvisionDir("/home/node/.codex"),), files=(AgentProvisionFile( Path("/tmp/codex-config.toml"), @@ -201,7 +200,7 @@ class TestCodexProvision(unittest.TestCase): provision = AgentProvisionPlan( template="codex", command="codex", prompt_mode="read_prompt_file", - image="", dockerfile="", guest_env={}, + image="", dockerfile="", guest_home="/home/node", guest_env={}, pre_copy=(AgentProvisionCommand( ("find", "/home/node/.codex", "-name", "*.sqlite", "-delete"), "could not reset runtime db files", @@ -223,7 +222,7 @@ class TestCodexProvision(unittest.TestCase): provision = AgentProvisionPlan( template="codex", command="codex", prompt_mode="read_prompt_file", - image="", dockerfile="", guest_env={}, + image="", dockerfile="", guest_home="/home/node", guest_env={}, dirs=(AgentProvisionDir("/home/node/.codex"),), ) bottle = _make_bottle(exec_result=ExecResult(1, "", "mkdir: nope\n")) diff --git a/tests/unit/test_docker_launch_teardown.py b/tests/unit/test_docker_launch_teardown.py index 8761237..0bfeae5 100644 --- a/tests/unit/test_docker_launch_teardown.py +++ b/tests/unit/test_docker_launch_teardown.py @@ -43,7 +43,6 @@ def _plan(tmp: str) -> DockerBottlePlan: identity="test-teardown-00001", ) return DockerBottlePlan( - guest_home="/home/node", spec=spec, stage_dir=stage, git_gate_plan=GitGatePlan( @@ -66,6 +65,7 @@ def _plan(tmp: str) -> DockerBottlePlan: prompt_mode="append_file", image="", dockerfile="", + guest_home="/home/node", guest_env={}, ), workspace_plan=workspace_plan(spec, guest_home="/home/node"), diff --git a/tests/unit/test_docker_provision_git_user.py b/tests/unit/test_docker_provision_git_user.py index 7bc8367..046cde8 100644 --- a/tests/unit/test_docker_provision_git_user.py +++ b/tests/unit/test_docker_provision_git_user.py @@ -61,7 +61,6 @@ def _plan(*, git_user: dict | None = None, # type: ignore copy_cwd=copy_cwd, user_cwd=user_cwd, ) return DockerBottlePlan( - guest_home="/home/node", spec=spec, stage_dir=stage_dir or Path("/tmp/stage"), slug="demo-abc12", @@ -95,6 +94,7 @@ def _plan(*, git_user: dict | None = None, # type: ignore prompt_mode="append_file", image="bot-bottle-claude:latest", dockerfile="", + guest_home="/home/node", guest_env={}, ), workspace_plan=workspace_plan(spec, guest_home="/home/node"), diff --git a/tests/unit/test_plan_print_parity.py b/tests/unit/test_plan_print_parity.py index 7ca7ed2..22c915d 100644 --- a/tests/unit/test_plan_print_parity.py +++ b/tests/unit/test_plan_print_parity.py @@ -86,6 +86,7 @@ def _agent_provision() -> AgentProvisionPlan: prompt_mode="append_file", image="", dockerfile="", + guest_home="/home/node", guest_env={"HTTPS_PROXY": "http://127.0.0.1:9999"}, ) @@ -93,7 +94,6 @@ def _agent_provision() -> AgentProvisionPlan: def _docker_plan(spec: BottleSpec, tmp: str) -> DockerBottlePlan: stage = Path(tmp) return DockerBottlePlan( - guest_home="/home/node", spec=spec, stage_dir=stage, git_gate_plan=_git_gate_plan(tmp), @@ -118,7 +118,6 @@ def _docker_plan(spec: BottleSpec, tmp: str) -> DockerBottlePlan: def _smolmachines_plan(spec: BottleSpec, tmp: str) -> SmolmachinesBottlePlan: stage = Path(tmp) return SmolmachinesBottlePlan( - guest_home="/home/node", spec=spec, stage_dir=stage, git_gate_plan=_git_gate_plan(tmp), diff --git a/tests/unit/test_smolmachines_prepare.py b/tests/unit/test_smolmachines_prepare.py index a7e6b5c..3f2a696 100644 --- a/tests/unit/test_smolmachines_prepare.py +++ b/tests/unit/test_smolmachines_prepare.py @@ -71,6 +71,7 @@ class TestSmolmachinesResolveEnv(unittest.TestCase): prompt_mode="append_file", dockerfile="", image="bot-bottle-claude:latest", + guest_home="/home/node", guest_env=dict(kwargs.get("guest_env") or {}), ) mock_app.side_effect = lambda **kw: _make_provision(**kw) # type: ignore diff --git a/tests/unit/test_smolmachines_provision.py b/tests/unit/test_smolmachines_provision.py index 5bedc5d..fad7839 100644 --- a/tests/unit/test_smolmachines_provision.py +++ b/tests/unit/test_smolmachines_provision.py @@ -140,7 +140,6 @@ def _plan( current_config_dir=Path("/tmp/current-config"), ) return SmolmachinesBottlePlan( - guest_home="/home/node", spec=spec, stage_dir=stage_dir or Path("/tmp/stage"), slug="demo-abc12", @@ -190,6 +189,7 @@ def _agent_provision( prompt_mode="append_file", image="", dockerfile="", + guest_home="/home/node", guest_env=dict(guest_env or {}), ) auth_dir = (guest_env or {}).get("CODEX_HOME", "/home/node/.codex") @@ -227,6 +227,7 @@ def _agent_provision( prompt_mode="read_prompt_file", image="bot-bottle-codex:latest", dockerfile="", + guest_home="/home/node", guest_env=dict(guest_env or {}), dirs=(AgentProvisionDir(auth_dir),), files=tuple(files),