@wrongstack/tools 0.73.1 → 0.82.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/dist/audit.d.ts +4 -4
  2. package/dist/audit.js +10 -2
  3. package/dist/audit.js.map +1 -1
  4. package/dist/{background-indexer-sbsseCCC.d.ts → background-indexer-DYm1FUxK.d.ts} +49 -17
  5. package/dist/bash.d.ts +4 -4
  6. package/dist/bash.js +18 -4
  7. package/dist/bash.js.map +1 -1
  8. package/dist/batch-tool-use.d.ts +4 -4
  9. package/dist/batch-tool-use.js.map +1 -1
  10. package/dist/builtin.js +266 -71
  11. package/dist/builtin.js.map +1 -1
  12. package/dist/circuit-breaker.d.ts +6 -6
  13. package/dist/circuit-breaker.js.map +1 -1
  14. package/dist/codebase-index/index.d.ts +12 -12
  15. package/dist/codebase-index/index.js +270 -106
  16. package/dist/codebase-index/index.js.map +1 -1
  17. package/dist/diff.d.ts +7 -7
  18. package/dist/diff.js.map +1 -1
  19. package/dist/document.d.ts +6 -6
  20. package/dist/document.js.map +1 -1
  21. package/dist/edit.d.ts +1 -1
  22. package/dist/edit.js.map +1 -1
  23. package/dist/exec.d.ts +3 -3
  24. package/dist/exec.js +15 -3
  25. package/dist/exec.js.map +1 -1
  26. package/dist/fetch.d.ts +1 -1
  27. package/dist/fetch.js +3 -1
  28. package/dist/fetch.js.map +1 -1
  29. package/dist/format.d.ts +4 -4
  30. package/dist/format.js +18 -4
  31. package/dist/format.js.map +1 -1
  32. package/dist/git.d.ts +10 -10
  33. package/dist/git.js +8 -2
  34. package/dist/git.js.map +1 -1
  35. package/dist/glob.d.ts +2 -2
  36. package/dist/glob.js.map +1 -1
  37. package/dist/grep.d.ts +6 -6
  38. package/dist/grep.js +10 -2
  39. package/dist/grep.js.map +1 -1
  40. package/dist/index.d.ts +7 -7
  41. package/dist/index.js +366 -136
  42. package/dist/index.js.map +1 -1
  43. package/dist/install.d.ts +5 -5
  44. package/dist/install.js +18 -4
  45. package/dist/install.js.map +1 -1
  46. package/dist/json.d.ts +8 -8
  47. package/dist/json.js.map +1 -1
  48. package/dist/lint.d.ts +4 -4
  49. package/dist/lint.js +18 -4
  50. package/dist/lint.js.map +1 -1
  51. package/dist/logs.d.ts +8 -8
  52. package/dist/logs.js.map +1 -1
  53. package/dist/memory.d.ts +2 -2
  54. package/dist/memory.js.map +1 -1
  55. package/dist/mode.d.ts +3 -3
  56. package/dist/mode.js.map +1 -1
  57. package/dist/outdated.d.ts +4 -4
  58. package/dist/outdated.js.map +1 -1
  59. package/dist/pack.js +266 -71
  60. package/dist/pack.js.map +1 -1
  61. package/dist/patch.d.ts +3 -3
  62. package/dist/patch.js.map +1 -1
  63. package/dist/process-registry.d.ts +3 -3
  64. package/dist/process-registry.js +7 -1
  65. package/dist/process-registry.js.map +1 -1
  66. package/dist/read.d.ts +2 -2
  67. package/dist/read.js.map +1 -1
  68. package/dist/replace.d.ts +4 -4
  69. package/dist/replace.js +8 -2
  70. package/dist/replace.js.map +1 -1
  71. package/dist/scaffold.d.ts +2 -2
  72. package/dist/scaffold.js.map +1 -1
  73. package/dist/search.d.ts +2 -2
  74. package/dist/search.js +16 -8
  75. package/dist/search.js.map +1 -1
  76. package/dist/test.d.ts +7 -7
  77. package/dist/test.js +18 -4
  78. package/dist/test.js.map +1 -1
  79. package/dist/todo.js +2 -1
  80. package/dist/todo.js.map +1 -1
  81. package/dist/tool-help.d.ts +4 -4
  82. package/dist/tool-help.js.map +1 -1
  83. package/dist/tool-search.d.ts +5 -5
  84. package/dist/tool-search.js.map +1 -1
  85. package/dist/tool-use.d.ts +2 -2
  86. package/dist/tool-use.js.map +1 -1
  87. package/dist/tree.d.ts +7 -7
  88. package/dist/tree.js +10 -2
  89. package/dist/tree.js.map +1 -1
  90. package/dist/typecheck.d.ts +4 -4
  91. package/dist/typecheck.js +18 -4
  92. package/dist/typecheck.js.map +1 -1
  93. package/dist/write.d.ts +1 -1
  94. package/dist/write.js.map +1 -1
  95. package/package.json +2 -2
package/dist/builtin.js CHANGED
@@ -19,6 +19,12 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
19
19
  if (typeof require !== "undefined") return require.apply(this, arguments);
20
20
  throw Error('Dynamic require of "' + x + '" is not supported');
21
21
  });
22
+ function expectDefined(value) {
23
+ if (value === null || value === void 0) {
24
+ throw new Error("Expected value to be defined");
25
+ }
26
+ return value;
27
+ }
22
28
  async function* spawnStream(opts) {
23
29
  const max = opts.maxBytes ?? 2e5;
24
30
  const flushAt = opts.flushBytes ?? 4 * 1024;
@@ -70,7 +76,7 @@ async function* spawnStream(opts) {
70
76
  waiter = resolve7;
71
77
  });
72
78
  }
73
- const chunk = queue.shift();
79
+ const chunk = expectDefined(queue.shift());
74
80
  if (chunk.kind === "close") {
75
81
  if (!spawnFailed) exitCode = chunk.code ?? 0;
76
82
  break;
@@ -97,6 +103,12 @@ async function* spawnStream(opts) {
97
103
  error
98
104
  };
99
105
  }
