Files
Codewalkers/docs/server-api.md
Lukas May 9b91ffe0e5 fix: Persist and expose task dependencies from detail output
Detail agents define task dependencies in YAML frontmatter but they were
silently dropped — never written to the task_dependencies table. This
caused all tasks to dispatch in parallel regardless of intended ordering,
and the frontend showed no dependency information.

- Add fileIdToDbId mapping and second-pass dependency creation in
  output-handler.ts (mirrors existing phase dependency pattern)
- Add task_dependency to changeset entry entityType enum
- Add listPhaseTaskDependencies tRPC procedure for batch querying
- Wire blockedBy in PhaseDetailPanel and PhaseWithTasks from real data
- Clarify dependency semantics in detail prompt
2026-03-03 13:46:29 +01:00

234 lines
10 KiB
Markdown

# Server & API Module
`apps/server/server/` — HTTP server, `apps/server/trpc/` — tRPC procedures, `apps/server/coordination/` — merge queue.
## HTTP Server
**Framework**: Native `node:http` (no Express/Fastify)
**Default**: `127.0.0.1:3847`
**PID file**: `~/.cw/server.pid`
### Routes
| Route | Method | Purpose |
|-------|--------|---------|
| `/health` | GET | Health check (`{ status, uptime, processCount }`) |
| `/status` | GET | Full server status with process list |
| `/trpc/*` | POST | All tRPC procedure calls |
### Lifecycle
- `CoordinationServer.start()` — checks PID file, creates HTTP server, emits `server:started`
- `CoordinationServer.stop()` — emits `server:stopped`, closes server, removes PID file
- `GracefulShutdown` handles SIGTERM/SIGINT/SIGHUP with 10s timeout
### tRPC Adapter
`trpc-adapter.ts` converts `node:http` IncomingMessage/ServerResponse to fetch Request/Response for tRPC. Subscriptions stream via ReadableStream bodies (SSE).
## tRPC Context
All procedures share a context with optional dependencies:
```typescript
interface TRPCContext {
eventBus: EventBus // always present
serverStartedAt: Date | null
processCount: number
agentManager?: AgentManager // optional
taskRepository?: TaskRepository
// ... all 10 repositories, 3 managers, credentialManager, workspaceRoot
}
```
Each procedure uses `require*Repository(ctx)` helpers that throw `TRPCError(INTERNAL_SERVER_ERROR)` if a dependency is missing.
## Procedure Reference
### System
| Procedure | Type | Description |
|-----------|------|-------------|
| health | query | Health check with uptime |
| status | query | Server status with process list |
| systemHealthCheck | query | Account, agent, project health |
### Agents
| Procedure | Type | Description |
|-----------|------|-------------|
| spawnAgent | mutation | Spawn new agent (taskId, prompt, provider, mode) |
| stopAgent | mutation | Stop agent by name or ID |
| deleteAgent | mutation | Delete agent and clean up worktree |
| dismissAgent | mutation | Dismiss agent (set userDismissedAt) |
| resumeAgent | mutation | Resume with answers |
| listAgents | query | All agents |
| getAgent | query | Single agent by name or ID |
| getAgentResult | query | Execution result |
| getAgentQuestions | query | Pending questions |
| getAgentOutput | query | Full output from DB log chunks |
| getActiveRefineAgent | query | Active refine agent for initiative |
| listWaitingAgents | query | Agents waiting for input |
| onAgentOutput | subscription | Live raw JSONL output stream via EventBus |
### Tasks
| Procedure | Type | Description |
|-----------|------|-------------|
| listTasks | query | Child tasks of parent |
| getTask | query | Single task |
| updateTaskStatus | mutation | Change task status |
| createInitiativeTask | mutation | Create task on initiative |
| createPhaseTask | mutation | Create task on phase |
| listInitiativeTasks | query | All tasks for initiative |
| listPhaseTasks | query | All tasks for phase |
| listPendingApprovals | query | Tasks with status=pending_approval |
| deleteTask | mutation | Delete a task by ID |
| listPhaseTaskDependencies | query | All task dependency edges for tasks in a phase |
| approveTask | mutation | Approve and complete task |
### Initiatives
| Procedure | Type | Description |
|-----------|------|-------------|
| createInitiative | mutation | Create with optional branch/projectIds/description, auto-creates root page; if description provided, auto-spawns discuss agent |
| listInitiatives | query | Filter by status; returns `activity` (state, activePhase, phase counts) computed from phases |
| getInitiative | query | With projects array |
| updateInitiative | mutation | Name, status |
| deleteInitiative | mutation | Cascade delete initiative and all children |
| updateInitiativeConfig | mutation | mergeRequiresApproval, executionMode, branch |
### Phases
| Procedure | Type | Description |
|-----------|------|-------------|
| createPhase | mutation | Create in initiative |
| listPhases | query | By initiative |
| getPhase | query | Single phase |
| updatePhase | mutation | Name, content, status |
| approvePhase | mutation | Validate and approve |
| deletePhase | mutation | Cascade delete |
| createPhasesFromPlan | mutation | Bulk create from agent output |
| createPhaseDependency | mutation | Add dependency edge |
| removePhaseDependency | mutation | Remove dependency edge |
| listInitiativePhaseDependencies | query | All dependency edges |
| getPhaseDependencies | query | What this phase depends on |
| getPhaseDependents | query | What depends on this phase |
### Phase Dispatch
| Procedure | Type | Description |
|-----------|------|-------------|
| queuePhase | mutation | Queue approved phase |
| queueAllPhases | mutation | Queue all approved phases for initiative |
| dispatchNextPhase | mutation | Start next ready phase |
| getPhaseQueueState | query | Queue state |
| createChildTasks | mutation | Create tasks from detail parent |
### Architect (High-Level Agent Spawning)
| Procedure | Type | Description |
|-----------|------|-------------|
| spawnArchitectDiscuss | mutation | Discussion agent |
| spawnArchitectPlan | mutation | Plan agent (generates phases). Passes initiative context (phases, execution tasks only, pages) |
| spawnArchitectRefine | mutation | Refine agent (generates proposals) |
| spawnArchitectDetail | mutation | Detail agent (generates tasks). Passes initiative context (phases, execution tasks only, pages) |
### Dispatch
| Procedure | Type | Description |
|-----------|------|-------------|
| queueTask | mutation | Add task to dispatch queue |
| dispatchNext | mutation | Dispatch next ready task |
| getQueueState | query | Queue state |
| completeTask | mutation | Complete with approval check |
### Coordination (Merge Queue)
| Procedure | Type | Description |
|-----------|------|-------------|
| queueMerge | mutation | Queue task for merge |
| processMerges | mutation | Process merge queue |
| getMergeQueueStatus | query | Queue state |
| getNextMergeable | query | Next ready-to-merge task |
### Projects
| Procedure | Type | Description |
|-----------|------|-------------|
| registerProject | mutation | Clone git repo, create record. Validates defaultBranch exists in repo |
| listProjects | query | All projects |
| getProject | query | Single project |
| updateProject | mutation | Update project settings (defaultBranch). Validates branch exists in repo |
| deleteProject | mutation | Delete clone and record |
| getInitiativeProjects | query | Projects for initiative |
| updateInitiativeProjects | mutation | Sync junction table |
### Pages
| Procedure | Type | Description |
|-----------|------|-------------|
| getRootPage | query | Auto-creates if missing |
| getPage | query | Single page |
| getPageUpdatedAtMap | query | Bulk updatedAt check |
| listPages | query | By initiative |
| listChildPages | query | By parent page |
| createPage | mutation | Create, emit page:created |
| updatePage | mutation | Title/content/sortOrder, emit page:updated |
| deletePage | mutation | Delete, emit page:deleted |
### Accounts
| Procedure | Type | Description |
|-----------|------|-------------|
| listAccounts | query | All accounts |
| addAccount | mutation | Create account |
| removeAccount | mutation | Delete account |
| refreshAccounts | mutation | Clear expired exhaustion |
| updateAccountAuth | mutation | Update credentials |
| markAccountExhausted | mutation | Set exhaustion timer |
| listProviderNames | query | Available provider names |
### Proposals
| Procedure | Type | Description |
|-----------|------|-------------|
| listProposals | query | By agent or initiative |
| acceptProposal | mutation | Apply side effects, auto-dismiss agent |
| dismissProposal | mutation | Dismiss, auto-dismiss agent |
| acceptAllProposals | mutation | Bulk accept with error collection |
| dismissAllProposals | mutation | Bulk dismiss |
### Subscriptions (SSE)
| Procedure | Type | Events |
|-----------|------|--------|
| onEvent | subscription | All 30+ event types |
| onAgentUpdate | subscription | agent:* events (8 types) |
| onTaskUpdate | subscription | task:* + phase:* events (8 types) |
| onPageUpdate | subscription | page:created/updated/deleted |
Subscriptions use `eventBusIterable()` — queue-based async generator, max 1000 events, 30s heartbeat.
## Coordination Module
`apps/server/coordination/` manages merge queue:
- **CoordinationManager** port: `queueMerge`, `getNextMergeable`, `processMerges`, `handleConflict`, `getQueueState`
- **DefaultCoordinationManager** adapter: in-memory queue, dependency-ordered processing
- **ConflictResolutionService**: creates resolution tasks for merge conflicts
- Merge flow: queue → check deps → merge via WorktreeManager → handle conflicts
- Events: `merge:queued`, `merge:started`, `merge:completed`, `merge:conflicted`
## Preview Procedures
Docker-based preview deployments. No database table — Docker is the source of truth.
| Procedure | Type | Description |
|-----------|------|-------------|
| `startPreview` | mutation | Start preview: `{initiativeId, phaseId?, projectId, branch}` → PreviewStatus |
| `stopPreview` | mutation | Stop preview: `{previewId}` |
| `listPreviews` | query | List active previews: `{initiativeId?}` → PreviewStatus[] |
| `getPreviewStatus` | query | Get preview status: `{previewId}` → PreviewStatus |
Context dependency: `requirePreviewManager(ctx)` — requires `PreviewManager` from container.
## Conversation Procedures
Inter-agent communication for parallel agents.
| Procedure | Type | Description |
|-----------|------|-------------|
| `createConversation` | mutation | Ask a question: `{fromAgentId, toAgentId?, phaseId?, taskId?, question}` → Conversation |
| `getPendingConversations` | query | Poll for incoming questions: `{agentId}` → Conversation[] |
| `getConversation` | query | Get conversation by ID: `{id}` → Conversation |
| `answerConversation` | mutation | Answer a conversation: `{id, answer}` → Conversation |
Target resolution: `toAgentId` → direct; `taskId` → find running agent by task; `phaseId` → find running agent by any task in phase.
Context dependency: `requireConversationRepository(ctx)`, `requireAgentManager(ctx)`.