@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
@@ -31,25 +31,37 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var warp_grep_exports = {};
32
32
  __export(warp_grep_exports, {
33
33
  LocalRipgrepProvider: () => LocalRipgrepProvider,
34
+ RemoteCommandsProvider: () => RemoteCommandsProvider,
34
35
  WARP_GREP_DESCRIPTION: () => WARP_GREP_DESCRIPTION,
35
36
  WARP_GREP_SYSTEM_PROMPT: () => SYSTEM_PROMPT,
36
37
  WARP_GREP_TOOL_NAME: () => WARP_GREP_TOOL_NAME,
37
38
  WarpGrepClient: () => WarpGrepClient,
38
- createAnthropicWarpGrepTool: () => createMorphWarpGrepTool2,
39
- createOpenAIWarpGrepTool: () => createMorphWarpGrepTool,
40
- createVercelWarpGrepTool: () => createMorphWarpGrepTool3,
39
+ anthropic: () => anthropic_exports,
40
+ executeToolCall: () => executeToolCall,
41
41
  executeWarpGrep: () => executeWarpGrep,
42
42
  formatResult: () => formatResult,
43
+ gemini: () => gemini_exports,
43
44
  getSystemPrompt: () => getSystemPrompt,
44
- runWarpGrep: () => runWarpGrep
45
+ normalizeFinishFiles: () => normalizeFinishFiles,
46
+ openai: () => openai_exports,
47
+ readFinishFiles: () => readFinishFiles,
48
+ runWarpGrep: () => runWarpGrep,
49
+ toolGrep: () => toolGrep,
50
+ toolListDirectory: () => toolListDirectory,
51
+ toolRead: () => toolRead,
52
+ vercel: () => vercel_exports
45
53
  });
46
54
  module.exports = __toCommonJS(warp_grep_exports);
47
55
 
48
56
  // tools/warp_grep/agent/config.ts
49
57
  var AGENT_CONFIG = {
50
- // Give the model freedom; failsafe cap to prevent infinite loops
51
- MAX_ROUNDS: 10,
52
- TIMEOUT_MS: 3e4
58
+ MAX_TURNS: 4,
59
+ TIMEOUT_MS: 3e4,
60
+ MAX_CONTEXT_CHARS: 54e4,
61
+ MAX_OUTPUT_LINES: 200,
62
+ MAX_READ_LINES: 800,
63
+ MAX_LIST_DEPTH: 3,
64
+ LIST_TIMEOUT_MS: 2e3
53
65
  };
