@morphllm/morphsdk 0.2.57 → 0.2.59

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 (170) 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-TICMYDII.js → chunk-APP75CBN.js} +33 -16
  17. package/dist/chunk-APP75CBN.js.map +1 -0
  18. package/dist/{chunk-QFIHUCTF.js → chunk-FN4EP3WY.js} +19 -19
  19. package/dist/chunk-FN4EP3WY.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-OXHGFHEU.js → chunk-VJU3BRET.js} +3 -3
  28. package/dist/chunk-VJU3BRET.js.map +1 -0
  29. package/dist/{chunk-TJIUA27P.js → chunk-XT5ZO6ES.js} +9 -5
  30. package/dist/chunk-XT5ZO6ES.js.map +1 -0
  31. package/dist/{chunk-LVPVVLTI.js → chunk-YV75OQTE.js} +105 -17
  32. package/dist/chunk-YV75OQTE.js.map +1 -0
  33. package/dist/{chunk-ZJIIICRA.js → chunk-ZO4PPFCZ.js} +60 -29
  34. package/dist/chunk-ZO4PPFCZ.js.map +1 -0
  35. package/dist/{client-CFoR--IU.d.ts → client-CextMMm9.d.ts} +10 -15
  36. package/dist/client.cjs +689 -343
  37. package/dist/client.cjs.map +1 -1
  38. package/dist/client.d.ts +3 -2
  39. package/dist/client.js +15 -15
  40. package/dist/finish-kXAcUJyB.d.ts +33 -0
  41. package/dist/gemini-CE80Pbdy.d.ts +117 -0
  42. package/dist/git/client.cjs +2 -2
  43. package/dist/git/client.cjs.map +1 -1
  44. package/dist/git/client.d.ts +1 -1
  45. package/dist/git/client.js +1 -1
  46. package/dist/git/index.cjs +2 -2
  47. package/dist/git/index.cjs.map +1 -1
  48. package/dist/git/index.js +1 -1
  49. package/dist/git/types.cjs.map +1 -1
  50. package/dist/git/types.d.ts +1 -1
  51. package/dist/index.cjs +702 -343
  52. package/dist/index.cjs.map +1 -1
  53. package/dist/index.d.ts +4 -3
  54. package/dist/index.js +17 -16
  55. package/dist/openai-Fvpqln7F.d.ts +89 -0
  56. package/dist/tools/warp_grep/agent/config.cjs +8 -4
  57. package/dist/tools/warp_grep/agent/config.cjs.map +1 -1
  58. package/dist/tools/warp_grep/agent/config.d.ts +7 -2
  59. package/dist/tools/warp_grep/agent/config.js +1 -1
  60. package/dist/tools/warp_grep/agent/formatter.cjs +32 -15
  61. package/dist/tools/warp_grep/agent/formatter.cjs.map +1 -1
  62. package/dist/tools/warp_grep/agent/formatter.d.ts +1 -1
  63. package/dist/tools/warp_grep/agent/formatter.js +1 -1
  64. package/dist/tools/warp_grep/agent/parser.cjs +104 -17
  65. package/dist/tools/warp_grep/agent/parser.cjs.map +1 -1
  66. package/dist/tools/warp_grep/agent/parser.d.ts +3 -5
  67. package/dist/tools/warp_grep/agent/parser.js +1 -3
  68. package/dist/tools/warp_grep/agent/prompt.cjs +132 -56
  69. package/dist/tools/warp_grep/agent/prompt.cjs.map +1 -1
  70. package/dist/tools/warp_grep/agent/prompt.d.ts +1 -1
  71. package/dist/tools/warp_grep/agent/prompt.js +1 -1
  72. package/dist/tools/warp_grep/agent/runner.cjs +459 -192
  73. package/dist/tools/warp_grep/agent/runner.cjs.map +1 -1
  74. package/dist/tools/warp_grep/agent/runner.d.ts +1 -0
  75. package/dist/tools/warp_grep/agent/runner.js +6 -8
  76. package/dist/tools/warp_grep/agent/types.cjs.map +1 -1
  77. package/dist/tools/warp_grep/agent/types.d.ts +9 -2
  78. package/dist/tools/warp_grep/anthropic.cjs +650 -260
  79. package/dist/tools/warp_grep/anthropic.cjs.map +1 -1
  80. package/dist/tools/warp_grep/anthropic.d.ts +4 -74
  81. package/dist/tools/warp_grep/anthropic.js +13 -15
  82. package/dist/tools/warp_grep/client.cjs +1593 -0
  83. package/dist/tools/warp_grep/client.cjs.map +1 -0
  84. package/dist/tools/warp_grep/client.d.ts +87 -0
  85. package/dist/tools/warp_grep/client.js +26 -0
  86. package/dist/tools/warp_grep/gemini.cjs +1587 -0
  87. package/dist/tools/warp_grep/gemini.cjs.map +1 -0
  88. package/dist/tools/warp_grep/gemini.d.ts +7 -0
  89. package/dist/tools/warp_grep/gemini.js +34 -0
  90. package/dist/tools/warp_grep/harness.cjs +556 -220
  91. package/dist/tools/warp_grep/harness.cjs.map +1 -1
  92. package/dist/tools/warp_grep/harness.d.ts +50 -119
  93. package/dist/tools/warp_grep/harness.js +33 -41
  94. package/dist/tools/warp_grep/harness.js.map +1 -1
  95. package/dist/tools/warp_grep/index.cjs +812 -346
  96. package/dist/tools/warp_grep/index.cjs.map +1 -1
  97. package/dist/tools/warp_grep/index.d.ts +11 -6
  98. package/dist/tools/warp_grep/index.js +43 -22
  99. package/dist/tools/warp_grep/openai.cjs +650 -258
  100. package/dist/tools/warp_grep/openai.cjs.map +1 -1
  101. package/dist/tools/warp_grep/openai.d.ts +4 -74
  102. package/dist/tools/warp_grep/openai.js +13 -13
  103. package/dist/tools/warp_grep/providers/local.cjs +66 -27
  104. package/dist/tools/warp_grep/providers/local.cjs.map +1 -1
  105. package/dist/tools/warp_grep/providers/local.d.ts +4 -9
  106. package/dist/tools/warp_grep/providers/local.js +2 -2
  107. package/dist/tools/warp_grep/providers/remote.cjs +211 -0
  108. package/dist/tools/warp_grep/providers/remote.cjs.map +1 -0
  109. package/dist/tools/warp_grep/providers/remote.d.ts +67 -0
  110. package/dist/tools/warp_grep/providers/remote.js +9 -0
  111. package/dist/tools/warp_grep/providers/types.cjs.map +1 -1
  112. package/dist/tools/warp_grep/providers/types.d.ts +7 -15
  113. package/dist/tools/warp_grep/vercel.cjs +662 -277
  114. package/dist/tools/warp_grep/vercel.cjs.map +1 -1
  115. package/dist/tools/warp_grep/vercel.d.ts +4 -51
  116. package/dist/tools/warp_grep/vercel.js +16 -14
  117. package/dist/types-a_hxdPI6.d.ts +144 -0
  118. package/dist/vercel-3yjvfmVB.d.ts +66 -0
  119. package/package.json +12 -2
  120. package/dist/chunk-6X5UOY7B.js.map +0 -1
  121. package/dist/chunk-73RQWOQC.js +0 -16
  122. package/dist/chunk-73RQWOQC.js.map +0 -1
  123. package/dist/chunk-7OQOOB3R.js +0 -1
  124. package/dist/chunk-CFF636UC.js +0 -70
  125. package/dist/chunk-CFF636UC.js.map +0 -1
  126. package/dist/chunk-EK7OQPWD.js +0 -44
  127. package/dist/chunk-EK7OQPWD.js.map +0 -1
  128. package/dist/chunk-GJ5TYNRD.js +0 -107
  129. package/dist/chunk-GJ5TYNRD.js.map +0 -1
  130. package/dist/chunk-HQO45BAJ.js +0 -14
  131. package/dist/chunk-HQO45BAJ.js.map +0 -1
  132. package/dist/chunk-IMYQOKFO.js +0 -83
  133. package/dist/chunk-IMYQOKFO.js.map +0 -1
  134. package/dist/chunk-KBQWGT5L.js +0 -77
  135. package/dist/chunk-KBQWGT5L.js.map +0 -1
  136. package/dist/chunk-LVPVVLTI.js.map +0 -1
  137. package/dist/chunk-OXHGFHEU.js.map +0 -1
  138. package/dist/chunk-QFIHUCTF.js.map +0 -1
  139. package/dist/chunk-TICMYDII.js.map +0 -1
  140. package/dist/chunk-TJIUA27P.js.map +0 -1
  141. package/dist/chunk-WETRQJGU.js +0 -129
  142. package/dist/chunk-WETRQJGU.js.map +0 -1
  143. package/dist/chunk-ZJIIICRA.js.map +0 -1
  144. package/dist/core-CpkYEi_T.d.ts +0 -158
  145. package/dist/tools/warp_grep/tools/analyse.cjs +0 -40
  146. package/dist/tools/warp_grep/tools/analyse.cjs.map +0 -1
  147. package/dist/tools/warp_grep/tools/analyse.d.ts +0 -10
  148. package/dist/tools/warp_grep/tools/analyse.js +0 -8
  149. package/dist/tools/warp_grep/tools/finish.cjs +0 -69
  150. package/dist/tools/warp_grep/tools/finish.cjs.map +0 -1
  151. package/dist/tools/warp_grep/tools/finish.d.ts +0 -10
  152. package/dist/tools/warp_grep/tools/finish.js +0 -10
  153. package/dist/tools/warp_grep/tools/grep.cjs +0 -38
  154. package/dist/tools/warp_grep/tools/grep.cjs.map +0 -1
  155. package/dist/tools/warp_grep/tools/grep.d.ts +0 -8
  156. package/dist/tools/warp_grep/tools/grep.js +0 -15
  157. package/dist/tools/warp_grep/tools/grep.js.map +0 -1
  158. package/dist/tools/warp_grep/tools/read.cjs +0 -38
  159. package/dist/tools/warp_grep/tools/read.cjs.map +0 -1
  160. package/dist/tools/warp_grep/tools/read.d.ts +0 -9
  161. package/dist/tools/warp_grep/tools/read.js +0 -8
  162. package/dist/tools/warp_grep/utils/format.cjs +0 -42
  163. package/dist/tools/warp_grep/utils/format.cjs.map +0 -1
  164. package/dist/tools/warp_grep/utils/format.d.ts +0 -4
  165. package/dist/tools/warp_grep/utils/format.js +0 -18
  166. package/dist/tools/warp_grep/utils/format.js.map +0 -1
  167. /package/dist/{chunk-7OQOOB3R.js.map → chunk-ISWL67SF.js.map} +0 -0
  168. /package/dist/tools/warp_grep/{tools/analyse.js.map → client.js.map} +0 -0
  169. /package/dist/tools/warp_grep/{tools/finish.js.map → gemini.js.map} +0 -0
  170. /package/dist/tools/warp_grep/{tools/read.js.map → providers/remote.js.map} +0 -0
