@wrongstack/tools 1.0.0 → 1.0.2

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 (70) hide show
  1. package/dist/auto-proceed-loop-guard.d.ts +1 -1
  2. package/dist/auto-proceed-loop-guard.js +1 -1
  3. package/dist/bash.js +1 -1
  4. package/dist/builtin.js +15 -15
  5. package/dist/{chunk-VVZPQPTY.js → chunk-3AU6CZWL.js} +4 -2
  6. package/dist/{chunk-N3K2SFEI.js → chunk-52UXXQMP.js} +1408 -200
  7. package/dist/{chunk-NN2SNP2R.js → chunk-6H4ERJP7.js} +137 -21
  8. package/dist/{chunk-DK4J2WMH.js → chunk-7XUEPBNT.js} +2 -2
  9. package/dist/{chunk-IYH4OHBP.js → chunk-DKHMPKDG.js} +2 -2
  10. package/dist/{chunk-NU2IZ72J.js → chunk-DL2ARI4S.js} +7 -5
  11. package/dist/{chunk-M6UV67BH.js → chunk-EL2NJXSK.js} +2 -2
  12. package/dist/{chunk-YEISRT4S.js → chunk-HWXIRVKH.js} +1408 -235
  13. package/dist/{chunk-GKSG5CPH.js → chunk-KVTEIUND.js} +2 -2
  14. package/dist/{chunk-GDDXX27P.js → chunk-MBR5VAB5.js} +2 -2
  15. package/dist/{chunk-KDEXUQY7.js → chunk-MGPR7VG3.js} +261 -258
  16. package/dist/{chunk-YULVUTK5.js → chunk-NFX2IUQA.js} +3 -3
  17. package/dist/{chunk-37QKUQ2Z.js → chunk-NL2S2CXD.js} +1 -1
  18. package/dist/{chunk-ZTCJCYLN.js → chunk-TI5COGLY.js} +49 -6
  19. package/dist/{chunk-CGXTR34H.js → chunk-TU5MTW2S.js} +2 -2
  20. package/dist/{chunk-AB2CAUOP.js → chunk-UCXFTCAI.js} +186 -36
  21. package/dist/{chunk-MK2JK35J.js → chunk-UOYRAS4J.js} +3 -3
  22. package/dist/{chunk-UCYQTZ7F.js → chunk-ZKC5UNGD.js} +56 -2
  23. package/dist/codebase-index/atlas-brief.d.ts +90 -0
  24. package/dist/codebase-index/atlas-export.d.ts +38 -0
  25. package/dist/codebase-index/atlas-projection.d.ts +114 -0
  26. package/dist/codebase-index/atlas-types.d.ts +90 -0
  27. package/dist/codebase-index/background-indexer.d.ts +15 -4
  28. package/dist/codebase-index/codebase-context-tool.d.ts +54 -0
  29. package/dist/codebase-index/concept-enrichment.d.ts +154 -0
  30. package/dist/codebase-index/context-retrieval.d.ts +91 -0
  31. package/dist/codebase-index/embedding-pass.d.ts +95 -0
  32. package/dist/codebase-index/graph-adjacency-cache.d.ts +36 -0
  33. package/dist/codebase-index/graph-rank-pass.d.ts +46 -0
  34. package/dist/codebase-index/graph-rank.d.ts +198 -0
  35. package/dist/codebase-index/index-service.d.ts +15 -1
  36. package/dist/codebase-index/index.d.ts +34 -19
  37. package/dist/codebase-index/index.js +126 -9
  38. package/dist/codebase-index/parser-worker-script.js +3 -3
  39. package/dist/codebase-index/perf-metrics.d.ts +19 -0
  40. package/dist/codebase-index/project-server-protocol.d.ts +2 -0
  41. package/dist/codebase-index/project-server-query-cache.d.ts +4 -0
  42. package/dist/codebase-index/project-server.js +54 -7
  43. package/dist/codebase-index/repo-map-fallback.d.ts +18 -0
  44. package/dist/codebase-index/repo-map-render.d.ts +42 -0
  45. package/dist/codebase-index/repo-map-types.d.ts +21 -0
  46. package/dist/codebase-index/repo-map.d.ts +28 -16
  47. package/dist/codebase-index/schema.d.ts +20 -0
  48. package/dist/codebase-index/worker-protocol.d.ts +47 -1
  49. package/dist/codebase-index/worker.js +11 -5
  50. package/dist/codebase-index/writer-concepts.d.ts +84 -0
  51. package/dist/codebase-index/writer-graph-decorate.d.ts +30 -0
  52. package/dist/codebase-index/writer-graph-reader.d.ts +22 -0
  53. package/dist/codebase-index/writer-rank.d.ts +78 -0
  54. package/dist/codebase-index/writer-schema.d.ts +51 -0
  55. package/dist/codebase-index/writer-vectors.d.ts +53 -0
  56. package/dist/codebase-index/writer.d.ts +59 -0
  57. package/dist/edit.js +7 -7
  58. package/dist/exec.js +1 -1
  59. package/dist/{go-parser-D7ELWQ7F.js → go-parser-QIEXU3P2.js} +4 -2
  60. package/dist/index.d.ts +48 -48
  61. package/dist/index.js +43 -19
  62. package/dist/pack.js +16 -16
  63. package/dist/{parser-dispatch-BDVCJXTV.js → parser-dispatch-37FT3EXQ.js} +4 -4
  64. package/dist/patch.js +7 -7
  65. package/dist/{py-parser-QC6MR4GB.js → py-parser-6GJTGUXK.js} +3 -3
  66. package/dist/read.js +7 -7
  67. package/dist/replace.js +7 -7
  68. package/dist/tool-tier.js +17 -17
  69. package/dist/write.js +7 -7
  70. package/package.json +5 -5
