@earendil-works/pi-coding-agent 0.99.1 → 0.99.2

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.
Files changed (143) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/dist/bundle/chunks/anthropic-messages-UID2PALB.js +6 -0
  3. package/dist/bundle/chunks/{azure-openai-responses-EN5WOBET.js → azure-openai-responses-TLHNIYZK.js} +1 -1
  4. package/dist/bundle/chunks/bedrock-converse-stream.js +1 -1
  5. package/dist/bundle/chunks/{chunk-IMTXZUO7.js → chunk-3KYEVQKX.js} +3 -3
  6. package/dist/bundle/chunks/{chunk-W2DOMZSC.js → chunk-3LH3ZQKY.js} +1 -1
  7. package/dist/bundle/chunks/chunk-3NVH2HQH.js +4 -0
  8. package/dist/bundle/chunks/{chunk-GUORCHFS.js → chunk-3YAHQSW6.js} +23 -20
  9. package/dist/bundle/chunks/{chunk-LLMKQWZS.js → chunk-45SXDISG.js} +5 -7
  10. package/dist/bundle/chunks/chunk-6D7LHLKG.js +2 -0
  11. package/dist/bundle/chunks/{chunk-AXPY26X7.js → chunk-7QSPBJKW.js} +3 -3
  12. package/dist/bundle/chunks/{chunk-SLDA2X2H.js → chunk-ECRK44UV.js} +1 -1
  13. package/dist/bundle/chunks/{chunk-PEHWOV5U.js → chunk-G3UZ5FWD.js} +12 -23
  14. package/dist/bundle/chunks/chunk-LD2P6SFZ.js +2 -0
  15. package/dist/bundle/chunks/{chunk-J4CWPC4N.js → chunk-OSKPX3Z5.js} +1 -1
  16. package/dist/bundle/chunks/{chunk-LRS5S6EK.js → chunk-R5J3MOBF.js} +1 -1
  17. package/dist/bundle/chunks/chunk-VIV3CWXG.js +2 -0
  18. package/dist/bundle/chunks/{cli-AZXNGIZH.js → cli-ALNBTL3U.js} +6 -4
  19. package/dist/bundle/chunks/{cloudflare-workers-ai-system-one-XJQQYGGU.js → cloudflare-workers-ai-system-one-NPQN263E.js} +1 -1
  20. package/dist/bundle/chunks/codemode-worker.js +23 -3
  21. package/dist/bundle/chunks/{execute-7XXPZAWW.js → execute-RC7W4ML3.js} +26 -6
  22. package/dist/bundle/chunks/github-copilot.js +1 -1
  23. package/dist/bundle/chunks/{google-generative-ai-CQAKKJTA.js → google-generative-ai-APTPZOQL.js} +1 -1
  24. package/dist/bundle/chunks/{google-vertex-AE36YXJU.js → google-vertex-MXCOSOY3.js} +1 -1
  25. package/dist/bundle/chunks/{llama-cpp-classify-PJJYKPLD.js → llama-cpp-classify-XT44PI3C.js} +1 -1
  26. package/dist/bundle/chunks/{mistral-conversations-KEYTXJM7.js → mistral-conversations-DKVFNQL6.js} +1 -1
  27. package/dist/bundle/chunks/{openai-codex-responses-JQTCOVEG.js → openai-codex-responses-3GKGNXC4.js} +1 -1
  28. package/dist/bundle/chunks/{openai-completions-XW2Q5HVC.js → openai-completions-JXDDPZ23.js} +1 -1
  29. package/dist/bundle/chunks/{openai-responses-6AXWFL75.js → openai-responses-S7GKCCDG.js} +1 -1
  30. package/dist/bundle/chunks/{openrouter-images-TPQ4V6OR.js → openrouter-images-ZVXWCSIM.js} +1 -1
  31. package/dist/bundle/chunks/{runtime-G5WJPRBM.js → runtime-NJPX4ID2.js} +1 -1
  32. package/dist/bundle/chunks/{typesafe-system-one-E7A4HNJI.js → typesafe-system-one-A4CZTQWZ.js} +1 -1
  33. package/dist/bundle/chunks/virtual-modules-5UGH4HRZ.js +2 -0
  34. package/dist/bundle/cli-runtime.js +1 -1
  35. package/dist/bundle/index.js +1 -1
  36. package/dist/bundle/rpc-entry.js +1 -1
  37. package/dist/config.d.ts +5 -8
  38. package/dist/config.d.ts.map +1 -1
  39. package/dist/config.js +16 -13
  40. package/dist/config.js.map +1 -1
  41. package/dist/core/agent-session.d.ts +7 -1
  42. package/dist/core/agent-session.d.ts.map +1 -1
  43. package/dist/core/agent-session.js +14 -2
  44. package/dist/core/agent-session.js.map +1 -1
  45. package/dist/core/extensions/loader.d.ts.map +1 -1
  46. package/dist/core/extensions/loader.js +13 -1
  47. package/dist/core/extensions/loader.js.map +1 -1
  48. package/dist/core/extensions/types.d.ts +6 -1
  49. package/dist/core/extensions/types.d.ts.map +1 -1
  50. package/dist/core/extensions/types.js.map +1 -1
  51. package/dist/core/mcp-servers.d.ts +28 -7
  52. package/dist/core/mcp-servers.d.ts.map +1 -1
  53. package/dist/core/mcp-servers.js +45 -11
  54. package/dist/core/mcp-servers.js.map +1 -1
  55. package/dist/core/model-runtime.d.ts +6 -0
  56. package/dist/core/model-runtime.d.ts.map +1 -1
  57. package/dist/core/model-runtime.js +22 -18
  58. package/dist/core/model-runtime.js.map +1 -1
  59. package/dist/core/remote-catalog-provider.d.ts.map +1 -1
  60. package/dist/core/remote-catalog-provider.js +4 -9
  61. package/dist/core/remote-catalog-provider.js.map +1 -1
  62. package/dist/core/sdk.d.ts.map +1 -1
  63. package/dist/core/sdk.js +1 -0
  64. package/dist/core/sdk.js.map +1 -1
  65. package/dist/core/tools/renderers/bash.d.ts.map +1 -1
  66. package/dist/core/tools/renderers/bash.js +11 -31
  67. package/dist/core/tools/renderers/bash.js.map +1 -1
  68. package/dist/core/virtual-models.d.ts +2 -0
  69. package/dist/core/virtual-models.d.ts.map +1 -1
  70. package/dist/core/virtual-models.js +19 -12
  71. package/dist/core/virtual-models.js.map +1 -1
  72. package/dist/extensions/codemode/execute.d.ts.map +1 -1
  73. package/dist/extensions/codemode/execute.js +43 -4
  74. package/dist/extensions/codemode/execute.js.map +1 -1
  75. package/dist/extensions/codemode/renderer.d.ts.map +1 -1
  76. package/dist/extensions/codemode/renderer.js +43 -25
  77. package/dist/extensions/codemode/renderer.js.map +1 -1
  78. package/dist/extensions/codemode/tool.d.ts +5 -4
  79. package/dist/extensions/codemode/tool.d.ts.map +1 -1
  80. package/dist/extensions/codemode/tool.js +22 -31
  81. package/dist/extensions/codemode/tool.js.map +1 -1
  82. package/dist/extensions/codemode/worker.d.ts +1 -1
  83. package/dist/extensions/codemode/worker.js +1 -1
  84. package/dist/extensions/codemode/worker.js.map +1 -1
  85. package/dist/extensions/mcp/cli.d.ts.map +1 -1
  86. package/dist/extensions/mcp/cli.js +18 -3
  87. package/dist/extensions/mcp/cli.js.map +1 -1
  88. package/dist/extensions/mcp/config.d.ts +4 -2
  89. package/dist/extensions/mcp/config.d.ts.map +1 -1
  90. package/dist/extensions/mcp/config.js +14 -2
  91. package/dist/extensions/mcp/config.js.map +1 -1
  92. package/dist/extensions/mcp/index.d.ts +32 -8
  93. package/dist/extensions/mcp/index.d.ts.map +1 -1
  94. package/dist/extensions/mcp/index.js +205 -52
  95. package/dist/extensions/mcp/index.js.map +1 -1
  96. package/dist/extensions/mcp/oauth.d.ts +2 -0
  97. package/dist/extensions/mcp/oauth.d.ts.map +1 -1
  98. package/dist/extensions/mcp/oauth.js +1 -1
  99. package/dist/extensions/mcp/oauth.js.map +1 -1
  100. package/dist/extensions/mcp/runtime.d.ts +2 -0
  101. package/dist/extensions/mcp/runtime.d.ts.map +1 -1
  102. package/dist/extensions/mcp/runtime.js +14 -8
  103. package/dist/extensions/mcp/runtime.js.map +1 -1
  104. package/dist/extensions/mcp/tools.d.ts +5 -4
  105. package/dist/extensions/mcp/tools.d.ts.map +1 -1
  106. package/dist/extensions/mcp/tools.js +33 -15
  107. package/dist/extensions/mcp/tools.js.map +1 -1
  108. package/dist/extensions/mcp/ui.d.ts.map +1 -1
  109. package/dist/extensions/mcp/ui.js +4 -2
  110. package/dist/extensions/mcp/ui.js.map +1 -1
  111. package/dist/extensions/tool-search/tool.d.ts +5 -4
  112. package/dist/extensions/tool-search/tool.d.ts.map +1 -1
  113. package/dist/extensions/tool-search/tool.js +7 -28
  114. package/dist/extensions/tool-search/tool.js.map +1 -1
  115. package/dist/modes/interactive/components/visual-truncate.d.ts +27 -3
  116. package/dist/modes/interactive/components/visual-truncate.d.ts.map +1 -1
  117. package/dist/modes/interactive/components/visual-truncate.js +39 -6
  118. package/dist/modes/interactive/components/visual-truncate.js.map +1 -1
  119. package/docs/cli.md +3 -3
  120. package/docs/extensions.md +3 -3
  121. package/docs/mcp.md +125 -82
  122. package/docs/providers.md +2 -0
  123. package/docs/sdk.md +1 -1
  124. package/docs/settings.md +3 -1
  125. package/examples/extensions/built-in-tool-renderer.ts +16 -40
  126. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  127. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  128. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  129. package/examples/extensions/gondolin/package-lock.json +2 -2
  130. package/examples/extensions/gondolin/package.json +1 -1
  131. package/examples/extensions/minimal-mode.ts +24 -96
  132. package/examples/extensions/sandbox/package-lock.json +2 -2
  133. package/examples/extensions/sandbox/package.json +1 -1
  134. package/examples/extensions/with-deps/package-lock.json +2 -2
  135. package/examples/extensions/with-deps/package.json +1 -1
  136. package/examples/sdk/14-codemode-mcp.ts +2 -2
  137. package/npm-shrinkwrap.json +26 -26
  138. package/package.json +10 -10
  139. package/dist/bundle/chunks/anthropic-messages-A6EXUBG6.js +0 -6
  140. package/dist/bundle/chunks/chunk-GOPCREV2.js +0 -4
  141. package/dist/bundle/chunks/chunk-HSPCVFST.js +0 -2
  142. package/dist/bundle/chunks/chunk-XNGRGP62.js +0 -2
  143. package/dist/bundle/chunks/virtual-modules-CSWRO37N.js +0 -2
