Phase 7 of v2.0. BooCoder gains a terminal-driven UX and subagent isolation primitive. CLI (src/cli.ts): standalone entry point for terminal use. - boocode run "task" [--agent x] [--model y] — create + stream output - boocode ls [--state x] — formatted task table - boocode attach <id> — WS stream of running task - boocode send <id> "msg" — follow-up message to task session Connects to BOOCODER_URL (default http://100.114.205.53:9502). Human inbox (routes/inbox.ts): GET /api/inbox (failed/blocked tasks), POST /api/inbox/:id/retry (reset to pending for re-dispatch). Cost tracking: dispatcher aggregates tokens_used from all messages in the task's session after completion, stores in tasks.cost_tokens. GET /api/stats/costs?group_by=project|agent|day for aggregation. Boomerang subagent isolation (3 new tools): - new_task: creates child task with parent_task_id linkage, runs in fresh isolated session. Orchestrator sees only output_summary. - list_tasks: query child tasks of current parent - check_task_status: read task state + output_summary The orchestrator pattern: an agent with tools: [new_task, list_tasks, check_task_status] can ONLY dispatch — can't read files or MCP. This is the Roo Code Boomerang Tasks capability-restriction principle. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
51 lines
1.5 KiB
TypeScript
51 lines
1.5 KiB
TypeScript
import { z } from 'zod';
|
|
import type { ToolDef, ToolContext } from './types.js';
|
|
|
|
const CheckTaskStatusInput = z.object({
|
|
task_id: z.string().uuid().describe('ID of the task to check'),
|
|
});
|
|
|
|
type CheckTaskStatusInputT = z.infer<typeof CheckTaskStatusInput>;
|
|
|
|
export const checkTaskStatusTool: ToolDef<CheckTaskStatusInputT> = {
|
|
name: 'check_task_status',
|
|
description: 'Check the status and output of a subtask by ID. Returns state, output_summary, and timing.',
|
|
inputSchema: CheckTaskStatusInput,
|
|
jsonSchema: {
|
|
type: 'function',
|
|
function: {
|
|
name: 'check_task_status',
|
|
description: 'Check the status and output of a subtask by ID.',
|
|
parameters: {
|
|
type: 'object',
|
|
properties: {
|
|
task_id: { type: 'string', description: 'ID of the task to check' },
|
|
},
|
|
required: ['task_id'],
|
|
},
|
|
},
|
|
},
|
|
|
|
async execute(input: CheckTaskStatusInputT, _projectRoot: string, context: ToolContext): Promise<unknown> {
|
|
const { sql } = context;
|
|
|
|
const [task] = await sql<{ id: string; state: string; output_summary: string | null; started_at: string | null; ended_at: string | null }[]>`
|
|
SELECT id, state, output_summary, started_at, ended_at
|
|
FROM tasks
|
|
WHERE id = ${input.task_id}
|
|
`;
|
|
|
|
if (!task) {
|
|
return { error: `Task ${input.task_id} not found` };
|
|
}
|
|
|
|
return {
|
|
id: task.id,
|
|
state: task.state,
|
|
output_summary: task.output_summary,
|
|
started_at: task.started_at,
|
|
ended_at: task.ended_at,
|
|
};
|
|
},
|
|
};
|