@cortexkit/aft-pi 0.50.2 → 0.51.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config.d.ts +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 +445 -299
- 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;
|
|
@@ -8779,7 +8855,7 @@ class BinaryBridge {
|
|
|
8779
8855
|
throw new Error(`${this.errorPrefix} Bridge is retiring after the on-disk binary changed; retry to respawn on the updated binary`);
|
|
8780
8856
|
}
|
|
8781
8857
|
if (this._shuttingDown) {
|
|
8782
|
-
throw new
|
|
8858
|
+
throw new BridgeTransportUnavailableError(`${this.errorPrefix} Bridge is shutting down, cannot send "${command}"`);
|
|
8783
8859
|
}
|
|
8784
8860
|
if (Object.hasOwn(params, "id")) {
|
|
8785
8861
|
throw new Error("params cannot contain reserved key 'id'");
|
|
@@ -8813,7 +8889,7 @@ class BinaryBridge {
|
|
|
8813
8889
|
await this.deliverConfigureWarnings(configResult, params, options);
|
|
8814
8890
|
await this.checkVersion(implicitTransportOptions);
|
|
8815
8891
|
if (!this.isAlive()) {
|
|
8816
|
-
throw new
|
|
8892
|
+
throw new BridgeTransportUnavailableError(`${this.errorPrefix} Bridge died during version check. Check logs: ${this.getLogFilePathVia()}`);
|
|
8817
8893
|
}
|
|
8818
8894
|
this.configured = true;
|
|
8819
8895
|
} finally {
|
|
@@ -8882,7 +8958,7 @@ class BinaryBridge {
|
|
|
8882
8958
|
if (!this.process?.stdin?.writable) {
|
|
8883
8959
|
this.pending.delete(id);
|
|
8884
8960
|
clearTimeout(timer);
|
|
8885
|
-
reject(new
|
|
8961
|
+
reject(new BridgeTransportUnavailableError(`${this.errorPrefix} stdin not writable for command "${command}"`));
|
|
8886
8962
|
return;
|
|
8887
8963
|
}
|
|
8888
8964
|
requestSentAt = Date.now();
|
|
@@ -8892,7 +8968,7 @@ class BinaryBridge {
|
|
|
8892
8968
|
if (entry) {
|
|
8893
8969
|
this.pending.delete(id);
|
|
8894
8970
|
clearTimeout(entry.timer);
|
|
8895
|
-
entry.reject(new
|
|
8971
|
+
entry.reject(new BridgeTransportUnavailableError(`${this.errorPrefix} Failed to write to stdin: ${err.message}`, { cause: err }));
|
|
8896
8972
|
}
|
|
8897
8973
|
}
|
|
8898
8974
|
});
|
|
@@ -9059,7 +9135,6 @@ class BinaryBridge {
|
|
|
9059
9135
|
}
|
|
9060
9136
|
spawnProcess(triggeringSessionId) {
|
|
9061
9137
|
this._retiringDueToBinaryChange = false;
|
|
9062
|
-
this.lastStatusBar = undefined;
|
|
9063
9138
|
if (triggeringSessionId) {
|
|
9064
9139
|
this.sessionLogVia(triggeringSessionId, `Spawning binary: ${this.binaryPath} (cwd: ${this.cwd})`);
|
|
9065
9140
|
} else {
|
|
@@ -9100,7 +9175,7 @@ class BinaryBridge {
|
|
|
9100
9175
|
}
|
|
9101
9176
|
}
|
|
9102
9177
|
}
|
|
9103
|
-
const child =
|
|
9178
|
+
const child = spawn2(this.binaryPath, [], {
|
|
9104
9179
|
cwd: this.cwd,
|
|
9105
9180
|
stdio: ["pipe", "pipe", "pipe"],
|
|
9106
9181
|
env
|
|
@@ -9130,7 +9205,7 @@ class BinaryBridge {
|
|
|
9130
9205
|
if (this.process !== currentChild)
|
|
9131
9206
|
return;
|
|
9132
9207
|
this.errorVia(`Process error: ${err.message}${this.formatStderrTail()}`);
|
|
9133
|
-
this.handleCrash();
|
|
9208
|
+
this.handleCrash(err);
|
|
9134
9209
|
});
|
|
9135
9210
|
child.on("exit", (code, signal) => {
|
|
9136
9211
|
if (this.process !== currentChild)
|
|
@@ -9143,7 +9218,7 @@ class BinaryBridge {
|
|
|
9143
9218
|
this.process = null;
|
|
9144
9219
|
this.configured = false;
|
|
9145
9220
|
this.clearRestartResetTimer();
|
|
9146
|
-
this.rejectAllPending(new
|
|
9221
|
+
this.rejectAllPending(new BridgeTransportUnavailableError(`${this.errorPrefix} Binary killed by ${signal}`));
|
|
9147
9222
|
return;
|
|
9148
9223
|
}
|
|
9149
9224
|
this.handleCrash();
|
|
@@ -9298,7 +9373,6 @@ class BinaryBridge {
|
|
|
9298
9373
|
this.consecutiveRequestTimeouts = 0;
|
|
9299
9374
|
this.scheduleRestartCountReset();
|
|
9300
9375
|
this.accountForBashTaskResponse(entry.command, response);
|
|
9301
|
-
this.captureStatusBar(response);
|
|
9302
9376
|
entry.resolve(response);
|
|
9303
9377
|
} else if (typeof response.type === "string") {
|
|
9304
9378
|
this.logVia(`Ignoring unknown stdout push frame type: ${response.type}`);
|
|
@@ -9319,14 +9393,6 @@ class BinaryBridge {
|
|
|
9319
9393
|
this.outstandingBackgroundTaskIds.add(taskId);
|
|
9320
9394
|
}
|
|
9321
9395
|
}
|
|
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
9396
|
handleTimeout(triggeringSessionId) {
|
|
9331
9397
|
this.consecutiveRequestTimeouts = 0;
|
|
9332
9398
|
this.spawnedBinaryFingerprint = null;
|
|
@@ -9367,7 +9433,7 @@ class BinaryBridge {
|
|
|
9367
9433
|
if (tail) {
|
|
9368
9434
|
this.errorVia(`Binary crashed (restarts: ${this._restartCount})${cause ? `: ${cause.message}` : ""}.${tail}`);
|
|
9369
9435
|
}
|
|
9370
|
-
this.rejectAllPending(new
|
|
9436
|
+
this.rejectAllPending(new BridgeTransportUnavailableError(`${this.errorPrefix} Binary crashed (restarts: ${this._restartCount})${cause ? `: ${cause.message}` : ""} (see ${this.getLogFilePathVia()})`, { cause }));
|
|
9371
9437
|
if (this._retiringDueToBinaryChange) {
|
|
9372
9438
|
this.logVia("Binary exited while retiring after an on-disk update; skipping auto-restart");
|
|
9373
9439
|
return;
|
|
@@ -13030,6 +13096,12 @@ function normalizeWindowsRoot(p) {
|
|
|
13030
13096
|
}
|
|
13031
13097
|
|
|
13032
13098
|
// ../aft-bridge/dist/subc-transport.js
|
|
13099
|
+
class SubcTransportShuttingDownError extends SubcCallError {
|
|
13100
|
+
constructor() {
|
|
13101
|
+
super("terminal", "subc transport is shutting down", "transport_shutting_down");
|
|
13102
|
+
this.name = "SubcTransportShuttingDownError";
|
|
13103
|
+
}
|
|
13104
|
+
}
|
|
13033
13105
|
var AFT_MODULE_ID = "aft";
|
|
13034
13106
|
var MAX_CONSECUTIVE_TRANSPORT_FAILURES = 3;
|
|
13035
13107
|
var BG_STABLE_MS = 5000;
|
|
@@ -13371,7 +13443,6 @@ class SubcTransport {
|
|
|
13371
13443
|
pool;
|
|
13372
13444
|
projectRoot;
|
|
13373
13445
|
generation;
|
|
13374
|
-
lastStatusBar;
|
|
13375
13446
|
cachedStatus = null;
|
|
13376
13447
|
constructor(pool, projectRoot, generation) {
|
|
13377
13448
|
this.pool = pool;
|
|
@@ -13387,20 +13458,12 @@ class SubcTransport {
|
|
|
13387
13458
|
getConcretePoolId() {
|
|
13388
13459
|
return this.pool.getConcretePoolId();
|
|
13389
13460
|
}
|
|
13390
|
-
getStatusBar() {
|
|
13391
|
-
return this.lastStatusBar;
|
|
13392
|
-
}
|
|
13393
13461
|
getCachedStatus() {
|
|
13394
13462
|
return this.cachedStatus;
|
|
13395
13463
|
}
|
|
13396
13464
|
cacheStatusSnapshot(snapshot) {
|
|
13397
13465
|
this.cachedStatus = snapshot;
|
|
13398
13466
|
}
|
|
13399
|
-
captureStatusBar(response) {
|
|
13400
|
-
const parsed = parseStatusBarCounts(response.status_bar);
|
|
13401
|
-
if (parsed)
|
|
13402
|
-
this.lastStatusBar = parsed;
|
|
13403
|
-
}
|
|
13404
13467
|
identityFor(session) {
|
|
13405
13468
|
return {
|
|
13406
13469
|
project_root: this.projectRoot,
|
|
@@ -13421,9 +13484,7 @@ class SubcTransport {
|
|
|
13421
13484
|
if (preview === true)
|
|
13422
13485
|
body.preview = true;
|
|
13423
13486
|
const reply = await this.pool.routeRequest(this.identityFor(sessionId), body, timeoutMs, onProgress, this.generation);
|
|
13424
|
-
|
|
13425
|
-
this.captureStatusBar(result);
|
|
13426
|
-
return result;
|
|
13487
|
+
return reliftReply(reply);
|
|
13427
13488
|
}
|
|
13428
13489
|
async send(command, params = {}, options) {
|
|
13429
13490
|
this.assertCurrent();
|
|
@@ -13437,9 +13498,7 @@ class SubcTransport {
|
|
|
13437
13498
|
if (editSlotSurvives !== undefined)
|
|
13438
13499
|
body.edit_slot_survives = editSlotSurvives;
|
|
13439
13500
|
const reply = await this.pool.routeRequest(this.identityFor(session), body, timeoutMs, onProgress, this.generation);
|
|
13440
|
-
|
|
13441
|
-
this.captureStatusBar(response);
|
|
13442
|
-
return response;
|
|
13501
|
+
return reliftReply(reply);
|
|
13443
13502
|
}
|
|
13444
13503
|
splitOptions(options) {
|
|
13445
13504
|
if (!options)
|
|
@@ -13710,7 +13769,7 @@ class SubcTransportPool {
|
|
|
13710
13769
|
getBridge(projectRoot) {
|
|
13711
13770
|
const root = this.canonicalRoot(projectRoot);
|
|
13712
13771
|
if (this.shuttingDown && this.lifecycleEnabled()) {
|
|
13713
|
-
throw new
|
|
13772
|
+
throw new SubcTransportShuttingDownError;
|
|
13714
13773
|
}
|
|
13715
13774
|
if (!this.lifecycleEnabled())
|
|
13716
13775
|
return this.makeFacade(root);
|
|
@@ -14010,7 +14069,7 @@ class SubcTransportPool {
|
|
|
14010
14069
|
}
|
|
14011
14070
|
async ensureClient() {
|
|
14012
14071
|
if (this.shuttingDown)
|
|
14013
|
-
throw new
|
|
14072
|
+
throw new SubcTransportShuttingDownError;
|
|
14014
14073
|
if (this.client)
|
|
14015
14074
|
return this.client;
|
|
14016
14075
|
if (this.connecting)
|
|
@@ -14024,7 +14083,7 @@ class SubcTransportPool {
|
|
|
14024
14083
|
try {
|
|
14025
14084
|
client.close();
|
|
14026
14085
|
} catch {}
|
|
14027
|
-
throw new
|
|
14086
|
+
throw new SubcTransportShuttingDownError;
|
|
14028
14087
|
}
|
|
14029
14088
|
this.client = client;
|
|
14030
14089
|
this.transportFailures = 0;
|
|
@@ -14289,8 +14348,24 @@ function isRouteGoodbyeError(error2) {
|
|
|
14289
14348
|
}
|
|
14290
14349
|
return error2.code === "route_closed" && error2.message.includes("route closed by subc");
|
|
14291
14350
|
}
|
|
14351
|
+
function hasEngineResponse(error2) {
|
|
14352
|
+
const response = error2.response;
|
|
14353
|
+
if (response !== null && typeof response === "object")
|
|
14354
|
+
return true;
|
|
14355
|
+
const cause = error2.cause;
|
|
14356
|
+
if (cause === null || typeof cause !== "object")
|
|
14357
|
+
return false;
|
|
14358
|
+
const causeResponse = cause.response;
|
|
14359
|
+
return causeResponse !== null && typeof causeResponse === "object";
|
|
14360
|
+
}
|
|
14361
|
+
function isBashTransportDeadError(error2) {
|
|
14362
|
+
if (!(error2 instanceof Error) || hasEngineResponse(error2) || isRouteGoodbyeError(error2)) {
|
|
14363
|
+
return false;
|
|
14364
|
+
}
|
|
14365
|
+
return error2 instanceof BridgeTransportUnavailableError || error2 instanceof SubcTransportShuttingDownError || isConsumerReconnectTransient(error2) || error2 instanceof StaleRouteHandleError || error2 instanceof SubcRootGenerationExpiredError || error2 instanceof SubcRootReapedError;
|
|
14366
|
+
}
|
|
14292
14367
|
function isTransportClassError(error2) {
|
|
14293
|
-
return isBridgeTransportTimeout(error2) ||
|
|
14368
|
+
return isBridgeTransportTimeout(error2) || isBashTransportDeadError(error2);
|
|
14294
14369
|
}
|
|
14295
14370
|
function adaptToolError(command, error2) {
|
|
14296
14371
|
if (!(error2 instanceof Error))
|
|
@@ -16860,9 +16935,6 @@ class RevivableProjectTransport {
|
|
|
16860
16935
|
getCwd() {
|
|
16861
16936
|
return this.projectRoot;
|
|
16862
16937
|
}
|
|
16863
|
-
getStatusBar() {
|
|
16864
|
-
return this.owner.currentBridge(this.projectRoot)?.getStatusBar();
|
|
16865
|
-
}
|
|
16866
16938
|
getCachedStatus() {
|
|
16867
16939
|
return this.owner.currentBridge(this.projectRoot)?.getCachedStatus() ?? null;
|
|
16868
16940
|
}
|
|
@@ -17881,7 +17953,7 @@ import {
|
|
|
17881
17953
|
// package.json
|
|
17882
17954
|
var package_default = {
|
|
17883
17955
|
name: "@cortexkit/aft-pi",
|
|
17884
|
-
version: "0.
|
|
17956
|
+
version: "0.51.0",
|
|
17885
17957
|
type: "module",
|
|
17886
17958
|
description: "Pi coding agent extension for Agent File Tools (AFT) — tree-sitter and LSP-powered code analysis",
|
|
17887
17959
|
main: "dist/index.js",
|
|
@@ -17904,19 +17976,19 @@ var package_default = {
|
|
|
17904
17976
|
"test:unit": "bun test src/__tests__ --path-ignore-patterns 'src/__tests__/e2e/**'"
|
|
17905
17977
|
},
|
|
17906
17978
|
dependencies: {
|
|
17907
|
-
"@cortexkit/aft-bridge": "0.
|
|
17979
|
+
"@cortexkit/aft-bridge": "0.51.0",
|
|
17908
17980
|
"comment-json": "^5.0.0",
|
|
17909
17981
|
diff: "^8.0.4",
|
|
17910
17982
|
typebox: "1.1.38",
|
|
17911
17983
|
zod: "^4.4.3"
|
|
17912
17984
|
},
|
|
17913
17985
|
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.
|
|
17986
|
+
"@cortexkit/aft-darwin-arm64": "0.51.0",
|
|
17987
|
+
"@cortexkit/aft-darwin-x64": "0.51.0",
|
|
17988
|
+
"@cortexkit/aft-linux-arm64": "0.51.0",
|
|
17989
|
+
"@cortexkit/aft-linux-x64": "0.51.0",
|
|
17990
|
+
"@cortexkit/aft-win32-arm64": "0.51.0",
|
|
17991
|
+
"@cortexkit/aft-win32-x64": "0.51.0"
|
|
17920
17992
|
},
|
|
17921
17993
|
devDependencies: {
|
|
17922
17994
|
"@earendil-works/pi-coding-agent": "^0.80.2",
|
|
@@ -17983,14 +18055,23 @@ function readStatusBar(value) {
|
|
|
17983
18055
|
if (typeof value !== "object" || value === null)
|
|
17984
18056
|
return;
|
|
17985
18057
|
const bar = asRecord2(value);
|
|
18058
|
+
const errors = readOptionalNumber(bar.errors);
|
|
18059
|
+
const warnings = readOptionalNumber(bar.warnings);
|
|
18060
|
+
const deadCode = readOptionalNumber(bar.dead_code);
|
|
18061
|
+
const unusedExports = readOptionalNumber(bar.unused_exports);
|
|
18062
|
+
const duplicates = readOptionalNumber(bar.duplicates);
|
|
18063
|
+
const todos = readOptionalNumber(bar.todos);
|
|
18064
|
+
if (errors === null && warnings === null && deadCode === null && unusedExports === null && duplicates === null && todos === null) {
|
|
18065
|
+
return;
|
|
18066
|
+
}
|
|
17986
18067
|
return {
|
|
17987
|
-
errors:
|
|
17988
|
-
warnings:
|
|
17989
|
-
dead_code:
|
|
17990
|
-
unused_exports:
|
|
17991
|
-
duplicates:
|
|
17992
|
-
todos:
|
|
17993
|
-
tier2_stale:
|
|
18068
|
+
...errors !== null ? { errors } : {},
|
|
18069
|
+
...warnings !== null ? { warnings } : {},
|
|
18070
|
+
...deadCode !== null ? { dead_code: deadCode } : {},
|
|
18071
|
+
...unusedExports !== null ? { unused_exports: unusedExports } : {},
|
|
18072
|
+
...duplicates !== null ? { duplicates } : {},
|
|
18073
|
+
...todos !== null ? { todos } : {},
|
|
18074
|
+
...bar.tier2_stale === true ? { tier2_stale: true } : {}
|
|
17994
18075
|
};
|
|
17995
18076
|
}
|
|
17996
18077
|
function formatFlag(enabled) {
|
|
@@ -17999,6 +18080,15 @@ function formatFlag(enabled) {
|
|
|
17999
18080
|
function formatCount(value) {
|
|
18000
18081
|
return value == null ? "—" : value.toLocaleString("en-US");
|
|
18001
18082
|
}
|
|
18083
|
+
function formatCacheRoleLabel(role) {
|
|
18084
|
+
if (role === "worktree") {
|
|
18085
|
+
return "worktree — shared repo index (built by the main checkout)";
|
|
18086
|
+
}
|
|
18087
|
+
if (role === "read_only") {
|
|
18088
|
+
return "read_only — sharing the repo index family (read-only borrow)";
|
|
18089
|
+
}
|
|
18090
|
+
return role;
|
|
18091
|
+
}
|
|
18002
18092
|
function formatSemanticIndexStatus(status, stage) {
|
|
18003
18093
|
if ((status === "loading" || status === "building") && stage === "fingerprint_change") {
|
|
18004
18094
|
return "Rebuilding (model changed)";
|
|
@@ -18099,7 +18189,7 @@ function formatStatusDialogMessage(status) {
|
|
|
18099
18189
|
`AFT version: ${status.version}`,
|
|
18100
18190
|
`Project root: ${status.project_root ?? "(not configured)"}`,
|
|
18101
18191
|
`Canonical root: ${status.canonical_root ?? "(not configured)"}`,
|
|
18102
|
-
`Cache role: ${status.cache_role}`,
|
|
18192
|
+
`Cache role: ${formatCacheRoleLabel(status.cache_role)}`,
|
|
18103
18193
|
"",
|
|
18104
18194
|
"Enabled features",
|
|
18105
18195
|
`- format_on_edit: ${formatFlag(status.features.format_on_edit)}`,
|
|
@@ -18131,7 +18221,19 @@ function formatStatusDialogMessage(status) {
|
|
|
18131
18221
|
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
18222
|
if (status.status_bar) {
|
|
18133
18223
|
const sb = status.status_bar;
|
|
18134
|
-
|
|
18224
|
+
const rows = [
|
|
18225
|
+
["errors", sb.errors],
|
|
18226
|
+
["warnings", sb.warnings],
|
|
18227
|
+
["dead code", sb.dead_code],
|
|
18228
|
+
["unused exports", sb.unused_exports],
|
|
18229
|
+
["duplicates", sb.duplicates],
|
|
18230
|
+
["todos", sb.todos]
|
|
18231
|
+
].filter((row) => typeof row[1] === "number");
|
|
18232
|
+
if (rows.length > 0) {
|
|
18233
|
+
lines.push("", `Code Health${sb.tier2_stale ? " (~ stale)" : ""}`);
|
|
18234
|
+
for (const [label, value] of rows)
|
|
18235
|
+
lines.push(`- ${label}: ${formatCount(value)}`);
|
|
18236
|
+
}
|
|
18135
18237
|
}
|
|
18136
18238
|
if (status.storage_dir ?? status.disk.storage_dir) {
|
|
18137
18239
|
lines.push(`- storage dir: ${status.storage_dir ?? status.disk.storage_dir}`);
|
|
@@ -18210,6 +18312,8 @@ async function callBridge(bridge, command, params = {}, extCtx, options) {
|
|
|
18210
18312
|
try {
|
|
18211
18313
|
response = await bridge.send(command, merged, Object.keys(sendOptions).length > 0 ? sendOptions : undefined);
|
|
18212
18314
|
} catch (error3) {
|
|
18315
|
+
if (command === "bash" && isBashTransportDeadError(error3))
|
|
18316
|
+
throw error3;
|
|
18213
18317
|
throw adaptToolError(command, error3);
|
|
18214
18318
|
}
|
|
18215
18319
|
if (response.success === false) {
|
|
@@ -18345,8 +18449,8 @@ function renderInner(s, error3, theme, innerWidth) {
|
|
|
18345
18449
|
}
|
|
18346
18450
|
lines.push(rowFull("Project root", s.project_root ?? "(not configured)", theme, innerWidth));
|
|
18347
18451
|
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));
|
|
18452
|
+
const cacheTone = s.cache_role === "main" ? "accent" : "muted";
|
|
18453
|
+
lines.push(rowFull("Cache role", theme.fg(cacheTone, formatCacheRoleLabel(s.cache_role)), theme, innerWidth));
|
|
18350
18454
|
lines.push("");
|
|
18351
18455
|
const colWidth = Math.floor((innerWidth - 2) / 2);
|
|
18352
18456
|
const left = [];
|
|
@@ -32839,6 +32943,7 @@ function resolveBashConfig(config2) {
|
|
|
32839
32943
|
rewrite: false,
|
|
32840
32944
|
compress: false,
|
|
32841
32945
|
background: false,
|
|
32946
|
+
host_fallback: false,
|
|
32842
32947
|
long_running_reminder_enabled: reminderEnabled,
|
|
32843
32948
|
long_running_reminder_interval_ms: reminderInterval,
|
|
32844
32949
|
foreground_wait_window_ms: foregroundWaitWindowMs
|
|
@@ -32854,7 +32959,8 @@ function resolveBashConfig(config2) {
|
|
|
32854
32959
|
enabled: true,
|
|
32855
32960
|
rewrite: top.rewrite ?? true,
|
|
32856
32961
|
compress: top.compress ?? true,
|
|
32857
|
-
background: top.background ?? true
|
|
32962
|
+
background: top.background ?? true,
|
|
32963
|
+
host_fallback: top.host_fallback ?? false
|
|
32858
32964
|
};
|
|
32859
32965
|
}
|
|
32860
32966
|
const hasLegacyFeatureFlag = legacy && (legacy.rewrite !== undefined || legacy.compress !== undefined || legacy.background !== undefined);
|
|
@@ -32941,6 +33047,7 @@ var BashFeaturesSchema = exports_external.object({
|
|
|
32941
33047
|
rewrite: exports_external.boolean().optional(),
|
|
32942
33048
|
compress: exports_external.boolean().optional(),
|
|
32943
33049
|
background: exports_external.boolean().optional(),
|
|
33050
|
+
host_fallback: exports_external.boolean().optional(),
|
|
32944
33051
|
long_running_reminder_enabled: exports_external.boolean().optional(),
|
|
32945
33052
|
long_running_reminder_interval_ms: exports_external.number().int().positive().optional(),
|
|
32946
33053
|
foreground_wait_window_ms: exports_external.number().int().positive().optional()
|
|
@@ -32969,6 +33076,9 @@ var InspectConfigSchema = exports_external.object({
|
|
|
32969
33076
|
expected_mirrors: exports_external.array(exports_external.tuple([exports_external.string().trim().min(1), exports_external.string().trim().min(1)])).optional()
|
|
32970
33077
|
}).optional()
|
|
32971
33078
|
});
|
|
33079
|
+
var WorktreeConfigSchema = exports_external.object({
|
|
33080
|
+
ram_overlay: exports_external.boolean().optional()
|
|
33081
|
+
});
|
|
32972
33082
|
var BackupConfigSchema = exports_external.object({
|
|
32973
33083
|
enabled: exports_external.boolean().optional(),
|
|
32974
33084
|
max_depth: exports_external.number().int().positive().optional(),
|
|
@@ -32993,6 +33103,7 @@ var AftConfigSchema = exports_external.preprocess((value) => stripHarnessSpecifi
|
|
|
32993
33103
|
callgraph_chunk_size: exports_external.number().optional(),
|
|
32994
33104
|
inspect: InspectConfigSchema.optional(),
|
|
32995
33105
|
backup: BackupConfigSchema.optional(),
|
|
33106
|
+
worktree: WorktreeConfigSchema.optional(),
|
|
32996
33107
|
sandbox: SandboxConfigSchema.optional(),
|
|
32997
33108
|
bash: BashConfigSchema.optional(),
|
|
32998
33109
|
experimental: ExperimentalConfigSchema.optional(),
|
|
@@ -33249,6 +33360,15 @@ function mergeLspConfig(base, override) {
|
|
|
33249
33360
|
return;
|
|
33250
33361
|
return Object.fromEntries(Object.entries(lsp).filter(([, v]) => v !== undefined));
|
|
33251
33362
|
}
|
|
33363
|
+
function mergeWorktreeConfig(baseWorktree, overrideWorktree) {
|
|
33364
|
+
if (baseWorktree === undefined && overrideWorktree === undefined)
|
|
33365
|
+
return;
|
|
33366
|
+
if (overrideWorktree === undefined)
|
|
33367
|
+
return baseWorktree;
|
|
33368
|
+
if (baseWorktree === undefined)
|
|
33369
|
+
return overrideWorktree;
|
|
33370
|
+
return { ...baseWorktree, ...overrideWorktree };
|
|
33371
|
+
}
|
|
33252
33372
|
function mergeInspectConfig(baseInspect, overrideInspect) {
|
|
33253
33373
|
const inspect = {
|
|
33254
33374
|
...baseInspect,
|
|
@@ -33334,6 +33454,7 @@ var PROJECT_SAFE_TOP_LEVEL_FIELDS = new Set([
|
|
|
33334
33454
|
"callgraph_store",
|
|
33335
33455
|
"callgraph_chunk_size",
|
|
33336
33456
|
"inspect",
|
|
33457
|
+
"worktree",
|
|
33337
33458
|
"experimental",
|
|
33338
33459
|
"bash"
|
|
33339
33460
|
]);
|
|
@@ -33378,11 +33499,13 @@ function mergeConfigs(base, override) {
|
|
|
33378
33499
|
const experimental = mergeExperimentalConfig(base.experimental, override.experimental);
|
|
33379
33500
|
const bash = mergeBashConfig(base.bash, override.bash);
|
|
33380
33501
|
const inspect = mergeInspectConfig(base.inspect, override.inspect);
|
|
33502
|
+
const worktree = mergeWorktreeConfig(base.worktree, override.worktree);
|
|
33381
33503
|
const sandbox = mergeSandboxConfig(base.sandbox, override.sandbox);
|
|
33382
33504
|
const bridge = base.bridge;
|
|
33383
33505
|
const safeOverride = pickProjectSafeFields(override);
|
|
33384
33506
|
delete safeOverride.bash;
|
|
33385
33507
|
delete safeOverride.inspect;
|
|
33508
|
+
delete safeOverride.worktree;
|
|
33386
33509
|
return {
|
|
33387
33510
|
...base,
|
|
33388
33511
|
...safeOverride,
|
|
@@ -33391,6 +33514,7 @@ function mergeConfigs(base, override) {
|
|
|
33391
33514
|
...lsp ? { lsp } : {},
|
|
33392
33515
|
...bash !== undefined ? { bash } : {},
|
|
33393
33516
|
...inspect !== undefined ? { inspect } : {},
|
|
33517
|
+
...worktree !== undefined ? { worktree } : {},
|
|
33394
33518
|
...sandbox !== undefined ? { sandbox } : {},
|
|
33395
33519
|
experimental,
|
|
33396
33520
|
semantic,
|
|
@@ -33472,7 +33596,7 @@ function loadAftConfig(projectDirectory) {
|
|
|
33472
33596
|
}
|
|
33473
33597
|
|
|
33474
33598
|
// src/lsp-auto-install.ts
|
|
33475
|
-
import { spawn as
|
|
33599
|
+
import { spawn as spawn3 } from "node:child_process";
|
|
33476
33600
|
import { createHash as createHash4 } from "node:crypto";
|
|
33477
33601
|
import {
|
|
33478
33602
|
createReadStream,
|
|
@@ -34072,7 +34196,7 @@ function runInstall(spec, version2, cwd, signal) {
|
|
|
34072
34196
|
return;
|
|
34073
34197
|
}
|
|
34074
34198
|
ensureInstallAnchor(cwd);
|
|
34075
|
-
const child =
|
|
34199
|
+
const child = spawn3(npm.command, ["install", "--no-save", "--ignore-scripts", "--silent", target], {
|
|
34076
34200
|
stdio: ["ignore", "pipe", "pipe"],
|
|
34077
34201
|
cwd,
|
|
34078
34202
|
env: npmSpawnEnv(npm)
|
|
@@ -35270,26 +35394,6 @@ function sendFeatureAnnouncement(version2, features, footer, storageDir) {
|
|
|
35270
35394
|
markAnnouncementSeen(storageDir, "pi", version2);
|
|
35271
35395
|
}
|
|
35272
35396
|
|
|
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
35397
|
// src/bash-wait-detach.ts
|
|
35294
35398
|
var BASH_TRANSPORT_TIMEOUT_MS = 30000;
|
|
35295
35399
|
async function sendBashWaitDetach(bridge, sessionID) {
|
|
@@ -36730,7 +36834,7 @@ DO NOT use bash for code search or code exploration. If you are about to run gre
|
|
|
36730
36834
|
"Piped commands run verbatim and show the pipeline's output; run test/build tools without pipes when you need AFT's summary."
|
|
36731
36835
|
],
|
|
36732
36836
|
parameters: bashParamsForConfig(bashCfg.background),
|
|
36733
|
-
async execute(_toolCallId, params,
|
|
36837
|
+
async execute(_toolCallId, params, signal, onUpdate, extCtx) {
|
|
36734
36838
|
const bridge = bridgeFor(ctx, extCtx.cwd);
|
|
36735
36839
|
const bashCfg2 = resolveBashConfig(ctx.config);
|
|
36736
36840
|
const foregroundWaitMs = resolveForegroundWaitMs(bashCfg2.foreground_wait_window_ms);
|
|
@@ -36765,30 +36869,62 @@ DO NOT use bash for code search or code exploration. If you are about to run gre
|
|
|
36765
36869
|
}
|
|
36766
36870
|
const bridgeCommand = spawnContext.command;
|
|
36767
36871
|
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
|
-
|
|
36872
|
+
let usedHostFallback = false;
|
|
36873
|
+
let response;
|
|
36874
|
+
try {
|
|
36875
|
+
response = await callBashWithPermissionLoop(bridge, {
|
|
36876
|
+
command: bridgeCommand,
|
|
36877
|
+
timeout: effectiveTimeout,
|
|
36878
|
+
workdir: spawnContext.cwd ?? params.workdir,
|
|
36879
|
+
env: spawnContext.env,
|
|
36880
|
+
description: params.description,
|
|
36881
|
+
background: effectiveBackground,
|
|
36882
|
+
notify_on_completion: effectiveBackground,
|
|
36883
|
+
compressed,
|
|
36884
|
+
pty: requestedPty,
|
|
36885
|
+
pty_rows: ptyRows,
|
|
36886
|
+
pty_cols: ptyCols,
|
|
36887
|
+
foreground_orchestrate: true,
|
|
36888
|
+
block_to_completion: blockToCompletion,
|
|
36889
|
+
wait: requestedWait,
|
|
36890
|
+
sandbox: params.sandbox
|
|
36891
|
+
}, extCtx, {
|
|
36892
|
+
transportTimeoutMs: orchestratedTransportTimeoutMs(blockToCompletion, requestedWait, effectiveTimeout, foregroundWaitMs),
|
|
36893
|
+
onProgress: ({ text }) => {
|
|
36894
|
+
streamed += text;
|
|
36895
|
+
const displayText = truncateToVisualLines(streamed, 100);
|
|
36896
|
+
onUpdate?.(bashResult(displayText, { streaming: true }));
|
|
36897
|
+
}
|
|
36898
|
+
});
|
|
36899
|
+
} catch (error53) {
|
|
36900
|
+
if (!bashCfg2.host_fallback || !isBashTransportDeadError(error53))
|
|
36901
|
+
throw error53;
|
|
36902
|
+
if (rawRequestedBackground) {
|
|
36903
|
+
throw new Error(`${BASH_HOST_FALLBACK_REFUSAL}; background:true is unsupported.`);
|
|
36904
|
+
}
|
|
36905
|
+
if (rawRequestedPty) {
|
|
36906
|
+
throw new Error(`${BASH_HOST_FALLBACK_REFUSAL}; pty:true is unsupported.`);
|
|
36907
|
+
}
|
|
36908
|
+
if (!extCtx.hasUI || typeof extCtx.ui?.confirm !== "function") {
|
|
36909
|
+
throw new BridgeError("Permission denied: host fallback execution requires an interactive UI.", "permission_denied");
|
|
36910
|
+
}
|
|
36911
|
+
const projectRoot = extCtx.cwd;
|
|
36912
|
+
const pattern = bashHostFallbackAskPattern(bridgeCommand, projectRoot);
|
|
36913
|
+
const approved = await extCtx.ui.confirm("AFT unavailable — run command on host?", pattern, {
|
|
36914
|
+
signal: signal ?? extCtx.signal
|
|
36915
|
+
});
|
|
36916
|
+
if (!approved) {
|
|
36917
|
+
throw new BridgeError("Permission denied: AFT host fallback execution was denied.", "permission_denied");
|
|
36918
|
+
}
|
|
36919
|
+
response = await runBashHostFallback({
|
|
36920
|
+
command: bridgeCommand,
|
|
36921
|
+
projectRoot,
|
|
36922
|
+
timeoutMs: timeout,
|
|
36923
|
+
signal: signal ?? extCtx.signal,
|
|
36924
|
+
env: spawnContext.env
|
|
36925
|
+
});
|
|
36926
|
+
usedHostFallback = true;
|
|
36927
|
+
}
|
|
36792
36928
|
if (response.success === false) {
|
|
36793
36929
|
throw new Error(response.message ?? "bash failed");
|
|
36794
36930
|
}
|
|
@@ -36805,7 +36941,7 @@ DO NOT use bash for code search or code exploration. If you are about to run gre
|
|
|
36805
36941
|
task_id: taskId
|
|
36806
36942
|
};
|
|
36807
36943
|
const output = response.output ?? "";
|
|
36808
|
-
return bashResult(withBashHints(output, bridgeCommand, aftSearchRegistered, extCtx.cwd), details);
|
|
36944
|
+
return bashResult(usedHostFallback ? output : withBashHints(output, bridgeCommand, aftSearchRegistered, extCtx.cwd), details);
|
|
36809
36945
|
},
|
|
36810
36946
|
renderCall(args, theme, context) {
|
|
36811
36947
|
return renderBashCall(args?.command, args?.description, theme, context);
|
|
@@ -37647,10 +37783,10 @@ function registerImportTools(pi, ctx) {
|
|
|
37647
37783
|
import { Type as Type8 } from "typebox";
|
|
37648
37784
|
var InspectParams = Type8.Object({
|
|
37649
37785
|
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."
|
|
37786
|
+
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
37787
|
})),
|
|
37652
37788
|
scope: Type8.Optional(Type8.Union([Type8.String(), Type8.Array(Type8.String())], {
|
|
37653
|
-
description: "Restrict
|
|
37789
|
+
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
37790
|
})),
|
|
37655
37791
|
topK: Type8.Optional(Type8.Integer({
|
|
37656
37792
|
minimum: 1,
|
|
@@ -37659,11 +37795,6 @@ var InspectParams = Type8.Object({
|
|
|
37659
37795
|
description: "Max drill-down items per category. Default 20, max 100."
|
|
37660
37796
|
}))
|
|
37661
37797
|
});
|
|
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
37798
|
function normalizeStringOrArray(value) {
|
|
37668
37799
|
return isEmptyParam(value) ? undefined : value;
|
|
37669
37800
|
}
|
|
@@ -37694,15 +37825,119 @@ function validateOptionalTopK(value) {
|
|
|
37694
37825
|
}
|
|
37695
37826
|
return value;
|
|
37696
37827
|
}
|
|
37697
|
-
function
|
|
37698
|
-
|
|
37699
|
-
|
|
37700
|
-
|
|
37701
|
-
|
|
37702
|
-
|
|
37703
|
-
|
|
37704
|
-
|
|
37705
|
-
|
|
37828
|
+
function terminalKind(response) {
|
|
37829
|
+
for (const value of [
|
|
37830
|
+
response.terminal,
|
|
37831
|
+
response.outcome,
|
|
37832
|
+
response.inspect_outcome,
|
|
37833
|
+
response.inspect_terminal,
|
|
37834
|
+
response.status
|
|
37835
|
+
]) {
|
|
37836
|
+
if (typeof value !== "string")
|
|
37837
|
+
continue;
|
|
37838
|
+
const normalized = value.toUpperCase().replaceAll("_", "-");
|
|
37839
|
+
if (normalized === "FRESH" || normalized === "INTERRUPTED" || normalized === "PHASE-FAILED") {
|
|
37840
|
+
return normalized;
|
|
37841
|
+
}
|
|
37842
|
+
}
|
|
37843
|
+
return;
|
|
37844
|
+
}
|
|
37845
|
+
function firstRecord(...values) {
|
|
37846
|
+
for (const value of values) {
|
|
37847
|
+
const record2 = asRecord3(value);
|
|
37848
|
+
if (record2)
|
|
37849
|
+
return record2;
|
|
37850
|
+
}
|
|
37851
|
+
return;
|
|
37852
|
+
}
|
|
37853
|
+
function firstString(...values) {
|
|
37854
|
+
for (const value of values) {
|
|
37855
|
+
const text = asString2(value);
|
|
37856
|
+
if (text !== undefined)
|
|
37857
|
+
return text;
|
|
37858
|
+
}
|
|
37859
|
+
return;
|
|
37860
|
+
}
|
|
37861
|
+
function parseInspectPhaseEntries(value) {
|
|
37862
|
+
if (!Array.isArray(value))
|
|
37863
|
+
return [];
|
|
37864
|
+
return value.flatMap((candidate) => {
|
|
37865
|
+
const entry = asRecord3(candidate);
|
|
37866
|
+
const id = asString2(entry?.id);
|
|
37867
|
+
if (!id)
|
|
37868
|
+
return [];
|
|
37869
|
+
const alsoSatisfied = Array.isArray(entry?.also_satisfied) ? entry.also_satisfied.filter((category) => typeof category === "string") : [];
|
|
37870
|
+
return [
|
|
37871
|
+
{
|
|
37872
|
+
id,
|
|
37873
|
+
producer: asString2(entry?.producer),
|
|
37874
|
+
category: asString2(entry?.category),
|
|
37875
|
+
alsoSatisfied
|
|
37876
|
+
}
|
|
37877
|
+
];
|
|
37878
|
+
});
|
|
37879
|
+
}
|
|
37880
|
+
function parseInspectTerminal(payload) {
|
|
37881
|
+
const response = asRecord3(payload);
|
|
37882
|
+
if (!response)
|
|
37883
|
+
return;
|
|
37884
|
+
const kind = terminalKind(response);
|
|
37885
|
+
if (!kind)
|
|
37886
|
+
return;
|
|
37887
|
+
const waitStamp = firstRecord(response.wait_stamp, response.waitStamp, response.blocking_wait_stamp);
|
|
37888
|
+
const phaseSource = kind === "FRESH" ? waitStamp ?? response : response;
|
|
37889
|
+
const phases = parseInspectPhaseEntries(phaseSource.phases ?? response.completed_phases ?? response.completedPhases);
|
|
37890
|
+
if (kind !== "PHASE-FAILED") {
|
|
37891
|
+
return {
|
|
37892
|
+
kind,
|
|
37893
|
+
phases,
|
|
37894
|
+
waitStampText: kind === "FRESH" ? firstString(waitStamp?.text, waitStamp?.human_text) : undefined
|
|
37895
|
+
};
|
|
37896
|
+
}
|
|
37897
|
+
const failedPhaseRecord = asRecord3(response.failed_phase);
|
|
37898
|
+
const failedPhaseId = firstString(failedPhaseRecord?.id, response.failed_phase);
|
|
37899
|
+
const failedPhase = failedPhaseId ? parseInspectPhaseEntries([
|
|
37900
|
+
{
|
|
37901
|
+
id: failedPhaseId,
|
|
37902
|
+
producer: firstString(failedPhaseRecord?.producer, response.failed_phase_producer, response.producer),
|
|
37903
|
+
category: firstString(failedPhaseRecord?.category, response.failed_phase_category, response.category)
|
|
37904
|
+
}
|
|
37905
|
+
])[0] : undefined;
|
|
37906
|
+
return {
|
|
37907
|
+
kind,
|
|
37908
|
+
phases,
|
|
37909
|
+
failedPhase,
|
|
37910
|
+
failureReason: asString2(response.failure_reason),
|
|
37911
|
+
failureDetail: asString2(response.failure_detail)
|
|
37912
|
+
};
|
|
37913
|
+
}
|
|
37914
|
+
function formatPhase(entry) {
|
|
37915
|
+
const details = [
|
|
37916
|
+
entry.producer ? `producer: ${entry.producer}` : undefined,
|
|
37917
|
+
entry.category ? `category: ${entry.category}` : undefined,
|
|
37918
|
+
entry.alsoSatisfied.length > 0 ? `also satisfied: ${entry.alsoSatisfied.join(", ")}` : undefined
|
|
37919
|
+
].filter((detail) => Boolean(detail));
|
|
37920
|
+
return details.length > 0 ? `${entry.id} (${details.join("; ")})` : entry.id;
|
|
37921
|
+
}
|
|
37922
|
+
function renderInspectTerminal(terminal, serverText) {
|
|
37923
|
+
const lines = [terminal.kind];
|
|
37924
|
+
if (terminal.kind === "FRESH") {
|
|
37925
|
+
lines.push(`wait-stamp: ${terminal.waitStampText ?? "not supplied"}`);
|
|
37926
|
+
}
|
|
37927
|
+
if (terminal.kind === "PHASE-FAILED") {
|
|
37928
|
+
if (terminal.failedPhase)
|
|
37929
|
+
lines.push(`failed phase: ${formatPhase(terminal.failedPhase)}`);
|
|
37930
|
+
lines.push(`failure reason: ${terminal.failureReason ?? "not supplied"}`);
|
|
37931
|
+
if (terminal.failureDetail)
|
|
37932
|
+
lines.push(`failure detail: ${terminal.failureDetail}`);
|
|
37933
|
+
}
|
|
37934
|
+
lines.push(terminal.phases.length > 0 ? `completed phases:
|
|
37935
|
+
${terminal.phases.map((phase) => `- ${formatPhase(phase)}`).join(`
|
|
37936
|
+
`)}` : "completed phases: none");
|
|
37937
|
+
if (serverText?.trim())
|
|
37938
|
+
lines.push(serverText);
|
|
37939
|
+
return lines.join(`
|
|
37940
|
+
`);
|
|
37706
37941
|
}
|
|
37707
37942
|
function diagnosticsSummaryPart(summary) {
|
|
37708
37943
|
const section = asRecord3(summary?.diagnostics);
|
|
@@ -37712,31 +37947,9 @@ function diagnosticsSummaryPart(summary) {
|
|
|
37712
37947
|
const warnings = asNumber2(section.warnings);
|
|
37713
37948
|
const info = asNumber2(section.info);
|
|
37714
37949
|
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;
|
|
37950
|
+
if (![errors3, warnings, info, hints].some((value) => value !== undefined))
|
|
37951
|
+
return;
|
|
37952
|
+
return `diagnostics ${errors3 ?? 0} errors/${warnings ?? 0} warnings/${info ?? 0} info/${hints ?? 0} hints`;
|
|
37740
37953
|
}
|
|
37741
37954
|
function diagnosticLocation(diagnostic) {
|
|
37742
37955
|
const file2 = asString2(diagnostic.file) ?? "(unknown file)";
|
|
@@ -37748,36 +37961,28 @@ function diagnosticLocation(diagnostic) {
|
|
|
37748
37961
|
return `${file2}:${line}`;
|
|
37749
37962
|
return `${file2}:${line}:${column}`;
|
|
37750
37963
|
}
|
|
37751
|
-
function diagnosticsDetailSection(details
|
|
37964
|
+
function diagnosticsDetailSection(details) {
|
|
37752
37965
|
const diagnostics = asRecords2(details?.diagnostics);
|
|
37753
37966
|
if (diagnostics.length === 0)
|
|
37754
37967
|
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(`
|
|
37968
|
+
return [
|
|
37969
|
+
"diagnostics",
|
|
37970
|
+
...diagnostics.map((diagnostic) => {
|
|
37971
|
+
const severity = asString2(diagnostic.severity) ?? "information";
|
|
37972
|
+
const message = asString2(diagnostic.message) ?? "(no message)";
|
|
37973
|
+
const source = asString2(diagnostic.source);
|
|
37974
|
+
return `- ${diagnosticLocation(diagnostic)} ${severity} ${message}${source ? ` [${source}]` : ""}`;
|
|
37975
|
+
})
|
|
37976
|
+
].join(`
|
|
37768
37977
|
`);
|
|
37769
37978
|
}
|
|
37770
37979
|
function countFrom(summary, key) {
|
|
37771
|
-
|
|
37772
|
-
return asNumber2(section?.count);
|
|
37980
|
+
return asNumber2(asRecord3(summary?.[key])?.count);
|
|
37773
37981
|
}
|
|
37774
37982
|
function tier2SummaryPart(summary, key, label) {
|
|
37775
37983
|
const section = asRecord3(summary?.[key]);
|
|
37776
37984
|
const count = asNumber2(section?.count);
|
|
37777
|
-
|
|
37778
|
-
return `${label} ${count}`;
|
|
37779
|
-
const status = asString2(section?.status);
|
|
37780
|
-
return `${label} ${status ?? "unavailable"}`;
|
|
37985
|
+
return count !== undefined ? `${label} ${count}` : `${label} unavailable`;
|
|
37781
37986
|
}
|
|
37782
37987
|
function shortDupOccurrence(entry) {
|
|
37783
37988
|
const [path2] = entry.split(":");
|
|
@@ -37785,95 +37990,41 @@ function shortDupOccurrence(entry) {
|
|
|
37785
37990
|
}
|
|
37786
37991
|
function tier2TopPreview(summary, theme) {
|
|
37787
37992
|
const lines = [];
|
|
37788
|
-
const
|
|
37789
|
-
const dupTop = Array.isArray(dup?.top) ? dup.top : [];
|
|
37993
|
+
const dupTop = Array.isArray(asRecord3(summary?.duplicates)?.top) ? asRecord3(summary?.duplicates)?.top : [];
|
|
37790
37994
|
for (const group of dupTop) {
|
|
37791
37995
|
const record2 = asRecord3(group);
|
|
37792
37996
|
const files = Array.isArray(record2?.files) ? record2.files : [];
|
|
37793
37997
|
const cost = asNumber2(record2?.cost);
|
|
37794
37998
|
if (files.length < 2)
|
|
37795
37999
|
continue;
|
|
37796
|
-
|
|
37797
|
-
const b = shortDupOccurrence(String(files[1]));
|
|
37798
|
-
lines.push(` dup ${a} ↔ ${b}${cost !== undefined ? ` (${cost})` : ""}`);
|
|
38000
|
+
lines.push(` dup ${shortDupOccurrence(String(files[0]))} ↔ ${shortDupOccurrence(String(files[1]))}${cost !== undefined ? ` (${cost})` : ""}`);
|
|
37799
38001
|
}
|
|
37800
38002
|
for (const [key, label] of [
|
|
37801
38003
|
["dead_code", "dead"],
|
|
37802
38004
|
["unused_exports", "unused"]
|
|
37803
38005
|
]) {
|
|
37804
|
-
const
|
|
37805
|
-
const top = Array.isArray(section?.top) ? section.top : [];
|
|
38006
|
+
const top = Array.isArray(asRecord3(summary?.[key])?.top) ? asRecord3(summary?.[key])?.top : [];
|
|
37806
38007
|
for (const item of top) {
|
|
37807
38008
|
const record2 = asRecord3(item);
|
|
37808
38009
|
const file2 = asString2(record2?.file);
|
|
37809
38010
|
const symbol2 = asString2(record2?.symbol);
|
|
37810
|
-
if (
|
|
37811
|
-
|
|
37812
|
-
lines.push(` ${label} ${symbol2} (${file2.split("/").pop()})`);
|
|
38011
|
+
if (file2 && symbol2)
|
|
38012
|
+
lines.push(` ${label} ${symbol2} (${file2.split("/").pop()})`);
|
|
37813
38013
|
}
|
|
37814
38014
|
}
|
|
37815
|
-
|
|
37816
|
-
return;
|
|
37817
|
-
return `${theme.fg("muted", "top findings:")}
|
|
38015
|
+
return lines.length > 0 ? `${theme.fg("muted", "top findings:")}
|
|
37818
38016
|
${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
|
-
});
|
|
38017
|
+
`)}` : undefined;
|
|
37867
38018
|
}
|
|
37868
38019
|
function buildInspectSections(payload, theme) {
|
|
38020
|
+
const terminal = parseInspectTerminal(payload);
|
|
38021
|
+
if (terminal)
|
|
38022
|
+
return [renderInspectTerminal(terminal, asString2(asRecord3(payload)?.text))];
|
|
37869
38023
|
const response = asRecord3(payload);
|
|
37870
38024
|
if (!response)
|
|
37871
38025
|
return [theme.fg("muted", "No inspect snapshot available.")];
|
|
37872
38026
|
const summary = asRecord3(response.summary);
|
|
37873
38027
|
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
38028
|
const parts = [
|
|
37878
38029
|
`todos ${countFrom(summary, "todos") ?? 0}`,
|
|
37879
38030
|
diagnosticsSummaryPart(summary),
|
|
@@ -37884,9 +38035,6 @@ function buildInspectSections(payload, theme) {
|
|
|
37884
38035
|
tier2SummaryPart(summary, "cycles", "cycles")
|
|
37885
38036
|
].filter((part) => Boolean(part));
|
|
37886
38037
|
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
38038
|
const topPreview = tier2TopPreview(summary, theme);
|
|
37891
38039
|
if (topPreview)
|
|
37892
38040
|
sections.push(topPreview);
|
|
@@ -37894,7 +38042,7 @@ function buildInspectSections(payload, theme) {
|
|
|
37894
38042
|
if (details) {
|
|
37895
38043
|
const names = Object.keys(details);
|
|
37896
38044
|
sections.push(names.length > 0 ? `details: ${names.join(", ")}` : theme.fg("muted", "No drill-down details returned."));
|
|
37897
|
-
const diagnosticsDetails = diagnosticsDetailSection(details
|
|
38045
|
+
const diagnosticsDetails = diagnosticsDetailSection(details);
|
|
37898
38046
|
if (diagnosticsDetails)
|
|
37899
38047
|
sections.push(diagnosticsDetails);
|
|
37900
38048
|
}
|
|
@@ -37910,15 +38058,19 @@ function renderInspectCall(args, theme, context) {
|
|
|
37910
38058
|
return renderToolCall("inspect", summary ? theme.fg("toolOutput", summary) : undefined, theme, context);
|
|
37911
38059
|
}
|
|
37912
38060
|
function renderInspectResult(result, theme, context) {
|
|
38061
|
+
const payload = extractStructuredPayload(result);
|
|
38062
|
+
const terminal = parseInspectTerminal(payload);
|
|
38063
|
+
if (terminal)
|
|
38064
|
+
return renderSections([renderInspectTerminal(terminal, asString2(asRecord3(payload)?.text))], context);
|
|
37913
38065
|
if (context.isError)
|
|
37914
38066
|
return renderErrorResult(result, "inspect failed", theme, context);
|
|
37915
|
-
return renderSections(buildInspectSections(
|
|
38067
|
+
return renderSections(buildInspectSections(payload, theme), context);
|
|
37916
38068
|
}
|
|
37917
38069
|
function registerInspectTool(pi, ctx) {
|
|
37918
38070
|
pi.registerTool({
|
|
37919
38071
|
name: "aft_inspect",
|
|
37920
38072
|
label: "inspect",
|
|
37921
|
-
description: "
|
|
38073
|
+
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
38074
|
|
|
37923
38075
|
` + "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
38076
|
parameters: InspectParams,
|
|
@@ -37934,13 +38086,12 @@ function registerInspectTool(pi, ctx) {
|
|
|
37934
38086
|
rawArgs.scope = scope;
|
|
37935
38087
|
if (topK !== undefined)
|
|
37936
38088
|
rawArgs.topK = topK;
|
|
37937
|
-
const response = await callToolCall(bridge, "inspect", rawArgs, extCtx
|
|
37938
|
-
|
|
37939
|
-
|
|
37940
|
-
|
|
38089
|
+
const response = await callToolCall(bridge, "inspect", rawArgs, extCtx);
|
|
38090
|
+
const terminal = parseInspectTerminal(response);
|
|
38091
|
+
if (terminal)
|
|
38092
|
+
return textResult(renderInspectTerminal(terminal, response.text), response);
|
|
38093
|
+
if (response.success === false)
|
|
37941
38094
|
throw new Error(response.text || response.message || "inspect failed");
|
|
37942
|
-
}
|
|
37943
|
-
runPendingTier2Categories(bridge, tier2RefreshCategories(response), extCtx);
|
|
37944
38095
|
return textResult(response.text, response);
|
|
37945
38096
|
},
|
|
37946
38097
|
renderCall(args, theme, context) {
|
|
@@ -39100,7 +39251,7 @@ var PLUGIN_VERSION = (() => {
|
|
|
39100
39251
|
return "0.0.0";
|
|
39101
39252
|
}
|
|
39102
39253
|
})();
|
|
39103
|
-
var ANNOUNCEMENT_VERSION = "0.
|
|
39254
|
+
var ANNOUNCEMENT_VERSION = "0.51.0";
|
|
39104
39255
|
var ANNOUNCEMENT_FEATURES = [
|
|
39105
39256
|
"Callgraph stays consistent under load: edits arriving mid-rebuild can no longer be silently lost from navigation results.",
|
|
39106
39257
|
"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 +39614,7 @@ ${lines}
|
|
|
39463
39614
|
pi.on("tool_result", async (event, extCtx) => {
|
|
39464
39615
|
const sessionID = resolveSessionId(extCtx);
|
|
39465
39616
|
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 }];
|
|
39617
|
+
const content = bgContent ?? event.content;
|
|
39472
39618
|
if (content === event.content)
|
|
39473
39619
|
return;
|
|
39474
39620
|
return { content, details: event.details, isError: event.isError };
|