@@ -1 +1 @@
1
- {"version":3,"file":"tools.js","sourceRoot":"","sources":["../../../src/extensions/mcp/tools.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Adapts MCP tools to pi tool definitions.\n *\n * Results map onto pi's model-facing content (text and images). Text over 20KB keeps its start and\n * end with the middle cut out, like Codex does, and the full text is saved to a temp file the model\n * can read. Binary resources other than images are saved to temp files too, and resource links name\n * the `read_mcp_resource` tool. Codemode scripts receive the whole `CallToolResult` without `_meta`\n * (`content` blocks as sent by the server, `structuredContent`, `isError`), never truncated: it is\n * the tool's `structuredContent`, and every MCP tool declares a `CallToolResult` output schema. MCP\n * errors (`isError`) are error results for the model, but scripts still resolve to the result.\n */\n\nimport { createHash, randomBytes } from \"node:crypto\";\nimport { writeFile } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { AgentToolResult } from \"@earendil-works/pi-agent-core\";\nimport type { ImageContent, JsonValue, TextContent } from \"@earendil-works/pi-ai\";\nimport {\n\ttype CallToolResult,\n\ttype ContentBlock,\n\ttype McpRequestOptions,\n\ttype Tool as McpTool,\n\ttoLlmContent,\n} from \"@earendil-works/pi-mcp\";\nimport { Text } from \"@earendil-works/pi-tui\";\nimport type { TSchema } from \"typebox\";\nimport type { ToolAnnotations, ToolDefinition, ToolExposure, ToolNamespace } from \"../../core/extensions/types.ts\";\nimport { formatToolCallWithArgs, getTextOutput, replaceTabs } from \"../../core/tools/render-utils.ts\";\nimport { formatSize, truncateMiddle } from \"../../core/tools/truncate.ts\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport type { McpExposure } from \"./config.ts\";\n\n/**\n * Tool exposure of an MCP exposure. Both deferred exposures leave tools out of the codemode\n * description; they differ only in which tool the MCP extension activates to reach them.\n */\nexport function toToolExposure(exposure: McpExposure): ToolExposure {\n\treturn exposure === \"codemode-deferred\" ? \"deferred\" : exposure;\n}\n\n/** Provider tool names are limited to 64 characters of `[A-Za-z0-9_-]`. */\nconst MAX_TOOL_NAME_LENGTH = 64;\n/** Model-facing text of an MCP result beyond this is cut in the middle. */\nexport const MCP_OUTPUT_MAX_BYTES = 20 * 1024;\n/** Result lines shown before the output is expanded. */\nconst OUTPUT_PREVIEW_LINES = 5;\n/** Tool that reads the resources named by resource links. */\nexport const READ_MCP_RESOURCE_TOOL = \"read_mcp_resource\";\n\nexport interface McpToolDetails {\n\tserver: string;\n\ttool: string;\n\t/** Temp file with the full text output, when the model-facing text was truncated. */\n\tfullOutputPath?: string;\n}\n\n/**\n * Saves the full text of a truncated result, or a binary resource, and returns the file path.\n * `extension` includes the dot, for example `.txt`.\n */\nexport type McpOutputSaver = (data: string | Uint8Array, extension: string) => Promise<string>;\n\nexport async function saveToTempFile(data: string | Uint8Array, extension: string): Promise<string> {\n\tconst path = join(tmpdir(), `pi-mcp-${randomBytes(8).toString(\"hex\")}${extension}`);\n\t// Results can carry private data, so only the user may read the file.\n\tawait writeFile(path, data, { mode: 0o600 });\n\treturn path;\n}\n\nexport interface McpToolCaller {\n\tcallTool(name: string, args: Record<string, unknown>, options: McpRequestOptions): Promise<CallToolResult>;\n}\n\n/**\n * `mcp__<server>__<tool>`, sanitized and shortened with a hash suffix when too long. `isTaken`\n * reports names already used by a different MCP tool: sanitizing can map two tools to one name\n * (`a.b` and `a_b`), and the second then gets the hash suffix too.\n */\nexport function createMcpToolName(\n\tserver: string,\n\ttool: string,\n\tisTaken: (name: string) => boolean = () => false,\n): string {\n\tconst name = `mcp__${server}__${tool}`.replace(/[^A-Za-z0-9_-]/g, \"_\");\n\tif (name.length <= MAX_TOOL_NAME_LENGTH && !isTaken(name)) return name;\n\tconst hash = createHash(\"sha256\").update(`${server}\\0${tool}`).digest(\"hex\").slice(0, 8);\n\treturn `${name.slice(0, MAX_TOOL_NAME_LENGTH - hash.length - 1)}_${hash}`;\n}\n\nfunction textOf(content: readonly (TextContent | ImageContent)[]): string {\n\treturn content\n\t\t.filter((block): block is TextContent => block.type === \"text\")\n\t\t.map((block) => block.text)\n\t\t.join(\"\\n\");\n}\n\n/**\n * Output schema of every MCP tool: the `CallToolResult` scripts receive, with the tool's own output\n * schema as `structuredContent`. Codemode detects this shape to render `CallToolResult<T>`\n * declarations.\n */\nexport function createMcpResultSchema(structuredContentSchema: Record<string, unknown> | undefined): TSchema {\n\treturn {\n\t\ttype: \"object\",\n\t\tproperties: {\n\t\t\tcontent: { type: \"array\", items: { type: \"object\" } },\n\t\t\t...(structuredContentSchema ? { structuredContent: structuredContentSchema } : {}),\n\t\t\tisError: { type: \"boolean\" },\n\t\t\t_meta: { type: \"object\" },\n\t\t},\n\t\trequired: [\"content\"],\n\t} as unknown as TSchema;\n}\n\n/**\n * Keep model-facing text within {@link MCP_OUTPUT_MAX_BYTES}. Longer text becomes one text block in\n * Codex's truncation format, followed by the path of the file with the full text; images follow it.\n */\nexport async function limitMcpContent(\n\tcontent: (TextContent | ImageContent)[],\n\tsaveOutput: McpOutputSaver = saveToTempFile,\n): Promise<{ content: (TextContent | ImageContent)[]; fullOutputPath?: string }> {\n\tconst combined = textOf(content);\n\tconst truncation = truncateMiddle(combined, MCP_OUTPUT_MAX_BYTES);\n\tif (!truncation.truncated) return { content };\n\tlet fullOutputPath: string | undefined;\n\tlet where: string;\n\ttry {\n\t\tfullOutputPath = await saveOutput(combined, \".txt\");\n\t\twhere = `[Full output: ${fullOutputPath} (read it with offset/limit)]`;\n\t} catch (error) {\n\t\twhere = `[Could not save the full output: ${error instanceof Error ? error.message : String(error)}]`;\n\t}\n\tconst tokens = Math.ceil(truncation.totalBytes / 4);\n\tconst text = `Warning: truncated output (original token count: ${tokens})\\nTotal output lines: ${truncation.totalLines}\\n\\n${truncation.content}\\n\\n${where}`;\n\treturn {\n\t\tcontent: [{ type: \"text\", text }, ...content.filter((block) => block.type === \"image\")],\n\t\t...(fullOutputPath ? { fullOutputPath } : {}),\n\t};\n}\n\nexport interface ConvertMcpResultOptions {\n\t/** Saves truncated text and binary resources. Default: a temp file. */\n\tsaveOutput?: McpOutputSaver;\n\t/** Whether the server's resources can be read with `read_mcp_resource`, which resource links then name. */\n\treadableResources?: boolean;\n}\n\n/** File extension for a saved binary resource: the one its URI ends in, else `.bin`. */\nfunction extensionOf(uri: string): string {\n\tconst path = URL.canParse(uri) ? new URL(uri).pathname : uri;\n\treturn /\\.[A-Za-z0-9]{1,8}$/.exec(path)?.[0] ?? \".bin\";\n}\n\n/** Blobs of these types are shown as text. */\nfunction isTextMimeType(mimeType: string | undefined): boolean {\n\tif (!mimeType) return false;\n\tconst type = mimeType.split(\";\", 1)[0].trim().toLowerCase();\n\treturn type.startsWith(\"text/\") || type === \"application/json\" || type.endsWith(\"+json\") || type.endsWith(\"+xml\");\n}\n\n/** Model-facing content of one block of `server`'s result. */\nasync function blockToContent(\n\tserver: string,\n\tblock: ContentBlock,\n\toptions: ConvertMcpResultOptions,\n): Promise<(TextContent | ImageContent)[]> {\n\tif (block.type === \"resource_link\") {\n\t\tconst details = [block.mimeType, block.size === undefined ? undefined : formatSize(block.size)].filter(Boolean);\n\t\tconst read = options.readableResources ? `. Read it with ${READ_MCP_RESOURCE_TOOL} (server \"${server}\")` : \"\";\n\t\tconst description = block.description ? `: ${block.description}` : \"\";\n\t\treturn [\n\t\t\t{\n\t\t\t\ttype: \"text\",\n\t\t\t\ttext: `[Resource ${block.uri} \"${block.title ?? block.name}\"${details.length > 0 ? ` (${details.join(\", \")})` : \"\"}${description}${read}]`,\n\t\t\t},\n\t\t];\n\t}\n\tif (block.type === \"resource\" && \"blob\" in block.resource && !block.resource.mimeType?.startsWith(\"image/\")) {\n\t\tconst { uri, mimeType, blob } = block.resource;\n\t\tconst data = Buffer.from(blob, \"base64\");\n\t\tif (isTextMimeType(mimeType)) return [{ type: \"text\", text: data.toString(\"utf8\") }];\n\t\tconst kind = `${mimeType ?? \"unknown type\"}, ${formatSize(data.length)}`;\n\t\ttry {\n\t\t\tconst path = await (options.saveOutput ?? saveToTempFile)(data, extensionOf(uri));\n\t\t\treturn [{ type: \"text\", text: `[Binary resource ${uri} (${kind}) saved to ${path}]` }];\n\t\t} catch (error) {\n\t\t\tconst reason = error instanceof Error ? error.message : String(error);\n\t\t\treturn [{ type: \"text\", text: `[Binary resource ${uri} (${kind}) could not be saved: ${reason}]` }];\n\t\t}\n\t}\n\treturn toLlmContent({ content: [block] });\n}\n\n/** Model-facing content of `server`'s content blocks, before the output limit. */\nexport async function toModelContent(\n\tserver: string,\n\tblocks: readonly ContentBlock[],\n\toptions: ConvertMcpResultOptions = {},\n): Promise<(TextContent | ImageContent)[]> {\n\treturn (await Promise.all(blocks.map((block) => blockToContent(server, block, options)))).flat();\n}\n\n/** Convert an MCP result. `isError` results become error results that keep the structured result. */\nexport async function convertMcpResult(\n\tserver: string,\n\ttool: string,\n\tresult: CallToolResult,\n\toptions: ConvertMcpResultOptions = {},\n): Promise<AgentToolResult<McpToolDetails>> {\n\t// Without content blocks, toLlmContent falls back to the structured content as JSON.\n\tconst converted: (TextContent | ImageContent)[] =\n\t\tresult.content.length > 0 ? await toModelContent(server, result.content, options) : toLlmContent(result);\n\tif (result.isError && textOf(converted) === \"\") {\n\t\tconverted.push({ type: \"text\", text: `MCP tool ${server}/${tool} returned an error` });\n\t}\n\tconst { content, fullOutputPath } = await limitMcpContent(converted, options.saveOutput);\n\tconst { _meta: _ignored, ...scriptResult } = result;\n\treturn {\n\t\tcontent,\n\t\tdetails: { server, tool, ...(fullOutputPath ? { fullOutputPath } : {}) },\n\t\tstructuredContent: scriptResult as unknown as JsonValue,\n\t\t...(result.isError ? { isError: true } : {}),\n\t};\n}\n\n/**\n * Tool input schemas must be objects. MCP servers may omit `type`, and some providers reject object\n * schemas without `properties`.\n */\nfunction toParameters(schema: Record<string, unknown>): TSchema {\n\treturn {\n\t\t...schema,\n\t\ttype: schema.type ?? \"object\",\n\t\t...(schema.properties === undefined ? { properties: {} } : {}),\n\t} as unknown as TSchema;\n}\n\nconst ANNOTATION_HINTS = [\"readOnlyHint\", \"destructiveHint\", \"idempotentHint\", \"openWorldHint\"] as const;\n\n/** The boolean hints of an MCP tool's annotations, or undefined when it has none. */\nfunction toToolAnnotations(tool: McpTool): ToolAnnotations | undefined {\n\tconst annotations: ToolAnnotations = {};\n\tfor (const hint of ANNOTATION_HINTS) {\n\t\tconst value = tool.annotations?.[hint];\n\t\tif (typeof value === \"boolean\") annotations[hint] = value;\n\t}\n\treturn Object.keys(annotations).length > 0 ? annotations : undefined;\n}\n\nexport function createMcpToolDefinition(options: {\n\tserver: string;\n\ttool: McpTool;\n\tname: string;\n\texposure: McpExposure;\n\tnamespace: ToolNamespace;\n\ttimeoutMs: number;\n\tgetClient: () => Promise<McpToolCaller>;\n\t/** Whether `read_mcp_resource` can read the server's resources. */\n\treadableResources?: () => boolean;\n}): ToolDefinition<TSchema, McpToolDetails> {\n\tconst { server, tool } = options;\n\tconst title = tool.title ?? tool.annotations?.title;\n\tconst annotations = toToolAnnotations(tool);\n\tconst label = `${server}/${tool.name}`;\n\treturn {\n\t\tname: options.name,\n\t\tlabel,\n\t\tdescription: tool.description?.trim() || title || `MCP tool ${tool.name} from server ${server}`,\n\t\tparameters: toParameters(tool.inputSchema),\n\t\toutputSchema: createMcpResultSchema(tool.outputSchema),\n\t\texposure: toToolExposure(options.exposure),\n\t\tnamespace: options.namespace,\n\t\t...(annotations ? { annotations } : {}),\n\t\trenderCall(args, theme, context) {\n\t\t\tconst component = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\tcomponent.setText(formatToolCallWithArgs(label, args, theme, context.expanded));\n\t\t\treturn component;\n\t\t},\n\t\trenderResult(result, options, theme, context) {\n\t\t\tconst output = getTextOutput(result, context.showImages).trim();\n\t\t\tconst lines = output ? replaceTabs(output).split(\"\\n\") : [];\n\t\t\tconst shown = options.expanded ? lines : lines.slice(0, OUTPUT_PREVIEW_LINES);\n\t\t\tconst color = context.isError ? \"error\" : \"toolOutput\";\n\t\t\tlet text = shown.map((line) => theme.fg(color, line)).join(\"\\n\");\n\t\t\tif (shown.length < lines.length) {\n\t\t\t\ttext += `\\n${theme.fg(\"muted\", `... (${lines.length - shown.length} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")}${theme.fg(\"muted\", \")\")}`;\n\t\t\t}\n\t\t\tconst component = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\tcomponent.setText(text ? `\\n${text}` : \"\");\n\t\t\treturn component;\n\t\t},\n\t\tasync execute(_toolCallId, params, signal, onUpdate) {\n\t\t\tconst client = await options.getClient();\n\t\t\tconst result = await client.callTool(tool.name, (params ?? {}) as Record<string, unknown>, {\n\t\t\t\tsignal,\n\t\t\t\ttimeoutMs: options.timeoutMs,\n\t\t\t\tonProgress: (progress) => {\n\t\t\t\t\tconst total = progress.total === undefined ? \"\" : `/${progress.total}`;\n\t\t\t\t\tconst text = progress.message ?? `Progress ${progress.progress}${total}`;\n\t\t\t\t\tonUpdate?.({ content: [{ type: \"text\", text }], details: { server, tool: tool.name } });\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn convertMcpResult(server, tool.name, result, { readableResources: options.readableResources?.() });\n\t\t},\n\t};\n}\n"]}
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../../../src/extensions/mcp/tools.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Adapts MCP tools to pi tool definitions.\n *\n * Results map onto pi's model-facing content (text and images). Text over 20KB keeps its start and\n * end with the middle cut out, like Codex does, and the full text is saved to a temp file the model\n * can read. Binary resources other than images are saved to temp files too, and resource links name\n * the `read_mcp_resource` tool. Codemode scripts receive the whole `CallToolResult` without `_meta`\n * (`content` blocks as sent by the server, `structuredContent`, `isError`), never truncated: it is\n * the tool's `structuredContent`, and every MCP tool declares a `CallToolResult` output schema. MCP\n * errors (`isError`) are error results for the model, but scripts still resolve to the result.\n */\n\nimport { createHash, randomBytes } from \"node:crypto\";\nimport { writeFile } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { AgentToolResult } from \"@earendil-works/pi-agent-core\";\nimport type { ImageContent, JsonValue, TextContent } from \"@earendil-works/pi-ai\";\nimport {\n\ttype CallToolResult,\n\ttype ContentBlock,\n\ttype McpRequestOptions,\n\ttype Tool as McpTool,\n\ttoLlmContent,\n} from \"@earendil-works/pi-mcp\";\nimport { Container, Spacer, Text } from \"@earendil-works/pi-tui\";\nimport type { TSchema } from \"typebox\";\nimport type { ToolAnnotations, ToolDefinition, ToolExposure, ToolNamespace } from \"../../core/extensions/types.ts\";\nimport { formatToolCallWithArgs, getTextOutput, replaceTabs } from \"../../core/tools/render-utils.ts\";\nimport { formatSize, truncateMiddle } from \"../../core/tools/truncate.ts\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport { VisualLinePreview } from \"../../modes/interactive/components/visual-truncate.ts\";\nimport type { McpExposure } from \"./config.ts\";\n\n/**\n * Tool exposure of an MCP exposure. `codemode` and `deferred` both leave tools out of the codemode\n * description; they differ only in which tool the MCP extension activates to reach them.\n */\nexport function toToolExposure(exposure: McpExposure): ToolExposure {\n\treturn exposure === \"codemode\" ? \"deferred\" : exposure;\n}\n\n/** Provider tool names are limited to 64 characters of `[A-Za-z0-9_-]`. */\nconst MAX_TOOL_NAME_LENGTH = 64;\n/** Model-facing text of an MCP result beyond this is cut in the middle. */\nexport const MCP_OUTPUT_MAX_BYTES = 20 * 1024;\n/** Visual (wrapped) result lines shown before the output is expanded. */\nconst OUTPUT_PREVIEW_LINES = 5;\n/** Tool that reads the resources named by resource links. */\nexport const READ_MCP_RESOURCE_TOOL = \"read_mcp_resource\";\n\nexport interface McpToolDetails {\n\tserver: string;\n\ttool: string;\n\t/** Temp file with the full text output, when the model-facing text was truncated. */\n\tfullOutputPath?: string;\n}\n\n/**\n * Saves the full text of a truncated result, or a binary resource, and returns the file path.\n * `extension` includes the dot, for example `.txt`.\n */\nexport type McpOutputSaver = (data: string | Uint8Array, extension: string) => Promise<string>;\n\nexport async function saveToTempFile(data: string | Uint8Array, extension: string): Promise<string> {\n\tconst path = join(tmpdir(), `pi-mcp-${randomBytes(8).toString(\"hex\")}${extension}`);\n\t// Results can carry private data, so only the user may read the file.\n\tawait writeFile(path, data, { mode: 0o600 });\n\treturn path;\n}\n\nexport interface McpToolCaller {\n\tcallTool(name: string, args: Record<string, unknown>, options: McpRequestOptions): Promise<CallToolResult>;\n}\n\n/**\n * `mcp__<server>__<tool>`, sanitized and shortened with a hash suffix when too long. Like Codex,\n * everything but `[A-Za-z0-9_]` becomes `_`, so the name is also the identifier codemode scripts\n * call it by. `isTaken` reports names used by a different MCP tool: sanitizing can map two tools to\n * one name (`a-b` and `a_b`), which then get the hash suffix.\n */\nexport function createMcpToolName(\n\tserver: string,\n\ttool: string,\n\tisTaken: (name: string) => boolean = () => false,\n): string {\n\tconst name = `mcp__${server}__${tool}`.replace(/[^A-Za-z0-9_]/g, \"_\");\n\tif (name.length <= MAX_TOOL_NAME_LENGTH && !isTaken(name)) return name;\n\tconst hash = createHash(\"sha256\").update(`${server}\\0${tool}`).digest(\"hex\").slice(0, 8);\n\treturn `${name.slice(0, MAX_TOOL_NAME_LENGTH - hash.length - 1)}_${hash}`;\n}\n\nfunction textOf(content: readonly (TextContent | ImageContent)[]): string {\n\treturn content\n\t\t.filter((block): block is TextContent => block.type === \"text\")\n\t\t.map((block) => block.text)\n\t\t.join(\"\\n\");\n}\n\n/**\n * Output schema of every MCP tool: the `CallToolResult` scripts receive, with the tool's own output\n * schema as `structuredContent`. Codemode detects this shape to render `CallToolResult<T>`\n * declarations.\n */\nexport function createMcpResultSchema(structuredContentSchema: Record<string, unknown> | undefined): TSchema {\n\treturn {\n\t\ttype: \"object\",\n\t\tproperties: {\n\t\t\tcontent: { type: \"array\", items: { type: \"object\" } },\n\t\t\t...(structuredContentSchema ? { structuredContent: structuredContentSchema } : {}),\n\t\t\tisError: { type: \"boolean\" },\n\t\t\t_meta: { type: \"object\" },\n\t\t},\n\t\trequired: [\"content\"],\n\t} as unknown as TSchema;\n}\n\n/**\n * Keep model-facing text within {@link MCP_OUTPUT_MAX_BYTES}. Longer text becomes one text block in\n * Codex's truncation format, followed by the path of the file with the full text; images follow it.\n */\nexport async function limitMcpContent(\n\tcontent: (TextContent | ImageContent)[],\n\tsaveOutput: McpOutputSaver = saveToTempFile,\n): Promise<{ content: (TextContent | ImageContent)[]; fullOutputPath?: string }> {\n\tconst combined = textOf(content);\n\tconst truncation = truncateMiddle(combined, MCP_OUTPUT_MAX_BYTES);\n\tif (!truncation.truncated) return { content };\n\tlet fullOutputPath: string | undefined;\n\tlet where: string;\n\ttry {\n\t\tfullOutputPath = await saveOutput(combined, \".txt\");\n\t\twhere = `[Full output: ${fullOutputPath} (read it with offset/limit)]`;\n\t} catch (error) {\n\t\twhere = `[Could not save the full output: ${error instanceof Error ? error.message : String(error)}]`;\n\t}\n\tconst tokens = Math.ceil(truncation.totalBytes / 4);\n\tconst text = `Warning: truncated output (original token count: ${tokens})\\nTotal output lines: ${truncation.totalLines}\\n\\n${truncation.content}\\n\\n${where}`;\n\treturn {\n\t\tcontent: [{ type: \"text\", text }, ...content.filter((block) => block.type === \"image\")],\n\t\t...(fullOutputPath ? { fullOutputPath } : {}),\n\t};\n}\n\nexport interface ConvertMcpResultOptions {\n\t/** Saves truncated text and binary resources. Default: a temp file. */\n\tsaveOutput?: McpOutputSaver;\n\t/** Whether the server's resources can be read with `read_mcp_resource`, which resource links then name. */\n\treadableResources?: boolean;\n}\n\n/** File extension for a saved binary resource: the one its URI ends in, else `.bin`. */\nfunction extensionOf(uri: string): string {\n\tconst path = URL.canParse(uri) ? new URL(uri).pathname : uri;\n\treturn /\\.[A-Za-z0-9]{1,8}$/.exec(path)?.[0] ?? \".bin\";\n}\n\n/** Blobs of these types are shown as text. */\nfunction isTextMimeType(mimeType: string | undefined): boolean {\n\tif (!mimeType) return false;\n\tconst type = mimeType.split(\";\", 1)[0].trim().toLowerCase();\n\treturn type.startsWith(\"text/\") || type === \"application/json\" || type.endsWith(\"+json\") || type.endsWith(\"+xml\");\n}\n\n/** Model-facing content of one block of `server`'s result. */\nasync function blockToContent(\n\tserver: string,\n\tblock: ContentBlock,\n\toptions: ConvertMcpResultOptions,\n): Promise<(TextContent | ImageContent)[]> {\n\tif (block.type === \"resource_link\") {\n\t\tconst details = [block.mimeType, block.size === undefined ? undefined : formatSize(block.size)].filter(Boolean);\n\t\tconst read = options.readableResources ? `. Read it with ${READ_MCP_RESOURCE_TOOL} (server \"${server}\")` : \"\";\n\t\tconst description = block.description ? `: ${block.description}` : \"\";\n\t\treturn [\n\t\t\t{\n\t\t\t\ttype: \"text\",\n\t\t\t\ttext: `[Resource ${block.uri} \"${block.title ?? block.name}\"${details.length > 0 ? ` (${details.join(\", \")})` : \"\"}${description}${read}]`,\n\t\t\t},\n\t\t];\n\t}\n\tif (block.type === \"resource\" && \"blob\" in block.resource && !block.resource.mimeType?.startsWith(\"image/\")) {\n\t\tconst { uri, mimeType, blob } = block.resource;\n\t\tconst data = Buffer.from(blob, \"base64\");\n\t\tif (isTextMimeType(mimeType)) return [{ type: \"text\", text: data.toString(\"utf8\") }];\n\t\tconst kind = `${mimeType ?? \"unknown type\"}, ${formatSize(data.length)}`;\n\t\ttry {\n\t\t\tconst path = await (options.saveOutput ?? saveToTempFile)(data, extensionOf(uri));\n\t\t\treturn [{ type: \"text\", text: `[Binary resource ${uri} (${kind}) saved to ${path}]` }];\n\t\t} catch (error) {\n\t\t\tconst reason = error instanceof Error ? error.message : String(error);\n\t\t\treturn [{ type: \"text\", text: `[Binary resource ${uri} (${kind}) could not be saved: ${reason}]` }];\n\t\t}\n\t}\n\treturn toLlmContent({ content: [block] });\n}\n\n/** Model-facing content of `server`'s content blocks, before the output limit. */\nexport async function toModelContent(\n\tserver: string,\n\tblocks: readonly ContentBlock[],\n\toptions: ConvertMcpResultOptions = {},\n): Promise<(TextContent | ImageContent)[]> {\n\treturn (await Promise.all(blocks.map((block) => blockToContent(server, block, options)))).flat();\n}\n\n/** Convert an MCP result. `isError` results become error results that keep the structured result. */\nexport async function convertMcpResult(\n\tserver: string,\n\ttool: string,\n\tresult: CallToolResult,\n\toptions: ConvertMcpResultOptions = {},\n): Promise<AgentToolResult<McpToolDetails>> {\n\t// Without content blocks, toLlmContent falls back to the structured content as JSON.\n\tconst converted: (TextContent | ImageContent)[] =\n\t\tresult.content.length > 0 ? await toModelContent(server, result.content, options) : toLlmContent(result);\n\tif (result.isError && textOf(converted) === \"\") {\n\t\tconverted.push({ type: \"text\", text: `MCP tool ${server}/${tool} returned an error` });\n\t}\n\tconst { content, fullOutputPath } = await limitMcpContent(converted, options.saveOutput);\n\tconst { _meta: _ignored, ...scriptResult } = result;\n\treturn {\n\t\tcontent,\n\t\tdetails: { server, tool, ...(fullOutputPath ? { fullOutputPath } : {}) },\n\t\tstructuredContent: scriptResult as unknown as JsonValue,\n\t\t...(result.isError ? { isError: true } : {}),\n\t};\n}\n\n/**\n * Tool input schemas must be objects. MCP servers may omit `type`, and some providers reject object\n * schemas without `properties`.\n */\nfunction toParameters(schema: Record<string, unknown>): TSchema {\n\treturn {\n\t\t...schema,\n\t\ttype: schema.type ?? \"object\",\n\t\t...(schema.properties === undefined ? { properties: {} } : {}),\n\t} as unknown as TSchema;\n}\n\nconst ANNOTATION_HINTS = [\"readOnlyHint\", \"destructiveHint\", \"idempotentHint\", \"openWorldHint\"] as const;\n\n/** The boolean hints of an MCP tool's annotations, or undefined when it has none. */\nfunction toToolAnnotations(tool: McpTool): ToolAnnotations | undefined {\n\tconst annotations: ToolAnnotations = {};\n\tfor (const hint of ANNOTATION_HINTS) {\n\t\tconst value = tool.annotations?.[hint];\n\t\tif (typeof value === \"boolean\") annotations[hint] = value;\n\t}\n\treturn Object.keys(annotations).length > 0 ? annotations : undefined;\n}\n\nexport function createMcpToolDefinition(options: {\n\tserver: string;\n\ttool: McpTool;\n\tname: string;\n\texposure: McpExposure;\n\tnamespace: ToolNamespace;\n\ttimeoutMs: number;\n\tgetClient: () => Promise<McpToolCaller>;\n\t/** Whether `read_mcp_resource` can read the server's resources. */\n\treadableResources?: () => boolean;\n}): ToolDefinition<TSchema, McpToolDetails> {\n\tconst { server, tool } = options;\n\tconst title = tool.title ?? tool.annotations?.title;\n\tconst annotations = toToolAnnotations(tool);\n\tconst label = `${server}/${tool.name}`;\n\treturn {\n\t\tname: options.name,\n\t\tlabel,\n\t\tdescription: tool.description?.trim() || title || `MCP tool ${tool.name} from server ${server}`,\n\t\tparameters: toParameters(tool.inputSchema),\n\t\toutputSchema: createMcpResultSchema(tool.outputSchema),\n\t\texposure: toToolExposure(options.exposure),\n\t\tnamespace: options.namespace,\n\t\t...(annotations ? { annotations } : {}),\n\t\trenderCall(args, theme, context) {\n\t\t\tconst component = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\tcomponent.setText(formatToolCallWithArgs(label, args, theme, context.expanded));\n\t\t\treturn component;\n\t\t},\n\t\trenderResult(result, options, theme, context) {\n\t\t\tconst component = (context.lastComponent as Container | undefined) ?? new Container();\n\t\t\tcomponent.clear();\n\t\t\tconst output = getTextOutput(result, context.showImages).trim();\n\t\t\tif (!output) return component;\n\t\t\tconst color = context.isError ? \"error\" : \"toolOutput\";\n\t\t\tconst styled = replaceTabs(output)\n\t\t\t\t.split(\"\\n\")\n\t\t\t\t.map((line) => theme.fg(color, line))\n\t\t\t\t.join(\"\\n\");\n\t\t\tcomponent.addChild(new Spacer(1));\n\t\t\tif (options.expanded) {\n\t\t\t\tcomponent.addChild(new Text(styled, 0, 0));\n\t\t\t} else {\n\t\t\t\t// Limit wrapped lines, not logical ones: MCP results are often one long JSON line.\n\t\t\t\tcomponent.addChild(\n\t\t\t\t\tnew VisualLinePreview({\n\t\t\t\t\t\ttext: styled,\n\t\t\t\t\t\tmaxVisualLines: OUTPUT_PREVIEW_LINES,\n\t\t\t\t\t\tkeep: \"start\",\n\t\t\t\t\t\tformatHint: (hidden) =>\n\t\t\t\t\t\t\t`${theme.fg(\"muted\", `... (${hidden} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")}${theme.fg(\"muted\", \")\")}`,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\tconst fullOutputPath = result.details?.fullOutputPath;\n\t\t\t\tif (fullOutputPath) component.addChild(new Text(theme.fg(\"muted\", `Full output: ${fullOutputPath}`), 0, 0));\n\t\t\t}\n\t\t\treturn component;\n\t\t},\n\t\tasync execute(_toolCallId, params, signal, onUpdate) {\n\t\t\tconst client = await options.getClient();\n\t\t\tconst result = await client.callTool(tool.name, (params ?? {}) as Record<string, unknown>, {\n\t\t\t\tsignal,\n\t\t\t\ttimeoutMs: options.timeoutMs,\n\t\t\t\tonProgress: (progress) => {\n\t\t\t\t\tconst total = progress.total === undefined ? \"\" : `/${progress.total}`;\n\t\t\t\t\tconst text = progress.message ?? `Progress ${progress.progress}${total}`;\n\t\t\t\t\tonUpdate?.({ content: [{ type: \"text\", text }], details: { server, tool: tool.name } });\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn convertMcpResult(server, tool.name, result, { readableResources: options.readableResources?.() });\n\t\t},\n\t};\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../../../src/extensions/mcp/ui.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACN,KAAK,SAAS,EAEd,KAAK,SAAS,EAEd,KAAK,UAAU,EAIf,KAAK,GAAG,EAGR,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAC9E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAGpE,OAAO,EAAsB,KAAK,KAAK,EAAE,MAAM,wCAAwC,CAAC;AAExF,MAAM,WAAW,OAAO;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,6BAA6B;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kDAAkD;IAClD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,qCAAqC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sDAAsD;IACtD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mDAAmD;IACnD,YAAY,EAAE,MAAM,CAAC;IACrB,kDAAkD;IAClD,WAAW,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,KAAK;IACrB;;;OAGG;IACH,IAAI,CAAC,KAAK,EAAE,MAAM,OAAO,EAAE,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC1G,8CAA8C;IAC9C,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7C;;;OAGG;IACH,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;CACvG;AAiBD,qBAAa,cAAe,YAAW,KAAK,EAAE,SAAS,EAAE,SAAS;IACjE,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAM;IAC1B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;IAC9B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAqB;IACjD,OAAO,CAAC,OAAO,CAAY;IAC3B,OAAO,CAAC,YAAY,CAAuC;IAC3D,OAAO,CAAC,WAAW,CAAwB;IAC3C,OAAO,CAAC,QAAQ,CAAS;IAEzB,YAAY,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAKlE;IAED,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,IAAI,OAAO,CAAC,KAAK,EAAE,OAAO,EAGzB;IAED,OAAO,CAAC,UAAU;IASlB,IAAI,CAAC,KAAK,EAAE,MAAM,OAAO,EAAE,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAkDxG;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAE3C;IAED,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAkDrG;IAED,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAG9B;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAI9B;IAED,UAAU,IAAI,IAAI,CAEjB;CACD;AAED,yDAAyD;AACzD,wBAAsB,cAAc,CACnC,GAAG,EAAE,uBAAuB,EAC5B,MAAM,EAAE,CAAC,EAAE,EAAE,KAAK,KAAK,OAAO,CAAC,IAAI,CAAC,GAClC,OAAO,CAAC,IAAI,CAAC,CAYf"}
1
+ {"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../../../src/extensions/mcp/ui.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACN,KAAK,SAAS,EAEd,KAAK,SAAS,EAGd,KAAK,UAAU,EAIf,KAAK,GAAG,EAGR,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAC9E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAGpE,OAAO,EAAsB,KAAK,KAAK,EAAE,MAAM,wCAAwC,CAAC;AAExF,MAAM,WAAW,OAAO;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,6BAA6B;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kDAAkD;IAClD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,qCAAqC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sDAAsD;IACtD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mDAAmD;IACnD,YAAY,EAAE,MAAM,CAAC;IACrB,kDAAkD;IAClD,WAAW,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,KAAK;IACrB;;;OAGG;IACH,IAAI,CAAC,KAAK,EAAE,MAAM,OAAO,EAAE,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC1G,8CAA8C;IAC9C,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7C;;;OAGG;IACH,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;CACvG;AAiBD,qBAAa,cAAe,YAAW,KAAK,EAAE,SAAS,EAAE,SAAS;IACjE,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAM;IAC1B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;IAC9B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAqB;IACjD,OAAO,CAAC,OAAO,CAAY;IAC3B,OAAO,CAAC,YAAY,CAAuC;IAC3D,OAAO,CAAC,WAAW,CAAwB;IAC3C,OAAO,CAAC,QAAQ,CAAS;IAEzB,YAAY,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAKlE;IAED,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,IAAI,OAAO,CAAC,KAAK,EAAE,OAAO,EAGzB;IAED,OAAO,CAAC,UAAU;IASlB,IAAI,CAAC,KAAK,EAAE,MAAM,OAAO,EAAE,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAkDxG;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAE3C;IAED,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAoDrG;IAED,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAG9B;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAI9B;IAED,UAAU,IAAI,IAAI,CAEjB;CACD;AAED,yDAAyD;AACzD,wBAAsB,cAAc,CACnC,GAAG,EAAE,uBAAuB,EAC5B,MAAM,EAAE,CAAC,EAAE,EAAE,KAAK,KAAK,OAAO,CAAC,IAAI,CAAC,GAClC,OAAO,CAAC,IAAI,CAAC,CAYf"}
@@ -2,7 +2,7 @@
2
2
  * The `/mcp` manager view: menus that rebuild while servers connect, a read-only status screen, and
3
3
  * the sign-in screen that accepts a pasted redirect URL.
4
4
  */
5
- import { Container, Input, SelectList, Spacer, Text, truncateToWidth, visibleWidth, } from "@earendil-works/pi-tui";
5
+ import { Container, hyperlink, Input, SelectList, Spacer, Text, truncateToWidth, visibleWidth, } from "@earendil-works/pi-tui";
6
6
  import { DynamicBorder } from "../../modes/interactive/components/dynamic-border.js";
7
7
  import { keyHint } from "../../modes/interactive/components/keybinding-hints.js";
8
8
  import { getSelectListTheme } from "../../modes/interactive/theme/theme.js";
@@ -122,10 +122,12 @@ export class McpManagerView {
122
122
  }
123
123
  signal.addEventListener("abort", onAbort, { once: true });
124
124
  const input = new Input();
125
+ const clickHint = process.platform === "darwin" ? "Cmd+click to open" : "Ctrl+click to open";
125
126
  const body = [
126
127
  new Spacer(1),
127
128
  new Text(this.theme.fg("muted", "Approve access in your browser. If it did not open, visit:"), 1, 0),
128
- new Text(this.theme.fg("accent", authorizationUrl), 1, 0),
129
+ new Text(this.theme.fg("accent", hyperlink(authorizationUrl, authorizationUrl)), 1, 0),
130
+ new Text(this.theme.fg("dim", hyperlink(clickHint, authorizationUrl)), 1, 0),
129
131
  new Spacer(1),
130
132
  new Text(this.theme.fg("muted", "If the browser runs on another machine, paste the URL it was redirected to:"), 1, 0),
131
133
  input,
@@ -1 +1 @@
1
- {"version":3,"file":"ui.js","sourceRoot":"","sources":["../../../src/extensions/mcp/ui.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The `/mcp` manager view: menus that rebuild while servers connect, a read-only status screen, and\n * the sign-in screen that accepts a pasted redirect URL.\n */\n\nimport {\n\ttype Component,\n\tContainer,\n\ttype Focusable,\n\tInput,\n\ttype SelectItem,\n\tSelectList,\n\tSpacer,\n\tText,\n\ttype TUI,\n\ttruncateToWidth,\n\tvisibleWidth,\n} from \"@earendil-works/pi-tui\";\nimport type { ExtensionCommandContext } from \"../../core/extensions/types.ts\";\nimport type { KeybindingsManager } from \"../../core/keybindings.ts\";\nimport { DynamicBorder } from \"../../modes/interactive/components/dynamic-border.ts\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport { getSelectListTheme, type Theme } from \"../../modes/interactive/theme/theme.ts\";\n\nexport interface McpMenu {\n\ttitle: string;\n\t/** Shown below the title. */\n\tdetails?: string;\n\t/** Shown below the details in the error color. */\n\terror?: string;\n\titems: SelectItem[];\n\t/** Shown when there are no items. */\n\tempty?: string;\n\t/** Value of the item selected when the menu opens. */\n\tselected?: string;\n\t/** What the confirm key does, for the key hint. */\n\tconfirmLabel: string;\n\t/** What the cancel key does, for the key hint. */\n\tcancelLabel: string;\n}\n\nexport interface McpUi {\n\t/**\n\t * Show a menu and resolve to the chosen item's value, or undefined when cancelled. `subscribe`\n\t * rebuilds the menu on every change, keeping the selected item.\n\t */\n\tmenu(build: () => McpMenu, subscribe?: (listener: () => void) => () => void): Promise<string | undefined>;\n\t/** Show a message while an operation runs. */\n\tstatus(title: string, message: string): void;\n\t/**\n\t * Show the authorization URL and wait for a pasted redirect URL. Resolves to undefined when\n\t * cancelled or when `signal` aborts (the browser reached the callback).\n\t */\n\tredirectUrl(title: string, authorizationUrl: string, signal: AbortSignal): Promise<string | undefined>;\n}\n\nfunction frame(theme: Theme, title: string, body: Component[], footer?: string): Container {\n\tconst container = new Container();\n\tcontainer.addChild(new DynamicBorder((text: string) => theme.fg(\"accent\", text)));\n\tcontainer.addChild(new Text(theme.fg(\"accent\", theme.bold(title)), 1, 0));\n\tfor (const child of body) container.addChild(child);\n\tif (footer) {\n\t\tcontainer.addChild(new Spacer(1));\n\t\tcontainer.addChild(new Text(theme.fg(\"dim\", footer), 1, 0));\n\t}\n\tcontainer.addChild(new DynamicBorder((text: string) => theme.fg(\"accent\", text)));\n\treturn container;\n}\n\nconst MAX_VISIBLE_ITEMS = 12;\n\nexport class McpManagerView implements McpUi, Component, Focusable {\n\tprivate readonly tui: TUI;\n\tprivate readonly theme: Theme;\n\tprivate readonly keybindings: KeybindingsManager;\n\tprivate content: Container;\n\tprivate inputHandler: ((data: string) => void) | undefined;\n\tprivate inputTarget: Focusable | undefined;\n\tprivate _focused = false;\n\n\tconstructor(tui: TUI, theme: Theme, keybindings: KeybindingsManager) {\n\t\tthis.tui = tui;\n\t\tthis.theme = theme;\n\t\tthis.keybindings = keybindings;\n\t\tthis.content = frame(theme, \"MCP servers\", [new Text(theme.fg(\"muted\", \"Loading…\"), 1, 1)]);\n\t}\n\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t\tif (this.inputTarget) this.inputTarget.focused = value;\n\t}\n\n\tprivate setContent(content: Container, inputHandler?: (data: string) => void, inputTarget?: Focusable): void {\n\t\tif (this.inputTarget) this.inputTarget.focused = false;\n\t\tthis.content = content;\n\t\tthis.inputHandler = inputHandler;\n\t\tthis.inputTarget = inputTarget;\n\t\tif (this.inputTarget) this.inputTarget.focused = this._focused;\n\t\tthis.tui.requestRender();\n\t}\n\n\tmenu(build: () => McpMenu, subscribe?: (listener: () => void) => () => void): Promise<string | undefined> {\n\t\treturn new Promise((resolve) => {\n\t\t\tlet unsubscribe: (() => void) | undefined;\n\t\t\tlet settled = false;\n\t\t\tconst finish = (value: string | undefined) => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tunsubscribe?.();\n\t\t\t\tresolve(value);\n\t\t\t};\n\t\t\tlet selected: string | undefined;\n\t\t\tconst render = () => {\n\t\t\t\tconst menu = build();\n\t\t\t\tconst wanted = selected ?? menu.selected;\n\t\t\t\tconst body: Component[] = [];\n\t\t\t\tif (menu.details) body.push(new Text(this.theme.fg(\"muted\", menu.details), 1, 0));\n\t\t\t\tif (menu.error) body.push(new Text(this.theme.fg(\"error\", menu.error), 1, 0));\n\t\t\t\tbody.push(new Spacer(1));\n\t\t\t\tconst footer = `${keyHint(\"tui.select.confirm\", menu.confirmLabel)} • ${keyHint(\"tui.select.cancel\", menu.cancelLabel)}`;\n\t\t\t\tif (menu.items.length === 0) {\n\t\t\t\t\tbody.push(new Text(this.theme.fg(\"muted\", menu.empty ?? \"Nothing to show.\"), 1, 0));\n\t\t\t\t\tthis.setContent(\n\t\t\t\t\t\tframe(this.theme, menu.title, body, keyHint(\"tui.select.cancel\", menu.cancelLabel)),\n\t\t\t\t\t\t(data) => {\n\t\t\t\t\t\t\tif (this.keybindings.matches(data, \"tui.select.cancel\")) finish(undefined);\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst list = new SelectList(\n\t\t\t\t\tmenu.items,\n\t\t\t\t\tMath.min(menu.items.length, MAX_VISIBLE_ITEMS),\n\t\t\t\t\tgetSelectListTheme(),\n\t\t\t\t);\n\t\t\t\tconst index = menu.items.findIndex((item) => item.value === wanted);\n\t\t\t\tif (index !== -1) list.setSelectedIndex(index);\n\t\t\t\tselected = list.getSelectedItem()?.value;\n\t\t\t\tlist.onSelectionChange = (item) => {\n\t\t\t\t\tselected = item.value;\n\t\t\t\t};\n\t\t\t\tlist.onSelect = (item) => finish(item.value);\n\t\t\t\tlist.onCancel = () => finish(undefined);\n\t\t\t\tbody.push(list);\n\t\t\t\tthis.setContent(frame(this.theme, menu.title, body, footer), (data) => list.handleInput(data));\n\t\t\t};\n\t\t\trender();\n\t\t\tunsubscribe = subscribe?.(() => {\n\t\t\t\tif (!settled) render();\n\t\t\t});\n\t\t});\n\t}\n\n\tstatus(title: string, message: string): void {\n\t\tthis.setContent(frame(this.theme, title, [new Spacer(1), new Text(this.theme.fg(\"muted\", message), 1, 0)]));\n\t}\n\n\tredirectUrl(title: string, authorizationUrl: string, signal: AbortSignal): Promise<string | undefined> {\n\t\treturn new Promise((resolve) => {\n\t\t\tlet settled = false;\n\t\t\tconst finish = (value: string | undefined) => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tsignal.removeEventListener(\"abort\", onAbort);\n\t\t\t\tresolve(value);\n\t\t\t};\n\t\t\tconst onAbort = () => finish(undefined);\n\t\t\tif (signal.aborted) {\n\t\t\t\tfinish(undefined);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\tconst input = new Input();\n\t\t\tconst body: Component[] = [\n\t\t\t\tnew Spacer(1),\n\t\t\t\tnew Text(this.theme.fg(\"muted\", \"Approve access in your browser. If it did not open, visit:\"), 1, 0),\n\t\t\t\tnew Text(this.theme.fg(\"accent\", authorizationUrl), 1, 0),\n\t\t\t\tnew Spacer(1),\n\t\t\t\tnew Text(\n\t\t\t\t\tthis.theme.fg(\"muted\", \"If the browser runs on another machine, paste the URL it was redirected to:\"),\n\t\t\t\t\t1,\n\t\t\t\t\t0,\n\t\t\t\t),\n\t\t\t\tinput,\n\t\t\t];\n\t\t\tthis.setContent(\n\t\t\t\tframe(\n\t\t\t\t\tthis.theme,\n\t\t\t\t\ttitle,\n\t\t\t\t\tbody,\n\t\t\t\t\t`${keyHint(\"tui.select.confirm\", \"submit\")} • ${keyHint(\"tui.select.cancel\", \"cancel\")}`,\n\t\t\t\t),\n\t\t\t\t(data) => {\n\t\t\t\t\tif (this.keybindings.matches(data, \"tui.select.confirm\")) {\n\t\t\t\t\t\tconst value = input.getValue().trim();\n\t\t\t\t\t\tif (value) finish(value);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (this.keybindings.matches(data, \"tui.select.cancel\")) {\n\t\t\t\t\t\tfinish(undefined);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tinput.handleInput(data);\n\t\t\t\t},\n\t\t\t\tinput,\n\t\t\t);\n\t\t});\n\t}\n\n\thandleInput(data: string): void {\n\t\tthis.inputHandler?.(data);\n\t\tthis.tui.requestRender();\n\t}\n\n\trender(width: number): string[] {\n\t\treturn this.content\n\t\t\t.render(width)\n\t\t\t.map((line) => (visibleWidth(line) > width ? truncateToWidth(line, width, \"\") : line));\n\t}\n\n\tinvalidate(): void {\n\t\tthis.content.invalidate();\n\t}\n}\n\n/** Run `manage` in the manager view until it returns. */\nexport async function showMcpManager(\n\tctx: ExtensionCommandContext,\n\tmanage: (ui: McpUi) => Promise<void>,\n): Promise<void> {\n\tawait ctx.ui.custom<void>((tui, theme, keybindings, done) => {\n\t\tconst view = new McpManagerView(tui, theme, keybindings);\n\t\tvoid manage(view).then(\n\t\t\t() => done(),\n\t\t\t(error: unknown) => {\n\t\t\t\tctx.ui.notify(error instanceof Error ? error.message : String(error), \"error\");\n\t\t\t\tdone();\n\t\t\t},\n\t\t);\n\t\treturn view;\n\t});\n}\n"]}
1
+ {"version":3,"file":"ui.js","sourceRoot":"","sources":["../../../src/extensions/mcp/ui.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The `/mcp` manager view: menus that rebuild while servers connect, a read-only status screen, and\n * the sign-in screen that accepts a pasted redirect URL.\n */\n\nimport {\n\ttype Component,\n\tContainer,\n\ttype Focusable,\n\thyperlink,\n\tInput,\n\ttype SelectItem,\n\tSelectList,\n\tSpacer,\n\tText,\n\ttype TUI,\n\ttruncateToWidth,\n\tvisibleWidth,\n} from \"@earendil-works/pi-tui\";\nimport type { ExtensionCommandContext } from \"../../core/extensions/types.ts\";\nimport type { KeybindingsManager } from \"../../core/keybindings.ts\";\nimport { DynamicBorder } from \"../../modes/interactive/components/dynamic-border.ts\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport { getSelectListTheme, type Theme } from \"../../modes/interactive/theme/theme.ts\";\n\nexport interface McpMenu {\n\ttitle: string;\n\t/** Shown below the title. */\n\tdetails?: string;\n\t/** Shown below the details in the error color. */\n\terror?: string;\n\titems: SelectItem[];\n\t/** Shown when there are no items. */\n\tempty?: string;\n\t/** Value of the item selected when the menu opens. */\n\tselected?: string;\n\t/** What the confirm key does, for the key hint. */\n\tconfirmLabel: string;\n\t/** What the cancel key does, for the key hint. */\n\tcancelLabel: string;\n}\n\nexport interface McpUi {\n\t/**\n\t * Show a menu and resolve to the chosen item's value, or undefined when cancelled. `subscribe`\n\t * rebuilds the menu on every change, keeping the selected item.\n\t */\n\tmenu(build: () => McpMenu, subscribe?: (listener: () => void) => () => void): Promise<string | undefined>;\n\t/** Show a message while an operation runs. */\n\tstatus(title: string, message: string): void;\n\t/**\n\t * Show the authorization URL and wait for a pasted redirect URL. Resolves to undefined when\n\t * cancelled or when `signal` aborts (the browser reached the callback).\n\t */\n\tredirectUrl(title: string, authorizationUrl: string, signal: AbortSignal): Promise<string | undefined>;\n}\n\nfunction frame(theme: Theme, title: string, body: Component[], footer?: string): Container {\n\tconst container = new Container();\n\tcontainer.addChild(new DynamicBorder((text: string) => theme.fg(\"accent\", text)));\n\tcontainer.addChild(new Text(theme.fg(\"accent\", theme.bold(title)), 1, 0));\n\tfor (const child of body) container.addChild(child);\n\tif (footer) {\n\t\tcontainer.addChild(new Spacer(1));\n\t\tcontainer.addChild(new Text(theme.fg(\"dim\", footer), 1, 0));\n\t}\n\tcontainer.addChild(new DynamicBorder((text: string) => theme.fg(\"accent\", text)));\n\treturn container;\n}\n\nconst MAX_VISIBLE_ITEMS = 12;\n\nexport class McpManagerView implements McpUi, Component, Focusable {\n\tprivate readonly tui: TUI;\n\tprivate readonly theme: Theme;\n\tprivate readonly keybindings: KeybindingsManager;\n\tprivate content: Container;\n\tprivate inputHandler: ((data: string) => void) | undefined;\n\tprivate inputTarget: Focusable | undefined;\n\tprivate _focused = false;\n\n\tconstructor(tui: TUI, theme: Theme, keybindings: KeybindingsManager) {\n\t\tthis.tui = tui;\n\t\tthis.theme = theme;\n\t\tthis.keybindings = keybindings;\n\t\tthis.content = frame(theme, \"MCP servers\", [new Text(theme.fg(\"muted\", \"Loading…\"), 1, 1)]);\n\t}\n\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t\tif (this.inputTarget) this.inputTarget.focused = value;\n\t}\n\n\tprivate setContent(content: Container, inputHandler?: (data: string) => void, inputTarget?: Focusable): void {\n\t\tif (this.inputTarget) this.inputTarget.focused = false;\n\t\tthis.content = content;\n\t\tthis.inputHandler = inputHandler;\n\t\tthis.inputTarget = inputTarget;\n\t\tif (this.inputTarget) this.inputTarget.focused = this._focused;\n\t\tthis.tui.requestRender();\n\t}\n\n\tmenu(build: () => McpMenu, subscribe?: (listener: () => void) => () => void): Promise<string | undefined> {\n\t\treturn new Promise((resolve) => {\n\t\t\tlet unsubscribe: (() => void) | undefined;\n\t\t\tlet settled = false;\n\t\t\tconst finish = (value: string | undefined) => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tunsubscribe?.();\n\t\t\t\tresolve(value);\n\t\t\t};\n\t\t\tlet selected: string | undefined;\n\t\t\tconst render = () => {\n\t\t\t\tconst menu = build();\n\t\t\t\tconst wanted = selected ?? menu.selected;\n\t\t\t\tconst body: Component[] = [];\n\t\t\t\tif (menu.details) body.push(new Text(this.theme.fg(\"muted\", menu.details), 1, 0));\n\t\t\t\tif (menu.error) body.push(new Text(this.theme.fg(\"error\", menu.error), 1, 0));\n\t\t\t\tbody.push(new Spacer(1));\n\t\t\t\tconst footer = `${keyHint(\"tui.select.confirm\", menu.confirmLabel)} • ${keyHint(\"tui.select.cancel\", menu.cancelLabel)}`;\n\t\t\t\tif (menu.items.length === 0) {\n\t\t\t\t\tbody.push(new Text(this.theme.fg(\"muted\", menu.empty ?? \"Nothing to show.\"), 1, 0));\n\t\t\t\t\tthis.setContent(\n\t\t\t\t\t\tframe(this.theme, menu.title, body, keyHint(\"tui.select.cancel\", menu.cancelLabel)),\n\t\t\t\t\t\t(data) => {\n\t\t\t\t\t\t\tif (this.keybindings.matches(data, \"tui.select.cancel\")) finish(undefined);\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst list = new SelectList(\n\t\t\t\t\tmenu.items,\n\t\t\t\t\tMath.min(menu.items.length, MAX_VISIBLE_ITEMS),\n\t\t\t\t\tgetSelectListTheme(),\n\t\t\t\t);\n\t\t\t\tconst index = menu.items.findIndex((item) => item.value === wanted);\n\t\t\t\tif (index !== -1) list.setSelectedIndex(index);\n\t\t\t\tselected = list.getSelectedItem()?.value;\n\t\t\t\tlist.onSelectionChange = (item) => {\n\t\t\t\t\tselected = item.value;\n\t\t\t\t};\n\t\t\t\tlist.onSelect = (item) => finish(item.value);\n\t\t\t\tlist.onCancel = () => finish(undefined);\n\t\t\t\tbody.push(list);\n\t\t\t\tthis.setContent(frame(this.theme, menu.title, body, footer), (data) => list.handleInput(data));\n\t\t\t};\n\t\t\trender();\n\t\t\tunsubscribe = subscribe?.(() => {\n\t\t\t\tif (!settled) render();\n\t\t\t});\n\t\t});\n\t}\n\n\tstatus(title: string, message: string): void {\n\t\tthis.setContent(frame(this.theme, title, [new Spacer(1), new Text(this.theme.fg(\"muted\", message), 1, 0)]));\n\t}\n\n\tredirectUrl(title: string, authorizationUrl: string, signal: AbortSignal): Promise<string | undefined> {\n\t\treturn new Promise((resolve) => {\n\t\t\tlet settled = false;\n\t\t\tconst finish = (value: string | undefined) => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tsignal.removeEventListener(\"abort\", onAbort);\n\t\t\t\tresolve(value);\n\t\t\t};\n\t\t\tconst onAbort = () => finish(undefined);\n\t\t\tif (signal.aborted) {\n\t\t\t\tfinish(undefined);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\tconst input = new Input();\n\t\t\tconst clickHint = process.platform === \"darwin\" ? \"Cmd+click to open\" : \"Ctrl+click to open\";\n\t\t\tconst body: Component[] = [\n\t\t\t\tnew Spacer(1),\n\t\t\t\tnew Text(this.theme.fg(\"muted\", \"Approve access in your browser. If it did not open, visit:\"), 1, 0),\n\t\t\t\tnew Text(this.theme.fg(\"accent\", hyperlink(authorizationUrl, authorizationUrl)), 1, 0),\n\t\t\t\tnew Text(this.theme.fg(\"dim\", hyperlink(clickHint, authorizationUrl)), 1, 0),\n\t\t\t\tnew Spacer(1),\n\t\t\t\tnew Text(\n\t\t\t\t\tthis.theme.fg(\"muted\", \"If the browser runs on another machine, paste the URL it was redirected to:\"),\n\t\t\t\t\t1,\n\t\t\t\t\t0,\n\t\t\t\t),\n\t\t\t\tinput,\n\t\t\t];\n\t\t\tthis.setContent(\n\t\t\t\tframe(\n\t\t\t\t\tthis.theme,\n\t\t\t\t\ttitle,\n\t\t\t\t\tbody,\n\t\t\t\t\t`${keyHint(\"tui.select.confirm\", \"submit\")} • ${keyHint(\"tui.select.cancel\", \"cancel\")}`,\n\t\t\t\t),\n\t\t\t\t(data) => {\n\t\t\t\t\tif (this.keybindings.matches(data, \"tui.select.confirm\")) {\n\t\t\t\t\t\tconst value = input.getValue().trim();\n\t\t\t\t\t\tif (value) finish(value);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (this.keybindings.matches(data, \"tui.select.cancel\")) {\n\t\t\t\t\t\tfinish(undefined);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tinput.handleInput(data);\n\t\t\t\t},\n\t\t\t\tinput,\n\t\t\t);\n\t\t});\n\t}\n\n\thandleInput(data: string): void {\n\t\tthis.inputHandler?.(data);\n\t\tthis.tui.requestRender();\n\t}\n\n\trender(width: number): string[] {\n\t\treturn this.content\n\t\t\t.render(width)\n\t\t\t.map((line) => (visibleWidth(line) > width ? truncateToWidth(line, width, \"\") : line));\n\t}\n\n\tinvalidate(): void {\n\t\tthis.content.invalidate();\n\t}\n}\n\n/** Run `manage` in the manager view until it returns. */\nexport async function showMcpManager(\n\tctx: ExtensionCommandContext,\n\tmanage: (ui: McpUi) => Promise<void>,\n): Promise<void> {\n\tawait ctx.ui.custom<void>((tui, theme, keybindings, done) => {\n\t\tconst view = new McpManagerView(tui, theme, keybindings);\n\t\tvoid manage(view).then(\n\t\t\t() => done(),\n\t\t\t(error: unknown) => {\n\t\t\t\tctx.ui.notify(error instanceof Error ? error.message : String(error), \"error\");\n\t\t\t\tdone();\n\t\t\t},\n\t\t);\n\t\treturn view;\n\t});\n}\n"]}
@@ -28,7 +28,8 @@ export interface ToolRanker {
28
28
  export declare function tokenize(text: string): string[];
29
29
  /**
30
30
  * Search text of a tool: the name, the name with `_`
31
- * as spaces, the description, schema descriptions and property names, and the namespace.
31
+ * as spaces, the description, schema descriptions and property names, and the namespace with its
32
+ * description and instructions.
32
33
  */
33
34
  export declare function createToolSearchDocument(tool: Pick<ToolInfo, "name" | "description" | "parameters">, namespace?: ToolNamespace): ToolSearchDocument;
34
35
  /** Okapi BM25 with the usual parameters. Ties keep document order. */
@@ -64,9 +65,9 @@ export interface ToolSearchToolOptions {
64
65
  tools?: Pick<ExtensionAPI, "getAllTools" | "getActiveTools" | "setActiveTools">;
65
66
  }
66
67
  /**
67
- * The `tool_search` description. `sources` lists the namespaces whose tools can be found, with
68
- * their descriptions.
68
+ * The `tool_search` description. It does not list the searchable tools or their namespaces, so it
69
+ * stays the same while tools are registered, for example when MCP servers connect.
69
70
  */
70
- export declare function createToolSearchDescription(sources?: readonly ToolNamespace[]): string;
71
+ export declare const TOOL_SEARCH_DESCRIPTION = "# Tool discovery\n\nSearches over deferred tool metadata with BM25 and exposes matching tools for the next model call.\n\nSome of the tools, such as tools of MCP servers, may not have been provided to you upfront, and you should use this tool (`tool_search`) to search for the required tools. For MCP tool discovery, always use `tool_search`.";
71
72
  export declare function createToolSearchToolDefinition(options?: ToolSearchToolOptions): ToolDefinition<typeof toolSearchSchema, ToolSearchToolDetails>;
72
73
  //# sourceMappingURL=tool.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../../src/extensions/tool-search/tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EACX,YAAY,EACZ,cAAc,EAEd,QAAQ,EACR,aAAa,EACb,MAAM,gCAAgC,CAAC;AAExC,eAAO,MAAM,qBAAqB,gBAAgB,CAAC;AACnD,eAAO,MAAM,yBAAyB,IAAI,CAAC;AAE3C,qGAAqG;AACrG,MAAM,WAAW,kBAAkB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,eAAe;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACd;AAED,2FAA2F;AAC3F,MAAM,WAAW,UAAU;IAC1B,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,kBAAkB,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,eAAe,EAAE,CAAC;CAChG;AAkCD,gGAAgG;AAChG,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAQ/C;AAuBD;;;GAGG;AACH,wBAAgB,wBAAwB,CACvC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,GAAG,YAAY,CAAC,EAC3D,SAAS,CAAC,EAAE,aAAa,GACvB,kBAAkB,CAKpB;AAED,sEAAsE;AACtE,qBAAa,UAAW,YAAW,UAAU;IAC5C,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAS;IAC5B,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAS;IAE3B,YAAY,OAAO,GAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,CAAA;KAAO,EAGpD;IAED,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,kBAAkB,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,eAAe,EAAE,CA4B9F;CACD;AAED,eAAO,MAAM,gBAAgB;;;EAK3B,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE9D,6FAA6F;AAC7F,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,YAAY,CAAC,GAAG,OAAO,CAErF;AAED,MAAM,WAAW,oBAAoB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,qBAAqB;IACrC,iCAAiC;IACjC,MAAM,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,qBAAqB;IACrC;;;OAGG;IACH,KAAK,CAAC,EAAE,IAAI,CAAC,YAAY,EAAE,aAAa,GAAG,gBAAgB,GAAG,gBAAgB,CAAC,CAAC;CAChF;AA2BD;;;GAGG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,GAAE,SAAS,aAAa,EAAO,GAAG,MAAM,CAW1F;AAED,wBAAgB,8BAA8B,CAC7C,OAAO,GAAE,qBAA0B,GACjC,cAAc,CAAC,OAAO,gBAAgB,EAAE,qBAAqB,CAAC,CAmChE"}
1
+ {"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../../src/extensions/tool-search/tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EACX,YAAY,EACZ,cAAc,EAEd,QAAQ,EACR,aAAa,EACb,MAAM,gCAAgC,CAAC;AAExC,eAAO,MAAM,qBAAqB,gBAAgB,CAAC;AACnD,eAAO,MAAM,yBAAyB,IAAI,CAAC;AAE3C,qGAAqG;AACrG,MAAM,WAAW,kBAAkB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,eAAe;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACd;AAED,2FAA2F;AAC3F,MAAM,WAAW,UAAU;IAC1B,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,kBAAkB,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,eAAe,EAAE,CAAC;CAChG;AAkCD,gGAAgG;AAChG,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAQ/C;AAuBD;;;;GAIG;AACH,wBAAgB,wBAAwB,CACvC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,GAAG,YAAY,CAAC,EAC3D,SAAS,CAAC,EAAE,aAAa,GACvB,kBAAkB,CAKpB;AAED,sEAAsE;AACtE,qBAAa,UAAW,YAAW,UAAU;IAC5C,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAS;IAC5B,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAS;IAE3B,YAAY,OAAO,GAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,CAAA;KAAO,EAGpD;IAED,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,kBAAkB,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,eAAe,EAAE,CA4B9F;CACD;AAED,eAAO,MAAM,gBAAgB;;;EAK3B,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE9D,6FAA6F;AAC7F,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,YAAY,CAAC,GAAG,OAAO,CAErF;AAED,MAAM,WAAW,oBAAoB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,qBAAqB;IACrC,iCAAiC;IACjC,MAAM,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,qBAAqB;IACrC;;;OAGG;IACH,KAAK,CAAC,EAAE,IAAI,CAAC,YAAY,EAAE,aAAa,GAAG,gBAAgB,GAAG,gBAAgB,CAAC,CAAC;CAChF;AA2BD;;;GAGG;AACH,eAAO,MAAM,uBAAuB,2VAAyX,CAAC;AAE9Z,wBAAgB,8BAA8B,CAC7C,OAAO,GAAE,qBAA0B,GACjC,cAAc,CAAC,OAAO,gBAAgB,EAAE,qBAAqB,CAAC,CAuBhE"}
@@ -78,13 +78,14 @@ function schemaText(schema, parts) {
78
78
  }
79
79
  /**
80
80
  * Search text of a tool: the name, the name with `_`
81
- * as spaces, the description, schema descriptions and property names, and the namespace.
81
+ * as spaces, the description, schema descriptions and property names, and the namespace with its
82
+ * description and instructions.
82
83
  */
83
84
  export function createToolSearchDocument(tool, namespace) {
84
85
  const parts = [tool.name, tool.name.replaceAll("_", " "), tool.description];
85
86
  schemaText(tool.parameters, parts);
86
87
  if (namespace)
87
- parts.push(namespace.name, namespace.description ?? "");
88
+ parts.push(namespace.name, namespace.description ?? "", namespace.instructions ?? "");
88
89
  return { name: tool.name, text: parts.filter((part) => part.trim()).join(" ") };
89
90
  }
90
91
  /** Okapi BM25 with the usual parameters. Ties keep document order. */
@@ -156,41 +157,19 @@ function searchAndLoad(tools, query, limit) {
156
157
  }));
157
158
  }
