feat(12-08): add TestHarness decompose mode helpers

- Add setArchitectDecomposeComplete and setArchitectDecomposeQuestions helpers
- Add planRepository to harness for plan operations
- Add createPlan and getTasksForPlan convenience methods
- Import TaskBreakdown and Plan types
This commit is contained in:
Lukas May
2026-02-01 11:55:28 +01:00
parent a61530359a
commit 4263c0884e

View File

@@ -13,7 +13,7 @@ import { EventEmitterBus } from '../events/bus.js';
import type { AgentManager } from '../agent/types.js'; import type { AgentManager } from '../agent/types.js';
import { MockAgentManager, type MockAgentScenario } from '../agent/mock-manager.js'; import { MockAgentManager, type MockAgentScenario } from '../agent/mock-manager.js';
import type { PendingQuestions, QuestionItem } from '../agent/types.js'; import type { PendingQuestions, QuestionItem } from '../agent/types.js';
import type { Decision, PhaseBreakdown } from '../agent/schema.js'; import type { Decision, PhaseBreakdown, TaskBreakdown } from '../agent/schema.js';
import type { WorktreeManager, Worktree, WorktreeDiff, MergeResult } from '../git/types.js'; import type { WorktreeManager, Worktree, WorktreeDiff, MergeResult } from '../git/types.js';
import type { DispatchManager } from '../dispatch/types.js'; import type { DispatchManager } from '../dispatch/types.js';
import { DefaultDispatchManager } from '../dispatch/manager.js'; import { DefaultDispatchManager } from '../dispatch/manager.js';
@@ -24,13 +24,15 @@ import type { MessageRepository } from '../db/repositories/message-repository.js
import type { AgentRepository } from '../db/repositories/agent-repository.js'; import type { AgentRepository } from '../db/repositories/agent-repository.js';
import type { InitiativeRepository } from '../db/repositories/initiative-repository.js'; import type { InitiativeRepository } from '../db/repositories/initiative-repository.js';
import type { PhaseRepository } from '../db/repositories/phase-repository.js'; import type { PhaseRepository } from '../db/repositories/phase-repository.js';
import type { Initiative, Phase } from '../db/schema.js'; import type { PlanRepository } from '../db/repositories/plan-repository.js';
import type { Initiative, Phase, Plan, Task } from '../db/schema.js';
import { import {
DrizzleTaskRepository, DrizzleTaskRepository,
DrizzleMessageRepository, DrizzleMessageRepository,
DrizzleAgentRepository, DrizzleAgentRepository,
DrizzleInitiativeRepository, DrizzleInitiativeRepository,
DrizzlePhaseRepository, DrizzlePhaseRepository,
DrizzlePlanRepository,
} from '../db/repositories/drizzle/index.js'; } from '../db/repositories/drizzle/index.js';
import { createTestDatabase } from '../db/repositories/drizzle/test-helpers.js'; import { createTestDatabase } from '../db/repositories/drizzle/test-helpers.js';
import { import {
@@ -207,6 +209,8 @@ export interface TestHarness {
initiativeRepository: InitiativeRepository; initiativeRepository: InitiativeRepository;
/** Phase repository */ /** Phase repository */
phaseRepository: PhaseRepository; phaseRepository: PhaseRepository;
/** Plan repository */
planRepository: PlanRepository;
// tRPC Caller // tRPC Caller
/** tRPC caller for direct procedure calls */ /** tRPC caller for direct procedure calls */
@@ -312,8 +316,24 @@ export interface TestHarness {
phases: PhaseBreakdown[] phases: PhaseBreakdown[]
): void; ): void;
/**
* Set up scenario where architect completes decomposition with tasks.
*/
setArchitectDecomposeComplete(
agentName: string,
tasks: TaskBreakdown[]
): void;
/**
* Set up scenario where architect needs questions in decompose mode.
*/
setArchitectDecomposeQuestions(
agentName: string,
questions: QuestionItem[]
): void;
// ========================================================================== // ==========================================================================
// Initiative/Phase Convenience Helpers // Initiative/Phase/Plan Convenience Helpers
// ========================================================================== // ==========================================================================
/** /**
@@ -338,6 +358,20 @@ export interface TestHarness {
initiativeId: string, initiativeId: string,
phases: Array<{ number: number; name: string; description: string }> phases: Array<{ number: number; name: string; description: string }>
): Promise<Phase[]>; ): Promise<Phase[]>;
/**
* Create a plan through tRPC.
*/
createPlan(
phaseId: string,
name: string,
description?: string
): Promise<Plan>;
/**
* Get tasks for a plan through tRPC.
*/
getTasksForPlan(planId: string): Promise<Task[]>;
} }
// ============================================================================= // =============================================================================
@@ -374,6 +408,7 @@ export function createTestHarness(): TestHarness {
const agentRepository = new DrizzleAgentRepository(db); const agentRepository = new DrizzleAgentRepository(db);
const initiativeRepository = new DrizzleInitiativeRepository(db); const initiativeRepository = new DrizzleInitiativeRepository(db);
const phaseRepository = new DrizzlePhaseRepository(db); const phaseRepository = new DrizzlePhaseRepository(db);
const planRepository = new DrizzlePlanRepository(db);
// Create real managers wired to mocks // Create real managers wired to mocks
const dispatchManager = new DefaultDispatchManager( const dispatchManager = new DefaultDispatchManager(
@@ -403,6 +438,7 @@ export function createTestHarness(): TestHarness {
coordinationManager, coordinationManager,
initiativeRepository, initiativeRepository,
phaseRepository, phaseRepository,
planRepository,
}); });
// Create tRPC caller // Create tRPC caller
@@ -425,6 +461,7 @@ export function createTestHarness(): TestHarness {
agentRepository, agentRepository,
initiativeRepository, initiativeRepository,
phaseRepository, phaseRepository,
planRepository,
// tRPC Caller // tRPC Caller
caller, caller,
@@ -523,8 +560,30 @@ export function createTestHarness(): TestHarness {
}); });
}, },
setArchitectDecomposeComplete: (
agentName: string,
tasks: TaskBreakdown[]
) => {
agentManager.setScenario(agentName, {
status: 'decompose_complete',
tasks,
delay: 0,
});
},
setArchitectDecomposeQuestions: (
agentName: string,
questions: QuestionItem[]
) => {
agentManager.setScenario(agentName, {
status: 'questions',
questions,
delay: 0,
});
},
// ======================================================================== // ========================================================================
// Initiative/Phase Convenience Helpers // Initiative/Phase/Plan Convenience Helpers
// ======================================================================== // ========================================================================
getInitiative: async (id: string) => { getInitiative: async (id: string) => {
@@ -549,6 +608,14 @@ export function createTestHarness(): TestHarness {
) => { ) => {
return caller.createPhasesFromBreakdown({ initiativeId, phases }); return caller.createPhasesFromBreakdown({ initiativeId, phases });
}, },
createPlan: (phaseId: string, name: string, description?: string) => {
return caller.createPlan({ phaseId, name, description });
},
getTasksForPlan: (planId: string) => {
return caller.listTasks({ planId });
},
}; };
return harness; return harness;