@morphllm/morphsdk 0.2.49 → 0.2.51

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 (62) hide show
  1. package/dist/{chunk-3OB2FTEW.js → chunk-2GZMA5OY.js} +4 -4
  2. package/dist/{chunk-6URINEOK.js → chunk-3IASMZXX.js} +5 -5
  3. package/dist/{chunk-FGRMMG62.js → chunk-HBH4FWIZ.js} +29 -22
  4. package/dist/chunk-HBH4FWIZ.js.map +1 -0
  5. package/dist/{chunk-Z2FBMSNE.js → chunk-HQO45BAJ.js} +5 -1
  6. package/dist/chunk-HQO45BAJ.js.map +1 -0
  7. package/dist/{chunk-L4CPOZKO.js → chunk-KMWLHINT.js} +3 -3
  8. package/dist/{chunk-SWQPIKPY.js → chunk-LVPVVLTI.js} +70 -49
  9. package/dist/chunk-LVPVVLTI.js.map +1 -0
  10. package/dist/{chunk-CCYRHMJV.js → chunk-W3QUAOGV.js} +4 -4
  11. package/dist/{chunk-7X53XYJ4.js → chunk-X3WAPQSV.js} +4 -4
  12. package/dist/{chunk-KM6V456Q.js → chunk-ZJIIICRA.js} +33 -10
  13. package/dist/chunk-ZJIIICRA.js.map +1 -0
  14. package/dist/client.cjs +120 -71
  15. package/dist/client.cjs.map +1 -1
  16. package/dist/client.js +13 -13
  17. package/dist/index.cjs +120 -71
  18. package/dist/index.cjs.map +1 -1
  19. package/dist/index.js +13 -13
  20. package/dist/tools/warp_grep/agent/parser.cjs +69 -48
  21. package/dist/tools/warp_grep/agent/parser.cjs.map +1 -1
  22. package/dist/tools/warp_grep/agent/parser.d.ts +2 -0
  23. package/dist/tools/warp_grep/agent/parser.js +1 -1
  24. package/dist/tools/warp_grep/agent/runner.cjs +88 -62
  25. package/dist/tools/warp_grep/agent/runner.cjs.map +1 -1
  26. package/dist/tools/warp_grep/agent/runner.js +7 -7
  27. package/dist/tools/warp_grep/agent/types.cjs.map +1 -1
  28. package/dist/tools/warp_grep/agent/types.d.ts +1 -1
  29. package/dist/tools/warp_grep/anthropic.cjs +120 -71
  30. package/dist/tools/warp_grep/anthropic.cjs.map +1 -1
  31. package/dist/tools/warp_grep/anthropic.js +10 -10
  32. package/dist/tools/warp_grep/index.cjs +120 -71
  33. package/dist/tools/warp_grep/index.cjs.map +1 -1
  34. package/dist/tools/warp_grep/index.js +12 -12
  35. package/dist/tools/warp_grep/openai.cjs +120 -71
  36. package/dist/tools/warp_grep/openai.cjs.map +1 -1
  37. package/dist/tools/warp_grep/openai.js +10 -10
  38. package/dist/tools/warp_grep/providers/local.cjs +32 -9
  39. package/dist/tools/warp_grep/providers/local.cjs.map +1 -1
  40. package/dist/tools/warp_grep/providers/local.js +1 -1
  41. package/dist/tools/warp_grep/providers/types.cjs.map +1 -1
  42. package/dist/tools/warp_grep/providers/types.d.ts +2 -0
  43. package/dist/tools/warp_grep/tools/grep.cjs +3 -0
  44. package/dist/tools/warp_grep/tools/grep.cjs.map +1 -1
  45. package/dist/tools/warp_grep/tools/grep.js +3 -0
  46. package/dist/tools/warp_grep/tools/grep.js.map +1 -1
  47. package/dist/tools/warp_grep/tools/read.cjs +4 -0
  48. package/dist/tools/warp_grep/tools/read.cjs.map +1 -1
  49. package/dist/tools/warp_grep/tools/read.js +1 -1
  50. package/dist/tools/warp_grep/vercel.cjs +120 -71
  51. package/dist/tools/warp_grep/vercel.cjs.map +1 -1
  52. package/dist/tools/warp_grep/vercel.js +10 -10
  53. package/package.json +1 -1
  54. package/dist/chunk-FGRMMG62.js.map +0 -1
  55. package/dist/chunk-KM6V456Q.js.map +0 -1
  56. package/dist/chunk-SWQPIKPY.js.map +0 -1
  57. package/dist/chunk-Z2FBMSNE.js.map +0 -1
  58. /package/dist/{chunk-3OB2FTEW.js.map → chunk-2GZMA5OY.js.map} +0 -0
  59. /package/dist/{chunk-6URINEOK.js.map → chunk-3IASMZXX.js.map} +0 -0
  60. /package/dist/{chunk-L4CPOZKO.js.map → chunk-KMWLHINT.js.map} +0 -0
  61. /package/dist/{chunk-CCYRHMJV.js.map → chunk-W3QUAOGV.js.map} +0 -0
  62. /package/dist/{chunk-7X53XYJ4.js.map → chunk-X3WAPQSV.js.map} +0 -0