158
159
  /**
159
- * The `tool_search` description. `sources` lists the namespaces whose tools can be found, with
160
- * their descriptions.
160
+ * The `tool_search` description. It does not list the searchable tools or their namespaces, so it
161
+ * stays the same while tools are registered, for example when MCP servers connect.
161
162
  */
162
- export function createToolSearchDescription(sources = []) {
163
- const listed = sources.length === 0
164
- ? "None currently enabled."
165
- : sources
166
- .map((source) => {
167
- const description = source.description?.trim().split(/\r?\n/)[0];
168
- return description ? `- ${source.name}: ${description}` : `- ${source.name}`;
169
- })
170
- .join("\n");
171
- return `# Tool discovery\n\nSearches over deferred tool metadata with BM25 and exposes matching tools for the next model call.\n\nYou have access to tools from the following sources:\n${listed}\n\nSome of the tools may not have been provided to you upfront, and you should use this tool (\`${TOOL_SEARCH_TOOL_NAME}\`) to search for the required tools. For MCP tool discovery, always use \`${TOOL_SEARCH_TOOL_NAME}\`.`;
172
- }
163
+ export const TOOL_SEARCH_DESCRIPTION = `# Tool discovery\n\nSearches over deferred tool metadata with BM25 and exposes matching tools for the next model call.\n\nSome of the tools, such as tools of MCP servers, may not have been provided to you upfront, and you should use this tool (\`${TOOL_SEARCH_TOOL_NAME}\`) to search for the required tools. For MCP tool discovery, always use \`${TOOL_SEARCH_TOOL_NAME}\`.`;
173
164
  export function createToolSearchToolDefinition(options = {}) {
174
165
  return {
175
166
  name: TOOL_SEARCH_TOOL_NAME,
176
167
  label: TOOL_SEARCH_TOOL_NAME,
177
- // Replaced with the searchable sources when the tool is activated.
178
- description: createToolSearchDescription(),
168
+ description: TOOL_SEARCH_DESCRIPTION,
179
169
  promptSnippet: "Search for tools that are not loaded yet and load the matches",
180
170
  parameters: toolSearchSchema,
181
171
  // Searching is not something scripts need; it changes what the model sees.
182
172
  exposure: "model-only",
183
- // List the namespaces of the searchable tools.
184
- prepareLoadout: (loadout) => {
185
- const sources = new Map();
186
- for (const tool of loadout.registered) {
187
- const namespace = loadout.getNamespace(tool.name);
188
- if (isSearchable(loadout.getExposure(tool.name)) && namespace && !sources.has(namespace.name)) {
189
- sources.set(namespace.name, namespace);
190
- }
191
- }
192
- return { descriptions: { [TOOL_SEARCH_TOOL_NAME]: createToolSearchDescription([...sources.values()]) } };
193
- },
194
173
  async execute(_toolCallId, { query, limit }) {
195
174
  if (query.trim() === "")
196
175
  throw new Error("query must not be empty");
@@ -1 +1 @@
1
- {"version":3,"file":"tool.js","sourceRoot":"","sources":["../../../src/extensions/tool-search/tool.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Tool discovery: a BM25 ranker over tool metadata, shared by `searchTools()` in codemode scripts and\n * the optional `tool_search` tool.\n *\n * `tool_search` searches tools that are not declared to\n * the model (`codemode` and `deferred` exposure) and loads the matches, so they are declared for the\n * next model call. Loading goes through the active tool set, so it is recorded in the transcript\n * like any other tool change and survives `/tree`, resume, and fork on that branch.\n */\n\nimport { type Static, Type } from \"typebox\";\nimport type {\n\tExtensionAPI,\n\tToolDefinition,\n\tToolExposure,\n\tToolInfo,\n\tToolNamespace,\n} from \"../../core/extensions/types.ts\";\n\nexport const TOOL_SEARCH_TOOL_NAME = \"tool_search\";\nexport const DEFAULT_TOOL_SEARCH_LIMIT = 8;\n\n/** A tool as the ranker sees it: its name and the text built by {@link createToolSearchDocument}. */\nexport interface ToolSearchDocument {\n\tname: string;\n\ttext: string;\n}\n\nexport interface ToolSearchMatch {\n\tname: string;\n\tscore: number;\n}\n\n/** Ranks tools for a query. BM25 today; a hybrid ranker with embeddings can replace it. */\nexport interface ToolRanker {\n\trank(query: string, documents: readonly ToolSearchDocument[], limit: number): ToolSearchMatch[];\n}\n\nconst STOP_WORDS: ReadonlySet<string> = new Set([\n\t\"a\",\n\t\"an\",\n\t\"and\",\n\t\"are\",\n\t\"as\",\n\t\"at\",\n\t\"be\",\n\t\"by\",\n\t\"for\",\n\t\"from\",\n\t\"in\",\n\t\"is\",\n\t\"it\",\n\t\"of\",\n\t\"on\",\n\t\"or\",\n\t\"that\",\n\t\"the\",\n\t\"this\",\n\t\"to\",\n\t\"with\",\n]);\n\n/** Naive singular form, so `issues` matches `issue` and `searches` matches `search`. */\nfunction stem(term: string): string {\n\tif (term.length > 4 && term.endsWith(\"ies\")) return `${term.slice(0, -3)}y`;\n\tif (term.length > 4 && /(ches|shes|sses|xes|zes)$/.test(term)) return term.slice(0, -2);\n\tif (term.length > 3 && term.endsWith(\"s\") && !term.endsWith(\"ss\")) return term.slice(0, -1);\n\treturn term;\n}\n\n/** Lowercase terms, split at camelCase boundaries and non-alphanumerics, without stop words. */\nexport function tokenize(text: string): string[] {\n\treturn text\n\t\t.replace(/([a-z0-9])([A-Z])/g, \"$1 $2\")\n\t\t.replace(/([A-Z]+)([A-Z][a-z])/g, \"$1 $2\")\n\t\t.toLowerCase()\n\t\t.split(/[^a-z0-9]+/)\n\t\t.filter((term) => term.length > 0 && !STOP_WORDS.has(term))\n\t\t.map(stem);\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** Schema descriptions and property names, recursively. */\nfunction schemaText(schema: unknown, parts: string[]): void {\n\tif (!isObject(schema)) return;\n\tif (typeof schema.description === \"string\") parts.push(schema.description);\n\tif (isObject(schema.properties)) {\n\t\tfor (const [name, property] of Object.entries(schema.properties)) {\n\t\t\tparts.push(name);\n\t\t\tschemaText(property, parts);\n\t\t}\n\t}\n\tschemaText(schema.items, parts);\n\tfor (const key of [\"anyOf\", \"oneOf\", \"allOf\"]) {\n\t\tconst variants = schema[key];\n\t\tif (Array.isArray(variants)) for (const variant of variants) schemaText(variant, parts);\n\t}\n}\n\n/**\n * Search text of a tool: the name, the name with `_`\n * as spaces, the description, schema descriptions and property names, and the namespace.\n */\nexport function createToolSearchDocument(\n\ttool: Pick<ToolInfo, \"name\" | \"description\" | \"parameters\">,\n\tnamespace?: ToolNamespace,\n): ToolSearchDocument {\n\tconst parts = [tool.name, tool.name.replaceAll(\"_\", \" \"), tool.description];\n\tschemaText(tool.parameters, parts);\n\tif (namespace) parts.push(namespace.name, namespace.description ?? \"\");\n\treturn { name: tool.name, text: parts.filter((part) => part.trim()).join(\" \") };\n}\n\n/** Okapi BM25 with the usual parameters. Ties keep document order. */\nexport class Bm25Ranker implements ToolRanker {\n\tprivate readonly k1: number;\n\tprivate readonly b: number;\n\n\tconstructor(options: { k1?: number; b?: number } = {}) {\n\t\tthis.k1 = options.k1 ?? 1.2;\n\t\tthis.b = options.b ?? 0.75;\n\t}\n\n\trank(query: string, documents: readonly ToolSearchDocument[], limit: number): ToolSearchMatch[] {\n\t\tconst queryTerms = [...new Set(tokenize(query))];\n\t\tif (queryTerms.length === 0 || documents.length === 0 || limit <= 0) return [];\n\t\tconst termCounts = documents.map((document) => {\n\t\t\tconst counts = new Map<string, number>();\n\t\t\tfor (const term of tokenize(document.text)) counts.set(term, (counts.get(term) ?? 0) + 1);\n\t\t\treturn counts;\n\t\t});\n\t\tconst lengths = termCounts.map((counts) => [...counts.values()].reduce((sum, count) => sum + count, 0));\n\t\tconst averageLength = lengths.reduce((sum, length) => sum + length, 0) / documents.length || 1;\n\t\tconst idf = new Map(\n\t\t\tqueryTerms.map((term) => {\n\t\t\t\tconst frequency = termCounts.filter((counts) => counts.has(term)).length;\n\t\t\t\treturn [term, Math.log(1 + (documents.length - frequency + 0.5) / (frequency + 0.5))] as const;\n\t\t\t}),\n\t\t);\n\t\tconst matches: ToolSearchMatch[] = [];\n\t\tdocuments.forEach((document, index) => {\n\t\t\tlet score = 0;\n\t\t\tfor (const term of queryTerms) {\n\t\t\t\tconst count = termCounts[index].get(term);\n\t\t\t\tif (!count) continue;\n\t\t\t\tconst norm = this.k1 * (1 - this.b + (this.b * lengths[index]) / averageLength);\n\t\t\t\tscore += (idf.get(term) ?? 0) * ((count * (this.k1 + 1)) / (count + norm));\n\t\t\t}\n\t\t\tif (score > 0) matches.push({ name: document.name, score });\n\t\t});\n\t\treturn matches.sort((a, b) => b.score - a.score).slice(0, limit);\n\t}\n}\n\nexport const toolSearchSchema = Type.Object({\n\tquery: Type.String({ description: \"Search query for deferred tools.\" }),\n\tlimit: Type.Optional(\n\t\tType.Number({ description: `Maximum number of tools to return. Defaults to ${DEFAULT_TOOL_SEARCH_LIMIT}.` }),\n\t),\n});\n\nexport type ToolSearchInput = Static<typeof toolSearchSchema>;\n\n/** Whether the tool is this `tool_search`, not another extension's tool of the same name. */\nexport function isToolSearchTool(tool: Pick<ToolInfo, \"name\" | \"parameters\">): boolean {\n\treturn tool.name === TOOL_SEARCH_TOOL_NAME && tool.parameters === toolSearchSchema;\n}\n\nexport interface ToolSearchResultTool {\n\tname: string;\n\tdescription: string;\n}\n\nexport interface ToolSearchToolDetails {\n\t/** Tools loaded by this call. */\n\tloaded: string[];\n}\n\nexport interface ToolSearchToolOptions {\n\t/**\n\t * The session's tools. `tool_search` searches the tools that are not declared to the model and\n\t * activates the matches. Without it, the tool finds nothing. An `ExtensionAPI` fits.\n\t */\n\ttools?: Pick<ExtensionAPI, \"getAllTools\" | \"getActiveTools\" | \"setActiveTools\">;\n}\n\n/** Whether `tool_search` can load a tool with this exposure. */\nfunction isSearchable(exposure: ToolExposure): boolean {\n\treturn exposure === \"codemode\" || exposure === \"deferred\";\n}\n\n/**\n * Rank the searchable tools that are not active yet and activate the matches, so the next model\n * call declares them. Activation is recorded in the transcript like any tool change.\n */\nfunction searchAndLoad(\n\ttools: NonNullable<ToolSearchToolOptions[\"tools\"]>,\n\tquery: string,\n\tlimit: number,\n): ToolSearchResultTool[] {\n\tconst active = tools.getActiveTools();\n\tconst candidates = tools.getAllTools().filter((tool) => isSearchable(tool.exposure) && !active.includes(tool.name));\n\tconst documents = candidates.map((tool) => createToolSearchDocument(tool, tool.namespace));\n\tconst matches = new Bm25Ranker().rank(query, documents, limit);\n\tif (matches.length > 0) tools.setActiveTools([...active, ...matches.map((match) => match.name)]);\n\treturn matches.map((match) => ({\n\t\tname: match.name,\n\t\tdescription: candidates.find((tool) => tool.name === match.name)?.description ?? \"\",\n\t}));\n}\n\n/**\n * The `tool_search` description. `sources` lists the namespaces whose tools can be found, with\n * their descriptions.\n */\nexport function createToolSearchDescription(sources: readonly ToolNamespace[] = []): string {\n\tconst listed =\n\t\tsources.length === 0\n\t\t\t? \"None currently enabled.\"\n\t\t\t: sources\n\t\t\t\t\t.map((source) => {\n\t\t\t\t\t\tconst description = source.description?.trim().split(/\\r?\\n/)[0];\n\t\t\t\t\t\treturn description ? `- ${source.name}: ${description}` : `- ${source.name}`;\n\t\t\t\t\t})\n\t\t\t\t\t.join(\"\\n\");\n\treturn `# Tool discovery\\n\\nSearches over deferred tool metadata with BM25 and exposes matching tools for the next model call.\\n\\nYou have access to tools from the following sources:\\n${listed}\\n\\nSome of the tools may not have been provided to you upfront, and you should use this tool (\\`${TOOL_SEARCH_TOOL_NAME}\\`) to search for the required tools. For MCP tool discovery, always use \\`${TOOL_SEARCH_TOOL_NAME}\\`.`;\n}\n\nexport function createToolSearchToolDefinition(\n\toptions: ToolSearchToolOptions = {},\n): ToolDefinition<typeof toolSearchSchema, ToolSearchToolDetails> {\n\treturn {\n\t\tname: TOOL_SEARCH_TOOL_NAME,\n\t\tlabel: TOOL_SEARCH_TOOL_NAME,\n\t\t// Replaced with the searchable sources when the tool is activated.\n\t\tdescription: createToolSearchDescription(),\n\t\tpromptSnippet: \"Search for tools that are not loaded yet and load the matches\",\n\t\tparameters: toolSearchSchema,\n\t\t// Searching is not something scripts need; it changes what the model sees.\n\t\texposure: \"model-only\",\n\t\t// List the namespaces of the searchable tools.\n\t\tprepareLoadout: (loadout) => {\n\t\t\tconst sources = new Map<string, ToolNamespace>();\n\t\t\tfor (const tool of loadout.registered) {\n\t\t\t\tconst namespace = loadout.getNamespace(tool.name);\n\t\t\t\tif (isSearchable(loadout.getExposure(tool.name)) && namespace && !sources.has(namespace.name)) {\n\t\t\t\t\tsources.set(namespace.name, namespace);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn { descriptions: { [TOOL_SEARCH_TOOL_NAME]: createToolSearchDescription([...sources.values()]) } };\n\t\t},\n\t\tasync execute(_toolCallId, { query, limit }) {\n\t\t\tif (query.trim() === \"\") throw new Error(\"query must not be empty\");\n\t\t\tconst max = limit ?? DEFAULT_TOOL_SEARCH_LIMIT;\n\t\t\tif (!Number.isInteger(max) || max <= 0) throw new Error(\"limit must be a positive integer\");\n\t\t\tconst tools = options.tools ? searchAndLoad(options.tools, query, max) : [];\n\t\t\tconst text =\n\t\t\t\ttools.length === 0\n\t\t\t\t\t? \"No matching tools found.\"\n\t\t\t\t\t: `Loaded ${tools.length} tool${tools.length === 1 ? \"\" : \"s\"}. They are available from your next call:\\n${tools\n\t\t\t\t\t\t\t.map((tool) => `- ${tool.name}: ${tool.description.trim().split(/\\r?\\n/)[0]}`)\n\t\t\t\t\t\t\t.join(\"\\n\")}`;\n\t\t\treturn { content: [{ type: \"text\", text }], details: { loaded: tools.map((tool) => tool.name) } };\n\t\t},\n\t};\n}\n"]}
1
+ {"version":3,"file":"tool.js","sourceRoot":"","sources":["../../../src/extensions/tool-search/tool.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Tool discovery: a BM25 ranker over tool metadata, shared by `searchTools()` in codemode scripts and\n * the optional `tool_search` tool.\n *\n * `tool_search` searches tools that are not declared to\n * the model (`codemode` and `deferred` exposure) and loads the matches, so they are declared for the\n * next model call. Loading goes through the active tool set, so it is recorded in the transcript\n * like any other tool change and survives `/tree`, resume, and fork on that branch.\n */\n\nimport { type Static, Type } from \"typebox\";\nimport type {\n\tExtensionAPI,\n\tToolDefinition,\n\tToolExposure,\n\tToolInfo,\n\tToolNamespace,\n} from \"../../core/extensions/types.ts\";\n\nexport const TOOL_SEARCH_TOOL_NAME = \"tool_search\";\nexport const DEFAULT_TOOL_SEARCH_LIMIT = 8;\n\n/** A tool as the ranker sees it: its name and the text built by {@link createToolSearchDocument}. */\nexport interface ToolSearchDocument {\n\tname: string;\n\ttext: string;\n}\n\nexport interface ToolSearchMatch {\n\tname: string;\n\tscore: number;\n}\n\n/** Ranks tools for a query. BM25 today; a hybrid ranker with embeddings can replace it. */\nexport interface ToolRanker {\n\trank(query: string, documents: readonly ToolSearchDocument[], limit: number): ToolSearchMatch[];\n}\n\nconst STOP_WORDS: ReadonlySet<string> = new Set([\n\t\"a\",\n\t\"an\",\n\t\"and\",\n\t\"are\",\n\t\"as\",\n\t\"at\",\n\t\"be\",\n\t\"by\",\n\t\"for\",\n\t\"from\",\n\t\"in\",\n\t\"is\",\n\t\"it\",\n\t\"of\",\n\t\"on\",\n\t\"or\",\n\t\"that\",\n\t\"the\",\n\t\"this\",\n\t\"to\",\n\t\"with\",\n]);\n\n/** Naive singular form, so `issues` matches `issue` and `searches` matches `search`. */\nfunction stem(term: string): string {\n\tif (term.length > 4 && term.endsWith(\"ies\")) return `${term.slice(0, -3)}y`;\n\tif (term.length > 4 && /(ches|shes|sses|xes|zes)$/.test(term)) return term.slice(0, -2);\n\tif (term.length > 3 && term.endsWith(\"s\") && !term.endsWith(\"ss\")) return term.slice(0, -1);\n\treturn term;\n}\n\n/** Lowercase terms, split at camelCase boundaries and non-alphanumerics, without stop words. */\nexport function tokenize(text: string): string[] {\n\treturn text\n\t\t.replace(/([a-z0-9])([A-Z])/g, \"$1 $2\")\n\t\t.replace(/([A-Z]+)([A-Z][a-z])/g, \"$1 $2\")\n\t\t.toLowerCase()\n\t\t.split(/[^a-z0-9]+/)\n\t\t.filter((term) => term.length > 0 && !STOP_WORDS.has(term))\n\t\t.map(stem);\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** Schema descriptions and property names, recursively. */\nfunction schemaText(schema: unknown, parts: string[]): void {\n\tif (!isObject(schema)) return;\n\tif (typeof schema.description === \"string\") parts.push(schema.description);\n\tif (isObject(schema.properties)) {\n\t\tfor (const [name, property] of Object.entries(schema.properties)) {\n\t\t\tparts.push(name);\n\t\t\tschemaText(property, parts);\n\t\t}\n\t}\n\tschemaText(schema.items, parts);\n\tfor (const key of [\"anyOf\", \"oneOf\", \"allOf\"]) {\n\t\tconst variants = schema[key];\n\t\tif (Array.isArray(variants)) for (const variant of variants) schemaText(variant, parts);\n\t}\n}\n\n/**\n * Search text of a tool: the name, the name with `_`\n * as spaces, the description, schema descriptions and property names, and the namespace with its\n * description and instructions.\n */\nexport function createToolSearchDocument(\n\ttool: Pick<ToolInfo, \"name\" | \"description\" | \"parameters\">,\n\tnamespace?: ToolNamespace,\n): ToolSearchDocument {\n\tconst parts = [tool.name, tool.name.replaceAll(\"_\", \" \"), tool.description];\n\tschemaText(tool.parameters, parts);\n\tif (namespace) parts.push(namespace.name, namespace.description ?? \"\", namespace.instructions ?? \"\");\n\treturn { name: tool.name, text: parts.filter((part) => part.trim()).join(\" \") };\n}\n\n/** Okapi BM25 with the usual parameters. Ties keep document order. */\nexport class Bm25Ranker implements ToolRanker {\n\tprivate readonly k1: number;\n\tprivate readonly b: number;\n\n\tconstructor(options: { k1?: number; b?: number } = {}) {\n\t\tthis.k1 = options.k1 ?? 1.2;\n\t\tthis.b = options.b ?? 0.75;\n\t}\n\n\trank(query: string, documents: readonly ToolSearchDocument[], limit: number): ToolSearchMatch[] {\n\t\tconst queryTerms = [...new Set(tokenize(query))];\n\t\tif (queryTerms.length === 0 || documents.length === 0 || limit <= 0) return [];\n\t\tconst termCounts = documents.map((document) => {\n\t\t\tconst counts = new Map<string, number>();\n\t\t\tfor (const term of tokenize(document.text)) counts.set(term, (counts.get(term) ?? 0) + 1);\n\t\t\treturn counts;\n\t\t});\n\t\tconst lengths = termCounts.map((counts) => [...counts.values()].reduce((sum, count) => sum + count, 0));\n\t\tconst averageLength = lengths.reduce((sum, length) => sum + length, 0) / documents.length || 1;\n\t\tconst idf = new Map(\n\t\t\tqueryTerms.map((term) => {\n\t\t\t\tconst frequency = termCounts.filter((counts) => counts.has(term)).length;\n\t\t\t\treturn [term, Math.log(1 + (documents.length - frequency + 0.5) / (frequency + 0.5))] as const;\n\t\t\t}),\n\t\t);\n\t\tconst matches: ToolSearchMatch[] = [];\n\t\tdocuments.forEach((document, index) => {\n\t\t\tlet score = 0;\n\t\t\tfor (const term of queryTerms) {\n\t\t\t\tconst count = termCounts[index].get(term);\n\t\t\t\tif (!count) continue;\n\t\t\t\tconst norm = this.k1 * (1 - this.b + (this.b * lengths[index]) / averageLength);\n\t\t\t\tscore += (idf.get(term) ?? 0) * ((count * (this.k1 + 1)) / (count + norm));\n\t\t\t}\n\t\t\tif (score > 0) matches.push({ name: document.name, score });\n\t\t});\n\t\treturn matches.sort((a, b) => b.score - a.score).slice(0, limit);\n\t}\n}\n\nexport const toolSearchSchema = Type.Object({\n\tquery: Type.String({ description: \"Search query for deferred tools.\" }),\n\tlimit: Type.Optional(\n\t\tType.Number({ description: `Maximum number of tools to return. Defaults to ${DEFAULT_TOOL_SEARCH_LIMIT}.` }),\n\t),\n});\n\nexport type ToolSearchInput = Static<typeof toolSearchSchema>;\n\n/** Whether the tool is this `tool_search`, not another extension's tool of the same name. */\nexport function isToolSearchTool(tool: Pick<ToolInfo, \"name\" | \"parameters\">): boolean {\n\treturn tool.name === TOOL_SEARCH_TOOL_NAME && tool.parameters === toolSearchSchema;\n}\n\nexport interface ToolSearchResultTool {\n\tname: string;\n\tdescription: string;\n}\n\nexport interface ToolSearchToolDetails {\n\t/** Tools loaded by this call. */\n\tloaded: string[];\n}\n\nexport interface ToolSearchToolOptions {\n\t/**\n\t * The session's tools. `tool_search` searches the tools that are not declared to the model and\n\t * activates the matches. Without it, the tool finds nothing. An `ExtensionAPI` fits.\n\t */\n\ttools?: Pick<ExtensionAPI, \"getAllTools\" | \"getActiveTools\" | \"setActiveTools\">;\n}\n\n/** Whether `tool_search` can load a tool with this exposure. */\nfunction isSearchable(exposure: ToolExposure): boolean {\n\treturn exposure === \"codemode\" || exposure === \"deferred\";\n}\n\n/**\n * Rank the searchable tools that are not active yet and activate the matches, so the next model\n * call declares them. Activation is recorded in the transcript like any tool change.\n */\nfunction searchAndLoad(\n\ttools: NonNullable<ToolSearchToolOptions[\"tools\"]>,\n\tquery: string,\n\tlimit: number,\n): ToolSearchResultTool[] {\n\tconst active = tools.getActiveTools();\n\tconst candidates = tools.getAllTools().filter((tool) => isSearchable(tool.exposure) && !active.includes(tool.name));\n\tconst documents = candidates.map((tool) => createToolSearchDocument(tool, tool.namespace));\n\tconst matches = new Bm25Ranker().rank(query, documents, limit);\n\tif (matches.length > 0) tools.setActiveTools([...active, ...matches.map((match) => match.name)]);\n\treturn matches.map((match) => ({\n\t\tname: match.name,\n\t\tdescription: candidates.find((tool) => tool.name === match.name)?.description ?? \"\",\n\t}));\n}\n\n/**\n * The `tool_search` description. It does not list the searchable tools or their namespaces, so it\n * stays the same while tools are registered, for example when MCP servers connect.\n */\nexport const TOOL_SEARCH_DESCRIPTION = `# Tool discovery\\n\\nSearches over deferred tool metadata with BM25 and exposes matching tools for the next model call.\\n\\nSome of the tools, such as tools of MCP servers, may not have been provided to you upfront, and you should use this tool (\\`${TOOL_SEARCH_TOOL_NAME}\\`) to search for the required tools. For MCP tool discovery, always use \\`${TOOL_SEARCH_TOOL_NAME}\\`.`;\n\nexport function createToolSearchToolDefinition(\n\toptions: ToolSearchToolOptions = {},\n): ToolDefinition<typeof toolSearchSchema, ToolSearchToolDetails> {\n\treturn {\n\t\tname: TOOL_SEARCH_TOOL_NAME,\n\t\tlabel: TOOL_SEARCH_TOOL_NAME,\n\t\tdescription: TOOL_SEARCH_DESCRIPTION,\n\t\tpromptSnippet: \"Search for tools that are not loaded yet and load the matches\",\n\t\tparameters: toolSearchSchema,\n\t\t// Searching is not something scripts need; it changes what the model sees.\n\t\texposure: \"model-only\",\n\t\tasync execute(_toolCallId, { query, limit }) {\n\t\t\tif (query.trim() === \"\") throw new Error(\"query must not be empty\");\n\t\t\tconst max = limit ?? DEFAULT_TOOL_SEARCH_LIMIT;\n\t\t\tif (!Number.isInteger(max) || max <= 0) throw new Error(\"limit must be a positive integer\");\n\t\t\tconst tools = options.tools ? searchAndLoad(options.tools, query, max) : [];\n\t\t\tconst text =\n\t\t\t\ttools.length === 0\n\t\t\t\t\t? \"No matching tools found.\"\n\t\t\t\t\t: `Loaded ${tools.length} tool${tools.length === 1 ? \"\" : \"s\"}. They are available from your next call:\\n${tools\n\t\t\t\t\t\t\t.map((tool) => `- ${tool.name}: ${tool.description.trim().split(/\\r?\\n/)[0]}`)\n\t\t\t\t\t\t\t.join(\"\\n\")}`;\n\t\t\treturn { content: [{ type: \"text\", text }], details: { loaded: tools.map((tool) => tool.name) } };\n\t\t},\n\t};\n}\n"]}
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * Shared utility for truncating text to visual lines (accounting for line wrapping).
3
- * Used by both tool-execution.ts and bash-execution.ts for consistent behavior.
3
+ * Used by tool renderers and bash-execution.ts for consistent behavior.
4
4
  */
5
+ import { type Component } from "@earendil-works/pi-tui";
5
6
  export interface VisualTruncateResult {
6
7
  /** The visual lines to display */
7
8
  visualLines: string[];
@@ -9,7 +10,7 @@ export interface VisualTruncateResult {
9
10
  skippedCount: number;
10
11
  }
11
12
  /**
12
- * Truncate text to a maximum number of visual lines (from the end).
13
+ * Truncate text to a maximum number of visual lines.
13
14
  * This accounts for line wrapping based on terminal width.
14
15
  *
15
16
  * @param text - The text content (may contain newlines)
@@ -18,7 +19,30 @@ export interface VisualTruncateResult {
18
19
  * @param paddingX - Horizontal padding for Text component (default 0).
19
20
  * Use 0 when result will be placed in a Box (Box adds its own padding).
20
21
  * Use 1 when result will be placed in a plain Container.
22
+ * @param keep - Which visual lines to keep: the last ones (default) or the first ones.
21
23
  * @returns The truncated visual lines and count of skipped lines
22
24
  */
23
- export declare function truncateToVisualLines(text: string, maxVisualLines: number, width: number, paddingX?: number): VisualTruncateResult;
25
+ export declare function truncateToVisualLines(text: string, maxVisualLines: number, width: number, paddingX?: number, keep?: "start" | "end"): VisualTruncateResult;
26
+ export interface VisualLinePreviewOptions {
27
+ /** Styled text; may contain newlines. */
28
+ text: string;
29
+ maxVisualLines: number;
30
+ /** Which visual lines to keep. The hint goes before kept end lines and after kept start lines. */
31
+ keep: "start" | "end";
32
+ /** Styled hint line for the given number of hidden visual lines. */
33
+ formatHint: (hidden: number) => string;
34
+ }
35
+ /**
36
+ * Collapsed tool output limited to a number of visual lines, like bash output. Limiting logical
37
+ * lines instead lets a single long line (such as minified JSON) wrap across the whole screen.
38
+ * Caches its lines per width, since it renders on every frame for every result in the transcript.
39
+ */
40
+ export declare class VisualLinePreview implements Component {
41
+ private options;
42
+ private cachedWidth;
43
+ private cachedLines;
44
+ constructor(options: VisualLinePreviewOptions);
45
+ render(width: number): string[];
46
+ invalidate(): void;
47
+ }
24
48
  //# sourceMappingURL=visual-truncate.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"visual-truncate.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/visual-truncate.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,WAAW,oBAAoB;IACpC,kCAAkC;IAClC,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,wDAAwD;IACxD,YAAY,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CACpC,IAAI,EAAE,MAAM,EACZ,cAAc,EAAE,MAAM,EACtB,KAAK,EAAE,MAAM,EACb,QAAQ,GAAE,MAAU,GAClB,oBAAoB,CAkBtB"}
1
+ {"version":3,"file":"visual-truncate.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/visual-truncate.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,KAAK,SAAS,EAAyB,MAAM,wBAAwB,CAAC;AAE/E,MAAM,WAAW,oBAAoB;IACpC,kCAAkC;IAClC,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,wDAAwD;IACxD,YAAY,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,qBAAqB,CACpC,IAAI,EAAE,MAAM,EACZ,cAAc,EAAE,MAAM,EACtB,KAAK,EAAE,MAAM,EACb,QAAQ,GAAE,MAAU,EACpB,IAAI,GAAE,OAAO,GAAG,KAAa,GAC3B,oBAAoB,CAkBtB;AAED,MAAM,WAAW,wBAAwB;IACxC,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,CAAC;IACvB,kGAAkG;IAClG,IAAI,EAAE,OAAO,GAAG,KAAK,CAAC;IACtB,oEAAoE;IACpE,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC;CACvC;AAED;;;;GAIG;AACH,qBAAa,iBAAkB,YAAW,SAAS;IAClD,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,WAAW,CAAqB;IACxC,OAAO,CAAC,WAAW,CAAuB;IAE1C,YAAY,OAAO,EAAE,wBAAwB,EAE5C;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAc9B;IAED,UAAU,IAAI,IAAI,CAGjB;CACD"}
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * Shared utility for truncating text to visual lines (accounting for line wrapping).
3
- * Used by both tool-execution.ts and bash-execution.ts for consistent behavior.
3
+ * Used by tool renderers and bash-execution.ts for consistent behavior.
4
4
  */
5
- import { Text } from "@earendil-works/pi-tui";
5
+ import { Text, truncateToWidth } from "@earendil-works/pi-tui";
6
6
  /**
7
- * Truncate text to a maximum number of visual lines (from the end).
7
+ * Truncate text to a maximum number of visual lines.
8
8
  * This accounts for line wrapping based on terminal width.
9
9
  *
10
10
  * @param text - The text content (may contain newlines)
@@ -13,9 +13,10 @@ import { Text } from "@earendil-works/pi-tui";
13
13
  * @param paddingX - Horizontal padding for Text component (default 0).
14
14
  * Use 0 when result will be placed in a Box (Box adds its own padding).
15
15
  * Use 1 when result will be placed in a plain Container.
16
+ * @param keep - Which visual lines to keep: the last ones (default) or the first ones.
16
17
  * @returns The truncated visual lines and count of skipped lines
17
18
  */
18
- export function truncateToVisualLines(text, maxVisualLines, width, paddingX = 0) {
19
+ export function truncateToVisualLines(text, maxVisualLines, width, paddingX = 0, keep = "end") {
19
20
  if (!text) {
20
21
  return { visualLines: [], skippedCount: 0 };
21
22
  }
@@ -25,9 +26,41 @@ export function truncateToVisualLines(text, maxVisualLines, width, paddingX = 0)
25
26
  if (allVisualLines.length <= maxVisualLines) {
26
27
  return { visualLines: allVisualLines, skippedCount: 0 };
27
28
  }
28
- // Take the last N visual lines
29
- const truncatedLines = allVisualLines.slice(-maxVisualLines);
29
+ const truncatedLines = keep === "start" ? allVisualLines.slice(0, maxVisualLines) : allVisualLines.slice(-maxVisualLines);
30
30
  const skippedCount = allVisualLines.length - maxVisualLines;
31
31
  return { visualLines: truncatedLines, skippedCount };
32
32
  }
33
+ /**
34
+ * Collapsed tool output limited to a number of visual lines, like bash output. Limiting logical
35
+ * lines instead lets a single long line (such as minified JSON) wrap across the whole screen.
36
+ * Caches its lines per width, since it renders on every frame for every result in the transcript.
37
+ */
38
+ export class VisualLinePreview {
39
+ options;
40
+ cachedWidth;
41
+ cachedLines;
42
+ constructor(options) {
43
+ this.options = options;
44
+ }
45
+ render(width) {
46
+ if (this.cachedLines === undefined || this.cachedWidth !== width) {
47
+ const { text, maxVisualLines, keep, formatHint } = this.options;
48
+ const preview = truncateToVisualLines(text, maxVisualLines, width, 0, keep);
49
+ const lines = preview.visualLines;
50
+ if (preview.skippedCount > 0) {
51
+ const hint = truncateToWidth(formatHint(preview.skippedCount), width, "...");
52
+ this.cachedLines = keep === "start" ? [...lines, hint] : [hint, ...lines];
53
+ }
54
+ else {
55
+ this.cachedLines = lines;
56
+ }
57
+ this.cachedWidth = width;
58
+ }
59
+ return this.cachedLines;
60
+ }
61
+ invalidate() {
62
+ this.cachedWidth = undefined;
63
+ this.cachedLines = undefined;
64
+ }
65
+ }
33
66
  //# sourceMappingURL=visual-truncate.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"visual-truncate.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/visual-truncate.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAS9C;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,qBAAqB,CACpC,IAAY,EACZ,cAAsB,EACtB,KAAa,EACb,QAAQ,GAAW,CAAC;IAEpB,IAAI,CAAC,IAAI,EAAE,CAAC;QACX,OAAO,EAAE,WAAW,EAAE,EAAE,EAAE,YAAY,EAAE,CAAC,EAAE,CAAC;IAC7C,CAAC;IAED,mEAAmE;IACnE,MAAM,QAAQ,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;IAC7C,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAE9C,IAAI,cAAc,CAAC,MAAM,IAAI,cAAc,EAAE,CAAC;QAC7C,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC,EAAE,CAAC;IACzD,CAAC;IAED,+BAA+B;IAC/B,MAAM,cAAc,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC,cAAc,CAAC,CAAC;IAC7D,MAAM,YAAY,GAAG,cAAc,CAAC,MAAM,GAAG,cAAc,CAAC;IAE5D,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC;AACtD,CAAC","sourcesContent":["/**\n * Shared utility for truncating text to visual lines (accounting for line wrapping).\n * Used by both tool-execution.ts and bash-execution.ts for consistent behavior.\n */\n\nimport { Text } from \"@earendil-works/pi-tui\";\n\nexport interface VisualTruncateResult {\n\t/** The visual lines to display */\n\tvisualLines: string[];\n\t/** Number of visual lines that were skipped (hidden) */\n\tskippedCount: number;\n}\n\n/**\n * Truncate text to a maximum number of visual lines (from the end).\n * This accounts for line wrapping based on terminal width.\n *\n * @param text - The text content (may contain newlines)\n * @param maxVisualLines - Maximum number of visual lines to show\n * @param width - Terminal/render width\n * @param paddingX - Horizontal padding for Text component (default 0).\n * Use 0 when result will be placed in a Box (Box adds its own padding).\n * Use 1 when result will be placed in a plain Container.\n * @returns The truncated visual lines and count of skipped lines\n */\nexport function truncateToVisualLines(\n\ttext: string,\n\tmaxVisualLines: number,\n\twidth: number,\n\tpaddingX: number = 0,\n): VisualTruncateResult {\n\tif (!text) {\n\t\treturn { visualLines: [], skippedCount: 0 };\n\t}\n\n\t// Create a temporary Text component to render and get visual lines\n\tconst tempText = new Text(text, paddingX, 0);\n\tconst allVisualLines = tempText.render(width);\n\n\tif (allVisualLines.length <= maxVisualLines) {\n\t\treturn { visualLines: allVisualLines, skippedCount: 0 };\n\t}\n\n\t// Take the last N visual lines\n\tconst truncatedLines = allVisualLines.slice(-maxVisualLines);\n\tconst skippedCount = allVisualLines.length - maxVisualLines;\n\n\treturn { visualLines: truncatedLines, skippedCount };\n}\n"]}
1
+ {"version":3,"file":"visual-truncate.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/visual-truncate.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAkB,IAAI,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAS/E;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,qBAAqB,CACpC,IAAY,EACZ,cAAsB,EACtB,KAAa,EACb,QAAQ,GAAW,CAAC,EACpB,IAAI,GAAoB,KAAK;IAE7B,IAAI,CAAC,IAAI,EAAE,CAAC;QACX,OAAO,EAAE,WAAW,EAAE,EAAE,EAAE,YAAY,EAAE,CAAC,EAAE,CAAC;IAC7C,CAAC;IAED,mEAAmE;IACnE,MAAM,QAAQ,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;IAC7C,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAE9C,IAAI,cAAc,CAAC,MAAM,IAAI,cAAc,EAAE,CAAC;QAC7C,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC,EAAE,CAAC;IACzD,CAAC;IAED,MAAM,cAAc,GACnB,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,cAAc,CAAC,CAAC;IACpG,MAAM,YAAY,GAAG,cAAc,CAAC,MAAM,GAAG,cAAc,CAAC;IAE5D,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC;AACtD,CAAC;AAYD;;;;GAIG;AACH,MAAM,OAAO,iBAAiB;IACrB,OAAO,CAA2B;IAClC,WAAW,CAAqB;IAChC,WAAW,CAAuB;IAE1C,YAAY,OAAiC;QAC5C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACxB,CAAC;IAED,MAAM,CAAC,KAAa;QACnB,IAAI,IAAI,CAAC,WAAW,KAAK,SAAS,IAAI,IAAI,CAAC,WAAW,KAAK,KAAK,EAAE,CAAC;YAClE,MAAM,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC;YAChE,MAAM,OAAO,GAAG,qBAAqB,CAAC,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;YAC5E,MAAM,KAAK,GAAG,OAAO,CAAC,WAAW,CAAC;YAClC,IAAI,OAAO,CAAC,YAAY,GAAG,CAAC,EAAE,CAAC;gBAC9B,MAAM,IAAI,GAAG,eAAe,CAAC,UAAU,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;gBAC7E,IAAI,CAAC,WAAW,GAAG,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG,KAAK,CAAC,CAAC;YAC3E,CAAC;iBAAM,CAAC;gBACP,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;YAC1B,CAAC;YACD,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;QAC1B,CAAC;QACD,OAAO,IAAI,CAAC,WAAW,CAAC;IACzB,CAAC;IAED,UAAU;QACT,IAAI,CAAC,WAAW,GAAG,SAAS,CAAC;QAC7B,IAAI,CAAC,WAAW,GAAG,SAAS,CAAC;IAC9B,CAAC;CACD","sourcesContent":["/**\n * Shared utility for truncating text to visual lines (accounting for line wrapping).\n * Used by tool renderers and bash-execution.ts for consistent behavior.\n */\n\nimport { type Component, Text, truncateToWidth } from \"@earendil-works/pi-tui\";\n\nexport interface VisualTruncateResult {\n\t/** The visual lines to display */\n\tvisualLines: string[];\n\t/** Number of visual lines that were skipped (hidden) */\n\tskippedCount: number;\n}\n\n/**\n * Truncate text to a maximum number of visual lines.\n * This accounts for line wrapping based on terminal width.\n *\n * @param text - The text content (may contain newlines)\n * @param maxVisualLines - Maximum number of visual lines to show\n * @param width - Terminal/render width\n * @param paddingX - Horizontal padding for Text component (default 0).\n * Use 0 when result will be placed in a Box (Box adds its own padding).\n * Use 1 when result will be placed in a plain Container.\n * @param keep - Which visual lines to keep: the last ones (default) or the first ones.\n * @returns The truncated visual lines and count of skipped lines\n */\nexport function truncateToVisualLines(\n\ttext: string,\n\tmaxVisualLines: number,\n\twidth: number,\n\tpaddingX: number = 0,\n\tkeep: \"start\" | \"end\" = \"end\",\n): VisualTruncateResult {\n\tif (!text) {\n\t\treturn { visualLines: [], skippedCount: 0 };\n\t}\n\n\t// Create a temporary Text component to render and get visual lines\n\tconst tempText = new Text(text, paddingX, 0);\n\tconst allVisualLines = tempText.render(width);\n\n\tif (allVisualLines.length <= maxVisualLines) {\n\t\treturn { visualLines: allVisualLines, skippedCount: 0 };\n\t}\n\n\tconst truncatedLines =\n\t\tkeep === \"start\" ? allVisualLines.slice(0, maxVisualLines) : allVisualLines.slice(-maxVisualLines);\n\tconst skippedCount = allVisualLines.length - maxVisualLines;\n\n\treturn { visualLines: truncatedLines, skippedCount };\n}\n\nexport interface VisualLinePreviewOptions {\n\t/** Styled text; may contain newlines. */\n\ttext: string;\n\tmaxVisualLines: number;\n\t/** Which visual lines to keep. The hint goes before kept end lines and after kept start lines. */\n\tkeep: \"start\" | \"end\";\n\t/** Styled hint line for the given number of hidden visual lines. */\n\tformatHint: (hidden: number) => string;\n}\n\n/**\n * Collapsed tool output limited to a number of visual lines, like bash output. Limiting logical\n * lines instead lets a single long line (such as minified JSON) wrap across the whole screen.\n * Caches its lines per width, since it renders on every frame for every result in the transcript.\n */\nexport class VisualLinePreview implements Component {\n\tprivate options: VisualLinePreviewOptions;\n\tprivate cachedWidth: number | undefined;\n\tprivate cachedLines: string[] | undefined;\n\n\tconstructor(options: VisualLinePreviewOptions) {\n\t\tthis.options = options;\n\t}\n\n\trender(width: number): string[] {\n\t\tif (this.cachedLines === undefined || this.cachedWidth !== width) {\n\t\t\tconst { text, maxVisualLines, keep, formatHint } = this.options;\n\t\t\tconst preview = truncateToVisualLines(text, maxVisualLines, width, 0, keep);\n\t\t\tconst lines = preview.visualLines;\n\t\t\tif (preview.skippedCount > 0) {\n\t\t\t\tconst hint = truncateToWidth(formatHint(preview.skippedCount), width, \"...\");\n\t\t\t\tthis.cachedLines = keep === \"start\" ? [...lines, hint] : [hint, ...lines];\n\t\t\t} else {\n\t\t\t\tthis.cachedLines = lines;\n\t\t\t}\n\t\t\tthis.cachedWidth = width;\n\t\t}\n\t\treturn this.cachedLines;\n\t}\n\n\tinvalidate(): void {\n\t\tthis.cachedWidth = undefined;\n\t\tthis.cachedLines = undefined;\n\t}\n}\n"]}