@kb-labs/agent-tools 2.89.0 → 2.94.0

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.
package/dist/index.d.ts CHANGED
@@ -628,18 +628,33 @@ declare const SOURCE_FILE_EXTENSIONS: {
628
628
  };
629
629
  /** Flat list of all source file extensions */
630
630
  declare const ALL_SOURCE_EXTENSIONS: readonly string[];
631
+ declare function shellSingleQuote(value: string): string;
631
632
  /**
632
- * Build `--include="*.ext"` flags for ripgrep / grep.
633
+ * Build `--include='*.ext'` flags for ripgrep / grep.
633
634
  * @example toRgIncludes(ALL_SOURCE_EXTENSIONS)
634
- * // → '--include="*.ts" --include="*.tsx" ...'
635
+ * // → "--include='*.ts' --include='*.tsx' ..."
635
636
  */
636
637
  declare function toRgIncludes(exts: readonly string[]): string;
637
638
  /**
638
- * Build `-name "*.ext"` flags for `find` (joined with ` -o `).
639
+ * Build `--include=*.ext` args for grep when using execa array mode (no shell).
640
+ * @example toRgIncludesArgs(['ts', 'tsx'])
641
+ * // → ['--include=*.ts', '--include=*.tsx']
642
+ */
643
+ declare function toRgIncludesArgs(exts: readonly string[]): string[];
644
+ /**
645
+ * Build `-name '*.ext'` flags for `find` (joined with ` -o `).
639
646
  * @example toFindNames(ALL_SOURCE_EXTENSIONS)
640
- * // → '-name "*.ts" -o -name "*.tsx" ...'
647
+ * // → "-name '*.ts' -o -name '*.tsx' ..."
641
648
  */
642
649
  declare function toFindNames(exts: readonly string[]): string;
650
+ /**
651
+ * Build `-name *.ext` args for `find` when using execa array mode (no shell).
652
+ * Returns a flat list of alternating pairs: ['-name', '*.ts', '-o', '-name', '*.tsx', ...]
653
+ * with no leading/trailing `-o`.
654
+ * @example toFindNamesArgs(['ts', 'tsx'])
655
+ * // → ['-name', '*.ts', '-o', '-name', '*.tsx']
656
+ */
657
+ declare function toFindNamesArgs(exts: readonly string[]): string[];
643
658
 