@@ -30,7 +30,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // tools/warp_grep/vercel.ts
31
31
  var vercel_exports = {};
32
32
  __export(vercel_exports, {
33
- createMorphWarpGrepTool: () => createMorphWarpGrepTool,
33
+ createWarpGrepTool: () => createWarpGrepTool,
34
+ default: () => vercel_default,
34
35
  execute: () => execute,
35
36
  formatResult: () => formatResult,
36
37
  getSystemPrompt: () => getSystemPrompt
@@ -41,9 +42,13 @@ var import_zod = require("zod");
41
42
 
42
43
  // tools/warp_grep/agent/config.ts
43
44
  var AGENT_CONFIG = {
44
- // Give the model freedom; failsafe cap to prevent infinite loops
45
- MAX_ROUNDS: 10,
46
- TIMEOUT_MS: 3e4
45
+ MAX_TURNS: 4,
46
+ TIMEOUT_MS: 3e4,
47
+ MAX_CONTEXT_CHARS: 54e4,
48
+ MAX_OUTPUT_LINES: 200,
49
+ MAX_READ_LINES: 800,
50
+ MAX_LIST_DEPTH: 3,
51
+ LIST_TIMEOUT_MS: 2e3
47
52
  };
48
53
  var BUILTIN_EXCLUDES = [
49
54
  // Version control
@@ -125,113 +130,191 @@ var BUILTIN_EXCLUDES = [
125
130
  ".*"
126
131
  ];
127
132
  var DEFAULT_EXCLUDES = (process.env.MORPH_WARP_GREP_EXCLUDE || "").split(",").map((s) => s.trim()).filter(Boolean).concat(BUILTIN_EXCLUDES);
128
- var DEFAULT_MODEL = "morph-warp-grep";
133
+ var DEFAULT_MODEL = "morph-warp-grep-v1";
129
134
 
130
135
  // tools/warp_grep/agent/prompt.ts
131
- var SYSTEM_PROMPT = `You are a code search agent. Your task is to find all relevant code for a given query.
136
+ var SYSTEM_PROMPT = `You are a code search agent. Your task is to find all relevant code for a given search_string.
132
137
 
133
- <workflow>
138
+ ### workflow
134
139
  You have exactly 4 turns. The 4th turn MUST be a \`finish\` call. Each turn allows up to 8 parallel tool calls.
135
140
 
136
- - Turn 1: Map the territory OR dive deep (based on query specificity)
141
+ - Turn 1: Map the territory OR dive deep (based on search_string specificity)
137
142
  - Turn 2-3: Refine based on findings
138
143
  - Turn 4: MUST call \`finish\` with all relevant code locations
139
144
  - You MAY call \`finish\` early if confident\u2014but never before at least 1 search turn.
145
+ - The user strongly prefers if you can call the finish tool early, but you must be correct
140
146
 
141
- Remember, if the task feels easy to you, it is strongly desirable to call \`finish\` early using fewer turns, but quality over speed.
142
- </workflow>
147
+ Remember, if the task feels easy to you, it is strongly desirable to call 'finish' early using fewer turns, but quality over speed
143
148
 
144
- <tools>
145
- ### \`analyse <path> [pattern]\`
146
- Directory tree or file search. Shows structure of a path, optionally filtered by regex pattern.
147
- - \`path\`: Required. Directory or file path (use \`.\` for repo root)
148
- - \`pattern\`: Optional regex to filter results
149
+ ### tools
150
+ Tool calls use nested XML elements:
151
+ \`\`\`xml
152
+ <tool_name>
153
+ <parameter>value</parameter>
154
+ </tool_name>
155
+ \`\`\`
156
+
157
+ ### \`list_directory\`
158
+ Directory tree view. Shows structure of a path, optionally filtered by regex pattern.
159
+
160
+ Elements:
161
+ - \`<path>\` (required): Directory path to list (use \`.\` for repo root)
162
+ - \`<pattern>\` (optional): Regex to filter results
149
163
 
150
164
  Examples:
151
165
  \`\`\`
152
- analyse .
153
- analyse src/api
154
- analyse . ".*\\.ts$"
155
- analyse src "test.*"
166
+ <list_directory>
167
+ <path>src/services</path>
168
+ </list_directory>
169
+
170
+ <list_directory>
171
+ <path>lib/utils</path>
172
+ <pattern>.*\\.(ts|js)$</pattern>
173
+ </list_directory>
156
174
  \`\`\`
157
175
 
158
- ### \`read <path>[:start-end]\`
159
- Read file contents. Line range is 1-based, inclusive.
176
+ ### \`read\`
177
+ Read file contents. Supports multiple line ranges.
160
178
  - Returns numbered lines for easy reference
161
- - Omit range to read entire file
179
+ - ALWAYS include import statements (usually lines 1-20). Better to over-include than miss context.
180
+
181
+ Elements:
182
+ - \`<path>\` (required): File path to read
183
+ - \`<lines>\` (optional): Line ranges like "1-50,75-80,100-120" (omit to read entire file)
162
184
 
163
185
  Examples:
164
186
  \`\`\`
165
- read src/main.py
166
- read src/db/conn.py:10-50
167
- read package.json:1-20
187
+ <read>
188
+ <path>src/main.py</path>
189
+ </read>
190
+
191
+ <read>
192
+ <path>src/auth.py</path>
193
+ <lines>1-20,45-80,150-200</lines>
194
+ </read>
168
195
  \`\`\`
169
196
 
170
- ### \`grep '<pattern>' <path>\`
171
- Ripgrep search. Finds pattern matches across files.
172
- - \`'<pattern>'\`: Required. Regex pattern wrapped in single quotes
173
- - \`<path>\`: Required. Directory or file to search (use \`.\` for repo root)
197
+ ### \`grep\`
198
+ Search for pattern matches across files. Returns matches with 1 line of context above and below.
199
+ - Match lines use \`:\` separator \u2192 \`filepath:linenum:content\`
200
+ - Context lines use \`-\` separator \u2192 \`filepath-linenum-content\`
201
+
202
+ Elements:
203
+ - \`<pattern>\` (required): Search pattern (regex). Use \`(a|b)\` for OR patterns.
204
+ - \`<sub_dir>\` (optional): Subdirectory to search in (defaults to \`.\`)
205
+ - \`<glob>\` (optional): File pattern filter like \`*.py\` or \`*.{ts,tsx}\`
174
206
 
175
207
  Examples:
176
208
  \`\`\`
177
- grep 'class.*Service' src/
178
- grep 'def authenticate' .
179
- grep 'import.*from' src/components/
180
- grep 'TODO' .
209
+ <grep>
210
+ <pattern>(authenticate|authorize|login)</pattern>
211
+ <sub_dir>src/auth/</sub_dir>
212
+ </grep>
213
+
214
+ <grep>
215
+ <pattern>class.*(Service|Controller)</pattern>
216
+ <glob>*.{ts,js}</glob>
217
+ </grep>
218
+
219
+ <grep>
220
+ <pattern>(DB_HOST|DATABASE_URL|connection)</pattern>
221
+ <glob>*.{py,yaml,env}</glob>
222
+ <sub_dir>lib/</sub_dir>
223
+ </grep>
181
224
  \`\`\`
182
225
 
183
- ### \`finish <file1:ranges> [file2:ranges ...]\`
184
- Submit final answer with all relevant code locations.
185
- - Include generous line ranges\u2014don't be stingy with context
186
- - Ranges are comma-separated: \`file.py:10-30,50-60\`
187
- - ALWAYS include import statements at the top of files (usually lines 1-20)
188
- - If code spans multiple files, include ALL of them
189
- - Small files can be returned in full
226
+ ### \`finish\`
227
+ Submit final answer with all relevant code locations. Uses nested \`<file>\` elements.
228
+
229
+ File elements:
230
+ - \`<path>\` (required): File path
231
+ - \`<lines>\` (optional): Line ranges like "1-50,75-80" (\`*\` for entire file)
232
+
233
+ ALWAYS include import statements (usually lines 1-20). Better to over-include than miss context.
190
234
 
191
235
  Examples:
192
236
  \`\`\`
193
- finish src/auth.py:1-15,25-50,75-80 src/models/user.py:1-10,20-45
194
- finish src/index.ts:1-100
237
+ <finish>
238
+ <file>
239
+ <path>src/auth.py</path>
240
+ <lines>1-15,25-50,75-80</lines>
241
+ </file>
242
+ <file>
243
+ <path>src/models/user.py</path>
244
+ <lines>*</lines>
245
+ </file>
246
+ </finish>
195
247
  \`\`\`
196
248
  </tools>
197
249
 
198
250
  <strategy>
199
- **Before your first tool call, classify the query:**
251
+ **Before your first tool call, classify the search_string:**
200
252
 
201
- | Query Type | Turn 1 Strategy | Early Finish? |
202
- |------------|-----------------|---------------|
203
- | **Specific** (function name, error string, unique identifier) | 8 parallel greps on likely paths | Often by turn 2 |
204
- | **Conceptual** (how does X work, where is Y handled) | analyse + 2-3 broad greps | Rarely early |
205
- | **Exploratory** (find all tests, list API endpoints) | analyse at multiple depths | Usually needs 3 turns |
253
+ | Search_string Type | Round 1 Strategy | Early Finish? |
254
+ |------------|------------------|---------------|
255
+ | **Specific** (function name, error string, unique identifier) | 8 parallel greps on likely paths | Often by round 2 |
256
+ | **Conceptual** (how does X work, where is Y handled) | list_directory + 2-3 broad greps | Rarely early |
257
+ | **Exploratory** (find all tests, list API endpoints) | list_directory at multiple depths | Usually needs 3 rounds |
206
258
 
207
259
  **Parallel call patterns:**
208
260
  - **Shotgun grep**: Same pattern, 8 different directories\u2014fast coverage
209
261
  - **Variant grep**: 8 pattern variations (synonyms, naming conventions)\u2014catches inconsistent codebases
210
- - **Funnel**: 1 analyse + 7 greps\u2014orient and search simultaneously
262
+ - **Funnel**: 1 list_directory + 7 greps\u2014orient and search simultaneously
211
263
  - **Deep read**: 8 reads on files you already identified\u2014gather full context fast
264
+
265
+ **Tool call expectations:**
266
+ - 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.
267
+ - 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.
268
+ - 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.
269
+ - 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.
212
270
  </strategy>
213
271
 
214
272
  <output_format>
215
273
  EVERY response MUST follow this exact format:
216
274
 
217
275
  1. First, wrap your reasoning in \`<think>...</think>\` tags containing:
218
- - Query classification (specific/conceptual/exploratory)
219
- - Confidence estimate (can I finish in 1-2 turns?)
220
- - This turn's parallel strategy
276
+ - Search_string classification (specific/conceptual/exploratory)
277
+ - Confidence estimate (can I finish in 1-2 rounds?)
278
+ - This round's parallel strategy
221
279
  - What signals would let me finish early?
222
280
 
223
- 2. Then, output tool calls wrapped in \`<tool_call>...</tool_call>\` tags, one per line.
281
+ 2. Then, output up to 8 tool calls using nested XML elements.
224
282
 
225
283
  Example:
226
284
  \`\`\`
227
285
  <think>
228
- This is a specific query about authentication. I'll grep for auth-related patterns.
229
- High confidence I can finish in 2 turns if I find the auth module.
286
+ This is a specific search_string about authentication. I'll grep for auth-related patterns.
287
+ 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
230
288
  Strategy: Shotgun grep across likely directories.
231
289
  </think>
232
- <tool_call>grep 'authenticate' src/</tool_call>
233
- <tool_call>grep 'login' src/</tool_call>
234
- <tool_call>analyse src/auth</tool_call>
290
+ <grep>
291
+ <pattern>(authenticate|login|session)</pattern>
292
+ <sub_dir>src/auth/</sub_dir>
293
+ </grep>
294
+ <grep>
295
+ <pattern>(middleware|interceptor)</pattern>
296
+ <glob>*.{ts,js}</glob>
297
+ </grep>
298
+ <list_directory>
299
+ <path>src/auth</path>
300
+ </list_directory>
301
+ \`\`\`
302
+
303
+ Finishing example:
304
+ \`\`\`
305
+ <think>
306
+ I think I have a rough idea, but this is my last turn so I must call the finish tool regardless.
307
+ </think>
308
+ <finish>
309
+ <file>
310
+ <path>src/auth/login.py</path>
311
+ <lines>1-50</lines>
312
+ </file>
313
+ <file>
314
+ <path>src/middleware/session.py</path>
315
+ <lines>10-80</lines>
316
+ </file>
317
+ </finish>
235
318
  \`\`\`
236
319
 
237
320
  No commentary outside \`<think>\`. No explanations after tool calls.
@@ -244,17 +327,111 @@ When calling \`finish\`:
244
327
  - Include any type definitions, interfaces, or constants used
245
328
  - Better to over-include than leave the user missing context
246
329
  - If unsure about boundaries, include more rather than less
247
- </finishing_requirements>
248
-
249
- Begin your exploration now to find code relevant to the query.`;
330
+ </finishing_requirements>`;
250
331
  function getSystemPrompt() {
251
332
  return SYSTEM_PROMPT;
252
333
  }
253
334
 
254
335
  // tools/warp_grep/agent/parser.ts
255
- var VALID_COMMANDS = ["analyse", "grep", "read", "finish"];
336
+ var VALID_COMMANDS = ["list_directory", "grep", "read", "finish"];
337
+ function isValidCommand(name) {
338
+ return VALID_COMMANDS.includes(name);
339
+ }
340
+ function getXmlElementText(xml, tagName) {
341
+ const regex = new RegExp(`<${tagName}>([\\s\\S]*?)</${tagName}>`, "i");
342
+ const match = xml.match(regex);
343
+ return match ? match[1].trim() : null;
344
+ }
345
+ function parseNestedXmlTools(text) {
346
+ const tools = [];
347
+ const toolRegex = /<([a-z_][a-z0-9_]*)>([\s\S]*?)<\/\1>/gi;
348
+ let match;
349
+ while ((match = toolRegex.exec(text)) !== null) {
350
+ const rawToolName = match[1].toLowerCase();
351
+ const content = match[2];
352
+ if (!isValidCommand(rawToolName)) continue;
353
+ const toolName = rawToolName;
354
+ if (toolName === "list_directory") {
355
+ const path5 = getXmlElementText(content, "path");
356
+ const pattern = getXmlElementText(content, "pattern");
357
+ if (path5) {
358
+ tools.push({ name: "list_directory", arguments: { path: path5, pattern } });
359
+ }
360
+ } else if (toolName === "grep") {
361
+ const pattern = getXmlElementText(content, "pattern");
362
+ const subDir = getXmlElementText(content, "sub_dir");
363
+ const glob = getXmlElementText(content, "glob");
364
+ if (pattern) {
365
+ tools.push({
366
+ name: "grep",
367
+ arguments: {
368
+ pattern,
369
+ path: subDir || ".",
370
+ ...glob && { glob }
371
+ }
372
+ });
373
+ }
374
+ } else if (toolName === "read") {
375
+ const path5 = getXmlElementText(content, "path");
376
+ const linesStr = getXmlElementText(content, "lines");
377
+ if (path5) {
378
+ const args = { path: path5 };
379
+ if (linesStr) {
380
+ const ranges = [];
381
+ for (const rangeStr of linesStr.split(",")) {
382
+ const trimmed = rangeStr.trim();
383
+ if (!trimmed) continue;
384
+ const [s, e] = trimmed.split("-").map((v) => parseInt(v.trim(), 10));
385
+ if (Number.isFinite(s) && Number.isFinite(e)) {
386
+ ranges.push([s, e]);
387
+ } else if (Number.isFinite(s)) {
388
+ ranges.push([s, s]);
389
+ }
390
+ }
391
+ if (ranges.length === 1) {
392
+ args.start = ranges[0][0];
393
+ args.end = ranges[0][1];
394
+ } else if (ranges.length > 1) {
395
+ args.lines = ranges;
396
+ }
397
+ }
398
+ tools.push({ name: "read", arguments: args });
399
+ }
400
+ } else if (toolName === "finish") {
401
+ const fileRegex = /<file>([\s\S]*?)<\/file>/gi;
402
+ const files = [];
403
+ let fileMatch;
404
+ while ((fileMatch = fileRegex.exec(content)) !== null) {
405
+ const fileContent = fileMatch[1];
406
+ const filePath = getXmlElementText(fileContent, "path");
407
+ const linesStr = getXmlElementText(fileContent, "lines");
408
+ if (filePath && linesStr) {
409
+ const ranges = [];
410
+ for (const rangeStr of linesStr.split(",")) {
411
+ if (rangeStr.trim() === "*") {
412
+ ranges.push([1, 999999]);
413
+ } else {
414
+ const [s, e] = rangeStr.split("-").map((v) => parseInt(v.trim(), 10));
415
+ if (Number.isFinite(s) && Number.isFinite(e)) {
416
+ ranges.push([s, e]);
417
+ }
418
+ }
419
+ }
420
+ if (ranges.length > 0) {
421
+ files.push({ path: filePath, lines: ranges });
422
+ }
423
+ }
424
+ }
425
+ if (files.length > 0) {
426
+ tools.push({ name: "finish", arguments: { files } });
427
+ }
428
+ }
429
+ }
430
+ return tools;
431
+ }
256
432
  function preprocessText(text) {
257
433
  let processed = text.replace(/<think>[\s\S]*?<\/think>/gi, "");
434
+ const nestedTools = parseNestedXmlTools(processed);
258
435
  const openingTagRegex = /<tool_call>|<tool>/gi;
259
436
  const closingTagRegex = /<\/tool_call>|<\/tool>/gi;
260
437
  const openingMatches = processed.match(openingTagRegex) || [];
@@ -291,7 +468,7 @@ function preprocessText(text) {
291
468
  }
292
469
  }
293
470
  }
294
- return toolCallLines;
471
+ return { lines: toolCallLines, nestedTools };
295
472
  }
296
473
  var LLMResponseParser = class {
297
474
  finishSpecSplitRe = /,(?=[^,\s]+:)/;
@@ -299,8 +476,8 @@ var LLMResponseParser = class {
299
476
  if (typeof text !== "string") {
300
477
  throw new TypeError("Command text must be a string.");
301
478
  }
302
- const lines = preprocessText(text);
303
- const commands = [];
479
+ const { lines, nestedTools } = preprocessText(text);
480
+ const commands = [...nestedTools];
304
481
  let finishAccumulator = null;
305
482
  lines.forEach((line) => {
306
483
  if (!line || line.startsWith("#")) return;
@@ -308,8 +485,8 @@ var LLMResponseParser = class {
308
485
  if (parts.length === 0) return;
309
486
  const cmd = parts[0];
310
487
  switch (cmd) {
311
- case "analyse":
312
- this.handleAnalyse(parts, line, commands);
488
+ case "list_directory":
489
+ this.handleListDirectory(parts, line, commands);
313
490
  break;
314
491
  case "grep":
315
492
  this.handleGrep(parts, line, commands);
@@ -327,8 +504,8 @@ var LLMResponseParser = class {
327
504
  if (finishAccumulator) {
328
505
  const map = finishAccumulator;
329
506
  const entries = [...map.entries()];
330
- const filesPayload = entries.map(([path4, ranges]) => ({
331
- path: path4,
507
+ const filesPayload = entries.map(([path5, ranges]) => ({
508
+ path: path5,
332
509
  lines: [...ranges].sort((a, b) => a[0] - b[0])
333
510
  }));
334
511
  commands.push({ name: "finish", arguments: { files: filesPayload } });
@@ -360,18 +537,17 @@ var LLMResponseParser = class {
360
537
  skip(message) {
361
538
  return { name: "_skip", arguments: { message } };
362
539
  }
363
- handleAnalyse(parts, rawLine, commands) {
540
+ handleListDirectory(parts, rawLine, commands) {
364
541
  if (parts.length < 2) {
365
542
  commands.push(this.skip(
366
- `[SKIPPED] Your command "${rawLine}" is missing a path. Correct format: analyse <path> [pattern]. Example: analyse src/`
543
+ `[SKIPPED] Your command "${rawLine}" is missing a path. Correct format: list_directory <path> [pattern]. Example: list_directory src/`
367
544
  ));
368
545
  return;
369
546
  }
370
- const path4 = parts[1];
547
+ const path5 = parts[1];
371
548
  const pattern = parts[2]?.replace(/^"|"$/g, "") ?? null;
372
- commands.push({ name: "analyse", arguments: { path: path4, pattern } });
549
+ commands.push({ name: "list_directory", arguments: { path: path5, pattern } });
373
550
  }
374
- // no glob tool in MCP
375
551
  handleGrep(parts, rawLine, commands) {
376
552
  if (parts.length < 3) {
377
553
  commands.push(this.skip(
@@ -442,8 +618,30 @@ var LLMResponseParser = class {
442
618
  }
443
619
  };
444
620
 
445
- // tools/warp_grep/tools/read.ts
621
+ // tools/warp_grep/agent/tools/grep.ts
622
+ async function toolGrep(provider, args) {
623
+ const res = await provider.grep(args);
624
+ if (res.error) {
625
+ return { output: res.error };
626
+ }
627
+ if (!res.lines.length) {
628
+ return { output: "no matches" };
629
+ }
630
+ return { output: res.lines.join("\n") };
631
+ }
632
+
633
+ // tools/warp_grep/agent/tools/read.ts
446
634
  async function toolRead(provider, args) {
635
+ if (args.lines && args.lines.length > 0) {
636
+ const chunks = [];
637
+ for (const [start, end] of args.lines) {
638
+ const res2 = await provider.read({ path: args.path, start, end });
639
+ if (res2.error) return res2.error;
640
+ chunks.push(res2.lines.join("\n"));
641
+ }
642
+ if (chunks.every((c) => c === "")) return "(empty file)";
643
+ return chunks.join("\n...\n");
644
+ }
447
645
  const res = await provider.read({ path: args.path, start: args.start, end: args.end });
448
646
  if (res.error) {
449
647
  return res.error;
@@ -452,16 +650,56 @@ async function toolRead(provider, args) {
452
650
  return res.lines.join("\n");
453
651
  }
454
652
 
455
- // tools/warp_grep/tools/analyse.ts
456
- async function toolAnalyse(provider, args) {
457
- const list = await provider.analyse({
653
+ // tools/warp_grep/agent/tools/list_directory.ts
654
+ async function toolListDirectory(provider, args) {
655
+ const list = await provider.listDirectory({
458
656
  path: args.path,
459
657
  pattern: args.pattern ?? null,
460
- maxResults: args.maxResults ?? 100,
461
- maxDepth: args.maxDepth ?? 2
658
+ maxResults: args.maxResults ?? AGENT_CONFIG.MAX_OUTPUT_LINES,
659
+ maxDepth: args.maxDepth ?? AGENT_CONFIG.MAX_LIST_DEPTH
462
660
  });
463
661
  if (!list.length) return "empty";
464
- return list.map((e) => `${" ".repeat(e.depth)}- ${e.type === "dir" ? "[D]" : "[F]"} ${e.name}`).join("\n");
662
+ if (list.length >= AGENT_CONFIG.MAX_OUTPUT_LINES) {
663
+ return "query not specific enough, tool called tried to return too much context and failed";
664
+ }
665
+ return list.map((e) => {
666
+ const indent = " ".repeat(e.depth);
667
+ const name = e.type === "dir" ? `${e.name}/` : e.name;
668
+ return `${indent}${name}`;
669
+ }).join("\n");
670
+ }
671
+
672
+ // tools/warp_grep/agent/tools/finish.ts
673
+ async function readFinishFiles(repoRoot, files, reader) {
674
+ const out = [];
675
+ for (const f of files) {
676
+ const ranges = mergeRanges(f.lines);
677
+ const chunks = [];
678
+ for (const [s, e] of ranges) {
679
+ const lines = await reader(f.path, s, e);
680
+ chunks.push(lines.join("\n"));
681
+ }
682
+ out.push({ path: f.path, ranges, content: chunks.join("\n") });
683
+ }
684
+ return out;
685
+ }
686
+ function mergeRanges(ranges) {
687
+ if (!ranges.length) return [];
688
+ const sorted = [...ranges].sort((a, b) => a[0] - b[0]);
689
+ const merged = [];
690
+ let [cs, ce] = sorted[0];
691
+ for (let i = 1; i < sorted.length; i++) {
692
+ const [s, e] = sorted[i];
693
+ if (s <= ce + 1) {
694
+ ce = Math.max(ce, e);
695
+ } else {
696
+ merged.push([cs, ce]);
697
+ cs = s;
698
+ ce = e;
699
+ }
700
+ }
701
+ merged.push([cs, ce]);
702
+ return merged;
465
703
  }
466
704
 
467
705
  // tools/utils/resilience.ts
@@ -554,8 +792,8 @@ var ToolOutputFormatter = class {
554
792
  switch (name) {
555
793
  case "read":
556
794
  return this.formatRead(safeArgs, payload, isError);
557
- case "analyse":
558
- return this.formatAnalyse(safeArgs, payload, isError);
795
+ case "list_directory":
796
+ return this.formatListDirectory(safeArgs, payload, isError);
559
797
  case "grep":
560
798
  return this.formatGrep(safeArgs, payload, isError);
561
799
  default:
@@ -568,39 +806,56 @@ ${payload}
568
806
  if (isError) {
569
807
  return payload;
570
808
  }
571
- const path4 = this.asString(args.path) || "...";
572
- return `<file path="${path4}">
809
+ const path5 = this.asString(args.path) || "...";
810
+ const start = args.start;
811
+ const end = args.end;
812
+ const linesArray = args.lines;
813
+ const attributes = [`path="${path5}"`];
814
+ if (linesArray && linesArray.length > 0) {
815
+ const rangeStr = linesArray.map(([s, e]) => `${s}-${e}`).join(",");
816
+ attributes.push(`lines="${rangeStr}"`);
817
+ } else if (start !== void 0 && end !== void 0) {
818
+ attributes.push(`lines="${start}-${end}"`);
819
+ }
820
+ return `<read ${attributes.join(" ")}>
573
821
  ${payload}
574
- </file>`;
822
+ </read>`;
575
823
  }
576
- formatAnalyse(args, payload, isError) {
577
- const path4 = this.asString(args.path) || ".";
824
+ formatListDirectory(args, payload, isError) {
825
+ const path5 = this.asString(args.path) || ".";
826
+ const pattern = this.asString(args.pattern);
827
+ const attributes = [`path="${path5}"`];
828
+ if (pattern) {
829
+ attributes.push(`pattern="${pattern}"`);
830
+ }
578
831
  if (isError) {
579
- return `<analyse_results path="${path4}" status="error">
580
- ${payload}
581
- </analyse_results>`;
832
+ attributes.push('status="error"');
582
833
  }
583
- return `<analyse_results path="${path4}">
834
+ return `<list_directory ${attributes.join(" ")}>
584
835
  ${payload}
585
- </analyse_results>`;
836
+ </list_directory>`;
586
837
  }
587
838
  formatGrep(args, payload, isError) {
588
839
  const pattern = this.asString(args.pattern);
589
- const path4 = this.asString(args.path);
840
+ const subDir = this.asString(args.path);
841
+ const glob = this.asString(args.glob);
590
842
  const attributes = [];
591
843
  if (pattern !== void 0) {
592
844
  attributes.push(`pattern="${pattern}"`);
593
845
  }
594
- if (path4 !== void 0) {
595
- attributes.push(`path="${path4}"`);
846
+ if (subDir !== void 0) {
847
+ attributes.push(`sub_dir="${subDir}"`);
848
+ }
849
+ if (glob !== void 0) {
850
+ attributes.push(`glob="${glob}"`);
596
851
  }
597
852
  if (isError) {
598
853
  attributes.push('status="error"');
599
854
  }
600
855
  const attrText = attributes.length ? ` ${attributes.join(" ")}` : "";
601
- return `<grep_output${attrText}>
856
+ return `<grep${attrText}>
602
857
  ${payload}
603
- </grep_output>`;
858
+ </grep>`;
604
859
  }
605
860
  asString(value) {
606
861
  if (value === null || value === void 0) {
@@ -614,66 +869,100 @@ function formatAgentToolOutput(toolName, args, output, options = {}) {
614
869
  return sharedFormatter.format(toolName, args, output, options);
615
870
  }
616
871
 
617
- // tools/warp_grep/tools/finish.ts
618
- async function readFinishFiles(repoRoot, files, reader) {
619
- const out = [];
620
- for (const f of files) {
621
- const ranges = mergeRanges(f.lines);
622
- const chunks = [];
623
- for (const [s, e] of ranges) {
624
- const lines = await reader(f.path, s, e);
625
- chunks.push(lines.join("\n"));
626
- }
627
- out.push({ path: f.path, ranges, content: chunks.join("\n") });
872
+ // tools/warp_grep/agent/helpers.ts
873
+ var import_path = __toESM(require("path"), 1);
874
+ var TRUNCATED_MARKER = "[truncated for context limit]";
875
+ function formatTurnMessage(turnsUsed, maxTurns) {
876
+ const turnsRemaining = maxTurns - turnsUsed;
877
+ if (turnsRemaining === 1) {
878
+ return `
879
+ 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`;
628
880
  }
629
- return out;
881
+ return `
882
+ You have used ${turnsUsed} turn${turnsUsed === 1 ? "" : "s"} and have ${turnsRemaining} remaining`;
630
883
  }
631
- function mergeRanges(ranges) {
632
- if (!ranges.length) return [];
633
- const sorted = [...ranges].sort((a, b) => a[0] - b[0]);
634
- const merged = [];
635
- let [cs, ce] = sorted[0];
636
- for (let i = 1; i < sorted.length; i++) {
637
- const [s, e] = sorted[i];
638
- if (s <= ce + 1) {
639
- ce = Math.max(ce, e);
640
- } else {
641
- merged.push([cs, ce]);
642
- cs = s;
643
- ce = e;
644
- }
645
- }
646
- merged.push([cs, ce]);
647
- return merged;
884
+ function calculateContextBudget(messages) {
885
+ const totalChars = messages.reduce((sum, m) => sum + m.content.length, 0);
886
+ const maxChars = AGENT_CONFIG.MAX_CONTEXT_CHARS;
887
+ const percent = Math.round(totalChars / maxChars * 100);
888
+ const usedK = Math.round(totalChars / 1e3);
889
+ const maxK = Math.round(maxChars / 1e3);
890
+ return `<context_budget>${percent}% (${usedK}K/${maxK}K chars)</context_budget>`;
648
891
  }
649
-
650
- // tools/warp_grep/agent/runner.ts
651
- var import_path = __toESM(require("path"), 1);
652
- var parser = new LLMResponseParser();
653
892
  async function buildInitialState(repoRoot, query, provider) {
654
893
  try {
655
- const entries = await provider.analyse({ path: ".", maxResults: 100 });
656
- const dirs = entries.filter((e) => e.type === "dir").map((d) => d.name).slice(0, 50);
657
- const files = entries.filter((e) => e.type === "file").map((f) => f.name).slice(0, 50);
658
- const parts = [
659
- `<repo_root>${repoRoot}</repo_root>`,
660
- `<top_dirs>${dirs.join(", ")}</top_dirs>`,
661
- `<top_files>${files.join(", ")}</top_files>`
662
- ];
663
- return parts.join("\n");
894
+ const entries = await provider.listDirectory({
895
+ path: ".",
896
+ maxResults: AGENT_CONFIG.MAX_OUTPUT_LINES,
897
+ maxDepth: 2
898
+ });
899
+ const treeLines = entries.map((e) => {
900
+ const indent = " ".repeat(e.depth);
901
+ const name = e.type === "dir" ? `${e.name}/` : e.name;
902
+ return `${indent}${name}`;
903
+ });
904
+ const repoName = import_path.default.basename(repoRoot);
905
+ const treeOutput = treeLines.length > 0 ? `${repoName}/
906
+ ${treeLines.join("\n")}` : `${repoName}/`;
907
+ return `<repo_structure>
908
+ ${treeOutput}
909
+ </repo_structure>
910
+
911
+ <search_string>
912
+ ${query}
913
+ </search_string>`;
664
914
  } catch {
665
- return `<repo_root>${repoRoot}</repo_root>`;
915
+ const repoName = import_path.default.basename(repoRoot);
916
+ return `<repo_structure>
917
+ ${repoName}/
918
+ </repo_structure>
919
+
920
+ <search_string>
921
+ ${query}
922
+ </search_string>`;
666
923
  }
667
924
  }
668
- async function callModel(messages, model, apiKey) {
669
- const api = "https://api.morphllm.com/v1/chat/completions";
925
+ function enforceContextLimit(messages, maxChars = AGENT_CONFIG.MAX_CONTEXT_CHARS) {
926
+ const getTotalChars = () => messages.reduce((sum, m) => sum + m.content.length, 0);
927
+ if (getTotalChars() <= maxChars) {
928
+ return messages;
929
+ }
930
+ const userIndices = [];
931
+ let firstUserSkipped = false;
932
+ for (let i = 0; i < messages.length; i++) {
933
+ if (messages[i].role === "user") {
934
+ if (!firstUserSkipped) {
935
+ firstUserSkipped = true;
936
+ continue;
937
+ }
938
+ userIndices.push(i);
939
+ }
940
+ }
941
+ for (const idx of userIndices) {
942
+ if (getTotalChars() <= maxChars) {
943
+ break;
944
+ }
945
+ if (messages[idx].content !== TRUNCATED_MARKER) {
946
+ messages[idx] = { role: "user", content: TRUNCATED_MARKER };
947
+ }
948
+ }
949
+ return messages;
950
+ }
951
+
952
+ // tools/warp_grep/agent/runner.ts
953
+ var import_path2 = __toESM(require("path"), 1);
954
+ var parser = new LLMResponseParser();
955
+ var DEFAULT_API_URL = "https://api.morphllm.com";
956
+ async function callModel(messages, model, options = {}) {
957
+ const baseUrl = DEFAULT_API_URL;
958
+ const apiKey = options.morphApiKey || process.env.MORPH_API_KEY || "";
670
959
  const fetchPromise = fetchWithRetry(
671
- api,
960
+ `${baseUrl}/v1/chat/completions`,
672
961
  {
673
962
  method: "POST",
674
963
  headers: {
675
964
  "Content-Type": "application/json",
676
- Authorization: `Bearer ${apiKey || process.env.MORPH_API_KEY || ""}`
965
+ Authorization: `Bearer ${apiKey}`
677
966
  },
678
967
  body: JSON.stringify({
679
968
  model,
@@ -682,10 +971,15 @@ async function callModel(messages, model, apiKey) {
682
971
  messages
683
972
  })
684
973
  },
685
- {}
974
+ options.retryConfig
686
975
  );
687
976
  const resp = await withTimeout(fetchPromise, AGENT_CONFIG.TIMEOUT_MS, "morph-warp-grep request timed out");
688
977
  if (!resp.ok) {
978
+ if (resp.status === 404) {
979
+ throw new Error(
980
+ "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"
981
+ );
982
+ }
689
983
  const t = await resp.text();
690
984
  throw new Error(`morph-warp-grep error ${resp.status}: ${t}`);
691
985
  }
@@ -697,22 +991,24 @@ async function callModel(messages, model, apiKey) {
697
991
  return content;
698
992
  }
699
993
  async function runWarpGrep(config) {
700
- const repoRoot = import_path.default.resolve(config.repoRoot || process.cwd());
994
+ const repoRoot = import_path2.default.resolve(config.repoRoot || process.cwd());
701
995
  const messages = [];
702
- const systemMessage = { role: "system", content: getSystemPrompt() };
703
- messages.push(systemMessage);
704
- const queryContent = `<query>${config.query}</query>`;
705
- messages.push({ role: "user", content: queryContent });
996
+ messages.push({ role: "system", content: getSystemPrompt() });
706
997
  const initialState = await buildInitialState(repoRoot, config.query, config.provider);
707
998
  messages.push({ role: "user", content: initialState });
708
- const maxRounds = AGENT_CONFIG.MAX_ROUNDS;
999
+ const maxTurns = AGENT_CONFIG.MAX_TURNS;
709
1000
  const model = config.model || DEFAULT_MODEL;
710
1001
  const provider = config.provider;
711
1002
  const errors = [];
712
1003
  let finishMeta;
713
1004
  let terminationReason = "terminated";
714
- for (let round = 1; round <= maxRounds; round += 1) {
715
- const assistantContent = await callModel(messages, model, config.apiKey).catch((e) => {
1005
+ for (let turn = 1; turn <= maxTurns; turn += 1) {
1006
+ enforceContextLimit(messages);
1007
+ const assistantContent = await callModel(messages, model, {
1008
+ morphApiKey: config.morphApiKey,
1009
+ morphApiUrl: config.morphApiUrl,
1010
+ retryConfig: config.retryConfig
1011
+ }).catch((e) => {
716
1012
  errors.push({ message: e instanceof Error ? e.message : String(e) });
717
1013
  return "";
718
1014
  });
@@ -720,13 +1016,13 @@ async function runWarpGrep(config) {
720
1016
  messages.push({ role: "assistant", content: assistantContent });
721
1017
  const toolCalls = parser.parse(assistantContent);
722
1018
  if (toolCalls.length === 0) {
723
- errors.push({ message: "No tool calls produced by the model." });
1019
+ 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" });
724
1020
  terminationReason = "terminated";
725
1021
  break;
726
1022
  }
727
1023
  const finishCalls = toolCalls.filter((c) => c.name === "finish");
728
1024
  const grepCalls = toolCalls.filter((c) => c.name === "grep");
729
- const analyseCalls = toolCalls.filter((c) => c.name === "analyse");
1025
+ const listDirCalls = toolCalls.filter((c) => c.name === "list_directory");
730
1026
  const readCalls = toolCalls.filter((c) => c.name === "read");
731
1027
  const skipCalls = toolCalls.filter((c) => c.name === "_skip");
732
1028
  const formatted = [];
@@ -738,24 +1034,18 @@ async function runWarpGrep(config) {
738
1034
  for (const c of grepCalls) {
739
1035
  const args = c.arguments ?? {};
740
1036
  allPromises.push(
741
- provider.grep({ pattern: args.pattern, path: args.path }).then(
742
- (grepRes) => {
743
- if (grepRes.error) {
744
- return { terminate: true, error: grepRes.error };
745
- }
746
- const output = grepRes.lines.join("\n") || "no matches";
747
- return formatAgentToolOutput("grep", args, output, { isError: false });
748
- },
1037
+ toolGrep(provider, args).then(
1038
+ ({ output }) => formatAgentToolOutput("grep", args, output, { isError: false }),
749
1039
  (err) => formatAgentToolOutput("grep", args, String(err), { isError: true })
750
1040
  )
751
1041
  );
752
1042
  }
753
- for (const c of analyseCalls) {
1043
+ for (const c of listDirCalls) {
754
1044
  const args = c.arguments ?? {};
755
1045
  allPromises.push(
756
- toolAnalyse(provider, args).then(
757
- (p) => formatAgentToolOutput("analyse", args, p, { isError: false }),
758
- (err) => formatAgentToolOutput("analyse", args, String(err), { isError: true })
1046
+ toolListDirectory(provider, args).then(
1047
+ (p) => formatAgentToolOutput("list_directory", args, p, { isError: false }),
1048
+ (err) => formatAgentToolOutput("list_directory", args, String(err), { isError: true })
759
1049
  )
760
1050
  );
761
1051
  }
@@ -770,34 +1060,12 @@ async function runWarpGrep(config) {
770
1060
  }
771
1061
  const allResults = await Promise.all(allPromises);
772
1062
  for (const result of allResults) {
773
- if (typeof result === "object" && "terminate" in result) {
774
- errors.push({ message: result.error });
775
- return {
776
- terminationReason: "terminated",
777
- messages,
778
- errors
779
- };
780
- }
781
1063
  formatted.push(result);
782
1064
  }
783
1065
  if (formatted.length > 0) {
784
- const turnsUsed = round;
785
- const turnsRemaining = 4 - turnsUsed;
786
- let turnMessage;
787
- if (turnsRemaining === 0) {
788
- turnMessage = `
789
-
790
- [Turn ${turnsUsed}/4] This is your LAST turn. You MUST call the finish tool now.`;
791
- } else if (turnsRemaining === 1) {
792
- turnMessage = `
793
-
794
- [Turn ${turnsUsed}/4] You have 1 turn remaining. Next turn you MUST call the finish tool.`;
795
- } else {
796
- turnMessage = `
797
-
798
- [Turn ${turnsUsed}/4] You have ${turnsRemaining} turns remaining.`;
799
- }
800
- messages.push({ role: "user", content: formatted.join("\n") + turnMessage });
1066
+ const turnMessage = formatTurnMessage(turn, maxTurns);
1067
+ const contextBudget = calculateContextBudget(messages);
1068
+ messages.push({ role: "user", content: formatted.join("\n") + turnMessage + "\n" + contextBudget });
801
1069
  }
802
1070
  if (finishCalls.length) {
803
1071
  const fc = finishCalls[0];
@@ -847,7 +1115,7 @@ async function runWarpGrep(config) {
847
1115
 
848
1116
  // tools/warp_grep/providers/local.ts
849
1117
  var import_promises2 = __toESM(require("fs/promises"), 1);
850
- var import_path3 = __toESM(require("path"), 1);
1118
+ var import_path4 = __toESM(require("path"), 1);
851
1119
 
852
1120
  // tools/warp_grep/utils/ripgrep.ts
853
1121
  var import_child_process = require("child_process");
@@ -912,21 +1180,21 @@ async function runRipgrep(args, opts) {
912
1180
 
913
1181
  // tools/warp_grep/utils/paths.ts
914
1182
  var import_fs = __toESM(require("fs"), 1);
915
- var import_path2 = __toESM(require("path"), 1);
1183
+ var import_path3 = __toESM(require("path"), 1);
916
1184
  function resolveUnderRepo(repoRoot, targetPath) {
917
- const absRoot = import_path2.default.resolve(repoRoot);
918
- const resolved = import_path2.default.resolve(absRoot, targetPath);
1185
+ const absRoot = import_path3.default.resolve(repoRoot);
1186
+ const resolved = import_path3.default.resolve(absRoot, targetPath);
919
1187
  ensureWithinRepo(absRoot, resolved);
920
1188
  return resolved;
921
1189
  }
922
1190
  function ensureWithinRepo(repoRoot, absTarget) {
923
- const rel = import_path2.default.relative(import_path2.default.resolve(repoRoot), import_path2.default.resolve(absTarget));
924
- if (rel.startsWith("..") || import_path2.default.isAbsolute(rel)) {
1191
+ const rel = import_path3.default.relative(import_path3.default.resolve(repoRoot), import_path3.default.resolve(absTarget));
1192
+ if (rel.startsWith("..") || import_path3.default.isAbsolute(rel)) {
925
1193
  throw new Error(`Path outside repository root: ${absTarget}`);
926
1194
  }
927
1195
  }
928
1196
  function toRepoRelative(repoRoot, absPath) {
929
- return import_path2.default.relative(import_path2.default.resolve(repoRoot), import_path2.default.resolve(absPath));
1197
+ return import_path3.default.relative(import_path3.default.resolve(repoRoot), import_path3.default.resolve(absPath));
930
1198
  }
931
1199
  function isSymlink(p) {
932
1200
  try {
@@ -969,10 +1237,18 @@ var LocalRipgrepProvider = class {
969
1237
  this.excludes = excludes;
970
1238
  }
971
1239
  async grep(params) {
972
- const abs = resolveUnderRepo(this.repoRoot, params.path);
1240
+ let abs;
1241
+ try {
1242
+ abs = resolveUnderRepo(this.repoRoot, params.path);
1243
+ } catch (err) {
1244
+ return {
1245
+ lines: [],
1246
+ error: `[PATH ERROR] ${err instanceof Error ? err.message : String(err)}`
1247
+ };
1248
+ }
973
1249
  const stat = await import_promises2.default.stat(abs).catch(() => null);
974
1250
  if (!stat) return { lines: [] };
975
- const targetArg = abs === import_path3.default.resolve(this.repoRoot) ? "." : toRepoRelative(this.repoRoot, abs);
1251
+ const targetArg = abs === import_path4.default.resolve(this.repoRoot) ? "." : toRepoRelative(this.repoRoot, abs);
976
1252
  const args = [
977
1253
  "--no-config",
978
1254
  "--no-heading",
@@ -981,6 +1257,9 @@ var LocalRipgrepProvider = class {
981
1257
  "--color=never",
982
1258
  "--trim",
983
1259
  "--max-columns=400",
1260
+ "-C",
1261
+ "1",
1262
+ ...params.glob ? ["--glob", params.glob] : [],
984
1263
  ...this.excludes.flatMap((e) => ["-g", `!${e}`]),
985
1264
  params.pattern,
986
1265
  targetArg || "."
@@ -1005,29 +1284,24 @@ Details: ${res.stderr}` : ""}`
1005
1284
  };
1006
1285
  }
1007
1286
  const lines = (res.stdout || "").trim().split(/\r?\n/).filter((l) => l.length > 0);
1008
- return { lines };
1009
- }
1010
- async glob(params) {
1011
- const abs = resolveUnderRepo(this.repoRoot, params.path);
1012
- const targetArg = abs === import_path3.default.resolve(this.repoRoot) ? "." : toRepoRelative(this.repoRoot, abs);
1013
- const args = [
1014
- "--no-config",
1015
- "--files",
1016
- "-g",
1017
- params.pattern,
1018
- ...this.excludes.flatMap((e) => ["-g", `!${e}`]),
1019
- targetArg || "."
1020
- ];
1021
- const res = await runRipgrep(args, { cwd: this.repoRoot });
1022
- if (res.exitCode === -1) {
1023
- console.warn(`[warp_grep] ripgrep not available for glob: ${res.stderr || "execution failed"}`);
1024
- return { files: [] };
1287
+ if (lines.length > AGENT_CONFIG.MAX_OUTPUT_LINES) {
1288
+ return {
1289
+ lines: [],
1290
+ error: "query not specific enough, tool tried to return too much context and failed"
1291
+ };
1025
1292
  }
1026
- const files = (res.stdout || "").trim().split(/\r?\n/).filter((l) => l.length > 0);
1027
- return { files };
1293
+ return { lines };
1028
1294
  }
1029
1295
  async read(params) {
1030
- const abs = resolveUnderRepo(this.repoRoot, params.path);
1296
+ let abs;
1297
+ try {
1298
+ abs = resolveUnderRepo(this.repoRoot, params.path);
1299
+ } catch (err) {
1300
+ return {
1301
+ lines: [],
1302
+ error: `[PATH ERROR] ${err instanceof Error ? err.message : String(err)}`
1303
+ };
1304
+ }
1031
1305
  const stat = await import_promises2.default.stat(abs).catch(() => null);
1032
1306
  if (!stat || !stat.isFile()) {
1033
1307
  return {
@@ -1047,7 +1321,15 @@ Details: ${res.stderr}` : ""}`
1047
1321
  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.`
1048
1322
  };
