@wrongstack/tools 0.318.0 → 0.319.1

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 (101) hide show
  1. package/dist/_edit-match.d.ts +1 -3
  2. package/dist/_util.d.ts +20 -0
  3. package/dist/audit.js +4 -4
  4. package/dist/bash.js +2 -2
  5. package/dist/builtin.d.ts +10 -0
  6. package/dist/builtin.js +46 -44
  7. package/dist/{chunk-TKA4VEX2.js → chunk-2OXHS3KZ.js} +17 -5
  8. package/dist/{chunk-X5K3U6GI.js → chunk-3M7LLN7W.js} +71 -7
  9. package/dist/{chunk-4AEZIFOW.js → chunk-5EUJF3WC.js} +36 -8
  10. package/dist/{chunk-CVALEVGA.js → chunk-64VIJPFV.js} +34 -13
  11. package/dist/{chunk-ZE6KLBUO.js → chunk-6AAOT4PW.js} +58 -10
  12. package/dist/{chunk-A6BRWIXN.js → chunk-6IEBD27U.js} +20 -5
  13. package/dist/{chunk-HTYEO67J.js → chunk-AKHYMB4V.js} +36 -12
  14. package/dist/{chunk-4E42D7UF.js → chunk-ATSKPZUK.js} +2 -2
  15. package/dist/{chunk-H6AWAZ2Y.js → chunk-B4HTSV6Z.js} +57 -6
  16. package/dist/{chunk-5ZYEGP2P.js → chunk-BK732J7I.js} +72 -27
  17. package/dist/{chunk-WI3VDXHD.js → chunk-BSJSNVGA.js} +108 -19
  18. package/dist/{chunk-UKGMDCXT.js → chunk-C2DQKVLO.js} +61 -28
  19. package/dist/{chunk-CIFAIIHI.js → chunk-CFLJFDYV.js} +100 -58
  20. package/dist/{chunk-JJQB6R7Y.js → chunk-CMOUCKGC.js} +6 -6
  21. package/dist/{chunk-MX25MTDJ.js → chunk-DC4KMPJO.js} +2 -2
  22. package/dist/{chunk-VZLX2JZG.js → chunk-DP6CXMJZ.js} +3 -3
  23. package/dist/{chunk-3QQSBUXR.js → chunk-EADULOZV.js} +36 -12
  24. package/dist/{chunk-6RNIFLG4.js → chunk-ELRRTWNP.js} +38 -6
  25. package/dist/{chunk-CPSAF2AU.js → chunk-FQNXYA6W.js} +45 -6
  26. package/dist/{chunk-ZZT45EHF.js → chunk-GMZYW52L.js} +3 -3
  27. package/dist/{chunk-ZLTFLC25.js → chunk-IIF5HIVF.js} +2 -2
  28. package/dist/{chunk-EMRGN4KM.js → chunk-IU4DV2PA.js} +18 -8
  29. package/dist/{chunk-AGUSOFNI.js → chunk-IWS56OY7.js} +30 -7
  30. package/dist/{chunk-MRZOVQ5D.js → chunk-IYKXK356.js} +98 -11
  31. package/dist/{chunk-6GZPSWP3.js → chunk-JDPQOR7C.js} +14 -7
  32. package/dist/{chunk-BLCSYKNN.js → chunk-KY4PXYSO.js} +10 -15
  33. package/dist/{chunk-WJYXMB2R.js → chunk-LOBRWKCR.js} +63 -14
  34. package/dist/{chunk-J5SKD6LN.js → chunk-MNP3GE7H.js} +38 -27
  35. package/dist/{chunk-S2GBLQ5S.js → chunk-O44IMQCN.js} +31 -7
  36. package/dist/{chunk-P7ZQ2FAJ.js → chunk-OG2BEUBY.js} +69 -34
  37. package/dist/{chunk-K23JNFE3.js → chunk-OTINMOKK.js} +233 -45
  38. package/dist/{chunk-PQTONQ4P.js → chunk-QPNYDH5B.js} +19 -5
  39. package/dist/{chunk-UE3UBMCP.js → chunk-RLMX75EM.js} +19 -8
  40. package/dist/{chunk-3U4H6ZRF.js → chunk-RNWUCZ2U.js} +53 -25
  41. package/dist/{chunk-YF3D5INN.js → chunk-RTZWBNTY.js} +121 -91
  42. package/dist/{chunk-SOG7XIRF.js → chunk-TTZOK6IY.js} +2 -2
  43. package/dist/{chunk-6GVXZCQV.js → chunk-UDVKRX5R.js} +2 -2
  44. package/dist/{chunk-CPVLVQYT.js → chunk-UQQS3VNT.js} +43 -9
  45. package/dist/{chunk-VB3MJGCV.js → chunk-VD2LV5WO.js} +82 -13
  46. package/dist/{chunk-5WNDJHT6.js → chunk-VPALDFYM.js} +2 -2
  47. package/dist/{chunk-FJEQZHZN.js → chunk-W2CECGTG.js} +24 -14
  48. package/dist/{chunk-CISOLTOP.js → chunk-X5FOFGXX.js} +72 -33
  49. package/dist/{chunk-CWALNI6K.js → chunk-X6KXNHUO.js} +1 -1
  50. package/dist/{chunk-EEOFQDT6.js → chunk-XRNN44QY.js} +46 -2
  51. package/dist/{chunk-EOOFNYIT.js → chunk-YOKD4GWJ.js} +67 -27
  52. package/dist/{chunk-D33S4RQG.js → chunk-ZUFHAHTE.js} +18 -6
  53. package/dist/codebase-index/generic-parser.d.ts +8 -1
  54. package/dist/codebase-index/index.js +9 -9
  55. package/dist/codebase-index/parser-worker-script.js +3 -3
  56. package/dist/codebase-index/project-server.js +5 -5
  57. package/dist/codebase-index/worker.js +4 -4
  58. package/dist/codebase-index/writer-refs.d.ts +1 -1
  59. package/dist/design.d.ts +1 -1
  60. package/dist/design.js +1 -1
  61. package/dist/diff.js +3 -2
  62. package/dist/document.js +2 -2
  63. package/dist/e2e.js +2 -2
  64. package/dist/edit.js +8 -8
  65. package/dist/exec.js +2 -2
  66. package/dist/fetch.js +2 -2
  67. package/dist/format.js +4 -4
  68. package/dist/{generic-parser-VUXDIAOZ.js → generic-parser-WFMIRHBX.js} +2 -2
  69. package/dist/git.js +2 -2
  70. package/dist/glob.js +2 -2
  71. package/dist/grep.d.ts +2 -0
  72. package/dist/grep.js +4 -2
  73. package/dist/index.js +46 -46
  74. package/dist/install.js +4 -4
  75. package/dist/json.js +2 -2
  76. package/dist/kanban-tool-types.d.ts +2 -0
  77. package/dist/kanban.js +2 -2
  78. package/dist/languages/index.js +2 -2
  79. package/dist/{legacy-bridge-SFNXIRAP.js → legacy-bridge-3T7SR4SK.js} +4 -4
  80. package/dist/lint.js +4 -4
  81. package/dist/logs.js +2 -2
  82. package/dist/outdated.js +4 -2
  83. package/dist/pack.js +45 -45
  84. package/dist/{parser-dispatch-X62UWXJS.js → parser-dispatch-QGC4HSP5.js} +4 -4
  85. package/dist/patch.js +8 -8
  86. package/dist/plan.js +4 -4
  87. package/dist/{py-parser-TDXSQZBC.js → py-parser-RFWG2HYI.js} +3 -3
  88. package/dist/read.js +8 -8
  89. package/dist/replace.js +9 -8
  90. package/dist/scaffold.js +2 -2
  91. package/dist/search.js +1 -1
  92. package/dist/session-kanban.js +1 -1
  93. package/dist/task.js +4 -4
  94. package/dist/test.js +4 -4
  95. package/dist/todo.js +3 -3
  96. package/dist/tool-tier.js +46 -46
  97. package/dist/{tree-sitter-parser-AIERW3YI.js → tree-sitter-parser-GILYQLS4.js} +2 -2
  98. package/dist/tree.js +2 -2
  99. package/dist/typecheck.js +4 -4
  100. package/dist/write.js +8 -8
  101. package/package.json +5 -5
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  parseTreeSitterAst
3
- } from "./chunk-EEOFQDT6.js";
3
+ } from "./chunk-XRNN44QY.js";
4
4
  import {
5
5
  spawnStream
6
6
  } from "./chunk-ZHH3BEWU.js";
