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
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/tools/tool-search.ts","../src/tools/prompts/read.ts","../src/tools/read.ts","../src/permissions/types.ts","../src/permissions/rules.ts","../src/permissions/classifier.ts","../src/tools/shell-safety/git-safety.ts","../src/tools/shell-safety/command-classification.ts","../src/permissions/pipeline.ts","../src/tools/write.ts","../src/tools/prompts/write.ts","../src/tools/file-lock.ts","../src/tools/edit.ts","../src/tools/edit-utils.ts","../src/tools/prompts/edit.ts","../src/tools/shell-safety/git-tracking.ts","../src/tools/prompts/bash.ts","../src/tools/bash.ts","../src/tools/glob.ts","../src/tools/prompts/glob.ts","../src/utils/shell-escape.ts","../src/tools/prompts/grep.ts","../src/tools/grep.ts","../src/tools/web-fetch.ts","../src/tools/prompts/web-fetch.ts","../src/tools/prompts/notebook.ts","../src/tools/notebook.ts","../src/tools/ask-user.ts","../src/tools/registry.ts","../src/permissions/helpers.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 * 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 = 256 * 1024; // 256 KB\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 if (filePath.startsWith(\"\\\\\\\\\") || filePath.startsWith(\"//\")) {\n return { content: \"Error: UNC paths are not allowed\", isError: true };\n }\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 if (\n resolved.startsWith(\"/proc/\") &&\n (resolved.endsWith(\"/fd/0\") || resolved.endsWith(\"/fd/1\") || resolved.endsWith(\"/fd/2\"))\n ) {\n return {\n content: `Error: Cannot read process file descriptor ${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 && !limit) {\n return {\n content: `Error: File is too large (${Math.round(stat.size / 1024)}KB, max ${MAX_FILE_SIZE / 1024}KB). 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 maxReadBytes = limit\n ? Math.min((limit + (offset - 1)) * 500, 10 * 1024 * 1024)\n : undefined;\n const content = await ctx.fs.readFile(\n filePath,\n maxReadBytes ? { maxBytes: maxReadBytes } : undefined,\n );\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 isPartialView: !!(limit || offset > 1),\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","import type { ToolContext } from \"../tools/types.js\";\n\n// --- Permission modes ---\n\nexport type PermissionMode =\n | \"default\"\n | \"plan\"\n | \"acceptEdits\"\n | \"auto\"\n | \"bypassPermissions\"\n | \"dontAsk\";\n\n// --- Rule behavior ---\n\nexport type PermissionBehavior = \"allow\" | \"deny\" | \"ask\";\n\n// --- Rule source provenance ---\n\nexport type PermissionRuleSource =\n | \"user\"\n | \"project\"\n | \"session\"\n | \"policy\";\n\n/** Precedence order: policy > project > user > session. */\nexport const RULE_SOURCE_PRECEDENCE: PermissionRuleSource[] = [\n \"policy\",\n \"project\",\n \"user\",\n \"session\",\n];\n\n// --- Rules ---\n\nexport interface PermissionRule {\n toolName: string;\n ruleContent?: string;\n behavior: PermissionBehavior;\n /** Where this rule came from. Higher-precedence sources override lower ones. */\n source?: PermissionRuleSource;\n}\n\n// --- Permission updates ---\n\nexport type PermissionUpdate =\n | { type: \"addRules\"; rules: PermissionRule[] }\n | { type: \"removeRules\"; toolName: string; behavior?: PermissionBehavior }\n | { type: \"setMode\"; mode: PermissionMode }\n | { type: \"addDirectories\"; directories: string[] }\n | { type: \"removeDirectories\"; directories: string[] };\n\n// --- Decision result types ---\n\nexport interface PermissionAllowResult<\n Input extends Record<string, unknown> = Record<string, unknown>,\n> {\n behavior: \"allow\";\n updatedInput?: Input;\n reason?: string;\n}\n\nexport interface PermissionDenyResult {\n behavior: \"deny\";\n message: string;\n reason?: string;\n}\n\nexport interface PermissionAskResult {\n behavior: \"ask\";\n message: string;\n reason?: string;\n suggestions?: PermissionRule[];\n}\n\nexport interface PermissionPassthroughResult {\n behavior: \"passthrough\";\n message: string;\n reason?: string;\n suggestions?: PermissionRule[];\n}\n\n/**\n * What `Tool.checkPermissions` returns. Includes `passthrough` for tools that\n * have no opinion and want the global pipeline to decide.\n */\nexport type PermissionResult<\n Input extends Record<string, unknown> = Record<string, unknown>,\n> =\n | PermissionAllowResult<Input>\n | PermissionDenyResult\n | PermissionAskResult\n | PermissionPassthroughResult;\n\n/**\n * Final decision after the pipeline resolves. No `passthrough` — always\n * one of allow / deny / ask.\n */\nexport type PermissionDecision<\n Input extends Record<string, unknown> = Record<string, unknown>,\n> =\n | PermissionAllowResult<Input>\n | PermissionDenyResult\n | PermissionAskResult;\n\n// --- Handler callback types ---\n\nexport interface PermissionRequest {\n toolName: string;\n input: Record<string, unknown>;\n message: string;\n suggestions?: PermissionRule[];\n isReadOnly: boolean;\n isDestructive: boolean;\n /** Abort signal from the session — handlers should stop promptly when fired. */\n signal?: AbortSignal;\n}\n\nexport interface PermissionResponse {\n allow: boolean;\n updatedInput?: Record<string, unknown>;\n feedback?: string;\n addRules?: PermissionRule[];\n}\n\nexport type PermissionHandler = (\n request: PermissionRequest,\n) => Promise<PermissionResponse>;\n\n// --- Configuration ---\n\nexport interface AutoModeConfig {\n /** Custom system prompt for the classifier. When omitted, uses a default. */\n classifierPrompt?: string;\n /** Model to use for classification. When omitted, uses the thread's model. */\n classifierModel?: string;\n}\n\nexport interface DenialTrackingConfig {\n /** Max consecutive denials before fallback (default: 3). */\n maxConsecutive?: number;\n /** Max total denials before fallback (default: 20). */\n maxTotal?: number;\n}\n\nexport interface PermissionConfig {\n mode?: PermissionMode;\n rules?: PermissionRule[];\n handler?: PermissionHandler;\n workingDirectories?: string[];\n /** Called when a permission update is applied (for host-side persistence). */\n onPermissionUpdate?: (update: PermissionUpdate) => void;\n /** Configuration for auto mode classifier. */\n autoMode?: AutoModeConfig;\n /** Configuration for denial tracking limits. */\n denialTracking?: DenialTrackingConfig;\n}\n\nexport interface PermissionContext {\n mode: PermissionMode;\n rules: PermissionRule[];\n workingDirectories: string[];\n}\n\n// --- Tool permission extension ---\n\n/**\n * Optional permission metadata a `Tool` can provide.\n * Kept as a separate interface so it can be imported without circular deps.\n */\nexport interface ToolPermissionMethods {\n isReadOnly?: boolean | ((args: Record<string, unknown>) => boolean);\n isDestructive?: boolean | ((args: Record<string, unknown>) => boolean);\n checkPermissions?: (\n args: Record<string, unknown>,\n ctx: ToolContext,\n ) => Promise<PermissionResult> | PermissionResult;\n}\n","import * as path from \"node:path\";\nimport * as fs from \"node:fs\";\nimport type {\n PermissionBehavior,\n PermissionContext,\n PermissionRule,\n} from \"./types.js\";\nimport { RULE_SOURCE_PRECEDENCE } from \"./types.js\";\n/**\n * Check whether a tool name matches a rule's `toolName` field.\n *\n * Supports:\n * - Exact match: `\"Bash\"` matches `\"Bash\"`\n * - MCP server-level wildcard: rule `\"mcp__myserver\"` matches any tool\n * on that server (e.g. `\"mcp__myserver__sometool\"`)\n */\nexport function toolMatchesRule(\n toolName: string,\n rule: PermissionRule,\n mcpInfo?: { serverName: string; toolName: string },\n): boolean {\n if (rule.toolName === toolName) return true;\n\n if (mcpInfo) {\n const serverPrefix = parseMcpServerPrefix(rule.toolName);\n if (serverPrefix && serverPrefix === mcpInfo.serverName) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Parse a server-level MCP rule like `\"mcp__myserver\"` (no tool suffix)\n * and return the server name, or `null` if it has a tool component or\n * doesn't match the MCP prefix pattern.\n */\nfunction parseMcpServerPrefix(ruleName: string): string | null {\n const parts = ruleName.split(\"__\");\n if (parts.length !== 2 || parts[0] !== \"mcp\" || !parts[1]) return null;\n return parts[1];\n}\n\nconst SAFE_WRAPPERS = [\"timeout\", \"time\", \"nice\", \"nohup\", \"stdbuf\"];\n\nconst COMPOUND_OPERATORS_RE = /\\s*(?:;|&&|\\|\\||\\|)\\s*/;\n\n/**\n * Strip leading env var assignments and safe wrapper commands from a\n * shell command so that deny/ask rules match the underlying command.\n */\nexport function stripForRuleMatching(command: string): string {\n let cmd = command.trim();\n // Strip env var prefixes\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 // Strip safe wrapper commands (and their flags)\n let changed = true;\n while (changed) {\n changed = false;\n for (const wrapper of SAFE_WRAPPERS) {\n if (cmd.startsWith(wrapper + \" \")) {\n cmd = cmd.slice(wrapper.length).trim();\n // Skip flags belonging to the wrapper\n while (cmd.startsWith(\"-\")) {\n const spaceIdx = cmd.indexOf(\" \");\n if (spaceIdx === -1) break;\n cmd = cmd.slice(spaceIdx).trim();\n }\n // Strip another round of env vars after the wrapper\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 changed = true;\n }\n }\n }\n return cmd;\n}\n\nfunction isCompoundCommand(content: string): boolean {\n return COMPOUND_OPERATORS_RE.test(content);\n}\n\n/**\n * Match a content string against a rule's `ruleContent`.\n *\n * Three match modes (following claude-code's bash/filesystem patterns):\n * - **exact**: `ruleContent === content`\n * - **prefix**: `ruleContent` ends with `:*` → prefix match\n * - **glob**: `ruleContent` contains `*` or `**` → simple glob match\n *\n * For deny/ask rules, also tries matching after stripping env vars and\n * safe wrapper commands from the content.\n */\nexport function contentMatchesRule(\n content: string,\n ruleContent: string,\n): boolean {\n if (ruleContent.endsWith(\":*\")) {\n const prefix = ruleContent.slice(0, -2);\n const matches = content === prefix || content.startsWith(prefix + \" \");\n if (matches && isCompoundCommand(content)) return false;\n if (matches) return true;\n // Retry after stripping env vars / wrappers\n const stripped = stripForRuleMatching(content);\n if (stripped !== content) {\n const strippedMatches = stripped === prefix || stripped.startsWith(prefix + \" \");\n if (strippedMatches && isCompoundCommand(stripped)) return false;\n return strippedMatches;\n }\n return false;\n }\n\n if (ruleContent.includes(\"*\")) {\n if (matchSimpleGlob(ruleContent, content)) return true;\n const stripped = stripForRuleMatching(content);\n if (stripped !== content) return matchSimpleGlob(ruleContent, stripped);\n return false;\n }\n\n if (ruleContent === content) return true;\n const stripped = stripForRuleMatching(content);\n return stripped !== content && ruleContent === stripped;\n}\n\n/**\n * Minimal glob matching for file-path rules.\n *\n * Supports `*` (any non-separator chars) and `**` (any chars including `/`).\n * Anchored: the entire string must match.\n */\nexport function matchSimpleGlob(pattern: string, value: string): boolean {\n let regex = \"^\";\n let i = 0;\n while (i < pattern.length) {\n if (pattern[i] === \"*\" && pattern[i + 1] === \"*\") {\n regex += \".*\";\n i += 2;\n if (pattern[i] === \"/\") i++;\n } else if (pattern[i] === \"*\") {\n regex += \"[^/]*\";\n i++;\n } else if (pattern[i] === \"?\") {\n regex += \"[^/]\";\n i++;\n } else {\n regex += escapeRegex(pattern[i]!);\n i++;\n }\n }\n regex += \"$\";\n\n return new RegExp(regex).test(value);\n}\n\nfunction escapeRegex(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\n/**\n * Return all rules in `context` that match the given tool and behavior,\n * optionally filtered by content.\n */\nexport function getMatchingRules(\n context: PermissionContext,\n toolName: string,\n behavior: PermissionBehavior,\n content?: string,\n mcpInfo?: { serverName: string; toolName: string },\n): PermissionRule[] {\n const matched = context.rules.filter((rule) => {\n if (rule.behavior !== behavior) return false;\n if (!toolMatchesRule(toolName, rule, mcpInfo)) return false;\n\n if (rule.ruleContent !== undefined) {\n if (content === undefined) return false;\n return contentMatchesRule(content, rule.ruleContent);\n }\n\n // Whole-tool rule (no ruleContent) — matches when no content filter\n // is requested, or always matches if content IS provided (whole-tool\n // rules override content-specific ones, matching claude-code behavior).\n return true;\n });\n\n // Sort by source precedence so higher-precedence sources win first\n matched.sort((a, b) => {\n const aIdx = a.source ? RULE_SOURCE_PRECEDENCE.indexOf(a.source) : RULE_SOURCE_PRECEDENCE.length;\n const bIdx = b.source ? RULE_SOURCE_PRECEDENCE.indexOf(b.source) : RULE_SOURCE_PRECEDENCE.length;\n return aIdx - bIdx;\n });\n\n return matched;\n}\n\n/**\n * Reject paths that contain shell expansion syntax which could cause TOCTOU\n * issues — the path resolves differently in Node vs when the shell evaluates it.\n */\nexport function containsShellExpansion(p: string): boolean {\n if (p.includes(\"$\") || p.includes(\"%\") || p.startsWith(\"=\")) return true;\n if (p.includes(\"`\")) return true;\n if (/^~[^/]/.test(p)) return true; // ~user, ~+, ~- (bare ~/... is fine)\n if (p.startsWith(\"\\\\\\\\\")) return true; // UNC paths\n return false;\n}\n\n/**\n * Check whether a file path falls within any of the configured working directories.\n */\nexport function isPathInWorkingDirectories(\n filePath: string,\n workingDirectories: string[],\n): boolean {\n if (workingDirectories.length === 0) return false;\n if (containsShellExpansion(filePath)) return false;\n\n const normalized = normalizePath(filePath);\n return workingDirectories.some((dir) => {\n const normalizedDir = normalizePath(dir);\n return (\n normalized === normalizedDir ||\n normalized.startsWith(normalizedDir + \"/\")\n );\n });\n}\n\nfunction normalizePath(p: string): string {\n let result = path.resolve(p);\n try {\n result = fs.realpathSync(result);\n } catch {\n // Path doesn't exist yet — fall through to the resolved path\n }\n while (result.endsWith(\"/\") && result.length > 1) {\n result = result.slice(0, -1);\n }\n if (process.platform === \"darwin\" || process.platform === \"win32\") {\n result = result.toLowerCase();\n }\n return result;\n}\n","import type { AIProvider, ChatParams } from \"../providers/types.js\";\nimport type { ChatMessage, ContentPart } from \"../session/types.js\";\nimport { contentToString } from \"../utils/content.js\";\n\nexport interface ClassifierResult {\n shouldBlock: boolean;\n reason: string;\n}\n\nconst DEFAULT_CLASSIFIER_PROMPT = `You are a security classifier for an AI coding agent. \nYour job is to determine whether a tool call should be automatically approved or blocked.\n\nAutomatically APPROVE tool calls that:\n- Read files within the project directory\n- Write/edit files within the project directory \n- Run common development commands (build, test, lint, format, git status/diff/log)\n- Search for files or code patterns\n- Create or update task items\n\nAutomatically BLOCK tool calls that:\n- Execute potentially destructive commands (rm -rf, drop database, force push)\n- Access files outside the project directory\n- Make network requests to unknown hosts\n- Run commands that could affect the system (install packages globally, modify system files)\n- Access secrets, credentials, or environment variables\n\nRespond with a JSON object: {\"shouldBlock\": boolean, \"reason\": \"brief explanation\"}`;\n\n/**\n * Run a side-query to classify whether a tool call should be auto-approved.\n */\nexport async function classifyPermission(\n toolName: string,\n args: Record<string, unknown>,\n recentMessages: ChatMessage[],\n provider: AIProvider,\n opts?: {\n classifierPrompt?: string;\n classifierModel?: string;\n model?: string;\n signal?: AbortSignal;\n },\n): Promise<ClassifierResult> {\n const model = opts?.classifierModel ?? opts?.model;\n if (!model) {\n return { shouldBlock: true, reason: \"No model configured for classifier.\" };\n }\n\n const contextWindow = recentMessages.slice(-6);\n const contextText = contextWindow\n .map((m) => `${m.role}: ${contentToString(m.content as string | ContentPart[]).slice(0, 200)}`)\n .join(\"\\n\");\n\n const userPrompt =\n `Tool: ${toolName}\\n` +\n `Arguments: ${JSON.stringify(args, null, 2).slice(0, 1000)}\\n\\n` +\n `Recent conversation context:\\n${contextText}`;\n\n const params: ChatParams = {\n model,\n system: opts?.classifierPrompt ?? DEFAULT_CLASSIFIER_PROMPT,\n messages: [{ role: \"user\", content: userPrompt }],\n max_tokens: 256,\n temperature: 0,\n outputFormat: {\n type: \"json_schema\",\n schema: {\n type: \"object\",\n properties: {\n shouldBlock: { type: \"boolean\" },\n reason: { type: \"string\" },\n },\n required: [\"shouldBlock\", \"reason\"],\n additionalProperties: false,\n },\n name: \"classifier_result\",\n strict: true,\n },\n };\n\n try {\n let text = \"\";\n for await (const chunk of provider.chat(params)) {\n if (opts?.signal?.aborted) break;\n for (const choice of chunk.choices) {\n if (choice.delta.content) {\n text += choice.delta.content;\n }\n }\n }\n\n if (opts?.signal?.aborted) {\n throw new DOMException(\"Aborted\", \"AbortError\");\n }\n\n const parsed = JSON.parse(text) as ClassifierResult;\n return {\n shouldBlock: parsed.shouldBlock ?? false,\n reason: parsed.reason ?? \"unknown\",\n };\n } catch {\n // On classifier failure, default to blocking (fail closed)\n return { shouldBlock: true, reason: \"Classifier failed; defaulting to block.\" };\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 * Patterns for bare repo top-level paths that are security-sensitive.\n * In a bare repo, these exist at the root without a `.git/` prefix.\n */\nconst BARE_REPO_INTERNAL_PATTERNS = [\n /^hooks\\//,\n /^config$/,\n /^info\\//,\n /^objects\\//,\n /^refs\\//,\n /^HEAD$/,\n /^index$/,\n /^packed-refs$/,\n /^shallow$/,\n /^modules\\//,\n];\n\n/**\n * Returns true if `filePath` targets a bare repo internal path\n * (e.g. `hooks/pre-commit`, `HEAD`, `refs/heads/main`).\n */\nexport function isBareRepoInternalPath(filePath: string): boolean {\n const normalized = filePath.replace(/\\\\/g, \"/\").replace(/^\\.\\//, \"\");\n return BARE_REPO_INTERNAL_PATTERNS.some((p) => p.test(normalized));\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/` or matches a bare repo internal path.\n */\nexport function commandWritesGitInternals(command: string): boolean {\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]) || isBareRepoInternalPath(match[1])) return true;\n }\n\n // cp/mv/ln targeting .git/ or bare repo paths\n const copyPatternDotGit = /\\b(?:cp|mv|ln)\\b.*\\s(\\S*\\.git\\/\\S+)/;\n const copyMatchDotGit = command.match(copyPatternDotGit);\n if (copyMatchDotGit && isGitInternalPath(copyMatchDotGit[1])) return true;\n\n const copyPatternBare = /\\b(?:cp|mv|ln)\\b.*\\s(\\S+)/g;\n let bareMatch: RegExpExecArray | null;\n while ((bareMatch = copyPatternBare.exec(command)) !== null) {\n if (isBareRepoInternalPath(bareMatch[1])) return true;\n }\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 \"uname\",\n \"whoami\",\n \"id\",\n \"groups\",\n \"ls\",\n \"ll\",\n \"la\",\n \"dir\",\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 \"locate\",\n \"readlink\",\n \"realpath\",\n \"basename\",\n \"dirname\",\n \"diff\",\n \"comm\",\n \"sort\",\n \"uniq\",\n \"cut\",\n \"tr\",\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 \"nproc\",\n \"arch\",\n \"lscpu\",\n \"lsb_release\",\n \"sw_vers\",\n \"sysctl\",\n \"getconf\",\n]);\n\n// Commands that are read-only only when specific dangerous flags are absent.\n// Moved out of READ_ONLY_COMMANDS to enforce flag-level validation.\nconst CONDITIONAL_READ_ONLY: Record<\n string,\n (command: string, tokens: string[]) => boolean\n> = {\n awk: () => false, // awk has system() — never read-only\n sed: (_cmd, tokens) => !tokens.some((t) =>\n t === \"-i\" || t === \"--in-place\" ||\n (t.startsWith(\"-\") && !t.startsWith(\"--\") && t.includes(\"i\"))\n ),\n find: (cmd) => !/\\b(-exec\\b|-execdir\\b|-ok\\b|-okdir\\b|-delete\\b|-fprint\\b|-fls\\b|-fprintf\\b)/.test(cmd),\n fd: (_cmd, tokens) => !tokens.some((t) => [\"-x\", \"--exec\", \"-X\", \"--exec-batch\"].includes(t)),\n fdfind: (_cmd, tokens) => !tokens.some((t) => [\"-x\", \"--exec\", \"-X\", \"--exec-batch\"].includes(t)),\n date: (_cmd, tokens) => !tokens.some((t) => [\"-s\", \"--set\"].includes(t)),\n hostname: (_cmd, tokens) => {\n const positional = tokens.filter((t) => !t.startsWith(\"-\"));\n return positional.length === 0;\n },\n info: (_cmd, tokens) => !tokens.some((t) => [\"-o\", \"--output\", \"--dribble\", \"--init-file\"].includes(t)),\n tree: (_cmd, tokens) => !tokens.some((t) => t === \"-R\"),\n dotnet: (_cmd, tokens) => {\n const positional = tokens.filter((t) => !t.startsWith(\"-\"));\n if (positional.length === 0) return true;\n const sub = positional[0];\n return [\"--version\", \"--info\", \"--list-sdks\", \"--list-runtimes\"].includes(sub)\n || tokens.includes(\"--version\") || tokens.includes(\"--info\")\n || tokens.includes(\"--list-sdks\") || tokens.includes(\"--list-runtimes\");\n },\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 \"stash\", // \"stash list\" / \"stash show\" — stash apply/pop are not here\n \"reflog\", // bare / \"reflog show\" / \"reflog list\" — expire/delete caught below\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// Flags on \"read-only\" git subcommands that write to the filesystem.\n// Checked for ALL read-only subcommands before allowing the classification.\nconst GIT_READ_ONLY_WRITE_FLAGS = new Set([\n \"--output\",\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 (matches -i anywhere in args, not just first flag)\n /\\bsed\\b.*\\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 */\nexport function splitCompoundCommand(command: string): string[] {\n return command\n .split(/\\s*(?:;|&&|\\|\\||(?<!\\|)\\|(?!\\|))\\s*/)\n .map((s) => s.trim())\n .filter(Boolean);\n}\n\nconst DANGEROUS_ENV_VARS = new Set([\n \"GIT_CONFIG_GLOBAL\",\n \"GIT_CONFIG_SYSTEM\",\n \"GIT_DIR\",\n \"GIT_WORK_TREE\",\n \"GIT_EXEC_PATH\",\n \"GIT_TEMPLATE_DIR\",\n \"LD_PRELOAD\",\n \"LD_LIBRARY_PATH\",\n \"PATH\",\n \"PYTHONPATH\",\n \"NODE_PATH\",\n \"PERL5LIB\",\n]);\n\n/**\n * Check whether a command contains dangerous env var prefix assignments.\n * Returns true if any env var in the prefix is in the DANGEROUS_ENV_VARS set.\n */\nfunction hasDangerousEnvVars(command: string): boolean {\n const envPattern = /^[A-Za-z_][A-Za-z0-9_]*(?==)/;\n let cmd = command.trim();\n while (/^[A-Za-z_][A-Za-z0-9_]*=\\S*\\s/.test(cmd)) {\n const match = cmd.match(envPattern);\n if (match && DANGEROUS_ENV_VARS.has(match[0])) return true;\n cmd = cmd.replace(/^[A-Za-z_][A-Za-z0-9_]*=\\S*\\s+/, \"\");\n }\n return false;\n}\n\n// Zsh builtins that can perform system-level operations\nconst ZSH_DANGEROUS_COMMANDS = new Set([\n \"zmodload\",\n \"emulate\",\n \"sysopen\",\n \"sysread\",\n \"syswrite\",\n \"sysseek\",\n \"zpty\",\n \"ztcp\",\n \"zsocket\",\n \"zf_rm\",\n \"zf_mv\",\n \"zf_ln\",\n \"zf_chmod\",\n \"zf_chown\",\n \"zf_mkdir\",\n \"zf_rmdir\",\n \"zf_chgrp\",\n]);\n\nconst MAX_SUBCOMMANDS = 50;\n\n/**\n * Detect shell injection patterns that embed arbitrary commands inside\n * otherwise safe-looking commands. Returns a reason string if injection\n * is detected, null otherwise.\n */\nexport function detectInjectionPatterns(command: string): string | null {\n if (/>\\(/.test(command)) return \"Output process substitution >(...)\";\n if (/=\\(/.test(command)) return \"Zsh =(...) process substitution\";\n if (/\\$\\{[^}]*[`$]/.test(command)) return \"Nested expansion in ${...}\";\n if (/[\\x00-\\x08\\x0e-\\x1f\\x7f]/.test(command)) return \"Control character injection\";\n // Unicode whitespace that isn't regular space/tab/newline\n if (/[\\u00A0\\u1680\\u2000-\\u200A\\u202F\\u205F\\u3000\\u200B-\\u200D\\uFEFF]/.test(command)) {\n return \"Unicode whitespace injection\";\n }\n if (/\\w#/.test(command) && !/['\"][^'\"]*#/.test(command)) {\n const stripped = command.replace(/'[^']*'/g, \"\").replace(/\"[^\"]*\"/g, \"\");\n if (/\\w#/.test(stripped)) return \"Mid-word comment injection\";\n }\n if (/\\\\n/.test(command)) {\n const stripped = command.replace(/'[^']*'/g, \"\");\n if (/\\$'[^']*\\\\n/.test(stripped)) return \"Escaped newline in $'...' string\";\n }\n return null;\n}\n\n/**\n * Check whether a command contains command substitution or process substitution.\n * These can embed arbitrary commands inside otherwise safe commands.\n */\nfunction hasCommandSubstitution(command: string): boolean {\n return /\\$\\(/.test(command) || /`[^`]+`/.test(command) || /<\\(/.test(command);\n}\n\n/**\n * Check whether a command contains unquoted variable expansion (`$VAR`).\n * Variable expansion can smuggle flags or values into otherwise safe commands\n * (e.g. `git diff $Z--output=/tmp/pwned`). We track quote state to allow\n * `$VAR` inside single quotes (where the shell does not expand).\n */\nfunction hasUnquotedExpansion(command: string): boolean {\n let inSingle = false;\n for (let i = 0; i < command.length; i++) {\n const ch = command[i];\n if (ch === \"'\" && !inSingle) { inSingle = true; continue; }\n if (ch === \"'\" && inSingle) { inSingle = false; continue; }\n if (inSingle) continue;\n if (ch === \"\\\\\" && i + 1 < command.length) { i++; continue; }\n if (ch === \"$\" && i + 1 < command.length) {\n const next = command[i + 1];\n if (next === \"(\") continue; // handled by hasCommandSubstitution\n if (next === \"{\" || (next >= \"A\" && next <= \"Z\") || (next >= \"a\" && next <= \"z\") || next === \"_\") {\n return true;\n }\n }\n }\n return false;\n}\n\nconst WRAPPER_COMMANDS = [\"sudo\", \"env\", \"nohup\", \"time\", \"nice\", \"ionice\", \"strace\", \"ltrace\", \"stdbuf\"];\nconst WRAPPER_WITH_DURATION = new Set([\"timeout\"]);\n\n/**\n * Phase 1: Strip leading env-var assignments (FOO=bar).\n */\nfunction stripEnvVars(cmd: string): string {\n let result = cmd.trim();\n while (/^[A-Za-z_][A-Za-z0-9_]*=\\S*\\s/.test(result)) {\n result = result.replace(/^[A-Za-z_][A-Za-z0-9_]*=\\S*\\s+/, \"\");\n }\n return result;\n}\n\n/**\n * Phase 2: Strip leading wrapper commands (sudo, env, nice, etc.) and their flags.\n */\nfunction stripWrappers(cmd: string): string {\n let result = cmd.trim();\n let prev = \"\";\n while (prev !== result) {\n prev = result;\n for (const prefix of WRAPPER_COMMANDS) {\n if (result.startsWith(prefix + \" \")) {\n result = result.slice(prefix.length).trim();\n while (result.startsWith(\"-\")) {\n const spaceIdx = result.indexOf(\" \");\n if (spaceIdx === -1) break;\n result = result.slice(spaceIdx).trim();\n }\n }\n }\n for (const prefix of WRAPPER_WITH_DURATION) {\n if (result.startsWith(prefix + \" \")) {\n result = result.slice(prefix.length).trim();\n while (result.startsWith(\"-\")) {\n const spaceIdx = result.indexOf(\" \");\n if (spaceIdx === -1) break;\n result = result.slice(spaceIdx).trim();\n }\n // Skip the duration/positional argument\n if (result && !result.startsWith(\"-\")) {\n const spaceIdx = result.indexOf(\" \");\n if (spaceIdx !== -1) {\n result = result.slice(spaceIdx).trim();\n }\n }\n }\n }\n }\n return result;\n}\n\n/**\n * Two-phase prefix stripping: env vars first, then wrappers.\n * Fixed order prevents bypass via interleaved env + wrapper patterns\n * (e.g. `nohup FOO=bar timeout 5 dangerous_cmd`).\n */\nfunction stripPrefixes(command: string): string {\n let cmd = command.trim();\n let prev = \"\";\n while (prev !== cmd) {\n prev = cmd;\n cmd = stripEnvVars(cmd);\n cmd = stripWrappers(cmd);\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 === \"reflog\") {\n const reflogSubcmd = positional[0];\n if (!reflogSubcmd || reflogSubcmd === \"show\" || reflogSubcmd === \"list\") {\n return { isReadOnly: true, isDestructive: false, reason: `git reflog${reflogSubcmd ? \" \" + reflogSubcmd : \"\"} is read-only` };\n }\n if (reflogSubcmd === \"expire\" || reflogSubcmd === \"delete\") {\n return { isReadOnly: false, isDestructive: true, reason: `git reflog ${reflogSubcmd} is destructive` };\n }\n return { isReadOnly: false, isDestructive: false, reason: `git reflog ${reflogSubcmd} is mutating` };\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 // Flag-level safety: reject flags known to cause file writes on\n // otherwise-read-only subcommands (e.g. `git diff --output=FILE`).\n for (const flag of flags) {\n const flagName = flag.split(\"=\")[0];\n if (GIT_READ_ONLY_WRITE_FLAGS.has(flagName)) {\n return { isReadOnly: false, isDestructive: false, reason: `git ${subcommand} with ${flagName} may write files` };\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 // Injection pattern detection (before any other classification)\n const injectionReason = detectInjectionPatterns(command);\n if (injectionReason) {\n return {\n isReadOnly: false,\n isDestructive: true,\n reason: `Injection detected: ${injectionReason}`,\n };\n }\n\n // Zsh dangerous builtins\n if (ZSH_DANGEROUS_COMMANDS.has(name)) {\n return {\n isReadOnly: false,\n isDestructive: true,\n reason: `Zsh dangerous command: ${name}`,\n };\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 // Commands with command substitution or unquoted variable expansion are never read-only\n if (hasCommandSubstitution(command)) {\n return { isReadOnly: false, isDestructive: false, reason: `Command contains command substitution` };\n }\n if (hasUnquotedExpansion(command)) {\n return { isReadOnly: false, isDestructive: false, reason: `Command contains unquoted variable expansion` };\n }\n\n // Commands with dangerous env var prefixes are never read-only\n if (hasDangerousEnvVars(command)) {\n return { isReadOnly: false, isDestructive: false, reason: `Command uses dangerous environment variable prefix` };\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 conditional read-only commands (require flag-level validation)\n const conditionalCheck = CONDITIONAL_READ_ONLY[name];\n if (conditionalCheck) {\n const stripped = stripPrefixes(command).trim();\n const tokens = stripped.split(/\\s+/).slice(1);\n if (conditionalCheck(command, tokens)) {\n return { isReadOnly: true, isDestructive: false, reason: `${name} is read-only (flags validated)` };\n }\n return { isReadOnly: false, isDestructive: false, reason: `${name} has potentially dangerous flags` };\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 > MAX_SUBCOMMANDS) {\n return {\n isReadOnly: false,\n isDestructive: false,\n reason: `Too many subcommands (${subCommands.length} > ${MAX_SUBCOMMANDS})`,\n };\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","import * as path from \"node:path\";\nimport * as fs from \"node:fs\";\nimport type { Tool, ToolContext } from \"../tools/types.js\";\nimport type { AIProvider } from \"../providers/types.js\";\nimport type { ChatMessage } from \"../session/types.js\";\nimport type {\n PermissionContext,\n PermissionDecision,\n PermissionResult,\n AutoModeConfig,\n} from \"./types.js\";\nimport { getMatchingRules, isPathInWorkingDirectories } from \"./rules.js\";\nimport { resolveToolFlag } from \"../tools/registry.js\";\nimport { classifyPermission } from \"./classifier.js\";\nimport type { DenialTracker } from \"./denial-tracking.js\";\nimport { splitCompoundCommand } from \"../tools/shell-safety/command-classification.js\";\nimport {\n extractContentHint,\n resolveAcceptEditsDecision,\n resolveAutoModeDecision,\n} from \"./helpers.js\";\n\nconst DANGEROUS_PATH_PATTERNS = [\n /(?:^|\\/)\\.git(?:\\/|$)/,\n /(?:^|\\/)\\.bashrc$/,\n /(?:^|\\/)\\.bash_profile$/,\n /(?:^|\\/)\\.zshrc$/,\n /(?:^|\\/)\\.zprofile$/,\n /(?:^|\\/)\\.profile$/,\n /(?:^|\\/)\\.ssh(?:\\/|$)/,\n /(?:^|\\/)\\.env$/,\n /(?:^|\\/)\\.npmrc$/,\n /(?:^|\\/)\\.vscode(?:\\/|$)/,\n /(?:^|\\/)\\.idea(?:\\/|$)/,\n /(?:^|\\/)\\.claude(?:\\/|$)/,\n /(?:^|\\/)\\.noumen(?:\\/|$)/,\n /(?:^|\\/)\\.gitconfig$/,\n /(?:^|\\/)\\.gitmodules$/,\n /(?:^|\\/)\\.mcp\\.json$/,\n /(?:^|\\/)\\.ripgreprc$/,\n /(?:^|\\/)\\.noumen\\.json$/,\n];\n\n/**\n * Resolve the permission decision for a tool invocation.\n *\n * Pipeline mirrors claude-code's `hasPermissionsToUseToolInner`:\n * 1. Deny rules for the whole tool\n * 2. Ask rules for the whole tool\n * 3. Tool's own `checkPermissions` (if defined)\n * 4. Mode-based bypass / enforcement\n * 5. Content-specific allow rules\n * 6. Fallback: passthrough → ask\n */\nexport interface ResolvePermissionOptions {\n provider?: AIProvider;\n model?: string;\n recentMessages?: ChatMessage[];\n autoModeConfig?: AutoModeConfig;\n signal?: AbortSignal;\n denialTracker?: DenialTracker;\n}\n\nexport async function resolvePermission(\n tool: Tool,\n input: Record<string, unknown>,\n ctx: ToolContext,\n permCtx: PermissionContext,\n opts?: ResolvePermissionOptions,\n): Promise<PermissionDecision> {\n const toolName = tool.name;\n const contentHint = extractContentHint(tool, input);\n\n // 1. Deny rules for whole tool (no ruleContent)\n const wholeDenyRules = getMatchingRules(\n permCtx,\n toolName,\n \"deny\",\n undefined,\n tool.mcpInfo,\n );\n if (wholeDenyRules.length > 0) {\n return {\n behavior: \"deny\",\n message: `Tool \"${toolName}\" is denied by rule.`,\n reason: \"rule\",\n };\n }\n\n // 1b. Content-specific deny rules\n if (contentHint !== undefined) {\n const contentDenyRules = getMatchingRules(\n permCtx,\n toolName,\n \"deny\",\n contentHint,\n tool.mcpInfo,\n );\n if (contentDenyRules.length > 0) {\n return {\n behavior: \"deny\",\n message: `Tool \"${toolName}\" with \"${contentHint}\" is denied by rule.`,\n reason: \"rule\",\n };\n }\n }\n\n // 2. Ask rules for whole tool\n const wholeAskRules = getMatchingRules(\n permCtx,\n toolName,\n \"ask\",\n undefined,\n tool.mcpInfo,\n );\n if (wholeAskRules.length > 0) {\n return {\n behavior: \"ask\",\n message: `Tool \"${toolName}\" requires approval.`,\n reason: \"rule\",\n };\n }\n\n // 2b. Content-specific ask rules (bypass-immune — user explicitly configured these)\n if (contentHint !== undefined) {\n const contentAskRules = getMatchingRules(\n permCtx,\n toolName,\n \"ask\",\n contentHint,\n tool.mcpInfo,\n );\n if (contentAskRules.length > 0) {\n return {\n behavior: \"ask\",\n message: `Tool \"${toolName}\" with \"${contentHint}\" requires approval.`,\n reason: \"rule\",\n };\n }\n }\n\n // 2c. Dangerous path safety check (bypass-immune)\n const dangerousFilePath =\n typeof input.file_path === \"string\" ? input.file_path\n : typeof input.path === \"string\" ? input.path\n : undefined;\n if (dangerousFilePath && isDangerousPath(dangerousFilePath, ctx.cwd)) {\n return {\n behavior: \"ask\",\n message: `Path \"${dangerousFilePath}\" targets a sensitive location.`,\n reason: \"safetyCheck\",\n };\n }\n\n // 2d. Bash command dangerous path check (bypass-immune)\n if (toolName === \"Bash\" && typeof input.command === \"string\") {\n const subCommands = splitCompoundCommand(input.command);\n for (const sub of subCommands) {\n const tokens = sub.trim().split(/\\s+/);\n for (const token of tokens) {\n if (token.startsWith(\"-\")) continue;\n if (isDangerousPath(token, ctx.cwd)) {\n return {\n behavior: \"ask\",\n message: `Bash command references sensitive path \"${token}\".`,\n reason: \"safetyCheck\",\n };\n }\n }\n }\n }\n\n // 3. Tool's own checkPermissions\n let toolResult: PermissionResult | undefined;\n if (tool.checkPermissions) {\n if (opts?.signal?.aborted) {\n throw new DOMException(\"Aborted\", \"AbortError\");\n }\n try {\n toolResult = await tool.checkPermissions(input, ctx);\n } catch (err) {\n if (err instanceof DOMException && err.name === \"AbortError\") throw err;\n if (err instanceof Error && err.name === \"AbortError\") throw err;\n console.warn(`[noumen/permissions] checkPermissions error for \"${toolName}\":`, err);\n }\n\n if (toolResult?.behavior === \"deny\") {\n return {\n behavior: \"deny\",\n message: toolResult.message,\n reason: toolResult.reason ?? \"tool\",\n };\n }\n if (toolResult?.behavior === \"ask\") {\n const isSafetyCheck = toolResult.reason === \"safetyCheck\";\n const isInteractive = !!tool.requiresUserInteraction;\n\n // Bypass-immune: always prompt regardless of mode\n if (isSafetyCheck || isInteractive) {\n return {\n behavior: \"ask\",\n message: toolResult.message,\n reason: toolResult.reason ?? \"tool\",\n suggestions: toolResult.suggestions,\n };\n }\n\n // bypassPermissions skips the tool ask; all other modes fall through\n // so dontAsk can convert to deny and auto can run the classifier.\n if (permCtx.mode !== \"bypassPermissions\") {\n // toolResult.behavior === \"ask\" is preserved; modes below handle it\n }\n }\n // tool \"allow\" / non-bypass \"ask\" falls through to mode checks\n }\n\n // Prefer any sanitized input the tool produced (e.g. resolved paths),\n // falling back to the raw input when checkPermissions was not defined\n // or returned a variant without updatedInput.\n const effectiveInput =\n (toolResult?.behavior === \"allow\" && toolResult.updatedInput)\n ? toolResult.updatedInput\n : input;\n\n // 3b. Interactive tool guard (bypass-immune)\n if (tool.requiresUserInteraction && permCtx.mode === \"bypassPermissions\") {\n return {\n behavior: \"ask\",\n message: `Tool \"${toolName}\" requires user interaction.`,\n reason: \"interaction\",\n };\n }\n\n // 4. Mode-based bypass / enforcement\n if (permCtx.mode === \"bypassPermissions\") {\n return {\n behavior: \"allow\",\n updatedInput: effectiveInput,\n reason: \"mode\",\n };\n }\n\n const isReadOnly = resolveToolFlag(tool.isReadOnly, input);\n const isDestructive = resolveToolFlag(tool.isDestructive, input);\n\n if (permCtx.mode === \"plan\" && !isReadOnly) {\n return {\n behavior: \"deny\",\n message: `Tool \"${toolName}\" is not allowed in plan mode (read-only).`,\n reason: \"mode\",\n };\n }\n\n if (permCtx.mode === \"acceptEdits\") {\n return resolveAcceptEditsDecision({\n toolName,\n input,\n effectiveInput,\n isReadOnly,\n isDestructive,\n workingDirectories: permCtx.workingDirectories,\n });\n }\n\n // Auto mode: use classifier to decide\n if (permCtx.mode === \"auto\" && opts?.autoModeConfig) {\n if (!opts.provider) {\n return {\n behavior: \"ask\",\n message: `Auto-mode requires an AI provider for classification. Falling back to ask.`,\n reason: \"classifier\",\n };\n }\n\n const classifierResult = await classifyPermission(\n toolName,\n input,\n opts.recentMessages ?? [],\n opts.provider,\n {\n classifierPrompt: opts.autoModeConfig.classifierPrompt,\n classifierModel: opts.autoModeConfig.classifierModel,\n model: opts.model,\n signal: opts.signal,\n },\n );\n\n return resolveAutoModeDecision({\n toolName,\n effectiveInput,\n classifierResult,\n denialTracker: opts.denialTracker,\n requiresUserInteraction: !!tool.requiresUserInteraction,\n });\n }\n\n // Tool's checkPermissions explicitly approved this call and no mode\n // (plan, acceptEdits, auto) overrode it — honor the tool's decision.\n if (toolResult?.behavior === \"allow\") {\n return {\n behavior: \"allow\",\n updatedInput: effectiveInput,\n reason: toolResult.reason ?? \"tool\",\n };\n }\n\n // Read-only tools are auto-allowed in any mode (except when an ask/deny\n // rule explicitly overrode them in steps 1-2 above, or the tool's own\n // checkPermissions returned \"ask\").\n if (isReadOnly && toolResult?.behavior !== \"ask\") {\n return {\n behavior: \"allow\",\n updatedInput: effectiveInput,\n reason: \"readOnly\",\n };\n }\n\n // 4b. Working directory enforcement (before allow rules so they can't\n // bypass cwd restrictions — bypass-immune safety check).\n if (permCtx.workingDirectories.length > 0) {\n const filePath =\n typeof input.file_path === \"string\" ? input.file_path\n : typeof input.path === \"string\" ? input.path\n : undefined;\n if (filePath && !isPathInWorkingDirectories(filePath, permCtx.workingDirectories)) {\n return {\n behavior: \"ask\",\n message: `Path \"${filePath}\" is outside configured working directories.`,\n reason: \"workingDirectory\",\n };\n }\n }\n\n // 5. Content-specific allow rules\n if (contentHint !== undefined) {\n const contentAllowRules = getMatchingRules(\n permCtx,\n toolName,\n \"allow\",\n contentHint,\n tool.mcpInfo,\n );\n if (contentAllowRules.length > 0) {\n return {\n behavior: \"allow\",\n updatedInput: effectiveInput,\n reason: \"rule\",\n };\n }\n }\n\n // Whole-tool allow rules\n const wholeAllowRules = getMatchingRules(\n permCtx,\n toolName,\n \"allow\",\n undefined,\n tool.mcpInfo,\n );\n if (wholeAllowRules.length > 0) {\n return {\n behavior: \"allow\",\n updatedInput: effectiveInput,\n reason: \"rule\",\n };\n }\n\n // If tool raised ask and no mode overrode it, surface the tool's ask\n // (dontAsk is handled as a post-processing step below to also catch\n // passthrough→ask conversions)\n let finalAsk: PermissionDecision | undefined;\n if (toolResult?.behavior === \"ask\") {\n finalAsk = {\n behavior: \"ask\",\n message: toolResult.message,\n reason: toolResult.reason ?? \"tool\",\n suggestions: toolResult.suggestions,\n };\n }\n\n // 6. Fallback: passthrough → ask\n if (!finalAsk) {\n const message =\n toolResult?.behavior === \"passthrough\"\n ? toolResult.message\n : `Tool \"${toolName}\" requires approval.`;\n const suggestions =\n toolResult?.behavior === \"passthrough\"\n ? toolResult.suggestions\n : undefined;\n\n finalAsk = {\n behavior: \"ask\",\n message,\n reason: \"default\",\n suggestions,\n };\n }\n\n // dontAsk mode: deny anything that would prompt. Applied after all\n // ask/passthrough→ask paths so no ask result can leak through.\n if (permCtx.mode === \"dontAsk\") {\n return {\n behavior: \"deny\",\n message: `Tool \"${toolName}\" requires approval, but mode is \"dontAsk\".`,\n reason: \"mode\",\n };\n }\n\n return finalAsk;\n}\n\n// extractContentHint is now imported from ./helpers.js\n\n/**\n * Check whether a file path targets a sensitive location that should always\n * prompt regardless of permission mode (bypass-immune safety check).\n */\nexport function isDangerousPath(filePath: string, basePath?: string): boolean {\n const base = basePath ?? process.cwd();\n const resolved = path.resolve(base, filePath);\n const relative = path.relative(base, resolved);\n const candidate = (relative.startsWith(\"..\") ? resolved.replace(/^\\/+/, \"\") : relative).toLowerCase();\n if (DANGEROUS_PATH_PATTERNS.some((p) => p.test(candidate))) return true;\n\n // Also check symlink-resolved path to prevent symlink-based bypasses\n try {\n const realPath = fs.realpathSync(resolved);\n if (realPath !== resolved) {\n const realRelative = path.relative(base, realPath);\n const realCandidate = (realRelative.startsWith(\"..\") ? realPath.replace(/^\\/+/, \"\") : realRelative).toLowerCase();\n if (DANGEROUS_PATH_PATTERNS.some((p) => p.test(realCandidate))) return true;\n }\n } catch {\n // Path doesn't exist yet — only the logical check applies\n }\n\n return false;\n}\n","import * as nodePath from \"node:path\";\nimport type { Tool, ToolResult, ToolContext } from \"./types.js\";\nimport { WRITE_PROMPT } from \"./prompts/write.js\";\nimport { isDangerousPath } from \"../permissions/pipeline.js\";\nimport { withFileLock } from \"./file-lock.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, ctx) {\n const filePath = args.file_path as string;\n if (filePath.startsWith(\"\\\\\\\\\") || filePath.startsWith(\"//\")) {\n return {\n behavior: \"deny\" as const,\n message: \"Error: UNC paths are not allowed\",\n };\n }\n if (isDangerousPath(filePath, ctx.cwd)) {\n return {\n behavior: \"ask\" as const,\n message: `Write targets sensitive path: ${filePath}`,\n reason: \"safetyCheck\",\n };\n }\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 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 overwriting.`,\n isError: true,\n };\n }\n }\n } catch {\n // stat/read failure — proceed, writeFile will catch real issues\n }\n }\n\n const dir = nodePath.dirname(filePath);\n if (dir && dir !== \".\" && dir !== \"/\") {\n await ctx.fs.mkdir(dir, { recursive: true }).catch(() => {});\n }\n\n // Hold a per-file lock for the write to prevent TOCTOU races when\n // concurrent writes target the same path.\n await withFileLock(filePath, async () => {\n await ctx.fs.writeFile(filePath, content);\n });\n\n ctx.notifyHook?.(\"FileWrite\", {\n event: \"FileWrite\",\n sessionId: ctx.sessionId ?? \"\",\n toolName: \"WriteFile\",\n filePath,\n isNew: !existed,\n }).catch(() => {});\n\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 * 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","/**\n * Per-file async lock to serialize read-modify-write operations.\n *\n * Prevents TOCTOU races where concurrent edits to the same file read the\n * same content and silently overwrite each other's changes.\n */\n\nconst fileLocks = new Map<string, Promise<void>>();\n\n/**\n * Execute `fn` while holding an exclusive lock on `filePath`. Concurrent\n * calls for the same path are serialized; different paths run in parallel.\n */\nexport async function withFileLock<T>(\n filePath: string,\n fn: () => Promise<T>,\n): Promise<T> {\n const prev = fileLocks.get(filePath) ?? Promise.resolve();\n let release!: () => void;\n const lock = new Promise<void>((resolve) => {\n release = resolve;\n });\n fileLocks.set(filePath, lock);\n\n await prev;\n try {\n return await fn();\n } finally {\n release();\n if (fileLocks.get(filePath) === lock) {\n fileLocks.delete(filePath);\n }\n }\n}\n","import * as nodePath from \"node:path\";\nimport type { Tool, ToolResult, ToolContext } from \"./types.js\";\nimport { findActualString, preserveQuoteStyle } from \"./edit-utils.js\";\nimport { EDIT_PROMPT } from \"./prompts/edit.js\";\nimport { isDangerousPath } from \"../permissions/pipeline.js\";\nimport { withFileLock } from \"./file-lock.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, ctx) {\n const filePath = args.file_path as string;\n if (filePath.startsWith(\"\\\\\\\\\") || filePath.startsWith(\"//\")) {\n return {\n behavior: \"deny\" as const,\n message: \"Error: UNC paths are not allowed\",\n };\n }\n if (isDangerousPath(filePath, ctx.cwd)) {\n return {\n behavior: \"ask\" as const,\n message: `Edit targets sensitive path: ${filePath}`,\n reason: \"safetyCheck\",\n };\n }\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 if (oldString === \"\") {\n const exists = await ctx.fs.exists(filePath);\n if (!exists) {\n if (ctx.checkpointManager && ctx.currentMessageId) {\n await ctx.checkpointManager.trackEdit(filePath, ctx.currentMessageId, ctx.sessionId ?? \"\");\n }\n await ctx.fs.writeFile(filePath, newString);\n ctx.notifyHook?.(\"FileWrite\", {\n event: \"FileWrite\", sessionId: ctx.sessionId ?? \"\",\n toolName: \"EditFile\", filePath, isNew: true,\n }).catch(() => {});\n if (ctx.fileStateCache) {\n ctx.fileStateCache.set(filePath, { content: newString, timestamp: Date.now() });\n }\n return { content: `Created new file ${filePath}.` };\n }\n const existing = await ctx.fs.readFile(filePath);\n if (existing.trim() !== \"\") {\n return {\n content: \"Error: old_string is empty but file already has content. Use WriteFile to overwrite, or provide the exact text to replace.\",\n isError: true,\n };\n }\n if (ctx.checkpointManager && ctx.currentMessageId) {\n await ctx.checkpointManager.trackEdit(filePath, ctx.currentMessageId, ctx.sessionId ?? \"\");\n }\n await ctx.fs.writeFile(filePath, newString);\n if (ctx.fileStateCache) {\n ctx.fileStateCache.set(filePath, { content: newString, timestamp: Date.now() });\n }\n return { content: `File ${filePath} has been updated successfully.` };\n }\n\n const MAX_EDIT_FILE_SIZE = 1024 * 1024 * 1024; // 1 GiB\n\n try {\n // File size guard\n try {\n const stat = await ctx.fs.stat(filePath);\n if (stat.size !== undefined && stat.size > MAX_EDIT_FILE_SIZE) {\n return {\n content: `Error: File is too large to edit (${Math.round(stat.size / 1024 / 1024)} MiB). Max: 1 GiB.`,\n isError: true,\n };\n }\n } catch {\n // stat failure — file might not exist, which is fine for creation\n }\n\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 // Ensure parent directory exists before entering the locked section\n const dir = nodePath.dirname(filePath);\n if (dir && dir !== \".\" && dir !== \"/\") {\n await ctx.fs.mkdir(dir, { recursive: true }).catch(() => {});\n }\n\n // Hold a per-file lock for the read-modify-write to prevent TOCTOU\n // races when concurrent edits target the same path.\n const updated = await withFileLock(filePath, async () => {\n const rawContent = await ctx.fs.readFile(filePath);\n const hasCRLF = rawContent.includes(\"\\r\\n\");\n const content = hasCRLF ? rawContent.replaceAll(\"\\r\\n\", \"\\n\") : rawContent;\n\n const actualOldString = findActualString(content, oldString);\n if (!actualOldString) {\n return {\n error: `Error: old_string not found in ${filePath}. Make sure the string matches exactly, including whitespace and indentation.`,\n };\n }\n\n if (!replaceAll) {\n const count = content.split(actualOldString).length - 1;\n if (count > 1) {\n return {\n error: `Error: old_string appears ${count} times in ${filePath}. Provide more context to make it unique, or set replace_all to true.`,\n };\n }\n }\n\n const actualNewString = preserveQuoteStyle(oldString, actualOldString, newString);\n\n let result: string;\n if (replaceAll) {\n result = 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 result = content.replace(deleteTarget, () => actualNewString);\n } else {\n result = content.replace(actualOldString, () => actualNewString);\n }\n\n if (hasCRLF) {\n result = result.replaceAll(\"\\n\", \"\\r\\n\");\n }\n\n await ctx.fs.writeFile(filePath, result);\n return { content: result };\n });\n\n if (\"error\" in updated) {\n return { content: String(updated.error), isError: true };\n }\n\n const editedContent = updated.content as string;\n\n ctx.notifyHook?.(\"FileWrite\", {\n event: \"FileWrite\",\n sessionId: ctx.sessionId ?? \"\",\n toolName: \"EditFile\",\n filePath,\n isNew: false,\n }).catch(() => {});\n\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: editedContent,\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 * 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","/**\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, extractCommandName } 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\nconst NON_ERROR_EXIT1_COMMANDS = new Set([\n \"grep\", \"egrep\", \"fgrep\", \"rg\", \"ag\", \"ack\",\n \"diff\", \"comm\",\n]);\n\nfunction isExpectedNonZeroExit(command: string, exitCode: number): boolean {\n if (exitCode !== 1) return false;\n const name = extractCommandName(command);\n return NON_ERROR_EXIT1_COMMANDS.has(name);\n}\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 headSize = Math.floor(MAX_OUTPUT_CHARS * 0.8);\n const tailSize = MAX_OUTPUT_CHARS - headSize;\n const dropped = output.length - MAX_OUTPUT_CHARS;\n output =\n output.slice(0, headSize) +\n `\\n\\n... ${dropped} chars truncated ...\\n\\n` +\n output.slice(-tailSize);\n }\n\n const isSemanticError = result.exitCode !== 0 &&\n !isExpectedNonZeroExit(command, result.exitCode);\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: isSemanticError,\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","import * as path from \"node:path\";\nimport 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(\"**/\") || path.isAbsolute(pattern)\n ? pattern\n : `**/${pattern}`;\n\n const resolvedPath = searchPath === ctx.cwd ? \".\" : searchPath;\n const command = `rg --files --hidden --glob ${shellEscape(fullPattern)} --sortr=modified ${shellEscape(resolvedPath)} | head -n ${String(MAX_RESULTS + 1)}`;\n\n try {\n let result = await ctx.computer.executeCommand(command, {\n cwd: ctx.cwd,\n });\n\n // rg not installed — fall back to find(1) which is universally available\n if (result.exitCode === 127 || result.stderr?.includes(\"not found\")) {\n const findCommand = `find ${shellEscape(resolvedPath)} -name ${shellEscape(pattern)} -type f | head -n ${String(MAX_RESULTS + 1)}`;\n result = await ctx.computer.executeCommand(findCommand, {\n cwd: ctx.cwd,\n });\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 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","/**\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 \"--hidden\",\n \"--glob\", \"'!.git'\",\n \"--glob\", \"'!.svn'\",\n \"--glob\", \"'!.hg'\",\n \"--glob\", \"'!.bzr'\",\n \"--glob\", \"'!.jj'\",\n \"--glob\", \"'!.sl'\",\n \"--max-columns\", \"500\",\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 const resolvedPath = searchPath === ctx.cwd ? \".\" : searchPath;\n rgArgs.push(\"--\", shellEscape(pattern), shellEscape(resolvedPath));\n\n const command = rgArgs.join(\" \");\n\n try {\n const result = await ctx.computer.executeCommand(command, {\n cwd: ctx.cwd,\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","import * as dns from \"node:dns\";\nimport type { Tool, ToolResult, ToolContext } from \"./types.js\";\nimport { WEB_FETCH_PROMPT } from \"./prompts/web-fetch.js\";\n\nfunction stripWww(hostname: string): string {\n return hostname.replace(/^www\\./, \"\");\n}\n\nconst MAX_CONTENT_LENGTH = 5 * 1024 * 1024;\nconst FETCH_TIMEOUT_MS = 30_000;\nconst MAX_OUTPUT_CHARS = 100_000;\nconst MAX_REDIRECTS = 5;\n\nexport function isPrivateIP(ip: string): boolean {\n const stripped = ip.replace(/^\\[|\\]$/g, \"\");\n\n if (stripped === \"::1\" || stripped === \"0.0.0.0\" || stripped === \"::\") return true;\n\n if (stripped.startsWith(\"fe80:\")) return true;\n\n const firstTwo = stripped.slice(0, 2).toLowerCase();\n if (firstTwo === \"fc\" || firstTwo === \"fd\") return true;\n\n if (stripped.toLowerCase().startsWith(\"::ffff:\")) {\n const embedded = stripped.slice(7);\n return embedded.includes(\".\") ? isPrivateIP(embedded) : true;\n }\n\n const parts = stripped.split(\".\");\n if (parts.length === 4 && parts.every((p) => /^\\d+$/.test(p))) {\n const [a, b] = parts.map(Number);\n if (a === 127) return true;\n if (a === 10) return true;\n if (a === 172 && b >= 16 && b <= 31) return true;\n if (a === 192 && b === 168) return true;\n if (a === 169 && b === 254) return true;\n if (a === 0) return true;\n }\n\n return false;\n}\n\nexport function isPrivateHost(hostname: string): boolean {\n if (\n hostname === \"localhost\" ||\n hostname === \"[::1]\" ||\n hostname === \"0.0.0.0\"\n ) {\n return true;\n }\n\n if (isPrivateIP(hostname)) return true;\n\n if (hostname.startsWith(\"fe80:\") || hostname.startsWith(\"[fe80:\")) return true;\n\n return false;\n}\n\n/**\n * Resolve a hostname via DNS and check that none of the resolved IPs are\n * private. Prevents DNS rebinding attacks where a public hostname resolves\n * to a loopback or RFC-1918 address.\n */\nexport async function checkDnsRebinding(hostname: string): Promise<string | null> {\n if (/^\\d+\\.\\d+\\.\\d+\\.\\d+$/.test(hostname) || hostname.includes(\":\")) {\n return isPrivateIP(hostname) ? hostname : null;\n }\n\n try {\n const addrs = await dns.promises.resolve4(hostname);\n for (const addr of addrs) {\n if (isPrivateIP(addr)) return addr;\n }\n } catch {\n // resolve4 failed — try resolve6\n }\n\n try {\n const addrs6 = await dns.promises.resolve6(hostname);\n for (const addr of addrs6) {\n if (isPrivateIP(addr)) return addr;\n }\n } catch {\n // no AAAA records either — allow (DNS may just not resolve yet)\n }\n\n return null;\n}\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 let parsedUrl: URL;\n try {\n parsedUrl = new URL(url);\n } catch {\n return { content: `Invalid URL: ${url}`, isError: true };\n }\n\n if (parsedUrl.username || parsedUrl.password) {\n return { content: `Blocked: URLs with embedded credentials are not allowed`, isError: true };\n }\n\n if (parsedUrl.protocol === \"http:\") {\n parsedUrl.protocol = \"https:\";\n }\n\n if (isPrivateHost(parsedUrl.hostname)) {\n return { content: `Blocked: \"${parsedUrl.hostname}\" resolves to a private/internal address`, isError: true };\n }\n\n const rebindIP = await checkDnsRebinding(parsedUrl.hostname);\n if (rebindIP) {\n return { content: `Blocked: \"${parsedUrl.hostname}\" resolves to private address ${rebindIP}`, isError: true };\n }\n\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n\n let currentUrl = parsedUrl.toString();\n const originalHost = stripWww(parsedUrl.hostname);\n let response: Response | undefined;\n for (let redirects = 0; redirects <= MAX_REDIRECTS; redirects++) {\n response = await fetch(currentUrl, {\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: \"manual\",\n });\n\n if (response.status >= 300 && response.status < 400) {\n const location = response.headers.get(\"location\");\n if (!location) break;\n const redirectUrl = new URL(location, currentUrl);\n if (stripWww(redirectUrl.hostname) !== originalHost) {\n clearTimeout(timeoutId);\n return { content: `Blocked: redirect to different host \"${redirectUrl.hostname}\" (original: \"${parsedUrl.hostname}\")`, isError: true };\n }\n if (isPrivateHost(redirectUrl.hostname)) {\n clearTimeout(timeoutId);\n return { content: `Blocked: redirect to private/internal address \"${redirectUrl.hostname}\"`, isError: true };\n }\n const redirectRebind = await checkDnsRebinding(redirectUrl.hostname);\n if (redirectRebind) {\n clearTimeout(timeoutId);\n return { content: `Blocked: redirect target \"${redirectUrl.hostname}\" resolves to private address ${redirectRebind}`, isError: true };\n }\n currentUrl = redirectUrl.toString();\n continue;\n }\n break;\n }\n\n clearTimeout(timeoutId);\n\n if (!response || !response.ok) {\n return {\n content: `HTTP ${response?.status ?? \"unknown\"}: ${response?.statusText ?? \"no response\"}`,\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 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","/**\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 let validatedArgs = args;\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 validatedArgs = parsed.data as Record<string, unknown>;\n }\n\n try {\n return await tool.call(validatedArgs, ctx);\n } catch (err) {\n return {\n content: `Error executing ${name}: ${err instanceof Error ? err.message : String(err)}`,\n isError: true,\n };\n }\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","import * as path from \"node:path\";\nimport type { PermissionDecision, PermissionContext } from \"./types.js\";\nimport type { DenialTracker } from \"./denial-tracking.js\";\nimport type { ClassifierResult } from \"./classifier.js\";\nimport type { Tool } from \"../tools/types.js\";\nimport { isPathInWorkingDirectories } from \"./rules.js\";\nimport { extractCommandName, splitCompoundCommand } from \"../tools/shell-safety/command-classification.js\";\n\nconst ACCEPT_EDITS_BASH_ALLOWLIST = new Set([\n \"mkdir\", \"touch\", \"mv\", \"cp\", \"sed\", \"chmod\",\n]);\n\n// ---------------------------------------------------------------------------\n// extractContentHint\n// ---------------------------------------------------------------------------\n\nexport function extractContentHint(\n tool: Tool,\n input: Record<string, unknown>,\n): string | undefined {\n if (typeof input.file_path === \"string\") return input.file_path;\n if (typeof input.command === \"string\") return input.command;\n if (typeof input.path === \"string\") return input.path;\n return undefined;\n}\n\n// ---------------------------------------------------------------------------\n// resolveAcceptEditsDecision\n// ---------------------------------------------------------------------------\n\nexport interface AcceptEditsInput {\n toolName: string;\n input: Record<string, unknown>;\n effectiveInput: Record<string, unknown>;\n isReadOnly: boolean;\n isDestructive: boolean;\n workingDirectories: string[];\n}\n\nexport function resolveAcceptEditsDecision(\n params: AcceptEditsInput,\n): PermissionDecision {\n const { toolName, input, effectiveInput, isReadOnly, isDestructive, workingDirectories } = params;\n\n if (isDestructive) {\n return {\n behavior: \"ask\",\n message: `Tool \"${toolName}\" is destructive and requires approval in acceptEdits mode.`,\n reason: \"mode\",\n };\n }\n\n if (toolName === \"Bash\") {\n const cmd = typeof input.command === \"string\" ? input.command : \"\";\n const subCommands = splitCompoundCommand(cmd);\n for (const sub of subCommands) {\n const baseName = extractCommandName(sub);\n if (!ACCEPT_EDITS_BASH_ALLOWLIST.has(baseName)) {\n return {\n behavior: \"ask\",\n message: `Tool \"${toolName}\" (${baseName}) is not in the acceptEdits allowlist.`,\n reason: \"mode\",\n };\n }\n }\n if (workingDirectories.length > 0) {\n for (const sub of subCommands) {\n const tokens = sub.trim().split(/\\s+/).slice(1);\n for (const token of tokens) {\n if (token.startsWith(\"-\")) continue;\n if (path.isAbsolute(token) && !isPathInWorkingDirectories(token, workingDirectories)) {\n return {\n behavior: \"ask\",\n message: `Bash command references path \"${token}\" outside working directories.`,\n reason: \"workingDirectory\",\n };\n }\n }\n }\n }\n }\n\n if (workingDirectories.length > 0) {\n const filePath =\n typeof input.file_path === \"string\" ? input.file_path\n : typeof input.path === \"string\" ? input.path\n : undefined;\n if (filePath && !isPathInWorkingDirectories(filePath, workingDirectories)) {\n return {\n behavior: \"ask\",\n message: `Path \"${filePath}\" is outside working directories in acceptEdits mode.`,\n reason: \"workingDirectory\",\n };\n }\n }\n\n const hasFilePath = typeof input.file_path === \"string\" || typeof input.path === \"string\";\n if (!isReadOnly && !hasFilePath && toolName !== \"Bash\") {\n return {\n behavior: \"ask\",\n message: `Tool \"${toolName}\" requires approval in acceptEdits mode.`,\n reason: \"mode\",\n };\n }\n\n return {\n behavior: \"allow\",\n updatedInput: effectiveInput,\n reason: \"mode\",\n };\n}\n\n// ---------------------------------------------------------------------------\n// resolveAutoModeDecision\n// ---------------------------------------------------------------------------\n\nexport interface AutoModeInput {\n toolName: string;\n effectiveInput: Record<string, unknown>;\n classifierResult: ClassifierResult;\n denialTracker?: DenialTracker;\n requiresUserInteraction: boolean;\n}\n\nexport function resolveAutoModeDecision(\n params: AutoModeInput,\n): PermissionDecision {\n const { toolName, effectiveInput, classifierResult, denialTracker, requiresUserInteraction } = params;\n\n if (classifierResult.shouldBlock) {\n if (denialTracker) {\n denialTracker.recordDenial();\n const fallback = denialTracker.shouldFallback();\n if (fallback.triggered) {\n if (fallback.reason === \"repeated_consecutive\") {\n return {\n behavior: \"deny\",\n message: `Auto-mode classifier denied too many actions without user approval. Aborting.`,\n reason: \"denial_limit\",\n };\n }\n denialTracker.resetAfterFallback(fallback.reason as \"consecutive\" | \"total\");\n return {\n behavior: \"ask\",\n message: `Auto-mode classifier denied too many consecutive actions. Falling back to user prompt.`,\n reason: \"denial_limit\",\n };\n }\n }\n return {\n behavior: \"deny\",\n message: `Auto-mode classifier flagged this call: ${classifierResult.reason}`,\n reason: \"classifier\",\n };\n }\n\n if (requiresUserInteraction) {\n return {\n behavior: \"ask\",\n message: `Tool \"${toolName}\" requires user interaction.`,\n reason: \"interaction\",\n };\n }\n\n denialTracker?.recordSuccess();\n\n return {\n behavior: \"allow\",\n updatedInput: effectiveInput,\n reason: \"classifier\",\n };\n}\n"],"mappings":"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","names":["parts","matchedTools","path","stripped","path","path","fs","resolve","nodePath","path","MAX_OUTPUT_CHARS","path","path","relative"]}
@@ -0,0 +1,16 @@
1
+ // src/providers/types.ts
2
+ var ChatStreamError = class extends Error {
3
+ status;
4
+ retryAfter;
5
+ constructor(message, opts) {
6
+ super(message, { cause: opts?.cause });
7
+ this.name = "ChatStreamError";
8
+ this.status = opts?.status;
9
+ this.retryAfter = opts?.retryAfter;
10
+ }
11
+ };
12
+
13
+ export {
14
+ ChatStreamError
15
+ };
16
+ //# sourceMappingURL=chunk-L3L3FG5T.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/providers/types.ts"],"sourcesContent":["import type { ChatMessage } from \"../session/types.js\";\nimport type { ThinkingConfig } from \"../thinking/types.js\";\n\nexport interface ToolParameterProperty {\n type: string;\n description?: string;\n enum?: string[];\n default?: unknown;\n minimum?: number;\n maximum?: number;\n}\n\nexport interface ToolDefinition {\n type: \"function\";\n function: {\n name: string;\n description: string;\n parameters: {\n type: \"object\";\n properties: Record<string, ToolParameterProperty>;\n required?: string[];\n };\n };\n}\n\n// Streaming chunk types (OpenAI-compatible)\n\nexport interface ChatStreamDelta {\n role?: \"assistant\";\n content?: string | null;\n thinking_content?: string | null;\n thinking_signature?: string | null;\n /** Opaque data payload for Anthropic redacted_thinking blocks. */\n redacted_thinking_data?: string | null;\n tool_calls?: Array<{\n index: number;\n id?: string;\n type?: \"function\";\n function?: {\n name?: string;\n arguments?: string;\n };\n }>;\n}\n\nexport interface ChatStreamChoice {\n index: number;\n delta: ChatStreamDelta;\n finish_reason: string | null;\n}\n\nexport interface ChatStreamChunk {\n id: string;\n choices: ChatStreamChoice[];\n model: string;\n usage?: {\n prompt_tokens: number;\n completion_tokens: number;\n total_tokens: number;\n cache_read_tokens?: number;\n cache_creation_tokens?: number;\n thinking_tokens?: number;\n };\n}\n\nexport interface ChatCompletionUsage {\n prompt_tokens: number;\n completion_tokens: number;\n total_tokens: number;\n cache_read_tokens?: number;\n cache_creation_tokens?: number;\n thinking_tokens?: number;\n}\n\n/**\n * Structured output format. When provided, the model is constrained to\n * produce a response matching the given JSON schema.\n *\n * - `json_schema`: the model must produce JSON conforming to the given schema.\n * - `json_object`: the model must produce valid JSON (no specific schema).\n */\nexport type OutputFormat = JsonSchemaOutputFormat | JsonObjectOutputFormat;\n\nexport interface JsonSchemaOutputFormat {\n type: \"json_schema\";\n /** JSON Schema object describing the expected output shape. */\n schema: Record<string, unknown>;\n /** Optional name for the schema (required by some providers). */\n name?: string;\n /** When true, the provider enforces strict schema adherence. */\n strict?: boolean;\n}\n\nexport interface JsonObjectOutputFormat {\n type: \"json_object\";\n}\n\nexport interface ChatParams {\n model: string;\n messages: ChatMessage[];\n tools?: ToolDefinition[];\n max_tokens?: number;\n system?: string;\n temperature?: number;\n thinking?: ThinkingConfig;\n /** Constrain the model to produce structured output matching this schema. */\n outputFormat?: OutputFormat;\n /**\n * When true, the provider should place the cache breakpoint on the\n * second-to-last message instead of the last. Used by subagent forks\n * to avoid writing fork-only tails into the shared prompt cache.\n */\n skipCacheWrite?: boolean;\n /** Abort signal — providers should forward this to cancel in-flight HTTP requests. */\n signal?: AbortSignal;\n}\n\nexport interface AIProvider {\n chat(params: ChatParams): AsyncIterable<ChatStreamChunk>;\n}\n\n/**\n * Extended error type that providers can throw to convey retry-relevant metadata.\n * Consumers (like the retry engine) can inspect these fields without knowing\n * provider-specific SDK error types.\n */\nexport class ChatStreamError extends Error {\n status?: number;\n retryAfter?: string;\n\n constructor(\n message: string,\n opts?: { status?: number; retryAfter?: string; cause?: unknown },\n ) {\n super(message, { cause: opts?.cause });\n this.name = \"ChatStreamError\";\n this.status = opts?.status;\n this.retryAfter = opts?.retryAfter;\n }\n}\n"],"mappings":";AA8HO,IAAM,kBAAN,cAA8B,MAAM;AAAA,EACzC;AAAA,EACA;AAAA,EAEA,YACE,SACA,MACA;AACA,UAAM,SAAS,EAAE,OAAO,MAAM,MAAM,CAAC;AACrC,SAAK,OAAO;AACZ,SAAK,SAAS,MAAM;AACpB,SAAK,aAAa,MAAM;AAAA,EAC1B;AACF;","names":[]}