@morphllm/morphsdk 0.2.57 → 0.2.58

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 (158) hide show
  1. package/dist/anthropic-CaFUHxBW.d.ts +89 -0
  2. package/dist/{chunk-6X5UOY7B.js → chunk-2CASO3ZO.js} +46 -79
  3. package/dist/chunk-2CASO3ZO.js.map +1 -0
  4. package/dist/chunk-374N3GIA.js +118 -0
  5. package/dist/chunk-374N3GIA.js.map +1 -0
  6. package/dist/chunk-3IQIT6MC.js +65 -0
  7. package/dist/chunk-3IQIT6MC.js.map +1 -0
  8. package/dist/chunk-4VGOBA2J.js +57 -0
  9. package/dist/chunk-4VGOBA2J.js.map +1 -0
  10. package/dist/chunk-527P5X2E.js +98 -0
  11. package/dist/chunk-527P5X2E.js.map +1 -0
  12. package/dist/chunk-6N6ZYZYD.js +74 -0
  13. package/dist/chunk-6N6ZYZYD.js.map +1 -0
  14. package/dist/chunk-6Y5JB4JC.js +195 -0
  15. package/dist/chunk-6Y5JB4JC.js.map +1 -0
  16. package/dist/{chunk-QFIHUCTF.js → chunk-7EIHYJSG.js} +18 -18
  17. package/dist/chunk-7EIHYJSG.js.map +1 -0
  18. package/dist/{chunk-TICMYDII.js → chunk-APP75CBN.js} +33 -16
  19. package/dist/chunk-APP75CBN.js.map +1 -0
  20. package/dist/chunk-ILJ3J5IA.js +72 -0
  21. package/dist/chunk-ILJ3J5IA.js.map +1 -0
  22. package/dist/chunk-ISWL67SF.js +1 -0
  23. package/dist/chunk-KW7OEGZK.js +9 -0
  24. package/dist/chunk-KW7OEGZK.js.map +1 -0
  25. package/dist/chunk-Q5AHGIQO.js +205 -0
  26. package/dist/chunk-Q5AHGIQO.js.map +1 -0
  27. package/dist/{chunk-TJIUA27P.js → chunk-XT5ZO6ES.js} +9 -5
  28. package/dist/chunk-XT5ZO6ES.js.map +1 -0
  29. package/dist/{chunk-LVPVVLTI.js → chunk-YV75OQTE.js} +105 -17
  30. package/dist/chunk-YV75OQTE.js.map +1 -0
  31. package/dist/{chunk-ZJIIICRA.js → chunk-ZO4PPFCZ.js} +60 -29
  32. package/dist/chunk-ZO4PPFCZ.js.map +1 -0
  33. package/dist/{client-CFoR--IU.d.ts → client-CextMMm9.d.ts} +10 -15
  34. package/dist/client.cjs +687 -341
  35. package/dist/client.cjs.map +1 -1
  36. package/dist/client.d.ts +3 -2
  37. package/dist/client.js +14 -14
  38. package/dist/finish-kXAcUJyB.d.ts +33 -0
  39. package/dist/gemini-CE80Pbdy.d.ts +117 -0
  40. package/dist/index.cjs +700 -341
  41. package/dist/index.cjs.map +1 -1
  42. package/dist/index.d.ts +4 -3
  43. package/dist/index.js +16 -15
  44. package/dist/openai-Fvpqln7F.d.ts +89 -0
  45. package/dist/tools/warp_grep/agent/config.cjs +8 -4
  46. package/dist/tools/warp_grep/agent/config.cjs.map +1 -1
  47. package/dist/tools/warp_grep/agent/config.d.ts +7 -2
  48. package/dist/tools/warp_grep/agent/config.js +1 -1
  49. package/dist/tools/warp_grep/agent/formatter.cjs +32 -15
  50. package/dist/tools/warp_grep/agent/formatter.cjs.map +1 -1
  51. package/dist/tools/warp_grep/agent/formatter.d.ts +1 -1
  52. package/dist/tools/warp_grep/agent/formatter.js +1 -1
  53. package/dist/tools/warp_grep/agent/parser.cjs +104 -17
  54. package/dist/tools/warp_grep/agent/parser.cjs.map +1 -1
  55. package/dist/tools/warp_grep/agent/parser.d.ts +3 -5
  56. package/dist/tools/warp_grep/agent/parser.js +1 -3
  57. package/dist/tools/warp_grep/agent/prompt.cjs +132 -56
  58. package/dist/tools/warp_grep/agent/prompt.cjs.map +1 -1
  59. package/dist/tools/warp_grep/agent/prompt.d.ts +1 -1
  60. package/dist/tools/warp_grep/agent/prompt.js +1 -1
  61. package/dist/tools/warp_grep/agent/runner.cjs +459 -192
  62. package/dist/tools/warp_grep/agent/runner.cjs.map +1 -1
  63. package/dist/tools/warp_grep/agent/runner.d.ts +1 -0
  64. package/dist/tools/warp_grep/agent/runner.js +6 -8
  65. package/dist/tools/warp_grep/agent/types.cjs.map +1 -1
  66. package/dist/tools/warp_grep/agent/types.d.ts +9 -2
  67. package/dist/tools/warp_grep/anthropic.cjs +650 -260
  68. package/dist/tools/warp_grep/anthropic.cjs.map +1 -1
  69. package/dist/tools/warp_grep/anthropic.d.ts +4 -74
  70. package/dist/tools/warp_grep/anthropic.js +13 -15
  71. package/dist/tools/warp_grep/client.cjs +1593 -0
  72. package/dist/tools/warp_grep/client.cjs.map +1 -0
  73. package/dist/tools/warp_grep/client.d.ts +87 -0
  74. package/dist/tools/warp_grep/client.js +26 -0
  75. package/dist/tools/warp_grep/gemini.cjs +1587 -0
  76. package/dist/tools/warp_grep/gemini.cjs.map +1 -0
  77. package/dist/tools/warp_grep/gemini.d.ts +7 -0
  78. package/dist/tools/warp_grep/gemini.js +34 -0
  79. package/dist/tools/warp_grep/harness.cjs +556 -220
  80. package/dist/tools/warp_grep/harness.cjs.map +1 -1
  81. package/dist/tools/warp_grep/harness.d.ts +50 -119
  82. package/dist/tools/warp_grep/harness.js +33 -41
  83. package/dist/tools/warp_grep/harness.js.map +1 -1
  84. package/dist/tools/warp_grep/index.cjs +812 -346
  85. package/dist/tools/warp_grep/index.cjs.map +1 -1
  86. package/dist/tools/warp_grep/index.d.ts +11 -6
  87. package/dist/tools/warp_grep/index.js +43 -22
  88. package/dist/tools/warp_grep/openai.cjs +650 -258
  89. package/dist/tools/warp_grep/openai.cjs.map +1 -1
  90. package/dist/tools/warp_grep/openai.d.ts +4 -74
  91. package/dist/tools/warp_grep/openai.js +13 -13
  92. package/dist/tools/warp_grep/providers/local.cjs +66 -27
  93. package/dist/tools/warp_grep/providers/local.cjs.map +1 -1
  94. package/dist/tools/warp_grep/providers/local.d.ts +4 -9
  95. package/dist/tools/warp_grep/providers/local.js +2 -2
  96. package/dist/tools/warp_grep/providers/remote.cjs +211 -0
  97. package/dist/tools/warp_grep/providers/remote.cjs.map +1 -0
  98. package/dist/tools/warp_grep/providers/remote.d.ts +67 -0
  99. package/dist/tools/warp_grep/providers/remote.js +9 -0
  100. package/dist/tools/warp_grep/providers/types.cjs.map +1 -1
  101. package/dist/tools/warp_grep/providers/types.d.ts +7 -15
  102. package/dist/tools/warp_grep/vercel.cjs +662 -277
  103. package/dist/tools/warp_grep/vercel.cjs.map +1 -1
  104. package/dist/tools/warp_grep/vercel.d.ts +4 -51
  105. package/dist/tools/warp_grep/vercel.js +16 -14
  106. package/dist/types-a_hxdPI6.d.ts +144 -0
  107. package/dist/vercel-3yjvfmVB.d.ts +66 -0
  108. package/package.json +12 -2
  109. package/dist/chunk-6X5UOY7B.js.map +0 -1
  110. package/dist/chunk-73RQWOQC.js +0 -16
  111. package/dist/chunk-73RQWOQC.js.map +0 -1
  112. package/dist/chunk-7OQOOB3R.js +0 -1
  113. package/dist/chunk-CFF636UC.js +0 -70
  114. package/dist/chunk-CFF636UC.js.map +0 -1
  115. package/dist/chunk-EK7OQPWD.js +0 -44
  116. package/dist/chunk-EK7OQPWD.js.map +0 -1
  117. package/dist/chunk-GJ5TYNRD.js +0 -107
  118. package/dist/chunk-GJ5TYNRD.js.map +0 -1
  119. package/dist/chunk-HQO45BAJ.js +0 -14
  120. package/dist/chunk-HQO45BAJ.js.map +0 -1
  121. package/dist/chunk-IMYQOKFO.js +0 -83
  122. package/dist/chunk-IMYQOKFO.js.map +0 -1
  123. package/dist/chunk-KBQWGT5L.js +0 -77
  124. package/dist/chunk-KBQWGT5L.js.map +0 -1
  125. package/dist/chunk-LVPVVLTI.js.map +0 -1
  126. package/dist/chunk-QFIHUCTF.js.map +0 -1
  127. package/dist/chunk-TICMYDII.js.map +0 -1
  128. package/dist/chunk-TJIUA27P.js.map +0 -1
  129. package/dist/chunk-WETRQJGU.js +0 -129
  130. package/dist/chunk-WETRQJGU.js.map +0 -1
  131. package/dist/chunk-ZJIIICRA.js.map +0 -1
  132. package/dist/core-CpkYEi_T.d.ts +0 -158
  133. package/dist/tools/warp_grep/tools/analyse.cjs +0 -40
  134. package/dist/tools/warp_grep/tools/analyse.cjs.map +0 -1
  135. package/dist/tools/warp_grep/tools/analyse.d.ts +0 -10
  136. package/dist/tools/warp_grep/tools/analyse.js +0 -8
  137. package/dist/tools/warp_grep/tools/finish.cjs +0 -69
  138. package/dist/tools/warp_grep/tools/finish.cjs.map +0 -1
  139. package/dist/tools/warp_grep/tools/finish.d.ts +0 -10
  140. package/dist/tools/warp_grep/tools/finish.js +0 -10
  141. package/dist/tools/warp_grep/tools/grep.cjs +0 -38
  142. package/dist/tools/warp_grep/tools/grep.cjs.map +0 -1
  143. package/dist/tools/warp_grep/tools/grep.d.ts +0 -8
  144. package/dist/tools/warp_grep/tools/grep.js +0 -15
  145. package/dist/tools/warp_grep/tools/grep.js.map +0 -1
  146. package/dist/tools/warp_grep/tools/read.cjs +0 -38
  147. package/dist/tools/warp_grep/tools/read.cjs.map +0 -1
  148. package/dist/tools/warp_grep/tools/read.d.ts +0 -9
  149. package/dist/tools/warp_grep/tools/read.js +0 -8
  150. package/dist/tools/warp_grep/utils/format.cjs +0 -42
  151. package/dist/tools/warp_grep/utils/format.cjs.map +0 -1
  152. package/dist/tools/warp_grep/utils/format.d.ts +0 -4
  153. package/dist/tools/warp_grep/utils/format.js +0 -18
  154. package/dist/tools/warp_grep/utils/format.js.map +0 -1
  155. /package/dist/{chunk-7OQOOB3R.js.map → chunk-ISWL67SF.js.map} +0 -0
  156. /package/dist/tools/warp_grep/{tools/analyse.js.map → client.js.map} +0 -0
  157. /package/dist/tools/warp_grep/{tools/finish.js.map → gemini.js.map} +0 -0
  158. /package/dist/tools/warp_grep/{tools/read.js.map → providers/remote.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../tools/warp_grep/harness.ts","../../../tools/warp_grep/agent/parser.ts","../../../tools/warp_grep/agent/formatter.ts","../../../tools/warp_grep/agent/prompt.ts","../../../tools/warp_grep/agent/config.ts","../../../tools/warp_grep/tools/finish.ts","../../../tools/warp_grep/providers/local.ts","../../../tools/warp_grep/utils/ripgrep.ts","../../../tools/warp_grep/utils/paths.ts","../../../tools/warp_grep/utils/files.ts"],"sourcesContent":["/**\n * Warp Grep Harness Primitives\n *\n * Building blocks for custom agent harnesses.\n * Use these when you want to control the agent loop yourself.\n *\n * @example\n * ```typescript\n * import {\n * parseToolCalls,\n * SYSTEM_PROMPT,\n * formatToolResult,\n * formatTurnMessage,\n * formatAnalyseTree,\n * resolveFinishFiles,\n * MAX_TURNS,\n * LocalRipgrepProvider,\n * type ToolCall,\n * type WarpGrepProvider,\n * } from '@morphllm/morphsdk/tools/warp-grep/harness';\n *\n * const provider = new LocalRipgrepProvider(repoRoot);\n * const messages = [\n * { role: 'system', content: SYSTEM_PROMPT },\n * { role: 'user', content: `<query>${query}</query>` },\n * ];\n *\n * for (let turn = 1; turn <= MAX_TURNS; turn++) {\n * const response = await myModel(messages);\n * messages.push({ role: 'assistant', content: response });\n *\n * const toolCalls = parseToolCalls(response);\n * const results: string[] = [];\n *\n * for (const call of toolCalls) {\n * if (call.name === 'finish') {\n * return await resolveFinishFiles(provider, call.arguments.files);\n * }\n *\n * let output: string;\n * if (call.name === 'grep') {\n * const r = await provider.grep(call.arguments);\n * output = r.error || r.lines.join('\\n') || 'no matches';\n * } else if (call.name === 'read') {\n * const r = await provider.read(call.arguments);\n * output = r.error || r.lines.join('\\n') || '(empty)';\n * } else if (call.name === 'analyse') {\n * const entries = await provider.analyse(call.arguments);\n * output = formatAnalyseTree(entries);\n * }\n *\n * results.push(formatToolResult(call.name, call.arguments, output));\n * }\n *\n * messages.push({\n * role: 'user',\n * content: results.join('\\n') + formatTurnMessage(turn)\n * });\n * }\n * ```\n */\n\nimport { LLMResponseParser } from './agent/parser.js';\nimport { formatAgentToolOutput } from './agent/formatter.js';\nimport { SYSTEM_PROMPT } from './agent/prompt.js';\nimport { AGENT_CONFIG, DEFAULT_EXCLUDES } from './agent/config.js';\nimport { readFinishFiles } from './tools/finish.js';\nimport { LocalRipgrepProvider } from './providers/local.js';\nimport type { ToolCall, ToolName, FinishFileSpec, ChatMessage } from './agent/types.js';\nimport type { WarpGrepProvider, GrepResult, ReadResult, AnalyseEntry } from './providers/types.js';\n\n// ════════════════════════════════════════════════════════════════════════════\n// PARSING\n// ════════════════════════════════════════════════════════════════════════════\n\nconst parser = new LLMResponseParser();\n\n/**\n * Parse model output into tool calls.\n * Automatically handles <think> block removal and <tool_call> extraction.\n *\n * @param text - Raw model response text\n * @returns Array of parsed tool calls\n *\n * @example\n * ```typescript\n * const response = `\n * <think>Looking for auth code...</think>\n * <tool_call>grep 'authenticate' src/</tool_call>\n * <tool_call>analyse src/auth</tool_call>\n * `;\n * const calls = parseToolCalls(response);\n * // [{ name: 'grep', arguments: { pattern: 'authenticate', path: 'src/' } },\n * // { name: 'analyse', arguments: { path: 'src/auth' } }]\n * ```\n */\nexport function parseToolCalls(text: string): ToolCall[] {\n return parser.parse(text);\n}\n\n// ════════════════════════════════════════════════════════════════════════════\n// SYSTEM PROMPT\n// ════════════════════════════════════════════════════════════════════════════\n\nexport { SYSTEM_PROMPT };\n\n// ════════════════════════════════════════════════════════════════════════════\n// FORMATTING\n// ════════════════════════════════════════════════════════════════════════════\n\n/**\n * Format tool output with XML wrapper for model consumption.\n * Handles grep, read, analyse with appropriate tags.\n *\n * @param name - Tool name ('grep', 'read', 'analyse')\n * @param args - Tool arguments\n * @param output - Tool output string\n * @param options - Optional settings (isError)\n * @returns Formatted XML string\n *\n * @example\n * ```typescript\n * const formatted = formatToolResult('grep', { pattern: 'auth', path: 'src/' }, 'src/auth.ts:10:function auth()');\n * // <grep_output pattern=\"auth\" path=\"src/\">\n * // src/auth.ts:10:function auth()\n * // </grep_output>\n * ```\n */\nexport function formatToolResult(\n name: string,\n args: Record<string, unknown>,\n output: string,\n options?: { isError?: boolean }\n): string {\n return formatAgentToolOutput(name, args, output, options ?? {});\n}\n\n/**\n * Format turn counter message for the model.\n *\n * @param turn - Current turn number (1-based)\n * @param maxTurns - Maximum turns allowed (default: 4)\n * @returns Turn message string\n *\n * @example\n * ```typescript\n * formatTurnMessage(1); // \"\\n\\n[Turn 1/4] You have 3 turns remaining.\"\n * formatTurnMessage(3); // \"\\n\\n[Turn 3/4] You have 1 turn remaining.\"\n * formatTurnMessage(4); // \"\\n\\n[Turn 4/4] This is your LAST turn. You MUST call finish now.\"\n * ```\n */\nexport function formatTurnMessage(turn: number, maxTurns = 4): string {\n const remaining = maxTurns - turn;\n if (remaining === 0) {\n return `\\n\\n[Turn ${turn}/${maxTurns}] This is your LAST turn. You MUST call finish now.`;\n }\n if (remaining === 1) {\n return `\\n\\n[Turn ${turn}/${maxTurns}] You have 1 turn remaining.`;\n }\n return `\\n\\n[Turn ${turn}/${maxTurns}] You have ${remaining} turns remaining.`;\n}\n\n/**\n * Convert AnalyseEntry[] to tree view string.\n * Matches the format expected by the model.\n *\n * @param entries - Array of analyse entries\n * @returns Tree view string\n *\n * @example\n * ```typescript\n * const entries = [\n * { name: 'src', path: 'src', type: 'dir', depth: 0 },\n * { name: 'index.ts', path: 'src/index.ts', type: 'file', depth: 1 },\n * ];\n * formatAnalyseTree(entries);\n * // \"- [D] src\\n - [F] index.ts\"\n * ```\n */\nexport function formatAnalyseTree(entries: AnalyseEntry[]): string {\n if (!entries.length) return 'empty';\n return entries\n .map((e) => `${' '.repeat(e.depth)}- ${e.type === 'dir' ? '[D]' : '[F]'} ${e.name}`)\n .join('\\n');\n}\n\n// ════════════════════════════════════════════════════════════════════════════\n// FINISH RESOLUTION\n// ════════════════════════════════════════════════════════════════════════════\n\n/**\n * Resolved file with path and content\n */\nexport type ResolvedFile = { path: string; content: string };\n\n/**\n * Resolve finish command - read all specified file ranges.\n *\n * @param provider - WarpGrepProvider implementation\n * @param files - Array of file specs from finish command\n * @returns Array of resolved files with content\n *\n * @example\n * ```typescript\n * const files = [\n * { path: 'src/auth.ts', lines: [[1, 50], [100, 120]] },\n * { path: 'src/types.ts', lines: [[1, 30]] },\n * ];\n * const resolved = await resolveFinishFiles(provider, files);\n * // [{ path: 'src/auth.ts', content: '...' }, { path: 'src/types.ts', content: '...' }]\n * ```\n */\nexport async function resolveFinishFiles(\n provider: WarpGrepProvider,\n files: FinishFileSpec[]\n): Promise<ResolvedFile[]> {\n return readFinishFiles('', files, async (p, s, e) => {\n const r = await provider.read({ path: p, start: s, end: e });\n return r.lines.map((l) => {\n const idx = l.indexOf('|');\n return idx >= 0 ? l.slice(idx + 1) : l;\n });\n });\n}\n\n// ════════════════════════════════════════════════════════════════════════════\n// CONSTANTS\n// ════════════════════════════════════════════════════════════════════════════\n\n/** Maximum turns before forced finish (default: 4) */\nexport const MAX_TURNS = 4;\n\n/** Request timeout in milliseconds */\nexport const TIMEOUT_MS = AGENT_CONFIG.TIMEOUT_MS;\n\n/** Default file/directory exclusions */\nexport { DEFAULT_EXCLUDES };\n\n// ════════════════════════════════════════════════════════════════════════════\n// PROVIDER + TYPES\n// ════════════════════════════════════════════════════════════════════════════\n\nexport { LocalRipgrepProvider };\n\nexport type {\n ToolCall,\n ToolName,\n FinishFileSpec,\n ChatMessage,\n WarpGrepProvider,\n GrepResult,\n ReadResult,\n AnalyseEntry,\n};\n\n","// Parses assistant lines into structured tool calls\nimport type { ToolCall } from './types.js';\n\n// Keep for backwards compatibility - no longer thrown, but exported for tests\nexport class LLMResponseParseError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'LLMResponseParseError';\n }\n}\n\n// Valid tool command names\nconst VALID_COMMANDS = ['analyse', 'grep', 'read', 'finish'];\n\n/**\n * Preprocesses text to handle XML tags:\n * 1. Removes <think>...</think> blocks entirely\n * 2. Extracts content from <tool>...</tool> or <tool_call>...</tool_call> tags\n * 3. Passes through raw tool calls (lines starting with valid commands)\n * 4. Discards unclosed <tool...> tags\n */\nfunction preprocessText(text: string): string[] {\n // Step 1: Remove <think>...</think> blocks (including multiline)\n let processed = text.replace(/<think>[\\s\\S]*?<\\/think>/gi, '');\n \n // Step 2: Check for unclosed <tool or <tool_call tags and discard them\n // Find all opening tags and their positions\n const openingTagRegex = /<tool_call>|<tool>/gi;\n const closingTagRegex = /<\\/tool_call>|<\\/tool>/gi;\n \n // Count opening and closing tags\n const openingMatches = processed.match(openingTagRegex) || [];\n const closingMatches = processed.match(closingTagRegex) || [];\n \n // If there are more opening than closing tags, we have unclosed tags\n // In that case, only process complete tag pairs\n if (openingMatches.length > closingMatches.length) {\n // Remove any content after the last complete closing tag\n const lastClosingMatch = /<\\/tool_call>|<\\/tool>/gi;\n let lastClosingIndex = -1;\n let match;\n while ((match = lastClosingMatch.exec(processed)) !== null) {\n lastClosingIndex = match.index + match[0].length;\n }\n if (lastClosingIndex > 0) {\n processed = processed.slice(0, lastClosingIndex);\n }\n }\n \n // Step 3: Extract content from <tool_call>...</tool_call> and <tool>...</tool> tags\n const toolCallLines: string[] = [];\n const toolTagRegex = /<tool_call>([\\s\\S]*?)<\\/tool_call>|<tool>([\\s\\S]*?)<\\/tool>/gi;\n let tagMatch;\n \n while ((tagMatch = toolTagRegex.exec(processed)) !== null) {\n const content = (tagMatch[1] || tagMatch[2] || '').trim();\n if (content) {\n // Split content by newlines in case there are multiple tool calls in one tag\n const lines = content.split(/\\r?\\n/).map(l => l.trim()).filter(l => l);\n toolCallLines.push(...lines);\n }\n }\n \n // Step 4: Also extract raw tool calls (lines starting with valid commands)\n // This provides backwards compatibility\n const allLines = processed.split(/\\r?\\n/).map(l => l.trim());\n for (const line of allLines) {\n if (!line) continue;\n \n // Skip lines that are inside XML tags (already processed above)\n if (line.startsWith('<')) continue;\n \n // Check if line starts with a valid command\n const firstWord = line.split(/\\s/)[0];\n if (VALID_COMMANDS.includes(firstWord)) {\n // Avoid duplicates\n if (!toolCallLines.includes(line)) {\n toolCallLines.push(line);\n }\n }\n }\n \n return toolCallLines;\n}\n\nexport class LLMResponseParser {\n private readonly finishSpecSplitRe = /,(?=[^,\\s]+:)/;\n\n parse(text: string): ToolCall[] {\n if (typeof text !== 'string') {\n // no way we hit this, but sure, we can throw here\n throw new TypeError('Command text must be a string.');\n }\n \n // Preprocess to handle XML tags\n const lines = preprocessText(text);\n \n const commands: ToolCall[] = [];\n let finishAccumulator: Map<string, number[][]> | null = null;\n\n lines.forEach((line) => {\n if (!line || line.startsWith('#')) return;\n const parts = this.splitLine(line);\n if (parts.length === 0) return;\n const cmd = parts[0];\n switch (cmd) {\n case 'analyse':\n this.handleAnalyse(parts, line, commands);\n break;\n case 'grep':\n this.handleGrep(parts, line, commands);\n break;\n case 'read':\n this.handleRead(parts, line, commands);\n break;\n case 'finish':\n finishAccumulator = this.handleFinish(parts, line, commands, finishAccumulator);\n break;\n default:\n // Silently ignore unknown commands after preprocessing\n // (they might be remnants of XML or other content)\n break;\n }\n });\n\n if (finishAccumulator) {\n const map = finishAccumulator as Map<string, number[][]>;\n const entries = [...map.entries()];\n const filesPayload = entries.map(([path, ranges]) => ({\n path,\n lines: [...ranges].sort((a, b) => a[0] - b[0]) as Array<[number, number]>,\n }));\n commands.push({ name: 'finish', arguments: { files: filesPayload } });\n }\n return commands;\n }\n\n private splitLine(line: string): string[] {\n // Split by whitespace but keep quoted blocks as one\n const parts: string[] = [];\n let current = '';\n let inSingle = false;\n for (let i = 0; i < line.length; i++) {\n const ch = line[i];\n if (ch === \"'\" && line[i - 1] !== '\\\\') {\n inSingle = !inSingle;\n current += ch;\n } else if (!inSingle && /\\s/.test(ch)) {\n if (current) {\n parts.push(current);\n current = '';\n }\n } else {\n current += ch;\n }\n }\n if (current) parts.push(current);\n return parts;\n }\n\n /** Helper to create a _skip tool call with an error message */\n private skip(message: string): ToolCall {\n return { name: '_skip', arguments: { message } };\n }\n\n private handleAnalyse(parts: string[], rawLine: string, commands: ToolCall[]) {\n // analyse <path> [pattern]\n if (parts.length < 2) {\n commands.push(this.skip(\n `[SKIPPED] Your command \"${rawLine}\" is missing a path. ` +\n `Correct format: analyse <path> [pattern]. Example: analyse src/`\n ));\n return;\n }\n const path = parts[1];\n const pattern = parts[2]?.replace(/^\"|\"$/g, '') ?? null;\n commands.push({ name: 'analyse', arguments: { path, pattern } });\n }\n\n // no glob tool in MCP\n\n private handleGrep(parts: string[], rawLine: string, commands: ToolCall[]) {\n // grep '<pattern>' <path>\n if (parts.length < 3) {\n commands.push(this.skip(\n `[SKIPPED] Your command \"${rawLine}\" is missing arguments. ` +\n `Correct format: grep '<pattern>' <path>. Example: grep 'TODO' src/`\n ));\n return;\n }\n let pat = parts[1];\n // Be lenient: accept unquoted patterns by treating the first arg as the pattern\n if (pat.startsWith(\"'\") && pat.endsWith(\"'\")) {\n pat = pat.slice(1, -1);\n }\n // If pattern is empty after processing, skip\n if (!pat) {\n commands.push(this.skip(\n `[SKIPPED] Your command \"${rawLine}\" has an empty pattern. ` +\n `Provide a non-empty search pattern. Example: grep 'function' src/`\n ));\n return;\n }\n commands.push({ name: 'grep', arguments: { pattern: pat, path: parts[2] } });\n }\n\n private handleRead(parts: string[], rawLine: string, commands: ToolCall[]) {\n // read <path>[:start-end]\n if (parts.length < 2) {\n commands.push(this.skip(\n `[SKIPPED] Your command \"${rawLine}\" is missing a path. ` +\n `Correct format: read <path> or read <path>:<start>-<end>. Example: read src/index.ts:1-50`\n ));\n return;\n }\n const spec = parts[1];\n const rangeIdx = spec.indexOf(':');\n if (rangeIdx === -1) {\n commands.push({ name: 'read', arguments: { path: spec } });\n return;\n }\n const filePath = spec.slice(0, rangeIdx);\n const range = spec.slice(rangeIdx + 1);\n const [s, e] = range.split('-').map(v => parseInt(v, 10));\n // If range is invalid, fallback to reading the whole file\n if (!Number.isFinite(s) || !Number.isFinite(e)) {\n commands.push({ name: 'read', arguments: { path: filePath } });\n return;\n }\n commands.push({ name: 'read', arguments: { path: filePath, start: s, end: e } });\n }\n\n private handleFinish(parts: string[], rawLine: string, commands: ToolCall[], acc: Map<string, number[][]> | null) {\n // finish file1:1-10,20-30 file2:5-7\n const map = acc ?? new Map<string, number[][]>();\n const args = parts.slice(1);\n for (const token of args) {\n const [filePath, rangesText] = token.split(':', 2);\n if (!filePath || !rangesText) {\n // Skip this malformed token, continue processing others\n commands.push(this.skip(\n `[SKIPPED] Invalid finish token \"${token}\". ` +\n `Correct format: finish <path>:<start>-<end>. Example: finish src/index.ts:1-50`\n ));\n continue;\n }\n const rangeSpecs = rangesText.split(',').filter(Boolean);\n for (const spec of rangeSpecs) {\n const [s, e] = spec.split('-').map(v => parseInt(v, 10));\n if (!Number.isFinite(s) || !Number.isFinite(e) || e < s) {\n // Skip this invalid range, continue with others\n commands.push(this.skip(\n `[SKIPPED] Invalid range \"${spec}\" in \"${token}\". ` +\n `Ranges must be <start>-<end> where start <= end. Example: 1-50`\n ));\n continue;\n }\n const arr = map.get(filePath) ?? [];\n arr.push([s, e]);\n map.set(filePath, arr);\n }\n }\n return map;\n }\n}\n","export class ToolOutputFormatter {\n\tformat(\n\t\ttoolName: string,\n\t\targs: Record<string, unknown> | null | undefined,\n\t\toutput: string,\n\t\toptions: { isError?: boolean } = {}\n\t): string {\n\t\tconst name = (toolName ?? \"\").trim();\n\t\tif (!name) {\n\t\t\treturn \"\";\n\t\t}\n\t\tconst payload = (output as any)?.toString?.()?.trim?.() ?? \"\";\n\t\tconst isError = Boolean(options.isError);\n\t\tconst safeArgs = args ?? {};\n\n\t\tif (!payload && !isError) {\n\t\t\treturn \"\";\n\t\t}\n\n\t\tswitch (name) {\n\t\t\tcase \"read\":\n\t\t\t\treturn this.formatRead(safeArgs, payload, isError);\n\t\t\tcase \"analyse\":\n\t\t\t\treturn this.formatAnalyse(safeArgs, payload, isError);\n\t\t\tcase \"grep\":\n\t\t\t\treturn this.formatGrep(safeArgs, payload, isError);\n\t\t\tdefault:\n\t\t\t\treturn payload ? `<tool_output>\\n${payload}\\n</tool_output>` : \"\";\n\t\t}\n\t}\n\n\tprivate formatRead(args: Record<string, unknown>, payload: string, isError: boolean): string {\n\t\tif (isError) {\n\t\t\treturn payload;\n\t\t}\n\t\tconst path = this.asString(args.path) || \"...\";\n\t\treturn `<file path=\"${path}\">\\n${payload}\\n</file>`;\n\t}\n\n\tprivate formatAnalyse(args: Record<string, unknown>, payload: string, isError: boolean): string {\n\t\tconst path = this.asString(args.path) || \".\";\n\t\tif (isError) {\n\t\t\treturn `<analyse_results path=\"${path}\" status=\"error\">\\n${payload}\\n</analyse_results>`;\n\t\t}\n\t\treturn `<analyse_results path=\"${path}\">\\n${payload}\\n</analyse_results>`;\n\t}\n\n\tprivate formatGrep(args: Record<string, unknown>, payload: string, isError: boolean): string {\n\t\tconst pattern = this.asString(args.pattern);\n\t\tconst path = this.asString(args.path);\n\t\tconst attributes: string[] = [];\n\t\tif (pattern !== undefined) {\n\t\t\tattributes.push(`pattern=\"${pattern}\"`);\n\t\t}\n\t\tif (path !== undefined) {\n\t\t\tattributes.push(`path=\"${path}\"`);\n\t\t}\n\t\tif (isError) {\n\t\t\tattributes.push('status=\"error\"');\n\t\t}\n\t\tconst attrText = attributes.length ? ` ${attributes.join(\" \")}` : \"\";\n\t\treturn `<grep_output${attrText}>\\n${payload}\\n</grep_output>`;\n\t}\n\n\tprivate asString(value: unknown): string | undefined {\n\t\tif (value === null || value === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn String(value);\n\t}\n}\n\nconst sharedFormatter = new ToolOutputFormatter();\n\nexport function formatAgentToolOutput(\n\ttoolName: string,\n\targs: Record<string, unknown> | null | undefined,\n\toutput: string,\n\toptions: { isError?: boolean } = {}\n): string {\n\treturn sharedFormatter.format(toolName, args, output, options);\n}\n\n","export const SYSTEM_PROMPT = `You are a code search agent. Your task is to find all relevant code for a given query.\n\n<workflow>\nYou have exactly 4 turns. The 4th turn MUST be a \\`finish\\` call. Each turn allows up to 8 parallel tool calls.\n\n- Turn 1: Map the territory OR dive deep (based on query specificity)\n- Turn 2-3: Refine based on findings\n- Turn 4: MUST call \\`finish\\` with all relevant code locations\n- You MAY call \\`finish\\` early if confident—but never before at least 1 search turn.\n\nRemember, if the task feels easy to you, it is strongly desirable to call \\`finish\\` early using fewer turns, but quality over speed.\n</workflow>\n\n<tools>\n### \\`analyse <path> [pattern]\\`\nDirectory tree or file search. Shows structure of a path, optionally filtered by regex pattern.\n- \\`path\\`: Required. Directory or file path (use \\`.\\` for repo root)\n- \\`pattern\\`: Optional regex to filter results\n\nExamples:\n\\`\\`\\`\nanalyse .\nanalyse src/api\nanalyse . \".*\\\\.ts$\"\nanalyse src \"test.*\"\n\\`\\`\\`\n\n### \\`read <path>[:start-end]\\`\nRead file contents. Line range is 1-based, inclusive.\n- Returns numbered lines for easy reference\n- Omit range to read entire file\n\nExamples:\n\\`\\`\\`\nread src/main.py\nread src/db/conn.py:10-50\nread package.json:1-20\n\\`\\`\\`\n\n### \\`grep '<pattern>' <path>\\`\nRipgrep search. Finds pattern matches across files.\n- \\`'<pattern>'\\`: Required. Regex pattern wrapped in single quotes\n- \\`<path>\\`: Required. Directory or file to search (use \\`.\\` for repo root)\n\nExamples:\n\\`\\`\\`\ngrep 'class.*Service' src/\ngrep 'def authenticate' .\ngrep 'import.*from' src/components/\ngrep 'TODO' .\n\\`\\`\\`\n\n### \\`finish <file1:ranges> [file2:ranges ...]\\`\nSubmit final answer with all relevant code locations.\n- Include generous line ranges—don't be stingy with context\n- Ranges are comma-separated: \\`file.py:10-30,50-60\\`\n- ALWAYS include import statements at the top of files (usually lines 1-20)\n- If code spans multiple files, include ALL of them\n- Small files can be returned in full\n\nExamples:\n\\`\\`\\`\nfinish src/auth.py:1-15,25-50,75-80 src/models/user.py:1-10,20-45\nfinish src/index.ts:1-100\n\\`\\`\\`\n</tools>\n\n<strategy>\n**Before your first tool call, classify the query:**\n\n| Query Type | Turn 1 Strategy | Early Finish? |\n|------------|-----------------|---------------|\n| **Specific** (function name, error string, unique identifier) | 8 parallel greps on likely paths | Often by turn 2 |\n| **Conceptual** (how does X work, where is Y handled) | analyse + 2-3 broad greps | Rarely early |\n| **Exploratory** (find all tests, list API endpoints) | analyse at multiple depths | Usually needs 3 turns |\n\n**Parallel call patterns:**\n- **Shotgun grep**: Same pattern, 8 different directories—fast coverage\n- **Variant grep**: 8 pattern variations (synonyms, naming conventions)—catches inconsistent codebases\n- **Funnel**: 1 analyse + 7 greps—orient and search simultaneously\n- **Deep read**: 8 reads on files you already identified—gather full context fast\n</strategy>\n\n<output_format>\nEVERY response MUST follow this exact format:\n\n1. First, wrap your reasoning in \\`<think>...</think>\\` tags containing:\n - Query classification (specific/conceptual/exploratory)\n - Confidence estimate (can I finish in 1-2 turns?)\n - This turn's parallel strategy\n - What signals would let me finish early?\n\n2. Then, output tool calls wrapped in \\`<tool_call>...</tool_call>\\` tags, one per line.\n\nExample:\n\\`\\`\\`\n<think>\nThis is a specific query about authentication. I'll grep for auth-related patterns.\nHigh confidence I can finish in 2 turns if I find the auth module.\nStrategy: Shotgun grep across likely directories.\n</think>\n<tool_call>grep 'authenticate' src/</tool_call>\n<tool_call>grep 'login' src/</tool_call>\n<tool_call>analyse src/auth</tool_call>\n\\`\\`\\`\n\nNo commentary outside \\`<think>\\`. No explanations after tool calls.\n</output_format>\n\n<finishing_requirements>\nWhen calling \\`finish\\`:\n- Include the import section (typically lines 1-20) of each file\n- Include all function/class definitions that are relevant\n- Include any type definitions, interfaces, or constants used\n- Better to over-include than leave the user missing context\n- If unsure about boundaries, include more rather than less\n</finishing_requirements>\n\nBegin your exploration now to find code relevant to the query.`;\n\nexport function getSystemPrompt(): string {\n\treturn SYSTEM_PROMPT;\n}\n","// Agent configuration defaults for morph-warp-grep\n// Hard-coded: SDK does not expose control over rounds or timeout.\nexport const AGENT_CONFIG = {\n // Give the model freedom; failsafe cap to prevent infinite loops\n MAX_ROUNDS: 10,\n TIMEOUT_MS: 30000,\n};\n\n/**\n * Comprehensive exclusion list for directories and files\n * These patterns are used with ripgrep's -g flag\n */\nconst BUILTIN_EXCLUDES = [\n // Version control\n '.git', '.svn', '.hg', '.bzr',\n \n // Dependencies\n 'node_modules', 'bower_components', '.pnpm', '.yarn',\n 'vendor', 'packages', 'Pods', '.bundle',\n \n // Python\n '__pycache__', '.pytest_cache', '.mypy_cache', '.ruff_cache',\n '.venv', 'venv', '.tox', '.nox', '.eggs', '*.egg-info',\n \n // Build outputs\n 'dist', 'build', 'out', 'output', 'target', '_build',\n '.next', '.nuxt', '.output', '.vercel', '.netlify',\n \n // Cache directories\n '.cache', '.parcel-cache', '.turbo', '.nx', '.gradle',\n \n // IDE/Editor\n '.idea', '.vscode', '.vs',\n \n // Coverage\n 'coverage', '.coverage', 'htmlcov', '.nyc_output',\n \n // Temporary\n 'tmp', 'temp', '.tmp', '.temp',\n \n // Lock files\n 'package-lock.json', 'yarn.lock', 'pnpm-lock.yaml', 'bun.lockb',\n 'Cargo.lock', 'Gemfile.lock', 'poetry.lock',\n \n // Binary/minified\n '*.min.js', '*.min.css', '*.bundle.js',\n '*.wasm', '*.so', '*.dll', '*.pyc',\n '*.map', '*.js.map',\n \n // Hidden directories catch-all\n '.*',\n];\n\nexport const DEFAULT_EXCLUDES = (process.env.MORPH_WARP_GREP_EXCLUDE || '')\n .split(',')\n .map(s => s.trim())\n .filter(Boolean)\n .concat(BUILTIN_EXCLUDES);\n\nexport const DEFAULT_MODEL = 'morph-warp-grep';\n\n\n","import type { FinishFileSpec } from '../agent/types.js';\nimport fs from 'fs/promises';\n\nexport function normalizeFinishFiles(files: FinishFileSpec[]): FinishFileSpec[] {\n return files.map((f) => {\n const merged = mergeRanges(f.lines);\n return { path: f.path, lines: merged };\n });\n}\n\nexport async function readFinishFiles(\n repoRoot: string,\n files: FinishFileSpec[],\n reader: (path: string, start: number, end: number) => Promise<string[]>\n): Promise<{ path: string; ranges: Array<[number, number]>; content: string }[]> {\n const out: { path: string; ranges: Array<[number, number]>; content: string }[] = [];\n for (const f of files) {\n const ranges = mergeRanges(f.lines);\n const chunks: string[] = [];\n for (const [s, e] of ranges) {\n const lines = await reader(f.path, s, e);\n chunks.push(lines.join('\\n'));\n }\n out.push({ path: f.path, ranges, content: chunks.join('\\n') });\n }\n return out;\n}\n\nfunction mergeRanges(ranges: Array<[number, number]>): Array<[number, number]> {\n if (!ranges.length) return [];\n const sorted = [...ranges].sort((a, b) => a[0] - b[0]);\n const merged: Array<[number, number]> = [];\n let [cs, ce] = sorted[0];\n for (let i = 1; i < sorted.length; i++) {\n const [s, e] = sorted[i];\n if (s <= ce + 1) {\n ce = Math.max(ce, e);\n } else {\n merged.push([cs, ce]);\n cs = s;\n ce = e;\n }\n }\n merged.push([cs, ce]);\n return merged;\n}\n\n\n","import fs from 'fs/promises';\nimport fssync from 'fs';\nimport path from 'path';\nimport { runRipgrep } from '../utils/ripgrep.js';\nimport { ensureWithinRepo, resolveUnderRepo, toRepoRelative, isSymlink, isTextualFile } from '../utils/paths.js';\nimport type { WarpGrepProvider, GrepResult, ReadResult, AnalyseEntry } from './types.js';\nimport { readAllLines } from '../utils/files.js';\nimport { DEFAULT_EXCLUDES } from '../agent/config.js';\n\nexport class LocalRipgrepProvider implements WarpGrepProvider {\n constructor(private readonly repoRoot: string, private readonly excludes: string[] = DEFAULT_EXCLUDES) {}\n\n async grep(params: { pattern: string; path: string }): Promise<GrepResult> {\n const abs = resolveUnderRepo(this.repoRoot, params.path);\n const stat = await fs.stat(abs).catch(() => null);\n if (!stat) return { lines: [] };\n const targetArg = abs === path.resolve(this.repoRoot) ? '.' : toRepoRelative(this.repoRoot, abs);\n const args = [\n '--no-config',\n '--no-heading',\n '--with-filename',\n '--line-number',\n '--color=never',\n '--trim',\n '--max-columns=400',\n ...this.excludes.flatMap((e) => ['-g', `!${e}`]),\n params.pattern,\n targetArg || '.',\n ];\n const res = await runRipgrep(args, { cwd: this.repoRoot });\n \n // Gracefully handle ripgrep not being available\n if (res.exitCode === -1) {\n return {\n lines: [],\n error: `[RIPGREP NOT AVAILABLE] ripgrep (rg) is required but failed to execute. Please install it:\\n` +\n ` • macOS: brew install ripgrep\\n` +\n ` • Ubuntu/Debian: apt install ripgrep\\n` +\n ` • Windows: choco install ripgrep\\n` +\n ` • Or visit: https://github.com/BurntSushi/ripgrep#installation\\n` +\n `Exit code: ${res.exitCode}${res.stderr ? `\\nDetails: ${res.stderr}` : ''}`,\n };\n }\n \n // Handle other ripgrep errors gracefully\n if (res.exitCode !== 0 && res.exitCode !== 1) {\n return {\n lines: [],\n error: `[RIPGREP ERROR] grep failed with exit code ${res.exitCode}${res.stderr ? `: ${res.stderr}` : ''}`,\n };\n }\n \n const lines = (res.stdout || '')\n .trim()\n .split(/\\r?\\n/)\n .filter((l) => l.length > 0);\n return { lines };\n }\n\n async glob(params: { pattern: string; path: string }): Promise<{ files: string[] }> {\n const abs = resolveUnderRepo(this.repoRoot, params.path);\n const targetArg = abs === path.resolve(this.repoRoot) ? '.' : toRepoRelative(this.repoRoot, abs);\n const args = [\n '--no-config',\n '--files',\n '-g',\n params.pattern,\n ...this.excludes.flatMap((e) => ['-g', `!${e}`]),\n targetArg || '.',\n ];\n const res = await runRipgrep(args, { cwd: this.repoRoot });\n \n // Gracefully handle ripgrep not being available\n if (res.exitCode === -1) {\n // Return empty files with a console warning - glob is less critical than grep\n console.warn(`[warp_grep] ripgrep not available for glob: ${res.stderr || 'execution failed'}`);\n return { files: [] };\n }\n \n const files = (res.stdout || '')\n .trim()\n .split(/\\r?\\n/)\n .filter((l) => l.length > 0);\n return { files };\n }\n\n async read(params: { path: string; start?: number; end?: number }): Promise<ReadResult> {\n const abs = resolveUnderRepo(this.repoRoot, params.path);\n const stat = await fs.stat(abs).catch(() => null);\n \n // Gracefully handle file not found / not a file\n if (!stat || !stat.isFile()) {\n return {\n lines: [],\n error: `[FILE NOT FOUND] You tried to read \"${params.path}\" but there is no file at this path. ` +\n `Double-check the path exists and is spelled correctly.`,\n };\n }\n \n // Gracefully handle symlinks\n if (isSymlink(abs)) {\n return {\n lines: [],\n error: `[SYMLINK] You tried to read \"${params.path}\" but this is a symlink. ` +\n `Try reading the actual file it points to instead.`,\n };\n }\n \n // Gracefully handle non-text or too-large files\n if (!isTextualFile(abs)) {\n return {\n lines: [],\n error: `[UNREADABLE FILE] You tried to read \"${params.path}\" but this file is either too large ` +\n `or not a text file, so it cannot be read. Try a different file.`,\n };\n }\n \n const lines = await readAllLines(abs);\n const total = lines.length;\n let s = params.start ?? 1;\n let e = Math.min(params.end ?? total, total);\n if (s > total && total > 0) {\n // Model hallucinated range - fallback to full file\n s = 1;\n e = total;\n }\n const out: string[] = [];\n for (let i = s; i <= e; i += 1) {\n const content = lines[i - 1] ?? '';\n out.push(`${i}|${content}`);\n }\n return { lines: out };\n }\n\n async analyse(params: { path: string; pattern?: string | null; maxResults?: number; maxDepth?: number }): Promise<AnalyseEntry[]> {\n const abs = resolveUnderRepo(this.repoRoot, params.path);\n const stat = await fs.stat(abs).catch(() => null);\n if (!stat || !stat.isDirectory()) {\n return [];\n }\n const maxResults = params.maxResults ?? 100;\n const maxDepth = params.maxDepth ?? 2;\n const regex = params.pattern ? new RegExp(params.pattern) : null;\n\n const results: AnalyseEntry[] = [];\n async function walk(dir: string, depth: number) {\n if (depth > maxDepth || results.length >= maxResults) return;\n const entries = await fs.readdir(dir, { withFileTypes: true });\n for (const entry of entries) {\n const full = path.join(dir, entry.name);\n const rel = toRepoRelative(abs, full).replace(/^[.][/\\\\]?/, '');\n if (DEFAULT_EXCLUDES.some((ex) => rel.split(path.sep).includes(ex))) continue;\n if (regex && !regex.test(entry.name)) continue;\n if (results.length >= maxResults) break;\n results.push({\n name: entry.name,\n path: toRepoRelative(path.resolve(''), full), // relative display\n type: entry.isDirectory() ? 'dir' : 'file',\n depth,\n });\n if (entry.isDirectory()) {\n await walk(full, depth + 1);\n }\n }\n }\n await walk(abs, 0);\n return results;\n }\n}\n\n\n","import { spawn } from 'child_process';\nimport { rgPath } from '@vscode/ripgrep';\n\nexport type ExecResult = { stdout: string; stderr: string; exitCode: number };\n\n// Cache the working ripgrep path to avoid repeated fallback checks\nlet resolvedRgPath: string | null = null;\nlet rgPathChecked = false;\n\nfunction spawnRg(rgBinary: string, args: string[], opts?: { cwd?: string; env?: NodeJS.ProcessEnv }): Promise<ExecResult> {\n return new Promise((resolve) => {\n const child = spawn(rgBinary, args, {\n cwd: opts?.cwd,\n env: { ...process.env, ...(opts?.env || {}) },\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n let stdout = '';\n let stderr = '';\n child.stdout.on('data', (d) => (stdout += d.toString()));\n child.stderr.on('data', (d) => (stderr += d.toString()));\n child.on('close', (code) => {\n resolve({ stdout, stderr, exitCode: typeof code === 'number' ? code : -1 });\n });\n child.on('error', () => {\n resolve({ stdout: '', stderr: 'Failed to spawn ripgrep.', exitCode: -1 });\n });\n });\n}\n\n// Check if a result indicates a binary compatibility failure (not a normal rg error)\nfunction isBinaryFailure(result: ExecResult): boolean {\n // Spawn error\n if (result.exitCode === -1) return true;\n // jemalloc page size issue (common on ARM64 with non-standard page sizes)\n if (result.stderr.includes('jemalloc') || result.stderr.includes('Unsupported system page size')) return true;\n // SIGABRT (134 = 128 + 6)\n if (result.exitCode === 134) return true;\n return false;\n}\n\nexport async function runRipgrep(args: string[], opts?: { cwd?: string; env?: NodeJS.ProcessEnv }): Promise<ExecResult> {\n // If we've already determined the working path, use it\n if (rgPathChecked && resolvedRgPath) {\n return spawnRg(resolvedRgPath, args, opts);\n }\n\n // First attempt: bundled ripgrep\n if (!rgPathChecked) {\n const result = await spawnRg(rgPath, args, opts);\n \n if (!isBinaryFailure(result)) {\n // Bundled binary works, cache it\n resolvedRgPath = rgPath;\n rgPathChecked = true;\n return result;\n }\n\n // Bundled binary failed, try system rg\n const fallbackResult = await spawnRg('rg', args, opts);\n \n if (!isBinaryFailure(fallbackResult)) {\n // System rg works, cache it\n resolvedRgPath = 'rg';\n rgPathChecked = true;\n return fallbackResult;\n }\n\n // Neither works, mark as checked and return the original error\n rgPathChecked = true;\n return { \n stdout: '', \n stderr: 'Failed to spawn ripgrep. Neither bundled nor system rg is available.', \n exitCode: -1 \n };\n }\n\n // rgPathChecked is true but resolvedRgPath is null - no working rg found\n return { \n stdout: '', \n stderr: 'Failed to spawn ripgrep. Neither bundled nor system rg is available.', \n exitCode: -1 \n };\n}\n\n\n","import fs from 'fs';\nimport path from 'path';\n\nexport function resolveUnderRepo(repoRoot: string, targetPath: string): string {\n const absRoot = path.resolve(repoRoot);\n const resolved = path.resolve(absRoot, targetPath);\n ensureWithinRepo(absRoot, resolved);\n return resolved;\n}\n\nexport function ensureWithinRepo(repoRoot: string, absTarget: string): void {\n const rel = path.relative(path.resolve(repoRoot), path.resolve(absTarget));\n if (rel.startsWith('..') || path.isAbsolute(rel)) {\n throw new Error(`Path outside repository root: ${absTarget}`);\n }\n}\n\nexport function toRepoRelative(repoRoot: string, absPath: string): string {\n return path.relative(path.resolve(repoRoot), path.resolve(absPath));\n}\n\nexport function isSymlink(p: string): boolean {\n try {\n const st = fs.lstatSync(p);\n return st.isSymbolicLink();\n } catch {\n return false;\n }\n}\n\nexport function isTextualFile(filePath: string, maxBytes = 2_000_000): boolean {\n try {\n const st = fs.statSync(filePath);\n if (!st.isFile()) return false;\n if (st.size > maxBytes) return false;\n const fd = fs.openSync(filePath, 'r');\n const buf = Buffer.alloc(512);\n const read = fs.readSync(fd, buf, 0, buf.length, 0);\n fs.closeSync(fd);\n for (let i = 0; i < read; i++) {\n const c = buf[i];\n if (c === 0) return false; // binary heuristic\n }\n return true;\n } catch {\n return false;\n }\n}\n\n\n","import fs from 'fs/promises';\n\nexport async function readAllLines(filePath: string): Promise<string[]> {\n const content = await fs.readFile(filePath, 'utf8');\n // Preserve newlines; split keeping consistency\n return content.split(/\\r?\\n/);\n}\n\n\n"],"mappings":"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","names":["path","path","import_promises","import_path","path","fs","fs","fs","path"]}
1
+ {"version":3,"sources":["../../../tools/warp_grep/harness.ts","../../../tools/warp_grep/agent/parser.ts","../../../tools/warp_grep/agent/prompt.ts","../../../tools/warp_grep/agent/formatter.ts","../../../tools/warp_grep/agent/helpers.ts","../../../tools/warp_grep/agent/config.ts","../../../tools/warp_grep/agent/tools/grep.ts","../../../tools/warp_grep/agent/tools/read.ts","../../../tools/warp_grep/agent/tools/list_directory.ts","../../../tools/warp_grep/agent/tools/finish.ts","../../../tools/warp_grep/providers/local.ts","../../../tools/warp_grep/utils/ripgrep.ts","../../../tools/warp_grep/utils/paths.ts","../../../tools/warp_grep/utils/files.ts"],"sourcesContent":["/**\n * Warp Grep Harness Primitives\n *\n * Building blocks for custom agent harnesses.\n * Use these when you want to control the agent loop yourself.\n *\n * @example\n * ```typescript\n * import {\n * parseToolCalls,\n * SYSTEM_PROMPT,\n * formatToolResult,\n * formatTurnMessage,\n * formatListDirectoryTree,\n * calculateContextBudget,\n * buildInitialState,\n * toolGrep,\n * toolRead,\n * toolListDirectory,\n * resolveFinishFiles,\n * AGENT_CONFIG,\n * LocalRipgrepProvider,\n * type ToolCall,\n * type WarpGrepProvider,\n * } from '@morphllm/morphsdk/tools/warp-grep/harness';\n *\n * const provider = new LocalRipgrepProvider(repoRoot);\n * const messages = [\n * { role: 'system', content: SYSTEM_PROMPT },\n * { role: 'user', content: await buildInitialState(repoRoot, query, provider) },\n * ];\n *\n * for (let turn = 1; turn <= AGENT_CONFIG.MAX_TURNS; turn++) {\n * const response = await myModel(messages);\n * messages.push({ role: 'assistant', content: response });\n *\n * const toolCalls = parseToolCalls(response);\n * const results: string[] = [];\n *\n * for (const call of toolCalls) {\n * if (call.name === 'finish') {\n * return await resolveFinishFiles(provider, call.arguments.files);\n * }\n *\n * let output: string;\n * if (call.name === 'grep') {\n * const r = await toolGrep(provider, call.arguments);\n * output = r.output;\n * } else if (call.name === 'read') {\n * output = await toolRead(provider, call.arguments);\n * } else if (call.name === 'list_directory') {\n * output = await toolListDirectory(provider, call.arguments);\n * }\n *\n * results.push(formatToolResult(call.name, call.arguments, output));\n * }\n *\n * const turnMsg = formatTurnMessage(turn, AGENT_CONFIG.MAX_TURNS);\n * const budget = calculateContextBudget(messages);\n * messages.push({ role: 'user', content: results.join('\\n') + turnMsg + '\\n' + budget });\n * }\n * ```\n */\n\nimport { LLMResponseParser } from './agent/parser.js';\nimport type { ToolCall, ToolName, FinishFileSpec, ChatMessage } from './agent/types.js';\nimport type { WarpGrepProvider, GrepResult, ReadResult, ListDirectoryEntry } from './providers/types.js';\n\n// ════════════════════════════════════════════════════════════════════════════\n// PARSING\n// ════════════════════════════════════════════════════════════════════════════\n\nexport { LLMResponseParser };\n\nconst parser = new LLMResponseParser();\n\nexport function parseToolCalls(text: string): ToolCall[] {\n return parser.parse(text);\n}\n\n// ════════════════════════════════════════════════════════════════════════════\n// SYSTEM PROMPT\n// ════════════════════════════════════════════════════════════════════════════\n\nexport { SYSTEM_PROMPT, getSystemPrompt } from './agent/prompt.js';\n\n// ════════════════════════════════════════════════════════════════════════════\n// FORMATTING\n// ════════════════════════════════════════════════════════════════════════════\n\nexport { formatAgentToolOutput as formatToolResult } from './agent/formatter.js';\n\n// ════════════════════════════════════════════════════════════════════════════\n// HELPERS - same functions runner.ts uses\n// ════════════════════════════════════════════════════════════════════════════\n\nexport {\n formatTurnMessage,\n calculateContextBudget,\n buildInitialState,\n formatListDirectoryTree,\n} from './agent/helpers.js';\n\n// ════════════════════════════════════════════════════════════════════════════\n// TOOL EXECUTORS\n// ════════════════════════════════════════════════════════════════════════════\n\nexport { toolGrep } from './agent/tools/grep.js';\nexport { toolRead } from './agent/tools/read.js';\nexport { toolListDirectory } from './agent/tools/list_directory.js';\nexport { readFinishFiles, normalizeFinishFiles } from './agent/tools/finish.js';\n\n// ════════════════════════════════════════════════════════════════════════════\n// FINISH RESOLUTION (convenience wrapper)\n// ════════════════════════════════════════════════════════════════════════════\n\nimport { readFinishFiles } from './agent/tools/finish.js';\n\nexport type ResolvedFile = { path: string; content: string };\n\nexport async function resolveFinishFiles(\n provider: WarpGrepProvider,\n files: FinishFileSpec[]\n): Promise<ResolvedFile[]> {\n return readFinishFiles('', files, async (p, s, e) => {\n const r = await provider.read({ path: p, start: s, end: e });\n return r.lines.map((l) => {\n const idx = l.indexOf('|');\n return idx >= 0 ? l.slice(idx + 1) : l;\n });\n });\n}\n\n// ════════════════════════════════════════════════════════════════════════════\n// CONFIG + CONSTANTS\n// ════════════════════════════════════════════════════════════════════════════\n\nexport { AGENT_CONFIG, DEFAULT_EXCLUDES } from './agent/config.js';\n\n// ════════════════════════════════════════════════════════════════════════════\n// PROVIDER + TYPES\n// ════════════════════════════════════════════════════════════════════════════\n\nexport { LocalRipgrepProvider } from './providers/local.js';\n\nexport type {\n ToolCall,\n ToolName,\n FinishFileSpec,\n ChatMessage,\n WarpGrepProvider,\n GrepResult,\n ReadResult,\n ListDirectoryEntry,\n};\n","// Parses assistant lines into structured tool calls\nimport type { ToolCall } from './types.js';\n\nconst VALID_COMMANDS = ['list_directory', 'grep', 'read', 'finish'] as const;\ntype ValidCommand = typeof VALID_COMMANDS[number];\n\nfunction isValidCommand(name: string): name is ValidCommand {\n return VALID_COMMANDS.includes(name as ValidCommand);\n}\n\nfunction getXmlElementText(xml: string, tagName: string): string | null {\n const regex = new RegExp(`<${tagName}>([\\\\s\\\\S]*?)</${tagName}>`, 'i');\n const match = xml.match(regex);\n return match ? match[1].trim() : null;\n}\n\nfunction parseNestedXmlTools(text: string): ToolCall[] {\n const tools: ToolCall[] = [];\n \n // Match any XML tool tags - this allows graceful handling of unknown tools\n // that might be added in future versions (they are simply ignored)\n const toolRegex = /<([a-z_][a-z0-9_]*)>([\\s\\S]*?)<\\/\\1>/gi;\n let match;\n \n while ((match = toolRegex.exec(text)) !== null) {\n const rawToolName = match[1].toLowerCase();\n const content = match[2];\n \n // Skip unknown tools silently - enables forward compatibility\n if (!isValidCommand(rawToolName)) continue;\n \n const toolName = rawToolName;\n \n if (toolName === 'list_directory') {\n const path = getXmlElementText(content, 'path');\n const pattern = getXmlElementText(content, 'pattern');\n if (path) {\n tools.push({ name: 'list_directory', arguments: { path, pattern } });\n }\n } else if (toolName === 'grep') {\n const pattern = getXmlElementText(content, 'pattern');\n const subDir = getXmlElementText(content, 'sub_dir');\n const glob = getXmlElementText(content, 'glob');\n if (pattern) {\n tools.push({ \n name: 'grep', \n arguments: { \n pattern, \n path: subDir || '.', \n ...(glob && { glob }) \n } \n });\n }\n } else if (toolName === 'read') {\n const path = getXmlElementText(content, 'path');\n const linesStr = getXmlElementText(content, 'lines');\n if (path) {\n const args: Record<string, unknown> = { path };\n if (linesStr) {\n const ranges: Array<[number, number]> = [];\n for (const rangeStr of linesStr.split(',')) {\n const trimmed = rangeStr.trim();\n if (!trimmed) continue;\n const [s, e] = trimmed.split('-').map(v => parseInt(v.trim(), 10));\n if (Number.isFinite(s) && Number.isFinite(e)) {\n ranges.push([s, e]);\n } else if (Number.isFinite(s)) {\n // Single line like \"100\"\n ranges.push([s, s]);\n }\n }\n if (ranges.length === 1) {\n args.start = ranges[0][0];\n args.end = ranges[0][1];\n } else if (ranges.length > 1) {\n args.lines = ranges;\n }\n }\n tools.push({ name: 'read', arguments: args });\n }\n } else if (toolName === 'finish') {\n // Parse nested <file> elements\n const fileRegex = /<file>([\\s\\S]*?)<\\/file>/gi;\n const files: Array<{ path: string; lines: Array<[number, number]> }> = [];\n let fileMatch;\n \n while ((fileMatch = fileRegex.exec(content)) !== null) {\n const fileContent = fileMatch[1];\n const filePath = getXmlElementText(fileContent, 'path');\n const linesStr = getXmlElementText(fileContent, 'lines');\n \n if (filePath && linesStr) {\n const ranges: Array<[number, number]> = [];\n for (const rangeStr of linesStr.split(',')) {\n if (rangeStr.trim() === '*') {\n ranges.push([1, 999999]); // Entire file\n } else {\n const [s, e] = rangeStr.split('-').map(v => parseInt(v.trim(), 10));\n if (Number.isFinite(s) && Number.isFinite(e)) {\n ranges.push([s, e]);\n }\n }\n }\n if (ranges.length > 0) {\n files.push({ path: filePath, lines: ranges });\n }\n }\n }\n \n if (files.length > 0) {\n tools.push({ name: 'finish', arguments: { files } });\n }\n }\n }\n \n return tools;\n}\n\nfunction preprocessText(text: string): { lines: string[]; nestedTools: ToolCall[] } {\n let processed = text.replace(/<think>[\\s\\S]*?<\\/think>/gi, '');\n const nestedTools = parseNestedXmlTools(processed);\n const openingTagRegex = /<tool_call>|<tool>/gi;\n const closingTagRegex = /<\\/tool_call>|<\\/tool>/gi;\n \n const openingMatches = processed.match(openingTagRegex) || [];\n const closingMatches = processed.match(closingTagRegex) || [];\n \n if (openingMatches.length > closingMatches.length) {\n const lastClosingMatch = /<\\/tool_call>|<\\/tool>/gi;\n let lastClosingIndex = -1;\n let match;\n while ((match = lastClosingMatch.exec(processed)) !== null) {\n lastClosingIndex = match.index + match[0].length;\n }\n if (lastClosingIndex > 0) {\n processed = processed.slice(0, lastClosingIndex);\n }\n }\n const toolCallLines: string[] = [];\n const toolTagRegex = /<tool_call>([\\s\\S]*?)<\\/tool_call>|<tool>([\\s\\S]*?)<\\/tool>/gi;\n let tagMatch;\n \n while ((tagMatch = toolTagRegex.exec(processed)) !== null) {\n const content = (tagMatch[1] || tagMatch[2] || '').trim();\n if (content) {\n const lines = content.split(/\\r?\\n/).map(l => l.trim()).filter(l => l);\n toolCallLines.push(...lines);\n }\n }\n \n // Also extract raw tool calls (lines starting with valid commands)\n const allLines = processed.split(/\\r?\\n/).map(l => l.trim());\n for (const line of allLines) {\n if (!line) continue;\n if (line.startsWith('<')) continue;\n \n const firstWord = line.split(/\\s/)[0];\n if (VALID_COMMANDS.includes(firstWord as ValidCommand)) {\n if (!toolCallLines.includes(line)) {\n toolCallLines.push(line);\n }\n }\n }\n \n return { lines: toolCallLines, nestedTools };\n}\n\nexport class LLMResponseParser {\n private readonly finishSpecSplitRe = /,(?=[^,\\s]+:)/;\n\n parse(text: string): ToolCall[] {\n if (typeof text !== 'string') {\n throw new TypeError('Command text must be a string.');\n }\n \n // Preprocess to handle XML tags\n const { lines, nestedTools } = preprocessText(text);\n \n // Start with nested XML tools (new format)\n const commands: ToolCall[] = [...nestedTools];\n let finishAccumulator: Map<string, number[][]> | null = null;\n\n lines.forEach((line) => {\n if (!line || line.startsWith('#')) return;\n const parts = this.splitLine(line);\n if (parts.length === 0) return;\n const cmd = parts[0];\n \n switch (cmd) {\n case 'list_directory':\n this.handleListDirectory(parts, line, commands);\n break;\n case 'grep':\n this.handleGrep(parts, line, commands);\n break;\n case 'read':\n this.handleRead(parts, line, commands);\n break;\n case 'finish':\n finishAccumulator = this.handleFinish(parts, line, commands, finishAccumulator);\n break;\n default:\n // Silently ignore unknown commands\n break;\n }\n });\n\n if (finishAccumulator) {\n const map = finishAccumulator as Map<string, number[][]>;\n const entries = [...map.entries()];\n const filesPayload = entries.map(([path, ranges]) => ({\n path,\n lines: [...ranges].sort((a, b) => a[0] - b[0]) as Array<[number, number]>,\n }));\n commands.push({ name: 'finish', arguments: { files: filesPayload } });\n }\n return commands;\n }\n\n private splitLine(line: string): string[] {\n // Split by whitespace but keep quoted blocks as one\n const parts: string[] = [];\n let current = '';\n let inSingle = false;\n for (let i = 0; i < line.length; i++) {\n const ch = line[i];\n if (ch === \"'\" && line[i - 1] !== '\\\\') {\n inSingle = !inSingle;\n current += ch;\n } else if (!inSingle && /\\s/.test(ch)) {\n if (current) {\n parts.push(current);\n current = '';\n }\n } else {\n current += ch;\n }\n }\n if (current) parts.push(current);\n return parts;\n }\n\n /** Helper to create a _skip tool call with an error message */\n private skip(message: string): ToolCall {\n return { name: '_skip', arguments: { message } };\n }\n\n private handleListDirectory(parts: string[], rawLine: string, commands: ToolCall[]) {\n // list_directory <path> [pattern]\n if (parts.length < 2) {\n commands.push(this.skip(\n `[SKIPPED] Your command \"${rawLine}\" is missing a path. ` +\n `Correct format: list_directory <path> [pattern]. Example: list_directory src/`\n ));\n return;\n }\n const path = parts[1];\n const pattern = parts[2]?.replace(/^\"|\"$/g, '') ?? null;\n commands.push({ name: 'list_directory', arguments: { path, pattern } });\n }\n\n private handleGrep(parts: string[], rawLine: string, commands: ToolCall[]) {\n // grep '<pattern>' <path>\n if (parts.length < 3) {\n commands.push(this.skip(\n `[SKIPPED] Your command \"${rawLine}\" is missing arguments. ` +\n `Correct format: grep '<pattern>' <path>. Example: grep 'TODO' src/`\n ));\n return;\n }\n let pat = parts[1];\n // Be lenient: accept unquoted patterns by treating the first arg as the pattern\n if (pat.startsWith(\"'\") && pat.endsWith(\"'\")) {\n pat = pat.slice(1, -1);\n }\n // If pattern is empty after processing, skip\n if (!pat) {\n commands.push(this.skip(\n `[SKIPPED] Your command \"${rawLine}\" has an empty pattern. ` +\n `Provide a non-empty search pattern. Example: grep 'function' src/`\n ));\n return;\n }\n commands.push({ name: 'grep', arguments: { pattern: pat, path: parts[2] } });\n }\n\n private handleRead(parts: string[], rawLine: string, commands: ToolCall[]) {\n // read <path>[:start-end]\n if (parts.length < 2) {\n commands.push(this.skip(\n `[SKIPPED] Your command \"${rawLine}\" is missing a path. ` +\n `Correct format: read <path> or read <path>:<start>-<end>. Example: read src/index.ts:1-50`\n ));\n return;\n }\n const spec = parts[1];\n const rangeIdx = spec.indexOf(':');\n if (rangeIdx === -1) {\n commands.push({ name: 'read', arguments: { path: spec } });\n return;\n }\n const filePath = spec.slice(0, rangeIdx);\n const range = spec.slice(rangeIdx + 1);\n const [s, e] = range.split('-').map(v => parseInt(v, 10));\n // If range is invalid, fallback to reading the whole file\n if (!Number.isFinite(s) || !Number.isFinite(e)) {\n commands.push({ name: 'read', arguments: { path: filePath } });\n return;\n }\n commands.push({ name: 'read', arguments: { path: filePath, start: s, end: e } });\n }\n\n private handleFinish(parts: string[], rawLine: string, commands: ToolCall[], acc: Map<string, number[][]> | null) {\n // finish file1:1-10,20-30 file2:5-7\n const map = acc ?? new Map<string, number[][]>();\n const args = parts.slice(1);\n for (const token of args) {\n const [filePath, rangesText] = token.split(':', 2);\n if (!filePath || !rangesText) {\n // Skip this malformed token, continue processing others\n commands.push(this.skip(\n `[SKIPPED] Invalid finish token \"${token}\". ` +\n `Correct format: finish <path>:<start>-<end>. Example: finish src/index.ts:1-50`\n ));\n continue;\n }\n const rangeSpecs = rangesText.split(',').filter(Boolean);\n for (const spec of rangeSpecs) {\n const [s, e] = spec.split('-').map(v => parseInt(v, 10));\n if (!Number.isFinite(s) || !Number.isFinite(e) || e < s) {\n // Skip this invalid range, continue with others\n commands.push(this.skip(\n `[SKIPPED] Invalid range \"${spec}\" in \"${token}\". ` +\n `Ranges must be <start>-<end> where start <= end. Example: 1-50`\n ));\n continue;\n }\n const arr = map.get(filePath) ?? [];\n arr.push([s, e]);\n map.set(filePath, arr);\n }\n }\n return map;\n }\n}\n","export const SYSTEM_PROMPT = `You are a code search agent. Your task is to find all relevant code for a given search_string.\n\n### workflow\nYou have exactly 4 turns. The 4th turn MUST be a \\`finish\\` call. Each turn allows up to 8 parallel tool calls.\n\n- Turn 1: Map the territory OR dive deep (based on search_string specificity)\n- Turn 2-3: Refine based on findings\n- Turn 4: MUST call \\`finish\\` with all relevant code locations\n- You MAY call \\`finish\\` early if confident—but never before at least 1 search turn.\n- The user strongly prefers if you can call the finish tool early, but you must be correct\n\nRemember, if the task feels easy to you, it is strongly desirable to call 'finish' early using fewer turns, but quality over speed\n\n### tools\nTool calls use nested XML elements:\n\\`\\`\\`xml\n<tool_name>\n <parameter>value</parameter>\n</tool_name>\n\\`\\`\\`\n\n### \\`list_directory\\`\nDirectory tree view. Shows structure of a path, optionally filtered by regex pattern.\n\nElements:\n- \\`<path>\\` (required): Directory path to list (use \\`.\\` for repo root)\n- \\`<pattern>\\` (optional): Regex to filter results\n\nExamples:\n\\`\\`\\`\n<list_directory>\n <path>src/services</path>\n</list_directory>\n\n<list_directory>\n <path>lib/utils</path>\n <pattern>.*\\\\.(ts|js)$</pattern>\n</list_directory>\n\\`\\`\\`\n\n### \\`read\\`\nRead file contents. Supports multiple line ranges.\n- Returns numbered lines for easy reference\n- ALWAYS include import statements (usually lines 1-20). Better to over-include than miss context.\n\nElements:\n- \\`<path>\\` (required): File path to read\n- \\`<lines>\\` (optional): Line ranges like \"1-50,75-80,100-120\" (omit to read entire file)\n\nExamples:\n\\`\\`\\`\n<read>\n <path>src/main.py</path>\n</read>\n\n<read>\n <path>src/auth.py</path>\n <lines>1-20,45-80,150-200</lines>\n</read>\n\\`\\`\\`\n\n### \\`grep\\`\nSearch for pattern matches across files. Returns matches with 1 line of context above and below.\n- Match lines use \\`:\\` separator → \\`filepath:linenum:content\\`\n- Context lines use \\`-\\` separator → \\`filepath-linenum-content\\`\n\nElements:\n- \\`<pattern>\\` (required): Search pattern (regex). Use \\`(a|b)\\` for OR patterns.\n- \\`<sub_dir>\\` (optional): Subdirectory to search in (defaults to \\`.\\`)\n- \\`<glob>\\` (optional): File pattern filter like \\`*.py\\` or \\`*.{ts,tsx}\\`\n\nExamples:\n\\`\\`\\`\n<grep>\n <pattern>(authenticate|authorize|login)</pattern>\n <sub_dir>src/auth/</sub_dir>\n</grep>\n\n<grep>\n <pattern>class.*(Service|Controller)</pattern>\n <glob>*.{ts,js}</glob>\n</grep>\n\n<grep>\n <pattern>(DB_HOST|DATABASE_URL|connection)</pattern>\n <glob>*.{py,yaml,env}</glob>\n <sub_dir>lib/</sub_dir>\n</grep>\n\\`\\`\\`\n\n### \\`finish\\`\nSubmit final answer with all relevant code locations. Uses nested \\`<file>\\` elements.\n\nFile elements:\n- \\`<path>\\` (required): File path\n- \\`<lines>\\` (optional): Line ranges like \"1-50,75-80\" (\\`*\\` for entire file)\n\nALWAYS include import statements (usually lines 1-20). Better to over-include than miss context.\n\nExamples:\n\\`\\`\\`\n<finish>\n <file>\n <path>src/auth.py</path>\n <lines>1-15,25-50,75-80</lines>\n </file>\n <file>\n <path>src/models/user.py</path>\n <lines>*</lines>\n </file>\n</finish>\n\\`\\`\\`\n</tools>\n\n<strategy>\n**Before your first tool call, classify the search_string:**\n\n| Search_string Type | Round 1 Strategy | Early Finish? |\n|------------|------------------|---------------|\n| **Specific** (function name, error string, unique identifier) | 8 parallel greps on likely paths | Often by round 2 |\n| **Conceptual** (how does X work, where is Y handled) | list_directory + 2-3 broad greps | Rarely early |\n| **Exploratory** (find all tests, list API endpoints) | list_directory at multiple depths | Usually needs 3 rounds |\n\n**Parallel call patterns:**\n- **Shotgun grep**: Same pattern, 8 different directories—fast coverage\n- **Variant grep**: 8 pattern variations (synonyms, naming conventions)—catches inconsistent codebases\n- **Funnel**: 1 list_directory + 7 greps—orient and search simultaneously\n- **Deep read**: 8 reads on files you already identified—gather full context fast\n\n**Tool call expectations:**\n- Low quality tool calls are ones that give back sparse information. This either means they are not well thought out and are not educated guesses OR, they are too broad and give back too many results.\n- High quality tool calls strike a balance between complexity in the tool call to exclude results we know we don't want, and how wide the search space is so that we don't miss anything. It is ok to start off with wider search spaces, but is imperative that you use your intuition from there on out and seek high quality tool calls only.\n- You are not starting blind, you have some information about root level repo structure going in, so use that to prevent making trivial repo wide queries.\n- The grep tool shows you which file path and line numbers the pattern was found in, use this information smartly when trying to read the file.\n</strategy>\n\n<output_format>\nEVERY response MUST follow this exact format:\n\n1. First, wrap your reasoning in \\`<think>...</think>\\` tags containing:\n - Search_string classification (specific/conceptual/exploratory)\n - Confidence estimate (can I finish in 1-2 rounds?)\n - This round's parallel strategy\n - What signals would let me finish early?\n\n2. Then, output up to 8 tool calls using nested XML elements.\n\nExample:\n\\`\\`\\`\n<think>\nThis is a specific search_string about authentication. I'll grep for auth-related patterns.\nHigh confidence I can finish in 2 rounds if I find the auth module. I have already been shown the repo's structure at root\nStrategy: Shotgun grep across likely directories.\n</think>\n<grep>\n <pattern>(authenticate|login|session)</pattern>\n <sub_dir>src/auth/</sub_dir>\n</grep>\n<grep>\n <pattern>(middleware|interceptor)</pattern>\n <glob>*.{ts,js}</glob>\n</grep>\n<list_directory>\n <path>src/auth</path>\n</list_directory>\n\\`\\`\\`\n\nFinishing example:\n\\`\\`\\`\n<think>\nI think I have a rough idea, but this is my last turn so I must call the finish tool regardless.\n</think>\n<finish>\n <file>\n <path>src/auth/login.py</path>\n <lines>1-50</lines>\n </file>\n <file>\n <path>src/middleware/session.py</path>\n <lines>10-80</lines>\n </file>\n</finish>\n\\`\\`\\`\n\nNo commentary outside \\`<think>\\`. No explanations after tool calls.\n</output_format>\n\n<finishing_requirements>\nWhen calling \\`finish\\`:\n- Include the import section (typically lines 1-20) of each file\n- Include all function/class definitions that are relevant\n- Include any type definitions, interfaces, or constants used\n- Better to over-include than leave the user missing context\n- If unsure about boundaries, include more rather than less\n</finishing_requirements>`;\n\nexport function getSystemPrompt(): string {\n return SYSTEM_PROMPT;\n}\n","export class ToolOutputFormatter {\n\tformat(\n\t\ttoolName: string,\n\t\targs: Record<string, unknown> | null | undefined,\n\t\toutput: string,\n\t\toptions: { isError?: boolean } = {}\n\t): string {\n\t\tconst name = (toolName ?? \"\").trim();\n\t\tif (!name) {\n\t\t\treturn \"\";\n\t\t}\n\t\tconst payload = (output as any)?.toString?.()?.trim?.() ?? \"\";\n\t\tconst isError = Boolean(options.isError);\n\t\tconst safeArgs = args ?? {};\n\n\t\tif (!payload && !isError) {\n\t\t\treturn \"\";\n\t\t}\n\n\t\tswitch (name) {\n\t\t\tcase \"read\":\n\t\t\t\treturn this.formatRead(safeArgs, payload, isError);\n\t\t\tcase \"list_directory\":\n\t\t\t\treturn this.formatListDirectory(safeArgs, payload, isError);\n\t\t\tcase \"grep\":\n\t\t\t\treturn this.formatGrep(safeArgs, payload, isError);\n\t\t\tdefault:\n\t\t\t\treturn payload ? `<tool_output>\\n${payload}\\n</tool_output>` : \"\";\n\t\t}\n\t}\n\n\tprivate formatRead(args: Record<string, unknown>, payload: string, isError: boolean): string {\n\t\tif (isError) {\n\t\t\treturn payload;\n\t\t}\n\t\tconst path = this.asString(args.path) || \"...\";\n\t\tconst start = args.start as number | undefined;\n\t\tconst end = args.end as number | undefined;\n\t\tconst linesArray = args.lines as Array<[number, number]> | undefined;\n\t\tconst attributes: string[] = [`path=\"${path}\"`];\n\t\tif (linesArray && linesArray.length > 0) {\n\t\t\tconst rangeStr = linesArray.map(([s, e]) => `${s}-${e}`).join(',');\n\t\t\tattributes.push(`lines=\"${rangeStr}\"`);\n\t\t} else if (start !== undefined && end !== undefined) {\n\t\t\tattributes.push(`lines=\"${start}-${end}\"`);\n\t\t}\n\t\treturn `<read ${attributes.join(\" \")}>\\n${payload}\\n</read>`;\n\t}\n\n\tprivate formatListDirectory(args: Record<string, unknown>, payload: string, isError: boolean): string {\n\t\tconst path = this.asString(args.path) || \".\";\n\t\tconst pattern = this.asString(args.pattern);\n\t\tconst attributes: string[] = [`path=\"${path}\"`];\n\t\tif (pattern) {\n\t\t\tattributes.push(`pattern=\"${pattern}\"`);\n\t\t}\n\t\tif (isError) {\n\t\t\tattributes.push('status=\"error\"');\n\t\t}\n\t\treturn `<list_directory ${attributes.join(\" \")}>\\n${payload}\\n</list_directory>`;\n\t}\n\n\tprivate formatGrep(args: Record<string, unknown>, payload: string, isError: boolean): string {\n\t\tconst pattern = this.asString(args.pattern);\n\t\tconst subDir = this.asString(args.path);\n\t\tconst glob = this.asString(args.glob);\n\t\tconst attributes: string[] = [];\n\t\tif (pattern !== undefined) {\n\t\t\tattributes.push(`pattern=\"${pattern}\"`);\n\t\t}\n\t\tif (subDir !== undefined) {\n\t\t\tattributes.push(`sub_dir=\"${subDir}\"`);\n\t\t}\n\t\tif (glob !== undefined) {\n\t\t\tattributes.push(`glob=\"${glob}\"`);\n\t\t}\n\t\tif (isError) {\n\t\t\tattributes.push('status=\"error\"');\n\t\t}\n\t\tconst attrText = attributes.length ? ` ${attributes.join(\" \")}` : \"\";\n\t\treturn `<grep${attrText}>\\n${payload}\\n</grep>`;\n\t}\n\n\tprivate asString(value: unknown): string | undefined {\n\t\tif (value === null || value === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn String(value);\n\t}\n}\n\nconst sharedFormatter = new ToolOutputFormatter();\n\nexport function formatAgentToolOutput(\n\ttoolName: string,\n\targs: Record<string, unknown> | null | undefined,\n\toutput: string,\n\toptions: { isError?: boolean } = {}\n): string {\n\treturn sharedFormatter.format(toolName, args, output, options);\n}\n\n","/**\n * Shared helper functions for warp-grep agent loop.\n * Used by both the internal runner and exported for harness users.\n */\n\nimport path from 'path';\nimport { AGENT_CONFIG } from './config.js';\nimport type { ChatMessage } from './types.js';\nimport type { WarpGrepProvider, ListDirectoryEntry } from '../providers/types.js';\n\nconst TRUNCATED_MARKER = '[truncated for context limit]';\n\n/**\n * Format the turn counter message shown to the model.\n */\nexport function formatTurnMessage(turnsUsed: number, maxTurns: number): string {\n const turnsRemaining = maxTurns - turnsUsed;\n if (turnsRemaining === 1) {\n return `\\nYou have used ${turnsUsed} turns, you only have 1 turn remaining. You have run out of turns to explore the code base and MUST call the finish tool now`;\n }\n return `\\nYou have used ${turnsUsed} turn${turnsUsed === 1 ? '' : 's'} and have ${turnsRemaining} remaining`;\n}\n\n/**\n * Calculate and format the context budget indicator.\n */\nexport function calculateContextBudget(messages: ChatMessage[]): string {\n const totalChars = messages.reduce((sum, m) => sum + m.content.length, 0);\n const maxChars = AGENT_CONFIG.MAX_CONTEXT_CHARS;\n const percent = Math.round((totalChars / maxChars) * 100);\n const usedK = Math.round(totalChars / 1000);\n const maxK = Math.round(maxChars / 1000);\n return `<context_budget>${percent}% (${usedK}K/${maxK}K chars)</context_budget>`;\n}\n\n/**\n * Build the initial state message containing repo structure and query.\n */\nexport async function buildInitialState(\n repoRoot: string,\n query: string,\n provider: WarpGrepProvider\n): Promise<string> {\n try {\n const entries = await provider.listDirectory({\n path: '.',\n maxResults: AGENT_CONFIG.MAX_OUTPUT_LINES,\n maxDepth: 2,\n });\n const treeLines = entries.map((e) => {\n const indent = ' '.repeat(e.depth);\n const name = e.type === 'dir' ? `${e.name}/` : e.name;\n return `${indent}${name}`;\n });\n\n const repoName = path.basename(repoRoot);\n const treeOutput =\n treeLines.length > 0 ? `${repoName}/\\n${treeLines.join('\\n')}` : `${repoName}/`;\n\n return `<repo_structure>\\n${treeOutput}\\n</repo_structure>\\n\\n<search_string>\\n${query}\\n</search_string>`;\n } catch {\n const repoName = path.basename(repoRoot);\n return `<repo_structure>\\n${repoName}/\\n</repo_structure>\\n\\n<search_string>\\n${query}\\n</search_string>`;\n }\n}\n\n/**\n * Format directory entries as an indented tree string.\n */\nexport function formatListDirectoryTree(entries: ListDirectoryEntry[]): string {\n if (!entries.length) return 'empty';\n return entries\n .map((e) => {\n const indent = ' '.repeat(e.depth);\n const name = e.type === 'dir' ? `${e.name}/` : e.name;\n return `${indent}${name}`;\n })\n .join('\\n');\n}\n\n/**\n * Enforce hard context limit by truncating user messages.\n * Preserves system prompt, first user message (initial query), and all assistant messages.\n * Removes tool result user messages from oldest to newest until under the threshold.\n * \n * @param messages - The conversation messages array (mutated in place)\n * @param maxChars - Maximum total character count (defaults to AGENT_CONFIG.MAX_CONTEXT_CHARS)\n * @returns The same messages array, truncated if necessary\n */\nexport function enforceContextLimit(\n messages: ChatMessage[],\n maxChars: number = AGENT_CONFIG.MAX_CONTEXT_CHARS\n): ChatMessage[] {\n const getTotalChars = () => messages.reduce((sum, m) => sum + m.content.length, 0);\n \n if (getTotalChars() <= maxChars) {\n return messages;\n }\n\n // Find indices of user messages, skipping the first one (initial query with repo structure)\n // We truncate tool result messages from oldest to newest\n const userIndices: number[] = [];\n let firstUserSkipped = false;\n for (let i = 0; i < messages.length; i++) {\n if (messages[i].role === 'user') {\n if (!firstUserSkipped) {\n firstUserSkipped = true;\n continue; // Skip first user message (contains the search query)\n }\n userIndices.push(i);\n }\n }\n\n // Truncate user messages from oldest to newest until under limit\n for (const idx of userIndices) {\n if (getTotalChars() <= maxChars) {\n break;\n }\n // Only truncate if not already truncated\n if (messages[idx].content !== TRUNCATED_MARKER) {\n messages[idx] = { role: 'user', content: TRUNCATED_MARKER };\n }\n }\n\n return messages;\n}\n\n","export const AGENT_CONFIG = {\n MAX_TURNS: 4,\n TIMEOUT_MS: 30_000,\n MAX_CONTEXT_CHARS: 540_000,\n MAX_OUTPUT_LINES: 200,\n MAX_READ_LINES: 800,\n MAX_LIST_DEPTH: 3,\n LIST_TIMEOUT_MS: 2_000,\n};\n\n/**\n * Comprehensive exclusion list for directories and files\n * These patterns are used with ripgrep's -g flag\n */\nconst BUILTIN_EXCLUDES = [\n // Version control\n '.git', '.svn', '.hg', '.bzr',\n \n // Dependencies\n 'node_modules', 'bower_components', '.pnpm', '.yarn',\n 'vendor', 'packages', 'Pods', '.bundle',\n \n // Python\n '__pycache__', '.pytest_cache', '.mypy_cache', '.ruff_cache',\n '.venv', 'venv', '.tox', '.nox', '.eggs', '*.egg-info',\n \n // Build outputs\n 'dist', 'build', 'out', 'output', 'target', '_build',\n '.next', '.nuxt', '.output', '.vercel', '.netlify',\n \n // Cache directories\n '.cache', '.parcel-cache', '.turbo', '.nx', '.gradle',\n \n // IDE/Editor\n '.idea', '.vscode', '.vs',\n \n // Coverage\n 'coverage', '.coverage', 'htmlcov', '.nyc_output',\n \n // Temporary\n 'tmp', 'temp', '.tmp', '.temp',\n \n // Lock files\n 'package-lock.json', 'yarn.lock', 'pnpm-lock.yaml', 'bun.lockb',\n 'Cargo.lock', 'Gemfile.lock', 'poetry.lock',\n \n // Binary/minified\n '*.min.js', '*.min.css', '*.bundle.js',\n '*.wasm', '*.so', '*.dll', '*.pyc',\n '*.map', '*.js.map',\n \n // Hidden directories catch-all\n '.*',\n];\n\nexport const DEFAULT_EXCLUDES = (process.env.MORPH_WARP_GREP_EXCLUDE || '')\n .split(',')\n .map(s => s.trim())\n .filter(Boolean)\n .concat(BUILTIN_EXCLUDES);\n\nexport const DEFAULT_MODEL = 'morph-warp-grep-v1';\n\n\n","import type { WarpGrepProvider } from '../../providers/types.js';\n\nexport async function toolGrep(\n provider: WarpGrepProvider,\n args: { pattern: string; path: string; glob?: string }\n): Promise<{ output: string }> {\n const res = await provider.grep(args);\n \n // Return errors as output - let the model see and handle them\n if (res.error) {\n return { output: res.error };\n }\n \n if (!res.lines.length) {\n return { output: 'no matches' };\n }\n \n return { output: res.lines.join('\\n') };\n}\n\n","import type { WarpGrepProvider } from '../../providers/types.js';\n\nexport async function toolRead(\n provider: WarpGrepProvider,\n args: { path: string; start?: number; end?: number; lines?: Array<[number, number]> }\n): Promise<string> {\n if (args.lines && args.lines.length > 0) {\n const chunks: string[] = [];\n for (const [start, end] of args.lines) {\n const res = await provider.read({ path: args.path, start, end });\n if (res.error) return res.error;\n chunks.push(res.lines.join('\\n'));\n }\n if (chunks.every(c => c === '')) return '(empty file)';\n return chunks.join('\\n...\\n');\n }\n\n const res = await provider.read({ path: args.path, start: args.start, end: args.end });\n if (res.error) {\n return res.error;\n }\n if (!res.lines.length) return '(empty file)';\n return res.lines.join('\\n');\n}\n\n","import type { WarpGrepProvider } from '../../providers/types.js';\nimport { AGENT_CONFIG } from '../config.js';\n\nexport async function toolListDirectory(\n provider: WarpGrepProvider,\n args: { path: string; pattern?: string | null; maxResults?: number; maxDepth?: number }\n): Promise<string> {\n const list = await provider.listDirectory({\n path: args.path,\n pattern: args.pattern ?? null,\n maxResults: args.maxResults ?? AGENT_CONFIG.MAX_OUTPUT_LINES,\n maxDepth: args.maxDepth ?? AGENT_CONFIG.MAX_LIST_DEPTH,\n });\n \n if (!list.length) return 'empty';\n if (list.length >= AGENT_CONFIG.MAX_OUTPUT_LINES) {\n return 'query not specific enough, tool called tried to return too much context and failed';\n }\n return list\n .map((e) => {\n const indent = ' '.repeat(e.depth);\n const name = e.type === 'dir' ? `${e.name}/` : e.name;\n return `${indent}${name}`;\n })\n .join('\\n');\n}\n\n","import type { FinishFileSpec } from '../types.js';\n\nexport function normalizeFinishFiles(files: FinishFileSpec[]): FinishFileSpec[] {\n return files.map((f) => {\n const merged = mergeRanges(f.lines);\n return { path: f.path, lines: merged };\n });\n}\n\nexport async function readFinishFiles(\n repoRoot: string,\n files: FinishFileSpec[],\n reader: (path: string, start: number, end: number) => Promise<string[]>\n): Promise<{ path: string; ranges: Array<[number, number]>; content: string }[]> {\n const out: { path: string; ranges: Array<[number, number]>; content: string }[] = [];\n for (const f of files) {\n const ranges = mergeRanges(f.lines);\n const chunks: string[] = [];\n for (const [s, e] of ranges) {\n const lines = await reader(f.path, s, e);\n chunks.push(lines.join('\\n'));\n }\n out.push({ path: f.path, ranges, content: chunks.join('\\n') });\n }\n return out;\n}\n\nfunction mergeRanges(ranges: Array<[number, number]>): Array<[number, number]> {\n if (!ranges.length) return [];\n const sorted = [...ranges].sort((a, b) => a[0] - b[0]);\n const merged: Array<[number, number]> = [];\n let [cs, ce] = sorted[0];\n for (let i = 1; i < sorted.length; i++) {\n const [s, e] = sorted[i];\n if (s <= ce + 1) {\n ce = Math.max(ce, e);\n } else {\n merged.push([cs, ce]);\n cs = s;\n ce = e;\n }\n }\n merged.push([cs, ce]);\n return merged;\n}\n\n","import fs from 'fs/promises';\nimport fssync from 'fs';\nimport path from 'path';\nimport { runRipgrep } from '../utils/ripgrep.js';\nimport { ensureWithinRepo, resolveUnderRepo, toRepoRelative, isSymlink, isTextualFile } from '../utils/paths.js';\nimport type { WarpGrepProvider, GrepResult, ReadResult, ListDirectoryEntry } from './types.js';\nimport { readAllLines } from '../utils/files.js';\nimport { DEFAULT_EXCLUDES, AGENT_CONFIG } from '../agent/config.js';\n\nexport class LocalRipgrepProvider implements WarpGrepProvider {\n constructor(private readonly repoRoot: string, private readonly excludes: string[] = DEFAULT_EXCLUDES) {}\n\n async grep(params: { pattern: string; path: string; glob?: string }): Promise<GrepResult> {\n let abs: string;\n try {\n abs = resolveUnderRepo(this.repoRoot, params.path);\n } catch (err) {\n return {\n lines: [],\n error: `[PATH ERROR] ${err instanceof Error ? err.message : String(err)}`,\n };\n }\n const stat = await fs.stat(abs).catch(() => null);\n if (!stat) return { lines: [] };\n const targetArg = abs === path.resolve(this.repoRoot) ? '.' : toRepoRelative(this.repoRoot, abs);\n const args = [\n '--no-config',\n '--no-heading',\n '--with-filename',\n '--line-number',\n '--color=never',\n '--trim',\n '--max-columns=400',\n '-C', '1',\n ...(params.glob ? ['--glob', params.glob] : []),\n ...this.excludes.flatMap((e) => ['-g', `!${e}`]),\n params.pattern,\n targetArg || '.',\n ];\n const res = await runRipgrep(args, { cwd: this.repoRoot });\n \n // Gracefully handle ripgrep not being available\n if (res.exitCode === -1) {\n return {\n lines: [],\n error: `[RIPGREP NOT AVAILABLE] ripgrep (rg) is required but failed to execute. Please install it:\\n` +\n ` • macOS: brew install ripgrep\\n` +\n ` • Ubuntu/Debian: apt install ripgrep\\n` +\n ` • Windows: choco install ripgrep\\n` +\n ` • Or visit: https://github.com/BurntSushi/ripgrep#installation\\n` +\n `Exit code: ${res.exitCode}${res.stderr ? `\\nDetails: ${res.stderr}` : ''}`,\n };\n }\n \n // Handle other ripgrep errors gracefully\n if (res.exitCode !== 0 && res.exitCode !== 1) {\n return {\n lines: [],\n error: `[RIPGREP ERROR] grep failed with exit code ${res.exitCode}${res.stderr ? `: ${res.stderr}` : ''}`,\n };\n }\n \n const lines = (res.stdout || '')\n .trim()\n .split(/\\r?\\n/)\n .filter((l) => l.length > 0);\n if (lines.length > AGENT_CONFIG.MAX_OUTPUT_LINES) {\n return {\n lines: [],\n error: 'query not specific enough, tool tried to return too much context and failed',\n };\n }\n \n return { lines };\n }\n\n async read(params: { path: string; start?: number; end?: number }): Promise<ReadResult> {\n let abs: string;\n try {\n abs = resolveUnderRepo(this.repoRoot, params.path);\n } catch (err) {\n return {\n lines: [],\n error: `[PATH ERROR] ${err instanceof Error ? err.message : String(err)}`,\n };\n }\n const stat = await fs.stat(abs).catch(() => null);\n \n // Gracefully handle file not found / not a file\n if (!stat || !stat.isFile()) {\n return {\n lines: [],\n error: `[FILE NOT FOUND] You tried to read \"${params.path}\" but there is no file at this path. ` +\n `Double-check the path exists and is spelled correctly.`,\n };\n }\n \n // Gracefully handle symlinks\n if (isSymlink(abs)) {\n return {\n lines: [],\n error: `[SYMLINK] You tried to read \"${params.path}\" but this is a symlink. ` +\n `Try reading the actual file it points to instead.`,\n };\n }\n \n // Gracefully handle non-text or too-large files\n if (!isTextualFile(abs)) {\n return {\n lines: [],\n error: `[UNREADABLE FILE] You tried to read \"${params.path}\" but this file is either too large ` +\n `or not a text file, so it cannot be read. Try a different file.`,\n };\n }\n \n let lines: string[];\n try {\n lines = await readAllLines(abs);\n } catch (err) {\n return {\n lines: [],\n error: `[READ ERROR] Failed to read \"${params.path}\": ${err instanceof Error ? err.message : String(err)}`,\n };\n }\n const total = lines.length;\n let s = params.start ?? 1;\n let e = Math.min(params.end ?? total, total);\n if (s > total && total > 0) {\n // Model hallucinated range - fallback to full file\n s = 1;\n e = total;\n }\n const out: string[] = [];\n for (let i = s; i <= e; i += 1) {\n const content = lines[i - 1] ?? '';\n out.push(`${i}|${content}`);\n }\n if (out.length > AGENT_CONFIG.MAX_READ_LINES) {\n const truncated = out.slice(0, AGENT_CONFIG.MAX_READ_LINES);\n truncated.push(`... [truncated: showing ${AGENT_CONFIG.MAX_READ_LINES} of ${out.length} lines]`);\n return { lines: truncated };\n }\n \n return { lines: out };\n }\n\n async listDirectory(params: { path: string; pattern?: string | null; maxResults?: number; maxDepth?: number }): Promise<ListDirectoryEntry[]> {\n let abs: string;\n try {\n abs = resolveUnderRepo(this.repoRoot, params.path);\n } catch {\n // Path outside repo - return empty (graceful failure)\n return [];\n }\n const stat = await fs.stat(abs).catch(() => null);\n if (!stat || !stat.isDirectory()) {\n return [];\n }\n const maxResults = params.maxResults ?? AGENT_CONFIG.MAX_OUTPUT_LINES;\n const maxDepth = params.maxDepth ?? AGENT_CONFIG.MAX_LIST_DEPTH;\n const regex = params.pattern ? new RegExp(params.pattern) : null;\n\n const results: ListDirectoryEntry[] = [];\n let timedOut = false;\n const startTime = Date.now();\n \n async function walk(dir: string, depth: number) {\n if (Date.now() - startTime > AGENT_CONFIG.LIST_TIMEOUT_MS) {\n timedOut = true;\n return;\n }\n if (depth > maxDepth || results.length >= maxResults) return;\n const entries = await fs.readdir(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (timedOut || results.length >= maxResults) break;\n const full = path.join(dir, entry.name);\n const rel = toRepoRelative(abs, full).replace(/^[.][/\\\\]?/, '');\n if (DEFAULT_EXCLUDES.some((ex) => rel.split(path.sep).includes(ex))) continue;\n if (regex && !regex.test(entry.name)) continue;\n results.push({\n name: entry.name,\n path: toRepoRelative(path.resolve(''), full), // relative display\n type: entry.isDirectory() ? 'dir' : 'file',\n depth,\n });\n if (entry.isDirectory()) {\n await walk(full, depth + 1);\n }\n }\n }\n await walk(abs, 0);\n return results;\n }\n}\n\n\n","import { spawn } from 'child_process';\nimport { rgPath } from '@vscode/ripgrep';\n\nexport type ExecResult = { stdout: string; stderr: string; exitCode: number };\n\n// Cache the working ripgrep path to avoid repeated fallback checks\nlet resolvedRgPath: string | null = null;\nlet rgPathChecked = false;\n\nfunction spawnRg(rgBinary: string, args: string[], opts?: { cwd?: string; env?: NodeJS.ProcessEnv }): Promise<ExecResult> {\n return new Promise((resolve) => {\n const child = spawn(rgBinary, args, {\n cwd: opts?.cwd,\n env: { ...process.env, ...(opts?.env || {}) },\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n let stdout = '';\n let stderr = '';\n child.stdout.on('data', (d) => (stdout += d.toString()));\n child.stderr.on('data', (d) => (stderr += d.toString()));\n child.on('close', (code) => {\n resolve({ stdout, stderr, exitCode: typeof code === 'number' ? code : -1 });\n });\n child.on('error', () => {\n resolve({ stdout: '', stderr: 'Failed to spawn ripgrep.', exitCode: -1 });\n });\n });\n}\n\n// Check if a result indicates a binary compatibility failure (not a normal rg error)\nfunction isBinaryFailure(result: ExecResult): boolean {\n // Spawn error\n if (result.exitCode === -1) return true;\n // jemalloc page size issue (common on ARM64 with non-standard page sizes)\n if (result.stderr.includes('jemalloc') || result.stderr.includes('Unsupported system page size')) return true;\n // SIGABRT (134 = 128 + 6)\n if (result.exitCode === 134) return true;\n return false;\n}\n\nexport async function runRipgrep(args: string[], opts?: { cwd?: string; env?: NodeJS.ProcessEnv }): Promise<ExecResult> {\n // If we've already determined the working path, use it\n if (rgPathChecked && resolvedRgPath) {\n return spawnRg(resolvedRgPath, args, opts);\n }\n\n // First attempt: bundled ripgrep\n if (!rgPathChecked) {\n const result = await spawnRg(rgPath, args, opts);\n \n if (!isBinaryFailure(result)) {\n // Bundled binary works, cache it\n resolvedRgPath = rgPath;\n rgPathChecked = true;\n return result;\n }\n\n // Bundled binary failed, try system rg\n const fallbackResult = await spawnRg('rg', args, opts);\n \n if (!isBinaryFailure(fallbackResult)) {\n // System rg works, cache it\n resolvedRgPath = 'rg';\n rgPathChecked = true;\n return fallbackResult;\n }\n\n // Neither works, mark as checked and return the original error\n rgPathChecked = true;\n return { \n stdout: '', \n stderr: 'Failed to spawn ripgrep. Neither bundled nor system rg is available.', \n exitCode: -1 \n };\n }\n\n // rgPathChecked is true but resolvedRgPath is null - no working rg found\n return { \n stdout: '', \n stderr: 'Failed to spawn ripgrep. Neither bundled nor system rg is available.', \n exitCode: -1 \n };\n}\n\n\n","import fs from 'fs';\nimport path from 'path';\n\nexport function resolveUnderRepo(repoRoot: string, targetPath: string): string {\n const absRoot = path.resolve(repoRoot);\n const resolved = path.resolve(absRoot, targetPath);\n ensureWithinRepo(absRoot, resolved);\n return resolved;\n}\n\nexport function ensureWithinRepo(repoRoot: string, absTarget: string): void {\n const rel = path.relative(path.resolve(repoRoot), path.resolve(absTarget));\n if (rel.startsWith('..') || path.isAbsolute(rel)) {\n throw new Error(`Path outside repository root: ${absTarget}`);\n }\n}\n\nexport function toRepoRelative(repoRoot: string, absPath: string): string {\n return path.relative(path.resolve(repoRoot), path.resolve(absPath));\n}\n\nexport function isSymlink(p: string): boolean {\n try {\n const st = fs.lstatSync(p);\n return st.isSymbolicLink();\n } catch {\n return false;\n }\n}\n\nexport function isTextualFile(filePath: string, maxBytes = 2_000_000): boolean {\n try {\n const st = fs.statSync(filePath);\n if (!st.isFile()) return false;\n if (st.size > maxBytes) return false;\n const fd = fs.openSync(filePath, 'r');\n const buf = Buffer.alloc(512);\n const read = fs.readSync(fd, buf, 0, buf.length, 0);\n fs.closeSync(fd);\n for (let i = 0; i < read; i++) {\n const c = buf[i];\n if (c === 0) return false; // binary heuristic\n }\n return true;\n } catch {\n return false;\n }\n}\n\n\n","import fs from 'fs/promises';\n\nexport async function readAllLines(filePath: string): Promise<string[]> {\n const content = await fs.readFile(filePath, 'utf8');\n // Preserve newlines; split keeping consistency\n return content.split(/\\r?\\n/);\n}\n\n\n"],"mappings":"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","names":["path","path","path","res","import_promises","import_path","import_path","path","fs","fs","fs","path"]}
@@ -1,10 +1,36 @@
1
- export { SYSTEM_PROMPT } from './agent/prompt.js';
2
- export { DEFAULT_EXCLUDES } from './agent/config.js';
3
- export { LocalRipgrepProvider } from './providers/local.js';
4
- import { ToolCall, FinishFileSpec } from './agent/types.js';
5
- export { ChatMessage, ToolName } from './agent/types.js';
6
- import { AnalyseEntry, WarpGrepProvider } from './providers/types.js';
1
+ export { LLMResponseParser } from './agent/parser.js';
2
+ import { ChatMessage, ToolCall, FinishFileSpec } from './agent/types.js';
3
+ export { ToolName } from './agent/types.js';
4
+ import { WarpGrepProvider, ListDirectoryEntry } from './providers/types.js';
7
5
  export { GrepResult, ReadResult } from './providers/types.js';
6
+ export { SYSTEM_PROMPT, getSystemPrompt } from './agent/prompt.js';
7
+ export { formatAgentToolOutput as formatToolResult } from './agent/formatter.js';
8
+ export { n as normalizeFinishFiles, r as readFinishFiles, t as toolGrep, b as toolListDirectory, a as toolRead } from '../../finish-kXAcUJyB.js';
9
+ export { AGENT_CONFIG, DEFAULT_EXCLUDES } from './agent/config.js';
10
+ export { LocalRipgrepProvider } from './providers/local.js';
11
+ import '../utils/resilience.js';
12
+
13
+ /**
14
+ * Shared helper functions for warp-grep agent loop.
15
+ * Used by both the internal runner and exported for harness users.
16
+ */
17
+
18
+ /**
19
+ * Format the turn counter message shown to the model.
20
+ */
21
+ declare function formatTurnMessage(turnsUsed: number, maxTurns: number): string;
22
+ /**
23
+ * Calculate and format the context budget indicator.
24
+ */
25
+ declare function calculateContextBudget(messages: ChatMessage[]): string;
26
+ /**
27
+ * Build the initial state message containing repo structure and query.
28
+ */
29
+ declare function buildInitialState(repoRoot: string, query: string, provider: WarpGrepProvider): Promise<string>;
30
+ /**
31
+ * Format directory entries as an indented tree string.
32
+ */
33
+ declare function formatListDirectoryTree(entries: ListDirectoryEntry[]): string;
8
34
 
9
35
  /**
10
36
  * Warp Grep Harness Primitives
@@ -19,9 +45,14 @@ export { GrepResult, ReadResult } from './providers/types.js';
19
45
  * SYSTEM_PROMPT,
20
46
  * formatToolResult,
21
47
  * formatTurnMessage,
22
- * formatAnalyseTree,
48
+ * formatListDirectoryTree,
49
+ * calculateContextBudget,
50
+ * buildInitialState,
51
+ * toolGrep,
52
+ * toolRead,
53
+ * toolListDirectory,
23
54
  * resolveFinishFiles,
24
- * MAX_TURNS,
55
+ * AGENT_CONFIG,
25
56
  * LocalRipgrepProvider,
26
57
  * type ToolCall,
27
58
  * type WarpGrepProvider,
@@ -30,10 +61,10 @@ export { GrepResult, ReadResult } from './providers/types.js';
30
61
  * const provider = new LocalRipgrepProvider(repoRoot);
31
62
  * const messages = [
32
63
  * { role: 'system', content: SYSTEM_PROMPT },
33
- * { role: 'user', content: `<query>${query}</query>` },
64
+ * { role: 'user', content: await buildInitialState(repoRoot, query, provider) },
34
65
  * ];
35
66
  *
36
- * for (let turn = 1; turn <= MAX_TURNS; turn++) {
67
+ * for (let turn = 1; turn <= AGENT_CONFIG.MAX_TURNS; turn++) {
37
68
  * const response = await myModel(messages);
38
69
  * messages.push({ role: 'assistant', content: response });
39
70
  *
@@ -47,130 +78,30 @@ export { GrepResult, ReadResult } from './providers/types.js';
47
78
  *
48
79
  * let output: string;
49
80
  * if (call.name === 'grep') {
50
- * const r = await provider.grep(call.arguments);
51
- * output = r.error || r.lines.join('\n') || 'no matches';
81
+ * const r = await toolGrep(provider, call.arguments);
82
+ * output = r.output;
52
83
  * } else if (call.name === 'read') {
53
- * const r = await provider.read(call.arguments);
54
- * output = r.error || r.lines.join('\n') || '(empty)';
55
- * } else if (call.name === 'analyse') {
56
- * const entries = await provider.analyse(call.arguments);
57
- * output = formatAnalyseTree(entries);
84
+ * output = await toolRead(provider, call.arguments);
85
+ * } else if (call.name === 'list_directory') {
86
+ * output = await toolListDirectory(provider, call.arguments);
58
87
  * }
59
88
  *
60
89
  * results.push(formatToolResult(call.name, call.arguments, output));
61
90
  * }
62
91
  *
63
- * messages.push({
64
- * role: 'user',
65
- * content: results.join('\n') + formatTurnMessage(turn)
66
- * });
92
+ * const turnMsg = formatTurnMessage(turn, AGENT_CONFIG.MAX_TURNS);
93
+ * const budget = calculateContextBudget(messages);
94
+ * messages.push({ role: 'user', content: results.join('\n') + turnMsg + '\n' + budget });
67
95
  * }
68
96
  * ```
69
97
  */
70
98
 
71
- /**
72
- * Parse model output into tool calls.
73
- * Automatically handles <think> block removal and <tool_call> extraction.
74
- *
75
- * @param text - Raw model response text
76
- * @returns Array of parsed tool calls
77
- *
78
- * @example
79
- * ```typescript
80
- * const response = `
81
- * <think>Looking for auth code...</think>
82
- * <tool_call>grep 'authenticate' src/</tool_call>
83
- * <tool_call>analyse src/auth</tool_call>
84
- * `;
85
- * const calls = parseToolCalls(response);
86
- * // [{ name: 'grep', arguments: { pattern: 'authenticate', path: 'src/' } },
87
- * // { name: 'analyse', arguments: { path: 'src/auth' } }]
88
- * ```
89
- */
90
99
  declare function parseToolCalls(text: string): ToolCall[];
91
100
 
92
- /**
93
- * Format tool output with XML wrapper for model consumption.
94
- * Handles grep, read, analyse with appropriate tags.
95
- *
96
- * @param name - Tool name ('grep', 'read', 'analyse')
97
- * @param args - Tool arguments
98
- * @param output - Tool output string
99
- * @param options - Optional settings (isError)
100
- * @returns Formatted XML string
101
- *
102
- * @example
103
- * ```typescript
104
- * const formatted = formatToolResult('grep', { pattern: 'auth', path: 'src/' }, 'src/auth.ts:10:function auth()');
105
- * // <grep_output pattern="auth" path="src/">
106
- * // src/auth.ts:10:function auth()
107
- * // </grep_output>
108
- * ```
109
- */
110
- declare function formatToolResult(name: string, args: Record<string, unknown>, output: string, options?: {
111
- isError?: boolean;
112
- }): string;
113
- /**
114
- * Format turn counter message for the model.
115
- *
116
- * @param turn - Current turn number (1-based)
117
- * @param maxTurns - Maximum turns allowed (default: 4)
118
- * @returns Turn message string
119
- *
120
- * @example
121
- * ```typescript
122
- * formatTurnMessage(1); // "\n\n[Turn 1/4] You have 3 turns remaining."
123
- * formatTurnMessage(3); // "\n\n[Turn 3/4] You have 1 turn remaining."
124
- * formatTurnMessage(4); // "\n\n[Turn 4/4] This is your LAST turn. You MUST call finish now."
125
- * ```
126
- */
127
- declare function formatTurnMessage(turn: number, maxTurns?: number): string;
128
- /**
129
- * Convert AnalyseEntry[] to tree view string.
130
- * Matches the format expected by the model.
131
- *
132
- * @param entries - Array of analyse entries
133
- * @returns Tree view string
134
- *
135
- * @example
136
- * ```typescript
137
- * const entries = [
138
- * { name: 'src', path: 'src', type: 'dir', depth: 0 },
139
- * { name: 'index.ts', path: 'src/index.ts', type: 'file', depth: 1 },
140
- * ];
141
- * formatAnalyseTree(entries);
142
- * // "- [D] src\n - [F] index.ts"
143
- * ```
144
- */
145
- declare function formatAnalyseTree(entries: AnalyseEntry[]): string;
146
- /**
147
- * Resolved file with path and content
148
- */
149
101
  type ResolvedFile = {
150
102
  path: string;
151
103
  content: string;
152
104
  };
153
- /**
154
- * Resolve finish command - read all specified file ranges.
155
- *
156
- * @param provider - WarpGrepProvider implementation
157
- * @param files - Array of file specs from finish command
158
- * @returns Array of resolved files with content
159
- *
160
- * @example
161
- * ```typescript
162
- * const files = [
163
- * { path: 'src/auth.ts', lines: [[1, 50], [100, 120]] },
164
- * { path: 'src/types.ts', lines: [[1, 30]] },
165
- * ];
166
- * const resolved = await resolveFinishFiles(provider, files);
167
- * // [{ path: 'src/auth.ts', content: '...' }, { path: 'src/types.ts', content: '...' }]
168
- * ```
169
- */
170
105
  declare function resolveFinishFiles(provider: WarpGrepProvider, files: FinishFileSpec[]): Promise<ResolvedFile[]>;
171
- /** Maximum turns before forced finish (default: 4) */
172
- declare const MAX_TURNS = 4;
173
- /** Request timeout in milliseconds */
174
- declare const TIMEOUT_MS: number;
175
106
 
176
- export { AnalyseEntry, FinishFileSpec, MAX_TURNS, type ResolvedFile, TIMEOUT_MS, ToolCall, WarpGrepProvider, formatAnalyseTree, formatToolResult, formatTurnMessage, parseToolCalls, resolveFinishFiles };
107
+ export { ChatMessage, FinishFileSpec, ListDirectoryEntry, type ResolvedFile, ToolCall, WarpGrepProvider, buildInitialState, calculateContextBudget, formatListDirectoryTree, formatTurnMessage, parseToolCalls, resolveFinishFiles };