container: Improve usability of web mode, error handling, and CLI commands

Use --network host so that web interfaces (e.g. opencode web) are
accessible from the host. Suppress Python tracebacks when the tool
exits with a non-zero code. Ignore SIGTSTP to prevent Ctrl+Z from
leaving orphaned containers. Rename force-cleanup to purge.
This commit is contained in:
Jeena 2026-03-28 22:07:58 +00:00
parent 61017da6ba
commit 2d3d5caacb
2 changed files with 15 additions and 9 deletions

View file

@ -63,12 +63,12 @@ agent-container update
This removes all existing containers and rebuilds the image from scratch. Containers are recreated automatically on the next run. The persistent home directory is not affected. This removes all existing containers and rebuilds the image from scratch. Containers are recreated automatically on the next run. The persistent home directory is not affected.
### Force Cleanup ### Purge
To remove all containers, the image, and the persistent home directory: To remove all containers, the image, and the persistent home directory:
```sh ```sh
agent-container force-cleanup agent-container purge
``` ```
## Sharing host config files via hard links ## Sharing host config files via hard links

View file

@ -3,6 +3,7 @@
import hashlib import hashlib
import logging import logging
import os import os
import signal
import subprocess import subprocess
import sys import sys
import time import time
@ -16,7 +17,7 @@ Usage:
agent-container opencode [args...] Run OpenCode in the container agent-container opencode [args...] Run OpenCode in the container
agent-container claude [args...] Run Claude Code in the container agent-container claude [args...] Run Claude Code in the container
agent-container update Rebuild image with latest versions agent-container update Rebuild image with latest versions
agent-container force-cleanup Remove all containers, image, and data agent-container purge Remove all containers, image, and data
""" """
@ -78,8 +79,8 @@ class AgentContainer:
) )
elif command == "update": elif command == "update":
self.update() self.update()
elif command == "force-cleanup": elif command == "purge":
self.force_cleanup() self.purge()
else: else:
logger.error(f"Unknown command: {command}") logger.error(f"Unknown command: {command}")
print(USAGE, file=sys.stderr) print(USAGE, file=sys.stderr)
@ -132,8 +133,10 @@ class AgentContainer:
raise RuntimeError("Container failed to start after recreation") raise RuntimeError("Container failed to start after recreation")
try: try:
signal.signal(signal.SIGTSTP, signal.SIG_IGN)
self._exec_tool(tool, args, env_vars, extra_env or {}) self._exec_tool(tool, args, env_vars, extra_env or {})
finally: finally:
signal.signal(signal.SIGTSTP, signal.SIG_DFL)
self.stop_container() self.stop_container()
def _exec_tool( def _exec_tool(
@ -151,7 +154,7 @@ class AgentContainer:
for var, val in extra_env.items(): for var, val in extra_env.items():
env_args += ["-e", f"{var}={val}"] env_args += ["-e", f"{var}={val}"]
subprocess.run( result = subprocess.run(
[ [
"docker", "docker",
"exec", "exec",
@ -163,8 +166,9 @@ class AgentContainer:
tool, tool,
*args, *args,
], ],
check=True,
) )
if result.returncode != 0:
sys.exit(result.returncode)
# ========================= # =========================
# Image handling # Image handling
@ -213,6 +217,8 @@ class AgentContainer:
"create", "create",
"--name", "--name",
self.container_name, self.container_name,
"--network",
"host",
"--user", "--user",
f"{self.host_uid}:{self.host_gid}", f"{self.host_uid}:{self.host_gid}",
"--volume", "--volume",
@ -263,8 +269,8 @@ class AgentContainer:
self.build_image(no_cache=True) self.build_image(no_cache=True)
logger.info("Update complete. Containers will be recreated on next run.") logger.info("Update complete. Containers will be recreated on next run.")
def force_cleanup(self) -> None: def purge(self) -> None:
logger.info("Running force cleanup...") logger.info("Purging all containers, image, and data...")
self._remove_all_containers() self._remove_all_containers()
if self.image_exists(): if self.image_exists():