106
+ function expectDefined2(value) {
107
+ if (value === null || value === void 0) {
108
+ throw new Error("Expected value to be defined");
109
+ }
110
+ return value;
111
+ }
100
112
  async function detectPackageManager(cwd) {
101
113
  const { stat: stat10 } = await import('node:fs/promises');
102
114
  try {
@@ -186,9 +198,9 @@ function collapseConsecutiveDuplicates(text, minRun = REPEAT_RUN_THRESHOLD) {
186
198
  while (j < lines.length && lines[j] === lines[i]) j++;
187
199
  const run = j - i;
188
200
  if (run >= minRun) {
189
- out.push(lines[i], `\u2026 \u27E8repeated ${run}\xD7\u27E9`);
201
+ out.push(expectDefined2(lines[i]), `\u2026 \u27E8repeated ${run}\xD7\u27E9`);
190
202
  } else {
191
- for (let k = i; k < j; k++) out.push(lines[k]);
203
+ for (let k = i; k < j; k++) out.push(expectDefined2(lines[k]));
192
204
  }
193
205
  i = j;
194
206
  }
@@ -265,7 +277,9 @@ var auditTool = {
265
277
  },
266
278
  async execute(input, ctx, opts) {
267
279
  let final;
268
- for await (const ev of auditTool.executeStream(input, ctx, opts)) {
280
+ const executeStream = auditTool.executeStream;
281
+ if (!executeStream) throw new Error("auditTool: stream execution unavailable");
282
+ for await (const ev of executeStream(input, ctx, opts)) {
269
283
  if (ev.type === "final") final = ev.output;
270
284
  }
271
285
  if (!final) throw new Error("audit: stream ended without final event");
@@ -482,6 +496,12 @@ var CircuitBreaker = class {
482
496
  };
483
497
 
484
498
  // src/process-registry.ts
499
+ function expectDefined3(value) {
500
+ if (value === null || value === void 0) {
501
+ throw new Error("Expected value to be defined");
502
+ }
503
+ return value;
504
+ }
485
505
  var SENSITIVE_FLAG_PATTERNS = [
486
506
  // --flag=value or --flag "value" (value captured up to next space or comma)
487
507
  /--(?:token|password|passwd|pwd|secret|api[-_]?key|api[-_]?secret|auth|credential|private[-_]?key|access[-_]?key|github[-_]?token|gh[-_]?token|bearer|jwt|oauth|pin|pincode|passphrase|access[-_]?token)(?:[=\s,][^\s]*)?/gi,
@@ -502,7 +522,7 @@ function redactCommand(cmd) {
502
522
  const sp = match.search(/\s/);
503
523
  const delim = eq !== -1 ? "=" : sp !== -1 ? match[sp] : null;
504
524
  if (delim !== null) {
505
- const flag = match.slice(0, match.indexOf(delim) + 1);
525
+ const flag = match.slice(0, match.indexOf(expectDefined3(delim)) + 1);
506
526
  return `${flag}[REDACTED]`;
507
527
  }
508
528
  const flagEnd = match.match(/^--?[a-zA-Z][a-zA-Z0-9_-]*/)?.[0] ?? match;
@@ -721,7 +741,9 @@ var bashTool = {
721
741
  },
722
742
  async execute(input, ctx, opts) {
723
743
  let final;
724
- for await (const ev of bashTool.executeStream(input, ctx, opts)) {
744
+ const executeStream = bashTool.executeStream;
745
+ if (!executeStream) throw new Error("bashTool: stream execution unavailable");
746
+ for await (const ev of executeStream(input, ctx, opts)) {
725
747
  if (ev.type === "final") final = ev.output;
726
748
  }
727
749
  if (!final) throw new Error("bash: stream ended without final event");
@@ -1087,6 +1109,12 @@ function lspKindToInternalKind(k) {
1087
1109
  }
1088
1110
 
1089
1111
  // src/codebase-index/writer.ts
1112
+ function expectDefined4(value) {
1113
+ if (value === null || value === void 0) {
1114
+ throw new Error("Expected value to be defined");
1115
+ }
1116
+ return value;
1117
+ }
1090
1118
  var DB_FILE = "index.db";
1091
1119
  function resolveIndexDir(projectRoot, override) {
1092
1120
  return override ?? resolveWstackPaths({ projectRoot }).projectCodebaseIndex;
@@ -1231,7 +1259,7 @@ var IndexStore = class {
1231
1259
  "SELECT file, lang, mtime_ms, symbol_count, last_indexed FROM files WHERE file = ?"
1232
1260
  ).all(file);
1233
1261
  if (!rows.length) return null;
1234
- const r = rows[0];
1262
+ const r = expectDefined4(rows[0]);
1235
1263
  return { file: r.file, lang: r.lang, mtimeMs: r.mtime_ms, symbolCount: r.symbol_count, lastIndexed: r.last_indexed };
1236
1264
  }
1237
1265
  getAllFileMetas() {
@@ -1313,7 +1341,7 @@ var IndexStore = class {
1313
1341
  const lastRows = this.db.prepare(
1314
1342
  "SELECT value FROM metadata WHERE key = 'last_indexed'"
1315
1343
  ).all();
1316
- const lastIndexed = lastRows.length ? Number(lastRows[0].value) : null;
1344
+ const lastIndexed = lastRows.length ? Number(lastRows[0]?.value) : null;
1317
1345
  const totalRows = this.db.prepare("SELECT COUNT(*) FROM symbols").all();
1318
1346
  const totalSymbols = totalRows[0] ? Number(totalRows[0]["COUNT(*)"]) : 0;
1319
1347
  const fileRows = this.db.prepare("SELECT COUNT(*) FROM files").all();
@@ -1388,8 +1416,9 @@ var IndexStore = class {
1388
1416
  let resolved = 0;
1389
1417
  for (const row of unresolved) {
1390
1418
  const target = this.db.prepare("SELECT id FROM symbols WHERE name = ? LIMIT 1").all(row.to_name);
1391
- if (target.length) {
1392
- this.db.prepare("UPDATE refs SET to_id = ? WHERE id = ?").run(target[0].id, row.id);
1419
+ const first = target[0];
1420
+ if (first) {
1421
+ this.db.prepare("UPDATE refs SET to_id = ? WHERE id = ?").run(first.id, row.id);
1393
1422
  resolved++;
1394
1423
  }
1395
1424
  }
@@ -2143,6 +2172,12 @@ function syncPyParse(filePath, lang) {
2143
2172
  return { file: filePath, lang, symbols: [], mtimeMs: Date.now() };
2144
2173
  }
2145
2174
  }
2175
+ function expectDefined5(value) {
2176
+ if (value === null || value === void 0) {
2177
+ throw new Error("Expected value to be defined");
2178
+ }
2179
+ return value;
2180
+ }
2146
2181
  function parseSymbols4(opts) {
2147
2182
  const { file, content, lang } = opts;
2148
2183
  const nativeAvailable = checkNativeParser();
@@ -2224,14 +2259,14 @@ function regexParse(opts) {
2224
2259
  const lines = content.split("\n");
2225
2260
  const lineOffsets = [0];
2226
2261
  for (let i = 0; i < lines.length; i++) {
2227
- lineOffsets.push(lineOffsets[i] + lines[i].length + 1);
2262
+ lineOffsets.push((lineOffsets[i] ?? 0) + (lines[i]?.length ?? 0) + 1);
2228
2263
  }
2229
2264
  function lineFromOffset(offset) {
2230
2265
  let lo = 0;
2231
2266
  let hi = lineOffsets.length - 1;
2232
2267
  while (lo < hi) {
2233
2268
  const mid = lo + hi + 1 >>> 1;
2234
- if (lineOffsets[mid] <= offset) lo = mid;
2269
+ if (expectDefined5(lineOffsets[mid]) <= offset) lo = mid;
2235
2270
  else hi = mid - 1;
2236
2271
  }
2237
2272
  return lo + 1;
@@ -2243,8 +2278,8 @@ function regexParse(opts) {
2243
2278
  for (const pattern of RS_PATTERNS) {
2244
2279
  pattern.regex.lastIndex = 0;
2245
2280
  for (let match = pattern.regex.exec(content); match !== null; match = pattern.regex.exec(content)) {
2246
- const name = match[1];
2247
- const offset = match.index;
2281
+ const name = expectDefined5(match[1]);
2282
+ const offset = match.index ?? 0;
2248
2283
  const line = lineFromOffset(offset);
2249
2284
  const col = offset - (lineOffsets[line - 1] ?? 0);
2250
2285
  const lineIdx = line - 1;
@@ -2273,6 +2308,12 @@ function regexParse(opts) {
2273
2308
  });
2274
2309
  return { file, lang, symbols: deduped, mtimeMs: Date.now() };
2275
2310
  }
2311
+ function expectDefined6(value) {
2312
+ if (value === null || value === void 0) {
2313
+ throw new Error("Expected value to be defined");
2314
+ }
2315
+ return value;
2316
+ }
2276
2317
  function parseSymbols5(opts) {
2277
2318
  const { file, content, lang } = opts;
2278
2319
  try {
@@ -2292,21 +2333,21 @@ function regexParse2(opts) {
2292
2333
  const lines = content.split("\n");
2293
2334
  const lineOffsets = [0];
2294
2335
  for (let i = 0; i < lines.length; i++) {
2295
- lineOffsets.push(lineOffsets[i] + lines[i].length + 1);
2336
+ lineOffsets.push((lineOffsets[i] ?? 0) + (lines[i]?.length ?? 0) + 1);
2296
2337
  }
2297
2338
  function lineFromOffset(offset) {
2298
2339
  let lo = 0;
2299
2340
  let hi = lineOffsets.length - 1;
2300
2341
  while (lo < hi) {
2301
2342
  const mid = lo + hi + 1 >>> 1;
2302
- if (lineOffsets[mid] <= offset) lo = mid;
2343
+ if (expectDefined6(lineOffsets[mid]) <= offset) lo = mid;
2303
2344
  else hi = mid - 1;
2304
2345
  }
2305
2346
  return lo + 1;
2306
2347
  }
2307
2348
  const rootMatch = content.match(/^\s*\{/m);
2308
2349
  if (rootMatch) {
2309
- const offset = rootMatch.index;
2350
+ const offset = expectDefined6(rootMatch.index);
2310
2351
  const line = lineFromOffset(offset);
2311
2352
  symbols.push(
2312
2353
  makeSymbol({
@@ -2322,8 +2363,8 @@ function regexParse2(opts) {
2322
2363
  }
2323
2364
  const topLevelKeyRegex = /^\s*"([^"]+)"\s*:/gm;
2324
2365
  for (let match = topLevelKeyRegex.exec(content); match !== null; match = topLevelKeyRegex.exec(content)) {
2325
- const key = match[1];
2326
- const offset = match.index;
2366
+ const key = expectDefined6(match[1]);
2367
+ const offset = match.index ?? 0;
2327
2368
  const line = lineFromOffset(offset);
2328
2369
  const col = offset - (lineOffsets[line - 1] ?? 0);
2329
2370
  let kind = "property";
@@ -2369,7 +2410,7 @@ function regexParse2(opts) {
2369
2410
  const defsRegex = /"\$defs"\s*:|"\$defs"\s*:/g;
2370
2411
  const defsMatch = defsRegex.exec(content);
2371
2412
  if (defsMatch !== null) {
2372
- const offset = defsMatch.index;
2413
+ const offset = expectDefined6(defsMatch.index);
2373
2414
  const line = lineFromOffset(offset);
2374
2415
  symbols.push(
2375
2416
  makeSymbol({
@@ -2392,9 +2433,9 @@ function regexParse2(opts) {
2392
2433
  for (const pat of defsPatterns) {
2393
2434
  pat.lastIndex = 0;
2394
2435
  for (let match = pat.exec(content); match !== null; match = pat.exec(content)) {
2395
- const offset = match.index;
2436
+ const offset = match.index ?? 0;
2396
2437
  const line = lineFromOffset(offset);
2397
- const key = match[0].match(/"([^"]+)"/)?.[1] ?? match[0];
2438
+ const key = match[0]?.match(/"([^"]+)"/)?.[1] ?? expectDefined6(match[0]);
2398
2439
  symbols.push(
2399
2440
  makeSymbol({
2400
2441
  name: key,
@@ -2413,12 +2454,12 @@ function regexParse2(opts) {
2413
2454
  function extractPackageScripts(content, symbols, file, lang, lineOffsets, lineFromOffset) {
2414
2455
  const scriptsBlockRegex = /"scripts"\s*:\s*\{([^}]+)\}/g;
2415
2456
  for (let match = scriptsBlockRegex.exec(content); match !== null; match = scriptsBlockRegex.exec(content)) {
2416
- const blockContent = match[0];
2417
- const blockOffset = match.index;
2457
+ const blockContent = expectDefined6(match[0]);
2458
+ const blockOffset = match.index ?? 0;
2418
2459
  const scriptKeyRegex = /"(\w[\w-]*)"\s*:/g;
2419
2460
  for (let scriptMatch = scriptKeyRegex.exec(blockContent); scriptMatch !== null; scriptMatch = scriptKeyRegex.exec(blockContent)) {
2420
- const key = scriptMatch[1];
2421
- const keyOffset = blockOffset + scriptMatch.index;
2461
+ const key = expectDefined6(scriptMatch[1]);
2462
+ const keyOffset = blockOffset + expectDefined6(scriptMatch.index);
2422
2463
  const line = lineFromOffset(keyOffset);
2423
2464
  symbols.push(
2424
2465
  makeSymbol({
@@ -2437,12 +2478,12 @@ function extractPackageScripts(content, symbols, file, lang, lineOffsets, lineFr
2437
2478
  function extractCompilerOptions(content, symbols, file, lang, lineOffsets, parentLine, lineFromOffset) {
2438
2479
  const optsBlockRegex = /"compilerOptions"\s*:\s*\{([^}]+)\}/g;
2439
2480
  for (let match = optsBlockRegex.exec(content); match !== null; match = optsBlockRegex.exec(content)) {
2440
- const blockContent = match[0];
2441
- const blockOffset = match.index;
2481
+ const blockContent = expectDefined6(match[0]);
2482
+ const blockOffset = match.index ?? 0;
2442
2483
  const optKeyRegex = /"(\w[\w]*)"\s*:/g;
2443
2484
  for (let optMatch = optKeyRegex.exec(blockContent); optMatch !== null; optMatch = optKeyRegex.exec(blockContent)) {
2444
- const key = optMatch[1];
2445
- const keyOffset = blockOffset + optMatch.index;
2485
+ const key = expectDefined6(optMatch[1]);
2486
+ const keyOffset = blockOffset + expectDefined6(optMatch.index);
2446
2487
  const line = lineFromOffset(keyOffset);
2447
2488
  if (line <= parentLine) continue;
2448
2489
  symbols.push(
@@ -2476,6 +2517,12 @@ function makeSymbol(opts) {
2476
2517
  }
2477
2518
 
2478
2519
  // src/codebase-index/yaml-parser.ts
2520
+ function expectDefined7(value) {
2521
+ if (value === null || value === void 0) {
2522
+ throw new Error("Expected value to be defined");
2523
+ }
2524
+ return value;
2525
+ }
2479
2526
  function parseSymbols6(opts) {
2480
2527
  const { file, content, lang } = opts;
2481
2528
  try {
@@ -2490,22 +2537,22 @@ function regexParse3(opts) {
2490
2537
  const lines = content.split("\n");
2491
2538
  const lineOffsets = [0];
2492
2539
  for (let i = 0; i < lines.length; i++) {
2493
- lineOffsets.push(lineOffsets[i] + lines[i].length + 1);
2540
+ lineOffsets.push((lineOffsets[i] ?? 0) + (lines[i]?.length ?? 0) + 1);
2494
2541
  }
2495
2542
  function lineFromOffset(offset) {
2496
2543
  let lo = 0;
2497
2544
  let hi = lineOffsets.length - 1;
2498
2545
  while (lo < hi) {
2499
2546
  const mid = lo + hi + 1 >>> 1;
2500
- if (lineOffsets[mid] <= offset) lo = mid;
2547
+ if (expectDefined7(lineOffsets[mid]) <= offset) lo = mid;
2501
2548
  else hi = mid - 1;
2502
2549
  }
2503
2550
  return lo + 1;
2504
2551
  }
2505
2552
  const anchorRegex = /&(\w[\w-]*)/g;
2506
2553
  for (let match = anchorRegex.exec(content); match !== null; match = anchorRegex.exec(content)) {
2507
- const name = match[1];
2508
- const offset = match.index;
2554
+ const name = expectDefined7(match[1]);
2555
+ const offset = match.index ?? 0;
2509
2556
  const line = lineFromOffset(offset);
2510
2557
  const col = offset - (lineOffsets[line - 1] ?? 0);
2511
2558
  symbols.push(
@@ -2522,8 +2569,8 @@ function regexParse3(opts) {
2522
2569
  }
2523
2570
  const aliasRegex = /\*(\w[\w-]*)/g;
2524
2571
  for (let match = aliasRegex.exec(content); match !== null; match = aliasRegex.exec(content)) {
2525
- const name = match[1];
2526
- const offset = match.index;
2572
+ const name = expectDefined7(match[1]);
2573
+ const offset = match.index ?? 0;
2527
2574
  const line = lineFromOffset(offset);
2528
2575
  const col = offset - (lineOffsets[line - 1] ?? 0);
2529
2576
  symbols.push(
@@ -2540,27 +2587,28 @@ function regexParse3(opts) {
2540
2587
  }
2541
2588
  const kvRegex = /^(\s*)([^:#\s][^:#\s]*)\s*:/gm;
2542
2589
  for (let match = kvRegex.exec(content); match !== null; match = kvRegex.exec(content)) {
2543
- const indent = match[1].length;
2590
+ const indent = match[1]?.length ?? 0;
2544
2591
  const key = match[2];
2545
- const offset = match.index;
2592
+ if (!key) continue;
2593
+ const offset = match.index ?? 0;
2546
2594
  const line = lineFromOffset(offset);
2547
2595
  const col = offset - (lineOffsets[line - 1] ?? 0);
2548
2596
  const lineContent = lines[line - 1] ?? "";
2549
2597
  if (/^[|&>]/.test(lineContent.trim())) continue;
2550
2598
  if (key === "---" || key === "...") continue;
2551
2599
  if (indent > 12) continue;
2552
- const value = extractValue(content, match.index);
2600
+ const value = extractValue(content, match.index ?? 0);
2553
2601
  const kind = isScalar(value) ? "literal" : "property";
2554
2602
  const signature = `${key}: ${truncate(value, 60)}`;
2555
2603
  symbols.push(makeSymbol2({ name: key, kind, line, col, signature, file, lang }));
2556
2604
  }
2557
2605
  const listItemRegex = /^-(\s+)([^:#\s][^:#\s]*)\s*:/gm;
2558
2606
  for (let match = listItemRegex.exec(content); match !== null; match = listItemRegex.exec(content)) {
2559
- const key = match[2];
2560
- const offset = match.index;
2607
+ const key = expectDefined7(match[2]);
2608
+ const offset = match.index ?? 0;
2561
2609
  const line = lineFromOffset(offset);
2562
2610
  const col = offset - (lineOffsets[line - 1] ?? 0);
2563
- const value = extractValue(content, offset + match[0].length);
2611
+ const value = extractValue(content, offset + match[0]?.length);
2564
2612
  const kind = isScalar(value) ? "literal" : "property";
2565
2613
  symbols.push(
2566
2614
  makeSymbol2({
@@ -2576,8 +2624,8 @@ function regexParse3(opts) {
2576
2624
  }
2577
2625
  const blockScalarRegex = /^(\s*)([^:#\s][^:#\s]*)\s*:\s*[|>](\s|$)/gm;
2578
2626
  for (let match = blockScalarRegex.exec(content); match !== null; match = blockScalarRegex.exec(content)) {
2579
- const key = match[2];
2580
- const offset = match.index;
2627
+ const key = expectDefined7(match[2]);
2628
+ const offset = match.index ?? 0;
2581
2629
  const line = lineFromOffset(offset);
2582
2630
  const col = offset - (lineOffsets[line - 1] ?? 0);
2583
2631
  symbols.push(
@@ -2676,7 +2724,47 @@ async function loadGitignoreMatcher(projectRoot) {
2676
2724
  return compileGitignore(lines);
2677
2725
  }
2678
2726
 
2727
+ // src/codebase-index/background-indexer.ts
2728
+ var _ready = false;
2729
+ var _indexing = false;
2730
+ var _currentFile = 0;
2731
+ var _totalFiles = 0;
2732
+ var _lastError = null;
2733
+ function setIndexReady() {
2734
+ _ready = true;
2735
+ }
2736
+ function getIndexState() {
2737
+ return {
2738
+ ready: _ready,
2739
+ indexing: _indexing,
2740
+ currentFile: _currentFile,
2741
+ totalFiles: _totalFiles,
2742
+ lastError: _lastError
2743
+ };
2744
+ }
2745
+ var _listeners = [];
2746
+ function emitState() {
2747
+ const state = getIndexState();
2748
+ for (const l of _listeners) l(state);
2749
+ }
2750
+ function _setIndexProgress(current, total) {
2751
+ _currentFile = current;
2752
+ _totalFiles = total;
2753
+ emitState();
2754
+ }
2755
+ Promise.resolve();
2756
+
2679
2757
  // src/codebase-index/indexer.ts
2758
+ function expectDefined8(value) {
2759
+ if (value === null || value === void 0) {
2760
+ throw new Error("Expected value to be defined");
2761
+ }
2762
+ return value;
2763
+ }
2764
+ var YIELD_EVERY_N = 50;
2765
+ function yieldEventLoop() {
2766
+ return new Promise((resolve7) => setImmediate(resolve7));
2767
+ }
2680
2768
  var DEFAULT_IGNORE = [
2681
2769
  "node_modules",
2682
2770
  ".git",
@@ -2780,7 +2868,12 @@ async function runIndexer(_ctx, opts) {
2780
2868
  if (!force) {
2781
2869
  for (const meta of store.getAllFileMetas()) existingMeta.set(meta.file, meta);
2782
2870
  }
2783
- for (const file of files) {
2871
+ for (let fi = 0; fi < files.length; fi++) {
2872
+ const file = expectDefined8(files[fi]);
2873
+ _setIndexProgress(fi + 1, files.length);
2874
+ if (fi > 0 && fi % YIELD_EVERY_N === 0) {
2875
+ await yieldEventLoop();
2876
+ }
2784
2877
  let stat10;
2785
2878
  try {
2786
2879
  stat10 = await fs12.stat(file);
@@ -2833,7 +2926,7 @@ async function runIndexer(_ctx, opts) {
2833
2926
  langStats[lang] = (langStats[lang] ?? 0) + count;
2834
2927
  if (parsed.refs && parsed.refs.length > 0) {
2835
2928
  for (let i = 0; i < symbolsWithIds.length; i++) {
2836
- const sym = symbolsWithIds[i];
2929
+ const sym = expectDefined8(symbolsWithIds[i]);
2837
2930
  const symRefs = parsed.refs.filter((r) => r.line === sym.line);
2838
2931
  if (symRefs.length > 0) {
2839
2932
  const refsWithFromId = symRefs.map((r) => ({ ...r, fromId: sym.id }));
@@ -2900,6 +2993,7 @@ var codebaseIndexTool = {
2900
2993
  langs: input.langs,
2901
2994
  indexDir: codebaseIndexDirOverride(ctx)
2902
2995
  });
2996
+ setIndexReady();
2903
2997
  return result;
2904
2998
  }
2905
2999
  };
@@ -2993,6 +3087,12 @@ var Bm25Index = class {
2993
3087
  };
2994
3088
 
2995
3089
  // src/codebase-index/codebase-search-tool.ts
3090
+ function expectDefined9(value) {
3091
+ if (value === null || value === void 0) {
3092
+ throw new Error("Expected value to be defined");
3093
+ }
3094
+ return value;
3095
+ }
2996
3096
  var codebaseSearchTool = {
2997
3097
  name: "codebase-search",
2998
3098
  category: "Project",
@@ -3035,6 +3135,31 @@ var codebaseSearchTool = {
3035
3135
  required: ["query"]
3036
3136
  },
3037
3137
  async execute(input, ctx) {
3138
+ const state = getIndexState();
3139
+ if (!state.ready) {
3140
+ return {
3141
+ results: [],
3142
+ total: 0,
3143
+ query: input.query,
3144
+ indexStatus: state.indexing ? `Indexing in progress (${state.currentFile}/${state.totalFiles} files) \u2014 retry in a moment.` : "Index not yet built. The codebase is being indexed at startup \u2014 search will be available shortly."
3145
+ };
3146
+ }
3147
+ if (state.indexing) {
3148
+ return {
3149
+ results: [],
3150
+ total: 0,
3151
+ query: input.query,
3152
+ indexStatus: `Index refresh in progress (${state.currentFile}/${state.totalFiles} files). Results may be incomplete.`
3153
+ };
3154
+ }
3155
+ if (state.lastError) {
3156
+ return {
3157
+ results: [],
3158
+ total: 0,
3159
+ query: input.query,
3160
+ indexStatus: `Index build failed: ${state.lastError}. Try /codebase-reindex.`
3161
+ };
3162
+ }
3038
3163
  const store = new IndexStore(ctx.projectRoot, { indexDir: codebaseIndexDirOverride(ctx) });
3039
3164
  try {
3040
3165
  const limit = Math.min(input.limit ?? 20, 100);
@@ -3057,7 +3182,7 @@ var codebaseSearchTool = {
3057
3182
  const top = scored.slice(0, limit);
3058
3183
  const qTokens = tokenise(input.query);
3059
3184
  const results = top.map(({ id, score }) => {
3060
- const c = candidates.find((c2) => c2.id === id);
3185
+ const c = expectDefined9(candidates.find((c2) => c2.id === id));
3061
3186
  const snippet = bm25.extractSnippet(id, qTokens);
3062
3187
  return {
3063
3188
  ...c,
@@ -3092,6 +3217,32 @@ var codebaseStatsTool = {
3092
3217
  additionalProperties: false
3093
3218
  },
3094
3219
  async execute(_input, ctx) {
3220
+ const idxState = getIndexState();
3221
+ if (!idxState.ready) {
3222
+ return {
3223
+ totalSymbols: 0,
3224
+ totalFiles: 0,
3225
+ byLang: {},
3226
+ byKind: {},
3227
+ lastIndexed: null,
3228
+ sizeBytes: 0,
3229
+ indexPath: "",
3230
+ version: SCHEMA_VERSION,
3231
+ indexStatus: idxState.indexing ? `Indexing in progress (${idxState.currentFile}/${idxState.totalFiles} files).` : "Index not yet built."
3232
+ };
3233
+ }
3234
+ if (idxState.indexing) {
3235
+ const store2 = new IndexStore(ctx.projectRoot, { indexDir: codebaseIndexDirOverride(ctx) });
3236
+ try {
3237
+ const stats = store2.getStats();
3238
+ return {
3239
+ ...stats,
3240
+ indexStatus: `Index refresh in progress (${idxState.currentFile}/${idxState.totalFiles} files). Stats may be incomplete.`
3241
+ };
3242
+ } finally {
3243
+ store2.close();
3244
+ }
3245
+ }
3095
3246
  const store = new IndexStore(ctx.projectRoot, { indexDir: codebaseIndexDirOverride(ctx) });
3096
3247
  try {
3097
3248
  const stats = store.getStats();
@@ -3895,7 +4046,9 @@ var fetchTool = {
3895
4046
  },
3896
4047
  async execute(input, ctx, opts) {
3897
4048
  let final;
3898
- for await (const ev of fetchTool.executeStream(input, ctx, opts)) {
4049
+ const executeStream = fetchTool.executeStream;
4050
+ if (!executeStream) throw new Error("fetchTool: stream execution unavailable");
4051
+ for await (const ev of executeStream(input, ctx, opts)) {
3899
4052
  if (ev.type === "final") final = ev.output;
3900
4053
  }
3901
4054
  if (!final) throw new Error("fetch: stream ended without final event");
@@ -4154,7 +4307,9 @@ var formatTool = {
4154
4307
  },
4155
4308
  async execute(input, ctx, opts) {
4156
4309
  let final;
4157
- for await (const ev of formatTool.executeStream(input, ctx, opts)) {
4310
+ const executeStream = formatTool.executeStream;
4311
+ if (!executeStream) throw new Error("formatTool: stream execution unavailable");
4312
+ for await (const ev of executeStream(input, ctx, opts)) {
4158
4313
  if (ev.type === "final") final = ev.output;
4159
4314
  }
4160
4315
  if (!final) throw new Error("format: stream ended without final event");
@@ -4598,6 +4753,12 @@ function capSubject(line) {
4598
4753
  }
4599
4754
 
4600
4755
  // src/grep.ts
4756
+ function expectDefined10(value) {
4757
+ if (value === null || value === void 0) {
4758
+ throw new Error("Expected value to be defined");
4759
+ }
4760
+ return value;
4761
+ }
4601
4762
  var DEFAULT_IGNORE3 = ["node_modules", ".git", "dist", "build", ".next", "coverage"];
4602
4763
  var grepTool = {
4603
4764
  name: "grep",
@@ -4646,7 +4807,9 @@ var grepTool = {
4646
4807
  },
4647
4808
  async execute(input, ctx, opts) {
4648
4809
  let final;
4649
- for await (const ev of grepTool.executeStream(input, ctx, opts)) {
4810
+ const executeStream = grepTool.executeStream;
4811
+ if (!executeStream) throw new Error("grepTool: stream execution unavailable");
4812
+ for await (const ev of executeStream(input, ctx, opts)) {
4650
4813
  if (ev.type === "final") final = ev.output;
4651
4814
  }
4652
4815
  if (!final) throw new Error("grep: stream ended without final event");
@@ -4737,7 +4900,7 @@ async function* runRgStream(input, base, mode, limit, signal) {
4737
4900
  waiter = r;
4738
4901
  });
4739
4902
  }
4740
- const c = queue.shift();
4903
+ const c = expectDefined10(queue.shift());
4741
4904
  if (c.kind === "error") {
4742
4905
  errored = true;
4743
4906
  continue;
@@ -4923,7 +5086,9 @@ var installTool = {
4923
5086
  },
4924
5087
  async execute(input, ctx, opts) {
4925
5088
  let final;
4926
- for await (const ev of installTool.executeStream(input, ctx, opts)) {
5089
+ const executeStream = installTool.executeStream;
5090
+ if (!executeStream) throw new Error("installTool: stream execution unavailable");
5091
+ for await (const ev of executeStream(input, ctx, opts)) {
4927
5092
  if (ev.type === "final") final = ev.output;
4928
5093
  }
4929
5094
  if (!final) throw new Error("install: stream ended without final event");
@@ -5138,7 +5303,9 @@ var lintTool = {
5138
5303
  },
5139
5304
  async execute(input, ctx, opts) {
5140
5305
  let final;
5141
- for await (const ev of lintTool.executeStream(input, ctx, opts)) {
5306
+ const executeStream = lintTool.executeStream;
5307
+ if (!executeStream) throw new Error("lintTool: stream execution unavailable");
5308
+ for await (const ev of executeStream(input, ctx, opts)) {
5142
5309
  if (ev.type === "final") final = ev.output;
5143
5310
  }
5144
5311
  if (!final) throw new Error("lint: stream ended without final event");
@@ -5765,14 +5932,15 @@ var planTool = {
5765
5932
  };
5766
5933
  function mkResult(plan, ok, message, todos) {
5767
5934
  const open = plan.items.filter((i) => i.status !== "done").length;
5768
- return {
5935
+ const result = {
5769
5936
  ok,
5770
5937
  message,
5771
5938
  plan: formatPlan(plan),
5772
5939
  count: plan.items.length,
5773
- open,
5774
- todos
5940
+ open
5775
5941
  };
5942
+ if (todos !== void 0) result.todos = todos;
5943
+ return result;
5776
5944
  }
5777
5945
  var MAX_BYTES2 = 5 * 1024 * 1024;
5778
5946
  var readTool = {
@@ -5846,6 +6014,12 @@ var readTool = {
5846
6014
  };
5847
6015
  }
5848
6016
  };
6017
+ function expectDefined11(value) {
6018
+ if (value === null || value === void 0) {
6019
+ throw new Error("Expected value to be defined");
6020
+ }
6021
+ return value;
6022
+ }
5849
6023
  var DEFAULT_IGNORE4 = ["node_modules", ".git", "dist", "build", ".next", "coverage"];
5850
6024
  var replaceTool = {
5851
6025
  name: "replace",
@@ -5925,8 +6099,8 @@ var replaceTool = {
5925
6099
  const count = matches.length;
5926
6100
  let newContentLf = contentLf;
5927
6101
  for (let i = matches.length - 1; i >= 0; i--) {
5928
- const m = matches[i];
5929
- newContentLf = newContentLf.slice(0, m.index) + input.replacement + newContentLf.slice(m.index + m[0].length);
6102
+ const m = expectDefined11(matches[i]);
6103
+ newContentLf = newContentLf.slice(0, m.index) + input.replacement + newContentLf.slice(expectDefined11(m.index) + m[0].length);
5930
6104
  }
5931
6105
  re.lastIndex = 0;
5932
6106
  totalReplacements += count;
@@ -6227,6 +6401,12 @@ function substituteVars(content, name, vars) {
6227
6401
  }
6228
6402
 
6229
6403
  // src/search.ts
6404
+ function expectDefined12(value) {
6405
+ if (value === null || value === void 0) {
6406
+ throw new Error("Expected value to be defined");
6407
+ }
6408
+ return value;
6409
+ }
6230
6410
  var DEFAULT_NUM = 10;
6231
6411
  var MAX_RESULTS = 50;
6232
6412
  var TIMEOUT_MS4 = 15e3;
@@ -6259,7 +6439,9 @@ var searchTool = {
6259
6439
  },
6260
6440
  async execute(input, ctx, opts) {
6261
6441
  let final;
6262
- for await (const ev of searchTool.executeStream(input, ctx, opts)) {
6442
+ const executeStream = searchTool.executeStream;
6443
+ if (!executeStream) throw new Error("searchTool: stream execution unavailable");
6444
+ for await (const ev of executeStream(input, ctx, opts)) {
6263
6445
  if (ev.type === "final") final = ev.output;
6264
6446
  }
6265
6447
  if (!final) throw new Error("search: stream ended without final event");
@@ -6320,11 +6502,11 @@ function parseDuckDuckGo(html, num) {
6320
6502
  const snippetRegex = /<a class="result-link"[^>]+href="([^"]+)"[^>]*>([^<]+)<\/a>/gi;
6321
6503
  const snippet2Regex = /<a class="result-snippet"[^>]*>([^<]+)<\/a>/gi;
6322
6504
  const linkMatches = takeFrom(
6323
- [...html.matchAll(snippetRegex)].filter((m) => m[1] && m[2]).map((m) => ({ url: m[1], title: stripTags2(m[2]) })),
6505
+ [...html.matchAll(snippetRegex)].filter((m) => m[1] && m[2]).map((m) => ({ url: expectDefined12(m[1]), title: stripTags2(expectDefined12(m[2])) })),
6324
6506
  num
6325
6507
  );
6326
6508
  const snippetMatches = takeFrom(
6327
- [...html.matchAll(snippet2Regex)].filter((m) => m[1]).map((m) => stripTags2(m[1])),
6509
+ [...html.matchAll(snippet2Regex)].filter((m) => m[1]).map((m) => stripTags2(expectDefined12(m[1]))),
6328
6510
  num
6329
6511
  );
6330
6512
  for (let i = 0; i < linkMatches.length && i < num; i++) {
@@ -6355,15 +6537,15 @@ function parseGoogleResults(html, num) {
6355
6537
  const urlRegex = /<cite[^>]*>([^<]+)<\/cite>/gi;
6356
6538
  const snippetRegex = /<span[^>]*class="[^"]*aXCZ0b[^>]*>([^<]+)<\/span>/gi;
6357
6539
  const titles = takeFrom(
6358
- [...html.matchAll(titleRegex)].filter((m) => m[1]).map((m) => stripTags2(m[1])),
6540
+ [...html.matchAll(titleRegex)].filter((m) => m[1]).map((m) => stripTags2(expectDefined12(m[1]))),
6359
6541
  num
6360
6542
  );
6361
6543
  const urls = takeFrom(
6362
- [...html.matchAll(urlRegex)].filter((m) => m[1]).map((m) => stripTags2(m[1]).replace(/^\*(https?:\/\/[^\s]+).*$/, "$1")).filter((u) => u.startsWith("http")),
6544
+ [...html.matchAll(urlRegex)].filter((m) => m[1]).map((m) => stripTags2(expectDefined12(m[1])).replace(/^\*(https?:\/\/[^\s]+).*$/, "$1")).filter((u) => u.startsWith("http")),
6363
6545
  num
6364
6546
  );
6365
6547
  const snippets = takeFrom(
6366
- [...html.matchAll(snippetRegex)].filter((m) => m[1]).map((m) => stripTags2(m[1])),
6548
+ [...html.matchAll(snippetRegex)].filter((m) => m[1]).map((m) => stripTags2(expectDefined12(m[1]))),
6367
6549
  num
6368
6550
  );
6369
6551
  for (let i = 0; i < Math.min(titles.length, num); i++) {
@@ -6392,11 +6574,11 @@ function parseBingResults(html, num) {
6392
6574
  const titleRegex = /<h2[^>]*>\s*<a[^>]+href="([^"]+)"[^>]*>([^<]+)<\/a>\s*<\/h2>/gi;
6393
6575
  const snippetRegex = /<p[^>]*class="[^"]*b_paractl[^"]*"[^>]*>([^<]+)<\/p>/gi;
6394
6576
  const entries = takeFrom(
6395
- [...html.matchAll(titleRegex)].filter((m) => m[1] && m[2]).map((m) => ({ url: m[1], title: stripTags2(m[2]) })),
6577
+ [...html.matchAll(titleRegex)].filter((m) => m[1] && m[2]).map((m) => ({ url: expectDefined12(m[1]), title: stripTags2(expectDefined12(m[2])) })),
6396
6578
  num
6397
6579
  );
6398
6580
  const snippets = takeFrom(
6399
- [...html.matchAll(snippetRegex)].filter((m) => m[1]).map((m) => stripTags2(m[1])),
6581
+ [...html.matchAll(snippetRegex)].filter((m) => m[1]).map((m) => stripTags2(expectDefined12(m[1]))),
6400
6582
  num
6401
6583
  );
6402
6584
  for (let i = 0; i < entries.length; i++) {
@@ -6466,7 +6648,9 @@ var testTool = {
6466
6648
  },
6467
6649
  async execute(input, ctx, opts) {
6468
6650
  let final;
6469
- for await (const ev of testTool.executeStream(input, ctx, opts)) {
6651
+ const executeStream = testTool.executeStream;
6652
+ if (!executeStream) throw new Error("testTool: stream execution unavailable");
6653
+ for await (const ev of executeStream(input, ctx, opts)) {
6470
6654
  if (ev.type === "final") final = ev.output;
6471
6655
  }
6472
6656
  if (!final) throw new Error("test: stream ended without final event");
@@ -6589,9 +6773,10 @@ var todoTool = {
6589
6773
  name: "todo",
6590
6774
  category: "Session",
6591
6775
  description: "Manage the session-level todo list. This is the primary mechanism for tracking multi-step work. The list is fully replaced on every call (not appended).",
6592
- usageHint: "BEST PRACTICE for complex tasks:\n- At the beginning of a non-trivial task, create a clear todo list with specific, actionable items.\n- Only **one** item should be `in_progress` at any time.\n- Update the list frequently as work progresses (mark items done, add new ones, change status).\n- The system and user can see this list, so keep it honest and up-to-date.\nThis tool is extremely valuable for maintaining focus and giving the user visibility into your plan.",
6776
+ usageHint: "BEST PRACTICE for complex tasks:\n- At the beginning of a non-trivial task, create a clear todo list with specific, actionable items.\n- Only **one** item should be `in_progress` at any time.\n- Update the list frequently as work progresses (mark items done, add new ones, change status).\n- **Re-order items** to reflect current priorities \u2014 the full list is replaced each call, so item order is entirely under your control.\n- When all items are completed the board auto-clears \u2014 you do NOT need to send an empty list.\n- The system and user can see this list, so keep it honest and up-to-date.\nThis tool is extremely valuable for maintaining focus and giving the user visibility into your plan.",
6593
6777
  permission: "auto",
6594
6778
  mutating: false,
6779
+ // mutates only conversation state (ctx.todos), not external state — no confirmation needed
6595
6780
  timeoutMs: 1e3,
6596
6781
  inputSchema: {
6597
6782
  type: "object",
@@ -6917,6 +7102,12 @@ var toolUseTool = {
6917
7102
  }
6918
7103
  }
6919
7104
  };
7105
+ function expectDefined13(value) {
7106
+ if (value === null || value === void 0) {
7107
+ throw new Error("Expected value to be defined");
7108
+ }
7109
+ return value;
7110
+ }
6920
7111
  var DEFAULT_IGNORE5 = [
6921
7112
  "node_modules",
6922
7113
  ".git",
@@ -6977,7 +7168,9 @@ var treeTool = {
6977
7168
  },
6978
7169
  async execute(input, ctx, opts) {
6979
7170
  let final;
6980
- for await (const ev of treeTool.executeStream(input, ctx, opts)) {
7171
+ const executeStream = treeTool.executeStream;
7172
+ if (!executeStream) throw new Error("treeTool: stream execution unavailable");
7173
+ for await (const ev of executeStream(input, ctx, opts)) {
6981
7174
  if (ev.type === "final") final = ev.output;
6982
7175
  }
6983
7176
  if (!final) throw new Error("tree: stream ended without final event");
@@ -7027,7 +7220,7 @@ var treeTool = {
7027
7220
  });
7028
7221
  while (!walkDone || queue.length > 0) {
7029
7222
  if (queue.length > 0) {
7030
- yield queue.shift();
7223
+ yield expectDefined13(queue.shift());
7031
7224
  } else {
7032
7225
  let pollTimer;
7033
7226
  const poll = new Promise((r) => {
@@ -7117,7 +7310,9 @@ var typecheckTool = {
7117
7310
  },
7118
7311
  async execute(input, ctx, opts) {
7119
7312
  let final;
7120
- for await (const ev of typecheckTool.executeStream(input, ctx, opts)) {
7313
+ const executeStream = typecheckTool.executeStream;
7314
+ if (!executeStream) throw new Error("typecheckTool: stream execution unavailable");
7315
+ for await (const ev of executeStream(input, ctx, opts)) {
7121
7316
  if (ev.type === "final") final = ev.output;
7122
7317
  }
7123
7318
  if (!final) throw new Error("typecheck: stream ended without final event");