@cortexkit/aft-pi 0.21.0 → 0.22.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/README.md +1 -1
- package/dist/bg-notifications.d.ts +0 -2
- package/dist/bg-notifications.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +407 -169
- package/dist/lsp-auto-install.d.ts.map +1 -1
- package/dist/lsp-github-install.d.ts +12 -1
- package/dist/lsp-github-install.d.ts.map +1 -1
- package/dist/notifications.d.ts.map +1 -1
- package/dist/tools/imports.d.ts +0 -1
- package/dist/tools/imports.d.ts.map +1 -1
- package/dist/tools/reading.d.ts.map +1 -1
- package/dist/tools/refactor.d.ts +0 -1
- package/dist/tools/refactor.d.ts.map +1 -1
- package/dist/tools/structure.d.ts +0 -1
- package/dist/tools/structure.d.ts.map +1 -1
- package/package.json +7 -7
package/dist/index.js
CHANGED
|
@@ -18761,7 +18761,7 @@ var require_fetch = __commonJS((exports, module) => {
|
|
|
18761
18761
|
request.cache = "no-store";
|
|
18762
18762
|
}
|
|
18763
18763
|
const newConnection = forceNewConnection ? "yes" : "no";
|
|
18764
|
-
if (request.mode === "websocket") {}
|
|
18764
|
+
if (request.mode === "websocket") {}
|
|
18765
18765
|
let requestBody = null;
|
|
18766
18766
|
if (request.body == null && fetchParams.processRequestEndOfBody) {
|
|
18767
18767
|
queueMicrotask(() => fetchParams.processRequestEndOfBody());
|
|
@@ -30476,17 +30476,24 @@ var require_src2 = __commonJS((exports, module) => {
|
|
|
30476
30476
|
// src/index.ts
|
|
30477
30477
|
import { createRequire as createRequire3 } from "node:module";
|
|
30478
30478
|
import { homedir as homedir9 } from "node:os";
|
|
30479
|
-
import { join as
|
|
30479
|
+
import { join as join13 } from "node:path";
|
|
30480
30480
|
|
|
30481
30481
|
// ../aft-bridge/dist/active-logger.js
|
|
30482
|
-
var active;
|
|
30482
|
+
var ACTIVE_LOGGER_SYMBOL = Symbol.for("aft-bridge-active-logger");
|
|
30483
|
+
function loggerGlobal() {
|
|
30484
|
+
return globalThis;
|
|
30485
|
+
}
|
|
30483
30486
|
function setActiveLogger(logger) {
|
|
30484
|
-
|
|
30487
|
+
loggerGlobal()[ACTIVE_LOGGER_SYMBOL] = logger;
|
|
30488
|
+
}
|
|
30489
|
+
function getActiveLogger() {
|
|
30490
|
+
return loggerGlobal()[ACTIVE_LOGGER_SYMBOL];
|
|
30485
30491
|
}
|
|
30486
30492
|
function getLogFilePath() {
|
|
30487
|
-
return
|
|
30493
|
+
return getActiveLogger()?.getLogFilePath?.();
|
|
30488
30494
|
}
|
|
30489
30495
|
function log(message, meta) {
|
|
30496
|
+
const active = getActiveLogger();
|
|
30490
30497
|
if (active) {
|
|
30491
30498
|
active.log(message, meta);
|
|
30492
30499
|
} else {
|
|
@@ -30494,6 +30501,7 @@ function log(message, meta) {
|
|
|
30494
30501
|
}
|
|
30495
30502
|
}
|
|
30496
30503
|
function warn(message, meta) {
|
|
30504
|
+
const active = getActiveLogger();
|
|
30497
30505
|
if (active) {
|
|
30498
30506
|
active.warn(message, meta);
|
|
30499
30507
|
} else {
|
|
@@ -30501,6 +30509,7 @@ function warn(message, meta) {
|
|
|
30501
30509
|
}
|
|
30502
30510
|
}
|
|
30503
30511
|
function error(message, meta) {
|
|
30512
|
+
const active = getActiveLogger();
|
|
30504
30513
|
if (active) {
|
|
30505
30514
|
active.error(message, meta);
|
|
30506
30515
|
} else {
|
|
@@ -30520,6 +30529,7 @@ function sessionError(sessionId, message) {
|
|
|
30520
30529
|
import { spawn } from "node:child_process";
|
|
30521
30530
|
import { homedir } from "node:os";
|
|
30522
30531
|
import { join } from "node:path";
|
|
30532
|
+
import { StringDecoder } from "node:string_decoder";
|
|
30523
30533
|
var DEFAULT_BRIDGE_TIMEOUT_MS = 30000;
|
|
30524
30534
|
var SEMANTIC_TIMEOUT_SAFETY_MARGIN_MS = 5000;
|
|
30525
30535
|
var MAX_STDOUT_BUFFER = 64 * 1024 * 1024;
|
|
@@ -30616,6 +30626,7 @@ class BinaryBridge {
|
|
|
30616
30626
|
configureWarningClients = new Map;
|
|
30617
30627
|
restartResetTimer = null;
|
|
30618
30628
|
errorPrefix;
|
|
30629
|
+
logger;
|
|
30619
30630
|
constructor(binaryPath, cwd, options, configOverrides) {
|
|
30620
30631
|
this.binaryPath = binaryPath;
|
|
30621
30632
|
this.cwd = cwd;
|
|
@@ -30628,6 +30639,28 @@ class BinaryBridge {
|
|
|
30628
30639
|
this.onBashCompletion = options?.onBashCompletion;
|
|
30629
30640
|
this.onBashLongRunning = options?.onBashLongRunning;
|
|
30630
30641
|
this.errorPrefix = options?.errorPrefix ?? "[aft-bridge]";
|
|
30642
|
+
this.logger = options?.logger;
|
|
30643
|
+
}
|
|
30644
|
+
logVia(message, meta) {
|
|
30645
|
+
const logger = this.logger ?? getActiveLogger();
|
|
30646
|
+
if (logger)
|
|
30647
|
+
logger.log(message, meta);
|
|
30648
|
+
else
|
|
30649
|
+
log(message, meta);
|
|
30650
|
+
}
|
|
30651
|
+
warnVia(message, meta) {
|
|
30652
|
+
const logger = this.logger ?? getActiveLogger();
|
|
30653
|
+
if (logger)
|
|
30654
|
+
logger.warn(message, meta);
|
|
30655
|
+
else
|
|
30656
|
+
warn(message, meta);
|
|
30657
|
+
}
|
|
30658
|
+
errorVia(message, meta) {
|
|
30659
|
+
const logger = this.logger ?? getActiveLogger();
|
|
30660
|
+
if (logger)
|
|
30661
|
+
logger.error(message, meta);
|
|
30662
|
+
else
|
|
30663
|
+
error(message, meta);
|
|
30631
30664
|
}
|
|
30632
30665
|
get restartCount() {
|
|
30633
30666
|
return this._restartCount;
|
|
@@ -30736,8 +30769,8 @@ class BinaryBridge {
|
|
|
30736
30769
|
return;
|
|
30737
30770
|
if (configResult.warnings.length === 0)
|
|
30738
30771
|
return;
|
|
30772
|
+
const sessionId = typeof params.session_id === "string" ? params.session_id : undefined;
|
|
30739
30773
|
try {
|
|
30740
|
-
const sessionId = typeof params.session_id === "string" ? params.session_id : undefined;
|
|
30741
30774
|
await this.onConfigureWarnings({
|
|
30742
30775
|
projectRoot: this.cwd,
|
|
30743
30776
|
sessionId,
|
|
@@ -30746,6 +30779,10 @@ class BinaryBridge {
|
|
|
30746
30779
|
});
|
|
30747
30780
|
} catch (err) {
|
|
30748
30781
|
warn(`configure warning delivery failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
30782
|
+
} finally {
|
|
30783
|
+
if (sessionId) {
|
|
30784
|
+
this.configureWarningClients.delete(sessionId);
|
|
30785
|
+
}
|
|
30749
30786
|
}
|
|
30750
30787
|
}
|
|
30751
30788
|
async handleConfigureWarningsFrame(frame) {
|
|
@@ -30757,16 +30794,23 @@ class BinaryBridge {
|
|
|
30757
30794
|
const projectRoot = typeof frame.project_root === "string" ? frame.project_root : this.cwd;
|
|
30758
30795
|
const rawSessionId = frame.session_id;
|
|
30759
30796
|
const sessionId = typeof rawSessionId === "string" && rawSessionId.length > 0 ? rawSessionId : null;
|
|
30760
|
-
|
|
30761
|
-
|
|
30762
|
-
|
|
30763
|
-
|
|
30764
|
-
|
|
30765
|
-
|
|
30797
|
+
try {
|
|
30798
|
+
await this.onConfigureWarnings({
|
|
30799
|
+
projectRoot,
|
|
30800
|
+
sessionId,
|
|
30801
|
+
client: sessionId ? this.configureWarningClients.get(sessionId) : undefined,
|
|
30802
|
+
warnings
|
|
30803
|
+
});
|
|
30804
|
+
} finally {
|
|
30805
|
+
if (sessionId) {
|
|
30806
|
+
this.configureWarningClients.delete(sessionId);
|
|
30807
|
+
}
|
|
30808
|
+
}
|
|
30766
30809
|
}
|
|
30767
30810
|
async shutdown() {
|
|
30768
30811
|
this._shuttingDown = true;
|
|
30769
30812
|
this.clearRestartResetTimer();
|
|
30813
|
+
this.configureWarningClients.clear();
|
|
30770
30814
|
this.rejectAllPending(new Error(`${this.errorPrefix} Bridge shutting down`));
|
|
30771
30815
|
if (this.process) {
|
|
30772
30816
|
const proc = this.process;
|
|
@@ -30790,10 +30834,12 @@ class BinaryBridge {
|
|
|
30790
30834
|
return;
|
|
30791
30835
|
try {
|
|
30792
30836
|
const resp = await this.send("version");
|
|
30837
|
+
if (resp.success === false) {
|
|
30838
|
+
throw new Error(`Binary version check failed: ${String(resp.code ?? "unknown")} — likely too old`);
|
|
30839
|
+
}
|
|
30793
30840
|
const binaryVersion = resp.version;
|
|
30794
|
-
if (
|
|
30795
|
-
|
|
30796
|
-
return;
|
|
30841
|
+
if (typeof binaryVersion !== "string") {
|
|
30842
|
+
throw new Error(`Binary did not report a version — likely too old (minVersion: ${this.minVersion})`);
|
|
30797
30843
|
}
|
|
30798
30844
|
log(`Binary version: ${binaryVersion}`);
|
|
30799
30845
|
if (compareSemver(binaryVersion, this.minVersion) < 0) {
|
|
@@ -30802,6 +30848,7 @@ class BinaryBridge {
|
|
|
30802
30848
|
}
|
|
30803
30849
|
} catch (err) {
|
|
30804
30850
|
warn(`Version check failed: ${err.message}`);
|
|
30851
|
+
throw err;
|
|
30805
30852
|
}
|
|
30806
30853
|
}
|
|
30807
30854
|
ensureSpawned(triggeringSessionId) {
|
|
@@ -30843,19 +30890,23 @@ class BinaryBridge {
|
|
|
30843
30890
|
env
|
|
30844
30891
|
});
|
|
30845
30892
|
const currentChild = child;
|
|
30893
|
+
const stdoutDecoder = new StringDecoder("utf8");
|
|
30846
30894
|
child.stdout?.on("data", (chunk) => {
|
|
30847
|
-
this.onStdoutData(
|
|
30895
|
+
this.onStdoutData(stdoutDecoder.write(chunk));
|
|
30896
|
+
});
|
|
30897
|
+
child.stdout?.on("end", () => {
|
|
30898
|
+
const remaining = stdoutDecoder.end();
|
|
30899
|
+
if (remaining)
|
|
30900
|
+
this.onStdoutData(remaining);
|
|
30848
30901
|
});
|
|
30902
|
+
const stderrDecoder = new StringDecoder("utf8");
|
|
30849
30903
|
child.stderr?.on("data", (chunk) => {
|
|
30850
|
-
|
|
30851
|
-
|
|
30852
|
-
|
|
30853
|
-
|
|
30854
|
-
|
|
30855
|
-
|
|
30856
|
-
log(tagged);
|
|
30857
|
-
this.pushStderrLine(tagged);
|
|
30858
|
-
}
|
|
30904
|
+
this.onStderrData(stderrDecoder.write(chunk));
|
|
30905
|
+
});
|
|
30906
|
+
child.stderr?.on("end", () => {
|
|
30907
|
+
const remaining = stderrDecoder.end();
|
|
30908
|
+
if (remaining)
|
|
30909
|
+
this.onStderrData(remaining);
|
|
30859
30910
|
});
|
|
30860
30911
|
child.on("error", (err) => {
|
|
30861
30912
|
if (this.process !== currentChild)
|
|
@@ -30888,6 +30939,17 @@ class BinaryBridge {
|
|
|
30888
30939
|
this.stderrTail.shift();
|
|
30889
30940
|
}
|
|
30890
30941
|
}
|
|
30942
|
+
onStderrData(data) {
|
|
30943
|
+
const lines = data.trimEnd().split(`
|
|
30944
|
+
`);
|
|
30945
|
+
for (const line of lines) {
|
|
30946
|
+
if (!line)
|
|
30947
|
+
continue;
|
|
30948
|
+
const tagged = tagStderrLine(line);
|
|
30949
|
+
log(tagged);
|
|
30950
|
+
this.pushStderrLine(tagged);
|
|
30951
|
+
}
|
|
30952
|
+
}
|
|
30891
30953
|
formatStderrTail() {
|
|
30892
30954
|
if (this.stderrTail.length === 0)
|
|
30893
30955
|
return "";
|
|
@@ -30967,6 +31029,7 @@ class BinaryBridge {
|
|
|
30967
31029
|
}
|
|
30968
31030
|
}
|
|
30969
31031
|
handleTimeout(triggeringSessionId) {
|
|
31032
|
+
this.rejectAllPending(new Error(`${this.errorPrefix} bridge killed during sibling timeout — request aborted`));
|
|
30970
31033
|
if (this.process) {
|
|
30971
31034
|
this.process.kill("SIGKILL");
|
|
30972
31035
|
this.process = null;
|
|
@@ -31292,23 +31355,23 @@ async function ensureOnnxRuntime(storageDir) {
|
|
|
31292
31355
|
const onnxBaseDir = join3(storageDir, "onnxruntime");
|
|
31293
31356
|
mkdirSync2(onnxBaseDir, { recursive: true });
|
|
31294
31357
|
const lockPath = join3(onnxBaseDir, ONNX_LOCK_FILE);
|
|
31295
|
-
|
|
31358
|
+
cleanupAbandonedStagingDirs(onnxBaseDir);
|
|
31296
31359
|
if (!acquireLock(lockPath)) {
|
|
31297
31360
|
warn(`ONNX Runtime install already in progress in another process (lock: ${lockPath}). Skipping.`);
|
|
31298
31361
|
return null;
|
|
31299
31362
|
}
|
|
31300
31363
|
try {
|
|
31364
|
+
cleanupIncompleteTargetIfUnowned(ortDir);
|
|
31301
31365
|
return await downloadOnnxRuntime(info, ortDir);
|
|
31302
31366
|
} finally {
|
|
31303
31367
|
releaseLock(lockPath);
|
|
31304
31368
|
}
|
|
31305
31369
|
}
|
|
31306
|
-
function
|
|
31370
|
+
function cleanupAbandonedStagingDirs(onnxBaseDir) {
|
|
31307
31371
|
try {
|
|
31308
31372
|
const entries = readdirSync(onnxBaseDir);
|
|
31309
|
-
const ortDirBaseName = ortDir.slice(onnxBaseDir.length + 1);
|
|
31310
31373
|
for (const entry of entries) {
|
|
31311
|
-
if (!entry.startsWith(`${
|
|
31374
|
+
if (!entry.startsWith(`${ORT_VERSION}.tmp.`))
|
|
31312
31375
|
continue;
|
|
31313
31376
|
const stagingDir = join3(onnxBaseDir, entry);
|
|
31314
31377
|
const parts = entry.split(".");
|
|
@@ -31339,6 +31402,8 @@ function cleanupAbandonedOnnxAttempts(onnxBaseDir, ortDir) {
|
|
|
31339
31402
|
}
|
|
31340
31403
|
}
|
|
31341
31404
|
} catch {}
|
|
31405
|
+
}
|
|
31406
|
+
function cleanupIncompleteTargetIfUnowned(ortDir) {
|
|
31342
31407
|
try {
|
|
31343
31408
|
if (existsSync2(ortDir) && !existsSync2(join3(ortDir, ONNX_INSTALLED_META_FILE))) {
|
|
31344
31409
|
log(`[onnx] removing half-populated install dir ${ortDir} (no meta file)`);
|
|
@@ -31529,25 +31594,7 @@ async function downloadOnnxRuntime(info, targetDir) {
|
|
|
31529
31594
|
realFiles.push(libFile);
|
|
31530
31595
|
}
|
|
31531
31596
|
}
|
|
31532
|
-
|
|
31533
|
-
const src = join3(extractedDir, libFile);
|
|
31534
|
-
const dst = join3(targetDir, libFile);
|
|
31535
|
-
try {
|
|
31536
|
-
copyFileSync(src, dst);
|
|
31537
|
-
if (process.platform !== "win32") {
|
|
31538
|
-
chmodSync2(dst, 493);
|
|
31539
|
-
}
|
|
31540
|
-
} catch (copyErr) {
|
|
31541
|
-
log(`ORT extract: failed to copy ${libFile}: ${copyErr}`);
|
|
31542
|
-
}
|
|
31543
|
-
}
|
|
31544
|
-
for (const link of symlinks) {
|
|
31545
|
-
const dst = join3(targetDir, link.name);
|
|
31546
|
-
try {
|
|
31547
|
-
unlinkSync2(dst);
|
|
31548
|
-
} catch {}
|
|
31549
|
-
symlinkSync(link.target, dst);
|
|
31550
|
-
}
|
|
31597
|
+
copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks);
|
|
31551
31598
|
const libPath = join3(targetDir, info.libName);
|
|
31552
31599
|
let libHash = null;
|
|
31553
31600
|
try {
|
|
@@ -31570,6 +31617,45 @@ async function downloadOnnxRuntime(info, targetDir) {
|
|
|
31570
31617
|
return null;
|
|
31571
31618
|
}
|
|
31572
31619
|
}
|
|
31620
|
+
function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, copyFile = copyFileSync) {
|
|
31621
|
+
const requiredLibs = new Set([info.libName]);
|
|
31622
|
+
for (const libFile of realFiles) {
|
|
31623
|
+
const src = join3(extractedDir, libFile);
|
|
31624
|
+
const dst = join3(targetDir, libFile);
|
|
31625
|
+
try {
|
|
31626
|
+
copyFile(src, dst);
|
|
31627
|
+
if (process.platform !== "win32") {
|
|
31628
|
+
chmodSync2(dst, 493);
|
|
31629
|
+
}
|
|
31630
|
+
} catch (copyErr) {
|
|
31631
|
+
if (requiredLibs.has(libFile)) {
|
|
31632
|
+
rmSync(targetDir, { recursive: true, force: true });
|
|
31633
|
+
throw copyErr;
|
|
31634
|
+
}
|
|
31635
|
+
log(`ORT extract: failed to copy optional ${libFile}: ${copyErr}`);
|
|
31636
|
+
}
|
|
31637
|
+
}
|
|
31638
|
+
for (const link of symlinks) {
|
|
31639
|
+
const dst = join3(targetDir, link.name);
|
|
31640
|
+
try {
|
|
31641
|
+
unlinkSync2(dst);
|
|
31642
|
+
} catch {}
|
|
31643
|
+
try {
|
|
31644
|
+
symlinkSync(link.target, dst);
|
|
31645
|
+
} catch (symlinkErr) {
|
|
31646
|
+
if (requiredLibs.has(link.name)) {
|
|
31647
|
+
rmSync(targetDir, { recursive: true, force: true });
|
|
31648
|
+
throw symlinkErr;
|
|
31649
|
+
}
|
|
31650
|
+
log(`ORT extract: failed to symlink optional ${link.name}: ${symlinkErr}`);
|
|
31651
|
+
}
|
|
31652
|
+
}
|
|
31653
|
+
const requiredPath = join3(targetDir, info.libName);
|
|
31654
|
+
if (!existsSync2(requiredPath)) {
|
|
31655
|
+
rmSync(targetDir, { recursive: true, force: true });
|
|
31656
|
+
throw new Error(`Required ONNX Runtime library missing after install: ${requiredPath}`);
|
|
31657
|
+
}
|
|
31658
|
+
}
|
|
31573
31659
|
async function extractZipArchive(archivePath, destinationDir) {
|
|
31574
31660
|
if (process.platform === "win32") {
|
|
31575
31661
|
execFileSync("tar.exe", ["-xf", archivePath, "-C", destinationDir], {
|
|
@@ -31753,11 +31839,13 @@ class BridgePool {
|
|
|
31753
31839
|
idleTimeoutMs;
|
|
31754
31840
|
bridgeOptions;
|
|
31755
31841
|
configOverrides;
|
|
31842
|
+
logger;
|
|
31756
31843
|
cleanupTimer = null;
|
|
31757
31844
|
constructor(binaryPath, options = {}, configOverrides = {}) {
|
|
31758
31845
|
this.binaryPath = binaryPath;
|
|
31759
31846
|
this.maxPoolSize = options.maxPoolSize ?? DEFAULT_MAX_POOL_SIZE;
|
|
31760
31847
|
this.idleTimeoutMs = options.idleTimeoutMs ?? DEFAULT_IDLE_TIMEOUT_MS;
|
|
31848
|
+
this.logger = options.logger;
|
|
31761
31849
|
this.bridgeOptions = {
|
|
31762
31850
|
timeoutMs: options.timeoutMs,
|
|
31763
31851
|
maxRestarts: options.maxRestarts,
|
|
@@ -31801,8 +31889,10 @@ class BridgePool {
|
|
|
31801
31889
|
cleanup() {
|
|
31802
31890
|
const now = Date.now();
|
|
31803
31891
|
for (const [dir, entry] of this.bridges) {
|
|
31892
|
+
if (entry.bridge.hasPendingRequests())
|
|
31893
|
+
continue;
|
|
31804
31894
|
if (now - entry.lastUsed > this.idleTimeoutMs) {
|
|
31805
|
-
entry.bridge.shutdown().catch((err) => error("cleanup shutdown failed:", err));
|
|
31895
|
+
entry.bridge.shutdown().catch((err) => this.error("cleanup shutdown failed:", err));
|
|
31806
31896
|
this.bridges.delete(dir);
|
|
31807
31897
|
}
|
|
31808
31898
|
}
|
|
@@ -31811,6 +31901,8 @@ class BridgePool {
|
|
|
31811
31901
|
let oldestDir = null;
|
|
31812
31902
|
let oldestTime = Infinity;
|
|
31813
31903
|
for (const [dir, entry] of this.bridges) {
|
|
31904
|
+
if (entry.bridge.hasPendingRequests())
|
|
31905
|
+
continue;
|
|
31814
31906
|
if (entry.lastUsed < oldestTime) {
|
|
31815
31907
|
oldestTime = entry.lastUsed;
|
|
31816
31908
|
oldestDir = dir;
|
|
@@ -31818,7 +31910,7 @@ class BridgePool {
|
|
|
31818
31910
|
}
|
|
31819
31911
|
if (oldestDir) {
|
|
31820
31912
|
const entry = this.bridges.get(oldestDir);
|
|
31821
|
-
entry?.bridge.shutdown().catch((err) => error("eviction shutdown failed:", err));
|
|
31913
|
+
entry?.bridge.shutdown().catch((err) => this.error("eviction shutdown failed:", err));
|
|
31822
31914
|
this.bridges.delete(oldestDir);
|
|
31823
31915
|
}
|
|
31824
31916
|
}
|
|
@@ -31836,7 +31928,21 @@ class BridgePool {
|
|
|
31836
31928
|
const shutdowns = Array.from(this.bridges.values()).map((entry) => entry.bridge.shutdown());
|
|
31837
31929
|
this.bridges.clear();
|
|
31838
31930
|
await Promise.allSettled(shutdowns);
|
|
31839
|
-
log(`Binary path updated to ${newPath}. All bridges cleared — next calls will use the new binary.`);
|
|
31931
|
+
this.log(`Binary path updated to ${newPath}. All bridges cleared — next calls will use the new binary.`);
|
|
31932
|
+
}
|
|
31933
|
+
log(message, meta) {
|
|
31934
|
+
const logger = this.logger ?? getActiveLogger();
|
|
31935
|
+
if (logger)
|
|
31936
|
+
logger.log(message, meta);
|
|
31937
|
+
else
|
|
31938
|
+
log(message, meta);
|
|
31939
|
+
}
|
|
31940
|
+
error(message, meta) {
|
|
31941
|
+
const logger = this.logger ?? getActiveLogger();
|
|
31942
|
+
if (logger)
|
|
31943
|
+
logger.error(message, meta);
|
|
31944
|
+
else
|
|
31945
|
+
error(message, meta);
|
|
31840
31946
|
}
|
|
31841
31947
|
setConfigureOverride(key, value) {
|
|
31842
31948
|
if (value === undefined) {
|
|
@@ -31956,7 +32062,7 @@ async function findBinary(expectedVersion) {
|
|
|
31956
32062
|
return syncResult;
|
|
31957
32063
|
}
|
|
31958
32064
|
log("Binary not found locally, attempting auto-download...");
|
|
31959
|
-
const downloaded = await ensureBinary();
|
|
32065
|
+
const downloaded = await ensureBinary(expectedVersion);
|
|
31960
32066
|
if (downloaded)
|
|
31961
32067
|
return downloaded;
|
|
31962
32068
|
throw new Error([
|
|
@@ -32630,8 +32736,6 @@ async function handleTurnEndBgCompletions(drainContext) {
|
|
|
32630
32736
|
}
|
|
32631
32737
|
async function triggerWakeIfPending(drainContext, skipDrain) {
|
|
32632
32738
|
const state = stateFor(drainContext.sessionID);
|
|
32633
|
-
if (state.wakeFiredThisIdle)
|
|
32634
|
-
return;
|
|
32635
32739
|
if (drainContext.isActive?.())
|
|
32636
32740
|
return;
|
|
32637
32741
|
if (!skipDrain && state.outstandingTaskIds.size > 0) {
|
|
@@ -32645,9 +32749,6 @@ async function triggerWakeIfPending(drainContext, skipDrain) {
|
|
|
32645
32749
|
sessionWarn2(drainContext.sessionID ?? "", `${LOG_PREFIX} wake send failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
32646
32750
|
});
|
|
32647
32751
|
}
|
|
32648
|
-
function resetBgWake(sessionID) {
|
|
32649
|
-
stateFor(sessionID).wakeFiredThisIdle = false;
|
|
32650
|
-
}
|
|
32651
32752
|
function formatSystemReminder(completions) {
|
|
32652
32753
|
const bullets = completions.map((completion) => formatCompletion(completion)).join(`
|
|
32653
32754
|
`);
|
|
@@ -32723,7 +32824,6 @@ function scheduleWake(state, sendWake, onSendFailure) {
|
|
|
32723
32824
|
state.pendingLongRunning = [];
|
|
32724
32825
|
sendWake(reminder).then(() => {
|
|
32725
32826
|
state.retryDelayMs = null;
|
|
32726
|
-
state.wakeFiredThisIdle = true;
|
|
32727
32827
|
}).catch((err) => {
|
|
32728
32828
|
state.pendingCompletions = [...pending, ...state.pendingCompletions];
|
|
32729
32829
|
state.pendingLongRunning = [...pendingLongRunning, ...state.pendingLongRunning];
|
|
@@ -32745,7 +32845,6 @@ function stateFor(sessionID) {
|
|
|
32745
32845
|
pendingCompletions: [],
|
|
32746
32846
|
pendingLongRunning: [],
|
|
32747
32847
|
debounceTimer: null,
|
|
32748
|
-
wakeFiredThisIdle: false,
|
|
32749
32848
|
firstCompletionAt: null,
|
|
32750
32849
|
scheduledFireAt: null,
|
|
32751
32850
|
scheduledCompletionCount: 0,
|
|
@@ -43998,7 +44097,7 @@ function finalize(ctx, schema) {
|
|
|
43998
44097
|
result.$schema = "http://json-schema.org/draft-07/schema#";
|
|
43999
44098
|
} else if (ctx.target === "draft-04") {
|
|
44000
44099
|
result.$schema = "http://json-schema.org/draft-04/schema#";
|
|
44001
|
-
} else if (ctx.target === "openapi-3.0") {}
|
|
44100
|
+
} else if (ctx.target === "openapi-3.0") {}
|
|
44002
44101
|
if (ctx.external?.uri) {
|
|
44003
44102
|
const id = ctx.external.registry.get(schema)?.id;
|
|
44004
44103
|
if (!id)
|
|
@@ -44246,7 +44345,7 @@ var literalProcessor = (schema, ctx, json, _params) => {
|
|
|
44246
44345
|
if (val === undefined) {
|
|
44247
44346
|
if (ctx.unrepresentable === "throw") {
|
|
44248
44347
|
throw new Error("Literal `undefined` cannot be represented in JSON Schema");
|
|
44249
|
-
}
|
|
44348
|
+
}
|
|
44250
44349
|
} else if (typeof val === "bigint") {
|
|
44251
44350
|
if (ctx.unrepresentable === "throw") {
|
|
44252
44351
|
throw new Error("BigInt literals cannot be represented in JSON Schema");
|
|
@@ -47046,7 +47145,8 @@ function loadAftConfig(projectDirectory) {
|
|
|
47046
47145
|
// src/lsp-auto-install.ts
|
|
47047
47146
|
import { spawn as spawn2 } from "node:child_process";
|
|
47048
47147
|
import { createHash as createHash3 } from "node:crypto";
|
|
47049
|
-
import { createReadStream, statSync as statSync3 } from "node:fs";
|
|
47148
|
+
import { createReadStream, mkdirSync as mkdirSync6, readFileSync as readFileSync5, renameSync as renameSync3, rmSync as rmSync2, statSync as statSync3 } from "node:fs";
|
|
47149
|
+
import { join as join10 } from "node:path";
|
|
47050
47150
|
|
|
47051
47151
|
// src/lsp-cache.ts
|
|
47052
47152
|
import {
|
|
@@ -47730,6 +47830,50 @@ function hashInstalledBinary(spec) {
|
|
|
47730
47830
|
stream.on("end", () => resolve2(hash2.digest("hex")));
|
|
47731
47831
|
});
|
|
47732
47832
|
}
|
|
47833
|
+
function installedBinaryPath(spec) {
|
|
47834
|
+
const candidates = process.platform === "win32" ? [
|
|
47835
|
+
lspBinaryPath(spec.npm, spec.binary),
|
|
47836
|
+
lspBinaryPath(spec.npm, `${spec.binary}.cmd`),
|
|
47837
|
+
lspBinaryPath(spec.npm, `${spec.binary}.exe`),
|
|
47838
|
+
lspBinaryPath(spec.npm, `${spec.binary}.bat`)
|
|
47839
|
+
] : [lspBinaryPath(spec.npm, spec.binary)];
|
|
47840
|
+
for (const candidate of candidates) {
|
|
47841
|
+
try {
|
|
47842
|
+
if (statSync3(candidate).isFile())
|
|
47843
|
+
return candidate;
|
|
47844
|
+
} catch {}
|
|
47845
|
+
}
|
|
47846
|
+
return null;
|
|
47847
|
+
}
|
|
47848
|
+
function sha256OfFileSync(path2) {
|
|
47849
|
+
return createHash3("sha256").update(readFileSync5(path2)).digest("hex");
|
|
47850
|
+
}
|
|
47851
|
+
function quarantineCachedNpmInstall(spec, reason) {
|
|
47852
|
+
const packageDir = lspPackageDir(spec.npm);
|
|
47853
|
+
const dest = join10(packageDir, "..", ".quarantine", encodeURIComponent(spec.npm), `${Date.now()}`);
|
|
47854
|
+
warn2(`[lsp] tofu_mismatch ${spec.npm}: ${reason}; quarantining ${packageDir} -> ${dest}`);
|
|
47855
|
+
try {
|
|
47856
|
+
mkdirSync6(join10(dest, ".."), { recursive: true });
|
|
47857
|
+
rmSync2(dest, { recursive: true, force: true });
|
|
47858
|
+
renameSync3(packageDir, dest);
|
|
47859
|
+
} catch (err) {
|
|
47860
|
+
warn2(`[lsp] tofu_mismatch ${spec.npm}: failed to quarantine cache entry: ${err}`);
|
|
47861
|
+
}
|
|
47862
|
+
}
|
|
47863
|
+
function validateCachedNpmInstall(spec) {
|
|
47864
|
+
const meta3 = readInstalledMeta(spec.npm);
|
|
47865
|
+
const binaryPath = installedBinaryPath(spec);
|
|
47866
|
+
if (!meta3?.sha256 || !meta3.version || !isSafeVersion(meta3.version) || !binaryPath) {
|
|
47867
|
+
quarantineCachedNpmInstall(spec, "missing/unsafe metadata or binary");
|
|
47868
|
+
return false;
|
|
47869
|
+
}
|
|
47870
|
+
const currentHash = sha256OfFileSync(binaryPath);
|
|
47871
|
+
if (currentHash !== meta3.sha256) {
|
|
47872
|
+
quarantineCachedNpmInstall(spec, `recorded ${meta3.sha256}, current ${currentHash}`);
|
|
47873
|
+
return false;
|
|
47874
|
+
}
|
|
47875
|
+
return true;
|
|
47876
|
+
}
|
|
47733
47877
|
function runAutoInstall(projectRoot, config2, fetchImpl2 = fetch) {
|
|
47734
47878
|
const cachedBinDirs = [];
|
|
47735
47879
|
const skipped = [];
|
|
@@ -47742,7 +47886,7 @@ function runAutoInstall(projectRoot, config2, fetchImpl2 = fetch) {
|
|
|
47742
47886
|
return projectExtensions;
|
|
47743
47887
|
};
|
|
47744
47888
|
for (const spec of NPM_LSP_TABLE) {
|
|
47745
|
-
if (isInstalled(spec.npm, spec.binary)) {
|
|
47889
|
+
if (isInstalled(spec.npm, spec.binary) && validateCachedNpmInstall(spec)) {
|
|
47746
47890
|
cachedBinDirs.push(lspBinDir(spec.npm));
|
|
47747
47891
|
}
|
|
47748
47892
|
if (config2.disabled.has(spec.id)) {
|
|
@@ -47794,16 +47938,17 @@ import {
|
|
|
47794
47938
|
createWriteStream as createWriteStream2,
|
|
47795
47939
|
existsSync as existsSync7,
|
|
47796
47940
|
lstatSync as lstatSync2,
|
|
47797
|
-
mkdirSync as
|
|
47941
|
+
mkdirSync as mkdirSync7,
|
|
47798
47942
|
readdirSync as readdirSync4,
|
|
47943
|
+
readFileSync as readFileSync6,
|
|
47799
47944
|
readlinkSync as readlinkSync2,
|
|
47800
47945
|
realpathSync as realpathSync3,
|
|
47801
|
-
renameSync as
|
|
47802
|
-
rmSync as
|
|
47946
|
+
renameSync as renameSync4,
|
|
47947
|
+
rmSync as rmSync3,
|
|
47803
47948
|
statSync as statSync4,
|
|
47804
47949
|
unlinkSync as unlinkSync6
|
|
47805
47950
|
} from "node:fs";
|
|
47806
|
-
import { dirname as dirname2, join as
|
|
47951
|
+
import { dirname as dirname2, join as join11, relative as relative2, resolve as resolve2 } from "node:path";
|
|
47807
47952
|
import { Readable as Readable2 } from "node:stream";
|
|
47808
47953
|
import { pipeline as pipeline2 } from "node:stream/promises";
|
|
47809
47954
|
|
|
@@ -47893,25 +48038,25 @@ function detectHostPlatform() {
|
|
|
47893
48038
|
|
|
47894
48039
|
// src/lsp-github-install.ts
|
|
47895
48040
|
function ghCacheRoot() {
|
|
47896
|
-
return
|
|
48041
|
+
return join11(aftCacheBase(), "lsp-binaries");
|
|
47897
48042
|
}
|
|
47898
48043
|
function ghPackageDir(spec) {
|
|
47899
|
-
return
|
|
48044
|
+
return join11(ghCacheRoot(), spec.id);
|
|
47900
48045
|
}
|
|
47901
48046
|
function ghBinDir(spec) {
|
|
47902
|
-
return
|
|
48047
|
+
return join11(ghPackageDir(spec), "bin");
|
|
47903
48048
|
}
|
|
47904
48049
|
function ghExtractDir(spec) {
|
|
47905
|
-
return
|
|
48050
|
+
return join11(ghPackageDir(spec), "extracted");
|
|
47906
48051
|
}
|
|
47907
48052
|
function ghBinaryPath(spec, platform) {
|
|
47908
48053
|
const ext = platform === "win32" ? ".exe" : "";
|
|
47909
|
-
return
|
|
48054
|
+
return join11(ghBinDir(spec), `${spec.binary}${ext}`);
|
|
47910
48055
|
}
|
|
47911
48056
|
function isGithubInstalled(spec, platform) {
|
|
47912
48057
|
for (const candidate of ghBinaryCandidates(spec, platform)) {
|
|
47913
48058
|
try {
|
|
47914
|
-
if (statSync4(
|
|
48059
|
+
if (statSync4(join11(ghBinDir(spec), candidate)).isFile())
|
|
47915
48060
|
return true;
|
|
47916
48061
|
} catch {}
|
|
47917
48062
|
}
|
|
@@ -47933,6 +48078,9 @@ function sha256OfFile(path2) {
|
|
|
47933
48078
|
stream.on("end", () => resolve3(hash2.digest("hex")));
|
|
47934
48079
|
});
|
|
47935
48080
|
}
|
|
48081
|
+
function sha256OfFileSync2(path2) {
|
|
48082
|
+
return createHash4("sha256").update(readFileSync6(path2)).digest("hex");
|
|
48083
|
+
}
|
|
47936
48084
|
async function fetchReleaseByTag(githubRepo, tag, fetchImpl2, signal) {
|
|
47937
48085
|
const candidates = [];
|
|
47938
48086
|
candidates.push(tag);
|
|
@@ -47953,11 +48101,7 @@ async function fetchReleaseByTag(githubRepo, tag, fetchImpl2, signal) {
|
|
|
47953
48101
|
const url2 = `https://api.github.com/repos/${githubRepo}/releases/tags/${encodeURIComponent(candidate)}`;
|
|
47954
48102
|
const timeout = controlledTimeoutSignal(15000, signal);
|
|
47955
48103
|
try {
|
|
47956
|
-
const res = await
|
|
47957
|
-
headers,
|
|
47958
|
-
redirect: "follow",
|
|
47959
|
-
signal: timeout.signal
|
|
47960
|
-
});
|
|
48104
|
+
const res = await fetchJsonFollowingRedirects(url2, headers, fetchImpl2, timeout.signal);
|
|
47961
48105
|
if (res.status === 404)
|
|
47962
48106
|
continue;
|
|
47963
48107
|
if (!res.ok) {
|
|
@@ -47987,6 +48131,23 @@ async function fetchReleaseByTag(githubRepo, tag, fetchImpl2, signal) {
|
|
|
47987
48131
|
}
|
|
47988
48132
|
return null;
|
|
47989
48133
|
}
|
|
48134
|
+
async function fetchJsonFollowingRedirects(url2, headers, fetchImpl2, signal) {
|
|
48135
|
+
const maxRedirects = 5;
|
|
48136
|
+
let currentUrl = url2;
|
|
48137
|
+
for (let i = 0;i <= maxRedirects; i += 1) {
|
|
48138
|
+
assertAllowedDownloadUrl(currentUrl);
|
|
48139
|
+
const res = await fetchImpl2(currentUrl, { headers, redirect: "manual", signal });
|
|
48140
|
+
if (res.status >= 300 && res.status < 400) {
|
|
48141
|
+
const location = res.headers.get("location");
|
|
48142
|
+
if (!location)
|
|
48143
|
+
throw new Error(`redirect status ${res.status} without Location`);
|
|
48144
|
+
currentUrl = new URL(location, currentUrl).toString();
|
|
48145
|
+
continue;
|
|
48146
|
+
}
|
|
48147
|
+
return res;
|
|
48148
|
+
}
|
|
48149
|
+
throw new Error(`too many redirects (>${maxRedirects})`);
|
|
48150
|
+
}
|
|
47990
48151
|
async function resolveTargetTag(spec, config2, fetchImpl2, signal) {
|
|
47991
48152
|
const pinned = config2.versions[spec.githubRepo];
|
|
47992
48153
|
if (pinned) {
|
|
@@ -48081,17 +48242,12 @@ function assertAllowedDownloadUrl(rawUrl) {
|
|
|
48081
48242
|
return parsed;
|
|
48082
48243
|
}
|
|
48083
48244
|
async function downloadFile(url2, destPath, fetchImpl2, assetSize, signal) {
|
|
48084
|
-
assertAllowedDownloadUrl(url2);
|
|
48085
48245
|
if (assetSize !== undefined && assetSize > MAX_DOWNLOAD_BYTES2) {
|
|
48086
48246
|
throw new Error(`asset size ${assetSize} exceeds max ${MAX_DOWNLOAD_BYTES2} (set lsp.versions to pin a smaller release if this is wrong)`);
|
|
48087
48247
|
}
|
|
48088
48248
|
const timeout = controlledTimeoutSignal(120000, signal);
|
|
48089
48249
|
try {
|
|
48090
|
-
const res = await
|
|
48091
|
-
headers: { accept: "application/octet-stream" },
|
|
48092
|
-
redirect: "follow",
|
|
48093
|
-
signal: timeout.signal
|
|
48094
|
-
});
|
|
48250
|
+
const res = await fetchFollowingRedirects(url2, fetchImpl2, timeout.signal);
|
|
48095
48251
|
if (!res.ok || !res.body) {
|
|
48096
48252
|
throw new Error(`download failed (${res.status})`);
|
|
48097
48253
|
}
|
|
@@ -48099,7 +48255,7 @@ async function downloadFile(url2, destPath, fetchImpl2, assetSize, signal) {
|
|
|
48099
48255
|
if (Number.isFinite(advertised) && advertised > MAX_DOWNLOAD_BYTES2) {
|
|
48100
48256
|
throw new Error(`Content-Length ${advertised} exceeds max ${MAX_DOWNLOAD_BYTES2}`);
|
|
48101
48257
|
}
|
|
48102
|
-
|
|
48258
|
+
mkdirSync7(dirname2(destPath), { recursive: true });
|
|
48103
48259
|
let bytesWritten = 0;
|
|
48104
48260
|
const guard = new TransformStream({
|
|
48105
48261
|
transform(chunk, controller) {
|
|
@@ -48123,6 +48279,27 @@ async function downloadFile(url2, destPath, fetchImpl2, assetSize, signal) {
|
|
|
48123
48279
|
timeout.cleanup();
|
|
48124
48280
|
}
|
|
48125
48281
|
}
|
|
48282
|
+
async function fetchFollowingRedirects(url2, fetchImpl2, signal) {
|
|
48283
|
+
const maxRedirects = 5;
|
|
48284
|
+
let currentUrl = url2;
|
|
48285
|
+
for (let i = 0;i <= maxRedirects; i += 1) {
|
|
48286
|
+
assertAllowedDownloadUrl(currentUrl);
|
|
48287
|
+
const res = await fetchImpl2(currentUrl, {
|
|
48288
|
+
headers: { accept: "application/octet-stream" },
|
|
48289
|
+
redirect: "manual",
|
|
48290
|
+
signal
|
|
48291
|
+
});
|
|
48292
|
+
if (res.status >= 300 && res.status < 400) {
|
|
48293
|
+
const location = res.headers.get("location");
|
|
48294
|
+
if (!location)
|
|
48295
|
+
throw new Error(`redirect status ${res.status} without Location`);
|
|
48296
|
+
currentUrl = new URL(location, currentUrl).toString();
|
|
48297
|
+
continue;
|
|
48298
|
+
}
|
|
48299
|
+
return res;
|
|
48300
|
+
}
|
|
48301
|
+
throw new Error(`too many redirects (>${maxRedirects})`);
|
|
48302
|
+
}
|
|
48126
48303
|
function validateExtraction(stagingRoot) {
|
|
48127
48304
|
const realStagingRoot = realpathSync3(stagingRoot);
|
|
48128
48305
|
let totalBytes = 0;
|
|
@@ -48134,7 +48311,7 @@ function validateExtraction(stagingRoot) {
|
|
|
48134
48311
|
throw new Error(`failed to read staging dir ${dir}: ${err}`);
|
|
48135
48312
|
}
|
|
48136
48313
|
for (const entry of entries) {
|
|
48137
|
-
const full =
|
|
48314
|
+
const full = join11(dir, entry);
|
|
48138
48315
|
let lst;
|
|
48139
48316
|
try {
|
|
48140
48317
|
lst = lstatSync2(full);
|
|
@@ -48172,27 +48349,83 @@ function validateExtraction(stagingRoot) {
|
|
|
48172
48349
|
};
|
|
48173
48350
|
walk(realStagingRoot);
|
|
48174
48351
|
}
|
|
48352
|
+
function precheckArchiveSize(archivePath, archiveType) {
|
|
48353
|
+
let totalBytes = 0;
|
|
48354
|
+
if (archiveType === "zip") {
|
|
48355
|
+
const out = execFileSync2("unzip", ["-l", archivePath], { encoding: "utf8" });
|
|
48356
|
+
const match = out.match(/^\s*(\d+)\s+\d+\s+files?\s*$/m);
|
|
48357
|
+
if (match)
|
|
48358
|
+
totalBytes = Number.parseInt(match[1] ?? "0", 10);
|
|
48359
|
+
} else {
|
|
48360
|
+
const out = execFileSync2("tar", ["-tvf", archivePath], { encoding: "utf8" });
|
|
48361
|
+
for (const line of out.split(`
|
|
48362
|
+
`)) {
|
|
48363
|
+
const parts = line.trim().split(/\s+/);
|
|
48364
|
+
if (parts.length >= 6) {
|
|
48365
|
+
const numeric = parts.map((part) => Number.parseInt(part, 10)).filter((value) => Number.isFinite(value) && value >= 0);
|
|
48366
|
+
if (numeric.length > 0)
|
|
48367
|
+
totalBytes += Math.max(...numeric);
|
|
48368
|
+
}
|
|
48369
|
+
}
|
|
48370
|
+
}
|
|
48371
|
+
if (totalBytes > MAX_EXTRACT_BYTES2) {
|
|
48372
|
+
throw new Error(`archive uncompressed size ${totalBytes} exceeds ${MAX_EXTRACT_BYTES2}`);
|
|
48373
|
+
}
|
|
48374
|
+
}
|
|
48175
48375
|
function extractArchiveSafely(archivePath, destDir, archiveType) {
|
|
48176
48376
|
const suffix = randomBytes(8).toString("hex");
|
|
48177
48377
|
const stagingDir = `${destDir}.staging-${suffix}`;
|
|
48178
48378
|
try {
|
|
48179
|
-
|
|
48379
|
+
rmSync3(stagingDir, { recursive: true, force: true });
|
|
48180
48380
|
} catch {}
|
|
48181
|
-
|
|
48381
|
+
mkdirSync7(stagingDir, { recursive: true });
|
|
48182
48382
|
try {
|
|
48383
|
+
precheckArchiveSize(archivePath, archiveType);
|
|
48183
48384
|
runPlatformExtractor(archivePath, stagingDir, archiveType);
|
|
48184
48385
|
validateExtraction(stagingDir);
|
|
48185
48386
|
try {
|
|
48186
|
-
|
|
48387
|
+
rmSync3(destDir, { recursive: true, force: true });
|
|
48187
48388
|
} catch {}
|
|
48188
|
-
|
|
48389
|
+
renameSync4(stagingDir, destDir);
|
|
48189
48390
|
} catch (err) {
|
|
48190
48391
|
try {
|
|
48191
|
-
|
|
48392
|
+
rmSync3(stagingDir, { recursive: true, force: true });
|
|
48192
48393
|
} catch {}
|
|
48193
48394
|
throw err;
|
|
48194
48395
|
}
|
|
48195
48396
|
}
|
|
48397
|
+
function quarantineCachedGithubInstall(spec, reason) {
|
|
48398
|
+
const packageDir = ghPackageDir(spec);
|
|
48399
|
+
const dest = join11(ghCacheRoot(), ".quarantine", encodeURIComponent(spec.id), `${Date.now()}`);
|
|
48400
|
+
warn2(`[lsp] tofu_mismatch ${spec.id}: ${reason}; quarantining ${packageDir} -> ${dest}`);
|
|
48401
|
+
try {
|
|
48402
|
+
mkdirSync7(dirname2(dest), { recursive: true });
|
|
48403
|
+
rmSync3(dest, { recursive: true, force: true });
|
|
48404
|
+
renameSync4(packageDir, dest);
|
|
48405
|
+
} catch (err) {
|
|
48406
|
+
warn2(`[lsp] tofu_mismatch ${spec.id}: failed to quarantine cache entry: ${err}`);
|
|
48407
|
+
}
|
|
48408
|
+
}
|
|
48409
|
+
function validateCachedGithubInstall(spec, platform) {
|
|
48410
|
+
const meta3 = readInstalledMetaIn(ghPackageDir(spec));
|
|
48411
|
+
const binaryPath = ghBinaryCandidates(spec, platform).map((candidate) => join11(ghBinDir(spec), candidate)).find((candidate) => {
|
|
48412
|
+
try {
|
|
48413
|
+
return statSync4(candidate).isFile();
|
|
48414
|
+
} catch {
|
|
48415
|
+
return false;
|
|
48416
|
+
}
|
|
48417
|
+
});
|
|
48418
|
+
if (!meta3?.sha256 || !meta3.version || !isSafeVersion(meta3.version) || !binaryPath) {
|
|
48419
|
+
quarantineCachedGithubInstall(spec, "missing/unsafe metadata or binary");
|
|
48420
|
+
return false;
|
|
48421
|
+
}
|
|
48422
|
+
const currentHash = sha256OfFileSync2(binaryPath);
|
|
48423
|
+
if (currentHash !== meta3.sha256) {
|
|
48424
|
+
quarantineCachedGithubInstall(spec, `recorded ${meta3.sha256}, current ${currentHash}`);
|
|
48425
|
+
return false;
|
|
48426
|
+
}
|
|
48427
|
+
return true;
|
|
48428
|
+
}
|
|
48196
48429
|
function runPlatformExtractor(archivePath, destDir, archiveType) {
|
|
48197
48430
|
if (archiveType === "zip") {
|
|
48198
48431
|
if (process.platform === "win32") {
|
|
@@ -48238,7 +48471,7 @@ async function downloadAndInstall(spec, tag, assets, platform, arch, fetchImpl2,
|
|
|
48238
48471
|
}
|
|
48239
48472
|
const pkgDir = ghPackageDir(spec);
|
|
48240
48473
|
const extractDir = ghExtractDir(spec);
|
|
48241
|
-
const archivePath =
|
|
48474
|
+
const archivePath = join11(pkgDir, expected.name);
|
|
48242
48475
|
log2(`[lsp] downloading ${spec.id} ${tag} → ${matchingAsset.url}`);
|
|
48243
48476
|
try {
|
|
48244
48477
|
await downloadFile(matchingAsset.url, archivePath, fetchImpl2, matchingAsset.size, signal);
|
|
@@ -48277,13 +48510,13 @@ async function downloadAndInstall(spec, tag, assets, platform, arch, fetchImpl2,
|
|
|
48277
48510
|
unlinkSync6(archivePath);
|
|
48278
48511
|
} catch {}
|
|
48279
48512
|
}
|
|
48280
|
-
const innerBinaryPath =
|
|
48513
|
+
const innerBinaryPath = join11(extractDir, spec.binaryPathInArchive(platform, arch, version2));
|
|
48281
48514
|
if (!existsSync7(innerBinaryPath)) {
|
|
48282
48515
|
error2(`[lsp] ${spec.id}: extracted binary not found at ${innerBinaryPath}`);
|
|
48283
48516
|
return null;
|
|
48284
48517
|
}
|
|
48285
48518
|
const targetBinary = ghBinaryPath(spec, platform);
|
|
48286
|
-
|
|
48519
|
+
mkdirSync7(dirname2(targetBinary), { recursive: true });
|
|
48287
48520
|
try {
|
|
48288
48521
|
copyFileSync3(innerBinaryPath, targetBinary);
|
|
48289
48522
|
if (platform !== "win32") {
|
|
@@ -48374,7 +48607,7 @@ function runGithubAutoInstall(relevantServers, config2, fetchImpl2 = fetch) {
|
|
|
48374
48607
|
};
|
|
48375
48608
|
}
|
|
48376
48609
|
for (const spec of GITHUB_LSP_TABLE) {
|
|
48377
|
-
if (isGithubInstalled(spec, host.platform)) {
|
|
48610
|
+
if (isGithubInstalled(spec, host.platform) && validateCachedGithubInstall(spec, host.platform)) {
|
|
48378
48611
|
cachedBinDirs.push(ghBinDir(spec));
|
|
48379
48612
|
}
|
|
48380
48613
|
if (config2.disabled.has(spec.id)) {
|
|
@@ -48458,8 +48691,8 @@ function discoverRelevantGithubServers(projectRoot) {
|
|
|
48458
48691
|
}
|
|
48459
48692
|
|
|
48460
48693
|
// src/notifications.ts
|
|
48461
|
-
import { existsSync as existsSync8, mkdirSync as
|
|
48462
|
-
import { join as
|
|
48694
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync8, readFileSync as readFileSync7, renameSync as renameSync5, rmSync as rmSync4, writeFileSync as writeFileSync5 } from "node:fs";
|
|
48695
|
+
import { join as join12 } from "node:path";
|
|
48463
48696
|
var WARNING_MARKER = "\uD83D\uDD27 AFT: ⚠️";
|
|
48464
48697
|
var FEATURE_MARKER = "\uD83D\uDD27 AFT: ✨";
|
|
48465
48698
|
var WARNED_TOOLS_FILE = "warned_tools.json";
|
|
@@ -48477,10 +48710,10 @@ function sendIgnoredMessage(client, sessionId, text) {
|
|
|
48477
48710
|
}
|
|
48478
48711
|
function readWarnedTools(storageDir) {
|
|
48479
48712
|
try {
|
|
48480
|
-
const warnedToolsPath =
|
|
48713
|
+
const warnedToolsPath = join12(storageDir, WARNED_TOOLS_FILE);
|
|
48481
48714
|
if (!existsSync8(warnedToolsPath))
|
|
48482
48715
|
return {};
|
|
48483
|
-
const parsed = JSON.parse(
|
|
48716
|
+
const parsed = JSON.parse(readFileSync7(warnedToolsPath, "utf-8"));
|
|
48484
48717
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
48485
48718
|
return {};
|
|
48486
48719
|
const warned = {};
|
|
@@ -48496,12 +48729,34 @@ function readWarnedTools(storageDir) {
|
|
|
48496
48729
|
}
|
|
48497
48730
|
function writeWarnedTools(storageDir, warned) {
|
|
48498
48731
|
try {
|
|
48499
|
-
|
|
48500
|
-
const warnedToolsPath =
|
|
48501
|
-
|
|
48732
|
+
mkdirSync8(storageDir, { recursive: true });
|
|
48733
|
+
const warnedToolsPath = join12(storageDir, WARNED_TOOLS_FILE);
|
|
48734
|
+
const tmpPath = join12(storageDir, `${WARNED_TOOLS_FILE}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`);
|
|
48735
|
+
writeFileSync5(tmpPath, `${JSON.stringify(warned, null, 2)}
|
|
48502
48736
|
`);
|
|
48737
|
+
renameSync5(tmpPath, warnedToolsPath);
|
|
48503
48738
|
} catch {}
|
|
48504
48739
|
}
|
|
48740
|
+
async function withWarnedToolsLock(storageDir, fn) {
|
|
48741
|
+
const lockDir = join12(storageDir, "warned_tools.lock");
|
|
48742
|
+
for (let attempt = 0;attempt < 5; attempt++) {
|
|
48743
|
+
try {
|
|
48744
|
+
mkdirSync8(storageDir, { recursive: true });
|
|
48745
|
+
mkdirSync8(lockDir, { mode: 448 });
|
|
48746
|
+
try {
|
|
48747
|
+
return await fn();
|
|
48748
|
+
} finally {
|
|
48749
|
+
rmSync4(lockDir, { recursive: true, force: true });
|
|
48750
|
+
}
|
|
48751
|
+
} catch (err) {
|
|
48752
|
+
const code = err.code;
|
|
48753
|
+
if (code !== "EEXIST")
|
|
48754
|
+
return null;
|
|
48755
|
+
await new Promise((resolve3) => setTimeout(resolve3, 10 * (attempt + 1)));
|
|
48756
|
+
}
|
|
48757
|
+
}
|
|
48758
|
+
return null;
|
|
48759
|
+
}
|
|
48505
48760
|
function warningKey(warning, projectRoot) {
|
|
48506
48761
|
const scope = warning.kind === "lsp_binary_missing" ? "_" : projectRoot ?? "_";
|
|
48507
48762
|
return [
|
|
@@ -48540,27 +48795,36 @@ ${warning.hint}`;
|
|
|
48540
48795
|
async function deliverConfigureWarnings(opts, warnings) {
|
|
48541
48796
|
if (warnings.length === 0)
|
|
48542
48797
|
return;
|
|
48543
|
-
const
|
|
48544
|
-
|
|
48545
|
-
|
|
48546
|
-
const
|
|
48547
|
-
|
|
48548
|
-
|
|
48549
|
-
|
|
48550
|
-
|
|
48798
|
+
const deliveredWithLock = await withWarnedToolsLock(opts.storageDir, async () => {
|
|
48799
|
+
const warned = readWarnedTools(opts.storageDir);
|
|
48800
|
+
let changed = false;
|
|
48801
|
+
for (const warning of warnings) {
|
|
48802
|
+
const key = warningKey(warning, opts.projectRoot);
|
|
48803
|
+
if (Object.hasOwn(warned, key))
|
|
48804
|
+
continue;
|
|
48805
|
+
if (!sendIgnoredMessage(opts.client, opts.sessionId, formatConfigureWarning(warning))) {
|
|
48806
|
+
continue;
|
|
48807
|
+
}
|
|
48808
|
+
warned[key] = opts.pluginVersion;
|
|
48809
|
+
changed = true;
|
|
48551
48810
|
}
|
|
48552
|
-
|
|
48553
|
-
|
|
48554
|
-
|
|
48555
|
-
|
|
48556
|
-
|
|
48811
|
+
if (changed) {
|
|
48812
|
+
const merged = { ...readWarnedTools(opts.storageDir), ...warned };
|
|
48813
|
+
writeWarnedTools(opts.storageDir, merged);
|
|
48814
|
+
}
|
|
48815
|
+
return true;
|
|
48816
|
+
});
|
|
48817
|
+
if (deliveredWithLock)
|
|
48818
|
+
return;
|
|
48819
|
+
for (const warning of warnings) {
|
|
48820
|
+
sendIgnoredMessage(opts.client, opts.sessionId, formatConfigureWarning(warning));
|
|
48557
48821
|
}
|
|
48558
48822
|
}
|
|
48559
48823
|
function sendFeatureAnnouncement(version2, features, storageDir) {
|
|
48560
|
-
const versionFile =
|
|
48824
|
+
const versionFile = join12(storageDir, "last_announced_version");
|
|
48561
48825
|
try {
|
|
48562
48826
|
if (existsSync8(versionFile)) {
|
|
48563
|
-
const lastVersion =
|
|
48827
|
+
const lastVersion = readFileSync7(versionFile, "utf-8").trim();
|
|
48564
48828
|
if (lastVersion === version2)
|
|
48565
48829
|
return;
|
|
48566
48830
|
}
|
|
@@ -48568,7 +48832,7 @@ function sendFeatureAnnouncement(version2, features, storageDir) {
|
|
|
48568
48832
|
log2([`${FEATURE_MARKER} v${version2}:`, ...features.map((feature) => ` • ${feature}`)].join(`
|
|
48569
48833
|
`));
|
|
48570
48834
|
try {
|
|
48571
|
-
|
|
48835
|
+
mkdirSync8(storageDir, { recursive: true });
|
|
48572
48836
|
writeFileSync5(versionFile, version2);
|
|
48573
48837
|
} catch {}
|
|
48574
48838
|
}
|
|
@@ -50011,7 +50275,6 @@ var ImportParams = Type6.Object({
|
|
|
50011
50275
|
defaultImport: Type6.Optional(Type6.String({ description: "Default import name (e.g. 'React')" })),
|
|
50012
50276
|
removeName: Type6.Optional(Type6.String({ description: "Named import to remove; omit to remove entire import" })),
|
|
50013
50277
|
typeOnly: Type6.Optional(Type6.Boolean({ description: "Type-only import (TS only)" })),
|
|
50014
|
-
dryRun: Type6.Optional(Type6.Boolean({ description: "Preview without writing" })),
|
|
50015
50278
|
validate: Type6.Optional(StringEnum2(["syntax", "full"], {
|
|
50016
50279
|
description: "Post-edit validation level (default: syntax)"
|
|
50017
50280
|
}))
|
|
@@ -50020,12 +50283,6 @@ function buildImportSections(args, payload, theme) {
|
|
|
50020
50283
|
const response = asRecord2(payload);
|
|
50021
50284
|
if (!response)
|
|
50022
50285
|
return [theme.fg("muted", "No import result.")];
|
|
50023
|
-
if (response.dry_run === true) {
|
|
50024
|
-
return [
|
|
50025
|
-
theme.fg("warning", `[dry run] ${args.op}`),
|
|
50026
|
-
asString(response.diff) || theme.fg("muted", "No diff available.")
|
|
50027
|
-
];
|
|
50028
|
-
}
|
|
50029
50286
|
if (args.op === "organize") {
|
|
50030
50287
|
const groups = asRecords(response.groups);
|
|
50031
50288
|
const groupText = groups.length > 0 ? groups.map((group) => `${asString(group.name) ?? "unknown"}: ${asNumber(group.count) ?? 0}`).join(" · ") : "No imports found";
|
|
@@ -50068,7 +50325,7 @@ function registerImportTools(pi, ctx) {
|
|
|
50068
50325
|
pi.registerTool({
|
|
50069
50326
|
name: "aft_import",
|
|
50070
50327
|
label: "import",
|
|
50071
|
-
description: "Language-aware import management. Supports TS, JS, TSX, Python, Rust, Go. Ops: `add
|
|
50328
|
+
description: "Language-aware import management. Supports TS, JS, TSX, Python, Rust, Go. Ops: `add`, `remove`, `organize`. Use aft_safety checkpoint/undo before broad cleanup.",
|
|
50072
50329
|
parameters: ImportParams,
|
|
50073
50330
|
async execute(_toolCallId, params, _signal, _onUpdate, extCtx) {
|
|
50074
50331
|
if ((params.op === "add" || params.op === "remove") && !params.module) {
|
|
@@ -50091,8 +50348,6 @@ function registerImportTools(pi, ctx) {
|
|
|
50091
50348
|
req.name = params.removeName;
|
|
50092
50349
|
if (params.typeOnly !== undefined)
|
|
50093
50350
|
req.type_only = params.typeOnly;
|
|
50094
|
-
if (params.dryRun !== undefined)
|
|
50095
|
-
req.dry_run = params.dryRun;
|
|
50096
50351
|
if (params.validate !== undefined)
|
|
50097
50352
|
req.validate = params.validate;
|
|
50098
50353
|
const response = await callBridge(bridge, commandMap[params.op], req, extCtx);
|
|
@@ -50573,7 +50828,7 @@ Pass a single \`target\`:
|
|
|
50573
50828
|
if (response.success === false) {
|
|
50574
50829
|
throw new Error(response.message || "zoom failed");
|
|
50575
50830
|
}
|
|
50576
|
-
return textResult(formatZoomText(targetLabel, response));
|
|
50831
|
+
return textResult(formatZoomText(targetLabel, response), response);
|
|
50577
50832
|
},
|
|
50578
50833
|
renderCall(args, theme, context) {
|
|
50579
50834
|
return renderZoomCall(args, theme, context);
|
|
@@ -50636,28 +50891,12 @@ var RefactorParams = Type10.Object({
|
|
|
50636
50891
|
name: Type10.Optional(Type10.String({ description: "New function name (for extract)" })),
|
|
50637
50892
|
startLine: Type10.Optional(Type10.Number({ description: "1-based start line (for extract)" })),
|
|
50638
50893
|
endLine: Type10.Optional(Type10.Number({ description: "1-based end line, inclusive (for extract)" })),
|
|
50639
|
-
callSiteLine: Type10.Optional(Type10.Number({ description: "1-based call site line (for inline)" }))
|
|
50640
|
-
dryRun: Type10.Optional(Type10.Boolean({ description: "Preview as diff" }))
|
|
50894
|
+
callSiteLine: Type10.Optional(Type10.Number({ description: "1-based call site line (for inline)" }))
|
|
50641
50895
|
});
|
|
50642
50896
|
function buildRefactorSections(args, payload, theme) {
|
|
50643
50897
|
const response = asRecord2(payload);
|
|
50644
50898
|
if (!response)
|
|
50645
50899
|
return [theme.fg("muted", "No refactor result.")];
|
|
50646
|
-
if (response.dry_run === true) {
|
|
50647
|
-
const diffs = asRecords(response.diffs);
|
|
50648
|
-
const sections = [theme.fg("warning", `[dry run] ${args.op}`)];
|
|
50649
|
-
if (diffs.length === 0) {
|
|
50650
|
-
sections.push(theme.fg("muted", "No diff available."));
|
|
50651
|
-
return sections;
|
|
50652
|
-
}
|
|
50653
|
-
diffs.forEach((diff) => {
|
|
50654
|
-
const file2 = shortenPath(asString(diff.file) ?? "(unknown file)");
|
|
50655
|
-
const rendered = renderUnifiedDiff(asString(diff.diff) ?? "") || theme.fg("muted", "No diff available.");
|
|
50656
|
-
sections.push(`${theme.fg("accent", file2)}
|
|
50657
|
-
${rendered}`);
|
|
50658
|
-
});
|
|
50659
|
-
return sections;
|
|
50660
|
-
}
|
|
50661
50900
|
if (args.op === "move") {
|
|
50662
50901
|
const results = asRecords(response.results);
|
|
50663
50902
|
return [
|
|
@@ -50700,7 +50939,7 @@ function registerRefactorTool(pi, ctx) {
|
|
|
50700
50939
|
pi.registerTool({
|
|
50701
50940
|
name: "aft_refactor",
|
|
50702
50941
|
label: "refactor",
|
|
50703
|
-
description: "Workspace-wide refactoring that updates imports and references across files. `move` relocates a top-level symbol
|
|
50942
|
+
description: "Workspace-wide refactoring that updates imports and references across files. `move` relocates a top-level symbol; `extract` pulls a line range into a new function; `inline` replaces a call site. Use aft_safety checkpoint/undo before risky refactors.",
|
|
50704
50943
|
parameters: RefactorParams,
|
|
50705
50944
|
async execute(_toolCallId, params, _signal, _onUpdate, extCtx) {
|
|
50706
50945
|
const bridge = bridgeFor(ctx, extCtx.cwd);
|
|
@@ -50725,8 +50964,6 @@ function registerRefactorTool(pi, ctx) {
|
|
|
50725
50964
|
}
|
|
50726
50965
|
if (params.callSiteLine !== undefined)
|
|
50727
50966
|
req.call_site_line = params.callSiteLine;
|
|
50728
|
-
if (params.dryRun !== undefined)
|
|
50729
|
-
req.dry_run = params.dryRun;
|
|
50730
50967
|
const response = await callBridge(bridge, commandMap[params.op], req, extCtx);
|
|
50731
50968
|
return textResult(JSON.stringify(response, null, 2));
|
|
50732
50969
|
},
|
|
@@ -50985,7 +51222,6 @@ var TransformParams = Type13.Object({
|
|
|
50985
51222
|
position: Type13.Optional(Type13.String({
|
|
50986
51223
|
description: "Position hint: 'first', 'last' (default), 'before:name', 'after:name' for add_member"
|
|
50987
51224
|
})),
|
|
50988
|
-
dryRun: Type13.Optional(Type13.Boolean({ description: "Preview without modifying" })),
|
|
50989
51225
|
validate: Type13.Optional(StringEnum7(["syntax", "full"], {
|
|
50990
51226
|
description: "Validation level (default: syntax)"
|
|
50991
51227
|
}))
|
|
@@ -50994,12 +51230,6 @@ function buildTransformSections(args, payload, theme) {
|
|
|
50994
51230
|
const response = asRecord2(payload);
|
|
50995
51231
|
if (!response)
|
|
50996
51232
|
return [theme.fg("muted", "No transform result.")];
|
|
50997
|
-
if (response.dry_run === true) {
|
|
50998
|
-
return [
|
|
50999
|
-
theme.fg("warning", `[dry run] ${args.op}`),
|
|
51000
|
-
asString(response.diff) ?? theme.fg("muted", "No diff available.")
|
|
51001
|
-
];
|
|
51002
|
-
}
|
|
51003
51233
|
const target = asString(response.target) ?? asString(response.scope) ?? args.target ?? args.container ?? args.field ?? args.filePath;
|
|
51004
51234
|
return [
|
|
51005
51235
|
`${theme.fg("success", "transformed")} ${theme.fg("accent", args.op)}`,
|
|
@@ -51025,7 +51255,7 @@ function registerStructureTool(pi, ctx) {
|
|
|
51025
51255
|
pi.registerTool({
|
|
51026
51256
|
name: "aft_transform",
|
|
51027
51257
|
label: "transform",
|
|
51028
|
-
description: "Scope-aware structural code transformations with correct indentation.
|
|
51258
|
+
description: "Scope-aware structural code transformations with correct indentation. Use aft_safety checkpoint/undo before risky transforms.",
|
|
51029
51259
|
parameters: TransformParams,
|
|
51030
51260
|
async execute(_toolCallId, params, _signal, _onUpdate, extCtx) {
|
|
51031
51261
|
validateTransformParams(params);
|
|
@@ -51051,8 +51281,6 @@ function registerStructureTool(pi, ctx) {
|
|
|
51051
51281
|
req.value = params.value;
|
|
51052
51282
|
if (params.position !== undefined)
|
|
51053
51283
|
req.position = params.position;
|
|
51054
|
-
if (params.dryRun !== undefined)
|
|
51055
|
-
req.dry_run = params.dryRun;
|
|
51056
51284
|
if (params.validate !== undefined)
|
|
51057
51285
|
req.validate = params.validate;
|
|
51058
51286
|
const response = await callBridge(bridge, params.op, req, extCtx);
|
|
@@ -51204,6 +51432,7 @@ var ALL_ONLY_TOOLS = new Set([
|
|
|
51204
51432
|
"aft_transform",
|
|
51205
51433
|
"aft_refactor"
|
|
51206
51434
|
]);
|
|
51435
|
+
var pendingEagerWarnings = new Map;
|
|
51207
51436
|
function isConfigureWarning(value) {
|
|
51208
51437
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
51209
51438
|
return false;
|
|
@@ -51213,17 +51442,29 @@ function isConfigureWarning(value) {
|
|
|
51213
51442
|
function coerceConfigureWarnings(warnings) {
|
|
51214
51443
|
return warnings.filter(isConfigureWarning);
|
|
51215
51444
|
}
|
|
51445
|
+
function drainPendingEagerWarnings(projectRoot) {
|
|
51446
|
+
const pending = pendingEagerWarnings.get(projectRoot) ?? [];
|
|
51447
|
+
pendingEagerWarnings.delete(projectRoot);
|
|
51448
|
+
return pending;
|
|
51449
|
+
}
|
|
51216
51450
|
async function handleConfigureWarningsForSession(context) {
|
|
51451
|
+
const validWarnings = coerceConfigureWarnings(context.warnings);
|
|
51217
51452
|
if (!context.sessionId) {
|
|
51218
|
-
|
|
51453
|
+
if (validWarnings.length === 0)
|
|
51454
|
+
return;
|
|
51455
|
+
const pending = pendingEagerWarnings.get(context.projectRoot) ?? [];
|
|
51456
|
+
pending.push(...validWarnings);
|
|
51457
|
+
pendingEagerWarnings.set(context.projectRoot, pending);
|
|
51458
|
+
warn2(`[configure] deferred warnings for ${context.projectRoot} arrived without session_id; buffering until first session-bound call`);
|
|
51219
51459
|
return;
|
|
51220
51460
|
}
|
|
51221
51461
|
if (!context.client) {
|
|
51222
51462
|
warn2(`[configure] deferred warnings for session ${context.sessionId} arrived without notification client; skipping notification`);
|
|
51223
51463
|
return;
|
|
51224
51464
|
}
|
|
51225
|
-
const
|
|
51226
|
-
|
|
51465
|
+
const pendingWarnings = drainPendingEagerWarnings(context.projectRoot);
|
|
51466
|
+
const combinedWarnings = [...pendingWarnings, ...validWarnings];
|
|
51467
|
+
if (combinedWarnings.length === 0)
|
|
51227
51468
|
return;
|
|
51228
51469
|
await deliverConfigureWarnings({
|
|
51229
51470
|
client: context.client,
|
|
@@ -51231,10 +51472,10 @@ async function handleConfigureWarningsForSession(context) {
|
|
|
51231
51472
|
storageDir: context.storageDir,
|
|
51232
51473
|
pluginVersion: context.pluginVersion,
|
|
51233
51474
|
projectRoot: context.projectRoot
|
|
51234
|
-
},
|
|
51475
|
+
}, combinedWarnings);
|
|
51235
51476
|
}
|
|
51236
51477
|
function resolveStorageDir() {
|
|
51237
|
-
return
|
|
51478
|
+
return join13(homedir9(), ".pi", "agent", "aft");
|
|
51238
51479
|
}
|
|
51239
51480
|
function resolveToolSurface(config2) {
|
|
51240
51481
|
const surface = config2.tool_surface ?? "recommended";
|
|
@@ -51407,11 +51648,12 @@ ${lines}
|
|
|
51407
51648
|
errorPrefix: "[aft-pi]",
|
|
51408
51649
|
minVersion: PLUGIN_VERSION,
|
|
51409
51650
|
onConfigureWarnings: async ({ projectRoot, sessionId, client, warnings }) => {
|
|
51651
|
+
const pendingWarnings = sessionId ? drainPendingEagerWarnings(projectRoot) : [];
|
|
51410
51652
|
await handleConfigureWarningsForSession({
|
|
51411
51653
|
projectRoot,
|
|
51412
51654
|
sessionId,
|
|
51413
51655
|
client,
|
|
51414
|
-
warnings,
|
|
51656
|
+
warnings: [...pendingWarnings, ...warnings],
|
|
51415
51657
|
storageDir,
|
|
51416
51658
|
pluginVersion: PLUGIN_VERSION
|
|
51417
51659
|
});
|
|
@@ -51520,10 +51762,6 @@ ${lines}
|
|
|
51520
51762
|
runtime: pi
|
|
51521
51763
|
});
|
|
51522
51764
|
});
|
|
51523
|
-
pi.on("input", (_event, extCtx) => {
|
|
51524
|
-
resetBgWake(resolveSessionId(extCtx));
|
|
51525
|
-
return { action: "continue" };
|
|
51526
|
-
});
|
|
51527
51765
|
pi.on("session_shutdown", async () => {
|
|
51528
51766
|
try {
|
|
51529
51767
|
await Promise.allSettled([abortInFlightAutoInstalls(), abortInFlightGithubInstalls()]);
|