Decomposed "Foundation Setup - Install Dependencies & Configure Tailwind" phase into 6 executable tasks: 1. Install Tailwind CSS, PostCSS & Autoprefixer 2. Map MUI theme to Tailwind design tokens 3. Setup CSS variables for dynamic theming 4. Install Radix UI primitives 5. Initialize shadcn/ui and setup component directory 6. Move MUI to devDependencies and verify setup Tasks follow logical dependency chain with final human verification checkpoint before proceeding with component migration. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
104 lines
4.7 KiB
Markdown
104 lines
4.7 KiB
Markdown
# Agent Module
|
|
|
|
`src/agent/` — Agent lifecycle management, output parsing, multi-provider support, and account failover.
|
|
|
|
## File Inventory
|
|
|
|
| File | Purpose |
|
|
|------|---------|
|
|
| `types.ts` | Core types: `AgentInfo`, `AgentManager` interface, `SpawnOptions`, `StreamEvent` |
|
|
| `manager.ts` | `MultiProviderAgentManager` — main orchestrator class |
|
|
| `process-manager.ts` | `AgentProcessManager` — worktree creation, command building, detached spawn |
|
|
| `output-handler.ts` | `OutputHandler` — JSONL stream parsing, completion detection, proposal creation |
|
|
| `file-tailer.ts` | `FileTailer` — watches output files, emits line events |
|
|
| `file-io.ts` | Input/output file I/O: frontmatter writing, signal.json reading, tiptap conversion |
|
|
| `markdown-to-tiptap.ts` | Markdown to Tiptap JSON conversion using MarkdownManager |
|
|
| `index.ts` | Public exports, `ClaudeAgentManager` deprecated alias |
|
|
|
|
### Sub-modules
|
|
|
|
| Directory | Purpose |
|
|
|-----------|---------|
|
|
| `providers/` | Provider registry, presets (7 providers), config types |
|
|
| `providers/parsers/` | Provider-specific output parsers (Claude JSONL, generic line) |
|
|
| `accounts/` | Account discovery, config dir setup, credential management, usage API |
|
|
| `credentials/` | `AccountCredentialManager` — credential injection per account |
|
|
| `lifecycle/` | `LifecycleController` — retry policy, signal recovery, missing signal instructions |
|
|
| `prompts/` | Mode-specific prompt builders (execute, discuss, breakdown, decompose, refine) |
|
|
|
|
## Key Flows
|
|
|
|
### Spawning an Agent
|
|
|
|
1. **tRPC procedure** calls `agentManager.spawn(options)`
|
|
2. Manager generates alias (adjective-animal), creates DB record
|
|
3. `AgentProcessManager.createWorktree()` — creates git worktree at `.cw-worktrees/agent/<alias>/`
|
|
4. `file-io.writeInputFiles()` — writes `.cw/input/` with initiative, pages, phase, task as frontmatter
|
|
5. Provider config builds spawn command via `buildSpawnCommand()`
|
|
6. `spawnDetached()` — launches detached child process with file output redirection
|
|
7. `FileTailer` watches output file, fires `onEvent` and `onRawContent` callbacks
|
|
8. `OutputHandler.handleStreamEvent()` processes each JSONL line
|
|
9. DB record updated with PID, output file path, session ID
|
|
10. `agent:spawned` event emitted
|
|
|
|
### Completion Detection
|
|
|
|
1. `FileTailer` detects process exit
|
|
2. `OutputHandler.handleCompletion()` triggered
|
|
3. **Primary path**: Reads `.cw/output/signal.json` from agent worktree
|
|
4. Signal contains `{ status: "done"|"questions"|"error", result?, questions?, error? }`
|
|
5. Agent DB status updated accordingly (idle, waiting_for_input, crashed)
|
|
6. For `done`: proposals created from structured output; `agent:stopped` emitted
|
|
7. For `questions`: parsed and stored as `pendingQuestions`; `agent:waiting` emitted
|
|
8. **Fallback**: If signal.json missing, lifecycle controller retries with instruction injection
|
|
|
|
### Account Failover
|
|
|
|
1. On usage-limit error, `markAccountExhausted(id, until)` called
|
|
2. `findNextAvailable(provider)` returns least-recently-used non-exhausted account
|
|
3. Agent re-spawned with new account's credentials
|
|
4. `agent:account_switched` event emitted
|
|
|
|
### Resume Flow
|
|
|
|
1. tRPC `resumeAgent` called with `answers: Record<string, string>`
|
|
2. Manager looks up agent's session ID and provider config
|
|
3. `buildResumeCommand()` creates resume command with session flag
|
|
4. `formatAnswersAsPrompt(answers)` converts answers to prompt text
|
|
5. New detached process spawned, same worktree, incremented session number
|
|
|
|
## Provider Configuration
|
|
|
|
Providers defined in `providers/presets.ts`:
|
|
|
|
| Provider | Command | Resume | Prompt Mode |
|
|
|----------|---------|--------|-------------|
|
|
| claude | `claude` | `--resume <id>` | native (`-p`) |
|
|
| claude-code | `claude` | `--resume <id>` | native |
|
|
| codex | `codex` | none | flag (`--prompt`) |
|
|
| aider | `aider` | none | flag (`--message`) |
|
|
| cline | `cline` | none | flag |
|
|
| continue | `continue` | none | flag |
|
|
| cursor-agent | `cursor` | none | flag |
|
|
|
|
Each provider config specifies: `command`, `args`, `resumeStyle`, `promptMode`, `structuredOutput`, `sessionId` extraction, `nonInteractive` options.
|
|
|
|
## Output Parsing
|
|
|
|
The `OutputHandler` processes JSONL streams from Claude CLI:
|
|
|
|
- `text_delta` events → accumulated as text output, emitted via `agent:output`
|
|
- `init` event → session ID extracted
|
|
- `result` event → final result with structured data
|
|
- Signal file (`signal.json`) → authoritative completion status
|
|
|
|
For providers without structured output, the generic line parser accumulates raw text.
|
|
|
|
## Log Chunks
|
|
|
|
Agent output is persisted to `agent_log_chunks` table:
|
|
- `onRawContent` callback fires for every output chunk
|
|
- Fire-and-forget DB insert (no FK to agents — survives deletion)
|
|
- Session tracking: spawn=1, resume=previousMax+1
|
|
- Read path concatenates all sessions for full output history
|