@cortexkit/aft-pi 0.26.0 → 0.26.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/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
|
}
|
|
@@ -31943,7 +32100,9 @@ class BridgePool {
|
|
|
31943
32100
|
onVersionMismatch: options.onVersionMismatch,
|
|
31944
32101
|
onConfigureWarnings: options.onConfigureWarnings,
|
|
31945
32102
|
onBashCompletion: options.onBashCompletion,
|
|
31946
|
-
onBashLongRunning: options.onBashLongRunning
|
|
32103
|
+
onBashLongRunning: options.onBashLongRunning,
|
|
32104
|
+
errorPrefix: options.errorPrefix,
|
|
32105
|
+
logger: options.logger
|
|
31947
32106
|
};
|
|
31948
32107
|
this.configOverrides = configOverrides;
|
|
31949
32108
|
if (Number.isFinite(this.idleTimeoutMs)) {
|
|
@@ -32015,24 +32174,32 @@ class BridgePool {
|
|
|
32015
32174
|
}
|
|
32016
32175
|
async replaceBinary(newPath) {
|
|
32017
32176
|
this.binaryPath = newPath;
|
|
32018
|
-
const shutdowns = Array.from(this.bridges.values()).map((entry) => entry.bridge.shutdown());
|
|
32019
32177
|
this.bridges.clear();
|
|
32020
|
-
await Promise.allSettled(shutdowns);
|
|
32021
32178
|
this.log(`Binary path updated to ${newPath}. All bridges cleared — next calls will use the new binary.`);
|
|
32022
32179
|
return newPath;
|
|
32023
32180
|
}
|
|
32024
32181
|
log(message, meta) {
|
|
32025
32182
|
const logger = this.logger ?? getActiveLogger();
|
|
32026
|
-
if (logger)
|
|
32027
|
-
|
|
32028
|
-
|
|
32183
|
+
if (logger) {
|
|
32184
|
+
try {
|
|
32185
|
+
logger.log(message, meta);
|
|
32186
|
+
} catch (err) {
|
|
32187
|
+
console.error(`[aft-bridge] ERROR: pool logger log threw: ${err instanceof Error ? err.message : String(err)}`);
|
|
32188
|
+
console.error(`[aft-bridge] ${message}`);
|
|
32189
|
+
}
|
|
32190
|
+
} else
|
|
32029
32191
|
log(message, meta);
|
|
32030
32192
|
}
|
|
32031
32193
|
error(message, meta) {
|
|
32032
32194
|
const logger = this.logger ?? getActiveLogger();
|
|
32033
|
-
if (logger)
|
|
32034
|
-
|
|
32035
|
-
|
|
32195
|
+
if (logger) {
|
|
32196
|
+
try {
|
|
32197
|
+
logger.error(message, meta);
|
|
32198
|
+
} catch (err) {
|
|
32199
|
+
console.error(`[aft-bridge] ERROR: pool logger error threw: ${err instanceof Error ? err.message : String(err)}`);
|
|
32200
|
+
console.error(`[aft-bridge] ERROR: ${message}`);
|
|
32201
|
+
}
|
|
32202
|
+
} else
|
|
32036
32203
|
error(message, meta);
|
|
32037
32204
|
}
|
|
32038
32205
|
setConfigureOverride(key, value) {
|
|
@@ -32059,7 +32226,7 @@ function normalizeKey(projectRoot) {
|
|
|
32059
32226
|
}
|
|
32060
32227
|
// ../aft-bridge/dist/resolver.js
|
|
32061
32228
|
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";
|
|
32229
|
+
import { chmodSync as chmodSync3, copyFileSync as copyFileSync2, existsSync as existsSync3, mkdirSync as mkdirSync3, renameSync as renameSync2 } from "node:fs";
|
|
32063
32230
|
import { createRequire as createRequire2 } from "node:module";
|
|
32064
32231
|
import { homedir as homedir4 } from "node:os";
|
|
32065
32232
|
import { join as join4 } from "node:path";
|
|
@@ -32090,15 +32257,19 @@ function copyToVersionedCache(npmBinaryPath, knownVersion) {
|
|
|
32090
32257
|
const versionedDir = join4(cacheDir, tag);
|
|
32091
32258
|
const ext = process.platform === "win32" ? ".exe" : "";
|
|
32092
32259
|
const cachedPath = join4(versionedDir, `aft${ext}`);
|
|
32093
|
-
if (existsSync3(cachedPath))
|
|
32094
|
-
|
|
32260
|
+
if (existsSync3(cachedPath)) {
|
|
32261
|
+
const cachedVersion = readBinaryVersion(cachedPath);
|
|
32262
|
+
if (cachedVersion === version)
|
|
32263
|
+
return cachedPath;
|
|
32264
|
+
warn(`Cached binary at ${cachedPath} reports ${cachedVersion ?? "no version"}, expected ${version}; refreshing from npm package`);
|
|
32265
|
+
}
|
|
32095
32266
|
mkdirSync3(versionedDir, { recursive: true });
|
|
32096
|
-
const tmpPath = `${cachedPath}.tmp`;
|
|
32267
|
+
const tmpPath = `${cachedPath}.${process.pid}.${Date.now()}.tmp`;
|
|
32097
32268
|
copyFileSync2(npmBinaryPath, tmpPath);
|
|
32098
32269
|
if (process.platform !== "win32") {
|
|
32099
32270
|
chmodSync3(tmpPath, 493);
|
|
32100
32271
|
}
|
|
32101
|
-
|
|
32272
|
+
renameSync2(tmpPath, cachedPath);
|
|
32102
32273
|
log(`Copied npm binary to versioned cache: ${cachedPath}`);
|
|
32103
32274
|
return cachedPath;
|
|
32104
32275
|
} catch (err) {
|
|
@@ -32106,6 +32277,17 @@ function copyToVersionedCache(npmBinaryPath, knownVersion) {
|
|
|
32106
32277
|
return null;
|
|
32107
32278
|
}
|
|
32108
32279
|
}
|
|
32280
|
+
function normalizeBareVersion(version) {
|
|
32281
|
+
return version.startsWith("v") ? version.slice(1) : version;
|
|
32282
|
+
}
|
|
32283
|
+
function isExpectedCachedBinary(binaryPath, expectedVersion) {
|
|
32284
|
+
const expected = normalizeBareVersion(expectedVersion);
|
|
32285
|
+
const actual = readBinaryVersion(binaryPath);
|
|
32286
|
+
if (actual === expected)
|
|
32287
|
+
return true;
|
|
32288
|
+
warn(`Cached binary at ${binaryPath} reports ${actual ?? "no version"}, expected ${expected}; skipping cache candidate`);
|
|
32289
|
+
return false;
|
|
32290
|
+
}
|
|
32109
32291
|
function platformKey(platform = process.platform, arch = process.arch) {
|
|
32110
32292
|
const archMap = PLATFORM_ARCH_MAP[platform];
|
|
32111
32293
|
if (!archMap) {
|
|
@@ -32130,7 +32312,7 @@ function findBinarySync(expectedVersion) {
|
|
|
32130
32312
|
if (pluginVersion) {
|
|
32131
32313
|
const tag = pluginVersion.startsWith("v") ? pluginVersion : `v${pluginVersion}`;
|
|
32132
32314
|
const versionCached = getCachedBinaryPath(tag);
|
|
32133
|
-
if (versionCached)
|
|
32315
|
+
if (versionCached && isExpectedCachedBinary(versionCached, pluginVersion))
|
|
32134
32316
|
return versionCached;
|
|
32135
32317
|
}
|
|
32136
32318
|
try {
|
|
@@ -32140,10 +32322,12 @@ function findBinarySync(expectedVersion) {
|
|
|
32140
32322
|
const resolved = req.resolve(packageBin);
|
|
32141
32323
|
if (existsSync3(resolved)) {
|
|
32142
32324
|
const npmVersion = readBinaryVersion(resolved);
|
|
32143
|
-
if (
|
|
32325
|
+
if (npmVersion === null) {
|
|
32326
|
+
warn(`npm platform package binary at ${resolved} did not report a version; skipping (continuing to PATH lookup)`);
|
|
32327
|
+
} else if (pluginVersion && npmVersion !== normalizeBareVersion(pluginVersion)) {
|
|
32144
32328
|
warn(`npm platform package binary v${npmVersion} does not match plugin v${pluginVersion}; skipping (continuing to PATH lookup)`);
|
|
32145
32329
|
} else {
|
|
32146
|
-
const copied = copyToVersionedCache(resolved, npmVersion
|
|
32330
|
+
const copied = copyToVersionedCache(resolved, npmVersion);
|
|
32147
32331
|
return copied ?? resolved;
|
|
32148
32332
|
}
|
|
32149
32333
|
}
|
|
@@ -32192,7 +32376,7 @@ async function findBinary(expectedVersion) {
|
|
|
32192
32376
|
`));
|
|
32193
32377
|
}
|
|
32194
32378
|
// ../aft-bridge/dist/url-fetch.js
|
|
32195
|
-
import { createHash as
|
|
32379
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
32196
32380
|
import { lookup } from "node:dns/promises";
|
|
32197
32381
|
import { existsSync as existsSync4, mkdirSync as mkdirSync4, readdirSync as readdirSync2, readFileSync as readFileSync2, unlinkSync as unlinkSync3, writeFileSync as writeFileSync2 } from "node:fs";
|
|
32198
32382
|
import { isIP } from "node:net";
|
|
@@ -32349,7 +32533,7 @@ function cacheDir(storageDir) {
|
|
|
32349
32533
|
return join5(storageDir, "url_cache");
|
|
32350
32534
|
}
|
|
32351
32535
|
function hashUrl(url) {
|
|
32352
|
-
return
|
|
32536
|
+
return createHash3("sha256").update(url).digest("hex").slice(0, 16);
|
|
32353
32537
|
}
|
|
32354
32538
|
function metaPath(storageDir, hash) {
|
|
32355
32539
|
return join5(cacheDir(storageDir), `${hash}.meta.json`);
|
|
@@ -32607,8 +32791,8 @@ async function fetchUrlToTempFile(url, storageDir, options = {}) {
|
|
|
32607
32791
|
const contentFile = contentPath(storageDir, hash, extension);
|
|
32608
32792
|
const tmpContent = `${contentFile}.tmp-${process.pid}`;
|
|
32609
32793
|
writeFileSync2(tmpContent, body);
|
|
32610
|
-
const { renameSync:
|
|
32611
|
-
|
|
32794
|
+
const { renameSync: renameSync3 } = await import("node:fs");
|
|
32795
|
+
renameSync3(tmpContent, contentFile);
|
|
32612
32796
|
const meta = {
|
|
32613
32797
|
url,
|
|
32614
32798
|
contentType,
|
|
@@ -32617,7 +32801,7 @@ async function fetchUrlToTempFile(url, storageDir, options = {}) {
|
|
|
32617
32801
|
};
|
|
32618
32802
|
const tmpMeta = `${metaFile}.tmp-${process.pid}`;
|
|
32619
32803
|
writeFileSync2(tmpMeta, JSON.stringify(meta));
|
|
32620
|
-
|
|
32804
|
+
renameSync3(tmpMeta, metaFile);
|
|
32621
32805
|
log(`URL cached (${total} bytes): ${url}`);
|
|
32622
32806
|
return contentFile;
|
|
32623
32807
|
}
|
|
@@ -32735,31 +32919,31 @@ function warn2(message, data) {
|
|
|
32735
32919
|
function error2(message, data) {
|
|
32736
32920
|
write("ERROR", message, data);
|
|
32737
32921
|
}
|
|
32738
|
-
function
|
|
32922
|
+
function sessionLog(sessionId, message, data) {
|
|
32739
32923
|
write("INFO", message, data, sessionId);
|
|
32740
32924
|
}
|
|
32741
|
-
function
|
|
32925
|
+
function sessionWarn(sessionId, message, data) {
|
|
32742
32926
|
write("WARN", message, data, sessionId);
|
|
32743
32927
|
}
|
|
32744
|
-
function
|
|
32928
|
+
function sessionError(sessionId, message, data) {
|
|
32745
32929
|
write("ERROR", message, data, sessionId);
|
|
32746
32930
|
}
|
|
32747
32931
|
var bridgeLogger = {
|
|
32748
32932
|
log(message, meta) {
|
|
32749
32933
|
if (meta?.sessionId)
|
|
32750
|
-
|
|
32934
|
+
sessionLog(meta.sessionId, message);
|
|
32751
32935
|
else
|
|
32752
32936
|
write("INFO", message);
|
|
32753
32937
|
},
|
|
32754
32938
|
warn(message, meta) {
|
|
32755
32939
|
if (meta?.sessionId)
|
|
32756
|
-
|
|
32940
|
+
sessionWarn(meta.sessionId, message);
|
|
32757
32941
|
else
|
|
32758
32942
|
write("WARN", message);
|
|
32759
32943
|
},
|
|
32760
32944
|
error(message, meta) {
|
|
32761
32945
|
if (meta?.sessionId)
|
|
32762
|
-
|
|
32946
|
+
sessionError(meta.sessionId, message);
|
|
32763
32947
|
else
|
|
32764
32948
|
write("ERROR", message);
|
|
32765
32949
|
},
|
|
@@ -32771,6 +32955,7 @@ var sessionBgStates = new Map;
|
|
|
32771
32955
|
var SESSION_BG_STATE_IDLE_TTL_MS = 60 * 60 * 1000;
|
|
32772
32956
|
var DEBOUNCE_STEP_MS = 200;
|
|
32773
32957
|
var DEBOUNCE_CAP_MS = 1000;
|
|
32958
|
+
var MAX_WAKE_SEND_ATTEMPTS = 5;
|
|
32774
32959
|
var UNKNOWN_COMPLETION_TTL_MS = 5000;
|
|
32775
32960
|
var UNKNOWN_COMPLETION_CAP = 32;
|
|
32776
32961
|
var DEFAULT_SESSION_ID = "__default__";
|
|
@@ -32820,16 +33005,22 @@ async function handlePushedBgLongRunning(drainContext, reminder) {
|
|
|
32820
33005
|
}
|
|
32821
33006
|
async function appendToolResultBgCompletions(drainContext, content) {
|
|
32822
33007
|
const state = stateFor(drainContext.sessionID);
|
|
33008
|
+
if (state.outstandingTaskIds.size === 0 && state.pendingCompletions.length === 0 && state.pendingLongRunning.length === 0)
|
|
33009
|
+
await drainCompletions(drainContext);
|
|
32823
33010
|
if (state.outstandingTaskIds.size === 0 && state.pendingCompletions.length === 0 && state.pendingLongRunning.length === 0)
|
|
32824
33011
|
return;
|
|
32825
|
-
if (state.outstandingTaskIds.size > 0) {
|
|
33012
|
+
if (state.outstandingTaskIds.size > 0 || !state.forcedDrainCompleted) {
|
|
32826
33013
|
await drainCompletions(drainContext);
|
|
32827
33014
|
}
|
|
32828
33015
|
if (state.pendingCompletions.length === 0 && state.pendingLongRunning.length === 0)
|
|
32829
33016
|
return;
|
|
33017
|
+
const deliveredCompletions = [...state.pendingCompletions];
|
|
32830
33018
|
const reminder = formatCombinedSystemReminder(state.pendingCompletions, state.pendingLongRunning);
|
|
32831
33019
|
state.pendingCompletions = [];
|
|
32832
33020
|
state.pendingLongRunning = [];
|
|
33021
|
+
state.wakeRetryAttempts = 0;
|
|
33022
|
+
state.wakeHardStopped = false;
|
|
33023
|
+
await ackCompletions(drainContext, deliveredCompletions);
|
|
32833
33024
|
if (state.debounceTimer) {
|
|
32834
33025
|
clearTimeout(state.debounceTimer);
|
|
32835
33026
|
state.debounceTimer = null;
|
|
@@ -32844,15 +33035,16 @@ async function handleTurnEndBgCompletions(drainContext) {
|
|
|
32844
33035
|
}
|
|
32845
33036
|
async function triggerWakeIfPending(drainContext, skipDrain) {
|
|
32846
33037
|
const state = stateFor(drainContext.sessionID);
|
|
32847
|
-
if (!skipDrain && state.outstandingTaskIds.size > 0) {
|
|
33038
|
+
if (!skipDrain && (state.outstandingTaskIds.size > 0 || !state.forcedDrainCompleted)) {
|
|
32848
33039
|
await drainCompletions(drainContext);
|
|
32849
33040
|
}
|
|
32850
33041
|
if (state.pendingCompletions.length === 0 && state.pendingLongRunning.length === 0)
|
|
32851
33042
|
return;
|
|
32852
|
-
scheduleWake(state, async (reminder) => {
|
|
33043
|
+
scheduleWake(state, async (reminder, deliveredCompletions) => {
|
|
32853
33044
|
drainContext.runtime.sendUserMessage(reminder, { deliverAs: "steer" });
|
|
32854
|
-
|
|
32855
|
-
|
|
33045
|
+
await ackCompletions(drainContext, deliveredCompletions);
|
|
33046
|
+
}, (err, hardStopped) => {
|
|
33047
|
+
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
33048
|
});
|
|
32857
33049
|
}
|
|
32858
33050
|
function formatSystemReminder(completions) {
|
|
@@ -32885,20 +33077,39 @@ function formatCombinedSystemReminder(completions, longRunning) {
|
|
|
32885
33077
|
${formatLongRunningReminder(longRunning)}`;
|
|
32886
33078
|
}
|
|
32887
33079
|
async function drainCompletions({ ctx, directory, sessionID }) {
|
|
33080
|
+
const state = stateFor(sessionID);
|
|
32888
33081
|
try {
|
|
32889
33082
|
const bridge = ctx.pool.getActiveBridgeForRoot(directory) ?? ctx.pool.getBridge(directory);
|
|
32890
33083
|
const params = sessionID ? { session_id: sessionID } : {};
|
|
32891
33084
|
const response = await bridge.send("bash_drain_completions", params);
|
|
32892
33085
|
if (response.success === false) {
|
|
32893
|
-
|
|
33086
|
+
sessionWarn(sessionID ?? "", `${LOG_PREFIX} drain failed: ${String(response.message ?? "unknown error")}`);
|
|
32894
33087
|
return;
|
|
32895
33088
|
}
|
|
32896
|
-
|
|
33089
|
+
state.forcedDrainCompleted = true;
|
|
33090
|
+
ingestDrainedBgCompletions(sessionID, response.bg_completions);
|
|
32897
33091
|
} catch (err) {
|
|
32898
|
-
|
|
33092
|
+
sessionWarn(sessionID ?? "", `${LOG_PREFIX} drain failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
33093
|
+
}
|
|
33094
|
+
}
|
|
33095
|
+
async function ackCompletions({ ctx, directory, sessionID }, completions) {
|
|
33096
|
+
const taskIds = [...new Set(completions.map((completion) => completion.task_id))];
|
|
33097
|
+
if (taskIds.length === 0)
|
|
33098
|
+
return;
|
|
33099
|
+
try {
|
|
33100
|
+
const bridge = ctx.pool.getActiveBridgeForRoot(directory) ?? ctx.pool.getBridge(directory);
|
|
33101
|
+
const params = sessionID ? { session_id: sessionID, task_ids: taskIds } : { task_ids: taskIds };
|
|
33102
|
+
const response = await bridge.send("bash_ack_completions", params);
|
|
33103
|
+
if (response.success === false) {
|
|
33104
|
+
sessionWarn(sessionID ?? "", `${LOG_PREFIX} ack failed: ${String(response.message ?? "unknown error")}`);
|
|
33105
|
+
}
|
|
33106
|
+
} catch (err) {
|
|
33107
|
+
sessionWarn(sessionID ?? "", `${LOG_PREFIX} ack failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
32899
33108
|
}
|
|
32900
33109
|
}
|
|
32901
33110
|
function scheduleWake(state, sendWake, onSendFailure) {
|
|
33111
|
+
if (state.wakeHardStopped)
|
|
33112
|
+
return;
|
|
32902
33113
|
const now = Date.now();
|
|
32903
33114
|
const pendingCount = state.pendingCompletions.length + state.pendingLongRunning.length;
|
|
32904
33115
|
if (state.debounceTimer && pendingCount <= state.scheduledCompletionCount) {
|
|
@@ -32927,13 +33138,22 @@ function scheduleWake(state, sendWake, onSendFailure) {
|
|
|
32927
33138
|
const reminder = formatCombinedSystemReminder(pending, pendingLongRunning);
|
|
32928
33139
|
state.pendingCompletions = [];
|
|
32929
33140
|
state.pendingLongRunning = [];
|
|
32930
|
-
sendWake(reminder).then(() => {
|
|
33141
|
+
sendWake(reminder, pending).then(() => {
|
|
32931
33142
|
state.retryDelayMs = null;
|
|
33143
|
+
state.wakeRetryAttempts = 0;
|
|
33144
|
+
state.wakeHardStopped = false;
|
|
32932
33145
|
}).catch((err) => {
|
|
32933
33146
|
state.pendingCompletions = [...pending, ...state.pendingCompletions];
|
|
32934
33147
|
state.pendingLongRunning = [...pendingLongRunning, ...state.pendingLongRunning];
|
|
33148
|
+
state.wakeRetryAttempts += 1;
|
|
33149
|
+
if (state.wakeRetryAttempts >= MAX_WAKE_SEND_ATTEMPTS) {
|
|
33150
|
+
state.retryDelayMs = null;
|
|
33151
|
+
state.wakeHardStopped = true;
|
|
33152
|
+
onSendFailure(err, true);
|
|
33153
|
+
return;
|
|
33154
|
+
}
|
|
32935
33155
|
state.retryDelayMs = Math.min((delay || DEBOUNCE_STEP_MS) * 2, DEBOUNCE_CAP_MS);
|
|
32936
|
-
onSendFailure(err);
|
|
33156
|
+
onSendFailure(err, false);
|
|
32937
33157
|
scheduleWake(state, sendWake, onSendFailure);
|
|
32938
33158
|
});
|
|
32939
33159
|
}, delay);
|
|
@@ -32954,6 +33174,9 @@ function stateFor(sessionID) {
|
|
|
32954
33174
|
scheduledFireAt: null,
|
|
32955
33175
|
scheduledCompletionCount: 0,
|
|
32956
33176
|
retryDelayMs: null,
|
|
33177
|
+
wakeRetryAttempts: 0,
|
|
33178
|
+
wakeHardStopped: false,
|
|
33179
|
+
forcedDrainCompleted: false,
|
|
32957
33180
|
unknownCompletions: [],
|
|
32958
33181
|
lastSeenAt: now
|
|
32959
33182
|
};
|
|
@@ -32963,6 +33186,22 @@ function stateFor(sessionID) {
|
|
|
32963
33186
|
}
|
|
32964
33187
|
return state;
|
|
32965
33188
|
}
|
|
33189
|
+
function ingestDrainedBgCompletions(sessionID, completions) {
|
|
33190
|
+
if (!Array.isArray(completions) || completions.length === 0)
|
|
33191
|
+
return [];
|
|
33192
|
+
const state = stateFor(sessionID);
|
|
33193
|
+
const accepted = [];
|
|
33194
|
+
for (const completion of completions) {
|
|
33195
|
+
if (!isBgCompletion(completion))
|
|
33196
|
+
continue;
|
|
33197
|
+
state.outstandingTaskIds.delete(completion.task_id);
|
|
33198
|
+
if (!state.pendingCompletions.some((pending) => pending.task_id === completion.task_id) && !accepted.some((pending) => pending.task_id === completion.task_id)) {
|
|
33199
|
+
accepted.push(completion);
|
|
33200
|
+
}
|
|
33201
|
+
}
|
|
33202
|
+
state.pendingCompletions.push(...accepted);
|
|
33203
|
+
return accepted;
|
|
33204
|
+
}
|
|
32966
33205
|
function cleanupIdleSessionStates(now = Date.now()) {
|
|
32967
33206
|
const cutoff = now - SESSION_BG_STATE_IDLE_TTL_MS;
|
|
32968
33207
|
for (const [sessionID, state] of sessionBgStates) {
|
|
@@ -33055,7 +33294,7 @@ import {
|
|
|
33055
33294
|
// package.json
|
|
33056
33295
|
var package_default = {
|
|
33057
33296
|
name: "@cortexkit/aft-pi",
|
|
33058
|
-
version: "0.26.
|
|
33297
|
+
version: "0.26.1",
|
|
33059
33298
|
type: "module",
|
|
33060
33299
|
description: "Pi coding agent extension for Agent File Tools (AFT) — tree-sitter and LSP-powered code analysis",
|
|
33061
33300
|
main: "dist/index.js",
|
|
@@ -33077,18 +33316,18 @@ var package_default = {
|
|
|
33077
33316
|
prepublishOnly: "bun run build"
|
|
33078
33317
|
},
|
|
33079
33318
|
dependencies: {
|
|
33080
|
-
"@cortexkit/aft-bridge": "0.26.
|
|
33319
|
+
"@cortexkit/aft-bridge": "0.26.1",
|
|
33081
33320
|
typebox: "^1.1.24",
|
|
33082
33321
|
"comment-json": "^5.0.0",
|
|
33083
33322
|
diff: "^8.0.4",
|
|
33084
33323
|
zod: "^4.1.8"
|
|
33085
33324
|
},
|
|
33086
33325
|
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.
|
|
33326
|
+
"@cortexkit/aft-darwin-arm64": "0.26.1",
|
|
33327
|
+
"@cortexkit/aft-darwin-x64": "0.26.1",
|
|
33328
|
+
"@cortexkit/aft-linux-arm64": "0.26.1",
|
|
33329
|
+
"@cortexkit/aft-linux-x64": "0.26.1",
|
|
33330
|
+
"@cortexkit/aft-win32-x64": "0.26.1"
|
|
33092
33331
|
},
|
|
33093
33332
|
devDependencies: {
|
|
33094
33333
|
"@earendil-works/pi-coding-agent": "*",
|
|
@@ -33573,7 +33812,7 @@ function registerStatusCommand(pi, ctx) {
|
|
|
33573
33812
|
|
|
33574
33813
|
// src/config.ts
|
|
33575
33814
|
var import_comment_json = __toESM(require_src2(), 1);
|
|
33576
|
-
import { existsSync as existsSync5, readFileSync as readFileSync3, renameSync as
|
|
33815
|
+
import { existsSync as existsSync5, readFileSync as readFileSync3, renameSync as renameSync3, unlinkSync as unlinkSync4, writeFileSync as writeFileSync3 } from "node:fs";
|
|
33577
33816
|
import { homedir as homedir5 } from "node:os";
|
|
33578
33817
|
import { join as join7 } from "node:path";
|
|
33579
33818
|
|
|
@@ -47348,7 +47587,7 @@ function migrateAftConfigFile(configPath, logger = { log: log2, warn: warn2 }) {
|
|
|
47348
47587
|
${serialized}` : serialized;
|
|
47349
47588
|
tmpPath = `${configPath}.tmp.${process.pid}`;
|
|
47350
47589
|
writeFileSync3(tmpPath, nextContent, "utf-8");
|
|
47351
|
-
|
|
47590
|
+
renameSync3(tmpPath, configPath);
|
|
47352
47591
|
logger.log(`Migrated config at ${configPath}: removed ${oldKeys.join(", ")}`);
|
|
47353
47592
|
return { migrated: true, oldKeys };
|
|
47354
47593
|
} catch (err) {
|
|
@@ -47563,17 +47802,17 @@ function loadAftConfig(projectDirectory) {
|
|
|
47563
47802
|
|
|
47564
47803
|
// src/lsp-auto-install.ts
|
|
47565
47804
|
import { spawn as spawn2 } from "node:child_process";
|
|
47566
|
-
import { createHash as
|
|
47567
|
-
import { createReadStream, mkdirSync as mkdirSync6, readFileSync as readFileSync5, renameSync as
|
|
47805
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
47806
|
+
import { createReadStream, mkdirSync as mkdirSync6, readFileSync as readFileSync5, renameSync as renameSync4, rmSync as rmSync3, statSync as statSync4 } from "node:fs";
|
|
47568
47807
|
import { join as join10 } from "node:path";
|
|
47569
47808
|
|
|
47570
47809
|
// src/lsp-cache.ts
|
|
47571
47810
|
import {
|
|
47572
|
-
closeSync as
|
|
47811
|
+
closeSync as closeSync3,
|
|
47573
47812
|
mkdirSync as mkdirSync5,
|
|
47574
|
-
openSync as
|
|
47813
|
+
openSync as openSync3,
|
|
47575
47814
|
readFileSync as readFileSync4,
|
|
47576
|
-
statSync as
|
|
47815
|
+
statSync as statSync3,
|
|
47577
47816
|
unlinkSync as unlinkSync5,
|
|
47578
47817
|
writeFileSync as writeFileSync4
|
|
47579
47818
|
} from "node:fs";
|
|
@@ -47606,7 +47845,7 @@ function lspBinDir(npmPackage) {
|
|
|
47606
47845
|
function isInstalled(npmPackage, binary) {
|
|
47607
47846
|
for (const candidate of lspBinaryCandidates(binary)) {
|
|
47608
47847
|
try {
|
|
47609
|
-
if (
|
|
47848
|
+
if (statSync3(join8(lspBinDir(npmPackage), candidate)).isFile())
|
|
47610
47849
|
return true;
|
|
47611
47850
|
} catch {}
|
|
47612
47851
|
}
|
|
@@ -47634,7 +47873,7 @@ function writeInstalledMetaIn(installDir, version2, sha256) {
|
|
|
47634
47873
|
function readInstalledMetaIn(installDir) {
|
|
47635
47874
|
const path2 = join8(installDir, INSTALLED_META_FILE);
|
|
47636
47875
|
try {
|
|
47637
|
-
if (!
|
|
47876
|
+
if (!statSync3(path2).isFile())
|
|
47638
47877
|
return null;
|
|
47639
47878
|
const raw = readFileSync4(path2, "utf8");
|
|
47640
47879
|
const parsed = JSON.parse(raw);
|
|
@@ -47664,13 +47903,13 @@ function acquireInstallLock(lockKey) {
|
|
|
47664
47903
|
const lock = lockPath(lockKey);
|
|
47665
47904
|
const tryClaim = () => {
|
|
47666
47905
|
try {
|
|
47667
|
-
const fd =
|
|
47906
|
+
const fd = openSync3(lock, "wx");
|
|
47668
47907
|
try {
|
|
47669
47908
|
writeFileSync4(fd, `${process.pid}
|
|
47670
47909
|
${new Date().toISOString()}
|
|
47671
47910
|
`);
|
|
47672
47911
|
} finally {
|
|
47673
|
-
|
|
47912
|
+
closeSync3(fd);
|
|
47674
47913
|
}
|
|
47675
47914
|
return true;
|
|
47676
47915
|
} catch (err) {
|
|
@@ -47691,7 +47930,7 @@ ${new Date().toISOString()}
|
|
|
47691
47930
|
const parsed = Number.parseInt(firstLine, 10);
|
|
47692
47931
|
if (Number.isFinite(parsed) && parsed > 0)
|
|
47693
47932
|
owningPid = parsed;
|
|
47694
|
-
lockMtimeMs =
|
|
47933
|
+
lockMtimeMs = statSync3(lock).mtimeMs;
|
|
47695
47934
|
} catch {
|
|
47696
47935
|
return tryClaim();
|
|
47697
47936
|
}
|
|
@@ -48233,7 +48472,7 @@ function hashInstalledBinary(spec) {
|
|
|
48233
48472
|
let pathToHash = null;
|
|
48234
48473
|
for (const p of candidates) {
|
|
48235
48474
|
try {
|
|
48236
|
-
if (
|
|
48475
|
+
if (statSync4(p).isFile()) {
|
|
48237
48476
|
pathToHash = p;
|
|
48238
48477
|
break;
|
|
48239
48478
|
}
|
|
@@ -48243,7 +48482,7 @@ function hashInstalledBinary(spec) {
|
|
|
48243
48482
|
reject(new Error(`installed binary not found at any of: ${candidates.join(", ")}`));
|
|
48244
48483
|
return;
|
|
48245
48484
|
}
|
|
48246
|
-
const hash2 =
|
|
48485
|
+
const hash2 = createHash4("sha256");
|
|
48247
48486
|
const stream = createReadStream(pathToHash);
|
|
48248
48487
|
stream.on("error", reject);
|
|
48249
48488
|
stream.on("data", (chunk) => hash2.update(chunk));
|
|
@@ -48259,14 +48498,14 @@ function installedBinaryPath(spec) {
|
|
|
48259
48498
|
] : [lspBinaryPath(spec.npm, spec.binary)];
|
|
48260
48499
|
for (const candidate of candidates) {
|
|
48261
48500
|
try {
|
|
48262
|
-
if (
|
|
48501
|
+
if (statSync4(candidate).isFile())
|
|
48263
48502
|
return candidate;
|
|
48264
48503
|
} catch {}
|
|
48265
48504
|
}
|
|
48266
48505
|
return null;
|
|
48267
48506
|
}
|
|
48268
48507
|
function sha256OfFileSync(path2) {
|
|
48269
|
-
return
|
|
48508
|
+
return createHash4("sha256").update(readFileSync5(path2)).digest("hex");
|
|
48270
48509
|
}
|
|
48271
48510
|
function quarantineCachedNpmInstall(spec, reason) {
|
|
48272
48511
|
const packageDir = lspPackageDir(spec.npm);
|
|
@@ -48274,8 +48513,8 @@ function quarantineCachedNpmInstall(spec, reason) {
|
|
|
48274
48513
|
warn2(`[lsp] tofu_mismatch ${spec.npm}: ${reason}; quarantining ${packageDir} -> ${dest}`);
|
|
48275
48514
|
try {
|
|
48276
48515
|
mkdirSync6(join10(dest, ".."), { recursive: true });
|
|
48277
|
-
|
|
48278
|
-
|
|
48516
|
+
rmSync3(dest, { recursive: true, force: true });
|
|
48517
|
+
renameSync4(packageDir, dest);
|
|
48279
48518
|
} catch (err) {
|
|
48280
48519
|
warn2(`[lsp] tofu_mismatch ${spec.npm}: failed to quarantine cache entry: ${err}`);
|
|
48281
48520
|
}
|
|
@@ -48351,11 +48590,11 @@ function runAutoInstall(projectRoot, config2, fetchImpl2 = fetch) {
|
|
|
48351
48590
|
|
|
48352
48591
|
// src/lsp-github-install.ts
|
|
48353
48592
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
48354
|
-
import { createHash as
|
|
48593
|
+
import { createHash as createHash5, randomBytes } from "node:crypto";
|
|
48355
48594
|
import {
|
|
48356
48595
|
copyFileSync as copyFileSync3,
|
|
48357
48596
|
createReadStream as createReadStream2,
|
|
48358
|
-
createWriteStream as
|
|
48597
|
+
createWriteStream as createWriteStream3,
|
|
48359
48598
|
existsSync as existsSync7,
|
|
48360
48599
|
lstatSync as lstatSync2,
|
|
48361
48600
|
mkdirSync as mkdirSync7,
|
|
@@ -48363,14 +48602,15 @@ import {
|
|
|
48363
48602
|
readFileSync as readFileSync6,
|
|
48364
48603
|
readlinkSync as readlinkSync2,
|
|
48365
48604
|
realpathSync as realpathSync3,
|
|
48366
|
-
renameSync as
|
|
48367
|
-
rmSync as
|
|
48368
|
-
statSync as
|
|
48369
|
-
unlinkSync as unlinkSync6
|
|
48605
|
+
renameSync as renameSync5,
|
|
48606
|
+
rmSync as rmSync4,
|
|
48607
|
+
statSync as statSync5,
|
|
48608
|
+
unlinkSync as unlinkSync6,
|
|
48609
|
+
writeFileSync as writeFileSync5
|
|
48370
48610
|
} from "node:fs";
|
|
48371
48611
|
import { dirname as dirname2, join as join11, relative as relative2, resolve as resolve2 } from "node:path";
|
|
48372
|
-
import { Readable as
|
|
48373
|
-
import { pipeline as
|
|
48612
|
+
import { Readable as Readable3 } from "node:stream";
|
|
48613
|
+
import { pipeline as pipeline3 } from "node:stream/promises";
|
|
48374
48614
|
|
|
48375
48615
|
// src/lsp-github-table.ts
|
|
48376
48616
|
function exe(platform, name) {
|
|
@@ -48469,6 +48709,7 @@ function ghBinDir(spec) {
|
|
|
48469
48709
|
function ghExtractDir(spec) {
|
|
48470
48710
|
return join11(ghPackageDir(spec), "extracted");
|
|
48471
48711
|
}
|
|
48712
|
+
var INSTALLED_META_FILE2 = ".aft-installed";
|
|
48472
48713
|
function ghBinaryPath(spec, platform) {
|
|
48473
48714
|
const ext = platform === "win32" ? ".exe" : "";
|
|
48474
48715
|
return join11(ghBinDir(spec), `${spec.binary}${ext}`);
|
|
@@ -48476,7 +48717,7 @@ function ghBinaryPath(spec, platform) {
|
|
|
48476
48717
|
function isGithubInstalled(spec, platform) {
|
|
48477
48718
|
for (const candidate of ghBinaryCandidates(spec, platform)) {
|
|
48478
48719
|
try {
|
|
48479
|
-
if (
|
|
48720
|
+
if (statSync5(join11(ghBinDir(spec), candidate)).isFile())
|
|
48480
48721
|
return true;
|
|
48481
48722
|
} catch {}
|
|
48482
48723
|
}
|
|
@@ -48487,11 +48728,45 @@ function ghBinaryCandidates(spec, platform) {
|
|
|
48487
48728
|
return [spec.binary];
|
|
48488
48729
|
return [spec.binary, `${spec.binary}.cmd`, `${spec.binary}.exe`, `${spec.binary}.bat`];
|
|
48489
48730
|
}
|
|
48490
|
-
|
|
48731
|
+
function readGithubInstalledMetaIn(installDir) {
|
|
48732
|
+
try {
|
|
48733
|
+
const path2 = join11(installDir, INSTALLED_META_FILE2);
|
|
48734
|
+
if (!statSync5(path2).isFile())
|
|
48735
|
+
return null;
|
|
48736
|
+
const parsed = JSON.parse(readFileSync6(path2, "utf8"));
|
|
48737
|
+
if (typeof parsed.version !== "string" || parsed.version.length === 0)
|
|
48738
|
+
return null;
|
|
48739
|
+
return {
|
|
48740
|
+
version: parsed.version,
|
|
48741
|
+
installedAt: typeof parsed.installedAt === "string" ? parsed.installedAt : "",
|
|
48742
|
+
...typeof parsed.sha256 === "string" && parsed.sha256.length > 0 ? { sha256: parsed.sha256 } : {},
|
|
48743
|
+
...typeof parsed.binarySha256 === "string" && parsed.binarySha256.length > 0 ? { binarySha256: parsed.binarySha256 } : {},
|
|
48744
|
+
...typeof parsed.archiveSha256 === "string" && parsed.archiveSha256.length > 0 ? { archiveSha256: parsed.archiveSha256 } : {}
|
|
48745
|
+
};
|
|
48746
|
+
} catch {
|
|
48747
|
+
return null;
|
|
48748
|
+
}
|
|
48749
|
+
}
|
|
48750
|
+
function writeGithubInstalledMetaIn(installDir, version2, binarySha256, archiveSha256) {
|
|
48751
|
+
try {
|
|
48752
|
+
mkdirSync7(installDir, { recursive: true });
|
|
48753
|
+
const meta3 = {
|
|
48754
|
+
version: version2,
|
|
48755
|
+
installedAt: new Date().toISOString(),
|
|
48756
|
+
sha256: binarySha256,
|
|
48757
|
+
binarySha256,
|
|
48758
|
+
...archiveSha256 ? { archiveSha256 } : {}
|
|
48759
|
+
};
|
|
48760
|
+
writeFileSync5(join11(installDir, INSTALLED_META_FILE2), JSON.stringify(meta3), "utf8");
|
|
48761
|
+
} catch (err) {
|
|
48762
|
+
warn2(`[lsp] failed to write github installed metadata in ${installDir}: ${err}`);
|
|
48763
|
+
}
|
|
48764
|
+
}
|
|
48765
|
+
var MAX_DOWNLOAD_BYTES3 = 256 * 1024 * 1024;
|
|
48491
48766
|
var MAX_EXTRACT_BYTES2 = 1024 * 1024 * 1024;
|
|
48492
48767
|
function sha256OfFile(path2) {
|
|
48493
48768
|
return new Promise((resolve3, reject) => {
|
|
48494
|
-
const hash2 =
|
|
48769
|
+
const hash2 = createHash5("sha256");
|
|
48495
48770
|
const stream = createReadStream2(path2);
|
|
48496
48771
|
stream.on("error", reject);
|
|
48497
48772
|
stream.on("data", (chunk) => hash2.update(chunk));
|
|
@@ -48499,7 +48774,7 @@ function sha256OfFile(path2) {
|
|
|
48499
48774
|
});
|
|
48500
48775
|
}
|
|
48501
48776
|
function sha256OfFileSync2(path2) {
|
|
48502
|
-
return
|
|
48777
|
+
return createHash5("sha256").update(readFileSync6(path2)).digest("hex");
|
|
48503
48778
|
}
|
|
48504
48779
|
async function fetchReleaseByTag(githubRepo, tag, fetchImpl2, signal) {
|
|
48505
48780
|
const candidates = [];
|
|
@@ -48662,8 +48937,8 @@ function assertAllowedDownloadUrl(rawUrl) {
|
|
|
48662
48937
|
return parsed;
|
|
48663
48938
|
}
|
|
48664
48939
|
async function downloadFile(url2, destPath, fetchImpl2, assetSize, signal) {
|
|
48665
|
-
if (assetSize !== undefined && assetSize >
|
|
48666
|
-
throw new Error(`asset size ${assetSize} exceeds max ${
|
|
48940
|
+
if (assetSize !== undefined && assetSize > MAX_DOWNLOAD_BYTES3) {
|
|
48941
|
+
throw new Error(`asset size ${assetSize} exceeds max ${MAX_DOWNLOAD_BYTES3} (set lsp.versions to pin a smaller release if this is wrong)`);
|
|
48667
48942
|
}
|
|
48668
48943
|
const timeout = controlledTimeoutSignal(120000, signal);
|
|
48669
48944
|
try {
|
|
@@ -48672,24 +48947,24 @@ async function downloadFile(url2, destPath, fetchImpl2, assetSize, signal) {
|
|
|
48672
48947
|
throw new Error(`download failed (${res.status})`);
|
|
48673
48948
|
}
|
|
48674
48949
|
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 ${
|
|
48950
|
+
if (Number.isFinite(advertised) && advertised > MAX_DOWNLOAD_BYTES3) {
|
|
48951
|
+
throw new Error(`Content-Length ${advertised} exceeds max ${MAX_DOWNLOAD_BYTES3}`);
|
|
48677
48952
|
}
|
|
48678
48953
|
mkdirSync7(dirname2(destPath), { recursive: true });
|
|
48679
48954
|
let bytesWritten = 0;
|
|
48680
48955
|
const guard = new TransformStream({
|
|
48681
48956
|
transform(chunk, controller) {
|
|
48682
48957
|
bytesWritten += chunk.byteLength;
|
|
48683
|
-
if (bytesWritten >
|
|
48684
|
-
controller.error(new Error(`download exceeded ${
|
|
48958
|
+
if (bytesWritten > MAX_DOWNLOAD_BYTES3) {
|
|
48959
|
+
controller.error(new Error(`download exceeded ${MAX_DOWNLOAD_BYTES3} bytes after streaming (server lied about size or sent unbounded body)`));
|
|
48685
48960
|
return;
|
|
48686
48961
|
}
|
|
48687
48962
|
controller.enqueue(chunk);
|
|
48688
48963
|
}
|
|
48689
48964
|
});
|
|
48690
48965
|
const guarded = res.body.pipeThrough(guard);
|
|
48691
|
-
const nodeStream =
|
|
48692
|
-
await
|
|
48966
|
+
const nodeStream = Readable3.fromWeb(guarded);
|
|
48967
|
+
await pipeline3(nodeStream, createWriteStream3(destPath), { signal: timeout.signal });
|
|
48693
48968
|
} catch (err) {
|
|
48694
48969
|
try {
|
|
48695
48970
|
unlinkSync6(destPath);
|
|
@@ -48769,7 +49044,7 @@ function validateExtraction(stagingRoot) {
|
|
|
48769
49044
|
};
|
|
48770
49045
|
walk(realStagingRoot);
|
|
48771
49046
|
}
|
|
48772
|
-
function
|
|
49047
|
+
function precheckArchiveContents(archivePath, archiveType) {
|
|
48773
49048
|
let totalBytes = 0;
|
|
48774
49049
|
if (archiveType === "zip") {
|
|
48775
49050
|
const out = execFileSync2("unzip", ["-l", archivePath], { encoding: "utf8" });
|
|
@@ -48780,6 +49055,9 @@ function precheckArchiveSize(archivePath, archiveType) {
|
|
|
48780
49055
|
const out = execFileSync2("tar", ["-tvf", archivePath], { encoding: "utf8" });
|
|
48781
49056
|
for (const line of out.split(`
|
|
48782
49057
|
`)) {
|
|
49058
|
+
if (line.startsWith("h")) {
|
|
49059
|
+
throw new Error(`archive contains hardlink entry: ${line.trim()}`);
|
|
49060
|
+
}
|
|
48783
49061
|
const parts = line.trim().split(/\s+/);
|
|
48784
49062
|
if (parts.length >= 6) {
|
|
48785
49063
|
const numeric = parts.map((part) => Number.parseInt(part, 10)).filter((value) => Number.isFinite(value) && value >= 0);
|
|
@@ -48796,20 +49074,20 @@ function extractArchiveSafely(archivePath, destDir, archiveType) {
|
|
|
48796
49074
|
const suffix = randomBytes(8).toString("hex");
|
|
48797
49075
|
const stagingDir = `${destDir}.staging-${suffix}`;
|
|
48798
49076
|
try {
|
|
48799
|
-
|
|
49077
|
+
rmSync4(stagingDir, { recursive: true, force: true });
|
|
48800
49078
|
} catch {}
|
|
48801
49079
|
mkdirSync7(stagingDir, { recursive: true });
|
|
48802
49080
|
try {
|
|
48803
|
-
|
|
49081
|
+
precheckArchiveContents(archivePath, archiveType);
|
|
48804
49082
|
runPlatformExtractor(archivePath, stagingDir, archiveType);
|
|
48805
49083
|
validateExtraction(stagingDir);
|
|
48806
49084
|
try {
|
|
48807
|
-
|
|
49085
|
+
rmSync4(destDir, { recursive: true, force: true });
|
|
48808
49086
|
} catch {}
|
|
48809
|
-
|
|
49087
|
+
renameSync5(stagingDir, destDir);
|
|
48810
49088
|
} catch (err) {
|
|
48811
49089
|
try {
|
|
48812
|
-
|
|
49090
|
+
rmSync4(stagingDir, { recursive: true, force: true });
|
|
48813
49091
|
} catch {}
|
|
48814
49092
|
throw err;
|
|
48815
49093
|
}
|
|
@@ -48820,28 +49098,44 @@ function quarantineCachedGithubInstall(spec, reason) {
|
|
|
48820
49098
|
warn2(`[lsp] tofu_mismatch ${spec.id}: ${reason}; quarantining ${packageDir} -> ${dest}`);
|
|
48821
49099
|
try {
|
|
48822
49100
|
mkdirSync7(dirname2(dest), { recursive: true });
|
|
48823
|
-
|
|
48824
|
-
|
|
49101
|
+
rmSync4(dest, { recursive: true, force: true });
|
|
49102
|
+
renameSync5(packageDir, dest);
|
|
48825
49103
|
} catch (err) {
|
|
48826
49104
|
warn2(`[lsp] tofu_mismatch ${spec.id}: failed to quarantine cache entry: ${err}`);
|
|
48827
49105
|
}
|
|
48828
49106
|
}
|
|
48829
49107
|
function validateCachedGithubInstall(spec, platform) {
|
|
48830
|
-
const
|
|
49108
|
+
const packageDir = ghPackageDir(spec);
|
|
49109
|
+
const meta3 = readGithubInstalledMetaIn(packageDir);
|
|
48831
49110
|
const binaryPath = ghBinaryCandidates(spec, platform).map((candidate) => join11(ghBinDir(spec), candidate)).find((candidate) => {
|
|
48832
49111
|
try {
|
|
48833
|
-
return
|
|
49112
|
+
return statSync5(candidate).isFile();
|
|
48834
49113
|
} catch {
|
|
48835
49114
|
return false;
|
|
48836
49115
|
}
|
|
48837
49116
|
});
|
|
48838
|
-
if (!meta3?.
|
|
49117
|
+
if (!meta3?.version || !isSafeVersion(meta3.version) || !binaryPath) {
|
|
48839
49118
|
quarantineCachedGithubInstall(spec, "missing/unsafe metadata or binary");
|
|
48840
49119
|
return false;
|
|
48841
49120
|
}
|
|
48842
49121
|
const currentHash = sha256OfFileSync2(binaryPath);
|
|
48843
|
-
|
|
48844
|
-
|
|
49122
|
+
const recordedBinaryHash = meta3.binarySha256 ?? meta3.sha256;
|
|
49123
|
+
if (recordedBinaryHash && currentHash === recordedBinaryHash) {
|
|
49124
|
+
if (meta3.sha256 !== currentHash || meta3.binarySha256 !== currentHash) {
|
|
49125
|
+
writeGithubInstalledMetaIn(packageDir, meta3.version, currentHash, meta3.archiveSha256);
|
|
49126
|
+
}
|
|
49127
|
+
return true;
|
|
49128
|
+
}
|
|
49129
|
+
if (meta3.sha256 && !meta3.binarySha256 && !meta3.archiveSha256) {
|
|
49130
|
+
writeGithubInstalledMetaIn(packageDir, meta3.version, currentHash, meta3.sha256);
|
|
49131
|
+
return true;
|
|
49132
|
+
}
|
|
49133
|
+
if (!recordedBinaryHash) {
|
|
49134
|
+
quarantineCachedGithubInstall(spec, "missing binary sha256 metadata");
|
|
49135
|
+
return false;
|
|
49136
|
+
}
|
|
49137
|
+
if (currentHash !== recordedBinaryHash) {
|
|
49138
|
+
quarantineCachedGithubInstall(spec, `recorded ${recordedBinaryHash}, current ${currentHash}`);
|
|
48845
49139
|
return false;
|
|
48846
49140
|
}
|
|
48847
49141
|
return true;
|
|
@@ -48910,10 +49204,11 @@ async function downloadAndInstall(spec, tag, assets, platform, arch, fetchImpl2,
|
|
|
48910
49204
|
return null;
|
|
48911
49205
|
}
|
|
48912
49206
|
log2(`[lsp] ${spec.id} ${tag} sha256=${archiveSha256}`);
|
|
48913
|
-
const previousMeta =
|
|
48914
|
-
|
|
48915
|
-
|
|
48916
|
-
|
|
49207
|
+
const previousMeta = readGithubInstalledMetaIn(ghPackageDir(spec));
|
|
49208
|
+
const previousArchiveSha256 = previousMeta?.archiveSha256 ?? (previousMeta?.binarySha256 ? undefined : previousMeta?.sha256);
|
|
49209
|
+
if (previousMeta && previousMeta.version === tag && previousArchiveSha256) {
|
|
49210
|
+
if (previousArchiveSha256 !== archiveSha256) {
|
|
49211
|
+
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
49212
|
try {
|
|
48918
49213
|
unlinkSync6(archivePath);
|
|
48919
49214
|
} catch {}
|
|
@@ -48948,7 +49243,9 @@ async function downloadAndInstall(spec, tag, assets, platform, arch, fetchImpl2,
|
|
|
48948
49243
|
return null;
|
|
48949
49244
|
}
|
|
48950
49245
|
log2(`[lsp] installed ${spec.id} ${tag} at ${targetBinary}`);
|
|
48951
|
-
|
|
49246
|
+
const binarySha256 = await sha256OfFile(targetBinary);
|
|
49247
|
+
log2(`[lsp] ${spec.id} ${tag} binary_sha256=${binarySha256}`);
|
|
49248
|
+
return { archiveSha256, binarySha256 };
|
|
48952
49249
|
}
|
|
48953
49250
|
async function ensureGithubInstalled(spec, config2, fetchImpl2, platform, arch, signal) {
|
|
48954
49251
|
const outcome = await withInstallLock(spec.githubRepo, async () => {
|
|
@@ -48974,14 +49271,14 @@ async function ensureGithubInstalled(spec, config2, fetchImpl2, platform, arch,
|
|
|
48974
49271
|
log2(`[lsp] reinstalling ${spec.id}@${tag}: no installed-version metadata recorded`);
|
|
48975
49272
|
}
|
|
48976
49273
|
}
|
|
48977
|
-
const
|
|
49274
|
+
const hashes = await downloadAndInstall(spec, tag, assets, platform, arch, fetchImpl2, signal).catch((err) => {
|
|
48978
49275
|
error2(`[lsp] github install ${spec.id} crashed: ${err}`);
|
|
48979
49276
|
return null;
|
|
48980
49277
|
});
|
|
48981
|
-
if (!
|
|
49278
|
+
if (!hashes) {
|
|
48982
49279
|
return { started: true, reason: "install failed (see plugin log)" };
|
|
48983
49280
|
}
|
|
48984
|
-
|
|
49281
|
+
writeGithubInstalledMetaIn(ghPackageDir(spec), tag, hashes.binarySha256, hashes.archiveSha256);
|
|
48985
49282
|
return { started: true };
|
|
48986
49283
|
});
|
|
48987
49284
|
if (outcome === null) {
|
|
@@ -49111,7 +49408,7 @@ function discoverRelevantGithubServers(projectRoot) {
|
|
|
49111
49408
|
}
|
|
49112
49409
|
|
|
49113
49410
|
// src/notifications.ts
|
|
49114
|
-
import { existsSync as existsSync8, mkdirSync as mkdirSync8, readFileSync as readFileSync7, renameSync as
|
|
49411
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync8, readFileSync as readFileSync7, renameSync as renameSync6, rmSync as rmSync5, writeFileSync as writeFileSync6 } from "node:fs";
|
|
49115
49412
|
import { join as join12 } from "node:path";
|
|
49116
49413
|
var WARNING_MARKER = "\uD83D\uDD27 AFT: ⚠️";
|
|
49117
49414
|
var FEATURE_MARKER = "\uD83D\uDD27 AFT: ✨";
|
|
@@ -49124,7 +49421,7 @@ function sendIgnoredMessage(client, sessionId, text) {
|
|
|
49124
49421
|
typedClient.ui.notify(text, "warning");
|
|
49125
49422
|
return true;
|
|
49126
49423
|
} catch (err) {
|
|
49127
|
-
|
|
49424
|
+
sessionLog(sessionId, `[aft-pi] notification send failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
49128
49425
|
return false;
|
|
49129
49426
|
}
|
|
49130
49427
|
}
|
|
@@ -49152,9 +49449,9 @@ function writeWarnedTools(storageDir, warned) {
|
|
|
49152
49449
|
mkdirSync8(storageDir, { recursive: true });
|
|
49153
49450
|
const warnedToolsPath = join12(storageDir, WARNED_TOOLS_FILE);
|
|
49154
49451
|
const tmpPath = join12(storageDir, `${WARNED_TOOLS_FILE}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`);
|
|
49155
|
-
|
|
49452
|
+
writeFileSync6(tmpPath, `${JSON.stringify(warned, null, 2)}
|
|
49156
49453
|
`);
|
|
49157
|
-
|
|
49454
|
+
renameSync6(tmpPath, warnedToolsPath);
|
|
49158
49455
|
} catch {}
|
|
49159
49456
|
}
|
|
49160
49457
|
async function withWarnedToolsLock(storageDir, fn) {
|
|
@@ -49166,7 +49463,7 @@ async function withWarnedToolsLock(storageDir, fn) {
|
|
|
49166
49463
|
try {
|
|
49167
49464
|
return await fn();
|
|
49168
49465
|
} finally {
|
|
49169
|
-
|
|
49466
|
+
rmSync5(lockDir, { recursive: true, force: true });
|
|
49170
49467
|
}
|
|
49171
49468
|
} catch (err) {
|
|
49172
49469
|
const code = err.code;
|
|
@@ -49253,7 +49550,7 @@ function sendFeatureAnnouncement(version2, features, storageDir) {
|
|
|
49253
49550
|
`));
|
|
49254
49551
|
try {
|
|
49255
49552
|
mkdirSync8(storageDir, { recursive: true });
|
|
49256
|
-
|
|
49553
|
+
writeFileSync6(versionFile, version2);
|
|
49257
49554
|
} catch {}
|
|
49258
49555
|
}
|
|
49259
49556
|
|
|
@@ -51856,33 +52153,39 @@ ${hintsBlock}` };
|
|
|
51856
52153
|
// src/index.ts
|
|
51857
52154
|
setActiveLogger(bridgeLogger);
|
|
51858
52155
|
function createVersionMismatchHandler(getPool, ensureCompatibleBinary = ensureBinary) {
|
|
51859
|
-
|
|
52156
|
+
const versionUpgradePromises = new Map;
|
|
51860
52157
|
return async (binaryVersion, minVersion) => {
|
|
51861
|
-
|
|
51862
|
-
|
|
51863
|
-
|
|
52158
|
+
const existing = versionUpgradePromises.get(minVersion);
|
|
52159
|
+
if (existing) {
|
|
52160
|
+
log2(`Version ${binaryVersion} < ${minVersion}; awaiting in-flight compatible binary upgrade`);
|
|
52161
|
+
return existing;
|
|
51864
52162
|
}
|
|
51865
|
-
|
|
51866
|
-
|
|
51867
|
-
|
|
51868
|
-
|
|
51869
|
-
|
|
51870
|
-
|
|
51871
|
-
|
|
51872
|
-
|
|
51873
|
-
|
|
51874
|
-
|
|
51875
|
-
|
|
52163
|
+
const upgradePromise = (async () => {
|
|
52164
|
+
warn2(`WARNING: aft binary v${binaryVersion} is older than plugin v${minVersion}. ` + "Some features may not work. Attempting to download a compatible binary...");
|
|
52165
|
+
try {
|
|
52166
|
+
const path2 = await ensureCompatibleBinary(`v${minVersion}`);
|
|
52167
|
+
if (!path2) {
|
|
52168
|
+
warn2(`Could not find or download v${minVersion}. Continuing with v${binaryVersion}.`);
|
|
52169
|
+
return null;
|
|
52170
|
+
}
|
|
52171
|
+
const pool = getPool();
|
|
52172
|
+
if (!pool) {
|
|
52173
|
+
warn2(`Found/downloaded compatible binary at ${path2}, but bridge pool is not ready.`);
|
|
52174
|
+
return null;
|
|
52175
|
+
}
|
|
52176
|
+
log2(`Found/downloaded compatible binary at ${path2}. Replacing running bridges...`);
|
|
52177
|
+
const replaced = await pool.replaceBinary(path2);
|
|
52178
|
+
log2("Binary replaced successfully. New bridges will use the updated binary.");
|
|
52179
|
+
return replaced;
|
|
52180
|
+
} catch (err) {
|
|
52181
|
+
error2(`Auto-download failed: ${err.message}. Install manually: cargo install agent-file-tools@${minVersion}`);
|
|
51876
52182
|
return null;
|
|
52183
|
+
} finally {
|
|
52184
|
+
versionUpgradePromises.delete(minVersion);
|
|
51877
52185
|
}
|
|
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
|
-
}
|
|
52186
|
+
})();
|
|
52187
|
+
versionUpgradePromises.set(minVersion, upgradePromise);
|
|
52188
|
+
return upgradePromise;
|
|
51886
52189
|
};
|
|
51887
52190
|
}
|
|
51888
52191
|
var PLUGIN_VERSION = (() => {
|