@posthog/agent 2.3.187 → 2.3.207
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/claude/conversion/tool-use-to-acp.js +9 -1
- package/dist/adapters/claude/conversion/tool-use-to-acp.js.map +1 -1
- package/dist/agent.js +18 -7
- package/dist/agent.js.map +1 -1
- package/dist/index.d.ts +57 -1
- package/dist/index.js +45 -1
- package/dist/index.js.map +1 -1
- package/dist/posthog-api.js +1 -1
- package/dist/posthog-api.js.map +1 -1
- package/dist/server/agent-server.js +26 -10
- package/dist/server/agent-server.js.map +1 -1
- package/dist/server/bin.cjs +26 -10
- package/dist/server/bin.cjs.map +1 -1
- package/package.json +1 -1
- package/src/acp-extensions.ts +15 -4
- package/src/adapters/claude/claude-agent.ts +1 -1
- package/src/adapters/claude/conversion/sdk-to-acp.ts +4 -3
- package/src/adapters/claude/conversion/tool-use-to-acp.ts +11 -3
- package/src/adapters/claude/permissions/permission-handlers.ts +4 -1
- package/src/index.ts +1 -0
- package/src/sagas/resume-saga.test.ts +0 -29
- package/src/sagas/resume-saga.ts +5 -6
|
@@ -175,7 +175,15 @@ function toolInfoFromToolUse(toolUse, options) {
|
|
|
175
175
|
const writeDisplayPath = writeFilePath ? toDisplayPath(writeFilePath, options?.cwd) : void 0;
|
|
176
176
|
const contentStr = input?.content ? String(input.content) : void 0;
|
|
177
177
|
if (writeFilePath) {
|
|
178
|
-
|
|
178
|
+
let oldContent = null;
|
|
179
|
+
if (options?.cachedFileContent && writeFilePath in options.cachedFileContent) {
|
|
180
|
+
oldContent = options.cachedFileContent[writeFilePath];
|
|
181
|
+
} else {
|
|
182
|
+
try {
|
|
183
|
+
oldContent = fs.readFileSync(writeFilePath, "utf-8");
|
|
184
|
+
} catch {
|
|
185
|
+
}
|
|
186
|
+
}
|
|
179
187
|
contentResult = toolContent().diff(writeFilePath, oldContent, contentStr ?? "").build();
|
|
180
188
|
} else if (contentStr) {
|
|
181
189
|
contentResult = toolContent().text(contentStr).build();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/adapters/claude/conversion/tool-use-to-acp.ts","../../../../src/utils/acp-content.ts","../../../../src/adapters/claude/mcp/tool-metadata.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport type {\n PlanEntry,\n ToolCall,\n ToolCallContent,\n ToolCallLocation,\n ToolCallUpdate,\n ToolKind,\n} from \"@agentclientprotocol/sdk\";\nimport type {\n ToolResultBlockParam,\n ToolUseBlock,\n WebSearchToolResultBlockParam,\n} from \"@anthropic-ai/sdk/resources\";\nimport type {\n BetaBashCodeExecutionToolResultBlockParam,\n BetaCodeExecutionToolResultBlockParam,\n BetaRequestMCPToolResultBlockParam,\n BetaTextEditorCodeExecutionToolResultBlockParam,\n BetaToolSearchToolResultBlockParam,\n BetaWebFetchToolResultBlockParam,\n BetaWebSearchToolResultBlockParam,\n} from \"@anthropic-ai/sdk/resources/beta.mjs\";\n\nconst SYSTEM_REMINDER_REGEX =\n /\\s*<system-reminder>[\\s\\S]*?<\\/system-reminder>/g;\n\nfunction stripSystemReminders(value: string): string {\n return value.replace(SYSTEM_REMINDER_REGEX, \"\");\n}\n\nimport { resourceLink, text, toolContent } from \"../../../utils/acp-content\";\nimport { getMcpToolMetadata } from \"../mcp/tool-metadata\";\n\ntype ToolInfo = Pick<ToolCall, \"title\" | \"kind\" | \"content\" | \"locations\">;\n\n/**\n * Convert an absolute file path to a project-relative path for display.\n * Returns the original path if it's outside the project directory or if no cwd is provided.\n */\nexport function toDisplayPath(filePath: string, cwd?: string): string {\n if (!cwd) return filePath;\n const resolvedCwd = path.resolve(cwd);\n const resolvedFile = path.resolve(filePath);\n if (\n resolvedFile.startsWith(resolvedCwd + path.sep) ||\n resolvedFile === resolvedCwd\n ) {\n return path.relative(resolvedCwd, resolvedFile);\n }\n return filePath;\n}\n\nexport function toolInfoFromToolUse(\n toolUse: Pick<ToolUseBlock, \"name\" | \"input\">,\n options?: {\n supportsTerminalOutput?: boolean;\n toolUseId?: string;\n cachedFileContent?: Record<string, string>;\n cwd?: string;\n },\n): ToolInfo {\n const name = toolUse.name;\n const input = toolUse.input as Record<string, unknown> | undefined;\n\n switch (name) {\n case \"Task\":\n case \"Agent\":\n return {\n title: input?.description ? String(input.description) : name,\n kind: \"think\",\n content: input?.prompt\n ? toolContent().text(String(input.prompt)).build()\n : [],\n };\n\n case \"NotebookRead\":\n return {\n title: input?.notebook_path\n ? `Read Notebook ${String(input.notebook_path)}`\n : \"Read Notebook\",\n kind: \"read\",\n content: [],\n locations: input?.notebook_path\n ? [{ path: String(input.notebook_path) }]\n : [],\n };\n\n case \"NotebookEdit\":\n return {\n title: input?.notebook_path\n ? `Edit Notebook ${String(input.notebook_path)}`\n : \"Edit Notebook\",\n kind: \"edit\",\n content: input?.new_source\n ? toolContent().text(String(input.new_source)).build()\n : [],\n locations: input?.notebook_path\n ? [{ path: String(input.notebook_path) }]\n : [],\n };\n\n case \"Bash\":\n if (options?.supportsTerminalOutput && options?.toolUseId) {\n return {\n title: input?.description\n ? String(input.description)\n : \"Execute command\",\n kind: \"execute\",\n content: [{ type: \"terminal\", terminalId: options.toolUseId }],\n };\n }\n return {\n title: input?.description\n ? String(input.description)\n : \"Execute command\",\n kind: \"execute\",\n content: input?.command\n ? toolContent().text(String(input.command)).build()\n : [],\n };\n\n case \"BashOutput\":\n return {\n title: \"Tail Logs\",\n kind: \"execute\",\n content: [],\n };\n\n case \"KillShell\":\n return {\n title: \"Kill Process\",\n kind: \"execute\",\n content: [],\n };\n\n case \"Read\": {\n let limit = \"\";\n const inputLimit = input?.limit as number | undefined;\n const inputOffset = (input?.offset as number | undefined) ?? 1;\n if (inputLimit) {\n limit = ` (${inputOffset} - ${inputOffset + inputLimit - 1})`;\n } else if (inputOffset > 1) {\n limit = ` (from line ${inputOffset})`;\n }\n const displayPath = input?.file_path\n ? toDisplayPath(String(input.file_path), options?.cwd)\n : \"File\";\n return {\n title: `Read ${displayPath}${limit}`,\n kind: \"read\",\n locations: input?.file_path\n ? [\n {\n path: String(input.file_path),\n line: inputOffset,\n },\n ]\n : [],\n content: [],\n };\n }\n\n case \"LS\":\n return {\n title: `List the ${input?.path ? `\\`${String(input.path)}\\`` : \"current\"} directory's contents`,\n kind: \"search\",\n content: [],\n locations: [],\n };\n\n case \"Edit\": {\n const filePath = input?.file_path ? String(input.file_path) : undefined;\n const displayPath = filePath\n ? toDisplayPath(filePath, options?.cwd)\n : undefined;\n let oldText: string | null = input?.old_string\n ? String(input.old_string)\n : null;\n let newText: string = input?.new_string ? String(input.new_string) : \"\";\n\n // try to display a rich diff by first checking if file content is cached\n // and valid (old_text exists in the content), then fall back to reading\n // file from disk, then fall back to fragemented snippet diff\n if (filePath && oldText !== null) {\n const fileContent = resolveFileContent(\n filePath,\n oldText,\n options?.cachedFileContent,\n );\n if (fileContent) {\n const newContent = input?.replace_all\n ? fileContent.replaceAll(oldText, newText)\n : fileContent.replace(oldText, newText);\n oldText = fileContent;\n newText = newContent;\n }\n }\n\n return {\n title: displayPath ? `Edit \\`${displayPath}\\`` : \"Edit\",\n kind: \"edit\",\n content:\n input && filePath\n ? [\n {\n type: \"diff\",\n path: filePath,\n oldText,\n newText,\n },\n ]\n : [],\n locations: filePath ? [{ path: filePath }] : [],\n };\n }\n\n case \"Write\": {\n let contentResult: ToolCallContent[] = [];\n const writeFilePath = input?.file_path\n ? String(input.file_path)\n : undefined;\n const writeDisplayPath = writeFilePath\n ? toDisplayPath(writeFilePath, options?.cwd)\n : undefined;\n const contentStr = input?.content ? String(input.content) : undefined;\n if (writeFilePath) {\n const oldContent =\n options?.cachedFileContent &&\n writeFilePath in options.cachedFileContent\n ? options.cachedFileContent[writeFilePath]\n : null;\n contentResult = toolContent()\n .diff(writeFilePath, oldContent, contentStr ?? \"\")\n .build();\n } else if (contentStr) {\n contentResult = toolContent().text(contentStr).build();\n }\n return {\n title: writeDisplayPath ? `Write ${writeDisplayPath}` : \"Write\",\n kind: \"edit\",\n content: contentResult,\n locations: writeFilePath ? [{ path: writeFilePath }] : [],\n };\n }\n\n case \"Glob\": {\n let label = \"Find\";\n const pathStr = input?.path ? String(input.path) : undefined;\n if (pathStr) {\n label += ` \"${pathStr}\"`;\n }\n if (input?.pattern) {\n label += ` \"${String(input.pattern)}\"`;\n }\n return {\n title: label,\n kind: \"search\",\n content: [],\n locations: pathStr ? [{ path: pathStr }] : [],\n };\n }\n\n case \"Grep\": {\n let label = \"grep\";\n\n if (input?.[\"-i\"]) {\n label += \" -i\";\n }\n if (input?.[\"-n\"]) {\n label += \" -n\";\n }\n\n if (input?.[\"-A\"] !== undefined) {\n label += ` -A ${input[\"-A\"]}`;\n }\n if (input?.[\"-B\"] !== undefined) {\n label += ` -B ${input[\"-B\"]}`;\n }\n if (input?.[\"-C\"] !== undefined) {\n label += ` -C ${input[\"-C\"]}`;\n }\n\n if (input?.output_mode) {\n switch (input.output_mode) {\n case \"files_with_matches\":\n label += \" -l\";\n break;\n case \"count\":\n label += \" -c\";\n break;\n default:\n break;\n }\n }\n\n if (input?.head_limit !== undefined) {\n label += ` | head -${input.head_limit}`;\n }\n\n if (input?.glob) {\n label += ` --include=\"${String(input.glob)}\"`;\n }\n\n if (input?.type) {\n label += ` --type=${String(input.type)}`;\n }\n\n if (input?.multiline) {\n label += \" -P\";\n }\n\n if (input?.pattern) {\n label += ` \"${String(input.pattern)}\"`;\n }\n\n if (input?.path) {\n label += ` ${String(input.path)}`;\n }\n\n return {\n title: label,\n kind: \"search\",\n content: [],\n };\n }\n\n case \"WebFetch\":\n return {\n title: \"Fetch\",\n kind: \"fetch\",\n content: input?.url\n ? [\n {\n type: \"content\",\n content: resourceLink(String(input.url), String(input.url), {\n description: input?.prompt ? String(input.prompt) : undefined,\n }),\n },\n ]\n : [],\n };\n\n case \"WebSearch\": {\n let label = `\"${input?.query ? String(input.query) : \"\"}\"`;\n const allowedDomains = input?.allowed_domains as string[] | undefined;\n const blockedDomains = input?.blocked_domains as string[] | undefined;\n\n if (allowedDomains && allowedDomains.length > 0) {\n label += ` (allowed: ${allowedDomains.join(\", \")})`;\n }\n\n if (blockedDomains && blockedDomains.length > 0) {\n label += ` (blocked: ${blockedDomains.join(\", \")})`;\n }\n\n return {\n title: label,\n kind: \"fetch\",\n content: [],\n };\n }\n\n case \"TodoWrite\":\n return {\n title: Array.isArray(input?.todos)\n ? `Update TODOs: ${input.todos.map((todo: { content?: string }) => todo.content).join(\", \")}`\n : \"Update TODOs\",\n kind: \"think\",\n content: [],\n };\n\n case \"ExitPlanMode\":\n return {\n title: \"Ready to code?\",\n kind: \"switch_mode\",\n content: input?.plan\n ? toolContent().text(String(input.plan)).build()\n : [],\n };\n\n case \"AskUserQuestion\": {\n const questions = input?.questions as\n | Array<{ question?: string }>\n | undefined;\n return {\n title: questions?.[0]?.question || \"Question\",\n kind: \"other\" as ToolKind,\n content: questions\n ? toolContent()\n .text(JSON.stringify(questions, null, 2))\n .build()\n : [],\n };\n }\n\n case \"Other\": {\n let output: string;\n try {\n output = JSON.stringify(input, null, 2);\n } catch {\n output = typeof input === \"string\" ? input : \"{}\";\n }\n return {\n title: name || \"Unknown Tool\",\n kind: \"other\",\n content: toolContent().text(`\\`\\`\\`json\\n${output}\\`\\`\\``).build(),\n };\n }\n\n default: {\n if (name?.startsWith(\"mcp__\")) {\n return mcpToolInfo(name, input);\n }\n return {\n title: name || \"Unknown Tool\",\n kind: \"other\",\n content: [],\n };\n }\n }\n}\n\nfunction mcpToolInfo(\n name: string,\n _input: Record<string, unknown> | undefined,\n): ToolInfo {\n const metadata = getMcpToolMetadata(name);\n // Fallback: parse tool name from mcp__<server>__<tool> prefix\n const title =\n metadata?.name ?? (name.split(\"__\").slice(2).join(\"__\") || name);\n\n return {\n title,\n kind: \"other\",\n content: [],\n };\n}\n\ninterface StructuredPatchHunk {\n oldStart: number;\n oldLines: number;\n newStart: number;\n newLines: number;\n lines: string[];\n}\n\ninterface StructuredPatch {\n oldFileName: string;\n newFileName: string;\n hunks: StructuredPatchHunk[];\n}\n\nexport function toolUpdateFromEditToolResponse(\n toolResponse: unknown,\n): { content: ToolCallContent[]; locations: ToolCallLocation[] } | null {\n if (!toolResponse || typeof toolResponse !== \"object\") return null;\n const response = toolResponse as Record<string, unknown>;\n\n const patches = response.structuredPatch as StructuredPatch[] | undefined;\n if (!Array.isArray(patches) || patches.length === 0) return null;\n\n const content: ToolCallContent[] = [];\n const locations: ToolCallLocation[] = [];\n\n for (const patch of patches) {\n if (!patch.hunks || patch.hunks.length === 0) continue;\n\n const filePath = patch.newFileName || patch.oldFileName;\n\n const oldLines: string[] = [];\n const newLines: string[] = [];\n for (const hunk of patch.hunks) {\n for (const line of hunk.lines) {\n if (line.startsWith(\"-\")) {\n oldLines.push(line.slice(1));\n } else if (line.startsWith(\"+\")) {\n newLines.push(line.slice(1));\n } else if (line.startsWith(\" \")) {\n oldLines.push(line.slice(1));\n newLines.push(line.slice(1));\n }\n }\n }\n\n content.push({\n type: \"diff\",\n path: filePath,\n oldText: oldLines.join(\"\\n\"),\n newText: newLines.join(\"\\n\"),\n });\n\n const firstHunk = patch.hunks[0];\n locations.push({\n path: filePath,\n line: firstHunk.newStart,\n });\n }\n\n if (content.length === 0) return null;\n return { content, locations };\n}\n\nexport function toolUpdateFromToolResult(\n toolResult:\n | ToolResultBlockParam\n | BetaWebSearchToolResultBlockParam\n | BetaWebFetchToolResultBlockParam\n | WebSearchToolResultBlockParam\n | BetaCodeExecutionToolResultBlockParam\n | BetaBashCodeExecutionToolResultBlockParam\n | BetaTextEditorCodeExecutionToolResultBlockParam\n | BetaRequestMCPToolResultBlockParam\n | BetaToolSearchToolResultBlockParam,\n toolUse: Pick<ToolUseBlock, \"name\" | \"input\"> | undefined,\n options?: {\n supportsTerminalOutput?: boolean;\n toolUseId?: string;\n cachedFileContent?: Record<string, string>;\n },\n): Pick<ToolCallUpdate, \"title\" | \"content\" | \"locations\" | \"_meta\"> {\n if (\n \"is_error\" in toolResult &&\n toolResult.is_error &&\n toolResult.content &&\n (toolResult.content as unknown[]).length > 0\n ) {\n return toAcpContentUpdate(toolResult.content, true);\n }\n\n switch (toolUse?.name) {\n case \"Read\":\n if (Array.isArray(toolResult.content) && toolResult.content.length > 0) {\n return {\n content: toolResult.content.map((item) => {\n const itemObj = item as {\n type?: string;\n text?: string;\n source?: { data?: string; media_type?: string };\n };\n if (itemObj.type === \"text\") {\n return {\n type: \"content\" as const,\n content: text(\n markdownEscape(stripSystemReminders(itemObj.text ?? \"\")),\n ),\n };\n }\n if (itemObj.type === \"image\" && itemObj.source) {\n return {\n type: \"content\" as const,\n content: {\n type: \"image\" as const,\n data: itemObj.source.data ?? \"\",\n mimeType: itemObj.source.media_type ?? \"image/png\",\n },\n };\n }\n return {\n type: \"content\" as const,\n content: item as { type: \"text\"; text: string },\n };\n }),\n };\n } else if (\n typeof toolResult.content === \"string\" &&\n toolResult.content.length > 0\n ) {\n return {\n content: toolContent()\n .text(markdownEscape(stripSystemReminders(toolResult.content)))\n .build(),\n };\n }\n return {};\n\n case \"Bash\": {\n const result = toolResult.content;\n const terminalId =\n \"tool_use_id\" in toolResult ? String(toolResult.tool_use_id) : \"\";\n const isError = \"is_error\" in toolResult && toolResult.is_error;\n\n let output = \"\";\n let exitCode = isError ? 1 : 0;\n\n if (\n result &&\n typeof result === \"object\" &&\n \"type\" in result &&\n (result as { type: string }).type === \"bash_code_execution_result\"\n ) {\n const bashResult = result as {\n stdout?: string;\n stderr?: string;\n return_code: number;\n };\n output = [bashResult.stdout, bashResult.stderr]\n .filter(Boolean)\n .join(\"\\n\");\n exitCode = bashResult.return_code;\n } else if (typeof result === \"string\") {\n output = result;\n } else if (\n Array.isArray(result) &&\n result.length > 0 &&\n \"text\" in result[0] &&\n typeof result[0].text === \"string\"\n ) {\n output = result.map((c: { text?: string }) => c.text ?? \"\").join(\"\\n\");\n }\n\n if (options?.supportsTerminalOutput) {\n return {\n content: [{ type: \"terminal\" as const, terminalId }],\n _meta: {\n terminal_info: {\n terminal_id: terminalId,\n },\n terminal_output: {\n terminal_id: terminalId,\n data: output,\n },\n terminal_exit: {\n terminal_id: terminalId,\n exit_code: exitCode,\n signal: null,\n },\n },\n };\n }\n if (output.trim()) {\n return {\n content: toolContent()\n .text(`\\`\\`\\`console\\n${output.trimEnd()}\\n\\`\\`\\``)\n .build(),\n };\n }\n return {};\n }\n case \"Edit\":\n case \"Write\":\n return {};\n\n case \"ExitPlanMode\": {\n return { title: \"Exited Plan Mode\" };\n }\n case \"AskUserQuestion\": {\n const content = toolResult.content;\n if (Array.isArray(content) && content.length > 0) {\n const firstItem = content[0];\n if (\n typeof firstItem === \"object\" &&\n firstItem !== null &&\n \"text\" in firstItem\n ) {\n return {\n title: \"Answer received\",\n content: toolContent().text(String(firstItem.text)).build(),\n };\n }\n }\n return { title: \"Question answered\" };\n }\n case \"WebFetch\": {\n const input = toolUse?.input as Record<string, unknown> | undefined;\n const url = input?.url ? String(input.url) : \"\";\n const prompt = input?.prompt ? String(input.prompt) : undefined;\n\n const resultContent = toAcpContentUpdate(\n toolResult.content,\n \"is_error\" in toolResult ? toolResult.is_error : false,\n );\n\n const content: ToolCallContent[] = [];\n if (url) {\n content.push({\n type: \"content\",\n content: resourceLink(url, url, {\n description: prompt,\n }),\n });\n }\n if (resultContent.content) {\n content.push(...resultContent.content);\n }\n\n return { content };\n }\n default: {\n return toAcpContentUpdate(\n toolResult.content,\n \"is_error\" in toolResult ? toolResult.is_error : false,\n );\n }\n }\n}\n\nfunction itemToText(item: unknown): string | null {\n if (!item || typeof item !== \"object\") return null;\n const obj = item as Record<string, unknown>;\n // Standard text block\n if (obj.type === \"text\" && typeof obj.text === \"string\") {\n return stripSystemReminders(obj.text);\n }\n // Any other structured object — serialize it\n try {\n return JSON.stringify(obj, null, 2);\n } catch {\n return null;\n }\n}\n\nfunction toAcpContentUpdate(\n content: unknown,\n isError: boolean = false,\n): Pick<ToolCallUpdate, \"content\"> {\n if (Array.isArray(content) && content.length > 0) {\n const texts: string[] = [];\n for (const item of content) {\n const t = itemToText(item);\n if (t) texts.push(t);\n }\n if (texts.length > 0) {\n const combined = texts.join(\"\\n\");\n return {\n content: toolContent()\n .text(isError ? `\\`\\`\\`\\n${combined}\\n\\`\\`\\`` : combined)\n .build(),\n };\n }\n } else if (typeof content === \"string\" && content.length > 0) {\n return {\n content: toolContent()\n .text(isError ? `\\`\\`\\`\\n${content}\\n\\`\\`\\`` : content)\n .build(),\n };\n } else if (content && typeof content === \"object\") {\n try {\n const json = JSON.stringify(content, null, 2);\n if (json && json !== \"{}\") {\n return {\n content: toolContent().text(json).build(),\n };\n }\n } catch {\n // ignore serialization errors\n }\n }\n return {};\n}\n\nexport type ClaudePlanEntry = {\n content: string;\n status: \"pending\" | \"in_progress\" | \"completed\";\n activeForm: string;\n};\n\nexport function planEntries(input: { todos: ClaudePlanEntry[] }): PlanEntry[] {\n return input.todos.map((input) => ({\n content: input.content,\n status: input.status,\n priority: \"medium\",\n }));\n}\n\n/**\n * attempt to resolve full file contents for diff generation\n *\n * 1) check file content cache exists, and is valid (old_text in content)\n * 2) if missing or invalid, read file from disk\n * 3) if both fail, return null, we'll fall back to fragmented snippet diff\n */\nfunction resolveFileContent(\n filePath: string,\n oldText: string,\n cachedFileContent?: Record<string, string>,\n): string | null {\n if (cachedFileContent && filePath in cachedFileContent) {\n const cached = cachedFileContent[filePath];\n if (cached.includes(oldText)) {\n return cached;\n }\n }\n\n try {\n const content = fs.readFileSync(filePath, \"utf-8\");\n if (content.includes(oldText)) {\n return content;\n }\n } catch {\n return null;\n }\n\n return null;\n}\n\nfunction markdownEscape(text: string): string {\n let escapedText = \"```\";\n for (const [m] of text.matchAll(/^```+/gm)) {\n while (m.length >= escapedText.length) {\n escapedText += \"`\";\n }\n }\n return `${escapedText}\\n${text}${text.endsWith(\"\\n\") ? \"\" : \"\\n\"}${escapedText}`;\n}\n","import type { ContentBlock, ToolCallContent } from \"@agentclientprotocol/sdk\";\n\nexport function text(value: string): ContentBlock {\n return { type: \"text\", text: value };\n}\n\nexport function image(\n data: string,\n mimeType: string,\n uri?: string,\n): ContentBlock {\n return { type: \"image\", data, mimeType, uri };\n}\n\nexport function resourceLink(\n uri: string,\n name: string,\n options?: {\n mimeType?: string;\n title?: string;\n description?: string;\n size?: number | null;\n },\n): ContentBlock {\n return {\n type: \"resource_link\",\n uri,\n name,\n ...options,\n };\n}\n\nclass ToolContentBuilder {\n private items: ToolCallContent[] = [];\n\n text(value: string): this {\n this.items.push({ type: \"content\", content: text(value) });\n return this;\n }\n\n image(data: string, mimeType: string, uri?: string): this {\n this.items.push({ type: \"content\", content: image(data, mimeType, uri) });\n return this;\n }\n\n diff(path: string, oldText: string | null, newText: string): this {\n this.items.push({ type: \"diff\", path, oldText, newText });\n return this;\n }\n\n build(): ToolCallContent[] {\n return this.items;\n }\n}\n\nexport function toolContent(): ToolContentBuilder {\n return new ToolContentBuilder();\n}\n","import type { McpServerStatus, Query } from \"@anthropic-ai/claude-agent-sdk\";\nimport { Logger } from \"../../../utils/logger\";\n\nexport interface McpToolMetadata {\n readOnly: boolean;\n name: string;\n description?: string;\n}\n\nconst mcpToolMetadataCache: Map<string, McpToolMetadata> = new Map();\n\nconst PENDING_RETRY_INTERVAL_MS = 1_000;\nconst PENDING_MAX_RETRIES = 10;\n\nfunction buildToolKey(serverName: string, toolName: string): string {\n return `mcp__${serverName}__${toolName}`;\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport async function fetchMcpToolMetadata(\n q: Query,\n logger: Logger = new Logger({ debug: false, prefix: \"[McpToolMetadata]\" }),\n): Promise<void> {\n let retries = 0;\n\n while (retries <= PENDING_MAX_RETRIES) {\n let statuses: McpServerStatus[];\n try {\n statuses = await q.mcpServerStatus();\n } catch (error) {\n logger.error(\"Failed to fetch MCP server status\", {\n error: error instanceof Error ? error.message : String(error),\n });\n return;\n }\n\n const pendingServers = statuses.filter((s) => s.status === \"pending\");\n\n for (const server of statuses) {\n if (server.status !== \"connected\" || !server.tools) {\n continue;\n }\n\n let readOnlyCount = 0;\n for (const tool of server.tools) {\n const toolKey = buildToolKey(server.name, tool.name);\n const readOnly = tool.annotations?.readOnly === true;\n\n mcpToolMetadataCache.set(toolKey, {\n readOnly,\n name: tool.name,\n description: tool.description,\n });\n if (readOnly) readOnlyCount++;\n }\n\n logger.info(\"Fetched MCP tool metadata\", {\n serverName: server.name,\n toolCount: server.tools.length,\n readOnlyCount,\n });\n }\n\n if (pendingServers.length === 0) {\n return;\n }\n\n retries++;\n if (retries > PENDING_MAX_RETRIES) {\n logger.warn(\"Gave up waiting for pending MCP servers\", {\n pendingServers: pendingServers.map((s) => s.name),\n });\n return;\n }\n\n logger.info(\"Waiting for pending MCP servers\", {\n pendingServers: pendingServers.map((s) => s.name),\n retry: retries,\n });\n await delay(PENDING_RETRY_INTERVAL_MS);\n }\n}\n\nexport function getMcpToolMetadata(\n toolName: string,\n): McpToolMetadata | undefined {\n return mcpToolMetadataCache.get(toolName);\n}\n\nexport function isMcpToolReadOnly(toolName: string): boolean {\n const metadata = mcpToolMetadataCache.get(toolName);\n return metadata?.readOnly === true;\n}\n\nexport function getConnectedMcpServerNames(): string[] {\n const names = new Set<string>();\n for (const key of mcpToolMetadataCache.keys()) {\n const parts = key.split(\"__\");\n if (parts.length >= 3) names.add(parts[1]);\n }\n return [...names];\n}\n\nexport function clearMcpToolMetadataCache(): void {\n mcpToolMetadataCache.clear();\n}\n"],"mappings":";AAAA,OAAO,QAAQ;AACf,OAAO,UAAU;;;ACCV,SAAS,KAAK,OAA6B;AAChD,SAAO,EAAE,MAAM,QAAQ,MAAM,MAAM;AACrC;AAEO,SAAS,MACd,MACA,UACA,KACc;AACd,SAAO,EAAE,MAAM,SAAS,MAAM,UAAU,IAAI;AAC9C;AAEO,SAAS,aACd,KACA,MACA,SAMc;AACd,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EACL;AACF;AAEA,IAAM,qBAAN,MAAyB;AAAA,EACf,QAA2B,CAAC;AAAA,EAEpC,KAAK,OAAqB;AACxB,SAAK,MAAM,KAAK,EAAE,MAAM,WAAW,SAAS,KAAK,KAAK,EAAE,CAAC;AACzD,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,MAAc,UAAkB,KAAoB;AACxD,SAAK,MAAM,KAAK,EAAE,MAAM,WAAW,SAAS,MAAM,MAAM,UAAU,GAAG,EAAE,CAAC;AACxE,WAAO;AAAA,EACT;AAAA,EAEA,KAAKA,OAAc,SAAwB,SAAuB;AAChE,SAAK,MAAM,KAAK,EAAE,MAAM,QAAQ,MAAAA,OAAM,SAAS,QAAQ,CAAC;AACxD,WAAO;AAAA,EACT;AAAA,EAEA,QAA2B;AACzB,WAAO,KAAK;AAAA,EACd;AACF;AAEO,SAAS,cAAkC;AAChD,SAAO,IAAI,mBAAmB;AAChC;;;AChDA,IAAM,uBAAqD,oBAAI,IAAI;AA6E5D,SAAS,mBACd,UAC6B;AAC7B,SAAO,qBAAqB,IAAI,QAAQ;AAC1C;;;AFjEA,IAAM,wBACJ;AAEF,SAAS,qBAAqB,OAAuB;AACnD,SAAO,MAAM,QAAQ,uBAAuB,EAAE;AAChD;AAWO,SAAS,cAAc,UAAkB,KAAsB;AACpE,MAAI,CAAC,IAAK,QAAO;AACjB,QAAM,cAAc,KAAK,QAAQ,GAAG;AACpC,QAAM,eAAe,KAAK,QAAQ,QAAQ;AAC1C,MACE,aAAa,WAAW,cAAc,KAAK,GAAG,KAC9C,iBAAiB,aACjB;AACA,WAAO,KAAK,SAAS,aAAa,YAAY;AAAA,EAChD;AACA,SAAO;AACT;AAEO,SAAS,oBACd,SACA,SAMU;AACV,QAAM,OAAO,QAAQ;AACrB,QAAM,QAAQ,QAAQ;AAEtB,UAAQ,MAAM;AAAA,IACZ,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,QACL,OAAO,OAAO,cAAc,OAAO,MAAM,WAAW,IAAI;AAAA,QACxD,MAAM;AAAA,QACN,SAAS,OAAO,SACZ,YAAY,EAAE,KAAK,OAAO,MAAM,MAAM,CAAC,EAAE,MAAM,IAC/C,CAAC;AAAA,MACP;AAAA,IAEF,KAAK;AACH,aAAO;AAAA,QACL,OAAO,OAAO,gBACV,iBAAiB,OAAO,MAAM,aAAa,CAAC,KAC5C;AAAA,QACJ,MAAM;AAAA,QACN,SAAS,CAAC;AAAA,QACV,WAAW,OAAO,gBACd,CAAC,EAAE,MAAM,OAAO,MAAM,aAAa,EAAE,CAAC,IACtC,CAAC;AAAA,MACP;AAAA,IAEF,KAAK;AACH,aAAO;AAAA,QACL,OAAO,OAAO,gBACV,iBAAiB,OAAO,MAAM,aAAa,CAAC,KAC5C;AAAA,QACJ,MAAM;AAAA,QACN,SAAS,OAAO,aACZ,YAAY,EAAE,KAAK,OAAO,MAAM,UAAU,CAAC,EAAE,MAAM,IACnD,CAAC;AAAA,QACL,WAAW,OAAO,gBACd,CAAC,EAAE,MAAM,OAAO,MAAM,aAAa,EAAE,CAAC,IACtC,CAAC;AAAA,MACP;AAAA,IAEF,KAAK;AACH,UAAI,SAAS,0BAA0B,SAAS,WAAW;AACzD,eAAO;AAAA,UACL,OAAO,OAAO,cACV,OAAO,MAAM,WAAW,IACxB;AAAA,UACJ,MAAM;AAAA,UACN,SAAS,CAAC,EAAE,MAAM,YAAY,YAAY,QAAQ,UAAU,CAAC;AAAA,QAC/D;AAAA,MACF;AACA,aAAO;AAAA,QACL,OAAO,OAAO,cACV,OAAO,MAAM,WAAW,IACxB;AAAA,QACJ,MAAM;AAAA,QACN,SAAS,OAAO,UACZ,YAAY,EAAE,KAAK,OAAO,MAAM,OAAO,CAAC,EAAE,MAAM,IAChD,CAAC;AAAA,MACP;AAAA,IAEF,KAAK;AACH,aAAO;AAAA,QACL,OAAO;AAAA,QACP,MAAM;AAAA,QACN,SAAS,CAAC;AAAA,MACZ;AAAA,IAEF,KAAK;AACH,aAAO;AAAA,QACL,OAAO;AAAA,QACP,MAAM;AAAA,QACN,SAAS,CAAC;AAAA,MACZ;AAAA,IAEF,KAAK,QAAQ;AACX,UAAI,QAAQ;AACZ,YAAM,aAAa,OAAO;AAC1B,YAAM,cAAe,OAAO,UAAiC;AAC7D,UAAI,YAAY;AACd,gBAAQ,KAAK,WAAW,MAAM,cAAc,aAAa,CAAC;AAAA,MAC5D,WAAW,cAAc,GAAG;AAC1B,gBAAQ,eAAe,WAAW;AAAA,MACpC;AACA,YAAM,cAAc,OAAO,YACvB,cAAc,OAAO,MAAM,SAAS,GAAG,SAAS,GAAG,IACnD;AACJ,aAAO;AAAA,QACL,OAAO,QAAQ,WAAW,GAAG,KAAK;AAAA,QAClC,MAAM;AAAA,QACN,WAAW,OAAO,YACd;AAAA,UACE;AAAA,YACE,MAAM,OAAO,MAAM,SAAS;AAAA,YAC5B,MAAM;AAAA,UACR;AAAA,QACF,IACA,CAAC;AAAA,QACL,SAAS,CAAC;AAAA,MACZ;AAAA,IACF;AAAA,IAEA,KAAK;AACH,aAAO;AAAA,QACL,OAAO,YAAY,OAAO,OAAO,KAAK,OAAO,MAAM,IAAI,CAAC,OAAO,SAAS;AAAA,QACxE,MAAM;AAAA,QACN,SAAS,CAAC;AAAA,QACV,WAAW,CAAC;AAAA,MACd;AAAA,IAEF,KAAK,QAAQ;AACX,YAAM,WAAW,OAAO,YAAY,OAAO,MAAM,SAAS,IAAI;AAC9D,YAAM,cAAc,WAChB,cAAc,UAAU,SAAS,GAAG,IACpC;AACJ,UAAI,UAAyB,OAAO,aAChC,OAAO,MAAM,UAAU,IACvB;AACJ,UAAI,UAAkB,OAAO,aAAa,OAAO,MAAM,UAAU,IAAI;AAKrE,UAAI,YAAY,YAAY,MAAM;AAChC,cAAM,cAAc;AAAA,UAClB;AAAA,UACA;AAAA,UACA,SAAS;AAAA,QACX;AACA,YAAI,aAAa;AACf,gBAAM,aAAa,OAAO,cACtB,YAAY,WAAW,SAAS,OAAO,IACvC,YAAY,QAAQ,SAAS,OAAO;AACxC,oBAAU;AACV,oBAAU;AAAA,QACZ;AAAA,MACF;AAEA,aAAO;AAAA,QACL,OAAO,cAAc,UAAU,WAAW,OAAO;AAAA,QACjD,MAAM;AAAA,QACN,SACE,SAAS,WACL;AAAA,UACE;AAAA,YACE,MAAM;AAAA,YACN,MAAM;AAAA,YACN;AAAA,YACA;AAAA,UACF;AAAA,QACF,IACA,CAAC;AAAA,QACP,WAAW,WAAW,CAAC,EAAE,MAAM,SAAS,CAAC,IAAI,CAAC;AAAA,MAChD;AAAA,IACF;AAAA,IAEA,KAAK,SAAS;AACZ,UAAI,gBAAmC,CAAC;AACxC,YAAM,gBAAgB,OAAO,YACzB,OAAO,MAAM,SAAS,IACtB;AACJ,YAAM,mBAAmB,gBACrB,cAAc,eAAe,SAAS,GAAG,IACzC;AACJ,YAAM,aAAa,OAAO,UAAU,OAAO,MAAM,OAAO,IAAI;AAC5D,UAAI,eAAe;AACjB,cAAM,aACJ,SAAS,qBACT,iBAAiB,QAAQ,oBACrB,QAAQ,kBAAkB,aAAa,IACvC;AACN,wBAAgB,YAAY,EACzB,KAAK,eAAe,YAAY,cAAc,EAAE,EAChD,MAAM;AAAA,MACX,WAAW,YAAY;AACrB,wBAAgB,YAAY,EAAE,KAAK,UAAU,EAAE,MAAM;AAAA,MACvD;AACA,aAAO;AAAA,QACL,OAAO,mBAAmB,SAAS,gBAAgB,KAAK;AAAA,QACxD,MAAM;AAAA,QACN,SAAS;AAAA,QACT,WAAW,gBAAgB,CAAC,EAAE,MAAM,cAAc,CAAC,IAAI,CAAC;AAAA,MAC1D;AAAA,IACF;AAAA,IAEA,KAAK,QAAQ;AACX,UAAI,QAAQ;AACZ,YAAM,UAAU,OAAO,OAAO,OAAO,MAAM,IAAI,IAAI;AACnD,UAAI,SAAS;AACX,iBAAS,KAAK,OAAO;AAAA,MACvB;AACA,UAAI,OAAO,SAAS;AAClB,iBAAS,KAAK,OAAO,MAAM,OAAO,CAAC;AAAA,MACrC;AACA,aAAO;AAAA,QACL,OAAO;AAAA,QACP,MAAM;AAAA,QACN,SAAS,CAAC;AAAA,QACV,WAAW,UAAU,CAAC,EAAE,MAAM,QAAQ,CAAC,IAAI,CAAC;AAAA,MAC9C;AAAA,IACF;AAAA,IAEA,KAAK,QAAQ;AACX,UAAI,QAAQ;AAEZ,UAAI,QAAQ,IAAI,GAAG;AACjB,iBAAS;AAAA,MACX;AACA,UAAI,QAAQ,IAAI,GAAG;AACjB,iBAAS;AAAA,MACX;AAEA,UAAI,QAAQ,IAAI,MAAM,QAAW;AAC/B,iBAAS,OAAO,MAAM,IAAI,CAAC;AAAA,MAC7B;AACA,UAAI,QAAQ,IAAI,MAAM,QAAW;AAC/B,iBAAS,OAAO,MAAM,IAAI,CAAC;AAAA,MAC7B;AACA,UAAI,QAAQ,IAAI,MAAM,QAAW;AAC/B,iBAAS,OAAO,MAAM,IAAI,CAAC;AAAA,MAC7B;AAEA,UAAI,OAAO,aAAa;AACtB,gBAAQ,MAAM,aAAa;AAAA,UACzB,KAAK;AACH,qBAAS;AACT;AAAA,UACF,KAAK;AACH,qBAAS;AACT;AAAA,UACF;AACE;AAAA,QACJ;AAAA,MACF;AAEA,UAAI,OAAO,eAAe,QAAW;AACnC,iBAAS,YAAY,MAAM,UAAU;AAAA,MACvC;AAEA,UAAI,OAAO,MAAM;AACf,iBAAS,eAAe,OAAO,MAAM,IAAI,CAAC;AAAA,MAC5C;AAEA,UAAI,OAAO,MAAM;AACf,iBAAS,WAAW,OAAO,MAAM,IAAI,CAAC;AAAA,MACxC;AAEA,UAAI,OAAO,WAAW;AACpB,iBAAS;AAAA,MACX;AAEA,UAAI,OAAO,SAAS;AAClB,iBAAS,KAAK,OAAO,MAAM,OAAO,CAAC;AAAA,MACrC;AAEA,UAAI,OAAO,MAAM;AACf,iBAAS,IAAI,OAAO,MAAM,IAAI,CAAC;AAAA,MACjC;AAEA,aAAO;AAAA,QACL,OAAO;AAAA,QACP,MAAM;AAAA,QACN,SAAS,CAAC;AAAA,MACZ;AAAA,IACF;AAAA,IAEA,KAAK;AACH,aAAO;AAAA,QACL,OAAO;AAAA,QACP,MAAM;AAAA,QACN,SAAS,OAAO,MACZ;AAAA,UACE;AAAA,YACE,MAAM;AAAA,YACN,SAAS,aAAa,OAAO,MAAM,GAAG,GAAG,OAAO,MAAM,GAAG,GAAG;AAAA,cAC1D,aAAa,OAAO,SAAS,OAAO,MAAM,MAAM,IAAI;AAAA,YACtD,CAAC;AAAA,UACH;AAAA,QACF,IACA,CAAC;AAAA,MACP;AAAA,IAEF,KAAK,aAAa;AAChB,UAAI,QAAQ,IAAI,OAAO,QAAQ,OAAO,MAAM,KAAK,IAAI,EAAE;AACvD,YAAM,iBAAiB,OAAO;AAC9B,YAAM,iBAAiB,OAAO;AAE9B,UAAI,kBAAkB,eAAe,SAAS,GAAG;AAC/C,iBAAS,cAAc,eAAe,KAAK,IAAI,CAAC;AAAA,MAClD;AAEA,UAAI,kBAAkB,eAAe,SAAS,GAAG;AAC/C,iBAAS,cAAc,eAAe,KAAK,IAAI,CAAC;AAAA,MAClD;AAEA,aAAO;AAAA,QACL,OAAO;AAAA,QACP,MAAM;AAAA,QACN,SAAS,CAAC;AAAA,MACZ;AAAA,IACF;AAAA,IAEA,KAAK;AACH,aAAO;AAAA,QACL,OAAO,MAAM,QAAQ,OAAO,KAAK,IAC7B,iBAAiB,MAAM,MAAM,IAAI,CAAC,SAA+B,KAAK,OAAO,EAAE,KAAK,IAAI,CAAC,KACzF;AAAA,QACJ,MAAM;AAAA,QACN,SAAS,CAAC;AAAA,MACZ;AAAA,IAEF,KAAK;AACH,aAAO;AAAA,QACL,OAAO;AAAA,QACP,MAAM;AAAA,QACN,SAAS,OAAO,OACZ,YAAY,EAAE,KAAK,OAAO,MAAM,IAAI,CAAC,EAAE,MAAM,IAC7C,CAAC;AAAA,MACP;AAAA,IAEF,KAAK,mBAAmB;AACtB,YAAM,YAAY,OAAO;AAGzB,aAAO;AAAA,QACL,OAAO,YAAY,CAAC,GAAG,YAAY;AAAA,QACnC,MAAM;AAAA,QACN,SAAS,YACL,YAAY,EACT,KAAK,KAAK,UAAU,WAAW,MAAM,CAAC,CAAC,EACvC,MAAM,IACT,CAAC;AAAA,MACP;AAAA,IACF;AAAA,IAEA,KAAK,SAAS;AACZ,UAAI;AACJ,UAAI;AACF,iBAAS,KAAK,UAAU,OAAO,MAAM,CAAC;AAAA,MACxC,QAAQ;AACN,iBAAS,OAAO,UAAU,WAAW,QAAQ;AAAA,MAC/C;AACA,aAAO;AAAA,QACL,OAAO,QAAQ;AAAA,QACf,MAAM;AAAA,QACN,SAAS,YAAY,EAAE,KAAK;AAAA,EAAe,MAAM,QAAQ,EAAE,MAAM;AAAA,MACnE;AAAA,IACF;AAAA,IAEA,SAAS;AACP,UAAI,MAAM,WAAW,OAAO,GAAG;AAC7B,eAAO,YAAY,MAAM,KAAK;AAAA,MAChC;AACA,aAAO;AAAA,QACL,OAAO,QAAQ;AAAA,QACf,MAAM;AAAA,QACN,SAAS,CAAC;AAAA,MACZ;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,YACP,MACA,QACU;AACV,QAAM,WAAW,mBAAmB,IAAI;AAExC,QAAM,QACJ,UAAU,SAAS,KAAK,MAAM,IAAI,EAAE,MAAM,CAAC,EAAE,KAAK,IAAI,KAAK;AAE7D,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,SAAS,CAAC;AAAA,EACZ;AACF;AAgBO,SAAS,+BACd,cACsE;AACtE,MAAI,CAAC,gBAAgB,OAAO,iBAAiB,SAAU,QAAO;AAC9D,QAAM,WAAW;AAEjB,QAAM,UAAU,SAAS;AACzB,MAAI,CAAC,MAAM,QAAQ,OAAO,KAAK,QAAQ,WAAW,EAAG,QAAO;AAE5D,QAAM,UAA6B,CAAC;AACpC,QAAM,YAAgC,CAAC;AAEvC,aAAW,SAAS,SAAS;AAC3B,QAAI,CAAC,MAAM,SAAS,MAAM,MAAM,WAAW,EAAG;AAE9C,UAAM,WAAW,MAAM,eAAe,MAAM;AAE5C,UAAM,WAAqB,CAAC;AAC5B,UAAM,WAAqB,CAAC;AAC5B,eAAW,QAAQ,MAAM,OAAO;AAC9B,iBAAW,QAAQ,KAAK,OAAO;AAC7B,YAAI,KAAK,WAAW,GAAG,GAAG;AACxB,mBAAS,KAAK,KAAK,MAAM,CAAC,CAAC;AAAA,QAC7B,WAAW,KAAK,WAAW,GAAG,GAAG;AAC/B,mBAAS,KAAK,KAAK,MAAM,CAAC,CAAC;AAAA,QAC7B,WAAW,KAAK,WAAW,GAAG,GAAG;AAC/B,mBAAS,KAAK,KAAK,MAAM,CAAC,CAAC;AAC3B,mBAAS,KAAK,KAAK,MAAM,CAAC,CAAC;AAAA,QAC7B;AAAA,MACF;AAAA,IACF;AAEA,YAAQ,KAAK;AAAA,MACX,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS,SAAS,KAAK,IAAI;AAAA,MAC3B,SAAS,SAAS,KAAK,IAAI;AAAA,IAC7B,CAAC;AAED,UAAM,YAAY,MAAM,MAAM,CAAC;AAC/B,cAAU,KAAK;AAAA,MACb,MAAM;AAAA,MACN,MAAM,UAAU;AAAA,IAClB,CAAC;AAAA,EACH;AAEA,MAAI,QAAQ,WAAW,EAAG,QAAO;AACjC,SAAO,EAAE,SAAS,UAAU;AAC9B;AAEO,SAAS,yBACd,YAUA,SACA,SAKmE;AACnE,MACE,cAAc,cACd,WAAW,YACX,WAAW,WACV,WAAW,QAAsB,SAAS,GAC3C;AACA,WAAO,mBAAmB,WAAW,SAAS,IAAI;AAAA,EACpD;AAEA,UAAQ,SAAS,MAAM;AAAA,IACrB,KAAK;AACH,UAAI,MAAM,QAAQ,WAAW,OAAO,KAAK,WAAW,QAAQ,SAAS,GAAG;AACtE,eAAO;AAAA,UACL,SAAS,WAAW,QAAQ,IAAI,CAAC,SAAS;AACxC,kBAAM,UAAU;AAKhB,gBAAI,QAAQ,SAAS,QAAQ;AAC3B,qBAAO;AAAA,gBACL,MAAM;AAAA,gBACN,SAAS;AAAA,kBACP,eAAe,qBAAqB,QAAQ,QAAQ,EAAE,CAAC;AAAA,gBACzD;AAAA,cACF;AAAA,YACF;AACA,gBAAI,QAAQ,SAAS,WAAW,QAAQ,QAAQ;AAC9C,qBAAO;AAAA,gBACL,MAAM;AAAA,gBACN,SAAS;AAAA,kBACP,MAAM;AAAA,kBACN,MAAM,QAAQ,OAAO,QAAQ;AAAA,kBAC7B,UAAU,QAAQ,OAAO,cAAc;AAAA,gBACzC;AAAA,cACF;AAAA,YACF;AACA,mBAAO;AAAA,cACL,MAAM;AAAA,cACN,SAAS;AAAA,YACX;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF,WACE,OAAO,WAAW,YAAY,YAC9B,WAAW,QAAQ,SAAS,GAC5B;AACA,eAAO;AAAA,UACL,SAAS,YAAY,EAClB,KAAK,eAAe,qBAAqB,WAAW,OAAO,CAAC,CAAC,EAC7D,MAAM;AAAA,QACX;AAAA,MACF;AACA,aAAO,CAAC;AAAA,IAEV,KAAK,QAAQ;AACX,YAAM,SAAS,WAAW;AAC1B,YAAM,aACJ,iBAAiB,aAAa,OAAO,WAAW,WAAW,IAAI;AACjE,YAAM,UAAU,cAAc,cAAc,WAAW;AAEvD,UAAI,SAAS;AACb,UAAI,WAAW,UAAU,IAAI;AAE7B,UACE,UACA,OAAO,WAAW,YAClB,UAAU,UACT,OAA4B,SAAS,8BACtC;AACA,cAAM,aAAa;AAKnB,iBAAS,CAAC,WAAW,QAAQ,WAAW,MAAM,EAC3C,OAAO,OAAO,EACd,KAAK,IAAI;AACZ,mBAAW,WAAW;AAAA,MACxB,WAAW,OAAO,WAAW,UAAU;AACrC,iBAAS;AAAA,MACX,WACE,MAAM,QAAQ,MAAM,KACpB,OAAO,SAAS,KAChB,UAAU,OAAO,CAAC,KAClB,OAAO,OAAO,CAAC,EAAE,SAAS,UAC1B;AACA,iBAAS,OAAO,IAAI,CAAC,MAAyB,EAAE,QAAQ,EAAE,EAAE,KAAK,IAAI;AAAA,MACvE;AAEA,UAAI,SAAS,wBAAwB;AACnC,eAAO;AAAA,UACL,SAAS,CAAC,EAAE,MAAM,YAAqB,WAAW,CAAC;AAAA,UACnD,OAAO;AAAA,YACL,eAAe;AAAA,cACb,aAAa;AAAA,YACf;AAAA,YACA,iBAAiB;AAAA,cACf,aAAa;AAAA,cACb,MAAM;AAAA,YACR;AAAA,YACA,eAAe;AAAA,cACb,aAAa;AAAA,cACb,WAAW;AAAA,cACX,QAAQ;AAAA,YACV;AAAA,UACF;AAAA,QACF;AAAA,MACF;AACA,UAAI,OAAO,KAAK,GAAG;AACjB,eAAO;AAAA,UACL,SAAS,YAAY,EAClB,KAAK;AAAA,EAAkB,OAAO,QAAQ,CAAC;AAAA,OAAU,EACjD,MAAM;AAAA,QACX;AAAA,MACF;AACA,aAAO,CAAC;AAAA,IACV;AAAA,IACA,KAAK;AAAA,IACL,KAAK;AACH,aAAO,CAAC;AAAA,IAEV,KAAK,gBAAgB;AACnB,aAAO,EAAE,OAAO,mBAAmB;AAAA,IACrC;AAAA,IACA,KAAK,mBAAmB;AACtB,YAAM,UAAU,WAAW;AAC3B,UAAI,MAAM,QAAQ,OAAO,KAAK,QAAQ,SAAS,GAAG;AAChD,cAAM,YAAY,QAAQ,CAAC;AAC3B,YACE,OAAO,cAAc,YACrB,cAAc,QACd,UAAU,WACV;AACA,iBAAO;AAAA,YACL,OAAO;AAAA,YACP,SAAS,YAAY,EAAE,KAAK,OAAO,UAAU,IAAI,CAAC,EAAE,MAAM;AAAA,UAC5D;AAAA,QACF;AAAA,MACF;AACA,aAAO,EAAE,OAAO,oBAAoB;AAAA,IACtC;AAAA,IACA,KAAK,YAAY;AACf,YAAM,QAAQ,SAAS;AACvB,YAAM,MAAM,OAAO,MAAM,OAAO,MAAM,GAAG,IAAI;AAC7C,YAAM,SAAS,OAAO,SAAS,OAAO,MAAM,MAAM,IAAI;AAEtD,YAAM,gBAAgB;AAAA,QACpB,WAAW;AAAA,QACX,cAAc,aAAa,WAAW,WAAW;AAAA,MACnD;AAEA,YAAM,UAA6B,CAAC;AACpC,UAAI,KAAK;AACP,gBAAQ,KAAK;AAAA,UACX,MAAM;AAAA,UACN,SAAS,aAAa,KAAK,KAAK;AAAA,YAC9B,aAAa;AAAA,UACf,CAAC;AAAA,QACH,CAAC;AAAA,MACH;AACA,UAAI,cAAc,SAAS;AACzB,gBAAQ,KAAK,GAAG,cAAc,OAAO;AAAA,MACvC;AAEA,aAAO,EAAE,QAAQ;AAAA,IACnB;AAAA,IACA,SAAS;AACP,aAAO;AAAA,QACL,WAAW;AAAA,QACX,cAAc,aAAa,WAAW,WAAW;AAAA,MACnD;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,WAAW,MAA8B;AAChD,MAAI,CAAC,QAAQ,OAAO,SAAS,SAAU,QAAO;AAC9C,QAAM,MAAM;AAEZ,MAAI,IAAI,SAAS,UAAU,OAAO,IAAI,SAAS,UAAU;AACvD,WAAO,qBAAqB,IAAI,IAAI;AAAA,EACtC;AAEA,MAAI;AACF,WAAO,KAAK,UAAU,KAAK,MAAM,CAAC;AAAA,EACpC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,mBACP,SACA,UAAmB,OACc;AACjC,MAAI,MAAM,QAAQ,OAAO,KAAK,QAAQ,SAAS,GAAG;AAChD,UAAM,QAAkB,CAAC;AACzB,eAAW,QAAQ,SAAS;AAC1B,YAAM,IAAI,WAAW,IAAI;AACzB,UAAI,EAAG,OAAM,KAAK,CAAC;AAAA,IACrB;AACA,QAAI,MAAM,SAAS,GAAG;AACpB,YAAM,WAAW,MAAM,KAAK,IAAI;AAChC,aAAO;AAAA,QACL,SAAS,YAAY,EAClB,KAAK,UAAU;AAAA,EAAW,QAAQ;AAAA,UAAa,QAAQ,EACvD,MAAM;AAAA,MACX;AAAA,IACF;AAAA,EACF,WAAW,OAAO,YAAY,YAAY,QAAQ,SAAS,GAAG;AAC5D,WAAO;AAAA,MACL,SAAS,YAAY,EAClB,KAAK,UAAU;AAAA,EAAW,OAAO;AAAA,UAAa,OAAO,EACrD,MAAM;AAAA,IACX;AAAA,EACF,WAAW,WAAW,OAAO,YAAY,UAAU;AACjD,QAAI;AACF,YAAM,OAAO,KAAK,UAAU,SAAS,MAAM,CAAC;AAC5C,UAAI,QAAQ,SAAS,MAAM;AACzB,eAAO;AAAA,UACL,SAAS,YAAY,EAAE,KAAK,IAAI,EAAE,MAAM;AAAA,QAC1C;AAAA,MACF;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AACA,SAAO,CAAC;AACV;AAQO,SAAS,YAAY,OAAkD;AAC5E,SAAO,MAAM,MAAM,IAAI,CAACC,YAAW;AAAA,IACjC,SAASA,OAAM;AAAA,IACf,QAAQA,OAAM;AAAA,IACd,UAAU;AAAA,EACZ,EAAE;AACJ;AASA,SAAS,mBACP,UACA,SACA,mBACe;AACf,MAAI,qBAAqB,YAAY,mBAAmB;AACtD,UAAM,SAAS,kBAAkB,QAAQ;AACzC,QAAI,OAAO,SAAS,OAAO,GAAG;AAC5B,aAAO;AAAA,IACT;AAAA,EACF;AAEA,MAAI;AACF,UAAM,UAAU,GAAG,aAAa,UAAU,OAAO;AACjD,QAAI,QAAQ,SAAS,OAAO,GAAG;AAC7B,aAAO;AAAA,IACT;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEA,SAAS,eAAeC,OAAsB;AAC5C,MAAI,cAAc;AAClB,aAAW,CAAC,CAAC,KAAKA,MAAK,SAAS,SAAS,GAAG;AAC1C,WAAO,EAAE,UAAU,YAAY,QAAQ;AACrC,qBAAe;AAAA,IACjB;AAAA,EACF;AACA,SAAO,GAAG,WAAW;AAAA,EAAKA,KAAI,GAAGA,MAAK,SAAS,IAAI,IAAI,KAAK,IAAI,GAAG,WAAW;AAChF;","names":["path","input","text"]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/adapters/claude/conversion/tool-use-to-acp.ts","../../../../src/utils/acp-content.ts","../../../../src/adapters/claude/mcp/tool-metadata.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport type {\n PlanEntry,\n ToolCall,\n ToolCallContent,\n ToolCallLocation,\n ToolCallUpdate,\n ToolKind,\n} from \"@agentclientprotocol/sdk\";\nimport type {\n ToolResultBlockParam,\n ToolUseBlock,\n WebSearchToolResultBlockParam,\n} from \"@anthropic-ai/sdk/resources\";\nimport type {\n BetaBashCodeExecutionToolResultBlockParam,\n BetaCodeExecutionToolResultBlockParam,\n BetaRequestMCPToolResultBlockParam,\n BetaTextEditorCodeExecutionToolResultBlockParam,\n BetaToolSearchToolResultBlockParam,\n BetaWebFetchToolResultBlockParam,\n BetaWebSearchToolResultBlockParam,\n} from \"@anthropic-ai/sdk/resources/beta.mjs\";\n\nconst SYSTEM_REMINDER_REGEX =\n /\\s*<system-reminder>[\\s\\S]*?<\\/system-reminder>/g;\n\nfunction stripSystemReminders(value: string): string {\n return value.replace(SYSTEM_REMINDER_REGEX, \"\");\n}\n\nimport { resourceLink, text, toolContent } from \"../../../utils/acp-content\";\nimport { getMcpToolMetadata } from \"../mcp/tool-metadata\";\n\ntype ToolInfo = Pick<ToolCall, \"title\" | \"kind\" | \"content\" | \"locations\">;\n\n/**\n * Convert an absolute file path to a project-relative path for display.\n * Returns the original path if it's outside the project directory or if no cwd is provided.\n */\nexport function toDisplayPath(filePath: string, cwd?: string): string {\n if (!cwd) return filePath;\n const resolvedCwd = path.resolve(cwd);\n const resolvedFile = path.resolve(filePath);\n if (\n resolvedFile.startsWith(resolvedCwd + path.sep) ||\n resolvedFile === resolvedCwd\n ) {\n return path.relative(resolvedCwd, resolvedFile);\n }\n return filePath;\n}\n\nexport function toolInfoFromToolUse(\n toolUse: Pick<ToolUseBlock, \"name\" | \"input\">,\n options?: {\n supportsTerminalOutput?: boolean;\n toolUseId?: string;\n cachedFileContent?: Record<string, string>;\n cwd?: string;\n },\n): ToolInfo {\n const name = toolUse.name;\n const input = toolUse.input as Record<string, unknown> | undefined;\n\n switch (name) {\n case \"Task\":\n case \"Agent\":\n return {\n title: input?.description ? String(input.description) : name,\n kind: \"think\",\n content: input?.prompt\n ? toolContent().text(String(input.prompt)).build()\n : [],\n };\n\n case \"NotebookRead\":\n return {\n title: input?.notebook_path\n ? `Read Notebook ${String(input.notebook_path)}`\n : \"Read Notebook\",\n kind: \"read\",\n content: [],\n locations: input?.notebook_path\n ? [{ path: String(input.notebook_path) }]\n : [],\n };\n\n case \"NotebookEdit\":\n return {\n title: input?.notebook_path\n ? `Edit Notebook ${String(input.notebook_path)}`\n : \"Edit Notebook\",\n kind: \"edit\",\n content: input?.new_source\n ? toolContent().text(String(input.new_source)).build()\n : [],\n locations: input?.notebook_path\n ? [{ path: String(input.notebook_path) }]\n : [],\n };\n\n case \"Bash\":\n if (options?.supportsTerminalOutput && options?.toolUseId) {\n return {\n title: input?.description\n ? String(input.description)\n : \"Execute command\",\n kind: \"execute\",\n content: [{ type: \"terminal\", terminalId: options.toolUseId }],\n };\n }\n return {\n title: input?.description\n ? String(input.description)\n : \"Execute command\",\n kind: \"execute\",\n content: input?.command\n ? toolContent().text(String(input.command)).build()\n : [],\n };\n\n case \"BashOutput\":\n return {\n title: \"Tail Logs\",\n kind: \"execute\",\n content: [],\n };\n\n case \"KillShell\":\n return {\n title: \"Kill Process\",\n kind: \"execute\",\n content: [],\n };\n\n case \"Read\": {\n let limit = \"\";\n const inputLimit = input?.limit as number | undefined;\n const inputOffset = (input?.offset as number | undefined) ?? 1;\n if (inputLimit) {\n limit = ` (${inputOffset} - ${inputOffset + inputLimit - 1})`;\n } else if (inputOffset > 1) {\n limit = ` (from line ${inputOffset})`;\n }\n const displayPath = input?.file_path\n ? toDisplayPath(String(input.file_path), options?.cwd)\n : \"File\";\n return {\n title: `Read ${displayPath}${limit}`,\n kind: \"read\",\n locations: input?.file_path\n ? [\n {\n path: String(input.file_path),\n line: inputOffset,\n },\n ]\n : [],\n content: [],\n };\n }\n\n case \"LS\":\n return {\n title: `List the ${input?.path ? `\\`${String(input.path)}\\`` : \"current\"} directory's contents`,\n kind: \"search\",\n content: [],\n locations: [],\n };\n\n case \"Edit\": {\n const filePath = input?.file_path ? String(input.file_path) : undefined;\n const displayPath = filePath\n ? toDisplayPath(filePath, options?.cwd)\n : undefined;\n let oldText: string | null = input?.old_string\n ? String(input.old_string)\n : null;\n let newText: string = input?.new_string ? String(input.new_string) : \"\";\n\n // try to display a rich diff by first checking if file content is cached\n // and valid (old_text exists in the content), then fall back to reading\n // file from disk, then fall back to fragemented snippet diff\n if (filePath && oldText !== null) {\n const fileContent = resolveFileContent(\n filePath,\n oldText,\n options?.cachedFileContent,\n );\n if (fileContent) {\n const newContent = input?.replace_all\n ? fileContent.replaceAll(oldText, newText)\n : fileContent.replace(oldText, newText);\n oldText = fileContent;\n newText = newContent;\n }\n }\n\n return {\n title: displayPath ? `Edit \\`${displayPath}\\`` : \"Edit\",\n kind: \"edit\",\n content:\n input && filePath\n ? [\n {\n type: \"diff\",\n path: filePath,\n oldText,\n newText,\n },\n ]\n : [],\n locations: filePath ? [{ path: filePath }] : [],\n };\n }\n\n case \"Write\": {\n let contentResult: ToolCallContent[] = [];\n const writeFilePath = input?.file_path\n ? String(input.file_path)\n : undefined;\n const writeDisplayPath = writeFilePath\n ? toDisplayPath(writeFilePath, options?.cwd)\n : undefined;\n const contentStr = input?.content ? String(input.content) : undefined;\n if (writeFilePath) {\n let oldContent: string | null = null;\n if (\n options?.cachedFileContent &&\n writeFilePath in options.cachedFileContent\n ) {\n oldContent = options.cachedFileContent[writeFilePath];\n } else {\n try {\n oldContent = fs.readFileSync(writeFilePath, \"utf-8\");\n } catch {\n // File doesn't exist — genuinely a new file\n }\n }\n contentResult = toolContent()\n .diff(writeFilePath, oldContent, contentStr ?? \"\")\n .build();\n } else if (contentStr) {\n contentResult = toolContent().text(contentStr).build();\n }\n return {\n title: writeDisplayPath ? `Write ${writeDisplayPath}` : \"Write\",\n kind: \"edit\",\n content: contentResult,\n locations: writeFilePath ? [{ path: writeFilePath }] : [],\n };\n }\n\n case \"Glob\": {\n let label = \"Find\";\n const pathStr = input?.path ? String(input.path) : undefined;\n if (pathStr) {\n label += ` \"${pathStr}\"`;\n }\n if (input?.pattern) {\n label += ` \"${String(input.pattern)}\"`;\n }\n return {\n title: label,\n kind: \"search\",\n content: [],\n locations: pathStr ? [{ path: pathStr }] : [],\n };\n }\n\n case \"Grep\": {\n let label = \"grep\";\n\n if (input?.[\"-i\"]) {\n label += \" -i\";\n }\n if (input?.[\"-n\"]) {\n label += \" -n\";\n }\n\n if (input?.[\"-A\"] !== undefined) {\n label += ` -A ${input[\"-A\"]}`;\n }\n if (input?.[\"-B\"] !== undefined) {\n label += ` -B ${input[\"-B\"]}`;\n }\n if (input?.[\"-C\"] !== undefined) {\n label += ` -C ${input[\"-C\"]}`;\n }\n\n if (input?.output_mode) {\n switch (input.output_mode) {\n case \"files_with_matches\":\n label += \" -l\";\n break;\n case \"count\":\n label += \" -c\";\n break;\n default:\n break;\n }\n }\n\n if (input?.head_limit !== undefined) {\n label += ` | head -${input.head_limit}`;\n }\n\n if (input?.glob) {\n label += ` --include=\"${String(input.glob)}\"`;\n }\n\n if (input?.type) {\n label += ` --type=${String(input.type)}`;\n }\n\n if (input?.multiline) {\n label += \" -P\";\n }\n\n if (input?.pattern) {\n label += ` \"${String(input.pattern)}\"`;\n }\n\n if (input?.path) {\n label += ` ${String(input.path)}`;\n }\n\n return {\n title: label,\n kind: \"search\",\n content: [],\n };\n }\n\n case \"WebFetch\":\n return {\n title: \"Fetch\",\n kind: \"fetch\",\n content: input?.url\n ? [\n {\n type: \"content\",\n content: resourceLink(String(input.url), String(input.url), {\n description: input?.prompt ? String(input.prompt) : undefined,\n }),\n },\n ]\n : [],\n };\n\n case \"WebSearch\": {\n let label = `\"${input?.query ? String(input.query) : \"\"}\"`;\n const allowedDomains = input?.allowed_domains as string[] | undefined;\n const blockedDomains = input?.blocked_domains as string[] | undefined;\n\n if (allowedDomains && allowedDomains.length > 0) {\n label += ` (allowed: ${allowedDomains.join(\", \")})`;\n }\n\n if (blockedDomains && blockedDomains.length > 0) {\n label += ` (blocked: ${blockedDomains.join(\", \")})`;\n }\n\n return {\n title: label,\n kind: \"fetch\",\n content: [],\n };\n }\n\n case \"TodoWrite\":\n return {\n title: Array.isArray(input?.todos)\n ? `Update TODOs: ${input.todos.map((todo: { content?: string }) => todo.content).join(\", \")}`\n : \"Update TODOs\",\n kind: \"think\",\n content: [],\n };\n\n case \"ExitPlanMode\":\n return {\n title: \"Ready to code?\",\n kind: \"switch_mode\",\n content: input?.plan\n ? toolContent().text(String(input.plan)).build()\n : [],\n };\n\n case \"AskUserQuestion\": {\n const questions = input?.questions as\n | Array<{ question?: string }>\n | undefined;\n return {\n title: questions?.[0]?.question || \"Question\",\n kind: \"other\" as ToolKind,\n content: questions\n ? toolContent()\n .text(JSON.stringify(questions, null, 2))\n .build()\n : [],\n };\n }\n\n case \"Other\": {\n let output: string;\n try {\n output = JSON.stringify(input, null, 2);\n } catch {\n output = typeof input === \"string\" ? input : \"{}\";\n }\n return {\n title: name || \"Unknown Tool\",\n kind: \"other\",\n content: toolContent().text(`\\`\\`\\`json\\n${output}\\`\\`\\``).build(),\n };\n }\n\n default: {\n if (name?.startsWith(\"mcp__\")) {\n return mcpToolInfo(name, input);\n }\n return {\n title: name || \"Unknown Tool\",\n kind: \"other\",\n content: [],\n };\n }\n }\n}\n\nfunction mcpToolInfo(\n name: string,\n _input: Record<string, unknown> | undefined,\n): ToolInfo {\n const metadata = getMcpToolMetadata(name);\n // Fallback: parse tool name from mcp__<server>__<tool> prefix\n const title =\n metadata?.name ?? (name.split(\"__\").slice(2).join(\"__\") || name);\n\n return {\n title,\n kind: \"other\",\n content: [],\n };\n}\n\ninterface StructuredPatchHunk {\n oldStart: number;\n oldLines: number;\n newStart: number;\n newLines: number;\n lines: string[];\n}\n\ninterface StructuredPatch {\n oldFileName: string;\n newFileName: string;\n hunks: StructuredPatchHunk[];\n}\n\nexport function toolUpdateFromEditToolResponse(\n toolResponse: unknown,\n): { content: ToolCallContent[]; locations: ToolCallLocation[] } | null {\n if (!toolResponse || typeof toolResponse !== \"object\") return null;\n const response = toolResponse as Record<string, unknown>;\n\n const patches = response.structuredPatch as StructuredPatch[] | undefined;\n if (!Array.isArray(patches) || patches.length === 0) return null;\n\n const content: ToolCallContent[] = [];\n const locations: ToolCallLocation[] = [];\n\n for (const patch of patches) {\n if (!patch.hunks || patch.hunks.length === 0) continue;\n\n const filePath = patch.newFileName || patch.oldFileName;\n\n const oldLines: string[] = [];\n const newLines: string[] = [];\n for (const hunk of patch.hunks) {\n for (const line of hunk.lines) {\n if (line.startsWith(\"-\")) {\n oldLines.push(line.slice(1));\n } else if (line.startsWith(\"+\")) {\n newLines.push(line.slice(1));\n } else if (line.startsWith(\" \")) {\n oldLines.push(line.slice(1));\n newLines.push(line.slice(1));\n }\n }\n }\n\n content.push({\n type: \"diff\",\n path: filePath,\n oldText: oldLines.join(\"\\n\"),\n newText: newLines.join(\"\\n\"),\n });\n\n const firstHunk = patch.hunks[0];\n locations.push({\n path: filePath,\n line: firstHunk.newStart,\n });\n }\n\n if (content.length === 0) return null;\n return { content, locations };\n}\n\nexport function toolUpdateFromToolResult(\n toolResult:\n | ToolResultBlockParam\n | BetaWebSearchToolResultBlockParam\n | BetaWebFetchToolResultBlockParam\n | WebSearchToolResultBlockParam\n | BetaCodeExecutionToolResultBlockParam\n | BetaBashCodeExecutionToolResultBlockParam\n | BetaTextEditorCodeExecutionToolResultBlockParam\n | BetaRequestMCPToolResultBlockParam\n | BetaToolSearchToolResultBlockParam,\n toolUse: Pick<ToolUseBlock, \"name\" | \"input\"> | undefined,\n options?: {\n supportsTerminalOutput?: boolean;\n toolUseId?: string;\n cachedFileContent?: Record<string, string>;\n },\n): Pick<ToolCallUpdate, \"title\" | \"content\" | \"locations\" | \"_meta\"> {\n if (\n \"is_error\" in toolResult &&\n toolResult.is_error &&\n toolResult.content &&\n (toolResult.content as unknown[]).length > 0\n ) {\n return toAcpContentUpdate(toolResult.content, true);\n }\n\n switch (toolUse?.name) {\n case \"Read\":\n if (Array.isArray(toolResult.content) && toolResult.content.length > 0) {\n return {\n content: toolResult.content.map((item) => {\n const itemObj = item as {\n type?: string;\n text?: string;\n source?: { data?: string; media_type?: string };\n };\n if (itemObj.type === \"text\") {\n return {\n type: \"content\" as const,\n content: text(\n markdownEscape(stripSystemReminders(itemObj.text ?? \"\")),\n ),\n };\n }\n if (itemObj.type === \"image\" && itemObj.source) {\n return {\n type: \"content\" as const,\n content: {\n type: \"image\" as const,\n data: itemObj.source.data ?? \"\",\n mimeType: itemObj.source.media_type ?? \"image/png\",\n },\n };\n }\n return {\n type: \"content\" as const,\n content: item as { type: \"text\"; text: string },\n };\n }),\n };\n } else if (\n typeof toolResult.content === \"string\" &&\n toolResult.content.length > 0\n ) {\n return {\n content: toolContent()\n .text(markdownEscape(stripSystemReminders(toolResult.content)))\n .build(),\n };\n }\n return {};\n\n case \"Bash\": {\n const result = toolResult.content;\n const terminalId =\n \"tool_use_id\" in toolResult ? String(toolResult.tool_use_id) : \"\";\n const isError = \"is_error\" in toolResult && toolResult.is_error;\n\n let output = \"\";\n let exitCode = isError ? 1 : 0;\n\n if (\n result &&\n typeof result === \"object\" &&\n \"type\" in result &&\n (result as { type: string }).type === \"bash_code_execution_result\"\n ) {\n const bashResult = result as {\n stdout?: string;\n stderr?: string;\n return_code: number;\n };\n output = [bashResult.stdout, bashResult.stderr]\n .filter(Boolean)\n .join(\"\\n\");\n exitCode = bashResult.return_code;\n } else if (typeof result === \"string\") {\n output = result;\n } else if (\n Array.isArray(result) &&\n result.length > 0 &&\n \"text\" in result[0] &&\n typeof result[0].text === \"string\"\n ) {\n output = result.map((c: { text?: string }) => c.text ?? \"\").join(\"\\n\");\n }\n\n if (options?.supportsTerminalOutput) {\n return {\n content: [{ type: \"terminal\" as const, terminalId }],\n _meta: {\n terminal_info: {\n terminal_id: terminalId,\n },\n terminal_output: {\n terminal_id: terminalId,\n data: output,\n },\n terminal_exit: {\n terminal_id: terminalId,\n exit_code: exitCode,\n signal: null,\n },\n },\n };\n }\n if (output.trim()) {\n return {\n content: toolContent()\n .text(`\\`\\`\\`console\\n${output.trimEnd()}\\n\\`\\`\\``)\n .build(),\n };\n }\n return {};\n }\n case \"Edit\":\n case \"Write\":\n return {};\n\n case \"ExitPlanMode\": {\n return { title: \"Exited Plan Mode\" };\n }\n case \"AskUserQuestion\": {\n const content = toolResult.content;\n if (Array.isArray(content) && content.length > 0) {\n const firstItem = content[0];\n if (\n typeof firstItem === \"object\" &&\n firstItem !== null &&\n \"text\" in firstItem\n ) {\n return {\n title: \"Answer received\",\n content: toolContent().text(String(firstItem.text)).build(),\n };\n }\n }\n return { title: \"Question answered\" };\n }\n case \"WebFetch\": {\n const input = toolUse?.input as Record<string, unknown> | undefined;\n const url = input?.url ? String(input.url) : \"\";\n const prompt = input?.prompt ? String(input.prompt) : undefined;\n\n const resultContent = toAcpContentUpdate(\n toolResult.content,\n \"is_error\" in toolResult ? toolResult.is_error : false,\n );\n\n const content: ToolCallContent[] = [];\n if (url) {\n content.push({\n type: \"content\",\n content: resourceLink(url, url, {\n description: prompt,\n }),\n });\n }\n if (resultContent.content) {\n content.push(...resultContent.content);\n }\n\n return { content };\n }\n default: {\n return toAcpContentUpdate(\n toolResult.content,\n \"is_error\" in toolResult ? toolResult.is_error : false,\n );\n }\n }\n}\n\nfunction itemToText(item: unknown): string | null {\n if (!item || typeof item !== \"object\") return null;\n const obj = item as Record<string, unknown>;\n // Standard text block\n if (obj.type === \"text\" && typeof obj.text === \"string\") {\n return stripSystemReminders(obj.text);\n }\n // Any other structured object — serialize it\n try {\n return JSON.stringify(obj, null, 2);\n } catch {\n return null;\n }\n}\n\nfunction toAcpContentUpdate(\n content: unknown,\n isError: boolean = false,\n): Pick<ToolCallUpdate, \"content\"> {\n if (Array.isArray(content) && content.length > 0) {\n const texts: string[] = [];\n for (const item of content) {\n const t = itemToText(item);\n if (t) texts.push(t);\n }\n if (texts.length > 0) {\n const combined = texts.join(\"\\n\");\n return {\n content: toolContent()\n .text(isError ? `\\`\\`\\`\\n${combined}\\n\\`\\`\\`` : combined)\n .build(),\n };\n }\n } else if (typeof content === \"string\" && content.length > 0) {\n return {\n content: toolContent()\n .text(isError ? `\\`\\`\\`\\n${content}\\n\\`\\`\\`` : content)\n .build(),\n };\n } else if (content && typeof content === \"object\") {\n try {\n const json = JSON.stringify(content, null, 2);\n if (json && json !== \"{}\") {\n return {\n content: toolContent().text(json).build(),\n };\n }\n } catch {\n // ignore serialization errors\n }\n }\n return {};\n}\n\nexport type ClaudePlanEntry = {\n content: string;\n status: \"pending\" | \"in_progress\" | \"completed\";\n activeForm: string;\n};\n\nexport function planEntries(input: { todos: ClaudePlanEntry[] }): PlanEntry[] {\n return input.todos.map((input) => ({\n content: input.content,\n status: input.status,\n priority: \"medium\",\n }));\n}\n\n/**\n * attempt to resolve full file contents for diff generation\n *\n * 1) check file content cache exists, and is valid (old_text in content)\n * 2) if missing or invalid, read file from disk\n * 3) if both fail, return null, we'll fall back to fragmented snippet diff\n */\nfunction resolveFileContent(\n filePath: string,\n oldText: string,\n cachedFileContent?: Record<string, string>,\n): string | null {\n if (cachedFileContent && filePath in cachedFileContent) {\n const cached = cachedFileContent[filePath];\n if (cached.includes(oldText)) {\n return cached;\n }\n }\n\n try {\n const content = fs.readFileSync(filePath, \"utf-8\");\n if (content.includes(oldText)) {\n return content;\n }\n } catch {\n return null;\n }\n\n return null;\n}\n\nfunction markdownEscape(text: string): string {\n let escapedText = \"```\";\n for (const [m] of text.matchAll(/^```+/gm)) {\n while (m.length >= escapedText.length) {\n escapedText += \"`\";\n }\n }\n return `${escapedText}\\n${text}${text.endsWith(\"\\n\") ? \"\" : \"\\n\"}${escapedText}`;\n}\n","import type { ContentBlock, ToolCallContent } from \"@agentclientprotocol/sdk\";\n\nexport function text(value: string): ContentBlock {\n return { type: \"text\", text: value };\n}\n\nexport function image(\n data: string,\n mimeType: string,\n uri?: string,\n): ContentBlock {\n return { type: \"image\", data, mimeType, uri };\n}\n\nexport function resourceLink(\n uri: string,\n name: string,\n options?: {\n mimeType?: string;\n title?: string;\n description?: string;\n size?: number | null;\n },\n): ContentBlock {\n return {\n type: \"resource_link\",\n uri,\n name,\n ...options,\n };\n}\n\nclass ToolContentBuilder {\n private items: ToolCallContent[] = [];\n\n text(value: string): this {\n this.items.push({ type: \"content\", content: text(value) });\n return this;\n }\n\n image(data: string, mimeType: string, uri?: string): this {\n this.items.push({ type: \"content\", content: image(data, mimeType, uri) });\n return this;\n }\n\n diff(path: string, oldText: string | null, newText: string): this {\n this.items.push({ type: \"diff\", path, oldText, newText });\n return this;\n }\n\n build(): ToolCallContent[] {\n return this.items;\n }\n}\n\nexport function toolContent(): ToolContentBuilder {\n return new ToolContentBuilder();\n}\n","import type { McpServerStatus, Query } from \"@anthropic-ai/claude-agent-sdk\";\nimport { Logger } from \"../../../utils/logger\";\n\nexport interface McpToolMetadata {\n readOnly: boolean;\n name: string;\n description?: string;\n}\n\nconst mcpToolMetadataCache: Map<string, McpToolMetadata> = new Map();\n\nconst PENDING_RETRY_INTERVAL_MS = 1_000;\nconst PENDING_MAX_RETRIES = 10;\n\nfunction buildToolKey(serverName: string, toolName: string): string {\n return `mcp__${serverName}__${toolName}`;\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport async function fetchMcpToolMetadata(\n q: Query,\n logger: Logger = new Logger({ debug: false, prefix: \"[McpToolMetadata]\" }),\n): Promise<void> {\n let retries = 0;\n\n while (retries <= PENDING_MAX_RETRIES) {\n let statuses: McpServerStatus[];\n try {\n statuses = await q.mcpServerStatus();\n } catch (error) {\n logger.error(\"Failed to fetch MCP server status\", {\n error: error instanceof Error ? error.message : String(error),\n });\n return;\n }\n\n const pendingServers = statuses.filter((s) => s.status === \"pending\");\n\n for (const server of statuses) {\n if (server.status !== \"connected\" || !server.tools) {\n continue;\n }\n\n let readOnlyCount = 0;\n for (const tool of server.tools) {\n const toolKey = buildToolKey(server.name, tool.name);\n const readOnly = tool.annotations?.readOnly === true;\n\n mcpToolMetadataCache.set(toolKey, {\n readOnly,\n name: tool.name,\n description: tool.description,\n });\n if (readOnly) readOnlyCount++;\n }\n\n logger.info(\"Fetched MCP tool metadata\", {\n serverName: server.name,\n toolCount: server.tools.length,\n readOnlyCount,\n });\n }\n\n if (pendingServers.length === 0) {\n return;\n }\n\n retries++;\n if (retries > PENDING_MAX_RETRIES) {\n logger.warn(\"Gave up waiting for pending MCP servers\", {\n pendingServers: pendingServers.map((s) => s.name),\n });\n return;\n }\n\n logger.info(\"Waiting for pending MCP servers\", {\n pendingServers: pendingServers.map((s) => s.name),\n retry: retries,\n });\n await delay(PENDING_RETRY_INTERVAL_MS);\n }\n}\n\nexport function getMcpToolMetadata(\n toolName: string,\n): McpToolMetadata | undefined {\n return mcpToolMetadataCache.get(toolName);\n}\n\nexport function isMcpToolReadOnly(toolName: string): boolean {\n const metadata = mcpToolMetadataCache.get(toolName);\n return metadata?.readOnly === true;\n}\n\nexport function getConnectedMcpServerNames(): string[] {\n const names = new Set<string>();\n for (const key of mcpToolMetadataCache.keys()) {\n const parts = key.split(\"__\");\n if (parts.length >= 3) names.add(parts[1]);\n }\n return [...names];\n}\n\nexport function clearMcpToolMetadataCache(): void {\n mcpToolMetadataCache.clear();\n}\n"],"mappings":"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","names":["path","input","text"]}
|
package/dist/agent.js
CHANGED
|
@@ -245,7 +245,7 @@ import { v7 as uuidv7 } from "uuid";
|
|
|
245
245
|
// package.json
|
|
246
246
|
var package_default = {
|
|
247
247
|
name: "@posthog/agent",
|
|
248
|
-
version: "2.3.
|
|
248
|
+
version: "2.3.207",
|
|
249
249
|
repository: "https://github.com/PostHog/code",
|
|
250
250
|
description: "TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog",
|
|
251
251
|
exports: {
|
|
@@ -1054,7 +1054,15 @@ function toolInfoFromToolUse(toolUse, options) {
|
|
|
1054
1054
|
const writeDisplayPath = writeFilePath ? toDisplayPath(writeFilePath, options?.cwd) : void 0;
|
|
1055
1055
|
const contentStr = input?.content ? String(input.content) : void 0;
|
|
1056
1056
|
if (writeFilePath) {
|
|
1057
|
-
|
|
1057
|
+
let oldContent = null;
|
|
1058
|
+
if (options?.cachedFileContent && writeFilePath in options.cachedFileContent) {
|
|
1059
|
+
oldContent = options.cachedFileContent[writeFilePath];
|
|
1060
|
+
} else {
|
|
1061
|
+
try {
|
|
1062
|
+
oldContent = fs.readFileSync(writeFilePath, "utf-8");
|
|
1063
|
+
} catch {
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1058
1066
|
contentResult = toolContent().diff(writeFilePath, oldContent, contentStr ?? "").build();
|
|
1059
1067
|
} else if (contentStr) {
|
|
1060
1068
|
contentResult = toolContent().text(contentStr).build();
|
|
@@ -1818,7 +1826,7 @@ async function handleSystemMessage(message, context) {
|
|
|
1818
1826
|
case "init":
|
|
1819
1827
|
break;
|
|
1820
1828
|
case "compact_boundary":
|
|
1821
|
-
await client.extNotification(
|
|
1829
|
+
await client.extNotification(POSTHOG_NOTIFICATIONS.COMPACT_BOUNDARY, {
|
|
1822
1830
|
sessionId,
|
|
1823
1831
|
trigger: message.compact_metadata.trigger,
|
|
1824
1832
|
preTokens: message.compact_metadata.pre_tokens,
|
|
@@ -1834,7 +1842,7 @@ async function handleSystemMessage(message, context) {
|
|
|
1834
1842
|
case "status":
|
|
1835
1843
|
if (message.status === "compacting") {
|
|
1836
1844
|
logger.info("Session compacting started", { sessionId });
|
|
1837
|
-
await client.extNotification(
|
|
1845
|
+
await client.extNotification(POSTHOG_NOTIFICATIONS.STATUS, {
|
|
1838
1846
|
sessionId,
|
|
1839
1847
|
status: "compacting"
|
|
1840
1848
|
});
|
|
@@ -1847,7 +1855,7 @@ async function handleSystemMessage(message, context) {
|
|
|
1847
1855
|
status: message.status,
|
|
1848
1856
|
summary: message.summary
|
|
1849
1857
|
});
|
|
1850
|
-
await client.extNotification(
|
|
1858
|
+
await client.extNotification(POSTHOG_NOTIFICATIONS.TASK_NOTIFICATION, {
|
|
1851
1859
|
sessionId,
|
|
1852
1860
|
taskId: message.task_id,
|
|
1853
1861
|
status: message.status,
|
|
@@ -2506,7 +2514,10 @@ async function handleDefaultPermissionFlow(context) {
|
|
|
2506
2514
|
sessionId,
|
|
2507
2515
|
suggestions
|
|
2508
2516
|
} = context;
|
|
2509
|
-
const toolInfo = toolInfoFromToolUse(
|
|
2517
|
+
const toolInfo = toolInfoFromToolUse(
|
|
2518
|
+
{ name: toolName, input: toolInput },
|
|
2519
|
+
{ cachedFileContent: context.fileContentCache, cwd: session?.cwd }
|
|
2520
|
+
);
|
|
2510
2521
|
const options = buildPermissionOptions(
|
|
2511
2522
|
toolName,
|
|
2512
2523
|
toolInput,
|
|
@@ -3872,7 +3883,7 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
3872
3883
|
settingsManager.getSettings().model || meta?.model || void 0
|
|
3873
3884
|
),
|
|
3874
3885
|
...meta?.taskRunId ? [
|
|
3875
|
-
this.client.extNotification(
|
|
3886
|
+
this.client.extNotification(POSTHOG_NOTIFICATIONS.SDK_SESSION, {
|
|
3876
3887
|
taskRunId: meta.taskRunId,
|
|
3877
3888
|
sessionId,
|
|
3878
3889
|
adapter: "claude"
|