644
659
  /**
645
660
  * Shared utilities for agent tool implementations.
@@ -726,4 +741,4 @@ declare class RemoteWorkspaceProvider implements IWorkspaceProvider {
726
741
  }): Promise<ShellResult>;
727
742
  }
728
743
 
729
- export { ALL_SOURCE_EXTENSIONS, DELEGATION_CONFIG, type DispatchFn, FILESYSTEM_CONFIG, type FileReadResult, type FileStatResult, type GlobResult, type GrepMatch, type GrepResult, type IArchiveMemory, type ITaskManager, type IWorkspaceProvider, MASS_REPLACE_CONFIG, PLAN_READ_ONLY_TOOL_NAMES, RemoteWorkspaceProvider, SEARCH_CONFIG, SHELL_CONFIG, SOURCE_FILE_EXTENSIONS, SUB_AGENT_PRESETS, type SessionMemoryBridge, type ShellResult, TODO_CONFIG, type Tool, type ToolContext, type ToolExecutionEnvelope, type ToolExecutor, ToolGateway, type ToolPolicy, ToolRegistry, type ToolResponseRequirements, createArchiveRecallTool, createAskParentTool, createAskUserTool, createCodeStatsTool, createFindDefinitionTool, createFsListTool, createFsPatchTool, createFsReadTool, createFsReplaceTool, createFsWriteTool, createGlobSearchTool, createGrepSearchTool, createListFilesTool, createMassReplaceTool, createMemoryBlockerTool, createMemoryConstraintTool, createMemoryCorrectionTool, createMemoryFindingTool, createMemoryGetTool, createMemoryPreferenceTool, createPlanValidateTool, createPlanWriteTool, createReportTool, createSessionSaveTool, createShellExecTool, createTaskCollectTool, createTaskStatusTool, createTaskSubmitTool, createTodoCreateTool, createTodoGetTool, createTodoUpdateTool, createToolRegistry, normalizeOffsetLimit, suggestDirectory, toFindNames, toRgIncludes, validatePath };
744
+ export { ALL_SOURCE_EXTENSIONS, DELEGATION_CONFIG, type DispatchFn, FILESYSTEM_CONFIG, type FileReadResult, type FileStatResult, type GlobResult, type GrepMatch, type GrepResult, type IArchiveMemory, type ITaskManager, type IWorkspaceProvider, MASS_REPLACE_CONFIG, PLAN_READ_ONLY_TOOL_NAMES, RemoteWorkspaceProvider, SEARCH_CONFIG, SHELL_CONFIG, SOURCE_FILE_EXTENSIONS, SUB_AGENT_PRESETS, type SessionMemoryBridge, type ShellResult, TODO_CONFIG, type Tool, type ToolContext, type ToolExecutionEnvelope, type ToolExecutor, ToolGateway, type ToolPolicy, ToolRegistry, type ToolResponseRequirements, createArchiveRecallTool, createAskParentTool, createAskUserTool, createCodeStatsTool, createFindDefinitionTool, createFsListTool, createFsPatchTool, createFsReadTool, createFsReplaceTool, createFsWriteTool, createGlobSearchTool, createGrepSearchTool, createListFilesTool, createMassReplaceTool, createMemoryBlockerTool, createMemoryConstraintTool, createMemoryCorrectionTool, createMemoryFindingTool, createMemoryGetTool, createMemoryPreferenceTool, createPlanValidateTool, createPlanWriteTool, createReportTool, createSessionSaveTool, createShellExecTool, createTaskCollectTool, createTaskStatusTool, createTaskSubmitTool, createTodoCreateTool, createTodoGetTool, createTodoUpdateTool, createToolRegistry, normalizeOffsetLimit, shellSingleQuote, suggestDirectory, toFindNames, toFindNamesArgs, toRgIncludes, toRgIncludesArgs, validatePath };
package/dist/index.js CHANGED
@@ -3,8 +3,9 @@ import * as path4 from 'path';
3
3
  import path4__default from 'path';
4
4
  import * as crypto from 'crypto';
5
5
  import { glob } from 'glob';
6
- import { execSync } from 'child_process';
6
+ import { execa } from 'execa';
7
7
  import { useLLM } from '@kb-labs/sdk';
8
+ import { execSync } from 'child_process';
8
9
  import * as readline from 'readline';
9
10
  import { useLLM as useLLM$1 } from '@kb-labs/sdk/hooks';
10
11
 
@@ -303,11 +304,30 @@ var SOURCE_FILE_EXTENSIONS = {
303
304
  cpp: ["cpp", "c", "h", "cc", "cxx"]
304
305
  };
305
306
  var ALL_SOURCE_EXTENSIONS = Object.values(SOURCE_FILE_EXTENSIONS).flat();
307
+ function shellSingleQuote(value) {
308
+ return `'${value.replace(/'/g, `'"'"'`)}'`;
309
+ }
306
310
  function toRgIncludes(exts) {
307
- return exts.map((e) => `--include="*.${e}"`).join(" ");
311
+ return exts.map((e) => `--include=${shellSingleQuote(`*.${e}`)}`).join(" ");
312
+ }
313
+ function toRgIncludesArgs(exts) {
314
+ return exts.map((e) => `--include=*.${e}`);
308
315
  }
309
316
  function toFindNames(exts) {
310
- return exts.map((e) => `-name "*.${e}"`).join(" -o ");
317
+ return exts.map((e) => `-name ${shellSingleQuote(`*.${e}`)}`).join(" -o ");
318
+ }
319
+ function toFindNamesArgs(exts) {
320
+ if (exts.length === 0) {
321
+ return [];
322
+ }
323
+ const result = [];
324
+ for (let i = 0; i < exts.length; i++) {
325
+ if (i > 0) {
326
+ result.push("-o");
327
+ }
328
+ result.push("-name", `*.${exts[i]}`);
329
+ }
330
+ return result;
311
331
  }
312
332
  function normalizeOffsetLimit(input, config) {
313
333
  const rawOffset = Number(input.offset);
@@ -1307,16 +1327,16 @@ ${continuationHint}`;
1307
1327
  var DEFAULT_EXCLUDES = SEARCH_CONFIG.defaultExcludes;
1308
1328
  var MAX_OUTPUT_CHARS2 = SEARCH_CONFIG.maxOutputChars;
1309
1329
  function buildFindExcludes(excludes) {
1310
- return excludes.map((d) => `! -path "*/${d}/*"`).join(" ");
1330
+ const args = [];
1331
+ for (const d of excludes) {
1332
+ args.push("!", "-path", `*/${d}/*`);
1333
+ }
1334
+ return args;
1311
1335
  }
1312
1336
  function buildGrepExcludes(excludes) {
1313
- return excludes.map((d) => `--exclude-dir=${d}`).join(" ");
1314
- }
1315
- function toSingleQuoted(value) {
1316
- return `'${value.replace(/'/g, `'"'"'`)}'`;
1337
+ return excludes.map((d) => `--exclude-dir=${d}`);
1317
1338
  }
1318
1339
  var SEARCH_TIMEOUT_MS = SEARCH_CONFIG.timeoutMs;
1319
- var SEARCH_MAX_BUFFER = SEARCH_CONFIG.maxBuffer;
1320
1340
  var DEFAULT_RESULT_LIMIT = SEARCH_CONFIG.defaultResultLimit;
1321
1341
  var MAX_RESULT_LIMIT = SEARCH_CONFIG.maxResultLimit;
1322
1342
  function validateDirectory(workingDir, directory) {
@@ -1400,14 +1420,20 @@ function createGlobSearchTool(context) {
1400
1420
  return { success: true, output: dirError };
1401
1421
  }
1402
1422
  const windowSize = Math.min(2e3, Math.max(500, offset + limit));
1403
- const cmd = `find "${fullPath}" -type f -iname "${pattern}" ${buildFindExcludes(excludes)} | head -${windowSize}`;
1404
- const output = execSync(cmd, {
1423
+ const args = [
1424
+ fullPath,
1425
+ "-type",
1426
+ "f",
1427
+ "-iname",
1428
+ pattern,
1429
+ ...buildFindExcludes(excludes)
1430
+ ];
1431
+ const result = await execa("find", args, {
1405
1432
  cwd: context.workingDir,
1406
- encoding: "utf-8",
1407
- maxBuffer: SEARCH_MAX_BUFFER,
1433
+ reject: false,
1408
1434
  timeout: SEARCH_TIMEOUT_MS
1409
1435
  });
1410
- const files = output.trim().split("\n").filter(Boolean).map((f) => path4.relative(context.workingDir, f));
1436
+ const files = result.stdout.split("\n").filter(Boolean).slice(0, windowSize).map((f) => path4.relative(context.workingDir, f));
1411
1437
  if (files.length === 0) {
1412
1438
  return {
1413
1439
  success: true,
@@ -1416,7 +1442,7 @@ function createGlobSearchTool(context) {
1416
1442
  }
1417
1443
  const page = paginate(files, offset, limit);
1418
1444
  const excludeNote = `[Excluded: ${DEFAULT_EXCLUDES.join(", ")}${extra && extra.length > 0 ? ` + ${extra.join(", ")}` : ""}]`;
1419
- const result = [
1445
+ const resultText = [
1420
1446
  `Found ${files.length} file(s) matching "${pattern}" in "${directory}" (showing ${page.page.length}, offset=${offset}, limit=${limit})`,
1421
1447
  excludeNote,
1422
1448
  "",
@@ -1426,7 +1452,7 @@ function createGlobSearchTool(context) {
1426
1452
  const continuationHint = page.hasMore ? `Next page: glob_search(pattern="${pattern}", directory="${directory}", offset=${page.nextOffset}, limit=${limit})` : "";
1427
1453
  return {
1428
1454
  success: true,
1429
- output: trimOutput2(result, MAX_OUTPUT_CHARS2, continuationHint),
1455
+ output: trimOutput2(resultText, MAX_OUTPUT_CHARS2, continuationHint),
1430
1456
  metadata: {
1431
1457
  totalMatches: files.length,
1432
1458
  offset,
@@ -1525,39 +1551,57 @@ function createGrepSearchTool(context) {
1525
1551
  return { success: true, output: dirError };
1526
1552
  }
1527
1553
  const windowSize = Math.min(2e3, Math.max(500, offset + limit));
1528
- const regexCmd = `grep -rIn ${toSingleQuoted(pattern)} "${fullPath}" ${buildGrepExcludes(excludes)}${filePattern ? ` --include="${filePattern}"` : ""}`;
1529
- const literalCmd = `grep -rIFn ${toSingleQuoted(pattern)} "${fullPath}" ${buildGrepExcludes(excludes)}${filePattern ? ` --include="${filePattern}"` : ""}`;
1530
- let cmd = mode === "literal" ? literalCmd : regexCmd;
1531
- cmd += ` | head -${windowSize}`;
1554
+ const buildArgs = (literal) => {
1555
+ const args = ["-rIn"];
1556
+ if (literal) {
1557
+ args.push("-F");
1558
+ }
1559
+ args.push(pattern, fullPath);
1560
+ args.push(...buildGrepExcludes(excludes));
1561
+ if (filePattern) {
1562
+ args.push(`--include=${filePattern}`);
1563
+ }
1564
+ return args;
1565
+ };
1532
1566
  let output = "";
1533
1567
  let usedLiteralFallback = false;
1534
- try {
1535
- output = execSync(cmd, {
1568
+ const runGrep = async (literal) => {
1569
+ const res = await execa("grep", buildArgs(literal), {
1536
1570
  cwd: context.workingDir,
1537
- encoding: "utf-8",
1538
- maxBuffer: SEARCH_MAX_BUFFER,
1571
+ reject: false,
1539
1572
  timeout: SEARCH_TIMEOUT_MS
1540
1573
  });
1541
- } catch (error) {
1542
- const status = error.status;
1543
- const stderrRaw = error.stderr;
1544
- const stderr = typeof stderrRaw === "string" ? stderrRaw : stderrRaw instanceof Buffer ? stderrRaw.toString("utf-8") : "";
1545
- const looksLikeInvalidRegex = status === 2 && /(unbalanced|parentheses|invalid regular expression|regular expression)/i.test(stderr);
1546
- if (!looksLikeInvalidRegex) {
1547
- throw error;
1548
- }
1549
- usedLiteralFallback = true;
1550
- if (mode === "regex") {
1551
- throw error;
1574
+ return { stdout: res.stdout, exitCode: res.exitCode ?? 0, stderr: res.stderr };
1575
+ };
1576
+ const initial = await runGrep(mode === "literal");
1577
+ if (initial.exitCode === 2) {
1578
+ const looksLikeInvalidRegex = /(unbalanced|parentheses|invalid regular expression|regular expression)/i.test(initial.stderr);
1579
+ if (looksLikeInvalidRegex && mode !== "regex") {
1580
+ usedLiteralFallback = true;
1581
+ const fallback = await runGrep(true);
1582
+ output = fallback.stdout;
1583
+ if (fallback.exitCode === 2) {
1584
+ return toolError({
1585
+ code: "SEARCH_FAILED",
1586
+ message: `Grep search failed: ${fallback.stderr}`,
1587
+ retryable: true,
1588
+ hint: 'Try mode="literal" for special characters, or narrow directory.',
1589
+ details: { directory, pattern, filePattern, mode }
1590
+ });
1591
+ }
1592
+ } else {
1593
+ return toolError({
1594
+ code: "SEARCH_FAILED",
1595
+ message: `Grep search failed: ${initial.stderr}`,
1596
+ retryable: true,
1597
+ hint: 'Try mode="literal" for special characters, or narrow directory.',
1598
+ details: { directory, pattern, filePattern, mode }
1599
+ });
1552
1600
  }
1553
- output = execSync(`${literalCmd} | head -${windowSize}`, {
1554
- cwd: context.workingDir,
1555
- encoding: "utf-8",
1556
- maxBuffer: SEARCH_MAX_BUFFER,
1557
- timeout: SEARCH_TIMEOUT_MS
1558
- });
1601
+ } else {
1602
+ output = initial.stdout;
1559
1603
  }
1560
- const lines = output.trim().split("\n").filter(Boolean);
1604
+ const lines = output.split("\n").filter(Boolean).slice(0, windowSize);
1561
1605
  if (lines.length === 0) {
1562
1606
  return {
1563
1607
  success: true,
@@ -1566,7 +1610,7 @@ function createGrepSearchTool(context) {
1566
1610
  }
1567
1611
  const page = paginate(lines, offset, limit);
1568
1612
  const excludeNote = `[Excluded: ${DEFAULT_EXCLUDES.join(", ")}${extra && extra.length > 0 ? ` + ${extra.join(", ")}` : ""}]`;
1569
- const result = [
1613
+ const resultText = [
1570
1614
  `Found ${lines.length} match(es) for "${pattern}" in "${directory}"${filePattern ? ` (${filePattern})` : ""}${usedLiteralFallback ? " (literal fallback)" : ""} (showing ${page.page.length}, offset=${offset}, limit=${limit})`,
1571
1615
  excludeNote,
1572
1616
  "",
@@ -1585,7 +1629,7 @@ function createGrepSearchTool(context) {
1585
1629
  const continuationHint = page.hasMore ? `Next page: grep_search(pattern="${pattern}", directory="${directory}", offset=${page.nextOffset}, limit=${limit})` : "";
1586
1630
  return {
1587
1631
  success: true,
1588
- output: trimOutput2(result, MAX_OUTPUT_CHARS2, continuationHint),
1632
+ output: trimOutput2(resultText, MAX_OUTPUT_CHARS2, continuationHint),
1589
1633
  metadata: {
1590
1634
  totalMatches: lines.length,
1591
1635
  offset,
@@ -1596,12 +1640,6 @@ function createGrepSearchTool(context) {
1596
1640
  }
1597
1641
  };
1598
1642
  } catch (error) {
1599
- if (error instanceof Error && "status" in error && error.status === 1) {
1600
- return {
1601
- success: true,
1602
- output: `No matches found for "${pattern}" in ${directory === "." ? "project root" : directory}.${filePattern ? "" : ' Try adding filePattern (e.g. "*.ts") to narrow the search.'}`
1603
- };
1604
- }
1605
1643
  if (error instanceof Error && "killed" in error && error.killed) {
1606
1644
  return toolError({
1607
1645
  code: "SEARCH_TIMEOUT",
@@ -1667,19 +1705,30 @@ function createListFilesTool(context) {
1667
1705
  const { offset, limit } = normalizeOffsetLimit2(input);
1668
1706
  try {
1669
1707
  const fullPath = path4.resolve(context.workingDir, directory);
1670
- let cmd;
1671
1708
  if (recursive) {
1672
- cmd = `find "${fullPath}" -type f ! -path "*/node_modules/*" ! -path "*/.git/*" ! -path "*/dist/*" ! -path "*/.kb/*" | head -100`;
1673
- } else {
1674
- cmd = `ls -la "${fullPath}" 2>/dev/null || echo "Directory not found"`;
1675
- }
1676
- const output = execSync(cmd, {
1677
- cwd: context.workingDir,
1678
- encoding: "utf-8",
1679
- maxBuffer: 1024 * 1024
1680
- });
1681
- if (recursive) {
1682
- const files = output.trim().split("\n").filter(Boolean).map((f) => path4.relative(context.workingDir, f));
1709
+ const args = [
1710
+ fullPath,
1711
+ "-type",
1712
+ "f",
1713
+ "!",
1714
+ "-path",
1715
+ "*/node_modules/*",
1716
+ "!",
1717
+ "-path",
1718
+ "*/.git/*",
1719
+ "!",
1720
+ "-path",
1721
+ "*/dist/*",
1722
+ "!",
1723
+ "-path",
1724
+ "*/.kb/*"
1725
+ ];
1726
+ const result = await execa("find", args, {
1727
+ cwd: context.workingDir,
1728
+ reject: false,
1729
+ timeout: SEARCH_TIMEOUT_MS
1730
+ });
1731
+ const files = result.stdout.split("\n").filter(Boolean).slice(0, 100).map((f) => path4.relative(context.workingDir, f));
1683
1732
  const page = paginate(files, offset, limit);
1684
1733
  return {
1685
1734
  success: true,
@@ -1697,11 +1746,24 @@ Next page: list_files(directory="${directory}", recursive=true, offset=${page.ne
1697
1746
  }
1698
1747
  };
1699
1748
  }
1749
+ let entries;
1750
+ try {
1751
+ entries = fs2.readdirSync(fullPath, { withFileTypes: true });
1752
+ } catch {
1753
+ return {
1754
+ success: true,
1755
+ output: "Directory not found"
1756
+ };
1757
+ }
1758
+ const lines = entries.sort((a, b) => a.name.localeCompare(b.name)).map((e) => {
1759
+ const indicator = e.isDirectory() ? "/" : e.isSymbolicLink() ? "@" : "";
1760
+ return `${e.name}${indicator}`;
1761
+ });
1700
1762
  return {
1701
1763
  success: true,
1702
1764
  output: `Contents of ${directory}:
1703
1765
 
1704
- ${output}`
1766
+ ${lines.join("\n")}`
1705
1767
  };
1706
1768
  } catch (error) {
1707
1769
  return {
@@ -1778,27 +1840,36 @@ function createFindDefinitionTool(context) {
1778
1840
  `trait ${name}`,
1779
1841
  `mod ${name}`
1780
1842
  ];
1781
- let includeFlags = "";
1843
+ let includeArgs;
1782
1844
  if (filePattern) {
1783
- includeFlags = `--include="${filePattern}"`;
1845
+ includeArgs = [`--include=${filePattern}`];
1784
1846
  } else {
1785
- includeFlags = toRgIncludes(ALL_SOURCE_EXTENSIONS);
1786
- }
1787
- const cmd = `grep -rn -E "(${patterns.join("|")})" "${fullPath}" ${includeFlags} ${buildGrepExcludes(DEFAULT_EXCLUDES)} --exclude-dir=bin --exclude-dir=obj --exclude-dir=target | head -30`;
1788
- const output = execSync(cmd, {
1847
+ includeArgs = toRgIncludesArgs(ALL_SOURCE_EXTENSIONS);
1848
+ }
1849
+ const args = [
1850
+ "-rn",
1851
+ "-E",
1852
+ `(${patterns.join("|")})`,
1853
+ fullPath,
1854
+ ...includeArgs,
1855
+ ...buildGrepExcludes(DEFAULT_EXCLUDES),
1856
+ "--exclude-dir=bin",
1857
+ "--exclude-dir=obj",
1858
+ "--exclude-dir=target"
1859
+ ];
1860
+ const result = await execa("grep", args, {
1789
1861
  cwd: context.workingDir,
1790
- encoding: "utf-8",
1791
- maxBuffer: 1024 * 1024,
1862
+ reject: false,
1792
1863
  timeout: SEARCH_TIMEOUT_MS
1793
1864
  });
1794
- const lines = output.trim().split("\n").filter(Boolean);
1865
+ const lines = result.stdout.split("\n").filter(Boolean).slice(0, 30);
1795
1866
  if (lines.length === 0) {
1796
1867
  return {
1797
1868
  success: true,
1798
1869
  output: `No definition found for "${name}" in ${directory === "." ? "project root" : directory}. Try: grep_search for text matching, or glob_search with "*${name.toLowerCase()}*" for filename matching.`
1799
1870
  };
1800
1871
  }
1801
- const result = lines.map((line) => {
1872
+ const resultLines = lines.map((line) => {
1802
1873
  const match = line.match(/^(.+?):(\d+):(.+)$/);
1803
1874
  if (match) {
1804
1875
  const [, filePath, lineNum, content] = match;
@@ -1812,15 +1883,9 @@ function createFindDefinitionTool(context) {
1812
1883
  success: true,
1813
1884
  output: `Found definition(s) for "${name}":
1814
1885
 
1815
- ${result.join("\n\n")}`
1886
+ ${resultLines.join("\n\n")}`
1816
1887
  };
1817
1888
  } catch (error) {
1818
- if (error instanceof Error && "status" in error && error.status === 1) {
1819
- return {
1820
- success: true,
1821
- output: `No definition found for "${name}" in ${directory === "." ? "project root" : directory}. Try: grep_search for text matching, or glob_search with "*${name.toLowerCase()}*" for filename matching.`
1822
- };
1823
- }
1824
1889
  if (error instanceof Error && "killed" in error && error.killed) {
1825
1890
  return {
1826
1891
  success: false,
@@ -1875,28 +1940,68 @@ function createCodeStatsTool(context) {
1875
1940
  if (dirError) {
1876
1941
  return { success: true, output: dirError };
1877
1942
  }
1878
- let extFilter;
1943
+ let extFilterArgs;
1879
1944
  if (extensionsInput) {
1880
1945
  const exts = extensionsInput.split(",").map((e) => e.trim());
1881
- extFilter = toFindNames(exts);
1946
+ extFilterArgs = toFindNamesArgs(exts);
1882
1947
  } else {
1883
- extFilter = toFindNames(ALL_SOURCE_EXTENSIONS);
1884
- }
1885
- const totalCmd = `find "${fullPath}" -type f \\( ${extFilter} \\) ! -path "*/node_modules/*" ! -path "*/dist/*" ! -path "*/.git/*" ! -path "*/bin/*" ! -path "*/obj/*" ! -path "*/target/*" ! -path "*/__pycache__/*" -exec wc -l {} + 2>/dev/null | tail -1 || echo "0 total"`;
1886
- const totalOutput = execSync(totalCmd, {
1887
- cwd: context.workingDir,
1888
- encoding: "utf-8"
1889
- }).trim();
1890
- const countByExtCmd = `find "${fullPath}" -type f \\( ${extFilter} \\) ! -path "*/node_modules/*" ! -path "*/dist/*" ! -path "*/.git/*" ! -path "*/bin/*" ! -path "*/obj/*" ! -path "*/target/*" ! -path "*/__pycache__/*" | sed 's/.*\\.//' | sort | uniq -c | sort -rn | head -200`;
1891
- const countByExt = execSync(countByExtCmd, {
1892
- cwd: context.workingDir,
1893
- encoding: "utf-8"
1894
- }).trim().split("\n").filter(Boolean);
1895
- const fileCountCmd = `find "${fullPath}" -type f \\( ${extFilter} \\) ! -path "*/node_modules/*" ! -path "*/dist/*" ! -path "*/.git/*" ! -path "*/bin/*" ! -path "*/obj/*" ! -path "*/target/*" ! -path "*/__pycache__/*" | wc -l`;
1896
- const fileCount = execSync(fileCountCmd, {
1948
+ extFilterArgs = toFindNamesArgs(ALL_SOURCE_EXTENSIONS);
1949
+ }
1950
+ const commonExcludes = [
1951
+ "!",
1952
+ "-path",
1953
+ "*/node_modules/*",
1954
+ "!",
1955
+ "-path",
1956
+ "*/dist/*",
1957
+ "!",
1958
+ "-path",
1959
+ "*/.git/*",
1960
+ "!",
1961
+ "-path",
1962
+ "*/bin/*",
1963
+ "!",
1964
+ "-path",
1965
+ "*/obj/*",
1966
+ "!",
1967
+ "-path",
1968
+ "*/target/*",
1969
+ "!",
1970
+ "-path",
1971
+ "*/__pycache__/*"
1972
+ ];
1973
+ const findArgs = [
1974
+ fullPath,
1975
+ "-type",
1976
+ "f",
1977
+ "(",
1978
+ ...extFilterArgs,
1979
+ ")",
1980
+ ...commonExcludes
1981
+ ];
1982
+ const findResult = await execa("find", findArgs, {
1897
1983
  cwd: context.workingDir,
1898
- encoding: "utf-8"
1899
- }).trim();
1984
+ reject: false,
1985
+ timeout: SEARCH_TIMEOUT_MS
1986
+ });
1987
+ const filePaths = findResult.stdout.split("\n").filter(Boolean);
1988
+ const fileCount = filePaths.length;
1989
+ const extCounts = /* @__PURE__ */ new Map();
1990
+ for (const fp of filePaths) {
1991
+ const ext = fp.includes(".") ? fp.split(".").pop() : "(no ext)";
1992
+ extCounts.set(ext, (extCounts.get(ext) ?? 0) + 1);
1993
+ }
1994
+ const countByExt = [...extCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 200).map(([ext, count]) => ` ${count} ${ext}`);
1995
+ let totalOutput = "0 total";
1996
+ if (filePaths.length > 0) {
1997
+ const wcResult = await execa("wc", ["-l", ...filePaths], {
1998
+ cwd: context.workingDir,
1999
+ reject: false
2000
+ });
2001
+ const wcLines = wcResult.stdout.trim().split("\n").filter(Boolean);
2002
+ const lastLine = wcLines[wcLines.length - 1] ?? "";
2003
+ totalOutput = lastLine.trim();
2004
+ }
1900
2005
  const page = paginate(countByExt, offset, limit);
