Split main.ts into worker.ts (queue) + agent-runner.ts (execution) #36

Closed
opened 2026-04-18 10:33:59 +00:00 by claude-desktop · 0 comments
Collaborator

User story

As a maintainer, I want src/main.ts (1212 lines) split so that the per-agent task queue and the Claude Agent SDK execution live in separate modules, so that Worker.runAgent (222 lines of container setup + session resume + SDK spawn) stops being the biggest unreadable block in the codebase and each concern can be tested in isolation.

Context

src/main.ts currently owns:

  • HTTP server and API routes
  • Worker class (queue, enqueue, getResult, processNext)
  • Worker.runAgent — 222 lines combining: pre-flight container checks, credential+token wiring, SDK spawn, session resume, session capture
  • Result store with TTL
  • SSE broadcast for dashboard events
  • Storage / history / queue introspection endpoints
  • Prompt building

The Worker lifecycle (FIFO queue, idempotent dispatch, backpressure) is orthogonal to what happens inside a single task (container setup, SDK invocation, session bookkeeping). Splitting the two lets future changes to either side land without touching the other.

Acceptance criteria

New file layout

  • src/worker.tsWorker class only (FIFO queue, enqueue, getResult, processNext, result store TTL). Knows nothing about the SDK; takes a runTask callback injected at construction.
  • src/agent-runner.ts — the logic currently in Worker.runAgent: container pre-flight, env construction, SDK spawn, session resume, session capture, retry-on-invalid-session. One exported function: runAgentTask(agent, task, session, env) → result.
  • src/main.ts — HTTP server + API routes + orchestration. Wires each Worker with runAgentTask from agent-runner.ts. Target ≤ 500 lines.

Session resume stays correct

  • Session-resume behavior is preserved to the character. The order of operations — check stored session → pass resume to SDK → on failure, drop session, retry fresh — is identical.
  • A unit test covers: (a) fresh dispatch with no stored session, (b) successful resume, (c) resume fails → session dropped and fresh retry runs.

Container mode unchanged

  • agent-runner.ts owns the cwd = hostCwd | workdir decision (the fix from commit 0e3ea72). Regression test: run a task in container mode and verify the SDK is spawned with a host-existing cwd.
  • Pre-flight check (ensureContainerReady) still fails fast with a clear error if the agent's container is down.

Behavior-preserving

  • All existing main.test.ts tests pass after the split. Tests can move into worker.test.ts and agent-runner.test.ts as appropriate.
  • Live E2E on charles/dummy-app issue → PR → merge still completes.
  • just qa green.

Public API stable

  • main.ts still exports getWorker (used by webhook.ts) with the same signature.
  • TaskRequest type stays exported from wherever callers currently import it (can stay in main.ts re-exported from the new module, or move to a shared types.ts — justify whichever choice in the PR).

Out of scope

  • webhook.ts split (see #A).
  • Hardening items (see #B).
  • Deeper test coverage for runAgent beyond the three session-resume cases listed above (see #D).

References

  • Codebase audit 2026-04-18.
  • Session-resume correctness: src/sessions.ts and its existing tests.

Dependencies

  • Not blocked by: anything (independent of #A / #B / #D).
  • Branch off: main
## User story As a **maintainer**, I want `src/main.ts` (1212 lines) split so that the per-agent task queue and the Claude Agent SDK execution live in separate modules, so that `Worker.runAgent` (222 lines of container setup + session resume + SDK spawn) stops being the biggest unreadable block in the codebase and each concern can be tested in isolation. ## Context `src/main.ts` currently owns: - HTTP server and API routes - `Worker` class (queue, enqueue, getResult, processNext) - `Worker.runAgent` — 222 lines combining: pre-flight container checks, credential+token wiring, SDK spawn, session resume, session capture - Result store with TTL - SSE broadcast for dashboard events - Storage / history / queue introspection endpoints - Prompt building The `Worker` lifecycle (FIFO queue, idempotent dispatch, backpressure) is orthogonal to what happens inside a single task (container setup, SDK invocation, session bookkeeping). Splitting the two lets future changes to either side land without touching the other. ## Acceptance criteria ### New file layout - [ ] `src/worker.ts` — `Worker` class only (FIFO queue, `enqueue`, `getResult`, `processNext`, result store TTL). Knows nothing about the SDK; takes a `runTask` callback injected at construction. - [ ] `src/agent-runner.ts` — the logic currently in `Worker.runAgent`: container pre-flight, env construction, SDK spawn, session resume, session capture, retry-on-invalid-session. One exported function: `runAgentTask(agent, task, session, env)` → result. - [ ] `src/main.ts` — HTTP server + API routes + orchestration. Wires each `Worker` with `runAgentTask` from `agent-runner.ts`. Target ≤ 500 lines. ### Session resume stays correct - [ ] Session-resume behavior is preserved to the character. The order of operations — check stored session → pass `resume` to SDK → on failure, drop session, retry fresh — is identical. - [ ] A unit test covers: (a) fresh dispatch with no stored session, (b) successful resume, (c) resume fails → session dropped and fresh retry runs. ### Container mode unchanged - [ ] `agent-runner.ts` owns the `cwd = hostCwd | workdir` decision (the fix from commit `0e3ea72`). Regression test: run a task in container mode and verify the SDK is spawned with a host-existing `cwd`. - [ ] Pre-flight check (`ensureContainerReady`) still fails fast with a clear error if the agent's container is down. ### Behavior-preserving - [ ] All existing `main.test.ts` tests pass after the split. Tests can move into `worker.test.ts` and `agent-runner.test.ts` as appropriate. - [ ] Live E2E on `charles/dummy-app` issue → PR → merge still completes. - [ ] `just qa` green. ### Public API stable - [ ] `main.ts` still exports `getWorker` (used by `webhook.ts`) with the same signature. - [ ] `TaskRequest` type stays exported from wherever callers currently import it (can stay in `main.ts` re-exported from the new module, or move to a shared `types.ts` — justify whichever choice in the PR). ## Out of scope - webhook.ts split (see **#A**). - Hardening items (see **#B**). - Deeper test coverage for `runAgent` beyond the three session-resume cases listed above (see **#D**). ## References - Codebase audit 2026-04-18. - Session-resume correctness: `src/sessions.ts` and its existing tests. ## Dependencies - **Not blocked by:** anything (independent of #A / #B / #D). - **Branch off:** `main`
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
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#36
No description provided.