feat(agents): ContainerLifecyclePort + Docker / host adapters #525

Merged
code-lead merged 1 commit from boss/515 into main 2026-04-28 10:54:48 +00:00
Collaborator

Introduces the M25 ContainerLifecyclePort that owns container pre-flight, env binding, exec wrapping, and per-dispatch release; adds Docker and no-op host adapters under infrastructure/agents/. Wiring into DefaultAgentDispatch is deferred to a follow-up ticket.

Closes #515

Test plan

  • bun test src/infrastructure/agents/ — 17 new unit tests pass.
  • bun x turbo run typecheck --filter=@claude-hooks/server clean.
  • bun x @biomejs/biome check apps/server/src/domain/ports/ apps/server/src/infrastructure/agents/ clean.
  • DockerContainerLifecycle.ensureReady runs creds-bind safety, container-running and settings.json pre-flight; throws on host_mode agents and unsafe binds.
  • DockerContainerLifecycle.buildExecEnv emits CLAUDE_CONFIG_DIR + CLAUDE_HOOKS_DOCKER_* shim contract vars + forge identity.
  • DockerContainerLifecycle.buildExecArgs returns the ["docker","exec","-i","-w",cwd,"-e","K=V",…,container] form.
  • HostContainerLifecycle.buildExecEnv points CLAUDE_CONFIG_DIR at the per-instance dir and skips shim contract vars.
  • release() is idempotent on both adapters.
Introduces the M25 ContainerLifecyclePort that owns container pre-flight, env binding, exec wrapping, and per-dispatch release; adds Docker and no-op host adapters under `infrastructure/agents/`. Wiring into `DefaultAgentDispatch` is deferred to a follow-up ticket. Closes #515 ## Test plan - [ ] `bun test src/infrastructure/agents/` — 17 new unit tests pass. - [ ] `bun x turbo run typecheck --filter=@claude-hooks/server` clean. - [ ] `bun x @biomejs/biome check apps/server/src/domain/ports/ apps/server/src/infrastructure/agents/` clean. - [ ] DockerContainerLifecycle.ensureReady runs creds-bind safety, container-running and settings.json pre-flight; throws on host_mode agents and unsafe binds. - [ ] DockerContainerLifecycle.buildExecEnv emits CLAUDE_CONFIG_DIR + CLAUDE_HOOKS_DOCKER_* shim contract vars + forge identity. - [ ] DockerContainerLifecycle.buildExecArgs returns the `["docker","exec","-i","-w",cwd,"-e","K=V",…,container]` form. - [ ] HostContainerLifecycle.buildExecEnv points CLAUDE_CONFIG_DIR at the per-instance dir and skips shim contract vars. - [ ] `release()` is idempotent on both adapters.
feat(agents): ContainerLifecyclePort + Docker / host adapters
All checks were successful
qa / qa (pull_request) Successful in 12m16s
qa / dockerfile (pull_request) Successful in 13s
37e7e320db
Introduces the M25 ContainerLifecyclePort that owns container pre-flight,
env binding, exec wrapping, and per-dispatch release. Two adapters under
infrastructure/agents/: DockerContainerLifecycle reuses the existing
buildAgentEnv / buildDockerExecArgs / writeInstanceSettings helpers so
behaviour stays byte-identical to the inline path; HostContainerLifecycle
is a no-op for the foreman singleton. Wiring into DefaultAgentDispatch
is deferred to a follow-up ticket.

Closes #515

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
reviewer approved these changes 2026-04-28 10:54:20 +00:00
reviewer left a comment

CI green. Port boundary is clean — ContainerHandle is a plain primitive object with no dockerode/child_process surface. All four ACs (port interface, Docker adapter pre-flight, host no-op adapter, unit tests) are met.

Two nits not worth blocking on:

  • dockerRunner is wired into the DI interface and initialised via makeDefaultDockerRunner() in the constructor but never read in any instance method — dead DI surface.
  • toRunnerAgent is duplicated verbatim across both adapter files; a shared helper would remove the copy.
CI green. Port boundary is clean — `ContainerHandle` is a plain primitive object with no `dockerode`/`child_process` surface. All four ACs (port interface, Docker adapter pre-flight, host no-op adapter, unit tests) are met. Two nits not worth blocking on: - `dockerRunner` is wired into the DI interface and initialised via `makeDefaultDockerRunner()` in the constructor but never read in any instance method — dead DI surface. - `toRunnerAgent` is duplicated verbatim across both adapter files; a shared helper would remove the copy.
code-lead deleted branch boss/515 2026-04-28 10:54:52 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
charles/claude-hooks!525
No description provided.