noumen 0.2.0 → 0.3.0

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 (83) hide show
  1. package/README.md +95 -16
  2. package/dist/a2a/index.d.ts +5 -5
  3. package/dist/a2a/index.js +3 -3
  4. package/dist/a2a/index.js.map +1 -1
  5. package/dist/acp/index.d.ts +5 -5
  6. package/dist/acp/index.js +4 -4
  7. package/dist/acp/index.js.map +1 -1
  8. package/dist/{agent-BrkbZyOT.d.ts → agent-1nFVUP9E.d.ts} +319 -15
  9. package/dist/{cache-DVqaCX8v.d.ts → cache-DsRqxx6v.d.ts} +1 -1
  10. package/dist/{chunk-BGG2E6JD.js → chunk-3HEYCV26.js} +1 -1
  11. package/dist/chunk-3SK5GCI6.js +75 -0
  12. package/dist/chunk-3SK5GCI6.js.map +1 -0
  13. package/dist/{chunk-NBDFQYUZ.js → chunk-4HW6LN6D.js} +4784 -2411
  14. package/dist/chunk-4HW6LN6D.js.map +1 -0
  15. package/dist/{chunk-7ZMN7XJE.js → chunk-5JN4SPI7.js} +6 -6
  16. package/dist/chunk-5JN4SPI7.js.map +1 -0
  17. package/dist/{chunk-CPFHEPW4.js → chunk-CS6WNDCF.js} +73 -41
  18. package/dist/chunk-CS6WNDCF.js.map +1 -0
  19. package/dist/chunk-EKOGVTBT.js +472 -0
  20. package/dist/chunk-EKOGVTBT.js.map +1 -0
  21. package/dist/{chunk-KY6ZPWHO.js → chunk-HEQQQGK5.js} +47 -28
  22. package/dist/chunk-HEQQQGK5.js.map +1 -0
  23. package/dist/{chunk-QTJ7VTJY.js → chunk-HL6JCRZJ.js} +1599 -481
  24. package/dist/chunk-HL6JCRZJ.js.map +1 -0
  25. package/dist/chunk-L3L3FG5T.js +16 -0
  26. package/dist/chunk-L3L3FG5T.js.map +1 -0
  27. package/dist/cli/index.js +36 -30
  28. package/dist/cli/index.js.map +1 -1
  29. package/dist/client/index.d.ts +2 -2
  30. package/dist/{headless-Q7XHHZIW.js → headless-FFU2DESQ.js} +3 -4
  31. package/dist/headless-FFU2DESQ.js.map +1 -0
  32. package/dist/index.d.ts +218 -68
  33. package/dist/index.js +37 -23
  34. package/dist/lsp/index.d.ts +4 -4
  35. package/dist/mcp/index.d.ts +5 -5
  36. package/dist/mcp/index.js +2 -1
  37. package/dist/mcp/index.js.map +1 -1
  38. package/dist/{provider-factory-34MSWJZ3.js → provider-factory-KCLIF34X.js} +2 -2
  39. package/dist/providers/anthropic.d.ts +2 -2
  40. package/dist/providers/anthropic.js +5 -3
  41. package/dist/providers/anthropic.js.map +1 -1
  42. package/dist/providers/bedrock.d.ts +2 -2
  43. package/dist/providers/bedrock.js +5 -3
  44. package/dist/providers/bedrock.js.map +1 -1
  45. package/dist/providers/gemini.d.ts +2 -1
  46. package/dist/providers/gemini.js +133 -95
  47. package/dist/providers/gemini.js.map +1 -1
  48. package/dist/providers/ollama.d.ts +13 -0
  49. package/dist/{ollama-YNXAYP3R.js → providers/ollama.js} +6 -4
  50. package/dist/providers/ollama.js.map +1 -0
  51. package/dist/providers/openai.d.ts +4 -1
  52. package/dist/providers/openai.js +2 -1
  53. package/dist/providers/openrouter.d.ts +1 -1
  54. package/dist/providers/openrouter.js +2 -1
  55. package/dist/providers/openrouter.js.map +1 -1
  56. package/dist/providers/vertex.d.ts +4 -2
  57. package/dist/providers/vertex.js +6 -3
  58. package/dist/providers/vertex.js.map +1 -1
  59. package/dist/{resolve-XM52G7YE.js → resolve-4JA2BBDA.js} +2 -2
  60. package/dist/server/index.d.ts +35 -20
  61. package/dist/server/index.js +276 -207
  62. package/dist/server/index.js.map +1 -1
  63. package/dist/{server-Cg1yWGaV.d.ts → server-CHMxuWKq.d.ts} +1 -1
  64. package/dist/{types-DwdzmXfs.d.ts → types-CD0rUKKT.d.ts} +2 -0
  65. package/dist/{types-3c88cRKH.d.ts → types-LrU4LRmX.d.ts} +28 -0
  66. package/dist/{types-CwKKucOF.d.ts → types-RPKUTu1k.d.ts} +27 -2
  67. package/dist/uuid-RVN2T26F.js +8 -0
  68. package/dist/uuid-RVN2T26F.js.map +1 -0
  69. package/dist/zod-7YXKWYMC.js +12 -0
  70. package/dist/zod-7YXKWYMC.js.map +1 -0
  71. package/package.json +19 -13
  72. package/dist/chunk-2ZTGQLYK.js +0 -356
  73. package/dist/chunk-2ZTGQLYK.js.map +0 -1
  74. package/dist/chunk-7ZMN7XJE.js.map +0 -1
  75. package/dist/chunk-CPFHEPW4.js.map +0 -1
  76. package/dist/chunk-KY6ZPWHO.js.map +0 -1
  77. package/dist/chunk-NBDFQYUZ.js.map +0 -1
  78. package/dist/chunk-QTJ7VTJY.js.map +0 -1
  79. package/dist/headless-Q7XHHZIW.js.map +0 -1
  80. package/dist/ollama-YNXAYP3R.js.map +0 -1
  81. /package/dist/{chunk-BGG2E6JD.js.map → chunk-3HEYCV26.js.map} +0 -0
  82. /package/dist/{provider-factory-34MSWJZ3.js.map → provider-factory-KCLIF34X.js.map} +0 -0
  83. /package/dist/{resolve-XM52G7YE.js.map → resolve-4JA2BBDA.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/tools/tool-search.ts","../src/utils/zod.ts","../src/tools/prompts/read.ts","../src/tools/read.ts","../src/tools/prompts/write.ts","../src/tools/write.ts","../src/tools/edit-utils.ts","../src/tools/prompts/edit.ts","../src/tools/edit.ts","../src/tools/shell-safety/git-safety.ts","../src/tools/shell-safety/command-classification.ts","../src/tools/shell-safety/git-tracking.ts","../src/tools/prompts/bash.ts","../src/tools/bash.ts","../src/tools/prompts/glob.ts","../src/utils/shell-escape.ts","../src/tools/glob.ts","../src/tools/prompts/grep.ts","../src/tools/grep.ts","../src/tools/prompts/web-fetch.ts","../src/tools/web-fetch.ts","../src/tools/prompts/notebook.ts","../src/tools/notebook.ts","../src/tools/ask-user.ts","../src/tools/registry.ts"],"sourcesContent":["import type { Tool, ToolResult, ToolContext, ToolParameters } from \"./types.js\";\n\nexport const TOOL_SEARCH_NAME = \"ToolSearch\";\n\n/**\n * Check if a tool should be deferred (requires ToolSearch to load).\n *\n * A tool is deferred if:\n * - It has `shouldDefer: true`\n * - It's an MCP tool (has `mcpInfo`) and doesn't have `alwaysLoad: true`\n *\n * A tool is never deferred if it has `alwaysLoad: true`, or if it IS\n * the ToolSearch tool itself.\n */\nexport function isDeferredTool(tool: Tool): boolean {\n if ((tool as ToolWithDeferral).alwaysLoad === true) return false;\n if (tool.mcpInfo !== undefined) return true;\n if (tool.name === TOOL_SEARCH_NAME) return false;\n return (tool as ToolWithDeferral).shouldDefer === true;\n}\n\n/**\n * Format a single deferred tool as a one-line reference for the system prompt.\n */\nexport function formatDeferredToolLine(tool: Tool): string {\n const desc = tool.description.split(\".\")[0];\n return `- ${tool.name}: ${desc}`;\n}\n\n/**\n * Parse a tool name into searchable parts. Handles MCP tools (mcp__server__action)\n * and CamelCase tool names.\n */\nfunction parseToolName(name: string): { parts: string[]; full: string; isMcp: boolean } {\n if (name.startsWith(\"mcp__\") || name.includes(\"__\")) {\n const withoutPrefix = name.replace(/^mcp__/, \"\").toLowerCase();\n const parts = withoutPrefix.split(\"__\").flatMap((p) => p.split(\"_\"));\n return { parts: parts.filter(Boolean), full: withoutPrefix.replace(/__/g, \" \").replace(/_/g, \" \"), isMcp: true };\n }\n\n const parts = name\n .replace(/([a-z])([A-Z])/g, \"$1 $2\")\n .replace(/_/g, \" \")\n .toLowerCase()\n .split(/\\s+/)\n .filter(Boolean);\n\n return { parts, full: parts.join(\" \"), isMcp: false };\n}\n\nfunction escapeRegExp(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\n/**\n * Keyword search over tool names and descriptions.\n */\nexport function searchToolsWithKeywords(\n query: string,\n deferredTools: Tool[],\n allTools: Tool[],\n maxResults: number,\n): string[] {\n const queryLower = query.toLowerCase().trim();\n\n const exactMatch =\n deferredTools.find((t) => t.name.toLowerCase() === queryLower) ??\n allTools.find((t) => t.name.toLowerCase() === queryLower);\n if (exactMatch) return [exactMatch.name];\n\n if (queryLower.startsWith(\"mcp__\") && queryLower.length > 5) {\n const prefixMatches = deferredTools\n .filter((t) => t.name.toLowerCase().startsWith(queryLower))\n .slice(0, maxResults)\n .map((t) => t.name);\n if (prefixMatches.length > 0) return prefixMatches;\n }\n\n const queryTerms = queryLower.split(/\\s+/).filter((t) => t.length > 0);\n const requiredTerms: string[] = [];\n const optionalTerms: string[] = [];\n\n for (const term of queryTerms) {\n if (term.startsWith(\"+\") && term.length > 1) {\n requiredTerms.push(term.slice(1));\n } else {\n optionalTerms.push(term);\n }\n }\n\n const allScoringTerms =\n requiredTerms.length > 0 ? [...requiredTerms, ...optionalTerms] : queryTerms;\n\n const termPatterns = new Map<string, RegExp>();\n for (const term of allScoringTerms) {\n if (!termPatterns.has(term)) {\n termPatterns.set(term, new RegExp(`\\\\b${escapeRegExp(term)}\\\\b`));\n }\n }\n\n let candidates = deferredTools;\n if (requiredTerms.length > 0) {\n candidates = deferredTools.filter((tool) => {\n const parsed = parseToolName(tool.name);\n const descLower = tool.description.toLowerCase();\n return requiredTerms.every((term) => {\n const pattern = termPatterns.get(term)!;\n return (\n parsed.parts.includes(term) ||\n parsed.parts.some((part) => part.includes(term)) ||\n pattern.test(descLower)\n );\n });\n });\n }\n\n const scored = candidates.map((tool) => {\n const parsed = parseToolName(tool.name);\n const descLower = tool.description.toLowerCase();\n let score = 0;\n\n for (const term of allScoringTerms) {\n const pattern = termPatterns.get(term)!;\n\n if (parsed.parts.includes(term)) {\n score += parsed.isMcp ? 12 : 10;\n } else if (parsed.parts.some((part) => part.includes(term))) {\n score += parsed.isMcp ? 6 : 5;\n }\n\n if (parsed.full.includes(term) && score === 0) {\n score += 3;\n }\n\n if (pattern.test(descLower)) {\n score += 2;\n }\n }\n\n return { name: tool.name, score };\n });\n\n return scored\n .filter((item) => item.score > 0)\n .sort((a, b) => b.score - a.score)\n .slice(0, maxResults)\n .map((item) => item.name);\n}\n\n/**\n * Format matched tool schemas as a `<functions>` block for the model.\n */\nfunction formatToolSchemas(tools: Tool[]): string {\n if (tools.length === 0) return \"No matching deferred tools found.\";\n\n const lines = tools.map((t) => {\n const schema = {\n description: t.description,\n name: t.name,\n parameters: t.parameters,\n };\n return `<function>${JSON.stringify(schema)}</function>`;\n });\n\n return `<functions>\\n${lines.join(\"\\n\")}\\n</functions>`;\n}\n\n/**\n * Extended Tool interface with deferral properties.\n */\nexport interface ToolWithDeferral extends Tool {\n shouldDefer?: boolean;\n alwaysLoad?: boolean;\n}\n\n/**\n * Create the ToolSearch tool. Requires access to the tool registry for\n * looking up deferred tools and their schemas.\n */\nexport function createToolSearchTool(\n getDeferredTools: () => Tool[],\n getAllTools: () => Tool[],\n getToolsByNames: (names: string[]) => Tool[],\n onDiscovered: (names: string[]) => void,\n): Tool {\n return {\n name: TOOL_SEARCH_NAME,\n description:\n \"Fetches full schema definitions for deferred tools so they can be called. \" +\n \"Deferred tools appear by name in <available-deferred-tools> sections. \" +\n \"Until fetched, only the name is known — there is no parameter schema, \" +\n \"so the tool cannot be invoked. Use this tool to load tool schemas.\\n\\n\" +\n \"Query forms:\\n\" +\n '- \"select:Read,Edit,Grep\" — fetch these exact tools by name\\n' +\n '- \"notebook jupyter\" — keyword search, up to max_results best matches\\n' +\n '- \"+slack send\" — require \"slack\" in the name, rank by remaining terms',\n isReadOnly: true,\n isConcurrencySafe: true,\n parameters: {\n type: \"object\",\n properties: {\n query: {\n type: \"string\",\n description:\n 'Query to find deferred tools. Use \"select:<tool_name>\" for direct selection, or keywords to search.',\n },\n max_results: {\n type: \"number\",\n description: \"Maximum number of results to return (default: 5)\",\n },\n },\n required: [\"query\"],\n } satisfies ToolParameters,\n\n async call(args: Record<string, unknown>): Promise<ToolResult> {\n const query = args.query as string;\n const maxResults = (args.max_results as number | undefined) ?? 5;\n const deferredTools = getDeferredTools();\n const allTools = getAllTools();\n\n const selectMatch = query.match(/^select:(.+)$/i);\n if (selectMatch) {\n const requested = selectMatch[1]!\n .split(\",\")\n .map((s) => s.trim())\n .filter(Boolean);\n\n const found: string[] = [];\n for (const toolName of requested) {\n const match =\n deferredTools.find((t) => t.name.toLowerCase() === toolName.toLowerCase()) ??\n allTools.find((t) => t.name.toLowerCase() === toolName.toLowerCase());\n if (match && !found.includes(match.name)) {\n found.push(match.name);\n }\n }\n\n if (found.length === 0) {\n return {\n content: JSON.stringify({\n matches: [],\n query,\n total_deferred_tools: deferredTools.length,\n }),\n };\n }\n\n onDiscovered(found);\n const matchedTools = getToolsByNames(found);\n return { content: formatToolSchemas(matchedTools) };\n }\n\n const matches = searchToolsWithKeywords(query, deferredTools, allTools, maxResults);\n\n if (matches.length === 0) {\n return {\n content: JSON.stringify({\n matches: [],\n query,\n total_deferred_tools: deferredTools.length,\n }),\n };\n }\n\n onDiscovered(matches);\n const matchedTools = getToolsByNames(matches);\n return { content: formatToolSchemas(matchedTools) };\n },\n };\n}\n","/**\n * Zod integration utilities. Users bring their own `zod` dependency — these\n * helpers accept duck-typed schemas so we don't force a hard dependency.\n */\n\nexport type JsonSchemaType = Record<string, unknown>;\n\n/**\n * Minimal interface matching Zod v4's safeParse return. Allows noumen to\n * validate tool input without depending on zod directly.\n */\nexport interface SafeParseResult {\n success: boolean;\n data?: unknown;\n error?: {\n issues: Array<{\n code: string;\n path: (string | number)[];\n message: string;\n }>;\n };\n}\n\nexport interface ZodLikeSchema {\n safeParse(data: unknown): SafeParseResult;\n}\n\nconst cache = new WeakMap<object, JsonSchemaType>();\n\n/**\n * Convert a Zod v4 schema to JSON Schema. Caches by schema identity.\n * Requires `zod/v4` to be installed — calls its native `toJSONSchema`.\n */\nexport function zodToJsonSchema(schema: ZodLikeSchema): JsonSchemaType {\n const hit = cache.get(schema);\n if (hit) return hit;\n\n const zod = (schema as unknown as { _zod?: unknown })._zod\n ? schema\n : undefined;\n\n if (!zod) {\n throw new Error(\n \"zodToJsonSchema requires a Zod v4 schema. Install zod and pass a z.object(…) schema.\",\n );\n }\n\n let toJSONSchema: ((s: unknown) => JsonSchemaType) | undefined;\n try {\n // Dynamic import isn't possible synchronously, so we look for the\n // schema's own conversion method first (Zod v4 attaches _toJSONSchema).\n const sAny = schema as unknown as Record<string, unknown>;\n if (typeof sAny._toJSONSchema === \"function\") {\n const result = sAny._toJSONSchema() as JsonSchemaType;\n cache.set(schema, result);\n return result;\n }\n // Fallback: try the module-level toJSONSchema from zod/v4\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n toJSONSchema = (globalThis as unknown as Record<string, unknown>)\n .__noumen_toJSONSchema as typeof toJSONSchema;\n } catch {\n // not available\n }\n\n if (toJSONSchema) {\n const result = toJSONSchema(schema) as JsonSchemaType;\n cache.set(schema, result);\n return result;\n }\n\n throw new Error(\n \"Could not convert Zod schema to JSON Schema. \" +\n \"Call `registerZodToJsonSchema(toJSONSchema)` from zod/v4 or upgrade to Zod v4.\",\n );\n}\n\n/**\n * Register the `toJSONSchema` function from `zod/v4` so `zodToJsonSchema` can use it.\n *\n * ```ts\n * import { toJSONSchema } from \"zod/v4\";\n * import { registerZodToJsonSchema } from \"noumen\";\n * registerZodToJsonSchema(toJSONSchema);\n * ```\n */\nexport function registerZodToJsonSchema(\n fn: (schema: unknown) => JsonSchemaType,\n): void {\n (globalThis as unknown as Record<string, unknown>).__noumen_toJSONSchema = fn;\n}\n\n/**\n * Format a Zod validation error into a human-readable string suitable\n * for feeding back to the model as a tool_result error.\n */\nexport function formatZodValidationError(\n toolName: string,\n issues: SafeParseResult[\"error\"],\n): string {\n if (!issues || !issues.issues.length) {\n return `${toolName}: validation failed with unknown error`;\n }\n\n const parts: string[] = [];\n\n const missing = issues.issues.filter(\n (i) => i.code === \"invalid_type\" && i.message.includes(\"required\"),\n );\n const unrecognized = issues.issues.filter(\n (i) => i.code === \"unrecognized_keys\",\n );\n const other = issues.issues.filter(\n (i) =>\n !missing.includes(i) && !unrecognized.includes(i),\n );\n\n if (missing.length) {\n parts.push(\n `Missing required parameter${missing.length > 1 ? \"s\" : \"\"}: ${missing.map((m) => formatPath(m.path)).join(\", \")}`,\n );\n }\n if (unrecognized.length) {\n parts.push(\n `Unrecognized parameter${unrecognized.length > 1 ? \"s\" : \"\"}: ${unrecognized.map((u) => u.message).join(\", \")}`,\n );\n }\n for (const issue of other) {\n const path = formatPath(issue.path);\n parts.push(`${path ? path + \": \" : \"\"}${issue.message}`);\n }\n\n return `${toolName} failed due to the following ${parts.length > 1 ? \"issues\" : \"issue\"}:\\n${parts.join(\"\\n\")}`;\n}\n\nfunction formatPath(path: (string | number)[]): string {\n return path\n .map((p, i) => (typeof p === \"number\" ? `[${p}]` : i > 0 ? `.${p}` : p))\n .join(\"\");\n}\n","/**\n * Model-facing prompt for the ReadFile tool.\n * Adapted from claude-code's FileReadTool/prompt.ts.\n */\n\nexport const READ_PROMPT = `Reads a file from the local filesystem. You can access any file directly by using this tool.\nAssume this tool is able to read all files on the machine. If the User provides a path to a file assume that path is valid. It is okay to read a file that does not exist; an error will be returned.\n\nUsage:\n- The file_path parameter must be an absolute path, not a relative path.\n- By default, it reads the entire file. Use offset and limit to read specific portions of large files.\n- Lines in the output are numbered with the format: LINE_NUMBER|LINE_CONTENT\n- If you read a file that exists but has empty contents you will receive a notice in place of file contents.\n- This tool can read image files (e.g. PNG, JPG) when the provider supports multimodal input.\n- This tool can read Jupyter notebooks (.ipynb files) and returns all cells with their outputs.\n- This tool can only read files, not directories. To list a directory, use an ls command via the Bash tool.\n- If the file has not changed since the last read, a \"file_unchanged\" result is returned to save context tokens.\n`;\n","import type { Tool, ToolResult, ToolContext } from \"./types.js\";\nimport type { ContentPart } from \"../session/types.js\";\nimport { READ_PROMPT } from \"./prompts/read.js\";\nimport {\n IMAGE_EXTENSIONS,\n maybeResizeAndDownsampleImageBuffer,\n compressImageBufferWithTokenLimit,\n createImageMetadataText,\n} from \"../utils/image-resizer.js\";\nimport * as path from \"node:path\";\n\nconst DEFAULT_MAX_IMAGE_TOKENS = 1600;\nconst MAX_FILE_SIZE = 10 * 1024 * 1024; // 10 MB\n\nconst BLOCKED_DEVICE_PATHS = new Set([\n \"/dev/zero\",\n \"/dev/random\",\n \"/dev/urandom\",\n \"/dev/full\",\n \"/dev/stdin\",\n \"/dev/tty\",\n \"/dev/console\",\n \"/dev/stdout\",\n \"/dev/stderr\",\n \"/dev/fd/0\",\n \"/dev/fd/1\",\n \"/dev/fd/2\",\n]);\n\nconst BINARY_EXTENSIONS = new Set([\n \".exe\", \".dll\", \".so\", \".dylib\", \".bin\", \".zip\", \".tar\", \".gz\", \".bz2\",\n \".xz\", \".7z\", \".rar\", \".wasm\", \".o\", \".a\", \".obj\", \".lib\", \".class\",\n \".pyc\", \".pyo\", \".jar\", \".war\", \".ear\", \".iso\", \".img\", \".dmg\",\n \".msi\", \".deb\", \".rpm\", \".apk\", \".ipa\",\n]);\n\nexport const readFileTool: Tool = {\n name: \"ReadFile\",\n description:\n \"Read a file from the filesystem. Returns the file content with line numbers. \" +\n \"For image files (.png, .jpg, .jpeg, .gif, .webp), returns the image data directly. \" +\n \"Use offset and limit to read specific portions of large text files.\",\n prompt: READ_PROMPT,\n isReadOnly: true,\n isConcurrencySafe: true,\n parameters: {\n type: \"object\",\n properties: {\n file_path: {\n type: \"string\",\n description: \"The path of the file to read (absolute or relative to cwd)\",\n },\n offset: {\n type: \"number\",\n description: \"Line number to start reading from (1-indexed). Defaults to 1.\",\n minimum: 1,\n },\n limit: {\n type: \"number\",\n description: \"Maximum number of lines to read. If omitted, reads entire file.\",\n minimum: 1,\n },\n },\n required: [\"file_path\"],\n },\n\n async call(\n args: Record<string, unknown>,\n ctx: ToolContext,\n ): Promise<ToolResult> {\n const filePath = args.file_path as string;\n const offset = (args.offset as number | undefined) ?? 1;\n const limit = args.limit as number | undefined;\n\n try {\n // Block device files that can hang or cause OOM\n const resolved = path.resolve(ctx.cwd, filePath);\n if (BLOCKED_DEVICE_PATHS.has(resolved)) {\n return {\n content: `Error: Cannot read device file ${filePath}.`,\n isError: true,\n };\n }\n\n const ext = path.extname(filePath).toLowerCase();\n\n // Block binary files (except images, handled below)\n if (BINARY_EXTENSIONS.has(ext)) {\n return {\n content: `Error: Cannot read binary ${ext} file. This tool only reads text files.`,\n isError: true,\n };\n }\n\n // Check if this is an image file\n if (IMAGE_EXTENSIONS.has(ext) && ctx.fs.readFileBytes) {\n return readImageFile(filePath, ext, ctx);\n }\n\n // File size guard\n try {\n const stat = await ctx.fs.stat(filePath);\n if (stat.size !== undefined && stat.size > MAX_FILE_SIZE) {\n return {\n content: `Error: File is too large (${Math.round(stat.size / 1024 / 1024)}MB). Use offset/limit to read specific portions.`,\n isError: true,\n };\n }\n } catch {\n // stat may fail for virtual/remote filesystems — proceed with read\n }\n\n // Dedup: if cache has same path/offset/limit and mtime is unchanged, skip re-read\n if (ctx.fileStateCache) {\n const cached = ctx.fileStateCache.get(filePath);\n if (\n cached &&\n !cached.isPartialView &&\n cached.offset !== undefined &&\n cached.offset === offset &&\n cached.limit === limit\n ) {\n try {\n const stat = await ctx.fs.stat(filePath);\n const mtime = stat.modifiedAt ? Math.floor(stat.modifiedAt.getTime()) : 0;\n if (mtime === cached.timestamp) {\n return { content: \"file_unchanged\" };\n }\n } catch {\n // stat failure — proceed with full read\n }\n }\n }\n\n const content = await ctx.fs.readFile(filePath);\n const lines = content.split(\"\\n\");\n\n const startIdx = Math.max(0, offset - 1);\n const endIdx = limit ? Math.min(lines.length, startIdx + limit) : lines.length;\n const selectedLines = lines.slice(startIdx, endIdx);\n\n const numbered = selectedLines.map(\n (line, i) => `${String(startIdx + i + 1).padStart(6)}|${line}`,\n );\n\n let result = numbered.join(\"\\n\");\n if (endIdx < lines.length) {\n result += `\\n... ${lines.length - endIdx} lines not shown ...`;\n }\n\n // Record this read in the file state cache\n if (ctx.fileStateCache) {\n let mtime = 0;\n try {\n const stat = await ctx.fs.stat(filePath);\n mtime = stat.modifiedAt ? Math.floor(stat.modifiedAt.getTime()) : 0;\n } catch {\n // If stat fails, use 0 — edits will still require a read\n }\n ctx.fileStateCache.set(filePath, {\n content: selectedLines.join(\"\\n\"),\n timestamp: mtime,\n offset,\n limit,\n });\n }\n\n return { content: result || \"File is empty.\" };\n } catch (err) {\n return {\n content: `Error reading file: ${err instanceof Error ? err.message : String(err)}`,\n isError: true,\n };\n }\n },\n};\n\nasync function readImageFile(\n filePath: string,\n ext: string,\n ctx: ToolContext,\n): Promise<ToolResult> {\n const imageBuffer = await ctx.fs.readFileBytes!(filePath);\n const originalSize = imageBuffer.length;\n const formatExt = ext.replace(/^\\./, \"\");\n\n const resized = await maybeResizeAndDownsampleImageBuffer(\n imageBuffer,\n originalSize,\n formatExt,\n );\n\n // Check token budget\n let base64 = resized.buffer.toString(\"base64\");\n let mediaType = resized.mediaType;\n const estimatedTokens = Math.ceil(base64.length * 0.125);\n\n if (estimatedTokens > DEFAULT_MAX_IMAGE_TOKENS) {\n try {\n const compressed = await compressImageBufferWithTokenLimit(\n imageBuffer,\n DEFAULT_MAX_IMAGE_TOKENS,\n `image/${formatExt}`,\n );\n base64 = compressed.base64;\n mediaType = compressed.mediaType;\n } catch {\n // Use the resized version as-is\n }\n }\n\n const parts: ContentPart[] = [\n {\n type: \"image\",\n data: base64,\n media_type: `image/${mediaType}`,\n },\n ];\n\n if (resized.dimensions) {\n parts.push({\n type: \"text\",\n text: createImageMetadataText(resized.dimensions),\n });\n }\n\n return { content: parts };\n}\n","/**\n * Model-facing prompt for the WriteFile tool.\n * Adapted from claude-code's FileWriteTool/prompt.ts.\n */\n\nexport const WRITE_PROMPT = `Writes a file to the local filesystem. Parent directories are created automatically if they don't exist.\n\nUsage:\n- This tool will overwrite the existing file if there is one at the provided path.\n- If this is an existing file, you MUST use the ReadFile tool first to read the file's contents. This tool will fail if you did not read the file first.\n- Prefer the EditFile tool for modifying existing files — it only sends the diff. Only use this tool to create new files or for complete rewrites.\n- NEVER create documentation files (*.md) or README files unless explicitly requested by the User.\n- Only use emojis if the user explicitly requests it. Avoid writing emojis to files unless asked.\n`;\n","import type { Tool, ToolResult, ToolContext } from \"./types.js\";\nimport { WRITE_PROMPT } from \"./prompts/write.js\";\n\nexport const writeFileTool: Tool = {\n name: \"WriteFile\",\n description:\n \"Create or overwrite a file with the given content. \" +\n \"Parent directories are created automatically if they don't exist.\",\n prompt: WRITE_PROMPT,\n isReadOnly: false,\n checkPermissions(args) {\n const filePath = args.file_path as string;\n return {\n behavior: \"passthrough\" as const,\n message: `Write to ${filePath}`,\n };\n },\n parameters: {\n type: \"object\",\n properties: {\n file_path: {\n type: \"string\",\n description: \"The path of the file to write (absolute or relative to cwd)\",\n },\n content: {\n type: \"string\",\n description: \"The content to write to the file\",\n },\n },\n required: [\"file_path\", \"content\"],\n },\n\n async call(\n args: Record<string, unknown>,\n ctx: ToolContext,\n ): Promise<ToolResult> {\n const filePath = args.file_path as string;\n const content = args.content as string;\n\n try {\n if (ctx.checkpointManager && ctx.currentMessageId) {\n await ctx.checkpointManager.trackEdit(filePath, ctx.currentMessageId, ctx.sessionId ?? \"\");\n }\n\n const existed = await ctx.fs.exists(filePath);\n\n if (existed && ctx.fileStateCache) {\n const cached = ctx.fileStateCache.get(filePath);\n if (!cached) {\n return {\n content: `Error: File ${filePath} exists but has not been read yet. Read it first before overwriting.`,\n isError: true,\n };\n }\n }\n\n await ctx.fs.writeFile(filePath, content);\n\n ctx.notifyHook?.(\"FileWrite\", {\n event: \"FileWrite\",\n sessionId: ctx.sessionId ?? \"\",\n toolName: \"WriteFile\",\n filePath,\n isNew: !existed,\n }).catch(() => {});\n\n // Update file state cache with the written content\n if (ctx.fileStateCache) {\n let mtime = 0;\n try {\n const stat = await ctx.fs.stat(filePath);\n mtime = stat.modifiedAt ? Math.floor(stat.modifiedAt.getTime()) : 0;\n } catch {\n // best-effort\n }\n ctx.fileStateCache.set(filePath, {\n content,\n timestamp: mtime,\n });\n }\n\n return {\n content: existed\n ? `File updated successfully at: ${filePath}`\n : `File created successfully at: ${filePath}`,\n };\n } catch (err) {\n return {\n content: `Error writing file: ${err instanceof Error ? err.message : String(err)}`,\n isError: true,\n };\n }\n },\n};\n","/**\n * Edit utilities: fuzzy matching and quote normalization.\n *\n * When the model produces an `old_string` with smart/curly quotes that\n * don't literally match the file (or vice versa), these helpers find the\n * actual on-disk string and rewrite the replacement to preserve the file's\n * quote style.\n */\n\nconst LEFT_SINGLE_CURLY = \"\\u2018\"; // '\nconst RIGHT_SINGLE_CURLY = \"\\u2019\"; // '\nconst LEFT_DOUBLE_CURLY = \"\\u201C\"; // \"\nconst RIGHT_DOUBLE_CURLY = \"\\u201D\"; // \"\n\n/**\n * Replace curly/smart quotes with their ASCII equivalents.\n */\nexport function normalizeQuotes(str: string): string {\n return str\n .replaceAll(LEFT_SINGLE_CURLY, \"'\")\n .replaceAll(RIGHT_SINGLE_CURLY, \"'\")\n .replaceAll(LEFT_DOUBLE_CURLY, '\"')\n .replaceAll(RIGHT_DOUBLE_CURLY, '\"');\n}\n\n/**\n * Find the actual substring in `fileContent` that matches `searchString`,\n * allowing for quote-normalization differences.\n *\n * Returns the literal bytes from the file that match (which may contain\n * curly quotes even though `searchString` used straight quotes), or null\n * if no match is found even after normalization.\n */\nexport function findActualString(\n fileContent: string,\n searchString: string,\n): string | null {\n // Fast path: exact match\n if (fileContent.includes(searchString)) {\n return searchString;\n }\n\n // Normalize both and try again\n const normalizedSearch = normalizeQuotes(searchString);\n const normalizedFile = normalizeQuotes(fileContent);\n\n const searchIndex = normalizedFile.indexOf(normalizedSearch);\n if (searchIndex !== -1) {\n return fileContent.substring(searchIndex, searchIndex + searchString.length);\n }\n\n return null;\n}\n\n/**\n * Count occurrences of `needle` in `haystack` using the same fuzzy matching\n * as `findActualString` — normalizes quotes before counting.\n */\nexport function countOccurrences(\n haystack: string,\n needle: string,\n): number {\n // Use the normalized form for counting\n const normalizedNeedle = normalizeQuotes(needle);\n const normalizedHaystack = normalizeQuotes(haystack);\n\n let count = 0;\n let pos = 0;\n while (true) {\n const idx = normalizedHaystack.indexOf(normalizedNeedle, pos);\n if (idx === -1) break;\n count++;\n pos = idx + 1;\n }\n return count;\n}\n\n/**\n * Detect whether a string uses curly quotes and which style.\n */\nfunction usesCurlyQuotes(str: string): {\n singleCurly: boolean;\n doubleCurly: boolean;\n} {\n return {\n singleCurly:\n str.includes(LEFT_SINGLE_CURLY) || str.includes(RIGHT_SINGLE_CURLY),\n doubleCurly:\n str.includes(LEFT_DOUBLE_CURLY) || str.includes(RIGHT_DOUBLE_CURLY),\n };\n}\n\n/**\n * When the file uses curly quotes but the model provided straight quotes\n * (or vice versa), rewrite `newString` to match the file's quote style.\n *\n * If `oldString === actualOldString`, no normalization happened and the\n * replacement is returned unchanged.\n */\nexport function preserveQuoteStyle(\n oldString: string,\n actualOldString: string,\n newString: string,\n): string {\n if (oldString === actualOldString) {\n return newString;\n }\n\n const fileStyle = usesCurlyQuotes(actualOldString);\n let result = newString;\n\n // File uses curly singles — convert straight singles to curly\n if (fileStyle.singleCurly) {\n result = convertStraightToCurlySingle(result);\n }\n\n // File uses curly doubles — convert straight doubles to curly\n if (fileStyle.doubleCurly) {\n result = convertStraightToCurlyDouble(result);\n }\n\n return result;\n}\n\n/**\n * Convert straight single quotes to curly, with simple open/close heuristics.\n * A quote after whitespace or at start-of-string opens; otherwise closes.\n */\nfunction convertStraightToCurlySingle(str: string): string {\n let result = \"\";\n let inWord = false;\n for (let i = 0; i < str.length; i++) {\n const ch = str[i];\n if (ch === \"'\") {\n const prev = i > 0 ? str[i - 1] : \" \";\n if (/\\s/.test(prev) || prev === \"(\" || prev === \"[\" || prev === \"{\") {\n result += LEFT_SINGLE_CURLY;\n inWord = true;\n } else {\n result += RIGHT_SINGLE_CURLY;\n inWord = false;\n }\n } else {\n result += ch;\n inWord = /\\w/.test(ch);\n }\n }\n return result;\n}\n\n/**\n * Convert straight double quotes to curly, alternating open/close.\n */\nfunction convertStraightToCurlyDouble(str: string): string {\n let result = \"\";\n let open = true;\n for (let i = 0; i < str.length; i++) {\n const ch = str[i];\n if (ch === '\"') {\n result += open ? LEFT_DOUBLE_CURLY : RIGHT_DOUBLE_CURLY;\n open = !open;\n } else {\n result += ch;\n }\n }\n return result;\n}\n\n/**\n * Strip trailing whitespace (spaces/tabs) from each line, preserving\n * the line-ending style (CRLF, LF, CR).\n */\nexport function stripTrailingWhitespace(str: string): string {\n // Split on line endings but keep the separators\n const parts = str.split(/(\\r\\n|\\n|\\r)/);\n const result: string[] = [];\n\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i];\n // Every other element is a separator\n if (i % 2 === 0) {\n result.push(part.replace(/[\\t ]+$/, \"\"));\n } else {\n result.push(part);\n }\n }\n\n return result.join(\"\");\n}\n","/**\n * Model-facing prompt for the EditFile tool.\n * Adapted from claude-code's FileEditTool/prompt.ts.\n */\n\nexport const EDIT_PROMPT = `Performs exact string replacements in files.\n\nUsage:\n- You must use the ReadFile tool at least once before editing a file. This tool will error if you attempt an edit without reading the file first.\n- When editing text from ReadFile output, ensure you preserve the exact indentation (tabs/spaces) as it appears AFTER the line number prefix. The line number prefix format is: spaces + line number + pipe. Everything after that is the actual file content to match. Never include any part of the line number prefix in the old_string or new_string.\n- ALWAYS prefer editing existing files in the codebase. NEVER write new files unless explicitly required.\n- Only use emojis if the user explicitly requests it. Avoid adding emojis to files unless asked.\n- The edit will FAIL if \\`old_string\\` is not unique in the file. Either provide a larger string with more surrounding context to make it unique or use \\`replace_all\\` to change every instance of \\`old_string\\`.\n- Use \\`replace_all\\` for replacing and renaming strings across the file. This parameter is useful if you want to rename a variable for instance.\n`;\n","import type { Tool, ToolResult, ToolContext } from \"./types.js\";\nimport { findActualString, preserveQuoteStyle } from \"./edit-utils.js\";\nimport { EDIT_PROMPT } from \"./prompts/edit.js\";\n\nexport const editFileTool: Tool = {\n name: \"EditFile\",\n description:\n \"Edit a file by replacing an exact string match with new content. \" +\n \"The old_string must match exactly (including whitespace and indentation). \" +\n \"Set replace_all to true to replace all occurrences.\",\n prompt: EDIT_PROMPT,\n isReadOnly: false,\n checkPermissions(args) {\n const filePath = args.file_path as string;\n return {\n behavior: \"passthrough\" as const,\n message: `Edit ${filePath}`,\n };\n },\n parameters: {\n type: \"object\",\n properties: {\n file_path: {\n type: \"string\",\n description: \"The path of the file to edit\",\n },\n old_string: {\n type: \"string\",\n description: \"The exact string to find and replace\",\n },\n new_string: {\n type: \"string\",\n description: \"The replacement string\",\n },\n replace_all: {\n type: \"boolean\",\n description:\n \"If true, replace all occurrences of old_string. Defaults to false.\",\n },\n },\n required: [\"file_path\", \"old_string\", \"new_string\"],\n },\n\n async call(\n args: Record<string, unknown>,\n ctx: ToolContext,\n ): Promise<ToolResult> {\n const filePath = args.file_path as string;\n const oldString = args.old_string as string;\n const newString = args.new_string as string;\n const replaceAll = (args.replace_all as boolean) ?? false;\n\n if (filePath.endsWith(\".ipynb\")) {\n return {\n content: `Error: ${filePath} is a Jupyter Notebook. Use the NotebookEdit tool to edit notebook files.`,\n isError: true,\n };\n }\n\n if (oldString === newString) {\n return {\n content: \"No changes to make: old_string and new_string are exactly the same.\",\n isError: true,\n };\n }\n\n try {\n // Read-before-edit enforcement\n if (ctx.fileStateCache) {\n const cached = ctx.fileStateCache.get(filePath);\n if (!cached || cached.isPartialView) {\n return {\n content: `Error: File has not been read yet. Use ReadFile on ${filePath} before editing.`,\n isError: true,\n };\n }\n\n try {\n const stat = await ctx.fs.stat(filePath);\n const mtime = stat.modifiedAt ? Math.floor(stat.modifiedAt.getTime()) : 0;\n if (mtime > cached.timestamp) {\n const currentContent = await ctx.fs.readFile(filePath);\n if (currentContent !== cached.content) {\n return {\n content: `Error: ${filePath} has been modified since last read. Re-read the file before editing.`,\n isError: true,\n };\n }\n }\n } catch {\n // stat/read failure — proceed anyway, the writeFile will catch real issues\n }\n }\n\n if (ctx.checkpointManager && ctx.currentMessageId) {\n await ctx.checkpointManager.trackEdit(filePath, ctx.currentMessageId, ctx.sessionId ?? \"\");\n }\n\n const content = await ctx.fs.readFile(filePath);\n\n // Fuzzy matching: try exact match first, then quote-normalized match\n const actualOldString = findActualString(content, oldString);\n if (!actualOldString) {\n return {\n content: `Error: old_string not found in ${filePath}. Make sure the string matches exactly, including whitespace and indentation.`,\n isError: true,\n };\n }\n\n if (!replaceAll) {\n const count = content.split(actualOldString).length - 1;\n if (count > 1) {\n return {\n content: `Error: old_string appears ${count} times in ${filePath}. Provide more context to make it unique, or set replace_all to true.`,\n isError: true,\n };\n }\n }\n\n // Preserve the file's quote style in the replacement text\n const actualNewString = preserveQuoteStyle(oldString, actualOldString, newString);\n\n let updated: string;\n if (replaceAll) {\n updated = content.split(actualOldString).join(actualNewString);\n } else if (actualNewString === \"\") {\n const hasTrailingNewline =\n !actualOldString.endsWith(\"\\n\") &&\n content.includes(actualOldString + \"\\n\");\n const deleteTarget = hasTrailingNewline\n ? actualOldString + \"\\n\"\n : actualOldString;\n updated = content.replace(deleteTarget, () => actualNewString);\n } else {\n updated = content.replace(actualOldString, () => actualNewString);\n }\n\n await ctx.fs.writeFile(filePath, updated);\n\n ctx.notifyHook?.(\"FileWrite\", {\n event: \"FileWrite\",\n sessionId: ctx.sessionId ?? \"\",\n toolName: \"EditFile\",\n filePath,\n isNew: false,\n }).catch(() => {});\n\n // Update cache with the full post-edit content\n if (ctx.fileStateCache) {\n let mtime = 0;\n try {\n const stat = await ctx.fs.stat(filePath);\n mtime = stat.modifiedAt ? Math.floor(stat.modifiedAt.getTime()) : 0;\n } catch {\n // best-effort\n }\n ctx.fileStateCache.set(filePath, {\n content: updated,\n timestamp: mtime,\n });\n }\n\n return {\n content: `File ${filePath} has been updated successfully.`,\n };\n } catch (err) {\n return {\n content: `Error editing file: ${err instanceof Error ? err.message : String(err)}`,\n isError: true,\n };\n }\n },\n};\n","/**\n * Git-specific safety checks.\n *\n * Detects bare repositories, git-internal path writes, and other\n * attack vectors (e.g. hook injection via .git/hooks/). Adapted from\n * claude-code's gitSafety.ts and git.ts.\n */\n\n/**\n * Paths inside `.git/` that are security-sensitive: writing to these\n * can inject hooks, alter config, or corrupt the repo.\n */\nconst GIT_INTERNAL_PATTERNS = [\n /\\.git\\/hooks\\//,\n /\\.git\\/config$/,\n /\\.git\\/info\\//,\n /\\.git\\/objects\\//,\n /\\.git\\/refs\\//,\n /\\.git\\/HEAD$/,\n /\\.git\\/index$/,\n /\\.git\\/packed-refs$/,\n /\\.git\\/shallow$/,\n /\\.git\\/modules\\//,\n];\n\n/**\n * Returns true if `path` targets a file inside `.git/` internals.\n * Used to detect attempts to write hooks, alter config, etc.\n */\nexport function isGitInternalPath(path: string): boolean {\n const normalized = path.replace(/\\\\/g, \"/\");\n return GIT_INTERNAL_PATTERNS.some((p) => p.test(normalized));\n}\n\n/**\n * Top-level entries expected in a bare git repository.\n * A bare repo has HEAD, objects/, refs/ at the top level with no\n * `.git` subdirectory — git operations in a bare repo can still\n * trigger hooks (e.g. post-checkout, fsmonitor) and are a known\n * sandbox-escape vector.\n */\nconst BARE_REPO_MARKERS = [\"HEAD\", \"objects\", \"refs\"];\n\n/**\n * Heuristic: does `dirEntries` (a list of filenames/dirnames in a\n * directory) look like a bare git repository?\n *\n * Returns true when all three markers (HEAD, objects/, refs/) are\n * present *and* there is no `.git` entry (which would indicate a\n * normal working tree).\n */\nexport function looksLikeBareRepo(dirEntries: string[]): boolean {\n const entrySet = new Set(dirEntries.map((e) => e.replace(/\\/$/, \"\")));\n if (entrySet.has(\".git\")) return false;\n return BARE_REPO_MARKERS.every((m) => entrySet.has(m));\n}\n\n/**\n * Check if a shell command targets git-internal paths for writes.\n * Scans for redirect operators (`>`, `>>`, `tee`) whose target is\n * inside `.git/`.\n */\nexport function commandWritesGitInternals(command: string): boolean {\n // Redirect targets: > .git/hooks/pre-commit, >> .git/config, tee .git/hooks/x\n const redirectPattern = /(?:>{1,2}|tee\\s+)\\s*(\\S+)/g;\n let match: RegExpExecArray | null;\n while ((match = redirectPattern.exec(command)) !== null) {\n if (isGitInternalPath(match[1])) return true;\n }\n\n // cp/mv/ln targeting .git/ paths\n const copyPattern = /\\b(?:cp|mv|ln)\\b.*\\s(\\S*\\.git\\/\\S+)/;\n const copyMatch = command.match(copyPattern);\n if (copyMatch && isGitInternalPath(copyMatch[1])) return true;\n\n return false;\n}\n","/**\n * Shell command safety classification.\n *\n * Classifies bash commands as read-only or potentially destructive so the\n * permission pipeline can make informed decisions without explicit per-command\n * rules.\n */\n\nimport type { CommandClassification, ShellSafetyConfig } from \"./types.js\";\nimport { commandWritesGitInternals } from \"./git-safety.js\";\n\n// -- Read-only commands: always safe, never modify state --\n\nconst READ_ONLY_COMMANDS = new Set([\n \"cat\",\n \"head\",\n \"tail\",\n \"less\",\n \"more\",\n \"wc\",\n \"file\",\n \"which\",\n \"whence\",\n \"where\",\n \"whereis\",\n \"type\",\n \"pwd\",\n \"date\",\n \"uname\",\n \"hostname\",\n \"whoami\",\n \"id\",\n \"groups\",\n \"ls\",\n \"ll\",\n \"la\",\n \"dir\",\n \"tree\",\n \"stat\",\n \"du\",\n \"df\",\n \"free\",\n \"uptime\",\n \"ps\",\n \"top\",\n \"htop\",\n \"lsof\",\n \"ss\",\n \"netstat\",\n \"ifconfig\",\n \"ip\",\n \"ping\",\n \"dig\",\n \"nslookup\",\n \"host\",\n \"traceroute\",\n \"grep\",\n \"egrep\",\n \"fgrep\",\n \"rg\",\n \"ag\",\n \"ack\",\n \"find\",\n \"fd\",\n \"fdfind\",\n \"locate\",\n \"readlink\",\n \"realpath\",\n \"basename\",\n \"dirname\",\n \"diff\",\n \"comm\",\n \"sort\",\n \"uniq\",\n \"cut\",\n \"tr\",\n \"awk\",\n \"sed\", // sed -i is destructive but caught by destructive patterns\n \"jq\",\n \"yq\",\n \"xxd\",\n \"hexdump\",\n \"od\",\n \"md5sum\",\n \"sha256sum\",\n \"shasum\",\n \"base64\",\n \"true\",\n \"false\",\n \"test\",\n \"[\",\n \"[[\",\n \"man\",\n \"help\",\n \"info\",\n \"nproc\",\n \"arch\",\n \"lscpu\",\n \"lsb_release\",\n \"sw_vers\",\n \"sysctl\",\n \"getconf\",\n \"dotnet\", // dotnet --info, dotnet --list-sdks\n]);\n\n// -- Git read-only subcommands --\n\nconst GIT_READ_ONLY_SUBCOMMANDS = new Set([\n \"status\",\n \"log\",\n \"diff\",\n \"show\",\n \"blame\",\n \"shortlog\",\n \"describe\",\n \"rev-parse\",\n \"rev-list\",\n \"cat-file\",\n \"ls-files\",\n \"ls-tree\",\n \"ls-remote\",\n \"name-rev\",\n \"for-each-ref\",\n \"count-objects\",\n \"fsck\",\n \"verify-pack\",\n \"reflog\",\n \"stash\", // \"stash list\" / \"stash show\" — stash apply/pop are not here\n \"tag\", // \"tag -l\" is safe; \"tag <name>\" creates — caught below\n \"branch\", // \"branch --list\" is safe; \"branch <name>\" creates — caught below\n \"remote\", // \"remote -v\" safe; \"remote add/remove\" — caught below\n \"config\", // \"config --list/--get\" safe\n \"help\",\n \"version\",\n \"--version\",\n \"--help\",\n]);\n\n// Subcommands of git that are always mutating when used\nconst GIT_MUTATING_SUBCOMMANDS = new Set([\n \"push\",\n \"pull\",\n \"fetch\",\n \"merge\",\n \"rebase\",\n \"cherry-pick\",\n \"revert\",\n \"commit\",\n \"add\",\n \"rm\",\n \"mv\",\n \"init\",\n \"clone\",\n \"checkout\",\n \"switch\",\n \"restore\",\n \"reset\",\n \"clean\",\n \"bisect\",\n \"am\",\n \"apply\",\n \"format-patch\",\n \"submodule\",\n \"worktree\",\n]);\n\n// -- Destructive patterns: commands that can cause irreversible damage --\n\nconst DESTRUCTIVE_PATTERNS: RegExp[] = [\n // rm -rf / rm -r / rm --recursive (but not plain rm single-file)\n /\\brm\\s+(-[a-zA-Z]*[rR][a-zA-Z]*|--recursive)\\b/,\n // rm on root-like paths\n /\\brm\\s+.*\\s+\\/($|\\s)/,\n // git force operations\n /\\bgit\\s+push\\s+.*--force\\b/,\n /\\bgit\\s+push\\s+-f\\b/,\n /\\bgit\\s+reset\\s+--hard\\b/,\n /\\bgit\\s+clean\\s+.*-[a-zA-Z]*f/,\n /\\bgit\\s+checkout\\s+--\\s+\\./,\n // Filesystem destruction\n /\\bchmod\\s+(-[a-zA-Z]*R[a-zA-Z]*|--recursive)\\s+777\\b/,\n /\\bchown\\s+(-[a-zA-Z]*R[a-zA-Z]*|--recursive)\\b/,\n /\\bdd\\s+/,\n /\\bmkfs\\b/,\n /\\bformat\\b/,\n /\\bfdisk\\b/,\n // Dangerous redirects\n />\\s*\\/dev\\/sd[a-z]/,\n // Database destructive operations\n /\\bDROP\\s+(TABLE|DATABASE|SCHEMA)\\b/i,\n /\\bTRUNCATE\\s+TABLE\\b/i,\n /\\bDELETE\\s+FROM\\b/i,\n // sed in-place\n /\\bsed\\s+(-[a-zA-Z]*i[a-zA-Z]*|--in-place)\\b/,\n // Container/system destruction\n /\\bdocker\\s+(rm|rmi|system\\s+prune|volume\\s+rm)\\b/,\n /\\bkubectl\\s+delete\\b/,\n // Kill processes\n /\\bkill\\s+-9\\b/,\n /\\bkillall\\b/,\n /\\bpkill\\b/,\n // Recursive operations on root\n /\\bfind\\s+\\/\\s+.*-delete\\b/,\n /\\bfind\\s+\\/\\s+.*-exec\\s+rm\\b/,\n];\n\nconst SAFE_ECHO_RE = /^(?:echo|printf)(?:\\s+(?:'[^']*'|[^|;&`$(){}><#\\\\!\"'\\s]+))*(?:\\s+2>&1)?\\s*$/;\n\nfunction hasTokenFlag(tokens: string[], ...flags: string[]): boolean {\n return tokens.some((t) => flags.includes(t));\n}\n\n/**\n * Split a compound command into individual sub-commands.\n * Handles: `;`, `&&`, `||`, `|`\n *\n * LIMITATION: Does not respect quoted strings — `echo \"hello && world\"` will\n * be split incorrectly. This is a conservative approximation: the resulting\n * fragments will fail to match the read-only allowlist, so the bias is toward\n * requiring permission (safe default). A proper fix would use a shell parser.\n */\nfunction splitCompoundCommand(command: string): string[] {\n return command\n .split(/\\s*(?:;|&&|\\|\\||(?<!\\|)\\|(?!\\|))\\s*/)\n .map((s) => s.trim())\n .filter(Boolean);\n}\n\n/**\n * Extract the base command name from a command string (first token after\n * env vars and redirects).\n */\nfunction stripPrefixes(command: string): string {\n let cmd = command.trim();\n while (/^[A-Za-z_][A-Za-z0-9_]*=\\S*\\s/.test(cmd)) {\n cmd = cmd.replace(/^[A-Za-z_][A-Za-z0-9_]*=\\S*\\s+/, \"\");\n }\n for (const prefix of [\"sudo\", \"env\", \"nohup\", \"time\", \"nice\", \"ionice\", \"strace\", \"ltrace\"]) {\n if (cmd.startsWith(prefix + \" \")) {\n cmd = cmd.slice(prefix.length).trim();\n while (cmd.startsWith(\"-\")) {\n const spaceIdx = cmd.indexOf(\" \");\n if (spaceIdx === -1) break;\n cmd = cmd.slice(spaceIdx).trim();\n }\n while (/^[A-Za-z_][A-Za-z0-9_]*=\\S*\\s/.test(cmd)) {\n cmd = cmd.replace(/^[A-Za-z_][A-Za-z0-9_]*=\\S*\\s+/, \"\");\n }\n }\n }\n return cmd;\n}\n\nexport function extractCommandName(command: string): string {\n const cmd = stripPrefixes(command);\n const firstToken = cmd.split(/\\s/)[0] ?? \"\";\n const base = firstToken.includes(\"/\") ? firstToken.split(\"/\").pop()! : firstToken;\n return base;\n}\n\nfunction classifyGitCommand(command: string): CommandClassification {\n // Handle git --version / git --help directly\n if (/\\bgit\\s+--version\\b/.test(command)) {\n return { isReadOnly: true, isDestructive: false, reason: \"git --version is read-only\" };\n }\n if (/\\bgit\\s+--help\\b/.test(command)) {\n return { isReadOnly: true, isDestructive: false, reason: \"git --help is read-only\" };\n }\n\n // Guard: git -c, --exec-path=, --config-env= enable arbitrary code execution\n // (e.g. git -c core.fsmonitor=malicious.sh status) regardless of subcommand\n if (/\\bgit\\s+(-c\\s|--exec-path=|--config-env=)/.test(command)) {\n return { isReadOnly: false, isDestructive: true, reason: \"git config injection vector (-c/--exec-path/--config-env)\" };\n }\n\n // Extract the git subcommand\n const match = command.match(/\\bgit\\s+(?:--[a-z-]+=?\\S*\\s+)*([a-z][a-z-]*)/);\n if (!match) {\n return { isReadOnly: false, isDestructive: false, reason: \"Cannot parse git subcommand\" };\n }\n const subcommand = match[1];\n\n if (GIT_READ_ONLY_SUBCOMMANDS.has(subcommand)) {\n const afterSubcmd = command.slice(command.indexOf(subcommand) + subcommand.length).trim();\n const tokens = afterSubcmd.split(/\\s+/).filter(Boolean);\n const positional = tokens.filter((t) => !t.startsWith(\"-\"));\n const flags = tokens.filter((t) => t.startsWith(\"-\"));\n\n if (subcommand === \"branch\") {\n if (hasTokenFlag(flags, \"--list\", \"-l\")) {\n return { isReadOnly: true, isDestructive: false, reason: \"git branch --list is read-only\" };\n }\n if (hasTokenFlag(flags, \"-d\", \"-D\", \"--delete\")) {\n return { isReadOnly: false, isDestructive: true, reason: \"git branch delete\" };\n }\n if (positional.length > 0) {\n return { isReadOnly: false, isDestructive: false, reason: \"git branch create\" };\n }\n }\n\n if (subcommand === \"tag\") {\n if (hasTokenFlag(flags, \"-l\", \"--list\")) {\n return { isReadOnly: true, isDestructive: false, reason: \"git tag --list is read-only\" };\n }\n if (hasTokenFlag(flags, \"-d\", \"-D\", \"--delete\")) {\n return { isReadOnly: false, isDestructive: true, reason: \"git tag delete\" };\n }\n if (positional.length > 0) {\n return { isReadOnly: false, isDestructive: false, reason: \"git tag create\" };\n }\n }\n\n if (subcommand === \"stash\") {\n const stashSubcmd = positional[0];\n if (stashSubcmd === \"list\" || stashSubcmd === \"show\") {\n return { isReadOnly: true, isDestructive: false, reason: `git stash ${stashSubcmd} is read-only` };\n }\n if (stashSubcmd === \"drop\" || stashSubcmd === \"clear\") {\n return { isReadOnly: false, isDestructive: true, reason: \"git stash destructive operation\" };\n }\n return { isReadOnly: false, isDestructive: false, reason: \"git stash mutating operation\" };\n }\n\n if (subcommand === \"config\") {\n if (hasTokenFlag(flags, \"--set\", \"--add\", \"--unset\", \"--unset-all\", \"--replace-all\", \"--rename-section\", \"--remove-section\")) {\n return { isReadOnly: false, isDestructive: false, reason: \"git config write operation\" };\n }\n if (positional.length >= 2) {\n return { isReadOnly: false, isDestructive: false, reason: \"git config set key value\" };\n }\n }\n\n if (subcommand === \"remote\") {\n const remoteSubcmd = positional[0];\n if (remoteSubcmd && [\"add\", \"remove\", \"rename\", \"set-url\", \"set-branches\", \"prune\"].includes(remoteSubcmd)) {\n return { isReadOnly: false, isDestructive: false, reason: \"git remote mutating operation\" };\n }\n }\n\n return { isReadOnly: true, isDestructive: false, reason: `git ${subcommand} is read-only` };\n }\n\n if (GIT_MUTATING_SUBCOMMANDS.has(subcommand)) {\n for (const pattern of DESTRUCTIVE_PATTERNS) {\n if (pattern.test(command)) {\n return { isReadOnly: false, isDestructive: true, reason: `Destructive: ${pattern.source}` };\n }\n }\n return { isReadOnly: false, isDestructive: false, reason: `git ${subcommand} is mutating` };\n }\n\n return { isReadOnly: false, isDestructive: false, reason: `Unknown git subcommand: ${subcommand}` };\n}\n\n/**\n * Classify a single (non-compound) command.\n */\nfunction classifySingleCommand(\n command: string,\n config?: ShellSafetyConfig,\n): CommandClassification {\n const name = extractCommandName(command);\n\n if (!name) {\n return { isReadOnly: false, isDestructive: false, reason: \"Empty command\" };\n }\n\n // Check destructive patterns first\n const allDestructive = [\n ...DESTRUCTIVE_PATTERNS,\n ...(config?.extraDestructivePatterns ?? []),\n ];\n for (const pattern of allDestructive) {\n if (pattern.test(command)) {\n return {\n isReadOnly: false,\n isDestructive: true,\n reason: `Matches destructive pattern: ${pattern.source}`,\n };\n }\n }\n\n // Git has its own classification\n if (name === \"git\") {\n return classifyGitCommand(command);\n }\n\n // xargs with git: treat as a git command (e.g. xargs git add)\n if (name === \"xargs\" && /\\bgit\\b/.test(command)) {\n return classifyGitCommand(command);\n }\n\n if ((name === \"echo\" || name === \"printf\") && SAFE_ECHO_RE.test(stripPrefixes(command).trim())) {\n return { isReadOnly: true, isDestructive: false, reason: `${name} with safe arguments is read-only` };\n }\n\n // Check against read-only allowlist\n const extraReadOnly = new Set(config?.extraReadOnlyCommands ?? []);\n if (READ_ONLY_COMMANDS.has(name) || extraReadOnly.has(name)) {\n return { isReadOnly: true, isDestructive: false, reason: `${name} is read-only` };\n }\n\n // Default: not read-only, not destructive\n return {\n isReadOnly: false,\n isDestructive: false,\n reason: `${name} is not in the read-only allowlist`,\n };\n}\n\n/**\n * Classify a shell command (potentially compound with pipes/chains).\n *\n * - A compound command is read-only only if ALL sub-commands are read-only.\n * - A compound command is destructive if ANY sub-command is destructive.\n */\nexport function classifyCommand(\n command: string,\n config?: ShellSafetyConfig,\n): CommandClassification {\n if (!command.trim()) {\n return { isReadOnly: true, isDestructive: false, reason: \"Empty command\" };\n }\n\n const subCommands = splitCompoundCommand(command);\n if (subCommands.length === 0) {\n return { isReadOnly: true, isDestructive: false, reason: \"Empty command\" };\n }\n\n if (subCommands.length > 1) {\n const hasCd = subCommands.some((s) => /^(cd|pushd)\\s/.test(s.trim()));\n const hasGit = subCommands.some((s) => {\n const n = extractCommandName(s);\n return n === \"git\" || (n === \"xargs\" && /\\bgit\\b/.test(s));\n });\n if (hasCd && hasGit) {\n return {\n isReadOnly: false,\n isDestructive: false,\n reason: \"cd + git compound may escape working directory (bare-repo risk)\",\n };\n }\n\n if (hasGit && commandWritesGitInternals(command)) {\n return {\n isReadOnly: false,\n isDestructive: true,\n reason: \"Compound command writes to git internal paths before running git\",\n };\n }\n }\n\n let allReadOnly = true;\n let anyDestructive = false;\n const reasons: string[] = [];\n\n for (const sub of subCommands) {\n const result = classifySingleCommand(sub, config);\n if (!result.isReadOnly) allReadOnly = false;\n if (result.isDestructive) anyDestructive = true;\n if (result.reason) reasons.push(result.reason);\n }\n\n return {\n isReadOnly: allReadOnly,\n isDestructive: anyDestructive,\n reason: reasons.join(\"; \"),\n };\n}\n","/**\n * Git operation tracking.\n *\n * Parses shell command + output to detect high-level git operations\n * (commits, pushes, PR creation, merges, rebases). Adapted from\n * claude-code's gitOperationTracking.ts.\n */\n\nexport type GitOperationType =\n | \"commit\"\n | \"push\"\n | \"pr_create\"\n | \"merge\"\n | \"rebase\";\n\nexport interface GitOperationEvent {\n type: GitOperationType;\n details: string;\n}\n\n/**\n * Detect git operations from a command string and its stdout output.\n * Returns an array of events (most commands produce 0 or 1).\n * Only detects on success — caller should check exit code first.\n */\nexport function detectGitOperations(\n command: string,\n stdout: string,\n): GitOperationEvent[] {\n const events: GitOperationEvent[] = [];\n const cmd = command.trim();\n\n // git commit\n if (/\\bgit\\s+commit\\b/.test(cmd)) {\n const shaMatch = stdout.match(/\\[[\\w/.-]+\\s+([0-9a-f]{7,40})\\]/);\n const sha = shaMatch ? shaMatch[1] : \"unknown\";\n events.push({ type: \"commit\", details: `commit ${sha}` });\n }\n\n // git merge\n if (/\\bgit\\s+merge\\b/.test(cmd)) {\n const branchMatch = cmd.match(/\\bgit\\s+merge\\s+(?:--\\S+\\s+)*(\\S+)/);\n const branch = branchMatch ? branchMatch[1] : \"unknown\";\n events.push({ type: \"merge\", details: `merge ${branch}` });\n }\n\n // git rebase\n if (/\\bgit\\s+rebase\\b/.test(cmd)) {\n const branchMatch = cmd.match(/\\bgit\\s+rebase\\s+(?:--\\S+\\s+)*(\\S+)/);\n const branch = branchMatch ? branchMatch[1] : \"unknown\";\n events.push({ type: \"rebase\", details: `rebase onto ${branch}` });\n }\n\n // git push\n if (/\\bgit\\s+push\\b/.test(cmd)) {\n const remoteMatch = cmd.match(/\\bgit\\s+push\\s+(?:--\\S+\\s+)*(\\S+)/);\n const remote = remoteMatch ? remoteMatch[1] : \"origin\";\n const branchMatch = stdout.match(/\\S+\\s+->\\s+(\\S+)/);\n const branch = branchMatch ? branchMatch[1] : \"\";\n events.push({\n type: \"push\",\n details: `push to ${remote}${branch ? ` (${branch})` : \"\"}`,\n });\n }\n\n // gh pr create / glab mr create\n if (/\\b(gh\\s+pr\\s+create|glab\\s+mr\\s+create)\\b/.test(cmd)) {\n const urlMatch = stdout.match(/(https?:\\/\\/\\S+(?:pull|merge_requests)\\/\\d+)/);\n const url = urlMatch ? urlMatch[1] : \"\";\n events.push({\n type: \"pr_create\",\n details: url ? `PR created: ${url}` : \"PR created\",\n });\n }\n\n return events;\n}\n\n/**\n * Check if command output indicates a git index.lock error.\n * This commonly occurs when another git process is running.\n */\nexport function hasGitIndexLockError(output: string): boolean {\n return /\\.git\\/index\\.lock/.test(output);\n}\n","/**\n * Model-facing prompt for the Bash tool.\n * Adapted from claude-code's BashTool/prompt.ts — stripped of product-specific\n * feature flags and made generic for noumen.\n */\n\nexport const BASH_PROMPT = `Executes a given bash command and returns its output.\n\nThe working directory persists between commands, but shell state does not.\n\nIMPORTANT: Avoid using this tool to run \\`find\\`, \\`grep\\`, \\`cat\\`, \\`head\\`, \\`tail\\`, \\`sed\\`, \\`awk\\`, or \\`echo\\` commands, unless explicitly instructed or after you have verified that a dedicated tool cannot accomplish your task. Instead, use the appropriate dedicated tool:\n\n- File search: Use Glob (NOT find or ls)\n- Content search: Use Grep (NOT grep or rg)\n- Read files: Use ReadFile (NOT cat/head/tail)\n- Edit files: Use EditFile (NOT sed/awk)\n- Write files: Use WriteFile (NOT echo >/cat <<EOF)\n- Communication: Output text directly (NOT echo/printf)\n\nWhile the Bash tool can do similar things, the built-in tools are preferred as they provide better structured output and integrate with the permission system.\n\n# Instructions\n\n- If your command will create new directories or files, first use this tool to run \\`ls\\` to verify the parent directory exists and is the correct location.\n- Always quote file paths that contain spaces with double quotes (e.g., cd \"path with spaces/file.txt\").\n- Try to maintain your current working directory throughout the session by using absolute paths and avoiding usage of \\`cd\\`. You may use \\`cd\\` if the User explicitly requests it.\n- You may specify an optional timeout in milliseconds (up to 600000ms / 10 minutes). By default, your command will timeout after 30000ms (0.5 minutes).\n- When issuing multiple commands:\n - If the commands are independent and can run in parallel, make multiple Bash tool calls in a single message.\n - If the commands depend on each other and must run sequentially, use a single Bash call with '&&' to chain them together.\n - Use ';' only when you need to run commands sequentially but don't care if earlier commands fail.\n - DO NOT use newlines to separate commands (newlines are ok in quoted strings).\n- For git commands:\n - Prefer to create a new commit rather than amending an existing commit.\n - Before running destructive operations (e.g., git reset --hard, git push --force, git checkout --), consider whether there is a safer alternative. Only use destructive operations when they are truly the best approach.\n - Never skip hooks (--no-verify) or bypass signing (--no-gpg-sign) unless the user has explicitly asked for it. If a hook fails, investigate and fix the underlying issue.\n- Avoid unnecessary \\`sleep\\` commands:\n - Do not sleep between commands that can run immediately — just run them.\n - Do not retry failing commands in a sleep loop — diagnose the root cause.\n - If you must sleep, keep the duration short (1-5 seconds) to avoid blocking the user.\n`;\n","import type { Tool, ToolResult, ToolContext } from \"./types.js\";\nimport { classifyCommand } from \"./shell-safety/command-classification.js\";\nimport { detectGitOperations, type GitOperationEvent } from \"./shell-safety/git-tracking.js\";\nimport { commandWritesGitInternals } from \"./shell-safety/git-safety.js\";\nimport { BASH_PROMPT } from \"./prompts/bash.js\";\n\nconst MAX_OUTPUT_CHARS = 100_000;\n\nexport const bashTool: Tool = {\n name: \"Bash\",\n description:\n \"Execute a bash shell command. Use this for running scripts, \" +\n \"installing packages, git operations, and other system commands.\",\n prompt: BASH_PROMPT,\n isReadOnly(args) {\n const command = args.command as string;\n return classifyCommand(command).isReadOnly;\n },\n isDestructive(args) {\n const command = args.command as string;\n return classifyCommand(command).isDestructive;\n },\n checkPermissions(args) {\n const command = args.command as string;\n const classification = classifyCommand(command);\n if (classification.isDestructive) {\n return {\n behavior: \"ask\" as const,\n message: `Destructive command: ${command}${classification.reason ? ` (${classification.reason})` : \"\"}`,\n };\n }\n if (commandWritesGitInternals(command)) {\n return {\n behavior: \"ask\" as const,\n message: `Command writes to .git/ internals: ${command}`,\n };\n }\n return {\n behavior: \"passthrough\" as const,\n message: `Execute: ${command}`,\n };\n },\n parameters: {\n type: \"object\",\n properties: {\n command: {\n type: \"string\",\n description: \"The bash command to execute\",\n },\n timeout: {\n type: \"number\",\n description: \"Timeout in milliseconds (default: 30000)\",\n },\n description: {\n type: \"string\",\n description: \"Short description of what this command does (5-10 words)\",\n },\n },\n required: [\"command\"],\n },\n\n async call(\n args: Record<string, unknown>,\n ctx: ToolContext,\n ): Promise<ToolResult> {\n const command = args.command as string;\n const timeout = args.timeout as number | undefined;\n\n try {\n const result = await ctx.computer.executeCommand(command, {\n timeout,\n cwd: ctx.cwd,\n });\n\n let output = \"\";\n if (result.stdout) {\n output += result.stdout;\n }\n if (result.stderr) {\n if (output) output += \"\\n\";\n output += `STDERR:\\n${result.stderr}`;\n }\n\n if (!output.trim()) {\n output = \"(no output)\";\n }\n\n if (output.length > MAX_OUTPUT_CHARS) {\n const totalChars = output.length;\n output =\n output.slice(0, MAX_OUTPUT_CHARS) +\n `\\n... output truncated (${totalChars} total chars)`;\n }\n\n if (result.exitCode !== 0) {\n output = `Exit code: ${result.exitCode}\\n${output}`;\n }\n\n const toolResult: ToolResult = {\n content: output,\n isError: result.exitCode !== 0,\n };\n\n // Track git operations on success\n if (result.exitCode === 0) {\n const gitOps = detectGitOperations(command, result.stdout ?? \"\");\n if (gitOps.length > 0) {\n toolResult.metadata = { gitOperations: gitOps };\n }\n }\n\n return toolResult;\n } catch (err) {\n return {\n content: `Error executing command: ${err instanceof Error ? err.message : String(err)}`,\n isError: true,\n };\n }\n },\n};\n","/**\n * Model-facing prompt for the Glob tool.\n * Adapted from claude-code's GlobTool/prompt.ts.\n */\n\nexport const GLOB_PROMPT = `Fast file pattern matching tool that works with any codebase size.\n\n- Supports glob patterns like \"**/*.js\" or \"src/**/*.ts\"\n- Returns matching file paths sorted by modification time\n- Use this tool when you need to find files by name patterns\n- When you are doing an open-ended search that may require multiple rounds of globbing and grepping, use the Agent tool instead\n`;\n","/**\n * Escape a string for safe interpolation into a single-quoted shell argument.\n * Handles embedded single quotes by ending the quote, inserting an escaped\n * quote, and re-opening. Wraps the result in single quotes.\n */\nexport function shellEscape(s: string): string {\n return \"'\" + s.replace(/'/g, \"'\\\\''\") + \"'\";\n}\n","import type { Tool, ToolResult, ToolContext } from \"./types.js\";\nimport { GLOB_PROMPT } from \"./prompts/glob.js\";\nimport { shellEscape } from \"../utils/shell-escape.js\";\n\nconst MAX_RESULTS = 200;\n\nexport const globTool: Tool = {\n name: \"Glob\",\n description:\n \"Find files matching a glob pattern. Uses ripgrep (rg --files --glob) \" +\n \"for fast, gitignore-aware file discovery. Returns matching file paths \" +\n \"sorted by modification time.\",\n prompt: GLOB_PROMPT,\n isReadOnly: true,\n isConcurrencySafe: true,\n parameters: {\n type: \"object\",\n properties: {\n pattern: {\n type: \"string\",\n description:\n 'Glob pattern to match files (e.g. \"*.ts\", \"src/**/*.tsx\")',\n },\n path: {\n type: \"string\",\n description: \"Directory to search in (defaults to cwd)\",\n },\n },\n required: [\"pattern\"],\n },\n\n async call(\n args: Record<string, unknown>,\n ctx: ToolContext,\n ): Promise<ToolResult> {\n const pattern = args.pattern as string;\n const searchPath = (args.path as string | undefined) ?? ctx.cwd;\n\n const fullPattern = pattern.startsWith(\"**/\")\n ? pattern\n : `**/${pattern}`;\n\n const command = `rg --files --glob ${shellEscape(fullPattern)} --sort=modified | head -n ${String(MAX_RESULTS + 1)}`;\n\n try {\n const result = await ctx.computer.executeCommand(command, {\n cwd: searchPath,\n });\n\n // rg exits with 1 when no matches; exit > 1 is a real error\n if (result.exitCode > 1) {\n return {\n content: `Glob error: ${result.stderr || result.stdout}`,\n isError: true,\n };\n }\n\n const lines = result.stdout\n .split(\"\\n\")\n .filter((l) => l.trim() !== \"\");\n\n if (lines.length === 0) {\n return { content: \"No files found matching the pattern.\" };\n }\n\n const truncated = lines.length > MAX_RESULTS;\n const files = truncated ? lines.slice(0, MAX_RESULTS) : lines;\n\n let output = files.join(\"\\n\");\n if (truncated) {\n output += `\\n\\n(Results truncated. More than ${MAX_RESULTS} files match.)`;\n }\n\n return { content: output };\n } catch (err) {\n return {\n content: `Error searching files: ${err instanceof Error ? err.message : String(err)}`,\n isError: true,\n };\n }\n },\n};\n","/**\n * Model-facing prompt for the Grep tool.\n * Adapted from claude-code's GrepTool/prompt.ts.\n */\n\nexport const GREP_PROMPT = `A powerful search tool built on ripgrep.\n\nUsage:\n- ALWAYS use Grep for search tasks. NEVER invoke \\`grep\\` or \\`rg\\` as a Bash command. The Grep tool has been optimized for correct permissions and access.\n- Supports full regex syntax (e.g., \"log.*Error\", \"function\\\\s+\\\\w+\")\n- Filter files with the glob parameter (e.g., \"*.js\", \"**/*.tsx\")\n- Returns matching lines with file paths and line numbers\n- Use the Agent tool for open-ended searches requiring multiple rounds\n- Pattern syntax: Uses ripgrep (not grep) — literal braces need escaping (use \\`interface\\\\{\\\\}\\` to find \\`interface{}\\` in Go code)\n- Multiline matching: By default patterns match within single lines only. For cross-line patterns like \\`struct \\\\{[\\\\s\\\\S]*?field\\`, pass a context_lines parameter.\n`;\n","import type { Tool, ToolResult, ToolContext } from \"./types.js\";\nimport { GREP_PROMPT } from \"./prompts/grep.js\";\nimport { shellEscape } from \"../utils/shell-escape.js\";\n\nconst MAX_MATCHES = 250;\n\nexport const grepTool: Tool = {\n name: \"Grep\",\n description:\n \"Search file contents using ripgrep (rg). Supports regex patterns. \" +\n \"Returns matching lines with file paths and line numbers.\",\n prompt: GREP_PROMPT,\n isReadOnly: true,\n isConcurrencySafe: true,\n parameters: {\n type: \"object\",\n properties: {\n pattern: {\n type: \"string\",\n description: \"Regular expression pattern to search for\",\n },\n path: {\n type: \"string\",\n description: \"File or directory to search in (defaults to cwd)\",\n },\n glob: {\n type: \"string\",\n description:\n 'Glob pattern to filter files (e.g. \"*.ts\", \"*.{js,jsx}\")',\n },\n case_insensitive: {\n type: \"boolean\",\n description: \"Case insensitive search (default: false)\",\n },\n context_lines: {\n type: \"number\",\n description: \"Number of context lines to show before and after each match\",\n },\n },\n required: [\"pattern\"],\n },\n\n async call(\n args: Record<string, unknown>,\n ctx: ToolContext,\n ): Promise<ToolResult> {\n const pattern = args.pattern as string;\n const searchPath = (args.path as string | undefined) ?? ctx.cwd;\n const glob = args.glob as string | undefined;\n const caseInsensitive = args.case_insensitive as boolean | undefined;\n const contextLines = args.context_lines as number | undefined;\n\n const rgArgs: string[] = [\n \"rg\",\n \"--line-number\",\n \"--no-heading\",\n \"--color=never\",\n `--max-count=${MAX_MATCHES}`,\n ];\n\n if (caseInsensitive) rgArgs.push(\"-i\");\n if (contextLines !== undefined) rgArgs.push(`-C${contextLines}`);\n if (glob) rgArgs.push(`--glob`, shellEscape(glob));\n\n rgArgs.push(\"--\", shellEscape(pattern), \".\");\n\n const command = rgArgs.join(\" \");\n\n try {\n const result = await ctx.computer.executeCommand(command, {\n cwd: searchPath,\n });\n\n if (result.exitCode === 1 && !result.stdout.trim()) {\n return { content: \"No matches found.\" };\n }\n\n if (result.exitCode > 1) {\n return {\n content: `Grep error: ${result.stderr || result.stdout}`,\n isError: true,\n };\n }\n\n const lines = result.stdout.split(\"\\n\");\n let output = result.stdout;\n\n if (lines.length > MAX_MATCHES) {\n output =\n lines.slice(0, MAX_MATCHES).join(\"\\n\") +\n `\\n\\n(Results truncated at ${MAX_MATCHES} matches.)`;\n }\n\n return { content: output || \"No matches found.\" };\n } catch (err) {\n return {\n content: `Error searching: ${err instanceof Error ? err.message : String(err)}`,\n isError: true,\n };\n }\n },\n};\n","/**\n * Model-facing prompt for the WebFetch tool.\n * Adapted from claude-code's WebFetchTool/prompt.ts.\n */\n\nexport const WEB_FETCH_PROMPT = `Fetches content from a specified URL and returns it in a readable format.\n\n- Takes a URL and fetches the page content, converting HTML to markdown\n- Returns the processed content for analysis\n- Use this tool when you need to retrieve and analyze web content\n\nUsage notes:\n- The URL must be a fully-formed valid URL\n- HTTP URLs will be automatically upgraded to HTTPS\n- This tool is read-only and does not modify any files\n- Results may be summarized if the content is very large\n- When a URL redirects to a different host, the tool will inform you and provide the redirect URL. You should then make a new WebFetch request with the redirect URL.\n- For GitHub URLs, prefer using the gh CLI via Bash instead (e.g., gh pr view, gh issue view, gh api).\n`;\n","import type { Tool, ToolResult, ToolContext } from \"./types.js\";\nimport { WEB_FETCH_PROMPT } from \"./prompts/web-fetch.js\";\n\nconst MAX_CONTENT_LENGTH = 5 * 1024 * 1024;\nconst FETCH_TIMEOUT_MS = 30_000;\nconst MAX_OUTPUT_CHARS = 100_000;\n\nexport const webFetchTool: Tool = {\n name: \"WebFetch\",\n description:\n \"Fetch a URL and return its contents as markdown. Useful for reading \" +\n \"web pages, documentation, API responses, and other online content. \" +\n \"Provide an optional prompt to extract specific information.\",\n prompt: WEB_FETCH_PROMPT,\n isReadOnly: true,\n isConcurrencySafe: true,\n parameters: {\n type: \"object\",\n properties: {\n url: {\n type: \"string\",\n description: \"The URL to fetch (must be a valid http/https URL)\",\n },\n prompt: {\n type: \"string\",\n description:\n \"Optional instruction for what to extract from the page content\",\n },\n },\n required: [\"url\"],\n },\n\n async call(\n args: Record<string, unknown>,\n _ctx: ToolContext,\n ): Promise<ToolResult> {\n const url = args.url as string;\n const prompt = args.prompt as string | undefined;\n\n try {\n new URL(url);\n } catch {\n return { content: `Invalid URL: ${url}`, isError: true };\n }\n\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n\n const response = await fetch(url, {\n signal: controller.signal,\n headers: {\n \"User-Agent\": \"noumen-agent/1.0\",\n Accept: \"text/html,application/xhtml+xml,application/xml;q=0.9,text/plain;q=0.8,*/*;q=0.7\",\n },\n redirect: \"follow\",\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n return {\n content: `HTTP ${response.status}: ${response.statusText}`,\n isError: true,\n };\n }\n\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n const contentLength = parseInt(\n response.headers.get(\"content-length\") ?? \"0\",\n 10,\n );\n\n if (contentLength > MAX_CONTENT_LENGTH) {\n return {\n content: `Response too large (${contentLength} bytes, limit ${MAX_CONTENT_LENGTH})`,\n isError: true,\n };\n }\n\n // Stream the body with a size cap to avoid OOM when Content-Length is absent\n let text = \"\";\n let bytesRead = 0;\n const reader = response.body?.getReader();\n const decoder = new TextDecoder();\n if (reader) {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n bytesRead += value.byteLength;\n if (bytesRead > MAX_CONTENT_LENGTH) {\n reader.cancel();\n return {\n content: `Response too large (>${MAX_CONTENT_LENGTH} bytes streamed, limit ${MAX_CONTENT_LENGTH})`,\n isError: true,\n };\n }\n text += decoder.decode(value, { stream: true });\n }\n text += decoder.decode();\n } else {\n text = await response.text();\n }\n\n let markdown: string;\n if (contentType.includes(\"text/html\") || contentType.includes(\"xhtml\")) {\n const { NodeHtmlMarkdown } = await import(\"node-html-markdown\");\n markdown = NodeHtmlMarkdown.translate(text);\n } else {\n markdown = text;\n }\n\n if (markdown.length > MAX_OUTPUT_CHARS) {\n const totalChars = markdown.length;\n markdown = markdown.slice(0, MAX_OUTPUT_CHARS) +\n `\\n\\n... content truncated (${totalChars} total chars)`;\n }\n\n let result = `# Content from ${url}\\n\\n${markdown}`;\n if (prompt) {\n result = `## Extraction prompt: ${prompt}\\n\\n${result}`;\n }\n\n return { content: result };\n } catch (err) {\n if (err instanceof Error && err.name === \"AbortError\") {\n return { content: `Fetch timed out after ${FETCH_TIMEOUT_MS}ms`, isError: true };\n }\n return {\n content: `Fetch error: ${err instanceof Error ? err.message : String(err)}`,\n isError: true,\n };\n }\n },\n};\n","/**\n * Model-facing prompt for the NotebookEdit tool.\n * Adapted from claude-code's NotebookEditTool/prompt.ts.\n */\n\nexport const NOTEBOOK_PROMPT = `Completely replaces the contents of a specific cell in a Jupyter notebook (.ipynb file) with new source. Jupyter notebooks are interactive documents that combine code, text, and visualizations, commonly used for data analysis and scientific computing. The notebook_path parameter must be an absolute path, not a relative path. The cell_number is 0-indexed. Use edit_mode=insert to add a new cell at the index specified by cell_number. Use edit_mode=delete to delete the cell at the index specified by cell_number.`;\n","import type { Tool, ToolResult, ToolContext } from \"./types.js\";\nimport { NOTEBOOK_PROMPT } from \"./prompts/notebook.js\";\n\ninterface NotebookCell {\n cell_type: string;\n source: string[];\n metadata: Record<string, unknown>;\n outputs?: unknown[];\n execution_count?: number | null;\n}\n\ninterface NotebookDocument {\n cells: NotebookCell[];\n metadata: Record<string, unknown>;\n nbformat: number;\n nbformat_minor: number;\n}\n\nexport const notebookEditTool: Tool = {\n name: \"NotebookEdit\",\n description:\n \"Edit a Jupyter notebook (.ipynb) file. Can replace, insert, or delete \" +\n \"cells. The notebook is pure JSON — no kernel execution.\",\n prompt: NOTEBOOK_PROMPT,\n isReadOnly: false,\n isConcurrencySafe: false,\n parameters: {\n type: \"object\",\n properties: {\n notebook_path: {\n type: \"string\",\n description: \"Path to the .ipynb file\",\n },\n cell_index: {\n type: \"number\",\n description: \"0-based index of the cell to edit. For insert, the new cell is placed at this index.\",\n },\n new_source: {\n type: \"string\",\n description:\n \"The new cell source content. Each line becomes an element in the source array.\",\n },\n cell_type: {\n type: \"string\",\n description: 'Cell type: \"code\" or \"markdown\" (default: \"code\")',\n },\n edit_mode: {\n type: \"string\",\n description:\n '\"replace\" (default) — replace existing cell source; ' +\n '\"insert\" — insert a new cell at cell_index; ' +\n '\"delete\" — delete the cell at cell_index (new_source is ignored)',\n },\n },\n required: [\"notebook_path\", \"cell_index\"],\n },\n\n async call(\n args: Record<string, unknown>,\n ctx: ToolContext,\n ): Promise<ToolResult> {\n const path = args.notebook_path as string;\n const cellIndex = args.cell_index as number;\n const newSource = (args.new_source as string | undefined) ?? \"\";\n const cellType = (args.cell_type as string | undefined) ?? \"code\";\n const editMode = (args.edit_mode as string | undefined) ?? \"replace\";\n\n try {\n const raw = await ctx.fs.readFile(path);\n let notebook: NotebookDocument;\n try {\n notebook = JSON.parse(raw);\n } catch {\n return { content: `Not a valid JSON notebook: ${path}`, isError: true };\n }\n\n if (!Array.isArray(notebook.cells)) {\n return { content: \"Notebook has no cells array.\", isError: true };\n }\n\n const sourceLines = newSource.split(\"\\n\").map((line, i, arr) =>\n i < arr.length - 1 ? line + \"\\n\" : line,\n );\n\n switch (editMode) {\n case \"replace\": {\n if (cellIndex < 0 || cellIndex >= notebook.cells.length) {\n return {\n content: `Cell index ${cellIndex} out of range (0-${notebook.cells.length - 1}).`,\n isError: true,\n };\n }\n notebook.cells[cellIndex].source = sourceLines;\n notebook.cells[cellIndex].cell_type = cellType;\n break;\n }\n case \"insert\": {\n if (cellIndex < 0 || cellIndex > notebook.cells.length) {\n return {\n content: `Insert index ${cellIndex} out of range (0-${notebook.cells.length}).`,\n isError: true,\n };\n }\n const newCell: NotebookCell = {\n cell_type: cellType,\n source: sourceLines,\n metadata: {},\n ...(cellType === \"code\"\n ? { outputs: [], execution_count: null }\n : {}),\n };\n notebook.cells.splice(cellIndex, 0, newCell);\n break;\n }\n case \"delete\": {\n if (cellIndex < 0 || cellIndex >= notebook.cells.length) {\n return {\n content: `Cell index ${cellIndex} out of range (0-${notebook.cells.length - 1}).`,\n isError: true,\n };\n }\n notebook.cells.splice(cellIndex, 1);\n break;\n }\n default:\n return {\n content: `Unknown edit_mode: ${editMode}. Use \"replace\", \"insert\", or \"delete\".`,\n isError: true,\n };\n }\n\n await ctx.fs.writeFile(path, JSON.stringify(notebook, null, 1) + \"\\n\");\n\n const action =\n editMode === \"delete\"\n ? `Deleted cell ${cellIndex}`\n : editMode === \"insert\"\n ? `Inserted new ${cellType} cell at index ${cellIndex}`\n : `Replaced cell ${cellIndex} content`;\n\n return { content: `${action} in ${path}. Notebook now has ${notebook.cells.length} cells.` };\n } catch (err) {\n return {\n content: `Error editing notebook: ${err instanceof Error ? err.message : String(err)}`,\n isError: true,\n };\n }\n },\n};\n","import type { Tool, ToolResult, ToolContext } from \"./types.js\";\n\nexport type UserInputHandler = (question: string) => Promise<string>;\n\nexport const askUserTool: Tool = {\n name: \"AskUser\",\n description:\n \"Ask the user a question and wait for their response. Use when you need \" +\n \"clarification, confirmation, or additional information before proceeding.\",\n isReadOnly: true,\n isConcurrencySafe: false,\n requiresUserInteraction: true,\n parameters: {\n type: \"object\",\n properties: {\n question: {\n type: \"string\",\n description: \"The question to ask the user\",\n },\n },\n required: [\"question\"],\n },\n\n async call(\n args: Record<string, unknown>,\n ctx: ToolContext,\n ): Promise<ToolResult> {\n const question = args.question as string;\n\n if (!ctx.userInputHandler) {\n return {\n content:\n \"Cannot ask user: no userInputHandler configured. \" +\n \"Set userInputHandler in AgentOptions or ThreadConfig.\",\n isError: true,\n };\n }\n\n try {\n const answer = await ctx.userInputHandler(question);\n return { content: answer };\n } catch (err) {\n return {\n content: `Error getting user input: ${err instanceof Error ? err.message : String(err)}`,\n isError: true,\n };\n }\n },\n};\n","import type { Tool, ToolContext, ToolResult } from \"./types.js\";\nimport type { ToolDefinition } from \"../providers/types.js\";\nimport { formatZodValidationError } from \"../utils/zod.js\";\nimport { isDeferredTool } from \"./tool-search.js\";\n\nfunction resolveToolPrompt(tool: Tool): string {\n if (tool.prompt === undefined) return tool.description;\n return typeof tool.prompt === \"function\" ? tool.prompt() : tool.prompt;\n}\nimport { readFileTool } from \"./read.js\";\nimport { writeFileTool } from \"./write.js\";\nimport { editFileTool } from \"./edit.js\";\nimport { bashTool } from \"./bash.js\";\nimport { globTool } from \"./glob.js\";\nimport { grepTool } from \"./grep.js\";\nimport { webFetchTool } from \"./web-fetch.js\";\nimport { notebookEditTool } from \"./notebook.js\";\nimport { askUserTool } from \"./ask-user.js\";\n\n/**\n * Resolve a tool flag that can be a static boolean or a function of the input.\n * Returns `defaultValue` when the flag is `undefined`.\n */\nexport function resolveToolFlag(\n flag: boolean | ((args: Record<string, unknown>) => boolean) | undefined,\n args: Record<string, unknown>,\n defaultValue = false,\n): boolean {\n if (flag === undefined) return defaultValue;\n if (typeof flag === \"function\") {\n try {\n return flag(args);\n } catch {\n return defaultValue;\n }\n }\n return flag;\n}\n\nexport class ToolRegistry {\n private tools: Map<string, Tool> = new Map();\n private _discoveredTools = new Set<string>();\n private _toolSearchEnabled = false;\n\n constructor(additionalTools?: Tool[]) {\n const builtIn = [\n readFileTool,\n writeFileTool,\n editFileTool,\n bashTool,\n globTool,\n grepTool,\n webFetchTool,\n notebookEditTool,\n askUserTool,\n ];\n\n for (const tool of builtIn) {\n this.tools.set(tool.name, tool);\n }\n\n if (additionalTools) {\n for (const tool of additionalTools) {\n this.tools.set(tool.name, tool);\n }\n }\n }\n\n enableToolSearch(): void {\n this._toolSearchEnabled = true;\n }\n\n register(tool: Tool): void {\n this.tools.set(tool.name, tool);\n }\n\n get(name: string): Tool | undefined {\n return this.tools.get(name);\n }\n\n async execute(\n name: string,\n args: Record<string, unknown>,\n ctx: ToolContext,\n ): Promise<ToolResult> {\n const tool = this.tools.get(name);\n if (!tool) {\n return {\n content: `Unknown tool: ${name}`,\n isError: true,\n };\n }\n\n if (tool.inputSchema) {\n const parsed = tool.inputSchema.safeParse(args);\n if (!parsed.success) {\n return {\n content: formatZodValidationError(name, parsed.error),\n isError: true,\n };\n }\n }\n\n return tool.call(args, ctx);\n }\n\n toToolDefinitions(): ToolDefinition[] {\n return Array.from(this.tools.values()).map((tool) => ({\n type: \"function\" as const,\n function: {\n name: tool.name,\n description: resolveToolPrompt(tool),\n parameters: tool.parameters,\n },\n }));\n }\n\n /**\n * Get tool definitions filtered by tool search. Eager tools (always sent)\n * plus any deferred tools the model has discovered via ToolSearch.\n * Falls back to all tools when tool search is not enabled.\n */\n getActiveToolDefinitions(): ToolDefinition[] {\n if (!this._toolSearchEnabled) return this.toToolDefinitions();\n\n return Array.from(this.tools.values())\n .filter((tool) => !isDeferredTool(tool) || this._discoveredTools.has(tool.name))\n .map((tool) => ({\n type: \"function\" as const,\n function: {\n name: tool.name,\n description: resolveToolPrompt(tool),\n parameters: tool.parameters,\n },\n }));\n }\n\n getEagerTools(): Tool[] {\n return Array.from(this.tools.values()).filter((tool) => !isDeferredTool(tool));\n }\n\n getDeferredTools(): Tool[] {\n return Array.from(this.tools.values()).filter(isDeferredTool);\n }\n\n getToolsByNames(names: string[]): Tool[] {\n return names\n .map((name) => this.tools.get(name))\n .filter((t): t is Tool => t !== undefined);\n }\n\n markDiscovered(names: string[]): void {\n for (const name of names) {\n this._discoveredTools.add(name);\n }\n }\n\n get discoveredTools(): ReadonlySet<string> {\n return this._discoveredTools;\n }\n\n listTools(): Tool[] {\n return Array.from(this.tools.values());\n }\n}\n"],"mappings":"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;AAEzD,SAAO;AACT;;;AC/DA,IAAM,qBAAqB,oBAAI,IAAI;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AACF,CAAC;AAID,IAAM,4BAA4B,oBAAI,IAAI;AAAA,EACxC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EA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","names":["parts","matchedTools","path","path","MAX_OUTPUT_CHARS","path"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli/headless.ts"],"sourcesContent":["import * as readline from \"node:readline\";\nimport { randomUUID } from \"node:crypto\";\nimport type { Agent } from \"../agent.js\";\nimport type { Thread } from \"../thread.js\";\nimport type { StreamEvent } from \"../session/types.js\";\nimport type { PermissionResponse } from \"../permissions/types.js\";\nimport type { MergedConfig } from \"./config.js\";\n\ninterface PromiseResolver<T> {\n resolve: (value: T) => void;\n reject: (err: Error) => void;\n}\n\ninterface SessionEntry {\n thread: Thread;\n abort: AbortController;\n pendingPermission: PromiseResolver<PermissionResponse> | null;\n pendingInput: PromiseResolver<string> | null;\n running: boolean;\n}\n\nfunction emit(obj: Record<string, unknown>): void {\n process.stdout.write(JSON.stringify(obj) + \"\\n\");\n}\n\nfunction serializeEvent(event: StreamEvent): Record<string, unknown> {\n if (event.type === \"error\") {\n return { type: \"error\", error: { message: event.error.message, name: event.error.name } };\n }\n if (event.type === \"retry_exhausted\") {\n return { ...event, error: { message: event.error.message, name: event.error.name } };\n }\n if (event.type === \"retry_attempt\") {\n return { ...event, error: { message: event.error.message, name: event.error.name } };\n }\n return event as unknown as Record<string, unknown>;\n}\n\n/**\n * Run the agent in headless mode: bidirectional NDJSON over stdin/stdout.\n *\n * Inbound commands (stdin, one JSON per line):\n * { type: \"prompt\", text, sessionId?, maxTurns? }\n * { type: \"permission_response\", sessionId, allow, updatedInput? }\n * { type: \"input_response\", sessionId, answer }\n * { type: \"abort\", sessionId }\n *\n * Outbound events (stdout, one JSON per line):\n * { type: \"ready\" }\n * { type: \"session_created\", sessionId }\n * { type: \"session_done\", sessionId }\n * All StreamEvent types with an added `sessionId` field\n */\nexport async function runHeadless(code: Agent, _config: MergedConfig): Promise<void> {\n await code.init();\n\n const sessions = new Map<string, SessionEntry>();\n\n emit({ type: \"ready\" });\n\n const rl = readline.createInterface({ input: process.stdin, terminal: false });\n\n for await (const line of rl) {\n if (!line.trim()) continue;\n\n let cmd: Record<string, unknown>;\n try {\n cmd = JSON.parse(line);\n } catch {\n emit({ type: \"error\", error: { message: \"Invalid JSON\", name: \"ParseError\" } });\n continue;\n }\n\n const cmdType = cmd.type as string;\n\n if (cmdType === \"prompt\") {\n const text = cmd.text as string;\n if (!text) {\n emit({ type: \"error\", error: { message: \"Missing required field: text\", name: \"ValidationError\" } });\n continue;\n }\n\n const sessionId = (cmd.sessionId as string) ?? randomUUID();\n const existing = sessions.get(sessionId);\n\n if (existing?.running) {\n emit({ type: \"error\", error: { message: \"Session is still running\", name: \"ConflictError\" }, sessionId });\n continue;\n }\n\n const abort = new AbortController();\n\n const permissionHandler = (req: import(\"../permissions/types.js\").PermissionRequest): Promise<PermissionResponse> => {\n const entry = sessions.get(sessionId);\n if (!entry) return Promise.reject(new Error(\"Session not found\"));\n return new Promise<PermissionResponse>((resolve, reject) => {\n entry.pendingPermission = { resolve, reject };\n });\n };\n\n const userInputHandler = (question: string): Promise<string> => {\n const entry = sessions.get(sessionId);\n if (!entry) return Promise.reject(new Error(\"Session not found\"));\n emit({ ...({} as Record<string, unknown>), type: \"user_input_request\", sessionId, question });\n return new Promise<string>((resolve, reject) => {\n entry.pendingInput = { resolve, reject };\n });\n };\n\n let thread: Thread;\n if (existing) {\n existing.abort = abort;\n existing.running = true;\n thread = existing.thread;\n } else {\n thread = code.createThread({\n sessionId,\n permissionHandler,\n userInputHandler,\n });\n sessions.set(sessionId, {\n thread,\n abort,\n pendingPermission: null,\n pendingInput: null,\n running: true,\n });\n }\n\n emit({ type: \"session_created\", sessionId });\n\n const maxTurns = cmd.maxTurns as number | undefined;\n\n (async () => {\n try {\n for await (const event of thread.run(text, { signal: abort.signal, maxTurns })) {\n emit({ ...serializeEvent(event), sessionId });\n }\n } catch (err) {\n if ((err as Error).name !== \"AbortError\") {\n const e = err instanceof Error ? err : new Error(String(err));\n emit({ type: \"error\", error: { message: e.message, name: e.name }, sessionId });\n }\n } finally {\n const entry = sessions.get(sessionId);\n if (entry) entry.running = false;\n emit({ type: \"session_done\", sessionId });\n }\n })();\n\n continue;\n }\n\n if (cmdType === \"permission_response\") {\n const sessionId = cmd.sessionId as string;\n const entry = sessions.get(sessionId);\n if (!entry?.pendingPermission) continue;\n const { sessionId: _sid, type: _type, ...response } = cmd;\n entry.pendingPermission.resolve(response as unknown as PermissionResponse);\n entry.pendingPermission = null;\n continue;\n }\n\n if (cmdType === \"input_response\") {\n const sessionId = cmd.sessionId as string;\n const entry = sessions.get(sessionId);\n if (!entry?.pendingInput) continue;\n entry.pendingInput.resolve((cmd.answer as string) ?? \"\");\n entry.pendingInput = null;\n continue;\n }\n\n if (cmdType === \"abort\") {\n const sessionId = cmd.sessionId as string;\n const entry = sessions.get(sessionId);\n if (entry) {\n entry.abort.abort();\n if (entry.pendingPermission) {\n entry.pendingPermission.reject(new Error(\"Session aborted\"));\n entry.pendingPermission = null;\n }\n if (entry.pendingInput) {\n entry.pendingInput.reject(new Error(\"Session aborted\"));\n entry.pendingInput = null;\n }\n }\n continue;\n }\n\n emit({ type: \"error\", error: { message: `Unknown command type: ${cmdType}`, name: \"ValidationError\" } });\n }\n\n await code.close();\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/providers/ollama.ts"],"sourcesContent":["import { OpenAIProvider } from \"./openai.js\";\n\nexport interface OllamaProviderOptions {\n /** Ollama server URL. Defaults to http://localhost:11434/v1. */\n baseURL?: string;\n model?: string;\n}\n\nexport class OllamaProvider extends OpenAIProvider {\n constructor(opts: OllamaProviderOptions = {}) {\n super({\n baseURL: opts.baseURL ?? \"http://localhost:11434/v1\",\n model: opts.model ?? \"qwen2.5-coder:32b\",\n });\n }\n}\n"],"mappings":";;;;;;AAQO,IAAM,iBAAN,cAA6B,eAAe;AAAA,EACjD,YAAY,OAA8B,CAAC,GAAG;AAC5C,UAAM;AAAA,MACJ,SAAS,KAAK,WAAW;AAAA,MACzB,OAAO,KAAK,SAAS;AAAA,IACvB,CAAC;AAAA,EACH;AACF;","names":[]}