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 { AgentManager } from '../agent/types.js';
|
||||
import type { TaskRepository } from '../db/repositories/task-repository.js';
|
||||
|
||||
// Re-export for convenience
|
||||
export type { EventBus, DomainEvent };
|
||||
@@ -23,6 +24,8 @@ export interface TRPCContext {
|
||||
processCount: number;
|
||||
/** Agent manager for agent lifecycle operations (optional until server wiring complete) */
|
||||
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;
|
||||
processCount: number;
|
||||
agentManager?: AgentManager;
|
||||
taskRepository?: TaskRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -47,5 +51,6 @@ export function createContext(options: CreateContextOptions): TRPCContext {
|
||||
serverStartedAt: options.serverStartedAt,
|
||||
processCount: options.processCount,
|
||||
agentManager: options.agentManager,
|
||||
taskRepository: options.taskRepository,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import { initTRPC, TRPCError } from '@trpc/server';
|
||||
import { z } from 'zod';
|
||||
import type { TRPCContext } from './context.js';
|
||||
import type { AgentInfo, AgentResult } from '../agent/types.js';
|
||||
import type { TaskRepository } from '../db/repositories/task-repository.js';
|
||||
|
||||
/**
|
||||
* Initialize tRPC with our context type.
|
||||
@@ -176,6 +177,19 @@ function requireAgentManager(ctx: TRPCContext) {
|
||||
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
|
||||
// =============================================================================
|
||||
@@ -193,6 +207,9 @@ function requireAgentManager(ctx: TRPCContext) {
|
||||
* - getAgentByName: Get agent by name
|
||||
* - resumeAgent: Resume an agent waiting for input
|
||||
* - 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({
|
||||
/**
|
||||
@@ -323,6 +340,61 @@ export const appRouter = router({
|
||||
const agent = await resolveAgent(ctx, input);
|
||||
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