@travisennis/acai 0.0.12 → 0.0.13

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 (237) hide show
  1. package/README.md +3 -2
  2. package/dist/agent/index.d.ts.map +1 -1
  3. package/dist/agent/index.js +2 -5
  4. package/dist/commands/history/types.d.ts +3 -2
  5. package/dist/commands/history/types.d.ts.map +1 -1
  6. package/dist/commands/init-project/utils.d.ts +0 -1
  7. package/dist/commands/init-project/utils.d.ts.map +1 -1
  8. package/dist/commands/init-project/utils.js +1 -1
  9. package/dist/commands/manager.d.ts.map +1 -1
  10. package/dist/commands/manager.js +0 -18
  11. package/dist/commands/share/html-renderer.d.ts.map +1 -1
  12. package/dist/commands/share/html-renderer.js +54 -48
  13. package/dist/commands/tools/index.js +39 -38
  14. package/dist/config/index.d.ts +0 -2
  15. package/dist/config/index.d.ts.map +1 -1
  16. package/dist/config/index.js +2 -6
  17. package/dist/index.d.ts +14 -0
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +94 -76
  20. package/dist/models/manager.d.ts +1 -10
  21. package/dist/models/manager.d.ts.map +1 -1
  22. package/dist/models/manager.js +2 -2
  23. package/dist/models/opencode-go-provider.d.ts +4 -4
  24. package/dist/models/opencode-go-provider.d.ts.map +1 -1
  25. package/dist/models/opencode-go-provider.js +29 -35
  26. package/dist/models/providers.d.ts +1 -1
  27. package/dist/models/providers.d.ts.map +1 -1
  28. package/dist/prompts/system-prompt.d.ts +0 -2
  29. package/dist/prompts/system-prompt.d.ts.map +1 -1
  30. package/dist/prompts/system-prompt.js +6 -10
  31. package/dist/repl/index.d.ts +27 -11
  32. package/dist/repl/index.d.ts.map +1 -1
  33. package/dist/repl/index.js +238 -254
  34. package/dist/skills/index.d.ts +12 -2
  35. package/dist/skills/index.d.ts.map +1 -1
  36. package/dist/skills/index.js +123 -73
  37. package/dist/terminal/control.d.ts +1 -21
  38. package/dist/terminal/control.d.ts.map +1 -1
  39. package/dist/terminal/control.js +1 -32
  40. package/dist/terminal/formatting.d.ts +0 -33
  41. package/dist/terminal/formatting.d.ts.map +1 -1
  42. package/dist/terminal/formatting.js +0 -91
  43. package/dist/terminal/highlight/theme.d.ts +0 -37
  44. package/dist/terminal/highlight/theme.d.ts.map +1 -1
  45. package/dist/terminal/highlight/theme.js +1 -79
  46. package/dist/terminal/keys.d.ts +0 -97
  47. package/dist/terminal/keys.d.ts.map +1 -1
  48. package/dist/terminal/keys.js +0 -194
  49. package/dist/terminal/select-prompt.d.ts.map +1 -1
  50. package/dist/terminal/select-prompt.js +65 -51
  51. package/dist/terminal/style.d.ts +1 -1
  52. package/dist/terminal/style.d.ts.map +1 -1
  53. package/dist/terminal/supports-color.d.ts.map +1 -1
  54. package/dist/terminal/supports-color.js +38 -20
  55. package/dist/terminal/supports-hyperlinks.d.ts +3 -0
  56. package/dist/terminal/supports-hyperlinks.d.ts.map +1 -1
  57. package/dist/terminal/supports-hyperlinks.js +72 -31
  58. package/dist/terminal/table/layout-manager.d.ts +0 -20
  59. package/dist/terminal/table/layout-manager.d.ts.map +1 -1
  60. package/dist/terminal/table/layout-manager.js +68 -44
  61. package/dist/terminal/table/utils.d.ts +0 -1
  62. package/dist/terminal/table/utils.d.ts.map +1 -1
  63. package/dist/terminal/table/utils.js +2 -4
  64. package/dist/tools/apply-patch.d.ts +5 -3
  65. package/dist/tools/apply-patch.d.ts.map +1 -1
  66. package/dist/tools/apply-patch.js +154 -123
  67. package/dist/tools/bash.d.ts.map +1 -1
  68. package/dist/tools/bash.js +11 -8
  69. package/dist/tools/dynamic-tool-loader.d.ts +6 -1
  70. package/dist/tools/dynamic-tool-loader.d.ts.map +1 -1
  71. package/dist/tools/dynamic-tool-loader.js +154 -135
  72. package/dist/tools/index.d.ts +3 -133
  73. package/dist/tools/index.d.ts.map +1 -1
  74. package/dist/tools/index.js +0 -20
  75. package/dist/tools/read-file.d.ts.map +1 -1
  76. package/dist/tools/read-file.js +32 -13
  77. package/dist/tools/skill.d.ts.map +1 -1
  78. package/dist/tools/skill.js +20 -13
  79. package/dist/tools/web-fetch.d.ts +2 -6
  80. package/dist/tools/web-fetch.d.ts.map +1 -1
  81. package/dist/tools/web-fetch.js +59 -36
  82. package/dist/tools/web-search.d.ts +0 -4
  83. package/dist/tools/web-search.d.ts.map +1 -1
  84. package/dist/tools/web-search.js +40 -32
  85. package/dist/tui/autocomplete/utils.d.ts +0 -15
  86. package/dist/tui/autocomplete/utils.d.ts.map +1 -1
  87. package/dist/tui/autocomplete/utils.js +0 -85
  88. package/dist/tui/autocomplete.d.ts +1 -1
  89. package/dist/tui/autocomplete.d.ts.map +1 -1
  90. package/dist/tui/autocomplete.js +1 -1
  91. package/dist/tui/components/editor.d.ts +12 -0
  92. package/dist/tui/components/editor.d.ts.map +1 -1
  93. package/dist/tui/components/editor.js +181 -195
  94. package/dist/tui/components/input.d.ts +4 -0
  95. package/dist/tui/components/input.d.ts.map +1 -1
  96. package/dist/tui/components/input.js +33 -31
  97. package/dist/tui/components/markdown.d.ts +30 -0
  98. package/dist/tui/components/markdown.d.ts.map +1 -1
  99. package/dist/tui/components/markdown.js +274 -242
  100. package/dist/tui/components/modal.d.ts.map +1 -1
  101. package/dist/tui/components/modal.js +11 -11
  102. package/dist/tui/components/select-list.d.ts +5 -0
  103. package/dist/tui/components/select-list.d.ts.map +1 -1
  104. package/dist/tui/components/select-list.js +69 -98
  105. package/dist/tui/components/table.d.ts +6 -0
  106. package/dist/tui/components/table.d.ts.map +1 -1
  107. package/dist/tui/components/table.js +61 -52
  108. package/dist/tui/index.d.ts +1 -8
  109. package/dist/tui/index.d.ts.map +1 -1
  110. package/dist/tui/index.js +0 -8
  111. package/dist/tui/tui.d.ts +9 -0
  112. package/dist/tui/tui.d.ts.map +1 -1
  113. package/dist/tui/tui.js +78 -48
  114. package/dist/tui/utils.d.ts +7 -0
  115. package/dist/tui/utils.d.ts.map +1 -1
  116. package/dist/tui/utils.js +117 -53
  117. package/dist/utils/bash.d.ts.map +1 -1
  118. package/dist/utils/bash.js +121 -104
  119. package/dist/utils/command-protection.d.ts +3 -2
  120. package/dist/utils/command-protection.d.ts.map +1 -1
  121. package/dist/utils/command-protection.js +42 -33
  122. package/dist/utils/filesystem/operations.d.ts +0 -15
  123. package/dist/utils/filesystem/operations.d.ts.map +1 -1
  124. package/dist/utils/filesystem/operations.js +1 -38
  125. package/dist/utils/filesystem/security.d.ts.map +1 -1
  126. package/dist/utils/filesystem/security.js +22 -15
  127. package/dist/utils/filetype-detection.d.ts +0 -1
  128. package/dist/utils/filetype-detection.d.ts.map +1 -1
  129. package/dist/utils/filetype-detection.js +0 -12
  130. package/dist/utils/formatting.d.ts +0 -30
  131. package/dist/utils/formatting.d.ts.map +1 -1
  132. package/dist/utils/formatting.js +0 -44
  133. package/dist/utils/git.d.ts +4 -6
  134. package/dist/utils/git.d.ts.map +1 -1
  135. package/dist/utils/git.js +36 -46
  136. package/dist/utils/ignore.d.ts +1 -1
  137. package/dist/utils/ignore.d.ts.map +1 -1
  138. package/dist/utils/ignore.js +1 -1
  139. package/dist/utils/process.d.ts.map +1 -1
  140. package/dist/utils/process.js +77 -79
  141. package/dist/utils/yaml.d.ts +0 -1
  142. package/dist/utils/yaml.d.ts.map +1 -1
  143. package/dist/utils/yaml.js +80 -89
  144. package/dist/utils/zod.d.ts +0 -3
  145. package/dist/utils/zod.d.ts.map +1 -1
  146. package/dist/utils/zod.js +0 -7
  147. package/package.json +25 -24
  148. package/dist/agent/sub-agent.d.ts +0 -23
  149. package/dist/agent/sub-agent.d.ts.map +0 -1
  150. package/dist/agent/sub-agent.js +0 -109
  151. package/dist/commands/add-directory/index.d.ts +0 -3
  152. package/dist/commands/add-directory/index.d.ts.map +0 -1
  153. package/dist/commands/add-directory/index.js +0 -50
  154. package/dist/commands/add-directory/utils.d.ts +0 -3
  155. package/dist/commands/add-directory/utils.d.ts.map +0 -1
  156. package/dist/commands/add-directory/utils.js +0 -15
  157. package/dist/commands/clear/index.d.ts +0 -3
  158. package/dist/commands/clear/index.d.ts.map +0 -1
  159. package/dist/commands/clear/index.js +0 -13
  160. package/dist/commands/generate-rules/index.d.ts +0 -3
  161. package/dist/commands/generate-rules/index.d.ts.map +0 -1
  162. package/dist/commands/generate-rules/index.js +0 -206
  163. package/dist/commands/generate-rules/service.d.ts +0 -22
  164. package/dist/commands/generate-rules/service.d.ts.map +0 -1
  165. package/dist/commands/generate-rules/service.js +0 -103
  166. package/dist/commands/generate-rules/utils.d.ts +0 -5
  167. package/dist/commands/generate-rules/utils.d.ts.map +0 -1
  168. package/dist/commands/generate-rules/utils.js +0 -25
  169. package/dist/commands/handoff/index.d.ts +0 -3
  170. package/dist/commands/handoff/index.d.ts.map +0 -1
  171. package/dist/commands/handoff/index.js +0 -97
  172. package/dist/commands/handoff/utils.d.ts +0 -4
  173. package/dist/commands/handoff/utils.d.ts.map +0 -1
  174. package/dist/commands/handoff/utils.js +0 -123
  175. package/dist/commands/list-directories/index.d.ts +0 -3
  176. package/dist/commands/list-directories/index.d.ts.map +0 -1
  177. package/dist/commands/list-directories/index.js +0 -35
  178. package/dist/commands/pickup/index.d.ts +0 -3
  179. package/dist/commands/pickup/index.d.ts.map +0 -1
  180. package/dist/commands/pickup/index.js +0 -141
  181. package/dist/commands/pickup/types.d.ts +0 -6
  182. package/dist/commands/pickup/types.d.ts.map +0 -1
  183. package/dist/commands/pickup/types.js +0 -1
  184. package/dist/commands/pickup/utils.d.ts +0 -7
  185. package/dist/commands/pickup/utils.d.ts.map +0 -1
  186. package/dist/commands/pickup/utils.js +0 -56
  187. package/dist/commands/remove-directory/index.d.ts +0 -3
  188. package/dist/commands/remove-directory/index.d.ts.map +0 -1
  189. package/dist/commands/remove-directory/index.js +0 -55
  190. package/dist/commands/review/index.d.ts +0 -3
  191. package/dist/commands/review/index.d.ts.map +0 -1
  192. package/dist/commands/review/index.js +0 -12
  193. package/dist/commands/review/review-panel.d.ts +0 -3
  194. package/dist/commands/review/review-panel.d.ts.map +0 -1
  195. package/dist/commands/review/review-panel.js +0 -186
  196. package/dist/commands/review/utils.d.ts +0 -18
  197. package/dist/commands/review/utils.d.ts.map +0 -1
  198. package/dist/commands/review/utils.js +0 -146
  199. package/dist/commands/shell/index.d.ts +0 -3
  200. package/dist/commands/shell/index.d.ts.map +0 -1
  201. package/dist/commands/shell/index.js +0 -96
  202. package/dist/subagents/index.d.ts +0 -16
  203. package/dist/subagents/index.d.ts.map +0 -1
  204. package/dist/subagents/index.js +0 -231
  205. package/dist/terminal/index.d.ts +0 -9
  206. package/dist/terminal/index.d.ts.map +0 -1
  207. package/dist/terminal/index.js +0 -8
  208. package/dist/tools/agent.d.ts +0 -27
  209. package/dist/tools/agent.d.ts.map +0 -1
  210. package/dist/tools/agent.js +0 -81
  211. package/dist/tools/directory-tree.d.ts +0 -28
  212. package/dist/tools/directory-tree.d.ts.map +0 -1
  213. package/dist/tools/directory-tree.js +0 -154
  214. package/dist/tools/glob.d.ts +0 -35
  215. package/dist/tools/glob.d.ts.map +0 -1
  216. package/dist/tools/glob.js +0 -167
  217. package/dist/tools/grep.d.ts +0 -100
  218. package/dist/tools/grep.d.ts.map +0 -1
  219. package/dist/tools/grep.js +0 -608
  220. package/dist/tools/ls.d.ts +0 -26
  221. package/dist/tools/ls.d.ts.map +0 -1
  222. package/dist/tools/ls.js +0 -83
  223. package/dist/tui/components/header.d.ts +0 -21
  224. package/dist/tui/components/header.d.ts.map +0 -1
  225. package/dist/tui/components/header.js +0 -63
  226. package/dist/utils/bash/parse.d.ts +0 -19
  227. package/dist/utils/bash/parse.d.ts.map +0 -1
  228. package/dist/utils/bash/parse.js +0 -223
  229. package/dist/utils/bash/quote.d.ts +0 -6
  230. package/dist/utils/bash/quote.d.ts.map +0 -1
  231. package/dist/utils/bash/quote.js +0 -23
  232. package/dist/utils/generators.d.ts +0 -3
  233. package/dist/utils/generators.d.ts.map +0 -1
  234. package/dist/utils/generators.js +0 -25
  235. package/dist/utils/glob.d.ts +0 -52
  236. package/dist/utils/glob.d.ts.map +0 -1
  237. package/dist/utils/glob.js +0 -376
