feat(05-02): add task tRPC procedures
- Add TaskRepository to TRPCContext (optional, same pattern as AgentManager) - Add requireTaskRepository helper function - Add listTasks procedure (query tasks by planId, ordered by order field) - Add getTask procedure (get single task by ID, throws NOT_FOUND) - Add updateTaskStatus procedure (update task status to pending/in_progress/completed/blocked)
This commit is contained in:
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
import type { EventBus, DomainEvent } from '../events/types.js';
|
import type { EventBus, DomainEvent } from '../events/types.js';
|
||||||
import type { AgentManager } from '../agent/types.js';
|
import type { AgentManager } from '../agent/types.js';
|
||||||
|
import type { TaskRepository } from '../db/repositories/task-repository.js';
|
||||||
|
|
||||||
// Re-export for convenience
|
// Re-export for convenience
|
||||||
export type { EventBus, DomainEvent };
|
export type { EventBus, DomainEvent };
|
||||||
@@ -23,6 +24,8 @@ export interface TRPCContext {
|
|||||||
processCount: number;
|
processCount: number;
|
||||||
/** Agent manager for agent lifecycle operations (optional until server wiring complete) */
|
/** Agent manager for agent lifecycle operations (optional until server wiring complete) */
|
||||||
agentManager?: AgentManager;
|
agentManager?: AgentManager;
|
||||||
|
/** Task repository for task CRUD operations (optional until server wiring complete) */
|
||||||
|
taskRepository?: TaskRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -33,6 +36,7 @@ export interface CreateContextOptions {
|
|||||||
serverStartedAt: Date | null;
|
serverStartedAt: Date | null;
|
||||||
processCount: number;
|
processCount: number;
|
||||||
agentManager?: AgentManager;
|
agentManager?: AgentManager;
|
||||||
|
taskRepository?: TaskRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -47,5 +51,6 @@ export function createContext(options: CreateContextOptions): TRPCContext {
|
|||||||
serverStartedAt: options.serverStartedAt,
|
serverStartedAt: options.serverStartedAt,
|
||||||
processCount: options.processCount,
|
processCount: options.processCount,
|
||||||
agentManager: options.agentManager,
|
agentManager: options.agentManager,
|
||||||
|
taskRepository: options.taskRepository,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { initTRPC, TRPCError } from '@trpc/server';
|
|||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import type { TRPCContext } from './context.js';
|
import type { TRPCContext } from './context.js';
|
||||||
import type { AgentInfo, AgentResult } from '../agent/types.js';
|
import type { AgentInfo, AgentResult } from '../agent/types.js';
|
||||||
|
import type { TaskRepository } from '../db/repositories/task-repository.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize tRPC with our context type.
|
* Initialize tRPC with our context type.
|
||||||
@@ -176,6 +177,19 @@ function requireAgentManager(ctx: TRPCContext) {
|
|||||||
return ctx.agentManager;
|
return ctx.agentManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to ensure taskRepository is available in context.
|
||||||
|
*/
|
||||||
|
function requireTaskRepository(ctx: TRPCContext): TaskRepository {
|
||||||
|
if (!ctx.taskRepository) {
|
||||||
|
throw new TRPCError({
|
||||||
|
code: 'INTERNAL_SERVER_ERROR',
|
||||||
|
message: 'Task repository not available',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return ctx.taskRepository;
|
||||||
|
}
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
// Application Router with Procedures
|
// Application Router with Procedures
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
@@ -193,6 +207,9 @@ function requireAgentManager(ctx: TRPCContext) {
|
|||||||
* - getAgentByName: Get agent by name
|
* - getAgentByName: Get agent by name
|
||||||
* - resumeAgent: Resume an agent waiting for input
|
* - resumeAgent: Resume an agent waiting for input
|
||||||
* - getAgentResult: Get result of agent's work
|
* - getAgentResult: Get result of agent's work
|
||||||
|
* - listTasks: List tasks for a plan
|
||||||
|
* - getTask: Get task by ID
|
||||||
|
* - updateTaskStatus: Update task status
|
||||||
*/
|
*/
|
||||||
export const appRouter = router({
|
export const appRouter = router({
|
||||||
/**
|
/**
|
||||||
@@ -323,6 +340,61 @@ export const appRouter = router({
|
|||||||
const agent = await resolveAgent(ctx, input);
|
const agent = await resolveAgent(ctx, input);
|
||||||
return agentManager.getResult(agent.id);
|
return agentManager.getResult(agent.id);
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
// ===========================================================================
|
||||||
|
// Task Procedures
|
||||||
|
// ===========================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List tasks for a plan.
|
||||||
|
* Returns tasks ordered by order field.
|
||||||
|
*/
|
||||||
|
listTasks: publicProcedure
|
||||||
|
.input(z.object({ planId: z.string().min(1) }))
|
||||||
|
.query(async ({ ctx, input }) => {
|
||||||
|
const taskRepository = requireTaskRepository(ctx);
|
||||||
|
return taskRepository.findByPlanId(input.planId);
|
||||||
|
}),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a task by ID.
|
||||||
|
* Throws NOT_FOUND if task doesn't exist.
|
||||||
|
*/
|
||||||
|
getTask: publicProcedure
|
||||||
|
.input(z.object({ id: z.string().min(1) }))
|
||||||
|
.query(async ({ ctx, input }) => {
|
||||||
|
const taskRepository = requireTaskRepository(ctx);
|
||||||
|
const task = await taskRepository.findById(input.id);
|
||||||
|
if (!task) {
|
||||||
|
throw new TRPCError({
|
||||||
|
code: 'NOT_FOUND',
|
||||||
|
message: `Task '${input.id}' not found`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return task;
|
||||||
|
}),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update a task's status.
|
||||||
|
* Returns the updated task.
|
||||||
|
*/
|
||||||
|
updateTaskStatus: publicProcedure
|
||||||
|
.input(z.object({
|
||||||
|
id: z.string().min(1),
|
||||||
|
status: z.enum(['pending', 'in_progress', 'completed', 'blocked']),
|
||||||
|
}))
|
||||||
|
.mutation(async ({ ctx, input }) => {
|
||||||
|
const taskRepository = requireTaskRepository(ctx);
|
||||||
|
// Check task exists first
|
||||||
|
const existing = await taskRepository.findById(input.id);
|
||||||
|
if (!existing) {
|
||||||
|
throw new TRPCError({
|
||||||
|
code: 'NOT_FOUND',
|
||||||
|
message: `Task '${input.id}' not found`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return taskRepository.update(input.id, { status: input.status });
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user