---
phase: 04-agent-lifecycle
plan: 04
type: execute
wave: 3
depends_on: ["04-03"]
files_modified: [src/trpc/router.ts, src/trpc/context.ts, src/cli/index.ts, src/cli/trpc-client.ts]
autonomous: true
---

<objective>
Add agent procedures to tRPC router and CLI commands for agent management.

Purpose: Enable users to spawn, stop, list, and manage agents via CLI (AGENT-01, 02, 03).
Output: tRPC procedures and CLI commands for full agent lifecycle management.
</objective>

<execution_context>
@~/.claude/get-shit-done/workflows/execute-plan.md
@~/.claude/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/04-agent-lifecycle/DISCOVERY.md
@.planning/phases/04-agent-lifecycle/04-03-SUMMARY.md

@src/trpc/router.ts
@src/trpc/context.ts
@src/cli/index.ts
@src/cli/trpc-client.ts
</context>

<tasks>

<task type="auto">
  <name>Task 1: Add AgentManager to tRPC context</name>
  <files>src/trpc/context.ts</files>
  <action>
Update tRPC context to include AgentManager:

1. Import AgentManager and ClaudeAgentManager
2. Add agentManager to context type
3. Create agentManager in context factory (requires repository and worktreeManager from context)

The context should wire up:
- AgentRepository (from database)
- WorktreeManager (from git module)
- EventBus (optional, for event emission)

Example pattern from existing context:
```typescript
export interface Context {
  // ... existing
  agentManager: AgentManager;
}

export function createContext(): Context {
  // ... existing setup
  const agentRepository = new DrizzleAgentRepository(db);
  const agentManager = new ClaudeAgentManager(
    agentRepository,
    worktreeManager,
    eventBus
  );
  return {
    // ... existing
    agentManager,
  };
}
```

Note: Context may need to be async if database/worktree setup is async.
  </action>
  <verify>npm run build passes</verify>
  <done>AgentManager available in tRPC context</done>
</task>

<task type="auto">
  <name>Task 2: Add agent procedures to tRPC router</name>
  <files>src/trpc/router.ts</files>
  <action>
Add agent procedures following existing patterns:

```typescript
// Add to router.ts

import { z } from 'zod';

// Input schemas - support lookup by name OR id
const spawnAgentInput = z.object({
  name: z.string(),           // Human-readable name (required)
  taskId: z.string(),
  prompt: z.string(),
  cwd: z.string().optional(),
});

const agentIdentifier = z.object({
  name: z.string().optional(),  // Lookup by name (preferred)
  id: z.string().optional(),    // Or by ID
}).refine(data => data.name || data.id, {
  message: 'Either name or id must be provided',
});

const resumeAgentInput = z.object({
  name: z.string().optional(),
  id: z.string().optional(),
  prompt: z.string(),
}).refine(data => data.name || data.id, {
  message: 'Either name or id must be provided',
});

// Helper to resolve agent by name or id
async function resolveAgent(ctx: Context, input: { name?: string; id?: string }) {
  if (input.name) {
    return ctx.agentManager.getByName(input.name);
  }
  return ctx.agentManager.get(input.id!);
}

// Add to router
export const appRouter = router({
  // ... existing procedures

  // Agent procedures
  spawnAgent: procedure
    .input(spawnAgentInput)
    .mutation(async ({ ctx, input }) => {
      const agent = await ctx.agentManager.spawn({
        name: input.name,
        taskId: input.taskId,
        prompt: input.prompt,
        cwd: input.cwd,
      });
      return agent;
    }),

  stopAgent: procedure
    .input(agentIdentifier)
    .mutation(async ({ ctx, input }) => {
      const agent = await resolveAgent(ctx, input);
      if (!agent) throw new Error('Agent not found');
      await ctx.agentManager.stop(agent.id);
      return { success: true, name: agent.name };
    }),

  listAgents: procedure
    .query(async ({ ctx }) => {
      return ctx.agentManager.list();
    }),

  getAgent: procedure
    .input(agentIdentifier)
    .query(async ({ ctx, input }) => {
      return resolveAgent(ctx, input);
    }),

  getAgentByName: procedure
    .input(z.object({ name: z.string() }))
    .query(async ({ ctx, input }) => {
      return ctx.agentManager.getByName(input.name);
    }),

  resumeAgent: procedure
    .input(resumeAgentInput)
    .mutation(async ({ ctx, input }) => {
      const agent = await resolveAgent(ctx, input);
      if (!agent) throw new Error('Agent not found');
      await ctx.agentManager.resume(agent.id, input.prompt);
      return { success: true, name: agent.name };
    }),

  getAgentResult: procedure
    .input(agentIdentifier)
    .query(async ({ ctx, input }) => {
      const agent = await resolveAgent(ctx, input);
      if (!agent) return null;
      return ctx.agentManager.getResult(agent.id);
    }),
});
```

Export updated AppRouter type for client.
  </action>
  <verify>npm run build passes</verify>
  <done>Agent tRPC procedures added: spawn, stop, list, get, resume, getResult</done>
</task>

<task type="auto">
  <name>Task 3: Add agent CLI commands</name>
  <files>src/cli/index.ts</files>
  <action>
