@cortexkit/aft-pi 0.26.0 → 0.26.2
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
CHANGED
|
@@ -6889,7 +6889,7 @@ ${len.toString(16)}\r
|
|
|
6889
6889
|
// ../../node_modules/.bun/undici@8.2.0/node_modules/undici/lib/dispatcher/client-h2.js
|
|
6890
6890
|
var require_client_h2 = __commonJS((exports, module) => {
|
|
6891
6891
|
var assert = __require("node:assert");
|
|
6892
|
-
var { pipeline:
|
|
6892
|
+
var { pipeline: pipeline3 } = __require("node:stream");
|
|
6893
6893
|
var util = require_util();
|
|
6894
6894
|
var {
|
|
6895
6895
|
RequestContentLengthMismatchError,
|
|
@@ -7658,7 +7658,7 @@ var require_client_h2 = __commonJS((exports, module) => {
|
|
|
7658
7658
|
}
|
|
7659
7659
|
function writeStream(abort, socket, expectsPayload, h2stream, body, client, request, contentLength) {
|
|
7660
7660
|
assert(contentLength !== 0 || client[kRunning] === 0, "stream body cannot be pipelined");
|
|
7661
|
-
const pipe =
|
|
7661
|
+
const pipe = pipeline3(body, h2stream, (err) => {
|
|
7662
7662
|
if (err) {
|
|
7663
7663
|
util.destroy(pipe, err);
|
|
7664
7664
|
abort(err);
|
|
@@ -10422,7 +10422,7 @@ var require_h2c_client = __commonJS((exports, module) => {
|
|
|
10422
10422
|
var require_readable = __commonJS((exports, module) => {
|
|
10423
10423
|
var assert = __require("node:assert");
|
|
10424
10424
|
var { addAbortListener } = __require("node:events");
|
|
10425
|
-
var { Readable:
|
|
10425
|
+
var { Readable: Readable3 } = __require("node:stream");
|
|
10426
10426
|
var { RequestAbortedError, NotSupportedError, InvalidArgumentError, AbortError } = require_errors();
|
|
10427
10427
|
var util = require_util();
|
|
10428
10428
|
var { ReadableStreamFrom } = require_util();
|
|
@@ -10436,7 +10436,7 @@ var require_readable = __commonJS((exports, module) => {
|
|
|
10436
10436
|
var kBytesRead = Symbol("kBytesRead");
|
|
10437
10437
|
var noop = () => {};
|
|
10438
10438
|
|
|
10439
|
-
class BodyReadable extends
|
|
10439
|
+
class BodyReadable extends Readable3 {
|
|
10440
10440
|
constructor({
|
|
10441
10441
|
resume,
|
|
10442
10442
|
abort,
|
|
@@ -10723,7 +10723,7 @@ var require_readable = __commonJS((exports, module) => {
|
|
|
10723
10723
|
var require_api_request = __commonJS((exports, module) => {
|
|
10724
10724
|
var assert = __require("node:assert");
|
|
10725
10725
|
var { AsyncResource } = __require("node:async_hooks");
|
|
10726
|
-
var { Readable:
|
|
10726
|
+
var { Readable: Readable3 } = require_readable();
|
|
10727
10727
|
var { InvalidArgumentError, RequestAbortedError } = require_errors();
|
|
10728
10728
|
var util = require_util();
|
|
10729
10729
|
function noop() {}
|
|
@@ -10807,7 +10807,7 @@ var require_api_request = __commonJS((exports, module) => {
|
|
|
10807
10807
|
const parsedHeaders = headers;
|
|
10808
10808
|
const contentType = parsedHeaders?.["content-type"];
|
|
10809
10809
|
const contentLength = parsedHeaders?.["content-length"];
|
|
10810
|
-
const res = new
|
|
10810
|
+
const res = new Readable3({
|
|
10811
10811
|
resume: () => controller.resume(),
|
|
10812
10812
|
abort: (reason) => controller.abort(reason),
|
|
10813
10813
|
contentType,
|
|
@@ -11137,7 +11137,7 @@ var require_api_stream = __commonJS((exports, module) => {
|
|
|
11137
11137
|
// ../../node_modules/.bun/undici@8.2.0/node_modules/undici/lib/api/api-pipeline.js
|
|
11138
11138
|
var require_api_pipeline = __commonJS((exports, module) => {
|
|
11139
11139
|
var {
|
|
11140
|
-
Readable:
|
|
11140
|
+
Readable: Readable3,
|
|
11141
11141
|
Duplex,
|
|
11142
11142
|
PassThrough
|
|
11143
11143
|
} = __require("node:stream");
|
|
@@ -11153,7 +11153,7 @@ var require_api_pipeline = __commonJS((exports, module) => {
|
|
|
11153
11153
|
function noop() {}
|
|
11154
11154
|
var kResume = Symbol("resume");
|
|
11155
11155
|
|
|
11156
|
-
class PipelineRequest extends
|
|
11156
|
+
class PipelineRequest extends Readable3 {
|
|
11157
11157
|
constructor() {
|
|
11158
11158
|
super({ autoDestroy: true });
|
|
11159
11159
|
this[kResume] = null;
|
|
@@ -11171,7 +11171,7 @@ var require_api_pipeline = __commonJS((exports, module) => {
|
|
|
11171
11171
|
}
|
|
11172
11172
|
}
|
|
11173
11173
|
|
|
11174
|
-
class PipelineResponse extends
|
|
11174
|
+
class PipelineResponse extends Readable3 {
|
|
11175
11175
|
constructor(resume) {
|
|
11176
11176
|
super({ autoDestroy: true });
|
|
11177
11177
|
this[kResume] = resume;
|
|
@@ -11326,7 +11326,7 @@ var require_api_pipeline = __commonJS((exports, module) => {
|
|
|
11326
11326
|
util.destroy(ret, err);
|
|
11327
11327
|
}
|
|
11328
11328
|
}
|
|
11329
|
-
function
|
|
11329
|
+
function pipeline3(opts, handler) {
|
|
11330
11330
|
try {
|
|
11331
11331
|
const pipelineHandler = new PipelineHandler(opts, handler);
|
|
11332
11332
|
this.dispatch({ ...opts, body: pipelineHandler.req }, pipelineHandler);
|
|
@@ -11335,7 +11335,7 @@ var require_api_pipeline = __commonJS((exports, module) => {
|
|
|
11335
11335
|
return new PassThrough().destroy(err);
|
|
11336
11336
|
}
|
|
11337
11337
|
}
|
|
11338
|
-
module.exports =
|
|
11338
|
+
module.exports = pipeline3;
|
|
11339
11339
|
});
|
|
11340
11340
|
|
|
11341
11341
|
// ../../node_modules/.bun/undici@8.2.0/node_modules/undici/lib/api/api-upgrade.js
|
|
@@ -15358,7 +15358,7 @@ var require_cache_revalidation_handler = __commonJS((exports, module) => {
|
|
|
15358
15358
|
// ../../node_modules/.bun/undici@8.2.0/node_modules/undici/lib/interceptor/cache.js
|
|
15359
15359
|
var require_cache2 = __commonJS((exports, module) => {
|
|
15360
15360
|
var assert = __require("node:assert");
|
|
15361
|
-
var { Readable:
|
|
15361
|
+
var { Readable: Readable3 } = __require("node:stream");
|
|
15362
15362
|
var util = require_util();
|
|
15363
15363
|
var CacheHandler = require_cache_handler();
|
|
15364
15364
|
var MemoryCacheStore = require_memory_cache_store();
|
|
@@ -15454,7 +15454,7 @@ var require_cache2 = __commonJS((exports, module) => {
|
|
|
15454
15454
|
return dispatch(opts, new CacheHandler(globalOpts, cacheKey, handler));
|
|
15455
15455
|
}
|
|
15456
15456
|
function sendCachedValue(handler, opts, result, age, context, isStale2) {
|
|
15457
|
-
const stream = util.isStream(result.body) ? result.body :
|
|
15457
|
+
const stream = util.isStream(result.body) ? result.body : Readable3.from(result.body ?? []);
|
|
15458
15458
|
assert(!stream.destroyed, "stream should not be destroyed");
|
|
15459
15459
|
assert(!stream.readableDidRead, "stream should not be readableDidRead");
|
|
15460
15460
|
const controller = {
|
|
@@ -15668,7 +15668,7 @@ var require_cache2 = __commonJS((exports, module) => {
|
|
|
15668
15668
|
// ../../node_modules/.bun/undici@8.2.0/node_modules/undici/lib/interceptor/decompress.js
|
|
15669
15669
|
var require_decompress = __commonJS((exports, module) => {
|
|
15670
15670
|
var { createInflate, createGunzip, createBrotliDecompress, createZstdDecompress } = __require("node:zlib");
|
|
15671
|
-
var { pipeline:
|
|
15671
|
+
var { pipeline: pipeline3 } = __require("node:stream");
|
|
15672
15672
|
var DecoratorHandler = require_decorator_handler();
|
|
15673
15673
|
var supportedEncodings = {
|
|
15674
15674
|
gzip: createGunzip,
|
|
@@ -15743,7 +15743,7 @@ var require_decompress = __commonJS((exports, module) => {
|
|
|
15743
15743
|
#setupMultipleDecompressors(controller) {
|
|
15744
15744
|
const lastDecompressor = this.#decompressors[this.#decompressors.length - 1];
|
|
15745
15745
|
this.#setupDecompressorEvents(lastDecompressor, controller);
|
|
15746
|
-
|
|
15746
|
+
pipeline3(this.#decompressors, (err) => {
|
|
15747
15747
|
if (err) {
|
|
15748
15748
|
super.onResponseError(controller, err);
|
|
15749
15749
|
return;
|
|
@@ -18046,7 +18046,7 @@ var require_fetch = __commonJS((exports, module) => {
|
|
|
18046
18046
|
subresourceSet
|
|
18047
18047
|
} = require_constants3();
|
|
18048
18048
|
var EE = __require("node:events");
|
|
18049
|
-
var { Readable:
|
|
18049
|
+
var { Readable: Readable3, pipeline: pipeline3, finished, isErrored, isReadable } = __require("node:stream");
|
|
18050
18050
|
var { addAbortListener, bufferToLowerCasedHeaderName } = require_util();
|
|
18051
18051
|
var { dataURLProcessor, serializeAMimeType, minimizeSupportedMimeType } = require_data_url();
|
|
18052
18052
|
var { getGlobalDispatcher } = require_global2();
|
|
@@ -18937,7 +18937,7 @@ var require_fetch = __commonJS((exports, module) => {
|
|
|
18937
18937
|
const headersList = new HeadersList;
|
|
18938
18938
|
appendHeadersListFromResponseHeaders(headersList, headers, rawHeaders);
|
|
18939
18939
|
const location = headersList.get("location", true);
|
|
18940
|
-
this.body = new
|
|
18940
|
+
this.body = new Readable3({ read: () => controller.resume() });
|
|
18941
18941
|
const willFollow = location && request.redirect === "follow" && redirectStatusSet.has(status);
|
|
18942
18942
|
const decoders = [];
|
|
18943
18943
|
if (request.method !== "HEAD" && request.method !== "CONNECT" && !nullBodyStatus.includes(status) && !willFollow) {
|
|
@@ -18981,7 +18981,7 @@ var require_fetch = __commonJS((exports, module) => {
|
|
|
18981
18981
|
status,
|
|
18982
18982
|
statusText,
|
|
18983
18983
|
headersList,
|
|
18984
|
-
body: decoders.length ?
|
|
18984
|
+
body: decoders.length ? pipeline3(this.body, ...decoders, (err) => {
|
|
18985
18985
|
if (err) {
|
|
18986
18986
|
this.onResponseError(controller, err);
|
|
18987
18987
|
}
|
|
@@ -22363,7 +22363,7 @@ ${value}`;
|
|
|
22363
22363
|
|
|
22364
22364
|
// ../../node_modules/.bun/undici@8.2.0/node_modules/undici/lib/web/eventsource/eventsource.js
|
|
22365
22365
|
var require_eventsource = __commonJS((exports, module) => {
|
|
22366
|
-
var { pipeline:
|
|
22366
|
+
var { pipeline: pipeline3 } = __require("node:stream");
|
|
22367
22367
|
var { fetching } = require_fetch();
|
|
22368
22368
|
var { makeRequest } = require_request2();
|
|
22369
22369
|
var { webidl } = require_webidl();
|
|
@@ -22492,7 +22492,7 @@ var require_eventsource = __commonJS((exports, module) => {
|
|
|
22492
22492
|
this.dispatchEvent(createFastMessageEvent(event.type, event.options));
|
|
22493
22493
|
}
|
|
22494
22494
|
});
|
|
22495
|
-
|
|
22495
|
+
pipeline3(response.body.stream, eventSourceStream, (error2) => {
|
|
22496
22496
|
if (error2?.aborted === false) {
|
|
22497
22497
|
this.close();
|
|
22498
22498
|
this.dispatchEvent(new Event("error"));
|
|
@@ -30490,12 +30490,22 @@ function getActiveLogger() {
|
|
|
30490
30490
|
return loggerGlobal()[ACTIVE_LOGGER_SYMBOL];
|
|
30491
30491
|
}
|
|
30492
30492
|
function getLogFilePath() {
|
|
30493
|
-
|
|
30493
|
+
try {
|
|
30494
|
+
return getActiveLogger()?.getLogFilePath?.();
|
|
30495
|
+
} catch (err) {
|
|
30496
|
+
console.error(`[aft-bridge] ERROR: active logger getLogFilePath threw: ${err instanceof Error ? err.message : String(err)}`);
|
|
30497
|
+
return;
|
|
30498
|
+
}
|
|
30494
30499
|
}
|
|
30495
30500
|
function log(message, meta) {
|
|
30496
30501
|
const active = getActiveLogger();
|
|
30497
30502
|
if (active) {
|
|
30498
|
-
|
|
30503
|
+
try {
|
|
30504
|
+
active.log(message, meta);
|
|
30505
|
+
} catch (err) {
|
|
30506
|
+
console.error(`[aft-bridge] ERROR: active logger log threw: ${err instanceof Error ? err.message : String(err)}`);
|
|
30507
|
+
console.error(`[aft-bridge] ${message}`);
|
|
30508
|
+
}
|
|
30499
30509
|
} else {
|
|
30500
30510
|
console.error(`[aft-bridge] ${message}`);
|
|
30501
30511
|
}
|
|
@@ -30503,7 +30513,12 @@ function log(message, meta) {
|
|
|
30503
30513
|
function warn(message, meta) {
|
|
30504
30514
|
const active = getActiveLogger();
|
|
30505
30515
|
if (active) {
|
|
30506
|
-
|
|
30516
|
+
try {
|
|
30517
|
+
active.warn(message, meta);
|
|
30518
|
+
} catch (err) {
|
|
30519
|
+
console.error(`[aft-bridge] ERROR: active logger warn threw: ${err instanceof Error ? err.message : String(err)}`);
|
|
30520
|
+
console.error(`[aft-bridge] WARN: ${message}`);
|
|
30521
|
+
}
|
|
30507
30522
|
} else {
|
|
30508
30523
|
console.error(`[aft-bridge] WARN: ${message}`);
|
|
30509
30524
|
}
|
|
@@ -30511,20 +30526,16 @@ function warn(message, meta) {
|
|
|
30511
30526
|
function error(message, meta) {
|
|
30512
30527
|
const active = getActiveLogger();
|
|
30513
30528
|
if (active) {
|
|
30514
|
-
|
|
30529
|
+
try {
|
|
30530
|
+
active.error(message, meta);
|
|
30531
|
+
} catch (err) {
|
|
30532
|
+
console.error(`[aft-bridge] ERROR: active logger error threw: ${err instanceof Error ? err.message : String(err)}`);
|
|
30533
|
+
console.error(`[aft-bridge] ERROR: ${message}`);
|
|
30534
|
+
}
|
|
30515
30535
|
} else {
|
|
30516
30536
|
console.error(`[aft-bridge] ERROR: ${message}`);
|
|
30517
30537
|
}
|
|
30518
30538
|
}
|
|
30519
|
-
function sessionLog(sessionId, message) {
|
|
30520
|
-
log(message, sessionId ? { sessionId } : undefined);
|
|
30521
|
-
}
|
|
30522
|
-
function sessionWarn(sessionId, message) {
|
|
30523
|
-
warn(message, sessionId ? { sessionId } : undefined);
|
|
30524
|
-
}
|
|
30525
|
-
function sessionError(sessionId, message) {
|
|
30526
|
-
error(message, sessionId ? { sessionId } : undefined);
|
|
30527
|
-
}
|
|
30528
30539
|
// ../aft-bridge/dist/bridge.js
|
|
30529
30540
|
import { spawn } from "node:child_process";
|
|
30530
30541
|
import { homedir } from "node:os";
|
|
@@ -30619,6 +30630,7 @@ class BinaryBridge {
|
|
|
30619
30630
|
pending = new Map;
|
|
30620
30631
|
nextId = 1;
|
|
30621
30632
|
stdoutBuffer = "";
|
|
30633
|
+
stderrBuffer = "";
|
|
30622
30634
|
stderrTail = [];
|
|
30623
30635
|
_restartCount = 0;
|
|
30624
30636
|
_shuttingDown = false;
|
|
@@ -30654,24 +30666,62 @@ class BinaryBridge {
|
|
|
30654
30666
|
}
|
|
30655
30667
|
logVia(message, meta) {
|
|
30656
30668
|
const logger = this.logger ?? getActiveLogger();
|
|
30657
|
-
if (logger)
|
|
30658
|
-
|
|
30659
|
-
|
|
30669
|
+
if (logger) {
|
|
30670
|
+
try {
|
|
30671
|
+
logger.log(message, meta);
|
|
30672
|
+
} catch (err) {
|
|
30673
|
+
console.error(`[aft-bridge] ERROR: logger log threw: ${err instanceof Error ? err.message : String(err)}`);
|
|
30674
|
+
console.error(`[aft-bridge] ${message}`);
|
|
30675
|
+
}
|
|
30676
|
+
} else {
|
|
30660
30677
|
log(message, meta);
|
|
30678
|
+
}
|
|
30661
30679
|
}
|
|
30662
30680
|
warnVia(message, meta) {
|
|
30663
30681
|
const logger = this.logger ?? getActiveLogger();
|
|
30664
|
-
if (logger)
|
|
30665
|
-
|
|
30666
|
-
|
|
30682
|
+
if (logger) {
|
|
30683
|
+
try {
|
|
30684
|
+
logger.warn(message, meta);
|
|
30685
|
+
} catch (err) {
|
|
30686
|
+
console.error(`[aft-bridge] ERROR: logger warn threw: ${err instanceof Error ? err.message : String(err)}`);
|
|
30687
|
+
console.error(`[aft-bridge] WARN: ${message}`);
|
|
30688
|
+
}
|
|
30689
|
+
} else {
|
|
30667
30690
|
warn(message, meta);
|
|
30691
|
+
}
|
|
30668
30692
|
}
|
|
30669
30693
|
errorVia(message, meta) {
|
|
30670
30694
|
const logger = this.logger ?? getActiveLogger();
|
|
30671
|
-
if (logger)
|
|
30672
|
-
|
|
30673
|
-
|
|
30695
|
+
if (logger) {
|
|
30696
|
+
try {
|
|
30697
|
+
logger.error(message, meta);
|
|
30698
|
+
} catch (err) {
|
|
30699
|
+
console.error(`[aft-bridge] ERROR: logger error threw: ${err instanceof Error ? err.message : String(err)}`);
|
|
30700
|
+
console.error(`[aft-bridge] ERROR: ${message}`);
|
|
30701
|
+
}
|
|
30702
|
+
} else {
|
|
30674
30703
|
error(message, meta);
|
|
30704
|
+
}
|
|
30705
|
+
}
|
|
30706
|
+
getLogFilePathVia() {
|
|
30707
|
+
if (this.logger?.getLogFilePath) {
|
|
30708
|
+
try {
|
|
30709
|
+
return this.logger.getLogFilePath();
|
|
30710
|
+
} catch (err) {
|
|
30711
|
+
console.error(`[aft-bridge] ERROR: logger getLogFilePath threw: ${err instanceof Error ? err.message : String(err)}`);
|
|
30712
|
+
return;
|
|
30713
|
+
}
|
|
30714
|
+
}
|
|
30715
|
+
return getLogFilePath();
|
|
30716
|
+
}
|
|
30717
|
+
sessionLogVia(sessionId, message) {
|
|
30718
|
+
this.logVia(message, sessionId ? { sessionId } : undefined);
|
|
30719
|
+
}
|
|
30720
|
+
sessionWarnVia(sessionId, message) {
|
|
30721
|
+
this.warnVia(message, sessionId ? { sessionId } : undefined);
|
|
30722
|
+
}
|
|
30723
|
+
sessionErrorVia(sessionId, message) {
|
|
30724
|
+
this.errorVia(message, sessionId ? { sessionId } : undefined);
|
|
30675
30725
|
}
|
|
30676
30726
|
get restartCount() {
|
|
30677
30727
|
return this._restartCount;
|
|
@@ -30730,7 +30780,7 @@ class BinaryBridge {
|
|
|
30730
30780
|
await this.deliverConfigureWarnings(configResult, params, options);
|
|
30731
30781
|
await this.checkVersion();
|
|
30732
30782
|
if (!this.isAlive()) {
|
|
30733
|
-
throw new Error(`${this.errorPrefix} Bridge died during version check. Check logs: ${
|
|
30783
|
+
throw new Error(`${this.errorPrefix} Bridge died during version check. Check logs: ${this.getLogFilePathVia()}`);
|
|
30734
30784
|
}
|
|
30735
30785
|
this.configured = true;
|
|
30736
30786
|
} finally {
|
|
@@ -30766,9 +30816,9 @@ class BinaryBridge {
|
|
|
30766
30816
|
const restartSuffix = keepBridgeOnTimeout ? "" : " — restarting bridge";
|
|
30767
30817
|
const timeoutMsg = `Request "${command}" (id=${id}) timed out after ${effectiveTimeoutMs}ms${restartSuffix}`;
|
|
30768
30818
|
if (requestSessionId) {
|
|
30769
|
-
|
|
30819
|
+
this.sessionWarnVia(requestSessionId, timeoutMsg);
|
|
30770
30820
|
} else {
|
|
30771
|
-
|
|
30821
|
+
this.warnVia(timeoutMsg);
|
|
30772
30822
|
}
|
|
30773
30823
|
reject(new Error(`${this.errorPrefix} Request "${command}" (id=${id}) timed out after ${effectiveTimeoutMs}ms`));
|
|
30774
30824
|
if (!keepBridgeOnTimeout) {
|
|
@@ -30795,7 +30845,7 @@ class BinaryBridge {
|
|
|
30795
30845
|
});
|
|
30796
30846
|
} catch (err) {
|
|
30797
30847
|
if (err instanceof BridgeReplacedDuringVersionCheck && canRetryAfterVersionSwap && command !== "configure" && command !== "version") {
|
|
30798
|
-
|
|
30848
|
+
this.logVia(`Retrying request "${command}" once after coordinated binary replacement: ${err.newBinaryPath}`);
|
|
30799
30849
|
return this.sendWithVersionMismatchRetry(command, params, options, false);
|
|
30800
30850
|
}
|
|
30801
30851
|
throw err;
|
|
@@ -30815,7 +30865,7 @@ class BinaryBridge {
|
|
|
30815
30865
|
warnings: configResult.warnings
|
|
30816
30866
|
});
|
|
30817
30867
|
} catch (err) {
|
|
30818
|
-
|
|
30868
|
+
this.warnVia(`configure warning delivery failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
30819
30869
|
} finally {
|
|
30820
30870
|
if (sessionId) {
|
|
30821
30871
|
this.configureWarningClients.delete(sessionId);
|
|
@@ -30849,7 +30899,7 @@ class BinaryBridge {
|
|
|
30849
30899
|
if (!snapshot || typeof snapshot !== "object" || Array.isArray(snapshot))
|
|
30850
30900
|
return;
|
|
30851
30901
|
this.cachedStatus = snapshot;
|
|
30852
|
-
|
|
30902
|
+
this.logVia("Received status_changed push frame; cached AFT status snapshot");
|
|
30853
30903
|
for (const listener of this.statusListeners) {
|
|
30854
30904
|
this.deliverStatusSnapshot(listener, this.cachedStatus);
|
|
30855
30905
|
}
|
|
@@ -30858,7 +30908,7 @@ class BinaryBridge {
|
|
|
30858
30908
|
try {
|
|
30859
30909
|
listener(snapshot);
|
|
30860
30910
|
} catch (err) {
|
|
30861
|
-
|
|
30911
|
+
this.warnVia(`status listener threw: ${err instanceof Error ? err.message : String(err)}`);
|
|
30862
30912
|
}
|
|
30863
30913
|
}
|
|
30864
30914
|
async shutdown() {
|
|
@@ -30876,7 +30926,7 @@ class BinaryBridge {
|
|
|
30876
30926
|
}, 5000);
|
|
30877
30927
|
proc.once("exit", () => {
|
|
30878
30928
|
clearTimeout(forceKillTimer);
|
|
30879
|
-
|
|
30929
|
+
this.logVia("Process exited during shutdown");
|
|
30880
30930
|
resolve();
|
|
30881
30931
|
});
|
|
30882
30932
|
proc.kill("SIGTERM");
|
|
@@ -30895,9 +30945,9 @@ class BinaryBridge {
|
|
|
30895
30945
|
if (typeof binaryVersion !== "string") {
|
|
30896
30946
|
throw new Error(`Binary did not report a version — likely too old (minVersion: ${this.minVersion})`);
|
|
30897
30947
|
}
|
|
30898
|
-
|
|
30948
|
+
this.logVia(`Binary version: ${binaryVersion}`);
|
|
30899
30949
|
if (compareSemver(binaryVersion, this.minVersion) < 0) {
|
|
30900
|
-
|
|
30950
|
+
this.warnVia(`Binary version ${binaryVersion} is older than required ${this.minVersion}`);
|
|
30901
30951
|
const replacementPath = await this.onVersionMismatch?.(binaryVersion, this.minVersion);
|
|
30902
30952
|
if (replacementPath === undefined) {
|
|
30903
30953
|
return;
|
|
@@ -30909,7 +30959,7 @@ class BinaryBridge {
|
|
|
30909
30959
|
throw new BridgeReplacedDuringVersionCheck(replacementPath);
|
|
30910
30960
|
}
|
|
30911
30961
|
} catch (err) {
|
|
30912
|
-
|
|
30962
|
+
this.warnVia(`Version check failed: ${err.message}`);
|
|
30913
30963
|
throw err;
|
|
30914
30964
|
}
|
|
30915
30965
|
}
|
|
@@ -30929,7 +30979,7 @@ class BinaryBridge {
|
|
|
30929
30979
|
}, 5000);
|
|
30930
30980
|
proc.once("exit", () => {
|
|
30931
30981
|
clearTimeout(forceKillTimer);
|
|
30932
|
-
|
|
30982
|
+
this.logVia("Process exited during coordinated binary replacement");
|
|
30933
30983
|
resolve();
|
|
30934
30984
|
});
|
|
30935
30985
|
proc.kill("SIGTERM");
|
|
@@ -30942,9 +30992,9 @@ class BinaryBridge {
|
|
|
30942
30992
|
}
|
|
30943
30993
|
spawnProcess(triggeringSessionId) {
|
|
30944
30994
|
if (triggeringSessionId) {
|
|
30945
|
-
|
|
30995
|
+
this.sessionLogVia(triggeringSessionId, `Spawning binary: ${this.binaryPath} (cwd: ${this.cwd})`);
|
|
30946
30996
|
} else {
|
|
30947
|
-
|
|
30997
|
+
this.logVia(`Spawning binary: ${this.binaryPath} (cwd: ${this.cwd})`);
|
|
30948
30998
|
}
|
|
30949
30999
|
const semantic = this.configOverrides.semantic;
|
|
30950
31000
|
const semanticBackend = (() => {
|
|
@@ -30991,11 +31041,12 @@ class BinaryBridge {
|
|
|
30991
31041
|
const remaining = stderrDecoder.end();
|
|
30992
31042
|
if (remaining)
|
|
30993
31043
|
this.onStderrData(remaining);
|
|
31044
|
+
this.flushStderrBuffer();
|
|
30994
31045
|
});
|
|
30995
31046
|
child.on("error", (err) => {
|
|
30996
31047
|
if (this.process !== currentChild)
|
|
30997
31048
|
return;
|
|
30998
|
-
|
|
31049
|
+
this.errorVia(`Process error: ${err.message}${this.formatStderrTail()}`);
|
|
30999
31050
|
this.handleCrash();
|
|
31000
31051
|
});
|
|
31001
31052
|
child.on("exit", (code, signal) => {
|
|
@@ -31003,7 +31054,7 @@ class BinaryBridge {
|
|
|
31003
31054
|
return;
|
|
31004
31055
|
if (this._shuttingDown)
|
|
31005
31056
|
return;
|
|
31006
|
-
|
|
31057
|
+
this.logVia(`Process exited: code=${code}, signal=${signal}`);
|
|
31007
31058
|
if (signal === "SIGTERM" || signal === "SIGKILL" || signal === "SIGHUP" || signal === "SIGINT") {
|
|
31008
31059
|
this.process = null;
|
|
31009
31060
|
this.configured = false;
|
|
@@ -31015,6 +31066,7 @@ class BinaryBridge {
|
|
|
31015
31066
|
});
|
|
31016
31067
|
this.process = child;
|
|
31017
31068
|
this.stdoutBuffer = "";
|
|
31069
|
+
this.stderrBuffer = "";
|
|
31018
31070
|
this.stderrTail = [];
|
|
31019
31071
|
}
|
|
31020
31072
|
pushStderrLine(line) {
|
|
@@ -31024,16 +31076,28 @@ class BinaryBridge {
|
|
|
31024
31076
|
}
|
|
31025
31077
|
}
|
|
31026
31078
|
onStderrData(data) {
|
|
31027
|
-
|
|
31028
|
-
|
|
31029
|
-
|
|
31079
|
+
this.stderrBuffer += data;
|
|
31080
|
+
let newlineIdx;
|
|
31081
|
+
while ((newlineIdx = this.stderrBuffer.indexOf(`
|
|
31082
|
+
`)) !== -1) {
|
|
31083
|
+
const line = this.stderrBuffer.slice(0, newlineIdx).replace(/\r$/, "");
|
|
31084
|
+
this.stderrBuffer = this.stderrBuffer.slice(newlineIdx + 1);
|
|
31030
31085
|
if (!line)
|
|
31031
31086
|
continue;
|
|
31032
31087
|
const tagged = tagStderrLine(line);
|
|
31033
|
-
|
|
31088
|
+
this.logVia(tagged);
|
|
31034
31089
|
this.pushStderrLine(tagged);
|
|
31035
31090
|
}
|
|
31036
31091
|
}
|
|
31092
|
+
flushStderrBuffer() {
|
|
31093
|
+
const line = this.stderrBuffer.replace(/\r$/, "");
|
|
31094
|
+
this.stderrBuffer = "";
|
|
31095
|
+
if (!line)
|
|
31096
|
+
return;
|
|
31097
|
+
const tagged = tagStderrLine(line);
|
|
31098
|
+
this.logVia(tagged);
|
|
31099
|
+
this.pushStderrLine(tagged);
|
|
31100
|
+
}
|
|
31037
31101
|
formatStderrTail() {
|
|
31038
31102
|
if (this.stderrTail.length === 0)
|
|
31039
31103
|
return "";
|
|
@@ -31091,7 +31155,7 @@ class BinaryBridge {
|
|
|
31091
31155
|
}
|
|
31092
31156
|
if (response.type === "configure_warnings") {
|
|
31093
31157
|
this.handleConfigureWarningsFrame(response).catch((err) => {
|
|
31094
|
-
|
|
31158
|
+
this.warnVia(`configure warning delivery failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
31095
31159
|
});
|
|
31096
31160
|
continue;
|
|
31097
31161
|
}
|
|
@@ -31109,10 +31173,10 @@ class BinaryBridge {
|
|
|
31109
31173
|
this.scheduleRestartCountReset();
|
|
31110
31174
|
entry.resolve(response);
|
|
31111
31175
|
} else if (typeof response.type === "string") {
|
|
31112
|
-
|
|
31176
|
+
this.logVia(`Ignoring unknown stdout push frame type: ${response.type}`);
|
|
31113
31177
|
}
|
|
31114
31178
|
} catch (_err) {
|
|
31115
|
-
|
|
31179
|
+
this.warnVia(`Failed to parse stdout line: ${line}`);
|
|
31116
31180
|
}
|
|
31117
31181
|
}
|
|
31118
31182
|
}
|
|
@@ -31126,17 +31190,17 @@ class BinaryBridge {
|
|
|
31126
31190
|
this.configured = false;
|
|
31127
31191
|
const tail = this.formatStderrTail();
|
|
31128
31192
|
this.stderrTail = [];
|
|
31129
|
-
const killedMsg = tail ? `Bridge killed after timeout.${tail}` : `Bridge killed after timeout (see ${
|
|
31193
|
+
const killedMsg = tail ? `Bridge killed after timeout.${tail}` : `Bridge killed after timeout (see ${this.getLogFilePathVia()})`;
|
|
31130
31194
|
if (tail) {
|
|
31131
31195
|
if (triggeringSessionId) {
|
|
31132
|
-
|
|
31196
|
+
this.sessionErrorVia(triggeringSessionId, killedMsg);
|
|
31133
31197
|
} else {
|
|
31134
|
-
|
|
31198
|
+
this.errorVia(killedMsg);
|
|
31135
31199
|
}
|
|
31136
31200
|
} else if (triggeringSessionId) {
|
|
31137
|
-
|
|
31201
|
+
this.sessionWarnVia(triggeringSessionId, killedMsg);
|
|
31138
31202
|
} else {
|
|
31139
|
-
|
|
31203
|
+
this.warnVia(killedMsg);
|
|
31140
31204
|
}
|
|
31141
31205
|
}
|
|
31142
31206
|
handleCrash(cause) {
|
|
@@ -31149,25 +31213,25 @@ class BinaryBridge {
|
|
|
31149
31213
|
this.configured = false;
|
|
31150
31214
|
const tail = this.formatStderrTail();
|
|
31151
31215
|
if (tail) {
|
|
31152
|
-
|
|
31216
|
+
this.errorVia(`Binary crashed (restarts: ${this._restartCount})${cause ? `: ${cause.message}` : ""}.${tail}`);
|
|
31153
31217
|
}
|
|
31154
|
-
this.rejectAllPending(new Error(`${this.errorPrefix} Binary crashed (restarts: ${this._restartCount})${cause ? `: ${cause.message}` : ""} (see ${
|
|
31218
|
+
this.rejectAllPending(new Error(`${this.errorPrefix} Binary crashed (restarts: ${this._restartCount})${cause ? `: ${cause.message}` : ""} (see ${this.getLogFilePathVia()})`));
|
|
31155
31219
|
if (this._restartCount < this.maxRestarts) {
|
|
31156
31220
|
const delay = 100 * 2 ** this._restartCount;
|
|
31157
31221
|
this._restartCount++;
|
|
31158
|
-
|
|
31222
|
+
this.logVia(`Auto-restart #${this._restartCount} in ${delay}ms`);
|
|
31159
31223
|
setTimeout(() => {
|
|
31160
31224
|
if (!this._shuttingDown && !this.isAlive()) {
|
|
31161
31225
|
try {
|
|
31162
31226
|
this.spawnProcess();
|
|
31163
31227
|
} catch (err) {
|
|
31164
|
-
|
|
31228
|
+
this.errorVia(`Failed to restart: ${err.message}`);
|
|
31165
31229
|
}
|
|
31166
31230
|
}
|
|
31167
31231
|
}, delay);
|
|
31168
31232
|
this.scheduleRestartCountReset();
|
|
31169
31233
|
} else {
|
|
31170
|
-
|
|
31234
|
+
this.errorVia(`Max restarts (${this.maxRestarts}) reached, giving up. Logs: ${this.getLogFilePathVia()}${tail}`);
|
|
31171
31235
|
this.scheduleRestartCountReset();
|
|
31172
31236
|
}
|
|
31173
31237
|
}
|
|
@@ -31193,9 +31257,12 @@ class BinaryBridge {
|
|
|
31193
31257
|
}
|
|
31194
31258
|
}
|
|
31195
31259
|
// ../aft-bridge/dist/downloader.js
|
|
31196
|
-
import {
|
|
31260
|
+
import { createHash } from "node:crypto";
|
|
31261
|
+
import { chmodSync, closeSync, createWriteStream, existsSync, mkdirSync, openSync, renameSync, rmSync, statSync, unlinkSync } from "node:fs";
|
|
31197
31262
|
import { homedir as homedir2 } from "node:os";
|
|
31198
31263
|
import { join as join2 } from "node:path";
|
|
31264
|
+
import { Readable } from "node:stream";
|
|
31265
|
+
import { pipeline } from "node:stream/promises";
|
|
31199
31266
|
|
|
31200
31267
|
// ../aft-bridge/dist/platform.js
|
|
31201
31268
|
var PLATFORM_ARCH_MAP = {
|
|
@@ -31213,6 +31280,11 @@ var PLATFORM_ASSET_MAP = {
|
|
|
31213
31280
|
|
|
31214
31281
|
// ../aft-bridge/dist/downloader.js
|
|
31215
31282
|
var REPO = "cortexkit/aft";
|
|
31283
|
+
var DOWNLOAD_TIMEOUT_MS = 300000;
|
|
31284
|
+
var LATEST_TAG_TIMEOUT_MS = 30000;
|
|
31285
|
+
var MAX_DOWNLOAD_BYTES = 200 * 1024 * 1024;
|
|
31286
|
+
var DOWNLOAD_LOCK_TIMEOUT_MS = 120000;
|
|
31287
|
+
var DOWNLOAD_LOCK_STALE_MS = 10 * 60000;
|
|
31216
31288
|
function getCacheDir() {
|
|
31217
31289
|
if (process.platform === "win32") {
|
|
31218
31290
|
const localAppData = process.env.LOCALAPPDATA || process.env.APPDATA;
|
|
@@ -31254,54 +31326,101 @@ async function downloadBinary(version) {
|
|
|
31254
31326
|
const downloadUrl = `https://github.com/${REPO}/releases/download/${tag}/${assetName}`;
|
|
31255
31327
|
const checksumUrl = `https://github.com/${REPO}/releases/download/${tag}/checksums.sha256`;
|
|
31256
31328
|
log(`Downloading AFT binary (${tag}) for ${platformKey}...`);
|
|
31329
|
+
const lockPath = join2(versionedCacheDir, ".download.lock");
|
|
31330
|
+
let releaseLock = null;
|
|
31331
|
+
let binaryController = null;
|
|
31332
|
+
let checksumController = null;
|
|
31333
|
+
let binaryTimeout = null;
|
|
31334
|
+
let checksumTimeout = null;
|
|
31335
|
+
const tmpPath = `${binaryPath}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`;
|
|
31257
31336
|
try {
|
|
31258
31337
|
if (!existsSync(versionedCacheDir)) {
|
|
31259
31338
|
mkdirSync(versionedCacheDir, { recursive: true });
|
|
31260
31339
|
}
|
|
31340
|
+
releaseLock = await acquireDownloadLock(lockPath);
|
|
31341
|
+
if (existsSync(binaryPath)) {
|
|
31342
|
+
return binaryPath;
|
|
31343
|
+
}
|
|
31344
|
+
binaryController = new AbortController;
|
|
31345
|
+
checksumController = new AbortController;
|
|
31346
|
+
const activeBinaryController = binaryController;
|
|
31347
|
+
const activeChecksumController = checksumController;
|
|
31348
|
+
binaryTimeout = setTimeout(() => activeBinaryController.abort(), DOWNLOAD_TIMEOUT_MS);
|
|
31349
|
+
checksumTimeout = setTimeout(() => activeChecksumController.abort(), DOWNLOAD_TIMEOUT_MS);
|
|
31261
31350
|
const [binaryResponse, checksumResponse] = await Promise.all([
|
|
31262
|
-
fetch(downloadUrl, { redirect: "follow" }),
|
|
31263
|
-
fetch(checksumUrl, { redirect: "follow" })
|
|
31351
|
+
fetch(downloadUrl, { redirect: "follow", signal: activeBinaryController.signal }),
|
|
31352
|
+
fetch(checksumUrl, { redirect: "follow", signal: activeChecksumController.signal })
|
|
31264
31353
|
]);
|
|
31265
31354
|
if (!binaryResponse.ok) {
|
|
31266
31355
|
throw new Error(`HTTP ${binaryResponse.status}: ${binaryResponse.statusText} (${downloadUrl})`);
|
|
31267
31356
|
}
|
|
31268
|
-
|
|
31357
|
+
if (!binaryResponse.body) {
|
|
31358
|
+
throw new Error(`Download response for ${assetName} had no body`);
|
|
31359
|
+
}
|
|
31360
|
+
const advertised = Number.parseInt(binaryResponse.headers.get("content-length") ?? "", 10);
|
|
31361
|
+
if (Number.isFinite(advertised) && advertised > MAX_DOWNLOAD_BYTES) {
|
|
31362
|
+
throw new Error(`Content-Length ${advertised} exceeds max ${MAX_DOWNLOAD_BYTES}`);
|
|
31363
|
+
}
|
|
31269
31364
|
if (!checksumResponse.ok) {
|
|
31270
31365
|
warn(`Checksum verification failed: no checksums.sha256 found for ${tag}. ` + "Binary download aborted for security reasons.");
|
|
31271
31366
|
return null;
|
|
31272
31367
|
}
|
|
31273
31368
|
const checksumText = await checksumResponse.text();
|
|
31369
|
+
clearTimeout(checksumTimeout);
|
|
31370
|
+
checksumTimeout = null;
|
|
31274
31371
|
const expectedHash = parseChecksumForAsset(checksumText, assetName);
|
|
31275
31372
|
if (!expectedHash) {
|
|
31276
31373
|
warn(`Checksum verification failed: checksums.sha256 found but no entry for ${assetName}. ` + "Binary download aborted for security reasons.");
|
|
31277
31374
|
return null;
|
|
31278
31375
|
}
|
|
31279
|
-
const
|
|
31280
|
-
|
|
31376
|
+
const hash = createHash("sha256");
|
|
31377
|
+
let bytesWritten = 0;
|
|
31378
|
+
const guard = new TransformStream({
|
|
31379
|
+
transform(chunk, controller) {
|
|
31380
|
+
bytesWritten += chunk.byteLength;
|
|
31381
|
+
if (bytesWritten > MAX_DOWNLOAD_BYTES) {
|
|
31382
|
+
controller.error(new Error(`download exceeded ${MAX_DOWNLOAD_BYTES} bytes after streaming (server lied about size or sent unbounded body)`));
|
|
31383
|
+
return;
|
|
31384
|
+
}
|
|
31385
|
+
hash.update(chunk);
|
|
31386
|
+
controller.enqueue(chunk);
|
|
31387
|
+
}
|
|
31388
|
+
});
|
|
31389
|
+
const guarded = binaryResponse.body.pipeThrough(guard);
|
|
31390
|
+
const nodeStream = Readable.fromWeb(guarded);
|
|
31391
|
+
await pipeline(nodeStream, createWriteStream(tmpPath), { signal: binaryController.signal });
|
|
31392
|
+
clearTimeout(binaryTimeout);
|
|
31393
|
+
binaryTimeout = null;
|
|
31394
|
+
const actualHash = hash.digest("hex");
|
|
31281
31395
|
if (actualHash !== expectedHash) {
|
|
31282
|
-
throw new Error(`Checksum mismatch for ${assetName}: expected ${expectedHash}, got ${actualHash}. The binary may have been tampered with
|
|
31396
|
+
throw new Error(`Checksum mismatch for ${assetName}: expected ${expectedHash}, got ${actualHash}. ` + "The binary may have been tampered with.");
|
|
31283
31397
|
}
|
|
31284
31398
|
log(`Checksum verified (SHA-256: ${actualHash.slice(0, 16)}...)`);
|
|
31285
|
-
const tmpPath = `${binaryPath}.tmp`;
|
|
31286
|
-
const { writeFileSync } = await import("node:fs");
|
|
31287
|
-
writeFileSync(tmpPath, Buffer.from(arrayBuffer));
|
|
31288
31399
|
if (process.platform !== "win32") {
|
|
31289
31400
|
chmodSync(tmpPath, 493);
|
|
31290
31401
|
}
|
|
31291
|
-
const { renameSync } = await import("node:fs");
|
|
31292
31402
|
renameSync(tmpPath, binaryPath);
|
|
31293
31403
|
log(`AFT binary ready at ${binaryPath}`);
|
|
31294
31404
|
return binaryPath;
|
|
31295
31405
|
} catch (err) {
|
|
31296
31406
|
const msg = err instanceof Error ? err.message : String(err);
|
|
31297
31407
|
error(`Failed to download AFT binary: ${msg}`);
|
|
31298
|
-
const tmpPath = `${binaryPath}.tmp`;
|
|
31299
31408
|
if (existsSync(tmpPath)) {
|
|
31300
31409
|
try {
|
|
31301
31410
|
unlinkSync(tmpPath);
|
|
31302
31411
|
} catch {}
|
|
31303
31412
|
}
|
|
31304
31413
|
return null;
|
|
31414
|
+
} finally {
|
|
31415
|
+
if (binaryTimeout) {
|
|
31416
|
+
binaryController?.abort();
|
|
31417
|
+
clearTimeout(binaryTimeout);
|
|
31418
|
+
}
|
|
31419
|
+
if (checksumTimeout) {
|
|
31420
|
+
checksumController?.abort();
|
|
31421
|
+
clearTimeout(checksumTimeout);
|
|
31422
|
+
}
|
|
31423
|
+
releaseLock?.();
|
|
31305
31424
|
}
|
|
31306
31425
|
}
|
|
31307
31426
|
async function ensureBinary(version) {
|
|
@@ -31318,6 +31437,39 @@ async function ensureBinary(version) {
|
|
|
31318
31437
|
log("No cached binary found, downloading latest...");
|
|
31319
31438
|
return downloadBinary();
|
|
31320
31439
|
}
|
|
31440
|
+
async function acquireDownloadLock(lockPath) {
|
|
31441
|
+
const startedAt = Date.now();
|
|
31442
|
+
while (true) {
|
|
31443
|
+
try {
|
|
31444
|
+
const fd = openSync(lockPath, "wx");
|
|
31445
|
+
return () => {
|
|
31446
|
+
try {
|
|
31447
|
+
closeSync(fd);
|
|
31448
|
+
} catch {}
|
|
31449
|
+
try {
|
|
31450
|
+
rmSync(lockPath, { force: true });
|
|
31451
|
+
} catch {}
|
|
31452
|
+
};
|
|
31453
|
+
} catch (err) {
|
|
31454
|
+
const code = err.code;
|
|
31455
|
+
if (code !== "EEXIST")
|
|
31456
|
+
throw err;
|
|
31457
|
+
try {
|
|
31458
|
+
const ageMs = Date.now() - statSync(lockPath).mtimeMs;
|
|
31459
|
+
if (ageMs > DOWNLOAD_LOCK_STALE_MS) {
|
|
31460
|
+
rmSync(lockPath, { force: true });
|
|
31461
|
+
continue;
|
|
31462
|
+
}
|
|
31463
|
+
} catch {
|
|
31464
|
+
continue;
|
|
31465
|
+
}
|
|
31466
|
+
if (Date.now() - startedAt > DOWNLOAD_LOCK_TIMEOUT_MS) {
|
|
31467
|
+
throw new Error(`Timed out waiting for download lock: ${lockPath}`);
|
|
31468
|
+
}
|
|
31469
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
31470
|
+
}
|
|
31471
|
+
}
|
|
31472
|
+
}
|
|
31321
31473
|
function parseChecksumForAsset(checksumText, assetName) {
|
|
31322
31474
|
for (const line of checksumText.split(`
|
|
31323
31475
|
`)) {
|
|
@@ -31332,9 +31484,12 @@ function parseChecksumForAsset(checksumText, assetName) {
|
|
|
31332
31484
|
return null;
|
|
31333
31485
|
}
|
|
31334
31486
|
async function fetchLatestTag() {
|
|
31487
|
+
const controller = new AbortController;
|
|
31488
|
+
const timeout = setTimeout(() => controller.abort(), LATEST_TAG_TIMEOUT_MS);
|
|
31335
31489
|
try {
|
|
31336
31490
|
const response = await fetch(`https://api.github.com/repos/${REPO}/releases/latest`, {
|
|
31337
|
-
headers: { Accept: "application/vnd.github.v3+json" }
|
|
31491
|
+
headers: { Accept: "application/vnd.github.v3+json" },
|
|
31492
|
+
signal: controller.signal
|
|
31338
31493
|
});
|
|
31339
31494
|
if (!response.ok)
|
|
31340
31495
|
return null;
|
|
@@ -31342,18 +31497,20 @@ async function fetchLatestTag() {
|
|
|
31342
31497
|
return data.tag_name ?? null;
|
|
31343
31498
|
} catch {
|
|
31344
31499
|
return null;
|
|
31500
|
+
} finally {
|
|
31501
|
+
clearTimeout(timeout);
|
|
31345
31502
|
}
|
|
31346
31503
|
}
|
|
31347
31504
|
// ../aft-bridge/dist/onnx-runtime.js
|
|
31348
31505
|
import { execFileSync } from "node:child_process";
|
|
31349
|
-
import { createHash } from "node:crypto";
|
|
31350
|
-
import { chmodSync as chmodSync2, closeSync, copyFileSync, createWriteStream, existsSync as existsSync2, lstatSync, mkdirSync as mkdirSync2, openSync, readdirSync, readFileSync, readlinkSync, realpathSync, rmSync, statSync, symlinkSync, unlinkSync as unlinkSync2, writeFileSync } from "node:fs";
|
|
31506
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
31507
|
+
import { chmodSync as chmodSync2, closeSync as closeSync2, copyFileSync, createWriteStream as createWriteStream2, existsSync as existsSync2, lstatSync, mkdirSync as mkdirSync2, openSync as openSync2, readdirSync, readFileSync, readlinkSync, realpathSync, rmSync as rmSync2, statSync as statSync2, symlinkSync, unlinkSync as unlinkSync2, writeFileSync } from "node:fs";
|
|
31351
31508
|
import { dirname, join as join3, relative, resolve } from "node:path";
|
|
31352
|
-
import { Readable } from "node:stream";
|
|
31353
|
-
import { pipeline } from "node:stream/promises";
|
|
31509
|
+
import { Readable as Readable2 } from "node:stream";
|
|
31510
|
+
import { pipeline as pipeline2 } from "node:stream/promises";
|
|
31354
31511
|
var ORT_VERSION = "1.24.4";
|
|
31355
31512
|
var ORT_REPO = "microsoft/onnxruntime";
|
|
31356
|
-
var
|
|
31513
|
+
var MAX_DOWNLOAD_BYTES2 = 256 * 1024 * 1024;
|
|
31357
31514
|
var MAX_EXTRACT_BYTES = 1 * 1024 * 1024 * 1024;
|
|
31358
31515
|
var ONNX_LOCK_FILE = ".aft-onnx-installing";
|
|
31359
31516
|
var ONNX_INSTALLED_META_FILE = ".aft-onnx-installed";
|
|
@@ -31471,7 +31628,7 @@ function cleanupAbandonedStagingDirs(onnxBaseDir) {
|
|
|
31471
31628
|
if (Number.isFinite(pid) && pid > 0) {
|
|
31472
31629
|
if (process.platform === "win32") {
|
|
31473
31630
|
try {
|
|
31474
|
-
const ageMs = Date.now() -
|
|
31631
|
+
const ageMs = Date.now() - statSync2(stagingDir).mtimeMs;
|
|
31475
31632
|
abandoned = ageMs > STALE_LOCK_MS;
|
|
31476
31633
|
} catch {
|
|
31477
31634
|
abandoned = true;
|
|
@@ -31485,7 +31642,7 @@ function cleanupAbandonedStagingDirs(onnxBaseDir) {
|
|
|
31485
31642
|
if (abandoned) {
|
|
31486
31643
|
log(`[onnx] removing abandoned staging dir ${stagingDir}`);
|
|
31487
31644
|
try {
|
|
31488
|
-
|
|
31645
|
+
rmSync2(stagingDir, { recursive: true, force: true });
|
|
31489
31646
|
} catch (err) {
|
|
31490
31647
|
warn(`[onnx] failed to remove ${stagingDir}: ${err}`);
|
|
31491
31648
|
}
|
|
@@ -31497,7 +31654,7 @@ function cleanupIncompleteTargetIfUnowned(ortDir) {
|
|
|
31497
31654
|
try {
|
|
31498
31655
|
if (existsSync2(ortDir) && !existsSync2(join3(ortDir, ONNX_INSTALLED_META_FILE))) {
|
|
31499
31656
|
log(`[onnx] removing half-populated install dir ${ortDir} (no meta file)`);
|
|
31500
|
-
|
|
31657
|
+
rmSync2(ortDir, { recursive: true, force: true });
|
|
31501
31658
|
}
|
|
31502
31659
|
} catch (err) {
|
|
31503
31660
|
warn(`[onnx] failed to sweep ${ortDir}: ${err}`);
|
|
@@ -31577,24 +31734,24 @@ async function downloadFileWithCap(url, destPath) {
|
|
|
31577
31734
|
throw new Error(`download failed (HTTP ${res.status})`);
|
|
31578
31735
|
}
|
|
31579
31736
|
const advertised = Number.parseInt(res.headers.get("content-length") ?? "", 10);
|
|
31580
|
-
if (Number.isFinite(advertised) && advertised >
|
|
31581
|
-
throw new Error(`Content-Length ${advertised} exceeds max ${
|
|
31737
|
+
if (Number.isFinite(advertised) && advertised > MAX_DOWNLOAD_BYTES2) {
|
|
31738
|
+
throw new Error(`Content-Length ${advertised} exceeds max ${MAX_DOWNLOAD_BYTES2}`);
|
|
31582
31739
|
}
|
|
31583
31740
|
mkdirSync2(dirname(destPath), { recursive: true });
|
|
31584
31741
|
let bytesWritten = 0;
|
|
31585
31742
|
const guard = new TransformStream({
|
|
31586
31743
|
transform(chunk, transformController) {
|
|
31587
31744
|
bytesWritten += chunk.byteLength;
|
|
31588
|
-
if (bytesWritten >
|
|
31589
|
-
transformController.error(new Error(`download exceeded ${
|
|
31745
|
+
if (bytesWritten > MAX_DOWNLOAD_BYTES2) {
|
|
31746
|
+
transformController.error(new Error(`download exceeded ${MAX_DOWNLOAD_BYTES2} bytes after streaming (server lied about size or sent unbounded body)`));
|
|
31590
31747
|
return;
|
|
31591
31748
|
}
|
|
31592
31749
|
transformController.enqueue(chunk);
|
|
31593
31750
|
}
|
|
31594
31751
|
});
|
|
31595
31752
|
const guarded = res.body.pipeThrough(guard);
|
|
31596
|
-
const nodeStream =
|
|
31597
|
-
await
|
|
31753
|
+
const nodeStream = Readable2.fromWeb(guarded);
|
|
31754
|
+
await pipeline2(nodeStream, createWriteStream2(destPath), { signal: controller.signal });
|
|
31598
31755
|
} catch (err) {
|
|
31599
31756
|
try {
|
|
31600
31757
|
unlinkSync2(destPath);
|
|
@@ -31693,16 +31850,16 @@ async function downloadOnnxRuntime(info, targetDir) {
|
|
|
31693
31850
|
warn(`Could not hash newly-installed ONNX library at ${libPath}: ${err}`);
|
|
31694
31851
|
}
|
|
31695
31852
|
writeOnnxInstalledMeta(targetDir, ORT_VERSION, libHash, archiveSha256);
|
|
31696
|
-
|
|
31853
|
+
rmSync2(tmpDir, { recursive: true, force: true });
|
|
31697
31854
|
log(`ONNX Runtime v${ORT_VERSION} installed to ${targetDir}`);
|
|
31698
31855
|
return targetDir;
|
|
31699
31856
|
} catch (err) {
|
|
31700
31857
|
error(`Failed to download ONNX Runtime: ${err}`);
|
|
31701
31858
|
try {
|
|
31702
|
-
|
|
31859
|
+
rmSync2(tmpDir, { recursive: true, force: true });
|
|
31703
31860
|
} catch {}
|
|
31704
31861
|
try {
|
|
31705
|
-
|
|
31862
|
+
rmSync2(targetDir, { recursive: true, force: true });
|
|
31706
31863
|
} catch {}
|
|
31707
31864
|
return null;
|
|
31708
31865
|
}
|
|
@@ -31719,7 +31876,7 @@ function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, c
|
|
|
31719
31876
|
}
|
|
31720
31877
|
} catch (copyErr) {
|
|
31721
31878
|
if (requiredLibs.has(libFile)) {
|
|
31722
|
-
|
|
31879
|
+
rmSync2(targetDir, { recursive: true, force: true });
|
|
31723
31880
|
throw copyErr;
|
|
31724
31881
|
}
|
|
31725
31882
|
log(`ORT extract: failed to copy optional ${libFile}: ${copyErr}`);
|
|
@@ -31734,7 +31891,7 @@ function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, c
|
|
|
31734
31891
|
symlinkSync(link.target, dst);
|
|
31735
31892
|
} catch (symlinkErr) {
|
|
31736
31893
|
if (requiredLibs.has(link.name)) {
|
|
31737
|
-
|
|
31894
|
+
rmSync2(targetDir, { recursive: true, force: true });
|
|
31738
31895
|
throw symlinkErr;
|
|
31739
31896
|
}
|
|
31740
31897
|
log(`ORT extract: failed to symlink optional ${link.name}: ${symlinkErr}`);
|
|
@@ -31742,7 +31899,7 @@ function copyOnnxLibraries(info, extractedDir, targetDir, realFiles, symlinks, c
|
|
|
31742
31899
|
}
|
|
31743
31900
|
const requiredPath = join3(targetDir, info.libName);
|
|
31744
31901
|
if (!existsSync2(requiredPath)) {
|
|
31745
|
-
|
|
31902
|
+
rmSync2(targetDir, { recursive: true, force: true });
|
|
31746
31903
|
throw new Error(`Required ONNX Runtime library missing after install: ${requiredPath}`);
|
|
31747
31904
|
}
|
|
31748
31905
|
}
|
|
@@ -31775,7 +31932,7 @@ function writeOnnxInstalledMeta(installDir, version, sha256, archiveSha256) {
|
|
|
31775
31932
|
function readOnnxInstalledMeta(installDir) {
|
|
31776
31933
|
const path = join3(installDir, ONNX_INSTALLED_META_FILE);
|
|
31777
31934
|
try {
|
|
31778
|
-
if (!
|
|
31935
|
+
if (!statSync2(path).isFile())
|
|
31779
31936
|
return null;
|
|
31780
31937
|
const raw = readFileSync(path, "utf8");
|
|
31781
31938
|
const parsed = JSON.parse(raw);
|
|
@@ -31792,20 +31949,20 @@ function readOnnxInstalledMeta(installDir) {
|
|
|
31792
31949
|
}
|
|
31793
31950
|
}
|
|
31794
31951
|
function sha256File(path) {
|
|
31795
|
-
const hash =
|
|
31952
|
+
const hash = createHash2("sha256");
|
|
31796
31953
|
hash.update(readFileSync(path));
|
|
31797
31954
|
return hash.digest("hex");
|
|
31798
31955
|
}
|
|
31799
31956
|
function acquireLock(lockPath) {
|
|
31800
31957
|
const tryClaim = () => {
|
|
31801
31958
|
try {
|
|
31802
|
-
const fd =
|
|
31959
|
+
const fd = openSync2(lockPath, "wx");
|
|
31803
31960
|
try {
|
|
31804
31961
|
writeFileSync(fd, `${process.pid}
|
|
31805
31962
|
${new Date().toISOString()}
|
|
31806
31963
|
`);
|
|
31807
31964
|
} finally {
|
|
31808
|
-
|
|
31965
|
+
closeSync2(fd);
|
|
31809
31966
|
}
|
|
31810
31967
|
return true;
|
|
31811
31968
|
} catch (err) {
|
|
@@ -31826,7 +31983,7 @@ ${new Date().toISOString()}
|
|
|
31826
31983
|
const parsed = Number.parseInt(firstLine, 10);
|
|
31827
31984
|
if (Number.isFinite(parsed) && parsed > 0)
|
|
31828
31985
|
owningPid = parsed;
|
|
31829
|
-
lockMtimeMs =
|
|
31986
|
+
lockMtimeMs = statSync2(lockPath).mtimeMs;
|
|
31830
31987
|
} catch {
|
|
31831
31988
|
return tryClaim();
|
|
31832
31989
|
}
|
|
@@ -31892,15 +32049,6 @@ import { homedir as homedir3 } from "node:os";
|
|
|
31892
32049
|
var DEFAULT_IDLE_TIMEOUT_MS = Infinity;
|
|
31893
32050
|
var DEFAULT_MAX_POOL_SIZE = 8;
|
|
31894
32051
|
var CLEANUP_INTERVAL_MS = 60 * 1000;
|
|
31895
|
-
|
|
31896
|
-
class HomeProjectRootError extends Error {
|
|
31897
|
-
projectRoot;
|
|
31898
|
-
constructor(projectRoot) {
|
|
31899
|
-
super(`aft refuses to spawn a bridge with project_root=${projectRoot} (user home directory). ` + `Open OpenCode/Pi from a project subdirectory instead, or set the session's ` + `directory to a real project root.`);
|
|
31900
|
-
this.projectRoot = projectRoot;
|
|
31901
|
-
this.name = "HomeProjectRootError";
|
|
31902
|
-
}
|
|
31903
|
-
}
|
|
31904
32052
|
function canonicalHomeDir() {
|
|
31905
32053
|
try {
|
|
31906
32054
|
const home = homedir3();
|
|
@@ -31943,7 +32091,9 @@ class BridgePool {
|
|
|
31943
32091
|
onVersionMismatch: options.onVersionMismatch,
|
|
31944
32092
|
onConfigureWarnings: options.onConfigureWarnings,
|
|
31945
32093
|
onBashCompletion: options.onBashCompletion,
|
|
31946
|
-
onBashLongRunning: options.onBashLongRunning
|
|
32094
|
+
onBashLongRunning: options.onBashLongRunning,
|
|
32095
|
+
errorPrefix: options.errorPrefix,
|
|
32096
|
+
logger: options.logger
|
|
31947
32097
|
};
|
|
31948
32098
|
this.configOverrides = configOverrides;
|
|
31949
32099
|
if (Number.isFinite(this.idleTimeoutMs)) {
|
|
@@ -31961,9 +32111,6 @@ class BridgePool {
|
|
|
31961
32111
|
}
|
|
31962
32112
|
getBridge(projectRoot) {
|
|
31963
32113
|
const key = normalizeKey(projectRoot);
|
|
31964
|
-
if (isHomeDirectoryRoot(key)) {
|
|
31965
|
-
throw new HomeProjectRootError(key);
|
|
31966
|
-
}
|
|
31967
32114
|
const existing = this.bridges.get(key);
|
|
31968
32115
|
if (existing) {
|
|
31969
32116
|
existing.lastUsed = Date.now();
|
|
@@ -32015,24 +32162,32 @@ class BridgePool {
|
|
|
32015
32162
|
}
|
|
32016
32163
|
async replaceBinary(newPath) {
|
|
32017
32164
|
this.binaryPath = newPath;
|
|
32018
|
-
const shutdowns = Array.from(this.bridges.values()).map((entry) => entry.bridge.shutdown());
|
|
32019
32165
|
this.bridges.clear();
|
|
32020
|
-
await Promise.allSettled(shutdowns);
|
|
32021
32166
|
this.log(`Binary path updated to ${newPath}. All bridges cleared — next calls will use the new binary.`);
|
|
32022
32167
|
return newPath;
|
|
32023
32168
|
}
|
|
32024
32169
|
log(message, meta) {
|
|
32025
32170
|
const logger = this.logger ?? getActiveLogger();
|
|
32026
|
-
if (logger)
|
|
32027
|
-
|
|
32028
|
-
|
|
32171
|
+
if (logger) {
|
|
32172
|
+
try {
|
|
32173
|
+
logger.log(message, meta);
|
|
32174
|
+
} catch (err) {
|
|
32175
|
+
console.error(`[aft-bridge] ERROR: pool logger log threw: ${err instanceof Error ? err.message : String(err)}`);
|
|
32176
|
+
console.error(`[aft-bridge] ${message}`);
|
|
32177
|
+
}
|
|
32178
|
+
} else
|
|
32029
32179
|
log(message, meta);
|
|
32030
32180
|
}
|
|
32031
32181
|
error(message, meta) {
|
|
32032
32182
|
const logger = this.logger ?? getActiveLogger();
|
|
32033
|
-
if (logger)
|
|
32034
|
-
|
|
32035
|
-
|
|
32183
|
+
if (logger) {
|
|
32184
|
+
try {
|
|
32185
|
+
logger.error(message, meta);
|
|
32186
|
+
} catch (err) {
|
|
32187
|
+
console.error(`[aft-bridge] ERROR: pool logger error threw: ${err instanceof Error ? err.message : String(err)}`);
|
|
32188
|
+
console.error(`[aft-bridge] ERROR: ${message}`);
|
|
32189
|
+
}
|
|
32190
|
+
} else
|
|
32036
32191
|
error(message, meta);
|
|
32037
32192
|
}
|
|
32038
32193
|
setConfigureOverride(key, value) {
|
|
@@ -32059,7 +32214,7 @@ function normalizeKey(projectRoot) {
|
|
|
32059
32214
|
}
|
|
32060
32215
|
// ../aft-bridge/dist/resolver.js
|
|
32061
32216
|
import { execSync, spawnSync } from "node:child_process";
|
|
32062
|
-
import { chmodSync as chmodSync3, copyFileSync as copyFileSync2, existsSync as existsSync3, mkdirSync as mkdirSync3, renameSync } from "node:fs";
|
|
32217
|
+
import { chmodSync as chmodSync3, copyFileSync as copyFileSync2, existsSync as existsSync3, mkdirSync as mkdirSync3, renameSync as renameSync2 } from "node:fs";
|
|
32063
32218
|
import { createRequire as createRequire2 } from "node:module";
|
|
32064
32219
|
import { homedir as homedir4 } from "node:os";
|
|
32065
32220
|
import { join as join4 } from "node:path";
|
|
@@ -32090,15 +32245,19 @@ function copyToVersionedCache(npmBinaryPath, knownVersion) {
|
|
|
32090
32245
|
const versionedDir = join4(cacheDir, tag);
|
|
32091
32246
|
const ext = process.platform === "win32" ? ".exe" : "";
|
|
32092
32247
|
const cachedPath = join4(versionedDir, `aft${ext}`);
|
|
32093
|
-
if (existsSync3(cachedPath))
|
|
32094
|
-
|
|
32248
|
+
if (existsSync3(cachedPath)) {
|
|
32249
|
+
const cachedVersion = readBinaryVersion(cachedPath);
|
|
32250
|
+
if (cachedVersion === version)
|
|
32251
|
+
return cachedPath;
|
|
32252
|
+
warn(`Cached binary at ${cachedPath} reports ${cachedVersion ?? "no version"}, expected ${version}; refreshing from npm package`);
|
|
32253
|
+
}
|
|
32095
32254
|
mkdirSync3(versionedDir, { recursive: true });
|
|
32096
|
-
const tmpPath = `${cachedPath}.tmp`;
|
|
32255
|
+
const tmpPath = `${cachedPath}.${process.pid}.${Date.now()}.tmp`;
|
|
32097
32256
|
copyFileSync2(npmBinaryPath, tmpPath);
|
|
32098
32257
|
if (process.platform !== "win32") {
|
|
32099
32258
|
chmodSync3(tmpPath, 493);
|
|
32100
32259
|
}
|
|
32101
|
-
|
|
32260
|
+
renameSync2(tmpPath, cachedPath);
|
|
32102
32261
|
log(`Copied npm binary to versioned cache: ${cachedPath}`);
|
|
32103
32262
|
return cachedPath;
|
|
32104
32263
|
} catch (err) {
|
|
@@ -32106,6 +32265,32 @@ function copyToVersionedCache(npmBinaryPath, knownVersion) {
|
|
|
32106
32265
|
return null;
|
|
32107
32266
|
}
|
|
32108
32267
|
}
|
|
32268
|
+
function normalizeBareVersion(version) {
|
|
32269
|
+
return version.startsWith("v") ? version.slice(1) : version;
|
|
32270
|
+
}
|
|
32271
|
+
function homeDirFromEnv(env) {
|
|
32272
|
+
return (process.platform === "win32" ? env.USERPROFILE || env.HOME : env.HOME) || homedir4();
|
|
32273
|
+
}
|
|
32274
|
+
function cacheDirFromEnv(env) {
|
|
32275
|
+
if (process.platform === "win32") {
|
|
32276
|
+
const base2 = env.LOCALAPPDATA || env.APPDATA || join4(homeDirFromEnv(env), "AppData", "Local");
|
|
32277
|
+
return join4(base2, "aft", "bin");
|
|
32278
|
+
}
|
|
32279
|
+
const base = env.XDG_CACHE_HOME || join4(homeDirFromEnv(env), ".cache");
|
|
32280
|
+
return join4(base, "aft", "bin");
|
|
32281
|
+
}
|
|
32282
|
+
function cachedBinaryPathFromEnv(version, env, ext) {
|
|
32283
|
+
const binaryPath = join4(cacheDirFromEnv(env), version, `aft${ext}`);
|
|
32284
|
+
return existsSync3(binaryPath) ? binaryPath : null;
|
|
32285
|
+
}
|
|
32286
|
+
function isExpectedCachedBinary(binaryPath, expectedVersion) {
|
|
32287
|
+
const expected = normalizeBareVersion(expectedVersion);
|
|
32288
|
+
const actual = readBinaryVersion(binaryPath);
|
|
32289
|
+
if (actual === expected)
|
|
32290
|
+
return true;
|
|
32291
|
+
warn(`Cached binary at ${binaryPath} reports ${actual ?? "no version"}, expected ${expected}; skipping cache candidate`);
|
|
32292
|
+
return false;
|
|
32293
|
+
}
|
|
32109
32294
|
function platformKey(platform = process.platform, arch = process.arch) {
|
|
32110
32295
|
const archMap = PLATFORM_ARCH_MAP[platform];
|
|
32111
32296
|
if (!archMap) {
|
|
@@ -32119,6 +32304,7 @@ function platformKey(platform = process.platform, arch = process.arch) {
|
|
|
32119
32304
|
}
|
|
32120
32305
|
function findBinarySync(expectedVersion) {
|
|
32121
32306
|
const ext = process.platform === "win32" ? ".exe" : "";
|
|
32307
|
+
const env = { ...process.env };
|
|
32122
32308
|
const pluginVersion = expectedVersion ?? (() => {
|
|
32123
32309
|
try {
|
|
32124
32310
|
const req = createRequire2(import.meta.url);
|
|
@@ -32129,8 +32315,8 @@ function findBinarySync(expectedVersion) {
|
|
|
32129
32315
|
})();
|
|
32130
32316
|
if (pluginVersion) {
|
|
32131
32317
|
const tag = pluginVersion.startsWith("v") ? pluginVersion : `v${pluginVersion}`;
|
|
32132
|
-
const versionCached =
|
|
32133
|
-
if (versionCached)
|
|
32318
|
+
const versionCached = cachedBinaryPathFromEnv(tag, env, ext);
|
|
32319
|
+
if (versionCached && isExpectedCachedBinary(versionCached, pluginVersion))
|
|
32134
32320
|
return versionCached;
|
|
32135
32321
|
}
|
|
32136
32322
|
try {
|
|
@@ -32140,10 +32326,12 @@ function findBinarySync(expectedVersion) {
|
|
|
32140
32326
|
const resolved = req.resolve(packageBin);
|
|
32141
32327
|
if (existsSync3(resolved)) {
|
|
32142
32328
|
const npmVersion = readBinaryVersion(resolved);
|
|
32143
|
-
if (
|
|
32329
|
+
if (npmVersion === null) {
|
|
32330
|
+
warn(`npm platform package binary at ${resolved} did not report a version; skipping (continuing to PATH lookup)`);
|
|
32331
|
+
} else if (pluginVersion && npmVersion !== normalizeBareVersion(pluginVersion)) {
|
|
32144
32332
|
warn(`npm platform package binary v${npmVersion} does not match plugin v${pluginVersion}; skipping (continuing to PATH lookup)`);
|
|
32145
32333
|
} else {
|
|
32146
|
-
const copied = copyToVersionedCache(resolved, npmVersion
|
|
32334
|
+
const copied = copyToVersionedCache(resolved, npmVersion);
|
|
32147
32335
|
return copied ?? resolved;
|
|
32148
32336
|
}
|
|
32149
32337
|
}
|
|
@@ -32152,12 +32340,13 @@ function findBinarySync(expectedVersion) {
|
|
|
32152
32340
|
const whichCmd = process.platform === "win32" ? "where aft" : "which aft";
|
|
32153
32341
|
const result = execSync(whichCmd, {
|
|
32154
32342
|
encoding: "utf-8",
|
|
32343
|
+
env,
|
|
32155
32344
|
stdio: ["pipe", "pipe", "pipe"]
|
|
32156
32345
|
}).trim();
|
|
32157
32346
|
if (result)
|
|
32158
32347
|
return result;
|
|
32159
32348
|
} catch {}
|
|
32160
|
-
const cargoPath = join4(
|
|
32349
|
+
const cargoPath = join4(homeDirFromEnv(env), ".cargo", "bin", `aft${ext}`);
|
|
32161
32350
|
if (existsSync3(cargoPath))
|
|
32162
32351
|
return cargoPath;
|
|
32163
32352
|
return null;
|
|
@@ -32192,7 +32381,7 @@ async function findBinary(expectedVersion) {
|
|
|
32192
32381
|
`));
|
|
32193
32382
|
}
|
|
32194
32383
|
// ../aft-bridge/dist/url-fetch.js
|
|
32195
|
-
import { createHash as
|
|
32384
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
32196
32385
|
import { lookup } from "node:dns/promises";
|
|
32197
32386
|
import { existsSync as existsSync4, mkdirSync as mkdirSync4, readdirSync as readdirSync2, readFileSync as readFileSync2, unlinkSync as unlinkSync3, writeFileSync as writeFileSync2 } from "node:fs";
|
|
32198
32387
|
import { isIP } from "node:net";
|
|
@@ -32349,7 +32538,7 @@ function cacheDir(storageDir) {
|
|
|
32349
32538
|
return join5(storageDir, "url_cache");
|
|
32350
32539
|
}
|
|
32351
32540
|
function hashUrl(url) {
|
|
32352
|
-
return
|
|
32541
|
+
return createHash3("sha256").update(url).digest("hex").slice(0, 16);
|
|
32353
32542
|
}
|
|
32354
32543
|
function metaPath(storageDir, hash) {
|
|
32355
32544
|
return join5(cacheDir(storageDir), `${hash}.meta.json`);
|
|
@@ -32607,8 +32796,8 @@ async function fetchUrlToTempFile(url, storageDir, options = {}) {
|
|
|
32607
32796
|
const contentFile = contentPath(storageDir, hash, extension);
|
|
32608
32797
|
const tmpContent = `${contentFile}.tmp-${process.pid}`;
|
|
32609
32798
|
writeFileSync2(tmpContent, body);
|
|
32610
|
-
const { renameSync:
|
|
32611
|
-
|
|
32799
|
+
const { renameSync: renameSync3 } = await import("node:fs");
|
|
32800
|
+
renameSync3(tmpContent, contentFile);
|
|
32612
32801
|
const meta = {
|
|
32613
32802
|
url,
|
|
32614
32803
|
contentType,
|
|
@@ -32617,7 +32806,7 @@ async function fetchUrlToTempFile(url, storageDir, options = {}) {
|
|
|
32617
32806
|
};
|
|
32618
32807
|
const tmpMeta = `${metaFile}.tmp-${process.pid}`;
|
|
32619
32808
|
writeFileSync2(tmpMeta, JSON.stringify(meta));
|
|
32620
|
-
|
|
32809
|
+
renameSync3(tmpMeta, metaFile);
|
|
32621
32810
|
log(`URL cached (${total} bytes): ${url}`);
|
|
32622
32811
|
return contentFile;
|
|
32623
32812
|
}
|
|
@@ -32735,31 +32924,31 @@ function warn2(message, data) {
|
|
|
32735
32924
|
function error2(message, data) {
|
|
32736
32925
|
write("ERROR", message, data);
|
|
32737
32926
|
}
|
|
32738
|
-
function
|
|
32927
|
+
function sessionLog(sessionId, message, data) {
|
|
32739
32928
|
write("INFO", message, data, sessionId);
|
|
32740
32929
|
}
|
|
32741
|
-
function
|
|
32930
|
+
function sessionWarn(sessionId, message, data) {
|
|
32742
32931
|
write("WARN", message, data, sessionId);
|
|
32743
32932
|
}
|
|
32744
|
-
function
|
|
32933
|
+
function sessionError(sessionId, message, data) {
|
|
32745
32934
|
write("ERROR", message, data, sessionId);
|
|
32746
32935
|
}
|
|
32747
32936
|
var bridgeLogger = {
|
|
32748
32937
|
log(message, meta) {
|
|
32749
32938
|
if (meta?.sessionId)
|
|
32750
|
-
|
|
32939
|
+
sessionLog(meta.sessionId, message);
|
|
32751
32940
|
else
|
|
32752
32941
|
write("INFO", message);
|
|
32753
32942
|
},
|
|
32754
32943
|
warn(message, meta) {
|
|
32755
32944
|
if (meta?.sessionId)
|
|
32756
|
-
|
|
32945
|
+
sessionWarn(meta.sessionId, message);
|
|
32757
32946
|
else
|
|
32758
32947
|
write("WARN", message);
|
|
32759
32948
|
},
|
|
32760
32949
|
error(message, meta) {
|
|
32761
32950
|
if (meta?.sessionId)
|
|
32762
|
-
|
|
32951
|
+
sessionError(meta.sessionId, message);
|
|
32763
32952
|
else
|
|
32764
32953
|
write("ERROR", message);
|
|
32765
32954
|
},
|
|
@@ -32771,6 +32960,7 @@ var sessionBgStates = new Map;
|
|
|
32771
32960
|
var SESSION_BG_STATE_IDLE_TTL_MS = 60 * 60 * 1000;
|
|
32772
32961
|
var DEBOUNCE_STEP_MS = 200;
|
|
32773
32962
|
var DEBOUNCE_CAP_MS = 1000;
|
|
32963
|
+
var MAX_WAKE_SEND_ATTEMPTS = 5;
|
|
32774
32964
|
var UNKNOWN_COMPLETION_TTL_MS = 5000;
|
|
32775
32965
|
var UNKNOWN_COMPLETION_CAP = 32;
|
|
32776
32966
|
var DEFAULT_SESSION_ID = "__default__";
|
|
@@ -32820,16 +33010,22 @@ async function handlePushedBgLongRunning(drainContext, reminder) {
|
|
|
32820
33010
|
}
|
|
32821
33011
|
async function appendToolResultBgCompletions(drainContext, content) {
|
|
32822
33012
|
const state = stateFor(drainContext.sessionID);
|
|
33013
|
+
if (state.outstandingTaskIds.size === 0 && state.pendingCompletions.length === 0 && state.pendingLongRunning.length === 0)
|
|
33014
|
+
await drainCompletions(drainContext);
|
|
32823
33015
|
if (state.outstandingTaskIds.size === 0 && state.pendingCompletions.length === 0 && state.pendingLongRunning.length === 0)
|
|
32824
33016
|
return;
|
|
32825
|
-
if (state.outstandingTaskIds.size > 0) {
|
|
33017
|
+
if (state.outstandingTaskIds.size > 0 || !state.forcedDrainCompleted) {
|
|
32826
33018
|
await drainCompletions(drainContext);
|
|
32827
33019
|
}
|
|
32828
33020
|
if (state.pendingCompletions.length === 0 && state.pendingLongRunning.length === 0)
|
|
32829
33021
|
return;
|
|
33022
|
+
const deliveredCompletions = [...state.pendingCompletions];
|
|
32830
33023
|
const reminder = formatCombinedSystemReminder(state.pendingCompletions, state.pendingLongRunning);
|
|
32831
33024
|
state.pendingCompletions = [];
|
|
32832
33025
|
state.pendingLongRunning = [];
|
|
33026
|
+
state.wakeRetryAttempts = 0;
|
|
33027
|
+
state.wakeHardStopped = false;
|
|
33028
|
+
await ackCompletions(drainContext, deliveredCompletions);
|
|
32833
33029
|
if (state.debounceTimer) {
|
|
32834
33030
|
clearTimeout(state.debounceTimer);
|
|
32835
33031
|
state.debounceTimer = null;
|
|
@@ -32844,15 +33040,16 @@ async function handleTurnEndBgCompletions(drainContext) {
|
|
|
32844
33040
|
}
|
|
32845
33041
|
async function triggerWakeIfPending(drainContext, skipDrain) {
|
|
32846
33042
|
const state = stateFor(drainContext.sessionID);
|
|
32847
|
-
if (!skipDrain && state.outstandingTaskIds.size > 0) {
|
|
33043
|
+
if (!skipDrain && (state.outstandingTaskIds.size > 0 || !state.forcedDrainCompleted)) {
|
|
32848
33044
|
await drainCompletions(drainContext);
|
|
32849
33045
|
}
|
|
32850
33046
|
if (state.pendingCompletions.length === 0 && state.pendingLongRunning.length === 0)
|
|
32851
33047
|
return;
|
|
32852
|
-
scheduleWake(state, async (reminder) => {
|
|
33048
|
+
scheduleWake(state, async (reminder, deliveredCompletions) => {
|
|
32853
33049
|
drainContext.runtime.sendUserMessage(reminder, { deliverAs: "steer" });
|
|
32854
|
-
|
|
32855
|
-
|
|
33050
|
+
await ackCompletions(drainContext, deliveredCompletions);
|
|
33051
|
+
}, (err, hardStopped) => {
|
|
33052
|
+
sessionWarn(drainContext.sessionID ?? "", hardStopped ? `${LOG_PREFIX} wake send failed ${MAX_WAKE_SEND_ATTEMPTS} times; stopping retries: ${err instanceof Error ? err.message : String(err)}` : `${LOG_PREFIX} wake send failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
32856
33053
|
});
|
|
32857
33054
|
}
|
|
32858
33055
|
function formatSystemReminder(completions) {
|
|
@@ -32885,20 +33082,39 @@ function formatCombinedSystemReminder(completions, longRunning) {
|
|
|
32885
33082
|
${formatLongRunningReminder(longRunning)}`;
|
|
32886
33083
|
}
|
|
32887
33084
|
async function drainCompletions({ ctx, directory, sessionID }) {
|
|
33085
|
+
const state = stateFor(sessionID);
|
|
32888
33086
|
try {
|
|
32889
33087
|
const bridge = ctx.pool.getActiveBridgeForRoot(directory) ?? ctx.pool.getBridge(directory);
|
|
32890
33088
|
const params = sessionID ? { session_id: sessionID } : {};
|
|
32891
33089
|
const response = await bridge.send("bash_drain_completions", params);
|
|
32892
33090
|
if (response.success === false) {
|
|
32893
|
-
|
|
33091
|
+
sessionWarn(sessionID ?? "", `${LOG_PREFIX} drain failed: ${String(response.message ?? "unknown error")}`);
|
|
32894
33092
|
return;
|
|
32895
33093
|
}
|
|
32896
|
-
|
|
33094
|
+
state.forcedDrainCompleted = true;
|
|
33095
|
+
ingestDrainedBgCompletions(sessionID, response.bg_completions);
|
|
32897
33096
|
} catch (err) {
|
|
32898
|
-
|
|
33097
|
+
sessionWarn(sessionID ?? "", `${LOG_PREFIX} drain failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
33098
|
+
}
|
|
33099
|
+
}
|
|
33100
|
+
async function ackCompletions({ ctx, directory, sessionID }, completions) {
|
|
33101
|
+
const taskIds = [...new Set(completions.map((completion) => completion.task_id))];
|
|
33102
|
+
if (taskIds.length === 0)
|
|
33103
|
+
return;
|
|
33104
|
+
try {
|
|
33105
|
+
const bridge = ctx.pool.getActiveBridgeForRoot(directory) ?? ctx.pool.getBridge(directory);
|
|
33106
|
+
const params = sessionID ? { session_id: sessionID, task_ids: taskIds } : { task_ids: taskIds };
|
|
33107
|
+
const response = await bridge.send("bash_ack_completions", params);
|
|
33108
|
+
if (response.success === false) {
|
|
33109
|
+
sessionWarn(sessionID ?? "", `${LOG_PREFIX} ack failed: ${String(response.message ?? "unknown error")}`);
|
|
33110
|
+
}
|
|
33111
|
+
} catch (err) {
|
|
33112
|
+
sessionWarn(sessionID ?? "", `${LOG_PREFIX} ack failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
32899
33113
|
}
|
|
32900
33114
|
}
|
|
32901
33115
|
function scheduleWake(state, sendWake, onSendFailure) {
|
|
33116
|
+
if (state.wakeHardStopped)
|
|
33117
|
+
return;
|
|
32902
33118
|
const now = Date.now();
|
|
32903
33119
|
const pendingCount = state.pendingCompletions.length + state.pendingLongRunning.length;
|
|
32904
33120
|
if (state.debounceTimer && pendingCount <= state.scheduledCompletionCount) {
|
|
@@ -32927,13 +33143,22 @@ function scheduleWake(state, sendWake, onSendFailure) {
|
|
|
32927
33143
|
const reminder = formatCombinedSystemReminder(pending, pendingLongRunning);
|
|
32928
33144
|
state.pendingCompletions = [];
|
|
32929
33145
|
state.pendingLongRunning = [];
|
|
32930
|
-
sendWake(reminder).then(() => {
|
|
33146
|
+
sendWake(reminder, pending).then(() => {
|
|
32931
33147
|
state.retryDelayMs = null;
|
|
33148
|
+
state.wakeRetryAttempts = 0;
|
|
33149
|
+
state.wakeHardStopped = false;
|
|
32932
33150
|
}).catch((err) => {
|
|
32933
33151
|
state.pendingCompletions = [...pending, ...state.pendingCompletions];
|
|
32934
33152
|
state.pendingLongRunning = [...pendingLongRunning, ...state.pendingLongRunning];
|
|
33153
|
+
state.wakeRetryAttempts += 1;
|
|
33154
|
+
if (state.wakeRetryAttempts >= MAX_WAKE_SEND_ATTEMPTS) {
|
|
33155
|
+
state.retryDelayMs = null;
|
|
33156
|
+
state.wakeHardStopped = true;
|
|
33157
|
+
onSendFailure(err, true);
|
|
33158
|
+
return;
|
|
33159
|
+
}
|
|
32935
33160
|
state.retryDelayMs = Math.min((delay || DEBOUNCE_STEP_MS) * 2, DEBOUNCE_CAP_MS);
|
|
32936
|
-
onSendFailure(err);
|
|
33161
|
+
onSendFailure(err, false);
|
|
32937
33162
|
scheduleWake(state, sendWake, onSendFailure);
|
|
32938
33163
|
});
|
|
32939
33164
|
}, delay);
|
|
@@ -32954,6 +33179,9 @@ function stateFor(sessionID) {
|
|
|
32954
33179
|
scheduledFireAt: null,
|
|
32955
33180
|
scheduledCompletionCount: 0,
|
|
32956
33181
|
retryDelayMs: null,
|
|
33182
|
+
wakeRetryAttempts: 0,
|
|
33183
|
+
wakeHardStopped: false,
|
|
33184
|
+
forcedDrainCompleted: false,
|
|
32957
33185
|
unknownCompletions: [],
|
|
32958
33186
|
lastSeenAt: now
|
|
32959
33187
|
};
|
|
@@ -32963,6 +33191,22 @@ function stateFor(sessionID) {
|
|
|
32963
33191
|
}
|
|
32964
33192
|
return state;
|
|
32965
33193
|
}
|
|
33194
|
+
function ingestDrainedBgCompletions(sessionID, completions) {
|
|
33195
|
+
if (!Array.isArray(completions) || completions.length === 0)
|
|
33196
|
+
return [];
|
|
33197
|
+
const state = stateFor(sessionID);
|
|
33198
|
+
const accepted = [];
|
|
33199
|
+
for (const completion of completions) {
|
|
33200
|
+
if (!isBgCompletion(completion))
|
|
33201
|
+
continue;
|
|
33202
|
+
state.outstandingTaskIds.delete(completion.task_id);
|
|
33203
|
+
if (!state.pendingCompletions.some((pending) => pending.task_id === completion.task_id) && !accepted.some((pending) => pending.task_id === completion.task_id)) {
|
|
33204
|
+
accepted.push(completion);
|
|
33205
|
+
}
|
|
33206
|
+
}
|
|
33207
|
+
state.pendingCompletions.push(...accepted);
|
|
33208
|
+
return accepted;
|
|
33209
|
+
}
|
|
32966
33210
|
function cleanupIdleSessionStates(now = Date.now()) {
|
|
32967
33211
|
const cutoff = now - SESSION_BG_STATE_IDLE_TTL_MS;
|
|
32968
33212
|
for (const [sessionID, state] of sessionBgStates) {
|
|
@@ -33055,7 +33299,7 @@ import {
|
|
|
33055
33299
|
// package.json
|
|
33056
33300
|
var package_default = {
|
|
33057
33301
|
name: "@cortexkit/aft-pi",
|
|
33058
|
-
version: "0.26.
|
|
33302
|
+
version: "0.26.2",
|
|
33059
33303
|
type: "module",
|
|
33060
33304
|
description: "Pi coding agent extension for Agent File Tools (AFT) — tree-sitter and LSP-powered code analysis",
|
|
33061
33305
|
main: "dist/index.js",
|
|
@@ -33077,18 +33321,18 @@ var package_default = {
|
|
|
33077
33321
|
prepublishOnly: "bun run build"
|
|
33078
33322
|
},
|
|
33079
33323
|
dependencies: {
|
|
33080
|
-
"@cortexkit/aft-bridge": "0.26.
|
|
33324
|
+
"@cortexkit/aft-bridge": "0.26.2",
|
|
33081
33325
|
typebox: "^1.1.24",
|
|
33082
33326
|
"comment-json": "^5.0.0",
|
|
33083
33327
|
diff: "^8.0.4",
|
|
33084
33328
|
zod: "^4.1.8"
|
|
33085
33329
|
},
|
|
33086
33330
|
optionalDependencies: {
|
|
33087
|
-
"@cortexkit/aft-darwin-arm64": "0.26.
|
|
33088
|
-
"@cortexkit/aft-darwin-x64": "0.26.
|
|
33089
|
-
"@cortexkit/aft-linux-arm64": "0.26.
|
|
33090
|
-
"@cortexkit/aft-linux-x64": "0.26.
|
|
33091
|
-
"@cortexkit/aft-win32-x64": "0.26.
|
|
33331
|
+
"@cortexkit/aft-darwin-arm64": "0.26.2",
|
|
33332
|
+
"@cortexkit/aft-darwin-x64": "0.26.2",
|
|
33333
|
+
"@cortexkit/aft-linux-arm64": "0.26.2",
|
|
33334
|
+
"@cortexkit/aft-linux-x64": "0.26.2",
|
|
33335
|
+
"@cortexkit/aft-win32-x64": "0.26.2"
|
|
33092
33336
|
},
|
|
33093
33337
|
devDependencies: {
|
|
33094
33338
|
"@earendil-works/pi-coding-agent": "*",
|
|
@@ -33573,7 +33817,7 @@ function registerStatusCommand(pi, ctx) {
|
|
|
33573
33817
|
|
|
33574
33818
|
// src/config.ts
|
|
33575
33819
|
var import_comment_json = __toESM(require_src2(), 1);
|
|
33576
|
-
import { existsSync as existsSync5, readFileSync as readFileSync3, renameSync as
|
|
33820
|
+
import { existsSync as existsSync5, readFileSync as readFileSync3, renameSync as renameSync3, unlinkSync as unlinkSync4, writeFileSync as writeFileSync3 } from "node:fs";
|
|
33577
33821
|
import { homedir as homedir5 } from "node:os";
|
|
33578
33822
|
import { join as join7 } from "node:path";
|
|
33579
33823
|
|
|
@@ -47348,7 +47592,7 @@ function migrateAftConfigFile(configPath, logger = { log: log2, warn: warn2 }) {
|
|
|
47348
47592
|
${serialized}` : serialized;
|
|
47349
47593
|
tmpPath = `${configPath}.tmp.${process.pid}`;
|
|
47350
47594
|
writeFileSync3(tmpPath, nextContent, "utf-8");
|
|
47351
|
-
|
|
47595
|
+
renameSync3(tmpPath, configPath);
|
|
47352
47596
|
logger.log(`Migrated config at ${configPath}: removed ${oldKeys.join(", ")}`);
|
|
47353
47597
|
return { migrated: true, oldKeys };
|
|
47354
47598
|
} catch (err) {
|
|
@@ -47563,17 +47807,17 @@ function loadAftConfig(projectDirectory) {
|
|
|
47563
47807
|
|
|
47564
47808
|
// src/lsp-auto-install.ts
|
|
47565
47809
|
import { spawn as spawn2 } from "node:child_process";
|
|
47566
|
-
import { createHash as
|
|
47567
|
-
import { createReadStream, mkdirSync as mkdirSync6, readFileSync as readFileSync5, renameSync as
|
|
47810
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
47811
|
+
import { createReadStream, mkdirSync as mkdirSync6, readFileSync as readFileSync5, renameSync as renameSync4, rmSync as rmSync3, statSync as statSync4 } from "node:fs";
|
|
47568
47812
|
import { join as join10 } from "node:path";
|
|
47569
47813
|
|
|
47570
47814
|
// src/lsp-cache.ts
|
|
47571
47815
|
import {
|
|
47572
|
-
closeSync as
|
|
47816
|
+
closeSync as closeSync3,
|
|
47573
47817
|
mkdirSync as mkdirSync5,
|
|
47574
|
-
openSync as
|
|
47818
|
+
openSync as openSync3,
|
|
47575
47819
|
readFileSync as readFileSync4,
|
|
47576
|
-
statSync as
|
|
47820
|
+
statSync as statSync3,
|
|
47577
47821
|
unlinkSync as unlinkSync5,
|
|
47578
47822
|
writeFileSync as writeFileSync4
|
|
47579
47823
|
} from "node:fs";
|
|
@@ -47606,7 +47850,7 @@ function lspBinDir(npmPackage) {
|
|
|
47606
47850
|
function isInstalled(npmPackage, binary) {
|
|
47607
47851
|
for (const candidate of lspBinaryCandidates(binary)) {
|
|
47608
47852
|
try {
|
|
47609
|
-
if (
|
|
47853
|
+
if (statSync3(join8(lspBinDir(npmPackage), candidate)).isFile())
|
|
47610
47854
|
return true;
|
|
47611
47855
|
} catch {}
|
|
47612
47856
|
}
|
|
@@ -47634,7 +47878,7 @@ function writeInstalledMetaIn(installDir, version2, sha256) {
|
|
|
47634
47878
|
function readInstalledMetaIn(installDir) {
|
|
47635
47879
|
const path2 = join8(installDir, INSTALLED_META_FILE);
|
|
47636
47880
|
try {
|
|
47637
|
-
if (!
|
|
47881
|
+
if (!statSync3(path2).isFile())
|
|
47638
47882
|
return null;
|
|
47639
47883
|
const raw = readFileSync4(path2, "utf8");
|
|
47640
47884
|
const parsed = JSON.parse(raw);
|
|
@@ -47664,13 +47908,13 @@ function acquireInstallLock(lockKey) {
|
|
|
47664
47908
|
const lock = lockPath(lockKey);
|
|
47665
47909
|
const tryClaim = () => {
|
|
47666
47910
|
try {
|
|
47667
|
-
const fd =
|
|
47911
|
+
const fd = openSync3(lock, "wx");
|
|
47668
47912
|
try {
|
|
47669
47913
|
writeFileSync4(fd, `${process.pid}
|
|
47670
47914
|
${new Date().toISOString()}
|
|
47671
47915
|
`);
|
|
47672
47916
|
} finally {
|
|
47673
|
-
|
|
47917
|
+
closeSync3(fd);
|
|
47674
47918
|
}
|
|
47675
47919
|
return true;
|
|
47676
47920
|
} catch (err) {
|
|
@@ -47691,7 +47935,7 @@ ${new Date().toISOString()}
|
|
|
47691
47935
|
const parsed = Number.parseInt(firstLine, 10);
|
|
47692
47936
|
if (Number.isFinite(parsed) && parsed > 0)
|
|
47693
47937
|
owningPid = parsed;
|
|
47694
|
-
lockMtimeMs =
|
|
47938
|
+
lockMtimeMs = statSync3(lock).mtimeMs;
|
|
47695
47939
|
} catch {
|
|
47696
47940
|
return tryClaim();
|
|
47697
47941
|
}
|
|
@@ -48233,7 +48477,7 @@ function hashInstalledBinary(spec) {
|
|
|
48233
48477
|
let pathToHash = null;
|
|
48234
48478
|
for (const p of candidates) {
|
|
48235
48479
|
try {
|
|
48236
|
-
if (
|
|
48480
|
+
if (statSync4(p).isFile()) {
|
|
48237
48481
|
pathToHash = p;
|
|
48238
48482
|
break;
|
|
48239
48483
|
}
|
|
@@ -48243,7 +48487,7 @@ function hashInstalledBinary(spec) {
|
|
|
48243
48487
|
reject(new Error(`installed binary not found at any of: ${candidates.join(", ")}`));
|
|
48244
48488
|
return;
|
|
48245
48489
|
}
|
|
48246
|
-
const hash2 =
|
|
48490
|
+
const hash2 = createHash4("sha256");
|
|
48247
48491
|
const stream = createReadStream(pathToHash);
|
|
48248
48492
|
stream.on("error", reject);
|
|
48249
48493
|
stream.on("data", (chunk) => hash2.update(chunk));
|
|
@@ -48259,14 +48503,14 @@ function installedBinaryPath(spec) {
|
|
|
48259
48503
|
] : [lspBinaryPath(spec.npm, spec.binary)];
|
|
48260
48504
|
for (const candidate of candidates) {
|
|
48261
48505
|
try {
|
|
48262
|
-
if (
|
|
48506
|
+
if (statSync4(candidate).isFile())
|
|
48263
48507
|
return candidate;
|
|
48264
48508
|
} catch {}
|
|
48265
48509
|
}
|
|
48266
48510
|
return null;
|
|
48267
48511
|
}
|
|
48268
48512
|
function sha256OfFileSync(path2) {
|
|
48269
|
-
return
|
|
48513
|
+
return createHash4("sha256").update(readFileSync5(path2)).digest("hex");
|
|
48270
48514
|
}
|
|
48271
48515
|
function quarantineCachedNpmInstall(spec, reason) {
|
|
48272
48516
|
const packageDir = lspPackageDir(spec.npm);
|
|
@@ -48274,8 +48518,8 @@ function quarantineCachedNpmInstall(spec, reason) {
|
|
|
48274
48518
|
warn2(`[lsp] tofu_mismatch ${spec.npm}: ${reason}; quarantining ${packageDir} -> ${dest}`);
|
|
48275
48519
|
try {
|
|
48276
48520
|
mkdirSync6(join10(dest, ".."), { recursive: true });
|
|
48277
|
-
|
|
48278
|
-
|
|
48521
|
+
rmSync3(dest, { recursive: true, force: true });
|
|
48522
|
+
renameSync4(packageDir, dest);
|
|
48279
48523
|
} catch (err) {
|
|
48280
48524
|
warn2(`[lsp] tofu_mismatch ${spec.npm}: failed to quarantine cache entry: ${err}`);
|
|
48281
48525
|
}
|
|
@@ -48351,11 +48595,11 @@ function runAutoInstall(projectRoot, config2, fetchImpl2 = fetch) {
|
|
|
48351
48595
|
|
|
48352
48596
|
// src/lsp-github-install.ts
|
|
48353
48597
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
48354
|
-
import { createHash as
|
|
48598
|
+
import { createHash as createHash5, randomBytes } from "node:crypto";
|
|
48355
48599
|
import {
|
|
48356
48600
|
copyFileSync as copyFileSync3,
|
|
48357
48601
|
createReadStream as createReadStream2,
|
|
48358
|
-
createWriteStream as
|
|
48602
|
+
createWriteStream as createWriteStream3,
|
|
48359
48603
|
existsSync as existsSync7,
|
|
48360
48604
|
lstatSync as lstatSync2,
|
|
48361
48605
|
mkdirSync as mkdirSync7,
|
|
@@ -48363,14 +48607,15 @@ import {
|
|
|
48363
48607
|
readFileSync as readFileSync6,
|
|
48364
48608
|
readlinkSync as readlinkSync2,
|
|
48365
48609
|
realpathSync as realpathSync3,
|
|
48366
|
-
renameSync as
|
|
48367
|
-
rmSync as
|
|
48368
|
-
statSync as
|
|
48369
|
-
unlinkSync as unlinkSync6
|
|
48610
|
+
renameSync as renameSync5,
|
|
48611
|
+
rmSync as rmSync4,
|
|
48612
|
+
statSync as statSync5,
|
|
48613
|
+
unlinkSync as unlinkSync6,
|
|
48614
|
+
writeFileSync as writeFileSync5
|
|
48370
48615
|
} from "node:fs";
|
|
48371
48616
|
import { dirname as dirname2, join as join11, relative as relative2, resolve as resolve2 } from "node:path";
|
|
48372
|
-
import { Readable as
|
|
48373
|
-
import { pipeline as
|
|
48617
|
+
import { Readable as Readable3 } from "node:stream";
|
|
48618
|
+
import { pipeline as pipeline3 } from "node:stream/promises";
|
|
48374
48619
|
|
|
48375
48620
|
// src/lsp-github-table.ts
|
|
48376
48621
|
function exe(platform, name) {
|
|
@@ -48469,6 +48714,7 @@ function ghBinDir(spec) {
|
|
|
48469
48714
|
function ghExtractDir(spec) {
|
|
48470
48715
|
return join11(ghPackageDir(spec), "extracted");
|
|
48471
48716
|
}
|
|
48717
|
+
var INSTALLED_META_FILE2 = ".aft-installed";
|
|
48472
48718
|
function ghBinaryPath(spec, platform) {
|
|
48473
48719
|
const ext = platform === "win32" ? ".exe" : "";
|
|
48474
48720
|
return join11(ghBinDir(spec), `${spec.binary}${ext}`);
|
|
@@ -48476,7 +48722,7 @@ function ghBinaryPath(spec, platform) {
|
|
|
48476
48722
|
function isGithubInstalled(spec, platform) {
|
|
48477
48723
|
for (const candidate of ghBinaryCandidates(spec, platform)) {
|
|
48478
48724
|
try {
|
|
48479
|
-
if (
|
|
48725
|
+
if (statSync5(join11(ghBinDir(spec), candidate)).isFile())
|
|
48480
48726
|
return true;
|
|
48481
48727
|
} catch {}
|
|
48482
48728
|
}
|
|
@@ -48487,11 +48733,45 @@ function ghBinaryCandidates(spec, platform) {
|
|
|
48487
48733
|
return [spec.binary];
|
|
48488
48734
|
return [spec.binary, `${spec.binary}.cmd`, `${spec.binary}.exe`, `${spec.binary}.bat`];
|
|
48489
48735
|
}
|
|
48490
|
-
|
|
48736
|
+
function readGithubInstalledMetaIn(installDir) {
|
|
48737
|
+
try {
|
|
48738
|
+
const path2 = join11(installDir, INSTALLED_META_FILE2);
|
|
48739
|
+
if (!statSync5(path2).isFile())
|
|
48740
|
+
return null;
|
|
48741
|
+
const parsed = JSON.parse(readFileSync6(path2, "utf8"));
|
|
48742
|
+
if (typeof parsed.version !== "string" || parsed.version.length === 0)
|
|
48743
|
+
return null;
|
|
48744
|
+
return {
|
|
48745
|
+
version: parsed.version,
|
|
48746
|
+
installedAt: typeof parsed.installedAt === "string" ? parsed.installedAt : "",
|
|
48747
|
+
...typeof parsed.sha256 === "string" && parsed.sha256.length > 0 ? { sha256: parsed.sha256 } : {},
|
|
48748
|
+
...typeof parsed.binarySha256 === "string" && parsed.binarySha256.length > 0 ? { binarySha256: parsed.binarySha256 } : {},
|
|
48749
|
+
...typeof parsed.archiveSha256 === "string" && parsed.archiveSha256.length > 0 ? { archiveSha256: parsed.archiveSha256 } : {}
|
|
48750
|
+
};
|
|
48751
|
+
} catch {
|
|
48752
|
+
return null;
|
|
48753
|
+
}
|
|
48754
|
+
}
|
|
48755
|
+
function writeGithubInstalledMetaIn(installDir, version2, binarySha256, archiveSha256) {
|
|
48756
|
+
try {
|
|
48757
|
+
mkdirSync7(installDir, { recursive: true });
|
|
48758
|
+
const meta3 = {
|
|
48759
|
+
version: version2,
|
|
48760
|
+
installedAt: new Date().toISOString(),
|
|
48761
|
+
sha256: binarySha256,
|
|
48762
|
+
binarySha256,
|
|
48763
|
+
...archiveSha256 ? { archiveSha256 } : {}
|
|
48764
|
+
};
|
|
48765
|
+
writeFileSync5(join11(installDir, INSTALLED_META_FILE2), JSON.stringify(meta3), "utf8");
|
|
48766
|
+
} catch (err) {
|
|
48767
|
+
warn2(`[lsp] failed to write github installed metadata in ${installDir}: ${err}`);
|
|
48768
|
+
}
|
|
48769
|
+
}
|
|
48770
|
+
var MAX_DOWNLOAD_BYTES3 = 256 * 1024 * 1024;
|
|
48491
48771
|
var MAX_EXTRACT_BYTES2 = 1024 * 1024 * 1024;
|
|
48492
48772
|
function sha256OfFile(path2) {
|
|
48493
48773
|
return new Promise((resolve3, reject) => {
|
|
48494
|
-
const hash2 =
|
|
48774
|
+
const hash2 = createHash5("sha256");
|
|
48495
48775
|
const stream = createReadStream2(path2);
|
|
48496
48776
|
stream.on("error", reject);
|
|
48497
48777
|
stream.on("data", (chunk) => hash2.update(chunk));
|
|
@@ -48499,7 +48779,7 @@ function sha256OfFile(path2) {
|
|
|
48499
48779
|
});
|
|
48500
48780
|
}
|
|
48501
48781
|
function sha256OfFileSync2(path2) {
|
|
48502
|
-
return
|
|
48782
|
+
return createHash5("sha256").update(readFileSync6(path2)).digest("hex");
|
|
48503
48783
|
}
|
|
48504
48784
|
async function fetchReleaseByTag(githubRepo, tag, fetchImpl2, signal) {
|
|
48505
48785
|
const candidates = [];
|
|
@@ -48662,8 +48942,8 @@ function assertAllowedDownloadUrl(rawUrl) {
|
|
|
48662
48942
|
return parsed;
|
|
48663
48943
|
}
|
|
48664
48944
|
async function downloadFile(url2, destPath, fetchImpl2, assetSize, signal) {
|
|
48665
|
-
if (assetSize !== undefined && assetSize >
|
|
48666
|
-
throw new Error(`asset size ${assetSize} exceeds max ${
|
|
48945
|
+
if (assetSize !== undefined && assetSize > MAX_DOWNLOAD_BYTES3) {
|
|
48946
|
+
throw new Error(`asset size ${assetSize} exceeds max ${MAX_DOWNLOAD_BYTES3} (set lsp.versions to pin a smaller release if this is wrong)`);
|
|
48667
48947
|
}
|
|
48668
48948
|
const timeout = controlledTimeoutSignal(120000, signal);
|
|
48669
48949
|
try {
|
|
@@ -48672,24 +48952,24 @@ async function downloadFile(url2, destPath, fetchImpl2, assetSize, signal) {
|
|
|
48672
48952
|
throw new Error(`download failed (${res.status})`);
|
|
48673
48953
|
}
|
|
48674
48954
|
const advertised = Number.parseInt(res.headers.get("content-length") ?? "", 10);
|
|
48675
|
-
if (Number.isFinite(advertised) && advertised >
|
|
48676
|
-
throw new Error(`Content-Length ${advertised} exceeds max ${
|
|
48955
|
+
if (Number.isFinite(advertised) && advertised > MAX_DOWNLOAD_BYTES3) {
|
|
48956
|
+
throw new Error(`Content-Length ${advertised} exceeds max ${MAX_DOWNLOAD_BYTES3}`);
|
|
48677
48957
|
}
|
|
48678
48958
|
mkdirSync7(dirname2(destPath), { recursive: true });
|
|
48679
48959
|
let bytesWritten = 0;
|
|
48680
48960
|
const guard = new TransformStream({
|
|
48681
48961
|
transform(chunk, controller) {
|
|
48682
48962
|
bytesWritten += chunk.byteLength;
|
|
48683
|
-
if (bytesWritten >
|
|
48684
|
-
controller.error(new Error(`download exceeded ${
|
|
48963
|
+
if (bytesWritten > MAX_DOWNLOAD_BYTES3) {
|
|
48964
|
+
controller.error(new Error(`download exceeded ${MAX_DOWNLOAD_BYTES3} bytes after streaming (server lied about size or sent unbounded body)`));
|
|
48685
48965
|
return;
|
|
48686
48966
|
}
|
|
48687
48967
|
controller.enqueue(chunk);
|
|
48688
48968
|
}
|
|
48689
48969
|
});
|
|
48690
48970
|
const guarded = res.body.pipeThrough(guard);
|
|
48691
|
-
const nodeStream =
|
|
48692
|
-
await
|
|
48971
|
+
const nodeStream = Readable3.fromWeb(guarded);
|
|
48972
|
+
await pipeline3(nodeStream, createWriteStream3(destPath), { signal: timeout.signal });
|
|
48693
48973
|
} catch (err) {
|
|
48694
48974
|
try {
|
|
48695
48975
|
unlinkSync6(destPath);
|
|
@@ -48769,7 +49049,7 @@ function validateExtraction(stagingRoot) {
|
|
|
48769
49049
|
};
|
|
48770
49050
|
walk(realStagingRoot);
|
|
48771
49051
|
}
|
|
48772
|
-
function
|
|
49052
|
+
function precheckArchiveContents(archivePath, archiveType) {
|
|
48773
49053
|
let totalBytes = 0;
|
|
48774
49054
|
if (archiveType === "zip") {
|
|
48775
49055
|
const out = execFileSync2("unzip", ["-l", archivePath], { encoding: "utf8" });
|
|
@@ -48780,6 +49060,9 @@ function precheckArchiveSize(archivePath, archiveType) {
|
|
|
48780
49060
|
const out = execFileSync2("tar", ["-tvf", archivePath], { encoding: "utf8" });
|
|
48781
49061
|
for (const line of out.split(`
|
|
48782
49062
|
`)) {
|
|
49063
|
+
if (line.startsWith("h")) {
|
|
49064
|
+
throw new Error(`archive contains hardlink entry: ${line.trim()}`);
|
|
49065
|
+
}
|
|
48783
49066
|
const parts = line.trim().split(/\s+/);
|
|
48784
49067
|
if (parts.length >= 6) {
|
|
48785
49068
|
const numeric = parts.map((part) => Number.parseInt(part, 10)).filter((value) => Number.isFinite(value) && value >= 0);
|
|
@@ -48796,20 +49079,20 @@ function extractArchiveSafely(archivePath, destDir, archiveType) {
|
|
|
48796
49079
|
const suffix = randomBytes(8).toString("hex");
|
|
48797
49080
|
const stagingDir = `${destDir}.staging-${suffix}`;
|
|
48798
49081
|
try {
|
|
48799
|
-
|
|
49082
|
+
rmSync4(stagingDir, { recursive: true, force: true });
|
|
48800
49083
|
} catch {}
|
|
48801
49084
|
mkdirSync7(stagingDir, { recursive: true });
|
|
48802
49085
|
try {
|
|
48803
|
-
|
|
49086
|
+
precheckArchiveContents(archivePath, archiveType);
|
|
48804
49087
|
runPlatformExtractor(archivePath, stagingDir, archiveType);
|
|
48805
49088
|
validateExtraction(stagingDir);
|
|
48806
49089
|
try {
|
|
48807
|
-
|
|
49090
|
+
rmSync4(destDir, { recursive: true, force: true });
|
|
48808
49091
|
} catch {}
|
|
48809
|
-
|
|
49092
|
+
renameSync5(stagingDir, destDir);
|
|
48810
49093
|
} catch (err) {
|
|
48811
49094
|
try {
|
|
48812
|
-
|
|
49095
|
+
rmSync4(stagingDir, { recursive: true, force: true });
|
|
48813
49096
|
} catch {}
|
|
48814
49097
|
throw err;
|
|
48815
49098
|
}
|
|
@@ -48820,28 +49103,44 @@ function quarantineCachedGithubInstall(spec, reason) {
|
|
|
48820
49103
|
warn2(`[lsp] tofu_mismatch ${spec.id}: ${reason}; quarantining ${packageDir} -> ${dest}`);
|
|
48821
49104
|
try {
|
|
48822
49105
|
mkdirSync7(dirname2(dest), { recursive: true });
|
|
48823
|
-
|
|
48824
|
-
|
|
49106
|
+
rmSync4(dest, { recursive: true, force: true });
|
|
49107
|
+
renameSync5(packageDir, dest);
|
|
48825
49108
|
} catch (err) {
|
|
48826
49109
|
warn2(`[lsp] tofu_mismatch ${spec.id}: failed to quarantine cache entry: ${err}`);
|
|
48827
49110
|
}
|
|
48828
49111
|
}
|
|
48829
49112
|
function validateCachedGithubInstall(spec, platform) {
|
|
48830
|
-
const
|
|
49113
|
+
const packageDir = ghPackageDir(spec);
|
|
49114
|
+
const meta3 = readGithubInstalledMetaIn(packageDir);
|
|
48831
49115
|
const binaryPath = ghBinaryCandidates(spec, platform).map((candidate) => join11(ghBinDir(spec), candidate)).find((candidate) => {
|
|
48832
49116
|
try {
|
|
48833
|
-
return
|
|
49117
|
+
return statSync5(candidate).isFile();
|
|
48834
49118
|
} catch {
|
|
48835
49119
|
return false;
|
|
48836
49120
|
}
|
|
48837
49121
|
});
|
|
48838
|
-
if (!meta3?.
|
|
49122
|
+
if (!meta3?.version || !isSafeVersion(meta3.version) || !binaryPath) {
|
|
48839
49123
|
quarantineCachedGithubInstall(spec, "missing/unsafe metadata or binary");
|
|
48840
49124
|
return false;
|
|
48841
49125
|
}
|
|
48842
49126
|
const currentHash = sha256OfFileSync2(binaryPath);
|
|
48843
|
-
|
|
48844
|
-
|
|
49127
|
+
const recordedBinaryHash = meta3.binarySha256 ?? meta3.sha256;
|
|
49128
|
+
if (recordedBinaryHash && currentHash === recordedBinaryHash) {
|
|
49129
|
+
if (meta3.sha256 !== currentHash || meta3.binarySha256 !== currentHash) {
|
|
49130
|
+
writeGithubInstalledMetaIn(packageDir, meta3.version, currentHash, meta3.archiveSha256);
|
|
49131
|
+
}
|
|
49132
|
+
return true;
|
|
49133
|
+
}
|
|
49134
|
+
if (meta3.sha256 && !meta3.binarySha256 && !meta3.archiveSha256) {
|
|
49135
|
+
writeGithubInstalledMetaIn(packageDir, meta3.version, currentHash, meta3.sha256);
|
|
49136
|
+
return true;
|
|
49137
|
+
}
|
|
49138
|
+
if (!recordedBinaryHash) {
|
|
49139
|
+
quarantineCachedGithubInstall(spec, "missing binary sha256 metadata");
|
|
49140
|
+
return false;
|
|
49141
|
+
}
|
|
49142
|
+
if (currentHash !== recordedBinaryHash) {
|
|
49143
|
+
quarantineCachedGithubInstall(spec, `recorded ${recordedBinaryHash}, current ${currentHash}`);
|
|
48845
49144
|
return false;
|
|
48846
49145
|
}
|
|
48847
49146
|
return true;
|
|
@@ -48910,10 +49209,11 @@ async function downloadAndInstall(spec, tag, assets, platform, arch, fetchImpl2,
|
|
|
48910
49209
|
return null;
|
|
48911
49210
|
}
|
|
48912
49211
|
log2(`[lsp] ${spec.id} ${tag} sha256=${archiveSha256}`);
|
|
48913
|
-
const previousMeta =
|
|
48914
|
-
|
|
48915
|
-
|
|
48916
|
-
|
|
49212
|
+
const previousMeta = readGithubInstalledMetaIn(ghPackageDir(spec));
|
|
49213
|
+
const previousArchiveSha256 = previousMeta?.archiveSha256 ?? (previousMeta?.binarySha256 ? undefined : previousMeta?.sha256);
|
|
49214
|
+
if (previousMeta && previousMeta.version === tag && previousArchiveSha256) {
|
|
49215
|
+
if (previousArchiveSha256 !== archiveSha256) {
|
|
49216
|
+
error2(`[lsp] ${spec.id} ${tag}: TOFU sha256 mismatch — refusing install. ` + `Previously installed archive sha256=${previousArchiveSha256}, downloaded sha256=${archiveSha256}. ` + `This means the published release for tag ${tag} changed. Investigate before proceeding.`);
|
|
48917
49217
|
try {
|
|
48918
49218
|
unlinkSync6(archivePath);
|
|
48919
49219
|
} catch {}
|
|
@@ -48948,7 +49248,9 @@ async function downloadAndInstall(spec, tag, assets, platform, arch, fetchImpl2,
|
|
|
48948
49248
|
return null;
|
|
48949
49249
|
}
|
|
48950
49250
|
log2(`[lsp] installed ${spec.id} ${tag} at ${targetBinary}`);
|
|
48951
|
-
|
|
49251
|
+
const binarySha256 = await sha256OfFile(targetBinary);
|
|
49252
|
+
log2(`[lsp] ${spec.id} ${tag} binary_sha256=${binarySha256}`);
|
|
49253
|
+
return { archiveSha256, binarySha256 };
|
|
48952
49254
|
}
|
|
48953
49255
|
async function ensureGithubInstalled(spec, config2, fetchImpl2, platform, arch, signal) {
|
|
48954
49256
|
const outcome = await withInstallLock(spec.githubRepo, async () => {
|
|
@@ -48974,14 +49276,14 @@ async function ensureGithubInstalled(spec, config2, fetchImpl2, platform, arch,
|
|
|
48974
49276
|
log2(`[lsp] reinstalling ${spec.id}@${tag}: no installed-version metadata recorded`);
|
|
48975
49277
|
}
|
|
48976
49278
|
}
|
|
48977
|
-
const
|
|
49279
|
+
const hashes = await downloadAndInstall(spec, tag, assets, platform, arch, fetchImpl2, signal).catch((err) => {
|
|
48978
49280
|
error2(`[lsp] github install ${spec.id} crashed: ${err}`);
|
|
48979
49281
|
return null;
|
|
48980
49282
|
});
|
|
48981
|
-
if (!
|
|
49283
|
+
if (!hashes) {
|
|
48982
49284
|
return { started: true, reason: "install failed (see plugin log)" };
|
|
48983
49285
|
}
|
|
48984
|
-
|
|
49286
|
+
writeGithubInstalledMetaIn(ghPackageDir(spec), tag, hashes.binarySha256, hashes.archiveSha256);
|
|
48985
49287
|
return { started: true };
|
|
48986
49288
|
});
|
|
48987
49289
|
if (outcome === null) {
|
|
@@ -49111,7 +49413,7 @@ function discoverRelevantGithubServers(projectRoot) {
|
|
|
49111
49413
|
}
|
|
49112
49414
|
|
|
49113
49415
|
// src/notifications.ts
|
|
49114
|
-
import { existsSync as existsSync8, mkdirSync as mkdirSync8, readFileSync as readFileSync7, renameSync as
|
|
49416
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync8, readFileSync as readFileSync7, renameSync as renameSync6, rmSync as rmSync5, writeFileSync as writeFileSync6 } from "node:fs";
|
|
49115
49417
|
import { join as join12 } from "node:path";
|
|
49116
49418
|
var WARNING_MARKER = "\uD83D\uDD27 AFT: ⚠️";
|
|
49117
49419
|
var FEATURE_MARKER = "\uD83D\uDD27 AFT: ✨";
|
|
@@ -49124,7 +49426,7 @@ function sendIgnoredMessage(client, sessionId, text) {
|
|
|
49124
49426
|
typedClient.ui.notify(text, "warning");
|
|
49125
49427
|
return true;
|
|
49126
49428
|
} catch (err) {
|
|
49127
|
-
|
|
49429
|
+
sessionLog(sessionId, `[aft-pi] notification send failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
49128
49430
|
return false;
|
|
49129
49431
|
}
|
|
49130
49432
|
}
|
|
@@ -49152,9 +49454,9 @@ function writeWarnedTools(storageDir, warned) {
|
|
|
49152
49454
|
mkdirSync8(storageDir, { recursive: true });
|
|
49153
49455
|
const warnedToolsPath = join12(storageDir, WARNED_TOOLS_FILE);
|
|
49154
49456
|
const tmpPath = join12(storageDir, `${WARNED_TOOLS_FILE}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`);
|
|
49155
|
-
|
|
49457
|
+
writeFileSync6(tmpPath, `${JSON.stringify(warned, null, 2)}
|
|
49156
49458
|
`);
|
|
49157
|
-
|
|
49459
|
+
renameSync6(tmpPath, warnedToolsPath);
|
|
49158
49460
|
} catch {}
|
|
49159
49461
|
}
|
|
49160
49462
|
async function withWarnedToolsLock(storageDir, fn) {
|
|
@@ -49166,7 +49468,7 @@ async function withWarnedToolsLock(storageDir, fn) {
|
|
|
49166
49468
|
try {
|
|
49167
49469
|
return await fn();
|
|
49168
49470
|
} finally {
|
|
49169
|
-
|
|
49471
|
+
rmSync5(lockDir, { recursive: true, force: true });
|
|
49170
49472
|
}
|
|
49171
49473
|
} catch (err) {
|
|
49172
49474
|
const code = err.code;
|
|
@@ -49253,7 +49555,7 @@ function sendFeatureAnnouncement(version2, features, storageDir) {
|
|
|
49253
49555
|
`));
|
|
49254
49556
|
try {
|
|
49255
49557
|
mkdirSync8(storageDir, { recursive: true });
|
|
49256
|
-
|
|
49558
|
+
writeFileSync6(versionFile, version2);
|
|
49257
49559
|
} catch {}
|
|
49258
49560
|
}
|
|
49259
49561
|
|
|
@@ -51856,33 +52158,39 @@ ${hintsBlock}` };
|
|
|
51856
52158
|
// src/index.ts
|
|
51857
52159
|
setActiveLogger(bridgeLogger);
|
|
51858
52160
|
function createVersionMismatchHandler(getPool, ensureCompatibleBinary = ensureBinary) {
|
|
51859
|
-
|
|
52161
|
+
const versionUpgradePromises = new Map;
|
|
51860
52162
|
return async (binaryVersion, minVersion) => {
|
|
51861
|
-
|
|
51862
|
-
|
|
51863
|
-
|
|
52163
|
+
const existing = versionUpgradePromises.get(minVersion);
|
|
52164
|
+
if (existing) {
|
|
52165
|
+
log2(`Version ${binaryVersion} < ${minVersion}; awaiting in-flight compatible binary upgrade`);
|
|
52166
|
+
return existing;
|
|
51864
52167
|
}
|
|
51865
|
-
|
|
51866
|
-
|
|
51867
|
-
|
|
51868
|
-
|
|
51869
|
-
|
|
51870
|
-
|
|
51871
|
-
|
|
51872
|
-
|
|
51873
|
-
|
|
51874
|
-
|
|
51875
|
-
|
|
52168
|
+
const upgradePromise = (async () => {
|
|
52169
|
+
warn2(`WARNING: aft binary v${binaryVersion} is older than plugin v${minVersion}. ` + "Some features may not work. Attempting to download a compatible binary...");
|
|
52170
|
+
try {
|
|
52171
|
+
const path2 = await ensureCompatibleBinary(`v${minVersion}`);
|
|
52172
|
+
if (!path2) {
|
|
52173
|
+
warn2(`Could not find or download v${minVersion}. Continuing with v${binaryVersion}.`);
|
|
52174
|
+
return null;
|
|
52175
|
+
}
|
|
52176
|
+
const pool = getPool();
|
|
52177
|
+
if (!pool) {
|
|
52178
|
+
warn2(`Found/downloaded compatible binary at ${path2}, but bridge pool is not ready.`);
|
|
52179
|
+
return null;
|
|
52180
|
+
}
|
|
52181
|
+
log2(`Found/downloaded compatible binary at ${path2}. Replacing running bridges...`);
|
|
52182
|
+
const replaced = await pool.replaceBinary(path2);
|
|
52183
|
+
log2("Binary replaced successfully. New bridges will use the updated binary.");
|
|
52184
|
+
return replaced;
|
|
52185
|
+
} catch (err) {
|
|
52186
|
+
error2(`Auto-download failed: ${err.message}. Install manually: cargo install agent-file-tools@${minVersion}`);
|
|
51876
52187
|
return null;
|
|
52188
|
+
} finally {
|
|
52189
|
+
versionUpgradePromises.delete(minVersion);
|
|
51877
52190
|
}
|
|
51878
|
-
|
|
51879
|
-
|
|
51880
|
-
|
|
51881
|
-
return replaced;
|
|
51882
|
-
} catch (err) {
|
|
51883
|
-
error2(`Auto-download failed: ${err.message}. Install manually: cargo install agent-file-tools@${minVersion}`);
|
|
51884
|
-
return null;
|
|
51885
|
-
}
|
|
52191
|
+
})();
|
|
52192
|
+
versionUpgradePromises.set(minVersion, upgradePromise);
|
|
52193
|
+
return upgradePromise;
|
|
51886
52194
|
};
|
|
51887
52195
|
}
|
|
51888
52196
|
var PLUGIN_VERSION = (() => {
|