@cortexkit/aft-opencode 0.44.0 → 0.45.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/index.js +202 -82
- package/dist/tui.js +139 -19
- package/package.json +8 -8
package/dist/index.js
CHANGED
|
@@ -8233,6 +8233,8 @@ function resolveBashKillTimeout(modelTimeout, foregroundWaitMs) {
|
|
|
8233
8233
|
}
|
|
8234
8234
|
// ../aft-bridge/dist/bridge.js
|
|
8235
8235
|
import { spawn } from "node:child_process";
|
|
8236
|
+
import { createHash } from "node:crypto";
|
|
8237
|
+
import { readFileSync } from "node:fs";
|
|
8236
8238
|
import { homedir as homedir2 } from "node:os";
|
|
8237
8239
|
import { join as join2 } from "node:path";
|
|
8238
8240
|
import { StringDecoder } from "node:string_decoder";
|
|
@@ -8332,6 +8334,22 @@ function bashTaskIdFrom(response) {
|
|
|
8332
8334
|
return camelCase;
|
|
8333
8335
|
return;
|
|
8334
8336
|
}
|
|
8337
|
+
function hashBinaryOnDisk(binaryPath) {
|
|
8338
|
+
try {
|
|
8339
|
+
return createHash("sha256").update(readFileSync(binaryPath)).digest("hex");
|
|
8340
|
+
} catch {
|
|
8341
|
+
return null;
|
|
8342
|
+
}
|
|
8343
|
+
}
|
|
8344
|
+
var binaryFingerprintReader = hashBinaryOnDisk;
|
|
8345
|
+
function readBinaryFingerprint(binaryPath) {
|
|
8346
|
+
try {
|
|
8347
|
+
const fingerprint = binaryFingerprintReader(binaryPath);
|
|
8348
|
+
return typeof fingerprint === "string" && fingerprint.length > 0 ? fingerprint : null;
|
|
8349
|
+
} catch {
|
|
8350
|
+
return null;
|
|
8351
|
+
}
|
|
8352
|
+
}
|
|
8335
8353
|
function tagStderrLine(line) {
|
|
8336
8354
|
return /^\[aft(-\w+)?\] /.test(line) ? line : `[aft] ${line}`;
|
|
8337
8355
|
}
|
|
@@ -8427,6 +8445,9 @@ class BinaryBridge {
|
|
|
8427
8445
|
binaryPath;
|
|
8428
8446
|
cwd;
|
|
8429
8447
|
process = null;
|
|
8448
|
+
spawnedBinaryFingerprint = null;
|
|
8449
|
+
lastBinaryFingerprintCheckAt = 0;
|
|
8450
|
+
_retiringDueToBinaryChange = false;
|
|
8430
8451
|
pending = new Map;
|
|
8431
8452
|
outstandingBackgroundTaskIds = new Set;
|
|
8432
8453
|
nextId = 1;
|
|
@@ -8546,6 +8567,24 @@ class BinaryBridge {
|
|
|
8546
8567
|
hasOutstandingBackgroundTasks() {
|
|
8547
8568
|
return this.outstandingBackgroundTaskIds.size > 0;
|
|
8548
8569
|
}
|
|
8570
|
+
maybeScheduleRespawnForUpdatedBinary(checkIntervalMs, now = Date.now()) {
|
|
8571
|
+
if (this._shuttingDown || this._retiringDueToBinaryChange || !this.isAlive())
|
|
8572
|
+
return false;
|
|
8573
|
+
if (this.pending.size > 0 || this.outstandingBackgroundTaskIds.size > 0)
|
|
8574
|
+
return false;
|
|
8575
|
+
if (now - this.lastBinaryFingerprintCheckAt < checkIntervalMs)
|
|
8576
|
+
return false;
|
|
8577
|
+
this.lastBinaryFingerprintCheckAt = now;
|
|
8578
|
+
const spawnedFingerprint = this.spawnedBinaryFingerprint;
|
|
8579
|
+
if (!spawnedFingerprint)
|
|
8580
|
+
return false;
|
|
8581
|
+
const currentFingerprint = readBinaryFingerprint(this.binaryPath);
|
|
8582
|
+
if (!currentFingerprint || currentFingerprint === spawnedFingerprint)
|
|
8583
|
+
return false;
|
|
8584
|
+
this._retiringDueToBinaryChange = true;
|
|
8585
|
+
this.logVia(`Binary contents changed on disk for ${this.binaryPath}; retiring this bridge so the next tool call respawns onto the updated binary.`);
|
|
8586
|
+
return true;
|
|
8587
|
+
}
|
|
8549
8588
|
getCwd() {
|
|
8550
8589
|
return this.cwd;
|
|
8551
8590
|
}
|
|
@@ -8578,6 +8617,9 @@ class BinaryBridge {
|
|
|
8578
8617
|
}
|
|
8579
8618
|
async sendWithVersionMismatchRetry(command, params, options, canRetryAfterVersionSwap) {
|
|
8580
8619
|
try {
|
|
8620
|
+
if (this._retiringDueToBinaryChange) {
|
|
8621
|
+
throw new Error(`${this.errorPrefix} Bridge is retiring after the on-disk binary changed; retry to respawn on the updated binary`);
|
|
8622
|
+
}
|
|
8581
8623
|
if (this._shuttingDown) {
|
|
8582
8624
|
throw new Error(`${this.errorPrefix} Bridge is shutting down, cannot send "${command}"`);
|
|
8583
8625
|
}
|
|
@@ -8776,6 +8818,7 @@ class BinaryBridge {
|
|
|
8776
8818
|
}
|
|
8777
8819
|
async shutdown() {
|
|
8778
8820
|
this._shuttingDown = true;
|
|
8821
|
+
this.spawnedBinaryFingerprint = null;
|
|
8779
8822
|
this.clearRestartResetTimer();
|
|
8780
8823
|
this.configureWarningClients.clear();
|
|
8781
8824
|
this.rejectAllPending(new Error(`${this.errorPrefix} Bridge shutting down`));
|
|
@@ -8829,6 +8872,9 @@ class BinaryBridge {
|
|
|
8829
8872
|
async replaceCurrentBinary(newBinaryPath) {
|
|
8830
8873
|
this.binaryPath = newBinaryPath;
|
|
8831
8874
|
this.configured = false;
|
|
8875
|
+
this.spawnedBinaryFingerprint = null;
|
|
8876
|
+
this.lastBinaryFingerprintCheckAt = 0;
|
|
8877
|
+
this._retiringDueToBinaryChange = false;
|
|
8832
8878
|
this.clearRestartResetTimer();
|
|
8833
8879
|
this.rejectAllPending(new Error(`${this.errorPrefix} Bridge restarting with updated binary: ${newBinaryPath}`));
|
|
8834
8880
|
if (!this.process)
|
|
@@ -8854,6 +8900,7 @@ class BinaryBridge {
|
|
|
8854
8900
|
this.spawnProcess(triggeringSessionId);
|
|
8855
8901
|
}
|
|
8856
8902
|
spawnProcess(triggeringSessionId) {
|
|
8903
|
+
this._retiringDueToBinaryChange = false;
|
|
8857
8904
|
this.lastStatusBar = undefined;
|
|
8858
8905
|
if (triggeringSessionId) {
|
|
8859
8906
|
this.sessionLogVia(triggeringSessionId, `Spawning binary: ${this.binaryPath} (cwd: ${this.cwd})`);
|
|
@@ -8944,6 +8991,8 @@ class BinaryBridge {
|
|
|
8944
8991
|
this.handleCrash();
|
|
8945
8992
|
});
|
|
8946
8993
|
this.process = child;
|
|
8994
|
+
this.spawnedBinaryFingerprint = readBinaryFingerprint(this.binaryPath);
|
|
8995
|
+
this.lastBinaryFingerprintCheckAt = Date.now();
|
|
8947
8996
|
this.stdoutBuffer = "";
|
|
8948
8997
|
this.stdoutReadOffset = 0;
|
|
8949
8998
|
this.stderrBuffer = "";
|
|
@@ -9122,6 +9171,7 @@ class BinaryBridge {
|
|
|
9122
9171
|
}
|
|
9123
9172
|
handleTimeout(triggeringSessionId) {
|
|
9124
9173
|
this.consecutiveRequestTimeouts = 0;
|
|
9174
|
+
this.spawnedBinaryFingerprint = null;
|
|
9125
9175
|
this.rejectAllPending(new Error(`${this.errorPrefix} bridge killed during sibling timeout — request aborted`));
|
|
9126
9176
|
this.outstandingBackgroundTaskIds.clear();
|
|
9127
9177
|
if (this.process) {
|
|
@@ -9148,6 +9198,7 @@ class BinaryBridge {
|
|
|
9148
9198
|
handleCrash(cause) {
|
|
9149
9199
|
const proc = this.process;
|
|
9150
9200
|
this.process = null;
|
|
9201
|
+
this.spawnedBinaryFingerprint = null;
|
|
9151
9202
|
if (proc && proc.exitCode === null && !proc.killed) {
|
|
9152
9203
|
proc.kill("SIGKILL");
|
|
9153
9204
|
}
|
|
@@ -9159,6 +9210,10 @@ class BinaryBridge {
|
|
|
9159
9210
|
this.errorVia(`Binary crashed (restarts: ${this._restartCount})${cause ? `: ${cause.message}` : ""}.${tail}`);
|
|
9160
9211
|
}
|
|
9161
9212
|
this.rejectAllPending(new Error(`${this.errorPrefix} Binary crashed (restarts: ${this._restartCount})${cause ? `: ${cause.message}` : ""} (see ${this.getLogFilePathVia()})`));
|
|
9213
|
+
if (this._retiringDueToBinaryChange) {
|
|
9214
|
+
this.logVia("Binary exited while retiring after an on-disk update; skipping auto-restart");
|
|
9215
|
+
return;
|
|
9216
|
+
}
|
|
9162
9217
|
if (this._restartCount < this.maxRestarts) {
|
|
9163
9218
|
const delay = 100 * 2 ** this._restartCount;
|
|
9164
9219
|
this._restartCount++;
|
|
@@ -9288,13 +9343,13 @@ function isEmptyParam(value) {
|
|
|
9288
9343
|
return false;
|
|
9289
9344
|
}
|
|
9290
9345
|
// ../aft-bridge/dist/config-tiers.js
|
|
9291
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
9346
|
+
import { existsSync, readFileSync as readFileSync2 } from "node:fs";
|
|
9292
9347
|
import { resolve as resolve2 } from "node:path";
|
|
9293
9348
|
function readConfigTiers(opts) {
|
|
9294
9349
|
const tiers = [];
|
|
9295
9350
|
try {
|
|
9296
9351
|
if (existsSync(opts.userConfigPath)) {
|
|
9297
|
-
const doc =
|
|
9352
|
+
const doc = readFileSync2(opts.userConfigPath, "utf-8");
|
|
9298
9353
|
tiers.push({
|
|
9299
9354
|
tier: "user",
|
|
9300
9355
|
source: resolve2(opts.userConfigPath),
|
|
@@ -9304,7 +9359,7 @@ function readConfigTiers(opts) {
|
|
|
9304
9359
|
} catch {}
|
|
9305
9360
|
try {
|
|
9306
9361
|
if (existsSync(opts.projectConfigPath)) {
|
|
9307
|
-
const doc =
|
|
9362
|
+
const doc = readFileSync2(opts.projectConfigPath, "utf-8");
|
|
9308
9363
|
tiers.push({
|
|
9309
9364
|
tier: "project",
|
|
9310
9365
|
source: resolve2(opts.projectConfigPath),
|
|
@@ -9322,8 +9377,8 @@ function formatDroppedKeyWarnings(dropped) {
|
|
|
9322
9377
|
}
|
|
9323
9378
|
// ../aft-bridge/dist/downloader.js
|
|
9324
9379
|
import { spawnSync } from "node:child_process";
|
|
9325
|
-
import { createHash, randomUUID } from "node:crypto";
|
|
9326
|
-
import { chmodSync, closeSync, copyFileSync, createWriteStream, existsSync as existsSync2, mkdirSync, openSync, readFileSync as
|
|
9380
|
+
import { createHash as createHash2, randomUUID } from "node:crypto";
|
|
9381
|
+
import { chmodSync, closeSync, copyFileSync, createWriteStream, existsSync as existsSync2, mkdirSync, openSync, readFileSync as readFileSync3, renameSync, rmSync, statSync, unlinkSync, writeSync } from "node:fs";
|
|
9327
9382
|
import { homedir as homedir3 } from "node:os";
|
|
9328
9383
|
import { join as join3 } from "node:path";
|
|
9329
9384
|
import { Readable } from "node:stream";
|
|
@@ -9467,7 +9522,7 @@ async function downloadBinary(version) {
|
|
|
9467
9522
|
warn(`Checksum verification failed: checksums.sha256 found but no entry for ${assetName}. ` + "Binary download aborted for security reasons.");
|
|
9468
9523
|
return null;
|
|
9469
9524
|
}
|
|
9470
|
-
const hash =
|
|
9525
|
+
const hash = createHash2("sha256");
|
|
9471
9526
|
let bytesWritten = 0;
|
|
9472
9527
|
const guard = new TransformStream({
|
|
9473
9528
|
transform(chunk, controller) {
|
|
@@ -9551,7 +9606,7 @@ async function acquireDownloadLock(lockPath) {
|
|
|
9551
9606
|
closeSync(fd);
|
|
9552
9607
|
} catch {}
|
|
9553
9608
|
try {
|
|
9554
|
-
if (
|
|
9609
|
+
if (readFileSync3(lockPath, "utf-8") === owner) {
|
|
9555
9610
|
rmSync(lockPath, { force: true });
|
|
9556
9611
|
}
|
|
9557
9612
|
} catch {}
|
|
@@ -9623,12 +9678,12 @@ function stripJsoncSymbols(value) {
|
|
|
9623
9678
|
}
|
|
9624
9679
|
// ../aft-bridge/dist/migration.js
|
|
9625
9680
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
9626
|
-
import { closeSync as closeSync3, existsSync as existsSync5, mkdirSync as mkdirSync4, openSync as openSync3, readFileSync as
|
|
9681
|
+
import { closeSync as closeSync3, existsSync as existsSync5, mkdirSync as mkdirSync4, openSync as openSync3, readFileSync as readFileSync5, renameSync as renameSync4, rmSync as rmSync2, statSync as statSync2, unlinkSync as unlinkSync3, writeFileSync as writeFileSync2 } from "node:fs";
|
|
9627
9682
|
import { homedir as homedir6, tmpdir } from "node:os";
|
|
9628
9683
|
import { basename, dirname as dirname2, join as join6, resolve as resolve4 } from "node:path";
|
|
9629
9684
|
|
|
9630
9685
|
// ../aft-bridge/dist/paths.js
|
|
9631
|
-
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as
|
|
9686
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync4, renameSync as renameSync2, writeFileSync } from "node:fs";
|
|
9632
9687
|
import { homedir as homedir4 } from "node:os";
|
|
9633
9688
|
import { dirname, isAbsolute as isAbsolute2, join as join4, resolve as resolve3 } from "node:path";
|
|
9634
9689
|
function homeDir() {
|
|
@@ -9702,7 +9757,7 @@ function shouldShowAnnouncement(storageRoot, harness, currentVersion) {
|
|
|
9702
9757
|
let lastVersion = "";
|
|
9703
9758
|
try {
|
|
9704
9759
|
if (existsSync3(versionFile)) {
|
|
9705
|
-
lastVersion =
|
|
9760
|
+
lastVersion = readFileSync4(versionFile, "utf-8").trim();
|
|
9706
9761
|
}
|
|
9707
9762
|
} catch {
|
|
9708
9763
|
return false;
|
|
@@ -10099,7 +10154,7 @@ function atomicCopyConfigFile(sourcePath, targetPath) {
|
|
|
10099
10154
|
let fd = null;
|
|
10100
10155
|
try {
|
|
10101
10156
|
fd = openSync3(tmpPath, "wx", 384);
|
|
10102
|
-
writeFileSync2(fd,
|
|
10157
|
+
writeFileSync2(fd, readFileSync5(sourcePath));
|
|
10103
10158
|
closeSync3(fd);
|
|
10104
10159
|
fd = null;
|
|
10105
10160
|
renameSync4(tmpPath, targetPath);
|
|
@@ -10178,7 +10233,7 @@ function markLegacySourcesMovedAside(sources, targetPath, logger) {
|
|
|
10178
10233
|
const desiredMarkerPath = `${source.path}${MOVED_MARKER_SUFFIX}`;
|
|
10179
10234
|
const markerPath = nonClobberingSidecarPath(desiredMarkerPath);
|
|
10180
10235
|
try {
|
|
10181
|
-
const original =
|
|
10236
|
+
const original = readFileSync5(source.path, "utf-8");
|
|
10182
10237
|
if (markerPath !== desiredMarkerPath) {
|
|
10183
10238
|
logger?.warn?.(`Preserving existing legacy AFT marker ${desiredMarkerPath}; writing new marker to ${markerPath}`);
|
|
10184
10239
|
}
|
|
@@ -10247,10 +10302,10 @@ function migrateAftConfigFile(opts) {
|
|
|
10247
10302
|
try {
|
|
10248
10303
|
const sources = existingSources.map((source) => ({
|
|
10249
10304
|
...source,
|
|
10250
|
-
content:
|
|
10305
|
+
content: readFileSync5(source.path, "utf-8")
|
|
10251
10306
|
}));
|
|
10252
10307
|
if (existsSync5(opts.targetPath)) {
|
|
10253
|
-
const targetContent =
|
|
10308
|
+
const targetContent = readFileSync5(opts.targetPath, "utf-8");
|
|
10254
10309
|
for (const source of sources) {
|
|
10255
10310
|
if (fileSemanticsMatch(source.content, targetContent))
|
|
10256
10311
|
continue;
|
|
@@ -10484,8 +10539,8 @@ function isNpmAvailable(deps = defaultDeps()) {
|
|
|
10484
10539
|
}
|
|
10485
10540
|
// ../aft-bridge/dist/onnx-runtime.js
|
|
10486
10541
|
import { execFileSync } from "node:child_process";
|
|
10487
|
-
import { createHash as
|
|
10488
|
-
import { chmodSync as chmodSync3, closeSync as closeSync4, copyFileSync as copyFileSync3, createWriteStream as createWriteStream2, existsSync as existsSync6, lstatSync, mkdirSync as mkdirSync5, openSync as openSync4, readdirSync as readdirSync2, readFileSync as
|
|
10542
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
10543
|
+
import { chmodSync as chmodSync3, closeSync as closeSync4, copyFileSync as copyFileSync3, createWriteStream as createWriteStream2, existsSync as existsSync6, lstatSync, mkdirSync as mkdirSync5, openSync as openSync4, readdirSync as readdirSync2, readFileSync as readFileSync6, readlinkSync, realpathSync, rmSync as rmSync3, statSync as statSync4, symlinkSync, unlinkSync as unlinkSync4, writeFileSync as writeFileSync3 } from "node:fs";
|
|
10489
10544
|
import { basename as basename2, dirname as dirname4, isAbsolute as isAbsolute4, join as join8, relative as relative2, resolve as resolve5, win32 } from "node:path";
|
|
10490
10545
|
import { Readable as Readable2 } from "node:stream";
|
|
10491
10546
|
import { pipeline as pipeline2 } from "node:stream/promises";
|
|
@@ -11038,7 +11093,7 @@ function readOnnxInstalledMeta(installDir) {
|
|
|
11038
11093
|
try {
|
|
11039
11094
|
if (!statSync4(path2).isFile())
|
|
11040
11095
|
return null;
|
|
11041
|
-
const raw =
|
|
11096
|
+
const raw = readFileSync6(path2, "utf8");
|
|
11042
11097
|
const parsed = JSON.parse(raw);
|
|
11043
11098
|
if (typeof parsed.version !== "string" || parsed.version.length === 0)
|
|
11044
11099
|
return null;
|
|
@@ -11053,8 +11108,8 @@ function readOnnxInstalledMeta(installDir) {
|
|
|
11053
11108
|
}
|
|
11054
11109
|
}
|
|
11055
11110
|
function sha256File(path2) {
|
|
11056
|
-
const hash =
|
|
11057
|
-
hash.update(
|
|
11111
|
+
const hash = createHash3("sha256");
|
|
11112
|
+
hash.update(readFileSync6(path2));
|
|
11058
11113
|
return hash.digest("hex");
|
|
11059
11114
|
}
|
|
11060
11115
|
function acquireLock(lockPath) {
|
|
@@ -11082,7 +11137,7 @@ ${new Date().toISOString()}
|
|
|
11082
11137
|
let owningPid = null;
|
|
11083
11138
|
let lockMtimeMs = 0;
|
|
11084
11139
|
try {
|
|
11085
|
-
const raw =
|
|
11140
|
+
const raw = readFileSync6(lockPath, "utf8");
|
|
11086
11141
|
const firstLine = raw.split(/\r?\n/, 1)[0]?.trim() ?? "";
|
|
11087
11142
|
const parsed = Number.parseInt(firstLine, 10);
|
|
11088
11143
|
if (Number.isFinite(parsed) && parsed > 0)
|
|
@@ -11107,7 +11162,7 @@ function releaseLock(lockPath) {
|
|
|
11107
11162
|
try {
|
|
11108
11163
|
let owningPid = null;
|
|
11109
11164
|
try {
|
|
11110
|
-
const raw =
|
|
11165
|
+
const raw = readFileSync6(lockPath, "utf8");
|
|
11111
11166
|
const firstLine = raw.split(/\r?\n/, 1)[0]?.trim() ?? "";
|
|
11112
11167
|
const parsed = Number.parseInt(firstLine, 10);
|
|
11113
11168
|
if (Number.isFinite(parsed) && parsed > 0)
|
|
@@ -11171,7 +11226,7 @@ function isProcessAlive(pid) {
|
|
|
11171
11226
|
}
|
|
11172
11227
|
}
|
|
11173
11228
|
// ../aft-bridge/dist/project-identity.js
|
|
11174
|
-
import { createHash as
|
|
11229
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
11175
11230
|
import { realpathSync as realpathSync2 } from "node:fs";
|
|
11176
11231
|
import { resolve as resolve6 } from "node:path";
|
|
11177
11232
|
function canonicalizeProjectRoot(dir) {
|
|
@@ -11202,7 +11257,7 @@ function normalizeWindowsRoot(p) {
|
|
|
11202
11257
|
return s;
|
|
11203
11258
|
}
|
|
11204
11259
|
function projectRootKeyHash(dir) {
|
|
11205
|
-
return
|
|
11260
|
+
return createHash4("sha256").update(canonicalizeProjectRoot(dir)).digest("hex").slice(0, 16);
|
|
11206
11261
|
}
|
|
11207
11262
|
|
|
11208
11263
|
// ../aft-bridge/dist/pool.js
|
|
@@ -11286,6 +11341,11 @@ class BridgePool {
|
|
|
11286
11341
|
for (const [dir, entry] of this.bridges) {
|
|
11287
11342
|
if (entry.bridge.hasPendingRequests() || entry.bridge.hasOutstandingBackgroundTasks())
|
|
11288
11343
|
continue;
|
|
11344
|
+
if (entry.bridge.maybeScheduleRespawnForUpdatedBinary(CLEANUP_INTERVAL_MS, now)) {
|
|
11345
|
+
this.staleBridges.add(entry.bridge);
|
|
11346
|
+
this.bridges.delete(dir);
|
|
11347
|
+
continue;
|
|
11348
|
+
}
|
|
11289
11349
|
if (now - entry.lastUsed > this.idleTimeoutMs) {
|
|
11290
11350
|
entry.bridge.shutdown().catch((err) => this.error("cleanup shutdown failed:", err));
|
|
11291
11351
|
this.bridges.delete(dir);
|
|
@@ -11382,10 +11442,11 @@ class BridgePool {
|
|
|
11382
11442
|
function normalizeKey(projectRoot) {
|
|
11383
11443
|
return canonicalizeProjectRoot(projectRoot);
|
|
11384
11444
|
}
|
|
11385
|
-
// ../../node_modules/.bun/@cortexkit+subc-client@0.
|
|
11445
|
+
// ../../node_modules/.bun/@cortexkit+subc-client@0.3.0/node_modules/@cortexkit/subc-client/src/client.ts
|
|
11386
11446
|
import { promises as fs2 } from "node:fs";
|
|
11447
|
+
import { debuglog } from "node:util";
|
|
11387
11448
|
|
|
11388
|
-
// ../../node_modules/.bun/@cortexkit+subc-client@0.
|
|
11449
|
+
// ../../node_modules/.bun/@cortexkit+subc-client@0.3.0/node_modules/@cortexkit/subc-client/src/auth.ts
|
|
11389
11450
|
import { createHmac, randomBytes, timingSafeEqual } from "node:crypto";
|
|
11390
11451
|
var NONCE_LEN = 32;
|
|
11391
11452
|
var MAX_AUTH_MESSAGE_LEN = 4096;
|
|
@@ -11449,7 +11510,7 @@ async function authenticateClient(sock, conn, deadlineMs) {
|
|
|
11449
11510
|
await writeMessage(sock, { client_auth: Array.from(clientAuth) }, deadlineMs);
|
|
11450
11511
|
}
|
|
11451
11512
|
|
|
11452
|
-
// ../../node_modules/.bun/@cortexkit+subc-client@0.
|
|
11513
|
+
// ../../node_modules/.bun/@cortexkit+subc-client@0.3.0/node_modules/@cortexkit/subc-client/src/connection-file.ts
|
|
11453
11514
|
import { promises as fs } from "node:fs";
|
|
11454
11515
|
var SCHEMA_VERSION = 1;
|
|
11455
11516
|
var MIN_KEY_LEN = 32;
|
|
@@ -11518,7 +11579,7 @@ async function readConnectionFile(path2) {
|
|
|
11518
11579
|
return info;
|
|
11519
11580
|
}
|
|
11520
11581
|
|
|
11521
|
-
// ../../node_modules/.bun/@cortexkit+subc-client@0.
|
|
11582
|
+
// ../../node_modules/.bun/@cortexkit+subc-client@0.3.0/node_modules/@cortexkit/subc-client/src/envelope.ts
|
|
11522
11583
|
var PROTOCOL_VERSION = 1;
|
|
11523
11584
|
var HEADER_LEN = 17;
|
|
11524
11585
|
var FROZEN_PREFIX_LEN = 5;
|
|
@@ -11625,7 +11686,7 @@ function encodeFrame(frame) {
|
|
|
11625
11686
|
return out;
|
|
11626
11687
|
}
|
|
11627
11688
|
|
|
11628
|
-
// ../../node_modules/.bun/@cortexkit+subc-client@0.
|
|
11689
|
+
// ../../node_modules/.bun/@cortexkit+subc-client@0.3.0/node_modules/@cortexkit/subc-client/src/socket.ts
|
|
11629
11690
|
import net from "node:net";
|
|
11630
11691
|
|
|
11631
11692
|
class SocketClosedError extends Error {
|
|
@@ -11656,6 +11717,9 @@ class SubcSocket {
|
|
|
11656
11717
|
buffered = 0;
|
|
11657
11718
|
waiter = null;
|
|
11658
11719
|
closedErr = null;
|
|
11720
|
+
bufferedBytes() {
|
|
11721
|
+
return this.buffered;
|
|
11722
|
+
}
|
|
11659
11723
|
constructor(sock) {
|
|
11660
11724
|
this.sock = sock;
|
|
11661
11725
|
sock.on("data", (chunk) => {
|
|
@@ -11814,9 +11878,14 @@ class SubcSocket {
|
|
|
11814
11878
|
}
|
|
11815
11879
|
}
|
|
11816
11880
|
|
|
11817
|
-
// ../../node_modules/.bun/@cortexkit+subc-client@0.
|
|
11881
|
+
// ../../node_modules/.bun/@cortexkit+subc-client@0.3.0/node_modules/@cortexkit/subc-client/src/client.ts
|
|
11882
|
+
var debug = debuglog("subc-client");
|
|
11818
11883
|
var DEFAULT_HANDSHAKE_TIMEOUT_MS = 1e4;
|
|
11819
11884
|
var DEFAULT_REQUEST_TIMEOUT_MS = 30000;
|
|
11885
|
+
var TIMEOUT_ARBITRATION_GRACE_MS = 50;
|
|
11886
|
+
var REQUEST_DEADLINE_MARKER = "request_deadline";
|
|
11887
|
+
var DEADLINE_NO_DROP_CODE = "deadline_exceeded_no_drop_observed";
|
|
11888
|
+
var ROUTE_OPEN_RETRY_DEADLINE_MS = 1e4;
|
|
11820
11889
|
var BODY_READ_TIMEOUT_MS = 30000;
|
|
11821
11890
|
var EMPTY_BODY = new Uint8Array(0);
|
|
11822
11891
|
var DEFAULT_MANAGED_TARGET_KIND = "management_surface";
|
|
@@ -11860,6 +11929,7 @@ class SubcClient {
|
|
|
11860
11929
|
closeStarted = false;
|
|
11861
11930
|
reconnecting = null;
|
|
11862
11931
|
generation = 1;
|
|
11932
|
+
readerActive = false;
|
|
11863
11933
|
constructor(sock, currentConn, opts) {
|
|
11864
11934
|
this.sock = sock;
|
|
11865
11935
|
this.currentConn = currentConn;
|
|
@@ -11918,7 +11988,7 @@ class SubcClient {
|
|
|
11918
11988
|
}
|
|
11919
11989
|
continue;
|
|
11920
11990
|
}
|
|
11921
|
-
if (err.kind === "outcome_unknown") {
|
|
11991
|
+
if (err.kind === "outcome_unknown" && err.code !== DEADLINE_NO_DROP_CODE) {
|
|
11922
11992
|
this.scheduleReconnectAfterDrop(err);
|
|
11923
11993
|
}
|
|
11924
11994
|
throw err;
|
|
@@ -12041,7 +12111,7 @@ class SubcClient {
|
|
|
12041
12111
|
timer: null
|
|
12042
12112
|
};
|
|
12043
12113
|
pending.timer = setTimeout(() => {
|
|
12044
|
-
this.
|
|
12114
|
+
this.arbitrateTimeout(key, pending, channel, corr, ms);
|
|
12045
12115
|
}, ms);
|
|
12046
12116
|
this.pending.set(key, pending);
|
|
12047
12117
|
this.sock.write(encodeFrame(frame), Date.now() + ms).catch((err) => {
|
|
@@ -12051,6 +12121,23 @@ class SubcClient {
|
|
|
12051
12121
|
});
|
|
12052
12122
|
});
|
|
12053
12123
|
}
|
|
12124
|
+
arbitrateTimeout(key, pending, channel, corr, ms) {
|
|
12125
|
+
const settleAsTimeout = () => {
|
|
12126
|
+
this.rejectPending(key, pending, new SubcError(this.timeoutMessage(channel, corr, ms), REQUEST_DEADLINE_MARKER));
|
|
12127
|
+
};
|
|
12128
|
+
const graceDeadline = Date.now() + this.opts.timeoutArbitrationGraceMs;
|
|
12129
|
+
const arbitrate = () => {
|
|
12130
|
+
if (this.pending.get(key) !== pending)
|
|
12131
|
+
return;
|
|
12132
|
+
const readerDraining = this.readerActive || this.sock.bufferedBytes() > 0;
|
|
12133
|
+
if (readerDraining && Date.now() < graceDeadline) {
|
|
12134
|
+
setImmediate(arbitrate);
|
|
12135
|
+
return;
|
|
12136
|
+
}
|
|
12137
|
+
settleAsTimeout();
|
|
12138
|
+
};
|
|
12139
|
+
setImmediate(arbitrate);
|
|
12140
|
+
}
|
|
12054
12141
|
async managedRequest(routeChannel, body, opts) {
|
|
12055
12142
|
const bytes = body instanceof Uint8Array ? body : this.encode(body);
|
|
12056
12143
|
const priority = opts.priority ?? 1 /* Interactive */;
|
|
@@ -12075,6 +12162,9 @@ class SubcClient {
|
|
|
12075
12162
|
if (!handedToSocket) {
|
|
12076
12163
|
return this.notSentCallError("request bytes were not queued to the subc socket", err);
|
|
12077
12164
|
}
|
|
12165
|
+
if (err instanceof SubcError && err.code === REQUEST_DEADLINE_MARKER) {
|
|
12166
|
+
return new SubcCallError("outcome_unknown", `managed call deadline exceeded after request bytes were queued to the local socket; no terminal response was observed; outcome unknown${causeMessage(err)}`, DEADLINE_NO_DROP_CODE, err);
|
|
12167
|
+
}
|
|
12078
12168
|
return this.outcomeUnknownCallError("connection dropped before the managed call returned a response", err);
|
|
12079
12169
|
};
|
|
12080
12170
|
return new Promise((resolve7, reject) => {
|
|
@@ -12088,7 +12178,7 @@ class SubcClient {
|
|
|
12088
12178
|
classifyFailure
|
|
12089
12179
|
};
|
|
12090
12180
|
pending.timer = setTimeout(() => {
|
|
12091
|
-
this.
|
|
12181
|
+
this.arbitrateTimeout(key, pending, channel, corr, ms);
|
|
12092
12182
|
}, ms);
|
|
12093
12183
|
this.pending.set(key, pending);
|
|
12094
12184
|
const write = this.sock.writeTracked(encodeFrame(frame), Date.now() + ms);
|
|
@@ -12133,6 +12223,9 @@ class SubcClient {
|
|
|
12133
12223
|
return cached.opening;
|
|
12134
12224
|
}
|
|
12135
12225
|
async openCachedRoute(cached) {
|
|
12226
|
+
const routeRetryDeadline = Date.now() + ROUTE_OPEN_RETRY_DEADLINE_MS;
|
|
12227
|
+
let routeRetryDelay = this.opts.reconnectBackoff.baseMs;
|
|
12228
|
+
let routeRetryAttempt = 0;
|
|
12136
12229
|
for (;; ) {
|
|
12137
12230
|
if (cached.closed)
|
|
12138
12231
|
throw this.routeClosedDuringOpen();
|
|
@@ -12166,6 +12259,15 @@ class SubcClient {
|
|
|
12166
12259
|
}
|
|
12167
12260
|
continue;
|
|
12168
12261
|
}
|
|
12262
|
+
if (!this.closeStarted && err instanceof SubcError && isRetryableRouteOpenCode(err.code)) {
|
|
12263
|
+
routeRetryAttempt += 1;
|
|
12264
|
+
if (routeRetryAttempt < this.opts.reconnectBackoff.maxAttempts && Date.now() < routeRetryDeadline) {
|
|
12265
|
+
await this.opts.sleep(routeRetryDelay);
|
|
12266
|
+
routeRetryDelay = Math.min(routeRetryDelay * 2, this.opts.reconnectBackoff.capMs);
|
|
12267
|
+
continue;
|
|
12268
|
+
}
|
|
12269
|
+
throw this.notSentCallError(`route.open failed for module ${cached.moduleId}: ${err.code} (retry budget exhausted)`, err);
|
|
12270
|
+
}
|
|
12169
12271
|
throw this.terminalCallError(`route.open failed for module ${cached.moduleId}`, err);
|
|
12170
12272
|
}
|
|
12171
12273
|
}
|
|
@@ -12259,9 +12361,16 @@ class SubcClient {
|
|
|
12259
12361
|
try {
|
|
12260
12362
|
for (;; ) {
|
|
12261
12363
|
const headerBytes = await sock.readExact(HEADER_LEN, Number.POSITIVE_INFINITY);
|
|
12262
|
-
|
|
12263
|
-
|
|
12264
|
-
|
|
12364
|
+
this.readerActive = true;
|
|
12365
|
+
try {
|
|
12366
|
+
const header = decodeHeader(headerBytes);
|
|
12367
|
+
const body = header.len === 0 ? new Uint8Array(0) : await sock.readExact(header.len, Date.now() + BODY_READ_TIMEOUT_MS);
|
|
12368
|
+
if (this.sock === sock && this.generation === generation) {
|
|
12369
|
+
this.dispatch({ header, body });
|
|
12370
|
+
}
|
|
12371
|
+
} finally {
|
|
12372
|
+
this.readerActive = false;
|
|
12373
|
+
}
|
|
12265
12374
|
}
|
|
12266
12375
|
} catch (err) {
|
|
12267
12376
|
if (this.sock === sock && this.generation === generation) {
|
|
@@ -12293,13 +12402,20 @@ class SubcClient {
|
|
|
12293
12402
|
this.failChannel(frame.header.channel, new SubcError("route closed by subc (GOODBYE)"));
|
|
12294
12403
|
return;
|
|
12295
12404
|
}
|
|
12405
|
+
if (frame.header.ty === 1 /* Response */ || frame.header.ty === 5 /* Error */ || frame.header.ty === 4 /* StreamEnd */) {
|
|
12406
|
+
debug("dropped terminal frame with no waiter: type=%d channel=%d corr=%s port=%s", frame.header.ty, frame.header.channel, frame.header.corr, this.sock.localPort() ?? "?");
|
|
12407
|
+
return;
|
|
12408
|
+
}
|
|
12296
12409
|
}
|
|
12297
12410
|
settle(key, pending, run) {
|
|
12411
|
+
if (this.pending.get(key) !== pending)
|
|
12412
|
+
return false;
|
|
12298
12413
|
this.pending.delete(key);
|
|
12299
12414
|
if (pending.timer)
|
|
12300
12415
|
clearTimeout(pending.timer);
|
|
12301
12416
|
run();
|
|
12302
12417
|
pending.onSettle?.();
|
|
12418
|
+
return true;
|
|
12303
12419
|
}
|
|
12304
12420
|
rejectPending(key, pending, err) {
|
|
12305
12421
|
this.settle(key, pending, () => pending.reject(pending.classifyFailure?.(err) ?? err));
|
|
@@ -12363,6 +12479,9 @@ function isConsumerReconnectTransient(err) {
|
|
|
12363
12479
|
const code = errorCode(err);
|
|
12364
12480
|
return code === "ECONNREFUSED" || code === "ECONNRESET" || code === "EPIPE" || code === "ETIMEDOUT" || code === "ENOENT";
|
|
12365
12481
|
}
|
|
12482
|
+
function isRetryableRouteOpenCode(code) {
|
|
12483
|
+
return code === "unknown_module" || code === "module_reloading" || code === "target_unavailable" || code === "module_timeout";
|
|
12484
|
+
}
|
|
12366
12485
|
async function connectionFileExists(path2) {
|
|
12367
12486
|
try {
|
|
12368
12487
|
await fs2.access(path2);
|
|
@@ -12378,7 +12497,8 @@ function normalizeConnectOptions(opts) {
|
|
|
12378
12497
|
identity: opts.identity,
|
|
12379
12498
|
targetKind: opts.targetKind ?? DEFAULT_MANAGED_TARGET_KIND,
|
|
12380
12499
|
reconnectBackoff: opts.reconnectBackoff ?? DEFAULT_RECONNECT_BACKOFF,
|
|
12381
|
-
sleep: opts.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)))
|
|
12500
|
+
sleep: opts.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms))),
|
|
12501
|
+
timeoutArbitrationGraceMs: opts.timeoutArbitrationGraceMs ?? TIMEOUT_ARBITRATION_GRACE_MS
|
|
12382
12502
|
};
|
|
12383
12503
|
}
|
|
12384
12504
|
function routeCacheKey(target, identity, consumerIdentity) {
|
|
@@ -12407,7 +12527,7 @@ function causeMessage(cause) {
|
|
|
12407
12527
|
return "";
|
|
12408
12528
|
return `: ${cause instanceof Error ? cause.message : String(cause)}`;
|
|
12409
12529
|
}
|
|
12410
|
-
// ../../node_modules/.bun/@cortexkit+subc-client@0.
|
|
12530
|
+
// ../../node_modules/.bun/@cortexkit+subc-client@0.3.0/node_modules/@cortexkit/subc-client/src/provider.ts
|
|
12411
12531
|
import { Buffer as Buffer2 } from "node:buffer";
|
|
12412
12532
|
var DEFAULT_HANDSHAKE_TIMEOUT_MS2 = 1e4;
|
|
12413
12533
|
var BODY_READ_TIMEOUT_MS2 = 30000;
|
|
@@ -13436,7 +13556,7 @@ async function createAftTransportPool(opts) {
|
|
|
13436
13556
|
return new BridgePool(opts.binaryPath, opts.poolOptions, opts.configOverrides);
|
|
13437
13557
|
}
|
|
13438
13558
|
// src/bg-notifications.ts
|
|
13439
|
-
import { createHash as
|
|
13559
|
+
import { createHash as createHash5, randomUUID as randomUUID2 } from "node:crypto";
|
|
13440
13560
|
|
|
13441
13561
|
// src/logger.ts
|
|
13442
13562
|
import * as fs3 from "node:fs";
|
|
@@ -13600,7 +13720,7 @@ async function resolvePromptContext(client, sessionId) {
|
|
|
13600
13720
|
|
|
13601
13721
|
// src/bg-notifications.ts
|
|
13602
13722
|
function hashReminder(text) {
|
|
13603
|
-
return
|
|
13723
|
+
return createHash5("sha256").update(text).digest("hex").slice(0, 16);
|
|
13604
13724
|
}
|
|
13605
13725
|
var CONSUMED_TASKIDS_CAP = 256;
|
|
13606
13726
|
var DELIVERED_AWAITING_ACK_CAP = 4096;
|
|
@@ -14364,7 +14484,7 @@ function formatDuration(completion) {
|
|
|
14364
14484
|
}
|
|
14365
14485
|
|
|
14366
14486
|
// src/config.ts
|
|
14367
|
-
import { existsSync as existsSync7, readFileSync as
|
|
14487
|
+
import { existsSync as existsSync7, readFileSync as readFileSync7, renameSync as renameSync5, unlinkSync as unlinkSync5, writeFileSync as writeFileSync4 } from "node:fs";
|
|
14368
14488
|
var import_comment_json = __toESM(require_src2(), 1);
|
|
14369
14489
|
|
|
14370
14490
|
// ../../node_modules/.bun/zod@4.4.3/node_modules/zod/v4/classic/external.js
|
|
@@ -28956,7 +29076,7 @@ function migrateAftConfigFile2(configPath, logger = { log: log2, warn: warn2 })
|
|
|
28956
29076
|
let tmpPath = null;
|
|
28957
29077
|
let oldKeys = [];
|
|
28958
29078
|
try {
|
|
28959
|
-
const content =
|
|
29079
|
+
const content = readFileSync7(configPath, "utf-8");
|
|
28960
29080
|
const rawConfig = import_comment_json.parse(content);
|
|
28961
29081
|
if (!rawConfig || typeof rawConfig !== "object" || Array.isArray(rawConfig)) {
|
|
28962
29082
|
return { migrated: false, oldKeys: [] };
|
|
@@ -29033,7 +29153,7 @@ function loadConfigFromPath(configPath) {
|
|
|
29033
29153
|
if (!existsSync7(configPath)) {
|
|
29034
29154
|
return null;
|
|
29035
29155
|
}
|
|
29036
|
-
const content =
|
|
29156
|
+
const content = readFileSync7(configPath, "utf-8");
|
|
29037
29157
|
const rawConfig = import_comment_json.parse(content);
|
|
29038
29158
|
migrateRawConfig(rawConfig, configPath, { log: log2, warn: warn2 });
|
|
29039
29159
|
const cleanConfig = stripJsoncSymbols(rawConfig);
|
|
@@ -29301,7 +29421,7 @@ function loadAftConfig(projectDirectory) {
|
|
|
29301
29421
|
}
|
|
29302
29422
|
|
|
29303
29423
|
// src/notifications.ts
|
|
29304
|
-
import { existsSync as existsSync8, readFileSync as
|
|
29424
|
+
import { existsSync as existsSync8, readFileSync as readFileSync8 } from "node:fs";
|
|
29305
29425
|
import { homedir as homedir9, platform } from "node:os";
|
|
29306
29426
|
import { join as join11 } from "node:path";
|
|
29307
29427
|
function isTuiMode() {
|
|
@@ -29344,7 +29464,7 @@ function readDesktopState() {
|
|
|
29344
29464
|
return { serverUrl: null };
|
|
29345
29465
|
}
|
|
29346
29466
|
try {
|
|
29347
|
-
const raw =
|
|
29467
|
+
const raw = readFileSync8(statePath, "utf-8");
|
|
29348
29468
|
const state = JSON.parse(raw);
|
|
29349
29469
|
let serverUrl = null;
|
|
29350
29470
|
const serverStr = state.server;
|
|
@@ -29843,7 +29963,7 @@ import {
|
|
|
29843
29963
|
existsSync as existsSync11,
|
|
29844
29964
|
mkdirSync as mkdirSync6,
|
|
29845
29965
|
openSync as openSync5,
|
|
29846
|
-
readFileSync as
|
|
29966
|
+
readFileSync as readFileSync11,
|
|
29847
29967
|
renameSync as renameSync6,
|
|
29848
29968
|
rmSync as rmSync5,
|
|
29849
29969
|
writeFileSync as writeFileSync7
|
|
@@ -29852,14 +29972,14 @@ import { dirname as dirname7 } from "node:path";
|
|
|
29852
29972
|
|
|
29853
29973
|
// src/hooks/auto-update-checker/cache.ts
|
|
29854
29974
|
import { spawn as spawn2 } from "node:child_process";
|
|
29855
|
-
import { cpSync, existsSync as existsSync10, mkdtempSync, readFileSync as
|
|
29975
|
+
import { cpSync, existsSync as existsSync10, mkdtempSync, readFileSync as readFileSync10, rmSync as rmSync4, writeFileSync as writeFileSync6 } from "node:fs";
|
|
29856
29976
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
29857
29977
|
import { basename as basename3, dirname as dirname6, join as join14 } from "node:path";
|
|
29858
29978
|
var import_comment_json3 = __toESM(require_src2(), 1);
|
|
29859
29979
|
|
|
29860
29980
|
// src/hooks/auto-update-checker/checker.ts
|
|
29861
29981
|
var import_comment_json2 = __toESM(require_src2(), 1);
|
|
29862
|
-
import { existsSync as existsSync9, readFileSync as
|
|
29982
|
+
import { existsSync as existsSync9, readFileSync as readFileSync9, statSync as statSync5, writeFileSync as writeFileSync5 } from "node:fs";
|
|
29863
29983
|
import { homedir as homedir11 } from "node:os";
|
|
29864
29984
|
import { dirname as dirname5, isAbsolute as isAbsolute6, join as join13, resolve as resolve7 } from "node:path";
|
|
29865
29985
|
import { fileURLToPath } from "node:url";
|
|
@@ -29965,7 +30085,7 @@ function getLocalDevPath(directory) {
|
|
|
29965
30085
|
try {
|
|
29966
30086
|
if (!existsSync9(configPath))
|
|
29967
30087
|
continue;
|
|
29968
|
-
const rawConfig = parseJsonConfig(
|
|
30088
|
+
const rawConfig = parseJsonConfig(readFileSync9(configPath, "utf-8"));
|
|
29969
30089
|
const plugins = getPluginEntries(rawConfig);
|
|
29970
30090
|
for (const entry of plugins) {
|
|
29971
30091
|
if (entry === PACKAGE_NAME || entry.startsWith(`${PACKAGE_NAME}@`))
|
|
@@ -29975,7 +30095,7 @@ function getLocalDevPath(directory) {
|
|
|
29975
30095
|
const pkgPath = findPackageJsonUp(localPath);
|
|
29976
30096
|
if (!pkgPath)
|
|
29977
30097
|
continue;
|
|
29978
|
-
const pkg = PackageJsonSchema.safeParse(JSON.parse(
|
|
30098
|
+
const pkg = PackageJsonSchema.safeParse(JSON.parse(readFileSync9(pkgPath, "utf-8")));
|
|
29979
30099
|
if (pkg.success && pkg.data.name === PACKAGE_NAME)
|
|
29980
30100
|
return localPath;
|
|
29981
30101
|
}
|
|
@@ -29992,7 +30112,7 @@ function findPackageJsonUp(startPath) {
|
|
|
29992
30112
|
const pkgPath = join13(dir, "package.json");
|
|
29993
30113
|
if (existsSync9(pkgPath)) {
|
|
29994
30114
|
try {
|
|
29995
|
-
const pkg = PackageJsonSchema.safeParse(JSON.parse(
|
|
30115
|
+
const pkg = PackageJsonSchema.safeParse(JSON.parse(readFileSync9(pkgPath, "utf-8")));
|
|
29996
30116
|
if (pkg.success && pkg.data.name === PACKAGE_NAME)
|
|
29997
30117
|
return pkgPath;
|
|
29998
30118
|
} catch {}
|
|
@@ -30013,7 +30133,7 @@ function getLocalDevVersion(directory) {
|
|
|
30013
30133
|
const pkgPath = findPackageJsonUp(localPath);
|
|
30014
30134
|
if (!pkgPath)
|
|
30015
30135
|
return null;
|
|
30016
|
-
const pkg = PackageJsonSchema.safeParse(JSON.parse(
|
|
30136
|
+
const pkg = PackageJsonSchema.safeParse(JSON.parse(readFileSync9(pkgPath, "utf-8")));
|
|
30017
30137
|
return pkg.success ? pkg.data.version ?? null : null;
|
|
30018
30138
|
} catch {
|
|
30019
30139
|
return null;
|
|
@@ -30032,7 +30152,7 @@ function findPluginEntry(directory) {
|
|
|
30032
30152
|
try {
|
|
30033
30153
|
if (!existsSync9(configPath))
|
|
30034
30154
|
continue;
|
|
30035
|
-
const rawConfig = parseJsonConfig(
|
|
30155
|
+
const rawConfig = parseJsonConfig(readFileSync9(configPath, "utf-8"));
|
|
30036
30156
|
const plugins = getPluginEntries(rawConfig);
|
|
30037
30157
|
for (const entry of plugins) {
|
|
30038
30158
|
if (entry === PACKAGE_NAME) {
|
|
@@ -30065,7 +30185,7 @@ function getCachedVersion(spec) {
|
|
|
30065
30185
|
try {
|
|
30066
30186
|
if (!existsSync9(packageJsonPath))
|
|
30067
30187
|
continue;
|
|
30068
|
-
const pkg = PackageJsonSchema.safeParse(JSON.parse(
|
|
30188
|
+
const pkg = PackageJsonSchema.safeParse(JSON.parse(readFileSync9(packageJsonPath, "utf-8")));
|
|
30069
30189
|
if (pkg.success && pkg.data.version) {
|
|
30070
30190
|
if (!spec)
|
|
30071
30191
|
cachedPackageVersion = pkg.data.version;
|
|
@@ -30115,9 +30235,9 @@ function createAutoUpdateSnapshot(installDir, packageJsonPath, packageName) {
|
|
|
30115
30235
|
cpSync(packageDir, stagedPackageDir, { recursive: true });
|
|
30116
30236
|
return {
|
|
30117
30237
|
packageJsonPath,
|
|
30118
|
-
packageJson: existsSync10(packageJsonPath) ?
|
|
30238
|
+
packageJson: existsSync10(packageJsonPath) ? readFileSync10(packageJsonPath, "utf-8") : null,
|
|
30119
30239
|
lockfilePath,
|
|
30120
|
-
lockfile: existsSync10(lockfilePath) ?
|
|
30240
|
+
lockfile: existsSync10(lockfilePath) ? readFileSync10(lockfilePath, "utf-8") : null,
|
|
30121
30241
|
packageDir,
|
|
30122
30242
|
stagedPackageDir,
|
|
30123
30243
|
tempDir
|
|
@@ -30155,7 +30275,7 @@ function removeFromPackageLock(installDir, packageName) {
|
|
|
30155
30275
|
if (!existsSync10(lockPath))
|
|
30156
30276
|
return false;
|
|
30157
30277
|
try {
|
|
30158
|
-
const lock = import_comment_json3.parse(
|
|
30278
|
+
const lock = import_comment_json3.parse(readFileSync10(lockPath, "utf-8"));
|
|
30159
30279
|
let modified = false;
|
|
30160
30280
|
if (lock.packages) {
|
|
30161
30281
|
const key = `node_modules/${packageName}`;
|
|
@@ -30181,7 +30301,7 @@ function ensureDependencyVersion(packageJsonPath, packageName, version2) {
|
|
|
30181
30301
|
if (!existsSync10(packageJsonPath))
|
|
30182
30302
|
return false;
|
|
30183
30303
|
try {
|
|
30184
|
-
const raw = import_comment_json3.parse(
|
|
30304
|
+
const raw = import_comment_json3.parse(readFileSync10(packageJsonPath, "utf-8"));
|
|
30185
30305
|
const pkgJson = PackageJsonSchema.safeParse(raw);
|
|
30186
30306
|
if (!pkgJson.success)
|
|
30187
30307
|
return false;
|
|
@@ -30435,7 +30555,7 @@ function hasRecentCheckTimestamp(file2, intervalMs) {
|
|
|
30435
30555
|
if (!existsSync11(file2))
|
|
30436
30556
|
return false;
|
|
30437
30557
|
try {
|
|
30438
|
-
const raw = JSON.parse(
|
|
30558
|
+
const raw = JSON.parse(readFileSync11(file2, "utf-8"));
|
|
30439
30559
|
const last = typeof raw.lastCheckedMs === "number" ? raw.lastCheckedMs : 0;
|
|
30440
30560
|
return Number.isFinite(last) && Date.now() - last < intervalMs;
|
|
30441
30561
|
} catch {
|
|
@@ -30539,12 +30659,12 @@ function showToast(ctx, title, message, variant = "info", duration3 = 3000) {
|
|
|
30539
30659
|
|
|
30540
30660
|
// src/lsp-auto-install.ts
|
|
30541
30661
|
import { spawn as spawn3 } from "node:child_process";
|
|
30542
|
-
import { createHash as
|
|
30662
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
30543
30663
|
import {
|
|
30544
30664
|
createReadStream,
|
|
30545
30665
|
existsSync as existsSync13,
|
|
30546
30666
|
mkdirSync as mkdirSync8,
|
|
30547
|
-
readFileSync as
|
|
30667
|
+
readFileSync as readFileSync14,
|
|
30548
30668
|
renameSync as renameSync7,
|
|
30549
30669
|
rmSync as rmSync6,
|
|
30550
30670
|
statSync as statSync7,
|
|
@@ -30557,7 +30677,7 @@ import {
|
|
|
30557
30677
|
closeSync as closeSync6,
|
|
30558
30678
|
mkdirSync as mkdirSync7,
|
|
30559
30679
|
openSync as openSync6,
|
|
30560
|
-
readFileSync as
|
|
30680
|
+
readFileSync as readFileSync12,
|
|
30561
30681
|
statSync as statSync6,
|
|
30562
30682
|
unlinkSync as unlinkSync6,
|
|
30563
30683
|
writeFileSync as writeFileSync8
|
|
@@ -30621,7 +30741,7 @@ function readInstalledMetaIn(installDir) {
|
|
|
30621
30741
|
try {
|
|
30622
30742
|
if (!statSync6(path3).isFile())
|
|
30623
30743
|
return null;
|
|
30624
|
-
const raw =
|
|
30744
|
+
const raw = readFileSync12(path3, "utf8");
|
|
30625
30745
|
const parsed = JSON.parse(raw);
|
|
30626
30746
|
if (typeof parsed.version !== "string" || parsed.version.length === 0)
|
|
30627
30747
|
return null;
|
|
@@ -30671,7 +30791,7 @@ ${new Date().toISOString()}
|
|
|
30671
30791
|
let owningPid = null;
|
|
30672
30792
|
let lockMtimeMs = 0;
|
|
30673
30793
|
try {
|
|
30674
|
-
const raw =
|
|
30794
|
+
const raw = readFileSync12(lock, "utf8");
|
|
30675
30795
|
const firstLine = raw.split(/\r?\n/, 1)[0]?.trim() ?? "";
|
|
30676
30796
|
const parsed = Number.parseInt(firstLine, 10);
|
|
30677
30797
|
if (Number.isFinite(parsed) && parsed > 0)
|
|
@@ -30709,7 +30829,7 @@ function releaseInstallLock(lockKey) {
|
|
|
30709
30829
|
try {
|
|
30710
30830
|
let owningPid = null;
|
|
30711
30831
|
try {
|
|
30712
|
-
const raw =
|
|
30832
|
+
const raw = readFileSync12(lock, "utf8");
|
|
30713
30833
|
const firstLine = raw.split(/\r?\n/, 1)[0]?.trim() ?? "";
|
|
30714
30834
|
const parsed = Number.parseInt(firstLine, 10);
|
|
30715
30835
|
if (Number.isFinite(parsed) && parsed > 0)
|
|
@@ -30750,7 +30870,7 @@ var VERSION_CHECK_FILE = ".aft-version-check";
|
|
|
30750
30870
|
function readVersionCheck(npmPackage) {
|
|
30751
30871
|
const file2 = join15(lspPackageDir(npmPackage), VERSION_CHECK_FILE);
|
|
30752
30872
|
try {
|
|
30753
|
-
const raw =
|
|
30873
|
+
const raw = readFileSync12(file2, "utf8");
|
|
30754
30874
|
const parsed = JSON.parse(raw);
|
|
30755
30875
|
if (typeof parsed.last_checked === "string") {
|
|
30756
30876
|
return {
|
|
@@ -30927,7 +31047,7 @@ var NPM_LSP_TABLE = [
|
|
|
30927
31047
|
];
|
|
30928
31048
|
|
|
30929
31049
|
// src/lsp-project-relevance.ts
|
|
30930
|
-
import { existsSync as existsSync12, readdirSync as readdirSync3, readFileSync as
|
|
31050
|
+
import { existsSync as existsSync12, readdirSync as readdirSync3, readFileSync as readFileSync13 } from "node:fs";
|
|
30931
31051
|
import { join as join16 } from "node:path";
|
|
30932
31052
|
var MAX_WALK_DIRS = 200;
|
|
30933
31053
|
var MAX_WALK_DEPTH = 4;
|
|
@@ -30969,7 +31089,7 @@ function hasPackageJsonDep(projectRoot, depNames) {
|
|
|
30969
31089
|
}
|
|
30970
31090
|
function readPackageJson(projectRoot) {
|
|
30971
31091
|
try {
|
|
30972
|
-
const raw =
|
|
31092
|
+
const raw = readFileSync13(join16(projectRoot, "package.json"), "utf8");
|
|
30973
31093
|
const parsed = JSON.parse(raw);
|
|
30974
31094
|
if (typeof parsed !== "object" || parsed === null)
|
|
30975
31095
|
return null;
|
|
@@ -31291,7 +31411,7 @@ function hashInstalledBinary(spec) {
|
|
|
31291
31411
|
reject(new Error(`installed binary not found at any of: ${candidates.join(", ")}`));
|
|
31292
31412
|
return;
|
|
31293
31413
|
}
|
|
31294
|
-
const hash2 =
|
|
31414
|
+
const hash2 = createHash6("sha256");
|
|
31295
31415
|
const stream = createReadStream(pathToHash);
|
|
31296
31416
|
stream.on("error", reject);
|
|
31297
31417
|
stream.on("data", (chunk) => hash2.update(chunk));
|
|
@@ -31314,7 +31434,7 @@ function installedBinaryPath(spec) {
|
|
|
31314
31434
|
return null;
|
|
31315
31435
|
}
|
|
31316
31436
|
function sha256OfFileSync(path3) {
|
|
31317
|
-
return
|
|
31437
|
+
return createHash6("sha256").update(readFileSync14(path3)).digest("hex");
|
|
31318
31438
|
}
|
|
31319
31439
|
function quarantineCachedNpmInstall(spec, reason) {
|
|
31320
31440
|
const packageDir = lspPackageDir(spec.npm);
|
|
@@ -31399,7 +31519,7 @@ function runAutoInstall(projectRoot, config2, fetchImpl = fetch) {
|
|
|
31399
31519
|
|
|
31400
31520
|
// src/lsp-github-install.ts
|
|
31401
31521
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
31402
|
-
import { createHash as
|
|
31522
|
+
import { createHash as createHash7, randomBytes as randomBytes2 } from "node:crypto";
|
|
31403
31523
|
import {
|
|
31404
31524
|
copyFileSync as copyFileSync4,
|
|
31405
31525
|
createReadStream as createReadStream2,
|
|
@@ -31408,7 +31528,7 @@ import {
|
|
|
31408
31528
|
lstatSync as lstatSync2,
|
|
31409
31529
|
mkdirSync as mkdirSync9,
|
|
31410
31530
|
readdirSync as readdirSync4,
|
|
31411
|
-
readFileSync as
|
|
31531
|
+
readFileSync as readFileSync15,
|
|
31412
31532
|
readlinkSync as readlinkSync2,
|
|
31413
31533
|
realpathSync as realpathSync3,
|
|
31414
31534
|
renameSync as renameSync8,
|
|
@@ -31542,7 +31662,7 @@ function readGithubInstalledMetaIn(installDir) {
|
|
|
31542
31662
|
const path3 = join18(installDir, INSTALLED_META_FILE2);
|
|
31543
31663
|
if (!statSync8(path3).isFile())
|
|
31544
31664
|
return null;
|
|
31545
|
-
const parsed = JSON.parse(
|
|
31665
|
+
const parsed = JSON.parse(readFileSync15(path3, "utf8"));
|
|
31546
31666
|
if (typeof parsed.version !== "string" || parsed.version.length === 0)
|
|
31547
31667
|
return null;
|
|
31548
31668
|
return {
|
|
@@ -31575,7 +31695,7 @@ var MAX_DOWNLOAD_BYTES3 = 256 * 1024 * 1024;
|
|
|
31575
31695
|
var MAX_EXTRACT_BYTES2 = 1024 * 1024 * 1024;
|
|
31576
31696
|
function sha256OfFile(path3) {
|
|
31577
31697
|
return new Promise((resolve9, reject) => {
|
|
31578
|
-
const hash2 =
|
|
31698
|
+
const hash2 = createHash7("sha256");
|
|
31579
31699
|
const stream = createReadStream2(path3);
|
|
31580
31700
|
stream.on("error", reject);
|
|
31581
31701
|
stream.on("data", (chunk) => hash2.update(chunk));
|
|
@@ -31583,7 +31703,7 @@ function sha256OfFile(path3) {
|
|
|
31583
31703
|
});
|
|
31584
31704
|
}
|
|
31585
31705
|
function sha256OfFileSync2(path3) {
|
|
31586
|
-
return
|
|
31706
|
+
return createHash7("sha256").update(readFileSync15(path3)).digest("hex");
|
|
31587
31707
|
}
|
|
31588
31708
|
async function fetchReleaseByTag(githubRepo, tag, fetchImpl, signal) {
|
|
31589
31709
|
const candidates = [];
|
|
@@ -32362,7 +32482,7 @@ import {
|
|
|
32362
32482
|
existsSync as existsSync15,
|
|
32363
32483
|
mkdirSync as mkdirSync10,
|
|
32364
32484
|
readdirSync as readdirSync5,
|
|
32365
|
-
readFileSync as
|
|
32485
|
+
readFileSync as readFileSync16,
|
|
32366
32486
|
renameSync as renameSync9,
|
|
32367
32487
|
unlinkSync as unlinkSync8,
|
|
32368
32488
|
writeFileSync as writeFileSync11
|
|
@@ -32542,7 +32662,7 @@ class AftRpcServer {
|
|
|
32542
32662
|
if (filePath === this.portFilePath)
|
|
32543
32663
|
continue;
|
|
32544
32664
|
try {
|
|
32545
|
-
const record2 = parseRpcPortRecord(
|
|
32665
|
+
const record2 = parseRpcPortRecord(readFileSync16(filePath, "utf-8"));
|
|
32546
32666
|
if (record2 === null) {
|
|
32547
32667
|
unlinkSync8(filePath);
|
|
32548
32668
|
continue;
|
|
@@ -36315,13 +36435,13 @@ var PLUGIN_VERSION = (() => {
|
|
|
36315
36435
|
return "0.0.0";
|
|
36316
36436
|
}
|
|
36317
36437
|
})();
|
|
36318
|
-
var ANNOUNCEMENT_VERSION = "0.
|
|
36438
|
+
var ANNOUNCEMENT_VERSION = "0.45.0";
|
|
36319
36439
|
var ANNOUNCEMENT_FEATURES = [
|
|
36320
|
-
"Code Health
|
|
36321
|
-
"
|
|
36322
|
-
"
|
|
36323
|
-
"
|
|
36324
|
-
"
|
|
36440
|
+
"Code Health verified against 12 real repositories: dead code is only reported for languages we can actually analyze (Java/Kotlin now say 'not analyzed' instead of guessing), and generated code (gen/ trees, *_pb.ts, DO NOT EDIT banners) moves out of the headline counts into its own bucket.",
|
|
36441
|
+
"Config files (playwright/eslint/tsup/vitest *.config.ts), Storybook stories, Mocha hooks, and SvelteKit hooks/$lib imports are no longer flagged as dead code.",
|
|
36442
|
+
"Rust module aliases, inline-module calls, and cross-crate pub use re-exports now resolve; Go interface methods (sort.Interface, Bubble Tea) are no longer flagged dead.",
|
|
36443
|
+
"Fixed npx @cortexkit/aft doctor --fix and setup failing to download the binary on fresh installs.",
|
|
36444
|
+
"Bridges now detect an updated aft binary on disk and respawn onto it automatically."
|
|
36325
36445
|
];
|
|
36326
36446
|
var ANNOUNCEMENT_FOOTER = "Join us on Discord: https://discord.gg/DSa65w8wuf";
|
|
36327
36447
|
var plugin = async (input) => initializePluginForDirectory(input);
|
package/dist/tui.js
CHANGED
|
@@ -7790,10 +7790,10 @@ var require_src2 = __commonJS((exports, module) => {
|
|
|
7790
7790
|
// src/tui/index.tsx
|
|
7791
7791
|
import { createMemo as createMemo2, createSignal as createSignal2, onCleanup as onCleanup2 } from "solid-js";
|
|
7792
7792
|
// package.json
|
|
7793
|
-
var version = "0.
|
|
7793
|
+
var version = "0.45.0";
|
|
7794
7794
|
|
|
7795
7795
|
// src/shared/rpc-client.ts
|
|
7796
|
-
import { existsSync, readdirSync, readFileSync, unlinkSync } from "node:fs";
|
|
7796
|
+
import { existsSync, readdirSync, readFileSync as readFileSync2, unlinkSync } from "node:fs";
|
|
7797
7797
|
import { join as join3 } from "node:path";
|
|
7798
7798
|
|
|
7799
7799
|
// src/shared/rpc-utils.ts
|
|
@@ -7856,6 +7856,8 @@ function error(message, meta) {
|
|
|
7856
7856
|
}
|
|
7857
7857
|
// ../aft-bridge/dist/bridge.js
|
|
7858
7858
|
import { spawn } from "node:child_process";
|
|
7859
|
+
import { createHash } from "node:crypto";
|
|
7860
|
+
import { readFileSync } from "node:fs";
|
|
7859
7861
|
import { homedir } from "node:os";
|
|
7860
7862
|
import { join } from "node:path";
|
|
7861
7863
|
import { StringDecoder } from "node:string_decoder";
|
|
@@ -7912,6 +7914,22 @@ function bashTaskIdFrom(response) {
|
|
|
7912
7914
|
return camelCase;
|
|
7913
7915
|
return;
|
|
7914
7916
|
}
|
|
7917
|
+
function hashBinaryOnDisk(binaryPath) {
|
|
7918
|
+
try {
|
|
7919
|
+
return createHash("sha256").update(readFileSync(binaryPath)).digest("hex");
|
|
7920
|
+
} catch {
|
|
7921
|
+
return null;
|
|
7922
|
+
}
|
|
7923
|
+
}
|
|
7924
|
+
var binaryFingerprintReader = hashBinaryOnDisk;
|
|
7925
|
+
function readBinaryFingerprint(binaryPath) {
|
|
7926
|
+
try {
|
|
7927
|
+
const fingerprint = binaryFingerprintReader(binaryPath);
|
|
7928
|
+
return typeof fingerprint === "string" && fingerprint.length > 0 ? fingerprint : null;
|
|
7929
|
+
} catch {
|
|
7930
|
+
return null;
|
|
7931
|
+
}
|
|
7932
|
+
}
|
|
7915
7933
|
function tagStderrLine(line) {
|
|
7916
7934
|
return /^\[aft(-\w+)?\] /.test(line) ? line : `[aft] ${line}`;
|
|
7917
7935
|
}
|
|
@@ -8003,6 +8021,9 @@ class BinaryBridge {
|
|
|
8003
8021
|
binaryPath;
|
|
8004
8022
|
cwd;
|
|
8005
8023
|
process = null;
|
|
8024
|
+
spawnedBinaryFingerprint = null;
|
|
8025
|
+
lastBinaryFingerprintCheckAt = 0;
|
|
8026
|
+
_retiringDueToBinaryChange = false;
|
|
8006
8027
|
pending = new Map;
|
|
8007
8028
|
outstandingBackgroundTaskIds = new Set;
|
|
8008
8029
|
nextId = 1;
|
|
@@ -8122,6 +8143,24 @@ class BinaryBridge {
|
|
|
8122
8143
|
hasOutstandingBackgroundTasks() {
|
|
8123
8144
|
return this.outstandingBackgroundTaskIds.size > 0;
|
|
8124
8145
|
}
|
|
8146
|
+
maybeScheduleRespawnForUpdatedBinary(checkIntervalMs, now = Date.now()) {
|
|
8147
|
+
if (this._shuttingDown || this._retiringDueToBinaryChange || !this.isAlive())
|
|
8148
|
+
return false;
|
|
8149
|
+
if (this.pending.size > 0 || this.outstandingBackgroundTaskIds.size > 0)
|
|
8150
|
+
return false;
|
|
8151
|
+
if (now - this.lastBinaryFingerprintCheckAt < checkIntervalMs)
|
|
8152
|
+
return false;
|
|
8153
|
+
this.lastBinaryFingerprintCheckAt = now;
|
|
8154
|
+
const spawnedFingerprint = this.spawnedBinaryFingerprint;
|
|
8155
|
+
if (!spawnedFingerprint)
|
|
8156
|
+
return false;
|
|
8157
|
+
const currentFingerprint = readBinaryFingerprint(this.binaryPath);
|
|
8158
|
+
if (!currentFingerprint || currentFingerprint === spawnedFingerprint)
|
|
8159
|
+
return false;
|
|
8160
|
+
this._retiringDueToBinaryChange = true;
|
|
8161
|
+
this.logVia(`Binary contents changed on disk for ${this.binaryPath}; retiring this bridge so the next tool call respawns onto the updated binary.`);
|
|
8162
|
+
return true;
|
|
8163
|
+
}
|
|
8125
8164
|
getCwd() {
|
|
8126
8165
|
return this.cwd;
|
|
8127
8166
|
}
|
|
@@ -8154,6 +8193,9 @@ class BinaryBridge {
|
|
|
8154
8193
|
}
|
|
8155
8194
|
async sendWithVersionMismatchRetry(command, params, options, canRetryAfterVersionSwap) {
|
|
8156
8195
|
try {
|
|
8196
|
+
if (this._retiringDueToBinaryChange) {
|
|
8197
|
+
throw new Error(`${this.errorPrefix} Bridge is retiring after the on-disk binary changed; retry to respawn on the updated binary`);
|
|
8198
|
+
}
|
|
8157
8199
|
if (this._shuttingDown) {
|
|
8158
8200
|
throw new Error(`${this.errorPrefix} Bridge is shutting down, cannot send "${command}"`);
|
|
8159
8201
|
}
|
|
@@ -8352,6 +8394,7 @@ class BinaryBridge {
|
|
|
8352
8394
|
}
|
|
8353
8395
|
async shutdown() {
|
|
8354
8396
|
this._shuttingDown = true;
|
|
8397
|
+
this.spawnedBinaryFingerprint = null;
|
|
8355
8398
|
this.clearRestartResetTimer();
|
|
8356
8399
|
this.configureWarningClients.clear();
|
|
8357
8400
|
this.rejectAllPending(new Error(`${this.errorPrefix} Bridge shutting down`));
|
|
@@ -8405,6 +8448,9 @@ class BinaryBridge {
|
|
|
8405
8448
|
async replaceCurrentBinary(newBinaryPath) {
|
|
8406
8449
|
this.binaryPath = newBinaryPath;
|
|
8407
8450
|
this.configured = false;
|
|
8451
|
+
this.spawnedBinaryFingerprint = null;
|
|
8452
|
+
this.lastBinaryFingerprintCheckAt = 0;
|
|
8453
|
+
this._retiringDueToBinaryChange = false;
|
|
8408
8454
|
this.clearRestartResetTimer();
|
|
8409
8455
|
this.rejectAllPending(new Error(`${this.errorPrefix} Bridge restarting with updated binary: ${newBinaryPath}`));
|
|
8410
8456
|
if (!this.process)
|
|
@@ -8430,6 +8476,7 @@ class BinaryBridge {
|
|
|
8430
8476
|
this.spawnProcess(triggeringSessionId);
|
|
8431
8477
|
}
|
|
8432
8478
|
spawnProcess(triggeringSessionId) {
|
|
8479
|
+
this._retiringDueToBinaryChange = false;
|
|
8433
8480
|
this.lastStatusBar = undefined;
|
|
8434
8481
|
if (triggeringSessionId) {
|
|
8435
8482
|
this.sessionLogVia(triggeringSessionId, `Spawning binary: ${this.binaryPath} (cwd: ${this.cwd})`);
|
|
@@ -8520,6 +8567,8 @@ class BinaryBridge {
|
|
|
8520
8567
|
this.handleCrash();
|
|
8521
8568
|
});
|
|
8522
8569
|
this.process = child;
|
|
8570
|
+
this.spawnedBinaryFingerprint = readBinaryFingerprint(this.binaryPath);
|
|
8571
|
+
this.lastBinaryFingerprintCheckAt = Date.now();
|
|
8523
8572
|
this.stdoutBuffer = "";
|
|
8524
8573
|
this.stdoutReadOffset = 0;
|
|
8525
8574
|
this.stderrBuffer = "";
|
|
@@ -8698,6 +8747,7 @@ class BinaryBridge {
|
|
|
8698
8747
|
}
|
|
8699
8748
|
handleTimeout(triggeringSessionId) {
|
|
8700
8749
|
this.consecutiveRequestTimeouts = 0;
|
|
8750
|
+
this.spawnedBinaryFingerprint = null;
|
|
8701
8751
|
this.rejectAllPending(new Error(`${this.errorPrefix} bridge killed during sibling timeout — request aborted`));
|
|
8702
8752
|
this.outstandingBackgroundTaskIds.clear();
|
|
8703
8753
|
if (this.process) {
|
|
@@ -8724,6 +8774,7 @@ class BinaryBridge {
|
|
|
8724
8774
|
handleCrash(cause) {
|
|
8725
8775
|
const proc = this.process;
|
|
8726
8776
|
this.process = null;
|
|
8777
|
+
this.spawnedBinaryFingerprint = null;
|
|
8727
8778
|
if (proc && proc.exitCode === null && !proc.killed) {
|
|
8728
8779
|
proc.kill("SIGKILL");
|
|
8729
8780
|
}
|
|
@@ -8735,6 +8786,10 @@ class BinaryBridge {
|
|
|
8735
8786
|
this.errorVia(`Binary crashed (restarts: ${this._restartCount})${cause ? `: ${cause.message}` : ""}.${tail}`);
|
|
8736
8787
|
}
|
|
8737
8788
|
this.rejectAllPending(new Error(`${this.errorPrefix} Binary crashed (restarts: ${this._restartCount})${cause ? `: ${cause.message}` : ""} (see ${this.getLogFilePathVia()})`));
|
|
8789
|
+
if (this._retiringDueToBinaryChange) {
|
|
8790
|
+
this.logVia("Binary exited while retiring after an on-disk update; skipping auto-restart");
|
|
8791
|
+
return;
|
|
8792
|
+
}
|
|
8738
8793
|
if (this._restartCount < this.maxRestarts) {
|
|
8739
8794
|
const delay = 100 * 2 ** this._restartCount;
|
|
8740
8795
|
this._restartCount++;
|
|
@@ -8819,7 +8874,7 @@ var ORT_PLATFORM_MAP = {
|
|
|
8819
8874
|
}
|
|
8820
8875
|
};
|
|
8821
8876
|
// ../aft-bridge/dist/project-identity.js
|
|
8822
|
-
import { createHash } from "node:crypto";
|
|
8877
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
8823
8878
|
import { realpathSync } from "node:fs";
|
|
8824
8879
|
import { resolve } from "node:path";
|
|
8825
8880
|
function canonicalizeProjectRoot(dir) {
|
|
@@ -8850,7 +8905,7 @@ function normalizeWindowsRoot(p) {
|
|
|
8850
8905
|
return s;
|
|
8851
8906
|
}
|
|
8852
8907
|
function projectRootKeyHash(dir) {
|
|
8853
|
-
return
|
|
8908
|
+
return createHash2("sha256").update(canonicalizeProjectRoot(dir)).digest("hex").slice(0, 16);
|
|
8854
8909
|
}
|
|
8855
8910
|
|
|
8856
8911
|
// ../aft-bridge/dist/pool.js
|
|
@@ -8934,6 +8989,11 @@ class BridgePool {
|
|
|
8934
8989
|
for (const [dir, entry] of this.bridges) {
|
|
8935
8990
|
if (entry.bridge.hasPendingRequests() || entry.bridge.hasOutstandingBackgroundTasks())
|
|
8936
8991
|
continue;
|
|
8992
|
+
if (entry.bridge.maybeScheduleRespawnForUpdatedBinary(CLEANUP_INTERVAL_MS, now)) {
|
|
8993
|
+
this.staleBridges.add(entry.bridge);
|
|
8994
|
+
this.bridges.delete(dir);
|
|
8995
|
+
continue;
|
|
8996
|
+
}
|
|
8937
8997
|
if (now - entry.lastUsed > this.idleTimeoutMs) {
|
|
8938
8998
|
entry.bridge.shutdown().catch((err) => this.error("cleanup shutdown failed:", err));
|
|
8939
8999
|
this.bridges.delete(dir);
|
|
@@ -9030,10 +9090,11 @@ class BridgePool {
|
|
|
9030
9090
|
function normalizeKey(projectRoot) {
|
|
9031
9091
|
return canonicalizeProjectRoot(projectRoot);
|
|
9032
9092
|
}
|
|
9033
|
-
// ../../node_modules/.bun/@cortexkit+subc-client@0.
|
|
9093
|
+
// ../../node_modules/.bun/@cortexkit+subc-client@0.3.0/node_modules/@cortexkit/subc-client/src/client.ts
|
|
9034
9094
|
import { promises as fs2 } from "node:fs";
|
|
9095
|
+
import { debuglog } from "node:util";
|
|
9035
9096
|
|
|
9036
|
-
// ../../node_modules/.bun/@cortexkit+subc-client@0.
|
|
9097
|
+
// ../../node_modules/.bun/@cortexkit+subc-client@0.3.0/node_modules/@cortexkit/subc-client/src/auth.ts
|
|
9037
9098
|
import { createHmac, randomBytes, timingSafeEqual } from "node:crypto";
|
|
9038
9099
|
var NONCE_LEN = 32;
|
|
9039
9100
|
var MAX_AUTH_MESSAGE_LEN = 4096;
|
|
@@ -9097,7 +9158,7 @@ async function authenticateClient(sock, conn, deadlineMs) {
|
|
|
9097
9158
|
await writeMessage(sock, { client_auth: Array.from(clientAuth) }, deadlineMs);
|
|
9098
9159
|
}
|
|
9099
9160
|
|
|
9100
|
-
// ../../node_modules/.bun/@cortexkit+subc-client@0.
|
|
9161
|
+
// ../../node_modules/.bun/@cortexkit+subc-client@0.3.0/node_modules/@cortexkit/subc-client/src/connection-file.ts
|
|
9101
9162
|
import { promises as fs } from "node:fs";
|
|
9102
9163
|
var SCHEMA_VERSION = 1;
|
|
9103
9164
|
var MIN_KEY_LEN = 32;
|
|
@@ -9166,7 +9227,7 @@ async function readConnectionFile(path) {
|
|
|
9166
9227
|
return info;
|
|
9167
9228
|
}
|
|
9168
9229
|
|
|
9169
|
-
// ../../node_modules/.bun/@cortexkit+subc-client@0.
|
|
9230
|
+
// ../../node_modules/.bun/@cortexkit+subc-client@0.3.0/node_modules/@cortexkit/subc-client/src/envelope.ts
|
|
9170
9231
|
var PROTOCOL_VERSION = 1;
|
|
9171
9232
|
var HEADER_LEN = 17;
|
|
9172
9233
|
var FROZEN_PREFIX_LEN = 5;
|
|
@@ -9273,7 +9334,7 @@ function encodeFrame(frame) {
|
|
|
9273
9334
|
return out;
|
|
9274
9335
|
}
|
|
9275
9336
|
|
|
9276
|
-
// ../../node_modules/.bun/@cortexkit+subc-client@0.
|
|
9337
|
+
// ../../node_modules/.bun/@cortexkit+subc-client@0.3.0/node_modules/@cortexkit/subc-client/src/socket.ts
|
|
9277
9338
|
import net from "node:net";
|
|
9278
9339
|
|
|
9279
9340
|
class SocketClosedError extends Error {
|
|
@@ -9304,6 +9365,9 @@ class SubcSocket {
|
|
|
9304
9365
|
buffered = 0;
|
|
9305
9366
|
waiter = null;
|
|
9306
9367
|
closedErr = null;
|
|
9368
|
+
bufferedBytes() {
|
|
9369
|
+
return this.buffered;
|
|
9370
|
+
}
|
|
9307
9371
|
constructor(sock) {
|
|
9308
9372
|
this.sock = sock;
|
|
9309
9373
|
sock.on("data", (chunk) => {
|
|
@@ -9462,9 +9526,14 @@ class SubcSocket {
|
|
|
9462
9526
|
}
|
|
9463
9527
|
}
|
|
9464
9528
|
|
|
9465
|
-
// ../../node_modules/.bun/@cortexkit+subc-client@0.
|
|
9529
|
+
// ../../node_modules/.bun/@cortexkit+subc-client@0.3.0/node_modules/@cortexkit/subc-client/src/client.ts
|
|
9530
|
+
var debug = debuglog("subc-client");
|
|
9466
9531
|
var DEFAULT_HANDSHAKE_TIMEOUT_MS = 1e4;
|
|
9467
9532
|
var DEFAULT_REQUEST_TIMEOUT_MS = 30000;
|
|
9533
|
+
var TIMEOUT_ARBITRATION_GRACE_MS = 50;
|
|
9534
|
+
var REQUEST_DEADLINE_MARKER = "request_deadline";
|
|
9535
|
+
var DEADLINE_NO_DROP_CODE = "deadline_exceeded_no_drop_observed";
|
|
9536
|
+
var ROUTE_OPEN_RETRY_DEADLINE_MS = 1e4;
|
|
9468
9537
|
var BODY_READ_TIMEOUT_MS = 30000;
|
|
9469
9538
|
var EMPTY_BODY = new Uint8Array(0);
|
|
9470
9539
|
var DEFAULT_MANAGED_TARGET_KIND = "management_surface";
|
|
@@ -9508,6 +9577,7 @@ class SubcClient {
|
|
|
9508
9577
|
closeStarted = false;
|
|
9509
9578
|
reconnecting = null;
|
|
9510
9579
|
generation = 1;
|
|
9580
|
+
readerActive = false;
|
|
9511
9581
|
constructor(sock, currentConn, opts) {
|
|
9512
9582
|
this.sock = sock;
|
|
9513
9583
|
this.currentConn = currentConn;
|
|
@@ -9566,7 +9636,7 @@ class SubcClient {
|
|
|
9566
9636
|
}
|
|
9567
9637
|
continue;
|
|
9568
9638
|
}
|
|
9569
|
-
if (err.kind === "outcome_unknown") {
|
|
9639
|
+
if (err.kind === "outcome_unknown" && err.code !== DEADLINE_NO_DROP_CODE) {
|
|
9570
9640
|
this.scheduleReconnectAfterDrop(err);
|
|
9571
9641
|
}
|
|
9572
9642
|
throw err;
|
|
@@ -9689,7 +9759,7 @@ class SubcClient {
|
|
|
9689
9759
|
timer: null
|
|
9690
9760
|
};
|
|
9691
9761
|
pending.timer = setTimeout(() => {
|
|
9692
|
-
this.
|
|
9762
|
+
this.arbitrateTimeout(key, pending, channel, corr, ms);
|
|
9693
9763
|
}, ms);
|
|
9694
9764
|
this.pending.set(key, pending);
|
|
9695
9765
|
this.sock.write(encodeFrame(frame), Date.now() + ms).catch((err) => {
|
|
@@ -9699,6 +9769,23 @@ class SubcClient {
|
|
|
9699
9769
|
});
|
|
9700
9770
|
});
|
|
9701
9771
|
}
|
|
9772
|
+
arbitrateTimeout(key, pending, channel, corr, ms) {
|
|
9773
|
+
const settleAsTimeout = () => {
|
|
9774
|
+
this.rejectPending(key, pending, new SubcError(this.timeoutMessage(channel, corr, ms), REQUEST_DEADLINE_MARKER));
|
|
9775
|
+
};
|
|
9776
|
+
const graceDeadline = Date.now() + this.opts.timeoutArbitrationGraceMs;
|
|
9777
|
+
const arbitrate = () => {
|
|
9778
|
+
if (this.pending.get(key) !== pending)
|
|
9779
|
+
return;
|
|
9780
|
+
const readerDraining = this.readerActive || this.sock.bufferedBytes() > 0;
|
|
9781
|
+
if (readerDraining && Date.now() < graceDeadline) {
|
|
9782
|
+
setImmediate(arbitrate);
|
|
9783
|
+
return;
|
|
9784
|
+
}
|
|
9785
|
+
settleAsTimeout();
|
|
9786
|
+
};
|
|
9787
|
+
setImmediate(arbitrate);
|
|
9788
|
+
}
|
|
9702
9789
|
async managedRequest(routeChannel, body, opts) {
|
|
9703
9790
|
const bytes = body instanceof Uint8Array ? body : this.encode(body);
|
|
9704
9791
|
const priority = opts.priority ?? 1 /* Interactive */;
|
|
@@ -9723,6 +9810,9 @@ class SubcClient {
|
|
|
9723
9810
|
if (!handedToSocket) {
|
|
9724
9811
|
return this.notSentCallError("request bytes were not queued to the subc socket", err);
|
|
9725
9812
|
}
|
|
9813
|
+
if (err instanceof SubcError && err.code === REQUEST_DEADLINE_MARKER) {
|
|
9814
|
+
return new SubcCallError("outcome_unknown", `managed call deadline exceeded after request bytes were queued to the local socket; no terminal response was observed; outcome unknown${causeMessage(err)}`, DEADLINE_NO_DROP_CODE, err);
|
|
9815
|
+
}
|
|
9726
9816
|
return this.outcomeUnknownCallError("connection dropped before the managed call returned a response", err);
|
|
9727
9817
|
};
|
|
9728
9818
|
return new Promise((resolve2, reject) => {
|
|
@@ -9736,7 +9826,7 @@ class SubcClient {
|
|
|
9736
9826
|
classifyFailure
|
|
9737
9827
|
};
|
|
9738
9828
|
pending.timer = setTimeout(() => {
|
|
9739
|
-
this.
|
|
9829
|
+
this.arbitrateTimeout(key, pending, channel, corr, ms);
|
|
9740
9830
|
}, ms);
|
|
9741
9831
|
this.pending.set(key, pending);
|
|
9742
9832
|
const write = this.sock.writeTracked(encodeFrame(frame), Date.now() + ms);
|
|
@@ -9781,6 +9871,9 @@ class SubcClient {
|
|
|
9781
9871
|
return cached.opening;
|
|
9782
9872
|
}
|
|
9783
9873
|
async openCachedRoute(cached) {
|
|
9874
|
+
const routeRetryDeadline = Date.now() + ROUTE_OPEN_RETRY_DEADLINE_MS;
|
|
9875
|
+
let routeRetryDelay = this.opts.reconnectBackoff.baseMs;
|
|
9876
|
+
let routeRetryAttempt = 0;
|
|
9784
9877
|
for (;; ) {
|
|
9785
9878
|
if (cached.closed)
|
|
9786
9879
|
throw this.routeClosedDuringOpen();
|
|
@@ -9814,6 +9907,15 @@ class SubcClient {
|
|
|
9814
9907
|
}
|
|
9815
9908
|
continue;
|
|
9816
9909
|
}
|
|
9910
|
+
if (!this.closeStarted && err instanceof SubcError && isRetryableRouteOpenCode(err.code)) {
|
|
9911
|
+
routeRetryAttempt += 1;
|
|
9912
|
+
if (routeRetryAttempt < this.opts.reconnectBackoff.maxAttempts && Date.now() < routeRetryDeadline) {
|
|
9913
|
+
await this.opts.sleep(routeRetryDelay);
|
|
9914
|
+
routeRetryDelay = Math.min(routeRetryDelay * 2, this.opts.reconnectBackoff.capMs);
|
|
9915
|
+
continue;
|
|
9916
|
+
}
|
|
9917
|
+
throw this.notSentCallError(`route.open failed for module ${cached.moduleId}: ${err.code} (retry budget exhausted)`, err);
|
|
9918
|
+
}
|
|
9817
9919
|
throw this.terminalCallError(`route.open failed for module ${cached.moduleId}`, err);
|
|
9818
9920
|
}
|
|
9819
9921
|
}
|
|
@@ -9907,9 +10009,16 @@ class SubcClient {
|
|
|
9907
10009
|
try {
|
|
9908
10010
|
for (;; ) {
|
|
9909
10011
|
const headerBytes = await sock.readExact(HEADER_LEN, Number.POSITIVE_INFINITY);
|
|
9910
|
-
|
|
9911
|
-
|
|
9912
|
-
|
|
10012
|
+
this.readerActive = true;
|
|
10013
|
+
try {
|
|
10014
|
+
const header = decodeHeader(headerBytes);
|
|
10015
|
+
const body = header.len === 0 ? new Uint8Array(0) : await sock.readExact(header.len, Date.now() + BODY_READ_TIMEOUT_MS);
|
|
10016
|
+
if (this.sock === sock && this.generation === generation) {
|
|
10017
|
+
this.dispatch({ header, body });
|
|
10018
|
+
}
|
|
10019
|
+
} finally {
|
|
10020
|
+
this.readerActive = false;
|
|
10021
|
+
}
|
|
9913
10022
|
}
|
|
9914
10023
|
} catch (err) {
|
|
9915
10024
|
if (this.sock === sock && this.generation === generation) {
|
|
@@ -9941,13 +10050,20 @@ class SubcClient {
|
|
|
9941
10050
|
this.failChannel(frame.header.channel, new SubcError("route closed by subc (GOODBYE)"));
|
|
9942
10051
|
return;
|
|
9943
10052
|
}
|
|
10053
|
+
if (frame.header.ty === 1 /* Response */ || frame.header.ty === 5 /* Error */ || frame.header.ty === 4 /* StreamEnd */) {
|
|
10054
|
+
debug("dropped terminal frame with no waiter: type=%d channel=%d corr=%s port=%s", frame.header.ty, frame.header.channel, frame.header.corr, this.sock.localPort() ?? "?");
|
|
10055
|
+
return;
|
|
10056
|
+
}
|
|
9944
10057
|
}
|
|
9945
10058
|
settle(key, pending, run) {
|
|
10059
|
+
if (this.pending.get(key) !== pending)
|
|
10060
|
+
return false;
|
|
9946
10061
|
this.pending.delete(key);
|
|
9947
10062
|
if (pending.timer)
|
|
9948
10063
|
clearTimeout(pending.timer);
|
|
9949
10064
|
run();
|
|
9950
10065
|
pending.onSettle?.();
|
|
10066
|
+
return true;
|
|
9951
10067
|
}
|
|
9952
10068
|
rejectPending(key, pending, err) {
|
|
9953
10069
|
this.settle(key, pending, () => pending.reject(pending.classifyFailure?.(err) ?? err));
|
|
@@ -10011,6 +10127,9 @@ function isConsumerReconnectTransient(err) {
|
|
|
10011
10127
|
const code = errorCode(err);
|
|
10012
10128
|
return code === "ECONNREFUSED" || code === "ECONNRESET" || code === "EPIPE" || code === "ETIMEDOUT" || code === "ENOENT";
|
|
10013
10129
|
}
|
|
10130
|
+
function isRetryableRouteOpenCode(code) {
|
|
10131
|
+
return code === "unknown_module" || code === "module_reloading" || code === "target_unavailable" || code === "module_timeout";
|
|
10132
|
+
}
|
|
10014
10133
|
async function connectionFileExists(path) {
|
|
10015
10134
|
try {
|
|
10016
10135
|
await fs2.access(path);
|
|
@@ -10026,7 +10145,8 @@ function normalizeConnectOptions(opts) {
|
|
|
10026
10145
|
identity: opts.identity,
|
|
10027
10146
|
targetKind: opts.targetKind ?? DEFAULT_MANAGED_TARGET_KIND,
|
|
10028
10147
|
reconnectBackoff: opts.reconnectBackoff ?? DEFAULT_RECONNECT_BACKOFF,
|
|
10029
|
-
sleep: opts.sleep ?? ((ms) => new Promise((resolve2) => setTimeout(resolve2, ms)))
|
|
10148
|
+
sleep: opts.sleep ?? ((ms) => new Promise((resolve2) => setTimeout(resolve2, ms))),
|
|
10149
|
+
timeoutArbitrationGraceMs: opts.timeoutArbitrationGraceMs ?? TIMEOUT_ARBITRATION_GRACE_MS
|
|
10030
10150
|
};
|
|
10031
10151
|
}
|
|
10032
10152
|
function routeCacheKey(target, identity, consumerIdentity) {
|
|
@@ -10055,7 +10175,7 @@ function causeMessage(cause) {
|
|
|
10055
10175
|
return "";
|
|
10056
10176
|
return `: ${cause instanceof Error ? cause.message : String(cause)}`;
|
|
10057
10177
|
}
|
|
10058
|
-
// ../../node_modules/.bun/@cortexkit+subc-client@0.
|
|
10178
|
+
// ../../node_modules/.bun/@cortexkit+subc-client@0.3.0/node_modules/@cortexkit/subc-client/src/provider.ts
|
|
10059
10179
|
import { Buffer as Buffer2 } from "node:buffer";
|
|
10060
10180
|
var DEFAULT_HANDSHAKE_TIMEOUT_MS2 = 1e4;
|
|
10061
10181
|
var BODY_READ_TIMEOUT_MS2 = 30000;
|
|
@@ -11273,7 +11393,7 @@ class AftRpcClient {
|
|
|
11273
11393
|
}
|
|
11274
11394
|
parsePortFile(filePath) {
|
|
11275
11395
|
try {
|
|
11276
|
-
const content =
|
|
11396
|
+
const content = readFileSync2(filePath, "utf-8");
|
|
11277
11397
|
return parseRpcPortRecord(content);
|
|
11278
11398
|
} catch {
|
|
11279
11399
|
return null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cortexkit/aft-opencode",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.45.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "OpenCode plugin for Agent File Tools (AFT) — tree-sitter and lsp powered code analysis",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@clack/prompts": "^1.6.0",
|
|
34
|
-
"@cortexkit/aft-bridge": "0.
|
|
34
|
+
"@cortexkit/aft-bridge": "0.45.0",
|
|
35
35
|
"@opentui/core": "^0.4.2",
|
|
36
36
|
"@opentui/solid": "^0.4.2",
|
|
37
37
|
"comment-json": "^4.6.2",
|
|
@@ -40,12 +40,12 @@
|
|
|
40
40
|
"zod": "^4.4.3"
|
|
41
41
|
},
|
|
42
42
|
"optionalDependencies": {
|
|
43
|
-
"@cortexkit/aft-darwin-arm64": "0.
|
|
44
|
-
"@cortexkit/aft-darwin-x64": "0.
|
|
45
|
-
"@cortexkit/aft-linux-arm64": "0.
|
|
46
|
-
"@cortexkit/aft-linux-x64": "0.
|
|
47
|
-
"@cortexkit/aft-win32-arm64": "0.
|
|
48
|
-
"@cortexkit/aft-win32-x64": "0.
|
|
43
|
+
"@cortexkit/aft-darwin-arm64": "0.45.0",
|
|
44
|
+
"@cortexkit/aft-darwin-x64": "0.45.0",
|
|
45
|
+
"@cortexkit/aft-linux-arm64": "0.45.0",
|
|
46
|
+
"@cortexkit/aft-linux-x64": "0.45.0",
|
|
47
|
+
"@cortexkit/aft-win32-arm64": "0.45.0",
|
|
48
|
+
"@cortexkit/aft-win32-x64": "0.45.0"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"@opencode-ai/plugin": "^1.17.11",
|