diff --git a/.planning/phases/10-multi-question-schema/10-01-PLAN.md b/.planning/phases/10-multi-question-schema/10-01-PLAN.md new file mode 100644 index 0000000..7b07fee --- /dev/null +++ b/.planning/phases/10-multi-question-schema/10-01-PLAN.md @@ -0,0 +1,181 @@ +--- +phase: 10-multi-question-schema +plan: 01 +type: execute +wave: 1 +depends_on: [] +files_modified: + - src/agent/schema.ts + - src/agent/types.ts + - src/events/types.ts +autonomous: true +--- + + +Extend agent output schema to return array of questions; update types throughout. + +Purpose: Enable agents to ask multiple questions in one pause, reducing round-trips. +Output: Updated Zod schema, TypeScript types, and event payloads supporting questions array. + + + +@~/.claude/get-shit-done/workflows/execute-plan.md +@~/.claude/get-shit-done/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/STATE.md +@.planning/phases/08.1-agent-output-schema/08.1-01-SUMMARY.md + +@src/agent/schema.ts +@src/agent/types.ts +@src/events/types.ts + + + + + + Task 1: Update agent output schema to questions array + src/agent/schema.ts + +Change `question` status variant from single question to array: + +Before: +```typescript +z.object({ + status: z.literal('question'), + question: z.string(), + options: z.array(optionSchema).optional(), + multiSelect: z.boolean().optional(), +}) +``` + +After: +```typescript +z.object({ + status: z.literal('questions'), // plural + questions: z.array(z.object({ + id: z.string(), // unique identifier for matching answers + question: z.string(), + options: z.array(optionSchema).optional(), + multiSelect: z.boolean().optional(), + })), +}) +``` + +Update `agentOutputJsonSchema` to match the Zod schema. + +Key points: +- Rename status from 'question' to 'questions' (plural) for clarity +- Each question has an `id` field so answers can be matched +- Single question case: `questions: [{ id: "q1", question: "..." }]` + + npm run typecheck passes + Schema exports updated AgentOutput type with questions array + + + + Task 2: Update PendingQuestion type to PendingQuestions + src/agent/types.ts + +Rename and restructure PendingQuestion: + +Before: +```typescript +export interface PendingQuestion { + question: string; + options?: Array<{ label: string; description?: string }>; + multiSelect?: boolean; +} +``` + +After: +```typescript +export interface QuestionItem { + id: string; + question: string; + options?: Array<{ label: string; description?: string }>; + multiSelect?: boolean; +} + +export interface PendingQuestions { + questions: QuestionItem[]; +} +``` + +Update AgentManager interface: +- Rename `getPendingQuestion` to `getPendingQuestions` +- Return type: `Promise` + + npm run typecheck passes + Types updated to array-based questions + + + + Task 3: Update AgentWaitingEvent payload + src/events/types.ts + +Update AgentWaitingEvent payload to use questions array: + +Before: +```typescript +export interface AgentWaitingEvent extends DomainEvent { + type: 'agent:waiting'; + payload: { + agentId: string; + name: string; + taskId: string; + sessionId: string; + question: string; + options?: Array<{ label: string; description?: string }>; + multiSelect?: boolean; + }; +} +``` + +After: +```typescript +export interface AgentWaitingEvent extends DomainEvent { + type: 'agent:waiting'; + payload: { + agentId: string; + name: string; + taskId: string; + sessionId: string; + questions: Array<{ + id: string; + question: string; + options?: Array<{ label: string; description?: string }>; + multiSelect?: boolean; + }>; + }; +} +``` + + npm run typecheck passes + Event payload uses questions array + + + + + +Before declaring plan complete: +- [ ] `npm run typecheck` passes +- [ ] `npm run build` succeeds +- [ ] Schema changes are consistent across all three files + + + + +- All tasks completed +- Agent output schema uses `questions` array (not single question) +- PendingQuestions type uses array +- AgentWaitingEvent payload uses questions array +- Each question has `id` field for answer matching + + + +After completion, create `.planning/phases/10-multi-question-schema/10-01-SUMMARY.md` + diff --git a/.planning/phases/10-multi-question-schema/10-02-PLAN.md b/.planning/phases/10-multi-question-schema/10-02-PLAN.md new file mode 100644 index 0000000..6a6e896 --- /dev/null +++ b/.planning/phases/10-multi-question-schema/10-02-PLAN.md @@ -0,0 +1,145 @@ +--- +phase: 10-multi-question-schema +plan: 02 +type: execute +wave: 2 +depends_on: ["10-01"] +files_modified: + - src/agent/manager.ts + - src/agent/mock-manager.ts +autonomous: true +--- + + +Update ClaudeAgentManager and MockAgentManager to handle questions array and batched answers. + +Purpose: Implementations must match the updated schema and types from Plan 01. +Output: Both managers handle multi-question flow with batched resume answers. + + + +@~/.claude/get-shit-done/workflows/execute-plan.md +@~/.claude/get-shit-done/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/phases/10-multi-question-schema/10-01-SUMMARY.md + +@src/agent/schema.ts +@src/agent/types.ts +@src/agent/manager.ts +@src/agent/mock-manager.ts + + + + + + Task 1: Update ClaudeAgentManager for questions array + src/agent/manager.ts + +Update handleAgentCompletion to handle 'questions' status (was 'question'): + +1. In switch statement, rename case 'question' to case 'questions' +2. Store pendingQuestions (plural) with the full questions array: +```typescript +case 'questions': { + if (active) { + active.pendingQuestions = { + questions: agentOutput.questions, + }; + } + // ... emit event with questions array +} +``` + +3. Update ActiveAgent interface: +```typescript +interface ActiveAgent { + subprocess: ResultPromise; + result?: AgentResult; + pendingQuestions?: PendingQuestions; // was pendingQuestion +} +``` + +4. Rename getPendingQuestion to getPendingQuestions, return pendingQuestions + +5. Update resume() signature to accept answers map: +```typescript +async resume(agentId: string, answers: Record): Promise +``` +The answers map keys are question IDs, values are the user's answers. +Format answers as structured prompt for Claude: one line per answer. + + npm run typecheck passes + ClaudeAgentManager handles questions array and batched answers + + + + Task 2: Update MockAgentManager for questions array + src/agent/mock-manager.ts + +1. Update MockAgentScenario type: +```typescript +| { + status: 'questions'; // was 'question' + questions: Array<{ + id: string; + question: string; + options?: Array<{ label: string; description?: string }>; + multiSelect?: boolean; + }>; + delay?: number; + } +``` + +2. Update MockAgentRecord interface: +```typescript +pendingQuestions?: PendingQuestions; // was pendingQuestion +``` + +3. Update completeAgent() switch case from 'question' to 'questions': +```typescript +case 'questions': + record.info.status = 'waiting_for_input'; + record.pendingQuestions = { + questions: scenario.questions, + }; + // emit event with questions array +``` + +4. Rename getPendingQuestion to getPendingQuestions + +5. Update resume() signature: +```typescript +async resume(agentId: string, answers: Record): Promise +``` +Clear pendingQuestions on resume. + + npm run typecheck passes + MockAgentManager handles questions array and batched answers + + + + + +Before declaring plan complete: +- [ ] `npm run typecheck` passes +- [ ] `npm run build` succeeds +- [ ] Both managers use questions array consistently +- [ ] resume() accepts answers map on both managers + + + + +- All tasks completed +- ClaudeAgentManager handles 'questions' status +- MockAgentManager handles 'questions' status +- Both resume() methods accept Record answers +- getPendingQuestions returns array-based type + + + +After completion, create `.planning/phases/10-multi-question-schema/10-02-SUMMARY.md` + diff --git a/.planning/phases/10-multi-question-schema/10-03-PLAN.md b/.planning/phases/10-multi-question-schema/10-03-PLAN.md new file mode 100644 index 0000000..cae78e7 --- /dev/null +++ b/.planning/phases/10-multi-question-schema/10-03-PLAN.md @@ -0,0 +1,139 @@ +--- +phase: 10-multi-question-schema +plan: 03 +type: execute +wave: 2 +depends_on: ["10-01"] +files_modified: + - src/test/harness.ts + - src/agent/manager.test.ts + - src/agent/mock-manager.test.ts + - src/test/harness.test.ts + - src/dispatch/manager.test.ts +autonomous: true +--- + + +Update TestHarness and all tests to use questions array schema. + +Purpose: Tests must exercise the new multi-question flow. +Output: All tests pass with updated schema, TestHarness provides multi-question helpers. + + + +@~/.claude/get-shit-done/workflows/execute-plan.md +@~/.claude/get-shit-done/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/phases/10-multi-question-schema/10-01-SUMMARY.md + +@src/test/harness.ts +@src/agent/mock-manager.ts + + + + + + Task 1: Update TestHarness convenience methods + src/test/harness.ts + +1. Update setAgentQuestion to setAgentQuestions (or keep name but accept array): +```typescript +setAgentQuestions( + agentName: string, + questions: Array<{ + id: string; + question: string; + options?: Array<{ label: string; description?: string }>; + multiSelect?: boolean; + }>, + delay?: number +): void { + this.agentManager.setScenario(agentName, { + status: 'questions', + questions, + delay, + }); +} +``` + +2. For single-question convenience, add helper that wraps: +```typescript +setAgentQuestion( + agentName: string, + questionId: string, + question: string, + options?: Array<{ label: string; description?: string }>, + delay?: number +): void { + this.setAgentQuestions(agentName, [{ + id: questionId, + question, + options, + }], delay); +} +``` + +3. Rename getPendingQuestion to getPendingQuestions, return PendingQuestions | null + + npm run typecheck passes + TestHarness supports questions array with convenience helpers + + + + Task 2: Update all tests for questions array + src/agent/manager.test.ts, src/agent/mock-manager.test.ts, src/test/harness.test.ts, src/dispatch/manager.test.ts + +Update all test files that use question scenarios: + +1. manager.test.ts: + - Update mock CLI output to use 'questions' status with array + - Update assertions for getPendingQuestions + +2. mock-manager.test.ts: + - Update all scenarios from { status: 'question', question: '...' } + to { status: 'questions', questions: [{ id: 'q1', question: '...' }] } + - Update assertions for pendingQuestions array + - Add test for multi-question scenario + +3. harness.test.ts: + - Update setAgentQuestion calls to new signature + - Update getPendingQuestions assertions + +4. dispatch/manager.test.ts: + - Update any question scenario mocks + +Search pattern to find affected code: +- `status: 'question'` → `status: 'questions'` +- `question:` (in scenarios) → `questions: [{ id: '...', question: ... }]` +- `getPendingQuestion` → `getPendingQuestions` +- `.question` assertions → `.questions[0].question` + + npm run test passes + All tests updated and passing with questions array + + + + + +Before declaring plan complete: +- [ ] `npm run typecheck` passes +- [ ] `npm run test` passes (all tests green) +- [ ] No references to old 'question' singular status remain + + + + +- All tasks completed +- TestHarness provides setAgentQuestions and setAgentQuestion helpers +- All existing tests updated to questions array format +- New test for multi-question scenario exists +- All tests pass + + + +After completion, create `.planning/phases/10-multi-question-schema/10-03-SUMMARY.md` + diff --git a/.planning/phases/10-multi-question-schema/10-04-PLAN.md b/.planning/phases/10-multi-question-schema/10-04-PLAN.md new file mode 100644 index 0000000..9e5df05 --- /dev/null +++ b/.planning/phases/10-multi-question-schema/10-04-PLAN.md @@ -0,0 +1,126 @@ +--- +phase: 10-multi-question-schema +plan: 04 +type: execute +wave: 3 +depends_on: ["10-02", "10-03"] +files_modified: + - src/test/e2e/edge-cases.test.ts + - src/test/e2e/recovery-scenarios.test.ts +autonomous: true +--- + + +Update E2E tests to use questions array schema and add multi-question E2E scenario. + +Purpose: Prove multi-question flow works end-to-end through dispatch/coordination. +Output: E2E tests pass with new schema, multi-question scenario validated. + + + +@~/.claude/get-shit-done/workflows/execute-plan.md +@~/.claude/get-shit-done/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/phases/10-multi-question-schema/10-02-SUMMARY.md +@.planning/phases/10-multi-question-schema/10-03-SUMMARY.md + +@src/test/e2e/edge-cases.test.ts +@src/test/e2e/recovery-scenarios.test.ts + + + + + + Task 1: Update existing E2E tests for questions array + src/test/e2e/edge-cases.test.ts, src/test/e2e/recovery-scenarios.test.ts + +Update all E2E tests that use question scenarios: + +1. edge-cases.test.ts: + - Find all setAgentQuestion calls, update to new signature with id + - Update any direct scenario setting to use questions array + - Update assertions checking question data + +2. recovery-scenarios.test.ts: + - Update Q&A flow tests to use questions array format + - Update resume calls to pass answers as Record + - Update assertions for getPendingQuestions + +Replace patterns: +- `harness.setAgentQuestion(name, question)` → `harness.setAgentQuestion(name, 'q1', question)` +- `agentManager.resume(id, answer)` → `agentManager.resume(id, { q1: answer })` + + npm run test:e2e passes + Existing E2E tests pass with questions array schema + + + + Task 2: Add multi-question E2E test + src/test/e2e/recovery-scenarios.test.ts + +Add new test in "Agent Q&A extended scenarios" describe block: + +```typescript +it('should handle agent asking multiple questions at once', async () => { + // Setup: agent asks two questions + harness.setAgentQuestions('worker', [ + { id: 'q1', question: 'Which database?', options: [{ label: 'SQLite' }, { label: 'Postgres' }] }, + { id: 'q2', question: 'Include tests?', options: [{ label: 'Yes' }, { label: 'No' }] }, + ]); + + // Dispatch task + await harness.dispatchManager.queueTask({ ... }); + await harness.dispatchManager.processQueue(); + await harness.waitForEvent('agent:waiting'); + + // Verify both questions present + const pending = await harness.getPendingQuestions('worker'); + expect(pending?.questions).toHaveLength(2); + expect(pending?.questions[0].id).toBe('q1'); + expect(pending?.questions[1].id).toBe('q2'); + + // Resume with answers for both questions + harness.setAgentDone('worker'); + const agent = await harness.agentManager.getByName('worker'); + await harness.agentManager.resume(agent!.id, { + q1: 'SQLite', + q2: 'Yes', + }); + + // Wait for completion + await harness.waitForEvent('agent:stopped'); + + // Verify task completed + const task = await harness.taskRepository.findById(...); + expect(task?.status).toBe('completed'); +}); +``` + + npm run test:e2e passes including new multi-question test + Multi-question E2E test validates full flow + + + + + +Before declaring plan complete: +- [ ] `npm run test` passes (all unit + E2E tests) +- [ ] Multi-question scenario test exists and passes +- [ ] No references to old single-question format in E2E tests + + + + +- All tasks completed +- All E2E tests updated to questions array format +- New multi-question E2E test validates batched answers +- All tests pass + + + +After completion, create `.planning/phases/10-multi-question-schema/10-04-SUMMARY.md` +