@travisennis/acai 0.0.10 → 0.0.11

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 (112) hide show
  1. package/README.md +5 -1
  2. package/dist/agent/index.d.ts.map +1 -1
  3. package/dist/agent/index.js +29 -27
  4. package/dist/cli/stdin.d.ts +2 -1
  5. package/dist/cli/stdin.d.ts.map +1 -1
  6. package/dist/commands/generate-rules/service.d.ts +3 -2
  7. package/dist/commands/generate-rules/service.d.ts.map +1 -1
  8. package/dist/commands/health/utils.d.ts +3 -2
  9. package/dist/commands/health/utils.d.ts.map +1 -1
  10. package/dist/commands/init-project/utils.d.ts +2 -1
  11. package/dist/commands/init-project/utils.d.ts.map +1 -1
  12. package/dist/commands/review/utils.d.ts +6 -1
  13. package/dist/commands/review/utils.d.ts.map +1 -1
  14. package/dist/index.js +1 -1
  15. package/dist/models/opencode-go-provider.d.ts +25 -0
  16. package/dist/models/opencode-go-provider.d.ts.map +1 -0
  17. package/dist/models/opencode-go-provider.js +78 -0
  18. package/dist/models/opencode-zen-provider.d.ts +3 -3
  19. package/dist/models/opencode-zen-provider.js +17 -17
  20. package/dist/models/openrouter-provider.d.ts +4 -1
  21. package/dist/models/openrouter-provider.d.ts.map +1 -1
  22. package/dist/models/openrouter-provider.js +39 -0
  23. package/dist/models/providers.d.ts +3 -3
  24. package/dist/models/providers.d.ts.map +1 -1
  25. package/dist/models/providers.js +6 -0
  26. package/dist/modes/manager.d.ts +2 -1
  27. package/dist/modes/manager.d.ts.map +1 -1
  28. package/dist/modes/prompts.d.ts +1 -1
  29. package/dist/modes/prompts.d.ts.map +1 -1
  30. package/dist/modes/prompts.js +1 -2
  31. package/dist/prompts/mentions.d.ts.map +1 -1
  32. package/dist/prompts/mentions.js +35 -6
  33. package/dist/repl/index.d.ts.map +1 -1
  34. package/dist/repl/index.js +9 -1
  35. package/dist/sessions/manager.d.ts +3 -3
  36. package/dist/sessions/manager.d.ts.map +1 -1
  37. package/dist/sessions/manager.js +1 -1
  38. package/dist/skills/index.d.ts +2 -1
  39. package/dist/skills/index.d.ts.map +1 -1
  40. package/dist/subagents/index.d.ts +2 -1
  41. package/dist/subagents/index.d.ts.map +1 -1
  42. package/dist/terminal/table/utils.d.ts +1 -1
  43. package/dist/terminal/table/utils.d.ts.map +1 -1
  44. package/dist/terminal/wrap-ansi.js +2 -2
  45. package/dist/tools/agent.js +1 -1
  46. package/dist/tools/apply-patch.d.ts +62 -0
  47. package/dist/tools/apply-patch.d.ts.map +1 -0
  48. package/dist/tools/apply-patch.js +377 -0
  49. package/dist/tools/bash.d.ts.map +1 -1
  50. package/dist/tools/bash.js +28 -7
  51. package/dist/tools/directory-tree.d.ts.map +1 -1
  52. package/dist/tools/directory-tree.js +1 -1
  53. package/dist/tools/dynamic-tool-loader.d.ts +1 -1
  54. package/dist/tools/dynamic-tool-loader.d.ts.map +1 -1
  55. package/dist/tools/edit-file.d.ts.map +1 -1
  56. package/dist/tools/edit-file.js +188 -79
  57. package/dist/tools/glob.d.ts.map +1 -1
  58. package/dist/tools/glob.js +22 -15
  59. package/dist/tools/grep.d.ts.map +1 -1
  60. package/dist/tools/grep.js +43 -29
  61. package/dist/tools/index.d.ts +15 -48
  62. package/dist/tools/index.d.ts.map +1 -1
  63. package/dist/tools/index.js +4 -4
  64. package/dist/tools/ls.d.ts.map +1 -1
  65. package/dist/tools/ls.js +1 -1
  66. package/dist/tools/read-file.d.ts +1 -3
  67. package/dist/tools/read-file.d.ts.map +1 -1
  68. package/dist/tools/read-file.js +21 -16
  69. package/dist/tools/save-file.d.ts.map +1 -1
  70. package/dist/tools/save-file.js +26 -21
  71. package/dist/tools/web-fetch.d.ts +0 -12
  72. package/dist/tools/web-fetch.d.ts.map +1 -1
  73. package/dist/tools/web-fetch.js +18 -1
  74. package/dist/tools/web-search.d.ts +0 -18
  75. package/dist/tools/web-search.d.ts.map +1 -1
  76. package/dist/tui/autocomplete/file-search-provider.js +1 -1
  77. package/dist/tui/autocomplete/utils.d.ts +2 -1
  78. package/dist/tui/autocomplete/utils.d.ts.map +1 -1
  79. package/dist/tui/autocomplete/utils.js +25 -23
  80. package/dist/tui/components/editor.d.ts +2 -1
  81. package/dist/tui/components/editor.d.ts.map +1 -1
  82. package/dist/tui/components/editor.js +1 -1
  83. package/dist/tui/components/markdown.d.ts +2 -2
  84. package/dist/tui/components/markdown.d.ts.map +1 -1
  85. package/dist/tui/components/welcome.d.ts +2 -1
  86. package/dist/tui/components/welcome.d.ts.map +1 -1
  87. package/dist/tui/editor-launcher.d.ts +3 -2
  88. package/dist/tui/editor-launcher.d.ts.map +1 -1
  89. package/dist/tui/index.d.ts +0 -1
  90. package/dist/tui/index.d.ts.map +1 -1
  91. package/dist/tui/tui.d.ts +1 -0
  92. package/dist/tui/tui.d.ts.map +1 -1
  93. package/dist/tui/tui.js +9 -0
  94. package/dist/tui/utils.d.ts +1 -5
  95. package/dist/tui/utils.d.ts.map +1 -1
  96. package/dist/tui/utils.js +271 -44
  97. package/package.json +18 -18
  98. package/dist/commands/add-directory/types.d.ts +0 -6
  99. package/dist/commands/add-directory/types.d.ts.map +0 -1
  100. package/dist/commands/add-directory/types.js +0 -1
  101. package/dist/commands/copy/types.d.ts +0 -3
  102. package/dist/commands/copy/types.d.ts.map +0 -1
  103. package/dist/commands/copy/types.js +0 -1
  104. package/dist/commands/review/types.d.ts +0 -12
  105. package/dist/commands/review/types.d.ts.map +0 -1
  106. package/dist/commands/review/types.js +0 -1
  107. package/dist/tools/code-search.d.ts +0 -41
  108. package/dist/tools/code-search.d.ts.map +0 -1
  109. package/dist/tools/code-search.js +0 -195
  110. package/dist/utils/iterables.d.ts +0 -2
  111. package/dist/utils/iterables.d.ts.map +0 -1
  112. package/dist/utils/iterables.js +0 -6