1901
2006
  return {
1902
2007
  success: true,
@@ -3114,11 +3219,12 @@ ${trimmed || "(command completed with no output)"}`,
3114
3219
  }
3115
3220
  };
3116
3221
  } catch (error) {
3117
- const stderr = error.stderr?.toString() || "";
3118
- const stdout = error.stdout?.toString() || "";
3119
- const exitCode = error.status ?? -1;
3222
+ const e = error;
3223
+ const stderr = e.stderr?.toString() || "";
3224
+ const stdout = e.stdout?.toString() || "";
3225
+ const exitCode = e.status ?? -1;
3120
3226
  const commandText = typeof command === "string" ? command.trim() : "";
3121
- if (error.code === "ETIMEDOUT" || error.signal === "SIGTERM") {
3227
+ if (e.code === "ETIMEDOUT" || e.signal === "SIGTERM") {
3122
3228
  return toolError({
3123
3229
  code: "SHELL_TIMEOUT",
3124
3230
  message: `Command timed out in ${resolvedCwd}`,
@@ -3981,6 +4087,6 @@ var RemoteWorkspaceProvider = class {
3981
4087
  }
3982
4088
  };
3983
4089
 
3984
- export { ALL_SOURCE_EXTENSIONS, DELEGATION_CONFIG, FILESYSTEM_CONFIG, MASS_REPLACE_CONFIG, PLAN_READ_ONLY_TOOL_NAMES, RemoteWorkspaceProvider, SEARCH_CONFIG, SHELL_CONFIG, SOURCE_FILE_EXTENSIONS, SUB_AGENT_PRESETS, TODO_CONFIG, ToolGateway, ToolRegistry, createArchiveRecallTool, createAskParentTool, createAskUserTool, createCodeStatsTool, createFindDefinitionTool, createFsListTool, createFsPatchTool, createFsReadTool, createFsReplaceTool, createFsWriteTool, createGlobSearchTool, createGrepSearchTool, createListFilesTool, createMassReplaceTool, createMemoryBlockerTool, createMemoryConstraintTool, createMemoryCorrectionTool, createMemoryFindingTool, createMemoryGetTool, createMemoryPreferenceTool, createPlanValidateTool, createPlanWriteTool, createReportTool, createSessionSaveTool, createShellExecTool, createTaskCollectTool, createTaskStatusTool, createTaskSubmitTool, createTodoCreateTool, createTodoGetTool, createTodoUpdateTool, createToolRegistry, normalizeOffsetLimit, suggestDirectory, toFindNames, toRgIncludes, validatePath };
4090
+ export { ALL_SOURCE_EXTENSIONS, DELEGATION_CONFIG, FILESYSTEM_CONFIG, MASS_REPLACE_CONFIG, PLAN_READ_ONLY_TOOL_NAMES, RemoteWorkspaceProvider, SEARCH_CONFIG, SHELL_CONFIG, SOURCE_FILE_EXTENSIONS, SUB_AGENT_PRESETS, TODO_CONFIG, ToolGateway, ToolRegistry, createArchiveRecallTool, createAskParentTool, createAskUserTool, createCodeStatsTool, createFindDefinitionTool, createFsListTool, createFsPatchTool, createFsReadTool, createFsReplaceTool, createFsWriteTool, createGlobSearchTool, createGrepSearchTool, createListFilesTool, createMassReplaceTool, createMemoryBlockerTool, createMemoryConstraintTool, createMemoryCorrectionTool, createMemoryFindingTool, createMemoryGetTool, createMemoryPreferenceTool, createPlanValidateTool, createPlanWriteTool, createReportTool, createSessionSaveTool, createShellExecTool, createTaskCollectTool, createTaskStatusTool, createTaskSubmitTool, createTodoCreateTool, createTodoGetTool, createTodoUpdateTool, createToolRegistry, normalizeOffsetLimit, shellSingleQuote, suggestDirectory, toFindNames, toFindNamesArgs, toRgIncludes, toRgIncludesArgs, validatePath };
3985
4091
  //# sourceMappingURL=index.js.map
3986
4092
  //# sourceMappingURL=index.js.map