@@ -13,7 +13,7 @@ import {
13
13
  outgoingCallsService,
14
14
  runStartupIndex,
15
15
  searchCodebaseIndex
16
- } from "./chunk-VZLX2JZG.js";
16
+ } from "./chunk-DP6CXMJZ.js";
17
17
  import {
18
18
  IndexTimeoutError,
19
19
  SCHEMA_VERSION,
@@ -21,15 +21,16 @@ import {
21
21
  indexCircuitBreaker,
22
22
  indexStorePool,
23
23
  resolveIndexDir
24
- } from "./chunk-BLCSYKNN.js";
24
+ } from "./chunk-KY4PXYSO.js";
25
25
  import {
26
26
  EXT_TO_LANG,
27
27
  detectLang,
28
28
  isIndexablePath
29
29
  } from "./chunk-YOHO4DVT.js";
30
30
  import {
31
- normalizeCommandOutput
32
- } from "./chunk-D33S4RQG.js";
31
+ normalizeCommandOutput,
32
+ safeResolveProjectPath
33
+ } from "./chunk-ZUFHAHTE.js";
33
34
 
34
35
  // src/codebase-index/codebase-ast-replace-tool.ts
35
36
  import * as path2 from "node:path";
@@ -689,7 +690,8 @@ var codebaseAstReplaceTool = {
689
690
  async execute(input, ctx) {
690
691
  try {
691
692
  const projectRoot = ctx.projectRoot ?? ctx.cwd ?? process.cwd();
692
- const result = await replaceSymbolInFile(input, projectRoot);
693
+ const file = await safeResolveProjectPath(input.file, ctx);
694
+ const result = await replaceSymbolInFile({ ...input, file }, projectRoot);
693
695
  return {
694
696
  status: "ok",
695
697
  file: path2.relative(projectRoot, result.file).replace(/\\/g, "/"),
@@ -711,7 +713,6 @@ var codebaseAstReplaceTool = {
711
713
 
712
714
  // src/codebase-index/codebase-invariant-check-tool.ts
713
715
  import * as fs2 from "node:fs/promises";
714
- import * as path3 from "node:path";
715
716
  import { toErrorMessage as toErrorMessage2 } from "@wrongstack/core/utils";
716
717
  var codebaseInvariantCheckTool = {
717
718
  name: "codebase-invariant-check",
@@ -751,8 +752,7 @@ var codebaseInvariantCheckTool = {
751
752
  let originalCode = input.originalCode;
752
753
  let lang = input.lang;
753
754
  if (!originalCode && input.file) {
754
- const root = ctx.projectRoot ?? ctx.cwd ?? process.cwd();
755
- const resolved = path3.isAbsolute(input.file) ? input.file : path3.resolve(root, input.file);
755
+ const resolved = await safeResolveProjectPath(input.file, ctx);
756
756
  originalCode = await fs2.readFile(resolved, "utf8");
757
757
  if (!lang) {
758
758
  lang = detectLang(resolved) ?? "ts";
@@ -791,7 +791,7 @@ var codebaseInvariantCheckTool = {
791
791
  };
792
792
 
793
793
  // src/codebase-index/codebase-impact-analysis-tool.ts
794
- import * as path4 from "node:path";
794
+ import * as path3 from "node:path";
795
795
  import { toErrorMessage as toErrorMessage3 } from "@wrongstack/core/utils";
796
796
  var TEST_FILE_REGEX = /(?:test|spec|mock|fixture|bench)[s]?[/\\._]/i;
797
797
  var codebaseImpactAnalysisTool = {
@@ -884,7 +884,7 @@ var codebaseImpactAnalysisTool = {
884
884
  const testFilesSet = /* @__PURE__ */ new Set();
885
885
  const callSites = [];
886
886
  for (const site of rawSites) {
887
- const relPath = path4.relative(projectRoot, site.symbol.file).replace(/\\/g, "/");
887
+ const relPath = path3.relative(projectRoot, site.symbol.file).replace(/\\/g, "/");
888
888
  const isTest = TEST_FILE_REGEX.test(relPath);
889
889
  if (isTest) {
890
890
  testFilesSet.add(relPath);
@@ -1088,9 +1088,10 @@ var codebaseIncomingCallsTool = {
1088
1088
  };
1089
1089
 
1090
1090
  // src/codebase-index/codebase-index-tool.ts
1091
- import { ToolValidationError } from "@wrongstack/core/types";
1091
+ import { ToolValidationError as ToolValidationError2 } from "@wrongstack/core/types";
1092
1092
 
1093
1093
  // src/codebase-index/codebase-search-tool.ts
1094
+ import { ToolValidationError } from "@wrongstack/core/types";
1094
1095
  import { toErrorMessage as toErrorMessage5 } from "@wrongstack/core/utils";
1095
1096
  var INDEXABLE_LANG_IDS = [
1096
1097
  ...new Set(Object.values(EXT_TO_LANG))
@@ -1167,6 +1168,18 @@ var codebaseSearchTool = {
1167
1168
  required: ["query"]
1168
1169
  },
1169
1170
  async execute(input, ctx, execOpts) {
1171
+ if (!input?.query || typeof input.query !== "string" || !input.query.trim()) {
1172
+ throw new ToolValidationError({
1173
+ message: "codebase-search: query is required and cannot be empty",
1174
+ field: "query"
1175
+ });
1176
+ }
1177
+ if (input.lspKind !== void 0 && (!Number.isInteger(input.lspKind) || input.lspKind < 1 || input.lspKind > 26)) {
1178
+ throw new ToolValidationError({
1179
+ message: "codebase-search: lspKind must be an integer between 1 and 26",
1180
+ field: "lspKind"
1181
+ });
1182
+ }
1170
1183
  const signal = execOpts?.signal ?? ctx?.signal;
1171
1184
  signal?.throwIfAborted();
1172
1185
  const state = getIndexState();
@@ -1190,7 +1203,7 @@ var codebaseSearchTool = {
1190
1203
  query: input.query,
1191
1204
  kind: input.kind?.toLowerCase(),
1192
1205
  lang: input.lang?.toLowerCase(),
1193
- file: input.file,
1206
+ file: input.file ? input.file.replace(/\\/g, "/").replace(/^\.\//, "") : void 0,
1194
1207
  lspKind: input.lspKind,
1195
1208
  limit
1196
1209
  },
@@ -1224,7 +1237,7 @@ var codebaseSearchTool = {
1224
1237
  try {
1225
1238
  const stats = await codebaseIndexStats(
1226
1239
  { projectRoot: ctx.projectRoot, indexDir: codebaseIndexDirOverride(ctx) },
1227
- { signal: execOpts?.signal }
1240
+ { signal }
1228
1241
  );
1229
1242
  hasPersistedIndex = stats.totalFiles > 0 || stats.lastIndexed !== null;
1230
1243
  } catch {
@@ -1276,12 +1289,20 @@ var codebaseIndexTool = {
1276
1289
  }
1277
1290
  },
1278
1291
  async execute(input, ctx, execOpts) {
1292
+ const signal = execOpts?.signal ?? ctx?.signal;
1293
+ signal?.throwIfAborted();
1279
1294
  if (input.langs) {
1295
+ if (!Array.isArray(input.langs) || input.langs.length === 0) {
1296
+ throw new ToolValidationError2({
1297
+ message: "codebase-index: langs cannot be an empty array. Pass at least one valid language or omit langs.",
1298
+ field: "langs"
1299
+ });
1300
+ }
1280
1301
  const unknown = input.langs.filter(
1281
1302
  (lang) => !INDEXABLE_LANG_IDS.includes(lang)
1282
1303
  );
1283
1304
  if (unknown.length > 0) {
1284
- throw new ToolValidationError({
1305
+ throw new ToolValidationError2({
1285
1306
  message: `codebase-index: unknown lang(s) ${unknown.map((l) => `"${l}"`).join(", ")}. Valid ids: ${INDEXABLE_LANG_IDS.join(", ")}.`,
1286
1307
  field: "langs"
1287
1308
  });
@@ -1297,23 +1318,27 @@ var codebaseIndexTool = {
1297
1318
  note: "A full index is already in progress. Retry codebase-index after it completes (check codebase-stats)."
1298
1319
  };
1299
1320
  }
1300
- const circuit = indexCircuitBreaker.snapshot();
1301
- if (circuit.state === "open" && circuit.cooldownRemainingMs > 0) {
1302
- return {
1303
- filesIndexed: 0,
1304
- symbolsIndexed: 0,
1305
- langStats: {},
1306
- durationMs: 0,
1307
- errors: [],
1308
- note: `Codebase indexing is paused after repeated failures (last: ${circuit.lastFailure ?? "unknown"}). Auto-retry possible in ${Math.ceil(circuit.cooldownRemainingMs / 1e3)}s; the user can run /codebase-reindex to retry immediately.`
1309
- };
1321
+ if (input.force) {
1322
+ indexCircuitBreaker.reset();
1323
+ } else {
1324
+ const circuit = indexCircuitBreaker.snapshot();
1325
+ if (circuit.state === "open" && circuit.cooldownRemainingMs > 0) {
1326
+ return {
1327
+ filesIndexed: 0,
1328
+ symbolsIndexed: 0,
1329
+ langStats: {},
1330
+ durationMs: 0,
1331
+ errors: [],
1332
+ note: `Codebase indexing is paused after repeated failures (last: ${circuit.lastFailure ?? "unknown"}). Auto-retry possible in ${Math.max(1, Math.ceil(circuit.cooldownRemainingMs / 1e3))}s; use force: true or run /codebase-reindex to retry immediately.`
1333
+ };
1334
+ }
1310
1335
  }
1311
1336
  const result = await runStartupIndex({
1312
1337
  projectRoot: ctx.projectRoot,
1313
1338
  force: input.force ?? false,
1314
1339
  langs: input.langs,
1315
1340
  indexDir: codebaseIndexDirOverride(ctx),
1316
- signal: execOpts?.signal
1341
+ signal
1317
1342
  });
1318
1343
  if (result.errors.length > MAX_REPORTED_ERRORS) {
1319
1344
  const hidden = result.errors.length - MAX_REPORTED_ERRORS;
@@ -1463,11 +1488,11 @@ import { toErrorMessage as toErrorMessage7 } from "@wrongstack/core/utils";
1463
1488
 
1464
1489
  // src/codebase-index/repo-map.ts
1465
1490
  import * as fs4 from "node:fs/promises";
1466
- import * as path6 from "node:path";
1491
+ import * as path5 from "node:path";
1467
1492
 
1468
1493
  // src/codebase-index/skeleton-extractor.ts
1469
1494
  import * as fs3 from "node:fs/promises";
1470
- import * as path5 from "node:path";
1495
+ import * as path4 from "node:path";
1471
1496
  var tsModule3 = null;
1472
1497
  async function loadTs3() {
1473
1498
  if (!tsModule3) {
@@ -1804,7 +1829,7 @@ async function extractDirectorySkeleton(opts) {
1804
1829
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build") {
1805
1830
  continue;
1806
1831
  }
1807
- const fullPath = path5.join(dir, entry.name);
1832
+ const fullPath = path4.join(dir, entry.name);
1808
1833
  if (entry.isDirectory()) {
1809
1834
  await scan(fullPath);
1810
1835
  } else if (entry.isFile() && isIndexablePath(fullPath)) {
@@ -1832,7 +1857,7 @@ async function extractDirectorySkeleton(opts) {
1832
1857
  totalSkelChars += res.skeleton.length;
1833
1858
  totalOrigLines += res.stats.originalLines;
1834
1859
  totalSkelLines += res.stats.skeletonLines;
1835
- const rel = path5.relative(opts.dirPath, fp).replace(/\\/g, "/");
1860
+ const rel = path4.relative(opts.dirPath, fp).replace(/\\/g, "/");
1836
1861
  combinedParts.push(
1837
1862
  `// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 ${rel} (${res.lang}) \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
1838
1863
  ${res.skeleton}`
@@ -1869,7 +1894,7 @@ async function generateRepoMap(opts) {
1869
1894
  const projectRoot = opts.projectRoot;
1870
1895
  const maxTokens = opts.maxTokens ?? 1200;
1871
1896
  const charBudget = maxTokens * 4;
1872
- const focusSet = new Set((opts.focusFiles ?? []).map((f) => path6.resolve(projectRoot, f)));
1897
+ const focusSet = new Set((opts.focusFiles ?? []).map((f) => path5.resolve(projectRoot, f)));
1873
1898
  const allFiles = [];
1874
1899
  async function scan(dir) {
1875
1900
  if (allFiles.length > 500) return;
@@ -1883,7 +1908,7 @@ async function generateRepoMap(opts) {
1883
1908
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "coverage") {
1884
1909
  continue;
1885
1910
  }
1886
- const fullPath = path6.join(dir, entry.name);
1911
+ const fullPath = path5.join(dir, entry.name);
1887
1912
  if (entry.isDirectory()) {
1888
1913
  await scan(fullPath);
1889
1914
  } else if (entry.isFile() && isIndexablePath(fullPath)) {
@@ -1903,7 +1928,7 @@ async function generateRepoMap(opts) {
1903
1928
  }
1904
1929
  const scoredFiles = [];
1905
1930
  for (const file of allFiles) {
1906
- const relPath = path6.relative(projectRoot, file).replace(/\\/g, "/");
1931
+ const relPath = path5.relative(projectRoot, file).replace(/\\/g, "/");
1907
1932
  let score = 10;
1908
1933
  if (focusSet.has(file)) {
1909
1934
  score += 100;
@@ -2009,7 +2034,6 @@ var codebaseRepoMapTool = {
2009
2034
 
2010
2035
  // src/codebase-index/codebase-skeleton-tool.ts
2011
2036
  import * as fs5 from "node:fs/promises";
2012
- import * as path7 from "node:path";
2013
2037
  import { toErrorMessage as toErrorMessage8 } from "@wrongstack/core/utils";
2014
2038
  var codebaseSkeletonTool = {
2015
2039
  name: "codebase-skeleton",
@@ -2048,8 +2072,10 @@ var codebaseSkeletonTool = {
2048
2072
  required: ["path"],
2049
2073
  additionalProperties: false
2050
2074
  },
2051
- async execute(input, ctx) {
2052
- const targetPath = path7.isAbsolute(input.path) ? input.path : path7.resolve(ctx.projectRoot ?? process.cwd(), input.path);
2075
+ async execute(input, ctx, execOpts) {
2076
+ const signal = execOpts?.signal ?? ctx?.signal;
2077
+ signal?.throwIfAborted();
2078
+ const targetPath = await safeResolveProjectPath(input.path, ctx);
2053
2079
  let stat3;
2054
2080
  try {
2055
2081
  stat3 = await fs5.stat(targetPath);
@@ -2104,6 +2130,7 @@ var codebaseSkeletonTool = {
2104
2130
  };
2105
2131
 
2106
2132
  // src/codebase-index/codebase-stats-tool.ts
2133
+ import { toErrorMessage as toErrorMessage9 } from "@wrongstack/core/utils";
2107
2134
  var codebaseStatsTool = {
2108
2135
  name: "codebase-stats",
2109
2136
  category: "Project",
@@ -2123,6 +2150,8 @@ var codebaseStatsTool = {
2123
2150
  additionalProperties: false
2124
2151
  },
2125
2152
  async execute(_input, ctx, execOpts) {
2153
+ const signal = execOpts?.signal ?? ctx?.signal;
2154
+ signal?.throwIfAborted();
2126
2155
  const idxState = getIndexState();
2127
2156
  const indexPath = resolveIndexDir(ctx.projectRoot, codebaseIndexDirOverride(ctx));
2128
2157
  if (idxState.indexing) {
@@ -2147,11 +2176,11 @@ var codebaseStatsTool = {
2147
2176
  try {
2148
2177
  stats = await codebaseIndexStats(
2149
2178
  { projectRoot: ctx.projectRoot, indexDir: codebaseIndexDirOverride(ctx) },
2150
- { signal: execOpts?.signal }
2179
+ { signal }
2151
2180
  );
2152
2181
  } catch (err) {
2153
- if (!(err instanceof IndexTimeoutError) && err?.name !== "IndexTimeoutError") {
2154
- throw err;
2182
+ if (signal?.aborted) {
2183
+ signal.throwIfAborted();
2155
2184
  }
2156
2185
  return {
2157
2186
  totalSymbols: 0,
@@ -2163,14 +2192,15 @@ var codebaseStatsTool = {
2163
2192
  indexPath,
2164
2193
  version: SCHEMA_VERSION,
2165
2194
  statsAvailable: false,
2166
- indexStatus: "Index statistics timed out. Do not repeatedly retry stats; try codebase-search directly or use the appropriate grep/glob/tree fallback."
2195
+ indexStatus: err instanceof IndexTimeoutError || err?.name === "IndexTimeoutError" ? "Index statistics timed out. Do not repeatedly retry stats; try codebase-search directly or use the appropriate grep/glob/tree fallback." : `Index statistics query failed: ${toErrorMessage9(err)}. The index may be corrupted or inaccessible; try /codebase-reindex.`
2167
2196
  };
2168
2197
  }
2169
2198
  const circuit = idxState.circuit;
2170
2199
  const hasPersistedIndex = stats.totalFiles > 0 || stats.lastIndexed !== null;
2171
2200
  let indexStatus;
2172
2201
  if (circuit.state === "open") {
2173
- indexStatus = `${hasPersistedIndex ? "Indexing" : "No persisted index data found, and indexing"} is paused after repeated failures (last: ${circuit.lastFailure ?? "unknown"}); auto-retry in ${Math.ceil(circuit.cooldownRemainingMs / 1e3)}s, or run /codebase-reindex. ` + (hasPersistedIndex ? "Stats reflect the last successful build." : "Build the index after recovery.");
2202
+ const cooldownSec = Math.max(1, Math.ceil(circuit.cooldownRemainingMs / 1e3));
2203
+ indexStatus = `${hasPersistedIndex ? "Indexing" : "No persisted index data found, and indexing"} is paused after repeated failures (last: ${circuit.lastFailure ?? "unknown"}); auto-retry in ${cooldownSec}s, or run /codebase-reindex. ` + (hasPersistedIndex ? "Stats reflect the last successful build." : "Build the index after recovery.");
2174
2204
  } else if (!hasPersistedIndex) {
2175
2205
  indexStatus = "No persisted index data found. Run codebase-index to build it before broad code exploration.";
2176
2206
  }
@@ -2191,25 +2221,25 @@ var codebaseStatsTool = {
2191
2221
 
2192
2222
  // src/codebase-index/codebase-targeted-test-tool.ts
2193
2223
  import * as fs6 from "node:fs/promises";
2194
- import * as path8 from "node:path";
2195
- import { toErrorMessage as toErrorMessage9 } from "@wrongstack/core/utils";
2224
+ import * as path6 from "node:path";
2225
+ import { toErrorMessage as toErrorMessage10 } from "@wrongstack/core/utils";
2196
2226
  var TEST_FILE_REGEX2 = /(?:test|spec|mock|fixture|bench)[s]?[/\\._]/i;
2197
2227
  async function findConventionTestFiles(projectRoot, sourceRelPath) {
2198
- const parsed = path8.parse(sourceRelPath);
2228
+ const parsed = path6.parse(sourceRelPath);
2199
2229
  const candidates = [
2200
- path8.join(parsed.dir, `${parsed.name}.test${parsed.ext}`),
2201
- path8.join(parsed.dir, `${parsed.name}.spec${parsed.ext}`),
2202
- path8.join(parsed.dir, `${parsed.name}_test${parsed.ext}`),
2203
- path8.join(parsed.dir, `test_${parsed.name}${parsed.ext}`),
2204
- path8.join("tests", `${parsed.name}.test${parsed.ext}`),
2205
- path8.join("tests", `${parsed.name}.spec${parsed.ext}`),
2206
- path8.join("test", `${parsed.name}.test${parsed.ext}`),
2207
- path8.join(parsed.dir, "__tests__", `${parsed.name}.test${parsed.ext}`),
2208
- path8.join(parsed.dir, "__tests__", `${parsed.name}${parsed.ext}`)
2230
+ path6.join(parsed.dir, `${parsed.name}.test${parsed.ext}`),
2231
+ path6.join(parsed.dir, `${parsed.name}.spec${parsed.ext}`),
2232
+ path6.join(parsed.dir, `${parsed.name}_test${parsed.ext}`),
2233
+ path6.join(parsed.dir, `test_${parsed.name}${parsed.ext}`),
2234
+ path6.join("tests", `${parsed.name}.test${parsed.ext}`),
2235
+ path6.join("tests", `${parsed.name}.spec${parsed.ext}`),
2236
+ path6.join("test", `${parsed.name}.test${parsed.ext}`),
2237
+ path6.join(parsed.dir, "__tests__", `${parsed.name}.test${parsed.ext}`),
2238
+ path6.join(parsed.dir, "__tests__", `${parsed.name}${parsed.ext}`)
2209
2239
  ];
2210
2240
  const found = [];
2211
2241
  for (const cand of candidates) {
2212
- const absPath = path8.resolve(projectRoot, cand);
2242
+ const absPath = path6.resolve(projectRoot, cand);
2213
2243
  try {
2214
2244
  const st = await fs6.stat(absPath);
2215
2245
  if (st.isFile()) {
@@ -2268,7 +2298,7 @@ var codebaseTargetedTestTool = {
2268
2298
  transitive: true
2269
2299
  });
2270
2300
  for (const site of serviced.calls) {
2271
- const relPath = path8.relative(projectRoot, site.symbol.file).replace(/\\/g, "/");
2301
+ const relPath = path6.relative(projectRoot, site.symbol.file).replace(/\\/g, "/");
2272
2302
  if (TEST_FILE_REGEX2.test(relPath)) {
2273
2303
  suitesSet.add(relPath);
2274
2304
  }
@@ -2345,7 +2375,7 @@ ${streamRes.stderr}`.trim(),
2345
2375
  failed: 0,
2346
2376
  durationMs: 0,
2347
2377
  output: "",
2348
- error: toErrorMessage9(err)
2378
+ error: toErrorMessage10(err)
2349
2379
  };
2350
2380
  }
2351
2381
  }
@@ -2353,7 +2383,7 @@ ${streamRes.stderr}`.trim(),
2353
2383
 
2354
2384
  // src/codebase-index/dead-code-scan.ts
2355
2385
  import * as fs7 from "node:fs";
2356
- import * as path9 from "node:path";
2386
+ import * as path7 from "node:path";
2357
2387
  var deadCodeScanTool = {
2358
2388
  name: "dead-code-scan",
2359
2389
  category: "Project",
@@ -2405,8 +2435,8 @@ function tryReadJson(filePath) {
2405
2435
  }
2406
2436
  }
2407
2437
  function resolveAgainst(base, relative7) {
2408
- if (path9.isAbsolute(relative7)) return relative7;
2409
- return path9.resolve(base, relative7);
2438
+ if (path7.isAbsolute(relative7)) return relative7;
2439
+ return path7.resolve(base, relative7);
2410
2440
  }
2411
2441
  function discoverEntryPoints(projectRoot, userEntryPoints) {
2412
2442
  const entries = /* @__PURE__ */ new Set();
@@ -2416,7 +2446,7 @@ function discoverEntryPoints(projectRoot, userEntryPoints) {
2416
2446
  if (fs7.existsSync(resolved)) entries.add(resolved);
2417
2447
  }
2418
2448
  }
2419
- const rootPkg = tryReadJson(path9.join(projectRoot, "package.json"));
2449
+ const rootPkg = tryReadJson(path7.join(projectRoot, "package.json"));
2420
2450
  if (rootPkg) {
2421
2451
  addPkgJsonEntryPoints(projectRoot, rootPkg, entries);
2422
2452
  }
@@ -2430,34 +2460,34 @@ function discoverEntryPoints(projectRoot, userEntryPoints) {
2430
2460
  workspaces = [];
2431
2461
  }
2432
2462
  for (const wsDir of workspaces) {
2433
- const pkgJsonPath = path9.join(wsDir, "package.json");
2463
+ const pkgJsonPath = path7.join(wsDir, "package.json");
2434
2464
  const pkg = tryReadJson(pkgJsonPath);
2435
2465
  if (pkg) {
2436
2466
  addPkgJsonEntryPoints(wsDir, pkg, entries);
2437
- const convention1 = path9.join(wsDir, "src", "index.ts");
2467
+ const convention1 = path7.join(wsDir, "src", "index.ts");
2438
2468
  if (fs7.existsSync(convention1)) entries.add(convention1);
2439
- const convention2 = path9.join(wsDir, "src", "main.ts");
2469
+ const convention2 = path7.join(wsDir, "src", "main.ts");
2440
2470
  if (fs7.existsSync(convention2)) entries.add(convention2);
2441
- const convention3 = path9.join(wsDir, "index.ts");
2471
+ const convention3 = path7.join(wsDir, "index.ts");
2442
2472
  if (fs7.existsSync(convention3)) entries.add(convention3);
2443
2473
  }
2444
2474
  }
2445
2475
  if (!rootPkg || !workspaces.length) {
2446
2476
  for (const name of ["src/index.ts", "src/main.ts", "index.ts"]) {
2447
- const convention = path9.join(projectRoot, name);
2477
+ const convention = path7.join(projectRoot, name);
2448
2478
  if (fs7.existsSync(convention)) entries.add(convention);
2449
2479
  }
2450
2480
  }
2451
2481
  return [...entries];
2452
2482
  }
2453
2483
  var BUILD_OUTPUT_DIRS = ["dist", "out", "build", "release"];
2454
- var BUILD_OUTPUT_DIR_NAMES = BUILD_OUTPUT_DIRS.map((d) => `${path9.sep}${d}${path9.sep}`);
2484
+ var BUILD_OUTPUT_DIR_NAMES = BUILD_OUTPUT_DIRS.map((d) => `${path7.sep}${d}${path7.sep}`);
2455
2485
  function trySourceEquivalent(resolved) {
2456
- resolved = resolved.replace(/[/\\]/g, path9.sep);
2486
+ resolved = resolved.replace(/[/\\]/g, path7.sep);
2457
2487
  for (const marker of BUILD_OUTPUT_DIR_NAMES) {
2458
2488
  const idx = resolved.indexOf(marker);
2459
2489
  if (idx === -1) continue;
2460
- const base = resolved.replace(marker, `${path9.sep}src${path9.sep}`);
2490
+ const base = resolved.replace(marker, `${path7.sep}src${path7.sep}`);
2461
2491
  const candidate = base.replace(/\.(js|mjs|cjs)$/, ".ts");
2462
2492
  if (candidate !== base && fs7.existsSync(candidate)) {
2463
2493
  return candidate;
@@ -2522,18 +2552,18 @@ function expandGlobPattern(entry, projectRoot) {
2522
2552
  const dirs = [];
2523
2553
  if (entry.includes("*")) {
2524
2554
  const base = entry.replace(/\/\*+$/, "");
2525
- const baseDir = path9.resolve(projectRoot, base);
2555
+ const baseDir = path7.resolve(projectRoot, base);
2526
2556
  try {
2527
2557
  const children = fs7.readdirSync(baseDir, { withFileTypes: true });
2528
2558
  for (const child of children) {
2529
2559
  if (child.isDirectory()) {
2530
- dirs.push(path9.join(baseDir, child.name));
2560
+ dirs.push(path7.join(baseDir, child.name));
2531
2561
  }
2532
2562
  }
2533
2563
  } catch {
2534
2564
  }
2535
2565
  } else {
2536
- dirs.push(path9.resolve(projectRoot, entry));
2566
+ dirs.push(path7.resolve(projectRoot, entry));
2537
2567
  }
2538
2568
  return dirs;
2539
2569
  }
@@ -2550,7 +2580,7 @@ function extractWorkspaceGlobs(pkg, projectRoot) {
2550
2580
  return dirs;
2551
2581
  }
2552
2582
  function extractPnpmWorkspaceDirs(projectRoot) {
2553
- const yamlPath = path9.join(projectRoot, "pnpm-workspace.yaml");
2583
+ const yamlPath = path7.join(projectRoot, "pnpm-workspace.yaml");
2554
2584
  if (!fs7.existsSync(yamlPath)) return [];
2555
2585
  try {
2556
2586
  const content = fs7.readFileSync(yamlPath, "utf8");
@@ -2587,8 +2617,8 @@ function extractPnpmWorkspaceDirs(projectRoot) {
2587
2617
  }
2588
2618
  function resolveModulePath(importerPath, moduleSpecifier, indexedFiles) {
2589
2619
  if (!moduleSpecifier.startsWith(".")) return [];
2590
- const dir = path9.dirname(importerPath);
2591
- const base = path9.resolve(dir, moduleSpecifier);
2620
+ const dir = path7.dirname(importerPath);
2621
+ const base = path7.resolve(dir, moduleSpecifier);
2592
2622
  const results = [];
2593
2623
  const stripped = base.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/, "");
2594
2624
  const skipBase = stripped !== base && /\.(ts|tsx|js|jsx|mjs|cjs)$/.test(base);
@@ -2600,18 +2630,18 @@ function resolveModulePath(importerPath, moduleSpecifier, indexedFiles) {
2600
2630
  if (indexedFiles.has(candidate + ".jsx")) results.push(candidate + ".jsx");
2601
2631
  if (indexedFiles.has(candidate + ".mjs")) results.push(candidate + ".mjs");
2602
2632
  if (indexedFiles.has(candidate + ".cjs")) results.push(candidate + ".cjs");
2603
- if (indexedFiles.has(path9.join(candidate, "index.ts")))
2604
- results.push(path9.join(candidate, "index.ts"));
2605
- if (indexedFiles.has(path9.join(candidate, "index.tsx")))
2606
- results.push(path9.join(candidate, "index.tsx"));
2607
- if (indexedFiles.has(path9.join(candidate, "index.js")))
2608
- results.push(path9.join(candidate, "index.js"));
2609
- if (indexedFiles.has(path9.join(candidate, "index.jsx")))
2610
- results.push(path9.join(candidate, "index.jsx"));
2611
- if (indexedFiles.has(path9.join(candidate, "index.mjs")))
2612
- results.push(path9.join(candidate, "index.mjs"));
2613
- if (indexedFiles.has(path9.join(candidate, "index.cjs")))
2614
- results.push(path9.join(candidate, "index.cjs"));
2633
+ if (indexedFiles.has(path7.join(candidate, "index.ts")))
2634
+ results.push(path7.join(candidate, "index.ts"));
2635
+ if (indexedFiles.has(path7.join(candidate, "index.tsx")))
2636
+ results.push(path7.join(candidate, "index.tsx"));
2637
+ if (indexedFiles.has(path7.join(candidate, "index.js")))
2638
+ results.push(path7.join(candidate, "index.js"));
2639
+ if (indexedFiles.has(path7.join(candidate, "index.jsx")))
2640
+ results.push(path7.join(candidate, "index.jsx"));
2641
+ if (indexedFiles.has(path7.join(candidate, "index.mjs")))
2642
+ results.push(path7.join(candidate, "index.mjs"));
2643
+ if (indexedFiles.has(path7.join(candidate, "index.cjs")))
2644
+ results.push(path7.join(candidate, "index.cjs"));
2615
2645
  }
2616
2646
  return [...new Set(results)];
2617
2647
  }
@@ -2643,7 +2673,7 @@ function runDeadCodeScan(projectRoot, opts = {}) {
2643
2673
  symbolById.set(s.id, s);
2644
2674
  }
2645
2675
  const discoveredFiles = discoverEntryPoints(projectRoot, opts.userEntryPoints);
2646
- const entryFileSet = new Set(discoveredFiles.map((f) => path9.resolve(f)));
2676
+ const entryFileSet = new Set(discoveredFiles.map((f) => path7.resolve(f)));
2647
2677
  const indexedFiles = /* @__PURE__ */ new Set();
2648
2678
  for (const s of allSymbols) indexedFiles.add(s.file);
2649
2679
  for (const fm of store.getAllFileMetas()) indexedFiles.add(fm.file);
@@ -2759,7 +2789,7 @@ function runDeadCodeScan(projectRoot, opts = {}) {
2759
2789
  const deadPackages = [];
2760
2790
  const pkgEntries = findPackageEntries(projectRoot);
2761
2791
  for (const [pkgName, pkgDir] of pkgEntries) {
2762
- const pkgFiles = allSymbols.filter((s) => s.file.startsWith(pkgDir + path9.sep));
2792
+ const pkgFiles = allSymbols.filter((s) => s.file.startsWith(pkgDir + path7.sep));
2763
2793
  if (pkgFiles.length === 0) continue;
2764
2794
  const pkgUsed = pkgFiles.filter((s) => alive.has(s.id));
2765
2795
  if (pkgUsed.length === 0) {
@@ -2795,7 +2825,7 @@ function runDeadCodeScan(projectRoot, opts = {}) {
2795
2825
  }
2796
2826
  function findPackageEntries(projectRoot) {
2797
2827
  const pkgMap = /* @__PURE__ */ new Map();
2798
- const rootPkg = tryReadJson(path9.join(projectRoot, "package.json"));
2828
+ const rootPkg = tryReadJson(path7.join(projectRoot, "package.json"));
2799
2829
  if (rootPkg && typeof rootPkg.name === "string") {
2800
2830
  pkgMap.set(rootPkg.name, projectRoot);
2801
2831
  }
@@ -2805,7 +2835,7 @@ function findPackageEntries(projectRoot) {
2805
2835
  wsDirs = extractPnpmWorkspaceDirs(projectRoot);
2806
2836
  }
2807
2837
  for (const wsDir of wsDirs) {
2808
- const wsPkg = tryReadJson(path9.join(wsDir, "package.json"));
2838
+ const wsPkg = tryReadJson(path7.join(wsDir, "package.json"));
2809
2839
  if (wsPkg && typeof wsPkg.name === "string") {
2810
2840
  pkgMap.set(wsPkg.name, wsDir);
2811
2841
  }
@@ -2835,4 +2865,4 @@ export {
2835
2865
  deadCodeScanTool,
2836
2866
  runDeadCodeScan
2837
2867
  };
2838
- //# sourceMappingURL=chunk-YF3D5INN.js.map
2868
+ //# sourceMappingURL=chunk-RTZWBNTY.js.map
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  normalizeCommandOutput,
6
6
  safeResolveReal
7
- } from "./chunk-D33S4RQG.js";
7
+ } from "./chunk-ZUFHAHTE.js";
8
8
 
9
9
  // src/languages/detect.ts
10
10
  import { createHash } from "node:crypto";
@@ -3515,4 +3515,4 @@ export {
3515
3515
  languagePackageTool,
3516
3516
  languageInfoTool
3517
3517
  };
3518
- //# sourceMappingURL=chunk-SOG7XIRF.js.map
3518
+ //# sourceMappingURL=chunk-TTZOK6IY.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  resolveIndexDir
3
- } from "./chunk-BLCSYKNN.js";
3
+ } from "./chunk-KY4PXYSO.js";
4
4
 
5
5
  // src/codebase-index/binary-frame.ts
6
6
  import { decode, encode } from "@msgpack/msgpack";
@@ -120,4 +120,4 @@ export {
120
120
  PROJECT_INDEX_SERVER_MAX_FRAME_CHARS,
121
121
  encodeProjectServerMessage
122
122
  };
123
- //# sourceMappingURL=chunk-6GVXZCQV.js.map
123
+ //# sourceMappingURL=chunk-UDVKRX5R.js.map