Add CLI commands for agent management using existing tRPC client pattern:

```typescript
// Add commands to CLI - use NAMES as primary identifier (like gastown)

// cw agent spawn --name <name> --task <taskId> <prompt>
// Example: cw agent spawn --name gastown --task task-123 "Fix the auth bug"
program
  .command('agent spawn <prompt>')
  .description('Spawn a new agent to work on a task')
  .requiredOption('--name <name>', 'Human-readable name for the agent (e.g., gastown)')
  .requiredOption('--task <taskId>', 'Task ID to assign to agent')
  .option('--cwd <path>', 'Working directory for agent')
  .action(async (prompt: string, options: { name: string; task: string; cwd?: string }) => {
    const client = await getTrpcClient();
    try {
      const agent = await client.spawnAgent.mutate({
        name: options.name,
        taskId: options.task,
        prompt,
        cwd: options.cwd,
      });
      console.log(`Agent '${agent.name}' spawned`);
      console.log(`  ID: ${agent.id}`);
      console.log(`  Task: ${agent.taskId}`);
      console.log(`  Status: ${agent.status}`);
      console.log(`  Worktree: ${agent.worktreeId}`);
    } catch (error) {
      console.error('Failed to spawn agent:', error);
      process.exit(1);
    }
  });

// cw agent stop <name>
// Example: cw agent stop gastown
program
  .command('agent stop <name>')
  .description('Stop a running agent by name')
  .action(async (name: string) => {
    const client = await getTrpcClient();
    try {
      const result = await client.stopAgent.mutate({ name });
      console.log(`Agent '${result.name}' stopped`);
    } catch (error) {
      console.error('Failed to stop agent:', error);
      process.exit(1);
    }
  });

// cw agent list
program
  .command('agent list')
  .description('List all agents')
  .action(async () => {
    const client = await getTrpcClient();
    try {
      const agents = await client.listAgents.query();
      if (agents.length === 0) {
        console.log('No agents found');
        return;
      }
      console.log('Agents:');
      for (const agent of agents) {
        const status = agent.status === 'waiting_for_input' ? 'WAITING' : agent.status.toUpperCase();
        console.log(`  ${agent.name} [${status}] - ${agent.taskId}`);
      }
    } catch (error) {
      console.error('Failed to list agents:', error);
      process.exit(1);
    }
  });

// cw agent get <name>
// Example: cw agent get gastown
program
  .command('agent get <name>')
  .description('Get agent details by name')
  .action(async (name: string) => {
    const client = await getTrpcClient();
    try {
      const agent = await client.getAgent.query({ name });
      if (!agent) {
        console.log(`Agent '${name}' not found`);
        return;
      }
      console.log(`Agent: ${agent.name}`);
      console.log(`  ID: ${agent.id}`);
      console.log(`  Task: ${agent.taskId}`);
      console.log(`  Session: ${agent.sessionId ?? '(none)'}`);
      console.log(`  Worktree: ${agent.worktreeId}`);
      console.log(`  Status: ${agent.status}`);
      console.log(`  Created: ${agent.createdAt}`);
      console.log(`  Updated: ${agent.updatedAt}`);
    } catch (error) {
      console.error('Failed to get agent:', error);
      process.exit(1);
    }
  });

// cw agent resume <name> <response>
// Example: cw agent resume gastown "Use option A"
program
  .command('agent resume <name> <response>')
  .description('Resume an agent that is waiting for input')
  .action(async (name: string, response: string) => {
    const client = await getTrpcClient();
    try {
      const result = await client.resumeAgent.mutate({ name, prompt: response });
      console.log(`Agent '${result.name}' resumed`);
    } catch (error) {
      console.error('Failed to resume agent:', error);
      process.exit(1);
    }
  });

// cw agent result <name>
// Example: cw agent result gastown
program
  .command('agent result <name>')
  .description('Get agent execution result')
  .action(async (name: string) => {
    const client = await getTrpcClient();
    try {
      const result = await client.getAgentResult.query({ name });
      if (!result) {
        console.log('No result available (agent may still be running)');
        return;
      }
      console.log(`Result: ${result.success ? 'SUCCESS' : 'FAILED'}`);
      console.log(`  Message: ${result.message}`);
      if (result.filesModified?.length) {
        console.log(`  Files modified: ${result.filesModified.join(', ')}`);
      }
    } catch (error) {
      console.error('Failed to get result:', error);
      process.exit(1);
    }
  });
```

Commands use commander.js pattern from existing CLI.
  </action>
  <verify>npm run build passes, cw agent --help shows commands</verify>
  <done>CLI commands added: agent spawn, stop, list, get, resume, result</done>
</task>

</tasks>

<verification>
Before declaring plan complete:
- [ ] npm run build succeeds without errors
- [ ] cw agent --help shows all agent commands
- [ ] Agent procedures accessible via tRPC client
- [ ] All 6 requirements satisfied (AGENT-01 through AGENT-07 except AGENT-06)
</verification>

<success_criteria>
- All tasks completed
- All verification checks pass
- No errors or warnings introduced
- Users can manage agents via CLI
</success_criteria>

<output>
After completion, create `.planning/phases/04-agent-lifecycle/04-04-SUMMARY.md`
</output>
