@kolisachint/hoocode-agent 0.4.159 → 0.4.161
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/dist/core/format-duration.d.ts.map +1 -1
- package/dist/core/format-duration.js +8 -3
- package/dist/core/format-duration.js.map +1 -1
- package/dist/core/tools/subagent.d.ts.map +1 -1
- package/dist/core/tools/subagent.js +10 -1
- package/dist/core/tools/subagent.js.map +1 -1
- package/dist/extensions/core/mcp-loader.d.ts.map +1 -1
- package/dist/extensions/core/mcp-loader.js +34 -3
- package/dist/extensions/core/mcp-loader.js.map +1 -1
- package/dist/modes/interactive/components/task-panel.d.ts.map +1 -1
- package/dist/modes/interactive/components/task-panel.js +3 -1
- package/dist/modes/interactive/components/task-panel.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +10 -0
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/resource-display.d.ts +3 -0
- package/dist/modes/interactive/resource-display.d.ts.map +1 -1
- package/dist/modes/interactive/resource-display.js +40 -25
- package/dist/modes/interactive/resource-display.js.map +1 -1
- package/dist/modes/interactive/theme/dark.json +2 -1
- package/dist/modes/interactive/theme/light.json +2 -1
- package/dist/modes/interactive/theme/theme-schema.json +8 -4
- package/dist/modes/interactive/theme/theme.d.ts +1 -1
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package.json +1 -1
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subagent.js","sourceRoot":"","sources":["../../../src/core/tools/subagent.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Task tool: delegate a focused task to a specialized subagent.\n *\n * Mirrors the Claude Code `Task` tool. The parent agent decides *when* to\n * delegate based on each agent's `description` (there is no deterministic gate)\n * and selects *which* agent via `subagent_type`. The chosen agent runs in a\n * fresh, isolated child process (SubagentPool) and only its final answer is\n * returned to the parent.\n *\n * Enabled by default (the `enableSubagent` setting defaults to true); disable\n * with `enableSubagent: false`. The `--enable-subagents` flag still force-enables\n * it. Nesting is bounded by the tree-wide depth cap (maxSubagentDepth, default 2:\n * a spawned subagent may itself delegate one more level, and depth-2 grandchildren\n * cannot). See buildSessionOptions in main.ts.\n */\n\nimport { Text } from \"@kolisachint/hoocode-tui\";\nimport { type Static, Type } from \"typebox\";\nimport { agentColorFor } from \"../../modes/interactive/theme/theme.js\";\nimport { type AgentDefinition, TASK_TOOL_NAME } from \"../agent-frontmatter.js\";\nimport { loadAgentRegistry } from \"../agent-registry.js\";\nimport type { ToolDefinition } from \"../extensions/types.js\";\nimport { defineTool } from \"../extensions/types.js\";\nimport { formatDurationSecs } from \"../format-duration.js\";\nimport { getProviderExhaustion } from \"../provider-health.js\";\nimport { SessionManager } from \"../session-manager.js\";\nimport { delegateAllowList, isDelegateAllowed } from \"../subagent-depth.js\";\nimport { type InboxRecord, subagentInbox } from \"../subagent-inbox.js\";\nimport type { SubagentResult, TaskResult } from \"../subagent-pool.js\";\nimport { getSubagentPool } from \"../subagent-pool-instance.js\";\nimport type { SubagentResultFile, SubagentTaskNode } from \"../subagent-result.js\";\nimport { taskStore } from \"../task-store.js\";\nimport { type WarmRunResult, WarmWorkerError } from \"../warm-subagent-pool.js\";\nimport { getWarmSubagentPool, warmSubagentsEnabled } from \"../warm-subagent-pool-instance.js\";\n\n// Re-exported from its home in agent-registry (where formatAgentsForPrompt uses\n// it to render the roster) so existing importers keep working without creating a\n// tools -> registry -> tools cycle.\nexport { summarizeAgentDescription } from \"../agent-registry.js\";\n\n/** System prompt appendix for the main session when the Task tool is enabled.\n * Instructs the parent agent on when and how to delegate effectively. The\n * available agents themselves are listed once, authoritatively, in the\n * `<available_agents>` block the system prompt emits whenever the Task tool is\n * active (see agent-session `_rebuildSystemPrompt`); this appendix references\n * that list rather than re-rendering the roster and paying for it twice. */\n/**\n * Build the main-session subagent instructions appended to the system prompt.\n *\n * The detailed background/barrier guidance (the three heaviest bullets) is only\n * emitted when the project actually has background-capable agents; otherwise a\n * single concise line covers the per-call `background: true` escape hatch. This\n * keeps the always-on cost down for the common case where nothing runs in the\n * background. `cwd` is used only to detect those agents.\n */\nexport function buildTaskMainPrompt(cwd: string = process.cwd()): string {\n\tconst hasBackgroundAgents = collectBackgroundAgentNames(cwd).size > 0;\n\n\tconst backgroundGuidance = hasBackgroundAgents\n\t\t? `- Background agents run non-blocking (or force per call with \\`background: true\\`): you get a short \"explore#1 finished\" notification and pull the full result with \\`TaskOutput\\` (e.g. \\`TaskOutput(\"explore#1\")\\`); \\`TaskOutput(list: true)\\` shows what's running.\n- After dispatching, don't idle — keep doing independent work (read/edit unrelated files, draft, dispatch more); barrier with \\`TaskOutput(wait: true)\\` (a named task, or all outstanding when no id) only when you genuinely can't proceed.`\n\t\t: `- You can force any task to run in the background with \\`background: true\\` (non-blocking): keep working, then pull its result with \\`TaskOutput\\` (e.g. \\`TaskOutput(\"explore#1\")\\`) or block on it with \\`TaskOutput(wait: true)\\`.`;\n\n\treturn `You have access to the **Task** tool. Use it to delegate self-contained tasks to specialized subagents that run in their own isolated context and return only their final answer. Pick an agent by name from the <available_agents> list in this prompt and pass it as \\`subagent_type\\`.\n\nWhen to delegate:\n1. The work is self-contained and you only need the final result, not intermediate steps.\n2. You want to investigate or edit something in parallel without losing your current context or reasoning chain.\n3. The task is a discrete unit (explore one module, run one test file, review one PR, fix one isolated bug).\n4. You need to run a long command or test suite and wait for its output without blocking your own reasoning.\n\nModel tier (optional \\`complexity\\`): set \\`fast\\` for quick reads/lookups, \\`standard\\` for multi-file edits, \\`capable\\` for deep architecture work. It maps to a model from \\`settings.modelCategories\\`. Omit it to use the agent's default; an agent that pins its own model ignores \\`complexity\\`.\n\nGuidelines:\n- Choose the agent whose description best matches the task.\n- Make every task specific and self-contained. The subagent cannot see this conversation; pass all necessary context (files, constraints, prior findings) in \\`prompt\\`.\n- Do NOT delegate tasks that require tight back-and-forth with your current reasoning, or edits to files you are actively reasoning about.\n- The subagent returns ONLY its final answer. Its intermediate reasoning, tool calls, and output are hidden from you.\n- Delegate proactively when work is self-contained or parallelizable: multi-step investigation, read-only exploration (use \\`explore\\`), research before changes (use \\`plan\\`), drafting a standalone file/section, or running a long command/test suite. Dispatch independent subtasks in the same turn. Handle only trivial single-step edits or tightly interactive back-and-forth inline.\n${backgroundGuidance}\n- When working through a TodoWrite plan, mark the plan item in_progress BEFORE dispatching subagents for it: each dispatch is attributed to the current in_progress item in the user's task panel, so dispatching first (or with several items in_progress) leaves the run unattributed.\n- To continue a previous subagent (for example one that returned partial results), call Task again with \\`resume_task_id\\` set to its task_id; it resumes with its full prior transcript and \\`prompt\\` is your follow-up.`;\n}\n\nconst taskParams = Type.Object({\n\tdescription: Type.String({\n\t\tdescription: \"A short (3-5 word) description of the task, shown in the task panel.\",\n\t}),\n\tprompt: Type.String({\n\t\tdescription:\n\t\t\t\"The full, self-contained task for the subagent. It cannot see this conversation, so include all needed context, files, and constraints.\",\n\t}),\n\tsubagent_type: Type.String({\n\t\tdescription: \"The name of the specialized agent to delegate to. Must be one of the available agents.\",\n\t}),\n\tcomplexity: Type.Optional(\n\t\tType.Union([Type.Literal(\"fast\"), Type.Literal(\"standard\"), Type.Literal(\"capable\")], {\n\t\t\tdescription:\n\t\t\t\t\"Model tier for this dispatch: fast (quick reads/lookups), standard (multi-file edits), capable (deep architecture). Maps to settings.modelCategories. Ignored if the chosen agent pins its own model; omit to use the agent's default.\",\n\t\t}),\n\t),\n\tbackground: Type.Optional(\n\t\tType.Boolean({\n\t\t\tdescription:\n\t\t\t\t\"Set true to run non-blocking: you get a short notification when it finishes and pull the full result with TaskOutput; set false to wait and get the answer inline. Defaults to the agent's own background setting.\",\n\t\t}),\n\t),\n\tresume_task_id: Type.Optional(\n\t\tType.String({\n\t\t\tdescription:\n\t\t\t\t\"Optional. To continue a previous subagent run, pass its task_id (returned by an earlier Task or TaskOutput call). The subagent resumes with its full prior transcript and `prompt` is your follow-up instruction.\",\n\t\t}),\n\t),\n});\n\ntype TaskParams = Static<typeof taskParams>;\n\nexport interface TaskToolDetails {\n\tsubagent_type: string;\n\tok: boolean;\n\terror?: string;\n\ttaskId: number;\n\t/** Pool-level task id usable for resume/polling. */\n\tpoolTaskId?: string;\n\t/** True when dispatched as a non-blocking background task. */\n\tbackground?: boolean;\n}\n\nexport interface TaskOutputDetails {\n\t/** The handle queried, when a specific task was named. */\n\ttask_id?: string;\n\t/** running | done | collected | failed | stalled | timeout | cancelled | list | empty | unknown */\n\tstatus: string;\n\tok: boolean;\n\t/** Number of subagents still running, included on roster/list responses. */\n\toutstanding?: number;\n}\n\n/**\n * A short, human-readable task name for the task panel: the first line limited\n * to ~8 words so it stays glanceable. A character cap guards a single long word.\n */\nfunction summarize(task: string): string {\n\tconst firstLine = (task.trim().split(\"\\n\")[0] ?? \"\").trim();\n\tif (!firstLine) return \"(task)\";\n\tconst words = firstLine.split(/\\s+/);\n\tlet name = words.length > 8 ? `${words.slice(0, 8).join(\" \")}…` : firstLine;\n\tif (name.length > 60) name = `${name.slice(0, 59)}…`;\n\treturn name;\n}\n\n/** Create the Task tool definition. Registered as a customTool when enabled. */\nexport function createTaskToolDefinition(cwd: string = process.cwd()): ToolDefinition {\n\t// Agents whose definitions opt into background execution. The agent loop reads\n\t// the tool's `background` flag per call and, for these, runs the dispatch\n\t// detached: the parent keeps reasoning and the subagent's answer is injected as\n\t// a follow-up message when it finishes (no polling needed). A per-call\n\t// `background` argument overrides the agent's default in either direction.\n\tconst backgroundAgents = collectBackgroundAgentNames(cwd);\n\treturn defineTool<typeof taskParams, TaskToolDetails>({\n\t\tname: TASK_TOOL_NAME,\n\t\tlabel: TASK_TOOL_NAME,\n\t\tbackground: (toolCall) => {\n\t\t\tconst override = toolCall.arguments?.background;\n\t\t\tif (typeof override === \"boolean\") return override;\n\t\t\treturn backgroundAgents.has(String(toolCall.arguments?.subagent_type ?? \"\"));\n\t\t},\n\t\t// Kept to mechanics only: the when-to-use / when-not-to guidance lives once in\n\t\t// the system-prompt block (buildTaskMainPrompt), the available agents are\n\t\t// listed there too, and the `complexity`/`background`/`resume_task_id`\n\t\t// semantics live in their parameter descriptions. Repeating any of that here\n\t\t// would re-spend those tokens on every turn.\n\t\tdescription:\n\t\t\t\"Delegate a focused task to a specialized subagent that runs in a fresh, isolated context (it cannot see this conversation). Choose one of the available agents (listed in the system prompt) via `subagent_type` and pass everything it needs via `prompt`; the subagent returns only its final answer.\",\n\t\tpromptSnippet: \"delegate a self-contained task to a specialized subagent (choose via subagent_type)\",\n\t\tparameters: taskParams,\n\n\t\tasync execute(_toolCallId, params: TaskParams, signal, _onUpdate, ctx) {\n\t\t\t// Snapshot the caller's available models so unconfigured model-category\n\t\t\t// tiers (fast/standard/capable) resolve to a derived default instead of a\n\t\t\t// no-op. Explicit settings.modelCategories still win inside the pool. The\n\t\t\t// registry can be absent in some tool contexts; an empty list just keeps\n\t\t\t// category derivation a no-op (inherit parent), so guard the access.\n\t\t\tconst availableModels = ctx.modelRegistry?.getAvailable() ?? [];\n\t\t\tconst pool = getSubagentPool(ctx.cwd, availableModels);\n\n\t\t\t// User-initiated cancel (Esc/abort): kill the dispatched run's whole\n\t\t\t// process tree and let the dispatch settle with status \"cancelled\" —\n\t\t\t// distinct from \"failed\" everywhere it surfaces (panel, inbox, result).\n\t\t\t// Cold dispatches only: a warm worker has no cancel surface (it is\n\t\t\t// reused), so warm runs still complete server-side and are discarded.\n\t\t\tconst cancelOnAbort = async (poolRunId: string, run: () => Promise<TaskResult>): Promise<TaskResult> => {\n\t\t\t\tif (!signal) return run();\n\t\t\t\tconst onAbort = () => {\n\t\t\t\t\tpool.cancel?.(poolRunId);\n\t\t\t\t};\n\t\t\t\tif (signal.aborted) onAbort();\n\t\t\t\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\ttry {\n\t\t\t\t\treturn await run();\n\t\t\t\t} finally {\n\t\t\t\t\tsignal.removeEventListener(\"abort\", onAbort);\n\t\t\t\t}\n\t\t\t};\n\n\t\t\t// Pre-flight: if the inherited provider recently exhausted its quota (the\n\t\t\t// parent's own turn failed with a usage/rate-limit error that did not\n\t\t\t// recover), skip the spawn. Subagents run on the same provider, so this\n\t\t\t// would only burn another failed attempt. The signal self-expires and is\n\t\t\t// cleared on the next successful response.\n\t\t\tconst provider = ctx.model?.provider;\n\t\t\tconst exhaustion = provider ? getProviderExhaustion(provider) : undefined;\n\t\t\tif (exhaustion) {\n\t\t\t\tconst skippedRunId = newDispatchTaskId();\n\t\t\t\tconst skipped = taskStore.create(params.description?.trim() || summarize(params.prompt), {\n\t\t\t\t\tsource: \"subagent\",\n\t\t\t\t\tsubagentMode: params.subagent_type,\n\t\t\t\t\tagent: skippedRunId,\n\t\t\t\t\tlinkedTaskId: linkedTodoId(),\n\t\t\t\t});\n\t\t\t\tregisterSubagentDispatch(skippedRunId, subagentInbox.nextLabel(params.subagent_type));\n\t\t\t\ttaskStore.update(skipped.id, { status: \"failed\", note: `${provider} exhausted` });\n\t\t\t\ttaskStore.patchAgent(skippedRunId, { state: \"failed\" });\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\" as const,\n\t\t\t\t\t\t\ttext:\n\t\t\t\t\t\t\t\t`Did not dispatch subagent \"${params.subagent_type}\": the \"${provider}\" provider appears ` +\n\t\t\t\t\t\t\t\t`exhausted or rate-limited (this session just failed with: ${exhaustion.message}). ` +\n\t\t\t\t\t\t\t\t`Subagents run on the same provider, so dispatching would fail too. Wait for the quota to ` +\n\t\t\t\t\t\t\t\t`reset or switch model/provider, then retry — or complete the work directly in this session.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: { subagent_type: params.subagent_type, ok: false, taskId: skipped.id },\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// Scoped delegation: a delegating agent may be restricted to certain subagent\n\t\t\t// types (its `delegate: <types>` frontmatter). The root is unrestricted.\n\t\t\tif (!isDelegateAllowed(params.subagent_type)) {\n\t\t\t\tconst allowed = delegateAllowList()?.join(\", \") ?? \"\";\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`This agent may not delegate to \"${params.subagent_type}\". Allowed subagent types: ${allowed || \"(none)\"}.`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Resume path: continue a previously dispatched subagent with a follow-up\n\t\t\t// prompt, reusing its persisted session (full prior transcript).\n\t\t\tconst resumeId = params.resume_task_id?.trim();\n\t\t\tif (resumeId) {\n\t\t\t\tconst summary = params.description?.trim() || summarize(params.prompt);\n\t\t\t\tconst runId = newDispatchTaskId();\n\t\t\t\tconst label = subagentInbox.nextLabel(params.subagent_type);\n\t\t\t\tconst task = taskStore.create(summary, {\n\t\t\t\t\tsource: \"subagent\",\n\t\t\t\t\tsubagentMode: params.subagent_type,\n\t\t\t\t\tagent: runId,\n\t\t\t\t\tlinkedTaskId: linkedTodoId(),\n\t\t\t\t});\n\t\t\t\tregisterSubagentDispatch(runId, label);\n\t\t\t\ttaskStore.update(task.id, { status: \"in_progress\" });\n\t\t\t\ttry {\n\t\t\t\t\tconst dispatchResult = await cancelOnAbort(runId, () =>\n\t\t\t\t\t\tpool.resume(resumeId, params.prompt, {\n\t\t\t\t\t\t\tmodel: ctx.model?.id,\n\t\t\t\t\t\t\tprovider: ctx.model?.provider,\n\t\t\t\t\t\t\ttaskId: runId,\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\t\t// The session lives under the original task id; keep it as the resume handle.\n\t\t\t\t\treturn finalizeDispatchResult(dispatchResult, params.subagent_type, runId, task.id, resumeId);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tmarkDispatchFailed(task.id, runId);\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// The model has already decided to delegate and which agent to use; honor\n\t\t\t// it. Validate the requested agent against the registry (no routing gate).\n\t\t\tconst registry = loadAgentRegistry({ cwd: ctx.cwd });\n\t\t\tconst def = registry.get(params.subagent_type);\n\t\t\tif (!def) {\n\t\t\t\tconst available = registry\n\t\t\t\t\t.list()\n\t\t\t\t\t.map((a) => a.name)\n\t\t\t\t\t.join(\", \");\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Unknown subagent_type: \"${params.subagent_type}\". Available agents: ${available || \"(none)\"}.`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst summary = params.description?.trim() || summarize(params.prompt);\n\t\t\t// One roster row per dispatch, keyed by the (pre-allocated) pool task id.\n\t\t\t// Keying by agent TYPE made concurrent same-type runs share a single row:\n\t\t\t// their activity, state, and stats collided last-writer-wins. The inbox\n\t\t\t// already keys by task id; this aligns the panel to the same model. The\n\t\t\t// pool's task_progress events carry the task id, so patching by this id\n\t\t\t// routes live activity to the right row.\n\t\t\tconst poolTaskId = newDispatchTaskId();\n\t\t\tconst label = subagentInbox.nextLabel(params.subagent_type);\n\t\t\tconst task = taskStore.create(summary, {\n\t\t\t\tsource: \"subagent\",\n\t\t\t\tsubagentMode: params.subagent_type,\n\t\t\t\tagent: poolTaskId,\n\t\t\t\t// Tie this run to the plan item it executes (the single in_progress\n\t\t\t\t// TodoWrite task, when unambiguous) so the panel can nest it there.\n\t\t\t\tlinkedTaskId: linkedTodoId(),\n\t\t\t});\n\t\t\tregisterSubagentDispatch(poolTaskId, label);\n\t\t\ttaskStore.update(task.id, { status: \"in_progress\" });\n\t\t\t// Fork agents inherit the parent's conversation via a forked session.\n\t\t\tconst forkSessionFile = def.fork\n\t\t\t\t? resolveForkSessionFile(def, ctx.sessionManager?.getSessionFile(), ctx.cwd)\n\t\t\t\t: undefined;\n\n\t\t\t// `complexity` is passed as the model: the pool's spawn() already lets a\n\t\t\t// non-`inherit` agent model win, then resolves a category string (fast/\n\t\t\t// standard/capable) via settings.modelCategories. So a pinned-model agent\n\t\t\t// ignores complexity, and an `inherit` agent picks up the requested tier —\n\t\t\t// no settings lookup needed here.\n\t\t\tconst dispatchModel = params.complexity ?? ctx.model?.id;\n\n\t\t\t// Whether this call runs detached. The agent loop reads the tool's\n\t\t\t// `background` flag (the same predicate) to run execute() detached; we\n\t\t\t// recompute it here to choose the notify-and-pull return shape.\n\t\t\tconst isBackground = params.background ?? backgroundAgents.has(params.subagent_type);\n\n\t\t\tif (isBackground) {\n\t\t\t\t// Notify-and-pull: register the dispatch in the inbox under the\n\t\t\t\t// pre-allocated id, await it, retain the body in the inbox, and return a\n\t\t\t\t// compact notification (not the body). The model pulls it with TaskOutput.\n\t\t\t\tsubagentInbox.observe(pool);\n\t\t\t\tsubagentInbox.start(poolTaskId, label, params.subagent_type);\n\n\t\t\t\t// Warm path (opt-in): run on a reused RPC worker, retain the body in the\n\t\t\t\t// inbox, and return the same notify-and-pull shape as the cold path. An\n\t\t\t\t// infra failure falls through to the cold dispatch below.\n\t\t\t\tif (warmSubagentsEnabled() && !forkSessionFile) {\n\t\t\t\t\tconst warm = getWarmSubagentPool(ctx.cwd, availableModels);\n\t\t\t\t\tif (warm.isPoolable(params.subagent_type)) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst warmResult = await warm.dispatch(\n\t\t\t\t\t\t\t\tparams.prompt,\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tagentType: params.subagent_type,\n\t\t\t\t\t\t\t\t\tcwd: ctx.cwd,\n\t\t\t\t\t\t\t\t\tmodel: dispatchModel,\n\t\t\t\t\t\t\t\t\tprovider: ctx.model?.provider,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t(activity) => taskStore.patchAgent(poolTaskId, { activity }),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tconst dispatchResult = warmResultToTaskResult(warmResult, params.subagent_type, task.id);\n\t\t\t\t\t\t\tsubagentInbox.finish(poolTaskId, dispatchResult);\n\t\t\t\t\t\t\treturn finalizeDispatchResult(\n\t\t\t\t\t\t\t\tdispatchResult,\n\t\t\t\t\t\t\t\tparams.subagent_type,\n\t\t\t\t\t\t\t\tpoolTaskId,\n\t\t\t\t\t\t\t\ttask.id,\n\t\t\t\t\t\t\t\tpoolTaskId,\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttaskId: poolTaskId,\n\t\t\t\t\t\t\t\t\tlabel,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\tif (!(error instanceof WarmWorkerError)) throw error;\n\t\t\t\t\t\t\tconsole.error(`[WARM] ${params.subagent_type} fell back to cold spawn: ${error.message}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tconst dispatchResult = await cancelOnAbort(poolTaskId, () =>\n\t\t\t\t\t\tpool.dispatch(params.prompt, {\n\t\t\t\t\t\t\tforceAgent: params.subagent_type,\n\t\t\t\t\t\t\tcontext: \"\",\n\t\t\t\t\t\t\tmodel: dispatchModel,\n\t\t\t\t\t\t\tprovider: ctx.model?.provider,\n\t\t\t\t\t\t\tsessionFile: forkSessionFile,\n\t\t\t\t\t\t\ttaskId: poolTaskId,\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\t\tsubagentInbox.finish(poolTaskId, dispatchResult);\n\t\t\t\t\treturn finalizeDispatchResult(dispatchResult, params.subagent_type, poolTaskId, task.id, poolTaskId, {\n\t\t\t\t\t\ttaskId: poolTaskId,\n\t\t\t\t\t\tlabel,\n\t\t\t\t\t});\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconst reason = error instanceof Error ? error.message : String(error);\n\t\t\t\t\tmarkDispatchFailed(task.id, poolTaskId);\n\t\t\t\t\tsubagentInbox.fail(poolTaskId, reason);\n\t\t\t\t\t// A background dispatch reports failure as a compact notification, not a\n\t\t\t\t\t// thrown tool error — the call was already answered by a placeholder.\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcontent: [{ type: \"text\" as const, text: `${label} failed ✗ — ${reason}` }],\n\t\t\t\t\t\tdetails: {\n\t\t\t\t\t\t\tsubagent_type: params.subagent_type,\n\t\t\t\t\t\t\tok: false,\n\t\t\t\t\t\t\terror: reason,\n\t\t\t\t\t\t\ttaskId: task.id,\n\t\t\t\t\t\t\tpoolTaskId,\n\t\t\t\t\t\t\tbackground: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Warm path (opt-in): for an eligible foreground dispatch, run on a reused\n\t\t\t// RPC worker to skip the cold-boot. Fork agents (forkSessionFile set) and\n\t\t\t// non-poolable types are excluded. Any infra failure falls through to the\n\t\t\t// cold pool below, so enabling this can only change latency, never whether\n\t\t\t// the task can run.\n\t\t\tif (warmSubagentsEnabled() && !forkSessionFile) {\n\t\t\t\tconst warm = getWarmSubagentPool(ctx.cwd, availableModels);\n\t\t\t\tif (warm.isPoolable(params.subagent_type)) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst warmResult = await warm.dispatch(\n\t\t\t\t\t\t\tparams.prompt,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tagentType: params.subagent_type,\n\t\t\t\t\t\t\t\tcwd: ctx.cwd,\n\t\t\t\t\t\t\t\tmodel: dispatchModel,\n\t\t\t\t\t\t\t\tprovider: ctx.model?.provider,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t// Mirror the cold pool's live progress on the task panel roster so a\n\t\t\t\t\t\t\t// warm dispatch reads as busy (⋯ grep), not stuck.\n\t\t\t\t\t\t\t(activity) => taskStore.patchAgent(poolTaskId, { activity }),\n\t\t\t\t\t\t);\n\t\t\t\t\t\tconst dispatchResult = warmResultToTaskResult(warmResult, params.subagent_type, task.id);\n\t\t\t\t\t\treturn finalizeDispatchResult(dispatchResult, params.subagent_type, poolTaskId, task.id, undefined);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t// A genuine infra failure (worker crash/timeout) retries cold; any other\n\t\t\t\t\t\t// error is a real dispatch failure and propagates.\n\t\t\t\t\t\tif (!(error instanceof WarmWorkerError)) {\n\t\t\t\t\t\t\ttaskStore.update(task.id, { status: \"failed\" });\n\t\t\t\t\t\t\ttaskStore.patchAgent(poolTaskId, { state: \"failed\", activity: \"\" });\n\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconsole.error(`[WARM] ${params.subagent_type} fell back to cold spawn: ${error.message}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Foreground: block the turn and return the subagent's full answer inline.\n\t\t\ttry {\n\t\t\t\tconst dispatchResult = await cancelOnAbort(poolTaskId, () =>\n\t\t\t\t\tpool.dispatch(params.prompt, {\n\t\t\t\t\t\tforceAgent: params.subagent_type,\n\t\t\t\t\t\tcontext: \"\",\n\t\t\t\t\t\tmodel: dispatchModel,\n\t\t\t\t\t\tprovider: ctx.model?.provider,\n\t\t\t\t\t\tsessionFile: forkSessionFile,\n\t\t\t\t\t\ttaskId: poolTaskId,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\treturn finalizeDispatchResult(\n\t\t\t\t\tdispatchResult,\n\t\t\t\t\tparams.subagent_type,\n\t\t\t\t\tpoolTaskId,\n\t\t\t\t\ttask.id,\n\t\t\t\t\tdispatchResult.task_id,\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\tmarkDispatchFailed(task.id, poolTaskId);\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t},\n\n\t\trenderCall(args, theme) {\n\t\t\tconst type = args.subagent_type ?? \"agent\";\n\t\t\t// The [type] tag carries the agent's identity color — the same hue this\n\t\t\t// agent has in the task panel and TaskOutput — so a transcript full of\n\t\t\t// concurrent dispatches is scannable by color.\n\t\t\tconst text = theme.fg(\"toolTitle\", theme.bold(\"Agent \")) + theme.fg(agentColorFor(type), `[${type}]`);\n\t\t\treturn new Text(text, 0, 0);\n\t\t},\n\t});\n}\n\n/**\n * For a `fork: true` agent, fork the parent's session so the subagent inherits the\n * full parent conversation (and its prompt cache) instead of starting fresh. Returns\n * the forked session file to dispatch the child with, or undefined to fall back to a\n * fresh session (non-fork agent, no parent session, or an empty/invalid source).\n */\nexport function resolveForkSessionFile(\n\tdef: Pick<AgentDefinition, \"fork\">,\n\tparentSessionPath: string | undefined,\n\tcwd: string,\n): string | undefined {\n\tif (!def.fork || !parentSessionPath) return undefined;\n\ttry {\n\t\treturn SessionManager.forkFrom(parentSessionPath, cwd).getSessionFile();\n\t} catch {\n\t\t// Empty/invalid parent session: fall back to a fresh subagent session.\n\t\treturn undefined;\n\t}\n}\n\n/** Pre-allocated pool task id for a dispatch (matches the pool's own format). */\nfunction newDispatchTaskId(): string {\n\treturn `dispatch-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;\n}\n\n/**\n * The TodoWrite plan item this dispatch is (most plausibly) working on: the\n * single in_progress main-agent task. TodoWrite discipline keeps exactly one\n * item in_progress, so when that holds the link is unambiguous; with zero or\n * several in_progress items no link is recorded rather than guessing. Used to\n * nest the run under its plan item in the task panel's flat lens.\n */\nfunction linkedTodoId(): number | undefined {\n\tconst inProgress = taskStore\n\t\t.list()\n\t\t.filter(\n\t\t\t(t) =>\n\t\t\t\tt.source === undefined &&\n\t\t\t\tt.agent === undefined &&\n\t\t\t\tt.parentTaskId === undefined &&\n\t\t\t\tt.status === \"in_progress\",\n\t\t);\n\treturn inProgress.length === 1 ? inProgress[0]?.id : undefined;\n}\n\n/**\n * Register this dispatch in the task store's roster, keyed by its run id (the\n * pool task id) so concurrent runs of the same agent type each get their own\n * row, state, activity, and stats. The friendly label (\"explore#1\") names the\n * row the same way the inbox names background tasks.\n */\nfunction registerSubagentDispatch(runId: string, label: string): void {\n\ttaskStore.upsertAgent({ id: runId, name: label, role: \"subagent\", kind: \"subagent\", state: \"running\" });\n}\n\n/**\n * Catch-path bookkeeping: mark the dispatch failed unless it already settled.\n * finalizeDispatchResult records a terminal status (failed/cancelled) *before*\n * throwing, so a blanket \"failed\" here would clobber a cancellation with a\n * failure the moment the thrown error passed through.\n */\nfunction markDispatchFailed(taskStoreId: number, runId: string): void {\n\tconst current = taskStore.list().find((t) => t.id === taskStoreId);\n\tif (current && current.status !== \"pending\" && current.status !== \"in_progress\") return;\n\ttaskStore.update(taskStoreId, { status: \"failed\" });\n\ttaskStore.patchAgent(runId, { state: \"failed\", activity: \"\" });\n}\n\n/** Names of agents configured to run in the background (non-blocking). */\nfunction collectBackgroundAgentNames(cwd: string): Set<string> {\n\tconst names = new Set<string>();\n\tfor (const agent of loadAgentRegistry({ cwd }).list()) {\n\t\tif (agent.background) names.add(agent.name);\n\t}\n\treturn names;\n}\n\n/**\n * Merge a child subagent's task subtree into the parent's task store, rooting\n * each top-level node under the dispatching task (`parentTaskId`). Recurses so a\n * subagent that itself delegated shows its nested work — the subtree the child\n * could not surface across the process boundary on its own. Each node is its own\n * task (no key-by-type collapse), preserving the order the child created them.\n */\nfunction mergeChildTaskTree(nodes: readonly SubagentTaskNode[] | undefined, parentTaskId: number): void {\n\tif (!nodes) return;\n\ttaskStore.batch(() => {\n\t\tfor (const node of nodes) {\n\t\t\tconst created = taskStore.create(node.title, {\n\t\t\t\tsource: node.source,\n\t\t\t\tsubagentMode: node.subagentMode,\n\t\t\t\tparentTaskId,\n\t\t\t});\n\t\t\ttaskStore.update(created.id, { status: node.status, usage: node.usage });\n\t\t\tmergeChildTaskTree(node.children, created.id);\n\t\t}\n\t});\n}\n\n/**\n * Adapt a warm-worker run into the TaskResult shape finalizeDispatchResult\n * consumes, so the warm and cold paths share one finish/render path. A warm run\n * returns its answer inline (no result.json), so we synthesize an equivalent\n * SubagentResult with the answer as the summary and the pulled usage. The warm\n * path is clean (no persisted session), so there is no task_tree to merge and no\n * resume handle.\n */\nfunction warmResultToTaskResult(warm: WarmRunResult, agentType: string, taskStoreId: number): TaskResult {\n\tconst resultData: SubagentResultFile = {\n\t\tsummary: warm.summary || \"(subagent returned no output)\",\n\t\tfiles_changed: [],\n\t\tconfidence: warm.ok ? 1 : 0,\n\t\tstatus: warm.status,\n\t\tusage: warm.usage,\n\t};\n\tconst result: SubagentResult = {\n\t\ttask_id: String(taskStoreId),\n\t\tok: warm.ok,\n\t\tstdout: \"\",\n\t\tstderr: \"\",\n\t\texit_code: warm.ok ? 0 : 1,\n\t\tstatus: warm.status,\n\t\terror: warm.error,\n\t\tresult_data: resultData as unknown as Record<string, unknown>,\n\t};\n\treturn { handled_inline: false, agent_type: agentType, result };\n}\n\n/**\n * Update the task panel from a finished dispatch and shape the tool result.\n *\n * Foreground calls return the subagent's full answer inline and signal a hard\n * failure by throwing (the agent loop derives a tool's error state from a thrown\n * error). A background call passes `background`: the body already lives in the\n * inbox, so it returns a compact, self-contained notification (success or\n * failure) and never throws — the call was already answered by a placeholder.\n */\nfunction finalizeDispatchResult(\n\tdispatchResult: TaskResult,\n\tsubagentType: string,\n\trunAgentId: string,\n\ttaskStoreId: number,\n\tresumeHandle: string | undefined,\n\tbackground?: { taskId: string; label: string },\n): { content: Array<{ type: \"text\"; text: string }>; details: TaskToolDetails } {\n\tconst result = dispatchResult.result;\n\tconst resultData = result?.result_data as SubagentResultFile | undefined;\n\tconst usage = resultData?.usage;\n\n\t// Merge the child's own task subtree under the dispatching task so nested\n\t// delegation (depth >= 2) is visible in the subagents lens's task tree.\n\tmergeChildTaskTree(resultData?.task_tree, taskStoreId);\n\n\t// Roll this run's usage into its own roster row (rows are per-dispatch).\n\tif (usage) {\n\t\ttaskStore.addAgentStats(runAgentId, { input: usage.input, output: usage.output, cost: usage.cost });\n\t}\n\n\tif (!result || !result.ok) {\n\t\t// A user-initiated cancel is not a failure: it gets its own terminal\n\t\t// status so the panel shows ⊘ cancelled (dim) instead of ✗ failed (red).\n\t\tconst cancelled = result?.status === \"cancelled\";\n\t\tconst failNote = result?.usedInheritedModelFallback ? \"inherited-model retry failed\" : undefined;\n\t\ttaskStore.update(taskStoreId, { status: cancelled ? \"cancelled\" : \"failed\", usage, note: failNote });\n\t\ttaskStore.patchAgent(runAgentId, { state: cancelled ? \"cancelled\" : \"failed\", activity: \"\" });\n\t\tconst reason = result?.error ?? (result?.status ? `subagent ${result.status}` : \"unknown error\");\n\t\tif (background) {\n\t\t\tconst verdict = cancelled ? \"cancelled ⊘\" : \"failed ✗\";\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\", text: `${background.label} ${verdict} — ${reason}` }],\n\t\t\t\tdetails: {\n\t\t\t\t\tsubagent_type: subagentType,\n\t\t\t\t\tok: false,\n\t\t\t\t\terror: reason,\n\t\t\t\t\ttaskId: taskStoreId,\n\t\t\t\t\tpoolTaskId: background.taskId,\n\t\t\t\t\tbackground: true,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\tif (cancelled) {\n\t\t\tthrow new Error(`Subagent (${subagentType}) cancelled by user.`);\n\t\t}\n\t\tconst stderr = result?.stderr?.trim();\n\t\tthrow new Error(`Subagent (${subagentType}) failed: ${reason}${stderr ? `\\nstderr: ${stderr.slice(-500)}` : \"\"}`);\n\t}\n\n\t// Leave the task in the store with its final status; it stays visible in the\n\t// task panel until the next user message arrives. Surface a ⚠ cue when the run\n\t// fell back to the inherited model rather than emitting a chat message — and\n\t// clear any stale note otherwise (note is clearable via an explicit undefined).\n\tconst fallbackNote = dispatchResult.result?.usedInheritedModelFallback ? \"ran on inherited model\" : undefined;\n\ttaskStore.update(taskStoreId, { status: \"done\", usage, note: fallbackNote });\n\t// Rows are per-run, so this run settles to done regardless of siblings.\n\ttaskStore.patchAgent(runAgentId, { state: \"done\", activity: \"\" });\n\tlet answer = resultData?.summary || \"(subagent returned no output)\";\n\t// Partial results are resumable; surface the handle so the parent can continue.\n\tif (result.status === \"partial\" && resumeHandle) {\n\t\tanswer += `\\n\\n[Partial result. To continue this subagent, call Task again with resume_task_id=\"${resumeHandle}\".]`;\n\t}\n\n\tif (background) {\n\t\t// Compact notification: the body is retained in the inbox; the model pulls it\n\t\t// with TaskOutput. Keeps a wide swarm from flooding the parent's context.\n\t\tconst partial = result.status === \"partial\" ? \" (partial — resume to continue)\" : \"\";\n\t\tconst outstanding = subagentInbox.outstanding().length;\n\t\tconst tail = outstanding > 0 ? ` ${outstanding} still running.` : \"\";\n\t\tconst text =\n\t\t\t`${background.label} finished ✓${partial} — ${summarize(answer)}.${tail}\\n` +\n\t\t\t`Read the full result with TaskOutput(\"${background.label}\").`;\n\t\treturn {\n\t\t\tcontent: [{ type: \"text\", text }],\n\t\t\tdetails: {\n\t\t\t\tsubagent_type: subagentType,\n\t\t\t\tok: true,\n\t\t\t\ttaskId: taskStoreId,\n\t\t\t\tpoolTaskId: background.taskId,\n\t\t\t\tbackground: true,\n\t\t\t},\n\t\t};\n\t}\n\n\treturn {\n\t\tcontent: [{ type: \"text\", text: answer }],\n\t\tdetails: { subagent_type: subagentType, ok: true, taskId: taskStoreId, poolTaskId: resumeHandle },\n\t};\n}\n\nconst taskOutputParams = Type.Object({\n\ttask_id: Type.Optional(\n\t\tType.String({\n\t\t\tdescription:\n\t\t\t\t'Handle of a background subagent — its task_id or friendly label (e.g. \"explore#1\") from a Task notification. Omit (or set list:true) to see every background task.',\n\t\t}),\n\t),\n\tlist: Type.Optional(\n\t\tType.Boolean({\n\t\t\tdescription:\n\t\t\t\t\"List all background subagents with their status (running/done/failed/cancelled) and current activity. No result bodies are returned.\",\n\t\t}),\n\t),\n\twait: Type.Optional(\n\t\tType.Boolean({\n\t\t\tdescription:\n\t\t\t\t\"Block until the named task finishes — or, with no task_id, until all outstanding subagents finish (a swarm barrier) — before returning. Bounded by timeout_ms.\",\n\t\t}),\n\t),\n\ttimeout_ms: Type.Optional(\n\t\tType.Number({ description: \"Maximum time to block in wait mode, in milliseconds (default 120000).\" }),\n\t),\n});\n\ntype TaskOutputParams = Static<typeof taskOutputParams>;\n\nconst TASK_OUTPUT_DEFAULT_TIMEOUT_MS = 120_000;\n\n/**\n * Elapsed time a record has run (so far, or until it settled), in the same\n * format the task panel uses so the two surfaces always agree.\n */\nfunction recordElapsed(rec: InboxRecord): string {\n\tconst end = rec.endedAt ?? Date.now();\n\treturn formatDurationSecs((end - rec.startedAt) / 1000);\n}\n\n/** A compact roster of every known background subagent — status + activity, no bodies. */\nfunction formatTaskRoster(): { content: Array<{ type: \"text\"; text: string }>; details: TaskOutputDetails } {\n\tconst all = subagentInbox.list();\n\tconst outstanding = subagentInbox.outstanding().length;\n\tif (all.length === 0) {\n\t\treturn {\n\t\t\tcontent: [{ type: \"text\", text: \"No background subagents have been dispatched.\" }],\n\t\t\tdetails: { status: \"empty\", ok: true, outstanding: 0 },\n\t\t};\n\t}\n\tconst lines = all.map((r) => {\n\t\tconst when = recordElapsed(r);\n\t\tswitch (r.lifecycle) {\n\t\t\tcase \"running\":\n\t\t\t\treturn `- ${r.label} running ${when}${r.lastActivity ? ` · ${r.lastActivity}` : \"\"}`;\n\t\t\tcase \"done\":\n\t\t\t\treturn `- ${r.label} done (uncollected) ${when} — ${r.summaryLine ?? \"\"}`;\n\t\t\tcase \"collected\":\n\t\t\t\treturn `- ${r.label} collected ${when} — ${r.summaryLine ?? \"\"}`;\n\t\t\tcase \"cancelled\":\n\t\t\t\treturn `- ${r.label} cancelled ⊘ — ${r.error ?? \"cancelled by user\"}`;\n\t\t\tdefault:\n\t\t\t\treturn `- ${r.label} ${r.lifecycle} ✗ — ${r.error ?? \"unknown error\"}`;\n\t\t}\n\t});\n\tconst header = `${all.length} background subagent${all.length === 1 ? \"\" : \"s\"} (${outstanding} running):`;\n\tconst hint = all.some((r) => r.lifecycle === \"done\") ? '\\nRead a finished one with TaskOutput(\"<label>\").' : \"\";\n\treturn {\n\t\tcontent: [{ type: \"text\", text: `${header}\\n${lines.join(\"\\n\")}${hint}` }],\n\t\tdetails: { status: \"list\", ok: true, outstanding },\n\t};\n}\n\n/**\n * TaskOutput tool: check on background subagents and pull their results.\n *\n * Background `Task` calls don't push their body into the conversation — they\n * leave it in the inbox and post a compact notification. TaskOutput is how the\n * model pulls a body, checks liveness, or waits. It never throws on a valid\n * handle (an error tool result would only confuse the loop): it reports status\n * instead. Modes: `list` (roster), a `task_id` to read/check one, and `wait` to\n * block until one task — or all outstanding tasks — finish.\n */\nexport function createTaskOutputToolDefinition(): ToolDefinition {\n\treturn defineTool<typeof taskOutputParams, TaskOutputDetails>({\n\t\tname: \"TaskOutput\",\n\t\tlabel: \"TaskOutput\",\n\t\tdescription: [\n\t\t\t\"Check on background subagents dispatched via Task, and pull their results.\",\n\t\t\t'Pass a task_id/label (e.g. \"explore#1\") to read a finished subagent\\'s full result, or to see its status while it runs.',\n\t\t\t\"Set list:true (or omit task_id) to list every background subagent with its status and current activity.\",\n\t\t\t\"Set wait:true to block until that task finishes — or, with no task_id, until all outstanding subagents finish (a swarm barrier).\",\n\t\t\t\"It never errors on a valid handle: a running task reports status, a finished one returns its result, an already-read one says so.\",\n\t\t].join(\"\\n\"),\n\t\tpromptSnippet: \"check status / list / collect the results of background subagents\",\n\t\tparameters: taskOutputParams,\n\n\t\tasync execute(_toolCallId, params: TaskOutputParams, _signal, _onUpdate, ctx) {\n\t\t\t// Touch the pool so the inbox is wired to its progress stream for activity.\n\t\t\t// The pool is normally already created by a prior dispatch; pass available\n\t\t\t// models so a first-touch here still seeds category derivation.\n\t\t\tsubagentInbox.observe(getSubagentPool(ctx.cwd, ctx.modelRegistry?.getAvailable() ?? []));\n\t\t\tconst handle = params.task_id?.trim();\n\n\t\t\t// Barrier: wait for the target (or all outstanding) to settle first.\n\t\t\tif (params.wait) {\n\t\t\t\tconst timeout = params.timeout_ms ?? TASK_OUTPUT_DEFAULT_TIMEOUT_MS;\n\t\t\t\tif (handle) await subagentInbox.waitFor(handle, timeout);\n\t\t\t\telse await subagentInbox.waitForAll(timeout);\n\t\t\t}\n\n\t\t\t// Roster when asked, or when no specific task was named.\n\t\t\tif (params.list || !handle) {\n\t\t\t\treturn formatTaskRoster();\n\t\t\t}\n\n\t\t\tconst rec = subagentInbox.get(handle);\n\t\t\tif (!rec) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\" as const,\n\t\t\t\t\t\t\ttext: `No background task \"${handle}\". Call TaskOutput with list:true to see active tasks.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: { task_id: handle, status: \"unknown\", ok: false },\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tif (rec.lifecycle === \"running\") {\n\t\t\t\tconst activity = rec.lastActivity ? ` (currently: ${rec.lastActivity})` : \"\";\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\" as const,\n\t\t\t\t\t\t\ttext: `${rec.label} is still running — ${recordElapsed(rec)} elapsed${activity}. Call TaskOutput again, or with wait:true to block until it finishes.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: { task_id: handle, status: \"running\", ok: true },\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tif (rec.lifecycle === \"done\") {\n\t\t\t\tconst collected = subagentInbox.collect(handle);\n\t\t\t\tconst body = collected?.body ?? rec.summaryLine ?? \"(subagent returned no output)\";\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\" as const, text: body }],\n\t\t\t\t\tdetails: { task_id: handle, status: \"done\", ok: true },\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tif (rec.lifecycle === \"collected\") {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\" as const,\n\t\t\t\t\t\t\ttext: `${rec.label} was already delivered — ${rec.summaryLine ?? \"(no summary kept)\"}.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: { task_id: handle, status: \"collected\", ok: true },\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// failed / stalled / timeout / cancelled\n\t\t\tconst glyph = rec.lifecycle === \"cancelled\" ? \"⊘\" : \"✗\";\n\t\t\treturn {\n\t\t\t\tcontent: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"text\" as const,\n\t\t\t\t\t\ttext: `${rec.label} ${rec.lifecycle} ${glyph} — ${rec.error ?? \"unknown error\"}.`,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tdetails: { task_id: handle, status: rec.lifecycle, ok: false },\n\t\t\t};\n\t\t},\n\n\t\trenderCall(args, theme) {\n\t\t\tconst target = args.list ? \"list\" : String(args.task_id ?? \"\");\n\t\t\t// A friendly label (\"explore#1\") gets its agent's identity color so the\n\t\t\t// pull visually pairs with the dispatch that produced it; raw ids and\n\t\t\t// \"list\" stay dim.\n\t\t\tconst hashIdx = target.indexOf(\"#\");\n\t\t\tconst styledTarget =\n\t\t\t\thashIdx > 0 ? theme.fg(agentColorFor(target.slice(0, hashIdx)), target) : theme.fg(\"dim\", target);\n\t\t\tconst text =\n\t\t\t\ttheme.fg(\"toolTitle\", theme.bold(\"TaskOutput \")) +\n\t\t\t\tstyledTarget +\n\t\t\t\t(args.wait ? theme.fg(\"dim\", \" (wait)\") : \"\");\n\t\t\treturn new Text(text, 0, 0);\n\t\t},\n\n\t\trenderResult(result, _options, theme) {\n\t\t\t// Display-only framing/colorization (the text sent to the model stays\n\t\t\t// plain). A single-task pull renders as a result CARD — a status-stamped\n\t\t\t// header, a left spine down the body, and a closing corner — so a\n\t\t\t// collected result reads as a discrete artifact instead of blending into\n\t\t\t// the surrounding tool chatter. Roster/list responses keep the line\n\t\t\t// colorization.\n\t\t\tconst text = result.content\n\t\t\t\t.map((c) => (c.type === \"text\" ? c.text : \"\"))\n\t\t\t\t.filter(Boolean)\n\t\t\t\t.join(\"\\n\");\n\t\t\tif (!text) return new Text(\"\", 0, 0);\n\n\t\t\tconst details = result.details as TaskOutputDetails | undefined;\n\t\t\tconst cardStatus = details?.task_id ? details.status : undefined;\n\t\t\tif (cardStatus && cardStatus !== \"list\" && cardStatus !== \"empty\") {\n\t\t\t\tconst presentation: Record<\n\t\t\t\t\tstring,\n\t\t\t\t\t{ glyph: string; color: \"success\" | \"warning\" | \"error\" | \"muted\" | \"dim\" }\n\t\t\t\t> = {\n\t\t\t\t\tdone: { glyph: \"✓\", color: \"success\" },\n\t\t\t\t\trunning: { glyph: \"◐\", color: \"warning\" },\n\t\t\t\t\tcollected: { glyph: \"✓\", color: \"muted\" },\n\t\t\t\t\tcancelled: { glyph: \"⊘\", color: \"dim\" },\n\t\t\t\t\tunknown: { glyph: \"?\", color: \"dim\" },\n\t\t\t\t};\n\t\t\t\tconst { glyph, color } = presentation[cardStatus] ?? { glyph: \"✗\", color: \"error\" as const };\n\t\t\t\tconst label = details?.task_id ?? \"\";\n\t\t\t\tconst hashIdx = label.indexOf(\"#\");\n\t\t\t\tconst labelColor = hashIdx > 0 ? agentColorFor(label.slice(0, hashIdx)) : \"accent\";\n\t\t\t\tconst spine = (s: string) => theme.fg(\"borderMuted\", s);\n\t\t\t\tconst header =\n\t\t\t\t\t`${spine(\"╭\")} ${theme.fg(color, glyph)} ` +\n\t\t\t\t\t`${theme.bold(theme.fg(color, cardStatus))} ${theme.fg(labelColor, label)}`;\n\t\t\t\tconst body = text\n\t\t\t\t\t.split(\"\\n\")\n\t\t\t\t\t.map((line) => `${spine(\"│\")} ${theme.fg(\"toolOutput\", line)}`)\n\t\t\t\t\t.join(\"\\n\");\n\t\t\t\treturn new Text(`${header}\\n${body}\\n${spine(\"╰\")}`, 0, 0);\n\t\t\t}\n\n\t\t\tconst rosterLine =\n\t\t\t\t/^- (\\S+)\\s{2}(running|done \\(uncollected\\)|collected|failed|stalled|timeout|cancelled)(.*)$/;\n\t\t\tconst styled = text\n\t\t\t\t.split(\"\\n\")\n\t\t\t\t.map((line) => {\n\t\t\t\t\tconst match = rosterLine.exec(line);\n\t\t\t\t\tif (!match) return theme.fg(\"toolOutput\", line);\n\t\t\t\t\tconst [, label, status, rest] = match as unknown as [string, string, string, string];\n\t\t\t\t\tconst hashIdx = label.indexOf(\"#\");\n\t\t\t\t\tconst labelColor = hashIdx > 0 ? agentColorFor(label.slice(0, hashIdx)) : \"accent\";\n\t\t\t\t\tconst statusColor =\n\t\t\t\t\t\tstatus === \"running\"\n\t\t\t\t\t\t\t? \"warning\"\n\t\t\t\t\t\t\t: status.startsWith(\"done\")\n\t\t\t\t\t\t\t\t? \"success\"\n\t\t\t\t\t\t\t\t: status === \"collected\" || status === \"cancelled\"\n\t\t\t\t\t\t\t\t\t? \"muted\"\n\t\t\t\t\t\t\t\t\t: \"error\";\n\t\t\t\t\treturn `- ${theme.fg(labelColor, label)} ${theme.fg(statusColor, status)}${theme.fg(\"dim\", rest)}`;\n\t\t\t\t})\n\t\t\t\t.join(\"\\n\");\n\t\t\treturn new Text(styled, 0, 0);\n\t\t},\n\t});\n}\n"]}
|
|
1
|
+
{"version":3,"file":"subagent.js","sourceRoot":"","sources":["../../../src/core/tools/subagent.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Task tool: delegate a focused task to a specialized subagent.\n *\n * Mirrors the Claude Code `Task` tool. The parent agent decides *when* to\n * delegate based on each agent's `description` (there is no deterministic gate)\n * and selects *which* agent via `subagent_type`. The chosen agent runs in a\n * fresh, isolated child process (SubagentPool) and only its final answer is\n * returned to the parent.\n *\n * Enabled by default (the `enableSubagent` setting defaults to true); disable\n * with `enableSubagent: false`. The `--enable-subagents` flag still force-enables\n * it. Nesting is bounded by the tree-wide depth cap (maxSubagentDepth, default 2:\n * a spawned subagent may itself delegate one more level, and depth-2 grandchildren\n * cannot). See buildSessionOptions in main.ts.\n */\n\nimport { Text } from \"@kolisachint/hoocode-tui\";\nimport { type Static, Type } from \"typebox\";\nimport { agentColorFor } from \"../../modes/interactive/theme/theme.js\";\nimport { type AgentDefinition, TASK_TOOL_NAME } from \"../agent-frontmatter.js\";\nimport { loadAgentRegistry } from \"../agent-registry.js\";\nimport type { ToolDefinition } from \"../extensions/types.js\";\nimport { defineTool } from \"../extensions/types.js\";\nimport { formatDurationSecs } from \"../format-duration.js\";\nimport { formatTokens } from \"../format-tokens.js\";\nimport { getProviderExhaustion } from \"../provider-health.js\";\nimport { SessionManager } from \"../session-manager.js\";\nimport { delegateAllowList, isDelegateAllowed } from \"../subagent-depth.js\";\nimport { type InboxRecord, subagentInbox } from \"../subagent-inbox.js\";\nimport type { SubagentResult, TaskResult } from \"../subagent-pool.js\";\nimport { getSubagentPool } from \"../subagent-pool-instance.js\";\nimport type { SubagentResultFile, SubagentTaskNode } from \"../subagent-result.js\";\nimport { taskStore } from \"../task-store.js\";\nimport { type WarmRunResult, WarmWorkerError } from \"../warm-subagent-pool.js\";\nimport { getWarmSubagentPool, warmSubagentsEnabled } from \"../warm-subagent-pool-instance.js\";\n\n// Re-exported from its home in agent-registry (where formatAgentsForPrompt uses\n// it to render the roster) so existing importers keep working without creating a\n// tools -> registry -> tools cycle.\nexport { summarizeAgentDescription } from \"../agent-registry.js\";\n\n/** System prompt appendix for the main session when the Task tool is enabled.\n * Instructs the parent agent on when and how to delegate effectively. The\n * available agents themselves are listed once, authoritatively, in the\n * `<available_agents>` block the system prompt emits whenever the Task tool is\n * active (see agent-session `_rebuildSystemPrompt`); this appendix references\n * that list rather than re-rendering the roster and paying for it twice. */\n/**\n * Build the main-session subagent instructions appended to the system prompt.\n *\n * The detailed background/barrier guidance (the three heaviest bullets) is only\n * emitted when the project actually has background-capable agents; otherwise a\n * single concise line covers the per-call `background: true` escape hatch. This\n * keeps the always-on cost down for the common case where nothing runs in the\n * background. `cwd` is used only to detect those agents.\n */\nexport function buildTaskMainPrompt(cwd: string = process.cwd()): string {\n\tconst hasBackgroundAgents = collectBackgroundAgentNames(cwd).size > 0;\n\n\tconst backgroundGuidance = hasBackgroundAgents\n\t\t? `- Background agents run non-blocking (or force per call with \\`background: true\\`): you get a short \"explore#1 finished\" notification and pull the full result with \\`TaskOutput\\` (e.g. \\`TaskOutput(\"explore#1\")\\`); \\`TaskOutput(list: true)\\` shows what's running.\n- After dispatching, don't idle — keep doing independent work (read/edit unrelated files, draft, dispatch more); barrier with \\`TaskOutput(wait: true)\\` (a named task, or all outstanding when no id) only when you genuinely can't proceed.`\n\t\t: `- You can force any task to run in the background with \\`background: true\\` (non-blocking): keep working, then pull its result with \\`TaskOutput\\` (e.g. \\`TaskOutput(\"explore#1\")\\`) or block on it with \\`TaskOutput(wait: true)\\`.`;\n\n\treturn `You have access to the **Task** tool. Use it to delegate self-contained tasks to specialized subagents that run in their own isolated context and return only their final answer. Pick an agent by name from the <available_agents> list in this prompt and pass it as \\`subagent_type\\`.\n\nWhen to delegate:\n1. The work is self-contained and you only need the final result, not intermediate steps.\n2. You want to investigate or edit something in parallel without losing your current context or reasoning chain.\n3. The task is a discrete unit (explore one module, run one test file, review one PR, fix one isolated bug).\n4. You need to run a long command or test suite and wait for its output without blocking your own reasoning.\n\nModel tier (optional \\`complexity\\`): set \\`fast\\` for quick reads/lookups, \\`standard\\` for multi-file edits, \\`capable\\` for deep architecture work. It maps to a model from \\`settings.modelCategories\\`. Omit it to use the agent's default; an agent that pins its own model ignores \\`complexity\\`.\n\nGuidelines:\n- Choose the agent whose description best matches the task.\n- Make every task specific and self-contained. The subagent cannot see this conversation; pass all necessary context (files, constraints, prior findings) in \\`prompt\\`.\n- Do NOT delegate tasks that require tight back-and-forth with your current reasoning, or edits to files you are actively reasoning about.\n- The subagent returns ONLY its final answer. Its intermediate reasoning, tool calls, and output are hidden from you.\n- Delegate proactively when work is self-contained or parallelizable: multi-step investigation, read-only exploration (use \\`explore\\`), research before changes (use \\`plan\\`), drafting a standalone file/section, or running a long command/test suite. Dispatch independent subtasks in the same turn. Handle only trivial single-step edits or tightly interactive back-and-forth inline.\n${backgroundGuidance}\n- When working through a TodoWrite plan, mark the plan item in_progress BEFORE dispatching subagents for it: each dispatch is attributed to the current in_progress item in the user's task panel, so dispatching first (or with several items in_progress) leaves the run unattributed.\n- To continue a previous subagent (for example one that returned partial results), call Task again with \\`resume_task_id\\` set to its task_id; it resumes with its full prior transcript and \\`prompt\\` is your follow-up.`;\n}\n\nconst taskParams = Type.Object({\n\tdescription: Type.String({\n\t\tdescription: \"A short (3-5 word) description of the task, shown in the task panel.\",\n\t}),\n\tprompt: Type.String({\n\t\tdescription:\n\t\t\t\"The full, self-contained task for the subagent. It cannot see this conversation, so include all needed context, files, and constraints.\",\n\t}),\n\tsubagent_type: Type.String({\n\t\tdescription: \"The name of the specialized agent to delegate to. Must be one of the available agents.\",\n\t}),\n\tcomplexity: Type.Optional(\n\t\tType.Union([Type.Literal(\"fast\"), Type.Literal(\"standard\"), Type.Literal(\"capable\")], {\n\t\t\tdescription:\n\t\t\t\t\"Model tier for this dispatch: fast (quick reads/lookups), standard (multi-file edits), capable (deep architecture). Maps to settings.modelCategories. Ignored if the chosen agent pins its own model; omit to use the agent's default.\",\n\t\t}),\n\t),\n\tbackground: Type.Optional(\n\t\tType.Boolean({\n\t\t\tdescription:\n\t\t\t\t\"Set true to run non-blocking: you get a short notification when it finishes and pull the full result with TaskOutput; set false to wait and get the answer inline. Defaults to the agent's own background setting.\",\n\t\t}),\n\t),\n\tresume_task_id: Type.Optional(\n\t\tType.String({\n\t\t\tdescription:\n\t\t\t\t\"Optional. To continue a previous subagent run, pass its task_id (returned by an earlier Task or TaskOutput call). The subagent resumes with its full prior transcript and `prompt` is your follow-up instruction.\",\n\t\t}),\n\t),\n});\n\ntype TaskParams = Static<typeof taskParams>;\n\nexport interface TaskToolDetails {\n\tsubagent_type: string;\n\tok: boolean;\n\terror?: string;\n\ttaskId: number;\n\t/** Pool-level task id usable for resume/polling. */\n\tpoolTaskId?: string;\n\t/** True when dispatched as a non-blocking background task. */\n\tbackground?: boolean;\n}\n\nexport interface TaskOutputDetails {\n\t/** The handle queried, when a specific task was named. */\n\ttask_id?: string;\n\t/** running | done | collected | failed | stalled | timeout | cancelled | list | empty | unknown */\n\tstatus: string;\n\tok: boolean;\n\t/** Number of subagents still running, included on roster/list responses. */\n\toutstanding?: number;\n}\n\n/**\n * A short, human-readable task name for the task panel: the first line limited\n * to ~8 words so it stays glanceable. A character cap guards a single long word.\n */\nfunction summarize(task: string): string {\n\tconst firstLine = (task.trim().split(\"\\n\")[0] ?? \"\").trim();\n\tif (!firstLine) return \"(task)\";\n\tconst words = firstLine.split(/\\s+/);\n\tlet name = words.length > 8 ? `${words.slice(0, 8).join(\" \")}…` : firstLine;\n\tif (name.length > 60) name = `${name.slice(0, 59)}…`;\n\treturn name;\n}\n\n/** Create the Task tool definition. Registered as a customTool when enabled. */\nexport function createTaskToolDefinition(cwd: string = process.cwd()): ToolDefinition {\n\t// Agents whose definitions opt into background execution. The agent loop reads\n\t// the tool's `background` flag per call and, for these, runs the dispatch\n\t// detached: the parent keeps reasoning and the subagent's answer is injected as\n\t// a follow-up message when it finishes (no polling needed). A per-call\n\t// `background` argument overrides the agent's default in either direction.\n\tconst backgroundAgents = collectBackgroundAgentNames(cwd);\n\treturn defineTool<typeof taskParams, TaskToolDetails>({\n\t\tname: TASK_TOOL_NAME,\n\t\tlabel: TASK_TOOL_NAME,\n\t\tbackground: (toolCall) => {\n\t\t\tconst override = toolCall.arguments?.background;\n\t\t\tif (typeof override === \"boolean\") return override;\n\t\t\treturn backgroundAgents.has(String(toolCall.arguments?.subagent_type ?? \"\"));\n\t\t},\n\t\t// Kept to mechanics only: the when-to-use / when-not-to guidance lives once in\n\t\t// the system-prompt block (buildTaskMainPrompt), the available agents are\n\t\t// listed there too, and the `complexity`/`background`/`resume_task_id`\n\t\t// semantics live in their parameter descriptions. Repeating any of that here\n\t\t// would re-spend those tokens on every turn.\n\t\tdescription:\n\t\t\t\"Delegate a focused task to a specialized subagent that runs in a fresh, isolated context (it cannot see this conversation). Choose one of the available agents (listed in the system prompt) via `subagent_type` and pass everything it needs via `prompt`; the subagent returns only its final answer.\",\n\t\tpromptSnippet: \"delegate a self-contained task to a specialized subagent (choose via subagent_type)\",\n\t\tparameters: taskParams,\n\n\t\tasync execute(_toolCallId, params: TaskParams, signal, _onUpdate, ctx) {\n\t\t\t// Snapshot the caller's available models so unconfigured model-category\n\t\t\t// tiers (fast/standard/capable) resolve to a derived default instead of a\n\t\t\t// no-op. Explicit settings.modelCategories still win inside the pool. The\n\t\t\t// registry can be absent in some tool contexts; an empty list just keeps\n\t\t\t// category derivation a no-op (inherit parent), so guard the access.\n\t\t\tconst availableModels = ctx.modelRegistry?.getAvailable() ?? [];\n\t\t\tconst pool = getSubagentPool(ctx.cwd, availableModels);\n\n\t\t\t// User-initiated cancel (Esc/abort): kill the dispatched run's whole\n\t\t\t// process tree and let the dispatch settle with status \"cancelled\" —\n\t\t\t// distinct from \"failed\" everywhere it surfaces (panel, inbox, result).\n\t\t\t// Cold dispatches only: a warm worker has no cancel surface (it is\n\t\t\t// reused), so warm runs still complete server-side and are discarded.\n\t\t\tconst cancelOnAbort = async (poolRunId: string, run: () => Promise<TaskResult>): Promise<TaskResult> => {\n\t\t\t\tif (!signal) return run();\n\t\t\t\tconst onAbort = () => {\n\t\t\t\t\tpool.cancel?.(poolRunId);\n\t\t\t\t};\n\t\t\t\tif (signal.aborted) onAbort();\n\t\t\t\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\ttry {\n\t\t\t\t\treturn await run();\n\t\t\t\t} finally {\n\t\t\t\t\tsignal.removeEventListener(\"abort\", onAbort);\n\t\t\t\t}\n\t\t\t};\n\n\t\t\t// Pre-flight: if the inherited provider recently exhausted its quota (the\n\t\t\t// parent's own turn failed with a usage/rate-limit error that did not\n\t\t\t// recover), skip the spawn. Subagents run on the same provider, so this\n\t\t\t// would only burn another failed attempt. The signal self-expires and is\n\t\t\t// cleared on the next successful response.\n\t\t\tconst provider = ctx.model?.provider;\n\t\t\tconst exhaustion = provider ? getProviderExhaustion(provider) : undefined;\n\t\t\tif (exhaustion) {\n\t\t\t\tconst skippedRunId = newDispatchTaskId();\n\t\t\t\tconst skipped = taskStore.create(params.description?.trim() || summarize(params.prompt), {\n\t\t\t\t\tsource: \"subagent\",\n\t\t\t\t\tsubagentMode: params.subagent_type,\n\t\t\t\t\tagent: skippedRunId,\n\t\t\t\t\tlinkedTaskId: linkedTodoId(),\n\t\t\t\t});\n\t\t\t\tregisterSubagentDispatch(skippedRunId, subagentInbox.nextLabel(params.subagent_type));\n\t\t\t\ttaskStore.update(skipped.id, { status: \"failed\", note: `${provider} exhausted` });\n\t\t\t\ttaskStore.patchAgent(skippedRunId, { state: \"failed\" });\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\" as const,\n\t\t\t\t\t\t\ttext:\n\t\t\t\t\t\t\t\t`Did not dispatch subagent \"${params.subagent_type}\": the \"${provider}\" provider appears ` +\n\t\t\t\t\t\t\t\t`exhausted or rate-limited (this session just failed with: ${exhaustion.message}). ` +\n\t\t\t\t\t\t\t\t`Subagents run on the same provider, so dispatching would fail too. Wait for the quota to ` +\n\t\t\t\t\t\t\t\t`reset or switch model/provider, then retry — or complete the work directly in this session.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: { subagent_type: params.subagent_type, ok: false, taskId: skipped.id },\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// Scoped delegation: a delegating agent may be restricted to certain subagent\n\t\t\t// types (its `delegate: <types>` frontmatter). The root is unrestricted.\n\t\t\tif (!isDelegateAllowed(params.subagent_type)) {\n\t\t\t\tconst allowed = delegateAllowList()?.join(\", \") ?? \"\";\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`This agent may not delegate to \"${params.subagent_type}\". Allowed subagent types: ${allowed || \"(none)\"}.`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Resume path: continue a previously dispatched subagent with a follow-up\n\t\t\t// prompt, reusing its persisted session (full prior transcript).\n\t\t\tconst resumeId = params.resume_task_id?.trim();\n\t\t\tif (resumeId) {\n\t\t\t\tconst summary = params.description?.trim() || summarize(params.prompt);\n\t\t\t\tconst runId = newDispatchTaskId();\n\t\t\t\tconst label = subagentInbox.nextLabel(params.subagent_type);\n\t\t\t\tconst task = taskStore.create(summary, {\n\t\t\t\t\tsource: \"subagent\",\n\t\t\t\t\tsubagentMode: params.subagent_type,\n\t\t\t\t\tagent: runId,\n\t\t\t\t\tlinkedTaskId: linkedTodoId(),\n\t\t\t\t});\n\t\t\t\tregisterSubagentDispatch(runId, label);\n\t\t\t\ttaskStore.update(task.id, { status: \"in_progress\" });\n\t\t\t\ttry {\n\t\t\t\t\tconst dispatchResult = await cancelOnAbort(runId, () =>\n\t\t\t\t\t\tpool.resume(resumeId, params.prompt, {\n\t\t\t\t\t\t\tmodel: ctx.model?.id,\n\t\t\t\t\t\t\tprovider: ctx.model?.provider,\n\t\t\t\t\t\t\ttaskId: runId,\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\t\t// The session lives under the original task id; keep it as the resume handle.\n\t\t\t\t\treturn finalizeDispatchResult(dispatchResult, params.subagent_type, runId, task.id, resumeId);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tmarkDispatchFailed(task.id, runId);\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// The model has already decided to delegate and which agent to use; honor\n\t\t\t// it. Validate the requested agent against the registry (no routing gate).\n\t\t\tconst registry = loadAgentRegistry({ cwd: ctx.cwd });\n\t\t\tconst def = registry.get(params.subagent_type);\n\t\t\tif (!def) {\n\t\t\t\tconst available = registry\n\t\t\t\t\t.list()\n\t\t\t\t\t.map((a) => a.name)\n\t\t\t\t\t.join(\", \");\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Unknown subagent_type: \"${params.subagent_type}\". Available agents: ${available || \"(none)\"}.`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst summary = params.description?.trim() || summarize(params.prompt);\n\t\t\t// One roster row per dispatch, keyed by the (pre-allocated) pool task id.\n\t\t\t// Keying by agent TYPE made concurrent same-type runs share a single row:\n\t\t\t// their activity, state, and stats collided last-writer-wins. The inbox\n\t\t\t// already keys by task id; this aligns the panel to the same model. The\n\t\t\t// pool's task_progress events carry the task id, so patching by this id\n\t\t\t// routes live activity to the right row.\n\t\t\tconst poolTaskId = newDispatchTaskId();\n\t\t\tconst label = subagentInbox.nextLabel(params.subagent_type);\n\t\t\tconst task = taskStore.create(summary, {\n\t\t\t\tsource: \"subagent\",\n\t\t\t\tsubagentMode: params.subagent_type,\n\t\t\t\tagent: poolTaskId,\n\t\t\t\t// Tie this run to the plan item it executes (the single in_progress\n\t\t\t\t// TodoWrite task, when unambiguous) so the panel can nest it there.\n\t\t\t\tlinkedTaskId: linkedTodoId(),\n\t\t\t});\n\t\t\tregisterSubagentDispatch(poolTaskId, label);\n\t\t\ttaskStore.update(task.id, { status: \"in_progress\" });\n\t\t\t// Fork agents inherit the parent's conversation via a forked session.\n\t\t\tconst forkSessionFile = def.fork\n\t\t\t\t? resolveForkSessionFile(def, ctx.sessionManager?.getSessionFile(), ctx.cwd)\n\t\t\t\t: undefined;\n\n\t\t\t// `complexity` is passed as the model: the pool's spawn() already lets a\n\t\t\t// non-`inherit` agent model win, then resolves a category string (fast/\n\t\t\t// standard/capable) via settings.modelCategories. So a pinned-model agent\n\t\t\t// ignores complexity, and an `inherit` agent picks up the requested tier —\n\t\t\t// no settings lookup needed here.\n\t\t\tconst dispatchModel = params.complexity ?? ctx.model?.id;\n\n\t\t\t// Whether this call runs detached. The agent loop reads the tool's\n\t\t\t// `background` flag (the same predicate) to run execute() detached; we\n\t\t\t// recompute it here to choose the notify-and-pull return shape.\n\t\t\tconst isBackground = params.background ?? backgroundAgents.has(params.subagent_type);\n\n\t\t\tif (isBackground) {\n\t\t\t\t// Notify-and-pull: register the dispatch in the inbox under the\n\t\t\t\t// pre-allocated id, await it, retain the body in the inbox, and return a\n\t\t\t\t// compact notification (not the body). The model pulls it with TaskOutput.\n\t\t\t\tsubagentInbox.observe(pool);\n\t\t\t\tsubagentInbox.start(poolTaskId, label, params.subagent_type);\n\n\t\t\t\t// Warm path (opt-in): run on a reused RPC worker, retain the body in the\n\t\t\t\t// inbox, and return the same notify-and-pull shape as the cold path. An\n\t\t\t\t// infra failure falls through to the cold dispatch below.\n\t\t\t\tif (warmSubagentsEnabled() && !forkSessionFile) {\n\t\t\t\t\tconst warm = getWarmSubagentPool(ctx.cwd, availableModels);\n\t\t\t\t\tif (warm.isPoolable(params.subagent_type)) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst warmResult = await warm.dispatch(\n\t\t\t\t\t\t\t\tparams.prompt,\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tagentType: params.subagent_type,\n\t\t\t\t\t\t\t\t\tcwd: ctx.cwd,\n\t\t\t\t\t\t\t\t\tmodel: dispatchModel,\n\t\t\t\t\t\t\t\t\tprovider: ctx.model?.provider,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t(activity) => taskStore.patchAgent(poolTaskId, { activity }),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tconst dispatchResult = warmResultToTaskResult(warmResult, params.subagent_type, task.id);\n\t\t\t\t\t\t\tsubagentInbox.finish(poolTaskId, dispatchResult);\n\t\t\t\t\t\t\treturn finalizeDispatchResult(\n\t\t\t\t\t\t\t\tdispatchResult,\n\t\t\t\t\t\t\t\tparams.subagent_type,\n\t\t\t\t\t\t\t\tpoolTaskId,\n\t\t\t\t\t\t\t\ttask.id,\n\t\t\t\t\t\t\t\tpoolTaskId,\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttaskId: poolTaskId,\n\t\t\t\t\t\t\t\t\tlabel,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\tif (!(error instanceof WarmWorkerError)) throw error;\n\t\t\t\t\t\t\tconsole.error(`[WARM] ${params.subagent_type} fell back to cold spawn: ${error.message}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tconst dispatchResult = await cancelOnAbort(poolTaskId, () =>\n\t\t\t\t\t\tpool.dispatch(params.prompt, {\n\t\t\t\t\t\t\tforceAgent: params.subagent_type,\n\t\t\t\t\t\t\tcontext: \"\",\n\t\t\t\t\t\t\tmodel: dispatchModel,\n\t\t\t\t\t\t\tprovider: ctx.model?.provider,\n\t\t\t\t\t\t\tsessionFile: forkSessionFile,\n\t\t\t\t\t\t\ttaskId: poolTaskId,\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\t\tsubagentInbox.finish(poolTaskId, dispatchResult);\n\t\t\t\t\treturn finalizeDispatchResult(dispatchResult, params.subagent_type, poolTaskId, task.id, poolTaskId, {\n\t\t\t\t\t\ttaskId: poolTaskId,\n\t\t\t\t\t\tlabel,\n\t\t\t\t\t});\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconst reason = error instanceof Error ? error.message : String(error);\n\t\t\t\t\tmarkDispatchFailed(task.id, poolTaskId);\n\t\t\t\t\tsubagentInbox.fail(poolTaskId, reason);\n\t\t\t\t\t// A background dispatch reports failure as a compact notification, not a\n\t\t\t\t\t// thrown tool error — the call was already answered by a placeholder.\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcontent: [{ type: \"text\" as const, text: `${label} failed ✗ — ${reason}` }],\n\t\t\t\t\t\tdetails: {\n\t\t\t\t\t\t\tsubagent_type: params.subagent_type,\n\t\t\t\t\t\t\tok: false,\n\t\t\t\t\t\t\terror: reason,\n\t\t\t\t\t\t\ttaskId: task.id,\n\t\t\t\t\t\t\tpoolTaskId,\n\t\t\t\t\t\t\tbackground: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Warm path (opt-in): for an eligible foreground dispatch, run on a reused\n\t\t\t// RPC worker to skip the cold-boot. Fork agents (forkSessionFile set) and\n\t\t\t// non-poolable types are excluded. Any infra failure falls through to the\n\t\t\t// cold pool below, so enabling this can only change latency, never whether\n\t\t\t// the task can run.\n\t\t\tif (warmSubagentsEnabled() && !forkSessionFile) {\n\t\t\t\tconst warm = getWarmSubagentPool(ctx.cwd, availableModels);\n\t\t\t\tif (warm.isPoolable(params.subagent_type)) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst warmResult = await warm.dispatch(\n\t\t\t\t\t\t\tparams.prompt,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tagentType: params.subagent_type,\n\t\t\t\t\t\t\t\tcwd: ctx.cwd,\n\t\t\t\t\t\t\t\tmodel: dispatchModel,\n\t\t\t\t\t\t\t\tprovider: ctx.model?.provider,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t// Mirror the cold pool's live progress on the task panel roster so a\n\t\t\t\t\t\t\t// warm dispatch reads as busy (⋯ grep), not stuck.\n\t\t\t\t\t\t\t(activity) => taskStore.patchAgent(poolTaskId, { activity }),\n\t\t\t\t\t\t);\n\t\t\t\t\t\tconst dispatchResult = warmResultToTaskResult(warmResult, params.subagent_type, task.id);\n\t\t\t\t\t\treturn finalizeDispatchResult(dispatchResult, params.subagent_type, poolTaskId, task.id, undefined);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t// A genuine infra failure (worker crash/timeout) retries cold; any other\n\t\t\t\t\t\t// error is a real dispatch failure and propagates.\n\t\t\t\t\t\tif (!(error instanceof WarmWorkerError)) {\n\t\t\t\t\t\t\ttaskStore.update(task.id, { status: \"failed\" });\n\t\t\t\t\t\t\ttaskStore.patchAgent(poolTaskId, { state: \"failed\", activity: \"\" });\n\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconsole.error(`[WARM] ${params.subagent_type} fell back to cold spawn: ${error.message}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Foreground: block the turn and return the subagent's full answer inline.\n\t\t\ttry {\n\t\t\t\tconst dispatchResult = await cancelOnAbort(poolTaskId, () =>\n\t\t\t\t\tpool.dispatch(params.prompt, {\n\t\t\t\t\t\tforceAgent: params.subagent_type,\n\t\t\t\t\t\tcontext: \"\",\n\t\t\t\t\t\tmodel: dispatchModel,\n\t\t\t\t\t\tprovider: ctx.model?.provider,\n\t\t\t\t\t\tsessionFile: forkSessionFile,\n\t\t\t\t\t\ttaskId: poolTaskId,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\treturn finalizeDispatchResult(\n\t\t\t\t\tdispatchResult,\n\t\t\t\t\tparams.subagent_type,\n\t\t\t\t\tpoolTaskId,\n\t\t\t\t\ttask.id,\n\t\t\t\t\tdispatchResult.task_id,\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\tmarkDispatchFailed(task.id, poolTaskId);\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t},\n\n\t\trenderCall(args, theme) {\n\t\t\tconst type = args.subagent_type ?? \"agent\";\n\t\t\t// The [type] tag carries the agent's identity color — the same hue this\n\t\t\t// agent has in the task panel and TaskOutput — so a transcript full of\n\t\t\t// concurrent dispatches is scannable by color.\n\t\t\tconst text = theme.fg(\"toolTitle\", theme.bold(\"Agent \")) + theme.fg(agentColorFor(type), `[${type}]`);\n\t\t\treturn new Text(text, 0, 0);\n\t\t},\n\t});\n}\n\n/**\n * For a `fork: true` agent, fork the parent's session so the subagent inherits the\n * full parent conversation (and its prompt cache) instead of starting fresh. Returns\n * the forked session file to dispatch the child with, or undefined to fall back to a\n * fresh session (non-fork agent, no parent session, or an empty/invalid source).\n */\nexport function resolveForkSessionFile(\n\tdef: Pick<AgentDefinition, \"fork\">,\n\tparentSessionPath: string | undefined,\n\tcwd: string,\n): string | undefined {\n\tif (!def.fork || !parentSessionPath) return undefined;\n\ttry {\n\t\treturn SessionManager.forkFrom(parentSessionPath, cwd).getSessionFile();\n\t} catch {\n\t\t// Empty/invalid parent session: fall back to a fresh subagent session.\n\t\treturn undefined;\n\t}\n}\n\n/** Pre-allocated pool task id for a dispatch (matches the pool's own format). */\nfunction newDispatchTaskId(): string {\n\treturn `dispatch-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;\n}\n\n/**\n * The TodoWrite plan item this dispatch is (most plausibly) working on: the\n * single in_progress main-agent task. TodoWrite discipline keeps exactly one\n * item in_progress, so when that holds the link is unambiguous; with zero or\n * several in_progress items no link is recorded rather than guessing. Used to\n * nest the run under its plan item in the task panel's flat lens.\n */\nfunction linkedTodoId(): number | undefined {\n\tconst inProgress = taskStore\n\t\t.list()\n\t\t.filter(\n\t\t\t(t) =>\n\t\t\t\tt.source === undefined &&\n\t\t\t\tt.agent === undefined &&\n\t\t\t\tt.parentTaskId === undefined &&\n\t\t\t\tt.status === \"in_progress\",\n\t\t);\n\treturn inProgress.length === 1 ? inProgress[0]?.id : undefined;\n}\n\n/**\n * Register this dispatch in the task store's roster, keyed by its run id (the\n * pool task id) so concurrent runs of the same agent type each get their own\n * row, state, activity, and stats. The friendly label (\"explore#1\") names the\n * row the same way the inbox names background tasks.\n */\nfunction registerSubagentDispatch(runId: string, label: string): void {\n\ttaskStore.upsertAgent({ id: runId, name: label, role: \"subagent\", kind: \"subagent\", state: \"running\" });\n}\n\n/**\n * Catch-path bookkeeping: mark the dispatch failed unless it already settled.\n * finalizeDispatchResult records a terminal status (failed/cancelled) *before*\n * throwing, so a blanket \"failed\" here would clobber a cancellation with a\n * failure the moment the thrown error passed through.\n */\nfunction markDispatchFailed(taskStoreId: number, runId: string): void {\n\tconst current = taskStore.list().find((t) => t.id === taskStoreId);\n\tif (current && current.status !== \"pending\" && current.status !== \"in_progress\") return;\n\ttaskStore.update(taskStoreId, { status: \"failed\" });\n\ttaskStore.patchAgent(runId, { state: \"failed\", activity: \"\" });\n}\n\n/** Names of agents configured to run in the background (non-blocking). */\nfunction collectBackgroundAgentNames(cwd: string): Set<string> {\n\tconst names = new Set<string>();\n\tfor (const agent of loadAgentRegistry({ cwd }).list()) {\n\t\tif (agent.background) names.add(agent.name);\n\t}\n\treturn names;\n}\n\n/**\n * Merge a child subagent's task subtree into the parent's task store, rooting\n * each top-level node under the dispatching task (`parentTaskId`). Recurses so a\n * subagent that itself delegated shows its nested work — the subtree the child\n * could not surface across the process boundary on its own. Each node is its own\n * task (no key-by-type collapse), preserving the order the child created them.\n */\nfunction mergeChildTaskTree(nodes: readonly SubagentTaskNode[] | undefined, parentTaskId: number): void {\n\tif (!nodes) return;\n\ttaskStore.batch(() => {\n\t\tfor (const node of nodes) {\n\t\t\tconst created = taskStore.create(node.title, {\n\t\t\t\tsource: node.source,\n\t\t\t\tsubagentMode: node.subagentMode,\n\t\t\t\tparentTaskId,\n\t\t\t});\n\t\t\ttaskStore.update(created.id, { status: node.status, usage: node.usage });\n\t\t\tmergeChildTaskTree(node.children, created.id);\n\t\t}\n\t});\n}\n\n/**\n * Adapt a warm-worker run into the TaskResult shape finalizeDispatchResult\n * consumes, so the warm and cold paths share one finish/render path. A warm run\n * returns its answer inline (no result.json), so we synthesize an equivalent\n * SubagentResult with the answer as the summary and the pulled usage. The warm\n * path is clean (no persisted session), so there is no task_tree to merge and no\n * resume handle.\n */\nfunction warmResultToTaskResult(warm: WarmRunResult, agentType: string, taskStoreId: number): TaskResult {\n\tconst resultData: SubagentResultFile = {\n\t\tsummary: warm.summary || \"(subagent returned no output)\",\n\t\tfiles_changed: [],\n\t\tconfidence: warm.ok ? 1 : 0,\n\t\tstatus: warm.status,\n\t\tusage: warm.usage,\n\t};\n\tconst result: SubagentResult = {\n\t\ttask_id: String(taskStoreId),\n\t\tok: warm.ok,\n\t\tstdout: \"\",\n\t\tstderr: \"\",\n\t\texit_code: warm.ok ? 0 : 1,\n\t\tstatus: warm.status,\n\t\terror: warm.error,\n\t\tresult_data: resultData as unknown as Record<string, unknown>,\n\t};\n\treturn { handled_inline: false, agent_type: agentType, result };\n}\n\n/**\n * Update the task panel from a finished dispatch and shape the tool result.\n *\n * Foreground calls return the subagent's full answer inline and signal a hard\n * failure by throwing (the agent loop derives a tool's error state from a thrown\n * error). A background call passes `background`: the body already lives in the\n * inbox, so it returns a compact, self-contained notification (success or\n * failure) and never throws — the call was already answered by a placeholder.\n */\nfunction finalizeDispatchResult(\n\tdispatchResult: TaskResult,\n\tsubagentType: string,\n\trunAgentId: string,\n\ttaskStoreId: number,\n\tresumeHandle: string | undefined,\n\tbackground?: { taskId: string; label: string },\n): { content: Array<{ type: \"text\"; text: string }>; details: TaskToolDetails } {\n\tconst result = dispatchResult.result;\n\tconst resultData = result?.result_data as SubagentResultFile | undefined;\n\tconst usage = resultData?.usage;\n\n\t// Merge the child's own task subtree under the dispatching task so nested\n\t// delegation (depth >= 2) is visible in the subagents lens's task tree.\n\tmergeChildTaskTree(resultData?.task_tree, taskStoreId);\n\n\t// Roll this run's usage into its own roster row (rows are per-dispatch).\n\tif (usage) {\n\t\ttaskStore.addAgentStats(runAgentId, { input: usage.input, output: usage.output, cost: usage.cost });\n\t}\n\n\tif (!result || !result.ok) {\n\t\t// A user-initiated cancel is not a failure: it gets its own terminal\n\t\t// status so the panel shows ⊘ cancelled (dim) instead of ✗ failed (red).\n\t\tconst cancelled = result?.status === \"cancelled\";\n\t\tconst failNote = result?.usedInheritedModelFallback ? \"inherited-model retry failed\" : undefined;\n\t\ttaskStore.update(taskStoreId, { status: cancelled ? \"cancelled\" : \"failed\", usage, note: failNote });\n\t\ttaskStore.patchAgent(runAgentId, { state: cancelled ? \"cancelled\" : \"failed\", activity: \"\" });\n\t\tconst reason = result?.error ?? (result?.status ? `subagent ${result.status}` : \"unknown error\");\n\t\tif (background) {\n\t\t\tconst verdict = cancelled ? \"cancelled ⊘\" : \"failed ✗\";\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\", text: `${background.label} ${verdict} — ${reason}` }],\n\t\t\t\tdetails: {\n\t\t\t\t\tsubagent_type: subagentType,\n\t\t\t\t\tok: false,\n\t\t\t\t\terror: reason,\n\t\t\t\t\ttaskId: taskStoreId,\n\t\t\t\t\tpoolTaskId: background.taskId,\n\t\t\t\t\tbackground: true,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\tif (cancelled) {\n\t\t\tthrow new Error(`Subagent (${subagentType}) cancelled by user.`);\n\t\t}\n\t\tconst stderr = result?.stderr?.trim();\n\t\tthrow new Error(`Subagent (${subagentType}) failed: ${reason}${stderr ? `\\nstderr: ${stderr.slice(-500)}` : \"\"}`);\n\t}\n\n\t// Leave the task in the store with its final status; it stays visible in the\n\t// task panel until the next user message arrives. Surface a ⚠ cue when the run\n\t// fell back to the inherited model rather than emitting a chat message — and\n\t// clear any stale note otherwise (note is clearable via an explicit undefined).\n\tconst fallbackNote = dispatchResult.result?.usedInheritedModelFallback ? \"ran on inherited model\" : undefined;\n\ttaskStore.update(taskStoreId, { status: \"done\", usage, note: fallbackNote });\n\t// Rows are per-run, so this run settles to done regardless of siblings.\n\ttaskStore.patchAgent(runAgentId, { state: \"done\", activity: \"\" });\n\tlet answer = resultData?.summary || \"(subagent returned no output)\";\n\t// Partial results are resumable; surface the handle so the parent can continue.\n\tif (result.status === \"partial\" && resumeHandle) {\n\t\tanswer += `\\n\\n[Partial result. To continue this subagent, call Task again with resume_task_id=\"${resumeHandle}\".]`;\n\t}\n\n\tif (background) {\n\t\t// Compact notification: the body is retained in the inbox; the model pulls it\n\t\t// with TaskOutput. Keeps a wide swarm from flooding the parent's context.\n\t\tconst partial = result.status === \"partial\" ? \" (partial — resume to continue)\" : \"\";\n\t\tconst outstanding = subagentInbox.outstanding().length;\n\t\tconst tail = outstanding > 0 ? ` ${outstanding} still running.` : \"\";\n\t\tconst text =\n\t\t\t`${background.label} finished ✓${partial} — ${summarize(answer)}.${tail}\\n` +\n\t\t\t`Read the full result with TaskOutput(\"${background.label}\").`;\n\t\treturn {\n\t\t\tcontent: [{ type: \"text\", text }],\n\t\t\tdetails: {\n\t\t\t\tsubagent_type: subagentType,\n\t\t\t\tok: true,\n\t\t\t\ttaskId: taskStoreId,\n\t\t\t\tpoolTaskId: background.taskId,\n\t\t\t\tbackground: true,\n\t\t\t},\n\t\t};\n\t}\n\n\treturn {\n\t\tcontent: [{ type: \"text\", text: answer }],\n\t\tdetails: { subagent_type: subagentType, ok: true, taskId: taskStoreId, poolTaskId: resumeHandle },\n\t};\n}\n\nconst taskOutputParams = Type.Object({\n\ttask_id: Type.Optional(\n\t\tType.String({\n\t\t\tdescription:\n\t\t\t\t'Handle of a background subagent — its task_id or friendly label (e.g. \"explore#1\") from a Task notification. Omit (or set list:true) to see every background task.',\n\t\t}),\n\t),\n\tlist: Type.Optional(\n\t\tType.Boolean({\n\t\t\tdescription:\n\t\t\t\t\"List all background subagents with their status (running/done/failed/cancelled) and current activity. No result bodies are returned.\",\n\t\t}),\n\t),\n\twait: Type.Optional(\n\t\tType.Boolean({\n\t\t\tdescription:\n\t\t\t\t\"Block until the named task finishes — or, with no task_id, until all outstanding subagents finish (a swarm barrier) — before returning. Bounded by timeout_ms.\",\n\t\t}),\n\t),\n\ttimeout_ms: Type.Optional(\n\t\tType.Number({ description: \"Maximum time to block in wait mode, in milliseconds (default 120000).\" }),\n\t),\n});\n\ntype TaskOutputParams = Static<typeof taskOutputParams>;\n\nconst TASK_OUTPUT_DEFAULT_TIMEOUT_MS = 120_000;\n\n/**\n * Elapsed time a record has run (so far, or until it settled), in the same\n * format the task panel uses so the two surfaces always agree.\n */\nfunction recordElapsed(rec: InboxRecord): string {\n\tconst end = rec.endedAt ?? Date.now();\n\treturn formatDurationSecs((end - rec.startedAt) / 1000);\n}\n\n/** A compact roster of every known background subagent — status + activity, no bodies. */\nfunction formatTaskRoster(): { content: Array<{ type: \"text\"; text: string }>; details: TaskOutputDetails } {\n\tconst all = subagentInbox.list();\n\tconst outstanding = subagentInbox.outstanding().length;\n\tif (all.length === 0) {\n\t\treturn {\n\t\t\tcontent: [{ type: \"text\", text: \"No background subagents have been dispatched.\" }],\n\t\t\tdetails: { status: \"empty\", ok: true, outstanding: 0 },\n\t\t};\n\t}\n\tconst lines = all.map((r) => {\n\t\tconst when = recordElapsed(r);\n\t\tswitch (r.lifecycle) {\n\t\t\tcase \"running\":\n\t\t\t\treturn `- ${r.label} running ${when}${r.lastActivity ? ` · ${r.lastActivity}` : \"\"}`;\n\t\t\tcase \"done\":\n\t\t\t\treturn `- ${r.label} done (uncollected) ${when} — ${r.summaryLine ?? \"\"}`;\n\t\t\tcase \"collected\":\n\t\t\t\treturn `- ${r.label} collected ${when} — ${r.summaryLine ?? \"\"}`;\n\t\t\tcase \"cancelled\":\n\t\t\t\treturn `- ${r.label} cancelled ⊘ — ${r.error ?? \"cancelled by user\"}`;\n\t\t\tdefault:\n\t\t\t\treturn `- ${r.label} ${r.lifecycle} ✗ — ${r.error ?? \"unknown error\"}`;\n\t\t}\n\t});\n\tconst header = `${all.length} background subagent${all.length === 1 ? \"\" : \"s\"} (${outstanding} running):`;\n\tconst hint = all.some((r) => r.lifecycle === \"done\") ? '\\nRead a finished one with TaskOutput(\"<label>\").' : \"\";\n\treturn {\n\t\tcontent: [{ type: \"text\", text: `${header}\\n${lines.join(\"\\n\")}${hint}` }],\n\t\tdetails: { status: \"list\", ok: true, outstanding },\n\t};\n}\n\n/**\n * TaskOutput tool: check on background subagents and pull their results.\n *\n * Background `Task` calls don't push their body into the conversation — they\n * leave it in the inbox and post a compact notification. TaskOutput is how the\n * model pulls a body, checks liveness, or waits. It never throws on a valid\n * handle (an error tool result would only confuse the loop): it reports status\n * instead. Modes: `list` (roster), a `task_id` to read/check one, and `wait` to\n * block until one task — or all outstanding tasks — finish.\n */\nexport function createTaskOutputToolDefinition(): ToolDefinition {\n\treturn defineTool<typeof taskOutputParams, TaskOutputDetails>({\n\t\tname: \"TaskOutput\",\n\t\tlabel: \"TaskOutput\",\n\t\tdescription: [\n\t\t\t\"Check on background subagents dispatched via Task, and pull their results.\",\n\t\t\t'Pass a task_id/label (e.g. \"explore#1\") to read a finished subagent\\'s full result, or to see its status while it runs.',\n\t\t\t\"Set list:true (or omit task_id) to list every background subagent with its status and current activity.\",\n\t\t\t\"Set wait:true to block until that task finishes — or, with no task_id, until all outstanding subagents finish (a swarm barrier).\",\n\t\t\t\"It never errors on a valid handle: a running task reports status, a finished one returns its result, an already-read one says so.\",\n\t\t].join(\"\\n\"),\n\t\tpromptSnippet: \"check status / list / collect the results of background subagents\",\n\t\tparameters: taskOutputParams,\n\n\t\tasync execute(_toolCallId, params: TaskOutputParams, _signal, _onUpdate, ctx) {\n\t\t\t// Touch the pool so the inbox is wired to its progress stream for activity.\n\t\t\t// The pool is normally already created by a prior dispatch; pass available\n\t\t\t// models so a first-touch here still seeds category derivation.\n\t\t\tsubagentInbox.observe(getSubagentPool(ctx.cwd, ctx.modelRegistry?.getAvailable() ?? []));\n\t\t\tconst handle = params.task_id?.trim();\n\n\t\t\t// Barrier: wait for the target (or all outstanding) to settle first.\n\t\t\tif (params.wait) {\n\t\t\t\tconst timeout = params.timeout_ms ?? TASK_OUTPUT_DEFAULT_TIMEOUT_MS;\n\t\t\t\tif (handle) await subagentInbox.waitFor(handle, timeout);\n\t\t\t\telse await subagentInbox.waitForAll(timeout);\n\t\t\t}\n\n\t\t\t// Roster when asked, or when no specific task was named.\n\t\t\tif (params.list || !handle) {\n\t\t\t\treturn formatTaskRoster();\n\t\t\t}\n\n\t\t\tconst rec = subagentInbox.get(handle);\n\t\t\tif (!rec) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\" as const,\n\t\t\t\t\t\t\ttext: `No background task \"${handle}\". Call TaskOutput with list:true to see active tasks.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: { task_id: handle, status: \"unknown\", ok: false },\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tif (rec.lifecycle === \"running\") {\n\t\t\t\tconst activity = rec.lastActivity ? ` (currently: ${rec.lastActivity})` : \"\";\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\" as const,\n\t\t\t\t\t\t\ttext: `${rec.label} is still running — ${recordElapsed(rec)} elapsed${activity}. Call TaskOutput again, or with wait:true to block until it finishes.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: { task_id: handle, status: \"running\", ok: true },\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tif (rec.lifecycle === \"done\") {\n\t\t\t\tconst collected = subagentInbox.collect(handle);\n\t\t\t\tconst body = collected?.body ?? rec.summaryLine ?? \"(subagent returned no output)\";\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\" as const, text: body }],\n\t\t\t\t\tdetails: { task_id: handle, status: \"done\", ok: true },\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tif (rec.lifecycle === \"collected\") {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\" as const,\n\t\t\t\t\t\t\ttext: `${rec.label} was already delivered — ${rec.summaryLine ?? \"(no summary kept)\"}.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: { task_id: handle, status: \"collected\", ok: true },\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// failed / stalled / timeout / cancelled\n\t\t\tconst glyph = rec.lifecycle === \"cancelled\" ? \"⊘\" : \"✗\";\n\t\t\treturn {\n\t\t\t\tcontent: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"text\" as const,\n\t\t\t\t\t\ttext: `${rec.label} ${rec.lifecycle} ${glyph} — ${rec.error ?? \"unknown error\"}.`,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tdetails: { task_id: handle, status: rec.lifecycle, ok: false },\n\t\t\t};\n\t\t},\n\n\t\trenderCall(args, theme) {\n\t\t\tconst target = args.list ? \"list\" : String(args.task_id ?? \"\");\n\t\t\t// A friendly label (\"explore#1\") gets its agent's identity color so the\n\t\t\t// pull visually pairs with the dispatch that produced it; raw ids and\n\t\t\t// \"list\" stay dim.\n\t\t\tconst hashIdx = target.indexOf(\"#\");\n\t\t\tconst styledTarget =\n\t\t\t\thashIdx > 0 ? theme.fg(agentColorFor(target.slice(0, hashIdx)), target) : theme.fg(\"dim\", target);\n\t\t\tconst text =\n\t\t\t\ttheme.fg(\"toolTitle\", theme.bold(\"TaskOutput \")) +\n\t\t\t\tstyledTarget +\n\t\t\t\t(args.wait ? theme.fg(\"dim\", \" (wait)\") : \"\");\n\t\t\treturn new Text(text, 0, 0);\n\t\t},\n\n\t\trenderResult(result, _options, theme) {\n\t\t\t// Display-only framing/colorization (the text sent to the model stays\n\t\t\t// plain). A single-task pull renders as a result CARD — a status-stamped\n\t\t\t// header, a left spine down the body, and a closing corner — so a\n\t\t\t// collected result reads as a discrete artifact instead of blending into\n\t\t\t// the surrounding tool chatter. Roster/list responses keep the line\n\t\t\t// colorization.\n\t\t\tconst text = result.content\n\t\t\t\t.map((c) => (c.type === \"text\" ? c.text : \"\"))\n\t\t\t\t.filter(Boolean)\n\t\t\t\t.join(\"\\n\");\n\t\t\tif (!text) return new Text(\"\", 0, 0);\n\n\t\t\tconst details = result.details as TaskOutputDetails | undefined;\n\t\t\tconst cardStatus = details?.task_id ? details.status : undefined;\n\t\t\tif (cardStatus && cardStatus !== \"list\" && cardStatus !== \"empty\") {\n\t\t\t\tconst presentation: Record<\n\t\t\t\t\tstring,\n\t\t\t\t\t{ glyph: string; color: \"success\" | \"warning\" | \"error\" | \"muted\" | \"dim\" }\n\t\t\t\t> = {\n\t\t\t\t\tdone: { glyph: \"✓\", color: \"success\" },\n\t\t\t\t\trunning: { glyph: \"◐\", color: \"warning\" },\n\t\t\t\t\tcollected: { glyph: \"✓\", color: \"muted\" },\n\t\t\t\t\tcancelled: { glyph: \"⊘\", color: \"dim\" },\n\t\t\t\t\tunknown: { glyph: \"?\", color: \"dim\" },\n\t\t\t\t};\n\t\t\t\tconst { glyph, color } = presentation[cardStatus] ?? { glyph: \"✗\", color: \"error\" as const };\n\t\t\t\tconst label = details?.task_id ?? \"\";\n\t\t\t\tconst hashIdx = label.indexOf(\"#\");\n\t\t\t\tconst labelColor = hashIdx > 0 ? agentColorFor(label.slice(0, hashIdx)) : \"accent\";\n\n\t\t\t\t// Look up inbox record for elapsed time\n\t\t\t\tconst inboxRecord = subagentInbox.get(label);\n\t\t\t\tconst elapsed = inboxRecord ? (inboxRecord.endedAt ?? Date.now()) - inboxRecord.startedAt : undefined;\n\t\t\t\tconst elapsedText = elapsed ? ` ${formatDurationSecs(elapsed / 1000)}` : \"\";\n\n\t\t\t\t// Look up task for token count\n\t\t\t\tconst task = inboxRecord ? taskStore.list().find((t) => t.agent === inboxRecord.taskId) : undefined;\n\t\t\t\tconst totalTokens = task?.usage ? task.usage.input + task.usage.output : undefined;\n\t\t\t\tconst tokenText = totalTokens !== undefined ? ` ${formatTokens(totalTokens)}` : \"\";\n\n\t\t\t\tconst spine = (s: string) => theme.fg(\"borderMuted\", s);\n\t\t\t\tconst header =\n\t\t\t\t\t`${spine(\"╭\")} ${theme.fg(color, glyph)} ` +\n\t\t\t\t\t`${theme.bold(theme.fg(color, cardStatus))} ${theme.fg(labelColor, label)}${tokenText}${elapsedText}`;\n\t\t\t\tconst body = text\n\t\t\t\t\t.split(\"\\n\")\n\t\t\t\t\t.map((line) => `${spine(\"│\")} ${theme.fg(\"toolOutput\", line)}`)\n\t\t\t\t\t.join(\"\\n\");\n\t\t\t\treturn new Text(`${header}\\n${body}\\n${spine(\"╰\")}`, 0, 0);\n\t\t\t}\n\n\t\t\tconst rosterLine =\n\t\t\t\t/^- (\\S+)\\s{2}(running|done \\(uncollected\\)|collected|failed|stalled|timeout|cancelled)(.*)$/;\n\t\t\tconst styled = text\n\t\t\t\t.split(\"\\n\")\n\t\t\t\t.map((line) => {\n\t\t\t\t\tconst match = rosterLine.exec(line);\n\t\t\t\t\tif (!match) return theme.fg(\"toolOutput\", line);\n\t\t\t\t\tconst [, label, status, rest] = match as unknown as [string, string, string, string];\n\t\t\t\t\tconst hashIdx = label.indexOf(\"#\");\n\t\t\t\t\tconst labelColor = hashIdx > 0 ? agentColorFor(label.slice(0, hashIdx)) : \"accent\";\n\t\t\t\t\tconst statusColor =\n\t\t\t\t\t\tstatus === \"running\"\n\t\t\t\t\t\t\t? \"warning\"\n\t\t\t\t\t\t\t: status.startsWith(\"done\")\n\t\t\t\t\t\t\t\t? \"success\"\n\t\t\t\t\t\t\t\t: status === \"collected\" || status === \"cancelled\"\n\t\t\t\t\t\t\t\t\t? \"muted\"\n\t\t\t\t\t\t\t\t\t: \"error\";\n\t\t\t\t\treturn `- ${theme.fg(labelColor, label)} ${theme.fg(statusColor, status)}${theme.fg(\"dim\", rest)}`;\n\t\t\t\t})\n\t\t\t\t.join(\"\\n\");\n\t\t\treturn new Text(styled, 0, 0);\n\t\t},\n\t});\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-loader.d.ts","sourceRoot":"","sources":["../../../src/extensions/core/mcp-loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAcH,OAAO,KAAK,EAAE,YAAY,EAAuD,MAAM,gCAAgC,CAAC;AAkBxH,MAAM,WAAW,eAAe;IAC/B,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAC;IACb,6EAA6E;IAC7E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+CAA+C;IAC/C,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,kEAAkE;IAClE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,6FAA6F;IAC7F,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC;IAChC,8CAA8C;IAC9C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,oEAAoE;IACpE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,6EAA6E;IAC7E,UAAU,CAAC,EAAE,OAAO,CAAC;CACrB;AAgXD,wBAAgB,cAAc,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CAqOrD","sourcesContent":["/**\n * MCP server loader — discovers server configs (standard mcp.json locations,\n * hoocode's per-server JSON files, plugin registrations), connects via JSON-RPC\n * 2.0 over stdio (`command`), Streamable HTTP (`{ \"type\": \"http\", \"url\": ... }`),\n * or legacy SSE (`\"type\": \"sse\"`), and registers each server tool as\n * `mcp_<server>_<tool>`.\n *\n * Config sources (first-wins by server name):\n * 1. ~/.agents/mcp.json (user), ./.agents/mcp.json (project),\n * ~/.config/claude/mcp.json (Claude Desktop)\n * 2. ~/.hoocode/mcp-servers/*.json and ./.hoocode/mcp-servers/*.json\n * 3. MCP servers registered by plugins/extensions during load\n */\n\nimport { type ChildProcess, spawn } from \"node:child_process\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { readdir } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { createInterface } from \"node:readline\";\nimport type { AgentToolResult, AgentToolUpdateCallback, McpRemoteOptions } from \"@kolisachint/hoocode-agent-core\";\nimport { connectHttpMcpServer, summarizeArgs } from \"@kolisachint/hoocode-agent-core\";\nimport { Text } from \"@kolisachint/hoocode-tui\";\nimport { type Static, Type } from \"typebox\";\nimport { getHooCodeDir } from \"../../config.js\";\nimport { getExtensionMcpServers } from \"../../core/extension-mcp-servers.js\";\nimport type { ExtensionAPI, ExtensionContext, SessionStartEvent, ToolDefinition } from \"../../core/extensions/types.js\";\nimport { clearMcpServerStatuses, setMcpServerStatus } from \"../../core/mcp-status.js\";\nimport { deferMcpSchemas, subagentSkipMcp } from \"../../core/subagent-depth.js\";\nimport { taskStore } from \"../../core/task-store.js\";\nimport { type DeferredMcpToolEntry, formatDeferredCatalog, selectResolvable } from \"./mcp-deferred.js\";\n\nconst HOOCODE_DIR = getHooCodeDir();\n\ninterface McpToolDef {\n\tname: string;\n\tdescription: string;\n\tinputSchema?: {\n\t\ttype?: string;\n\t\tproperties?: Record<string, { type?: string; description?: string }>;\n\t\trequired?: string[];\n\t};\n}\n\nexport interface McpServerConfig {\n\t/** Unique server identifier used as prefix for registered tool names */\n\tname: string;\n\t/** Executable to spawn (stdio transport). One of command/url is required. */\n\tcommand?: string;\n\t/** Optional arguments passed to the command */\n\targs?: string[];\n\t/** Optional extra environment variables for the server process */\n\tenv?: Record<string, string>;\n\t/** Transport: \"stdio\" (default with command), \"http\" (Streamable HTTP), or \"sse\" (legacy) */\n\ttype?: \"stdio\" | \"http\" | \"sse\";\n\t/** Remote server URL (http/sse transports) */\n\turl?: string;\n\t/** Extra HTTP headers (e.g. Authorization) for remote transports */\n\theaders?: Record<string, string>;\n\t/** Run MCP tools in background by default (default: true for MCP servers) */\n\tbackground?: boolean;\n}\n\n/** Standard MCP config format used by Claude Desktop, Claude Code, VS Code / Copilot */\ninterface StandardMcpServerConfig {\n\tcommand?: string;\n\targs?: string[];\n\tenv?: Record<string, string>;\n\ttype?: \"stdio\" | \"http\" | \"sse\";\n\turl?: string;\n\theaders?: Record<string, string>;\n\tbackground?: boolean;\n}\n\ninterface StandardMcpConfig {\n\tmcpServers?: Record<string, StandardMcpServerConfig>;\n}\n\ninterface McpConnection {\n\trpc(method: string, params?: unknown, timeoutMs?: number): Promise<unknown>;\n\t/** Send a JSON-RPC notification (no id, no response expected). */\n\tnotify(method: string, params?: unknown): void;\n\tterminate(): void;\n}\n\nconst mcpConnections = new Map<string, McpConnection>();\n/**\n * Server configs retained by name so a tool call can transparently reconnect a\n * dropped server (process churn between turns, server exit, a racing teardown)\n * instead of permanently failing with \"not connected\".\n */\nconst mcpServerConfigs = new Map<string, McpServerConfig>();\n/** Remote-transport options (OAuth storage, auth callbacks) per server name. */\nconst mcpRemoteOptions = new Map<string, McpRemoteOptions>();\n/**\n * Servers with a browser authorization flow in flight. While a name is here,\n * a failed handshake must NOT tear the connection down (that would kill the\n * OAuth loopback listener); the auth-completion handler reconnects instead.\n */\nconst mcpAuthPending = new Set<string>();\n\n/** Timeout for the connection handshake (initialize / tools/list). Tool calls\n * themselves are left untimed since MCP tools can be long-running. */\nconst MCP_HANDSHAKE_TIMEOUT_MS = 15000;\n\nfunction spawnMcpServer(config: McpServerConfig & { command: string }): McpConnection {\n\tconst proc: ChildProcess = spawn(config.command, config.args ?? [], {\n\t\tenv: { ...process.env, ...(config.env ?? {}) },\n\t\tstdio: [\"pipe\", \"pipe\", \"pipe\"],\n\t});\n\n\tlet nextId = 1;\n\tconst pending = new Map<number, { resolve: (r: unknown) => void; reject: (e: Error) => void }>();\n\n\tconst rl = createInterface({ input: proc.stdout! });\n\trl.on(\"line\", (line) => {\n\t\tif (!line.trim()) return;\n\t\ttry {\n\t\t\tconst msg = JSON.parse(line) as {\n\t\t\t\tid?: number;\n\t\t\t\tresult?: unknown;\n\t\t\t\terror?: { message: string };\n\t\t\t};\n\t\t\tif (msg.id === undefined) return;\n\t\t\tconst cb = pending.get(msg.id);\n\t\t\tif (!cb) return;\n\t\t\tpending.delete(msg.id);\n\t\t\tif (msg.error) cb.reject(new Error(msg.error.message));\n\t\t\telse cb.resolve(msg.result);\n\t\t} catch {\n\t\t\t// ignore non-JSON server startup output\n\t\t}\n\t});\n\n\tproc.on(\"exit\", () => {\n\t\tfor (const cb of pending.values()) cb.reject(new Error(`MCP server \"${config.name}\" exited unexpectedly`));\n\t\tpending.clear();\n\t\tmcpConnections.delete(config.name);\n\t});\n\n\tfunction rpc(method: string, params?: unknown, timeoutMs?: number): Promise<unknown> {\n\t\tconst id = nextId++;\n\t\treturn new Promise<unknown>((resolve, reject) => {\n\t\t\tlet timer: NodeJS.Timeout | undefined;\n\t\t\tif (timeoutMs && timeoutMs > 0) {\n\t\t\t\ttimer = setTimeout(() => {\n\t\t\t\t\tif (pending.delete(id)) {\n\t\t\t\t\t\treject(new Error(`MCP server \"${config.name}\" timed out after ${timeoutMs}ms on ${method}`));\n\t\t\t\t\t}\n\t\t\t\t}, timeoutMs);\n\t\t\t\ttimer.unref?.();\n\t\t\t}\n\t\t\tpending.set(id, {\n\t\t\t\tresolve: (r) => {\n\t\t\t\t\tif (timer) clearTimeout(timer);\n\t\t\t\t\tresolve(r);\n\t\t\t\t},\n\t\t\t\treject: (e) => {\n\t\t\t\t\tif (timer) clearTimeout(timer);\n\t\t\t\t\treject(e);\n\t\t\t\t},\n\t\t\t});\n\t\t\tproc.stdin!.write(`${JSON.stringify({ jsonrpc: \"2.0\", id, method, params })}\\n`);\n\t\t});\n\t}\n\n\tfunction notify(method: string, params?: unknown): void {\n\t\tproc.stdin!.write(`${JSON.stringify({ jsonrpc: \"2.0\", method, params })}\\n`);\n\t}\n\n\treturn {\n\t\trpc,\n\t\tnotify,\n\t\tterminate: () => {\n\t\t\trl.close();\n\t\t\tproc.kill();\n\t\t},\n\t};\n}\n\n/** Remote servers use `{ type: \"http\" | \"sse\", url }`; stdio servers use `command`. */\nfunction isRemoteServer(config: McpServerConfig): boolean {\n\treturn config.type === \"http\" || config.type === \"sse\" || (!config.command && typeof config.url === \"string\");\n}\n\nfunction openMcpConnection(config: McpServerConfig): McpConnection {\n\tif (isRemoteServer(config)) {\n\t\tif (typeof config.url !== \"string\") {\n\t\t\tthrow new Error(`MCP server \"${config.name}\" has type \"${config.type}\" but no \"url\"`);\n\t\t}\n\t\treturn connectHttpMcpServer(\n\t\t\t{\n\t\t\t\tname: config.name,\n\t\t\t\turl: config.url,\n\t\t\t\theaders: config.headers,\n\t\t\t\ttype: config.type === \"sse\" ? \"sse\" : \"http\",\n\t\t\t},\n\t\t\tmcpRemoteOptions.get(config.name),\n\t\t);\n\t}\n\tif (typeof config.command !== \"string\") {\n\t\tthrow new Error(`MCP server \"${config.name}\" needs a \"command\" (stdio) or a \"url\" (http/sse)`);\n\t}\n\treturn spawnMcpServer(config as McpServerConfig & { command: string });\n}\n\nasync function connectMcpServer(config: McpServerConfig): Promise<{ conn: McpConnection; tools: McpToolDef[] }> {\n\tmcpConnections.get(config.name)?.terminate();\n\n\tconst conn = openMcpConnection(config);\n\tmcpConnections.set(config.name, conn);\n\n\ttry {\n\t\tawait conn.rpc(\n\t\t\t\"initialize\",\n\t\t\t{\n\t\t\t\tprotocolVersion: \"2024-11-05\",\n\t\t\t\tcapabilities: { tools: {} },\n\t\t\t\tclientInfo: { name: \"hoocode\", version: \"1.0.0\" },\n\t\t\t},\n\t\t\tMCP_HANDSHAKE_TIMEOUT_MS,\n\t\t);\n\n\t\t// Per the MCP spec the client must acknowledge a successful initialize with the\n\t\t// initialized notification before issuing further requests; strict servers gate\n\t\t// tools/call on it.\n\t\tconn.notify(\"notifications/initialized\");\n\n\t\tconst toolsResult = (await conn.rpc(\"tools/list\", {}, MCP_HANDSHAKE_TIMEOUT_MS)) as {\n\t\t\ttools?: McpToolDef[];\n\t\t};\n\t\treturn { conn, tools: toolsResult.tools ?? [] };\n\t} catch (error) {\n\t\t// Don't leave a half-connected entry behind: remote transports have no\n\t\t// process-exit event to evict them, so getOrConnectMcp would keep handing\n\t\t// out the dead connection instead of reconnecting. Exception: a pending\n\t\t// browser authorization — terminating would kill the OAuth loopback\n\t\t// listener; the auth-completion handler reconnects that server itself.\n\t\tif (!mcpAuthPending.has(config.name)) {\n\t\t\tconn.terminate();\n\t\t\tif (mcpConnections.get(config.name) === conn) mcpConnections.delete(config.name);\n\t\t}\n\t\tthrow error;\n\t}\n}\n\n/**\n * Return a live connection for a server, lazily reconnecting from the retained\n * config when the previous connection was torn down. Returns undefined only when\n * no config is known or a fresh connect attempt fails.\n */\nasync function getOrConnectMcp(name: string): Promise<McpConnection | undefined> {\n\tconst existing = mcpConnections.get(name);\n\tif (existing) return existing;\n\tconst config = mcpServerConfigs.get(name);\n\tif (!config) return undefined;\n\ttry {\n\t\tconst { conn } = await connectMcpServer(config);\n\t\treturn conn;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nlet mcpExitCleanupInstalled = false;\n/** Kill spawned MCP servers when the host process exits so they don't linger as\n * orphans (their stdin merely goes idle, which doesn't terminate them). */\nfunction installMcpExitCleanup(): void {\n\tif (mcpExitCleanupInstalled) return;\n\tmcpExitCleanupInstalled = true;\n\tprocess.once(\"exit\", () => {\n\t\tfor (const conn of mcpConnections.values()) {\n\t\t\ttry {\n\t\t\t\tconn.terminate();\n\t\t\t} catch {\n\t\t\t\t// best-effort cleanup\n\t\t\t}\n\t\t}\n\t\tmcpConnections.clear();\n\t});\n}\n\nfunction buildMcpSchema(tool: McpToolDef): ReturnType<typeof Type.Object> {\n\tconst props = tool.inputSchema?.properties ?? {};\n\tconst required = new Set(tool.inputSchema?.required ?? []);\n\tconst shape: Record<string, ReturnType<typeof Type.String>> = {};\n\n\tfor (const [key, prop] of Object.entries(props)) {\n\t\tlet field: ReturnType<typeof Type.String>;\n\t\tswitch (prop.type) {\n\t\t\tcase \"number\":\n\t\t\tcase \"integer\":\n\t\t\t\tfield = Type.Number({ description: prop.description }) as unknown as ReturnType<typeof Type.String>;\n\t\t\t\tbreak;\n\t\t\tcase \"boolean\":\n\t\t\t\tfield = Type.Boolean({ description: prop.description }) as unknown as ReturnType<typeof Type.String>;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tfield = Type.String({ description: prop.description });\n\t\t}\n\t\tshape[key] = required.has(key) ? field : (Type.Optional(field) as unknown as ReturnType<typeof Type.String>);\n\t}\n\n\treturn Type.Object(shape);\n}\n\n/**\n * Parse standard MCP config format (used by Claude Desktop, VS Code, etc.)\n * into hoocode's McpServerConfig format.\n */\nfunction parseStandardMcpConfig(config: StandardMcpConfig, _source: string): McpServerConfig[] {\n\tif (!config.mcpServers) return [];\n\n\tconst servers: McpServerConfig[] = [];\n\tfor (const [name, serverConfig] of Object.entries(config.mcpServers)) {\n\t\tservers.push({\n\t\t\tname,\n\t\t\tcommand: serverConfig.command,\n\t\t\targs: serverConfig.args,\n\t\t\tenv: serverConfig.env,\n\t\t\ttype: serverConfig.type,\n\t\t\turl: serverConfig.url,\n\t\t\theaders: serverConfig.headers,\n\t\t\tbackground: serverConfig.background,\n\t\t});\n\t}\n\treturn servers;\n}\n\n/**\n * Load MCP servers from a standard mcp.json file.\n * Returns an array of McpServerConfig, or empty array if file doesn't exist or is invalid.\n */\nfunction loadStandardMcpFile(filePath: string): McpServerConfig[] {\n\tif (!existsSync(filePath)) return [];\n\n\ttry {\n\t\tconst content = readFileSync(filePath, \"utf8\");\n\t\tconst config = JSON.parse(content) as StandardMcpConfig;\n\t\treturn parseStandardMcpConfig(config, filePath);\n\t} catch {\n\t\treturn [];\n\t}\n}\n\n/**\n * Build the full {@link ToolDefinition} for one MCP tool — the complete JSON\n * schema plus the connect/execute machinery. Shared by the eager path (register\n * every tool up front) and the deferred path (materialize on resolve), so both\n * produce identical, callable tools.\n */\nfunction buildMcpToolDefinition(serverConfig: McpServerConfig, tool: McpToolDef): ToolDefinition {\n\tconst toolName = `mcp_${serverConfig.name}_${tool.name}`;\n\tconst schema = buildMcpSchema(tool);\n\tconst capturedServer = serverConfig.name;\n\tconst capturedTool = tool.name;\n\t// MCP tools default to background mode since they are external processes with potential high latency\n\tconst isBackground = serverConfig.background !== false;\n\n\treturn {\n\t\tname: toolName,\n\t\tlabel: `[MCP] ${serverConfig.name} › ${tool.name}`,\n\t\tdescription: tool.description,\n\t\tparameters: schema,\n\t\tbackground: isBackground,\n\t\t// Render a clean, prefixed title in chat — `MCP [server › tool] <args>` —\n\t\t// parallel to the subagent `Task [type] <desc>` line. Without this the\n\t\t// ToolExecutionComponent falls back to the raw `mcp_<server>_<tool>` name.\n\t\t// The args summary reuses the same helper as the background start/finish\n\t\t// messages so the chat title stays in sync with them.\n\t\trenderCall(args, theme) {\n\t\t\tconst summary = summarizeArgs((args ?? {}) as Record<string, unknown>);\n\t\t\tconst text =\n\t\t\t\ttheme.fg(\"toolTitle\", theme.bold(\"MCP \")) +\n\t\t\t\ttheme.fg(\"accent\", `[${capturedServer} › ${capturedTool}]`) +\n\t\t\t\t(summary ? theme.fg(\"dim\", ` ${summary}`) : \"\");\n\t\t\treturn new Text(text, 0, 0);\n\t\t},\n\t\tasync execute(\n\t\t\t_toolCallId: string,\n\t\t\tparams: Static<typeof schema>,\n\t\t\tsignal: AbortSignal,\n\t\t\t_onUpdate: AgentToolUpdateCallback,\n\t\t): Promise<AgentToolResult<undefined>> {\n\t\t\t// Background MCP tools get a task store entry so they appear in the task pane.\n\t\t\t// Foreground tools skip this (their result is awaited inline). The server\n\t\t\t// name rides in subagentMode and becomes the row's `[server]` origin tag;\n\t\t\t// the title carries just the tool.\n\t\t\tconst task = isBackground\n\t\t\t\t? taskStore.create(capturedTool, { source: \"mcp\", subagentMode: capturedServer })\n\t\t\t\t: undefined;\n\t\t\tif (task) taskStore.update(task.id, { status: \"in_progress\" });\n\n\t\t\t// Lazily (re)connect: a dropped connection (server exit, process churn\n\t\t\t// between turns, a racing teardown) should transparently reconnect from\n\t\t\t// the retained config rather than permanently fail with \"not connected\".\n\t\t\tconst activeConn = await getOrConnectMcp(capturedServer);\n\t\t\tif (!activeConn) {\n\t\t\t\tif (task) taskStore.update(task.id, { status: \"failed\" });\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{ type: \"text\", text: `MCP server \"${capturedServer}\" is not connected (reconnect attempt failed)` },\n\t\t\t\t\t],\n\t\t\t\t\tdetails: undefined,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst abortPromise = new Promise<never>((_, reject) => {\n\t\t\t\t\tsignal.addEventListener(\"abort\", () => reject(new Error(\"Aborted\")));\n\t\t\t\t});\n\n\t\t\t\tconst result = await Promise.race([\n\t\t\t\t\tactiveConn.rpc(\"tools/call\", { name: capturedTool, arguments: params }),\n\t\t\t\t\tabortPromise,\n\t\t\t\t]);\n\n\t\t\t\tif (task) taskStore.update(task.id, { status: \"done\" });\n\t\t\t\treturn { content: [{ type: \"text\", text: JSON.stringify(result, null, 2) }], details: undefined };\n\t\t\t} catch (error) {\n\t\t\t\tif (task) taskStore.update(task.id, { status: \"failed\" });\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t},\n\t} as ToolDefinition;\n}\n\nconst RESOLVE_MCP_TOOLS_NAME = \"ResolveMcpTools\";\n\nexport function setupMcpLoader(pi: ExtensionAPI): void {\n\tpi.on(\"session_start\", async (_event: SessionStartEvent, ctx: ExtensionContext) => {\n\t\t// A spawned subagent whose tool allowlist has no MCP tools is told by its\n\t\t// parent to skip server connection entirely (see SUBAGENT_SKIP_MCP_ENV).\n\t\t// Each connect is a ~15s-timeout handshake; doing it for a subagent that can\n\t\t// never call the tools is pure startup latency.\n\t\tif (subagentSkipMcp()) return;\n\n\t\tinstallMcpExitCleanup();\n\t\t// Rebuild the status registry from scratch: a reload or session switch runs\n\t\t// this pass again and the startup summary must not double-count.\n\t\tclearMcpServerStatuses();\n\t\tconst allServerConfigs: McpServerConfig[] = [];\n\t\tconst seenNames = new Set<string>();\n\n\t\t// 1. Load from standard mcp.json locations\n\t\t// User-level: ~/.agents/mcp.json\n\t\tconst userAgentsConfig = loadStandardMcpFile(join(homedir(), \".agents\", \"mcp.json\"));\n\t\tfor (const config of userAgentsConfig) {\n\t\t\tif (!seenNames.has(config.name)) {\n\t\t\t\tseenNames.add(config.name);\n\t\t\t\tallServerConfigs.push(config);\n\t\t\t}\n\t\t}\n\n\t\t// Project-level: ./.agents/mcp.json\n\t\tconst projectAgentsConfig = loadStandardMcpFile(join(ctx.cwd, \".agents\", \"mcp.json\"));\n\t\tfor (const config of projectAgentsConfig) {\n\t\t\tif (!seenNames.has(config.name)) {\n\t\t\t\tseenNames.add(config.name);\n\t\t\t\tallServerConfigs.push(config);\n\t\t\t}\n\t\t}\n\n\t\t// Claude Desktop: ~/.config/claude/mcp.json\n\t\tconst claudeDesktopConfig = loadStandardMcpFile(join(homedir(), \".config\", \"claude\", \"mcp.json\"));\n\t\tfor (const config of claudeDesktopConfig) {\n\t\t\tif (!seenNames.has(config.name)) {\n\t\t\t\tseenNames.add(config.name);\n\t\t\t\tallServerConfigs.push(config);\n\t\t\t}\n\t\t}\n\n\t\t// 2. Load from hoocode's per-server format (existing behavior)\n\t\tconst searchDirs = [join(HOOCODE_DIR, \"mcp-servers\"), join(ctx.cwd, \".hoocode\", \"mcp-servers\")];\n\n\t\tfor (const dir of searchDirs) {\n\t\t\tif (!existsSync(dir)) continue;\n\n\t\t\tlet files: string[];\n\t\t\ttry {\n\t\t\t\tfiles = (await readdir(dir)).filter((f) => f.endsWith(\".json\"));\n\t\t\t} catch {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tfor (const file of files) {\n\t\t\t\tconst cfgPath = join(dir, file);\n\t\t\t\tlet serverConfig: McpServerConfig;\n\n\t\t\t\ttry {\n\t\t\t\t\tserverConfig = JSON.parse(readFileSync(cfgPath, \"utf8\")) as McpServerConfig;\n\t\t\t\t\tif (!serverConfig.name || (!serverConfig.command && !serverConfig.url)) {\n\t\t\t\t\t\tctx.ui.notify(`MCP: config \"${file}\" is missing required \"name\" or \"command\"/\"url\"`, \"warning\");\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t} catch (err) {\n\t\t\t\t\tctx.ui.notify(`MCP: failed to parse \"${file}\": ${String(err)}`, \"error\");\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Skip if already loaded from standard config\n\t\t\t\tif (seenNames.has(serverConfig.name)) continue;\n\t\t\t\tseenNames.add(serverConfig.name);\n\t\t\t\tallServerConfigs.push(serverConfig);\n\t\t\t}\n\t\t}\n\n\t\t// 2b. Load from plugins/extensions that registered MCP servers during load.\n\t\tfor (const entry of getExtensionMcpServers()) {\n\t\t\tfor (const serverConfig of parseStandardMcpConfig(\n\t\t\t\t{ mcpServers: entry.mcpServers },\n\t\t\t\t`plugin:${entry.source}`,\n\t\t\t)) {\n\t\t\t\tif (seenNames.has(serverConfig.name)) continue;\n\t\t\t\tseenNames.add(serverConfig.name);\n\t\t\t\tallServerConfigs.push(serverConfig);\n\t\t\t}\n\t\t}\n\n\t\t// Deferral (spec §2): inject MCP tool names only and materialize each schema\n\t\t// on demand via ResolveMcpTools. Default-on and top-level only — a subagent that\n\t\t// needs MCP has this env cleared, so it eager-registers its allowlisted tools\n\t\t// at dispatch (the dispatch ↔ schema interaction) and they are immediately callable.\n\t\tconst defer = deferMcpSchemas();\n\t\tconst deferredCatalog: DeferredMcpToolEntry[] = [];\n\t\t// Retain each deferred tool's raw definition + config so ResolveMcpTools can\n\t\t// build the full ToolDefinition on request.\n\t\tconst deferredByName = new Map<string, { serverConfig: McpServerConfig; tool: McpToolDef }>();\n\t\tconst resolvedNames = new Set<string>();\n\n\t\t// Remote servers get OAuth support: tokens persist under\n\t\t// ~/.hoocode/mcp-auth, and when a server demands interactive (browser)\n\t\t// authorization the handshake fails fast while the flow keeps running in\n\t\t// the background — on completion the server is reconnected and its tools\n\t\t// registered (eagerly, since the deferred catalog is already sealed).\n\t\tconst buildRemoteOptions = (serverConfig: McpServerConfig): McpRemoteOptions => ({\n\t\t\tauthStorageDir: join(HOOCODE_DIR, \"mcp-auth\"),\n\t\t\tonAuthRequired: (authorizationUrl, completed) => {\n\t\t\t\tmcpAuthPending.add(serverConfig.name);\n\t\t\t\tctx.ui.notify(\n\t\t\t\t\t`MCP: \"${serverConfig.name}\" requires authorization — complete the sign-in opened in your browser` +\n\t\t\t\t\t\t(authorizationUrl ? `: ${authorizationUrl}` : \"\"),\n\t\t\t\t\t\"warning\",\n\t\t\t\t);\n\t\t\t\tcompleted\n\t\t\t\t\t.then(async () => {\n\t\t\t\t\t\tmcpAuthPending.delete(serverConfig.name);\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst { tools } = await connectMcpServer(serverConfig);\n\t\t\t\t\t\t\tfor (const tool of tools) pi.registerTool(buildMcpToolDefinition(serverConfig, tool));\n\t\t\t\t\t\t\tsetMcpServerStatus({\n\t\t\t\t\t\t\t\tname: serverConfig.name,\n\t\t\t\t\t\t\t\ttoolCount: tools.length,\n\t\t\t\t\t\t\t\tbackground: serverConfig.background !== false,\n\t\t\t\t\t\t\t\tdeferred: false,\n\t\t\t\t\t\t\t\tstate: \"connected\",\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\t\t`MCP: connected \"${serverConfig.name}\" after authorization (${tools.length} tool${tools.length === 1 ? \"\" : \"s\"})`,\n\t\t\t\t\t\t\t\t\"info\",\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\t\t`MCP: failed to connect \"${serverConfig.name}\" after authorization: ${String(err)}`,\n\t\t\t\t\t\t\t\t\"error\",\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t\t.catch((err: unknown) => {\n\t\t\t\t\t\tmcpAuthPending.delete(serverConfig.name);\n\t\t\t\t\t\tctx.ui.notify(`MCP: authorization for \"${serverConfig.name}\" failed: ${String(err)}`, \"error\");\n\t\t\t\t\t});\n\t\t\t},\n\t\t});\n\n\t\t// 3. Connect to all servers and register (or defer) tools\n\t\tfor (const serverConfig of allServerConfigs) {\n\t\t\t// Retain the config so a tool call can lazily reconnect a dropped server.\n\t\t\tmcpServerConfigs.set(serverConfig.name, serverConfig);\n\t\t\tmcpRemoteOptions.set(serverConfig.name, buildRemoteOptions(serverConfig));\n\t\t\ttry {\n\t\t\t\tconst { tools } = await connectMcpServer(serverConfig);\n\n\t\t\t\tfor (const tool of tools) {\n\t\t\t\t\tconst toolName = `mcp_${serverConfig.name}_${tool.name}`;\n\t\t\t\t\tif (defer) {\n\t\t\t\t\t\tdeferredCatalog.push({ toolName, server: serverConfig.name, description: tool.description });\n\t\t\t\t\t\tdeferredByName.set(toolName, { serverConfig, tool });\n\t\t\t\t\t} else {\n\t\t\t\t\t\tpi.registerTool(buildMcpToolDefinition(serverConfig, tool));\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// A successful connect is reported by the startup resource summary (one\n\t\t\t\t// `mcp` cell plus a details row), not as a transient line above it.\n\t\t\t\tsetMcpServerStatus({\n\t\t\t\t\tname: serverConfig.name,\n\t\t\t\t\ttoolCount: tools.length,\n\t\t\t\t\tbackground: serverConfig.background !== false,\n\t\t\t\t\tdeferred: defer,\n\t\t\t\t\tstate: \"connected\",\n\t\t\t\t});\n\t\t\t} catch (err) {\n\t\t\t\tif (mcpAuthPending.has(serverConfig.name)) {\n\t\t\t\t\tsetMcpServerStatus({\n\t\t\t\t\t\tname: serverConfig.name,\n\t\t\t\t\t\ttoolCount: 0,\n\t\t\t\t\t\tbackground: serverConfig.background !== false,\n\t\t\t\t\t\tdeferred: defer,\n\t\t\t\t\t\tstate: \"authorizing\",\n\t\t\t\t\t});\n\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t`MCP: \"${serverConfig.name}\" is waiting for browser authorization; tools will register once it completes`,\n\t\t\t\t\t\t\"info\",\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tctx.ui.notify(`MCP: failed to connect \"${serverConfig.name}\": ${String(err)}`, \"error\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// 4. In deferred mode, register the single resolver that materializes schemas on demand.\n\t\tif (defer && deferredCatalog.length > 0) {\n\t\t\tconst resolveParams = Type.Object(\n\t\t\t\t{\n\t\t\t\t\tnames: Type.Array(Type.String(), {\n\t\t\t\t\t\tdescription: \"MCP tool names to make callable (e.g. 'mcp_github_create_pr' or 'create_pr').\",\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t\t{ additionalProperties: false },\n\t\t\t);\n\t\t\tpi.registerTool({\n\t\t\t\tname: RESOLVE_MCP_TOOLS_NAME,\n\t\t\t\tlabel: RESOLVE_MCP_TOOLS_NAME,\n\t\t\t\tdescription:\n\t\t\t\t\t\"MCP tools are connected but their schemas are loaded on demand to keep context small. Call this with the tool name(s) you need to make them callable, then call the tool(s). Available MCP tools:\\n\" +\n\t\t\t\t\tformatDeferredCatalog(deferredCatalog),\n\t\t\t\tpromptSnippet: \"Resolve deferred MCP tool schemas by name before calling them.\",\n\t\t\t\tparameters: resolveParams,\n\t\t\t\tasync execute(_toolCallId: string, params: Static<typeof resolveParams>) {\n\t\t\t\t\tconst matched = selectResolvable(deferredCatalog, params.names ?? []);\n\t\t\t\t\tconst newlyResolved: string[] = [];\n\t\t\t\t\tfor (const entry of matched) {\n\t\t\t\t\t\tif (resolvedNames.has(entry.toolName)) continue;\n\t\t\t\t\t\tconst raw = deferredByName.get(entry.toolName);\n\t\t\t\t\t\tif (!raw) continue;\n\t\t\t\t\t\tpi.registerTool(buildMcpToolDefinition(raw.serverConfig, raw.tool));\n\t\t\t\t\t\tresolvedNames.add(entry.toolName);\n\t\t\t\t\t\tnewlyResolved.push(entry.toolName);\n\t\t\t\t\t}\n\t\t\t\t\tconst text = matched.length\n\t\t\t\t\t\t? `Resolved ${newlyResolved.length} MCP tool(s): ${matched.map((m) => m.toolName).join(\", \")}. They are now callable.`\n\t\t\t\t\t\t: `No MCP tools matched: ${(params.names ?? []).join(\", \") || \"(none)\"}. See ResolveMcpTools for the catalog.`;\n\t\t\t\t\treturn { content: [{ type: \"text\" as const, text }], details: undefined };\n\t\t\t\t},\n\t\t\t} as ToolDefinition);\n\t\t}\n\t});\n}\n"]}
|
|
1
|
+
{"version":3,"file":"mcp-loader.d.ts","sourceRoot":"","sources":["../../../src/extensions/core/mcp-loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAcH,OAAO,KAAK,EAAE,YAAY,EAAuD,MAAM,gCAAgC,CAAC;AAuBxH,MAAM,WAAW,eAAe;IAC/B,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAC;IACb,6EAA6E;IAC7E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+CAA+C;IAC/C,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,kEAAkE;IAClE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,6FAA6F;IAC7F,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC;IAChC,8CAA8C;IAC9C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,oEAAoE;IACpE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,6EAA6E;IAC7E,UAAU,CAAC,EAAE,OAAO,CAAC;CACrB;AAiZD,wBAAgB,cAAc,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CAqOrD","sourcesContent":["/**\n * MCP server loader — discovers server configs (standard mcp.json locations,\n * hoocode's per-server JSON files, plugin registrations), connects via JSON-RPC\n * 2.0 over stdio (`command`), Streamable HTTP (`{ \"type\": \"http\", \"url\": ... }`),\n * or legacy SSE (`\"type\": \"sse\"`), and registers each server tool as\n * `mcp_<server>_<tool>`.\n *\n * Config sources (first-wins by server name):\n * 1. ~/.agents/mcp.json (user), ./.agents/mcp.json (project),\n * ~/.config/claude/mcp.json (Claude Desktop)\n * 2. ~/.hoocode/mcp-servers/*.json and ./.hoocode/mcp-servers/*.json\n * 3. MCP servers registered by plugins/extensions during load\n */\n\nimport { type ChildProcess, spawn } from \"node:child_process\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { readdir } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { createInterface } from \"node:readline\";\nimport type { AgentToolResult, AgentToolUpdateCallback, McpRemoteOptions } from \"@kolisachint/hoocode-agent-core\";\nimport { connectHttpMcpServer, summarizeArgs } from \"@kolisachint/hoocode-agent-core\";\nimport { Text } from \"@kolisachint/hoocode-tui\";\nimport { type Static, Type } from \"typebox\";\nimport { getHooCodeDir } from \"../../config.js\";\nimport { getExtensionMcpServers } from \"../../core/extension-mcp-servers.js\";\nimport type { ExtensionAPI, ExtensionContext, SessionStartEvent, ToolDefinition } from \"../../core/extensions/types.js\";\nimport { formatDurationSecs } from \"../../core/format-duration.js\";\nimport { clearMcpServerStatuses, setMcpServerStatus } from \"../../core/mcp-status.js\";\nimport { deferMcpSchemas, subagentSkipMcp } from \"../../core/subagent-depth.js\";\nimport { taskStore } from \"../../core/task-store.js\";\nimport { type DeferredMcpToolEntry, formatDeferredCatalog, selectResolvable } from \"./mcp-deferred.js\";\n\nconst HOOCODE_DIR = getHooCodeDir();\n\ninterface McpToolDetails {\n\telapsed?: number;\n}\n\ninterface McpToolDef {\n\tname: string;\n\tdescription: string;\n\tinputSchema?: {\n\t\ttype?: string;\n\t\tproperties?: Record<string, { type?: string; description?: string }>;\n\t\trequired?: string[];\n\t};\n}\n\nexport interface McpServerConfig {\n\t/** Unique server identifier used as prefix for registered tool names */\n\tname: string;\n\t/** Executable to spawn (stdio transport). One of command/url is required. */\n\tcommand?: string;\n\t/** Optional arguments passed to the command */\n\targs?: string[];\n\t/** Optional extra environment variables for the server process */\n\tenv?: Record<string, string>;\n\t/** Transport: \"stdio\" (default with command), \"http\" (Streamable HTTP), or \"sse\" (legacy) */\n\ttype?: \"stdio\" | \"http\" | \"sse\";\n\t/** Remote server URL (http/sse transports) */\n\turl?: string;\n\t/** Extra HTTP headers (e.g. Authorization) for remote transports */\n\theaders?: Record<string, string>;\n\t/** Run MCP tools in background by default (default: true for MCP servers) */\n\tbackground?: boolean;\n}\n\n/** Standard MCP config format used by Claude Desktop, Claude Code, VS Code / Copilot */\ninterface StandardMcpServerConfig {\n\tcommand?: string;\n\targs?: string[];\n\tenv?: Record<string, string>;\n\ttype?: \"stdio\" | \"http\" | \"sse\";\n\turl?: string;\n\theaders?: Record<string, string>;\n\tbackground?: boolean;\n}\n\ninterface StandardMcpConfig {\n\tmcpServers?: Record<string, StandardMcpServerConfig>;\n}\n\ninterface McpConnection {\n\trpc(method: string, params?: unknown, timeoutMs?: number): Promise<unknown>;\n\t/** Send a JSON-RPC notification (no id, no response expected). */\n\tnotify(method: string, params?: unknown): void;\n\tterminate(): void;\n}\n\nconst mcpConnections = new Map<string, McpConnection>();\n/**\n * Server configs retained by name so a tool call can transparently reconnect a\n * dropped server (process churn between turns, server exit, a racing teardown)\n * instead of permanently failing with \"not connected\".\n */\nconst mcpServerConfigs = new Map<string, McpServerConfig>();\n/** Remote-transport options (OAuth storage, auth callbacks) per server name. */\nconst mcpRemoteOptions = new Map<string, McpRemoteOptions>();\n/**\n * Servers with a browser authorization flow in flight. While a name is here,\n * a failed handshake must NOT tear the connection down (that would kill the\n * OAuth loopback listener); the auth-completion handler reconnects instead.\n */\nconst mcpAuthPending = new Set<string>();\n\n/** Timeout for the connection handshake (initialize / tools/list). Tool calls\n * themselves are left untimed since MCP tools can be long-running. */\nconst MCP_HANDSHAKE_TIMEOUT_MS = 15000;\n\nfunction spawnMcpServer(config: McpServerConfig & { command: string }): McpConnection {\n\tconst proc: ChildProcess = spawn(config.command, config.args ?? [], {\n\t\tenv: { ...process.env, ...(config.env ?? {}) },\n\t\tstdio: [\"pipe\", \"pipe\", \"pipe\"],\n\t});\n\n\tlet nextId = 1;\n\tconst pending = new Map<number, { resolve: (r: unknown) => void; reject: (e: Error) => void }>();\n\n\tconst rl = createInterface({ input: proc.stdout! });\n\trl.on(\"line\", (line) => {\n\t\tif (!line.trim()) return;\n\t\ttry {\n\t\t\tconst msg = JSON.parse(line) as {\n\t\t\t\tid?: number;\n\t\t\t\tresult?: unknown;\n\t\t\t\terror?: { message: string };\n\t\t\t};\n\t\t\tif (msg.id === undefined) return;\n\t\t\tconst cb = pending.get(msg.id);\n\t\t\tif (!cb) return;\n\t\t\tpending.delete(msg.id);\n\t\t\tif (msg.error) cb.reject(new Error(msg.error.message));\n\t\t\telse cb.resolve(msg.result);\n\t\t} catch {\n\t\t\t// ignore non-JSON server startup output\n\t\t}\n\t});\n\n\tproc.on(\"exit\", () => {\n\t\tfor (const cb of pending.values()) cb.reject(new Error(`MCP server \"${config.name}\" exited unexpectedly`));\n\t\tpending.clear();\n\t\tmcpConnections.delete(config.name);\n\t});\n\n\tfunction rpc(method: string, params?: unknown, timeoutMs?: number): Promise<unknown> {\n\t\tconst id = nextId++;\n\t\treturn new Promise<unknown>((resolve, reject) => {\n\t\t\tlet timer: NodeJS.Timeout | undefined;\n\t\t\tif (timeoutMs && timeoutMs > 0) {\n\t\t\t\ttimer = setTimeout(() => {\n\t\t\t\t\tif (pending.delete(id)) {\n\t\t\t\t\t\treject(new Error(`MCP server \"${config.name}\" timed out after ${timeoutMs}ms on ${method}`));\n\t\t\t\t\t}\n\t\t\t\t}, timeoutMs);\n\t\t\t\ttimer.unref?.();\n\t\t\t}\n\t\t\tpending.set(id, {\n\t\t\t\tresolve: (r) => {\n\t\t\t\t\tif (timer) clearTimeout(timer);\n\t\t\t\t\tresolve(r);\n\t\t\t\t},\n\t\t\t\treject: (e) => {\n\t\t\t\t\tif (timer) clearTimeout(timer);\n\t\t\t\t\treject(e);\n\t\t\t\t},\n\t\t\t});\n\t\t\tproc.stdin!.write(`${JSON.stringify({ jsonrpc: \"2.0\", id, method, params })}\\n`);\n\t\t});\n\t}\n\n\tfunction notify(method: string, params?: unknown): void {\n\t\tproc.stdin!.write(`${JSON.stringify({ jsonrpc: \"2.0\", method, params })}\\n`);\n\t}\n\n\treturn {\n\t\trpc,\n\t\tnotify,\n\t\tterminate: () => {\n\t\t\trl.close();\n\t\t\tproc.kill();\n\t\t},\n\t};\n}\n\n/** Remote servers use `{ type: \"http\" | \"sse\", url }`; stdio servers use `command`. */\nfunction isRemoteServer(config: McpServerConfig): boolean {\n\treturn config.type === \"http\" || config.type === \"sse\" || (!config.command && typeof config.url === \"string\");\n}\n\nfunction openMcpConnection(config: McpServerConfig): McpConnection {\n\tif (isRemoteServer(config)) {\n\t\tif (typeof config.url !== \"string\") {\n\t\t\tthrow new Error(`MCP server \"${config.name}\" has type \"${config.type}\" but no \"url\"`);\n\t\t}\n\t\treturn connectHttpMcpServer(\n\t\t\t{\n\t\t\t\tname: config.name,\n\t\t\t\turl: config.url,\n\t\t\t\theaders: config.headers,\n\t\t\t\ttype: config.type === \"sse\" ? \"sse\" : \"http\",\n\t\t\t},\n\t\t\tmcpRemoteOptions.get(config.name),\n\t\t);\n\t}\n\tif (typeof config.command !== \"string\") {\n\t\tthrow new Error(`MCP server \"${config.name}\" needs a \"command\" (stdio) or a \"url\" (http/sse)`);\n\t}\n\treturn spawnMcpServer(config as McpServerConfig & { command: string });\n}\n\nasync function connectMcpServer(config: McpServerConfig): Promise<{ conn: McpConnection; tools: McpToolDef[] }> {\n\tmcpConnections.get(config.name)?.terminate();\n\n\tconst conn = openMcpConnection(config);\n\tmcpConnections.set(config.name, conn);\n\n\ttry {\n\t\tawait conn.rpc(\n\t\t\t\"initialize\",\n\t\t\t{\n\t\t\t\tprotocolVersion: \"2024-11-05\",\n\t\t\t\tcapabilities: { tools: {} },\n\t\t\t\tclientInfo: { name: \"hoocode\", version: \"1.0.0\" },\n\t\t\t},\n\t\t\tMCP_HANDSHAKE_TIMEOUT_MS,\n\t\t);\n\n\t\t// Per the MCP spec the client must acknowledge a successful initialize with the\n\t\t// initialized notification before issuing further requests; strict servers gate\n\t\t// tools/call on it.\n\t\tconn.notify(\"notifications/initialized\");\n\n\t\tconst toolsResult = (await conn.rpc(\"tools/list\", {}, MCP_HANDSHAKE_TIMEOUT_MS)) as {\n\t\t\ttools?: McpToolDef[];\n\t\t};\n\t\treturn { conn, tools: toolsResult.tools ?? [] };\n\t} catch (error) {\n\t\t// Don't leave a half-connected entry behind: remote transports have no\n\t\t// process-exit event to evict them, so getOrConnectMcp would keep handing\n\t\t// out the dead connection instead of reconnecting. Exception: a pending\n\t\t// browser authorization — terminating would kill the OAuth loopback\n\t\t// listener; the auth-completion handler reconnects that server itself.\n\t\tif (!mcpAuthPending.has(config.name)) {\n\t\t\tconn.terminate();\n\t\t\tif (mcpConnections.get(config.name) === conn) mcpConnections.delete(config.name);\n\t\t}\n\t\tthrow error;\n\t}\n}\n\n/**\n * Return a live connection for a server, lazily reconnecting from the retained\n * config when the previous connection was torn down. Returns undefined only when\n * no config is known or a fresh connect attempt fails.\n */\nasync function getOrConnectMcp(name: string): Promise<McpConnection | undefined> {\n\tconst existing = mcpConnections.get(name);\n\tif (existing) return existing;\n\tconst config = mcpServerConfigs.get(name);\n\tif (!config) return undefined;\n\ttry {\n\t\tconst { conn } = await connectMcpServer(config);\n\t\treturn conn;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nlet mcpExitCleanupInstalled = false;\n/** Kill spawned MCP servers when the host process exits so they don't linger as\n * orphans (their stdin merely goes idle, which doesn't terminate them). */\nfunction installMcpExitCleanup(): void {\n\tif (mcpExitCleanupInstalled) return;\n\tmcpExitCleanupInstalled = true;\n\tprocess.once(\"exit\", () => {\n\t\tfor (const conn of mcpConnections.values()) {\n\t\t\ttry {\n\t\t\t\tconn.terminate();\n\t\t\t} catch {\n\t\t\t\t// best-effort cleanup\n\t\t\t}\n\t\t}\n\t\tmcpConnections.clear();\n\t});\n}\n\nfunction buildMcpSchema(tool: McpToolDef): ReturnType<typeof Type.Object> {\n\tconst props = tool.inputSchema?.properties ?? {};\n\tconst required = new Set(tool.inputSchema?.required ?? []);\n\tconst shape: Record<string, ReturnType<typeof Type.String>> = {};\n\n\tfor (const [key, prop] of Object.entries(props)) {\n\t\tlet field: ReturnType<typeof Type.String>;\n\t\tswitch (prop.type) {\n\t\t\tcase \"number\":\n\t\t\tcase \"integer\":\n\t\t\t\tfield = Type.Number({ description: prop.description }) as unknown as ReturnType<typeof Type.String>;\n\t\t\t\tbreak;\n\t\t\tcase \"boolean\":\n\t\t\t\tfield = Type.Boolean({ description: prop.description }) as unknown as ReturnType<typeof Type.String>;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tfield = Type.String({ description: prop.description });\n\t\t}\n\t\tshape[key] = required.has(key) ? field : (Type.Optional(field) as unknown as ReturnType<typeof Type.String>);\n\t}\n\n\treturn Type.Object(shape);\n}\n\n/**\n * Parse standard MCP config format (used by Claude Desktop, VS Code, etc.)\n * into hoocode's McpServerConfig format.\n */\nfunction parseStandardMcpConfig(config: StandardMcpConfig, _source: string): McpServerConfig[] {\n\tif (!config.mcpServers) return [];\n\n\tconst servers: McpServerConfig[] = [];\n\tfor (const [name, serverConfig] of Object.entries(config.mcpServers)) {\n\t\tservers.push({\n\t\t\tname,\n\t\t\tcommand: serverConfig.command,\n\t\t\targs: serverConfig.args,\n\t\t\tenv: serverConfig.env,\n\t\t\ttype: serverConfig.type,\n\t\t\turl: serverConfig.url,\n\t\t\theaders: serverConfig.headers,\n\t\t\tbackground: serverConfig.background,\n\t\t});\n\t}\n\treturn servers;\n}\n\n/**\n * Load MCP servers from a standard mcp.json file.\n * Returns an array of McpServerConfig, or empty array if file doesn't exist or is invalid.\n */\nfunction loadStandardMcpFile(filePath: string): McpServerConfig[] {\n\tif (!existsSync(filePath)) return [];\n\n\ttry {\n\t\tconst content = readFileSync(filePath, \"utf8\");\n\t\tconst config = JSON.parse(content) as StandardMcpConfig;\n\t\treturn parseStandardMcpConfig(config, filePath);\n\t} catch {\n\t\treturn [];\n\t}\n}\n\n/**\n * Build the full {@link ToolDefinition} for one MCP tool — the complete JSON\n * schema plus the connect/execute machinery. Shared by the eager path (register\n * every tool up front) and the deferred path (materialize on resolve), so both\n * produce identical, callable tools.\n */\nfunction buildMcpToolDefinition(serverConfig: McpServerConfig, tool: McpToolDef): ToolDefinition {\n\tconst toolName = `mcp_${serverConfig.name}_${tool.name}`;\n\tconst schema = buildMcpSchema(tool);\n\tconst capturedServer = serverConfig.name;\n\tconst capturedTool = tool.name;\n\t// MCP tools default to background mode since they are external processes with potential high latency\n\tconst isBackground = serverConfig.background !== false;\n\n\treturn {\n\t\tname: toolName,\n\t\tlabel: `[MCP] ${serverConfig.name} › ${tool.name}`,\n\t\tdescription: tool.description,\n\t\tparameters: schema,\n\t\tbackground: isBackground,\n\t\t// Render a clean, prefixed title in chat — `MCP [server › tool] <args>` —\n\t\t// parallel to the subagent `Task [type] <desc>` line. Without this the\n\t\t// ToolExecutionComponent falls back to the raw `mcp_<server>_<tool>` name.\n\t\t// The args summary reuses the same helper as the background start/finish\n\t\t// messages so the chat title stays in sync with them.\n\t\trenderCall(args, theme) {\n\t\t\tconst summary = summarizeArgs((args ?? {}) as Record<string, unknown>);\n\t\t\tconst text =\n\t\t\t\ttheme.fg(\"toolTitle\", theme.bold(\"MCP \")) +\n\t\t\t\ttheme.fg(\"mcp\", `[${capturedServer} › ${capturedTool}]`) +\n\t\t\t\t(summary ? theme.fg(\"dim\", ` ${summary}`) : \"\");\n\t\t\treturn new Text(text, 0, 0);\n\t\t},\n\t\tasync execute(\n\t\t\t_toolCallId: string,\n\t\t\tparams: Static<typeof schema>,\n\t\t\tsignal: AbortSignal,\n\t\t\t_onUpdate: AgentToolUpdateCallback,\n\t\t): Promise<AgentToolResult<McpToolDetails>> {\n\t\t\tconst startTime = Date.now();\n\t\t\t// Background MCP tools get a task store entry so they appear in the task pane.\n\t\t\t// Foreground tools skip this (their result is awaited inline). The server\n\t\t\t// name rides in subagentMode and becomes the row's `[server]` origin tag;\n\t\t\t// the title carries just the tool.\n\t\t\tconst task = isBackground\n\t\t\t\t? taskStore.create(capturedTool, { source: \"mcp\", subagentMode: capturedServer })\n\t\t\t\t: undefined;\n\t\t\tif (task) taskStore.update(task.id, { status: \"in_progress\" });\n\n\t\t\t// Lazily (re)connect: a dropped connection (server exit, process churn\n\t\t\t// between turns, a racing teardown) should transparently reconnect from\n\t\t\t// the retained config rather than permanently fail with \"not connected\".\n\t\t\tconst activeConn = await getOrConnectMcp(capturedServer);\n\t\t\tif (!activeConn) {\n\t\t\t\tif (task) taskStore.update(task.id, { status: \"failed\" });\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{ type: \"text\", text: `MCP server \"${capturedServer}\" is not connected (reconnect attempt failed)` },\n\t\t\t\t\t],\n\t\t\t\t\tdetails: { elapsed: Date.now() - startTime } as McpToolDetails,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst abortPromise = new Promise<never>((_, reject) => {\n\t\t\t\t\tsignal.addEventListener(\"abort\", () => reject(new Error(\"Aborted\")));\n\t\t\t\t});\n\n\t\t\t\tconst result = await Promise.race([\n\t\t\t\t\tactiveConn.rpc(\"tools/call\", { name: capturedTool, arguments: params }),\n\t\t\t\t\tabortPromise,\n\t\t\t\t]);\n\n\t\t\t\tif (task) taskStore.update(task.id, { status: \"done\" });\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: JSON.stringify(result, null, 2) }],\n\t\t\t\t\tdetails: { elapsed: Date.now() - startTime } as McpToolDetails,\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\tif (task) taskStore.update(task.id, { status: \"failed\" });\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t},\n\t\trenderResult(result, _options, theme, context) {\n\t\t\tconst text = result.content\n\t\t\t\t.map((c) => (c.type === \"text\" ? c.text : \"\"))\n\t\t\t\t.filter(Boolean)\n\t\t\t\t.join(\"\\n\");\n\t\t\tif (!text) return new Text(\"\", 0, 0);\n\n\t\t\tconst details = result.details as McpToolDetails | undefined;\n\t\t\tconst elapsed = details?.elapsed;\n\t\t\tconst elapsedText = elapsed ? ` ${formatDurationSecs(elapsed / 1000)}` : \"\";\n\t\t\tconst identity = `${capturedServer} › ${capturedTool}`;\n\n\t\t\t// Use context.isError to determine status (framework sets this when tools throw)\n\t\t\tconst isError = context.isError;\n\t\t\tconst statusGlyph = isError ? \"✗\" : \"✓\";\n\t\t\tconst statusLabel = isError ? \"failed\" : \"done\";\n\t\t\tconst statusColor = isError ? \"error\" : \"success\";\n\n\t\t\tconst spine = (s: string) => theme.fg(\"borderMuted\", s);\n\t\t\tconst header =\n\t\t\t\t`${spine(\"╭\")} ${theme.fg(statusColor, statusGlyph)} ` +\n\t\t\t\t`${theme.bold(theme.fg(statusColor, statusLabel))} ` +\n\t\t\t\t`${theme.fg(\"mcp\", identity)}${elapsedText}`;\n\t\t\tconst body = text\n\t\t\t\t.split(\"\\n\")\n\t\t\t\t.map((line) => `${spine(\"│\")} ${theme.fg(\"toolOutput\", line)}`)\n\t\t\t\t.join(\"\\n\");\n\t\t\treturn new Text(`${header}\\n${body}\\n${spine(\"╰\")}`, 0, 0);\n\t\t},\n\t} as ToolDefinition;\n}\n\nconst RESOLVE_MCP_TOOLS_NAME = \"ResolveMcpTools\";\n\nexport function setupMcpLoader(pi: ExtensionAPI): void {\n\tpi.on(\"session_start\", async (_event: SessionStartEvent, ctx: ExtensionContext) => {\n\t\t// A spawned subagent whose tool allowlist has no MCP tools is told by its\n\t\t// parent to skip server connection entirely (see SUBAGENT_SKIP_MCP_ENV).\n\t\t// Each connect is a ~15s-timeout handshake; doing it for a subagent that can\n\t\t// never call the tools is pure startup latency.\n\t\tif (subagentSkipMcp()) return;\n\n\t\tinstallMcpExitCleanup();\n\t\t// Rebuild the status registry from scratch: a reload or session switch runs\n\t\t// this pass again and the startup summary must not double-count.\n\t\tclearMcpServerStatuses();\n\t\tconst allServerConfigs: McpServerConfig[] = [];\n\t\tconst seenNames = new Set<string>();\n\n\t\t// 1. Load from standard mcp.json locations\n\t\t// User-level: ~/.agents/mcp.json\n\t\tconst userAgentsConfig = loadStandardMcpFile(join(homedir(), \".agents\", \"mcp.json\"));\n\t\tfor (const config of userAgentsConfig) {\n\t\t\tif (!seenNames.has(config.name)) {\n\t\t\t\tseenNames.add(config.name);\n\t\t\t\tallServerConfigs.push(config);\n\t\t\t}\n\t\t}\n\n\t\t// Project-level: ./.agents/mcp.json\n\t\tconst projectAgentsConfig = loadStandardMcpFile(join(ctx.cwd, \".agents\", \"mcp.json\"));\n\t\tfor (const config of projectAgentsConfig) {\n\t\t\tif (!seenNames.has(config.name)) {\n\t\t\t\tseenNames.add(config.name);\n\t\t\t\tallServerConfigs.push(config);\n\t\t\t}\n\t\t}\n\n\t\t// Claude Desktop: ~/.config/claude/mcp.json\n\t\tconst claudeDesktopConfig = loadStandardMcpFile(join(homedir(), \".config\", \"claude\", \"mcp.json\"));\n\t\tfor (const config of claudeDesktopConfig) {\n\t\t\tif (!seenNames.has(config.name)) {\n\t\t\t\tseenNames.add(config.name);\n\t\t\t\tallServerConfigs.push(config);\n\t\t\t}\n\t\t}\n\n\t\t// 2. Load from hoocode's per-server format (existing behavior)\n\t\tconst searchDirs = [join(HOOCODE_DIR, \"mcp-servers\"), join(ctx.cwd, \".hoocode\", \"mcp-servers\")];\n\n\t\tfor (const dir of searchDirs) {\n\t\t\tif (!existsSync(dir)) continue;\n\n\t\t\tlet files: string[];\n\t\t\ttry {\n\t\t\t\tfiles = (await readdir(dir)).filter((f) => f.endsWith(\".json\"));\n\t\t\t} catch {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tfor (const file of files) {\n\t\t\t\tconst cfgPath = join(dir, file);\n\t\t\t\tlet serverConfig: McpServerConfig;\n\n\t\t\t\ttry {\n\t\t\t\t\tserverConfig = JSON.parse(readFileSync(cfgPath, \"utf8\")) as McpServerConfig;\n\t\t\t\t\tif (!serverConfig.name || (!serverConfig.command && !serverConfig.url)) {\n\t\t\t\t\t\tctx.ui.notify(`MCP: config \"${file}\" is missing required \"name\" or \"command\"/\"url\"`, \"warning\");\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t} catch (err) {\n\t\t\t\t\tctx.ui.notify(`MCP: failed to parse \"${file}\": ${String(err)}`, \"error\");\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Skip if already loaded from standard config\n\t\t\t\tif (seenNames.has(serverConfig.name)) continue;\n\t\t\t\tseenNames.add(serverConfig.name);\n\t\t\t\tallServerConfigs.push(serverConfig);\n\t\t\t}\n\t\t}\n\n\t\t// 2b. Load from plugins/extensions that registered MCP servers during load.\n\t\tfor (const entry of getExtensionMcpServers()) {\n\t\t\tfor (const serverConfig of parseStandardMcpConfig(\n\t\t\t\t{ mcpServers: entry.mcpServers },\n\t\t\t\t`plugin:${entry.source}`,\n\t\t\t)) {\n\t\t\t\tif (seenNames.has(serverConfig.name)) continue;\n\t\t\t\tseenNames.add(serverConfig.name);\n\t\t\t\tallServerConfigs.push(serverConfig);\n\t\t\t}\n\t\t}\n\n\t\t// Deferral (spec §2): inject MCP tool names only and materialize each schema\n\t\t// on demand via ResolveMcpTools. Default-on and top-level only — a subagent that\n\t\t// needs MCP has this env cleared, so it eager-registers its allowlisted tools\n\t\t// at dispatch (the dispatch ↔ schema interaction) and they are immediately callable.\n\t\tconst defer = deferMcpSchemas();\n\t\tconst deferredCatalog: DeferredMcpToolEntry[] = [];\n\t\t// Retain each deferred tool's raw definition + config so ResolveMcpTools can\n\t\t// build the full ToolDefinition on request.\n\t\tconst deferredByName = new Map<string, { serverConfig: McpServerConfig; tool: McpToolDef }>();\n\t\tconst resolvedNames = new Set<string>();\n\n\t\t// Remote servers get OAuth support: tokens persist under\n\t\t// ~/.hoocode/mcp-auth, and when a server demands interactive (browser)\n\t\t// authorization the handshake fails fast while the flow keeps running in\n\t\t// the background — on completion the server is reconnected and its tools\n\t\t// registered (eagerly, since the deferred catalog is already sealed).\n\t\tconst buildRemoteOptions = (serverConfig: McpServerConfig): McpRemoteOptions => ({\n\t\t\tauthStorageDir: join(HOOCODE_DIR, \"mcp-auth\"),\n\t\t\tonAuthRequired: (authorizationUrl, completed) => {\n\t\t\t\tmcpAuthPending.add(serverConfig.name);\n\t\t\t\tctx.ui.notify(\n\t\t\t\t\t`MCP: \"${serverConfig.name}\" requires authorization — complete the sign-in opened in your browser` +\n\t\t\t\t\t\t(authorizationUrl ? `: ${authorizationUrl}` : \"\"),\n\t\t\t\t\t\"warning\",\n\t\t\t\t);\n\t\t\t\tcompleted\n\t\t\t\t\t.then(async () => {\n\t\t\t\t\t\tmcpAuthPending.delete(serverConfig.name);\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst { tools } = await connectMcpServer(serverConfig);\n\t\t\t\t\t\t\tfor (const tool of tools) pi.registerTool(buildMcpToolDefinition(serverConfig, tool));\n\t\t\t\t\t\t\tsetMcpServerStatus({\n\t\t\t\t\t\t\t\tname: serverConfig.name,\n\t\t\t\t\t\t\t\ttoolCount: tools.length,\n\t\t\t\t\t\t\t\tbackground: serverConfig.background !== false,\n\t\t\t\t\t\t\t\tdeferred: false,\n\t\t\t\t\t\t\t\tstate: \"connected\",\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\t\t`MCP: connected \"${serverConfig.name}\" after authorization (${tools.length} tool${tools.length === 1 ? \"\" : \"s\"})`,\n\t\t\t\t\t\t\t\t\"info\",\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\t\t`MCP: failed to connect \"${serverConfig.name}\" after authorization: ${String(err)}`,\n\t\t\t\t\t\t\t\t\"error\",\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t\t.catch((err: unknown) => {\n\t\t\t\t\t\tmcpAuthPending.delete(serverConfig.name);\n\t\t\t\t\t\tctx.ui.notify(`MCP: authorization for \"${serverConfig.name}\" failed: ${String(err)}`, \"error\");\n\t\t\t\t\t});\n\t\t\t},\n\t\t});\n\n\t\t// 3. Connect to all servers and register (or defer) tools\n\t\tfor (const serverConfig of allServerConfigs) {\n\t\t\t// Retain the config so a tool call can lazily reconnect a dropped server.\n\t\t\tmcpServerConfigs.set(serverConfig.name, serverConfig);\n\t\t\tmcpRemoteOptions.set(serverConfig.name, buildRemoteOptions(serverConfig));\n\t\t\ttry {\n\t\t\t\tconst { tools } = await connectMcpServer(serverConfig);\n\n\t\t\t\tfor (const tool of tools) {\n\t\t\t\t\tconst toolName = `mcp_${serverConfig.name}_${tool.name}`;\n\t\t\t\t\tif (defer) {\n\t\t\t\t\t\tdeferredCatalog.push({ toolName, server: serverConfig.name, description: tool.description });\n\t\t\t\t\t\tdeferredByName.set(toolName, { serverConfig, tool });\n\t\t\t\t\t} else {\n\t\t\t\t\t\tpi.registerTool(buildMcpToolDefinition(serverConfig, tool));\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// A successful connect is reported by the startup resource summary (one\n\t\t\t\t// `mcp` cell plus a details row), not as a transient line above it.\n\t\t\t\tsetMcpServerStatus({\n\t\t\t\t\tname: serverConfig.name,\n\t\t\t\t\ttoolCount: tools.length,\n\t\t\t\t\tbackground: serverConfig.background !== false,\n\t\t\t\t\tdeferred: defer,\n\t\t\t\t\tstate: \"connected\",\n\t\t\t\t});\n\t\t\t} catch (err) {\n\t\t\t\tif (mcpAuthPending.has(serverConfig.name)) {\n\t\t\t\t\tsetMcpServerStatus({\n\t\t\t\t\t\tname: serverConfig.name,\n\t\t\t\t\t\ttoolCount: 0,\n\t\t\t\t\t\tbackground: serverConfig.background !== false,\n\t\t\t\t\t\tdeferred: defer,\n\t\t\t\t\t\tstate: \"authorizing\",\n\t\t\t\t\t});\n\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t`MCP: \"${serverConfig.name}\" is waiting for browser authorization; tools will register once it completes`,\n\t\t\t\t\t\t\"info\",\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tctx.ui.notify(`MCP: failed to connect \"${serverConfig.name}\": ${String(err)}`, \"error\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// 4. In deferred mode, register the single resolver that materializes schemas on demand.\n\t\tif (defer && deferredCatalog.length > 0) {\n\t\t\tconst resolveParams = Type.Object(\n\t\t\t\t{\n\t\t\t\t\tnames: Type.Array(Type.String(), {\n\t\t\t\t\t\tdescription: \"MCP tool names to make callable (e.g. 'mcp_github_create_pr' or 'create_pr').\",\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t\t{ additionalProperties: false },\n\t\t\t);\n\t\t\tpi.registerTool({\n\t\t\t\tname: RESOLVE_MCP_TOOLS_NAME,\n\t\t\t\tlabel: RESOLVE_MCP_TOOLS_NAME,\n\t\t\t\tdescription:\n\t\t\t\t\t\"MCP tools are connected but their schemas are loaded on demand to keep context small. Call this with the tool name(s) you need to make them callable, then call the tool(s). Available MCP tools:\\n\" +\n\t\t\t\t\tformatDeferredCatalog(deferredCatalog),\n\t\t\t\tpromptSnippet: \"Resolve deferred MCP tool schemas by name before calling them.\",\n\t\t\t\tparameters: resolveParams,\n\t\t\t\tasync execute(_toolCallId: string, params: Static<typeof resolveParams>) {\n\t\t\t\t\tconst matched = selectResolvable(deferredCatalog, params.names ?? []);\n\t\t\t\t\tconst newlyResolved: string[] = [];\n\t\t\t\t\tfor (const entry of matched) {\n\t\t\t\t\t\tif (resolvedNames.has(entry.toolName)) continue;\n\t\t\t\t\t\tconst raw = deferredByName.get(entry.toolName);\n\t\t\t\t\t\tif (!raw) continue;\n\t\t\t\t\t\tpi.registerTool(buildMcpToolDefinition(raw.serverConfig, raw.tool));\n\t\t\t\t\t\tresolvedNames.add(entry.toolName);\n\t\t\t\t\t\tnewlyResolved.push(entry.toolName);\n\t\t\t\t\t}\n\t\t\t\t\tconst text = matched.length\n\t\t\t\t\t\t? `Resolved ${newlyResolved.length} MCP tool(s): ${matched.map((m) => m.toolName).join(\", \")}. They are now callable.`\n\t\t\t\t\t\t: `No MCP tools matched: ${(params.names ?? []).join(\", \") || \"(none)\"}. See ResolveMcpTools for the catalog.`;\n\t\t\t\t\treturn { content: [{ type: \"text\" as const, text }], details: undefined };\n\t\t\t\t},\n\t\t\t} as ToolDefinition);\n\t\t}\n\t});\n}\n"]}
|
|
@@ -22,6 +22,7 @@ import { Text } from "@kolisachint/hoocode-tui";
|
|
|
22
22
|
import { Type } from "typebox";
|
|
23
23
|
import { getHooCodeDir } from "../../config.js";
|
|
24
24
|
import { getExtensionMcpServers } from "../../core/extension-mcp-servers.js";
|
|
25
|
+
import { formatDurationSecs } from "../../core/format-duration.js";
|
|
25
26
|
import { clearMcpServerStatuses, setMcpServerStatus } from "../../core/mcp-status.js";
|
|
26
27
|
import { deferMcpSchemas, subagentSkipMcp } from "../../core/subagent-depth.js";
|
|
27
28
|
import { taskStore } from "../../core/task-store.js";
|
|
@@ -295,11 +296,12 @@ function buildMcpToolDefinition(serverConfig, tool) {
|
|
|
295
296
|
renderCall(args, theme) {
|
|
296
297
|
const summary = summarizeArgs((args ?? {}));
|
|
297
298
|
const text = theme.fg("toolTitle", theme.bold("MCP ")) +
|
|
298
|
-
theme.fg("
|
|
299
|
+
theme.fg("mcp", `[${capturedServer} › ${capturedTool}]`) +
|
|
299
300
|
(summary ? theme.fg("dim", ` ${summary}`) : "");
|
|
300
301
|
return new Text(text, 0, 0);
|
|
301
302
|
},
|
|
302
303
|
async execute(_toolCallId, params, signal, _onUpdate) {
|
|
304
|
+
const startTime = Date.now();
|
|
303
305
|
// Background MCP tools get a task store entry so they appear in the task pane.
|
|
304
306
|
// Foreground tools skip this (their result is awaited inline). The server
|
|
305
307
|
// name rides in subagentMode and becomes the row's `[server]` origin tag;
|
|
@@ -320,7 +322,7 @@ function buildMcpToolDefinition(serverConfig, tool) {
|
|
|
320
322
|
content: [
|
|
321
323
|
{ type: "text", text: `MCP server "${capturedServer}" is not connected (reconnect attempt failed)` },
|
|
322
324
|
],
|
|
323
|
-
details:
|
|
325
|
+
details: { elapsed: Date.now() - startTime },
|
|
324
326
|
};
|
|
325
327
|
}
|
|
326
328
|
try {
|
|
@@ -333,7 +335,10 @@ function buildMcpToolDefinition(serverConfig, tool) {
|
|
|
333
335
|
]);
|
|
334
336
|
if (task)
|
|
335
337
|
taskStore.update(task.id, { status: "done" });
|
|
336
|
-
return {
|
|
338
|
+
return {
|
|
339
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
340
|
+
details: { elapsed: Date.now() - startTime },
|
|
341
|
+
};
|
|
337
342
|
}
|
|
338
343
|
catch (error) {
|
|
339
344
|
if (task)
|
|
@@ -341,6 +346,32 @@ function buildMcpToolDefinition(serverConfig, tool) {
|
|
|
341
346
|
throw error;
|
|
342
347
|
}
|
|
343
348
|
},
|
|
349
|
+
renderResult(result, _options, theme, context) {
|
|
350
|
+
const text = result.content
|
|
351
|
+
.map((c) => (c.type === "text" ? c.text : ""))
|
|
352
|
+
.filter(Boolean)
|
|
353
|
+
.join("\n");
|
|
354
|
+
if (!text)
|
|
355
|
+
return new Text("", 0, 0);
|
|
356
|
+
const details = result.details;
|
|
357
|
+
const elapsed = details?.elapsed;
|
|
358
|
+
const elapsedText = elapsed ? ` ${formatDurationSecs(elapsed / 1000)}` : "";
|
|
359
|
+
const identity = `${capturedServer} › ${capturedTool}`;
|
|
360
|
+
// Use context.isError to determine status (framework sets this when tools throw)
|
|
361
|
+
const isError = context.isError;
|
|
362
|
+
const statusGlyph = isError ? "✗" : "✓";
|
|
363
|
+
const statusLabel = isError ? "failed" : "done";
|
|
364
|
+
const statusColor = isError ? "error" : "success";
|
|
365
|
+
const spine = (s) => theme.fg("borderMuted", s);
|
|
366
|
+
const header = `${spine("╭")} ${theme.fg(statusColor, statusGlyph)} ` +
|
|
367
|
+
`${theme.bold(theme.fg(statusColor, statusLabel))} ` +
|
|
368
|
+
`${theme.fg("mcp", identity)}${elapsedText}`;
|
|
369
|
+
const body = text
|
|
370
|
+
.split("\n")
|
|
371
|
+
.map((line) => `${spine("│")} ${theme.fg("toolOutput", line)}`)
|
|
372
|
+
.join("\n");
|
|
373
|
+
return new Text(`${header}\n${body}\n${spine("╰")}`, 0, 0);
|
|
374
|
+
},
|
|
344
375
|
};
|
|
345
376
|
}
|
|
346
377
|
const RESOLVE_MCP_TOOLS_NAME = "ResolveMcpTools";
|