@@ -1,16 +1,16 @@
1
1
  import {
2
2
  WARP_GREP_DESCRIPTION,
3
3
  formatResult
4
- } from "./chunk-L4CPOZKO.js";
4
+ } from "./chunk-KMWLHINT.js";
5
5
  import {
6
6
  runWarpGrep
7
- } from "./chunk-FGRMMG62.js";
7
+ } from "./chunk-HBH4FWIZ.js";
8
8
  import {
9
9
  getSystemPrompt
10
10
  } from "./chunk-WETRQJGU.js";
11
11
  import {
12
12
  LocalRipgrepProvider
13
- } from "./chunk-KM6V456Q.js";
13
+ } from "./chunk-ZJIIICRA.js";
14
14
 
15
15
  // tools/warp_grep/openai.ts
16
16
  var TOOL_PARAMETERS = {
@@ -79,4 +79,4 @@ export {
79
79
  createMorphWarpGrepTool,
80
80
  openai_default
81
81
  };
82
- //# sourceMappingURL=chunk-3OB2FTEW.js.map
82
+ //# sourceMappingURL=chunk-2GZMA5OY.js.map
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  createMorphWarpGrepTool as createMorphWarpGrepTool2
3
- } from "./chunk-7X53XYJ4.js";
3
+ } from "./chunk-X3WAPQSV.js";
4
4
  import {
5
5
  createMorphWarpGrepTool
6
- } from "./chunk-3OB2FTEW.js";
6
+ } from "./chunk-2GZMA5OY.js";
7
7
  import {
8
8
  createMorphWarpGrepTool as createMorphWarpGrepTool3
9
- } from "./chunk-CCYRHMJV.js";
9
+ } from "./chunk-W3QUAOGV.js";
10
10
  import {
11
11
  WarpGrepClient
12
- } from "./chunk-L4CPOZKO.js";
12
+ } from "./chunk-KMWLHINT.js";
13
13
  import {
14
14
  createCodebaseSearchTool as createCodebaseSearchTool3
15
15
  } from "./chunk-UBX7QYBD.js";
@@ -280,4 +280,4 @@ export {
280
280
  VercelToolFactory,
281
281
  MorphClient
282
282
  };
283
- //# sourceMappingURL=chunk-6URINEOK.js.map
283
+ //# sourceMappingURL=chunk-3IASMZXX.js.map
@@ -1,30 +1,30 @@
1
1
  import {
2
- formatAgentToolOutput
3
- } from "./chunk-TICMYDII.js";
2
+ readFinishFiles
3
+ } from "./chunk-EK7OQPWD.js";
4
4
  import {
5
- GrepState,
6
- formatTurnGrepOutput,
7
- parseAndFilterGrepOutput
8
- } from "./chunk-NDZO5IPV.js";
5
+ toolRead
6
+ } from "./chunk-HQO45BAJ.js";
9
7
  import {
10
8
  LLMResponseParser
11
- } from "./chunk-SWQPIKPY.js";
9
+ } from "./chunk-LVPVVLTI.js";
12
10
  import {
13
11
  getSystemPrompt
14
12
  } from "./chunk-WETRQJGU.js";
15
13
  import {
16
- toolRead
17
- } from "./chunk-Z2FBMSNE.js";
14
+ toolAnalyse
15
+ } from "./chunk-73RQWOQC.js";
18
16
  import {
19
17
  AGENT_CONFIG,
20
18
  DEFAULT_MODEL
21
19
  } from "./chunk-TJIUA27P.js";
22
20
  import {
23
- toolAnalyse
24
- } from "./chunk-73RQWOQC.js";
21
+ formatAgentToolOutput
22
+ } from "./chunk-TICMYDII.js";
25
23
  import {
26
- readFinishFiles
27
- } from "./chunk-EK7OQPWD.js";
24
+ GrepState,
25
+ formatTurnGrepOutput,
26
+ parseAndFilterGrepOutput
27
+ } from "./chunk-NDZO5IPV.js";
28
28
  import {
29
29
  fetchWithRetry,
30
30
  withTimeout
@@ -103,14 +103,7 @@ async function runWarpGrep(config) {
103
103
  });
104
104
  if (!assistantContent) break;
105
105
  messages.push({ role: "assistant", content: assistantContent });
