@cortexkit/aft-opencode 0.50.3 → 0.51.0

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;
@@ -8703,7 +8774,7 @@ class BinaryBridge {
8703
8774
  throw new Error(`${this.errorPrefix} Bridge is retiring after the on-disk binary changed; retry to respawn on the updated binary`);
8704
8775
  }
8705
8776
  if (this._shuttingDown) {
8706
- throw new Error(`${this.errorPrefix} Bridge is shutting down, cannot send "${command}"`);
8777
+ throw new BridgeTransportUnavailableError(`${this.errorPrefix} Bridge is shutting down, cannot send "${command}"`);
8707
8778
  }
8708
8779
  if (Object.hasOwn(params, "id")) {
8709
8780
  throw new Error("params cannot contain reserved key 'id'");
@@ -8737,7 +8808,7 @@ class BinaryBridge {
8737
8808
  await this.deliverConfigureWarnings(configResult, params, options);
8738
8809
  await this.checkVersion(implicitTransportOptions);
8739
8810
  if (!this.isAlive()) {
8740
- throw new Error(`${this.errorPrefix} Bridge died during version check. Check logs: ${this.getLogFilePathVia()}`);
8811
+ throw new BridgeTransportUnavailableError(`${this.errorPrefix} Bridge died during version check. Check logs: ${this.getLogFilePathVia()}`);
8741
8812
  }
8742
8813
  this.configured = true;
8743
8814
  } finally {
@@ -8806,7 +8877,7 @@ class BinaryBridge {
8806
8877
  if (!this.process?.stdin?.writable) {
8807
8878
  this.pending.delete(id);
8808
8879
  clearTimeout(timer);
8809
- reject(new Error(`${this.errorPrefix} stdin not writable for command "${command}"`));
8880
+ reject(new BridgeTransportUnavailableError(`${this.errorPrefix} stdin not writable for command "${command}"`));
8810
8881
  return;
8811
8882
  }
8812
8883
  requestSentAt = Date.now();
@@ -8816,7 +8887,7 @@ class BinaryBridge {
8816
8887
  if (entry) {
8817
8888
  this.pending.delete(id);
8818
8889
  clearTimeout(entry.timer);
8819
- entry.reject(new Error(`${this.errorPrefix} Failed to write to stdin: ${err.message}`));
8890
+ entry.reject(new BridgeTransportUnavailableError(`${this.errorPrefix} Failed to write to stdin: ${err.message}`, { cause: err }));
8820
8891
  }
8821
8892
  }
8822
8893
  });
@@ -8983,7 +9054,6 @@ class BinaryBridge {
8983
9054
  }
8984
9055
  spawnProcess(triggeringSessionId) {
8985
9056
  this._retiringDueToBinaryChange = false;
8986
- this.lastStatusBar = undefined;
8987
9057
  if (triggeringSessionId) {
8988
9058
  this.sessionLogVia(triggeringSessionId, `Spawning binary: ${this.binaryPath} (cwd: ${this.cwd})`);
8989
9059
  } else {
@@ -9024,7 +9094,7 @@ class BinaryBridge {
9024
9094
  }
9025
9095
  }
9026
9096
  }
9027
- const child = spawn(this.binaryPath, [], {
9097
+ const child = spawn2(this.binaryPath, [], {
9028
9098
  cwd: this.cwd,
9029
9099
  stdio: ["pipe", "pipe", "pipe"],
9030
9100
  env
@@ -9054,7 +9124,7 @@ class BinaryBridge {
9054
9124
  if (this.process !== currentChild)
9055
9125
  return;
9056
9126
  this.errorVia(`Process error: ${err.message}${this.formatStderrTail()}`);
9057
- this.handleCrash();
9127
+ this.handleCrash(err);
9058
9128
  });
9059
9129
  child.on("exit", (code, signal) => {
9060
9130
  if (this.process !== currentChild)
@@ -9067,7 +9137,7 @@ class BinaryBridge {
9067
9137
  this.process = null;
9068
9138
  this.configured = false;
9069
9139
  this.clearRestartResetTimer();
9070
- this.rejectAllPending(new Error(`${this.errorPrefix} Binary killed by ${signal}`));
9140
+ this.rejectAllPending(new BridgeTransportUnavailableError(`${this.errorPrefix} Binary killed by ${signal}`));
9071
9141
  return;
9072
9142
  }
9073
9143
  this.handleCrash();
@@ -9222,7 +9292,6 @@ class BinaryBridge {
9222
9292
  this.consecutiveRequestTimeouts = 0;
9223
9293
  this.scheduleRestartCountReset();
9224
9294
  this.accountForBashTaskResponse(entry.command, response);
9225
- this.captureStatusBar(response);
9226
9295
  entry.resolve(response);
9227
9296
  } else if (typeof response.type === "string") {
9228
9297
  this.logVia(`Ignoring unknown stdout push frame type: ${response.type}`);
@@ -9243,14 +9312,6 @@ class BinaryBridge {
9243
9312
  this.outstandingBackgroundTaskIds.add(taskId);
9244
9313
  }
9245
9314
  }
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
9315
  handleTimeout(triggeringSessionId) {
9255
9316
  this.consecutiveRequestTimeouts = 0;
9256
9317
  this.spawnedBinaryFingerprint = null;
@@ -9291,7 +9352,7 @@ class BinaryBridge {
9291
9352
  if (tail) {
9292
9353
  this.errorVia(`Binary crashed (restarts: ${this._restartCount})${cause ? `: ${cause.message}` : ""}.${tail}`);
9293
9354
  }
9294
- this.rejectAllPending(new Error(`${this.errorPrefix} Binary crashed (restarts: ${this._restartCount})${cause ? `: ${cause.message}` : ""} (see ${this.getLogFilePathVia()})`));
9355
+ this.rejectAllPending(new BridgeTransportUnavailableError(`${this.errorPrefix} Binary crashed (restarts: ${this._restartCount})${cause ? `: ${cause.message}` : ""} (see ${this.getLogFilePathVia()})`, { cause }));
9295
9356
  if (this._retiringDueToBinaryChange) {
9296
9357
  this.logVia("Binary exited while retiring after an on-disk update; skipping auto-restart");
9297
9358
  return;
@@ -12640,6 +12701,12 @@ function projectRootKeyHash(dir) {
12640
12701
  }
12641
12702
 
12642
12703
  // ../aft-bridge/dist/subc-transport.js
12704
+ class SubcTransportShuttingDownError extends SubcCallError {
12705
+ constructor() {
12706
+ super("terminal", "subc transport is shutting down", "transport_shutting_down");
12707
+ this.name = "SubcTransportShuttingDownError";
12708
+ }
12709
+ }
12643
12710
  var AFT_MODULE_ID = "aft";
12644
12711
  var MAX_CONSECUTIVE_TRANSPORT_FAILURES = 3;
12645
12712
  var BG_STABLE_MS = 5000;
@@ -12981,7 +13048,6 @@ class SubcTransport {
12981
13048
  pool;
12982
13049
  projectRoot;
12983
13050
  generation;
12984
- lastStatusBar;
12985
13051
  cachedStatus = null;
12986
13052
  constructor(pool, projectRoot, generation) {
12987
13053
  this.pool = pool;
@@ -12997,20 +13063,12 @@ class SubcTransport {
12997
13063
  getConcretePoolId() {
12998
13064
  return this.pool.getConcretePoolId();
12999
13065
  }
13000
- getStatusBar() {
13001
- return this.lastStatusBar;
13002
- }
13003
13066
  getCachedStatus() {
13004
13067
  return this.cachedStatus;
13005
13068
  }
13006
13069
  cacheStatusSnapshot(snapshot) {
13007
13070
  this.cachedStatus = snapshot;
13008
13071
  }
13009
- captureStatusBar(response) {
13010
- const parsed = parseStatusBarCounts(response.status_bar);
13011
- if (parsed)
13012
- this.lastStatusBar = parsed;
13013
- }
13014
13072
  identityFor(session) {
13015
13073
  return {
13016
13074
  project_root: this.projectRoot,
@@ -13031,9 +13089,7 @@ class SubcTransport {
13031
13089
  if (preview === true)
13032
13090
  body.preview = true;
13033
13091
  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;
13092
+ return reliftReply(reply);
13037
13093
  }
13038
13094
  async send(command, params = {}, options) {
13039
13095
  this.assertCurrent();
@@ -13047,9 +13103,7 @@ class SubcTransport {
13047
13103
  if (editSlotSurvives !== undefined)
13048
13104
  body.edit_slot_survives = editSlotSurvives;
13049
13105
  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;
13106
+ return reliftReply(reply);
13053
13107
  }
13054
13108
  splitOptions(options) {
13055
13109
  if (!options)
@@ -13320,7 +13374,7 @@ class SubcTransportPool {
13320
13374
  getBridge(projectRoot) {
13321
13375
  const root = this.canonicalRoot(projectRoot);
13322
13376
  if (this.shuttingDown && this.lifecycleEnabled()) {
13323
- throw new SubcCallError("terminal", "subc transport is shutting down");
13377
+ throw new SubcTransportShuttingDownError;
13324
13378
  }
13325
13379
  if (!this.lifecycleEnabled())
13326
13380
  return this.makeFacade(root);
@@ -13620,7 +13674,7 @@ class SubcTransportPool {
13620
13674
  }
13621
13675
  async ensureClient() {
13622
13676
  if (this.shuttingDown)
13623
- throw new SubcCallError("terminal", "subc transport is shutting down");
13677
+ throw new SubcTransportShuttingDownError;
13624
13678
  if (this.client)
13625
13679
  return this.client;
13626
13680
  if (this.connecting)
@@ -13634,7 +13688,7 @@ class SubcTransportPool {
13634
13688
  try {
13635
13689
  client.close();
13636
13690
  } catch {}
13637
- throw new SubcCallError("terminal", "subc transport is shutting down");
13691
+ throw new SubcTransportShuttingDownError;
13638
13692
  }
13639
13693
  this.client = client;
13640
13694
  this.transportFailures = 0;
@@ -13899,8 +13953,24 @@ function isRouteGoodbyeError(error2) {
13899
13953
  }
13900
13954
  return error2.code === "route_closed" && error2.message.includes("route closed by subc");
13901
13955
  }
13956
+ function hasEngineResponse(error2) {
13957
+ const response = error2.response;
13958
+ if (response !== null && typeof response === "object")
13959
+ return true;
13960
+ const cause = error2.cause;
13961
+ if (cause === null || typeof cause !== "object")
13962
+ return false;
13963
+ const causeResponse = cause.response;
13964
+ return causeResponse !== null && typeof causeResponse === "object";
13965
+ }
13966
+ function isBashTransportDeadError(error2) {
13967
+ if (!(error2 instanceof Error) || hasEngineResponse(error2) || isRouteGoodbyeError(error2)) {
13968
+ return false;
13969
+ }
13970
+ return error2 instanceof BridgeTransportUnavailableError || error2 instanceof SubcTransportShuttingDownError || isConsumerReconnectTransient(error2) || error2 instanceof StaleRouteHandleError || error2 instanceof SubcRootGenerationExpiredError || error2 instanceof SubcRootReapedError;
13971
+ }
13902
13972
  function isTransportClassError(error2) {
13903
- return isBridgeTransportTimeout(error2) || isConsumerReconnectTransient(error2) || error2 instanceof StaleRouteHandleError || error2 instanceof SubcRootGenerationExpiredError || error2 instanceof SubcRootReapedError;
13973
+ return isBridgeTransportTimeout(error2) || isBashTransportDeadError(error2);
13904
13974
  }
13905
13975
  function adaptToolError(command, error2) {
13906
13976
  if (!(error2 instanceof Error))
@@ -16451,9 +16521,6 @@ class RevivableProjectTransport {
16451
16521
  getCwd() {
16452
16522
  return this.projectRoot;
16453
16523
  }
16454
- getStatusBar() {
16455
- return this.owner.currentBridge(this.projectRoot)?.getStatusBar();
16456
- }
16457
16524
  getCachedStatus() {
16458
16525
  return this.owner.currentBridge(this.projectRoot)?.getCachedStatus() ?? null;
16459
16526
  }
@@ -17803,6 +17870,8 @@ async function callBridge(ctx, runtime, command, params = {}, options) {
17803
17870
  try {
17804
17871
  response = await bridgeFor(ctx, runtime).send(command, merged, Object.keys(sendOptions).length > 0 ? sendOptions : undefined);
17805
17872
  } catch (error3) {
17873
+ if (command === "bash" && isBashTransportDeadError(error3))
17874
+ throw error3;
17806
17875
  throw adaptToolError(command, error3);
17807
17876
  } finally {
17808
17877
  markBridgeEnd();
@@ -32230,6 +32299,7 @@ var BashFeaturesSchema = exports_external.object({
32230
32299
  rewrite: exports_external.boolean().optional(),
32231
32300
  compress: exports_external.boolean().optional(),
32232
32301
  background: exports_external.boolean().optional(),
32302
+ host_fallback: exports_external.boolean().optional(),
32233
32303
  subagent_background: exports_external.boolean().optional(),
32234
32304
  long_running_reminder_enabled: exports_external.boolean().optional(),
32235
32305
  long_running_reminder_interval_ms: exports_external.number().int().positive().optional(),
@@ -32259,6 +32329,9 @@ var InspectConfigSchema = exports_external.object({
32259
32329
  expected_mirrors: exports_external.array(exports_external.tuple([exports_external.string().trim().min(1), exports_external.string().trim().min(1)])).optional()
32260
32330
  }).optional()
32261
32331
  });
32332
+ var WorktreeConfigSchema = exports_external.object({
32333
+ ram_overlay: exports_external.boolean().optional()
32334
+ });
32262
32335
  var BackupConfigSchema = exports_external.object({
32263
32336
  enabled: exports_external.boolean().optional(),
32264
32337
  max_depth: exports_external.number().int().positive().optional(),
@@ -32284,6 +32357,7 @@ var AftConfigSchema = exports_external.preprocess((value) => stripHarnessSpecifi
32284
32357
  callgraph_chunk_size: exports_external.number().optional(),
32285
32358
  inspect: InspectConfigSchema.optional(),
32286
32359
  backup: BackupConfigSchema.optional(),
32360
+ worktree: WorktreeConfigSchema.optional(),
32287
32361
  sandbox: SandboxConfigSchema.optional(),
32288
32362
  bash: BashConfigSchema.optional(),
32289
32363
  experimental: ExperimentalConfigSchema.optional(),
@@ -32311,6 +32385,7 @@ function resolveBashConfig(config2) {
32311
32385
  rewrite: false,
32312
32386
  compress: false,
32313
32387
  background: false,
32388
+ host_fallback: false,
32314
32389
  subagent_background: false,
32315
32390
  long_running_reminder_enabled: reminderEnabled,
32316
32391
  long_running_reminder_interval_ms: reminderInterval,
@@ -32329,6 +32404,7 @@ function resolveBashConfig(config2) {
32329
32404
  rewrite: top.rewrite ?? true,
32330
32405
  compress: top.compress ?? true,
32331
32406
  background: top.background ?? true,
32407
+ host_fallback: top.host_fallback ?? false,
32332
32408
  subagent_background: topSubagentBg
32333
32409
  };
32334
32410
  }
@@ -32609,6 +32685,15 @@ function mergeLspConfig(baseLsp, overrideLsp) {
32609
32685
  }
32610
32686
  return Object.fromEntries(Object.entries(lsp).filter(([, value]) => value !== undefined));
32611
32687
  }
32688
+ function mergeWorktreeConfig(baseWorktree, overrideWorktree) {
32689
+ if (baseWorktree === undefined && overrideWorktree === undefined)
32690
+ return;
32691
+ if (overrideWorktree === undefined)
32692
+ return baseWorktree;
32693
+ if (baseWorktree === undefined)
32694
+ return overrideWorktree;
32695
+ return { ...baseWorktree, ...overrideWorktree };
32696
+ }
32612
32697
  function mergeInspectConfig(baseInspect, overrideInspect) {
32613
32698
  const inspect = {
32614
32699
  ...baseInspect,
@@ -32697,6 +32782,7 @@ var PROJECT_SAFE_TOP_LEVEL_FIELDS = new Set([
32697
32782
  "callgraph_store",
32698
32783
  "callgraph_chunk_size",
32699
32784
  "inspect",
32785
+ "worktree",
32700
32786
  "experimental",
32701
32787
  "bash"
32702
32788
  ]);
@@ -32743,11 +32829,13 @@ function mergeConfigs(base, override) {
32743
32829
  const experimental = mergeExperimentalConfig(base.experimental, override.experimental);
32744
32830
  const bash = mergeBashConfig(base.bash, override.bash);
32745
32831
  const inspect = mergeInspectConfig(base.inspect, override.inspect);
32832
+ const worktree = mergeWorktreeConfig(base.worktree, override.worktree);
32746
32833
  const sandbox = mergeSandboxConfig(base.sandbox, override.sandbox);
32747
32834
  const bridge = base.bridge;
32748
32835
  const safeOverride = pickProjectSafeFields(override);
32749
32836
  delete safeOverride.bash;
32750
32837
  delete safeOverride.inspect;
32838
+ delete safeOverride.worktree;
32751
32839
  return {
32752
32840
  ...base,
32753
32841
  ...safeOverride,
@@ -32756,6 +32844,7 @@ function mergeConfigs(base, override) {
32756
32844
  ...lsp ? { lsp } : {},
32757
32845
  ...bash !== undefined ? { bash } : {},
32758
32846
  ...inspect !== undefined ? { inspect } : {},
32847
+ ...worktree !== undefined ? { worktree } : {},
32759
32848
  ...sandbox !== undefined ? { sandbox } : {},
32760
32849
  experimental,
32761
32850
  semantic,
@@ -33393,7 +33482,7 @@ import {
33393
33482
  import { dirname as dirname8 } from "node:path";
33394
33483
 
33395
33484
  // src/hooks/auto-update-checker/cache.ts
33396
- import { spawn as spawn2 } from "node:child_process";
33485
+ import { spawn as spawn3 } from "node:child_process";
33397
33486
  import { cpSync, existsSync as existsSync13, mkdtempSync, readFileSync as readFileSync10, rmSync as rmSync4, writeFileSync as writeFileSync6 } from "node:fs";
33398
33487
  import { tmpdir as tmpdir2 } from "node:os";
33399
33488
  import { basename as basename3, dirname as dirname7, join as join15 } from "node:path";
@@ -33805,7 +33894,7 @@ async function runNpmInstallSafe(installDir, options = {}) {
33805
33894
  warnNpmInstallFailure(reason, stderrTail);
33806
33895
  return { ok: false, reason };
33807
33896
  }
33808
- const proc = spawn2(npm.command, ["install", "--no-audit", "--no-fund", "--no-progress", "--ignore-scripts"], {
33897
+ const proc = spawn3(npm.command, ["install", "--no-audit", "--no-fund", "--no-progress", "--ignore-scripts"], {
33809
33898
  cwd: installDir,
33810
33899
  stdio: ["ignore", "pipe", "pipe"],
33811
33900
  env: npmSpawnEnv(npm)
@@ -34134,7 +34223,7 @@ function showToast(ctx, title, message, variant = "info", duration3 = 3000) {
34134
34223
  }
34135
34224
 
34136
34225
  // src/lsp-auto-install.ts
34137
- import { spawn as spawn3 } from "node:child_process";
34226
+ import { spawn as spawn4 } from "node:child_process";
34138
34227
  import { createHash as createHash6 } from "node:crypto";
34139
34228
  import {
34140
34229
  createReadStream,
@@ -34734,7 +34823,7 @@ function runInstall(spec, version2, cwd, signal) {
34734
34823
  return;
34735
34824
  }
34736
34825
  ensureInstallAnchor(cwd);
34737
- const child = spawn3(npm.command, ["install", "--no-save", "--ignore-scripts", "--silent", target], {
34826
+ const child = spawn4(npm.command, ["install", "--no-save", "--ignore-scripts", "--silent", target], {
34738
34827
  stdio: ["ignore", "pipe", "pipe"],
34739
34828
  cwd,
34740
34829
  env: npmSpawnEnv(npm)
@@ -36441,14 +36530,23 @@ function readStatusBar(value) {
36441
36530
  if (typeof value !== "object" || value === null)
36442
36531
  return;
36443
36532
  const bar = asRecord(value);
36533
+ const errors3 = readOptionalNumber(bar.errors);
36534
+ const warnings = readOptionalNumber(bar.warnings);
36535
+ const deadCode = readOptionalNumber(bar.dead_code);
36536
+ const unusedExports = readOptionalNumber(bar.unused_exports);
36537
+ const duplicates = readOptionalNumber(bar.duplicates);
36538
+ const todos = readOptionalNumber(bar.todos);
36539
+ if (errors3 === null && warnings === null && deadCode === null && unusedExports === null && duplicates === null && todos === null) {
36540
+ return;
36541
+ }
36444
36542
  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)
36543
+ ...errors3 !== null ? { errors: errors3 } : {},
36544
+ ...warnings !== null ? { warnings } : {},
36545
+ ...deadCode !== null ? { dead_code: deadCode } : {},
36546
+ ...unusedExports !== null ? { unused_exports: unusedExports } : {},
36547
+ ...duplicates !== null ? { duplicates } : {},
36548
+ ...todos !== null ? { todos } : {},
36549
+ ...bar.tier2_stale === true ? { tier2_stale: true } : {}
36452
36550
  };
36453
36551
  }
36454
36552
  function formatFlag(enabled) {
@@ -36457,6 +36555,15 @@ function formatFlag(enabled) {
36457
36555
  function formatCount(value) {
36458
36556
  return value == null ? "—" : value.toLocaleString("en-US");
36459
36557
  }
36558
+ function formatCacheRoleLabel(role) {
36559
+ if (role === "worktree") {
36560
+ return "worktree — shared repo index (built by the main checkout)";
36561
+ }
36562
+ if (role === "read_only") {
36563
+ return "read_only — sharing the repo index family (read-only borrow)";
36564
+ }
36565
+ return role;
36566
+ }
36460
36567
  function formatSemanticIndexStatus(status, stage) {
36461
36568
  if ((status === "loading" || status === "building") && stage === "fingerprint_change") {
36462
36569
  return "Rebuilding (model changed)";
@@ -36561,7 +36668,7 @@ function formatStatusMarkdown(status) {
36561
36668
  `- **Version:** \`${status.version}\``,
36562
36669
  `- **Project root:** \`${status.project_root ?? "(not configured)"}\``,
36563
36670
  `- **Canonical root:** \`${status.canonical_root ?? "(not configured)"}\``,
36564
- `- **Cache role:** \`${status.cache_role}\``,
36671
+ `- **Cache role:** \`${formatCacheRoleLabel(status.cache_role)}\``,
36565
36672
  "",
36566
36673
  "### Enabled features",
36567
36674
  `- \`format_on_edit\`: ${formatFlag(status.features.format_on_edit)}`,
@@ -36608,7 +36715,19 @@ function formatStatusMarkdown(status) {
36608
36715
  }
36609
36716
  if (status.status_bar) {
36610
36717
  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)}`);
36718
+ const rows = [
36719
+ ["Errors", sb.errors],
36720
+ ["Warnings", sb.warnings],
36721
+ ["Dead code", sb.dead_code],
36722
+ ["Unused exports", sb.unused_exports],
36723
+ ["Duplicates", sb.duplicates],
36724
+ ["TODOs", sb.todos]
36725
+ ].filter((row) => typeof row[1] === "number");
36726
+ if (rows.length > 0) {
36727
+ lines.push("", `### Code Health${sb.tier2_stale ? " (~ stale)" : ""}`);
36728
+ for (const [label, value] of rows)
36729
+ lines.push(`- **${label}:** ${formatCount(value)}`);
36730
+ }
36612
36731
  }
36613
36732
  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
36733
  return lines.join(`
@@ -36695,27 +36814,6 @@ function registerShutdownCleanup(fn) {
36695
36814
  };
36696
36815
  }
36697
36816
 
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
36817
  // src/sync-watch-abort.ts
36720
36818
  var abortFlags = new Map;
36721
36819
  function signalSyncWatchAbort(sessionID) {
@@ -37464,6 +37562,7 @@ function createBashTool(ctx, aftSearchRegisteredOverride) {
37464
37562
  const shellEnv = await ctx.plugin?.trigger?.("shell.env", { cwd, sessionID: context.sessionID, callID: getCallID(context) }, { env: {} });
37465
37563
  const removeAbortListener = listenForForegroundAbort(ctx, context, !effectiveBackground && !requestedPty);
37466
37564
  let data;
37565
+ let usedHostFallback = false;
37467
37566
  try {
37468
37567
  data = await withPermissionLoop(ctx, context, {
37469
37568
  command,
@@ -37489,6 +37588,31 @@ function createBashTool(ctx, aftSearchRegisteredOverride) {
37489
37588
  metadata?.({ output: accumulatedOutput, description });
37490
37589
  }
37491
37590
  });
37591
+ } catch (error53) {
37592
+ if (!bashCfg.host_fallback || !isBashTransportDeadError(error53))
37593
+ throw error53;
37594
+ if (rawRequestedBackground) {
37595
+ throw new Error(`${BASH_HOST_FALLBACK_REFUSAL}; background:true is unsupported.`);
37596
+ }
37597
+ if (rawRequestedPty) {
37598
+ throw new Error(`${BASH_HOST_FALLBACK_REFUSAL}; pty:true is unsupported.`);
37599
+ }
37600
+ const projectRoot = projectRootFor(context);
37601
+ const pattern = bashHostFallbackAskPattern(command, projectRoot);
37602
+ await runAsk(context.ask({
37603
+ permission: "bash",
37604
+ patterns: [pattern],
37605
+ always: [],
37606
+ metadata: { command, cwd: projectRoot, host_fallback: true }
37607
+ }));
37608
+ data = await runBashHostFallback({
37609
+ command,
37610
+ projectRoot,
37611
+ timeoutMs: rawTimeout,
37612
+ signal: context.abort,
37613
+ env: shellEnv?.env
37614
+ });
37615
+ usedHostFallback = true;
37492
37616
  } finally {
37493
37617
  removeAbortListener();
37494
37618
  }
@@ -37506,7 +37630,8 @@ function createBashTool(ctx, aftSearchRegisteredOverride) {
37506
37630
  metadata?.(metadataPayload2);
37507
37631
  return { output: rendered2, title: uiTitle, metadata: metadataPayload2 };
37508
37632
  }
37509
- const rendered = maybeAppendGrepSearchHint(data.output ?? "", command, aftSearchRegistered, projectRootFor(context));
37633
+ const output = data.output ?? "";
37634
+ const rendered = usedHostFallback ? output : maybeAppendGrepSearchHint(output, command, aftSearchRegistered, projectRootFor(context));
37510
37635
  const metadataPayload = foregroundMetadata(description, data, rendered);
37511
37636
  metadata?.(metadataPayload);
37512
37637
  return {
@@ -38870,6 +38995,125 @@ async function resolveAndGateScope(ctx, context, scope) {
38870
38995
  }
38871
38996
  return { scope: Array.isArray(scope) ? resolved : resolved[0] };
38872
38997
  }
38998
+ function asRecord2(value) {
38999
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : undefined;
39000
+ }
39001
+ function asString(value) {
39002
+ return typeof value === "string" ? value : undefined;
39003
+ }
39004
+ function firstRecord(...values) {
39005
+ for (const value of values) {
39006
+ const record2 = asRecord2(value);
39007
+ if (record2)
39008
+ return record2;
39009
+ }
39010
+ return;
39011
+ }
39012
+ function firstString(...values) {
39013
+ for (const value of values) {
39014
+ const text = asString(value);
39015
+ if (text !== undefined)
39016
+ return text;
39017
+ }
39018
+ return;
39019
+ }
39020
+ function terminalKind(response) {
39021
+ for (const value of [
39022
+ response.inspect_terminal,
39023
+ response.terminal,
39024
+ response.outcome,
39025
+ response.inspect_outcome,
39026
+ response.status
39027
+ ]) {
39028
+ if (typeof value !== "string")
39029
+ continue;
39030
+ const normalized = value.toUpperCase().replaceAll("_", "-");
39031
+ if (normalized === "FRESH" || normalized === "INTERRUPTED" || normalized === "PHASE-FAILED") {
39032
+ return normalized;
39033
+ }
39034
+ }
39035
+ return;
39036
+ }
39037
+ function parseInspectPhaseEntries(value) {
39038
+ if (!Array.isArray(value))
39039
+ return [];
39040
+ return value.flatMap((candidate) => {
39041
+ const entry = asRecord2(candidate);
39042
+ const id = asString(entry?.id);
39043
+ if (!id)
39044
+ return [];
39045
+ const alsoSatisfied = Array.isArray(entry?.also_satisfied) ? entry.also_satisfied.filter((category) => typeof category === "string") : [];
39046
+ return [
39047
+ {
39048
+ id,
39049
+ producer: asString(entry?.producer),
39050
+ category: asString(entry?.category),
39051
+ alsoSatisfied
39052
+ }
39053
+ ];
39054
+ });
39055
+ }
39056
+ function parseInspectTerminal(payload) {
39057
+ const response = asRecord2(payload);
39058
+ if (!response)
39059
+ return;
39060
+ const kind = terminalKind(response);
39061
+ if (!kind)
39062
+ return;
39063
+ const waitStamp = firstRecord(response.wait_stamp, response.waitStamp, response.blocking_wait_stamp);
39064
+ const phases = parseInspectPhaseEntries(kind === "FRESH" ? waitStamp?.phases ?? response.completed_phases ?? response.completedPhases ?? response.phases : response.completed_phases ?? response.completedPhases ?? response.phases);
39065
+ if (kind !== "PHASE-FAILED") {
39066
+ return {
39067
+ kind,
39068
+ phases,
39069
+ waitStampText: kind === "FRESH" ? firstString(waitStamp?.text, waitStamp?.human_text) : undefined
39070
+ };
39071
+ }
39072
+ const failedPhaseRecord = asRecord2(response.failed_phase);
39073
+ const failedPhaseId = firstString(failedPhaseRecord?.id, response.failed_phase);
39074
+ const failedPhase = failedPhaseId ? parseInspectPhaseEntries([
39075
+ {
39076
+ id: failedPhaseId,
39077
+ producer: firstString(failedPhaseRecord?.producer, response.failed_phase_producer, response.producer),
39078
+ category: firstString(failedPhaseRecord?.category, response.failed_phase_category, response.category)
39079
+ }
39080
+ ])[0] : undefined;
39081
+ return {
39082
+ kind,
39083
+ phases,
39084
+ failedPhase,
39085
+ failureReason: asString(response.failure_reason),
39086
+ failureDetail: asString(response.failure_detail)
39087
+ };
39088
+ }
39089
+ function formatPhase(entry) {
39090
+ const details = [
39091
+ entry.producer ? `producer: ${entry.producer}` : undefined,
39092
+ entry.category ? `category: ${entry.category}` : undefined,
39093
+ entry.alsoSatisfied.length > 0 ? `also satisfied: ${entry.alsoSatisfied.join(", ")}` : undefined
39094
+ ].filter((detail) => Boolean(detail));
39095
+ return details.length > 0 ? `${entry.id} (${details.join("; ")})` : entry.id;
39096
+ }
39097
+ function renderInspectTerminal(terminal, serverText) {
39098
+ const lines = [terminal.kind];
39099
+ if (terminal.kind === "FRESH") {
39100
+ lines.push(`wait-stamp: ${terminal.waitStampText ?? "not supplied"}`);
39101
+ }
39102
+ if (terminal.kind === "PHASE-FAILED") {
39103
+ if (terminal.failedPhase)
39104
+ lines.push(`failed phase: ${formatPhase(terminal.failedPhase)}`);
39105
+ lines.push(`failure reason: ${terminal.failureReason ?? "not supplied"}`);
39106
+ if (terminal.failureDetail)
39107
+ lines.push(`failure detail: ${terminal.failureDetail}`);
39108
+ }
39109
+ lines.push(terminal.phases.length > 0 ? `completed phases:
39110
+ ${terminal.phases.map((phase) => `- ${formatPhase(phase)}`).join(`
39111
+ `)}` : "completed phases: none");
39112
+ if (serverText?.trim())
39113
+ lines.push(serverText);
39114
+ return lines.join(`
39115
+ `);
39116
+ }
38873
39117
  function inspectToolSurfaceEnabled(config2) {
38874
39118
  return (config2.tool_surface ?? "recommended") !== "minimal" && config2.inspect?.enabled !== false;
38875
39119
  }
@@ -38885,9 +39129,8 @@ function createInspectTier2IdleScheduler(options) {
38885
39129
  timers.delete(sessionID);
38886
39130
  };
38887
39131
  const clearAll = () => {
38888
- for (const timer of timers.values()) {
39132
+ for (const timer of timers.values())
38889
39133
  clearTimer(timer);
38890
- }
38891
39134
  timers.clear();
38892
39135
  };
38893
39136
  const schedule = (sessionID) => {
@@ -38908,12 +39151,12 @@ function createInspectTier2IdleScheduler(options) {
38908
39151
  }
38909
39152
  function inspectTools(ctx) {
38910
39153
  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.
39154
+ 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
39155
 
38913
39156
  ` + "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
39157
  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.")),
39158
+ 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.")),
39159
+ 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
39160
  topK: arg(z10.number().int().positive().max(100).optional().describe("Max drill-down items per category. Default 20, max 100."))
38918
39161
  },
38919
39162
  execute: async (args, context) => {
@@ -38921,27 +39164,23 @@ function inspectTools(ctx) {
38921
39164
  const scoped = await resolveAndGateScope(ctx, context, normalizeStringOrArray(args.scope));
38922
39165
  if (scoped.denial)
38923
39166
  return permissionDeniedResponse(scoped.denial);
38924
- const scope = scoped.scope;
38925
- const topK = args.topK === undefined || args.topK === null ? undefined : args.topK;
38926
39167
  const rawArgs = {};
38927
39168
  if (sections !== undefined)
38928
39169
  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) {
39170
+ if (scoped.scope !== undefined)
39171
+ rawArgs.scope = scoped.scope;
39172
+ if (args.topK !== undefined && args.topK !== null)
39173
+ rawArgs.topK = args.topK;
39174
+ const response = await callToolCall(ctx, context, "inspect", rawArgs);
39175
+ const terminal = parseInspectTerminal(response);
39176
+ if (terminal)
39177
+ return renderInspectTerminal(terminal, response.text);
39178
+ if (response.success === false)
38937
39179
  throw new Error(response.message || "inspect failed");
38938
- }
38939
39180
  return response.text;
38940
39181
  }
38941
39182
  };
38942
- return {
38943
- aft_inspect: inspectTool
38944
- };
39183
+ return { aft_inspect: inspectTool };
38945
39184
  }
38946
39185
 
38947
39186
  // src/tools/navigation.ts
@@ -39943,7 +40182,7 @@ var PLUGIN_VERSION = (() => {
39943
40182
  return "0.0.0";
39944
40183
  }
39945
40184
  })();
39946
- var ANNOUNCEMENT_VERSION = "0.50.3";
40185
+ var ANNOUNCEMENT_VERSION = "0.51.0";
39947
40186
  var ANNOUNCEMENT_FEATURES = [
39948
40187
  "Callgraph stays consistent under load: edits arriving mid-rebuild can no longer be silently lost from navigation results.",
39949
40188
  "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 +40717,6 @@ Install: ${getManualInstallHint()}`).catch(() => {});
40478
40717
  const sessionID = extractSessionID(eventInput.event.properties);
40479
40718
  if (eventType === "session.deleted" && sessionID) {
40480
40719
  inspectTier2Idle.clear(sessionID);
40481
- clearStatusBarSession(sessionID);
40482
40720
  pool.closeSession(input.directory, sessionID).catch(() => {});
40483
40721
  return;
40484
40722
  }
@@ -40567,12 +40805,6 @@ Install: ${getManualInstallHint()}`).catch(() => {});
40567
40805
  }
40568
40806
  const sessionDir = getSessionDirectoryCached(toolInput.sessionID) ?? input.directory;
40569
40807
  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
40808
  },
40577
40809
  config: async (config2) => {
40578
40810
  if (!config2 || typeof config2 !== "object")