@cortexkit/aft-opencode 0.50.3 → 0.51.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
@@ -8244,6 +8244,120 @@ function skipSpaces(input, start) {
8244
8244
  index++;
8245
8245
  return index;
8246
8246
  }
8247
+ // ../aft-bridge/dist/bash-host-fallback.js
8248
+ import { spawn } from "node:child_process";
8249
+ var BASH_HOST_FALLBACK_BANNER = "[AFT host fallback - module transport down; no rewrites/compression/background]";
8250
+ var BASH_HOST_FALLBACK_MAX_OUTPUT_BYTES = 100 * 1024;
8251
+ var BASH_HOST_FALLBACK_MAX_TIMEOUT_MS = 10 * 60 * 1000;
8252
+ var BASH_HOST_FALLBACK_REFUSAL = "AFT transport is down; only foreground execution is available in host fallback";
8253
+ function bashHostFallbackAskPattern(command, cwd) {
8254
+ return `AFT UNAVAILABLE - host fallback execution:
8255
+
8256
+ Exact command:
8257
+ ${command}
8258
+
8259
+ Working directory:
8260
+ ${cwd}`;
8261
+ }
8262
+ function appendTail(chunks, chunk) {
8263
+ const combined = Buffer.concat([...chunks, chunk]);
8264
+ if (combined.byteLength <= BASH_HOST_FALLBACK_MAX_OUTPUT_BYTES) {
8265
+ return { chunks: [combined], truncated: false };
8266
+ }
8267
+ return {
8268
+ chunks: [combined.subarray(combined.byteLength - BASH_HOST_FALLBACK_MAX_OUTPUT_BYTES)],
8269
+ truncated: true
8270
+ };
8271
+ }
8272
+ function renderOutput(output, exitCode) {
8273
+ const body = output.toString("utf8");
8274
+ const separator = body.length === 0 || body.endsWith(`
8275
+ `) ? "" : `
8276
+ `;
8277
+ return `${BASH_HOST_FALLBACK_BANNER}
8278
+ ${body}${separator}[exit code: ${exitCode}]`;
8279
+ }
8280
+ async function runBashHostFallback(options) {
8281
+ const timeoutMs = Math.min(Math.max(1, options.timeoutMs ?? BASH_HOST_FALLBACK_MAX_TIMEOUT_MS), BASH_HOST_FALLBACK_MAX_TIMEOUT_MS);
8282
+ if (options.signal?.aborted) {
8283
+ throw new DOMException("The host fallback command was aborted", "AbortError");
8284
+ }
8285
+ return await new Promise((resolve2, reject) => {
8286
+ const child = spawn(options.command, {
8287
+ cwd: options.projectRoot,
8288
+ shell: true,
8289
+ env: { ...process.env, ...options.env },
8290
+ stdio: ["ignore", "pipe", "pipe"],
8291
+ detached: process.platform !== "win32",
8292
+ windowsHide: true
8293
+ });
8294
+ let chunks = [];
8295
+ let truncated = false;
8296
+ let timedOut = false;
8297
+ let aborted = false;
8298
+ let settled = false;
8299
+ let abortForceTimer;
8300
+ const capture = (chunk) => {
8301
+ const next = appendTail(chunks, Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
8302
+ chunks = next.chunks;
8303
+ truncated ||= next.truncated;
8304
+ };
8305
+ child.stdout?.on("data", capture);
8306
+ child.stderr?.on("data", capture);
8307
+ const kill = (signal) => {
8308
+ if (child.exitCode !== null || child.signalCode !== null)
8309
+ return;
8310
+ if (process.platform !== "win32" && child.pid !== undefined) {
8311
+ try {
8312
+ process.kill(-child.pid, signal);
8313
+ return;
8314
+ } catch {}
8315
+ }
8316
+ child.kill(signal);
8317
+ };
8318
+ const onAbort = () => {
8319
+ aborted = true;
8320
+ kill("SIGTERM");
8321
+ abortForceTimer = setTimeout(() => kill("SIGKILL"), 250);
8322
+ abortForceTimer.unref?.();
8323
+ };
8324
+ options.signal?.addEventListener("abort", onAbort, { once: true });
8325
+ const timer = setTimeout(() => {
8326
+ timedOut = true;
8327
+ kill("SIGKILL");
8328
+ }, timeoutMs);
8329
+ const cleanup = () => {
8330
+ clearTimeout(timer);
8331
+ if (abortForceTimer !== undefined)
8332
+ clearTimeout(abortForceTimer);
8333
+ options.signal?.removeEventListener("abort", onAbort);
8334
+ };
8335
+ child.once("error", (error2) => {
8336
+ if (settled)
8337
+ return;
8338
+ settled = true;
8339
+ cleanup();
8340
+ reject(error2);
8341
+ });
8342
+ child.once("close", (code) => {
8343
+ if (settled)
8344
+ return;
8345
+ settled = true;
8346
+ cleanup();
8347
+ if (aborted) {
8348
+ reject(new DOMException("The host fallback command was aborted", "AbortError"));
8349
+ return;
8350
+ }
8351
+ const exitCode = timedOut ? 124 : code ?? 1;
8352
+ resolve2({
8353
+ success: true,
8354
+ output: renderOutput(Buffer.concat(chunks), exitCode),
8355
+ exit_code: exitCode,
8356
+ truncated
8357
+ });
8358
+ });
8359
+ });
8360
+ }
8247
8361
  // ../aft-bridge/dist/bash-timeout.js
8248
8362
  function resolveBashKillTimeout(modelTimeout, foregroundWaitMs) {
8249
8363
  if (modelTimeout !== undefined && modelTimeout >= foregroundWaitMs) {
@@ -8252,7 +8366,7 @@ function resolveBashKillTimeout(modelTimeout, foregroundWaitMs) {
8252
8366
  return;
8253
8367
  }
8254
8368
  // ../aft-bridge/dist/bridge.js
8255
- import { spawn } from "node:child_process";
8369
+ import { spawn as spawn2 } from "node:child_process";
8256
8370
  import { createHash } from "node:crypto";
8257
8371
  import { readFileSync } from "node:fs";
8258
8372
  import { homedir as homedir2 } from "node:os";
@@ -8282,56 +8396,6 @@ function isPassiveCommand(command) {
8282
8396
  return PASSIVE_COMMANDS.has(command);
8283
8397
  }
8284
8398
 
8285
- // ../aft-bridge/dist/status-bar.js
8286
- var STATUS_BAR_HEARTBEAT_CALLS = 15;
8287
- function createStatusBarEmitState() {
8288
- return { callsSinceEmit: 0 };
8289
- }
8290
- function parseStatusBarCounts(value) {
8291
- if (!value || typeof value !== "object")
8292
- return;
8293
- const record = value;
8294
- const num = (key) => {
8295
- const raw = record[key];
8296
- return typeof raw === "number" && Number.isFinite(raw) ? raw : 0;
8297
- };
8298
- return {
8299
- errors: num("errors"),
8300
- warnings: num("warnings"),
8301
- dead_code: num("dead_code"),
8302
- unused_exports: num("unused_exports"),
8303
- duplicates: num("duplicates"),
8304
- todos: num("todos"),
8305
- tier2_stale: record.tier2_stale === true,
8306
- ...typeof record.line === "string" ? { line: record.line } : {}
8307
- };
8308
- }
8309
- function countsEqual(a, b) {
8310
- return a.errors === b.errors && a.warnings === b.warnings && a.dead_code === b.dead_code && a.unused_exports === b.unused_exports && a.duplicates === b.duplicates && a.todos === b.todos && a.tier2_stale === b.tier2_stale && a.line === b.line;
8311
- }
8312
- function shouldEmitStatusBar(state, next) {
8313
- const changed = state.last === undefined || !countsEqual(state.last, next);
8314
- state.callsSinceEmit += 1;
8315
- const heartbeat = state.callsSinceEmit >= STATUS_BAR_HEARTBEAT_CALLS;
8316
- if (changed || heartbeat) {
8317
- state.last = next;
8318
- state.callsSinceEmit = 0;
8319
- return true;
8320
- }
8321
- return false;
8322
- }
8323
- function formatStatusBar(counts) {
8324
- if (counts.line !== undefined)
8325
- return counts.line;
8326
- const staleMark = counts.tier2_stale ? "~" : "";
8327
- return `[AFT E${counts.errors} W${counts.warnings} | ` + `${staleMark}D${counts.dead_code} U${counts.unused_exports} C${counts.duplicates} | ` + `T${counts.todos}]`;
8328
- }
8329
- function statusBarLine(counts) {
8330
- return `
8331
-
8332
- ${formatStatusBar(counts)}`;
8333
- }
8334
-
8335
8399
  // ../aft-bridge/dist/bridge.js
8336
8400
  var DEFAULT_BRIDGE_TIMEOUT_MS = 30000;
8337
8401
  var BRIDGE_HANG_TIMEOUT_THRESHOLD = 2;
@@ -8460,6 +8524,14 @@ class BridgeTransportTimeoutError extends Error {
8460
8524
  this.name = "BridgeTransportTimeoutError";
8461
8525
  }
8462
8526
  }
8527
+
8528
+ class BridgeTransportUnavailableError extends Error {
8529
+ code = "bridge_transport_unavailable";
8530
+ constructor(message, options) {
8531
+ super(message, options);
8532
+ this.name = "BridgeTransportUnavailableError";
8533
+ }
8534
+ }
8463
8535
  function isBridgeTransportTimeout(err) {
8464
8536
  return err instanceof Error && err.code === "transport_timeout";
8465
8537
  }
@@ -8502,7 +8574,6 @@ class BinaryBridge {
8502
8574
  configureWarningClients = new Map;
8503
8575
  restartResetTimer = null;
8504
8576
  lastChildActivityAt = 0;
8505
- lastStatusBar;
8506
8577
  consecutiveRequestTimeouts = 0;
8507
8578
  errorPrefix;
8508
8579
  logger;
@@ -8602,6 +8673,20 @@ class BinaryBridge {
8602
8673
  isAlive() {
8603
8674
  return this.process !== null && this.process.exitCode === null && !this.process.killed;
8604
8675
  }
8676
+ invalidateTransportProcess(error2) {
8677
+ const proc = this.process;
8678
+ if (!proc)
8679
+ return;
8680
+ this.process = null;
8681
+ this.spawnedBinaryFingerprint = null;
8682
+ if (proc.exitCode === null && !proc.killed) {
8683
+ proc.kill("SIGKILL");
8684
+ }
8685
+ this.clearRestartResetTimer();
8686
+ this.configured = false;
8687
+ this.outstandingBackgroundTaskIds.clear();
8688
+ this.rejectAllPending(error2);
8689
+ }
8605
8690
  hasPendingRequests() {
8606
8691
  return this.pending.size > 0;
8607
8692
  }
@@ -8703,7 +8788,7 @@ class BinaryBridge {
8703
8788
  throw new Error(`${this.errorPrefix} Bridge is retiring after the on-disk binary changed; retry to respawn on the updated binary`);
8704
8789
  }
8705
8790
  if (this._shuttingDown) {
8706
- throw new Error(`${this.errorPrefix} Bridge is shutting down, cannot send "${command}"`);
8791
+ throw new BridgeTransportUnavailableError(`${this.errorPrefix} Bridge is shutting down, cannot send "${command}"`);
8707
8792
  }
8708
8793
  if (Object.hasOwn(params, "id")) {
8709
8794
  throw new Error("params cannot contain reserved key 'id'");
@@ -8737,7 +8822,7 @@ class BinaryBridge {
8737
8822
  await this.deliverConfigureWarnings(configResult, params, options);
8738
8823
  await this.checkVersion(implicitTransportOptions);
8739
8824
  if (!this.isAlive()) {
8740
- throw new Error(`${this.errorPrefix} Bridge died during version check. Check logs: ${this.getLogFilePathVia()}`);
8825
+ throw new BridgeTransportUnavailableError(`${this.errorPrefix} Bridge died during version check. Check logs: ${this.getLogFilePathVia()}`);
8741
8826
  }
8742
8827
  this.configured = true;
8743
8828
  } finally {
@@ -8767,6 +8852,7 @@ class BinaryBridge {
8767
8852
  `;
8768
8853
  const keepBridgeOnTimeout = passive || options?.keepBridgeOnTimeout === true;
8769
8854
  let requestSentAt = Date.now();
8855
+ const child = this.process;
8770
8856
  const response = await new Promise((resolve2, reject) => {
8771
8857
  const timer = setTimeout(() => {
8772
8858
  const entry = this.pending.get(id);
@@ -8803,21 +8889,27 @@ class BinaryBridge {
8803
8889
  this.handleTimeout(requestSessionId);
8804
8890
  }, effectiveTimeoutMs);
8805
8891
  this.pending.set(id, { resolve: resolve2, reject, timer, onProgress: options?.onProgress, command });
8806
- if (!this.process?.stdin?.writable) {
8892
+ if (!child?.stdin?.writable) {
8807
8893
  this.pending.delete(id);
8808
8894
  clearTimeout(timer);
8809
- reject(new Error(`${this.errorPrefix} stdin not writable for command "${command}"`));
8895
+ const error2 = new BridgeTransportUnavailableError(`${this.errorPrefix} stdin not writable for command "${command}"`);
8896
+ reject(error2);
8897
+ if (this.process === child)
8898
+ this.invalidateTransportProcess(error2);
8810
8899
  return;
8811
8900
  }
8812
8901
  requestSentAt = Date.now();
8813
- this.process.stdin.write(line, (err) => {
8902
+ child.stdin.write(line, (err) => {
8814
8903
  if (err) {
8904
+ const error2 = new BridgeTransportUnavailableError(`${this.errorPrefix} Failed to write to stdin: ${err.message}`, { cause: err });
8815
8905
  const entry = this.pending.get(id);
8816
8906
  if (entry) {
8817
8907
  this.pending.delete(id);
8818
8908
  clearTimeout(entry.timer);
8819
- entry.reject(new Error(`${this.errorPrefix} Failed to write to stdin: ${err.message}`));
8909
+ entry.reject(error2);
8820
8910
  }
8911
+ if (this.process === child)
8912
+ this.invalidateTransportProcess(error2);
8821
8913
  }
8822
8914
  });
8823
8915
  });
@@ -8977,13 +9069,15 @@ class BinaryBridge {
8977
9069
  });
8978
9070
  }
8979
9071
  ensureSpawned(triggeringSessionId) {
8980
- if (this.isAlive())
9072
+ if (this.isAlive() && this.process?.stdin?.writable)
8981
9073
  return;
9074
+ if (this.process !== null) {
9075
+ this.invalidateTransportProcess(new BridgeTransportUnavailableError(`${this.errorPrefix} Child stdin is not writable`));
9076
+ }
8982
9077
  this.spawnProcess(triggeringSessionId);
8983
9078
  }
8984
9079
  spawnProcess(triggeringSessionId) {
8985
9080
  this._retiringDueToBinaryChange = false;
8986
- this.lastStatusBar = undefined;
8987
9081
  if (triggeringSessionId) {
8988
9082
  this.sessionLogVia(triggeringSessionId, `Spawning binary: ${this.binaryPath} (cwd: ${this.cwd})`);
8989
9083
  } else {
@@ -9024,7 +9118,7 @@ class BinaryBridge {
9024
9118
  }
9025
9119
  }
9026
9120
  }
9027
- const child = spawn(this.binaryPath, [], {
9121
+ const child = spawn2(this.binaryPath, [], {
9028
9122
  cwd: this.cwd,
9029
9123
  stdio: ["pipe", "pipe", "pipe"],
9030
9124
  env
@@ -9054,7 +9148,7 @@ class BinaryBridge {
9054
9148
  if (this.process !== currentChild)
9055
9149
  return;
9056
9150
  this.errorVia(`Process error: ${err.message}${this.formatStderrTail()}`);
9057
- this.handleCrash();
9151
+ this.handleCrash(err);
9058
9152
  });
9059
9153
  child.on("exit", (code, signal) => {
9060
9154
  if (this.process !== currentChild)
@@ -9067,7 +9161,7 @@ class BinaryBridge {
9067
9161
  this.process = null;
9068
9162
  this.configured = false;
9069
9163
  this.clearRestartResetTimer();
9070
- this.rejectAllPending(new Error(`${this.errorPrefix} Binary killed by ${signal}`));
9164
+ this.rejectAllPending(new BridgeTransportUnavailableError(`${this.errorPrefix} Binary killed by ${signal}`));
9071
9165
  return;
9072
9166
  }
9073
9167
  this.handleCrash();
@@ -9222,7 +9316,6 @@ class BinaryBridge {
9222
9316
  this.consecutiveRequestTimeouts = 0;
9223
9317
  this.scheduleRestartCountReset();
9224
9318
  this.accountForBashTaskResponse(entry.command, response);
9225
- this.captureStatusBar(response);
9226
9319
  entry.resolve(response);
9227
9320
  } else if (typeof response.type === "string") {
9228
9321
  this.logVia(`Ignoring unknown stdout push frame type: ${response.type}`);
@@ -9243,14 +9336,6 @@ class BinaryBridge {
9243
9336
  this.outstandingBackgroundTaskIds.add(taskId);
9244
9337
  }
9245
9338
  }
9246
- captureStatusBar(response) {
9247
- const parsed = parseStatusBarCounts(response.status_bar);
9248
- if (parsed)
9249
- this.lastStatusBar = parsed;
9250
- }
9251
- getStatusBar() {
9252
- return this.lastStatusBar;
9253
- }
9254
9339
  handleTimeout(triggeringSessionId) {
9255
9340
  this.consecutiveRequestTimeouts = 0;
9256
9341
  this.spawnedBinaryFingerprint = null;
@@ -9291,7 +9376,7 @@ class BinaryBridge {
9291
9376
  if (tail) {
9292
9377
  this.errorVia(`Binary crashed (restarts: ${this._restartCount})${cause ? `: ${cause.message}` : ""}.${tail}`);
9293
9378
  }
9294
- this.rejectAllPending(new Error(`${this.errorPrefix} Binary crashed (restarts: ${this._restartCount})${cause ? `: ${cause.message}` : ""} (see ${this.getLogFilePathVia()})`));
9379
+ this.rejectAllPending(new BridgeTransportUnavailableError(`${this.errorPrefix} Binary crashed (restarts: ${this._restartCount})${cause ? `: ${cause.message}` : ""} (see ${this.getLogFilePathVia()})`, { cause }));
9295
9380
  if (this._retiringDueToBinaryChange) {
9296
9381
  this.logVia("Binary exited while retiring after an on-disk update; skipping auto-restart");
9297
9382
  return;
@@ -12640,6 +12725,12 @@ function projectRootKeyHash(dir) {
12640
12725
  }
12641
12726
 
12642
12727
  // ../aft-bridge/dist/subc-transport.js
12728
+ class SubcTransportShuttingDownError extends SubcCallError {
12729
+ constructor() {
12730
+ super("terminal", "subc transport is shutting down", "transport_shutting_down");
12731
+ this.name = "SubcTransportShuttingDownError";
12732
+ }
12733
+ }
12643
12734
  var AFT_MODULE_ID = "aft";
12644
12735
  var MAX_CONSECUTIVE_TRANSPORT_FAILURES = 3;
12645
12736
  var BG_STABLE_MS = 5000;
@@ -12981,7 +13072,6 @@ class SubcTransport {
12981
13072
  pool;
12982
13073
  projectRoot;
12983
13074
  generation;
12984
- lastStatusBar;
12985
13075
  cachedStatus = null;
12986
13076
  constructor(pool, projectRoot, generation) {
12987
13077
  this.pool = pool;
@@ -12997,20 +13087,12 @@ class SubcTransport {
12997
13087
  getConcretePoolId() {
12998
13088
  return this.pool.getConcretePoolId();
12999
13089
  }
13000
- getStatusBar() {
13001
- return this.lastStatusBar;
13002
- }
13003
13090
  getCachedStatus() {
13004
13091
  return this.cachedStatus;
13005
13092
  }
13006
13093
  cacheStatusSnapshot(snapshot) {
13007
13094
  this.cachedStatus = snapshot;
13008
13095
  }
13009
- captureStatusBar(response) {
13010
- const parsed = parseStatusBarCounts(response.status_bar);
13011
- if (parsed)
13012
- this.lastStatusBar = parsed;
13013
- }
13014
13096
  identityFor(session) {
13015
13097
  return {
13016
13098
  project_root: this.projectRoot,
@@ -13031,9 +13113,7 @@ class SubcTransport {
13031
13113
  if (preview === true)
13032
13114
  body.preview = true;
13033
13115
  const reply = await this.pool.routeRequest(this.identityFor(sessionId), body, timeoutMs, onProgress, this.generation);
13034
- const result = reliftReply(reply);
13035
- this.captureStatusBar(result);
13036
- return result;
13116
+ return reliftReply(reply);
13037
13117
  }
13038
13118
  async send(command, params = {}, options) {
13039
13119
  this.assertCurrent();
@@ -13047,9 +13127,7 @@ class SubcTransport {
13047
13127
  if (editSlotSurvives !== undefined)
13048
13128
  body.edit_slot_survives = editSlotSurvives;
13049
13129
  const reply = await this.pool.routeRequest(this.identityFor(session), body, timeoutMs, onProgress, this.generation);
13050
- const response = reliftReply(reply);
13051
- this.captureStatusBar(response);
13052
- return response;
13130
+ return reliftReply(reply);
13053
13131
  }
13054
13132
  splitOptions(options) {
13055
13133
  if (!options)
@@ -13320,7 +13398,7 @@ class SubcTransportPool {
13320
13398
  getBridge(projectRoot) {
13321
13399
  const root = this.canonicalRoot(projectRoot);
13322
13400
  if (this.shuttingDown && this.lifecycleEnabled()) {
13323
- throw new SubcCallError("terminal", "subc transport is shutting down");
13401
+ throw new SubcTransportShuttingDownError;
13324
13402
  }
13325
13403
  if (!this.lifecycleEnabled())
13326
13404
  return this.makeFacade(root);
@@ -13620,7 +13698,7 @@ class SubcTransportPool {
13620
13698
  }
13621
13699
  async ensureClient() {
13622
13700
  if (this.shuttingDown)
13623
- throw new SubcCallError("terminal", "subc transport is shutting down");
13701
+ throw new SubcTransportShuttingDownError;
13624
13702
  if (this.client)
13625
13703
  return this.client;
13626
13704
  if (this.connecting)
@@ -13634,7 +13712,7 @@ class SubcTransportPool {
13634
13712
  try {
13635
13713
  client.close();
13636
13714
  } catch {}
13637
- throw new SubcCallError("terminal", "subc transport is shutting down");
13715
+ throw new SubcTransportShuttingDownError;
13638
13716
  }
13639
13717
  this.client = client;
13640
13718
  this.transportFailures = 0;
@@ -13899,8 +13977,24 @@ function isRouteGoodbyeError(error2) {
13899
13977
  }
13900
13978
  return error2.code === "route_closed" && error2.message.includes("route closed by subc");
13901
13979
  }
13980
+ function hasEngineResponse(error2) {
13981
+ const response = error2.response;
13982
+ if (response !== null && typeof response === "object")
13983
+ return true;
13984
+ const cause = error2.cause;
13985
+ if (cause === null || typeof cause !== "object")
13986
+ return false;
13987
+ const causeResponse = cause.response;
13988
+ return causeResponse !== null && typeof causeResponse === "object";
13989
+ }
13990
+ function isBashTransportDeadError(error2) {
13991
+ if (!(error2 instanceof Error) || hasEngineResponse(error2) || isRouteGoodbyeError(error2)) {
13992
+ return false;
13993
+ }
13994
+ return error2 instanceof BridgeTransportUnavailableError || error2 instanceof SubcTransportShuttingDownError || isConsumerReconnectTransient(error2) || error2 instanceof StaleRouteHandleError || error2 instanceof SubcRootGenerationExpiredError || error2 instanceof SubcRootReapedError;
13995
+ }
13902
13996
  function isTransportClassError(error2) {
13903
- return isBridgeTransportTimeout(error2) || isConsumerReconnectTransient(error2) || error2 instanceof StaleRouteHandleError || error2 instanceof SubcRootGenerationExpiredError || error2 instanceof SubcRootReapedError;
13997
+ return isBridgeTransportTimeout(error2) || isBashTransportDeadError(error2);
13904
13998
  }
13905
13999
  function adaptToolError(command, error2) {
13906
14000
  if (!(error2 instanceof Error))
@@ -16451,9 +16545,6 @@ class RevivableProjectTransport {
16451
16545
  getCwd() {
16452
16546
  return this.projectRoot;
16453
16547
  }
16454
- getStatusBar() {
16455
- return this.owner.currentBridge(this.projectRoot)?.getStatusBar();
16456
- }
16457
16548
  getCachedStatus() {
16458
16549
  return this.owner.currentBridge(this.projectRoot)?.getCachedStatus() ?? null;
16459
16550
  }
@@ -17803,6 +17894,8 @@ async function callBridge(ctx, runtime, command, params = {}, options) {
17803
17894
  try {
17804
17895
  response = await bridgeFor(ctx, runtime).send(command, merged, Object.keys(sendOptions).length > 0 ? sendOptions : undefined);
17805
17896
  } catch (error3) {
17897
+ if (command === "bash" && isBashTransportDeadError(error3))
17898
+ throw error3;
17806
17899
  throw adaptToolError(command, error3);
17807
17900
  } finally {
17808
17901
  markBridgeEnd();
@@ -32230,6 +32323,7 @@ var BashFeaturesSchema = exports_external.object({
32230
32323
  rewrite: exports_external.boolean().optional(),
32231
32324
  compress: exports_external.boolean().optional(),
32232
32325
  background: exports_external.boolean().optional(),
32326
+ host_fallback: exports_external.boolean().optional(),
32233
32327
  subagent_background: exports_external.boolean().optional(),
32234
32328
  long_running_reminder_enabled: exports_external.boolean().optional(),
32235
32329
  long_running_reminder_interval_ms: exports_external.number().int().positive().optional(),
@@ -32259,6 +32353,9 @@ var InspectConfigSchema = exports_external.object({
32259
32353
  expected_mirrors: exports_external.array(exports_external.tuple([exports_external.string().trim().min(1), exports_external.string().trim().min(1)])).optional()
32260
32354
  }).optional()
32261
32355
  });
32356
+ var WorktreeConfigSchema = exports_external.object({
32357
+ ram_overlay: exports_external.boolean().optional()
32358
+ });
32262
32359
  var BackupConfigSchema = exports_external.object({
32263
32360
  enabled: exports_external.boolean().optional(),
32264
32361
  max_depth: exports_external.number().int().positive().optional(),
@@ -32284,6 +32381,7 @@ var AftConfigSchema = exports_external.preprocess((value) => stripHarnessSpecifi
32284
32381
  callgraph_chunk_size: exports_external.number().optional(),
32285
32382
  inspect: InspectConfigSchema.optional(),
32286
32383
  backup: BackupConfigSchema.optional(),
32384
+ worktree: WorktreeConfigSchema.optional(),
32287
32385
  sandbox: SandboxConfigSchema.optional(),
32288
32386
  bash: BashConfigSchema.optional(),
32289
32387
  experimental: ExperimentalConfigSchema.optional(),
@@ -32311,6 +32409,7 @@ function resolveBashConfig(config2) {
32311
32409
  rewrite: false,
32312
32410
  compress: false,
32313
32411
  background: false,
32412
+ host_fallback: false,
32314
32413
  subagent_background: false,
32315
32414
  long_running_reminder_enabled: reminderEnabled,
32316
32415
  long_running_reminder_interval_ms: reminderInterval,
@@ -32329,6 +32428,7 @@ function resolveBashConfig(config2) {
32329
32428
  rewrite: top.rewrite ?? true,
32330
32429
  compress: top.compress ?? true,
32331
32430
  background: top.background ?? true,
32431
+ host_fallback: top.host_fallback ?? false,
32332
32432
  subagent_background: topSubagentBg
32333
32433
  };
32334
32434
  }
@@ -32609,6 +32709,15 @@ function mergeLspConfig(baseLsp, overrideLsp) {
32609
32709
  }
32610
32710
  return Object.fromEntries(Object.entries(lsp).filter(([, value]) => value !== undefined));
32611
32711
  }
32712
+ function mergeWorktreeConfig(baseWorktree, overrideWorktree) {
32713
+ if (baseWorktree === undefined && overrideWorktree === undefined)
32714
+ return;
32715
+ if (overrideWorktree === undefined)
32716
+ return baseWorktree;
32717
+ if (baseWorktree === undefined)
32718
+ return overrideWorktree;
32719
+ return { ...baseWorktree, ...overrideWorktree };
32720
+ }
32612
32721
  function mergeInspectConfig(baseInspect, overrideInspect) {
32613
32722
  const inspect = {
32614
32723
  ...baseInspect,
@@ -32697,6 +32806,7 @@ var PROJECT_SAFE_TOP_LEVEL_FIELDS = new Set([
32697
32806
  "callgraph_store",
32698
32807
  "callgraph_chunk_size",
32699
32808
  "inspect",
32809
+ "worktree",
32700
32810
  "experimental",
32701
32811
  "bash"
32702
32812
  ]);
@@ -32743,11 +32853,13 @@ function mergeConfigs(base, override) {
32743
32853
  const experimental = mergeExperimentalConfig(base.experimental, override.experimental);
32744
32854
  const bash = mergeBashConfig(base.bash, override.bash);
32745
32855
  const inspect = mergeInspectConfig(base.inspect, override.inspect);
32856
+ const worktree = mergeWorktreeConfig(base.worktree, override.worktree);
32746
32857
  const sandbox = mergeSandboxConfig(base.sandbox, override.sandbox);
32747
32858
  const bridge = base.bridge;
32748
32859
  const safeOverride = pickProjectSafeFields(override);
32749
32860
  delete safeOverride.bash;
32750
32861
  delete safeOverride.inspect;
32862
+ delete safeOverride.worktree;
32751
32863
  return {
32752
32864
  ...base,
32753
32865
  ...safeOverride,
@@ -32756,6 +32868,7 @@ function mergeConfigs(base, override) {
32756
32868
  ...lsp ? { lsp } : {},
32757
32869
  ...bash !== undefined ? { bash } : {},
32758
32870
  ...inspect !== undefined ? { inspect } : {},
32871
+ ...worktree !== undefined ? { worktree } : {},
32759
32872
  ...sandbox !== undefined ? { sandbox } : {},
32760
32873
  experimental,
32761
32874
  semantic,
@@ -33393,7 +33506,7 @@ import {
33393
33506
  import { dirname as dirname8 } from "node:path";
33394
33507
 
33395
33508
  // src/hooks/auto-update-checker/cache.ts
33396
- import { spawn as spawn2 } from "node:child_process";
33509
+ import { spawn as spawn3 } from "node:child_process";
33397
33510
  import { cpSync, existsSync as existsSync13, mkdtempSync, readFileSync as readFileSync10, rmSync as rmSync4, writeFileSync as writeFileSync6 } from "node:fs";
33398
33511
  import { tmpdir as tmpdir2 } from "node:os";
33399
33512
  import { basename as basename3, dirname as dirname7, join as join15 } from "node:path";
@@ -33805,7 +33918,7 @@ async function runNpmInstallSafe(installDir, options = {}) {
33805
33918
  warnNpmInstallFailure(reason, stderrTail);
33806
33919
  return { ok: false, reason };
33807
33920
  }
33808
- const proc = spawn2(npm.command, ["install", "--no-audit", "--no-fund", "--no-progress", "--ignore-scripts"], {
33921
+ const proc = spawn3(npm.command, ["install", "--no-audit", "--no-fund", "--no-progress", "--ignore-scripts"], {
33809
33922
  cwd: installDir,
33810
33923
  stdio: ["ignore", "pipe", "pipe"],
33811
33924
  env: npmSpawnEnv(npm)
@@ -34134,7 +34247,7 @@ function showToast(ctx, title, message, variant = "info", duration3 = 3000) {
34134
34247
  }
34135
34248
 
34136
34249
  // src/lsp-auto-install.ts
34137
- import { spawn as spawn3 } from "node:child_process";
34250
+ import { spawn as spawn4 } from "node:child_process";
34138
34251
  import { createHash as createHash6 } from "node:crypto";
34139
34252
  import {
34140
34253
  createReadStream,
@@ -34734,7 +34847,7 @@ function runInstall(spec, version2, cwd, signal) {
34734
34847
  return;
34735
34848
  }
34736
34849
  ensureInstallAnchor(cwd);
34737
- const child = spawn3(npm.command, ["install", "--no-save", "--ignore-scripts", "--silent", target], {
34850
+ const child = spawn4(npm.command, ["install", "--no-save", "--ignore-scripts", "--silent", target], {
34738
34851
  stdio: ["ignore", "pipe", "pipe"],
34739
34852
  cwd,
34740
34853
  env: npmSpawnEnv(npm)
@@ -36441,14 +36554,23 @@ function readStatusBar(value) {
36441
36554
  if (typeof value !== "object" || value === null)
36442
36555
  return;
36443
36556
  const bar = asRecord(value);
36557
+ const errors3 = readOptionalNumber(bar.errors);
36558
+ const warnings = readOptionalNumber(bar.warnings);
36559
+ const deadCode = readOptionalNumber(bar.dead_code);
36560
+ const unusedExports = readOptionalNumber(bar.unused_exports);
36561
+ const duplicates = readOptionalNumber(bar.duplicates);
36562
+ const todos = readOptionalNumber(bar.todos);
36563
+ if (errors3 === null && warnings === null && deadCode === null && unusedExports === null && duplicates === null && todos === null) {
36564
+ return;
36565
+ }
36444
36566
  return {
36445
- errors: readNumber(bar.errors),
36446
- warnings: readNumber(bar.warnings),
36447
- dead_code: readNumber(bar.dead_code),
36448
- unused_exports: readNumber(bar.unused_exports),
36449
- duplicates: readNumber(bar.duplicates),
36450
- todos: readNumber(bar.todos),
36451
- tier2_stale: readBoolean(bar.tier2_stale)
36567
+ ...errors3 !== null ? { errors: errors3 } : {},
36568
+ ...warnings !== null ? { warnings } : {},
36569
+ ...deadCode !== null ? { dead_code: deadCode } : {},
36570
+ ...unusedExports !== null ? { unused_exports: unusedExports } : {},
36571
+ ...duplicates !== null ? { duplicates } : {},
36572
+ ...todos !== null ? { todos } : {},
36573
+ ...bar.tier2_stale === true ? { tier2_stale: true } : {}
36452
36574
  };
36453
36575
  }
36454
36576
  function formatFlag(enabled) {
@@ -36457,6 +36579,15 @@ function formatFlag(enabled) {
36457
36579
  function formatCount(value) {
36458
36580
  return value == null ? "—" : value.toLocaleString("en-US");
36459
36581
  }
36582
+ function formatCacheRoleLabel(role) {
36583
+ if (role === "worktree") {
36584
+ return "worktree — shared repo index (built by the main checkout)";
36585
+ }
36586
+ if (role === "read_only") {
36587
+ return "read_only — sharing the repo index family (read-only borrow)";
36588
+ }
36589
+ return role;
36590
+ }
36460
36591
  function formatSemanticIndexStatus(status, stage) {
36461
36592
  if ((status === "loading" || status === "building") && stage === "fingerprint_change") {
36462
36593
  return "Rebuilding (model changed)";
@@ -36561,7 +36692,7 @@ function formatStatusMarkdown(status) {
36561
36692
  `- **Version:** \`${status.version}\``,
36562
36693
  `- **Project root:** \`${status.project_root ?? "(not configured)"}\``,
36563
36694
  `- **Canonical root:** \`${status.canonical_root ?? "(not configured)"}\``,
36564
- `- **Cache role:** \`${status.cache_role}\``,
36695
+ `- **Cache role:** \`${formatCacheRoleLabel(status.cache_role)}\``,
36565
36696
  "",
36566
36697
  "### Enabled features",
36567
36698
  `- \`format_on_edit\`: ${formatFlag(status.features.format_on_edit)}`,
@@ -36608,7 +36739,19 @@ function formatStatusMarkdown(status) {
36608
36739
  }
36609
36740
  if (status.status_bar) {
36610
36741
  const sb = status.status_bar;
36611
- lines.push("", `### Code Health${sb.tier2_stale ? " (~ stale)" : ""}`, `- **Errors:** ${formatCount(sb.errors)}`, `- **Warnings:** ${formatCount(sb.warnings)}`, `- **Dead code:** ${formatCount(sb.dead_code)}`, `- **Unused exports:** ${formatCount(sb.unused_exports)}`, `- **Duplicates:** ${formatCount(sb.duplicates)}`, `- **TODOs:** ${formatCount(sb.todos)}`);
36742
+ const rows = [
36743
+ ["Errors", sb.errors],
36744
+ ["Warnings", sb.warnings],
36745
+ ["Dead code", sb.dead_code],
36746
+ ["Unused exports", sb.unused_exports],
36747
+ ["Duplicates", sb.duplicates],
36748
+ ["TODOs", sb.todos]
36749
+ ].filter((row) => typeof row[1] === "number");
36750
+ if (rows.length > 0) {
36751
+ lines.push("", `### Code Health${sb.tier2_stale ? " (~ stale)" : ""}`);
36752
+ for (const [label, value] of rows)
36753
+ lines.push(`- **${label}:** ${formatCount(value)}`);
36754
+ }
36612
36755
  }
36613
36756
  lines.push("", "### Current session", `- **ID:** \`${status.session.id}\``, `- **Tracked files:** ${formatCount(status.session.tracked_files)}`, `- **Checkpoints:** ${formatCount(status.session.checkpoints)}`, `- **Project checkpoints (all sessions):** ${formatCount(status.checkpoints_total)}`);
36614
36757
  return lines.join(`
@@ -36695,27 +36838,6 @@ function registerShutdownCleanup(fn) {
36695
36838
  };
36696
36839
  }
36697
36840
 
36698
- // src/status-bar-inject.ts
36699
- var emitStateBySession = new Map;
36700
- function statusBarSuffixForSession(sessionID, counts, force = false) {
36701
- if (!counts)
36702
- return "";
36703
- let state = emitStateBySession.get(sessionID);
36704
- if (!state) {
36705
- state = createStatusBarEmitState();
36706
- emitStateBySession.set(sessionID, state);
36707
- }
36708
- if (force) {
36709
- state.last = counts;
36710
- state.callsSinceEmit = 0;
36711
- return statusBarLine(counts);
36712
- }
36713
- return shouldEmitStatusBar(state, counts) ? statusBarLine(counts) : "";
36714
- }
36715
- function clearStatusBarSession(sessionID) {
36716
- emitStateBySession.delete(sessionID);
36717
- }
36718
-
36719
36841
  // src/sync-watch-abort.ts
36720
36842
  var abortFlags = new Map;
36721
36843
  function signalSyncWatchAbort(sessionID) {
@@ -37464,6 +37586,7 @@ function createBashTool(ctx, aftSearchRegisteredOverride) {
37464
37586
  const shellEnv = await ctx.plugin?.trigger?.("shell.env", { cwd, sessionID: context.sessionID, callID: getCallID(context) }, { env: {} });
37465
37587
  const removeAbortListener = listenForForegroundAbort(ctx, context, !effectiveBackground && !requestedPty);
37466
37588
  let data;
37589
+ let usedHostFallback = false;
37467
37590
  try {
37468
37591
  data = await withPermissionLoop(ctx, context, {
37469
37592
  command,
@@ -37489,6 +37612,31 @@ function createBashTool(ctx, aftSearchRegisteredOverride) {
37489
37612
  metadata?.({ output: accumulatedOutput, description });
37490
37613
  }
37491
37614
  });
37615
+ } catch (error53) {
37616
+ if (!bashCfg.host_fallback || !isBashTransportDeadError(error53))
37617
+ throw error53;
37618
+ if (rawRequestedBackground) {
37619
+ throw new Error(`${BASH_HOST_FALLBACK_REFUSAL}; background:true is unsupported.`);
37620
+ }
37621
+ if (rawRequestedPty) {
37622
+ throw new Error(`${BASH_HOST_FALLBACK_REFUSAL}; pty:true is unsupported.`);
37623
+ }
37624
+ const projectRoot = projectRootFor(context);
37625
+ const pattern = bashHostFallbackAskPattern(command, projectRoot);
37626
+ await runAsk(context.ask({
37627
+ permission: "bash",
37628
+ patterns: [pattern],
37629
+ always: [],
37630
+ metadata: { command, cwd: projectRoot, host_fallback: true }
37631
+ }));
37632
+ data = await runBashHostFallback({
37633
+ command,
37634
+ projectRoot,
37635
+ timeoutMs: rawTimeout,
37636
+ signal: context.abort,
37637
+ env: shellEnv?.env
37638
+ });
37639
+ usedHostFallback = true;
37492
37640
  } finally {
37493
37641
  removeAbortListener();
37494
37642
  }
@@ -37506,7 +37654,8 @@ function createBashTool(ctx, aftSearchRegisteredOverride) {
37506
37654
  metadata?.(metadataPayload2);
37507
37655
  return { output: rendered2, title: uiTitle, metadata: metadataPayload2 };
37508
37656
  }
37509
- const rendered = maybeAppendGrepSearchHint(data.output ?? "", command, aftSearchRegistered, projectRootFor(context));
37657
+ const output = data.output ?? "";
37658
+ const rendered = usedHostFallback ? output : maybeAppendGrepSearchHint(output, command, aftSearchRegistered, projectRootFor(context));
37510
37659
  const metadataPayload = foregroundMetadata(description, data, rendered);
37511
37660
  metadata?.(metadataPayload);
37512
37661
  return {
@@ -38870,6 +39019,125 @@ async function resolveAndGateScope(ctx, context, scope) {
38870
39019
  }
38871
39020
  return { scope: Array.isArray(scope) ? resolved : resolved[0] };
38872
39021
  }
39022
+ function asRecord2(value) {
39023
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : undefined;
39024
+ }
39025
+ function asString(value) {
39026
+ return typeof value === "string" ? value : undefined;
39027
+ }
39028
+ function firstRecord(...values) {
39029
+ for (const value of values) {
39030
+ const record2 = asRecord2(value);
39031
+ if (record2)
39032
+ return record2;
39033
+ }
39034
+ return;
39035
+ }
39036
+ function firstString(...values) {
39037
+ for (const value of values) {
39038
+ const text = asString(value);
39039
+ if (text !== undefined)
39040
+ return text;
39041
+ }
39042
+ return;
39043
+ }
39044
+ function terminalKind(response) {
39045
+ for (const value of [
39046
+ response.inspect_terminal,
39047
+ response.terminal,
39048
+ response.outcome,
39049
+ response.inspect_outcome,
39050
+ response.status
39051
+ ]) {
39052
+ if (typeof value !== "string")
39053
+ continue;
39054
+ const normalized = value.toUpperCase().replaceAll("_", "-");
39055
+ if (normalized === "FRESH" || normalized === "INTERRUPTED" || normalized === "PHASE-FAILED") {
39056
+ return normalized;
39057
+ }
39058
+ }
39059
+ return;
39060
+ }
39061
+ function parseInspectPhaseEntries(value) {
39062
+ if (!Array.isArray(value))
39063
+ return [];
39064
+ return value.flatMap((candidate) => {
39065
+ const entry = asRecord2(candidate);
39066
+ const id = asString(entry?.id);
39067
+ if (!id)
39068
+ return [];
39069
+ const alsoSatisfied = Array.isArray(entry?.also_satisfied) ? entry.also_satisfied.filter((category) => typeof category === "string") : [];
39070
+ return [
39071
+ {
39072
+ id,
39073
+ producer: asString(entry?.producer),
39074
+ category: asString(entry?.category),
39075
+ alsoSatisfied
39076
+ }
39077
+ ];
39078
+ });
39079
+ }
39080
+ function parseInspectTerminal(payload) {
39081
+ const response = asRecord2(payload);
39082
+ if (!response)
39083
+ return;
39084
+ const kind = terminalKind(response);
39085
+ if (!kind)
39086
+ return;
39087
+ const waitStamp = firstRecord(response.wait_stamp, response.waitStamp, response.blocking_wait_stamp);
39088
+ const phases = parseInspectPhaseEntries(kind === "FRESH" ? waitStamp?.phases ?? response.completed_phases ?? response.completedPhases ?? response.phases : response.completed_phases ?? response.completedPhases ?? response.phases);
39089
+ if (kind !== "PHASE-FAILED") {
39090
+ return {
39091
+ kind,
39092
+ phases,
39093
+ waitStampText: kind === "FRESH" ? firstString(waitStamp?.text, waitStamp?.human_text) : undefined
39094
+ };
39095
+ }
39096
+ const failedPhaseRecord = asRecord2(response.failed_phase);
39097
+ const failedPhaseId = firstString(failedPhaseRecord?.id, response.failed_phase);
39098
+ const failedPhase = failedPhaseId ? parseInspectPhaseEntries([
39099
+ {
39100
+ id: failedPhaseId,
39101
+ producer: firstString(failedPhaseRecord?.producer, response.failed_phase_producer, response.producer),
39102
+ category: firstString(failedPhaseRecord?.category, response.failed_phase_category, response.category)
39103
+ }
39104
+ ])[0] : undefined;
39105
+ return {
39106
+ kind,
39107
+ phases,
39108
+ failedPhase,
39109
+ failureReason: asString(response.failure_reason),
39110
+ failureDetail: asString(response.failure_detail)
39111
+ };
39112
+ }
39113
+ function formatPhase(entry) {
39114
+ const details = [
39115
+ entry.producer ? `producer: ${entry.producer}` : undefined,
39116
+ entry.category ? `category: ${entry.category}` : undefined,
39117
+ entry.alsoSatisfied.length > 0 ? `also satisfied: ${entry.alsoSatisfied.join(", ")}` : undefined
39118
+ ].filter((detail) => Boolean(detail));
39119
+ return details.length > 0 ? `${entry.id} (${details.join("; ")})` : entry.id;
39120
+ }
39121
+ function renderInspectTerminal(terminal, serverText) {
39122
+ const lines = [terminal.kind];
39123
+ if (terminal.kind === "FRESH") {
39124
+ lines.push(`wait-stamp: ${terminal.waitStampText ?? "not supplied"}`);
39125
+ }
39126
+ if (terminal.kind === "PHASE-FAILED") {
39127
+ if (terminal.failedPhase)
39128
+ lines.push(`failed phase: ${formatPhase(terminal.failedPhase)}`);
39129
+ lines.push(`failure reason: ${terminal.failureReason ?? "not supplied"}`);
39130
+ if (terminal.failureDetail)
39131
+ lines.push(`failure detail: ${terminal.failureDetail}`);
39132
+ }
39133
+ lines.push(terminal.phases.length > 0 ? `completed phases:
39134
+ ${terminal.phases.map((phase) => `- ${formatPhase(phase)}`).join(`
39135
+ `)}` : "completed phases: none");
39136
+ if (serverText?.trim())
39137
+ lines.push(serverText);
39138
+ return lines.join(`
39139
+ `);
39140
+ }
38873
39141
  function inspectToolSurfaceEnabled(config2) {
38874
39142
  return (config2.tool_surface ?? "recommended") !== "minimal" && config2.inspect?.enabled !== false;
38875
39143
  }
@@ -38885,9 +39153,8 @@ function createInspectTier2IdleScheduler(options) {
38885
39153
  timers.delete(sessionID);
38886
39154
  };
38887
39155
  const clearAll = () => {
38888
- for (const timer of timers.values()) {
39156
+ for (const timer of timers.values())
38889
39157
  clearTimer(timer);
38890
- }
38891
39158
  timers.clear();
38892
39159
  };
38893
39160
  const schedule = (sessionID) => {
@@ -38908,12 +39175,12 @@ function createInspectTier2IdleScheduler(options) {
38908
39175
  }
38909
39176
  function inspectTools(ctx) {
38910
39177
  const inspectTool = {
38911
- description: "Codebase health snapshot. One call returns summary stats for: TODOs, diagnostics, file/symbol metrics, dead code, unused exports, code duplicates, and TS/JS import cycles. Pass `sections` for per-category drill-down details.\n\n" + "Categories run in tiers — Tier 1 (todos, metrics) return synchronously from cache. Tier 2 (dead_code, unused_exports, duplicates, cycles) waits for a fresh reuse scan up to a short deadline; if a category is still scanning the response reports `complete: false` with `pending_categories: [...]` rather than a fabricated clean count. Rust module cycles are out of scope for `cycles`.\n\n" + `Use when: starting work on unfamiliar code, after multi-edit batches to check diagnostics, before a refactor, before review, or to verify cleanup completeness.
39178
+ description: "Blocking-fresh codebase health inspection. Each call completes current analysis and produces exactly one terminal result: FRESH includes a wait-stamp and completed phases; INTERRUPTED and PHASE-FAILED retain completed phases, with PHASE-FAILED also reporting its phase attribution and failure reason. `sections` selects drill-down detail, not the categories verified.\n\n" + "Use `scope=` to narrow returned results. It does not reduce the fresh verification work. Passive health changes use the alert channel; do not infer inspect completion from that channel.\n\n" + `Use when: starting work on unfamiliar code, after multi-edit batches to check diagnostics, before a refactor, before review, or to verify cleanup completeness.
38912
39179
 
38913
39180
  ` + "Treat `dead_code` as a hint, not proof: reachability is call-based, so symbols reached only via method dispatch or referenced only in type position may be false positives — verify before deleting.",
38914
39181
  args: {
38915
- sections: arg(z10.union([z10.string(), z10.array(z10.string())]).optional().describe("Categories to include in detailed drill-down (e.g. 'todos' or ['todos', 'dead_code', 'cycles']). Use 'all' for every active category. Omit for summary-only mode.")),
38916
- scope: arg(z10.union([z10.string(), z10.array(z10.string())]).optional().describe("Restrict scan/results to paths under this scope (file or directory, absolute or relative to project root). Tier 1 scopes the scan; Tier 2 scans project-wide and applies scope as a result filter.")),
39182
+ sections: arg(z10.union([z10.string(), z10.array(z10.string())]).optional().describe("Categories to include in detailed drill-down (e.g. 'todos' or ['todos', 'dead_code', 'cycles']). Use 'all' for every active category. Omit for summary-only mode. `sections` changes detail, not the categories verified.")),
39183
+ scope: arg(z10.union([z10.string(), z10.array(z10.string())]).optional().describe("Restrict returned results to paths under this scope (file or directory, absolute or relative to project root). `scope=` narrows results; it does not reduce the blocking-fresh verification work.")),
38917
39184
  topK: arg(z10.number().int().positive().max(100).optional().describe("Max drill-down items per category. Default 20, max 100."))
38918
39185
  },
38919
39186
  execute: async (args, context) => {
@@ -38921,27 +39188,23 @@ function inspectTools(ctx) {
38921
39188
  const scoped = await resolveAndGateScope(ctx, context, normalizeStringOrArray(args.scope));
38922
39189
  if (scoped.denial)
38923
39190
  return permissionDeniedResponse(scoped.denial);
38924
- const scope = scoped.scope;
38925
- const topK = args.topK === undefined || args.topK === null ? undefined : args.topK;
38926
39191
  const rawArgs = {};
38927
39192
  if (sections !== undefined)
38928
39193
  rawArgs.sections = sections;
38929
- if (scope !== undefined)
38930
- rawArgs.scope = scope;
38931
- if (topK !== undefined)
38932
- rawArgs.topK = topK;
38933
- const response = await callToolCall(ctx, context, "inspect", rawArgs, {
38934
- keepBridgeOnTimeout: true
38935
- });
38936
- if (response.success === false) {
39194
+ if (scoped.scope !== undefined)
39195
+ rawArgs.scope = scoped.scope;
39196
+ if (args.topK !== undefined && args.topK !== null)
39197
+ rawArgs.topK = args.topK;
39198
+ const response = await callToolCall(ctx, context, "inspect", rawArgs);
39199
+ const terminal = parseInspectTerminal(response);
39200
+ if (terminal)
39201
+ return renderInspectTerminal(terminal, response.text);
39202
+ if (response.success === false)
38937
39203
  throw new Error(response.message || "inspect failed");
38938
- }
38939
39204
  return response.text;
38940
39205
  }
38941
39206
  };
38942
- return {
38943
- aft_inspect: inspectTool
38944
- };
39207
+ return { aft_inspect: inspectTool };
38945
39208
  }
38946
39209
 
38947
39210
  // src/tools/navigation.ts
@@ -39740,7 +40003,7 @@ function semanticTools(ctx) {
39740
40003
  query: arg3(z15.string().describe("Concept, regex, literal text, filename, or capability to find. Examples: 'fuzzy match with whitespace tolerance', '^export', 'Cargo.lock'.")),
39741
40004
  topK: arg3(optionalInt(1, 100).describe("Number of results (default: 10, max: 100)")),
39742
40005
  includeTests: arg3(z15.boolean().optional().describe("Include test files (*.test.*, *_test.rs, __tests__/, …) plus test-support, fixture, mock, snapshot, and corpus files. Defaults to false.")),
39743
- path: arg3(z15.string().optional().describe("Search a different project root (absolute or ~ path). Requires that project to have been indexed by AFT."))
40006
+ path: arg3(z15.string().optional().describe("Only set this to search a different Git project (absolute or ~ path). Omit it for the current configured workspace, including non-Git workspace roots; this is not a subdirectory filter. Unindexed external projects use a bounded lexical fallback."))
39744
40007
  },
39745
40008
  execute: async (args, context) => {
39746
40009
  if (isEmptyParam(args.query) || typeof args.query !== "string" || args.query.trim().length === 0) {
@@ -39943,7 +40206,7 @@ var PLUGIN_VERSION = (() => {
39943
40206
  return "0.0.0";
39944
40207
  }
39945
40208
  })();
39946
- var ANNOUNCEMENT_VERSION = "0.50.3";
40209
+ var ANNOUNCEMENT_VERSION = "0.51.1";
39947
40210
  var ANNOUNCEMENT_FEATURES = [
39948
40211
  "Callgraph stays consistent under load: edits arriving mid-rebuild can no longer be silently lost from navigation results.",
39949
40212
  "aft_zoom handles real-world .jsonc: files with comment banners above the opening brace now resolve, and not-found errors point at the segment that actually failed (thanks @iceteaSA).",
@@ -40478,7 +40741,6 @@ Install: ${getManualInstallHint()}`).catch(() => {});
40478
40741
  const sessionID = extractSessionID(eventInput.event.properties);
40479
40742
  if (eventType === "session.deleted" && sessionID) {
40480
40743
  inspectTier2Idle.clear(sessionID);
40481
- clearStatusBarSession(sessionID);
40482
40744
  pool.closeSession(input.directory, sessionID).catch(() => {});
40483
40745
  return;
40484
40746
  }
@@ -40567,12 +40829,6 @@ Install: ${getManualInstallHint()}`).catch(() => {});
40567
40829
  }
40568
40830
  const sessionDir = getSessionDirectoryCached(toolInput.sessionID) ?? input.directory;
40569
40831
  await appendInTurnBgCompletions({ ctx, directory: sessionDir, sessionID: toolInput.sessionID }, output);
40570
- if (output.output !== undefined) {
40571
- const activeBridge = ctx.pool.getActiveBridgeForRoot(sessionDir);
40572
- const suffix = statusBarSuffixForSession(toolInput.sessionID, activeBridge?.getStatusBar(), toolInput.tool === "aft_inspect");
40573
- if (suffix)
40574
- output.output += suffix;
40575
- }
40576
40832
  },
40577
40833
  config: async (config2) => {
40578
40834
  if (!config2 || typeof config2 !== "object")