106
- let toolCalls = [];
107
- try {
108
- toolCalls = parser.parse(assistantContent);
109
- } catch (e) {
110
- errors.push({ message: e instanceof Error ? e.message : String(e) });
111
- terminationReason = "terminated";
112
- break;
113
- }
106
+ const toolCalls = parser.parse(assistantContent);
114
107
  if (toolCalls.length === 0) {
115
108
  errors.push({ message: "No tool calls produced by the model." });
116
109
  terminationReason = "terminated";
@@ -120,7 +113,12 @@ async function runWarpGrep(config) {
120
113
  const grepCalls = toolCalls.filter((c) => c.name === "grep");
121
114
  const analyseCalls = toolCalls.filter((c) => c.name === "analyse");
122
115
  const readCalls = toolCalls.filter((c) => c.name === "read");
116
+ const skipCalls = toolCalls.filter((c) => c.name === "_skip");
123
117
  const formatted = [];
118
+ for (const c of skipCalls) {
119
+ const msg = c.arguments?.message || "Command skipped due to parsing error";
120
+ formatted.push(msg);
121
+ }
124
122
  const otherPromises = [];
125
123
  for (const c of analyseCalls) {
126
124
  const args = c.arguments ?? {};
@@ -146,6 +144,15 @@ async function runWarpGrep(config) {
146
144
  const args = c.arguments ?? {};
147
145
  try {
148
146
  const grepRes = await provider.grep({ pattern: args.pattern, path: args.path });
147
+ if (grepRes.error) {
148
+ errors.push({ message: grepRes.error });
149
+ terminationReason = "terminated";
150
+ return {
151
+ terminationReason: "terminated",
152
+ messages,
153
+ errors
154
+ };
155
+ }
149
156
  const rawOutput = Array.isArray(grepRes.lines) ? grepRes.lines.join("\n") : "";
150
157
  const newMatches = parseAndFilterGrepOutput(rawOutput, grepState);
151
158
  let formattedPayload = formatTurnGrepOutput(newMatches);
@@ -218,4 +225,4 @@ async function runWarpGrep(config) {
218
225
  export {
219
226
  runWarpGrep
220
227
  };
221
- //# sourceMappingURL=chunk-FGRMMG62.js.map
228
+ //# sourceMappingURL=chunk-HBH4FWIZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../tools/warp_grep/agent/runner.ts"],"sourcesContent":["import { AGENT_CONFIG, DEFAULT_MODEL } from './config.js';\nimport { getSystemPrompt } from './prompt.js';\nimport type { AgentRunResult, ChatMessage, SessionConfig, ToolCall, AgentFinish } from './types.js';\nimport { LLMResponseParser } from './parser.js';\nimport type { WarpGrepProvider } from '../providers/types.js';\nimport { toolRead } from '../tools/read.js';\nimport { toolAnalyse } from '../tools/analyse.js';\nimport { fetchWithRetry, withTimeout } from '../../utils/resilience.js';\nimport { formatAgentToolOutput } from './formatter.js';\nimport { GrepState, parseAndFilterGrepOutput, formatTurnGrepOutput } from './grep_helpers.js';\nimport { readFinishFiles } from '../tools/finish.js';\nimport path from 'path';\nimport fs from 'fs/promises';\n\ntype EventName =\n | 'initial_state'\n | 'round_start'\n | 'round_end'\n | 'finish'\n | 'error';\n\nexport type EventCallback = (name: EventName, payload: Record<string, unknown>) => void;\n\nconst parser = new LLMResponseParser();\n\nasync function buildInitialState(repoRoot: string, query: string): Promise<string> {\n // Summarize top-level directories and file counts\n try {\n const entries = await fs.readdir(repoRoot, { withFileTypes: true });\n const dirs = entries.filter(e => e.isDirectory()).map(d => d.name).slice(0, 50);\n const files = entries.filter(e => e.isFile()).map(f => f.name).slice(0, 50);\n const parts = [\n `<repo_root>${repoRoot}</repo_root>`,\n `<top_dirs>${dirs.join(', ')}</top_dirs>`,\n `<top_files>${files.join(', ')}</top_files>`,\n ];\n return parts.join('\\n');\n } catch {\n return `<repo_root>${repoRoot}</repo_root>`;\n }\n}\n\nfunction formatAssistantToolBlock(name: string, args: Record<string, unknown>, payload: string, isError = false): string {\n const argStr = Object.entries(args)\n .map(([k, v]) => `${k}=${JSON.stringify(v)}`)\n .join(' ');\n const prefix = isError ? 'error' : 'result';\n return `<${prefix} name=\"${name}\" ${argStr}>\\n${payload}\\n</${prefix}>`;\n}\n\nasync function callModel(messages: ChatMessage[], model: string, apiKey?: string): Promise<string> {\n const api = 'https://api.morphllm.com/v1/chat/completions';\n const fetchPromise = fetchWithRetry(\n api,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${apiKey || process.env.MORPH_API_KEY || ''}`,\n },\n body: JSON.stringify({\n model,\n temperature: 0.0,\n max_tokens: 1024,\n messages,\n }),\n },\n {}\n );\n const resp = await withTimeout(fetchPromise, AGENT_CONFIG.TIMEOUT_MS, 'morph-warp-grep request timed out');\n if (!resp.ok) {\n // keeping these cases are real throws, if this happens retry will likely not help, so best we just throw here, notice the error and fix\n const t = await resp.text();\n throw new Error(`morph-warp-grep error ${resp.status}: ${t}`);\n }\n const data = await resp.json();\n const content = data?.choices?.[0]?.message?.content;\n if (!content || typeof content !== 'string') {\n throw new Error('Invalid response from model');\n }\n return content;\n}\n\nexport async function runWarpGrep(config: SessionConfig & { provider: WarpGrepProvider }): Promise<AgentRunResult> {\n const repoRoot = path.resolve(config.repoRoot || process.cwd());\n const messages: ChatMessage[] = [];\n\n // system\n const systemMessage = { role: 'system' as const, content: getSystemPrompt() };\n messages.push(systemMessage);\n // user query\n const queryContent = `<query>${config.query}</query>`;\n messages.push({ role: 'user', content: queryContent });\n // initial state\n const initialState = await buildInitialState(repoRoot, config.query);\n messages.push({ role: 'user', content: initialState });\n\n const maxRounds = AGENT_CONFIG.MAX_ROUNDS;\n const model = config.model || DEFAULT_MODEL;\n const provider = config.provider;\n const errors: Array<{ message: string }> = [];\n const grepState = new GrepState();\n\n let finishMeta: AgentFinish | undefined;\n let terminationReason: AgentRunResult['terminationReason'] = 'terminated';\n\n for (let round = 1; round <= maxRounds; round += 1) {\n // call model\n const assistantContent = await callModel(messages, model, config.apiKey).catch((e: unknown) => {\n errors.push({ message: e instanceof Error ? e.message : String(e) });\n return '';\n });\n if (!assistantContent) break;\n messages.push({ role: 'assistant', content: assistantContent });\n\n // parse tool calls (no longer throws - returns _skip calls for malformed commands)\n const toolCalls = parser.parse(assistantContent);\n if (toolCalls.length === 0) {\n errors.push({ message: 'No tool calls produced by the model.' });\n terminationReason = 'terminated';\n break;\n }\n\n const finishCalls = toolCalls.filter(c => c.name === 'finish');\n const grepCalls = toolCalls.filter(c => c.name === 'grep');\n const analyseCalls = toolCalls.filter(c => c.name === 'analyse');\n const readCalls = toolCalls.filter(c => c.name === 'read');\n const skipCalls = toolCalls.filter(c => c.name === '_skip');\n\n const formatted: string[] = [];\n\n // Surface any skipped commands as feedback to the LLM\n for (const c of skipCalls) {\n const msg = (c.arguments as { message?: string })?.message || 'Command skipped due to parsing error';\n formatted.push(msg);\n }\n\n // Execute non-grep tools in parallel\n const otherPromises: Array<Promise<string>> = [];\n for (const c of analyseCalls) {\n const args = (c.arguments ?? {}) as { path: string; pattern?: string | null };\n otherPromises.push(\n toolAnalyse(provider, args).then(\n p => formatAgentToolOutput('analyse', args, p, { isError: false }),\n err => formatAgentToolOutput('analyse', args, String(err), { isError: true })\n )\n );\n }\n for (const c of readCalls) {\n const args = (c.arguments ?? {}) as { path: string; start?: number; end?: number };\n otherPromises.push(\n toolRead(provider, args).then(\n p => formatAgentToolOutput('read', args, p, { isError: false }),\n err => formatAgentToolOutput('read', args, String(err), { isError: true })\n )\n );\n }\n const otherResults = await Promise.all(otherPromises);\n formatted.push(...otherResults);\n\n // Execute grep calls sequentially like MCP runner to keep outputs compact\n for (const c of grepCalls) {\n const args = (c.arguments ?? {}) as { pattern: string; path: string };\n try {\n const grepRes = await provider.grep({ pattern: args.pattern, path: args.path });\n \n // Check for ripgrep availability error - terminate early with clear message\n if (grepRes.error) {\n errors.push({ message: grepRes.error });\n terminationReason = 'terminated';\n // Return immediately with the error so user knows to install ripgrep\n return {\n terminationReason: 'terminated',\n messages,\n errors,\n };\n }\n \n const rawOutput = Array.isArray(grepRes.lines) ? grepRes.lines.join('\\n') : '';\n const newMatches = parseAndFilterGrepOutput(rawOutput, grepState);\n let formattedPayload = formatTurnGrepOutput(newMatches);\n if (formattedPayload === \"No new matches found.\") {\n formattedPayload = \"no new matches\";\n }\n formatted.push(formatAgentToolOutput('grep', args, formattedPayload, { isError: false }));\n } catch (err) {\n formatted.push(formatAgentToolOutput('grep', args, String(err), { isError: true }));\n }\n }\n\n if (formatted.length > 0) {\n // Add turn counter message\n const turnsUsed = round;\n const turnsRemaining = 4 - turnsUsed;\n let turnMessage: string;\n if (turnsRemaining === 0) {\n turnMessage = `\\n\\n[Turn ${turnsUsed}/4] This is your LAST turn. You MUST call the finish tool now.`;\n } else if (turnsRemaining === 1) {\n turnMessage = `\\n\\n[Turn ${turnsUsed}/4] You have 1 turn remaining. Next turn you MUST call the finish tool.`;\n } else {\n turnMessage = `\\n\\n[Turn ${turnsUsed}/4] You have ${turnsRemaining} turns remaining.`;\n }\n messages.push({ role: 'user', content: formatted.join('\\n') + turnMessage });\n }\n\n if (finishCalls.length) {\n const fc = finishCalls[0];\n const files = ((fc.arguments as any)?.files ?? []) as AgentFinish['files'];\n finishMeta = { files };\n terminationReason = 'completed';\n break;\n }\n }\n\n if (terminationReason !== 'completed' || !finishMeta) {\n return { terminationReason, messages, errors };\n }\n\n // Build finish payload\n const parts: string[] = ['Relevant context found:'];\n for (const f of finishMeta.files) {\n const ranges = f.lines.map(([s, e]) => `${s}-${e}`).join(', ');\n parts.push(`- ${f.path}: ${ranges}`);\n }\n const payload = parts.join('\\n');\n\n // Resolve file contents for returned ranges\n // Wrap reader in try-catch to handle non-existent or unreadable files gracefully\n const resolved = await readFinishFiles(\n repoRoot,\n finishMeta.files,\n async (p: string, s: number, e: number) => {\n try {\n const rr = await provider.read({ path: p, start: s, end: e });\n // rr.lines are \"line|content\" → strip the \"line|\" prefix\n return rr.lines.map(l => {\n const idx = l.indexOf('|');\n return idx >= 0 ? l.slice(idx + 1) : l;\n });\n } catch {\n // File doesn't exist or can't be read - return placeholder\n // This handles cases where the agent hallucinated a path or the file was deleted\n return [`[couldn't find: ${p}]`];\n }\n }\n );\n\n return {\n terminationReason: 'completed',\n messages,\n finish: { payload, metadata: finishMeta, resolved },\n };\n}\n\n\n"],"mappings":"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","names":[]}
@@ -1,10 +1,14 @@
1
1
  // tools/warp_grep/tools/read.ts
2
2
  async function toolRead(provider, args) {
3
3
  const res = await provider.read({ path: args.path, start: args.start, end: args.end });
4
+ if (res.error) {
5
+ return res.error;
6
+ }
7
+ if (!res.lines.length) return "(empty file)";
4
8
  return res.lines.join("\n");
5
9
  }
6
10
 
7
11
  export {
8
12
  toolRead
9
13
  };
10
- //# sourceMappingURL=chunk-Z2FBMSNE.js.map
14
+ //# sourceMappingURL=chunk-HQO45BAJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../tools/warp_grep/tools/read.ts"],"sourcesContent":["import type { WarpGrepProvider } from '../providers/types.js';\n\nexport async function toolRead(\n provider: WarpGrepProvider,\n args: { path: string; start?: number; end?: number }\n): Promise<string> {\n const res = await provider.read({ path: args.path, start: args.start, end: args.end });\n // Return error message if present (graceful handling)\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\n"],"mappings":";AAEA,eAAsB,SACpB,UACA,MACiB;AACjB,QAAM,MAAM,MAAM,SAAS,KAAK,EAAE,MAAM,KAAK,MAAM,OAAO,KAAK,OAAO,KAAK,KAAK,IAAI,CAAC;AAErF,MAAI,IAAI,OAAO;AACb,WAAO,IAAI;AAAA,EACb;AACA,MAAI,CAAC,IAAI,MAAM,OAAQ,QAAO;AAC9B,SAAO,IAAI,MAAM,KAAK,IAAI;AAC5B;","names":[]}
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  runWarpGrep
3
- } from "./chunk-FGRMMG62.js";
3
+ } from "./chunk-HBH4FWIZ.js";
4
4
  import {
5
5
  LocalRipgrepProvider
6
- } from "./chunk-KM6V456Q.js";
6
+ } from "./chunk-ZJIIICRA.js";
7
7
 
8
8
  // tools/warp_grep/core.ts
9
9
  var WarpGrepClient = class {
@@ -102,4 +102,4 @@ export {
102
102
  formatResult,
103
103
  WARP_GREP_DESCRIPTION
104
104
  };
105
- //# sourceMappingURL=chunk-L4CPOZKO.js.map
105
+ //# sourceMappingURL=chunk-KMWLHINT.js.map
@@ -55,24 +55,23 @@ var LLMResponseParser = class {
55
55
  const lines = preprocessText(text);
56
56
  const commands = [];
57
57
  let finishAccumulator = null;
58
- lines.forEach((line, idx) => {
58
+ lines.forEach((line) => {
59
59
  if (!line || line.startsWith("#")) return;
60
- const ctx = { lineNumber: idx + 1, raw: line };
61
- const parts = this.splitLine(line, ctx);
60
+ const parts = this.splitLine(line);
62
61
  if (parts.length === 0) return;
63
62
  const cmd = parts[0];
64
63
  switch (cmd) {
65
64
  case "analyse":
66
- this.handleAnalyse(parts, ctx, commands);
65
+ this.handleAnalyse(parts, line, commands);
67
66
  break;
68
67
  case "grep":
69
- this.handleGrep(parts, ctx, commands);
68
+ this.handleGrep(parts, line, commands);
70
69
  break;
71
70
  case "read":
72
- this.handleRead(parts, ctx, commands);
71
+ this.handleRead(parts, line, commands);
73
72
  break;
74
73
  case "finish":
75
- finishAccumulator = this.handleFinish(parts, ctx, finishAccumulator);
74
+ finishAccumulator = this.handleFinish(parts, line, commands, finishAccumulator);
76
75
  break;
77
76
  default:
78
77
  break;
@@ -89,53 +88,68 @@ var LLMResponseParser = class {
89
88
  }
90
89
  return commands;
91
90
  }
92
- splitLine(line, ctx) {
93
- try {
94
- const parts = [];
95
- let current = "";
96
- let inSingle = false;
97
- for (let i = 0; i < line.length; i++) {
98
- const ch = line[i];
99
- if (ch === "'" && line[i - 1] !== "\\") {
100
- inSingle = !inSingle;
101
- current += ch;
102
- } else if (!inSingle && /\s/.test(ch)) {
103
- if (current) {
104
- parts.push(current);
105
- current = "";
106
- }
107
- } else {
108
- current += ch;
91
+ splitLine(line) {
92
+ const parts = [];
93
+ let current = "";
94
+ let inSingle = false;
95
+ for (let i = 0; i < line.length; i++) {
96
+ const ch = line[i];
97
+ if (ch === "'" && line[i - 1] !== "\\") {
98
+ inSingle = !inSingle;
99
+ current += ch;
100
+ } else if (!inSingle && /\s/.test(ch)) {
101
+ if (current) {
102
+ parts.push(current);
103
+ current = "";
109
104
  }
105
+ } else {
106
+ current += ch;
110
107
  }
111
- if (current) parts.push(current);
112
- return parts;
113
- } catch {
114
- throw new LLMResponseParseError(`Line ${ctx.lineNumber}: Unable to parse line.`);
115
108
  }
109
+ if (current) parts.push(current);
110
+ return parts;
116
111
  }
117
- handleAnalyse(parts, ctx, commands) {
112
+ /** Helper to create a _skip tool call with an error message */
113
+ skip(message) {
114
+ return { name: "_skip", arguments: { message } };
115
+ }
116
+ handleAnalyse(parts, rawLine, commands) {
118
117
  if (parts.length < 2) {
119
- throw new LLMResponseParseError(`Line ${ctx.lineNumber}: analyse requires <path>`);
118
+ commands.push(this.skip(
119
+ `[SKIPPED] Your command "${rawLine}" is missing a path. Correct format: analyse <path> [pattern]. Example: analyse src/`
120
+ ));
121
+ return;
120
122
  }
121
123
  const path = parts[1];
122
124
  const pattern = parts[2]?.replace(/^"|"$/g, "") ?? null;
123
125
  commands.push({ name: "analyse", arguments: { path, pattern } });
124
126
  }
125
127
  // no glob tool in MCP
126
- handleGrep(parts, ctx, commands) {
128
+ handleGrep(parts, rawLine, commands) {
127
129
  if (parts.length < 3) {
128
- throw new LLMResponseParseError(`Line ${ctx.lineNumber}: grep requires '<pattern>' and <path>`);
130
+ commands.push(this.skip(
131
+ `[SKIPPED] Your command "${rawLine}" is missing arguments. Correct format: grep '<pattern>' <path>. Example: grep 'TODO' src/`
132
+ ));
133
+ return;
129
134
  }
130
- const pat = parts[1];
131
- if (!pat.startsWith("'") || !pat.endsWith("'")) {
132
- throw new LLMResponseParseError(`Line ${ctx.lineNumber}: grep pattern must be single-quoted`);
135
+ let pat = parts[1];
136
+ if (pat.startsWith("'") && pat.endsWith("'")) {
137
+ pat = pat.slice(1, -1);
133
138
  }
134
- commands.push({ name: "grep", arguments: { pattern: pat.slice(1, -1), path: parts[2] } });
139
+ if (!pat) {
140
+ commands.push(this.skip(
141
+ `[SKIPPED] Your command "${rawLine}" has an empty pattern. Provide a non-empty search pattern. Example: grep 'function' src/`
142
+ ));
143
+ return;
144
+ }
145
+ commands.push({ name: "grep", arguments: { pattern: pat, path: parts[2] } });
135
146
  }
136
- handleRead(parts, ctx, commands) {
147
+ handleRead(parts, rawLine, commands) {
137
148
  if (parts.length < 2) {
138
- throw new LLMResponseParseError(`Line ${ctx.lineNumber}: read requires <path> or <path>:<start-end>`);
149
+ commands.push(this.skip(
150
+ `[SKIPPED] Your command "${rawLine}" is missing a path. Correct format: read <path> or read <path>:<start>-<end>. Example: read src/index.ts:1-50`
151
+ ));
152
+ return;
139
153
  }
140
154
  const spec = parts[1];
141
155
  const rangeIdx = spec.indexOf(":");
@@ -143,31 +157,38 @@ var LLMResponseParser = class {
143
157
  commands.push({ name: "read", arguments: { path: spec } });
144
158
  return;
145
159
  }
146
- const path = spec.slice(0, rangeIdx);
160
+ const filePath = spec.slice(0, rangeIdx);
147
161
  const range = spec.slice(rangeIdx + 1);
148
162
  const [s, e] = range.split("-").map((v) => parseInt(v, 10));
149
163
  if (!Number.isFinite(s) || !Number.isFinite(e)) {
150
- throw new LLMResponseParseError(`Line ${ctx.lineNumber}: invalid read range '${range}'`);
164
+ commands.push({ name: "read", arguments: { path: filePath } });
165
+ return;
151
166
  }
152
- commands.push({ name: "read", arguments: { path, start: s, end: e } });
167
+ commands.push({ name: "read", arguments: { path: filePath, start: s, end: e } });
153
168
  }
154
- handleFinish(parts, ctx, acc) {
169
+ handleFinish(parts, rawLine, commands, acc) {
155
170
  const map = acc ?? /* @__PURE__ */ new Map();
156
171
  const args = parts.slice(1);
157
172
  for (const token of args) {
158
- const [path, rangesText] = token.split(":", 2);
159
- if (!path || !rangesText) {
160
- throw new LLMResponseParseError(`Line ${ctx.lineNumber}: invalid finish token '${token}'`);
173
+ const [filePath, rangesText] = token.split(":", 2);
174
+ if (!filePath || !rangesText) {
175
+ commands.push(this.skip(
176
+ `[SKIPPED] Invalid finish token "${token}". Correct format: finish <path>:<start>-<end>. Example: finish src/index.ts:1-50`
177
+ ));
178
+ continue;
161
179
  }
162
180
  const rangeSpecs = rangesText.split(",").filter(Boolean);
163
181
  for (const spec of rangeSpecs) {
164
182
  const [s, e] = spec.split("-").map((v) => parseInt(v, 10));
165
183
  if (!Number.isFinite(s) || !Number.isFinite(e) || e < s) {
166
- throw new LLMResponseParseError(`Line ${ctx.lineNumber}: invalid range '${spec}'`);
184
+ commands.push(this.skip(
185
+ `[SKIPPED] Invalid range "${spec}" in "${token}". Ranges must be <start>-<end> where start <= end. Example: 1-50`
186
+ ));
187
+ continue;
167
188
  }
168
- const arr = map.get(path) ?? [];
189
+ const arr = map.get(filePath) ?? [];
169
190
  arr.push([s, e]);
170
- map.set(path, arr);
191
+ map.set(filePath, arr);
171
192
  }
172
193
  }
173
194
  return map;
@@ -178,4 +199,4 @@ export {
178
199
  LLMResponseParseError,
179
200
  LLMResponseParser
180
201
  };
181
- //# sourceMappingURL=chunk-SWQPIKPY.js.map
202
+ //# sourceMappingURL=chunk-LVPVVLTI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../tools/warp_grep/agent/parser.ts"],"sourcesContent":["// 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"],"mappings":"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","names":[]}
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  WARP_GREP_DESCRIPTION
3
- } from "./chunk-L4CPOZKO.js";
3
+ } from "./chunk-KMWLHINT.js";
4
4
  import {
5
5
  runWarpGrep
6
- } from "./chunk-FGRMMG62.js";
6
+ } from "./chunk-HBH4FWIZ.js";
7
7
  import {
8
8
  LocalRipgrepProvider
9
- } from "./chunk-KM6V456Q.js";
9
+ } from "./chunk-ZJIIICRA.js";
10
10
 
11
11
  // tools/warp_grep/vercel.ts
12
12
  import { tool } from "ai";
@@ -67,4 +67,4 @@ export {
67
67
  execute,
68
68
  createMorphWarpGrepTool
69
69
  };
70
- //# sourceMappingURL=chunk-CCYRHMJV.js.map
70
+ //# sourceMappingURL=chunk-W3QUAOGV.js.map
@@ -1,16 +1,16 @@
1
1
  import {
2
2
  WARP_GREP_DESCRIPTION,
3
3
  formatResult
4
- } from "./chunk-L4CPOZKO.js";
4
+ } from "./chunk-KMWLHINT.js";
5
5
  import {
6
6
  runWarpGrep
7
- } from "./chunk-FGRMMG62.js";
7
+ } from "./chunk-HBH4FWIZ.js";
8
8
  import {
9
9
  getSystemPrompt
10
10
  } from "./chunk-WETRQJGU.js";
11
11
  import {
12
12
  LocalRipgrepProvider
13
- } from "./chunk-KM6V456Q.js";
13
+ } from "./chunk-ZJIIICRA.js";
14
14
 
15
15
  // tools/warp_grep/anthropic.ts
16
16
  var INPUT_SCHEMA = {
@@ -73,4 +73,4 @@ export {
73
73
  createMorphWarpGrepTool,
74
74
  anthropic_default
75
75
  };
76
- //# sourceMappingURL=chunk-7X53XYJ4.js.map
76
+ //# sourceMappingURL=chunk-X3WAPQSV.js.map
@@ -41,10 +41,22 @@ var LocalRipgrepProvider = class {
41
41
  ];
42
42
  const res = await runRipgrep(args, { cwd: this.repoRoot });
43
43
  if (res.exitCode === -1) {
44
- throw new Error(res.stderr || "ripgrep (rg) execution failed.");
44
+ return {
45
+ lines: [],
46
+ error: `[RIPGREP NOT AVAILABLE] ripgrep (rg) is required but failed to execute. Please install it:
47
+ \u2022 macOS: brew install ripgrep
48
+ \u2022 Ubuntu/Debian: apt install ripgrep
49
+ \u2022 Windows: choco install ripgrep
50
+ \u2022 Or visit: https://github.com/BurntSushi/ripgrep#installation
51
+ Exit code: ${res.exitCode}${res.stderr ? `
52
+ Details: ${res.stderr}` : ""}`
53
+ };
45
54
  }
46
55
  if (res.exitCode !== 0 && res.exitCode !== 1) {
47
- throw new Error(res.stderr || `ripgrep failed with code ${res.exitCode}`);
56
+ return {
57
+ lines: [],
58
+ error: `[RIPGREP ERROR] grep failed with exit code ${res.exitCode}${res.stderr ? `: ${res.stderr}` : ""}`
59
+ };
48
60
  }
49
61
  const lines = (res.stdout || "").trim().split(/\r?\n/).filter((l) => l.length > 0);
50
62
  return { lines };
@@ -62,7 +74,8 @@ var LocalRipgrepProvider = class {
62
74
  ];
63
75
  const res = await runRipgrep(args, { cwd: this.repoRoot });
64
76
  if (res.exitCode === -1) {
65
- throw new Error(res.stderr || "ripgrep (rg) execution failed.");
77
+ console.warn(`[warp_grep] ripgrep not available for glob: ${res.stderr || "execution failed"}`);
78
+ return { files: [] };
66
79
  }
67
80
  const files = (res.stdout || "").trim().split(/\r?\n/).filter((l) => l.length > 0);
68
81
  return { files };
@@ -71,20 +84,30 @@ var LocalRipgrepProvider = class {
71
84
  const abs = resolveUnderRepo(this.repoRoot, params.path);
72
85
  const stat = await fs.stat(abs).catch(() => null);
73
86
  if (!stat || !stat.isFile()) {
74
- throw new Error(`Path is not a file: ${params.path}`);
87
+ return {
88
+ lines: [],
89
+ error: `[FILE NOT FOUND] You tried to read "${params.path}" but there is no file at this path. Double-check the path exists and is spelled correctly.`
90
+ };
75
91
  }
76
92
  if (isSymlink(abs)) {
77
- throw new Error(`Refusing to read symlink: ${params.path}`);
93
+ return {
94
+ lines: [],
95
+ error: `[SYMLINK] You tried to read "${params.path}" but this is a symlink. Try reading the actual file it points to instead.`
96
+ };
78
97
  }
79
98
  if (!isTextualFile(abs)) {
80
- throw new Error(`Non-text or too-large file: ${params.path}`);
99
+ return {
100
+ lines: [],
101
+ error: `[UNREADABLE FILE] You tried to read "${params.path}" but this file is either too large or not a text file, so it cannot be read. Try a different file.`
102
+ };
81
103
  }
82
104
  const lines = await readAllLines(abs);
83
105
  const total = lines.length;
84
- const s = params.start ?? 1;
85
- const e = Math.min(params.end ?? total, total);
106
+ let s = params.start ?? 1;
107
+ let e = Math.min(params.end ?? total, total);
86
108
  if (s > total && total > 0) {
87
- throw new Error(`start ${s} exceeds file length (${total})`);
109
+ s = 1;
110
+ e = total;
88
111
  }
89
112
  const out = [];
90
113
  for (let i = s; i <= e; i += 1) {
@@ -132,4 +155,4 @@ var LocalRipgrepProvider = class {
132
155
  export {
133
156
  LocalRipgrepProvider
134
157
  };
135
- //# sourceMappingURL=chunk-KM6V456Q.js.map
158
+ //# sourceMappingURL=chunk-ZJIIICRA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../tools/warp_grep/providers/local.ts"],"sourcesContent":["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"],"mappings":"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","names":[]}