@cortexkit/aft-pi 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 +16 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/dialogs/status-dialog.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +473 -303
- package/dist/shared/status.d.ts +13 -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 +29 -1
- package/dist/tools/inspect.d.ts.map +1 -1
- package/package.json +8 -8
- package/dist/status-bar-inject.d.ts +0 -12
- package/dist/status-bar-inject.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -8325,6 +8325,120 @@ function skipSpaces(input, start) {
|
|
|
8325
8325
|
index++;
|
|
8326
8326
|
return index;
|
|
8327
8327
|
}
|
|
8328
|
+
// ../aft-bridge/dist/bash-host-fallback.js
|
|
8329
|
+
import { spawn } from "node:child_process";
|
|
8330
|
+
var BASH_HOST_FALLBACK_BANNER = "[AFT host fallback - module transport down; no rewrites/compression/background]";
|
|
8331
|
+
var BASH_HOST_FALLBACK_MAX_OUTPUT_BYTES = 100 * 1024;
|
|
8332
|
+
var BASH_HOST_FALLBACK_MAX_TIMEOUT_MS = 10 * 60 * 1000;
|
|
8333
|
+
var BASH_HOST_FALLBACK_REFUSAL = "AFT transport is down; only foreground execution is available in host fallback";
|
|
8334
|
+
function bashHostFallbackAskPattern(command, cwd) {
|
|
8335
|
+
return `AFT UNAVAILABLE - host fallback execution:
|
|
8336
|
+
|
|
8337
|
+
Exact command:
|
|
8338
|
+
${command}
|
|
8339
|
+
|
|
8340
|
+
Working directory:
|
|
8341
|
+
${cwd}`;
|
|
8342
|
+
}
|
|
8343
|
+
function appendTail(chunks, chunk) {
|
|
8344
|
+
const combined = Buffer.concat([...chunks, chunk]);
|
|
8345
|
+
if (combined.byteLength <= BASH_HOST_FALLBACK_MAX_OUTPUT_BYTES) {
|
|
8346
|
+
return { chunks: [combined], truncated: false };
|
|
8347
|
+
}
|
|
8348
|
+
return {
|
|
8349
|
+
chunks: [combined.subarray(combined.byteLength - BASH_HOST_FALLBACK_MAX_OUTPUT_BYTES)],
|
|
8350
|
+
truncated: true
|
|
8351
|
+
};
|
|
8352
|
+
}
|
|
8353
|
+
function renderOutput(output, exitCode) {
|
|
8354
|
+
const body = output.toString("utf8");
|
|
8355
|
+
const separator = body.length === 0 || body.endsWith(`
|
|
8356
|
+
`) ? "" : `
|
|
8357
|
+
`;
|
|
8358
|
+
return `${BASH_HOST_FALLBACK_BANNER}
|
|
8359
|
+
${body}${separator}[exit code: ${exitCode}]`;
|
|
8360
|
+
}
|
|
8361
|
+
async function runBashHostFallback(options) {
|
|
8362
|
+
const timeoutMs = Math.min(Math.max(1, options.timeoutMs ?? BASH_HOST_FALLBACK_MAX_TIMEOUT_MS), BASH_HOST_FALLBACK_MAX_TIMEOUT_MS);
|
|
8363
|
+
if (options.signal?.aborted) {
|
|
8364
|
+
throw new DOMException("The host fallback command was aborted", "AbortError");
|
|
8365
|
+
}
|
|
8366
|
+
return await new Promise((resolve2, reject) => {
|
|
8367
|
+
const child = spawn(options.command, {
|
|
8368
|
+
cwd: options.projectRoot,
|
|
8369
|
+
shell: true,
|
|
8370
|
+
env: { ...process.env, ...options.env },
|
|
8371
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
8372
|
+
detached: process.platform !== "win32",
|
|
8373
|
+
windowsHide: true
|
|
8374
|
+
});
|
|
8375
|
+
let chunks = [];
|
|
8376
|
+
let truncated = false;
|
|
8377
|
+
let timedOut = false;
|
|
8378
|
+
let aborted = false;
|
|
8379
|
+
let settled = false;
|
|
8380
|
+
let abortForceTimer;
|
|
8381
|
+
const capture = (chunk) => {
|
|
8382
|
+
const next = appendTail(chunks, Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
8383
|
+
chunks = next.chunks;
|
|
8384
|
+
truncated ||= next.truncated;
|
|
8385
|
+
};
|
|
8386
|
+
child.stdout?.on("data", capture);
|
|
8387
|
+
child.stderr?.on("data", capture);
|
|
8388
|
+
const kill = (signal) => {
|
|
8389
|
+
if (child.exitCode !== null || child.signalCode !== null)
|
|
8390
|
+
return;
|
|
8391
|
+
if (process.platform !== "win32" && child.pid !== undefined) {
|
|
8392
|
+
try {
|
|
8393
|
+
process.kill(-child.pid, signal);
|
|
8394
|
+
return;
|
|
8395
|
+
} catch {}
|
|
8396
|
+
}
|
|
8397
|
+
child.kill(signal);
|
|
8398
|
+
};
|
|
8399
|
+
const onAbort = () => {
|
|
8400
|
+
aborted = true;
|
|
8401
|
+
kill("SIGTERM");
|
|
8402
|
+
abortForceTimer = setTimeout(() => kill("SIGKILL"), 250);
|
|
8403
|
+
abortForceTimer.unref?.();
|
|
8404
|
+
};
|
|
8405
|
+
options.signal?.addEventListener("abort", onAbort, { once: true });
|
|
8406
|
+
const timer = setTimeout(() => {
|
|
8407
|
+
timedOut = true;
|
|
8408
|
+
kill("SIGKILL");
|
|
8409
|
+
}, timeoutMs);
|
|
8410
|
+
const cleanup = () => {
|
|
8411
|
+
clearTimeout(timer);
|
|
8412
|
+
if (abortForceTimer !== undefined)
|
|
8413
|
+
clearTimeout(abortForceTimer);
|
|
8414
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
8415
|
+
};
|
|
8416
|
+
child.once("error", (error2) => {
|
|
8417
|
+
if (settled)
|
|
8418
|
+
return;
|
|
8419
|
+
settled = true;
|
|
8420
|
+
cleanup();
|
|
8421
|
+
reject(error2);
|
|
8422
|
+
});
|
|
8423
|
+
child.once("close", (code) => {
|
|
8424
|
+
if (settled)
|
|
8425
|
+
return;
|
|
8426
|
+
settled = true;
|
|
8427
|
+
cleanup();
|
|
8428
|
+
if (aborted) {
|
|
8429
|
+
reject(new DOMException("The host fallback command was aborted", "AbortError"));
|
|
8430
|
+
return;
|
|
8431
|
+
}
|
|
8432
|
+
const exitCode = timedOut ? 124 : code ?? 1;
|
|
8433
|
+
resolve2({
|
|
8434
|
+
success: true,
|
|
8435
|
+
output: renderOutput(Buffer.concat(chunks), exitCode),
|
|
8436
|
+
exit_code: exitCode,
|
|
8437
|
+
truncated
|
|
8438
|
+
});
|
|
8439
|
+
});
|
|
8440
|
+
});
|
|
8441
|
+
}
|
|
8328
8442
|
// ../aft-bridge/dist/bash-timeout.js
|
|
8329
8443
|
function resolveBashKillTimeout(modelTimeout, foregroundWaitMs) {
|
|
8330
8444
|
if (modelTimeout !== undefined && modelTimeout >= foregroundWaitMs) {
|
|
@@ -8333,7 +8447,7 @@ function resolveBashKillTimeout(modelTimeout, foregroundWaitMs) {
|
|
|
8333
8447
|
return;
|
|
8334
8448
|
}
|
|
8335
8449
|
// ../aft-bridge/dist/bridge.js
|
|
8336
|
-
import { spawn } from "node:child_process";
|
|
8450
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
8337
8451
|
import { createHash } from "node:crypto";
|
|
8338
8452
|
import { readFileSync } from "node:fs";
|
|
8339
8453
|
import { homedir as homedir2 } from "node:os";
|
|
@@ -8363,51 +8477,6 @@ function isPassiveCommand(command) {
|
|
|
8363
8477
|
return PASSIVE_COMMANDS.has(command);
|
|
8364
8478
|
}
|
|
8365
8479
|
|
|
8366
|
-
// ../aft-bridge/dist/status-bar.js
|
|
8367
|
-
var STATUS_BAR_HEARTBEAT_CALLS = 15;
|
|
8368
|
-
function createStatusBarEmitState() {
|
|
8369
|
-
return { callsSinceEmit: 0 };
|
|
8370
|
-
}
|
|
8371
|
-
function parseStatusBarCounts(value) {
|
|
8372
|
-
if (!value || typeof value !== "object")
|
|
8373
|
-
return;
|
|
8374
|
-
const record = value;
|
|
8375
|
-
const num = (key) => {
|
|
8376
|
-
const raw = record[key];
|
|
8377
|
-
return typeof raw === "number" && Number.isFinite(raw) ? raw : 0;
|
|
8378
|
-
};
|
|
8379
|
-
return {
|
|
8380
|
-
errors: num("errors"),
|
|
8381
|
-
warnings: num("warnings"),
|
|
8382
|
-
dead_code: num("dead_code"),
|
|
8383
|
-
unused_exports: num("unused_exports"),
|
|
8384
|
-
duplicates: num("duplicates"),
|
|
8385
|
-
todos: num("todos"),
|
|
8386
|
-
tier2_stale: record.tier2_stale === true,
|
|
8387
|
-
...typeof record.line === "string" ? { line: record.line } : {}
|
|
8388
|
-
};
|
|
8389
|
-
}
|
|
8390
|
-
function countsEqual(a, b) {
|
|
8391
|
-
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;
|
|
8392
|
-
}
|
|
8393
|
-
function shouldEmitStatusBar(state, next) {
|
|
8394
|
-
const changed = state.last === undefined || !countsEqual(state.last, next);
|
|
8395
|
-
state.callsSinceEmit += 1;
|
|
8396
|
-
const heartbeat = state.callsSinceEmit >= STATUS_BAR_HEARTBEAT_CALLS;
|
|
8397
|
-
if (changed || heartbeat) {
|
|
8398
|
-
state.last = next;
|
|
8399
|
-
state.callsSinceEmit = 0;
|
|
8400
|
-
return true;
|
|
8401
|
-
}
|
|
8402
|
-
return false;
|
|
8403
|
-
}
|
|
8404
|
-
function formatStatusBar(counts) {
|
|
8405
|
-
if (counts.line !== undefined)
|
|
8406
|
-
return counts.line;
|
|
8407
|
-
const staleMark = counts.tier2_stale ? "~" : "";
|
|
8408
|
-
return `[AFT E${counts.errors} W${counts.warnings} | ` + `${staleMark}D${counts.dead_code} U${counts.unused_exports} C${counts.duplicates} | ` + `T${counts.todos}]`;
|
|
8409
|
-
}
|
|
8410
|
-
|
|
8411
8480
|
// ../aft-bridge/dist/bridge.js
|
|
8412
8481
|
var DEFAULT_BRIDGE_TIMEOUT_MS = 30000;
|
|
8413
8482
|
var BRIDGE_HANG_TIMEOUT_THRESHOLD = 2;
|
|
@@ -8536,6 +8605,14 @@ class BridgeTransportTimeoutError extends Error {
|
|
|
8536
8605
|
this.name = "BridgeTransportTimeoutError";
|
|
8537
8606
|
}
|
|
8538
8607
|
}
|
|
8608
|
+
|
|
8609
|
+
class BridgeTransportUnavailableError extends Error {
|
|
8610
|
+
code = "bridge_transport_unavailable";
|
|
8611
|
+
constructor(message, options) {
|
|
8612
|
+
super(message, options);
|
|
8613
|
+
this.name = "BridgeTransportUnavailableError";
|
|
8614
|
+
}
|
|
8615
|
+
}
|
|
8539
8616
|
function isBridgeTransportTimeout(err) {
|
|
8540
8617
|
return err instanceof Error && err.code === "transport_timeout";
|
|
8541
8618
|
}
|
|
@@ -8578,7 +8655,6 @@ class BinaryBridge {
|
|
|
8578
8655
|
configureWarningClients = new Map;
|
|
8579
8656
|
restartResetTimer = null;
|
|
8580
8657
|
lastChildActivityAt = 0;
|
|
8581
|
-
lastStatusBar;
|
|
8582
8658
|
consecutiveRequestTimeouts = 0;
|
|
8583
8659
|
errorPrefix;
|
|
8584
8660
|
logger;
|
|
@@ -8678,6 +8754,20 @@ class BinaryBridge {
|
|
|
8678
8754
|
isAlive() {
|
|
8679
8755
|
return this.process !== null && this.process.exitCode === null && !this.process.killed;
|
|
8680
8756
|
}
|
|
8757
|
+
invalidateTransportProcess(error2) {
|
|
8758
|
+
const proc = this.process;
|
|
8759
|
+
if (!proc)
|
|
8760
|
+
return;
|
|
8761
|
+
this.process = null;
|
|
8762
|
+
this.spawnedBinaryFingerprint = null;
|
|
8763
|
+
if (proc.exitCode === null && !proc.killed) {
|
|
8764
|
+
proc.kill("SIGKILL");
|
|
8765
|
+
}
|
|
8766
|
+
this.clearRestartResetTimer();
|
|
8767
|
+
this.configured = false;
|
|
8768
|
+
this.outstandingBackgroundTaskIds.clear();
|
|
8769
|
+
this.rejectAllPending(error2);
|
|
8770
|
+
}
|
|
8681
8771
|
hasPendingRequests() {
|
|
8682
8772
|
return this.pending.size > 0;
|
|
8683
8773
|
}
|
|
@@ -8779,7 +8869,7 @@ class BinaryBridge {
|
|
|
8779
8869
|
throw new Error(`${this.errorPrefix} Bridge is retiring after the on-disk binary changed; retry to respawn on the updated binary`);
|
|
8780
8870
|
}
|
|
8781
8871
|
if (this._shuttingDown) {
|
|
8782
|
-
throw new
|
|
8872
|
+
throw new BridgeTransportUnavailableError(`${this.errorPrefix} Bridge is shutting down, cannot send "${command}"`);
|
|
8783
8873
|
}
|
|
8784
8874
|
if (Object.hasOwn(params, "id")) {
|
|
8785
8875
|
throw new Error("params cannot contain reserved key 'id'");
|
|
@@ -8813,7 +8903,7 @@ class BinaryBridge {
|
|
|
8813
8903
|
await this.deliverConfigureWarnings(configResult, params, options);
|
|
8814
8904
|
await this.checkVersion(implicitTransportOptions);
|
|
8815
8905
|
if (!this.isAlive()) {
|
|
8816
|
-
throw new
|
|
8906
|
+
throw new BridgeTransportUnavailableError(`${this.errorPrefix} Bridge died during version check. Check logs: ${this.getLogFilePathVia()}`);
|
|
8817
8907
|
}
|
|
8818
8908
|
this.configured = true;
|
|
8819
8909
|
} finally {
|
|
@@ -8843,6 +8933,7 @@ class BinaryBridge {
|
|
|
8843
8933
|
`;
|
|
8844
8934
|
const keepBridgeOnTimeout = passive || options?.keepBridgeOnTimeout === true;
|
|
8845
8935
|
let requestSentAt = Date.now();
|
|
8936
|
+
const child = this.process;
|
|
8846
8937
|
const response = await new Promise((resolve2, reject) => {
|
|
8847
8938
|
const timer = setTimeout(() => {
|
|
8848
8939
|
const entry = this.pending.get(id);
|
|
@@ -8879,21 +8970,27 @@ class BinaryBridge {
|
|
|
8879
8970
|
this.handleTimeout(requestSessionId);
|
|
8880
8971
|
}, effectiveTimeoutMs);
|
|
8881
8972
|
this.pending.set(id, { resolve: resolve2, reject, timer, onProgress: options?.onProgress, command });
|
|
8882
|
-
if (!
|
|
8973
|
+
if (!child?.stdin?.writable) {
|
|
8883
8974
|
this.pending.delete(id);
|
|
8884
8975
|
clearTimeout(timer);
|
|
8885
|
-
|
|
8976
|
+
const error2 = new BridgeTransportUnavailableError(`${this.errorPrefix} stdin not writable for command "${command}"`);
|
|
8977
|
+
reject(error2);
|
|
8978
|
+
if (this.process === child)
|
|
8979
|
+
this.invalidateTransportProcess(error2);
|
|
8886
8980
|
return;
|
|
8887
8981
|
}
|
|
8888
8982
|
requestSentAt = Date.now();
|
|
8889
|
-
|
|
8983
|
+
child.stdin.write(line, (err) => {
|
|
8890
8984
|
if (err) {
|
|
8985
|
+
const error2 = new BridgeTransportUnavailableError(`${this.errorPrefix} Failed to write to stdin: ${err.message}`, { cause: err });
|
|
8891
8986
|
const entry = this.pending.get(id);
|
|
8892
8987
|
if (entry) {
|
|
8893
8988
|
this.pending.delete(id);
|
|
8894
8989
|
clearTimeout(entry.timer);
|
|
8895
|
-
entry.reject(
|
|
8990
|
+
entry.reject(error2);
|
|
8896
8991
|
}
|
|
8992
|
+
if (this.process === child)
|
|
8993
|
+
this.invalidateTransportProcess(error2);
|
|
8897
8994
|
}
|
|
8898
8995
|
});
|
|
8899
8996
|
});
|
|
@@ -9053,13 +9150,15 @@ class BinaryBridge {
|
|
|
9053
9150
|
});
|
|
9054
9151
|
}
|
|
9055
9152
|
ensureSpawned(triggeringSessionId) {
|
|
9056
|
-
if (this.isAlive())
|
|
9153
|
+
if (this.isAlive() && this.process?.stdin?.writable)
|
|
9057
9154
|
return;
|
|
9155
|
+
if (this.process !== null) {
|
|
9156
|
+
this.invalidateTransportProcess(new BridgeTransportUnavailableError(`${this.errorPrefix} Child stdin is not writable`));
|
|
9157
|
+
}
|
|
9058
9158
|
this.spawnProcess(triggeringSessionId);
|
|
9059
9159
|
}
|
|
9060
9160
|
spawnProcess(triggeringSessionId) {
|
|
9061
9161
|
this._retiringDueToBinaryChange = false;
|
|
9062
|
-
this.lastStatusBar = undefined;
|
|
9063
9162
|
if (triggeringSessionId) {
|
|
9064
9163
|
this.sessionLogVia(triggeringSessionId, `Spawning binary: ${this.binaryPath} (cwd: ${this.cwd})`);
|
|
9065
9164
|
} else {
|
|
@@ -9100,7 +9199,7 @@ class BinaryBridge {
|
|
|
9100
9199
|
}
|
|
9101
9200
|
}
|
|
9102
9201
|
}
|
|
9103
|
-
const child =
|
|
9202
|
+
const child = spawn2(this.binaryPath, [], {
|
|
9104
9203
|
cwd: this.cwd,
|
|
9105
9204
|
stdio: ["pipe", "pipe", "pipe"],
|
|
9106
9205
|
env
|
|
@@ -9130,7 +9229,7 @@ class BinaryBridge {
|
|
|
9130
9229
|
if (this.process !== currentChild)
|
|
9131
9230
|
return;
|
|
9132
9231
|
this.errorVia(`Process error: ${err.message}${this.formatStderrTail()}`);
|
|
9133
|
-
this.handleCrash();
|
|
9232
|
+
this.handleCrash(err);
|
|
9134
9233
|
});
|
|
9135
9234
|
child.on("exit", (code, signal) => {
|
|
9136
9235
|
if (this.process !== currentChild)
|
|
@@ -9143,7 +9242,7 @@ class BinaryBridge {
|
|
|
9143
9242
|
this.process = null;
|
|
9144
9243
|
this.configured = false;
|
|
9145
9244
|
this.clearRestartResetTimer();
|
|
9146
|
-
this.rejectAllPending(new
|
|
9245
|
+
this.rejectAllPending(new BridgeTransportUnavailableError(`${this.errorPrefix} Binary killed by ${signal}`));
|
|
9147
9246
|
return;
|
|
9148
9247
|
}
|
|
9149
9248
|
this.handleCrash();
|
|
@@ -9298,7 +9397,6 @@ class BinaryBridge {
|
|
|
9298
9397
|
this.consecutiveRequestTimeouts = 0;
|
|
9299
9398
|
this.scheduleRestartCountReset();
|
|
9300
9399
|
this.accountForBashTaskResponse(entry.command, response);
|
|
9301
|
-
this.captureStatusBar(response);
|
|
9302
9400
|
entry.resolve(response);
|
|
9303
9401
|
} else if (typeof response.type === "string") {
|
|
9304
9402
|
this.logVia(`Ignoring unknown stdout push frame type: ${response.type}`);
|
|
@@ -9319,14 +9417,6 @@ class BinaryBridge {
|
|
|
9319
9417
|
this.outstandingBackgroundTaskIds.add(taskId);
|
|
9320
9418
|
}
|
|
9321
9419
|
}
|
|
9322
|
-
captureStatusBar(response) {
|
|
9323
|
-
const parsed = parseStatusBarCounts(response.status_bar);
|
|
9324
|
-
if (parsed)
|
|
9325
|
-
this.lastStatusBar = parsed;
|
|
9326
|
-
}
|
|
9327
|
-
getStatusBar() {
|
|
9328
|
-
return this.lastStatusBar;
|
|
9329
|
-
}
|
|
9330
9420
|
handleTimeout(triggeringSessionId) {
|
|
9331
9421
|
this.consecutiveRequestTimeouts = 0;
|
|
9332
9422
|
this.spawnedBinaryFingerprint = null;
|
|
@@ -9367,7 +9457,7 @@ class BinaryBridge {
|
|
|
9367
9457
|
if (tail) {
|
|
9368
9458
|
this.errorVia(`Binary crashed (restarts: ${this._restartCount})${cause ? `: ${cause.message}` : ""}.${tail}`);
|
|
9369
9459
|
}
|
|
9370
|
-
this.rejectAllPending(new
|
|
9460
|
+
this.rejectAllPending(new BridgeTransportUnavailableError(`${this.errorPrefix} Binary crashed (restarts: ${this._restartCount})${cause ? `: ${cause.message}` : ""} (see ${this.getLogFilePathVia()})`, { cause }));
|
|
9371
9461
|
if (this._retiringDueToBinaryChange) {
|
|
9372
9462
|
this.logVia("Binary exited while retiring after an on-disk update; skipping auto-restart");
|
|
9373
9463
|
return;
|
|
@@ -13030,6 +13120,12 @@ function normalizeWindowsRoot(p) {
|
|
|
13030
13120
|
}
|
|
13031
13121
|
|
|
13032
13122
|
// ../aft-bridge/dist/subc-transport.js
|
|
13123
|
+
class SubcTransportShuttingDownError extends SubcCallError {
|
|
13124
|
+
constructor() {
|
|
13125
|
+
super("terminal", "subc transport is shutting down", "transport_shutting_down");
|
|
13126
|
+
this.name = "SubcTransportShuttingDownError";
|
|
13127
|
+
}
|
|
13128
|
+
}
|
|
13033
13129
|
var AFT_MODULE_ID = "aft";
|
|
13034
13130
|
var MAX_CONSECUTIVE_TRANSPORT_FAILURES = 3;
|
|
13035
13131
|
var BG_STABLE_MS = 5000;
|
|
@@ -13371,7 +13467,6 @@ class SubcTransport {
|
|
|
13371
13467
|
pool;
|
|
13372
13468
|
projectRoot;
|
|
13373
13469
|
generation;
|
|
13374
|
-
lastStatusBar;
|
|
13375
13470
|
cachedStatus = null;
|
|
13376
13471
|
constructor(pool, projectRoot, generation) {
|
|
13377
13472
|
this.pool = pool;
|
|
@@ -13387,20 +13482,12 @@ class SubcTransport {
|
|
|
13387
13482
|
getConcretePoolId() {
|
|
13388
13483
|
return this.pool.getConcretePoolId();
|
|
13389
13484
|
}
|
|
13390
|
-
getStatusBar() {
|
|
13391
|
-
return this.lastStatusBar;
|
|
13392
|
-
}
|
|
13393
13485
|
getCachedStatus() {
|
|
13394
13486
|
return this.cachedStatus;
|
|
13395
13487
|
}
|
|
13396
13488
|
cacheStatusSnapshot(snapshot) {
|
|
13397
13489
|
this.cachedStatus = snapshot;
|
|
13398
13490
|
}
|
|
13399
|
-
captureStatusBar(response) {
|
|
13400
|
-
const parsed = parseStatusBarCounts(response.status_bar);
|
|
13401
|
-
if (parsed)
|
|
13402
|
-
this.lastStatusBar = parsed;
|
|
13403
|
-
}
|
|
13404
13491
|
identityFor(session) {
|
|
13405
13492
|
return {
|
|
13406
13493
|
project_root: this.projectRoot,
|
|
@@ -13421,9 +13508,7 @@ class SubcTransport {
|
|
|
13421
13508
|
if (preview === true)
|
|
13422
13509
|
body.preview = true;
|
|
13423
13510
|
const reply = await this.pool.routeRequest(this.identityFor(sessionId), body, timeoutMs, onProgress, this.generation);
|
|
13424
|
-
|
|
13425
|
-
this.captureStatusBar(result);
|
|
13426
|
-
return result;
|
|
13511
|
+
return reliftReply(reply);
|
|
13427
13512
|
}
|
|
13428
13513
|
async send(command, params = {}, options) {
|
|
13429
13514
|
this.assertCurrent();
|
|
@@ -13437,9 +13522,7 @@ class SubcTransport {
|
|
|
13437
13522
|
if (editSlotSurvives !== undefined)
|
|
13438
13523
|
body.edit_slot_survives = editSlotSurvives;
|
|
13439
13524
|
const reply = await this.pool.routeRequest(this.identityFor(session), body, timeoutMs, onProgress, this.generation);
|
|
13440
|
-
|
|
13441
|
-
this.captureStatusBar(response);
|
|
13442
|
-
return response;
|
|
13525
|
+
return reliftReply(reply);
|
|
13443
13526
|
}
|
|
13444
13527
|
splitOptions(options) {
|
|
13445
13528
|
if (!options)
|
|
@@ -13710,7 +13793,7 @@ class SubcTransportPool {
|
|
|
13710
13793
|
getBridge(projectRoot) {
|
|
13711
13794
|
const root = this.canonicalRoot(projectRoot);
|
|
13712
13795
|
if (this.shuttingDown && this.lifecycleEnabled()) {
|
|
13713
|
-
throw new
|
|
13796
|
+
throw new SubcTransportShuttingDownError;
|
|
13714
13797
|
}
|
|
13715
13798
|
if (!this.lifecycleEnabled())
|
|
13716
13799
|
return this.makeFacade(root);
|
|
@@ -14010,7 +14093,7 @@ class SubcTransportPool {
|
|
|
14010
14093
|
}
|
|
14011
14094
|
async ensureClient() {
|
|
14012
14095
|
if (this.shuttingDown)
|
|
14013
|
-
throw new
|
|
14096
|
+
throw new SubcTransportShuttingDownError;
|
|
14014
14097
|
if (this.client)
|
|
14015
14098
|
return this.client;
|
|
14016
14099
|
if (this.connecting)
|
|
@@ -14024,7 +14107,7 @@ class SubcTransportPool {
|
|
|
14024
14107
|
try {
|
|
14025
14108
|
client.close();
|
|
14026
14109
|
} catch {}
|
|
14027
|
-
throw new
|
|
14110
|
+
throw new SubcTransportShuttingDownError;
|
|
14028
14111
|
}
|
|
14029
14112
|
this.client = client;
|
|
14030
14113
|
this.transportFailures = 0;
|
|
@@ -14289,8 +14372,24 @@ function isRouteGoodbyeError(error2) {
|
|
|
14289
14372
|
}
|
|
14290
14373
|
return error2.code === "route_closed" && error2.message.includes("route closed by subc");
|
|
14291
14374
|
}
|
|
14375
|
+
function hasEngineResponse(error2) {
|
|
14376
|
+
const response = error2.response;
|
|
14377
|
+
if (response !== null && typeof response === "object")
|
|
14378
|
+
return true;
|
|
14379
|
+
const cause = error2.cause;
|
|
14380
|
+
if (cause === null || typeof cause !== "object")
|
|
14381
|
+
return false;
|
|
14382
|
+
const causeResponse = cause.response;
|
|
14383
|
+
return causeResponse !== null && typeof causeResponse === "object";
|
|
14384
|
+
}
|
|
14385
|
+
function isBashTransportDeadError(error2) {
|
|
14386
|
+
if (!(error2 instanceof Error) || hasEngineResponse(error2) || isRouteGoodbyeError(error2)) {
|
|
14387
|
+
return false;
|
|
14388
|
+
}
|
|
14389
|
+
return error2 instanceof BridgeTransportUnavailableError || error2 instanceof SubcTransportShuttingDownError || isConsumerReconnectTransient(error2) || error2 instanceof StaleRouteHandleError || error2 instanceof SubcRootGenerationExpiredError || error2 instanceof SubcRootReapedError;
|
|
14390
|
+
}
|
|
14292
14391
|
function isTransportClassError(error2) {
|
|
14293
|
-
return isBridgeTransportTimeout(error2) ||
|
|
14392
|
+
return isBridgeTransportTimeout(error2) || isBashTransportDeadError(error2);
|
|
14294
14393
|
}
|
|
14295
14394
|
function adaptToolError(command, error2) {
|
|
14296
14395
|
if (!(error2 instanceof Error))
|
|
@@ -16860,9 +16959,6 @@ class RevivableProjectTransport {
|
|
|
16860
16959
|
getCwd() {
|
|
16861
16960
|
return this.projectRoot;
|
|
16862
16961
|
}
|
|
16863
|
-
getStatusBar() {
|
|
16864
|
-
return this.owner.currentBridge(this.projectRoot)?.getStatusBar();
|
|
16865
|
-
}
|
|
16866
16962
|
getCachedStatus() {
|
|
16867
16963
|
return this.owner.currentBridge(this.projectRoot)?.getCachedStatus() ?? null;
|
|
16868
16964
|
}
|
|
@@ -17881,7 +17977,7 @@ import {
|
|
|
17881
17977
|
// package.json
|
|
17882
17978
|
var package_default = {
|
|
17883
17979
|
name: "@cortexkit/aft-pi",
|
|
17884
|
-
version: "0.
|
|
17980
|
+
version: "0.51.1",
|
|
17885
17981
|
type: "module",
|
|
17886
17982
|
description: "Pi coding agent extension for Agent File Tools (AFT) — tree-sitter and LSP-powered code analysis",
|
|
17887
17983
|
main: "dist/index.js",
|
|
@@ -17904,19 +18000,19 @@ var package_default = {
|
|
|
17904
18000
|
"test:unit": "bun test src/__tests__ --path-ignore-patterns 'src/__tests__/e2e/**'"
|
|
17905
18001
|
},
|
|
17906
18002
|
dependencies: {
|
|
17907
|
-
"@cortexkit/aft-bridge": "0.
|
|
18003
|
+
"@cortexkit/aft-bridge": "0.51.1",
|
|
17908
18004
|
"comment-json": "^5.0.0",
|
|
17909
18005
|
diff: "^8.0.4",
|
|
17910
18006
|
typebox: "1.1.38",
|
|
17911
18007
|
zod: "^4.4.3"
|
|
17912
18008
|
},
|
|
17913
18009
|
optionalDependencies: {
|
|
17914
|
-
"@cortexkit/aft-darwin-arm64": "0.
|
|
17915
|
-
"@cortexkit/aft-darwin-x64": "0.
|
|
17916
|
-
"@cortexkit/aft-linux-arm64": "0.
|
|
17917
|
-
"@cortexkit/aft-linux-x64": "0.
|
|
17918
|
-
"@cortexkit/aft-win32-arm64": "0.
|
|
17919
|
-
"@cortexkit/aft-win32-x64": "0.
|
|
18010
|
+
"@cortexkit/aft-darwin-arm64": "0.51.1",
|
|
18011
|
+
"@cortexkit/aft-darwin-x64": "0.51.1",
|
|
18012
|
+
"@cortexkit/aft-linux-arm64": "0.51.1",
|
|
18013
|
+
"@cortexkit/aft-linux-x64": "0.51.1",
|
|
18014
|
+
"@cortexkit/aft-win32-arm64": "0.51.1",
|
|
18015
|
+
"@cortexkit/aft-win32-x64": "0.51.1"
|
|
17920
18016
|
},
|
|
17921
18017
|
devDependencies: {
|
|
17922
18018
|
"@earendil-works/pi-coding-agent": "^0.80.2",
|
|
@@ -17983,14 +18079,23 @@ function readStatusBar(value) {
|
|
|
17983
18079
|
if (typeof value !== "object" || value === null)
|
|
17984
18080
|
return;
|
|
17985
18081
|
const bar = asRecord2(value);
|
|
18082
|
+
const errors = readOptionalNumber(bar.errors);
|
|
18083
|
+
const warnings = readOptionalNumber(bar.warnings);
|
|
18084
|
+
const deadCode = readOptionalNumber(bar.dead_code);
|
|
18085
|
+
const unusedExports = readOptionalNumber(bar.unused_exports);
|
|
18086
|
+
const duplicates = readOptionalNumber(bar.duplicates);
|
|
18087
|
+
const todos = readOptionalNumber(bar.todos);
|
|
18088
|
+
if (errors === null && warnings === null && deadCode === null && unusedExports === null && duplicates === null && todos === null) {
|
|
18089
|
+
return;
|
|
18090
|
+
}
|
|
17986
18091
|
return {
|
|
17987
|
-
errors:
|
|
17988
|
-
warnings:
|
|
17989
|
-
dead_code:
|
|
17990
|
-
unused_exports:
|
|
17991
|
-
duplicates:
|
|
17992
|
-
todos:
|
|
17993
|
-
tier2_stale:
|
|
18092
|
+
...errors !== null ? { errors } : {},
|
|
18093
|
+
...warnings !== null ? { warnings } : {},
|
|
18094
|
+
...deadCode !== null ? { dead_code: deadCode } : {},
|
|
18095
|
+
...unusedExports !== null ? { unused_exports: unusedExports } : {},
|
|
18096
|
+
...duplicates !== null ? { duplicates } : {},
|
|
18097
|
+
...todos !== null ? { todos } : {},
|
|
18098
|
+
...bar.tier2_stale === true ? { tier2_stale: true } : {}
|
|
17994
18099
|
};
|
|
17995
18100
|
}
|
|
17996
18101
|
function formatFlag(enabled) {
|
|
@@ -17999,6 +18104,15 @@ function formatFlag(enabled) {
|
|
|
17999
18104
|
function formatCount(value) {
|
|
18000
18105
|
return value == null ? "—" : value.toLocaleString("en-US");
|
|
18001
18106
|
}
|
|
18107
|
+
function formatCacheRoleLabel(role) {
|
|
18108
|
+
if (role === "worktree") {
|
|
18109
|
+
return "worktree — shared repo index (built by the main checkout)";
|
|
18110
|
+
}
|
|
18111
|
+
if (role === "read_only") {
|
|
18112
|
+
return "read_only — sharing the repo index family (read-only borrow)";
|
|
18113
|
+
}
|
|
18114
|
+
return role;
|
|
18115
|
+
}
|
|
18002
18116
|
function formatSemanticIndexStatus(status, stage) {
|
|
18003
18117
|
if ((status === "loading" || status === "building") && stage === "fingerprint_change") {
|
|
18004
18118
|
return "Rebuilding (model changed)";
|
|
@@ -18099,7 +18213,7 @@ function formatStatusDialogMessage(status) {
|
|
|
18099
18213
|
`AFT version: ${status.version}`,
|
|
18100
18214
|
`Project root: ${status.project_root ?? "(not configured)"}`,
|
|
18101
18215
|
`Canonical root: ${status.canonical_root ?? "(not configured)"}`,
|
|
18102
|
-
`Cache role: ${status.cache_role}`,
|
|
18216
|
+
`Cache role: ${formatCacheRoleLabel(status.cache_role)}`,
|
|
18103
18217
|
"",
|
|
18104
18218
|
"Enabled features",
|
|
18105
18219
|
`- format_on_edit: ${formatFlag(status.features.format_on_edit)}`,
|
|
@@ -18131,7 +18245,19 @@ function formatStatusDialogMessage(status) {
|
|
|
18131
18245
|
lines.push("", "Disk usage", `- trigram index: ${formatBytes(status.disk.trigram_disk_bytes)}`, `- semantic index: ${formatBytes(status.disk.semantic_disk_bytes)}`, "", "Runtime", `- LSP servers: ${formatCount(status.lsp_servers)}`, `- symbol cache: ${formatCount(status.symbol_cache.local_entries)} local / ${formatCount(status.symbol_cache.warm_entries)} warm`);
|
|
18132
18246
|
if (status.status_bar) {
|
|
18133
18247
|
const sb = status.status_bar;
|
|
18134
|
-
|
|
18248
|
+
const rows = [
|
|
18249
|
+
["errors", sb.errors],
|
|
18250
|
+
["warnings", sb.warnings],
|
|
18251
|
+
["dead code", sb.dead_code],
|
|
18252
|
+
["unused exports", sb.unused_exports],
|
|
18253
|
+
["duplicates", sb.duplicates],
|
|
18254
|
+
["todos", sb.todos]
|
|
18255
|
+
].filter((row) => typeof row[1] === "number");
|
|
18256
|
+
if (rows.length > 0) {
|
|
18257
|
+
lines.push("", `Code Health${sb.tier2_stale ? " (~ stale)" : ""}`);
|
|
18258
|
+
for (const [label, value] of rows)
|
|
18259
|
+
lines.push(`- ${label}: ${formatCount(value)}`);
|
|
18260
|
+
}
|
|
18135
18261
|
}
|
|
18136
18262
|
if (status.storage_dir ?? status.disk.storage_dir) {
|
|
18137
18263
|
lines.push(`- storage dir: ${status.storage_dir ?? status.disk.storage_dir}`);
|
|
@@ -18210,6 +18336,8 @@ async function callBridge(bridge, command, params = {}, extCtx, options) {
|
|
|
18210
18336
|
try {
|
|
18211
18337
|
response = await bridge.send(command, merged, Object.keys(sendOptions).length > 0 ? sendOptions : undefined);
|
|
18212
18338
|
} catch (error3) {
|
|
18339
|
+
if (command === "bash" && isBashTransportDeadError(error3))
|
|
18340
|
+
throw error3;
|
|
18213
18341
|
throw adaptToolError(command, error3);
|
|
18214
18342
|
}
|
|
18215
18343
|
if (response.success === false) {
|
|
@@ -18345,8 +18473,8 @@ function renderInner(s, error3, theme, innerWidth) {
|
|
|
18345
18473
|
}
|
|
18346
18474
|
lines.push(rowFull("Project root", s.project_root ?? "(not configured)", theme, innerWidth));
|
|
18347
18475
|
lines.push(rowFull("Canonical root", s.canonical_root ?? "(not configured)", theme, innerWidth));
|
|
18348
|
-
const cacheTone = s.cache_role === "main" ? "accent" :
|
|
18349
|
-
lines.push(rowFull("Cache role", theme.fg(cacheTone, s.cache_role), theme, innerWidth));
|
|
18476
|
+
const cacheTone = s.cache_role === "main" ? "accent" : "muted";
|
|
18477
|
+
lines.push(rowFull("Cache role", theme.fg(cacheTone, formatCacheRoleLabel(s.cache_role)), theme, innerWidth));
|
|
18350
18478
|
lines.push("");
|
|
18351
18479
|
const colWidth = Math.floor((innerWidth - 2) / 2);
|
|
18352
18480
|
const left = [];
|
|
@@ -32839,6 +32967,7 @@ function resolveBashConfig(config2) {
|
|
|
32839
32967
|
rewrite: false,
|
|
32840
32968
|
compress: false,
|
|
32841
32969
|
background: false,
|
|
32970
|
+
host_fallback: false,
|
|
32842
32971
|
long_running_reminder_enabled: reminderEnabled,
|
|
32843
32972
|
long_running_reminder_interval_ms: reminderInterval,
|
|
32844
32973
|
foreground_wait_window_ms: foregroundWaitWindowMs
|
|
@@ -32854,7 +32983,8 @@ function resolveBashConfig(config2) {
|
|
|
32854
32983
|
enabled: true,
|
|
32855
32984
|
rewrite: top.rewrite ?? true,
|
|
32856
32985
|
compress: top.compress ?? true,
|
|
32857
|
-
background: top.background ?? true
|
|
32986
|
+
background: top.background ?? true,
|
|
32987
|
+
host_fallback: top.host_fallback ?? false
|
|
32858
32988
|
};
|
|
32859
32989
|
}
|
|
32860
32990
|
const hasLegacyFeatureFlag = legacy && (legacy.rewrite !== undefined || legacy.compress !== undefined || legacy.background !== undefined);
|
|
@@ -32941,6 +33071,7 @@ var BashFeaturesSchema = exports_external.object({
|
|
|
32941
33071
|
rewrite: exports_external.boolean().optional(),
|
|
32942
33072
|
compress: exports_external.boolean().optional(),
|
|
32943
33073
|
background: exports_external.boolean().optional(),
|
|
33074
|
+
host_fallback: exports_external.boolean().optional(),
|
|
32944
33075
|
long_running_reminder_enabled: exports_external.boolean().optional(),
|
|
32945
33076
|
long_running_reminder_interval_ms: exports_external.number().int().positive().optional(),
|
|
32946
33077
|
foreground_wait_window_ms: exports_external.number().int().positive().optional()
|
|
@@ -32969,6 +33100,9 @@ var InspectConfigSchema = exports_external.object({
|
|
|
32969
33100
|
expected_mirrors: exports_external.array(exports_external.tuple([exports_external.string().trim().min(1), exports_external.string().trim().min(1)])).optional()
|
|
32970
33101
|
}).optional()
|
|
32971
33102
|
});
|
|
33103
|
+
var WorktreeConfigSchema = exports_external.object({
|
|
33104
|
+
ram_overlay: exports_external.boolean().optional()
|
|
33105
|
+
});
|
|
32972
33106
|
var BackupConfigSchema = exports_external.object({
|
|
32973
33107
|
enabled: exports_external.boolean().optional(),
|
|
32974
33108
|
max_depth: exports_external.number().int().positive().optional(),
|
|
@@ -32993,6 +33127,7 @@ var AftConfigSchema = exports_external.preprocess((value) => stripHarnessSpecifi
|
|
|
32993
33127
|
callgraph_chunk_size: exports_external.number().optional(),
|
|
32994
33128
|
inspect: InspectConfigSchema.optional(),
|
|
32995
33129
|
backup: BackupConfigSchema.optional(),
|
|
33130
|
+
worktree: WorktreeConfigSchema.optional(),
|
|
32996
33131
|
sandbox: SandboxConfigSchema.optional(),
|
|
32997
33132
|
bash: BashConfigSchema.optional(),
|
|
32998
33133
|
experimental: ExperimentalConfigSchema.optional(),
|
|
@@ -33249,6 +33384,15 @@ function mergeLspConfig(base, override) {
|
|
|
33249
33384
|
return;
|
|
33250
33385
|
return Object.fromEntries(Object.entries(lsp).filter(([, v]) => v !== undefined));
|
|
33251
33386
|
}
|
|
33387
|
+
function mergeWorktreeConfig(baseWorktree, overrideWorktree) {
|
|
33388
|
+
if (baseWorktree === undefined && overrideWorktree === undefined)
|
|
33389
|
+
return;
|
|
33390
|
+
if (overrideWorktree === undefined)
|
|
33391
|
+
return baseWorktree;
|
|
33392
|
+
if (baseWorktree === undefined)
|
|
33393
|
+
return overrideWorktree;
|
|
33394
|
+
return { ...baseWorktree, ...overrideWorktree };
|
|
33395
|
+
}
|
|
33252
33396
|
function mergeInspectConfig(baseInspect, overrideInspect) {
|
|
33253
33397
|
const inspect = {
|
|
33254
33398
|
...baseInspect,
|
|
@@ -33334,6 +33478,7 @@ var PROJECT_SAFE_TOP_LEVEL_FIELDS = new Set([
|
|
|
33334
33478
|
"callgraph_store",
|
|
33335
33479
|
"callgraph_chunk_size",
|
|
33336
33480
|
"inspect",
|
|
33481
|
+
"worktree",
|
|
33337
33482
|
"experimental",
|
|
33338
33483
|
"bash"
|
|
33339
33484
|
]);
|
|
@@ -33378,11 +33523,13 @@ function mergeConfigs(base, override) {
|
|
|
33378
33523
|
const experimental = mergeExperimentalConfig(base.experimental, override.experimental);
|
|
33379
33524
|
const bash = mergeBashConfig(base.bash, override.bash);
|
|
33380
33525
|
const inspect = mergeInspectConfig(base.inspect, override.inspect);
|
|
33526
|
+
const worktree = mergeWorktreeConfig(base.worktree, override.worktree);
|
|
33381
33527
|
const sandbox = mergeSandboxConfig(base.sandbox, override.sandbox);
|
|
33382
33528
|
const bridge = base.bridge;
|
|
33383
33529
|
const safeOverride = pickProjectSafeFields(override);
|
|
33384
33530
|
delete safeOverride.bash;
|
|
33385
33531
|
delete safeOverride.inspect;
|
|
33532
|
+
delete safeOverride.worktree;
|
|
33386
33533
|
return {
|
|
33387
33534
|
...base,
|
|
33388
33535
|
...safeOverride,
|
|
@@ -33391,6 +33538,7 @@ function mergeConfigs(base, override) {
|
|
|
33391
33538
|
...lsp ? { lsp } : {},
|
|
33392
33539
|
...bash !== undefined ? { bash } : {},
|
|
33393
33540
|
...inspect !== undefined ? { inspect } : {},
|
|
33541
|
+
...worktree !== undefined ? { worktree } : {},
|
|
33394
33542
|
...sandbox !== undefined ? { sandbox } : {},
|
|
33395
33543
|
experimental,
|
|
33396
33544
|
semantic,
|
|
@@ -33472,7 +33620,7 @@ function loadAftConfig(projectDirectory) {
|
|
|
33472
33620
|
}
|
|
33473
33621
|
|
|
33474
33622
|
// src/lsp-auto-install.ts
|
|
33475
|
-
import { spawn as
|
|
33623
|
+
import { spawn as spawn3 } from "node:child_process";
|
|
33476
33624
|
import { createHash as createHash4 } from "node:crypto";
|
|
33477
33625
|
import {
|
|
33478
33626
|
createReadStream,
|
|
@@ -34072,7 +34220,7 @@ function runInstall(spec, version2, cwd, signal) {
|
|
|
34072
34220
|
return;
|
|
34073
34221
|
}
|
|
34074
34222
|
ensureInstallAnchor(cwd);
|
|
34075
|
-
const child =
|
|
34223
|
+
const child = spawn3(npm.command, ["install", "--no-save", "--ignore-scripts", "--silent", target], {
|
|
34076
34224
|
stdio: ["ignore", "pipe", "pipe"],
|
|
34077
34225
|
cwd,
|
|
34078
34226
|
env: npmSpawnEnv(npm)
|
|
@@ -35270,26 +35418,6 @@ function sendFeatureAnnouncement(version2, features, footer, storageDir) {
|
|
|
35270
35418
|
markAnnouncementSeen(storageDir, "pi", version2);
|
|
35271
35419
|
}
|
|
35272
35420
|
|
|
35273
|
-
// src/status-bar-inject.ts
|
|
35274
|
-
var DEFAULT_SESSION = "__default__";
|
|
35275
|
-
var emitStateBySession = new Map;
|
|
35276
|
-
function statusBarBlockForSession(sessionID, counts, force = false) {
|
|
35277
|
-
if (!counts)
|
|
35278
|
-
return;
|
|
35279
|
-
const key = sessionID ?? DEFAULT_SESSION;
|
|
35280
|
-
let state = emitStateBySession.get(key);
|
|
35281
|
-
if (!state) {
|
|
35282
|
-
state = createStatusBarEmitState();
|
|
35283
|
-
emitStateBySession.set(key, state);
|
|
35284
|
-
}
|
|
35285
|
-
if (force) {
|
|
35286
|
-
state.last = counts;
|
|
35287
|
-
state.callsSinceEmit = 0;
|
|
35288
|
-
return formatStatusBar(counts);
|
|
35289
|
-
}
|
|
35290
|
-
return shouldEmitStatusBar(state, counts) ? formatStatusBar(counts) : undefined;
|
|
35291
|
-
}
|
|
35292
|
-
|
|
35293
35421
|
// src/bash-wait-detach.ts
|
|
35294
35422
|
var BASH_TRANSPORT_TIMEOUT_MS = 30000;
|
|
35295
35423
|
async function sendBashWaitDetach(bridge, sessionID) {
|
|
@@ -36730,7 +36858,7 @@ DO NOT use bash for code search or code exploration. If you are about to run gre
|
|
|
36730
36858
|
"Piped commands run verbatim and show the pipeline's output; run test/build tools without pipes when you need AFT's summary."
|
|
36731
36859
|
],
|
|
36732
36860
|
parameters: bashParamsForConfig(bashCfg.background),
|
|
36733
|
-
async execute(_toolCallId, params,
|
|
36861
|
+
async execute(_toolCallId, params, signal, onUpdate, extCtx) {
|
|
36734
36862
|
const bridge = bridgeFor(ctx, extCtx.cwd);
|
|
36735
36863
|
const bashCfg2 = resolveBashConfig(ctx.config);
|
|
36736
36864
|
const foregroundWaitMs = resolveForegroundWaitMs(bashCfg2.foreground_wait_window_ms);
|
|
@@ -36765,30 +36893,62 @@ DO NOT use bash for code search or code exploration. If you are about to run gre
|
|
|
36765
36893
|
}
|
|
36766
36894
|
const bridgeCommand = spawnContext.command;
|
|
36767
36895
|
let streamed = "";
|
|
36768
|
-
|
|
36769
|
-
|
|
36770
|
-
|
|
36771
|
-
|
|
36772
|
-
|
|
36773
|
-
|
|
36774
|
-
|
|
36775
|
-
|
|
36776
|
-
|
|
36777
|
-
|
|
36778
|
-
|
|
36779
|
-
|
|
36780
|
-
|
|
36781
|
-
|
|
36782
|
-
|
|
36783
|
-
|
|
36784
|
-
|
|
36785
|
-
|
|
36786
|
-
|
|
36787
|
-
|
|
36788
|
-
|
|
36789
|
-
|
|
36790
|
-
|
|
36791
|
-
|
|
36896
|
+
let usedHostFallback = false;
|
|
36897
|
+
let response;
|
|
36898
|
+
try {
|
|
36899
|
+
response = await callBashWithPermissionLoop(bridge, {
|
|
36900
|
+
command: bridgeCommand,
|
|
36901
|
+
timeout: effectiveTimeout,
|
|
36902
|
+
workdir: spawnContext.cwd ?? params.workdir,
|
|
36903
|
+
env: spawnContext.env,
|
|
36904
|
+
description: params.description,
|
|
36905
|
+
background: effectiveBackground,
|
|
36906
|
+
notify_on_completion: effectiveBackground,
|
|
36907
|
+
compressed,
|
|
36908
|
+
pty: requestedPty,
|
|
36909
|
+
pty_rows: ptyRows,
|
|
36910
|
+
pty_cols: ptyCols,
|
|
36911
|
+
foreground_orchestrate: true,
|
|
36912
|
+
block_to_completion: blockToCompletion,
|
|
36913
|
+
wait: requestedWait,
|
|
36914
|
+
sandbox: params.sandbox
|
|
36915
|
+
}, extCtx, {
|
|
36916
|
+
transportTimeoutMs: orchestratedTransportTimeoutMs(blockToCompletion, requestedWait, effectiveTimeout, foregroundWaitMs),
|
|
36917
|
+
onProgress: ({ text }) => {
|
|
36918
|
+
streamed += text;
|
|
36919
|
+
const displayText = truncateToVisualLines(streamed, 100);
|
|
36920
|
+
onUpdate?.(bashResult(displayText, { streaming: true }));
|
|
36921
|
+
}
|
|
36922
|
+
});
|
|
36923
|
+
} catch (error53) {
|
|
36924
|
+
if (!bashCfg2.host_fallback || !isBashTransportDeadError(error53))
|
|
36925
|
+
throw error53;
|
|
36926
|
+
if (rawRequestedBackground) {
|
|
36927
|
+
throw new Error(`${BASH_HOST_FALLBACK_REFUSAL}; background:true is unsupported.`);
|
|
36928
|
+
}
|
|
36929
|
+
if (rawRequestedPty) {
|
|
36930
|
+
throw new Error(`${BASH_HOST_FALLBACK_REFUSAL}; pty:true is unsupported.`);
|
|
36931
|
+
}
|
|
36932
|
+
if (!extCtx.hasUI || typeof extCtx.ui?.confirm !== "function") {
|
|
36933
|
+
throw new BridgeError("Permission denied: host fallback execution requires an interactive UI.", "permission_denied");
|
|
36934
|
+
}
|
|
36935
|
+
const projectRoot = extCtx.cwd;
|
|
36936
|
+
const pattern = bashHostFallbackAskPattern(bridgeCommand, projectRoot);
|
|
36937
|
+
const approved = await extCtx.ui.confirm("AFT unavailable — run command on host?", pattern, {
|
|
36938
|
+
signal: signal ?? extCtx.signal
|
|
36939
|
+
});
|
|
36940
|
+
if (!approved) {
|
|
36941
|
+
throw new BridgeError("Permission denied: AFT host fallback execution was denied.", "permission_denied");
|
|
36942
|
+
}
|
|
36943
|
+
response = await runBashHostFallback({
|
|
36944
|
+
command: bridgeCommand,
|
|
36945
|
+
projectRoot,
|
|
36946
|
+
timeoutMs: timeout,
|
|
36947
|
+
signal: signal ?? extCtx.signal,
|
|
36948
|
+
env: spawnContext.env
|
|
36949
|
+
});
|
|
36950
|
+
usedHostFallback = true;
|
|
36951
|
+
}
|
|
36792
36952
|
if (response.success === false) {
|
|
36793
36953
|
throw new Error(response.message ?? "bash failed");
|
|
36794
36954
|
}
|
|
@@ -36805,7 +36965,7 @@ DO NOT use bash for code search or code exploration. If you are about to run gre
|
|
|
36805
36965
|
task_id: taskId
|
|
36806
36966
|
};
|
|
36807
36967
|
const output = response.output ?? "";
|
|
36808
|
-
return bashResult(withBashHints(output, bridgeCommand, aftSearchRegistered, extCtx.cwd), details);
|
|
36968
|
+
return bashResult(usedHostFallback ? output : withBashHints(output, bridgeCommand, aftSearchRegistered, extCtx.cwd), details);
|
|
36809
36969
|
},
|
|
36810
36970
|
renderCall(args, theme, context) {
|
|
36811
36971
|
return renderBashCall(args?.command, args?.description, theme, context);
|
|
@@ -37647,10 +37807,10 @@ function registerImportTools(pi, ctx) {
|
|
|
37647
37807
|
import { Type as Type8 } from "typebox";
|
|
37648
37808
|
var InspectParams = Type8.Object({
|
|
37649
37809
|
sections: Type8.Optional(Type8.Union([Type8.String(), Type8.Array(Type8.String())], {
|
|
37650
|
-
description: "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."
|
|
37810
|
+
description: "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."
|
|
37651
37811
|
})),
|
|
37652
37812
|
scope: Type8.Optional(Type8.Union([Type8.String(), Type8.Array(Type8.String())], {
|
|
37653
|
-
description: "Restrict
|
|
37813
|
+
description: "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."
|
|
37654
37814
|
})),
|
|
37655
37815
|
topK: Type8.Optional(Type8.Integer({
|
|
37656
37816
|
minimum: 1,
|
|
@@ -37659,11 +37819,6 @@ var InspectParams = Type8.Object({
|
|
|
37659
37819
|
description: "Max drill-down items per category. Default 20, max 100."
|
|
37660
37820
|
}))
|
|
37661
37821
|
});
|
|
37662
|
-
var TIER2_INSPECT_CATEGORIES = new Set(["dead_code", "unused_exports", "duplicates", "cycles"]);
|
|
37663
|
-
var INSPECT_TIER2_RUN_TIMEOUT_MS = 5 * 60000;
|
|
37664
|
-
var INSPECT_TIER2_MIN_TRIGGER_INTERVAL_MS = 4 * 60000;
|
|
37665
|
-
var runningTier2Categories = new WeakMap;
|
|
37666
|
-
var lastTier2TriggerAtByBridge = new WeakMap;
|
|
37667
37822
|
function normalizeStringOrArray(value) {
|
|
37668
37823
|
return isEmptyParam(value) ? undefined : value;
|
|
37669
37824
|
}
|
|
@@ -37694,15 +37849,119 @@ function validateOptionalTopK(value) {
|
|
|
37694
37849
|
}
|
|
37695
37850
|
return value;
|
|
37696
37851
|
}
|
|
37697
|
-
function
|
|
37698
|
-
|
|
37699
|
-
|
|
37700
|
-
|
|
37701
|
-
|
|
37702
|
-
|
|
37703
|
-
|
|
37704
|
-
|
|
37705
|
-
|
|
37852
|
+
function terminalKind(response) {
|
|
37853
|
+
for (const value of [
|
|
37854
|
+
response.terminal,
|
|
37855
|
+
response.outcome,
|
|
37856
|
+
response.inspect_outcome,
|
|
37857
|
+
response.inspect_terminal,
|
|
37858
|
+
response.status
|
|
37859
|
+
]) {
|
|
37860
|
+
if (typeof value !== "string")
|
|
37861
|
+
continue;
|
|
37862
|
+
const normalized = value.toUpperCase().replaceAll("_", "-");
|
|
37863
|
+
if (normalized === "FRESH" || normalized === "INTERRUPTED" || normalized === "PHASE-FAILED") {
|
|
37864
|
+
return normalized;
|
|
37865
|
+
}
|
|
37866
|
+
}
|
|
37867
|
+
return;
|
|
37868
|
+
}
|
|
37869
|
+
function firstRecord(...values) {
|
|
37870
|
+
for (const value of values) {
|
|
37871
|
+
const record2 = asRecord3(value);
|
|
37872
|
+
if (record2)
|
|
37873
|
+
return record2;
|
|
37874
|
+
}
|
|
37875
|
+
return;
|
|
37876
|
+
}
|
|
37877
|
+
function firstString(...values) {
|
|
37878
|
+
for (const value of values) {
|
|
37879
|
+
const text = asString2(value);
|
|
37880
|
+
if (text !== undefined)
|
|
37881
|
+
return text;
|
|
37882
|
+
}
|
|
37883
|
+
return;
|
|
37884
|
+
}
|
|
37885
|
+
function parseInspectPhaseEntries(value) {
|
|
37886
|
+
if (!Array.isArray(value))
|
|
37887
|
+
return [];
|
|
37888
|
+
return value.flatMap((candidate) => {
|
|
37889
|
+
const entry = asRecord3(candidate);
|
|
37890
|
+
const id = asString2(entry?.id);
|
|
37891
|
+
if (!id)
|
|
37892
|
+
return [];
|
|
37893
|
+
const alsoSatisfied = Array.isArray(entry?.also_satisfied) ? entry.also_satisfied.filter((category) => typeof category === "string") : [];
|
|
37894
|
+
return [
|
|
37895
|
+
{
|
|
37896
|
+
id,
|
|
37897
|
+
producer: asString2(entry?.producer),
|
|
37898
|
+
category: asString2(entry?.category),
|
|
37899
|
+
alsoSatisfied
|
|
37900
|
+
}
|
|
37901
|
+
];
|
|
37902
|
+
});
|
|
37903
|
+
}
|
|
37904
|
+
function parseInspectTerminal(payload) {
|
|
37905
|
+
const response = asRecord3(payload);
|
|
37906
|
+
if (!response)
|
|
37907
|
+
return;
|
|
37908
|
+
const kind = terminalKind(response);
|
|
37909
|
+
if (!kind)
|
|
37910
|
+
return;
|
|
37911
|
+
const waitStamp = firstRecord(response.wait_stamp, response.waitStamp, response.blocking_wait_stamp);
|
|
37912
|
+
const phaseSource = kind === "FRESH" ? waitStamp ?? response : response;
|
|
37913
|
+
const phases = parseInspectPhaseEntries(phaseSource.phases ?? response.completed_phases ?? response.completedPhases);
|
|
37914
|
+
if (kind !== "PHASE-FAILED") {
|
|
37915
|
+
return {
|
|
37916
|
+
kind,
|
|
37917
|
+
phases,
|
|
37918
|
+
waitStampText: kind === "FRESH" ? firstString(waitStamp?.text, waitStamp?.human_text) : undefined
|
|
37919
|
+
};
|
|
37920
|
+
}
|
|
37921
|
+
const failedPhaseRecord = asRecord3(response.failed_phase);
|
|
37922
|
+
const failedPhaseId = firstString(failedPhaseRecord?.id, response.failed_phase);
|
|
37923
|
+
const failedPhase = failedPhaseId ? parseInspectPhaseEntries([
|
|
37924
|
+
{
|
|
37925
|
+
id: failedPhaseId,
|
|
37926
|
+
producer: firstString(failedPhaseRecord?.producer, response.failed_phase_producer, response.producer),
|
|
37927
|
+
category: firstString(failedPhaseRecord?.category, response.failed_phase_category, response.category)
|
|
37928
|
+
}
|
|
37929
|
+
])[0] : undefined;
|
|
37930
|
+
return {
|
|
37931
|
+
kind,
|
|
37932
|
+
phases,
|
|
37933
|
+
failedPhase,
|
|
37934
|
+
failureReason: asString2(response.failure_reason),
|
|
37935
|
+
failureDetail: asString2(response.failure_detail)
|
|
37936
|
+
};
|
|
37937
|
+
}
|
|
37938
|
+
function formatPhase(entry) {
|
|
37939
|
+
const details = [
|
|
37940
|
+
entry.producer ? `producer: ${entry.producer}` : undefined,
|
|
37941
|
+
entry.category ? `category: ${entry.category}` : undefined,
|
|
37942
|
+
entry.alsoSatisfied.length > 0 ? `also satisfied: ${entry.alsoSatisfied.join(", ")}` : undefined
|
|
37943
|
+
].filter((detail) => Boolean(detail));
|
|
37944
|
+
return details.length > 0 ? `${entry.id} (${details.join("; ")})` : entry.id;
|
|
37945
|
+
}
|
|
37946
|
+
function renderInspectTerminal(terminal, serverText) {
|
|
37947
|
+
const lines = [terminal.kind];
|
|
37948
|
+
if (terminal.kind === "FRESH") {
|
|
37949
|
+
lines.push(`wait-stamp: ${terminal.waitStampText ?? "not supplied"}`);
|
|
37950
|
+
}
|
|
37951
|
+
if (terminal.kind === "PHASE-FAILED") {
|
|
37952
|
+
if (terminal.failedPhase)
|
|
37953
|
+
lines.push(`failed phase: ${formatPhase(terminal.failedPhase)}`);
|
|
37954
|
+
lines.push(`failure reason: ${terminal.failureReason ?? "not supplied"}`);
|
|
37955
|
+
if (terminal.failureDetail)
|
|
37956
|
+
lines.push(`failure detail: ${terminal.failureDetail}`);
|
|
37957
|
+
}
|
|
37958
|
+
lines.push(terminal.phases.length > 0 ? `completed phases:
|
|
37959
|
+
${terminal.phases.map((phase) => `- ${formatPhase(phase)}`).join(`
|
|
37960
|
+
`)}` : "completed phases: none");
|
|
37961
|
+
if (serverText?.trim())
|
|
37962
|
+
lines.push(serverText);
|
|
37963
|
+
return lines.join(`
|
|
37964
|
+
`);
|
|
37706
37965
|
}
|
|
37707
37966
|
function diagnosticsSummaryPart(summary) {
|
|
37708
37967
|
const section = asRecord3(summary?.diagnostics);
|
|
@@ -37712,31 +37971,9 @@ function diagnosticsSummaryPart(summary) {
|
|
|
37712
37971
|
const warnings = asNumber2(section.warnings);
|
|
37713
37972
|
const info = asNumber2(section.info);
|
|
37714
37973
|
const hints = asNumber2(section.hints);
|
|
37715
|
-
|
|
37716
|
-
|
|
37717
|
-
|
|
37718
|
-
const provisionalCounts = asRecord3(section.provisional_counts);
|
|
37719
|
-
const provisionalValues = provisionalCounts ? [
|
|
37720
|
-
asNumber2(provisionalCounts.errors),
|
|
37721
|
-
asNumber2(provisionalCounts.warnings),
|
|
37722
|
-
asNumber2(provisionalCounts.info),
|
|
37723
|
-
asNumber2(provisionalCounts.hints)
|
|
37724
|
-
] : [];
|
|
37725
|
-
const provisionalText = provisionalCounts ? ` (${provisionalValues[0] ?? 0} errors/${provisionalValues[1] ?? 0} warnings/${provisionalValues[2] ?? 0} info/${provisionalValues[3] ?? 0} hints)` : "";
|
|
37726
|
-
const provisionalFraming = `provisional — analyzer not ready; counts excluded from E/W${provisionalText}`;
|
|
37727
|
-
if (status === "pending") {
|
|
37728
|
-
return `diagnostics ${provisionalFraming} — still pending (servers: ${diagnosticsServerSummary(section)}); wait for the LSP update and use the next normal aft_inspect, not repeated polling`;
|
|
37729
|
-
}
|
|
37730
|
-
if (status === "incomplete") {
|
|
37731
|
-
return `diagnostics ${provisionalFraming} (incomplete — servers: ${diagnosticsServerSummary(section)})`;
|
|
37732
|
-
}
|
|
37733
|
-
if (provisionalCounts) {
|
|
37734
|
-
return `diagnostics ${provisionalFraming}`;
|
|
37735
|
-
}
|
|
37736
|
-
if (hasCounts) {
|
|
37737
|
-
return `diagnostics ${counts}`;
|
|
37738
|
-
}
|
|
37739
|
-
return;
|
|
37974
|
+
if (![errors3, warnings, info, hints].some((value) => value !== undefined))
|
|
37975
|
+
return;
|
|
37976
|
+
return `diagnostics ${errors3 ?? 0} errors/${warnings ?? 0} warnings/${info ?? 0} info/${hints ?? 0} hints`;
|
|
37740
37977
|
}
|
|
37741
37978
|
function diagnosticLocation(diagnostic) {
|
|
37742
37979
|
const file2 = asString2(diagnostic.file) ?? "(unknown file)";
|
|
@@ -37748,36 +37985,28 @@ function diagnosticLocation(diagnostic) {
|
|
|
37748
37985
|
return `${file2}:${line}`;
|
|
37749
37986
|
return `${file2}:${line}:${column}`;
|
|
37750
37987
|
}
|
|
37751
|
-
function diagnosticsDetailSection(details
|
|
37988
|
+
function diagnosticsDetailSection(details) {
|
|
37752
37989
|
const diagnostics = asRecords2(details?.diagnostics);
|
|
37753
37990
|
if (diagnostics.length === 0)
|
|
37754
37991
|
return;
|
|
37755
|
-
|
|
37756
|
-
|
|
37757
|
-
|
|
37758
|
-
|
|
37759
|
-
|
|
37760
|
-
|
|
37761
|
-
|
|
37762
|
-
|
|
37763
|
-
|
|
37764
|
-
const suffix = source ? ` [${source}]` : "";
|
|
37765
|
-
lines.push(`- ${diagnosticLocation(diagnostic)} ${severity} ${message}${suffix}`);
|
|
37766
|
-
}
|
|
37767
|
-
return lines.join(`
|
|
37992
|
+
return [
|
|
37993
|
+
"diagnostics",
|
|
37994
|
+
...diagnostics.map((diagnostic) => {
|
|
37995
|
+
const severity = asString2(diagnostic.severity) ?? "information";
|
|
37996
|
+
const message = asString2(diagnostic.message) ?? "(no message)";
|
|
37997
|
+
const source = asString2(diagnostic.source);
|
|
37998
|
+
return `- ${diagnosticLocation(diagnostic)} ${severity} ${message}${source ? ` [${source}]` : ""}`;
|
|
37999
|
+
})
|
|
38000
|
+
].join(`
|
|
37768
38001
|
`);
|
|
37769
38002
|
}
|
|
37770
38003
|
function countFrom(summary, key) {
|
|
37771
|
-
|
|
37772
|
-
return asNumber2(section?.count);
|
|
38004
|
+
return asNumber2(asRecord3(summary?.[key])?.count);
|
|
37773
38005
|
}
|
|
37774
38006
|
function tier2SummaryPart(summary, key, label) {
|
|
37775
38007
|
const section = asRecord3(summary?.[key]);
|
|
37776
38008
|
const count = asNumber2(section?.count);
|
|
37777
|
-
|
|
37778
|
-
return `${label} ${count}`;
|
|
37779
|
-
const status = asString2(section?.status);
|
|
37780
|
-
return `${label} ${status ?? "unavailable"}`;
|
|
38009
|
+
return count !== undefined ? `${label} ${count}` : `${label} unavailable`;
|
|
37781
38010
|
}
|
|
37782
38011
|
function shortDupOccurrence(entry) {
|
|
37783
38012
|
const [path2] = entry.split(":");
|
|
@@ -37785,95 +38014,41 @@ function shortDupOccurrence(entry) {
|
|
|
37785
38014
|
}
|
|
37786
38015
|
function tier2TopPreview(summary, theme) {
|
|
37787
38016
|
const lines = [];
|
|
37788
|
-
const
|
|
37789
|
-
const dupTop = Array.isArray(dup?.top) ? dup.top : [];
|
|
38017
|
+
const dupTop = Array.isArray(asRecord3(summary?.duplicates)?.top) ? asRecord3(summary?.duplicates)?.top : [];
|
|
37790
38018
|
for (const group of dupTop) {
|
|
37791
38019
|
const record2 = asRecord3(group);
|
|
37792
38020
|
const files = Array.isArray(record2?.files) ? record2.files : [];
|
|
37793
38021
|
const cost = asNumber2(record2?.cost);
|
|
37794
38022
|
if (files.length < 2)
|
|
37795
38023
|
continue;
|
|
37796
|
-
|
|
37797
|
-
const b = shortDupOccurrence(String(files[1]));
|
|
37798
|
-
lines.push(` dup ${a} ↔ ${b}${cost !== undefined ? ` (${cost})` : ""}`);
|
|
38024
|
+
lines.push(` dup ${shortDupOccurrence(String(files[0]))} ↔ ${shortDupOccurrence(String(files[1]))}${cost !== undefined ? ` (${cost})` : ""}`);
|
|
37799
38025
|
}
|
|
37800
38026
|
for (const [key, label] of [
|
|
37801
38027
|
["dead_code", "dead"],
|
|
37802
38028
|
["unused_exports", "unused"]
|
|
37803
38029
|
]) {
|
|
37804
|
-
const
|
|
37805
|
-
const top = Array.isArray(section?.top) ? section.top : [];
|
|
38030
|
+
const top = Array.isArray(asRecord3(summary?.[key])?.top) ? asRecord3(summary?.[key])?.top : [];
|
|
37806
38031
|
for (const item of top) {
|
|
37807
38032
|
const record2 = asRecord3(item);
|
|
37808
38033
|
const file2 = asString2(record2?.file);
|
|
37809
38034
|
const symbol2 = asString2(record2?.symbol);
|
|
37810
|
-
if (
|
|
37811
|
-
|
|
37812
|
-
lines.push(` ${label} ${symbol2} (${file2.split("/").pop()})`);
|
|
38035
|
+
if (file2 && symbol2)
|
|
38036
|
+
lines.push(` ${label} ${symbol2} (${file2.split("/").pop()})`);
|
|
37813
38037
|
}
|
|
37814
38038
|
}
|
|
37815
|
-
|
|
37816
|
-
return;
|
|
37817
|
-
return `${theme.fg("muted", "top findings:")}
|
|
38039
|
+
return lines.length > 0 ? `${theme.fg("muted", "top findings:")}
|
|
37818
38040
|
${lines.join(`
|
|
37819
|
-
`)}
|
|
37820
|
-
}
|
|
37821
|
-
function tier2RefreshCategories(response) {
|
|
37822
|
-
const scannerState = asRecord3(response.scanner_state);
|
|
37823
|
-
const categories = new Set;
|
|
37824
|
-
for (const key of ["pending_categories", "stale_categories"]) {
|
|
37825
|
-
const values = scannerState?.[key];
|
|
37826
|
-
if (!Array.isArray(values))
|
|
37827
|
-
continue;
|
|
37828
|
-
for (const category of values) {
|
|
37829
|
-
if (typeof category === "string" && TIER2_INSPECT_CATEGORIES.has(category)) {
|
|
37830
|
-
categories.add(category);
|
|
37831
|
-
}
|
|
37832
|
-
}
|
|
37833
|
-
}
|
|
37834
|
-
return [...categories];
|
|
37835
|
-
}
|
|
37836
|
-
function runPendingTier2Categories(bridge, categories, extCtx) {
|
|
37837
|
-
const now = Date.now();
|
|
37838
|
-
const running = runningTier2Categories.get(bridge) ?? new Set;
|
|
37839
|
-
const lastTriggerAt = lastTier2TriggerAtByBridge.get(bridge) ?? new Map;
|
|
37840
|
-
const toRun = categories.filter((category) => {
|
|
37841
|
-
if (running.has(category))
|
|
37842
|
-
return false;
|
|
37843
|
-
const previousTriggerAt = lastTriggerAt.get(category);
|
|
37844
|
-
return previousTriggerAt === undefined || previousTriggerAt + INSPECT_TIER2_MIN_TRIGGER_INTERVAL_MS <= now;
|
|
37845
|
-
});
|
|
37846
|
-
if (toRun.length === 0)
|
|
37847
|
-
return;
|
|
37848
|
-
for (const category of toRun) {
|
|
37849
|
-
running.add(category);
|
|
37850
|
-
lastTriggerAt.set(category, now);
|
|
37851
|
-
}
|
|
37852
|
-
runningTier2Categories.set(bridge, running);
|
|
37853
|
-
lastTier2TriggerAtByBridge.set(bridge, lastTriggerAt);
|
|
37854
|
-
callBridge(bridge, "inspect_tier2_run", { categories: toRun }, extCtx, {
|
|
37855
|
-
transportTimeoutMs: INSPECT_TIER2_RUN_TIMEOUT_MS
|
|
37856
|
-
}).catch(() => {}).finally(() => {
|
|
37857
|
-
const active = runningTier2Categories.get(bridge);
|
|
37858
|
-
if (!active)
|
|
37859
|
-
return;
|
|
37860
|
-
for (const category of toRun) {
|
|
37861
|
-
active.delete(category);
|
|
37862
|
-
}
|
|
37863
|
-
if (active.size === 0) {
|
|
37864
|
-
runningTier2Categories.delete(bridge);
|
|
37865
|
-
}
|
|
37866
|
-
});
|
|
38041
|
+
`)}` : undefined;
|
|
37867
38042
|
}
|
|
37868
38043
|
function buildInspectSections(payload, theme) {
|
|
38044
|
+
const terminal = parseInspectTerminal(payload);
|
|
38045
|
+
if (terminal)
|
|
38046
|
+
return [renderInspectTerminal(terminal, asString2(asRecord3(payload)?.text))];
|
|
37869
38047
|
const response = asRecord3(payload);
|
|
37870
38048
|
if (!response)
|
|
37871
38049
|
return [theme.fg("muted", "No inspect snapshot available.")];
|
|
37872
38050
|
const summary = asRecord3(response.summary);
|
|
37873
38051
|
const metrics = asRecord3(summary?.metrics);
|
|
37874
|
-
const scannerState = asRecord3(response.scanner_state);
|
|
37875
|
-
const stale = Array.isArray(scannerState?.stale_categories) ? scannerState.stale_categories.length : 0;
|
|
37876
|
-
const pending = Array.isArray(scannerState?.pending_categories) ? scannerState.pending_categories.length : 0;
|
|
37877
38052
|
const parts = [
|
|
37878
38053
|
`todos ${countFrom(summary, "todos") ?? 0}`,
|
|
37879
38054
|
diagnosticsSummaryPart(summary),
|
|
@@ -37884,9 +38059,6 @@ function buildInspectSections(payload, theme) {
|
|
|
37884
38059
|
tier2SummaryPart(summary, "cycles", "cycles")
|
|
37885
38060
|
].filter((part) => Boolean(part));
|
|
37886
38061
|
const sections = [theme.fg("accent", parts.join(" · "))];
|
|
37887
|
-
if (stale > 0 || pending > 0) {
|
|
37888
|
-
sections.push(theme.fg("warning", `scanner state: ${stale} stale · ${pending} pending. Treat stale_categories/pending_categories as stale or incomplete cache state. AFT schedules a Tier-2 refresh after its next idle or inspect-triggered background run; use one later normal aft_inspect after that refresh, not a polling loop`));
|
|
37889
|
-
}
|
|
37890
38062
|
const topPreview = tier2TopPreview(summary, theme);
|
|
37891
38063
|
if (topPreview)
|
|
37892
38064
|
sections.push(topPreview);
|
|
@@ -37894,7 +38066,7 @@ function buildInspectSections(payload, theme) {
|
|
|
37894
38066
|
if (details) {
|
|
37895
38067
|
const names = Object.keys(details);
|
|
37896
38068
|
sections.push(names.length > 0 ? `details: ${names.join(", ")}` : theme.fg("muted", "No drill-down details returned."));
|
|
37897
|
-
const diagnosticsDetails = diagnosticsDetailSection(details
|
|
38069
|
+
const diagnosticsDetails = diagnosticsDetailSection(details);
|
|
37898
38070
|
if (diagnosticsDetails)
|
|
37899
38071
|
sections.push(diagnosticsDetails);
|
|
37900
38072
|
}
|
|
@@ -37910,15 +38082,19 @@ function renderInspectCall(args, theme, context) {
|
|
|
37910
38082
|
return renderToolCall("inspect", summary ? theme.fg("toolOutput", summary) : undefined, theme, context);
|
|
37911
38083
|
}
|
|
37912
38084
|
function renderInspectResult(result, theme, context) {
|
|
38085
|
+
const payload = extractStructuredPayload(result);
|
|
38086
|
+
const terminal = parseInspectTerminal(payload);
|
|
38087
|
+
if (terminal)
|
|
38088
|
+
return renderSections([renderInspectTerminal(terminal, asString2(asRecord3(payload)?.text))], context);
|
|
37913
38089
|
if (context.isError)
|
|
37914
38090
|
return renderErrorResult(result, "inspect failed", theme, context);
|
|
37915
|
-
return renderSections(buildInspectSections(
|
|
38091
|
+
return renderSections(buildInspectSections(payload, theme), context);
|
|
37916
38092
|
}
|
|
37917
38093
|
function registerInspectTool(pi, ctx) {
|
|
37918
38094
|
pi.registerTool({
|
|
37919
38095
|
name: "aft_inspect",
|
|
37920
38096
|
label: "inspect",
|
|
37921
|
-
description: "
|
|
38097
|
+
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.
|
|
37922
38098
|
|
|
37923
38099
|
` + "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.",
|
|
37924
38100
|
parameters: InspectParams,
|
|
@@ -37934,13 +38110,12 @@ function registerInspectTool(pi, ctx) {
|
|
|
37934
38110
|
rawArgs.scope = scope;
|
|
37935
38111
|
if (topK !== undefined)
|
|
37936
38112
|
rawArgs.topK = topK;
|
|
37937
|
-
const response = await callToolCall(bridge, "inspect", rawArgs, extCtx
|
|
37938
|
-
|
|
37939
|
-
|
|
37940
|
-
|
|
38113
|
+
const response = await callToolCall(bridge, "inspect", rawArgs, extCtx);
|
|
38114
|
+
const terminal = parseInspectTerminal(response);
|
|
38115
|
+
if (terminal)
|
|
38116
|
+
return textResult(renderInspectTerminal(terminal, response.text), response);
|
|
38117
|
+
if (response.success === false)
|
|
37941
38118
|
throw new Error(response.text || response.message || "inspect failed");
|
|
37942
|
-
}
|
|
37943
|
-
runPendingTier2Categories(bridge, tier2RefreshCategories(response), extCtx);
|
|
37944
38119
|
return textResult(response.text, response);
|
|
37945
38120
|
},
|
|
37946
38121
|
renderCall(args, theme, context) {
|
|
@@ -38729,7 +38904,7 @@ var SearchParams2 = Type13.Object({
|
|
|
38729
38904
|
description: "Include test files (*.test.*, *_test.rs, __tests__/, …) plus test-support, fixture, mock, snapshot, and corpus files. Defaults to false."
|
|
38730
38905
|
})),
|
|
38731
38906
|
path: Type13.Optional(Type13.String({
|
|
38732
|
-
description: "
|
|
38907
|
+
description: "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."
|
|
38733
38908
|
}))
|
|
38734
38909
|
});
|
|
38735
38910
|
function buildSemanticSections(args, payload, theme) {
|
|
@@ -39100,7 +39275,7 @@ var PLUGIN_VERSION = (() => {
|
|
|
39100
39275
|
return "0.0.0";
|
|
39101
39276
|
}
|
|
39102
39277
|
})();
|
|
39103
|
-
var ANNOUNCEMENT_VERSION = "0.
|
|
39278
|
+
var ANNOUNCEMENT_VERSION = "0.51.1";
|
|
39104
39279
|
var ANNOUNCEMENT_FEATURES = [
|
|
39105
39280
|
"Callgraph stays consistent under load: edits arriving mid-rebuild can no longer be silently lost from navigation results.",
|
|
39106
39281
|
"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).",
|
|
@@ -39463,12 +39638,7 @@ ${lines}
|
|
|
39463
39638
|
pi.on("tool_result", async (event, extCtx) => {
|
|
39464
39639
|
const sessionID = resolveSessionId(extCtx);
|
|
39465
39640
|
const bgContent = await appendToolResultBgCompletions({ ctx, directory: extCtx.cwd, sessionID }, event.content);
|
|
39466
|
-
|
|
39467
|
-
const isInspect = typeof event.details === "object" && event.details !== null && "scanner_state" in event.details;
|
|
39468
|
-
const activeBridge = pool.getActiveBridgeForRoot(extCtx.cwd);
|
|
39469
|
-
const bar = statusBarBlockForSession(sessionID, activeBridge?.getStatusBar(), isInspect);
|
|
39470
|
-
if (bar)
|
|
39471
|
-
content = [...content, { type: "text", text: bar }];
|
|
39641
|
+
const content = bgContent ?? event.content;
|
|
39472
39642
|
if (content === event.content)
|
|
39473
39643
|
return;
|
|
39474
39644
|
return { content, details: event.details, isError: event.isError };
|