@@ -9,7 +9,7 @@ import {
9
9
  projectIndexServerBuildId,
10
10
  projectIndexServerEndpoint,
11
11
  projectIndexServerMetadataPath
12
- } from "./chunk-GDDXX27P.js";
12
+ } from "./chunk-MBR5VAB5.js";
13
13
  import {
14
14
  CircuitOpenError,
15
15
  IndexTimeoutError,
@@ -24,7 +24,10 @@ import {
24
24
  searchService,
25
25
  statsService,
26
26
  symbolGraphService
27
- } from "./chunk-N3K2SFEI.js";
27
+ } from "./chunk-52UXXQMP.js";
28
+ import {
29
+ recordIpcPending
30
+ } from "./chunk-ZKC5UNGD.js";
28
31
  import {
29
32
  isIndexablePath
30
33
  } from "./chunk-YOHO4DVT.js";
@@ -385,6 +388,7 @@ var ProjectServerConnection = class {
385
388
  onAbort,
386
389
  onProgress: options.onProgress
387
390
  });
391
+ recordIpcPending(this.pending.size);
388
392
  if (signal && onAbort) {
389
393
  signal.addEventListener("abort", onAbort, { once: true });
390
394
  if (signal.aborted) {
@@ -1032,6 +1036,7 @@ async function callInline(op, args, opts) {
1032
1036
  }
1033
1037
  var chain = Promise.resolve();
1034
1038
  function withMutex(job) {
1039
+ if (process.env["WRONGSTACK_INDEX_BENCH_NO_HOST_MUTEX"] === "1") return job();
1035
1040
  const run = chain.then(job, job);
1036
1041
  chain = run.then(
1037
1042
  () => void 0,
@@ -1048,6 +1053,7 @@ function circuitOpenError() {
1048
1053
  var DEFAULT_DEBOUNCE_MS = 400;
1049
1054
  var DEFAULT_COALESCE_WINDOW_MS = 50;
1050
1055
  var debounceTimers = /* @__PURE__ */ new Map();
1056
+ var pendingReindexCompletions = /* @__PURE__ */ new Map();
1051
1057
  var readyReindexBatches = /* @__PURE__ */ new Map();
1052
1058
  function debounceKey(projectRoot, indexDir, file) {
1053
1059
  return JSON.stringify([projectRoot, indexDir ?? "", file]);
@@ -1055,6 +1061,11 @@ function debounceKey(projectRoot, indexDir, file) {
1055
1061
  function reindexBatchKey(projectRoot, indexDir) {
1056
1062
  return JSON.stringify([projectRoot, indexDir ?? ""]);
1057
1063
  }
1064
+ function settleReindexCompletions(completions, _error) {
1065
+ for (const completion of completions) {
1066
+ completion.resolve();
1067
+ }
1068
+ }
1058
1069
  function flushReadyReindexBatch(key) {
1059
1070
  const batch = readyReindexBatches.get(key);
1060
1071
  if (!batch) return;
@@ -1062,6 +1073,7 @@ function flushReadyReindexBatch(key) {
1062
1073
  if (!indexCircuitBreaker.allowRequest()) {
1063
1074
  const error = circuitOpenError();
1064
1075
  for (const onError of batch.onErrors) onError(error);
1076
+ settleReindexCompletions(batch.completions, error);
1065
1077
  return;
1066
1078
  }
1067
1079
  void withMutex(
@@ -1075,21 +1087,28 @@ function flushReadyReindexBatch(key) {
1075
1087
  { timeoutMs: batch.timeoutMs }
1076
1088
  )
1077
1089
  ).then(
1078
- () => indexCircuitBreaker.recordSuccess(),
1090
+ () => {
1091
+ indexCircuitBreaker.recordSuccess();
1092
+ settleReindexCompletions(batch.completions);
1093
+ },
1079
1094
  (err) => {
1080
1095
  indexCircuitBreaker.recordFailure(err);
1081
1096
  for (const onError of batch.onErrors) onError(err);
1097
+ settleReindexCompletions(batch.completions, err);
1082
1098
  }
1083
1099
  );
1084
1100
  }
1085
1101
  function addReadyReindex(opts) {
1086
1102
  const key = reindexBatchKey(opts.projectRoot, opts.indexDir);
1087
1103
  const windowMs = opts.coalesceWindowMs ?? DEFAULT_COALESCE_WINDOW_MS;
1104
+ const pending2 = pendingReindexCompletions.get(key);
1105
+ pendingReindexCompletions.delete(key);
1088
1106
  const existing = readyReindexBatches.get(key);
1089
1107
  if (existing) {
1090
1108
  existing.files.add(opts.file);
1091
1109
  existing.timeoutMs = Math.max(existing.timeoutMs, opts.timeoutMs);
1092
1110
  if (opts.onError) existing.onErrors.add(opts.onError);
1111
+ if (pending2) for (const completion of pending2) existing.completions.add(completion);
1093
1112
  if (windowMs > 0 && existing.flush) {
1094
1113
  clearTimeout(existing.flush);
1095
1114
  existing.flush = setTimeout(() => flushReadyReindexBatch(key), windowMs);
@@ -1102,7 +1121,8 @@ function addReadyReindex(opts) {
1102
1121
  indexDir: opts.indexDir,
1103
1122
  files: /* @__PURE__ */ new Set([opts.file]),
1104
1123
  timeoutMs: opts.timeoutMs,
1105
- onErrors: new Set(opts.onError ? [opts.onError] : [])
1124
+ onErrors: new Set(opts.onError ? [opts.onError] : []),
1125
+ completions: pending2 ?? /* @__PURE__ */ new Set()
1106
1126
  };
1107
1127
  batch.flush = setTimeout(() => flushReadyReindexBatch(key), Math.max(0, windowMs));
1108
1128
  batch.flush.unref?.();
@@ -1170,7 +1190,13 @@ async function runStartupIndex(opts) {
1170
1190
  }
1171
1191
  function enqueueReindex(opts) {
1172
1192
  const files = opts.files.filter(isIndexableFile);
1173
- if (files.length === 0) return;
1193
+ if (files.length === 0) return Promise.resolve();
1194
+ const completion = new Promise((resolve, reject) => {
1195
+ const key = reindexBatchKey(opts.projectRoot, opts.indexDir);
1196
+ const pending2 = pendingReindexCompletions.get(key) ?? /* @__PURE__ */ new Set();
1197
+ pending2.add({ resolve, reject });
1198
+ pendingReindexCompletions.set(key, pending2);
1199
+ });
1174
1200
  const ms = opts.debounceMs ?? DEFAULT_DEBOUNCE_MS;
1175
1201
  for (const file of files) {
1176
1202
  const key = debounceKey(opts.projectRoot, opts.indexDir, file);
@@ -1190,6 +1216,7 @@ function enqueueReindex(opts) {
1190
1216
  timer.unref?.();
1191
1217
  debounceTimers.set(key, timer);
1192
1218
  }
1219
+ return completion;
1193
1220
  }
1194
1221
  function cancelPendingReindexes() {
1195
1222
  for (const t of debounceTimers.values()) clearTimeout(t);
@@ -1197,7 +1224,15 @@ function cancelPendingReindexes() {
1197
1224
  for (const batch of readyReindexBatches.values()) {
1198
1225
  if (batch.flush) clearTimeout(batch.flush);
1199
1226
  }
1227
+ const cancelled = new Error("pending reindex cancelled");
1228
+ for (const batch of readyReindexBatches.values()) {
1229
+ settleReindexCompletions(batch.completions, cancelled);
1230
+ }
1200
1231
  readyReindexBatches.clear();
1232
+ for (const completions of pendingReindexCompletions.values()) {
1233
+ settleReindexCompletions(completions, cancelled);
1234
+ }
1235
+ pendingReindexCompletions.clear();
1201
1236
  }
1202
1237
  async function searchCodebaseIndex(args, opts = {}) {
1203
1238
  return callIndexOp("search", args, {
@@ -1211,6 +1246,12 @@ async function codebaseIndexStats(args, opts = {}) {
1211
1246
  signal: opts.signal
1212
1247
  });
1213
1248
  }
1249
+ async function codebaseContext(args) {
1250
+ return callIndexOp("context", args, { timeoutMs: DEFAULT_QUERY_TIMEOUT_MS });
1251
+ }
1252
+ async function codebaseVectorSearch(args) {
1253
+ return callIndexOp("vectorSearch", args, { timeoutMs: DEFAULT_QUERY_TIMEOUT_MS });
1254
+ }
1214
1255
  async function packageGraphService2(args) {
1215
1256
  return callIndexOp("packageGraph", args, { timeoutMs: DEFAULT_QUERY_TIMEOUT_MS });
1216
1257
  }
@@ -1260,6 +1301,8 @@ export {
1260
1301
  cancelPendingReindexes,
1261
1302
  searchCodebaseIndex,
1262
1303
  codebaseIndexStats,
1304
+ codebaseContext,
1305
+ codebaseVectorSearch,
1263
1306
  packageGraphService2 as packageGraphService,
1264
1307
  fileGraphService2 as fileGraphService,
1265
1308
  symbolGraphService2 as symbolGraphService,
@@ -1269,4 +1312,4 @@ export {
1269
1312
  checkCodebaseIndexServerHealth,
1270
1313
  ensureCodebaseIndexServer
1271
1314
  };
1272
- //# sourceMappingURL=chunk-ZTCJCYLN.js.map
1315
+ //# sourceMappingURL=chunk-TI5COGLY.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  enqueueReindex
3
- } from "./chunk-ZTCJCYLN.js";
3
+ } from "./chunk-TI5COGLY.js";
4
4
  import {
5
5
  resolveRealInsideRoot,
6
6
  safeResolveReal,
@@ -395,4 +395,4 @@ function extractPatchedFiles(output) {
395
395
  export {
396
396
  patchTool
397
397
  };
398
- //# sourceMappingURL=chunk-CGXTR34H.js.map
398
+ //# sourceMappingURL=chunk-TU5MTW2S.js.map
@@ -3,6 +3,7 @@ import {
3
3
  } from "./chunk-RV7BVTDG.js";
4
4
  import {
5
5
  codebaseAstReplaceTool,
6
+ codebaseContextTool,
6
7
  codebaseImpactAnalysisTool,
7
8
  codebaseIncomingCallsTool,
8
9
  codebaseIndexTool,
@@ -14,7 +15,7 @@ import {
14
15
  codebaseStatsTool,
15
16
  codebaseTargetedTestTool,
16
17
  deadCodeScanTool
17
- } from "./chunk-YEISRT4S.js";
18
+ } from "./chunk-HWXIRVKH.js";
18
19
  import {
19
20
  planTool
20
21
  } from "./chunk-5KS24LTS.js";
@@ -62,7 +63,7 @@ import {
62
63
  } from "./chunk-AQ5YBURX.js";
63
64
  import {
64
65
  patchTool
65
- } from "./chunk-CGXTR34H.js";
66
+ } from "./chunk-TU5MTW2S.js";
66
67
  import {
67
68
  jsonTool
68
69
  } from "./chunk-VZGPASGD.js";
@@ -88,7 +89,7 @@ import {
88
89
  } from "./chunk-7N5U2RAU.js";
89
90
  import {
90
91
  replaceTool
91
- } from "./chunk-IYH4OHBP.js";
92
+ } from "./chunk-DKHMPKDG.js";
92
93
  import {
93
94
  globTool
94
95
  } from "./chunk-ASEXQRA7.js";
@@ -100,11 +101,11 @@ import {
100
101
  checkAndBlockKillCommand,
101
102
  diagnoseBashism,
102
103
  shellArgs
103
- } from "./chunk-NN2SNP2R.js";
104
+ } from "./chunk-6H4ERJP7.js";
104
105
  import {
105
106
  detectDanger,
106
107
  execTool
107
- } from "./chunk-KDEXUQY7.js";
108
+ } from "./chunk-MGPR7VG3.js";
108
109
  import {
109
110
  buildChildEnv
110
111
  } from "./chunk-BTSFTGIL.js";
@@ -133,13 +134,13 @@ import {
133
134
  } from "./chunk-SOR7OCYP.js";
134
135
  import {
135
136
  readTool
136
- } from "./chunk-MK2JK35J.js";
137
+ } from "./chunk-UOYRAS4J.js";
137
138
  import {
138
139
  writeTool
139
- } from "./chunk-GKSG5CPH.js";
140
+ } from "./chunk-KVTEIUND.js";
140
141
  import {
141
142
  editTool
142
- } from "./chunk-DK4J2WMH.js";
143
+ } from "./chunk-7XUEPBNT.js";
143
144
  import {
144
145
  resolvePowerShell
145
146
  } from "./chunk-KE7A76VC.js";
@@ -474,14 +475,72 @@ var pwshTool = {
474
475
  const startedAt = Date.now();
475
476
  const detached = !isWin;
476
477
  if (isBackground) {
477
- const child2 = spawn(bin, args, {
478
+ let child2;
479
+ try {
480
+ child2 = spawn(bin, args, {
481
+ cwd: targetCwd,
482
+ env,
483
+ detached,
484
+ stdio: ["ignore", "ignore", "ignore"],
485
+ windowsHide: true
486
+ });
487
+ } catch (err) {
488
+ registry.afterCall(Date.now() - startedAt, true, isBackground);
489
+ emitProcessStarted({
490
+ parentPid: process.pid,
491
+ command: redactCommand(`${bin} ${args.join(" ")}`),
492
+ args: redactCommand(args.join(" ")).split(" ").filter(Boolean),
493
+ cwd: targetCwd,
494
+ background: true,
495
+ startedAt: new Date(startedAt).toISOString()
496
+ });
497
+ emitProcessCompleted({
498
+ exitCode: 1,
499
+ durationMs: Date.now() - startedAt,
500
+ stdoutBytes: 0,
501
+ stderrBytes: 0,
502
+ timedOut: false,
503
+ endedAt: (/* @__PURE__ */ new Date()).toISOString()
504
+ });
505
+ yield {
506
+ type: "final",
507
+ output: {
508
+ output: "",
509
+ exit_code: 1,
510
+ timed_out: false,
511
+ pid: null,
512
+ error: `pwsh: spawn failed: ${err instanceof Error ? err.message : String(err)}`
513
+ }
514
+ };
515
+ return;
516
+ }
517
+ const pid2 = child2.pid;
518
+ let bgTelemetryCompleted = false;
519
+ let bgErrorOccurred = false;
520
+ let bgSettled = false;
521
+ emitProcessStarted({
522
+ ...pid2 !== void 0 ? { pid: pid2 } : {},
523
+ parentPid: process.pid,
524
+ command: redactCommand(`${bin} ${args.join(" ")}`),
525
+ args: redactCommand(args.join(" ")).split(" ").filter(Boolean),
478
526
  cwd: targetCwd,
479
- env,
480
- detached,
481
- stdio: ["ignore", "ignore", "ignore"],
482
- windowsHide: true
527
+ background: true,
528
+ startedAt: new Date(startedAt).toISOString()
483
529
  });
484
- const pid2 = child2.pid;
530
+ const completeBackground = (exitCode, sig) => {
531
+ if (bgTelemetryCompleted) return;
532
+ bgTelemetryCompleted = true;
533
+ emitProcessCompleted({
534
+ ...pid2 !== void 0 ? { pid: pid2 } : {},
535
+ exitCode,
536
+ ...sig ? { signal: sig } : {},
537
+ durationMs: Date.now() - startedAt,
538
+ stdoutBytes: 0,
539
+ stderrBytes: 0,
540
+ timedOut: false,
541
+ endedAt: (/* @__PURE__ */ new Date()).toISOString()
542
+ });
543
+ };
485
544
  if (typeof pid2 === "number") {
486
545
  registry.register({
487
546
  pid: pid2,
@@ -493,10 +552,19 @@ var pwshTool = {
493
552
  processGroupLeader: detached && child2.pid === pid2,
494
553
  background: true
495
554
  });
496
- child2.on("close", () => registry.unregister(pid2));
497
- child2.on("error", () => {
555
+ child2.on("close", (code, signal) => {
556
+ bgSettled = true;
498
557
  registry.unregister(pid2);
558
+ if (bgErrorOccurred) return;
559
+ const failed = code !== 0 && code !== null || !!signal;
560
+ registry.afterCall(Date.now() - startedAt, failed, isBackground);
561
+ completeBackground(code ?? (signal ? 1 : 0), signal ?? void 0);
562
+ });
563
+ child2.on("error", () => {
564
+ if (bgSettled) return;
565
+ bgErrorOccurred = true;
499
566
  registry.afterCall(Date.now() - startedAt, true, isBackground);
567
+ completeBackground(1);
500
568
  });
501
569
  child2.unref();
502
570
  const jobId = `job_${pid2}`;
@@ -521,6 +589,7 @@ Working directory: ${targetCwd}`,
521
589
  };
522
590
  return;
523
591
  }
592
+ completeBackground(1);
524
593
  yield {
525
594
  type: "final",
526
595
  output: {
@@ -534,13 +603,46 @@ Working directory: ${targetCwd}`,
534
603
  return;
535
604
  }
536
605
  const spool = createOutputSpool({ tool: "pwsh", thresholdBytes: MAX_OUTPUT });
537
- const child = spawn(bin, args, {
538
- cwd: targetCwd,
539
- env,
540
- detached,
541
- stdio: ["ignore", "pipe", "pipe"],
542
- windowsHide: true
543
- });
606
+ let child;
607
+ try {
608
+ child = spawn(bin, args, {
609
+ cwd: targetCwd,
610
+ env,
611
+ detached,
612
+ stdio: ["ignore", "pipe", "pipe"],
613
+ windowsHide: true
614
+ });
615
+ } catch (err) {
616
+ registry.afterCall(Date.now() - startedAt, true, isBackground);
617
+ spool.finalize();
618
+ emitProcessStarted({
619
+ parentPid: process.pid,
620
+ command: redactCommand(`${bin} ${args.join(" ")}`),
621
+ args: redactCommand(args.join(" ")).split(" ").filter(Boolean),
622
+ cwd: targetCwd,
623
+ background: false,
624
+ startedAt: new Date(startedAt).toISOString()
625
+ });
626
+ emitProcessCompleted({
627
+ exitCode: 1,
628
+ durationMs: Date.now() - startedAt,
629
+ stdoutBytes: 0,
630
+ stderrBytes: 0,
631
+ timedOut: false,
632
+ endedAt: (/* @__PURE__ */ new Date()).toISOString()
633
+ });
634
+ yield {
635
+ type: "final",
636
+ output: {
637
+ output: "",
638
+ exit_code: 1,
639
+ timed_out: false,
640
+ pid: null,
641
+ error: `pwsh: spawn failed: ${err instanceof Error ? err.message : String(err)}`
642
+ }
643
+ };
644
+ return;
645
+ }
544
646
  const pid = child.pid;
545
647
  let stdoutBytes = 0;
546
648
  let stderrBytes = 0;
@@ -688,17 +790,25 @@ Working directory: ${targetCwd}`,
688
790
  push({ kind: "data", text });
689
791
  pauseIfFlooded();
690
792
  };
691
- child.stdout?.on("data", (chunk) => onData(chunk, "stdout"));
692
- child.stderr?.on("data", (chunk) => onData(chunk, "stderr"));
793
+ const onStdoutData = (chunk) => onData(chunk, "stdout");
794
+ const onStderrData = (chunk) => onData(chunk, "stderr");
795
+ child.stdout?.on("data", onStdoutData);
796
+ child.stderr?.on("data", onStderrData);
797
+ let fgErrorOccurred = false;
798
+ let sawClose = false;
693
799
  child.on("error", (err) => {
800
+ if (sawClose) return;
801
+ fgErrorOccurred = true;
694
802
  for (const t of timers) clearTimeout(t);
695
803
  registry.afterCall(Date.now() - startedAt, true);
696
804
  completeForeground(1);
697
805
  push({ kind: "error", err });
698
806
  });
699
807
  child.on("close", (code, signal) => {
808
+ sawClose = true;
700
809
  for (const t of timers) clearTimeout(t);
701
810
  if (typeof pid === "number") registry.unregister(pid);
811
+ if (fgErrorOccurred) return;
702
812
  registry.afterCall(Date.now() - startedAt, code !== 0 && code !== null);
703
813
  completeForeground(timedOut ? 124 : code ?? (signal ? 1 : 0), signal ?? void 0);
704
814
  const tail = stdoutDecoder.end() + stderrDecoder.end();
@@ -713,7 +823,33 @@ Working directory: ${targetCwd}`,
713
823
  while (true) {
714
824
  const c = await next();
715
825
  resumeIfDrained();
716
- if (c.kind === "error") throw c.err;
826
+ if (c.kind === "error") {
827
+ const isAbort = c.err?.code === "ABORT_ERR" || callerSignal.aborted;
828
+ const remainder = flush();
829
+ if (remainder !== null) {
830
+ yield { type: "partial_output", text: remainder };
831
+ }
832
+ const spooled = spool.finalize();
833
+ yield {
834
+ type: "final",
835
+ output: {
836
+ output: normalizeCommandOutput(buf) + (spooled ? spoolNote(spooled) : ""),
837
+ exit_code: isAbort ? 124 : 1,
838
+ timed_out: isAbort,
839
+ pid: pid ?? null,
840
+ error: isAbort ? "Command aborted by user or signal" : c.err.message
841
+ }
842
+ };
843
+ ctx.recordSideEffect?.({
844
+ toolUseId: `pwsh-${Date.now()}`,
845
+ toolName: "pwsh",
846
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
847
+ input: { command: redactCommand(input.command) },
848
+ outcome: isAbort ? "aborted" : `error (${c.err.message})`,
849
+ risk: "shell"
850
+ });
851
+ return;
852
+ }
717
853
  if (c.kind === "end") {
718
854
  const remainder = flush();
719
855
  if (remainder !== null) {
@@ -739,14 +875,16 @@ Working directory: ${targetCwd}`,
739
875
  const finalResultText = formattedOutput + (spooled ? spoolNote(spooled) : "") + (hint ? `
740
876
 
741
877
  ${hint}` : "") + cautionText;
742
- ctx.recordSideEffect?.({
743
- toolUseId: `pwsh-${Date.now()}`,
744
- toolName: "pwsh",
745
- ts: (/* @__PURE__ */ new Date()).toISOString(),
746
- input: { command: redactCommand(input.command) },
747
- outcome: timedOut ? `timed out (exit ${c.code})` : `exit ${c.code}`,
748
- risk: "shell"
749
- });
878
+ if (!fgErrorOccurred) {
879
+ ctx.recordSideEffect?.({
880
+ toolUseId: `pwsh-${Date.now()}`,
881
+ toolName: "pwsh",
882
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
883
+ input: { command: redactCommand(input.command) },
884
+ outcome: timedOut ? `timed out (exit ${c.code})` : `exit ${c.code}`,
885
+ risk: "shell"
886
+ });
887
+ }
750
888
  const isAborted = callerSignal.aborted;
751
889
  yield {
752
890
  type: "final",
@@ -768,7 +906,16 @@ ${hint}` : "") + cautionText;
768
906
  }
769
907
  } finally {
770
908
  for (const t of timers) clearTimeout(t);
909
+ spool.finalize();
771
910
  callerSignal.removeEventListener("abort", onAbort);
911
+ child.stdout?.off("data", onStdoutData);
912
+ child.stderr?.off("data", onStderrData);
913
+ child.stdout?.destroy();
914
+ child.stderr?.destroy();
915
+ if (!sawClose && child.exitCode === null && !child.killed) {
916
+ if (typeof pid === "number") registry.kill(pid, { force: true });
917
+ else killWithTimeout(2e3);
918
+ }
772
919
  }
773
920
  }
774
921
  };
@@ -1087,7 +1234,8 @@ var BUILTIN_TOOL_DESCRIPTIONS = {
1087
1234
  "codebase-stats": "Report codebase-index health, indexed file and symbol counts, languages, and freshness. Use it before relying on indexed discovery results.",
1088
1235
  "codebase-search": "Search indexed symbols, signatures, and documentation with optional language, kind, path, or LSP-kind filters. Use it for semantic discovery before broad text search.",
1089
1236
  "codebase-skeleton": "Extract a compact structural skeleton from a source file or directory, preserving declarations while omitting implementation detail. Use it to understand unfamiliar code quickly.",
1090
- "codebase-repo-map": "Generate a reference-weighted, token-budgeted Repository Map of the codebase within ~1200 tokens by default. Use at the beginning of complex tasks or when navigating unfamiliar repositories to get a bird-eye view of the architecture.",
1237
+ "codebase-context": "Find the files and declarations a task touches from a plain-language description. Ranked symbol search seeds a personalised walk over the reference graph, so results include what the matches are structurally attached to, not just what matched by name. Start here for any task spanning more than one file.",
1238
+ "codebase-repo-map": "Generate a centrality-ranked, token-budgeted Repository Map within ~1200 tokens by default: package clusters with their hub file, the repo-wide hotspots, then the signatures of the most central files. Use at the beginning of complex tasks or when navigating unfamiliar repositories to get a bird-eye view of the architecture.",
1091
1239
  "codebase-impact-analysis": "Find likely callers, dependents, related tests, and change risk for a named symbol. Use it before changing a public or widely used declaration.",
1092
1240
  "codebase-targeted-test": "Discover and run tests that cover a specified symbol, source file, or explicit test files. Use it for focused regression validation after a change.",
1093
1241
  "security-ast-scan": "Statically scan source code for supported security patterns and return findings with locations. Use it as a focused code check, not as a substitute for a full security assessment.",
@@ -1159,6 +1307,7 @@ var TIER1_TOOLS = [
1159
1307
  codebaseSearchTool,
1160
1308
  codebaseSkeletonTool,
1161
1309
  codebaseRepoMapTool,
1310
+ codebaseContextTool,
1162
1311
  codebaseImpactAnalysisTool,
1163
1312
  codebaseTargetedTestTool,
1164
1313
  securityAstScanTool,
@@ -1220,6 +1369,7 @@ var rawBuiltinTools = [
1220
1369
  codebaseSearchTool,
1221
1370
  codebaseSkeletonTool,
1222
1371
  codebaseRepoMapTool,
1372
+ codebaseContextTool,
1223
1373
  codebaseImpactAnalysisTool,
1224
1374
  codebaseTargetedTestTool,
1225
1375
  securityAstScanTool,
@@ -1288,4 +1438,4 @@ export {
1288
1438
  TIER3_TOOLS,
1289
1439
  builtinTools
1290
1440
  };
1291
- //# sourceMappingURL=chunk-AB2CAUOP.js.map
1441
+ //# sourceMappingURL=chunk-UCXFTCAI.js.map
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  getIndexState,
3
3
  searchCodebaseIndex
4
- } from "./chunk-ZTCJCYLN.js";
4
+ } from "./chunk-TI5COGLY.js";
5
5
  import {
6
6
  codebaseIndexDirOverride
7
- } from "./chunk-N3K2SFEI.js";
7
+ } from "./chunk-52UXXQMP.js";
8
8
  import {
9
9
  isBinaryBuffer,
10
10
  safeResolveReal,
@@ -340,4 +340,4 @@ ${interesting.join("\n")}` : "symbols/imports: (none detected)"
340
340
  export {
341
341
  readTool
342
342
  };
343
- //# sourceMappingURL=chunk-MK2JK35J.js.map
343
+ //# sourceMappingURL=chunk-UOYRAS4J.js.map
@@ -94,10 +94,58 @@ function dedupeRefs(refs) {
94
94
  });
95
95
  }
96
96
 
97
+ // src/codebase-index/perf-metrics.ts
98
+ var counters = {
99
+ filesystemBytesRead: 0,
100
+ filesystemReadCount: 0,
101
+ parserGateWaitMs: 0,
102
+ parserGateCalls: 0,
103
+ parserSubprocessCount: 0,
104
+ ipcPendingPeak: 0,
105
+ writeQueueWaitMs: 0,
106
+ writeQueueCalls: 0
107
+ };
108
+ function resetCodebaseIndexPerfMetrics() {
109
+ for (const key of Object.keys(counters)) {
110
+ counters[key] = 0;
111
+ }
112
+ }
113
+ function getCodebaseIndexPerfSnapshot() {
114
+ return { ...counters };
115
+ }
116
+ function recordFilesystemRead(bytes) {
117
+ counters.filesystemBytesRead += Math.max(0, bytes);
118
+ counters.filesystemReadCount++;
119
+ }
120
+ function recordParserGateWait(waitMs) {
121
+ counters.parserGateWaitMs += Math.max(0, waitMs);
122
+ counters.parserGateCalls++;
123
+ }
124
+ function recordParserSubprocess() {
125
+ counters.parserSubprocessCount++;
126
+ }
127
+ function recordIpcPending(depth) {
128
+ counters.ipcPendingPeak = Math.max(counters.ipcPendingPeak, depth);
129
+ }
130
+ function recordWriteQueueWait(waitMs) {
131
+ counters.writeQueueWaitMs += Math.max(0, waitMs);
132
+ counters.writeQueueCalls++;
133
+ }
134
+
97
135
  // src/codebase-index/spawn-gate.ts
98
136
  var chain = Promise.resolve();
99
137
  function withSpawnGate(fn) {
100
- const run = chain.then(fn, fn);
138
+ const queuedAt = performance.now();
139
+ const run = chain.then(
140
+ () => {
141
+ recordParserGateWait(performance.now() - queuedAt);
142
+ return fn();
143
+ },
144
+ () => {
145
+ recordParserGateWait(performance.now() - queuedAt);
146
+ return fn();
147
+ }
148
+ );
101
149
  chain = run.then(
102
150
  () => void 0,
103
151
  () => void 0
@@ -108,6 +156,12 @@ function withSpawnGate(fn) {
108
156
  export {
109
157
  parseParserOutput,
110
158
  parseParserBatchOutput,
159
+ resetCodebaseIndexPerfMetrics,
160
+ getCodebaseIndexPerfSnapshot,
161
+ recordFilesystemRead,
162
+ recordParserSubprocess,
163
+ recordIpcPending,
164
+ recordWriteQueueWait,
111
165
  withSpawnGate
112
166
  };
113
- //# sourceMappingURL=chunk-UCYQTZ7F.js.map
167
+ //# sourceMappingURL=chunk-ZKC5UNGD.js.map