/** * 9plan_queue_pull tool * * Removes the front plan from queue and marks it active. */ import type { SessionStoreInterface } from "../types.js"; import { formatResponse, NinePlanError } from "../types.js"; // Input schema (no required inputs) export const queuePullInputSchema = {}; // Input type export type QueuePullInput = Record; /** * Handle queue pull tool call */ export function handleQueuePull( store: SessionStoreInterface, sessionName: string, _args: QueuePullInput, ): { content: { type: "text"; text: string }[] } { try { const plan = store.pullPlan(); const planPath = store.getSessionPath() + `/plans/${plan.id}.txt`; // Format plan content for display const planContent = `## Context ${plan.context ?? "(none)"} ## Goal ${plan.goal} ## Inputs ${plan.inputs ?? "(none)"} ## Outputs ${plan.outputs ?? "(none)"} ## Approach ${plan.approach ?? "(none)"} ## Testing ${plan.testing ?? "(none)"} ## Success Criteria ${plan.successCriteria ?? "(none)"} ## Notes ${plan.notes ?? "(none)"}`; const response = formatResponse( sessionName, `Active plan: ${plan.id} Path: ${planPath} ${planContent} --- Review for any ambiguities before starting execution. If the plan has inputs from other plans, use 9plan_history_search to find their outputs. If the plan's Notes indicate it was previously decomposed, use 9plan_history_get to retrieve child outcomes.`, ); return { content: [{ type: "text", text: response }], }; } catch (error) { if (error instanceof NinePlanError) { // Special handling for queue empty (not really an error) if (error.category === "QUEUE_EMPTY") { const completedCount = store.getCompletedCount(); const response = formatResponse( sessionName, `Queue is empty. Task complete! Completed plans: ${String(completedCount)} Use 9plan_history_search to review what was accomplished.`, ); return { content: [{ type: "text", text: response }], }; } // Special handling for plan already active if (error.category === "PLAN_ALREADY_ACTIVE") { const active = store.getActivePlan(); if (active) { const activePath = store.getSessionPath() + `/plans/${active.id}.txt`; const response = formatResponse( sessionName, `Error: Cannot pull - a plan is already active Active plan: ${active.id} Path: ${activePath} Complete, defer, or discard the active plan before pulling another.`, ); return { content: [{ type: "text", text: response }], }; } } return { content: [{ type: "text", text: error.format(sessionName) }], }; } throw error; } } // Tool configuration for registration export const queuePullToolConfig = { title: "Pull Plan from Queue", description: "Removes the front plan from queue and marks it as active. Returns the plan ID and file path. Only one plan can be active at a time.", inputSchema: queuePullInputSchema, };