54
66
  var BUILTIN_EXCLUDES = [
55
67
  // Version control
@@ -131,113 +143,191 @@ var BUILTIN_EXCLUDES = [
131
143
  ".*"
132
144
  ];
133
145
  var DEFAULT_EXCLUDES = (process.env.MORPH_WARP_GREP_EXCLUDE || "").split(",").map((s) => s.trim()).filter(Boolean).concat(BUILTIN_EXCLUDES);
134
- var DEFAULT_MODEL = "morph-warp-grep";
146
+ var DEFAULT_MODEL = "morph-warp-grep-v1";
135
147
 
136
148
  // tools/warp_grep/agent/prompt.ts
137
- var SYSTEM_PROMPT = `You are a code search agent. Your task is to find all relevant code for a given query.
149
+ var SYSTEM_PROMPT = `You are a code search agent. Your task is to find all relevant code for a given search_string.
138
150
 
139
- <workflow>
151
+ ### workflow
140
152
  You have exactly 4 turns. The 4th turn MUST be a \`finish\` call. Each turn allows up to 8 parallel tool calls.
141
153
 
142
- - Turn 1: Map the territory OR dive deep (based on query specificity)
154
+ - Turn 1: Map the territory OR dive deep (based on search_string specificity)
143
155
  - Turn 2-3: Refine based on findings
144
156
  - Turn 4: MUST call \`finish\` with all relevant code locations
145
157
  - You MAY call \`finish\` early if confident\u2014but never before at least 1 search turn.
158
+ - The user strongly prefers if you can call the finish tool early, but you must be correct
146
159
 
147
- Remember, if the task feels easy to you, it is strongly desirable to call \`finish\` early using fewer turns, but quality over speed.
148
- </workflow>
160
+ Remember, if the task feels easy to you, it is strongly desirable to call 'finish' early using fewer turns, but quality over speed
149
161
 
150
- <tools>
151
- ### \`analyse <path> [pattern]\`
152
- Directory tree or file search. Shows structure of a path, optionally filtered by regex pattern.
153
- - \`path\`: Required. Directory or file path (use \`.\` for repo root)
154
- - \`pattern\`: Optional regex to filter results
162
+ ### tools
163
+ Tool calls use nested XML elements:
164
+ \`\`\`xml
165
+ <tool_name>
166
+ <parameter>value</parameter>
167
+ </tool_name>
168
+ \`\`\`
169
+
170
+ ### \`list_directory\`
171
+ Directory tree view. Shows structure of a path, optionally filtered by regex pattern.
172
+
173
+ Elements:
174
+ - \`<path>\` (required): Directory path to list (use \`.\` for repo root)
175
+ - \`<pattern>\` (optional): Regex to filter results
155
176
 
156
177
  Examples:
157
178
  \`\`\`
158
- analyse .
159
- analyse src/api
160
- analyse . ".*\\.ts$"
161
- analyse src "test.*"
179
+ <list_directory>
180
+ <path>src/services</path>
181
+ </list_directory>
182
+
183
+ <list_directory>
184
+ <path>lib/utils</path>
185
+ <pattern>.*\\.(ts|js)$</pattern>
186
+ </list_directory>
162
187
  \`\`\`
163
188
 
164
- ### \`read <path>[:start-end]\`
165
- Read file contents. Line range is 1-based, inclusive.
189
+ ### \`read\`
190
+ Read file contents. Supports multiple line ranges.
166
191
  - Returns numbered lines for easy reference
167
- - Omit range to read entire file
192
+ - ALWAYS include import statements (usually lines 1-20). Better to over-include than miss context.
193
+
194
+ Elements:
195
+ - \`<path>\` (required): File path to read
196
+ - \`<lines>\` (optional): Line ranges like "1-50,75-80,100-120" (omit to read entire file)
168
197
 
169
198
  Examples:
170
199
  \`\`\`
171
- read src/main.py
172
- read src/db/conn.py:10-50
173
- read package.json:1-20
200
+ <read>
201
+ <path>src/main.py</path>
202
+ </read>
203
+
204
+ <read>
205
+ <path>src/auth.py</path>
206
+ <lines>1-20,45-80,150-200</lines>
207
+ </read>
174
208
  \`\`\`
175
209
 
176
- ### \`grep '<pattern>' <path>\`
177
- Ripgrep search. Finds pattern matches across files.
178
- - \`'<pattern>'\`: Required. Regex pattern wrapped in single quotes
179
- - \`<path>\`: Required. Directory or file to search (use \`.\` for repo root)
210
+ ### \`grep\`
211
+ Search for pattern matches across files. Returns matches with 1 line of context above and below.
212
+ - Match lines use \`:\` separator \u2192 \`filepath:linenum:content\`
213
+ - Context lines use \`-\` separator \u2192 \`filepath-linenum-content\`
214
+
215
+ Elements:
216
+ - \`<pattern>\` (required): Search pattern (regex). Use \`(a|b)\` for OR patterns.
217
+ - \`<sub_dir>\` (optional): Subdirectory to search in (defaults to \`.\`)
218
+ - \`<glob>\` (optional): File pattern filter like \`*.py\` or \`*.{ts,tsx}\`
180
219
 
181
220
  Examples:
182
221
  \`\`\`
183
- grep 'class.*Service' src/
184
- grep 'def authenticate' .
185
- grep 'import.*from' src/components/
186
- grep 'TODO' .
222
+ <grep>
223
+ <pattern>(authenticate|authorize|login)</pattern>
224
+ <sub_dir>src/auth/</sub_dir>
225
+ </grep>
226
+
227
+ <grep>
228
+ <pattern>class.*(Service|Controller)</pattern>
229
+ <glob>*.{ts,js}</glob>
230
+ </grep>
231
+
232
+ <grep>
233
+ <pattern>(DB_HOST|DATABASE_URL|connection)</pattern>
234
+ <glob>*.{py,yaml,env}</glob>
235
+ <sub_dir>lib/</sub_dir>
236
+ </grep>
187
237
  \`\`\`
188
238
 
189
- ### \`finish <file1:ranges> [file2:ranges ...]\`
190
- Submit final answer with all relevant code locations.
191
- - Include generous line ranges\u2014don't be stingy with context
192
- - Ranges are comma-separated: \`file.py:10-30,50-60\`
193
- - ALWAYS include import statements at the top of files (usually lines 1-20)
194
- - If code spans multiple files, include ALL of them
195
- - Small files can be returned in full
239
+ ### \`finish\`
240
+ Submit final answer with all relevant code locations. Uses nested \`<file>\` elements.
241
+
242
+ File elements:
243
+ - \`<path>\` (required): File path
244
+ - \`<lines>\` (optional): Line ranges like "1-50,75-80" (\`*\` for entire file)
245
+
246
+ ALWAYS include import statements (usually lines 1-20). Better to over-include than miss context.
196
247
 
197
248
  Examples:
198
249
  \`\`\`
199
- finish src/auth.py:1-15,25-50,75-80 src/models/user.py:1-10,20-45
200
- finish src/index.ts:1-100
250
+ <finish>
251
+ <file>
252
+ <path>src/auth.py</path>
253
+ <lines>1-15,25-50,75-80</lines>
254
+ </file>
255
+ <file>
256
+ <path>src/models/user.py</path>
257
+ <lines>*</lines>
258
+ </file>
259
+ </finish>
201
260
  \`\`\`
202
261
  </tools>
203
262
 
204
263
  <strategy>
205
- **Before your first tool call, classify the query:**
264
+ **Before your first tool call, classify the search_string:**
206
265
 
207
- | Query Type | Turn 1 Strategy | Early Finish? |
208
- |------------|-----------------|---------------|
209
- | **Specific** (function name, error string, unique identifier) | 8 parallel greps on likely paths | Often by turn 2 |
210
- | **Conceptual** (how does X work, where is Y handled) | analyse + 2-3 broad greps | Rarely early |
211
- | **Exploratory** (find all tests, list API endpoints) | analyse at multiple depths | Usually needs 3 turns |
266
+ | Search_string Type | Round 1 Strategy | Early Finish? |
267
+ |------------|------------------|---------------|
268
+ | **Specific** (function name, error string, unique identifier) | 8 parallel greps on likely paths | Often by round 2 |
269
+ | **Conceptual** (how does X work, where is Y handled) | list_directory + 2-3 broad greps | Rarely early |
270
+ | **Exploratory** (find all tests, list API endpoints) | list_directory at multiple depths | Usually needs 3 rounds |
212
271
 
213
272
  **Parallel call patterns:**
214
273
  - **Shotgun grep**: Same pattern, 8 different directories\u2014fast coverage
215
274
  - **Variant grep**: 8 pattern variations (synonyms, naming conventions)\u2014catches inconsistent codebases
216
- - **Funnel**: 1 analyse + 7 greps\u2014orient and search simultaneously
275
+ - **Funnel**: 1 list_directory + 7 greps\u2014orient and search simultaneously
217
276
  - **Deep read**: 8 reads on files you already identified\u2014gather full context fast
277
+
278
+ **Tool call expectations:**
279
+ - 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.
280
+ - 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.
281
+ - 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.
282
+ - 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.
218
283
  </strategy>
219
284
 
220
285
  <output_format>
221
286
  EVERY response MUST follow this exact format:
222
287
 
223
288
  1. First, wrap your reasoning in \`<think>...</think>\` tags containing:
224
- - Query classification (specific/conceptual/exploratory)
225
- - Confidence estimate (can I finish in 1-2 turns?)
226
- - This turn's parallel strategy
289
+ - Search_string classification (specific/conceptual/exploratory)
290
+ - Confidence estimate (can I finish in 1-2 rounds?)
291
+ - This round's parallel strategy
227
292
  - What signals would let me finish early?
228
293
 
229
- 2. Then, output tool calls wrapped in \`<tool_call>...</tool_call>\` tags, one per line.
294
+ 2. Then, output up to 8 tool calls using nested XML elements.
230
295
 
231
296
  Example:
232
297
  \`\`\`
233
298
  <think>
234
- This is a specific query about authentication. I'll grep for auth-related patterns.
235
- High confidence I can finish in 2 turns if I find the auth module.
299
+ This is a specific search_string about authentication. I'll grep for auth-related patterns.
300
+ High confidence I can finish in 2 rounds if I find the auth module. I have already been shown the repo's structure at root
236
301
  Strategy: Shotgun grep across likely directories.
237
302
  </think>
238
- <tool_call>grep 'authenticate' src/</tool_call>
239
- <tool_call>grep 'login' src/</tool_call>
240
- <tool_call>analyse src/auth</tool_call>
303
+ <grep>
304
+ <pattern>(authenticate|login|session)</pattern>
305
+ <sub_dir>src/auth/</sub_dir>
306
+ </grep>
307
+ <grep>
308
+ <pattern>(middleware|interceptor)</pattern>
309
+ <glob>*.{ts,js}</glob>
310
+ </grep>
311
+ <list_directory>
312
+ <path>src/auth</path>
313
+ </list_directory>
314
+ \`\`\`
315
+
316
+ Finishing example:
317
+ \`\`\`
318
+ <think>
319
+ I think I have a rough idea, but this is my last turn so I must call the finish tool regardless.
320
+ </think>
321
+ <finish>
322
+ <file>
323
+ <path>src/auth/login.py</path>
324
+ <lines>1-50</lines>
325
+ </file>
326
+ <file>
327
+ <path>src/middleware/session.py</path>
328
+ <lines>10-80</lines>
329
+ </file>
330
+ </finish>
241
331
  \`\`\`
242
332
 
243
333
  No commentary outside \`<think>\`. No explanations after tool calls.
@@ -250,17 +340,111 @@ When calling \`finish\`:
250
340
  - Include any type definitions, interfaces, or constants used
251
341
  - Better to over-include than leave the user missing context
252
342
  - If unsure about boundaries, include more rather than less
253
- </finishing_requirements>
254
-
255
- Begin your exploration now to find code relevant to the query.`;
343
+ </finishing_requirements>`;
256
344
  function getSystemPrompt() {
257
345
  return SYSTEM_PROMPT;
258
346
  }
259
347
 
260
348
  // tools/warp_grep/agent/parser.ts
261
- var VALID_COMMANDS = ["analyse", "grep", "read", "finish"];
349
+ var VALID_COMMANDS = ["list_directory", "grep", "read", "finish"];
350
+ function isValidCommand(name) {
351
+ return VALID_COMMANDS.includes(name);
352
+ }
353
+ function getXmlElementText(xml, tagName) {
354
+ const regex = new RegExp(`<${tagName}>([\\s\\S]*?)</${tagName}>`, "i");
355
+ const match = xml.match(regex);
356
+ return match ? match[1].trim() : null;
357
+ }
358
+ function parseNestedXmlTools(text) {
359
+ const tools = [];
360
+ const toolRegex = /<([a-z_][a-z0-9_]*)>([\s\S]*?)<\/\1>/gi;
361
+ let match;
362
+ while ((match = toolRegex.exec(text)) !== null) {
363
+ const rawToolName = match[1].toLowerCase();
364
+ const content = match[2];
365
+ if (!isValidCommand(rawToolName)) continue;
366
+ const toolName = rawToolName;
367
+ if (toolName === "list_directory") {
368
+ const path5 = getXmlElementText(content, "path");
369
+ const pattern = getXmlElementText(content, "pattern");
370
+ if (path5) {
371
+ tools.push({ name: "list_directory", arguments: { path: path5, pattern } });
372
+ }
373
+ } else if (toolName === "grep") {
374
+ const pattern = getXmlElementText(content, "pattern");
375
+ const subDir = getXmlElementText(content, "sub_dir");
376
+ const glob = getXmlElementText(content, "glob");
377
+ if (pattern) {
378
+ tools.push({
379
+ name: "grep",
380
+ arguments: {
381
+ pattern,
382
+ path: subDir || ".",
383
+ ...glob && { glob }
384
+ }
385
+ });
386
+ }
387
+ } else if (toolName === "read") {
388
+ const path5 = getXmlElementText(content, "path");
389
+ const linesStr = getXmlElementText(content, "lines");
390
+ if (path5) {
391
+ const args = { path: path5 };
392
+ if (linesStr) {
393
+ const ranges = [];
394
+ for (const rangeStr of linesStr.split(",")) {
395
+ const trimmed = rangeStr.trim();
396
+ if (!trimmed) continue;
397
+ const [s, e] = trimmed.split("-").map((v) => parseInt(v.trim(), 10));
398
+ if (Number.isFinite(s) && Number.isFinite(e)) {
399
+ ranges.push([s, e]);
400
+ } else if (Number.isFinite(s)) {
401
+ ranges.push([s, s]);
402
+ }
403
+ }
404
+ if (ranges.length === 1) {
405
+ args.start = ranges[0][0];
406
+ args.end = ranges[0][1];
407
+ } else if (ranges.length > 1) {
408
+ args.lines = ranges;
409
+ }
410
+ }
411
+ tools.push({ name: "read", arguments: args });
412
+ }
413
+ } else if (toolName === "finish") {
414
+ const fileRegex = /<file>([\s\S]*?)<\/file>/gi;
415
+ const files = [];
416
+ let fileMatch;
417
+ while ((fileMatch = fileRegex.exec(content)) !== null) {
418
+ const fileContent = fileMatch[1];
419
+ const filePath = getXmlElementText(fileContent, "path");
420
+ const linesStr = getXmlElementText(fileContent, "lines");
421
+ if (filePath && linesStr) {
422
+ const ranges = [];
423
+ for (const rangeStr of linesStr.split(",")) {
424
+ if (rangeStr.trim() === "*") {
425
+ ranges.push([1, 999999]);
426
+ } else {
427
+ const [s, e] = rangeStr.split("-").map((v) => parseInt(v.trim(), 10));
428
+ if (Number.isFinite(s) && Number.isFinite(e)) {
429
+ ranges.push([s, e]);
430
+ }
431
+ }
432
+ }
433
+ if (ranges.length > 0) {
434
+ files.push({ path: filePath, lines: ranges });
435
+ }
436
+ }
437
+ }
438
+ if (files.length > 0) {
439
+ tools.push({ name: "finish", arguments: { files } });
440
+ }
441
+ }
442
+ }
443
+ return tools;
444
+ }
262
445
  function preprocessText(text) {
263
446
  let processed = text.replace(/<think>[\s\S]*?<\/think>/gi, "");
447
+ const nestedTools = parseNestedXmlTools(processed);
264
448
  const openingTagRegex = /<tool_call>|<tool>/gi;
265
449
  const closingTagRegex = /<\/tool_call>|<\/tool>/gi;
266
450
  const openingMatches = processed.match(openingTagRegex) || [];
@@ -297,7 +481,7 @@ function preprocessText(text) {
297
481
  }
298
482
  }
299
483
  }
300
- return toolCallLines;
484
+ return { lines: toolCallLines, nestedTools };
301
485
  }
302
486
  var LLMResponseParser = class {
303
487
  finishSpecSplitRe = /,(?=[^,\s]+:)/;
@@ -305,8 +489,8 @@ var LLMResponseParser = class {
305
489
  if (typeof text !== "string") {
306
490
  throw new TypeError("Command text must be a string.");
307
491
  }
308
- const lines = preprocessText(text);
309
- const commands = [];
492
+ const { lines, nestedTools } = preprocessText(text);
493
+ const commands = [...nestedTools];
310
494
  let finishAccumulator = null;
311
495
  lines.forEach((line) => {
312
496
  if (!line || line.startsWith("#")) return;
@@ -314,8 +498,8 @@ var LLMResponseParser = class {
314
498
  if (parts.length === 0) return;
315
499
  const cmd = parts[0];
316
500
  switch (cmd) {
317
- case "analyse":
318
- this.handleAnalyse(parts, line, commands);
501
+ case "list_directory":
502
+ this.handleListDirectory(parts, line, commands);
319
503
  break;
320
504
  case "grep":
321
505
  this.handleGrep(parts, line, commands);
@@ -333,8 +517,8 @@ var LLMResponseParser = class {
333
517
  if (finishAccumulator) {
334
518
  const map = finishAccumulator;
335
519
  const entries = [...map.entries()];
336
- const filesPayload = entries.map(([path4, ranges]) => ({
337
- path: path4,
520
+ const filesPayload = entries.map(([path5, ranges]) => ({
521
+ path: path5,
338
522
  lines: [...ranges].sort((a, b) => a[0] - b[0])
339
523
  }));
340
524
  commands.push({ name: "finish", arguments: { files: filesPayload } });
@@ -366,18 +550,17 @@ var LLMResponseParser = class {
366
550
  skip(message) {
367
551
  return { name: "_skip", arguments: { message } };
368
552
  }
369
- handleAnalyse(parts, rawLine, commands) {
553
+ handleListDirectory(parts, rawLine, commands) {
370
554
  if (parts.length < 2) {
371
555
  commands.push(this.skip(
372
- `[SKIPPED] Your command "${rawLine}" is missing a path. Correct format: analyse <path> [pattern]. Example: analyse src/`
556
+ `[SKIPPED] Your command "${rawLine}" is missing a path. Correct format: list_directory <path> [pattern]. Example: list_directory src/`
373
557
  ));
374
558
  return;
375
559
  }
376
- const path4 = parts[1];
560
+ const path5 = parts[1];
377
561
  const pattern = parts[2]?.replace(/^"|"$/g, "") ?? null;
378
- commands.push({ name: "analyse", arguments: { path: path4, pattern } });
562
+ commands.push({ name: "list_directory", arguments: { path: path5, pattern } });
379
563
  }
380
- // no glob tool in MCP
381
564
  handleGrep(parts, rawLine, commands) {
382
565
  if (parts.length < 3) {
383
566
  commands.push(this.skip(
@@ -448,8 +631,30 @@ var LLMResponseParser = class {
448
631
  }
449
632
  };
450
633
 
451
- // tools/warp_grep/tools/read.ts
634
+ // tools/warp_grep/agent/tools/grep.ts
635
+ async function toolGrep(provider, args) {
636
+ const res = await provider.grep(args);
637
+ if (res.error) {
638
+ return { output: res.error };
639
+ }
640
+ if (!res.lines.length) {
641
+ return { output: "no matches" };
642
+ }
643
+ return { output: res.lines.join("\n") };
644
+ }
645
+
646
+ // tools/warp_grep/agent/tools/read.ts
452
647
  async function toolRead(provider, args) {
648
+ if (args.lines && args.lines.length > 0) {
649
+ const chunks = [];
650
+ for (const [start, end] of args.lines) {
651
+ const res2 = await provider.read({ path: args.path, start, end });
652
+ if (res2.error) return res2.error;
653
+ chunks.push(res2.lines.join("\n"));
654
+ }
655
+ if (chunks.every((c) => c === "")) return "(empty file)";
656
+ return chunks.join("\n...\n");
657
+ }
453
658
  const res = await provider.read({ path: args.path, start: args.start, end: args.end });
454
659
  if (res.error) {
455
660
  return res.error;
@@ -458,16 +663,62 @@ async function toolRead(provider, args) {
458
663
  return res.lines.join("\n");
459
664
  }
460
665
 
461
- // tools/warp_grep/tools/analyse.ts
462
- async function toolAnalyse(provider, args) {
463
- const list = await provider.analyse({
666
+ // tools/warp_grep/agent/tools/list_directory.ts
667
+ async function toolListDirectory(provider, args) {
668
+ const list = await provider.listDirectory({
464
669
  path: args.path,
465
670
  pattern: args.pattern ?? null,
466
- maxResults: args.maxResults ?? 100,
467
- maxDepth: args.maxDepth ?? 2
671
+ maxResults: args.maxResults ?? AGENT_CONFIG.MAX_OUTPUT_LINES,
672
+ maxDepth: args.maxDepth ?? AGENT_CONFIG.MAX_LIST_DEPTH
468
673
  });
469
674
  if (!list.length) return "empty";
470
- return list.map((e) => `${" ".repeat(e.depth)}- ${e.type === "dir" ? "[D]" : "[F]"} ${e.name}`).join("\n");
675
+ if (list.length >= AGENT_CONFIG.MAX_OUTPUT_LINES) {
676
+ return "query not specific enough, tool called tried to return too much context and failed";
677
+ }
678
+ return list.map((e) => {
679
+ const indent = " ".repeat(e.depth);
680
+ const name = e.type === "dir" ? `${e.name}/` : e.name;
681
+ return `${indent}${name}`;
682
+ }).join("\n");
683
+ }
684
+
685
+ // tools/warp_grep/agent/tools/finish.ts
686
+ function normalizeFinishFiles(files) {
687
+ return files.map((f) => {
688
+ const merged = mergeRanges(f.lines);
689
+ return { path: f.path, lines: merged };
690
+ });
691
+ }
692
+ async function readFinishFiles(repoRoot, files, reader) {
693
+ const out = [];
694
+ for (const f of files) {
695
+ const ranges = mergeRanges(f.lines);
696
+ const chunks = [];
697
+ for (const [s, e] of ranges) {
698
+ const lines = await reader(f.path, s, e);
699
+ chunks.push(lines.join("\n"));
700
+ }
701
+ out.push({ path: f.path, ranges, content: chunks.join("\n") });
702
+ }
703
+ return out;
704
+ }
705
+ function mergeRanges(ranges) {
706
+ if (!ranges.length) return [];
707
+ const sorted = [...ranges].sort((a, b) => a[0] - b[0]);
708
+ const merged = [];
709
+ let [cs, ce] = sorted[0];
710
+ for (let i = 1; i < sorted.length; i++) {
711
+ const [s, e] = sorted[i];
712
+ if (s <= ce + 1) {
713
+ ce = Math.max(ce, e);
714
+ } else {
715
+ merged.push([cs, ce]);
716
+ cs = s;
717
+ ce = e;
718
+ }
719
+ }
720
+ merged.push([cs, ce]);
721
+ return merged;
471
722
  }
472
723
 
473
724
  // tools/utils/resilience.ts
@@ -560,8 +811,8 @@ var ToolOutputFormatter = class {
560
811
  switch (name) {
561
812
  case "read":
562
813
  return this.formatRead(safeArgs, payload, isError);
563
- case "analyse":
564
- return this.formatAnalyse(safeArgs, payload, isError);
814
+ case "list_directory":
815
+ return this.formatListDirectory(safeArgs, payload, isError);
565
816
  case "grep":
566
817
  return this.formatGrep(safeArgs, payload, isError);
567
818
  default:
@@ -574,39 +825,56 @@ ${payload}
574
825
  if (isError) {
575
826
  return payload;
576
827
  }
577
- const path4 = this.asString(args.path) || "...";
578
- return `<file path="${path4}">
828
+ const path5 = this.asString(args.path) || "...";
829
+ const start = args.start;
830
+ const end = args.end;
831
+ const linesArray = args.lines;
832
+ const attributes = [`path="${path5}"`];
833
+ if (linesArray && linesArray.length > 0) {
834
+ const rangeStr = linesArray.map(([s, e]) => `${s}-${e}`).join(",");
835
+ attributes.push(`lines="${rangeStr}"`);
836
+ } else if (start !== void 0 && end !== void 0) {
837
+ attributes.push(`lines="${start}-${end}"`);
838
+ }
839
+ return `<read ${attributes.join(" ")}>
579
840
  ${payload}
580
- </file>`;
841
+ </read>`;
581
842
  }
582
- formatAnalyse(args, payload, isError) {
583
- const path4 = this.asString(args.path) || ".";
843
+ formatListDirectory(args, payload, isError) {
844
+ const path5 = this.asString(args.path) || ".";
845
+ const pattern = this.asString(args.pattern);
846
+ const attributes = [`path="${path5}"`];
847
+ if (pattern) {
848
+ attributes.push(`pattern="${pattern}"`);
849
+ }
584
850
  if (isError) {
585
- return `<analyse_results path="${path4}" status="error">
586
- ${payload}
587
- </analyse_results>`;
851
+ attributes.push('status="error"');
588
852
  }
589
- return `<analyse_results path="${path4}">
853
+ return `<list_directory ${attributes.join(" ")}>
590
854
  ${payload}
591
- </analyse_results>`;
855
+ </list_directory>`;
592
856
  }
593
857
  formatGrep(args, payload, isError) {
594
858
  const pattern = this.asString(args.pattern);
595
- const path4 = this.asString(args.path);
859
+ const subDir = this.asString(args.path);
860
+ const glob = this.asString(args.glob);
596
861
  const attributes = [];
597
862
  if (pattern !== void 0) {
598
863
  attributes.push(`pattern="${pattern}"`);
599
864
  }
600
- if (path4 !== void 0) {
601
- attributes.push(`path="${path4}"`);
865
+ if (subDir !== void 0) {
866
+ attributes.push(`sub_dir="${subDir}"`);
867
+ }
868
+ if (glob !== void 0) {
869
+ attributes.push(`glob="${glob}"`);
602
870
  }
603
871
  if (isError) {
604
872
  attributes.push('status="error"');
605
873
  }
606
874
  const attrText = attributes.length ? ` ${attributes.join(" ")}` : "";
607
- return `<grep_output${attrText}>
875
+ return `<grep${attrText}>
608
876
  ${payload}
609
- </grep_output>`;
877
+ </grep>`;
610
878
  }
611
879
  asString(value) {
612
880
  if (value === null || value === void 0) {
@@ -620,66 +888,100 @@ function formatAgentToolOutput(toolName, args, output, options = {}) {
620
888
  return sharedFormatter.format(toolName, args, output, options);
621
889
  }
622
890
 
623
- // tools/warp_grep/tools/finish.ts
624
- async function readFinishFiles(repoRoot, files, reader) {
625
- const out = [];
626
- for (const f of files) {
627
- const ranges = mergeRanges(f.lines);
628
- const chunks = [];
629
- for (const [s, e] of ranges) {
630
- const lines = await reader(f.path, s, e);
631
- chunks.push(lines.join("\n"));
632
- }
633
- out.push({ path: f.path, ranges, content: chunks.join("\n") });
891
+ // tools/warp_grep/agent/helpers.ts
892
+ var import_path = __toESM(require("path"), 1);
893
+ var TRUNCATED_MARKER = "[truncated for context limit]";
894
+ function formatTurnMessage(turnsUsed, maxTurns) {
895
+ const turnsRemaining = maxTurns - turnsUsed;
896
+ if (turnsRemaining === 1) {
897
+ return `
898
+ You 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`;
634
899
  }
635
- return out;
900
+ return `
901
+ You have used ${turnsUsed} turn${turnsUsed === 1 ? "" : "s"} and have ${turnsRemaining} remaining`;
636
902
  }
637
- function mergeRanges(ranges) {
638
- if (!ranges.length) return [];
639
- const sorted = [...ranges].sort((a, b) => a[0] - b[0]);
640
- const merged = [];
641
- let [cs, ce] = sorted[0];
642
- for (let i = 1; i < sorted.length; i++) {
643
- const [s, e] = sorted[i];
644
- if (s <= ce + 1) {
645
- ce = Math.max(ce, e);
646
- } else {
647
- merged.push([cs, ce]);
648
- cs = s;
649
- ce = e;
650
- }
651
- }
652
- merged.push([cs, ce]);
653
- return merged;
903
+ function calculateContextBudget(messages) {
904
+ const totalChars = messages.reduce((sum, m) => sum + m.content.length, 0);
905
+ const maxChars = AGENT_CONFIG.MAX_CONTEXT_CHARS;
906
+ const percent = Math.round(totalChars / maxChars * 100);
907
+ const usedK = Math.round(totalChars / 1e3);
908
+ const maxK = Math.round(maxChars / 1e3);
909
+ return `<context_budget>${percent}% (${usedK}K/${maxK}K chars)</context_budget>`;
654
910
  }
655
-
656
- // tools/warp_grep/agent/runner.ts
657
- var import_path = __toESM(require("path"), 1);
658
- var parser = new LLMResponseParser();
659
911
  async function buildInitialState(repoRoot, query, provider) {
660
912
  try {
661
- const entries = await provider.analyse({ path: ".", maxResults: 100 });
662
- const dirs = entries.filter((e) => e.type === "dir").map((d) => d.name).slice(0, 50);
663
- const files = entries.filter((e) => e.type === "file").map((f) => f.name).slice(0, 50);
664
- const parts = [
665
- `<repo_root>${repoRoot}</repo_root>`,
666
- `<top_dirs>${dirs.join(", ")}</top_dirs>`,
667
- `<top_files>${files.join(", ")}</top_files>`
668
- ];
669
- return parts.join("\n");
913
+ const entries = await provider.listDirectory({
914
+ path: ".",
915
+ maxResults: AGENT_CONFIG.MAX_OUTPUT_LINES,
916
+ maxDepth: 2
917
+ });
918
+ const treeLines = entries.map((e) => {
919
+ const indent = " ".repeat(e.depth);
920
+ const name = e.type === "dir" ? `${e.name}/` : e.name;
921
+ return `${indent}${name}`;
922
+ });
923
+ const repoName = import_path.default.basename(repoRoot);
924
+ const treeOutput = treeLines.length > 0 ? `${repoName}/
925
+ ${treeLines.join("\n")}` : `${repoName}/`;
926
+ return `<repo_structure>
927
+ ${treeOutput}
928
+ </repo_structure>
929
+
930
+ <search_string>
931
+ ${query}
932
+ </search_string>`;
670
933
  } catch {
671
- return `<repo_root>${repoRoot}</repo_root>`;
934
+ const repoName = import_path.default.basename(repoRoot);
935
+ return `<repo_structure>
936
+ ${repoName}/
937
+ </repo_structure>
938
+
939
+ <search_string>
940
+ ${query}
941
+ </search_string>`;
942
+ }
943
+ }
944
+ function enforceContextLimit(messages, maxChars = AGENT_CONFIG.MAX_CONTEXT_CHARS) {
945
+ const getTotalChars = () => messages.reduce((sum, m) => sum + m.content.length, 0);
946
+ if (getTotalChars() <= maxChars) {
947
+ return messages;
948
+ }
949
+ const userIndices = [];
950
+ let firstUserSkipped = false;
951
+ for (let i = 0; i < messages.length; i++) {
952
+ if (messages[i].role === "user") {
953
+ if (!firstUserSkipped) {
954
+ firstUserSkipped = true;
955
+ continue;
956
+ }
957
+ userIndices.push(i);
958
+ }
959
+ }
960
+ for (const idx of userIndices) {
961
+ if (getTotalChars() <= maxChars) {
962
+ break;
963
+ }
964
+ if (messages[idx].content !== TRUNCATED_MARKER) {
965
+ messages[idx] = { role: "user", content: TRUNCATED_MARKER };
966
+ }
672
967
  }
968
+ return messages;
673
969
  }
674
- async function callModel(messages, model, apiKey) {
675
- const api = "https://api.morphllm.com/v1/chat/completions";
970
+
971
+ // tools/warp_grep/agent/runner.ts
972
+ var import_path2 = __toESM(require("path"), 1);
973
+ var parser = new LLMResponseParser();
974
+ var DEFAULT_API_URL = "https://api.morphllm.com";
975
+ async function callModel(messages, model, options = {}) {
976
+ const baseUrl = DEFAULT_API_URL;
977
+ const apiKey = options.morphApiKey || process.env.MORPH_API_KEY || "";
676
978
  const fetchPromise = fetchWithRetry(
677
- api,
979
+ `${baseUrl}/v1/chat/completions`,
678
980
  {
679
981
  method: "POST",
680
982
  headers: {
681
983
  "Content-Type": "application/json",
682
- Authorization: `Bearer ${apiKey || process.env.MORPH_API_KEY || ""}`
984
+ Authorization: `Bearer ${apiKey}`
683
985
  },
684
986
  body: JSON.stringify({
685
987
  model,
@@ -688,10 +990,15 @@ async function callModel(messages, model, apiKey) {
688
990
  messages
689
991
  })
690
992
  },
691
- {}
993
+ options.retryConfig
692
994
  );
693
995
  const resp = await withTimeout(fetchPromise, AGENT_CONFIG.TIMEOUT_MS, "morph-warp-grep request timed out");
694
996
  if (!resp.ok) {
997
+ if (resp.status === 404) {
998
+ throw new Error(
999
+ "The endpoint you are trying to call is likely deprecated. Please update with: npm cache clean --force && npx -y @morphllm/morphmcp@latest or visit: https://morphllm.com/mcp"
1000
+ );
1001
+ }
695
1002
  const t = await resp.text();
696
1003
  throw new Error(`morph-warp-grep error ${resp.status}: ${t}`);
697
1004
  }
@@ -703,22 +1010,24 @@ async function callModel(messages, model, apiKey) {
703
1010
  return content;
704
1011
  }
705
1012
  async function runWarpGrep(config) {
706
- const repoRoot = import_path.default.resolve(config.repoRoot || process.cwd());
1013
+ const repoRoot = import_path2.default.resolve(config.repoRoot || process.cwd());
707
1014
  const messages = [];
708
- const systemMessage = { role: "system", content: getSystemPrompt() };
709
- messages.push(systemMessage);
710
- const queryContent = `<query>${config.query}</query>`;
711
- messages.push({ role: "user", content: queryContent });
1015
+ messages.push({ role: "system", content: getSystemPrompt() });
712
1016
  const initialState = await buildInitialState(repoRoot, config.query, config.provider);
713
1017
  messages.push({ role: "user", content: initialState });
714
- const maxRounds = AGENT_CONFIG.MAX_ROUNDS;
1018
+ const maxTurns = AGENT_CONFIG.MAX_TURNS;
715
1019
  const model = config.model || DEFAULT_MODEL;
716
1020
  const provider = config.provider;
717
1021
  const errors = [];
718
1022
  let finishMeta;
719
1023
  let terminationReason = "terminated";
720
- for (let round = 1; round <= maxRounds; round += 1) {
721
- const assistantContent = await callModel(messages, model, config.apiKey).catch((e) => {
1024
+ for (let turn = 1; turn <= maxTurns; turn += 1) {
1025
+ enforceContextLimit(messages);
1026
+ const assistantContent = await callModel(messages, model, {
1027
+ morphApiKey: config.morphApiKey,
1028
+ morphApiUrl: config.morphApiUrl,
1029
+ retryConfig: config.retryConfig
1030
+ }).catch((e) => {
722
1031
  errors.push({ message: e instanceof Error ? e.message : String(e) });
723
1032
  return "";
724
1033
  });
@@ -726,13 +1035,13 @@ async function runWarpGrep(config) {
726
1035
  messages.push({ role: "assistant", content: assistantContent });
727
1036
  const toolCalls = parser.parse(assistantContent);
728
1037
  if (toolCalls.length === 0) {
729
- errors.push({ message: "No tool calls produced by the model." });
1038
+ errors.push({ message: "No tool calls produced by the model. Your MCP is likely out of date! Update it by running: npm cache clean --force && npx -y @morphllm/morphmcp@latest" });
730
1039
  terminationReason = "terminated";
731
1040
  break;
732
1041
  }
733
1042
  const finishCalls = toolCalls.filter((c) => c.name === "finish");
734
1043
  const grepCalls = toolCalls.filter((c) => c.name === "grep");
735
- const analyseCalls = toolCalls.filter((c) => c.name === "analyse");
1044
+ const listDirCalls = toolCalls.filter((c) => c.name === "list_directory");
736
1045
  const readCalls = toolCalls.filter((c) => c.name === "read");
737
1046
  const skipCalls = toolCalls.filter((c) => c.name === "_skip");
738
1047
  const formatted = [];
@@ -744,24 +1053,18 @@ async function runWarpGrep(config) {
744
1053
  for (const c of grepCalls) {
745
1054
  const args = c.arguments ?? {};
746
1055
  allPromises.push(
747
- provider.grep({ pattern: args.pattern, path: args.path }).then(
748
- (grepRes) => {
749
- if (grepRes.error) {
750
- return { terminate: true, error: grepRes.error };
751
- }
752
- const output = grepRes.lines.join("\n") || "no matches";
753
- return formatAgentToolOutput("grep", args, output, { isError: false });
754
- },
1056
+ toolGrep(provider, args).then(
1057
+ ({ output }) => formatAgentToolOutput("grep", args, output, { isError: false }),
755
1058
  (err) => formatAgentToolOutput("grep", args, String(err), { isError: true })
756
1059
  )
757
1060
  );
758
1061
  }
759
- for (const c of analyseCalls) {
1062
+ for (const c of listDirCalls) {
760
1063
  const args = c.arguments ?? {};
761
1064
  allPromises.push(
762
- toolAnalyse(provider, args).then(
763
- (p) => formatAgentToolOutput("analyse", args, p, { isError: false }),
764
- (err) => formatAgentToolOutput("analyse", args, String(err), { isError: true })
1065
+ toolListDirectory(provider, args).then(
1066
+ (p) => formatAgentToolOutput("list_directory", args, p, { isError: false }),
1067
+ (err) => formatAgentToolOutput("list_directory", args, String(err), { isError: true })
765
1068
  )
766
1069
  );
767
1070
  }
@@ -776,34 +1079,12 @@ async function runWarpGrep(config) {
776
1079
  }
777
1080
  const allResults = await Promise.all(allPromises);
778
1081
  for (const result of allResults) {
779
- if (typeof result === "object" && "terminate" in result) {
780
- errors.push({ message: result.error });
781
- return {
782
- terminationReason: "terminated",
783
- messages,
784
- errors
785
- };
786
- }
787
1082
  formatted.push(result);
788
1083
  }
789
1084
  if (formatted.length > 0) {
790
- const turnsUsed = round;
791
- const turnsRemaining = 4 - turnsUsed;
792
- let turnMessage;
793
- if (turnsRemaining === 0) {
794
- turnMessage = `
795
-
796
- [Turn ${turnsUsed}/4] This is your LAST turn. You MUST call the finish tool now.`;
797
- } else if (turnsRemaining === 1) {
798
- turnMessage = `
799
-
800
- [Turn ${turnsUsed}/4] You have 1 turn remaining. Next turn you MUST call the finish tool.`;
801
- } else {
802
- turnMessage = `
803
-
804
- [Turn ${turnsUsed}/4] You have ${turnsRemaining} turns remaining.`;
805
- }
806
- messages.push({ role: "user", content: formatted.join("\n") + turnMessage });
1085
+ const turnMessage = formatTurnMessage(turn, maxTurns);
1086
+ const contextBudget = calculateContextBudget(messages);
1087
+ messages.push({ role: "user", content: formatted.join("\n") + turnMessage + "\n" + contextBudget });
807
1088
  }
808
1089
  if (finishCalls.length) {
809
1090
  const fc = finishCalls[0];
@@ -853,7 +1134,7 @@ async function runWarpGrep(config) {
853
1134
 
854
1135
  // tools/warp_grep/providers/local.ts
855
1136
  var import_promises2 = __toESM(require("fs/promises"), 1);
856
- var import_path3 = __toESM(require("path"), 1);
1137
+ var import_path4 = __toESM(require("path"), 1);
857
1138
 
858
1139
  // tools/warp_grep/utils/ripgrep.ts
859
1140
  var import_child_process = require("child_process");
@@ -918,21 +1199,21 @@ async function runRipgrep(args, opts) {
918
1199
 
919
1200
  // tools/warp_grep/utils/paths.ts
920
1201
  var import_fs = __toESM(require("fs"), 1);
921
- var import_path2 = __toESM(require("path"), 1);
1202
+ var import_path3 = __toESM(require("path"), 1);
922
1203
  function resolveUnderRepo(repoRoot, targetPath) {
923
- const absRoot = import_path2.default.resolve(repoRoot);
924
- const resolved = import_path2.default.resolve(absRoot, targetPath);
1204
+ const absRoot = import_path3.default.resolve(repoRoot);
1205
+ const resolved = import_path3.default.resolve(absRoot, targetPath);
925
1206
  ensureWithinRepo(absRoot, resolved);
926
1207
  return resolved;
927
1208
  }
928
1209
  function ensureWithinRepo(repoRoot, absTarget) {
929
- const rel = import_path2.default.relative(import_path2.default.resolve(repoRoot), import_path2.default.resolve(absTarget));
930
- if (rel.startsWith("..") || import_path2.default.isAbsolute(rel)) {
1210
+ const rel = import_path3.default.relative(import_path3.default.resolve(repoRoot), import_path3.default.resolve(absTarget));
1211
+ if (rel.startsWith("..") || import_path3.default.isAbsolute(rel)) {
931
1212
  throw new Error(`Path outside repository root: ${absTarget}`);
932
1213
  }
933
1214
  }
934
1215
  function toRepoRelative(repoRoot, absPath) {
935
- return import_path2.default.relative(import_path2.default.resolve(repoRoot), import_path2.default.resolve(absPath));
1216
+ return import_path3.default.relative(import_path3.default.resolve(repoRoot), import_path3.default.resolve(absPath));
936
1217
  }
937
1218
  function isSymlink(p) {
938
1219
  try {
@@ -975,10 +1256,18 @@ var LocalRipgrepProvider = class {
975
1256
  this.excludes = excludes;
976
1257
  }
977
1258
  async grep(params) {
978
- const abs = resolveUnderRepo(this.repoRoot, params.path);
1259
+ let abs;
1260
+ try {
1261
+ abs = resolveUnderRepo(this.repoRoot, params.path);
1262
+ } catch (err) {
1263
+ return {
1264
+ lines: [],
1265
+ error: `[PATH ERROR] ${err instanceof Error ? err.message : String(err)}`
1266
+ };
1267
+ }
979
1268
  const stat = await import_promises2.default.stat(abs).catch(() => null);
980
1269
  if (!stat) return { lines: [] };
981
- const targetArg = abs === import_path3.default.resolve(this.repoRoot) ? "." : toRepoRelative(this.repoRoot, abs);
1270
+ const targetArg = abs === import_path4.default.resolve(this.repoRoot) ? "." : toRepoRelative(this.repoRoot, abs);
982
1271
  const args = [
983
1272
  "--no-config",
984
1273
  "--no-heading",
@@ -987,6 +1276,9 @@ var LocalRipgrepProvider = class {
987
1276
  "--color=never",
988
1277
  "--trim",
989
1278
  "--max-columns=400",
1279
+ "-C",
1280
+ "1",
1281
+ ...params.glob ? ["--glob", params.glob] : [],
990
1282
  ...this.excludes.flatMap((e) => ["-g", `!${e}`]),
991
1283
  params.pattern,
992
1284
  targetArg || "."
@@ -1011,29 +1303,24 @@ Details: ${res.stderr}` : ""}`
1011
1303
  };
1012
1304
  }
1013
1305
  const lines = (res.stdout || "").trim().split(/\r?\n/).filter((l) => l.length > 0);
1014
- return { lines };
1015
- }
1016
- async glob(params) {
1017
- const abs = resolveUnderRepo(this.repoRoot, params.path);
1018
- const targetArg = abs === import_path3.default.resolve(this.repoRoot) ? "." : toRepoRelative(this.repoRoot, abs);
1019
- const args = [
1020
- "--no-config",
1021
- "--files",
1022
- "-g",
1023
- params.pattern,
1024
- ...this.excludes.flatMap((e) => ["-g", `!${e}`]),
1025
- targetArg || "."
1026
- ];
1027
- const res = await runRipgrep(args, { cwd: this.repoRoot });
1028
- if (res.exitCode === -1) {
1029
- console.warn(`[warp_grep] ripgrep not available for glob: ${res.stderr || "execution failed"}`);
1030
- return { files: [] };
1306
+ if (lines.length > AGENT_CONFIG.MAX_OUTPUT_LINES) {
1307
+ return {
1308
+ lines: [],
1309
+ error: "query not specific enough, tool tried to return too much context and failed"
1310
+ };
1031
1311
  }
1032
- const files = (res.stdout || "").trim().split(/\r?\n/).filter((l) => l.length > 0);
1033
- return { files };
1312
+ return { lines };
1034
1313
  }
1035
1314
  async read(params) {
1036
- const abs = resolveUnderRepo(this.repoRoot, params.path);
1315
+ let abs;
1316
+ try {
1317
+ abs = resolveUnderRepo(this.repoRoot, params.path);
1318
+ } catch (err) {
1319
+ return {
1320
+ lines: [],
1321
+ error: `[PATH ERROR] ${err instanceof Error ? err.message : String(err)}`
1322
+ };
1323
+ }
1037
1324
  const stat = await import_promises2.default.stat(abs).catch(() => null);
1038
1325
  if (!stat || !stat.isFile()) {
1039
1326
  return {
@@ -1053,7 +1340,15 @@ Details: ${res.stderr}` : ""}`
1053
1340
  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.`