@@ -38,47 +38,53 @@ function parsePatchHeader(lines, startIdx) {
38
38
  }
39
39
  return null;
40
40
  }
41
+ function parseOneChunk(lines, startIdx) {
42
+ const contextLine = lines[startIdx].substring(2).trim();
43
+ let i = startIdx + 1;
44
+ const oldLines = [];
45
+ const newLines = [];
46
+ let isEndOfFile = false;
47
+ while (i < lines.length && !lines[i].startsWith("@@")) {
48
+ const changeLine = lines[i];
49
+ if (changeLine === "*** End of File") {
50
+ isEndOfFile = true;
51
+ i++;
52
+ break;
53
+ }
54
+ if (changeLine.startsWith("***")) {
55
+ break;
56
+ }
57
+ if (changeLine.startsWith(" ")) {
58
+ const content = changeLine.substring(1);
59
+ oldLines.push(content);
60
+ newLines.push(content);
61
+ }
62
+ else if (changeLine.startsWith("-")) {
63
+ oldLines.push(changeLine.substring(1));
64
+ }
65
+ else if (changeLine.startsWith("+")) {
66
+ newLines.push(changeLine.substring(1));
67
+ }
68
+ i++;
69
+ }
70
+ return {
71
+ chunk: {
72
+ oldLines,
73
+ newLines,
74
+ changeContext: contextLine || undefined,
75
+ isEndOfFile: isEndOfFile || undefined,
76
+ },
77
+ nextIdx: i,
78
+ };
79
+ }
41
80
  function parseUpdateFileChunks(lines, startIdx) {
42
81
  const chunks = [];
43
82
  let i = startIdx;
44
83
  while (i < lines.length && !lines[i].startsWith("***")) {
45
84
  if (lines[i].startsWith("@@")) {
46
- const contextLine = lines[i].substring(2).trim();
47
- i++;
48
- const oldLines = [];
49
- const newLines = [];
50
- let isEndOfFile = false;
51
- while (i < lines.length && !lines[i].startsWith("@@")) {
52
- const changeLine = lines[i];
53
- // Check for end of file marker first (before general *** check)
54
- if (changeLine === "*** End of File") {
55
- isEndOfFile = true;
56
- i++;
57
- break;
58
- }
59
- // Check for other *** markers (new file operations)
60
- if (changeLine.startsWith("***")) {
61
- break;
62
- }
63
- if (changeLine.startsWith(" ")) {
64
- const content = changeLine.substring(1);
65
- oldLines.push(content);
66
- newLines.push(content);
67
- }
68
- else if (changeLine.startsWith("-")) {
69
- oldLines.push(changeLine.substring(1));
70
- }
71
- else if (changeLine.startsWith("+")) {
72
- newLines.push(changeLine.substring(1));
73
- }
74
- i++;
75
- }
76
- chunks.push({
77
- oldLines,
78
- newLines,
79
- changeContext: contextLine || undefined,
80
- isEndOfFile: isEndOfFile || undefined,
81
- });
85
+ const { chunk, nextIdx } = parseOneChunk(lines, i);
86
+ chunks.push(chunk);
87
+ i = nextIdx;
82
88
  }
83
89
  else {
84
90
  i++;
@@ -175,36 +181,50 @@ function applyReplacements(lines, replacements) {
175
181
  }
176
182
  return result;
177
183
  }
178
- function computeReplacements(originalLines, filePath, chunks) {
184
+ function findContextLine(originalLines, changeContext, lineIndex, filePath) {
185
+ const contextIdx = seekSequence(originalLines, [changeContext], lineIndex);
186
+ if (contextIdx === -1) {
187
+ throw new Error(`Failed to find context '${changeContext}' in ${filePath}`);
188
+ }
189
+ return contextIdx + 1;
190
+ }
191
+ function computeInsertionIndex(originalLines) {
192
+ return originalLines.length > 0 &&
193
+ originalLines[originalLines.length - 1] === ""
194
+ ? originalLines.length - 1
195
+ : originalLines.length;
196
+ }
197
+ function findPatternWithFallback(originalLines, oldLines, newLines, lineIndex) {
198
+ let pattern = oldLines;
199
+ let newSlice = newLines;
200
+ let found = seekSequence(originalLines, pattern, lineIndex);
201
+ if (found === -1 &&
202
+ pattern.length > 0 &&
203
+ pattern[pattern.length - 1] === "") {
204
+ pattern = pattern.slice(0, -1);
205
+ if (newSlice.length > 0 && newSlice[newSlice.length - 1] === "") {
206
+ newSlice = newSlice.slice(0, -1);
207
+ }
208
+ found = seekSequence(originalLines, pattern, lineIndex);
209
+ }
210
+ return { pattern, newSlice, found };
211
+ }
212
+ export function computeReplacements(originalLines, filePath, chunks) {
179
213
  const replacements = [];
180
214
  let lineIndex = 0;
181
215
  for (const chunk of chunks) {
182
216
  if (chunk.changeContext) {
183
- const contextIdx = seekSequence(originalLines, [chunk.changeContext], lineIndex);
184
- if (contextIdx === -1) {
185
- throw new Error(`Failed to find context '${chunk.changeContext}' in ${filePath}`);
186
- }
187
- lineIndex = contextIdx + 1;
217
+ lineIndex = findContextLine(originalLines, chunk.changeContext, lineIndex, filePath);
188
218
  }
189
219
  if (chunk.oldLines.length === 0) {
190
- const insertionIdx = originalLines.length > 0 &&
191
- originalLines[originalLines.length - 1] === ""
192
- ? originalLines.length - 1
193
- : originalLines.length;
194
- replacements.push([insertionIdx, 0, chunk.newLines]);
220
+ replacements.push([
221
+ computeInsertionIndex(originalLines),
222
+ 0,
223
+ chunk.newLines,
224
+ ]);
195
225
  continue;
196
226
  }
197
- let pattern = chunk.oldLines;
198
- let newSlice = chunk.newLines;
199
- let found = seekSequence(originalLines, pattern, lineIndex);
200
- if (found === -1 &&
201
- pattern.length > 0 &&
202
- pattern[pattern.length - 1] === "") {
203
- pattern = pattern.slice(0, -1);
204
- if (newSlice.length > 0 && newSlice[newSlice.length - 1] === "")
205
- newSlice = newSlice.slice(0, -1);
206
- found = seekSequence(originalLines, pattern, lineIndex);
207
- }
227
+ const { pattern, newSlice, found } = findPatternWithFallback(originalLines, chunk.oldLines, chunk.newLines, lineIndex);
208
228
  if (found !== -1) {
209
229
  replacements.push([found, pattern.length, newSlice]);
210
230
  lineIndex = found + pattern.length;
@@ -242,39 +262,91 @@ function deriveNewContentsFromChunks(fileAbsPath, chunks) {
242
262
  content: newContent,
243
263
  };
244
264
  }
245
- async function applyChanges(changes, signal) {
265
+ async function applyAddChange(change, changed) {
266
+ const dir = path.dirname(change.path);
267
+ if (dir !== "." && dir !== "/")
268
+ await fsp.mkdir(dir, { recursive: true });
269
+ await fsp.writeFile(change.path, change.content, "utf-8");
270
+ changed.push(change.path);
271
+ }
272
+ async function applyDeleteChange(change, changed) {
273
+ await fsp.unlink(change.path).catch(() => { });
274
+ changed.push(change.path);
275
+ }
276
+ async function applyUpdateChange(change, changed) {
277
+ if (change.movePath) {
278
+ const dir = path.dirname(change.movePath);
279
+ if (dir !== "." && dir !== "/")
280
+ await fsp.mkdir(dir, { recursive: true });
281
+ await fsp.writeFile(change.movePath, change.newContent, "utf-8");
282
+ await fsp.unlink(change.path).catch(() => { });
283
+ changed.push(change.movePath);
284
+ return;
285
+ }
286
+ await fsp.writeFile(change.path, change.newContent, "utf-8");
287
+ changed.push(change.path);
288
+ }
289
+ export async function applyChanges(changes, signal) {
246
290
  const changed = [];
247
291
  for (const change of changes) {
248
292
  if (signal?.aborted)
249
293
  throw new Error("Cancelled");
250
294
  if (change.type === "add") {
251
- const dir = path.dirname(change.path);
252
- if (dir !== "." && dir !== "/")
253
- await fsp.mkdir(dir, { recursive: true });
254
- await fsp.writeFile(change.path, change.content, "utf-8");
255
- changed.push(change.path);
295
+ await applyAddChange(change, changed);
256
296
  continue;
257
297
  }
258
298
  if (change.type === "delete") {
259
- await fsp.unlink(change.path).catch(() => { });
260
- changed.push(change.path);
261
- continue;
262
- }
263
- // update
264
- if (change.movePath) {
265
- const dir = path.dirname(change.movePath);
266
- if (dir !== "." && dir !== "/")
267
- await fsp.mkdir(dir, { recursive: true });
268
- await fsp.writeFile(change.movePath, change.newContent, "utf-8");
269
- await fsp.unlink(change.path).catch(() => { });
270
- changed.push(change.movePath);
299
+ await applyDeleteChange(change, changed);
271
300
  continue;
272
301
  }
273
- await fsp.writeFile(change.path, change.newContent, "utf-8");
274
- changed.push(change.path);
302
+ await applyUpdateChange(change, changed);
275
303
  }
276
304
  return changed;
277
305
  }
306
+ async function processHunk(hunk, root, allowedDirectories, projectConfig, primaryDir, abortSignal) {
307
+ if (abortSignal?.aborted) {
308
+ throw new Error("Cancelled");
309
+ }
310
+ const p = resolvePathInRoot(root, hunk.path);
311
+ const validPath = await validatePath(p.abs, allowedDirectories, {
312
+ requireExistence: hunk.type !== "add",
313
+ abortSignal,
314
+ });
315
+ if (hunk.type === "add") {
316
+ return {
317
+ change: { type: "add", path: validPath, content: hunk.contents },
318
+ };
319
+ }
320
+ if (hunk.type === "delete") {
321
+ validateFileNotReadOnly(validPath, projectConfig, primaryDir);
322
+ return { change: { type: "delete", path: validPath } };
323
+ }
324
+ // update
325
+ validateFileNotReadOnly(validPath, projectConfig, primaryDir);
326
+ let moveAbs;
327
+ if (hunk.movePath) {
328
+ const moveP = resolvePathInRoot(root, hunk.movePath);
329
+ moveAbs = await validatePath(moveP.abs, allowedDirectories, {
330
+ requireExistence: false,
331
+ abortSignal,
332
+ });
333
+ }
334
+ const upd = deriveNewContentsFromChunks(validPath, hunk.chunks);
335
+ const change = {
336
+ type: "update",
337
+ path: validPath,
338
+ movePath: moveAbs,
339
+ newContent: upd.content,
340
+ unifiedDiff: upd.unifiedDiff,
341
+ };
342
+ if (upd.unifiedDiff) {
343
+ return {
344
+ change,
345
+ diffLine: `*** Update File: ${path.relative(root, moveAbs ?? validPath)}\n${upd.unifiedDiff}\n`,
346
+ };
347
+ }
348
+ return { change };
349
+ }
278
350
  export const createApplyPatchTool = async (options) => {
279
351
  const { primaryDir, allowedDirs } = options.workspace;
280
352
  const allowedDirectories = allowedDirs ?? [primaryDir];
@@ -316,56 +388,15 @@ export const createApplyPatchTool = async (options) => {
316
388
  if (hunks.length === 0) {
317
389
  return "No changes found in patch.";
318
390
  }
319
- // Build a list of resolved file changes (absolute paths), and a diff preview.
320
391
  const changes = [];
321
392
  let diffOutput = "";
322
393
  for (const hunk of hunks) {
323
- if (abortSignal?.aborted)
324
- throw new Error("Cancelled");
325
- const p = resolvePathInRoot(root, hunk.path);
326
- // Validate path is within allowed directories
327
- const validPath = await validatePath(p.abs, allowedDirectories, {
328
- requireExistence: hunk.type !== "add",
329
- abortSignal,
330
- });
331
- if (hunk.type === "add") {
332
- changes.push({
333
- type: "add",
334
- path: validPath,
335
- content: hunk.contents,
336
- });
337
- continue;
338
- }
339
- if (hunk.type === "delete") {
340
- // Validate file is not read-only before deletion
341
- validateFileNotReadOnly(validPath, projectConfig, primaryDir);
342
- changes.push({ type: "delete", path: validPath });
343
- continue;
344
- }
345
- // update - validate file is not read-only
346
- validateFileNotReadOnly(validPath, projectConfig, primaryDir);
347
- let moveAbs;
348
- if (hunk.movePath) {
349
- const moveP = resolvePathInRoot(root, hunk.movePath);
350
- moveAbs = await validatePath(moveP.abs, allowedDirectories, {
351
- requireExistence: false,
352
- abortSignal,
353
- });
354
- }
355
- const upd = deriveNewContentsFromChunks(validPath, hunk.chunks);
356
- changes.push({
357
- type: "update",
358
- path: validPath,
359
- movePath: moveAbs,
360
- newContent: upd.content,
361
- unifiedDiff: upd.unifiedDiff,
362
- });
363
- if (upd.unifiedDiff) {
364
- diffOutput += `*** Update File: ${path.relative(root, moveAbs ?? validPath)}\n`;
365
- diffOutput += `${upd.unifiedDiff}\n`;
394
+ const { change, diffLine } = await processHunk(hunk, root, allowedDirectories, projectConfig, primaryDir, abortSignal);
395
+ changes.push(change);
396
+ if (diffLine) {
397
+ diffOutput += diffLine;
366
398
  }
367
399
  }
368
- // Apply changes
369
400
  const changedAbs = await applyChanges(changes, abortSignal);
370
401
  const changedRel = changedAbs.map((p) => path.relative(root, p));
371
402
  clearProjectStatusCache();
@@ -1 +1 @@
1
- {"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../source/tools/bash.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAepD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AA0CvD,eAAO,MAAM,QAAQ;;CAEpB,CAAC;AA6MF,QAAA,MAAM,WAAW;;;;;iBAkBf,CAAC;AAEH,KAAK,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEnD,eAAO,MAAM,cAAc,GAAU,SAAS;IAC5C,SAAS,EAAE,gBAAgB,CAAC;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;;;;;;;;;;yBAyGwB,eAAe;mDAIK,eAAe,mBACrC,oBAAoB,GACpC,OAAO,CAAC,MAAM,CAAC;EA6BrB,CAAC"}
1
+ {"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../source/tools/bash.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAepD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AA0CvD,eAAO,MAAM,QAAQ;;CAEpB,CAAC;AAkNF,QAAA,MAAM,WAAW;;;;;iBAkBf,CAAC;AAEH,KAAK,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEnD,eAAO,MAAM,cAAc,GAAU,SAAS;IAC5C,SAAS,EAAE,gBAAgB,CAAC;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;;;;;;;;;;yBA8GwB,eAAe;mDAIK,eAAe,mBACrC,oBAAoB,GACpC,OAAO,CAAC,MAAM,CAAC;EA6BrB,CAAC"}
@@ -206,7 +206,7 @@ export const BashTool = {
206
206
  // }
207
207
  // Tools available:
208
208
  // ${installedTools}`;
209
- const simpleDescription = "Run terminal commands.";
209
+ const simpleDescription = "Run terminal commands. When you need to run multiple independent commands (e.g. `git status`, `git diff`, `git log`; or several `rg`/`grep` searches with different patterns), ALWAYS issue multiple Bash tool calls in the same assistant message rather than running one, waiting for the result, then running the next. The runtime executes parallel tool calls concurrently, so batching independent commands is several times faster than serial calls. Only sequence commands when one truly depends on the output of another.";
210
210
  // Command execution timeout in milliseconds
211
211
  const DEFAULT_TIMEOUT = 1.5 * 60 * 1000; // 1.5 minutes
212
212
  // Maximum output size in bytes (50KB) to prevent context window exhaustion
@@ -217,6 +217,9 @@ const MAX_OUTPUT_SIZE = 50 * 1024;
217
217
  * The footer is always appended at the end, even when output is truncated.
218
218
  */
219
219
  function truncateOutput(output, footer) {
220
+ if (output.length === 0) {
221
+ return footer;
222
+ }
220
223
  if (output.length <= MAX_OUTPUT_SIZE) {
221
224
  return `${output}\n${footer}`;
222
225
  }
@@ -297,13 +300,13 @@ export const createBashTool = async (options) => {
297
300
  const timeStr = elapsedMs < 1000 ? `${elapsedMs}ms` : `${(elapsedMs / 1000).toFixed(1)}s`;
298
301
  const metadataFooter = `[exit:${exitCode} | ${timeStr}]`;
299
302
  if (exitCode !== 0) {
300
- const errorMessage = error
301
- ? error.message
302
- : `Command exited with code ${exitCode}`;
303
- const combinedOutput = output
304
- ? `${errorMessage}\n${output}`
305
- : errorMessage;
306
- throw new Error(truncateOutput(combinedOutput, metadataFooter));
303
+ const execError = error;
304
+ const wasKilled = execError?.killed === true || execError?.signal != null;
305
+ if (wasKilled) {
306
+ const timeoutOutput = output || `Command timed out after ${timeout.toLocaleString()}ms`;
307
+ return truncateOutput(timeoutOutput, metadataFooter);
308
+ }
309
+ return truncateOutput(output, metadataFooter);
307
310
  }
308
311
  // Check for binary output and handle specially
309
312
  if (isBinaryOutput(output)) {
@@ -25,7 +25,12 @@ export declare function getShebang(scriptPath: string): string | null;
25
25
  export declare function parseShebang(shebang: string, scriptPath: string): InterpreterResult;
26
26
  export declare function resolveToolInterpreter(scriptPath: string): InterpreterResult | null;
27
27
  export declare function parseTextSchema(content: string): ToolMetadata | null;
28
- export declare function parseToolMetadata(output: string): ToolMetadata;
28
+ /**
29
+ * Processes child process stdout/stderr into a result string.
30
+ * Trims, truncates oversized output, falls back to stderr or a placeholder,
31
+ * and attempts JSON parsing for structured output.
32
+ */
33
+ export declare function processChildOutput(stdout: string, stderr: string): string;
29
34
  interface DynamicToolObject {
30
35
  toolDef: {
31
36
  description: string;
@@ -1 +1 @@
1
- {"version":3,"file":"dynamic-tool-loader.d.ts","sourceRoot":"","sources":["../../source/tools/dynamic-tool-loader.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,KAAK,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAGvE,QAAA,MAAM,kBAAkB;;;;;;;;;;;;;;;iBAatB,CAAC;AAEH,KAAK,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAMvD,UAAU,iBAAiB;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAyBD,wBAAgB,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAc5D;AAED,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,GACjB,iBAAiB,CAUnB;AAED,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,MAAM,GACjB,iBAAiB,GAAG,IAAI,CA0B1B;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAwFpE;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,CAS9D;AAsOD,UAAU,iBAAiB;IACzB,OAAO,EAAE;QACP,WAAW,EAAE,MAAM,CAAC;QAEpB,WAAW,EAAE,GAAG,CAAC;KAClB,CAAC;IACF,OAAO,EAAE,CACP,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,OAAO,EAAE,oBAAoB,KAC1B,OAAO,CAAC,MAAM,CAAC,CAAC;CACtB;AAwED,wBAAsB,gBAAgB,CAAC,EACrC,OAAO,EACP,iBAAsB,EACtB,cAAc,GACf,EAAE;IACD,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC,8CAuJA"}
1
+ {"version":3,"file":"dynamic-tool-loader.d.ts","sourceRoot":"","sources":["../../source/tools/dynamic-tool-loader.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,KAAK,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAGvE,QAAA,MAAM,kBAAkB;;;;;;;;;;;;;;;iBAatB,CAAC;AAEH,KAAK,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAMvD,UAAU,iBAAiB;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAyBD,wBAAgB,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAc5D;AAED,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,GACjB,iBAAiB,CAUnB;AAED,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,MAAM,GACjB,iBAAiB,GAAG,IAAI,CA0B1B;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CA4CpE;AA4LD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CA4BzE;AAoFD,UAAU,iBAAiB;IACzB,OAAO,EAAE;QACP,WAAW,EAAE,MAAM,CAAC;QAEpB,WAAW,EAAE,GAAG,CAAC;KAClB,CAAC;IACF,OAAO,EAAE,CACP,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,OAAO,EAAE,oBAAoB,KAC1B,OAAO,CAAC,MAAM,CAAC,CAAC;CACtB;AAwED,wBAAsB,gBAAgB,CAAC,EACrC,OAAO,EACP,iBAAsB,EACtB,cAAc,GACf,EAAE;IACD,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC,8CAiKA"}