@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/config.d.ts +6 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +386 -154
- package/dist/shared/status.d.ts +15 -18
- package/dist/shared/status.d.ts.map +1 -1
- package/dist/tools/_shared.d.ts.map +1 -1
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/inspect.d.ts +28 -0
- package/dist/tools/inspect.d.ts.map +1 -1
- package/package.json +8 -8
- package/src/shared/status.ts +79 -50
- package/src/tui/index.tsx +55 -45
- package/src/tui/sidebar.tsx +79 -55
- package/src/tui-compiled/index.tsx +87 -69
- package/src/tui-compiled/sidebar.tsx +102 -84
- package/dist/status-bar-inject.d.ts +0 -11
- package/dist/status-bar-inject.d.ts.map +0 -1
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
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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) ||
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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:
|
|
36446
|
-
warnings:
|
|
36447
|
-
dead_code:
|
|
36448
|
-
unused_exports:
|
|
36449
|
-
duplicates:
|
|
36450
|
-
todos:
|
|
36451
|
-
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
|
-
|
|
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
|
|
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: "
|
|
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
|
|
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
|
-
|
|
38935
|
-
|
|
38936
|
-
|
|
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.
|
|
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")
|