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