@@ -118,25 +118,180 @@ function validateEdits(edits) {
118
118
  throw new Error("Invalid oldText in edit. The value of oldText must be at least one character");
119
119
  }
120
120
  }
121
- async function applyEditsSequentially(edits, content, abortSignal, filePath) {
122
- let modifiedContent = content;
123
- for (const edit of edits) {
124
- if (abortSignal?.aborted) {
125
- throw new Error("File edit operation aborted during processing");
121
+ /**
122
+ * Normalize text for fuzzy matching by:
123
+ * - Unicode NFKC normalization (canonical compatibility decomposition)
124
+ * - Converting smart quotes to straight quotes
125
+ * - Unifying various dash characters to hyphen
126
+ * - Normalizing whitespace characters to regular space
127
+ * - Removing trailing whitespace from each line
128
+ */
129
+ function normalizeForFuzzyMatch(text) {
130
+ return text
131
+ .normalize("NFKC")
132
+ .split("\n")
133
+ .map((line) => line.trimEnd())
134
+ .join("\n")
135
+ .replace(/[\u2018\u2019\u201A\u201B]/g, "'") // curly single quotes → '
136
+ .replace(/[\u201C\u201D\u201E\u201F]/g, '"') // curly double quotes → "
137
+ .replace(/[\u2010\u2011\u2012\u2013\u2014\u2015\u2212]/g, "-") // dashes → -
138
+ .replace(/[\u00A0\u2002-\u200A\u202F\u205F\u3000]/g, " "); // spaces → space
139
+ }
140
+ /**
141
+ * Find text in content, trying exact match first, then fuzzy match.
142
+ * When fuzzy match is used, positions are in the normalized content.
143
+ * IMPORTANT: When fuzzy matching is needed, the caller must work entirely
144
+ * in normalized space to avoid position mapping issues.
145
+ */
146
+ function fuzzyFindText(content, searchText) {
147
+ // Try exact match first
148
+ const exactIndex = content.indexOf(searchText);
149
+ if (exactIndex !== -1) {
150
+ return {
151
+ found: true,
152
+ index: exactIndex,
153
+ matchLength: searchText.length,
154
+ usedFuzzyMatch: false,
155
+ };
156
+ }
157
+ // Fall back to fuzzy matching
158
+ const fuzzyContent = normalizeForFuzzyMatch(content);
159
+ const fuzzySearch = normalizeForFuzzyMatch(searchText);
160
+ const fuzzyIndex = fuzzyContent.indexOf(fuzzySearch);
161
+ if (fuzzyIndex === -1) {
162
+ return { found: false, index: -1, matchLength: 0, usedFuzzyMatch: false };
163
+ }
164
+ return {
165
+ found: true,
166
+ index: fuzzyIndex,
167
+ matchLength: fuzzySearch.length,
168
+ usedFuzzyMatch: true,
169
+ };
170
+ }
171
+ /**
172
+ * Count how many times searchText appears in content (exact or fuzzy).
173
+ * Used to ensure uniqueness.
174
+ */
175
+ function countMatches(content, searchText) {
176
+ // Count exact matches first
177
+ const exactEscaped = searchText.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
178
+ const exactRegex = new RegExp(exactEscaped, "g");
179
+ const exactMatches = content.match(exactRegex);
180
+ const exactCount = exactMatches ? exactMatches.length : 0;
181
+ if (exactCount > 0) {
182
+ return exactCount;
183
+ }
184
+ // Count fuzzy matches
185
+ const fuzzyContent = normalizeForFuzzyMatch(content);
186
+ const fuzzySearch = normalizeForFuzzyMatch(searchText);
187
+ const fuzzyEscaped = fuzzySearch.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
188
+ const fuzzyRegex = new RegExp(fuzzyEscaped, "g");
189
+ const fuzzyMatches = fuzzyContent.match(fuzzyRegex);
190
+ return fuzzyMatches ? fuzzyMatches.length : 0;
191
+ }
192
+ /**
193
+ * Preflight validation: Find all edit positions, validate uniqueness and no overlaps.
194
+ * If any edit requires fuzzy matching, normalize the entire content and work in
195
+ * normalized space. This avoids position mapping issues.
196
+ */
197
+ function preflightEdits(edits, content) {
198
+ const normalizedEdits = edits.map((edit) => ({
199
+ oldText: normalizeLineEndings(edit.oldText),
200
+ newText: normalizeLineEndings(edit.newText),
201
+ }));
202
+ // Check if any edit requires fuzzy matching
203
+ const needsFuzzyMatching = normalizedEdits.some((edit) => content.indexOf(edit.oldText) === -1);
204
+ // Use normalized content if fuzzy matching is needed
205
+ const baseContent = needsFuzzyMatching
206
+ ? normalizeForFuzzyMatch(content)
207
+ : content;
208
+ const matchedEdits = [];
209
+ // First pass: Find all match positions
210
+ for (let i = 0; i < normalizedEdits.length; i++) {
211
+ const edit = normalizedEdits[i];
212
+ // Check uniqueness
213
+ const matchCount = countMatches(baseContent, edit.oldText);
214
+ if (matchCount === 0) {
215
+ return {
216
+ success: false,
217
+ matchedEdits: [],
218
+ errorMessage: `Edit ${i + 1}: Could not find the exact text. ` +
219
+ "The oldText must match exactly including all whitespace and newlines.",
220
+ usedFuzzyMatch: needsFuzzyMatching,
221
+ baseContent,
222
+ };
126
223
  }
127
- const result = await applyNormalizedEdit(edit, modifiedContent);
128
- if (result.success) {
129
- modifiedContent = result.content;
224
+ if (matchCount > 1) {
225
+ const fuzzyContext = needsFuzzyMatching
226
+ ? " (including fuzzy matches)"
227
+ : "";
228
+ return {
229
+ success: false,
230
+ matchedEdits: [],
231
+ errorMessage: `Edit ${i + 1}: oldText matches ${matchCount} locations${fuzzyContext} but should match only 1. ` +
232
+ "Please provide a more specific oldText that includes more surrounding context.",
233
+ usedFuzzyMatch: needsFuzzyMatching,
234
+ baseContent,
235
+ };
130
236
  }
131
- else if (result.errorMessage) {
132
- throw new Error(result.errorMessage);
237
+ // Find the match position
238
+ const matchResult = fuzzyFindText(baseContent, edit.oldText);
239
+ if (!matchResult.found) {
240
+ return {
241
+ success: false,
242
+ matchedEdits: [],
243
+ errorMessage: `Edit ${i + 1}: Could not find the text (unexpected error).`,
244
+ usedFuzzyMatch: needsFuzzyMatching,
245
+ baseContent,
246
+ };
133
247
  }
134
- else {
135
- throw new Error(`Could not find the exact text in ${filePath}. The oldText must match exactly including all whitespace and newlines. ` +
136
- "Tip: Check for invisible characters, extra/missing whitespace, or line ending differences.");
248
+ matchedEdits.push({
249
+ ...edit,
250
+ index: matchResult.index,
251
+ matchLength: matchResult.matchLength,
252
+ editIndex: i,
253
+ });
254
+ }
255
+ // Sort by position (ascending) for overlap detection
256
+ matchedEdits.sort((a, b) => a.index - b.index);
257
+ // Check for overlapping edits
258
+ for (let i = 0; i < matchedEdits.length - 1; i++) {
259
+ const current = matchedEdits[i];
260
+ const next = matchedEdits[i + 1];
261
+ // Check if current edit overlaps with next edit
262
+ if (current.index + current.matchLength > next.index) {
263
+ return {
264
+ success: false,
265
+ matchedEdits: [],
266
+ errorMessage: `Edits ${current.editIndex + 1} and ${next.editIndex + 1} overlap in the file. ` +
267
+ "Each edit must target a distinct region. Please combine overlapping edits into a single edit.",
268
+ usedFuzzyMatch: needsFuzzyMatching,
269
+ baseContent,
270
+ };
137
271
  }
138
272
  }
139
- return modifiedContent;
273
+ return {
274
+ success: true,
275
+ matchedEdits,
276
+ usedFuzzyMatch: needsFuzzyMatching,
277
+ baseContent,
278
+ };
279
+ }
280
+ /**
281
+ * Apply edits in reverse position order (highest index first).
282
+ * This prevents position shifting - earlier edits don't affect later ones.
283
+ * All positions are relative to baseContent (normalized if fuzzy matching).
284
+ */
285
+ function applyEditsReverseOrder(content, matchedEdits) {
286
+ let result = content;
287
+ // Process in reverse order (highest index first)
288
+ for (let i = matchedEdits.length - 1; i >= 0; i--) {
289
+ const edit = matchedEdits[i];
290
+ const before = result.slice(0, edit.index);
291
+ const after = result.slice(edit.index + edit.matchLength);
292
+ result = before + edit.newText + after;
293
+ }
294
+ return result;
140
295
  }
141
296
  function formatDiff(diff, _filePath) {
142
297
  let numBackticks = 3;
@@ -158,11 +313,27 @@ export async function applyFileEdits(filePath, edits, dryRun = false, abortSigna
158
313
  const originalLineEnding = detectLineEnding(bomStrippedContent);
159
314
  const content = normalizeLineEndings(bomStrippedContent);
160
315
  validateEdits(edits);
161
- const modifiedContent = await applyEditsSequentially(edits, content, abortSignal, filePath);
316
+ // PREFLIGHT: Find all positions, validate no overlaps
317
+ const preflight = preflightEdits(edits, content);
318
+ if (!preflight.success) {
319
+ throw new Error(`Edit validation failed: ${preflight.errorMessage}`);
320
+ }
321
+ // All edits validated - apply in reverse order
322
+ // Note: baseContent is normalized if fuzzy matching was needed
323
+ const modifiedContent = applyEditsReverseOrder(preflight.baseContent, preflight.matchedEdits);
324
+ // Verify something actually changed
325
+ if (modifiedContent === preflight.baseContent) {
326
+ throw new Error("No changes were made - all edits resulted in identical content");
327
+ }
162
328
  const finalContentWithLineEndings = restoreLineEndings(modifiedContent, originalLineEnding);
163
329
  const finalContent = originalBom + finalContentWithLineEndings;
164
- const diff = createUnifiedDiff(content, finalContent, filePath);
330
+ // Use baseContent for diff (normalized if fuzzy matching)
331
+ const diff = createUnifiedDiff(preflight.baseContent, modifiedContent, filePath);
165
332
  const formattedDiff = formatDiff(diff, filePath);
333
+ // Add fuzzy match indicator if applicable
334
+ const result = preflight.usedFuzzyMatch
335
+ ? `${formattedDiff}\n\n(Note: Used fuzzy matching - file content has been normalized)`
336
+ : formattedDiff;
166
337
  if (!dryRun) {
167
338
  if (abortSignal?.aborted) {
168
339
  throw new Error("File edit operation aborted before writing");
@@ -172,67 +343,5 @@ export async function applyFileEdits(filePath, edits, dryRun = false, abortSigna
172
343
  signal: abortSignal,
173
344
  });
174
345
  }
175
- return formattedDiff;
176
- }
177
- /**
178
- * Applies a single edit with normalized line endings
179
- * Returns an error if oldText matches more than one location in the file
180
- */
181
- async function applyNormalizedEdit(edit, content) {
182
- // Normalize line endings to match the normalized content
183
- const normalizedOldText = normalizeLineEndings(edit.oldText);
184
- const normalizedNewText = normalizeLineEndings(edit.newText);
185
- // First, check how many matches exist (without replacing)
186
- const matchCountResult = countMatches(content, normalizedOldText);
187
- const matchCount = matchCountResult.count;
188
- // If more than one match, require unique oldText
189
- if (matchCount > 1) {
190
- return {
191
- success: false,
192
- content,
193
- matchCount,
194
- errorMessage: `oldText matches ${matchCount} locations in the file but should match only 1. ` +
195
- "Please provide a more specific oldText that includes more surrounding context (e.g., 3+ lines, " +
196
- "function/class names, or unique surrounding code) to uniquely identify the location you want to edit.",
197
- };
198
- }
199
- // If no matches, return failure
200
- if (matchCount === 0) {
201
- return { success: false, content };
202
- }
203
- // Exactly one match - apply the edit
204
- const originalResult = applyLiteralEdit(content, normalizedOldText, normalizedNewText);
205
- return { success: true, content: originalResult.content };
206
- }
207
- /**
208
- * Count the number of literal matches in content without replacing
209
- */
210
- function countMatches(content, search) {
211
- if (search === "") {
212
- return { count: 0 };
213
- }
214
- // Escape special regex characters for literal matching
215
- const escapedSearch = search.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
216
- const regex = new RegExp(escapedSearch, "g");
217
- // Count matches without modifying content
218
- const matches = content.match(regex);
219
- return { count: matches ? matches.length : 0 };
220
- }
221
- /**
222
- * Applies a literal search and replace operation
223
- */
224
- function applyLiteralEdit(content, search, replace) {
225
- if (search === "") {
226
- return { matchCount: 0, content };
227
- }
228
- // Escape special regex characters for literal matching
229
- const escapedSearch = search.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
230
- const regex = new RegExp(escapedSearch, "g");
231
- // Use replace with callback to count matches while replacing all occurrences
232
- let matchCount = 0;
233
- const modifiedContent = content.replace(regex, () => {
234
- matchCount++;
235
- return replace;
236
- });
237
- return { matchCount, content: modifiedContent };
346
+ return result;
238
347
  }
@@ -1 +1 @@
1
- {"version":3,"file":"glob.d.ts","sourceRoot":"","sources":["../../source/tools/glob.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AA8CvD,eAAO,MAAM,QAAQ;;CAEpB,CAAC;AAEF,eAAO,MAAM,WAAW;;;;;;;;;iBA0EtB,CAAC;AAEH,KAAK,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEnD,eAAO,MAAM,cAAc;;;;;;;;;;;;;;gCAMK,eAAe;wGAmBtC,eAAe,mBACD,oBAAoB,GACpC,OAAO,CAAC,MAAM,CAAC;CA6CrB,CAAC"}
1
+ {"version":3,"file":"glob.d.ts","sourceRoot":"","sources":["../../source/tools/glob.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AA6EvD,eAAO,MAAM,QAAQ;;CAEpB,CAAC;AAEF,eAAO,MAAM,WAAW;;;;;;;;;iBA0EtB,CAAC;AAEH,KAAK,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEnD,eAAO,MAAM,cAAc;;;;;;;;;;;;;;gCAMK,eAAe;wGAmBtC,eAAe,mBACD,oBAAoB,GACpC,OAAO,CAAC,MAAM,CAAC;CAuCrB,CAAC"}
@@ -38,6 +38,24 @@ function formatResult(sortedFiles) {
38
38
  ? sortedFiles.join("\n")
39
39
  : "No files found matching the specified patterns.";
40
40
  }
41
+ function normalizePatternArray(patterns) {
42
+ return Array.isArray(patterns) ? patterns : [patterns];
43
+ }
44
+ function buildGlobOptions(effectivePath, gitignore, recursive, expandDirectories, ignoreFiles, cwd) {
45
+ return {
46
+ cwd: cwd || effectivePath,
47
+ ...(gitignore !== null && { gitignore }),
48
+ ...(recursive !== null && { recursive }),
49
+ ...(expandDirectories !== null && { expandDirectories }),
50
+ ...(ignoreFiles !== null && { ignoreFiles }),
51
+ };
52
+ }
53
+ function limitResults(sortedFiles, effectiveMaxResults) {
54
+ if (effectiveMaxResults > 0 && sortedFiles.length > effectiveMaxResults) {
55
+ return sortedFiles.slice(0, effectiveMaxResults);
56
+ }
57
+ return sortedFiles;
58
+ }
41
59
  export const GlobTool = {
42
60
  name: "Glob",
43
61
  };
@@ -125,27 +143,16 @@ export const createGlobTool = () => {
125
143
  throw new Error("Glob search aborted");
126
144
  }
127
145
  const effectivePath = typeof path === "string" && path.trim() !== "" ? path : process.cwd();
128
- const patternArray = Array.isArray(patterns) ? patterns : [patterns];
146
+ const patternArray = normalizePatternArray(patterns);
129
147
  const effectiveMaxResults = maxResults ?? DEFAULT_MAX_RESULTS;
130
- const globOptions = {
131
- cwd: cwd || process.cwd(),
132
- ...(gitignore !== null && { gitignore }),
133
- ...(recursive !== null && { recursive }),
134
- ...(expandDirectories !== null && { expandDirectories }),
135
- ...(ignoreFiles !== null && { ignoreFiles }),
136
- };
137
- const matchingFiles = await glob(patternArray, {
138
- ...globOptions,
139
- cwd: effectivePath,
140
- });
148
+ const globOptions = buildGlobOptions(effectivePath, gitignore, recursive, expandDirectories, ignoreFiles, cwd);
149
+ const matchingFiles = await glob(patternArray, globOptions);
141
150
  const filesToStat = matchingFiles.length > MAX_STAT_FILES
142
151
  ? matchingFiles.slice(0, MAX_STAT_FILES)
143
152
  : matchingFiles;
144
153
  const filesWithStats = await Promise.all(filesToStat.map((filePath) => getFileWithStats(filePath, effectivePath)));
145
154
  const sortedFiles = sortFilesByMtime(filesWithStats);
146
- const result = effectiveMaxResults > 0 && sortedFiles.length > effectiveMaxResults
147
- ? sortedFiles.slice(0, effectiveMaxResults)
148
- : sortedFiles;
155
+ const result = limitResults(sortedFiles, effectiveMaxResults);
149
156
  return formatResult(result);
150
157
  },
151
158
  };
@@ -1 +1 @@
1
- {"version":3,"file":"grep.d.ts","sourceRoot":"","sources":["../../source/tools/grep.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAKvD,eAAO,MAAM,QAAQ;;CAEpB,CAAC;AAEF,QAAA,MAAM,WAAW;;;;;;;;;;iBAoCf,CAAC;AAEH,KAAK,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEnD,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;kFAapB,eAAe;sHAoCb,eAAe,mBACD,oBAAoB,GACpC,OAAO,CAAC,MAAM,CAAC;CAkErB,CAAC;AAEF,UAAU,WAAW;IACnB,SAAS,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC3B,UAAU,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC5B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,aAAa,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC/B,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAqLD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CA8B9D;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,WAAgB,GACxB,MAAM,EAAE,CAgEV;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,KAAK,CAAC;QACjB,KAAK,EAAE,MAAM,CAAC;QACd,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;KACd,CAAC,CAAC;CACJ;AAED,UAAU,UAAU;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,WAAW,EAAE,CAAC;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,EAAE,CAqDrE;AA8BD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,CAEhE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,CAE/D;AAyBD;;GAEG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,WAAW,EAAE,EACtB,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACpC;IAAE,SAAS,EAAE,WAAW,EAAE,CAAC;IAAC,WAAW,EAAE,OAAO,CAAA;CAAE,CAqDpD;AAED,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,WAAgB,EACzB,WAAW,CAAC,EAAE,WAAW,GAAG,IAAI,GAC/B,OAAO,CAAC,UAAU,CAAC,CAgGrB"}
1
+ {"version":3,"file":"grep.d.ts","sourceRoot":"","sources":["../../source/tools/grep.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAKvD,eAAO,MAAM,QAAQ;;CAEpB,CAAC;AAEF,QAAA,MAAM,WAAW;;;;;;;;;;iBAoCf,CAAC;AAEH,KAAK,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEnD,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;kFAapB,eAAe;sHAoCb,eAAe,mBACD,oBAAoB,GACpC,OAAO,CAAC,MAAM,CAAC;CAkErB,CAAC;AAEF,UAAU,WAAW;IACnB,SAAS,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC3B,UAAU,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC5B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,aAAa,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC/B,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAuMD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CA8B9D;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,WAAgB,GACxB,MAAM,EAAE,CAgEV;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,KAAK,CAAC;QACjB,KAAK,EAAE,MAAM,CAAC;QACd,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;KACd,CAAC,CAAC;CACJ;AAED,UAAU,UAAU;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,WAAW,EAAE,CAAC;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,EAAE,CAqDrE;AA8BD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,CAEhE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,CAE/D;AAyBD;;GAEG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,WAAW,EAAE,EACtB,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACpC;IAAE,SAAS,EAAE,WAAW,EAAE,CAAC;IAAC,WAAW,EAAE,OAAO,CAAA;CAAE,CAoDpD;AAED,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,WAAgB,EACzB,WAAW,CAAC,EAAE,WAAW,GAAG,IAAI,GAC/B,OAAO,CAAC,UAAU,CAAC,CAgGrB"}
@@ -133,39 +133,47 @@ function skipCharacterClass(pattern, startIndex) {
133
133
  }
134
134
  return i;
135
135
  }
136
+ /**
137
+ * Checks if a character is valid inside braces (digits 0-9 or comma).
138
+ */
139
+ function isValidBraceChar(c) {
140
+ return (c >= "0" && c <= "9") || c === ",";
141
+ }
142
+ /**
143
+ * Checks if empty braces have a preceding atom.
144
+ * Empty braces with no preceding atom are treated as literal.
145
+ */
146
+ function hasPrecedingAtom(pattern, startIndex) {
147
+ if (startIndex === 0)
148
+ return false;
149
+ const prev = pattern[startIndex - 1];
150
+ return /\S/.test(prev);
151
+ }
136
152
  /**
137
153
  * Parses and validates the content inside braces {..}.
138
154
  * Returns true if the brace content is invalid.
139
155
  */
140
156
  function isInvalidBraceContent(pattern, startIndex) {
141
- let j = startIndex + 1;
157
+ const j = startIndex + 1;
158
+ // Find closing brace and check for invalid characters
142
159
  let hasDigits = false;
143
- let hasComma = false;
144
- // Parse content inside braces
145
- while (j < pattern.length && pattern[j] !== "}") {
146
- const c = pattern[j];
147
- if (c >= "0" && c <= "9") {
148
- hasDigits = true;
149
- }
150
- else if (c === "," && !hasComma) {
151
- hasComma = true;
152
- }
153
- else {
154
- // Invalid character inside braces
160
+ let k = j;
161
+ while (k < pattern.length && pattern[k] !== "}") {
162
+ if (!isValidBraceChar(pattern[k])) {
155
163
  return true;
156
164
  }
157
- j++;
165
+ if (pattern[k] >= "0" && pattern[k] <= "9") {
166
+ hasDigits = true;
167
+ }
168
+ k++;
158
169
  }
159
170
  // No closing brace found
160
- if (j >= pattern.length) {
171
+ if (k >= pattern.length) {
161
172
  return true;
162
173
  }
163
- // Empty braces {} with no preceding atom are treated as literal
164
- if (!hasDigits) {
165
- const prev = startIndex > 0 ? pattern[startIndex - 1] : undefined;
166
- if (prev !== undefined && /\S/.test(prev)) {
167
- return true;
168
- }
174
+ // Empty braces {} with preceding atom are invalid
175
+ if (!hasDigits && hasPrecedingAtom(pattern, startIndex)) {
176
+ return true;
169
177
  }
170
178
  return false;
171
179
  }
@@ -184,24 +192,31 @@ function hasInvalidRepetition(pattern) {
184
192
  i = skipCharacterClass(pattern, i);
185
193
  continue;
186
194
  }
195
+ // Unmatched closing brace is invalid
187
196
  if (ch === "}") {
188
- // Unmatched closing brace is invalid
189
197
  return true;
190
198
  }
199
+ // Handle opening brace
191
200
  if (ch === "{") {
192
201
  if (isInvalidBraceContent(pattern, i)) {
193
202
  return true;
194
203
  }
195
- // Find closing brace to move past it
196
- let j = i + 1;
197
- while (j < pattern.length && pattern[j] !== "}") {
198
- j++;
199
- }
200
- i = j;
204
+ i = findClosingBrace(pattern, i);
201
205
  }
202
206
  }
203
207
  return false;
204
208
  }
209
+ /**
210
+ * Finds the index of the closing brace matching an opening brace.
211
+ * Returns the index of the closing brace, or the last index of pattern if not found.
212
+ */
213
+ function findClosingBrace(pattern, startIndex) {
214
+ let j = startIndex + 1;
215
+ while (j < pattern.length && pattern[j] !== "}") {
216
+ j++;
217
+ }
218
+ return j;
219
+ }
205
220
  /**
206
221
  * Count bracket/paren/brace pairs in a regex pattern, excluding character classes.
207
222
  */
@@ -489,7 +504,6 @@ export function truncateMatches(matches, maxResults) {
489
504
  matchesKept++;
490
505
  }
491
506
  else {
492
- break;
493
507
  }
494
508
  }
495
509
  else if (match.isContext) {
@@ -11,6 +11,20 @@ export type CompleteToolNames = keyof CompleteToolSet;
11
11
  export declare function initTools({ workspace, }: {
12
12
  workspace: WorkspaceContext;
13
13
  }): Promise<{
14
+ readonly ApplyPatch: {
15
+ toolDef: {
16
+ description: string;
17
+ inputSchema: import("zod").ZodObject<{
18
+ patchText: import("zod").ZodString;
19
+ }, import("zod/v4/core").$strip>;
20
+ };
21
+ display({ patchText }: {
22
+ patchText: string;
23
+ }): string;
24
+ execute({ patchText }: {
25
+ patchText: string;
26
+ }, { abortSignal }: import("./types.ts").ToolExecutionOptions): Promise<string>;
27
+ };
14
28
  readonly Edit: {
15
29
  toolDef: {
16
30
  description: string;
@@ -112,7 +126,6 @@ export declare function initTools({ workspace, }: {
112
126
  }>>>;
113
127
  startLine: import("zod").ZodPipe<import("zod").ZodTransform<unknown, unknown>, import("zod").ZodNullable<import("zod").ZodCoercedNumber<unknown>>>;
114
128
  lineCount: import("zod").ZodPipe<import("zod").ZodTransform<unknown, unknown>, import("zod").ZodNullable<import("zod").ZodCoercedNumber<unknown>>>;
115
- maxBytes: import("zod").ZodPipe<import("zod").ZodTransform<unknown, unknown>, import("zod").ZodNullable<import("zod").ZodCoercedNumber<unknown>>>;
116
129
  }, import("zod/v4/core").$strip>;
117
130
  };
118
131
  display({ path: providedPath, startLine, lineCount }: {
@@ -120,14 +133,12 @@ export declare function initTools({ workspace, }: {
120
133
  encoding: "utf8" | "ascii" | "utf-8" | "utf16le" | "ucs2" | "ucs-2" | "base64" | "base64url" | "latin1" | "binary" | "hex" | null;
121
134
  startLine: number | null;
122
135
  lineCount: number | null;
123
- maxBytes: number | null;
124
136
  }): string;
125
- execute({ path: providedPath, encoding, startLine, lineCount, maxBytes, }: {
137
+ execute({ path: providedPath, encoding, startLine, lineCount, }: {
126
138
  path: string;
127
139
  encoding: "utf8" | "ascii" | "utf-8" | "utf16le" | "ucs2" | "ucs-2" | "base64" | "base64url" | "latin1" | "binary" | "hex" | null;
128
140
  startLine: number | null;
129
141
  lineCount: number | null;
130
- maxBytes: number | null;
131
142
  }, { abortSignal }: import("./types.ts").ToolExecutionOptions): Promise<string>;
132
143
  };
133
144
  readonly Glob: {
@@ -203,50 +214,6 @@ export declare function initTools({ workspace, }: {
203
214
  maxResults: number | null;
204
215
  }, { abortSignal }: import("./types.ts").ToolExecutionOptions): Promise<string>;
205
216
  };
206
- readonly CodeSearch: {
207
- toolDef: {
208
- description: string;
209
- inputSchema: import("zod").ZodObject<{
210
- query: import("zod").ZodString;
211
- path: import("zod").ZodDefault<import("zod").ZodString>;
212
- regexPattern: import("zod").ZodPipe<import("zod").ZodTransform<unknown, unknown>, import("zod").ZodNullable<import("zod").ZodString>>;
213
- filePattern: import("zod").ZodPipe<import("zod").ZodTransform<unknown, unknown>, import("zod").ZodNullable<import("zod").ZodString>>;
214
- excludePattern: import("zod").ZodPipe<import("zod").ZodTransform<unknown, unknown>, import("zod").ZodNullable<import("zod").ZodString>>;
215
- excludeDir: import("zod").ZodPipe<import("zod").ZodTransform<unknown, unknown>, import("zod").ZodNullable<import("zod").ZodString>>;
216
- maxResults: import("zod").ZodPipe<import("zod").ZodTransform<unknown, unknown>, import("zod").ZodNullable<import("zod").ZodCoercedNumber<unknown>>>;
217
- contextLines: import("zod").ZodPipe<import("zod").ZodTransform<unknown, unknown>, import("zod").ZodNullable<import("zod").ZodCoercedNumber<unknown>>>;
218
- filesOnly: import("zod").ZodPipe<import("zod").ZodTransform<unknown, unknown>, import("zod").ZodNullable<import("zod").ZodCoercedBoolean<unknown>>>;
219
- showContent: import("zod").ZodPipe<import("zod").ZodTransform<unknown, unknown>, import("zod").ZodNullable<import("zod").ZodCoercedBoolean<unknown>>>;
220
- codeOnly: import("zod").ZodPipe<import("zod").ZodTransform<unknown, unknown>, import("zod").ZodNullable<import("zod").ZodCoercedBoolean<unknown>>>;
221
- }, import("zod/v4/core").$strip>;
222
- };
223
- display({ query, path, regexPattern, filePattern, excludePattern, excludeDir, maxResults, contextLines, filesOnly, showContent, codeOnly, }: {
224
- query: string;
225
- path: string;
226
- regexPattern: string | null;
227
- filePattern: string | null;
228
- excludePattern: string | null;
229
- excludeDir: string | null;
230
- maxResults: number | null;
231
- contextLines: number | null;
232
- filesOnly: boolean | null;
233
- showContent: boolean | null;
234
- codeOnly: boolean | null;
235
- }): string;
236
- execute({ query, path, regexPattern, filePattern, excludePattern, excludeDir, maxResults, contextLines, filesOnly, showContent, codeOnly, }: {
237
- query: string;
238
- path: string;
239
- regexPattern: string | null;
240
- filePattern: string | null;
241
- excludePattern: string | null;
242
- excludeDir: string | null;
243
- maxResults: number | null;
244
- contextLines: number | null;
245
- filesOnly: boolean | null;
246
- showContent: boolean | null;
247
- codeOnly: boolean | null;
248
- }, { abortSignal }: import("./types.ts").ToolExecutionOptions): Promise<string>;
249
- };
250
217
  readonly DirectoryTree: {
251
218
  toolDef: {
252
219
  description: string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../source/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;AAE/B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAoBpD,MAAM,MAAM,eAAe,GAAG;IAC5B,CAAC,UAAU,CAAC,IAAI,MAAM,eAAe,CAAC,OAAO,SAAS,CAAC,GAAG,eAAe,CACvE,OAAO,SAAS,CACjB,CAAC,CAAC,CAAC;CACL,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,CAAC,UAAU,CAAC,IAAI,MAAM,eAAe,CAAC,OAAO,SAAS,CAAC,GAAG,IAAI,CAC5D,OAAO,EACP,MAAM,CACP;CACF,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,MAAM,eAAe,CAAC;AAEtD,wBAAsB,SAAS,CAAC,EAC9B,SAAS,GACV,EAAE;IACD,SAAS,EAAE,gBAAgB,CAAC;CAC7B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0EA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../source/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;AAE/B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAoBpD,MAAM,MAAM,eAAe,GAAG;IAC5B,CAAC,UAAU,CAAC,IAAI,MAAM,eAAe,CAAC,OAAO,SAAS,CAAC,GAAG,eAAe,CACvE,OAAO,SAAS,CACjB,CAAC,CAAC,CAAC;CACL,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,CAAC,UAAU,CAAC,IAAI,MAAM,eAAe,CAAC,OAAO,SAAS,CAAC,GAAG,IAAI,CAC5D,OAAO,EACP,MAAM,CACP;CACF,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,MAAM,eAAe,CAAC;AAEtD,wBAAsB,SAAS,CAAC,EAC9B,SAAS,GACV,EAAE;IACD,SAAS,EAAE,gBAAgB,CAAC;CAC7B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0EA"}
@@ -1,7 +1,7 @@
1
1
  import { config } from "../config/index.js";
2
2
  import { AgentTool, createAgentTools } from "./agent.js";
3
+ import { ApplyPatchTool, createApplyPatchTool } from "./apply-patch.js";
3
4
  import { BashTool, createBashTool } from "./bash.js";
4
- import { CodeSearchTool, createCodeSearchTool } from "./code-search.js";
5
5
  import { createDirectoryTreeTool, DirectoryTreeTool, } from "./directory-tree.js";
6
6
  import { loadDynamicTools } from "./dynamic-tool-loader.js";
7
7
  import { createEditFileTool, EditFileTool } from "./edit-file.js";
@@ -21,7 +21,6 @@ export async function initTools({ workspace, }) {
21
21
  const directoryTreeTool = await createDirectoryTreeTool({ workspace });
22
22
  const globTool = createGlobTool();
23
23
  const grepTool = createGrepTool();
24
- const codeSearchTool = createCodeSearchTool();
25
24
  const thinkTool = createThinkTool();
26
25
  const lsTool = await createLsTool({ workspace });
27
26
  const projectConfig = await config.getConfig();
@@ -30,16 +29,17 @@ export async function initTools({ workspace, }) {
30
29
  const agentTool = await createAgentTools({ workspace });
31
30
  const webSearchTool = await createWebSearchTool();
32
31
  const webFetchTool = await createWebFetchTool();
32
+ const applyPatchTool = await createApplyPatchTool({ workspace });
33
33
  const dynamicTools = await loadDynamicTools({
34
34
  baseDir: workspace.primaryDir,
35
35
  existingToolNames: [
36
+ ApplyPatchTool.name,
36
37
  EditFileTool.name,
37
38
  BashTool.name,
38
39
  SaveFileTool.name,
39
40
  ReadFileTool.name,
40
41
  GlobTool.name,
41
42
  GrepTool.name,
42
- CodeSearchTool.name,
43
43
  DirectoryTreeTool.name,
44
44
  ThinkTool.name,
45
45
  LsTool.name,
@@ -51,13 +51,13 @@ export async function initTools({ workspace, }) {
51
51
  });
52
52
  // Build tools object for AI SDK
53
53
  const tools = {
54
+ [ApplyPatchTool.name]: applyPatchTool,
54
55
  [EditFileTool.name]: editFileTool,
55
56
  [BashTool.name]: bashTool,
56
57
  [SaveFileTool.name]: saveFileTool,
57
58
  [ReadFileTool.name]: readFileTool,
58
59
  [GlobTool.name]: globTool,
59
60
  [GrepTool.name]: grepTool,
60
- [CodeSearchTool.name]: codeSearchTool,
61
61
  [DirectoryTreeTool.name]: directoryTreeTool,
62
62
  [ThinkTool.name]: thinkTool,
63
63
  [LsTool.name]: lsTool,
@@ -1 +1 @@
1
- {"version":3,"file":"ls.d.ts","sourceRoot":"","sources":["../../source/tools/ls.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAMpD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEvD,eAAO,MAAM,MAAM;;CAElB,CAAC;AAEF,QAAA,MAAM,WAAW;;;iBAQf,CAAC;AAEH,KAAK,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAIjD,eAAO,MAAM,YAAY,GAAU,SAAS;IAC1C,SAAS,EAAE,gBAAgB,CAAC;CAC7B;;;;;;;;2CAS0C,aAAa;2CAOnB,aAAa,mBAC3B,oBAAoB,GACpC,OAAO,CAAC,MAAM,CAAC;EA6DrB,CAAC"}
1
+ {"version":3,"file":"ls.d.ts","sourceRoot":"","sources":["../../source/tools/ls.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAMpD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEvD,eAAO,MAAM,MAAM;;CAElB,CAAC;AAEF,QAAA,MAAM,WAAW;;;iBAQf,CAAC;AAEH,KAAK,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAIjD,eAAO,MAAM,YAAY,GAAU,SAAS;IAC1C,SAAS,EAAE,gBAAgB,CAAC;CAC7B;;;;;;;;2CAU0C,aAAa;2CAOnB,aAAa,mBAC3B,oBAAoB,GACpC,OAAO,CAAC,MAAM,CAAC;EA6DrB,CAAC"}
package/dist/tools/ls.js CHANGED
@@ -24,7 +24,7 @@ export const createLsTool = async (options) => {
24
24
  const allowedDirectory = allowedDirs ?? [primaryDir];
25
25
  return {
26
26
  toolDef: {
27
- description: "List files in a directory.",
27
+ description: "List files in a single directory. Fast and simple - use this when you need a quick flat list of files in one directory. For recursive tree views, use DirectoryTree instead.",
28
28
  inputSchema,
29
29
  },
30
30
  display({ path: providedPath, limit }) {