feat(14-05): add phase dependency and dispatch procedures
- Import PhaseDispatchManager type from dispatch module - Add requirePhaseDispatchManager helper function - Add createPhaseDependency: creates dependency between two phases - Add getPhaseDependencies: returns phase IDs that a phase depends on - Add queuePhase: queues phase for dispatch - Add dispatchNextPhase: dispatches next available phase - Add getPhaseQueueState: returns phase queue state All procedures follow existing naming conventions and error handling patterns.
This commit is contained in:
@@ -14,7 +14,7 @@ import type { MessageRepository } from '../db/repositories/message-repository.js
|
||||
import type { InitiativeRepository } from '../db/repositories/initiative-repository.js';
|
||||
import type { PhaseRepository } from '../db/repositories/phase-repository.js';
|
||||
import type { PlanRepository } from '../db/repositories/plan-repository.js';
|
||||
import type { DispatchManager } from '../dispatch/types.js';
|
||||
import type { DispatchManager, PhaseDispatchManager } from '../dispatch/types.js';
|
||||
import type { CoordinationManager } from '../coordination/types.js';
|
||||
import type { Phase, Plan, Task } from '../db/schema.js';
|
||||
import { buildDiscussPrompt, buildBreakdownPrompt, buildDecomposePrompt } from '../agent/prompts.js';
|
||||
@@ -278,6 +278,19 @@ function requirePlanRepository(ctx: TRPCContext): PlanRepository {
|
||||
return ctx.planRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to ensure phaseDispatchManager is available in context.
|
||||
*/
|
||||
function requirePhaseDispatchManager(ctx: TRPCContext): PhaseDispatchManager {
|
||||
if (!ctx.phaseDispatchManager) {
|
||||
throw new TRPCError({
|
||||
code: 'INTERNAL_SERVER_ERROR',
|
||||
message: 'Phase dispatch manager not available',
|
||||
});
|
||||
}
|
||||
return ctx.phaseDispatchManager;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Application Router with Procedures
|
||||
// =============================================================================
|
||||
@@ -855,6 +868,87 @@ export const appRouter = router({
|
||||
return created;
|
||||
}),
|
||||
|
||||
/**
|
||||
* Create a dependency between two phases.
|
||||
* The phase with phaseId depends on the phase with dependsOnPhaseId.
|
||||
*/
|
||||
createPhaseDependency: publicProcedure
|
||||
.input(z.object({
|
||||
phaseId: z.string().min(1),
|
||||
dependsOnPhaseId: z.string().min(1),
|
||||
}))
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
const repo = requirePhaseRepository(ctx);
|
||||
|
||||
// Validate both phases exist
|
||||
const phase = await repo.findById(input.phaseId);
|
||||
if (!phase) {
|
||||
throw new TRPCError({
|
||||
code: 'NOT_FOUND',
|
||||
message: `Phase '${input.phaseId}' not found`,
|
||||
});
|
||||
}
|
||||
|
||||
const dependsOnPhase = await repo.findById(input.dependsOnPhaseId);
|
||||
if (!dependsOnPhase) {
|
||||
throw new TRPCError({
|
||||
code: 'NOT_FOUND',
|
||||
message: `Phase '${input.dependsOnPhaseId}' not found`,
|
||||
});
|
||||
}
|
||||
|
||||
await repo.createDependency(input.phaseId, input.dependsOnPhaseId);
|
||||
return { success: true };
|
||||
}),
|
||||
|
||||
/**
|
||||
* Get dependencies for a phase.
|
||||
* Returns IDs of phases that this phase depends on.
|
||||
*/
|
||||
getPhaseDependencies: publicProcedure
|
||||
.input(z.object({ phaseId: z.string().min(1) }))
|
||||
.query(async ({ ctx, input }) => {
|
||||
const repo = requirePhaseRepository(ctx);
|
||||
const dependencies = await repo.getDependencies(input.phaseId);
|
||||
return { dependencies };
|
||||
}),
|
||||
|
||||
// ===========================================================================
|
||||
// Phase Dispatch Procedures
|
||||
// ===========================================================================
|
||||
|
||||
/**
|
||||
* Queue a phase for dispatch.
|
||||
* Phase will be dispatched when all dependencies complete.
|
||||
*/
|
||||
queuePhase: publicProcedure
|
||||
.input(z.object({ phaseId: z.string().min(1) }))
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
const phaseDispatchManager = requirePhaseDispatchManager(ctx);
|
||||
await phaseDispatchManager.queuePhase(input.phaseId);
|
||||
return { success: true };
|
||||
}),
|
||||
|
||||
/**
|
||||
* Dispatch next available phase.
|
||||
* Returns dispatch result with phase info.
|
||||
*/
|
||||
dispatchNextPhase: publicProcedure
|
||||
.mutation(async ({ ctx }) => {
|
||||
const phaseDispatchManager = requirePhaseDispatchManager(ctx);
|
||||
return phaseDispatchManager.dispatchNextPhase();
|
||||
}),
|
||||
|
||||
/**
|
||||
* Get current phase queue state.
|
||||
* Returns queued, ready, and blocked phase counts.
|
||||
*/
|
||||
getPhaseQueueState: publicProcedure
|
||||
.query(async ({ ctx }) => {
|
||||
const phaseDispatchManager = requirePhaseDispatchManager(ctx);
|
||||
return phaseDispatchManager.getPhaseQueueState();
|
||||
}),
|
||||
|
||||
// ===========================================================================
|
||||
// Plan Procedures
|
||||
// ===========================================================================
|
||||
|
||||
Reference in New Issue
Block a user