@wrongstack/tools 0.307.0 → 0.307.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.
package/dist/index.js CHANGED
@@ -1034,8 +1034,8 @@ async function* spawnStream(opts) {
1034
1034
  try {
1035
1035
  for (; ; ) {
1036
1036
  while (queue.length === 0) {
1037
- await new Promise((resolve23) => {
1038
- waiter = resolve23;
1037
+ await new Promise((resolve24) => {
1038
+ waiter = resolve24;
1039
1039
  });
1040
1040
  }
1041
1041
  const chunk = queue.shift();
@@ -1138,9 +1138,9 @@ async function detectPackageManager(cwd, stopAt) {
1138
1138
  return "npm";
1139
1139
  }
1140
1140
  async function detectPackageManagerInDir(dir) {
1141
- const fs43 = await import("node:fs/promises");
1141
+ const fs44 = await import("node:fs/promises");
1142
1142
  try {
1143
- const raw = await fs43.readFile(path3.join(dir, "package.json"), "utf8");
1143
+ const raw = await fs44.readFile(path3.join(dir, "package.json"), "utf8");
1144
1144
  const declared = JSON.parse(raw).packageManager;
1145
1145
  if (typeof declared === "string") {
1146
1146
  const name = declared.split("@")[0] ?? "";
@@ -1159,7 +1159,7 @@ async function detectPackageManagerInDir(dir) {
1159
1159
  ];
1160
1160
  for (const [file, manager] of lockfiles) {
1161
1161
  try {
1162
- await fs43.stat(`${dir}/${file}`);
1162
+ await fs44.stat(`${dir}/${file}`);
1163
1163
  return manager;
1164
1164
  } catch {
1165
1165
  }
@@ -4140,15 +4140,15 @@ async function changedPaths(before, after, beforeSizes, afterSizes) {
4140
4140
  const beforeSet = new Set(before);
4141
4141
  const afterSet = new Set(after);
4142
4142
  const changed = /* @__PURE__ */ new Set();
4143
- for (const path49 of after) {
4144
- if (!beforeSet.has(path49)) changed.add(path49);
4143
+ for (const path50 of after) {
4144
+ if (!beforeSet.has(path50)) changed.add(path50);
4145
4145
  }
4146
- for (const path49 of before) {
4147
- if (!afterSet.has(path49)) changed.add(path49);
4146
+ for (const path50 of before) {
4147
+ if (!afterSet.has(path50)) changed.add(path50);
4148
4148
  }
4149
4149
  if (beforeSizes && afterSizes) {
4150
- for (const path49 of after) {
4151
- if (beforeSizes.get(path49) !== afterSizes.get(path49)) changed.add(path49);
4150
+ for (const path50 of after) {
4151
+ if (beforeSizes.get(path50) !== afterSizes.get(path50)) changed.add(path50);
4152
4152
  }
4153
4153
  }
4154
4154
  return [...changed].sort();
@@ -5643,7 +5643,7 @@ async function syncGoParse(filePath, content, lang) {
5643
5643
  }
5644
5644
  const goBinary = resolveWin32Command("go");
5645
5645
  const goResult = await new Promise(
5646
- (resolve23, reject) => {
5646
+ (resolve24, reject) => {
5647
5647
  let settled = false;
5648
5648
  const proc = spawn5(goBinary, ["run", scriptPath], {
5649
5649
  stdio: ["pipe", "pipe", "pipe"],
@@ -5672,7 +5672,7 @@ async function syncGoParse(filePath, content, lang) {
5672
5672
  if (settled) return;
5673
5673
  settled = true;
5674
5674
  clearTimeout(timer);
5675
- resolve23({ code: code2, stdout: stdout2 });
5675
+ resolve24({ code: code2, stdout: stdout2 });
5676
5676
  });
5677
5677
  }
5678
5678
  );
@@ -6348,7 +6348,7 @@ async function resolvePython() {
6348
6348
  return null;
6349
6349
  }
6350
6350
  function commandIsAvailable(command) {
6351
- return new Promise((resolve23) => {
6351
+ return new Promise((resolve24) => {
6352
6352
  let settled = false;
6353
6353
  const proc = spawn6(command, ["--version"], {
6354
6354
  stdio: "ignore",
@@ -6358,7 +6358,7 @@ function commandIsAvailable(command) {
6358
6358
  if (settled) return;
6359
6359
  settled = true;
6360
6360
  clearTimeout(timer);
6361
- resolve23(available);
6361
+ resolve24(available);
6362
6362
  };
6363
6363
  const timer = setTimeout(() => {
6364
6364
  proc.kill("SIGKILL");
@@ -6370,7 +6370,7 @@ function commandIsAvailable(command) {
6370
6370
  });
6371
6371
  }
6372
6372
  function spawnPyParser(pyBinary, scriptPath, filePath, content) {
6373
- return new Promise((resolve23, reject) => {
6373
+ return new Promise((resolve24, reject) => {
6374
6374
  let settled = false;
6375
6375
  const proc = spawn6(pyBinary, [scriptPath, filePath], {
6376
6376
  stdio: ["pipe", "pipe", "pipe"],
@@ -6399,7 +6399,7 @@ function spawnPyParser(pyBinary, scriptPath, filePath, content) {
6399
6399
  if (settled) return;
6400
6400
  settled = true;
6401
6401
  clearTimeout(timer);
6402
- resolve23({ code, stdout });
6402
+ resolve24({ code, stdout });
6403
6403
  });
6404
6404
  });
6405
6405
  }
@@ -9615,10 +9615,10 @@ var bashTool = {
9615
9615
  queue.push(c);
9616
9616
  }
9617
9617
  };
9618
- const next = () => new Promise((resolve23) => {
9618
+ const next = () => new Promise((resolve24) => {
9619
9619
  const c = queue.shift();
9620
- if (c) resolve23(c);
9621
- else resolveNext = resolve23;
9620
+ if (c) resolve24(c);
9621
+ else resolveNext = resolve24;
9622
9622
  });
9623
9623
  let lastFlush = Date.now();
9624
9624
  const flush = () => {
@@ -10071,11 +10071,11 @@ var BrowserArtifactStore = class {
10071
10071
  };
10072
10072
  async function hashFile(target) {
10073
10073
  const hash = createHash3("sha256");
10074
- await new Promise((resolve23, reject) => {
10074
+ await new Promise((resolve24, reject) => {
10075
10075
  const stream = createReadStream(target);
10076
10076
  stream.on("data", (chunk) => hash.update(chunk));
10077
10077
  stream.once("error", reject);
10078
- stream.once("end", resolve23);
10078
+ stream.once("end", resolve24);
10079
10079
  });
10080
10080
  return hash.digest("hex");
10081
10081
  }
@@ -10230,7 +10230,7 @@ var BrowserNetworkGuardProxy = class {
10230
10230
  async start() {
10231
10231
  if (this.url) return this.url;
10232
10232
  if (this.startPromise) return this.startPromise;
10233
- this.startPromise = new Promise((resolve23, reject) => {
10233
+ this.startPromise = new Promise((resolve24, reject) => {
10234
10234
  const onError = (error) => {
10235
10235
  this.server.off("listening", onListening);
10236
10236
  reject(error);
@@ -10243,7 +10243,7 @@ var BrowserNetworkGuardProxy = class {
10243
10243
  return;
10244
10244
  }
10245
10245
  this.url = `http://127.0.0.1:${address.port}`;
10246
- resolve23(this.url);
10246
+ resolve24(this.url);
10247
10247
  };
10248
10248
  this.server.once("error", onError);
10249
10249
  this.server.once("listening", onListening);
@@ -10258,7 +10258,7 @@ var BrowserNetworkGuardProxy = class {
10258
10258
  for (const socket of this.sockets) socket.destroy();
10259
10259
  this.sockets.clear();
10260
10260
  if (!this.server.listening) return;
10261
- await new Promise((resolve23) => this.server.close(() => resolve23()));
10261
+ await new Promise((resolve24) => this.server.close(() => resolve24()));
10262
10262
  }
10263
10263
  async forwardHttp(request2, response) {
10264
10264
  try {
@@ -10831,7 +10831,7 @@ function pushBounded(target, value, limit) {
10831
10831
  }
10832
10832
  async function abortable(signal, operation, onAbort) {
10833
10833
  signal.throwIfAborted();
10834
- return new Promise((resolve23, reject) => {
10834
+ return new Promise((resolve24, reject) => {
10835
10835
  let settled = false;
10836
10836
  let aborting = false;
10837
10837
  const finish = (fn) => {
@@ -10849,7 +10849,7 @@ async function abortable(signal, operation, onAbort) {
10849
10849
  signal.addEventListener("abort", abort, { once: true });
10850
10850
  operation().then(
10851
10851
  (value) => {
10852
- if (!aborting) finish(() => resolve23(value));
10852
+ if (!aborting) finish(() => resolve24(value));
10853
10853
  },
10854
10854
  (err) => {
10855
10855
  if (!aborting) finish(() => reject(err));
@@ -12116,10 +12116,16 @@ function buildFileGraphNodeState(pkgSyms, localFiles, packageOf) {
12116
12116
  }
12117
12117
  return { fileNodes, symToFile, fileStats, ensureFileNode };
12118
12118
  }
12119
- function buildSymbolGraphNodes(symById, relatedIds, fileFilter, packageOf) {
12119
+ function buildSymbolGraphNodes(symById, relatedIds, localFiles, packageOf) {
12120
+ const local = new Set(
12121
+ [...typeof localFiles === "string" ? [localFiles] : localFiles].map(
12122
+ (file) => file.replace(/\\/g, "/")
12123
+ )
12124
+ );
12125
+ const isLocal = (file) => local.has(file.replace(/\\/g, "/"));
12120
12126
  return [...relatedIds].map((id) => symById.get(id)).filter((symbol) => symbol !== void 0).sort((a, b) => {
12121
- const aExternal = a.file === fileFilter ? 0 : 1;
12122
- const bExternal = b.file === fileFilter ? 0 : 1;
12127
+ const aExternal = isLocal(a.file) ? 0 : 1;
12128
+ const bExternal = isLocal(b.file) ? 0 : 1;
12123
12129
  return aExternal - bExternal || a.file.localeCompare(b.file) || a.line - b.line || a.id - b.id;
12124
12130
  }).map((s) => ({
12125
12131
  id: `sym:${s.id}`,
@@ -12133,7 +12139,7 @@ function buildSymbolGraphNodes(symById, relatedIds, fileFilter, packageOf) {
12133
12139
  line: s.line,
12134
12140
  signature: s.signature,
12135
12141
  scope: s.scope,
12136
- external: s.file !== fileFilter
12142
+ external: !isLocal(s.file)
12137
12143
  }));
12138
12144
  }
12139
12145
  function addWeightedEdge(edgeMap, source, target, callType, weight) {
@@ -12168,6 +12174,56 @@ function materializeWeightedEdges(edgeMap, idPrefix) {
12168
12174
  return edges;
12169
12175
  }
12170
12176
 
12177
+ // src/codebase-index/writer-helpers.ts
12178
+ import { resolveWstackPaths as resolveWstackPaths2 } from "@wrongstack/core/utils";
12179
+ function escapeLike(value) {
12180
+ return value.replace(/[\\%_]/g, (char) => `\\${char}`);
12181
+ }
12182
+ function posixIndexPath(file) {
12183
+ return file.replace(/\\/g, "/").replace(/^\.\//, "");
12184
+ }
12185
+ function indexedFileMatchSql(column = "file") {
12186
+ return `(${column} = ? OR replace(${column}, '\\', '/') = ? OR replace(${column}, '\\', '/') LIKE ? ESCAPE '\\')`;
12187
+ }
12188
+ function indexedFileMatchArgs(file) {
12189
+ const posix4 = posixIndexPath(file.trim());
12190
+ return [file, posix4, `%/${escapeLike(posix4)}`];
12191
+ }
12192
+ function matchesIndexedPackageFilter(storedFile, packageLabel, filter) {
12193
+ if (packageLabel === filter) return true;
12194
+ const posixFile = posixIndexPath(storedFile);
12195
+ const posixFilter = posixIndexPath(filter.trim());
12196
+ if (!posixFilter) return false;
12197
+ return posixFile === posixFilter || posixFile.endsWith(`/${posixFilter}`) || posixFile.includes(`/${posixFilter}/`);
12198
+ }
12199
+ function assignRefsToSymbols(refs, symbols) {
12200
+ if (refs.length === 0 || symbols.length === 0) return [];
12201
+ const ordered = [...symbols].sort((a, b) => a.line - b.line || a.col - b.col || a.id - b.id);
12202
+ const seen = /* @__PURE__ */ new Set();
12203
+ const assigned = [];
12204
+ for (const ref of refs) {
12205
+ let owner2;
12206
+ for (const symbol of ordered) {
12207
+ if (symbol.line > ref.line) break;
12208
+ owner2 = symbol;
12209
+ }
12210
+ if (!owner2 && ref.callType === "import") owner2 = ordered[0];
12211
+ if (!owner2 || owner2.id <= 0) continue;
12212
+ const key = `${owner2.id}:${ref.toName}:${ref.callType}:${ref.module ?? ""}`;
12213
+ if (seen.has(key)) continue;
12214
+ seen.add(key);
12215
+ assigned.push({ ...ref, fromId: owner2.id });
12216
+ }
12217
+ return assigned;
12218
+ }
12219
+ function resolveIndexDir(projectRoot, override) {
12220
+ return override ?? resolveWstackPaths2({ projectRoot }).projectCodebaseIndex;
12221
+ }
12222
+ function codebaseIndexDirOverride(ctx) {
12223
+ const v = ctx.meta?.["codebaseIndexDir"];
12224
+ return typeof v === "string" ? v : void 0;
12225
+ }
12226
+
12171
12227
  // src/codebase-index/writer-ref-mapper.ts
12172
12228
  function mapWriterRefRow(row) {
12173
12229
  return {
@@ -12223,10 +12279,23 @@ function mapCallSiteRow(row) {
12223
12279
  line: row.ref_line
12224
12280
  };
12225
12281
  }
12282
+ function resolveIndexedFiles(stmt, file) {
12283
+ const rows = stmt(
12284
+ `SELECT DISTINCT file FROM symbols WHERE ${indexedFileMatchSql("file")} ORDER BY length(file), file`
12285
+ ).all(...indexedFileMatchArgs(file));
12286
+ return rows.map((row) => row.file);
12287
+ }
12226
12288
  function resolveSymbolIds(stmt, symbolName, file) {
12227
- const baseSql = file ? `SELECT id FROM symbols WHERE name = ? AND file = ? ORDER BY id` : `SELECT id FROM symbols WHERE name = ? ORDER BY id`;
12228
- const args = file ? [symbolName, file] : [symbolName];
12229
- const rows = stmt(baseSql).all(...args);
12289
+ if (!file) {
12290
+ const rows2 = stmt("SELECT id FROM symbols WHERE name = ? ORDER BY id").all(symbolName);
12291
+ return rows2.map((r) => r.id);
12292
+ }
12293
+ const indexedFiles = resolveIndexedFiles(stmt, file);
12294
+ if (indexedFiles.length === 0) return [];
12295
+ const placeholders = indexedFiles.map(() => "?").join(",");
12296
+ const rows = stmt(
12297
+ `SELECT id FROM symbols WHERE name = ? AND file IN (${placeholders}) ORDER BY id`
12298
+ ).all(symbolName, ...indexedFiles);
12230
12299
  return rows.map((r) => r.id);
12231
12300
  }
12232
12301
  function findIncomingCallsByName(stmt, symbolName, file, limit) {
@@ -12548,7 +12617,7 @@ function getFileGraphWithStatement(stmt, packageFilter) {
12548
12617
  const allFiles = stmt("SELECT DISTINCT file FROM symbols").all();
12549
12618
  const packageOf = readPackageLabeller(stmt);
12550
12619
  const langOf = (file) => detectLang(file) ?? "other";
12551
- const pkgFilePaths = allFiles.filter((f) => packageOf(f.file) === packageFilter).map((f) => f.file);
12620
+ const pkgFilePaths = allFiles.filter((f) => matchesIndexedPackageFilter(f.file, packageOf(f.file), packageFilter)).map((f) => f.file);
12552
12621
  const localFiles = new Set(pkgFilePaths);
12553
12622
  if (localFiles.size === 0) return { nodes: [], edges: [] };
12554
12623
  const filePlaceholders = [...localFiles].map(() => "?").join(",");
@@ -12624,9 +12693,12 @@ function getFileGraphWithStatement(stmt, packageFilter) {
12624
12693
  return { nodes: [...fileNodes.values()], edges };
12625
12694
  }
12626
12695
  function getSymbolGraphWithStatement(stmt, fileFilter) {
12696
+ const indexedFiles = resolveIndexedFiles(stmt, fileFilter);
12697
+ if (indexedFiles.length === 0) return { nodes: [], edges: [] };
12698
+ const filePlaceholders = indexedFiles.map(() => "?").join(",");
12627
12699
  const syms = stmt(
12628
- "SELECT id, name, kind, lang, file, line, signature, scope FROM symbols WHERE file = ? ORDER BY line, id"
12629
- ).all(fileFilter);
12700
+ `SELECT id, name, kind, lang, file, line, signature, scope FROM symbols WHERE file IN (${filePlaceholders}) ORDER BY line, id`
12701
+ ).all(...indexedFiles);
12630
12702
  if (syms.length === 0) return { nodes: [], edges: [] };
12631
12703
  const symById = new Map(syms.map((symbol) => [symbol.id, symbol]));
12632
12704
  const relatedIds = new Set(syms.map((symbol) => symbol.id));
@@ -12636,16 +12708,16 @@ function getSymbolGraphWithStatement(stmt, fileFilter) {
12636
12708
  SELECT r.from_id, r.to_id, r.to_name, r.call_type, r.line
12637
12709
  FROM refs r
12638
12710
  JOIN symbols s ON s.id = r.from_id
12639
- WHERE s.file = ?
12711
+ WHERE s.file IN (${filePlaceholders})
12640
12712
  UNION
12641
12713
  SELECT r.from_id, r.to_id, r.to_name, r.call_type, r.line
12642
12714
  FROM refs r
12643
12715
  JOIN symbols s ON s.id = r.to_id
12644
- WHERE s.file = ?
12716
+ WHERE s.file IN (${filePlaceholders})
12645
12717
  )
12646
12718
  WHERE to_id IS NOT NULL
12647
12719
  GROUP BY from_id, to_id, call_type`
12648
- ).all(fileFilter, fileFilter);
12720
+ ).all(...indexedFiles, ...indexedFiles);
12649
12721
  const edgeMap = /* @__PURE__ */ new Map();
12650
12722
  for (const r of refRows) {
12651
12723
  if (r.to_id == null) continue;
@@ -12664,43 +12736,15 @@ function getSymbolGraphWithStatement(stmt, fileFilter) {
12664
12736
  ).all(...missingIds);
12665
12737
  for (const s of extras) symById.set(s.id, s);
12666
12738
  }
12667
- const nodes = buildSymbolGraphNodes(symById, relatedIds, fileFilter, readPackageLabeller(stmt));
12739
+ const nodes = buildSymbolGraphNodes(
12740
+ symById,
12741
+ relatedIds,
12742
+ new Set(syms.map((symbol) => symbol.file)),
12743
+ readPackageLabeller(stmt)
12744
+ );
12668
12745
  return { nodes, edges };
12669
12746
  }
12670
12747
 
12671
- // src/codebase-index/writer-helpers.ts
12672
- import { resolveWstackPaths as resolveWstackPaths2 } from "@wrongstack/core/utils";
12673
- function escapeLike(value) {
12674
- return value.replace(/[\\%_]/g, (char) => `\\${char}`);
12675
- }
12676
- function assignRefsToSymbols(refs, symbols) {
12677
- if (refs.length === 0 || symbols.length === 0) return [];
12678
- const ordered = [...symbols].sort((a, b) => a.line - b.line || a.col - b.col || a.id - b.id);
12679
- const seen = /* @__PURE__ */ new Set();
12680
- const assigned = [];
12681
- for (const ref of refs) {
12682
- let owner2;
12683
- for (const symbol of ordered) {
12684
- if (symbol.line > ref.line) break;
12685
- owner2 = symbol;
12686
- }
12687
- if (!owner2 && ref.callType === "import") owner2 = ordered[0];
12688
- if (!owner2 || owner2.id <= 0) continue;
12689
- const key = `${owner2.id}:${ref.toName}:${ref.callType}:${ref.module ?? ""}`;
12690
- if (seen.has(key)) continue;
12691
- seen.add(key);
12692
- assigned.push({ ...ref, fromId: owner2.id });
12693
- }
12694
- return assigned;
12695
- }
12696
- function resolveIndexDir(projectRoot, override) {
12697
- return override ?? resolveWstackPaths2({ projectRoot }).projectCodebaseIndex;
12698
- }
12699
- function codebaseIndexDirOverride(ctx) {
12700
- const v = ctx.meta?.["codebaseIndexDir"];
12701
- return typeof v === "string" ? v : void 0;
12702
- }
12703
-
12704
12748
  // src/codebase-index/vector-search.ts
12705
12749
  var RRF_K = 60;
12706
12750
  var VECTOR_DIMENSIONS = 384;
@@ -14343,8 +14387,8 @@ function isProjectIndexServerHealth(value) {
14343
14387
  return typeof health.checkedAt === "number" && typeof health.uptimeMs === "number" && typeof memory?.rss === "number" && typeof memory.heapUsed === "number" && typeof memory.heapTotal === "number" && typeof memory.external === "number" && typeof health.clients === "number" && typeof health.activeRequests === "number" && typeof health.activeWrites === "number" && typeof health.queuedWrites === "number" && typeof health.pendingExternalFiles === "number" && typeof health.watchingExternal === "boolean" && typeof activity?.indexing === "boolean" && typeof activity.currentFile === "number" && typeof activity.totalFiles === "number" && typeof activity.generation === "number";
14344
14388
  }
14345
14389
  function delay(ms) {
14346
- return new Promise((resolve23) => {
14347
- const timer = setTimeout(resolve23, ms);
14390
+ return new Promise((resolve24) => {
14391
+ const timer = setTimeout(resolve24, ms);
14348
14392
  timer.unref?.();
14349
14393
  });
14350
14394
  }
@@ -14550,7 +14594,7 @@ var ProjectServerConnection = class {
14550
14594
  return Promise.reject(new Error("codebase-index server connection is not available"));
14551
14595
  }
14552
14596
  const id = this.nextId++;
14553
- return new Promise((resolve23, reject) => {
14597
+ return new Promise((resolve24, reject) => {
14554
14598
  const timer = setTimeout(() => {
14555
14599
  const entry = this.pending.get(id);
14556
14600
  if (!entry) return;
@@ -14573,7 +14617,7 @@ var ProjectServerConnection = class {
14573
14617
  entry.reject(cancellationError(signal));
14574
14618
  } : void 0;
14575
14619
  this.pending.set(id, {
14576
- resolve: resolve23,
14620
+ resolve: resolve24,
14577
14621
  reject,
14578
14622
  timer,
14579
14623
  signal,
@@ -14642,7 +14686,7 @@ var ProjectServerConnection = class {
14642
14686
  this.binaryBuffer = [];
14643
14687
  this.useBinary = false;
14644
14688
  this.textDecoder = null;
14645
- return new Promise((resolve23, reject) => {
14689
+ return new Promise((resolve24, reject) => {
14646
14690
  const socket = net3.createConnection(this.endpoint);
14647
14691
  this.socket = socket;
14648
14692
  const timer = setTimeout(() => {
@@ -14654,7 +14698,7 @@ var ProjectServerConnection = class {
14654
14698
  clearTimeout(timer);
14655
14699
  this.connectResolve = null;
14656
14700
  this.connectReject = null;
14657
- resolve23();
14701
+ resolve24();
14658
14702
  };
14659
14703
  const finishReject = (error) => {
14660
14704
  clearTimeout(timer);
@@ -15703,9 +15747,9 @@ var ParserWorkerPool = class {
15703
15747
  for (let i = 0; i < files.length; i++) {
15704
15748
  chunks[i % workerCount].push(files[i]);
15705
15749
  }
15706
- return new Promise((resolve23, reject) => {
15750
+ return new Promise((resolve24, reject) => {
15707
15751
  this.pending.set(batchId, {
15708
- resolve: resolve23,
15752
+ resolve: resolve24,
15709
15753
  reject,
15710
15754
  accumulated: [],
15711
15755
  expectedWorkers: workerCount,
@@ -15736,10 +15780,10 @@ var ParserWorkerPool = class {
15736
15780
  await Promise.allSettled(
15737
15781
  workers.map(
15738
15782
  (w) => Promise.race([
15739
- new Promise((resolve23) => {
15740
- w.once("exit", () => resolve23());
15783
+ new Promise((resolve24) => {
15784
+ w.once("exit", () => resolve24());
15741
15785
  }),
15742
- new Promise((resolve23) => setTimeout(() => resolve23(), 2e3))
15786
+ new Promise((resolve24) => setTimeout(() => resolve24(), 2e3))
15743
15787
  ]).then(() => {
15744
15788
  if (!w.threadId) return;
15745
15789
  return w.terminate().catch(() => {
@@ -15800,7 +15844,7 @@ function shouldUseParserWorkerPool(candidateFileCount, parseBatchCount) {
15800
15844
  return !isFrugalPerf() && candidateFileCount >= WORKER_POOL_THRESHOLD && parseBatchCount > 1;
15801
15845
  }
15802
15846
  function yieldEventLoop() {
15803
- return new Promise((resolve23) => setImmediate(resolve23));
15847
+ return new Promise((resolve24) => setImmediate(resolve24));
15804
15848
  }
15805
15849
  function throwIfAborted(signal) {
15806
15850
  if (!signal?.aborted) return;
@@ -15832,7 +15876,7 @@ function normalizeComparablePath(value) {
15832
15876
  return process.platform === "win32" ? resolved.toLowerCase() : resolved;
15833
15877
  }
15834
15878
  function gitOutput(projectRoot, args) {
15835
- return new Promise((resolve23, reject) => {
15879
+ return new Promise((resolve24, reject) => {
15836
15880
  execFile(
15837
15881
  "git",
15838
15882
  ["-C", projectRoot, ...args],
@@ -15843,7 +15887,7 @@ function gitOutput(projectRoot, args) {
15843
15887
  },
15844
15888
  (error, stdout) => {
15845
15889
  if (error) reject(error);
15846
- else resolve23(Buffer.isBuffer(stdout) ? stdout : Buffer.from(stdout));
15890
+ else resolve24(Buffer.isBuffer(stdout) ? stdout : Buffer.from(stdout));
15847
15891
  }
15848
15892
  );
15849
15893
  });
@@ -16643,7 +16687,7 @@ function callIndexOp(op, args, opts) {
16643
16687
  opts.signal.reason instanceof Error ? opts.signal.reason : new Error("Indexing cancelled")
16644
16688
  );
16645
16689
  }
16646
- return new Promise((resolve23, reject) => {
16690
+ return new Promise((resolve24, reject) => {
16647
16691
  const id = nextRpcId++;
16648
16692
  const timer = setTimeout(() => {
16649
16693
  pending.delete(id);
@@ -16665,7 +16709,7 @@ function callIndexOp(op, args, opts) {
16665
16709
  pending.set(id, {
16666
16710
  resolve: (v) => {
16667
16711
  cleanup();
16668
- resolve23(v);
16712
+ resolve24(v);
16669
16713
  },
16670
16714
  reject: (e) => {
16671
16715
  cleanup();
@@ -17629,9 +17673,90 @@ var codebaseAstReplaceTool = {
17629
17673
  }
17630
17674
  };
17631
17675
 
17632
- // src/codebase-index/codebase-impact-analysis-tool.ts
17676
+ // src/codebase-index/codebase-invariant-check-tool.ts
17677
+ import * as fs22 from "node:fs/promises";
17633
17678
  import * as path27 from "node:path";
17634
17679
  import { toErrorMessage as toErrorMessage4 } from "@wrongstack/core/utils";
17680
+ init_languages2();
17681
+ var codebaseInvariantCheckTool = {
17682
+ name: "codebase-invariant-check",
17683
+ category: "Inspect",
17684
+ icon: "index",
17685
+ permission: "auto",
17686
+ subjectKey: "file",
17687
+ mutating: false,
17688
+ capabilities: ["fs.read"],
17689
+ description: "Mathematically verify AST backward-compatibility invariants between original code and candidate mutations across TypeScript, Python, Go, Rust, Java, etc. Detects missing exports (INV-001), mandatory parameter additions (INV-002), interface breaking expansions (INV-003), and return type changes (INV-004) with zero hallucinations.",
17690
+ usageHint: "PRE-FLIGHT AST INVARIANT AUDIT:\n\n- Provide `file` and `modifiedCode` (or both `originalCode` and `modifiedCode`).\n- Returns `valid: true` if changes are strictly backward compatible.\n- Returns structured `violations[]` with exact rule IDs, offending symbol names, and fix instructions.",
17691
+ inputSchema: {
17692
+ type: "object",
17693
+ properties: {
17694
+ file: {
17695
+ type: "string",
17696
+ description: "Path to existing source file to compare against candidate modifications."
17697
+ },
17698
+ originalCode: {
17699
+ type: "string",
17700
+ description: "Original source code string (if not reading from an existing file)."
17701
+ },
17702
+ modifiedCode: {
17703
+ type: "string",
17704
+ description: "The candidate modified code string to validate."
17705
+ },
17706
+ lang: {
17707
+ type: "string",
17708
+ description: "Language hint (ts, py, go, rs, etc.). Inferred from file path if omitted."
17709
+ }
17710
+ },
17711
+ required: ["modifiedCode"],
17712
+ additionalProperties: false
17713
+ },
17714
+ async execute(input, ctx) {
17715
+ try {
17716
+ let originalCode = input.originalCode;
17717
+ let lang = input.lang;
17718
+ if (!originalCode && input.file) {
17719
+ const resolved = path27.isAbsolute(input.file) ? input.file : path27.resolve(ctx.projectRoot, input.file);
17720
+ originalCode = await fs22.readFile(resolved, "utf8");
17721
+ if (!lang) {
17722
+ lang = detectLang(resolved) ?? "ts";
17723
+ }
17724
+ }
17725
+ if (originalCode === void 0) {
17726
+ return {
17727
+ valid: false,
17728
+ violations: [],
17729
+ summary: "Neither originalCode nor file was provided for invariant comparison.",
17730
+ error: "Missing originalCode or file path."
17731
+ };
17732
+ }
17733
+ const res = await polyglotInvariantEngine.evaluate({
17734
+ originalCode,
17735
+ modifiedCode: input.modifiedCode,
17736
+ lang,
17737
+ filePath: input.file
17738
+ });
17739
+ const summary = res.valid ? "AST Invariants PASSED. Mutation is 100% backward compatible." : `AST Invariants FAILED with ${res.violations.length} violation(s):
17740
+ ` + res.violations.map((v) => ` - [${v.ruleId}] ${v.symbolName}: ${v.message}`).join("\n");
17741
+ return {
17742
+ valid: res.valid,
17743
+ violations: res.violations,
17744
+ summary
17745
+ };
17746
+ } catch (err) {
17747
+ return {
17748
+ valid: false,
17749
+ violations: [],
17750
+ summary: `Error during invariant evaluation: ${toErrorMessage4(err)}`,
17751
+ error: toErrorMessage4(err)
17752
+ };
17753
+ }
17754
+ }
17755
+ };
17756
+
17757
+ // src/codebase-index/codebase-impact-analysis-tool.ts
17758
+ import * as path28 from "node:path";
17759
+ import { toErrorMessage as toErrorMessage5 } from "@wrongstack/core/utils";
17635
17760
  var TEST_FILE_REGEX = /(?:test|spec|mock|fixture|bench)[s]?[/\\._]/i;
17636
17761
  var codebaseImpactAnalysisTool = {
17637
17762
  name: "codebase-impact-analysis",
@@ -17668,6 +17793,9 @@ var codebaseImpactAnalysisTool = {
17668
17793
  const limit = 200;
17669
17794
  const transitive = input.transitive ?? true;
17670
17795
  let rawSites = [];
17796
+ let symbolFound = true;
17797
+ let indexUnavailable = false;
17798
+ let indexError;
17671
17799
  try {
17672
17800
  const serviced = await incomingCallsService2({
17673
17801
  projectRoot,
@@ -17678,13 +17806,49 @@ var codebaseImpactAnalysisTool = {
17678
17806
  transitive
17679
17807
  });
17680
17808
  rawSites = serviced.calls;
17681
- } catch {
17809
+ symbolFound = serviced.symbolFound;
17810
+ } catch (err) {
17811
+ symbolFound = false;
17812
+ indexUnavailable = true;
17813
+ indexError = toErrorMessage5(err);
17814
+ }
17815
+ if (indexUnavailable) {
17816
+ const detail = indexError ? ` (${indexError})` : "";
17817
+ const reason = `Index query failed for '${input.symbol}'. Run codebase-index, then retry.${detail}`;
17818
+ return {
17819
+ status: "error",
17820
+ symbol: input.symbol,
17821
+ riskLevel: "low",
17822
+ summary: reason,
17823
+ totalCallSites: 0,
17824
+ affectedProductionFiles: [],
17825
+ affectedTestFiles: [],
17826
+ callSites: [],
17827
+ recommendedActionPlan: [reason],
17828
+ symbolFound: false,
17829
+ error: reason
17830
+ };
17831
+ }
17832
+ if (!symbolFound) {
17833
+ const reason = `Symbol '${input.symbol}' was not found in the index` + (input.file ? ` for file filter '${input.file}'` : "") + ". Use codebase-search to verify the name.";
17834
+ return {
17835
+ status: "ok",
17836
+ symbol: input.symbol,
17837
+ riskLevel: "low",
17838
+ summary: reason,
17839
+ totalCallSites: 0,
17840
+ affectedProductionFiles: [],
17841
+ affectedTestFiles: [],
17842
+ callSites: [],
17843
+ recommendedActionPlan: [reason],
17844
+ symbolFound: false
17845
+ };
17682
17846
  }
17683
17847
  const prodFilesSet = /* @__PURE__ */ new Set();
17684
17848
  const testFilesSet = /* @__PURE__ */ new Set();
17685
17849
  const callSites = [];
17686
17850
  for (const site of rawSites) {
17687
- const relPath = path27.relative(projectRoot, site.symbol.file).replace(/\\/g, "/");
17851
+ const relPath = path28.relative(projectRoot, site.symbol.file).replace(/\\/g, "/");
17688
17852
  const isTest = TEST_FILE_REGEX.test(relPath);
17689
17853
  if (isTest) {
17690
17854
  testFilesSet.add(relPath);
@@ -17734,7 +17898,8 @@ var codebaseImpactAnalysisTool = {
17734
17898
  affectedProductionFiles: prodFiles,
17735
17899
  affectedTestFiles: testFiles,
17736
17900
  callSites,
17737
- recommendedActionPlan
17901
+ recommendedActionPlan,
17902
+ symbolFound: true
17738
17903
  };
17739
17904
  } catch (err) {
17740
17905
  return {
@@ -17747,14 +17912,15 @@ var codebaseImpactAnalysisTool = {
17747
17912
  affectedTestFiles: [],
17748
17913
  callSites: [],
17749
17914
  recommendedActionPlan: [],
17750
- error: toErrorMessage4(err)
17915
+ symbolFound: false,
17916
+ error: toErrorMessage5(err)
17751
17917
  };
17752
17918
  }
17753
17919
  }
17754
17920
  };
17755
17921
 
17756
17922
  // src/codebase-index/codebase-incoming-calls-tool.ts
17757
- import { toErrorMessage as toErrorMessage5 } from "@wrongstack/core/utils";
17923
+ import { toErrorMessage as toErrorMessage6 } from "@wrongstack/core/utils";
17758
17924
  var codebaseIncomingCallsTool = {
17759
17925
  name: "codebase-incoming-calls",
17760
17926
  category: "Project",
@@ -17827,7 +17993,7 @@ var codebaseIncomingCallsTool = {
17827
17993
  symbol: input.symbol,
17828
17994
  calls: [],
17829
17995
  total: 0,
17830
- indexStatus: `Index query failed: ${toErrorMessage5(err)}. Fall back to grep for this lookup.`
17996
+ indexStatus: `Index query failed: ${toErrorMessage6(err)}. Fall back to grep for this lookup.`
17831
17997
  };
17832
17998
  }
17833
17999
  const { calls, symbolFound, ambiguous, totalMatches } = serviced;
@@ -17882,7 +18048,7 @@ var codebaseIncomingCallsTool = {
17882
18048
  import { ToolValidationError } from "@wrongstack/core/types";
17883
18049
 
17884
18050
  // src/codebase-index/codebase-search-tool.ts
17885
- import { toErrorMessage as toErrorMessage6 } from "@wrongstack/core/utils";
18051
+ import { toErrorMessage as toErrorMessage7 } from "@wrongstack/core/utils";
17886
18052
  var INDEXABLE_LANG_IDS = [
17887
18053
  "ts",
17888
18054
  "tsx",
@@ -18007,7 +18173,7 @@ var codebaseSearchTool = {
18007
18173
  results: [],
18008
18174
  total: 0,
18009
18175
  query: input.query,
18010
- indexStatus: `Index query failed: ${toErrorMessage6(err)}. Fall back to grep/glob for this lookup.`
18176
+ indexStatus: `Index query failed: ${toErrorMessage7(err)}. Fall back to grep/glob for this lookup.`
18011
18177
  };
18012
18178
  }
18013
18179
  const { results, total } = searched;
@@ -18115,7 +18281,7 @@ var codebaseIndexTool = {
18115
18281
  };
18116
18282
 
18117
18283
  // src/codebase-index/codebase-outgoing-calls-tool.ts
18118
- import { toErrorMessage as toErrorMessage7 } from "@wrongstack/core/utils";
18284
+ import { toErrorMessage as toErrorMessage8 } from "@wrongstack/core/utils";
18119
18285
  var codebaseOutgoingCallsTool = {
18120
18286
  name: "codebase-outgoing-calls",
18121
18287
  category: "Project",
@@ -18188,7 +18354,7 @@ var codebaseOutgoingCallsTool = {
18188
18354
  symbol: input.symbol,
18189
18355
  calls: [],
18190
18356
  total: 0,
18191
- indexStatus: `Index query failed: ${toErrorMessage7(err)}. Fall back to grep for this lookup.`
18357
+ indexStatus: `Index query failed: ${toErrorMessage8(err)}. Fall back to grep for this lookup.`
18192
18358
  };
18193
18359
  }
18194
18360
  const { calls, symbolFound, unresolvedCount, totalMatches } = serviced;
@@ -18240,18 +18406,18 @@ var codebaseOutgoingCallsTool = {
18240
18406
  };
18241
18407
 
18242
18408
  // src/codebase-index/codebase-repo-map-tool.ts
18243
- import { toErrorMessage as toErrorMessage8 } from "@wrongstack/core/utils";
18409
+ import { toErrorMessage as toErrorMessage9 } from "@wrongstack/core/utils";
18244
18410
 
18245
18411
  // src/codebase-index/repo-map.ts
18246
18412
  init_languages2();
18247
- import * as fs23 from "node:fs/promises";
18248
- import * as path29 from "node:path";
18413
+ import * as fs24 from "node:fs/promises";
18414
+ import * as path30 from "node:path";
18249
18415
 
18250
18416
  // src/codebase-index/skeleton-extractor.ts
18251
18417
  init_languages2();
18252
18418
  init_tree_sitter_parser();
18253
- import * as fs22 from "node:fs/promises";
18254
- import * as path28 from "node:path";
18419
+ import * as fs23 from "node:fs/promises";
18420
+ import * as path29 from "node:path";
18255
18421
  var tsModule3 = null;
18256
18422
  async function loadTs3() {
18257
18423
  if (!tsModule3) {
@@ -18579,7 +18745,7 @@ async function extractDirectorySkeleton(opts) {
18579
18745
  if (filePaths.length >= maxFiles) return;
18580
18746
  let entries;
18581
18747
  try {
18582
- entries = await fs22.readdir(dir, { withFileTypes: true });
18748
+ entries = await fs23.readdir(dir, { withFileTypes: true });
18583
18749
  } catch {
18584
18750
  return;
18585
18751
  }
@@ -18588,7 +18754,7 @@ async function extractDirectorySkeleton(opts) {
18588
18754
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build") {
18589
18755
  continue;
18590
18756
  }
18591
- const fullPath = path28.join(dir, entry.name);
18757
+ const fullPath = path29.join(dir, entry.name);
18592
18758
  if (entry.isDirectory()) {
18593
18759
  await scan(fullPath);
18594
18760
  } else if (entry.isFile() && isIndexablePath(fullPath)) {
@@ -18605,7 +18771,7 @@ async function extractDirectorySkeleton(opts) {
18605
18771
  const combinedParts = [];
18606
18772
  for (const fp of filePaths) {
18607
18773
  try {
18608
- const content = await fs22.readFile(fp, "utf8");
18774
+ const content = await fs23.readFile(fp, "utf8");
18609
18775
  const res = await extractFileSkeleton({
18610
18776
  file: fp,
18611
18777
  content,
@@ -18616,7 +18782,7 @@ async function extractDirectorySkeleton(opts) {
18616
18782
  totalSkelChars += res.skeleton.length;
18617
18783
  totalOrigLines += res.stats.originalLines;
18618
18784
  totalSkelLines += res.stats.skeletonLines;
18619
- const rel = path28.relative(opts.dirPath, fp).replace(/\\/g, "/");
18785
+ const rel = path29.relative(opts.dirPath, fp).replace(/\\/g, "/");
18620
18786
  combinedParts.push(
18621
18787
  `// \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
18622
18788
  ${res.skeleton}`
@@ -18653,13 +18819,13 @@ async function generateRepoMap(opts) {
18653
18819
  const projectRoot = opts.projectRoot;
18654
18820
  const maxTokens = opts.maxTokens ?? 1200;
18655
18821
  const charBudget = maxTokens * 4;
18656
- const focusSet = new Set((opts.focusFiles ?? []).map((f) => path29.resolve(projectRoot, f)));
18822
+ const focusSet = new Set((opts.focusFiles ?? []).map((f) => path30.resolve(projectRoot, f)));
18657
18823
  const allFiles = [];
18658
18824
  async function scan(dir) {
18659
18825
  if (allFiles.length > 500) return;
18660
18826
  let entries;
18661
18827
  try {
18662
- entries = await fs23.readdir(dir, { withFileTypes: true });
18828
+ entries = await fs24.readdir(dir, { withFileTypes: true });
18663
18829
  } catch {
18664
18830
  return;
18665
18831
  }
@@ -18667,7 +18833,7 @@ async function generateRepoMap(opts) {
18667
18833
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "coverage") {
18668
18834
  continue;
18669
18835
  }
18670
- const fullPath = path29.join(dir, entry.name);
18836
+ const fullPath = path30.join(dir, entry.name);
18671
18837
  if (entry.isDirectory()) {
18672
18838
  await scan(fullPath);
18673
18839
  } else if (entry.isFile() && isIndexablePath(fullPath)) {
@@ -18687,7 +18853,7 @@ async function generateRepoMap(opts) {
18687
18853
  }
18688
18854
  const scoredFiles = [];
18689
18855
  for (const file of allFiles) {
18690
- const relPath = path29.relative(projectRoot, file).replace(/\\/g, "/");
18856
+ const relPath = path30.relative(projectRoot, file).replace(/\\/g, "/");
18691
18857
  let score = 10;
18692
18858
  if (focusSet.has(file)) {
18693
18859
  score += 100;
@@ -18702,7 +18868,7 @@ async function generateRepoMap(opts) {
18702
18868
  for (const candidate of scoredFiles) {
18703
18869
  if (currentChars >= charBudget) break;
18704
18870
  try {
18705
- const content = await fs23.readFile(candidate.file, "utf8");
18871
+ const content = await fs24.readFile(candidate.file, "utf8");
18706
18872
  if (content.length === 0) continue;
18707
18873
  const skeletonResult = await extractFileSkeleton({
18708
18874
  file: candidate.file,
@@ -18785,16 +18951,16 @@ var codebaseRepoMapTool = {
18785
18951
  totalFilesScanned: 0,
18786
18952
  estimatedTokens: 0,
18787
18953
  rankedFiles: [],
18788
- error: toErrorMessage8(err)
18954
+ error: toErrorMessage9(err)
18789
18955
  };
18790
18956
  }
18791
18957
  }
18792
18958
  };
18793
18959
 
18794
18960
  // src/codebase-index/codebase-skeleton-tool.ts
18795
- import * as fs24 from "node:fs/promises";
18796
- import * as path30 from "node:path";
18797
- import { toErrorMessage as toErrorMessage9 } from "@wrongstack/core/utils";
18961
+ import * as fs25 from "node:fs/promises";
18962
+ import * as path31 from "node:path";
18963
+ import { toErrorMessage as toErrorMessage10 } from "@wrongstack/core/utils";
18798
18964
  var codebaseSkeletonTool = {
18799
18965
  name: "codebase-skeleton",
18800
18966
  category: "Project",
@@ -18833,13 +18999,13 @@ var codebaseSkeletonTool = {
18833
18999
  additionalProperties: false
18834
19000
  },
18835
19001
  async execute(input, ctx) {
18836
- const targetPath = path30.isAbsolute(input.path) ? input.path : path30.resolve(ctx.projectRoot ?? process.cwd(), input.path);
19002
+ const targetPath = path31.isAbsolute(input.path) ? input.path : path31.resolve(ctx.projectRoot ?? process.cwd(), input.path);
18837
19003
  let stat22;
18838
19004
  try {
18839
- stat22 = await fs24.stat(targetPath);
19005
+ stat22 = await fs25.stat(targetPath);
18840
19006
  } catch (err) {
18841
19007
  throw new Error(
18842
- `codebase-skeleton: file or directory not found at "${input.path}": ${toErrorMessage9(err)}`
19008
+ `codebase-skeleton: file or directory not found at "${input.path}": ${toErrorMessage10(err)}`
18843
19009
  );
18844
19010
  }
18845
19011
  const options = {
@@ -18872,7 +19038,7 @@ var codebaseSkeletonTool = {
18872
19038
  files: dirResult.files
18873
19039
  };
18874
19040
  }
18875
- const content = await fs24.readFile(targetPath, "utf8");
19041
+ const content = await fs25.readFile(targetPath, "utf8");
18876
19042
  const fileResult = await extractFileSkeleton({
18877
19043
  file: targetPath,
18878
19044
  content,
@@ -18976,28 +19142,28 @@ var codebaseStatsTool = {
18976
19142
  // src/codebase-index/codebase-targeted-test-tool.ts
18977
19143
  init_spawn_stream();
18978
19144
  init_util();
18979
- import * as fs25 from "node:fs/promises";
18980
- import * as path31 from "node:path";
18981
- import { toErrorMessage as toErrorMessage10 } from "@wrongstack/core/utils";
19145
+ import * as fs26 from "node:fs/promises";
19146
+ import * as path32 from "node:path";
19147
+ import { toErrorMessage as toErrorMessage11 } from "@wrongstack/core/utils";
18982
19148
  var TEST_FILE_REGEX2 = /(?:test|spec|mock|fixture|bench)[s]?[/\\._]/i;
18983
19149
  async function findConventionTestFiles(projectRoot, sourceRelPath) {
18984
- const parsed = path31.parse(sourceRelPath);
19150
+ const parsed = path32.parse(sourceRelPath);
18985
19151
  const candidates = [
18986
- path31.join(parsed.dir, `${parsed.name}.test${parsed.ext}`),
18987
- path31.join(parsed.dir, `${parsed.name}.spec${parsed.ext}`),
18988
- path31.join(parsed.dir, `${parsed.name}_test${parsed.ext}`),
18989
- path31.join(parsed.dir, `test_${parsed.name}${parsed.ext}`),
18990
- path31.join("tests", `${parsed.name}.test${parsed.ext}`),
18991
- path31.join("tests", `${parsed.name}.spec${parsed.ext}`),
18992
- path31.join("test", `${parsed.name}.test${parsed.ext}`),
18993
- path31.join(parsed.dir, "__tests__", `${parsed.name}.test${parsed.ext}`),
18994
- path31.join(parsed.dir, "__tests__", `${parsed.name}${parsed.ext}`)
19152
+ path32.join(parsed.dir, `${parsed.name}.test${parsed.ext}`),
19153
+ path32.join(parsed.dir, `${parsed.name}.spec${parsed.ext}`),
19154
+ path32.join(parsed.dir, `${parsed.name}_test${parsed.ext}`),
19155
+ path32.join(parsed.dir, `test_${parsed.name}${parsed.ext}`),
19156
+ path32.join("tests", `${parsed.name}.test${parsed.ext}`),
19157
+ path32.join("tests", `${parsed.name}.spec${parsed.ext}`),
19158
+ path32.join("test", `${parsed.name}.test${parsed.ext}`),
19159
+ path32.join(parsed.dir, "__tests__", `${parsed.name}.test${parsed.ext}`),
19160
+ path32.join(parsed.dir, "__tests__", `${parsed.name}${parsed.ext}`)
18995
19161
  ];
18996
19162
  const found = [];
18997
19163
  for (const cand of candidates) {
18998
- const absPath = path31.resolve(projectRoot, cand);
19164
+ const absPath = path32.resolve(projectRoot, cand);
18999
19165
  try {
19000
- const st = await fs25.stat(absPath);
19166
+ const st = await fs26.stat(absPath);
19001
19167
  if (st.isFile()) {
19002
19168
  found.push(cand.replace(/\\/g, "/"));
19003
19169
  }
@@ -19054,7 +19220,7 @@ var codebaseTargetedTestTool = {
19054
19220
  transitive: true
19055
19221
  });
19056
19222
  for (const site of serviced.calls) {
19057
- const relPath = path31.relative(projectRoot, site.symbol.file).replace(/\\/g, "/");
19223
+ const relPath = path32.relative(projectRoot, site.symbol.file).replace(/\\/g, "/");
19058
19224
  if (TEST_FILE_REGEX2.test(relPath)) {
19059
19225
  suitesSet.add(relPath);
19060
19226
  }
@@ -19131,7 +19297,7 @@ ${streamRes.stderr}`.trim(),
19131
19297
  failed: 0,
19132
19298
  durationMs: 0,
19133
19299
  output: "",
19134
- error: toErrorMessage10(err)
19300
+ error: toErrorMessage11(err)
19135
19301
  };
19136
19302
  }
19137
19303
  }
@@ -19139,8 +19305,8 @@ ${streamRes.stderr}`.trim(),
19139
19305
 
19140
19306
  // src/codebase-index/dead-code-scan.ts
19141
19307
  init_languages2();
19142
- import * as fs26 from "node:fs";
19143
- import * as path32 from "node:path";
19308
+ import * as fs27 from "node:fs";
19309
+ import * as path33 from "node:path";
19144
19310
  var deadCodeScanTool = {
19145
19311
  name: "dead-code-scan",
19146
19312
  category: "Project",
@@ -19185,25 +19351,25 @@ var deadCodeScanTool = {
19185
19351
  };
19186
19352
  function tryReadJson(filePath) {
19187
19353
  try {
19188
- const raw = fs26.readFileSync(filePath, "utf8");
19354
+ const raw = fs27.readFileSync(filePath, "utf8");
19189
19355
  return JSON.parse(raw);
19190
19356
  } catch {
19191
19357
  return null;
19192
19358
  }
19193
19359
  }
19194
19360
  function resolveAgainst(base, relative20) {
19195
- if (path32.isAbsolute(relative20)) return relative20;
19196
- return path32.resolve(base, relative20);
19361
+ if (path33.isAbsolute(relative20)) return relative20;
19362
+ return path33.resolve(base, relative20);
19197
19363
  }
19198
19364
  function discoverEntryPoints(projectRoot, userEntryPoints) {
19199
19365
  const entries = /* @__PURE__ */ new Set();
19200
19366
  if (userEntryPoints) {
19201
19367
  for (const ep of userEntryPoints) {
19202
19368
  const resolved = resolveAgainst(projectRoot, ep);
19203
- if (fs26.existsSync(resolved)) entries.add(resolved);
19369
+ if (fs27.existsSync(resolved)) entries.add(resolved);
19204
19370
  }
19205
19371
  }
19206
- const rootPkg = tryReadJson(path32.join(projectRoot, "package.json"));
19372
+ const rootPkg = tryReadJson(path33.join(projectRoot, "package.json"));
19207
19373
  if (rootPkg) {
19208
19374
  addPkgJsonEntryPoints(projectRoot, rootPkg, entries);
19209
19375
  }
@@ -19217,45 +19383,45 @@ function discoverEntryPoints(projectRoot, userEntryPoints) {
19217
19383
  workspaces = [];
19218
19384
  }
19219
19385
  for (const wsDir of workspaces) {
19220
- const pkgJsonPath = path32.join(wsDir, "package.json");
19386
+ const pkgJsonPath = path33.join(wsDir, "package.json");
19221
19387
  const pkg = tryReadJson(pkgJsonPath);
19222
19388
  if (pkg) {
19223
19389
  addPkgJsonEntryPoints(wsDir, pkg, entries);
19224
- const convention1 = path32.join(wsDir, "src", "index.ts");
19225
- if (fs26.existsSync(convention1)) entries.add(convention1);
19226
- const convention2 = path32.join(wsDir, "src", "main.ts");
19227
- if (fs26.existsSync(convention2)) entries.add(convention2);
19228
- const convention3 = path32.join(wsDir, "index.ts");
19229
- if (fs26.existsSync(convention3)) entries.add(convention3);
19390
+ const convention1 = path33.join(wsDir, "src", "index.ts");
19391
+ if (fs27.existsSync(convention1)) entries.add(convention1);
19392
+ const convention2 = path33.join(wsDir, "src", "main.ts");
19393
+ if (fs27.existsSync(convention2)) entries.add(convention2);
19394
+ const convention3 = path33.join(wsDir, "index.ts");
19395
+ if (fs27.existsSync(convention3)) entries.add(convention3);
19230
19396
  }
19231
19397
  }
19232
19398
  if (!rootPkg || !workspaces.length) {
19233
19399
  for (const name of ["src/index.ts", "src/main.ts", "index.ts"]) {
19234
- const convention = path32.join(projectRoot, name);
19235
- if (fs26.existsSync(convention)) entries.add(convention);
19400
+ const convention = path33.join(projectRoot, name);
19401
+ if (fs27.existsSync(convention)) entries.add(convention);
19236
19402
  }
19237
19403
  }
19238
19404
  return [...entries];
19239
19405
  }
19240
19406
  var BUILD_OUTPUT_DIRS = ["dist", "out", "build", "release"];
19241
- var BUILD_OUTPUT_DIR_NAMES = BUILD_OUTPUT_DIRS.map((d) => `${path32.sep}${d}${path32.sep}`);
19407
+ var BUILD_OUTPUT_DIR_NAMES = BUILD_OUTPUT_DIRS.map((d) => `${path33.sep}${d}${path33.sep}`);
19242
19408
  function trySourceEquivalent(resolved) {
19243
- resolved = resolved.replace(/[/\\]/g, path32.sep);
19409
+ resolved = resolved.replace(/[/\\]/g, path33.sep);
19244
19410
  for (const marker of BUILD_OUTPUT_DIR_NAMES) {
19245
19411
  const idx = resolved.indexOf(marker);
19246
19412
  if (idx === -1) continue;
19247
- const base = resolved.replace(marker, `${path32.sep}src${path32.sep}`);
19413
+ const base = resolved.replace(marker, `${path33.sep}src${path33.sep}`);
19248
19414
  const candidate = base.replace(/\.(js|mjs|cjs)$/, ".ts");
19249
- if (candidate !== base && fs26.existsSync(candidate)) {
19415
+ if (candidate !== base && fs27.existsSync(candidate)) {
19250
19416
  return candidate;
19251
19417
  }
19252
19418
  const dtsStripped = base.replace(/\.d\.ts$/, "");
19253
19419
  const candidateDts = dtsStripped + ".ts";
19254
- if (candidateDts !== base && candidateDts !== candidate && fs26.existsSync(candidateDts)) {
19420
+ if (candidateDts !== base && candidateDts !== candidate && fs27.existsSync(candidateDts)) {
19255
19421
  return candidateDts;
19256
19422
  }
19257
19423
  const candidateNoExt = base + ".ts";
19258
- if (candidate !== candidateNoExt && candidateNoExt !== candidateDts && fs26.existsSync(candidateNoExt)) {
19424
+ if (candidate !== candidateNoExt && candidateNoExt !== candidateDts && fs27.existsSync(candidateNoExt)) {
19259
19425
  return candidateNoExt;
19260
19426
  }
19261
19427
  }
@@ -19263,9 +19429,9 @@ function trySourceEquivalent(resolved) {
19263
19429
  }
19264
19430
  function tryAddEntryPath(pkgDir, rawPath, entries) {
19265
19431
  const resolved = resolveAgainst(pkgDir, rawPath);
19266
- if (fs26.existsSync(resolved)) entries.add(resolved);
19432
+ if (fs27.existsSync(resolved)) entries.add(resolved);
19267
19433
  const tsResolved = resolved.replace(/\.(js|mjs|cjs)$/, ".ts");
19268
- if (tsResolved !== resolved && fs26.existsSync(tsResolved)) {
19434
+ if (tsResolved !== resolved && fs27.existsSync(tsResolved)) {
19269
19435
  entries.add(tsResolved);
19270
19436
  }
19271
19437
  const srcAlt = trySourceEquivalent(resolved);
@@ -19309,18 +19475,18 @@ function expandGlobPattern(entry, projectRoot) {
19309
19475
  const dirs = [];
19310
19476
  if (entry.includes("*")) {
19311
19477
  const base = entry.replace(/\/\*+$/, "");
19312
- const baseDir = path32.resolve(projectRoot, base);
19478
+ const baseDir = path33.resolve(projectRoot, base);
19313
19479
  try {
19314
- const children = fs26.readdirSync(baseDir, { withFileTypes: true });
19480
+ const children = fs27.readdirSync(baseDir, { withFileTypes: true });
19315
19481
  for (const child of children) {
19316
19482
  if (child.isDirectory()) {
19317
- dirs.push(path32.join(baseDir, child.name));
19483
+ dirs.push(path33.join(baseDir, child.name));
19318
19484
  }
19319
19485
  }
19320
19486
  } catch {
19321
19487
  }
19322
19488
  } else {
19323
- dirs.push(path32.resolve(projectRoot, entry));
19489
+ dirs.push(path33.resolve(projectRoot, entry));
19324
19490
  }
19325
19491
  return dirs;
19326
19492
  }
@@ -19337,10 +19503,10 @@ function extractWorkspaceGlobs(pkg, projectRoot) {
19337
19503
  return dirs;
19338
19504
  }
19339
19505
  function extractPnpmWorkspaceDirs(projectRoot) {
19340
- const yamlPath = path32.join(projectRoot, "pnpm-workspace.yaml");
19341
- if (!fs26.existsSync(yamlPath)) return [];
19506
+ const yamlPath = path33.join(projectRoot, "pnpm-workspace.yaml");
19507
+ if (!fs27.existsSync(yamlPath)) return [];
19342
19508
  try {
19343
- const content = fs26.readFileSync(yamlPath, "utf8");
19509
+ const content = fs27.readFileSync(yamlPath, "utf8");
19344
19510
  const dirs = [];
19345
19511
  let inPackages = false;
19346
19512
  const lines = content.split("\n");
@@ -19374,8 +19540,8 @@ function extractPnpmWorkspaceDirs(projectRoot) {
19374
19540
  }
19375
19541
  function resolveModulePath(importerPath, moduleSpecifier, indexedFiles) {
19376
19542
  if (!moduleSpecifier.startsWith(".")) return [];
19377
- const dir = path32.dirname(importerPath);
19378
- const base = path32.resolve(dir, moduleSpecifier);
19543
+ const dir = path33.dirname(importerPath);
19544
+ const base = path33.resolve(dir, moduleSpecifier);
19379
19545
  const results = [];
19380
19546
  const stripped = base.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/, "");
19381
19547
  const skipBase = stripped !== base && /\.(ts|tsx|js|jsx|mjs|cjs)$/.test(base);
@@ -19387,18 +19553,18 @@ function resolveModulePath(importerPath, moduleSpecifier, indexedFiles) {
19387
19553
  if (indexedFiles.has(candidate + ".jsx")) results.push(candidate + ".jsx");
19388
19554
  if (indexedFiles.has(candidate + ".mjs")) results.push(candidate + ".mjs");
19389
19555
  if (indexedFiles.has(candidate + ".cjs")) results.push(candidate + ".cjs");
19390
- if (indexedFiles.has(path32.join(candidate, "index.ts")))
19391
- results.push(path32.join(candidate, "index.ts"));
19392
- if (indexedFiles.has(path32.join(candidate, "index.tsx")))
19393
- results.push(path32.join(candidate, "index.tsx"));
19394
- if (indexedFiles.has(path32.join(candidate, "index.js")))
19395
- results.push(path32.join(candidate, "index.js"));
19396
- if (indexedFiles.has(path32.join(candidate, "index.jsx")))
19397
- results.push(path32.join(candidate, "index.jsx"));
19398
- if (indexedFiles.has(path32.join(candidate, "index.mjs")))
19399
- results.push(path32.join(candidate, "index.mjs"));
19400
- if (indexedFiles.has(path32.join(candidate, "index.cjs")))
19401
- results.push(path32.join(candidate, "index.cjs"));
19556
+ if (indexedFiles.has(path33.join(candidate, "index.ts")))
19557
+ results.push(path33.join(candidate, "index.ts"));
19558
+ if (indexedFiles.has(path33.join(candidate, "index.tsx")))
19559
+ results.push(path33.join(candidate, "index.tsx"));
19560
+ if (indexedFiles.has(path33.join(candidate, "index.js")))
19561
+ results.push(path33.join(candidate, "index.js"));
19562
+ if (indexedFiles.has(path33.join(candidate, "index.jsx")))
19563
+ results.push(path33.join(candidate, "index.jsx"));
19564
+ if (indexedFiles.has(path33.join(candidate, "index.mjs")))
19565
+ results.push(path33.join(candidate, "index.mjs"));
19566
+ if (indexedFiles.has(path33.join(candidate, "index.cjs")))
19567
+ results.push(path33.join(candidate, "index.cjs"));
19402
19568
  }
19403
19569
  return [...new Set(results)];
19404
19570
  }
@@ -19430,7 +19596,7 @@ function runDeadCodeScan(projectRoot, opts = {}) {
19430
19596
  symbolById.set(s.id, s);
19431
19597
  }
19432
19598
  const discoveredFiles = discoverEntryPoints(projectRoot, opts.userEntryPoints);
19433
- const entryFileSet = new Set(discoveredFiles.map((f) => path32.resolve(f)));
19599
+ const entryFileSet = new Set(discoveredFiles.map((f) => path33.resolve(f)));
19434
19600
  const indexedFiles = /* @__PURE__ */ new Set();
19435
19601
  for (const s of allSymbols) indexedFiles.add(s.file);
19436
19602
  for (const fm of store.getAllFileMetas()) indexedFiles.add(fm.file);
@@ -19456,7 +19622,7 @@ function runDeadCodeScan(projectRoot, opts = {}) {
19456
19622
  if (scannedBarrels.has(epFile)) continue;
19457
19623
  scannedBarrels.add(epFile);
19458
19624
  try {
19459
- const content = fs26.readFileSync(epFile, "utf8");
19625
+ const content = fs27.readFileSync(epFile, "utf8");
19460
19626
  const strippedContent = content.replace(/\/\*[\s\S]*?\*\//g, (m) => " ".repeat(m.length)).replace(/\/\/[^\n]*/g, (m) => " ".repeat(m.length));
19461
19627
  const reExportRe = /export\s+(?:(?:type\s+)?\{[\s\S]*?\}\s+from|\*\s+as\s+\w+\s+from|\*\s+from)\s+['"]([^'"]+)['"]/g;
19462
19628
  for (; ; ) {
@@ -19546,7 +19712,7 @@ function runDeadCodeScan(projectRoot, opts = {}) {
19546
19712
  const deadPackages = [];
19547
19713
  const pkgEntries = findPackageEntries(projectRoot);
19548
19714
  for (const [pkgName, pkgDir] of pkgEntries) {
19549
- const pkgFiles = allSymbols.filter((s) => s.file.startsWith(pkgDir + path32.sep));
19715
+ const pkgFiles = allSymbols.filter((s) => s.file.startsWith(pkgDir + path33.sep));
19550
19716
  if (pkgFiles.length === 0) continue;
19551
19717
  const pkgUsed = pkgFiles.filter((s) => alive.has(s.id));
19552
19718
  if (pkgUsed.length === 0) {
@@ -19582,7 +19748,7 @@ function runDeadCodeScan(projectRoot, opts = {}) {
19582
19748
  }
19583
19749
  function findPackageEntries(projectRoot) {
19584
19750
  const pkgMap = /* @__PURE__ */ new Map();
19585
- const rootPkg = tryReadJson(path32.join(projectRoot, "package.json"));
19751
+ const rootPkg = tryReadJson(path33.join(projectRoot, "package.json"));
19586
19752
  if (rootPkg && typeof rootPkg.name === "string") {
19587
19753
  pkgMap.set(rootPkg.name, projectRoot);
19588
19754
  }
@@ -19592,7 +19758,7 @@ function findPackageEntries(projectRoot) {
19592
19758
  wsDirs = extractPnpmWorkspaceDirs(projectRoot);
19593
19759
  }
19594
19760
  for (const wsDir of wsDirs) {
19595
- const wsPkg = tryReadJson(path32.join(wsDir, "package.json"));
19761
+ const wsPkg = tryReadJson(path33.join(wsDir, "package.json"));
19596
19762
  if (wsPkg && typeof wsPkg.name === "string") {
19597
19763
  pkgMap.set(wsPkg.name, wsDir);
19598
19764
  }
@@ -19602,7 +19768,7 @@ function findPackageEntries(projectRoot) {
19602
19768
  }
19603
19769
 
19604
19770
  // src/clarify.ts
19605
- import { toErrorMessage as toErrorMessage11 } from "@wrongstack/core/utils";
19771
+ import { toErrorMessage as toErrorMessage12 } from "@wrongstack/core/utils";
19606
19772
  var clarifyTool = {
19607
19773
  name: "clarify",
19608
19774
  category: "Meta",
@@ -19675,15 +19841,15 @@ var clarifyTool = {
19675
19841
  question: input.question ?? "",
19676
19842
  selectedOptions: [],
19677
19843
  decisionSummary: "",
19678
- error: toErrorMessage11(err)
19844
+ error: toErrorMessage12(err)
19679
19845
  };
19680
19846
  }
19681
19847
  }
19682
19848
  };
19683
19849
 
19684
19850
  // src/design.ts
19685
- import * as fs27 from "node:fs/promises";
19686
- import * as path33 from "node:path";
19851
+ import * as fs28 from "node:fs/promises";
19852
+ import * as path34 from "node:path";
19687
19853
  import {
19688
19854
  applyTokenOverrides,
19689
19855
  getDesignKitLoader,
@@ -19698,17 +19864,17 @@ import {
19698
19864
  setDesignOverrides
19699
19865
  } from "@wrongstack/core/design";
19700
19866
  async function resolveReal(p) {
19701
- const resolved = path33.resolve(p);
19867
+ const resolved = path34.resolve(p);
19702
19868
  let probe = resolved;
19703
19869
  const missing = [];
19704
19870
  for (; ; ) {
19705
19871
  try {
19706
- return path33.resolve(await fs27.realpath(probe), ...missing);
19872
+ return path34.resolve(await fs28.realpath(probe), ...missing);
19707
19873
  } catch (err) {
19708
19874
  if (err.code === "ENOENT") {
19709
- const parent = path33.dirname(probe);
19875
+ const parent = path34.dirname(probe);
19710
19876
  if (parent === probe) return resolved;
19711
- missing.unshift(path33.basename(probe));
19877
+ missing.unshift(path34.basename(probe));
19712
19878
  probe = parent;
19713
19879
  continue;
19714
19880
  }
@@ -19909,16 +20075,16 @@ Run \`design {action:"materialize"}\` to write the tuned tokens to your theme fi
19909
20075
  outPath: input.out
19910
20076
  });
19911
20077
  const root = await resolveReal(ctx.projectRoot);
19912
- const absResolved = path33.isAbsolute(result.path) ? path33.resolve(result.path) : path33.resolve(path33.join(ctx.projectRoot, result.path));
19913
- const absParent = await resolveReal(path33.dirname(absResolved));
19914
- const abs = path33.join(absParent, path33.basename(absResolved));
19915
- const rel = path33.relative(root, abs);
19916
- if (rel.startsWith("..") || path33.isAbsolute(rel)) {
20078
+ const absResolved = path34.isAbsolute(result.path) ? path34.resolve(result.path) : path34.resolve(path34.join(ctx.projectRoot, result.path));
20079
+ const absParent = await resolveReal(path34.dirname(absResolved));
20080
+ const abs = path34.join(absParent, path34.basename(absResolved));
20081
+ const rel = path34.relative(root, abs);
20082
+ if (rel.startsWith("..") || path34.isAbsolute(rel)) {
19917
20083
  throw new Error(`design: materialize path "${result.path}" would escape the project root`);
19918
20084
  }
19919
20085
  let exists = false;
19920
20086
  try {
19921
- await fs27.access(abs);
20087
+ await fs28.access(abs);
19922
20088
  exists = true;
19923
20089
  } catch {
19924
20090
  }
@@ -19935,8 +20101,8 @@ ${result.content}
19935
20101
  \`\`\``
19936
20102
  };
19937
20103
  }
19938
- await fs27.mkdir(path33.dirname(abs), { recursive: true });
19939
- await fs27.writeFile(abs, result.content);
20104
+ await fs28.mkdir(path34.dirname(abs), { recursive: true });
20105
+ await fs28.writeFile(abs, result.content);
19940
20106
  return {
19941
20107
  action,
19942
20108
  kit: active.kit,
@@ -19986,8 +20152,8 @@ Replace off-palette colors with kit tokens (or the materialized CSS vars / token
19986
20152
  init_util();
19987
20153
  import { spawn as spawn7 } from "node:child_process";
19988
20154
  import { statSync as statSync3 } from "node:fs";
19989
- import * as fs28 from "node:fs/promises";
19990
- import * as path34 from "node:path";
20155
+ import * as fs29 from "node:fs/promises";
20156
+ import * as path35 from "node:path";
19991
20157
  import { buildChildEnv as buildChildEnv3 } from "@wrongstack/core/utils";
19992
20158
  import { ToolValidationError as ToolValidationError2 } from "@wrongstack/core/types";
19993
20159
  var MAX_FILE_DUMP_BYTES = 5 * 1024 * 1024;
@@ -20102,18 +20268,18 @@ function findGitDir(cwd) {
20102
20268
  let dir = cwd;
20103
20269
  for (let i = 0; i < 20; i++) {
20104
20270
  try {
20105
- const stat22 = statSync3(path34.join(dir, ".git"));
20271
+ const stat22 = statSync3(path35.join(dir, ".git"));
20106
20272
  if (stat22.isDirectory()) return dir;
20107
20273
  } catch {
20108
20274
  }
20109
- const parent = path34.dirname(dir);
20275
+ const parent = path35.dirname(dir);
20110
20276
  if (parent === dir) break;
20111
20277
  dir = parent;
20112
20278
  }
20113
20279
  return null;
20114
20280
  }
20115
20281
  function runGit(args, cwd, signal) {
20116
- return new Promise((resolve23) => {
20282
+ return new Promise((resolve24) => {
20117
20283
  let stdout = "";
20118
20284
  let stderr = "";
20119
20285
  const child = spawn7("git", args, {
@@ -20129,8 +20295,8 @@ function runGit(args, cwd, signal) {
20129
20295
  child.stderr?.on("data", (c) => {
20130
20296
  stderr += c.toString();
20131
20297
  });
20132
- child.on("close", (code) => resolve23({ stdout, stderr, exitCode: code ?? 0 }));
20133
- child.on("error", (e) => resolve23({ stdout: "", stderr: e.message, exitCode: 1 }));
20298
+ child.on("close", (code) => resolve24({ stdout, stderr, exitCode: code ?? 0 }));
20299
+ child.on("error", (e) => resolve24({ stdout: "", stderr: e.message, exitCode: 1 }));
20134
20300
  });
20135
20301
  }
20136
20302
  async function fileDiff(input, ctx, _signal) {
@@ -20148,7 +20314,7 @@ async function fileDiff(input, ctx, _signal) {
20148
20314
  let truncated = false;
20149
20315
  for (const file of files) {
20150
20316
  const absPath = await safeResolveReal(file, ctx);
20151
- const stat22 = await fs28.stat(absPath).catch(() => null);
20317
+ const stat22 = await fs29.stat(absPath).catch(() => null);
20152
20318
  if (!stat22?.isFile()) continue;
20153
20319
  if (stat22.size > MAX_FILE_DUMP_BYTES) {
20154
20320
  truncated = true;
@@ -20157,7 +20323,7 @@ async function fileDiff(input, ctx, _signal) {
20157
20323
  );
20158
20324
  continue;
20159
20325
  }
20160
- const content = await fs28.readFile(absPath, "utf8");
20326
+ const content = await fs29.readFile(absPath, "utf8");
20161
20327
  const lines = content.split(/\r?\n/);
20162
20328
  results.push(formatWithLineNumbers(file, lines));
20163
20329
  }
@@ -20180,8 +20346,8 @@ ${numbered}`;
20180
20346
 
20181
20347
  // src/document.ts
20182
20348
  init_util();
20183
- import * as fs29 from "node:fs/promises";
20184
- import * as path35 from "node:path";
20349
+ import * as fs30 from "node:fs/promises";
20350
+ import * as path36 from "node:path";
20185
20351
  var documentTool = {
20186
20352
  name: "document",
20187
20353
  category: "Project",
@@ -20229,7 +20395,7 @@ var documentTool = {
20229
20395
  ) : input.path ? [await safeResolveReal(input.path, ctx)] : [];
20230
20396
  for (const absPath of fileList) {
20231
20397
  try {
20232
- const content = await fs29.readFile(absPath, "utf8");
20398
+ const content = await fs30.readFile(absPath, "utf8");
20233
20399
  filesProcessed++;
20234
20400
  const processed = processFile(
20235
20401
  content,
@@ -20267,12 +20433,12 @@ async function resolveFiles(filesInput, cwd, ctx) {
20267
20433
  if (!entry) continue;
20268
20434
  let absPath;
20269
20435
  try {
20270
- absPath = ensureInsideRoot(path35.resolve(cwd, entry), ctx);
20436
+ absPath = ensureInsideRoot(path36.resolve(cwd, entry), ctx);
20271
20437
  } catch {
20272
20438
  continue;
20273
20439
  }
20274
20440
  try {
20275
- const stat22 = await fs29.stat(absPath);
20441
+ const stat22 = await fs30.stat(absPath);
20276
20442
  if (stat22.isFile()) resolved.push(absPath);
20277
20443
  } catch {
20278
20444
  }
@@ -20343,7 +20509,7 @@ function processFile(content, absPath, _style, _overwrite, target) {
20343
20509
  // src/e2e.ts
20344
20510
  init_util();
20345
20511
  import { open, readdir as readdir9 } from "node:fs/promises";
20346
- import * as path36 from "node:path";
20512
+ import * as path37 from "node:path";
20347
20513
  async function readBoundedText(filePath, maxBytes) {
20348
20514
  let handle;
20349
20515
  try {
@@ -20393,8 +20559,8 @@ var MAX_PACKAGE_BYTES = 512 * 1024;
20393
20559
  var MAX_CONFIG_BYTES = 512 * 1024;
20394
20560
  var MAX_SPEC_SAMPLES = 20;
20395
20561
  function relativePath(root, target) {
20396
- const value = path36.relative(root, target) || ".";
20397
- return value.split(path36.sep).join("/");
20562
+ const value = path37.relative(root, target) || ".";
20563
+ return value.split(path37.sep).join("/");
20398
20564
  }
20399
20565
  function escapeRegExp(value) {
20400
20566
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -20466,7 +20632,7 @@ async function scanWorkspace(root, maxDepth, signal) {
20466
20632
  }
20467
20633
  for (const entry of entries) {
20468
20634
  signal.throwIfAborted();
20469
- const absolutePath = path36.join(current.directory, entry.name);
20635
+ const absolutePath = path37.join(current.directory, entry.name);
20470
20636
  if (entry.isFile()) {
20471
20637
  if (entry.name === "package.json") result.packageFiles.push(absolutePath);
20472
20638
  const framework = CONFIG_NAMES.get(entry.name);
@@ -20527,9 +20693,9 @@ async function detectPackageManager3(projectRoot, scanRoot, declared) {
20527
20693
  if (names.has("bun.lock") || names.has("bun.lockb")) return "bun";
20528
20694
  if (names.has("package-lock.json") || names.has("npm-shrinkwrap.json")) return "npm";
20529
20695
  if (directory === scanRoot) break;
20530
- const parent = path36.dirname(directory);
20531
- const relativeParent = path36.relative(scanRoot, parent);
20532
- if (parent === directory || relativeParent.startsWith("..") || path36.isAbsolute(relativeParent)) {
20696
+ const parent = path37.dirname(directory);
20697
+ const relativeParent = path37.relative(scanRoot, parent);
20698
+ if (parent === directory || relativeParent.startsWith("..") || path37.isAbsolute(relativeParent)) {
20533
20699
  break;
20534
20700
  }
20535
20701
  directory = parent;
@@ -20574,7 +20740,7 @@ function isSpec(framework, filename) {
20574
20740
  return /\.(?:spec|test)\.(?:[cm]?[jt]sx?)$/i.test(filename);
20575
20741
  }
20576
20742
  async function collectSpecs(root, framework, testDirectory, signal) {
20577
- const roots = testDirectory ? [path36.resolve(root, testDirectory)] : framework === "cypress" ? [path36.join(root, "cypress", "e2e"), path36.join(root, "cypress", "integration")] : [path36.join(root, "tests")];
20743
+ const roots = testDirectory ? [path37.resolve(root, testDirectory)] : framework === "cypress" ? [path37.join(root, "cypress", "e2e"), path37.join(root, "cypress", "integration")] : [path37.join(root, "tests")];
20578
20744
  const samples = [];
20579
20745
  let count = 0;
20580
20746
  let scanned = 0;
@@ -20593,7 +20759,7 @@ async function collectSpecs(root, framework, testDirectory, signal) {
20593
20759
  }
20594
20760
  for (const entry of entries) {
20595
20761
  signal.throwIfAborted();
20596
- const target = path36.join(directory, entry.name);
20762
+ const target = path37.join(directory, entry.name);
20597
20763
  if (entry.isDirectory() && !SKIP_DIRECTORIES.has(entry.name)) queue.push(target);
20598
20764
  else if (entry.isFile() && isSpec(framework, entry.name)) {
20599
20765
  count += 1;
@@ -20613,7 +20779,7 @@ function nearestPackage(projectRoot, packagesByDirectory, scanRoot) {
20613
20779
  const found = packagesByDirectory.get(directory);
20614
20780
  if (found) return found;
20615
20781
  if (directory === scanRoot) return void 0;
20616
- const parent = path36.dirname(directory);
20782
+ const parent = path37.dirname(directory);
20617
20783
  if (parent === directory || relativePath(scanRoot, parent).startsWith("..")) return void 0;
20618
20784
  directory = parent;
20619
20785
  }
@@ -20624,13 +20790,13 @@ async function discoverE2EProjects(root, options) {
20624
20790
  const packages = (await Promise.all(scan.packageFiles.map(readPackageInfo))).filter(
20625
20791
  (info) => Boolean(info)
20626
20792
  );
20627
- const packagesByDirectory = new Map(packages.map((info) => [path36.dirname(info.path), info]));
20793
+ const packagesByDirectory = new Map(packages.map((info) => [path37.dirname(info.path), info]));
20628
20794
  const candidates = /* @__PURE__ */ new Map();
20629
20795
  for (const config of scan.configs) {
20630
20796
  if (options.framework && options.framework !== "all" && config.framework !== options.framework) {
20631
20797
  continue;
20632
20798
  }
20633
- const projectRoot = path36.dirname(config.absolutePath);
20799
+ const projectRoot = path37.dirname(config.absolutePath);
20634
20800
  candidates.set(`${config.framework}:${projectRoot}`, {
20635
20801
  framework: config.framework,
20636
20802
  root: projectRoot,
@@ -20638,7 +20804,7 @@ async function discoverE2EProjects(root, options) {
20638
20804
  });
20639
20805
  }
20640
20806
  for (const info of packages) {
20641
- const projectRoot = path36.dirname(info.path);
20807
+ const projectRoot = path37.dirname(info.path);
20642
20808
  for (const framework of frameworkFromPackage(info)) {
20643
20809
  if (options.framework && options.framework !== "all" && framework !== options.framework)
20644
20810
  continue;
@@ -20654,10 +20820,10 @@ async function discoverE2EProjects(root, options) {
20654
20820
  const scripts = matchingScripts(info, candidate.framework);
20655
20821
  const manager = await detectPackageManager3(candidate.root, root, info?.packageManager);
20656
20822
  const testDirectory = candidate.framework === "playwright" ? staticString(source, "testDir") : void 0;
20657
- const resolvedTestDirectory = testDirectory ? path36.resolve(candidate.root, testDirectory) : void 0;
20658
- const relativeTestDirectory = resolvedTestDirectory ? path36.relative(root, resolvedTestDirectory) : void 0;
20823
+ const resolvedTestDirectory = testDirectory ? path37.resolve(candidate.root, testDirectory) : void 0;
20824
+ const relativeTestDirectory = resolvedTestDirectory ? path37.relative(root, resolvedTestDirectory) : void 0;
20659
20825
  const unsafeTestDirectory = Boolean(
20660
- relativeTestDirectory && (relativeTestDirectory.startsWith("..") || path36.isAbsolute(relativeTestDirectory))
20826
+ relativeTestDirectory && (relativeTestDirectory.startsWith("..") || path37.isAbsolute(relativeTestDirectory))
20661
20827
  );
20662
20828
  const specs = options.includeSpecs === false || unsafeTestDirectory ? { count: 0, samples: [], truncated: false } : await collectSpecs(candidate.root, candidate.framework, testDirectory, options.signal);
20663
20829
  const warnings = [];
@@ -20757,7 +20923,7 @@ var e2ePlanTool = {
20757
20923
  };
20758
20924
 
20759
20925
  // src/edit.ts
20760
- import * as fs30 from "node:fs/promises";
20926
+ import * as fs31 from "node:fs/promises";
20761
20927
  import {
20762
20928
  atomicWrite as atomicWrite3,
20763
20929
  detectNewlineStyle,
@@ -20981,7 +21147,7 @@ function prefixSimilarity(a, b) {
20981
21147
  }
20982
21148
 
20983
21149
  // src/_syntax-check.ts
20984
- import * as path37 from "node:path";
21150
+ import * as path38 from "node:path";
20985
21151
  var TS_LIKE = /* @__PURE__ */ new Set([".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"]);
20986
21152
  var MAX_CHECK_CHARS = 15e5;
20987
21153
  var MAX_ERRORS = 5;
@@ -21005,15 +21171,15 @@ async function checkSyntax(filePath, content, previousContent) {
21005
21171
  return { errors, preExisting };
21006
21172
  }
21007
21173
  function isJsoncFile(filePath) {
21008
- const base = path37.basename(filePath).toLowerCase();
21174
+ const base = path38.basename(filePath).toLowerCase();
21009
21175
  if (base.endsWith(".jsonc")) return true;
21010
21176
  if (/^(tsconfig|jsconfig)([.-].*)?\.json$/.test(base)) return true;
21011
- const dir = path37.basename(path37.dirname(filePath)).toLowerCase();
21177
+ const dir = path38.basename(path38.dirname(filePath)).toLowerCase();
21012
21178
  return dir === ".vscode";
21013
21179
  }
21014
21180
  async function parseErrors(filePath, content) {
21015
21181
  if (content.length > MAX_CHECK_CHARS) return void 0;
21016
- const ext = path37.extname(filePath).toLowerCase();
21182
+ const ext = path38.extname(filePath).toLowerCase();
21017
21183
  if (ext === ".json" || ext === ".jsonc") {
21018
21184
  try {
21019
21185
  JSON.parse(content);
@@ -21040,7 +21206,7 @@ async function parseErrors(filePath, content) {
21040
21206
  ts2.ScriptKind.JSX
21041
21207
  );
21042
21208
  const sourceFile = ts2.createSourceFile(
21043
- path37.basename(filePath),
21209
+ path38.basename(filePath),
21044
21210
  content,
21045
21211
  ts2.ScriptTarget.Latest,
21046
21212
  /* setParentNodes */
@@ -21131,7 +21297,7 @@ var editTool = {
21131
21297
  });
21132
21298
  }
21133
21299
  const absPath = await safeResolveReal(input.path, ctx);
21134
- const stat22 = await fs30.stat(absPath).catch((err) => {
21300
+ const stat22 = await fs31.stat(absPath).catch((err) => {
21135
21301
  if (err.code === "ENOENT") {
21136
21302
  throw new ToolValidationError3({
21137
21303
  message: `edit: file "${input.path}" does not exist. Use \`write\` instead.`,
@@ -21148,8 +21314,8 @@ var editTool = {
21148
21314
  });
21149
21315
  }
21150
21316
  const autoRead = !ctx.hasRead(absPath);
21151
- const original = await fs30.readFile(absPath, "utf8");
21152
- const updated = await fs30.stat(absPath);
21317
+ const original = await fs31.readFile(absPath, "utf8");
21318
+ const updated = await fs31.stat(absPath);
21153
21319
  const mtimeTolerance = process.platform === "win32" ? 2e3 : 1;
21154
21320
  const originalHash = sha256hex(original);
21155
21321
  const lastReadHash = ctx.lastReadHash?.(absPath);
@@ -21257,7 +21423,7 @@ var editTool = {
21257
21423
  enqueueReindex({ projectRoot: ctx.projectRoot, files: [absPath] });
21258
21424
  } catch {
21259
21425
  }
21260
- const written = await fs30.stat(absPath);
21426
+ const written = await fs31.stat(absPath);
21261
21427
  ctx.recordRead(absPath, written.mtimeMs, "write", sha256hex(newFile));
21262
21428
  ctx.session.recordFileChange({
21263
21429
  path: absPath,
@@ -21307,14 +21473,14 @@ import {
21307
21473
  emitProcessOutput as emitProcessOutput3,
21308
21474
  emitProcessStarted as emitProcessStarted3
21309
21475
  } from "@wrongstack/core/observability";
21310
- import { toErrorMessage as toErrorMessage12 } from "@wrongstack/core/utils/error";
21476
+ import { toErrorMessage as toErrorMessage13 } from "@wrongstack/core/utils/error";
21311
21477
  init_output_spool();
21312
21478
  init_util();
21313
21479
  init_win32_resolve();
21314
21480
 
21315
21481
  // src/exec-kill-guard.ts
21316
21482
  import * as os8 from "node:os";
21317
- import * as path38 from "node:path";
21483
+ import * as path39 from "node:path";
21318
21484
  var isWin3 = os8.platform() === "win32";
21319
21485
  async function checkExecKillCommand(cmd, args) {
21320
21486
  if (!cmd) return { blocked: false };
@@ -21531,7 +21697,7 @@ async function checkKillTarget(target) {
21531
21697
  reason: `Blocked: kill ${target.signal} '${target.name}' targets a WrongStack process name.`
21532
21698
  };
21533
21699
  }
21534
- const currentImage = path38.basename(process.execPath).toLowerCase().replace(/\.exe$/, "");
21700
+ const currentImage = path39.basename(process.execPath).toLowerCase().replace(/\.exe$/, "");
21535
21701
  const targetsNodeRuntime = nameLower === "node" || nameLower.startsWith("node");
21536
21702
  if (targetsNodeRuntime && currentImage === "node") {
21537
21703
  return {
@@ -22445,7 +22611,7 @@ var execTool = {
22445
22611
  }
22446
22612
  };
22447
22613
  function runCommand(cmd, args, cwd, timeout, signal, sessionId, danger) {
22448
- return new Promise((resolve23) => {
22614
+ return new Promise((resolve24) => {
22449
22615
  let stdout = "";
22450
22616
  let stderr = "";
22451
22617
  let killed = false;
@@ -22453,7 +22619,7 @@ function runCommand(cmd, args, cwd, timeout, signal, sessionId, danger) {
22453
22619
  const finish = (result) => {
22454
22620
  if (resolvedOnce.value) return;
22455
22621
  resolvedOnce.value = true;
22456
- resolve23(result);
22622
+ resolve24(result);
22457
22623
  };
22458
22624
  const startedAt = Date.now();
22459
22625
  let stdoutBytes = 0;
@@ -22505,7 +22671,7 @@ function runCommand(cmd, args, cwd, timeout, signal, sessionId, danger) {
22505
22671
  command: cmd,
22506
22672
  args,
22507
22673
  stdout: "",
22508
- stderr: `spawn failed: ${toErrorMessage12(err)}`,
22674
+ stderr: `spawn failed: ${toErrorMessage13(err)}`,
22509
22675
  exitCode: 1,
22510
22676
  truncated: false,
22511
22677
  allowed: true,
@@ -23129,10 +23295,10 @@ function parseFormatterCounts(fixer, output) {
23129
23295
  };
23130
23296
  }
23131
23297
  async function detectFixer(cwd) {
23132
- const fs43 = await import("node:fs/promises");
23298
+ const fs44 = await import("node:fs/promises");
23133
23299
  const exists = async (file) => {
23134
23300
  try {
23135
- await fs43.stat(`${cwd}/${file}`);
23301
+ await fs44.stat(`${cwd}/${file}`);
23136
23302
  return true;
23137
23303
  } catch {
23138
23304
  return false;
@@ -23155,7 +23321,7 @@ async function detectFixer(cwd) {
23155
23321
  if (await exists(cfg)) return "prettier";
23156
23322
  }
23157
23323
  try {
23158
- const raw = await fs43.readFile(`${cwd}/package.json`, "utf8");
23324
+ const raw = await fs44.readFile(`${cwd}/package.json`, "utf8");
23159
23325
  const pkg = JSON.parse(raw);
23160
23326
  if (pkg["prettier"] !== void 0) return "prettier";
23161
23327
  } catch {
@@ -23167,7 +23333,7 @@ async function detectFixer(cwd) {
23167
23333
  init_util();
23168
23334
  import { spawn as spawn9 } from "node:child_process";
23169
23335
  import { statSync as statSync4 } from "node:fs";
23170
- import { dirname as dirname13, resolve as resolve18, sep as sep6 } from "node:path";
23336
+ import { dirname as dirname13, resolve as resolve19, sep as sep6 } from "node:path";
23171
23337
  import { assessCommitSafety } from "@wrongstack/core/coordination";
23172
23338
  import { buildChildEnv as buildChildEnv4 } from "@wrongstack/core/utils";
23173
23339
  var TIMEOUT_MS2 = 3e4;
@@ -23328,8 +23494,8 @@ function validateWorktreeInput(input, projectRoot) {
23328
23494
  return reject(`unsafe worktree path: ${input.worktreePath}`);
23329
23495
  }
23330
23496
  if ((input.worktreeAction === "add" || input.worktreeAction === "remove") && input.worktreePath) {
23331
- const root = resolve18(projectRoot);
23332
- const abs = resolve18(root, input.worktreePath);
23497
+ const root = resolve19(projectRoot);
23498
+ const abs = resolve19(root, input.worktreePath);
23333
23499
  if (abs !== root && !abs.startsWith(root + sep6)) {
23334
23500
  return reject(`unsafe worktree path (escapes project root): ${input.worktreePath}`);
23335
23501
  }
@@ -23423,7 +23589,7 @@ function buildArgs(input) {
23423
23589
  }
23424
23590
  }
23425
23591
  function runGit2(args, cwd, signal) {
23426
- return new Promise((resolve23) => {
23592
+ return new Promise((resolve24) => {
23427
23593
  let stdout = "";
23428
23594
  let stderr = "";
23429
23595
  const child = spawn9("git", args, {
@@ -23444,7 +23610,7 @@ function runGit2(args, cwd, signal) {
23444
23610
  }
23445
23611
  });
23446
23612
  child.on("error", (err) => {
23447
- resolve23({
23613
+ resolve24({
23448
23614
  command: args[0],
23449
23615
  stdout: normalizeCommandOutput(stdout),
23450
23616
  stderr: err.message,
@@ -23453,7 +23619,7 @@ function runGit2(args, cwd, signal) {
23453
23619
  });
23454
23620
  });
23455
23621
  child.on("close", (code) => {
23456
- resolve23({
23622
+ resolve24({
23457
23623
  command: args[0],
23458
23624
  stdout: normalizeCommandOutput(stdout),
23459
23625
  stderr: normalizeCommandOutput(stderr),
@@ -23465,8 +23631,8 @@ function runGit2(args, cwd, signal) {
23465
23631
  }
23466
23632
 
23467
23633
  // src/glob.ts
23468
- import * as fs31 from "node:fs/promises";
23469
- import * as path39 from "node:path";
23634
+ import * as fs32 from "node:fs/promises";
23635
+ import * as path40 from "node:path";
23470
23636
  import { compileGlob as compileGlob2, DEFAULT_WALK_IGNORE_DIRS as DEFAULT_WALK_IGNORE_DIRS2 } from "@wrongstack/core/utils";
23471
23637
  import { ToolValidationError as ToolValidationError6 } from "@wrongstack/core/types";
23472
23638
 
@@ -23546,7 +23712,7 @@ var globTool = {
23546
23712
  return;
23547
23713
  }
23548
23714
  try {
23549
- const st = await fs31.stat(full);
23715
+ const st = await fs32.stat(full);
23550
23716
  if (truncated || results.length >= limit) {
23551
23717
  truncated = true;
23552
23718
  return;
@@ -23567,7 +23733,7 @@ var globTool = {
23567
23733
  }
23568
23734
  let entries;
23569
23735
  try {
23570
- entries = await fs31.readdir(dir, { withFileTypes: true });
23736
+ entries = await fs32.readdir(dir, { withFileTypes: true });
23571
23737
  } catch {
23572
23738
  return;
23573
23739
  }
@@ -23577,7 +23743,7 @@ var globTool = {
23577
23743
  const name = e.name;
23578
23744
  if (DEFAULT_IGNORE2.has(name)) continue;
23579
23745
  const rel = relPrefix ? `${relPrefix}/${name}` : name;
23580
- const full = path39.join(dir, name);
23746
+ const full = path40.join(dir, name);
23581
23747
  if (e.isDirectory()) {
23582
23748
  if (isGitIgnored(rel, true)) continue;
23583
23749
  subdirs.push({ full, rel });
@@ -23592,15 +23758,15 @@ var globTool = {
23592
23758
  }
23593
23759
  } else if (e.isSymbolicLink()) {
23594
23760
  try {
23595
- const st = await fs31.stat(full);
23761
+ const st = await fs32.stat(full);
23596
23762
  if (st.isDirectory()) {
23597
23763
  if (isGitIgnored(rel, true)) continue;
23598
- const real = await fs31.realpath(full);
23764
+ const real = await fs32.realpath(full);
23599
23765
  await assertRealInsideRoot(real, ctx);
23600
23766
  subdirs.push({ full, rel });
23601
23767
  } else if (st.isFile()) {
23602
23768
  if (isGitIgnored(rel, false)) continue;
23603
- const real = await fs31.realpath(full);
23769
+ const real = await fs32.realpath(full);
23604
23770
  await assertRealInsideRoot(real, ctx);
23605
23771
  re.lastIndex = 0;
23606
23772
  const relMatch = re.test(rel);
@@ -23630,8 +23796,8 @@ var globTool = {
23630
23796
 
23631
23797
  // src/grep.ts
23632
23798
  import { spawn as spawn10 } from "node:child_process";
23633
- import * as fs32 from "node:fs/promises";
23634
- import * as path40 from "node:path";
23799
+ import * as fs33 from "node:fs/promises";
23800
+ import * as path41 from "node:path";
23635
23801
  import { ToolValidationError as ToolValidationError7 } from "@wrongstack/core/types";
23636
23802
  import {
23637
23803
  buildChildEnv as buildChildEnv5,
@@ -23866,7 +24032,7 @@ var grepTool = {
23866
24032
  };
23867
24033
  var rgAvailabilityCache;
23868
24034
  function detectRg() {
23869
- rgAvailabilityCache ??= new Promise((resolve23) => {
24035
+ rgAvailabilityCache ??= new Promise((resolve24) => {
23870
24036
  try {
23871
24037
  const p = spawn10("rg", ["--version"], {
23872
24038
  env: buildChildEnv5(),
@@ -23874,10 +24040,10 @@ function detectRg() {
23874
24040
  signal: AbortSignal.timeout(1e4),
23875
24041
  windowsHide: true
23876
24042
  });
23877
- p.on("error", () => resolve23(false));
23878
- p.on("close", (code) => resolve23(code === 0));
24043
+ p.on("error", () => resolve24(false));
24044
+ p.on("close", (code) => resolve24(code === 0));
23879
24045
  } catch {
23880
- resolve23(false);
24046
+ resolve24(false);
23881
24047
  }
23882
24048
  });
23883
24049
  return rgAvailabilityCache;
@@ -23894,8 +24060,8 @@ async function* runRgStream(input, base, mode, limit, signal) {
23894
24060
  for (const ignored of DEFAULT_IGNORE3) {
23895
24061
  args.push("--glob", `!${ignored}/**`, "--glob", `!**/${ignored}/**`);
23896
24062
  }
23897
- const gitignorePath = path40.join(base, ".gitignore");
23898
- if (await fs32.access(gitignorePath).then(
24063
+ const gitignorePath = path41.join(base, ".gitignore");
24064
+ if (await fs33.access(gitignorePath).then(
23899
24065
  () => true,
23900
24066
  () => false
23901
24067
  )) {
@@ -24085,9 +24251,9 @@ async function runNative(input, base, mode, limit, signal) {
24085
24251
  if (globRe && !globRe.test(name) && !globRe.test(full)) return;
24086
24252
  if (globRe) globRe.lastIndex = 0;
24087
24253
  try {
24088
- const stat22 = await fs32.stat(full);
24254
+ const stat22 = await fs33.stat(full);
24089
24255
  if (!stat22.isFile() || stat22.size > maxBytes || stopped || signal.aborted) return;
24090
- const file = await fs32.open(full, "r");
24256
+ const file = await fs33.open(full, "r");
24091
24257
  try {
24092
24258
  let bytesReadTotal = 0;
24093
24259
  let lineNumber = 0;
@@ -24172,7 +24338,7 @@ async function runNative(input, base, mode, limit, signal) {
24172
24338
  if (stopped || signal.aborted) return;
24173
24339
  let entries;
24174
24340
  try {
24175
- entries = await fs32.readdir(dir, { withFileTypes: true });
24341
+ entries = await fs33.readdir(dir, { withFileTypes: true });
24176
24342
  } catch {
24177
24343
  return;
24178
24344
  }
@@ -24183,7 +24349,7 @@ async function runNative(input, base, mode, limit, signal) {
24183
24349
  if (DEFAULT_IGNORE3.has(e.name)) continue;
24184
24350
  if (e.isSymbolicLink()) continue;
24185
24351
  const rel = relPrefix ? `${relPrefix}/${e.name}` : e.name;
24186
- const full = path40.join(dir, e.name);
24352
+ const full = path41.join(dir, e.name);
24187
24353
  if (e.isDirectory()) {
24188
24354
  if (isGitIgnored(rel, true)) continue;
24189
24355
  subdirs.push({ full, rel });
@@ -24423,7 +24589,7 @@ function resolveManifestPath(cwd, pkgManager) {
24423
24589
  }
24424
24590
 
24425
24591
  // src/json.ts
24426
- import * as fs33 from "node:fs/promises";
24592
+ import * as fs34 from "node:fs/promises";
24427
24593
  import { deepMerge as deepMergeCore } from "@wrongstack/core/utils";
24428
24594
  init_util();
24429
24595
  var MAX_JSON_FILE_BYTES = 16 * 1024 * 1024;
@@ -24438,11 +24604,11 @@ var JsonFileTooLargeError = class extends Error {
24438
24604
  };
24439
24605
  async function readJsonFileBounded(filePath, ctx) {
24440
24606
  const resolved = await safeResolveReal(filePath, ctx);
24441
- const stat22 = await fs33.stat(resolved);
24607
+ const stat22 = await fs34.stat(resolved);
24442
24608
  if (stat22.size > MAX_JSON_FILE_BYTES) {
24443
24609
  throw new JsonFileTooLargeError(filePath, stat22.size);
24444
24610
  }
24445
- return fs33.readFile(resolved, "utf8");
24611
+ return fs34.readFile(resolved, "utf8");
24446
24612
  }
24447
24613
  var jsonTool = {
24448
24614
  name: "json",
@@ -24919,60 +25085,60 @@ function jmespathSearch(data, query) {
24919
25085
  }
24920
25086
  function validateJsonSchema(data, schema) {
24921
25087
  const errors = [];
24922
- function check(value, s, path49) {
25088
+ function check(value, s, path50) {
24923
25089
  if (s["type"]) {
24924
25090
  const expectedType = s["type"];
24925
25091
  const actualType = Array.isArray(value) ? "array" : value === null ? "null" : typeof value;
24926
25092
  if (expectedType === "integer") {
24927
- if (!Number.isInteger(value)) errors.push(`${path49}: expected integer, got ${actualType}`);
25093
+ if (!Number.isInteger(value)) errors.push(`${path50}: expected integer, got ${actualType}`);
24928
25094
  } else if (expectedType !== actualType) {
24929
- errors.push(`${path49}: expected ${expectedType}, got ${actualType}`);
25095
+ errors.push(`${path50}: expected ${expectedType}, got ${actualType}`);
24930
25096
  }
24931
25097
  }
24932
25098
  if (typeof value === "string" && s["format"] === "uri" && value) {
24933
25099
  try {
24934
25100
  new URL(value);
24935
25101
  } catch {
24936
- errors.push(`${path49}: not a valid URI`);
25102
+ errors.push(`${path50}: not a valid URI`);
24937
25103
  }
24938
25104
  }
24939
25105
  if (typeof value === "string" && s["pattern"]) {
24940
25106
  const compiled = compileUserRegex(s["pattern"], "");
24941
25107
  if (!compiled.ok) {
24942
- errors.push(`${path49}: invalid schema pattern \u2014 ${compiled.reason}`);
25108
+ errors.push(`${path50}: invalid schema pattern \u2014 ${compiled.reason}`);
24943
25109
  } else if (!compiled.regex.test(capSubject(value))) {
24944
- errors.push(`${path49}: does not match pattern ${s["pattern"]}`);
25110
+ errors.push(`${path50}: does not match pattern ${s["pattern"]}`);
24945
25111
  }
24946
25112
  }
24947
25113
  if (typeof value === "string" && s["minLength"] !== void 0 && value.length < s["minLength"]) {
24948
- errors.push(`${path49}: string too short (min ${s["minLength"]})`);
25114
+ errors.push(`${path50}: string too short (min ${s["minLength"]})`);
24949
25115
  }
24950
25116
  if (typeof value === "string" && s["maxLength"] !== void 0 && value.length > s["maxLength"]) {
24951
- errors.push(`${path49}: string too long (max ${s["maxLength"]})`);
25117
+ errors.push(`${path50}: string too long (max ${s["maxLength"]})`);
24952
25118
  }
24953
25119
  if (typeof value === "number" && s["minimum"] !== void 0 && value < s["minimum"]) {
24954
- errors.push(`${path49}: below minimum ${s["minimum"]}`);
25120
+ errors.push(`${path50}: below minimum ${s["minimum"]}`);
24955
25121
  }
24956
25122
  if (typeof value === "number" && s["maximum"] !== void 0 && value > s["maximum"]) {
24957
- errors.push(`${path49}: above maximum ${s["maximum"]}`);
25123
+ errors.push(`${path50}: above maximum ${s["maximum"]}`);
24958
25124
  }
24959
25125
  if (Array.isArray(value) && s["items"] && Array.isArray(s["items"])) {
24960
25126
  for (let i = 0; i < value.length; i++) {
24961
- check(value[i], s["items"], `${path49}[${i}]`);
25127
+ check(value[i], s["items"], `${path50}[${i}]`);
24962
25128
  }
24963
25129
  }
24964
25130
  if (typeof value === "object" && value !== null && !Array.isArray(value) && s["properties"]) {
24965
25131
  const props = s["properties"];
24966
25132
  for (const [k, propSchema] of Object.entries(props)) {
24967
- check(value[k], propSchema, `${path49}.${k}`);
25133
+ check(value[k], propSchema, `${path50}.${k}`);
24968
25134
  }
24969
25135
  }
24970
25136
  }
24971
25137
  check(data, schema, "$");
24972
25138
  return { valid: errors.length === 0, errors };
24973
25139
  }
24974
- function simpleQuery(data, path49) {
24975
- const parts = path49.replace(/\[(\d+)\]/g, ".$1").split(".").filter(Boolean);
25140
+ function simpleQuery(data, path50) {
25141
+ const parts = path50.replace(/\[(\d+)\]/g, ".$1").split(".").filter(Boolean);
24976
25142
  let current = data;
24977
25143
  for (const part of parts) {
24978
25144
  if (current === null || current === void 0) return void 0;
@@ -28084,7 +28250,7 @@ async function dockerLogs(service, lines, filterRe, cwd, signal, since) {
28084
28250
  };
28085
28251
  }
28086
28252
  args.push("--timestamps", service);
28087
- return new Promise((resolve23) => {
28253
+ return new Promise((resolve24) => {
28088
28254
  let stdout = "";
28089
28255
  let stderr = "";
28090
28256
  const MAX = 2e5;
@@ -28100,7 +28266,7 @@ async function dockerLogs(service, lines, filterRe, cwd, signal, since) {
28100
28266
  if (settled) return;
28101
28267
  settled = true;
28102
28268
  clearTimeout(timer);
28103
- resolve23(result);
28269
+ resolve24(result);
28104
28270
  };
28105
28271
  const child = spawn11("docker", args, {
28106
28272
  cwd,
@@ -28145,7 +28311,7 @@ async function dockerLogs(service, lines, filterRe, cwd, signal, since) {
28145
28311
  }
28146
28312
  var DOCKER_LOGS_TIMEOUT_MS = 3e3;
28147
28313
  var MAX_TAIL_LINES = 1e5;
28148
- async function fileLogs(path49, lines, filterRe) {
28314
+ async function fileLogs(path50, lines, filterRe) {
28149
28315
  const { createInterface } = await import("node:readline");
28150
28316
  const { createReadStream: createReadStream2 } = await import("node:fs");
28151
28317
  const entries = [];
@@ -28154,7 +28320,7 @@ async function fileLogs(path49, lines, filterRe) {
28154
28320
  let writeIdx = 0;
28155
28321
  let totalLines = 0;
28156
28322
  const rl = createInterface({
28157
- input: createReadStream2(path49),
28323
+ input: createReadStream2(path50),
28158
28324
  crlfDelay: Number.POSITIVE_INFINITY
28159
28325
  });
28160
28326
  for await (const line of rl) {
@@ -28175,7 +28341,7 @@ async function fileLogs(path49, lines, filterRe) {
28175
28341
  if (parsed) entries.push(parsed);
28176
28342
  }
28177
28343
  return {
28178
- source: path49,
28344
+ source: path50,
28179
28345
  entries,
28180
28346
  total: entries.length,
28181
28347
  truncated: totalLines > effLines,
@@ -28317,7 +28483,7 @@ var outdatedTool = {
28317
28483
  }
28318
28484
  };
28319
28485
  function runOutdated(manager, args, cwd, signal) {
28320
- return new Promise((resolve23) => {
28486
+ return new Promise((resolve24) => {
28321
28487
  let stdout = "";
28322
28488
  let stderr = "";
28323
28489
  const MAX = 1e5;
@@ -28342,10 +28508,10 @@ function runOutdated(manager, args, cwd, signal) {
28342
28508
  });
28343
28509
  child.on("close", (code) => {
28344
28510
  const result = parseOutdatedOutput(stdout, code ?? 0);
28345
- resolve23(result);
28511
+ resolve24(result);
28346
28512
  });
28347
28513
  child.on("error", (e) => {
28348
- resolve23({
28514
+ resolve24({
28349
28515
  exit_code: 1,
28350
28516
  packages: [],
28351
28517
  total: 0,
@@ -28405,10 +28571,10 @@ Note: exit code 1 from \`outdated\` means outdated packages were found (expected
28405
28571
  // src/patch.ts
28406
28572
  init_util();
28407
28573
  import { spawn as spawn13 } from "node:child_process";
28408
- import * as fs34 from "node:fs/promises";
28574
+ import * as fs35 from "node:fs/promises";
28409
28575
  import * as os9 from "node:os";
28410
- import * as path41 from "node:path";
28411
- import { buildChildEnv as buildChildEnv8, toErrorMessage as toErrorMessage13 } from "@wrongstack/core/utils";
28576
+ import * as path42 from "node:path";
28577
+ import { buildChildEnv as buildChildEnv8, toErrorMessage as toErrorMessage14 } from "@wrongstack/core/utils";
28412
28578
  var patchTool = {
28413
28579
  name: "patch",
28414
28580
  category: "Filesystem",
@@ -28452,26 +28618,26 @@ var patchTool = {
28452
28618
  try {
28453
28619
  dir = input.directory ? await safeResolveReal(input.directory, ctx) : ctx.cwd;
28454
28620
  } catch (err) {
28455
- return refuse(`patch refused: ${toErrorMessage13(err)}`);
28621
+ return refuse(`patch refused: ${toErrorMessage14(err)}`);
28456
28622
  }
28457
- const realRoot = await fs34.realpath(ctx.projectRoot).catch(() => path41.resolve(ctx.projectRoot));
28623
+ const realRoot = await fs35.realpath(ctx.projectRoot).catch(() => path42.resolve(ctx.projectRoot));
28458
28624
  const targets = extractDiffTargets(input.patch);
28459
28625
  const resolvedTargets = [];
28460
28626
  for (const t of targets) {
28461
28627
  const stripped = stripPathComponents(t.raw, strip);
28462
28628
  if (!stripped) continue;
28463
- if (path41.isAbsolute(stripped)) {
28629
+ if (path42.isAbsolute(stripped)) {
28464
28630
  return refuse(`patch refused: target "${t.raw}" strips to absolute path`);
28465
28631
  }
28466
- const candidate = path41.resolve(dir, stripped);
28632
+ const candidate = path42.resolve(dir, stripped);
28467
28633
  let real;
28468
28634
  try {
28469
28635
  real = await resolveRealInsideRoot(candidate, ctx);
28470
28636
  } catch (err) {
28471
- return refuse(`patch refused: target "${t.raw}" ${toErrorMessage13(err)}`);
28637
+ return refuse(`patch refused: target "${t.raw}" ${toErrorMessage14(err)}`);
28472
28638
  }
28473
- const rel = path41.relative(realRoot, real);
28474
- if (rel.startsWith("..") || path41.isAbsolute(rel)) {
28639
+ const rel = path42.relative(realRoot, real);
28640
+ if (rel.startsWith("..") || path42.isAbsolute(rel)) {
28475
28641
  return refuse(`patch refused: target "${t.raw}" resolves outside project root`);
28476
28642
  }
28477
28643
  resolvedTargets.push({ raw: t.raw, deleted: t.deleted, abs: real });
@@ -28480,17 +28646,17 @@ var patchTool = {
28480
28646
  const beforeExisted = /* @__PURE__ */ new Set();
28481
28647
  if (!dryRun) {
28482
28648
  for (const target of resolvedTargets) {
28483
- const existed = (await fs34.stat(target.abs).catch(() => null))?.isFile() ?? false;
28649
+ const existed = (await fs35.stat(target.abs).catch(() => null))?.isFile() ?? false;
28484
28650
  if (existed) beforeExisted.add(target.abs);
28485
28651
  beforeContents.set(target.abs, await readTextForTracking(target.abs));
28486
28652
  }
28487
28653
  }
28488
- const tmpDir = await fs34.mkdtemp(path41.join(os9.tmpdir(), ".wstack_patch_"));
28654
+ const tmpDir = await fs35.mkdtemp(path42.join(os9.tmpdir(), ".wstack_patch_"));
28489
28655
  try {
28490
- await fs34.chmod(tmpDir, 448).catch(() => {
28656
+ await fs35.chmod(tmpDir, 448).catch(() => {
28491
28657
  });
28492
- const patchFile = path41.join(tmpDir, "in.diff");
28493
- await fs34.writeFile(patchFile, input.patch, { mode: 384 });
28658
+ const patchFile = path42.join(tmpDir, "in.diff");
28659
+ await fs35.writeFile(patchFile, input.patch, { mode: 384 });
28494
28660
  const args = [`-p${strip}`, "--merge", ...dryRun ? ["--dry-run"] : [], "-i", patchFile];
28495
28661
  const result = await runPatch(args, dir, opts.signal, {
28496
28662
  patchFile,
@@ -28502,7 +28668,7 @@ var patchTool = {
28502
28668
  for (const target of resolvedTargets) {
28503
28669
  const abs = target.abs;
28504
28670
  const before = beforeContents.get(abs) ?? null;
28505
- const stat22 = await fs34.stat(abs).catch(() => null);
28671
+ const stat22 = await fs35.stat(abs).catch(() => null);
28506
28672
  if (!stat22?.isFile()) {
28507
28673
  if (beforeExisted.has(abs)) {
28508
28674
  touched.push(abs);
@@ -28535,7 +28701,7 @@ var patchTool = {
28535
28701
  }
28536
28702
  if (result.exitCode !== 0) {
28537
28703
  if (!dryRun) {
28538
- const partial = touched.length > 0 ? ` ${touched.length} file(s) were still modified on disk and have been recorded for rewind: ${touched.map((p) => path41.relative(realRoot, p) || p).join(", ")}.` : "";
28704
+ const partial = touched.length > 0 ? ` ${touched.length} file(s) were still modified on disk and have been recorded for rewind: ${touched.map((p) => path42.relative(realRoot, p) || p).join(", ")}.` : "";
28539
28705
  return {
28540
28706
  applied: touched.length,
28541
28707
  rejected: 1,
@@ -28543,7 +28709,7 @@ var patchTool = {
28543
28709
  // success path (which returns GNU patch's dir-relative names).
28544
28710
  // `touched` entries are realpaths from resolveRealInsideRoot, and
28545
28711
  // realRoot is also a realpath, so path.relative is like-for-like.
28546
- files: touched.map((p) => path41.relative(realRoot, p) || p),
28712
+ files: touched.map((p) => path42.relative(realRoot, p) || p),
28547
28713
  dry_run: dryRun,
28548
28714
  message: `patch failed: ${result.stderr || result.stdout}${partial}`
28549
28715
  };
@@ -28559,7 +28725,7 @@ var patchTool = {
28559
28725
  }
28560
28726
  const patched = result.engine === "git" ? [
28561
28727
  ...new Set(
28562
- resolvedTargets.map((target) => path41.relative(dir, target.abs) || target.abs)
28728
+ resolvedTargets.map((target) => path42.relative(dir, target.abs) || target.abs)
28563
28729
  )
28564
28730
  ] : extractPatchedFiles(result.stdout);
28565
28731
  return {
@@ -28570,7 +28736,7 @@ var patchTool = {
28570
28736
  message: result.stdout || "patch applied"
28571
28737
  };
28572
28738
  } finally {
28573
- await fs34.rm(tmpDir, { recursive: true, force: true }).catch(() => {
28739
+ await fs35.rm(tmpDir, { recursive: true, force: true }).catch(() => {
28574
28740
  });
28575
28741
  }
28576
28742
  }
@@ -28578,9 +28744,9 @@ var patchTool = {
28578
28744
  var MAX_TRACKING_BYTES = 5 * 1024 * 1024;
28579
28745
  async function readTextForTracking(absPath) {
28580
28746
  try {
28581
- const stat22 = await fs34.stat(absPath);
28747
+ const stat22 = await fs35.stat(absPath);
28582
28748
  if (!stat22.isFile() || stat22.size > MAX_TRACKING_BYTES) return null;
28583
- const buf = await fs34.readFile(absPath);
28749
+ const buf = await fs35.readFile(absPath);
28584
28750
  if (buf.includes(0)) return null;
28585
28751
  return buf.toString("utf8");
28586
28752
  } catch {
@@ -28664,7 +28830,7 @@ function runPatch(args, cwd, signal, fallback) {
28664
28830
  });
28665
28831
  }
28666
28832
  function runPatchProcess(command, args, cwd, signal) {
28667
- return new Promise((resolve23) => {
28833
+ return new Promise((resolve24) => {
28668
28834
  let stdout = "";
28669
28835
  let stderr = "";
28670
28836
  const env = { ...buildChildEnv8(), LANG: "C", LC_ALL: "C" };
@@ -28683,11 +28849,11 @@ function runPatchProcess(command, args, cwd, signal) {
28683
28849
  });
28684
28850
  child.on(
28685
28851
  "close",
28686
- (code) => resolve23({ exitCode: code ?? 1, stdout, stderr, unavailable: false })
28852
+ (code) => resolve24({ exitCode: code ?? 1, stdout, stderr, unavailable: false })
28687
28853
  );
28688
28854
  child.on(
28689
28855
  "error",
28690
- (e) => resolve23({
28856
+ (e) => resolve24({
28691
28857
  exitCode: 1,
28692
28858
  stdout: "",
28693
28859
  stderr: e.message,
@@ -29478,9 +29644,9 @@ function mkResult(plan, ok, message, todos) {
29478
29644
 
29479
29645
  // src/read.ts
29480
29646
  init_util();
29481
- import * as fs35 from "node:fs/promises";
29647
+ import * as fs36 from "node:fs/promises";
29482
29648
  import { FsError, ToolValidationError as ToolValidationError8 } from "@wrongstack/core/types";
29483
- import { toErrorMessage as toErrorMessage14 } from "@wrongstack/core/utils";
29649
+ import { toErrorMessage as toErrorMessage15 } from "@wrongstack/core/utils";
29484
29650
  var ADVANCED_MODE_META_KEY = "tools.read.advancedMode";
29485
29651
  var MAX_BYTES2 = 5 * 1024 * 1024;
29486
29652
  var readTool = {
@@ -29538,7 +29704,7 @@ var readTool = {
29538
29704
  const shouldIncludeSymbols = input.includeSymbols === true || input.includeSymbols !== false && ctx.meta[ADVANCED_MODE_META_KEY] === true;
29539
29705
  let stat22;
29540
29706
  try {
29541
- stat22 = await fs35.stat(absPath);
29707
+ stat22 = await fs36.stat(absPath);
29542
29708
  } catch (err) {
29543
29709
  const code = err.code;
29544
29710
  if (code === "ENOENT") {
@@ -29550,7 +29716,7 @@ var readTool = {
29550
29716
  });
29551
29717
  }
29552
29718
  throw new FsError({
29553
- message: `read: failed to stat "${input.path}": ${toErrorMessage14(err)}`,
29719
+ message: `read: failed to stat "${input.path}": ${toErrorMessage15(err)}`,
29554
29720
  code: "FS_READ_FAILED",
29555
29721
  path: absPath,
29556
29722
  context: { errno: code },
@@ -29590,7 +29756,7 @@ var readTool = {
29590
29756
  ...symResult2?.symbols ? { symbols: symResult2.symbols } : {}
29591
29757
  };
29592
29758
  }
29593
- const buf = await fs35.readFile(absPath);
29759
+ const buf = await fs36.readFile(absPath);
29594
29760
  if (isBinaryBuffer(buf)) {
29595
29761
  throw new FsError({
29596
29762
  message: `read: "${input.path}" appears to be binary`,
@@ -29757,8 +29923,8 @@ ${interesting.join("\n")}` : "symbols/imports: (none detected)"
29757
29923
 
29758
29924
  // src/replace.ts
29759
29925
  import { spawn as spawn14 } from "node:child_process";
29760
- import * as fs36 from "node:fs/promises";
29761
- import * as path42 from "node:path";
29926
+ import * as fs37 from "node:fs/promises";
29927
+ import * as path43 from "node:path";
29762
29928
  import { ToolValidationError as ToolValidationError9 } from "@wrongstack/core/types";
29763
29929
  import {
29764
29930
  atomicWrite as atomicWrite4,
@@ -29841,14 +30007,14 @@ var replaceTool = {
29841
30007
  const dryRun = input.dry_run ?? true;
29842
30008
  const filesInput = Array.isArray(input.files) ? input.files.join(",") : input.files;
29843
30009
  const fileList = await resolveFiles2(filesInput, ctx, globRe);
29844
- const realRoot = await fs36.realpath(ctx.projectRoot).catch(() => ctx.projectRoot);
30010
+ const realRoot = await fs37.realpath(ctx.projectRoot).catch(() => ctx.projectRoot);
29845
30011
  const results = [];
29846
30012
  let totalReplacements = 0;
29847
30013
  let diffBytesUsed = 0;
29848
30014
  let diffsOmitted = 0;
29849
30015
  let diffsTruncated = 0;
29850
30016
  for (const absPath of fileList) {
29851
- const lstat2 = await fs36.lstat(absPath).catch((err) => {
30017
+ const lstat2 = await fs37.lstat(absPath).catch((err) => {
29852
30018
  if (err.code === "ENOENT") return null;
29853
30019
  throw err;
29854
30020
  });
@@ -29856,17 +30022,17 @@ var replaceTool = {
29856
30022
  if (lstat2.isSymbolicLink()) continue;
29857
30023
  let realPath;
29858
30024
  try {
29859
- realPath = await fs36.realpath(absPath);
30025
+ realPath = await fs37.realpath(absPath);
29860
30026
  } catch {
29861
30027
  continue;
29862
30028
  }
29863
- const rel = path42.relative(realRoot, realPath);
29864
- if (rel.startsWith("..") || path42.isAbsolute(rel)) continue;
29865
- const stat22 = await fs36.stat(realPath).catch(() => null);
30029
+ const rel = path43.relative(realRoot, realPath);
30030
+ if (rel.startsWith("..") || path43.isAbsolute(rel)) continue;
30031
+ const stat22 = await fs37.stat(realPath).catch(() => null);
29866
30032
  if (!stat22?.isFile()) continue;
29867
30033
  let content;
29868
30034
  try {
29869
- const buf = await fs36.readFile(realPath);
30035
+ const buf = await fs37.readFile(realPath);
29870
30036
  if (isBinaryBuffer(buf)) continue;
29871
30037
  content = buf.toString("utf8");
29872
30038
  } catch {
@@ -29889,7 +30055,7 @@ var replaceTool = {
29889
30055
  if (!dryRun) {
29890
30056
  const newContent = toStyle2(newContentLf, style);
29891
30057
  await atomicWrite4(realPath, newContent, { mode: stat22.mode & 511 });
29892
- const written = await fs36.stat(realPath).catch(() => null);
30058
+ const written = await fs37.stat(realPath).catch(() => null);
29893
30059
  if (written) {
29894
30060
  ctx.recordRead?.(realPath, written.mtimeMs, "write", sha256hex(newContent));
29895
30061
  }
@@ -29989,8 +30155,8 @@ async function resolveFiles2(filesInput, ctx, extraGlob) {
29989
30155
  const resolved = [];
29990
30156
  for (const p of parts) {
29991
30157
  const absPath = await safeResolveReal(p, ctx);
29992
- if (extraGlob && !passesExtraGlob(extraGlob, path42.basename(absPath), absPath)) continue;
29993
- const stat22 = await fs36.stat(absPath).catch(() => null);
30158
+ if (extraGlob && !passesExtraGlob(extraGlob, path43.basename(absPath), absPath)) continue;
30159
+ const stat22 = await fs37.stat(absPath).catch(() => null);
29994
30160
  if (stat22?.isFile()) {
29995
30161
  resolved.push(absPath);
29996
30162
  }
@@ -30004,7 +30170,7 @@ async function globFiles(pattern, base, extraGlob) {
30004
30170
  const { promise } = spawnRgFind(pattern, base);
30005
30171
  const files = await promise;
30006
30172
  if (extraGlob) {
30007
- return files.filter((f) => passesExtraGlob(extraGlob, path42.basename(f), f));
30173
+ return files.filter((f) => passesExtraGlob(extraGlob, path43.basename(f), f));
30008
30174
  }
30009
30175
  return files;
30010
30176
  } catch {
@@ -30014,17 +30180,17 @@ async function globFiles(pattern, base, extraGlob) {
30014
30180
  }
30015
30181
  var rgAvailabilityCache2;
30016
30182
  function checkRg() {
30017
- rgAvailabilityCache2 ??= new Promise((resolve23) => {
30183
+ rgAvailabilityCache2 ??= new Promise((resolve24) => {
30018
30184
  try {
30019
30185
  const p = spawn14("rg", ["--version"], {
30020
30186
  env: buildChildEnv9(),
30021
30187
  stdio: "ignore",
30022
30188
  windowsHide: true
30023
30189
  });
30024
- p.on("error", () => resolve23(false));
30025
- p.on("close", (code) => resolve23(code === 0));
30190
+ p.on("error", () => resolve24(false));
30191
+ p.on("close", (code) => resolve24(code === 0));
30026
30192
  } catch {
30027
- resolve23(false);
30193
+ resolve24(false);
30028
30194
  }
30029
30195
  });
30030
30196
  return rgAvailabilityCache2;
@@ -30050,10 +30216,10 @@ function spawnRgFind(pattern, base) {
30050
30216
  }
30051
30217
  });
30052
30218
  return {
30053
- promise: new Promise((resolve23, reject) => {
30219
+ promise: new Promise((resolve24, reject) => {
30054
30220
  child.on("error", reject);
30055
30221
  child.on("close", () => {
30056
- resolve23(buf.split("\n").filter(Boolean));
30222
+ resolve24(buf.split("\n").filter(Boolean));
30057
30223
  });
30058
30224
  })
30059
30225
  };
@@ -30064,15 +30230,15 @@ async function globNative(pattern, base, extraGlob) {
30064
30230
  const walk2 = async (dir) => {
30065
30231
  let entries;
30066
30232
  try {
30067
- entries = await fs36.readdir(dir, { withFileTypes: true });
30233
+ entries = await fs37.readdir(dir, { withFileTypes: true });
30068
30234
  } catch {
30069
30235
  return;
30070
30236
  }
30071
30237
  for (const e of entries) {
30072
30238
  if (DEFAULT_IGNORE4.includes(e.name)) continue;
30073
- const full = path42.join(dir, e.name);
30239
+ const full = path43.join(dir, e.name);
30074
30240
  try {
30075
- const stat22 = await fs36.lstat(full);
30241
+ const stat22 = await fs37.lstat(full);
30076
30242
  if (stat22.isSymbolicLink()) continue;
30077
30243
  } catch {
30078
30244
  continue;
@@ -30096,8 +30262,8 @@ async function globNative(pattern, base, extraGlob) {
30096
30262
 
30097
30263
  // src/scaffold.ts
30098
30264
  init_util();
30099
- import * as fs37 from "node:fs/promises";
30100
- import * as path43 from "node:path";
30265
+ import * as fs38 from "node:fs/promises";
30266
+ import * as path44 from "node:path";
30101
30267
  import { atomicWrite as atomicWrite5 } from "@wrongstack/core/utils";
30102
30268
  var BUILT_IN_TEMPLATES = {
30103
30269
  "npm-package": {
@@ -30248,16 +30414,16 @@ async function handleBuiltIn(name, templateFiles, cwd, ctx, dryRun, vars) {
30248
30414
  let filesCreated = 0;
30249
30415
  for (const [filePath, content] of Object.entries(templateFiles)) {
30250
30416
  const resolvedPath = substituteVars(filePath, name, vars);
30251
- const joinedPath = path43.join(cwd, resolvedPath);
30252
- const root = path43.resolve(ctx.projectRoot);
30253
- const target = path43.resolve(joinedPath);
30254
- const rel = path43.relative(root, target);
30255
- if (rel.startsWith("..") || path43.isAbsolute(rel)) {
30417
+ const joinedPath = path44.join(cwd, resolvedPath);
30418
+ const root = path44.resolve(ctx.projectRoot);
30419
+ const target = path44.resolve(joinedPath);
30420
+ const rel = path44.relative(root, target);
30421
+ if (rel.startsWith("..") || path44.isAbsolute(rel)) {
30256
30422
  throw new Error(`scaffold: generated path "${resolvedPath}" would escape project root`);
30257
30423
  }
30258
30424
  const fullPath = target;
30259
30425
  if (!dryRun) {
30260
- await fs37.mkdir(path43.dirname(fullPath), { recursive: true });
30426
+ await fs38.mkdir(path44.dirname(fullPath), { recursive: true });
30261
30427
  await atomicWrite5(fullPath, substituteVars(content, name, vars));
30262
30428
  }
30263
30429
  files.push(resolvedPath);
@@ -30290,7 +30456,7 @@ function substituteVars(content, name, vars) {
30290
30456
  // src/search.ts
30291
30457
  import { FetchError as FetchError3, ToolValidationError as ToolValidationError10 } from "@wrongstack/core/types";
30292
30458
  import { expectDefined as expectDefined9 } from "@wrongstack/core/utils";
30293
- import { toErrorMessage as toErrorMessage15 } from "@wrongstack/core/utils";
30459
+ import { toErrorMessage as toErrorMessage16 } from "@wrongstack/core/utils";
30294
30460
  var DEFAULT_NUM = 10;
30295
30461
  var MAX_RESULTS = 50;
30296
30462
  var MAX_SNIPPET_CHARS = 300;
@@ -30500,9 +30666,9 @@ async function duckduckgoSearch(query, signal) {
30500
30666
  return { results: parseDuckDuckGo(html, MAX_RESULTS) };
30501
30667
  } catch (err) {
30502
30668
  console.log(
30503
- JSON.stringify({ level: "debug", event: "search_failed", query, error: toErrorMessage15(err) })
30669
+ JSON.stringify({ level: "debug", event: "search_failed", query, error: toErrorMessage16(err) })
30504
30670
  );
30505
- return { results: [], error: `duckduckgo unreachable: ${toErrorMessage15(err)}` };
30671
+ return { results: [], error: `duckduckgo unreachable: ${toErrorMessage16(err)}` };
30506
30672
  }
30507
30673
  }
30508
30674
  function takeFrom(iter, max) {
@@ -30568,7 +30734,7 @@ async function googleSearch(query, signal) {
30568
30734
  const html = await fetchWithTimeout(url, signal, TIMEOUT_MS3).then((r) => r.text());
30569
30735
  return { results: parseGoogleResults(html, MAX_RESULTS) };
30570
30736
  } catch (err) {
30571
- return { results: [], error: `google unreachable: ${toErrorMessage15(err)}` };
30737
+ return { results: [], error: `google unreachable: ${toErrorMessage16(err)}` };
30572
30738
  }
30573
30739
  }
30574
30740
  function parseGoogleResults(html, num) {
@@ -30605,7 +30771,7 @@ async function bingSearch(query, signal) {
30605
30771
  const html = await fetchWithTimeout(url, signal, TIMEOUT_MS3).then((r) => r.text());
30606
30772
  return { results: parseBingResults(html, MAX_RESULTS) };
30607
30773
  } catch (err) {
30608
- return { results: [], error: `bing unreachable: ${toErrorMessage15(err)}` };
30774
+ return { results: [], error: `bing unreachable: ${toErrorMessage16(err)}` };
30609
30775
  }
30610
30776
  }
30611
30777
  function parseBingResults(html, num) {
@@ -30703,9 +30869,9 @@ function decodeHtmlEntities(text) {
30703
30869
  }
30704
30870
 
30705
30871
  // src/security-ast-scan-tool.ts
30706
- import * as fs38 from "node:fs/promises";
30707
- import * as path44 from "node:path";
30708
- import { toErrorMessage as toErrorMessage16 } from "@wrongstack/core/utils";
30872
+ import * as fs39 from "node:fs/promises";
30873
+ import * as path45 from "node:path";
30874
+ import { toErrorMessage as toErrorMessage17 } from "@wrongstack/core/utils";
30709
30875
  var SECRET_PATTERNS = [
30710
30876
  { name: "AWS Access Key", regex: /\b(AKIA[0-9A-Z]{16})\b/ },
30711
30877
  { name: "GitHub Token", regex: /\b(gh[pousr]_[A-Za-z0-9_]{36,255})\b/ },
@@ -30871,9 +31037,9 @@ var securityAstScanTool = {
30871
31037
  let targetFile = input.file ?? "inline-code.ts";
30872
31038
  let content = input.content;
30873
31039
  if (!content && input.file) {
30874
- const absPath = path44.isAbsolute(input.file) ? input.file : path44.resolve(projectRoot, input.file);
30875
- targetFile = path44.relative(projectRoot, absPath).replace(/\\/g, "/");
30876
- content = await fs38.readFile(absPath, "utf8");
31040
+ const absPath = path45.isAbsolute(input.file) ? input.file : path45.resolve(projectRoot, input.file);
31041
+ targetFile = path45.relative(projectRoot, absPath).replace(/\\/g, "/");
31042
+ content = await fs39.readFile(absPath, "utf8");
30877
31043
  }
30878
31044
  if (!content) {
30879
31045
  return {
@@ -30914,15 +31080,15 @@ var securityAstScanTool = {
30914
31080
  warningCount: 0,
30915
31081
  findings: [],
30916
31082
  summary: "",
30917
- error: toErrorMessage16(err)
31083
+ error: toErrorMessage17(err)
30918
31084
  };
30919
31085
  }
30920
31086
  }
30921
31087
  };
30922
31088
 
30923
31089
  // src/set-working-dir.ts
30924
- import * as fs39 from "node:fs/promises";
30925
- import { toErrorMessage as toErrorMessage17 } from "@wrongstack/core/utils";
31090
+ import * as fs40 from "node:fs/promises";
31091
+ import { toErrorMessage as toErrorMessage18 } from "@wrongstack/core/utils";
30926
31092
  var setWorkingDirTool = {
30927
31093
  name: "set_working_dir",
30928
31094
  category: "Context",
@@ -30956,12 +31122,12 @@ var setWorkingDirTool = {
30956
31122
  } catch (err) {
30957
31123
  return {
30958
31124
  current: ctx.workingDir,
30959
- error: toErrorMessage17(err)
31125
+ error: toErrorMessage18(err)
30960
31126
  };
30961
31127
  }
30962
31128
  let isDirectory = false;
30963
31129
  try {
30964
- isDirectory = (await fs39.stat(resolved)).isDirectory();
31130
+ isDirectory = (await fs40.stat(resolved)).isDirectory();
30965
31131
  } catch {
30966
31132
  isDirectory = false;
30967
31133
  }
@@ -31496,7 +31662,7 @@ ${formatTaskList2(file.tasks)}` : file.tasks.length > 0 ? formatTaskList2(file.t
31496
31662
  init_spawn_stream();
31497
31663
  init_util();
31498
31664
  init_legacy_bridge();
31499
- import * as path45 from "node:path";
31665
+ import * as path46 from "node:path";
31500
31666
  var testTool = {
31501
31667
  name: "test",
31502
31668
  category: "Code Quality",
@@ -31603,7 +31769,7 @@ async function detectRunner(cwd) {
31603
31769
  const candidates = ["vitest.config.ts", "jest.config.js", ".mocharc.json"];
31604
31770
  for (const f of candidates) {
31605
31771
  try {
31606
- await stat22(path45.join(cwd, f));
31772
+ await stat22(path46.join(cwd, f));
31607
31773
  if (f.includes("vitest")) return "vitest";
31608
31774
  if (f.includes("jest")) return "jest";
31609
31775
  if (f.includes("mocha")) return "mocha";
@@ -31980,8 +32146,8 @@ var toolUseTool = {
31980
32146
 
31981
32147
  // src/tree.ts
31982
32148
  init_util();
31983
- import * as fs40 from "node:fs/promises";
31984
- import * as path46 from "node:path";
32149
+ import * as fs41 from "node:fs/promises";
32150
+ import * as path47 from "node:path";
31985
32151
  import { DEFAULT_WALK_IGNORE_DIRS as DEFAULT_WALK_IGNORE_DIRS4, expectDefined as expectDefined10 } from "@wrongstack/core/utils";
31986
32152
  var DEFAULT_IGNORE5 = /* @__PURE__ */ new Set([
31987
32153
  ...DEFAULT_WALK_IGNORE_DIRS4,
@@ -32144,7 +32310,7 @@ var treeTool = {
32144
32310
  async function walkDir(dir, depth, opts) {
32145
32311
  opts.signal.throwIfAborted();
32146
32312
  if (opts.retention.truncated) return;
32147
- const entries = await fs40.readdir(dir, { withFileTypes: true }).catch(() => []);
32313
+ const entries = await fs41.readdir(dir, { withFileTypes: true }).catch(() => []);
32148
32314
  const filtered = entries.filter((e) => {
32149
32315
  if (!opts.showHidden && e.name.startsWith(".")) return false;
32150
32316
  if (opts.exclude.has(e.name)) return false;
@@ -32186,7 +32352,7 @@ async function walkDir(dir, depth, opts) {
32186
32352
  opts.retention.outputBytes += lineBytes;
32187
32353
  if (entry.isDirectory() && (opts.maxDepth === 0 || depth < opts.maxDepth)) {
32188
32354
  const childPrefix = opts.prefix + connector;
32189
- await walkDir(path46.join(dir, entry.name), depth + 1, {
32355
+ await walkDir(path47.join(dir, entry.name), depth + 1, {
32190
32356
  ...opts,
32191
32357
  prefix: childPrefix,
32192
32358
  isLast
@@ -32199,7 +32365,7 @@ async function walkDir(dir, depth, opts) {
32199
32365
  init_spawn_stream();
32200
32366
  init_util();
32201
32367
  init_legacy_bridge();
32202
- import * as path47 from "node:path";
32368
+ import * as path48 from "node:path";
32203
32369
  var typecheckTool = {
32204
32370
  name: "typecheck",
32205
32371
  category: "Code Quality",
@@ -32311,8 +32477,8 @@ async function findTsConfig(cwd) {
32311
32477
  const candidates = ["tsconfig.json", "tsconfig.base.json"];
32312
32478
  for (const f of candidates) {
32313
32479
  try {
32314
- const s = await stat22(path47.join(cwd, f));
32315
- if (s.isFile()) return path47.join(cwd, f);
32480
+ const s = await stat22(path48.join(cwd, f));
32481
+ if (s.isFile()) return path48.join(cwd, f);
32316
32482
  } catch {
32317
32483
  }
32318
32484
  }
@@ -32320,7 +32486,7 @@ async function findTsConfig(cwd) {
32320
32486
  }
32321
32487
 
32322
32488
  // src/write.ts
32323
- import * as fs41 from "node:fs/promises";
32489
+ import * as fs42 from "node:fs/promises";
32324
32490
  import { ToolValidationError as ToolValidationError11 } from "@wrongstack/core/types";
32325
32491
  import {
32326
32492
  atomicWrite as atomicWrite6,
@@ -32397,14 +32563,14 @@ async function prepareWrite(input, ctx) {
32397
32563
  let existed = false;
32398
32564
  let prev = "";
32399
32565
  try {
32400
- const stat22 = await fs41.stat(absPath);
32566
+ const stat22 = await fs42.stat(absPath);
32401
32567
  existed = stat22.isFile();
32402
32568
  if (existed) {
32403
32569
  if (!ctx.hasRead(absPath)) {
32404
- prev = await fs41.readFile(absPath, "utf8");
32570
+ prev = await fs42.readFile(absPath, "utf8");
32405
32571
  ctx.recordRead(absPath, stat22.mtimeMs, "write", sha256hex(prev));
32406
32572
  } else {
32407
- prev = await fs41.readFile(absPath, "utf8");
32573
+ prev = await fs42.readFile(absPath, "utf8");
32408
32574
  }
32409
32575
  }
32410
32576
  } catch (err) {
@@ -32425,7 +32591,7 @@ async function finishWrite(input, ctx, prepared, signal) {
32425
32591
  const rawDiff = prepared.existed ? unifiedDiff3(prepared.prev, content, { fromFile: input.path, toFile: input.path }) : `+++ ${input.path}
32426
32592
  + (new file, ${content.split("\n").length} lines)`;
32427
32593
  const { text: diff, truncated: diffTruncated } = truncateDiffPayload(rawDiff, MAX_DIFF_BYTES3);
32428
- const stat22 = await fs41.stat(prepared.absPath);
32594
+ const stat22 = await fs42.stat(prepared.absPath);
32429
32595
  ctx.recordRead(prepared.absPath, stat22.mtimeMs, "write", sha256hex(content));
32430
32596
  ctx.session.recordFileChange({
32431
32597
  path: prepared.absPath,
@@ -32481,6 +32647,7 @@ var TIER1_TOOLS = [
32481
32647
  editTool,
32482
32648
  clarifyTool,
32483
32649
  codebaseAstReplaceTool,
32650
+ codebaseInvariantCheckTool,
32484
32651
  codebaseStatsTool,
32485
32652
  codebaseSearchTool,
32486
32653
  codebaseSkeletonTool,
@@ -32540,6 +32707,7 @@ var builtinTools = [
32540
32707
  editTool,
32541
32708
  clarifyTool,
32542
32709
  codebaseAstReplaceTool,
32710
+ codebaseInvariantCheckTool,
32543
32711
  codebaseStatsTool,
32544
32712
  codebaseSearchTool,
32545
32713
  codebaseSkeletonTool,
@@ -33596,8 +33764,8 @@ function createGlobalPsSlashCommand() {
33596
33764
  }
33597
33765
 
33598
33766
  // src/skill.ts
33599
- import * as fs42 from "node:fs/promises";
33600
- import * as path48 from "node:path";
33767
+ import * as fs43 from "node:fs/promises";
33768
+ import * as path49 from "node:path";
33601
33769
  import {
33602
33770
  missingRequiredRuntimeTools,
33603
33771
  missingRuntimeCapabilities,
@@ -33661,7 +33829,7 @@ function makeSkillTool(skillLoader) {
33661
33829
  field: "name"
33662
33830
  });
33663
33831
  }
33664
- const dir = path48.dirname(manifest.path);
33832
+ const dir = path49.dirname(manifest.path);
33665
33833
  let loadedResource;
33666
33834
  if (input.resource?.trim()) {
33667
33835
  loadedResource = await loadResource(dir, input.resource.trim());
@@ -33720,15 +33888,15 @@ ${listing}${warningLine}`;
33720
33888
  }
33721
33889
  async function loadResource(skillDir, rel) {
33722
33890
  const norm = rel.replace(/\\/g, "/");
33723
- if (path48.isAbsolute(rel) || norm.split("/").some((seg) => seg === "..")) {
33891
+ if (path49.isAbsolute(rel) || norm.split("/").some((seg) => seg === "..")) {
33724
33892
  throw new ToolValidationError13({
33725
33893
  message: `skill: invalid resource path "${rel}"`,
33726
33894
  field: "resource"
33727
33895
  });
33728
33896
  }
33729
- const absPath = path48.resolve(skillDir, rel);
33730
- const root = path48.resolve(skillDir);
33731
- if (absPath !== root && !absPath.startsWith(root + path48.sep)) {
33897
+ const absPath = path49.resolve(skillDir, rel);
33898
+ const root = path49.resolve(skillDir);
33899
+ if (absPath !== root && !absPath.startsWith(root + path49.sep)) {
33732
33900
  throw new ToolValidationError13({
33733
33901
  message: `skill: resource "${rel}" escapes the skill directory`,
33734
33902
  field: "resource"
@@ -33737,15 +33905,15 @@ async function loadResource(skillDir, rel) {
33737
33905
  let realPath;
33738
33906
  let realRoot;
33739
33907
  try {
33740
- realRoot = await fs42.realpath(root);
33741
- realPath = await fs42.realpath(absPath);
33908
+ realRoot = await fs43.realpath(root);
33909
+ realPath = await fs43.realpath(absPath);
33742
33910
  } catch {
33743
33911
  throw new ToolValidationError13({
33744
33912
  message: `skill: resource "${rel}" not readable`,
33745
33913
  field: "resource"
33746
33914
  });
33747
33915
  }
33748
- if (realPath !== realRoot && !realPath.startsWith(realRoot + path48.sep)) {
33916
+ if (realPath !== realRoot && !realPath.startsWith(realRoot + path49.sep)) {
33749
33917
  throw new ToolValidationError13({
33750
33918
  message: `skill: resource "${rel}" resolves outside the skill directory`,
33751
33919
  field: "resource"
@@ -33753,7 +33921,7 @@ async function loadResource(skillDir, rel) {
33753
33921
  }
33754
33922
  let buf;
33755
33923
  try {
33756
- buf = await fs42.readFile(realPath);
33924
+ buf = await fs43.readFile(realPath);
33757
33925
  } catch {
33758
33926
  throw new ToolValidationError13({
33759
33927
  message: `skill: resource "${rel}" not readable`,
@@ -33782,17 +33950,17 @@ async function walk(root, dir, out) {
33782
33950
  if (out.length >= MAX_LISTED_RESOURCES) return;
33783
33951
  let entries;
33784
33952
  try {
33785
- entries = await fs42.readdir(dir, { withFileTypes: true });
33953
+ entries = await fs43.readdir(dir, { withFileTypes: true });
33786
33954
  } catch {
33787
33955
  return;
33788
33956
  }
33789
33957
  for (const e of entries) {
33790
33958
  if (out.length >= MAX_LISTED_RESOURCES) return;
33791
- const fullPath = path48.join(dir, e.name);
33959
+ const fullPath = path49.join(dir, e.name);
33792
33960
  let isDir = e.isDirectory();
33793
33961
  if (e.isSymbolicLink()) {
33794
33962
  try {
33795
- isDir = (await fs42.stat(fullPath)).isDirectory();
33963
+ isDir = (await fs43.stat(fullPath)).isDirectory();
33796
33964
  } catch {
33797
33965
  continue;
33798
33966
  }
@@ -33803,8 +33971,8 @@ async function walk(root, dir, out) {
33803
33971
  } else if (e.isFile()) {
33804
33972
  if (e.name === "SKILL.md" || e.name === "SKILL.save.md") continue;
33805
33973
  try {
33806
- const stat22 = await fs42.stat(fullPath);
33807
- const rel = path48.relative(root, fullPath).split(path48.sep).join("/");
33974
+ const stat22 = await fs43.stat(fullPath);
33975
+ const rel = path49.relative(root, fullPath).split(path49.sep).join("/");
33808
33976
  out.push({ path: rel, bytes: stat22.size });
33809
33977
  } catch {
33810
33978
  }
@@ -33900,12 +34068,14 @@ var TOOL_ICON_MAP = {
33900
34068
  "codebase-stats": "index",
33901
34069
  "codebase-incoming-calls": "index",
33902
34070
  "codebase-outgoing-calls": "index",
34071
+ "codebase-invariant-check": "index",
33903
34072
  "dead-code-scan": "index",
33904
34073
  codebase_index: "index",
33905
34074
  codebase_search: "index",
33906
34075
  codebase_stats: "index",
33907
34076
  codebase_incoming_calls: "index",
33908
34077
  codebase_outgoing_calls: "index",
34078
+ codebase_invariant_check: "index",
33909
34079
  dead_code_scan: "index",
33910
34080
  // Data
33911
34081
  json: "json",
@@ -34078,6 +34248,7 @@ export {
34078
34248
  codebaseImpactAnalysisTool,
34079
34249
  codebaseIndexStats,
34080
34250
  codebaseIndexTool,
34251
+ codebaseInvariantCheckTool,
34081
34252
  codebaseRepoMapTool,
34082
34253
  codebaseSearchTool,
34083
34254
  codebaseSkeletonTool,