1049
1323
  }
1050
- const lines = await readAllLines(abs);
1324
+ let lines;
1325
+ try {
1326
+ lines = await readAllLines(abs);
1327
+ } catch (err) {
1328
+ return {
1329
+ lines: [],
1330
+ error: `[READ ERROR] Failed to read "${params.path}": ${err instanceof Error ? err.message : String(err)}`
1331
+ };
1332
+ }
1051
1333
  const total = lines.length;
1052
1334
  let s = params.start ?? 1;
1053
1335
  let e = Math.min(params.end ?? total, total);
@@ -1060,30 +1342,46 @@ Details: ${res.stderr}` : ""}`
1060
1342
  const content = lines[i - 1] ?? "";
1061
1343
  out.push(`${i}|${content}`);
1062
1344
  }
1345
+ if (out.length > AGENT_CONFIG.MAX_READ_LINES) {
1346
+ const truncated = out.slice(0, AGENT_CONFIG.MAX_READ_LINES);
1347
+ truncated.push(`... [truncated: showing ${AGENT_CONFIG.MAX_READ_LINES} of ${out.length} lines]`);
1348
+ return { lines: truncated };
1349
+ }
1063
1350
  return { lines: out };
1064
1351
  }
1065
- async analyse(params) {
1066
- const abs = resolveUnderRepo(this.repoRoot, params.path);
1352
+ async listDirectory(params) {
1353
+ let abs;
1354
+ try {
1355
+ abs = resolveUnderRepo(this.repoRoot, params.path);
1356
+ } catch {
1357
+ return [];
1358
+ }
1067
1359
  const stat = await import_promises2.default.stat(abs).catch(() => null);
1068
1360
  if (!stat || !stat.isDirectory()) {
1069
1361
  return [];
1070
1362
  }
1071
- const maxResults = params.maxResults ?? 100;
1072
- const maxDepth = params.maxDepth ?? 2;
1363
+ const maxResults = params.maxResults ?? AGENT_CONFIG.MAX_OUTPUT_LINES;
1364
+ const maxDepth = params.maxDepth ?? AGENT_CONFIG.MAX_LIST_DEPTH;
1073
1365
  const regex = params.pattern ? new RegExp(params.pattern) : null;
1074
1366
  const results = [];
1367
+ let timedOut = false;
1368
+ const startTime = Date.now();
1075
1369
  async function walk(dir, depth) {
1370
+ if (Date.now() - startTime > AGENT_CONFIG.LIST_TIMEOUT_MS) {
1371
+ timedOut = true;
1372
+ return;
1373
+ }
1076
1374
  if (depth > maxDepth || results.length >= maxResults) return;
1077
1375
  const entries = await import_promises2.default.readdir(dir, { withFileTypes: true });
1078
1376
  for (const entry of entries) {
1079
- const full = import_path3.default.join(dir, entry.name);
1377
+ if (timedOut || results.length >= maxResults) break;
1378
+ const full = import_path4.default.join(dir, entry.name);
1080
1379
  const rel = toRepoRelative(abs, full).replace(/^[.][/\\]?/, "");
1081
- if (DEFAULT_EXCLUDES.some((ex) => rel.split(import_path3.default.sep).includes(ex))) continue;
1380
+ if (DEFAULT_EXCLUDES.some((ex) => rel.split(import_path4.default.sep).includes(ex))) continue;
1082
1381
  if (regex && !regex.test(entry.name)) continue;
1083
- if (results.length >= maxResults) break;
1084
1382
  results.push({
1085
1383
  name: entry.name,
1086
- path: toRepoRelative(import_path3.default.resolve(""), full),
1384
+ path: toRepoRelative(import_path4.default.resolve(""), full),
1087
1385
  // relative display
1088
1386
  type: entry.isDirectory() ? "dir" : "file",
1089
1387
  depth
@@ -1098,10 +1396,121 @@ Details: ${res.stderr}` : ""}`
1098
1396
  }
1099
1397
  };
1100
1398
 
1101
- // tools/warp_grep/prompts.ts
1102
- 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.';
1399
+ // tools/warp_grep/providers/remote.ts
1400
+ var RemoteCommandsProvider = class {
1401
+ constructor(repoRoot, commands) {
1402
+ this.repoRoot = repoRoot;
1403
+ this.commands = commands;
1404
+ }
1405
+ /**
1406
+ * Run grep command and parse ripgrep output
1407
+ */
1408
+ async grep(params) {
1409
+ try {
1410
+ const stdout = await this.commands.grep(params.pattern, params.path, params.glob);
1411
+ const lines = (stdout || "").trim().split(/\r?\n/).filter((l) => l.length > 0);
1412
+ if (lines.length > AGENT_CONFIG.MAX_OUTPUT_LINES) {
1413
+ return {
1414
+ lines: [],
1415
+ error: "Query not specific enough - too many results returned. Try a more specific pattern."
1416
+ };
1417
+ }
1418
+ return { lines };
1419
+ } catch (error) {
1420
+ return {
1421
+ lines: [],
1422
+ error: `[GREP ERROR] ${error instanceof Error ? error.message : String(error)}`
1423
+ };
1424
+ }
1425
+ }
1426
+ /**
1427
+ * Read file and add line numbers
1428
+ */
1429
+ async read(params) {
1430
+ const start = params.start ?? 1;
1431
+ const end = params.end ?? 1e6;
1432
+ try {
1433
+ const stdout = await this.commands.read(params.path, start, end);
1434
+ const contentLines = (stdout || "").split("\n");
1435
+ if (contentLines.length > 0 && contentLines[contentLines.length - 1] === "") {
1436
+ contentLines.pop();
1437
+ }
1438
+ const lines = contentLines.map((content, idx) => `${start + idx}|${content}`);
1439
+ if (lines.length > AGENT_CONFIG.MAX_READ_LINES) {
1440
+ const truncated = lines.slice(0, AGENT_CONFIG.MAX_READ_LINES);
1441
+ truncated.push(`... [truncated: showing ${AGENT_CONFIG.MAX_READ_LINES} of ${lines.length} lines]`);
1442
+ return { lines: truncated };
1443
+ }
1444
+ return { lines };
1445
+ } catch (error) {
1446
+ return {
1447
+ lines: [],
1448
+ error: `[READ ERROR] ${error instanceof Error ? error.message : String(error)}`
1449
+ };
1450
+ }
1451
+ }
1452
+ /**
1453
+ * List directory and parse find output
1454
+ */
1455
+ async listDirectory(params) {
1456
+ const maxDepth = params.maxDepth ?? AGENT_CONFIG.MAX_LIST_DEPTH;
1457
+ const maxResults = params.maxResults ?? AGENT_CONFIG.MAX_OUTPUT_LINES;
1458
+ try {
1459
+ const stdout = await this.commands.listDir(params.path, maxDepth);
1460
+ const paths = (stdout || "").trim().split(/\r?\n/).filter((p) => p.length > 0);
1461
+ const regex = params.pattern ? new RegExp(params.pattern) : null;
1462
+ const entries = [];
1463
+ for (const fullPath of paths) {
1464
+ if (fullPath === params.path || fullPath === this.repoRoot) continue;
1465
+ const name = fullPath.split("/").pop() || "";
1466
+ if (regex && !regex.test(name)) continue;
1467
+ let relativePath = fullPath;
1468
+ if (fullPath.startsWith(this.repoRoot)) {
1469
+ relativePath = fullPath.slice(this.repoRoot.length).replace(/^\//, "");
1470
+ }
1471
+ const depth = relativePath.split("/").filter(Boolean).length - 1;
1472
+ const hasExtension = name.includes(".") && !name.startsWith(".");
1473
+ const type = hasExtension ? "file" : "dir";
1474
+ entries.push({
1475
+ name,
1476
+ path: relativePath,
1477
+ type,
1478
+ depth: Math.max(0, depth)
1479
+ });
1480
+ if (entries.length >= maxResults) break;
1481
+ }
1482
+ return entries;
1483
+ } catch (error) {
1484
+ return [];
1485
+ }
1486
+ }
1487
+ };
1103
1488
 
1104
- // tools/warp_grep/core.ts
1489
+ // tools/warp_grep/client.ts
1490
+ async function executeToolCall(input, config) {
1491
+ const parsed = typeof input === "string" ? JSON.parse(input) : input;
1492
+ const provider = config.remoteCommands ? new RemoteCommandsProvider(config.repoRoot, config.remoteCommands) : config.provider ?? new LocalRipgrepProvider(config.repoRoot, config.excludes);
1493
+ const result = await runWarpGrep({
1494
+ query: parsed.query,
1495
+ repoRoot: config.repoRoot,
1496
+ provider,
1497
+ excludes: config.excludes,
1498
+ includes: config.includes,
1499
+ debug: config.debug ?? false,
1500
+ morphApiKey: config.morphApiKey,
1501
+ morphApiUrl: config.morphApiUrl,
1502
+ retryConfig: config.retryConfig
1503
+ });
1504
+ const finish = result.finish;
1505
+ if (result.terminationReason !== "completed" || !finish?.metadata) {
1506
+ return { success: false, error: "Search did not complete" };
1507
+ }
1508
+ const contexts = (finish.resolved ?? []).map((r) => ({
1509
+ file: r.path,
1510
+ content: r.content
1511
+ }));
1512
+ return { success: true, contexts, summary: finish.payload };
1513
+ }
1105
1514
  function formatResult(result) {
1106
1515
  if (!result.success) {
1107
1516
  return `Search failed: ${result.error}`;
@@ -1125,61 +1534,37 @@ function formatResult(result) {
1125
1534
  return lines.join("\n");
1126
1535
  }
1127
1536
 
1537
+ // tools/warp_grep/prompts.ts
1538
+ 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.';
1539
+
1128
1540
  // tools/warp_grep/vercel.ts
1129
- var warpGrepSchema = import_zod.z.object({
1130
- query: import_zod.z.string().describe("Free-form repository question")
1131
- });
1132
1541
  async function execute(input, config) {
1133
- const provider = config.provider ?? new LocalRipgrepProvider(config.repoRoot, config.excludes);
1134
- const result = await runWarpGrep({
1135
- query: input.query,
1136
- repoRoot: config.repoRoot,
1137
- provider,
1138
- excludes: config.excludes,
1139
- includes: config.includes,
1140
- debug: config.debug ?? false,
1141
- apiKey: config.apiKey
1142
- });
1143
- const finish = result.finish;
1144
- if (result.terminationReason !== "completed" || !finish?.metadata) {
1145
- return { success: false, error: "Search did not complete" };
1146
- }
1147
- const contexts = (finish.resolved ?? []).map((r) => ({
1148
- file: r.path,
1149
- content: r.content
1150
- }));
1151
- return { success: true, contexts, summary: finish.payload };
1542
+ return executeToolCall(input, config);
1152
1543
  }
1153
- function createMorphWarpGrepTool(config) {
1544
+ function createWarpGrepTool(config) {
1545
+ const schema = import_zod.z.object({
1546
+ query: import_zod.z.string().describe("Free-form repository question")
1547
+ });
1154
1548
  return (0, import_ai.tool)({
1155
1549
  description: config.description ?? WARP_GREP_DESCRIPTION,
1156
- inputSchema: warpGrepSchema,
1550
+ inputSchema: schema,
1157
1551
  execute: async (params) => {
1158
- const provider = config.provider ?? new LocalRipgrepProvider(config.repoRoot, config.excludes);
1159
- const result = await runWarpGrep({
1160
- query: params.query,
1161
- repoRoot: config.repoRoot,
1162
- provider,
1163
- excludes: config.excludes,
1164
- includes: config.includes,
1165
- debug: config.debug ?? false,
1166
- apiKey: config.apiKey
1167
- });
1168
- const finish = result.finish;
1169
- if (result.terminationReason !== "completed" || !finish?.metadata) {
1170
- return { success: false, error: "Search did not complete" };
1552
+ const result = await executeToolCall(params, config);
1553
+ if (!result.success) {
1554
+ throw new Error(`Failed to search codebase: ${result.error}`);
1171
1555
  }
1172
- const contexts = (finish.resolved ?? []).map((r) => ({
1173
- file: r.path,
1174
- content: r.content
1175
- }));
1176
- return { success: true, contexts, summary: finish.payload };
1556
+ return {
1557
+ success: true,
1558
+ contexts: result.contexts,
1559
+ summary: result.summary
1560
+ };
1177
1561
  }
1178
1562
  });
1179
1563
  }
1564
+ var vercel_default = createWarpGrepTool;
1180
1565
  // Annotate the CommonJS export names for ESM import in node:
1181
1566
  0 && (module.exports = {
1182
- createMorphWarpGrepTool,
1567
+ createWarpGrepTool,
1183
1568
  execute,
1184
1569
  formatResult,
1185
1570
  getSystemPrompt