1054
1341
  };
1055
1342
  }
1056
- const lines = await readAllLines(abs);
1343
+ let lines;
1344
+ try {
1345
+ lines = await readAllLines(abs);
1346
+ } catch (err) {
1347
+ return {
1348
+ lines: [],
1349
+ error: `[READ ERROR] Failed to read "${params.path}": ${err instanceof Error ? err.message : String(err)}`
1350
+ };
1351
+ }
1057
1352
  const total = lines.length;
1058
1353
  let s = params.start ?? 1;
1059
1354
  let e = Math.min(params.end ?? total, total);
@@ -1066,30 +1361,46 @@ Details: ${res.stderr}` : ""}`
1066
1361
  const content = lines[i - 1] ?? "";
1067
1362
  out.push(`${i}|${content}`);
1068
1363
  }
1364
+ if (out.length > AGENT_CONFIG.MAX_READ_LINES) {
1365
+ const truncated = out.slice(0, AGENT_CONFIG.MAX_READ_LINES);
1366
+ truncated.push(`... [truncated: showing ${AGENT_CONFIG.MAX_READ_LINES} of ${out.length} lines]`);
1367
+ return { lines: truncated };
1368
+ }
1069
1369
  return { lines: out };
1070
1370
  }
1071
- async analyse(params) {
1072
- const abs = resolveUnderRepo(this.repoRoot, params.path);
1371
+ async listDirectory(params) {
1372
+ let abs;
1373
+ try {
1374
+ abs = resolveUnderRepo(this.repoRoot, params.path);
1375
+ } catch {
1376
+ return [];
1377
+ }
1073
1378
  const stat = await import_promises2.default.stat(abs).catch(() => null);
1074
1379
  if (!stat || !stat.isDirectory()) {
1075
1380
  return [];
1076
1381
  }
1077
- const maxResults = params.maxResults ?? 100;
1078
- const maxDepth = params.maxDepth ?? 2;
1382
+ const maxResults = params.maxResults ?? AGENT_CONFIG.MAX_OUTPUT_LINES;
1383
+ const maxDepth = params.maxDepth ?? AGENT_CONFIG.MAX_LIST_DEPTH;
1079
1384
  const regex = params.pattern ? new RegExp(params.pattern) : null;
1080
1385
  const results = [];
1386
+ let timedOut = false;
1387
+ const startTime = Date.now();
1081
1388
  async function walk(dir, depth) {
1389
+ if (Date.now() - startTime > AGENT_CONFIG.LIST_TIMEOUT_MS) {
1390
+ timedOut = true;
1391
+ return;
1392
+ }
1082
1393
  if (depth > maxDepth || results.length >= maxResults) return;
1083
1394
  const entries = await import_promises2.default.readdir(dir, { withFileTypes: true });
1084
1395
  for (const entry of entries) {
1085
- const full = import_path3.default.join(dir, entry.name);
1396
+ if (timedOut || results.length >= maxResults) break;
1397
+ const full = import_path4.default.join(dir, entry.name);
1086
1398
  const rel = toRepoRelative(abs, full).replace(/^[.][/\\]?/, "");
1087
- if (DEFAULT_EXCLUDES.some((ex) => rel.split(import_path3.default.sep).includes(ex))) continue;
1399
+ if (DEFAULT_EXCLUDES.some((ex) => rel.split(import_path4.default.sep).includes(ex))) continue;
1088
1400
  if (regex && !regex.test(entry.name)) continue;
1089
- if (results.length >= maxResults) break;
1090
1401
  results.push({
1091
1402
  name: entry.name,
1092
- path: toRepoRelative(import_path3.default.resolve(""), full),
1403
+ path: toRepoRelative(import_path4.default.resolve(""), full),
1093
1404
  // relative display
1094
1405
  type: entry.isDirectory() ? "dir" : "file",
1095
1406
  depth
@@ -1104,12 +1415,103 @@ Details: ${res.stderr}` : ""}`
1104
1415
  }
1105
1416
  };
1106
1417
 
1107
- // tools/warp_grep/core.ts
1418
+ // tools/warp_grep/providers/remote.ts
1419
+ var RemoteCommandsProvider = class {
1420
+ constructor(repoRoot, commands) {
1421
+ this.repoRoot = repoRoot;
1422
+ this.commands = commands;
1423
+ }
1424
+ /**
1425
+ * Run grep command and parse ripgrep output
1426
+ */
1427
+ async grep(params) {
1428
+ try {
1429
+ const stdout = await this.commands.grep(params.pattern, params.path, params.glob);
1430
+ const lines = (stdout || "").trim().split(/\r?\n/).filter((l) => l.length > 0);
1431
+ if (lines.length > AGENT_CONFIG.MAX_OUTPUT_LINES) {
1432
+ return {
1433
+ lines: [],
1434
+ error: "Query not specific enough - too many results returned. Try a more specific pattern."
1435
+ };
1436
+ }
1437
+ return { lines };
1438
+ } catch (error) {
1439
+ return {
1440
+ lines: [],
1441
+ error: `[GREP ERROR] ${error instanceof Error ? error.message : String(error)}`
1442
+ };
1443
+ }
1444
+ }
1445
+ /**
1446
+ * Read file and add line numbers
1447
+ */
1448
+ async read(params) {
1449
+ const start = params.start ?? 1;
1450
+ const end = params.end ?? 1e6;
1451
+ try {
1452
+ const stdout = await this.commands.read(params.path, start, end);
1453
+ const contentLines = (stdout || "").split("\n");
1454
+ if (contentLines.length > 0 && contentLines[contentLines.length - 1] === "") {
1455
+ contentLines.pop();
1456
+ }
1457
+ const lines = contentLines.map((content, idx) => `${start + idx}|${content}`);
1458
+ if (lines.length > AGENT_CONFIG.MAX_READ_LINES) {
1459
+ const truncated = lines.slice(0, AGENT_CONFIG.MAX_READ_LINES);
1460
+ truncated.push(`... [truncated: showing ${AGENT_CONFIG.MAX_READ_LINES} of ${lines.length} lines]`);
1461
+ return { lines: truncated };
1462
+ }
1463
+ return { lines };
1464
+ } catch (error) {
1465
+ return {
1466
+ lines: [],
1467
+ error: `[READ ERROR] ${error instanceof Error ? error.message : String(error)}`
1468
+ };
1469
+ }
1470
+ }
1471
+ /**
1472
+ * List directory and parse find output
1473
+ */
1474
+ async listDirectory(params) {
1475
+ const maxDepth = params.maxDepth ?? AGENT_CONFIG.MAX_LIST_DEPTH;
1476
+ const maxResults = params.maxResults ?? AGENT_CONFIG.MAX_OUTPUT_LINES;
1477
+ try {
1478
+ const stdout = await this.commands.listDir(params.path, maxDepth);
1479
+ const paths = (stdout || "").trim().split(/\r?\n/).filter((p) => p.length > 0);
1480
+ const regex = params.pattern ? new RegExp(params.pattern) : null;
1481
+ const entries = [];
1482
+ for (const fullPath of paths) {
1483
+ if (fullPath === params.path || fullPath === this.repoRoot) continue;
1484
+ const name = fullPath.split("/").pop() || "";
1485
+ if (regex && !regex.test(name)) continue;
1486
+ let relativePath = fullPath;
1487
+ if (fullPath.startsWith(this.repoRoot)) {
1488
+ relativePath = fullPath.slice(this.repoRoot.length).replace(/^\//, "");
1489
+ }
1490
+ const depth = relativePath.split("/").filter(Boolean).length - 1;
1491
+ const hasExtension = name.includes(".") && !name.startsWith(".");
1492
+ const type = hasExtension ? "file" : "dir";
1493
+ entries.push({
1494
+ name,
1495
+ path: relativePath,
1496
+ type,
1497
+ depth: Math.max(0, depth)
1498
+ });
1499
+ if (entries.length >= maxResults) break;
1500
+ }
1501
+ return entries;
1502
+ } catch (error) {
1503
+ return [];
1504
+ }
1505
+ }
1506
+ };
1507
+
1508
+ // tools/warp_grep/client.ts
1108
1509
  var WarpGrepClient = class {
1109
1510
  config;
1110
1511
  constructor(config = {}) {
1111
1512
  this.config = {
1112
- apiKey: config.apiKey,
1513
+ morphApiKey: config.morphApiKey,
1514
+ morphApiUrl: config.morphApiUrl,
1113
1515
  debug: config.debug,
1114
1516
  timeout: config.timeout,
1115
1517
  retryConfig: config.retryConfig
@@ -1137,38 +1539,50 @@ var WarpGrepClient = class {
1137
1539
  * ```
1138
1540
  */
1139
1541
  async execute(input) {
1140
- const provider = input.provider ?? new LocalRipgrepProvider(input.repoRoot, input.excludes);
1141
- const result = await runWarpGrep({
1142
- query: input.query,
1143
- repoRoot: input.repoRoot,
1144
- provider,
1145
- excludes: input.excludes,
1146
- includes: input.includes,
1147
- debug: input.debug ?? this.config.debug ?? false,
1148
- apiKey: this.config.apiKey
1149
- });
1150
- const finish = result.finish;
1151
- if (result.terminationReason !== "completed" || !finish?.metadata) {
1152
- return {
1153
- success: false,
1154
- error: "Search did not complete"
1155
- };
1156
- }
1157
- const contexts = (finish.resolved ?? []).map((r) => ({
1158
- file: r.path,
1159
- content: r.content
1160
- }));
1161
- return {
1162
- success: true,
1163
- contexts,
1164
- summary: finish.payload
1165
- };
1542
+ return executeToolCall(
1543
+ { query: input.query },
1544
+ {
1545
+ repoRoot: input.repoRoot,
1546
+ remoteCommands: input.remoteCommands,
1547
+ provider: input.provider,
1548
+ excludes: input.excludes,
1549
+ includes: input.includes,
1550
+ debug: input.debug ?? this.config.debug,
1551
+ morphApiKey: this.config.morphApiKey,
1552
+ morphApiUrl: this.config.morphApiUrl,
1553
+ retryConfig: this.config.retryConfig
1554
+ }
1555
+ );
1166
1556
  }
1167
1557
  };
1168
1558
  async function executeWarpGrep(input, config) {
1169
1559
  const client = new WarpGrepClient(config);
1170
1560
  return client.execute(input);
1171
1561
  }
1562
+ async function executeToolCall(input, config) {
1563
+ const parsed = typeof input === "string" ? JSON.parse(input) : input;
1564
+ const provider = config.remoteCommands ? new RemoteCommandsProvider(config.repoRoot, config.remoteCommands) : config.provider ?? new LocalRipgrepProvider(config.repoRoot, config.excludes);
1565
+ const result = await runWarpGrep({
1566
+ query: parsed.query,
1567
+ repoRoot: config.repoRoot,
1568
+ provider,
1569
+ excludes: config.excludes,
1570
+ includes: config.includes,
1571
+ debug: config.debug ?? false,
1572
+ morphApiKey: config.morphApiKey,
1573
+ morphApiUrl: config.morphApiUrl,
1574
+ retryConfig: config.retryConfig
1575
+ });
1576
+ const finish = result.finish;
1577
+ if (result.terminationReason !== "completed" || !finish?.metadata) {
1578
+ return { success: false, error: "Search did not complete" };
1579
+ }
1580
+ const contexts = (finish.resolved ?? []).map((r) => ({
1581
+ file: r.path,
1582
+ content: r.content
1583
+ }));
1584
+ return { success: true, contexts, summary: finish.payload };
1585
+ }
1172
1586
  function formatResult(result) {
1173
1587
  if (!result.success) {
1174
1588
  return `Search failed: ${result.error}`;
@@ -1196,48 +1610,39 @@ function formatResult(result) {
1196
1610
  var WARP_GREP_TOOL_NAME = "warpgrep_codebase_search";
1197
1611
  var WARP_GREP_DESCRIPTION = 'IMPORTANT: If you need to explore the codebase to gather context, and the task does not involve a single file or function which is provided by name, you should ALWAYS use the warpgrep codebase search tool first instead of running search commands. When the task requires exploration beyond a single known file, invoke warpgrep first with a natural-language query describing the target functionality, bug, or architectural concern. Warp Grep is a fast and accurate tool that can search for all relevant context in a codebase. Keep queries action-oriented (e.g., "Find where billing invoices are generated and emailed"), and after reviewing the summarized results, you may verify important findings with other search tools or direct file reads to ensure completeness. Warp Grep can be used for query types like: find function responsible for <small feature>; find code that does <description>; find code path for <big feature>; Where does <minimal error message> come from?; or any query of that type. When a task requires exploration beyond a single known file, ALWAYS default to warpgrep codebase search before other search mechanisms.';
1198
1612
 
1199
- // tools/warp_grep/openai.ts
1200
- var TOOL_PARAMETERS = {
1613
+ // tools/warp_grep/anthropic.ts
1614
+ var anthropic_exports = {};
1615
+ __export(anthropic_exports, {
1616
+ createWarpGrepTool: () => createWarpGrepTool,
1617
+ execute: () => execute,
1618
+ formatResult: () => formatResult,
1619
+ getSystemPrompt: () => getSystemPrompt,
1620
+ warpGrepTool: () => warpGrepTool
1621
+ });
1622
+ var INPUT_SCHEMA = {
1201
1623
  type: "object",
1202
1624
  properties: {
1203
1625
  query: { type: "string", description: "Free-form repository question" }
1204
1626
  },
1205
1627
  required: ["query"]
1206
1628
  };
1629
+ var warpGrepTool = {
1630
+ name: WARP_GREP_TOOL_NAME,
1631
+ description: WARP_GREP_DESCRIPTION,
1632
+ input_schema: INPUT_SCHEMA
1633
+ };
1207
1634
  async function execute(input, config) {
1208
- const parsed = typeof input === "string" ? JSON.parse(input) : input;
1209
- const provider = config.provider ?? new LocalRipgrepProvider(config.repoRoot, config.excludes);
1210
- const result = await runWarpGrep({
1211
- query: parsed.query,
1212
- repoRoot: config.repoRoot,
1213
- provider,
1214
- excludes: config.excludes,
1215
- includes: config.includes,
1216
- debug: config.debug ?? false,
1217
- apiKey: config.apiKey
1218
- });
1219
- const finish = result.finish;
1220
- if (result.terminationReason !== "completed" || !finish?.metadata) {
1221
- return { success: false, error: "Search did not complete" };
1222
- }
1223
- const contexts = (finish.resolved ?? []).map((r) => ({
1224
- file: r.path,
1225
- content: r.content
1226
- }));
1227
- return { success: true, contexts, summary: finish.payload };
1635
+ return executeToolCall(input, config);
1228
1636
  }
1229
- function createMorphWarpGrepTool(config) {
1637
+ function createWarpGrepTool(config) {
1230
1638
  const tool2 = {
1231
- type: "function",
1232
- function: {
1233
- name: config.name ?? WARP_GREP_TOOL_NAME,
1234
- description: config.description ?? WARP_GREP_DESCRIPTION,
1235
- parameters: TOOL_PARAMETERS
1236
- }
1639
+ name: config.name ?? WARP_GREP_TOOL_NAME,
1640
+ description: config.description ?? WARP_GREP_DESCRIPTION,
1641
+ input_schema: INPUT_SCHEMA
1237
1642
  };
1238
1643
  return Object.assign(tool2, {
1239
1644
  execute: async (input) => {
1240
- return execute(input, config);
1645
+ return executeToolCall(input, config);
1241
1646
  },
1242
1647
  formatResult: (result) => {
1243
1648
  return formatResult(result);
@@ -1248,45 +1653,46 @@ function createMorphWarpGrepTool(config) {
1248
1653
  });
1249
1654
  }
1250
1655
 
1251
- // tools/warp_grep/anthropic.ts
1252
- var INPUT_SCHEMA = {
1656
+ // tools/warp_grep/openai.ts
1657
+ var openai_exports = {};
1658
+ __export(openai_exports, {
1659
+ createWarpGrepTool: () => createWarpGrepTool2,
1660
+ default: () => openai_default,
1661
+ execute: () => execute2,
1662
+ formatResult: () => formatResult,
1663
+ getSystemPrompt: () => getSystemPrompt,
1664
+ warpGrepTool: () => warpGrepTool2
1665
+ });
1666
+ var TOOL_PARAMETERS = {
1253
1667
  type: "object",
1254
1668
  properties: {
1255
1669
  query: { type: "string", description: "Free-form repository question" }
1256
1670
  },
1257
1671
  required: ["query"]
1258
1672
  };
1259
- async function execute2(input, config) {
1260
- const parsed = typeof input === "string" ? JSON.parse(input) : input;
1261
- const provider = config.provider ?? new LocalRipgrepProvider(config.repoRoot, config.excludes);
1262
- const result = await runWarpGrep({
1263
- query: parsed.query,
1264
- repoRoot: config.repoRoot,
1265
- provider,
1266
- excludes: config.excludes,
1267
- includes: config.includes,
1268
- debug: config.debug ?? false,
1269
- apiKey: config.apiKey
1270
- });
1271
- const finish = result.finish;
1272
- if (result.terminationReason !== "completed" || !finish?.metadata) {
1273
- return { success: false, error: "Search did not complete" };
1673
+ var warpGrepTool2 = {
1674
+ type: "function",
1675
+ function: {
1676
+ name: WARP_GREP_TOOL_NAME,
1677
+ description: WARP_GREP_DESCRIPTION,
1678
+ parameters: TOOL_PARAMETERS
1274
1679
  }
1275
- const contexts = (finish.resolved ?? []).map((r) => ({
1276
- file: r.path,
1277
- content: r.content
1278
- }));
1279
- return { success: true, contexts, summary: finish.payload };
1680
+ };
1681
+ async function execute2(input, config) {
1682
+ return executeToolCall(input, config);
1280
1683
  }
1281
- function createMorphWarpGrepTool2(config) {
1684
+ function createWarpGrepTool2(config) {
1282
1685
  const tool2 = {
1283
- name: config.name ?? WARP_GREP_TOOL_NAME,
1284
- description: config.description ?? WARP_GREP_DESCRIPTION,
1285
- input_schema: INPUT_SCHEMA
1686
+ type: "function",
1687
+ function: {
1688
+ name: config.name ?? WARP_GREP_TOOL_NAME,
1689
+ description: config.description ?? WARP_GREP_DESCRIPTION,
1690
+ parameters: TOOL_PARAMETERS
1691
+ }
1286
1692
  };
1287
1693
  return Object.assign(tool2, {
1288
1694
  execute: async (input) => {
1289
- return execute2(input, config);
1695
+ return executeToolCall(input, config);
1290
1696
  },
1291
1697
  formatResult: (result) => {
1292
1698
  return formatResult(result);
@@ -1296,53 +1702,113 @@ function createMorphWarpGrepTool2(config) {
1296
1702
  }
1297
1703
  });
1298
1704
  }
1705
+ var openai_default = warpGrepTool2;
1299
1706
 
1300
1707
  // tools/warp_grep/vercel.ts
1708
+ var vercel_exports = {};
1709
+ __export(vercel_exports, {
1710
+ createWarpGrepTool: () => createWarpGrepTool3,
1711
+ default: () => vercel_default,
1712
+ execute: () => execute3,
1713
+ formatResult: () => formatResult,
1714
+ getSystemPrompt: () => getSystemPrompt
1715
+ });
1301
1716
  var import_ai = require("ai");
1302
1717
  var import_zod = require("zod");
1303
- var warpGrepSchema = import_zod.z.object({
1304
- query: import_zod.z.string().describe("Free-form repository question")
1305
- });
1306
- function createMorphWarpGrepTool3(config) {
1718
+ async function execute3(input, config) {
1719
+ return executeToolCall(input, config);
1720
+ }
1721
+ function createWarpGrepTool3(config) {
1722
+ const schema = import_zod.z.object({
1723
+ query: import_zod.z.string().describe("Free-form repository question")
1724
+ });
1307
1725
  return (0, import_ai.tool)({
1308
1726
  description: config.description ?? WARP_GREP_DESCRIPTION,
1309
- inputSchema: warpGrepSchema,
1727
+ inputSchema: schema,
1310
1728
  execute: async (params) => {
1311
- const provider = config.provider ?? new LocalRipgrepProvider(config.repoRoot, config.excludes);
1312
- const result = await runWarpGrep({
1313
- query: params.query,
1314
- repoRoot: config.repoRoot,
1315
- provider,
1316
- excludes: config.excludes,
1317
- includes: config.includes,
1318
- debug: config.debug ?? false,
1319
- apiKey: config.apiKey
1320
- });
1321
- const finish = result.finish;
1322
- if (result.terminationReason !== "completed" || !finish?.metadata) {
1323
- return { success: false, error: "Search did not complete" };
1729
+ const result = await executeToolCall(params, config);
1730
+ if (!result.success) {
1731
+ throw new Error(`Failed to search codebase: ${result.error}`);
1324
1732
  }
1325
- const contexts = (finish.resolved ?? []).map((r) => ({
1326
- file: r.path,
1327
- content: r.content
1328
- }));
1329
- return { success: true, contexts, summary: finish.payload };
1733
+ return {
1734
+ success: true,
1735
+ contexts: result.contexts,
1736
+ summary: result.summary
1737
+ };
1738
+ }
1739
+ });
1740
+ }
1741
+ var vercel_default = createWarpGrepTool3;
1742
+
1743
+ // tools/warp_grep/gemini.ts
1744
+ var gemini_exports = {};
1745
+ __export(gemini_exports, {
1746
+ createMorphWarpGrepTool: () => createMorphWarpGrepTool,
1747
+ default: () => gemini_default,
1748
+ execute: () => execute4,
1749
+ formatResult: () => formatResult,
1750
+ getSystemPrompt: () => getSystemPrompt,
1751
+ warpGrepFunctionDeclaration: () => warpGrepFunctionDeclaration
1752
+ });
1753
+ var import_generative_ai = require("@google/generative-ai");
1754
+ var TOOL_PARAMETERS2 = {
1755
+ type: import_generative_ai.SchemaType.OBJECT,
1756
+ properties: {
1757
+ query: {
1758
+ type: import_generative_ai.SchemaType.STRING,
1759
+ description: "Free-form repository question"
1760
+ }
1761
+ },
1762
+ required: ["query"]
1763
+ };
1764
+ var warpGrepFunctionDeclaration = {
1765
+ name: WARP_GREP_TOOL_NAME,
1766
+ description: WARP_GREP_DESCRIPTION,
1767
+ parameters: TOOL_PARAMETERS2
1768
+ };
1769
+ async function execute4(input, config) {
1770
+ return executeToolCall(input, config);
1771
+ }
1772
+ function createMorphWarpGrepTool(config) {
1773
+ const declaration = {
1774
+ name: config.name ?? WARP_GREP_TOOL_NAME,
1775
+ description: config.description ?? WARP_GREP_DESCRIPTION,
1776
+ parameters: TOOL_PARAMETERS2
1777
+ };
1778
+ return Object.assign(declaration, {
1779
+ execute: async (input) => {
1780
+ return executeToolCall(input, config);
1781
+ },
1782
+ formatResult: (result) => {
1783
+ return formatResult(result);
1784
+ },
1785
+ getSystemPrompt: () => {
1786
+ return getSystemPrompt();
1330
1787
  }
1331
1788
  });
1332
1789
  }
1790
+ var gemini_default = warpGrepFunctionDeclaration;
1333
1791
  // Annotate the CommonJS export names for ESM import in node:
1334
1792
  0 && (module.exports = {
1335
1793
  LocalRipgrepProvider,
1794
+ RemoteCommandsProvider,
1336
1795
  WARP_GREP_DESCRIPTION,
1337
1796
  WARP_GREP_SYSTEM_PROMPT,
1338
1797
  WARP_GREP_TOOL_NAME,
1339
1798
  WarpGrepClient,
1340
- createAnthropicWarpGrepTool,
1341
- createOpenAIWarpGrepTool,
1342
- createVercelWarpGrepTool,
1799
+ anthropic,
1800
+ executeToolCall,
1343
1801
  executeWarpGrep,
1344
1802
  formatResult,
1803
+ gemini,
1345
1804
  getSystemPrompt,
1346
- runWarpGrep
1805
+ normalizeFinishFiles,
1806
+ openai,
1807
+ readFinishFiles,
1808
+ runWarpGrep,
1809
+ toolGrep,
1810
+ toolListDirectory,
1811
+ toolRead,
1812
+ vercel
1347
1813
  });
1348
1814
  //# sourceMappingURL=index.cjs.map