@cortexkit/aft-opencode 0.57.1 → 0.57.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/entry/server.js +402 -92
- package/dist/index.js +402 -92
- package/dist/logger.d.ts +6 -0
- package/dist/logger.d.ts.map +1 -1
- package/dist/shared/status.d.ts +8 -0
- package/dist/shared/status.d.ts.map +1 -1
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/permissions.d.ts.map +1 -1
- package/dist/tui/v2-status.d.ts +7 -0
- package/dist/tui/v2-status.d.ts.map +1 -1
- package/package.json +8 -8
- package/src/logger.ts +13 -0
- package/src/shared/status.ts +9 -0
- package/src/tui/v2-status.ts +9 -2
- package/src/tui-compiled/v2-status.ts +9 -2
package/dist/entry/server.js
CHANGED
|
@@ -11966,17 +11966,17 @@ async function renameIfPresent(from, to) {
|
|
|
11966
11966
|
throw error;
|
|
11967
11967
|
}
|
|
11968
11968
|
}
|
|
11969
|
-
// ../../node_modules/.bun/@cortexkit+subc-client@0.
|
|
11969
|
+
// ../../node_modules/.bun/@cortexkit+subc-client@0.13.1/node_modules/@cortexkit/subc-client/dist/client.js
|
|
11970
11970
|
import { promises as fs3 } from "node:fs";
|
|
11971
11971
|
import { debuglog } from "node:util";
|
|
11972
11972
|
|
|
11973
|
-
// ../../node_modules/.bun/@cortexkit+subc-client@0.
|
|
11973
|
+
// ../../node_modules/.bun/@cortexkit+subc-client@0.13.1/node_modules/@cortexkit/subc-client/dist/auth.js
|
|
11974
11974
|
import { createHmac, randomBytes, timingSafeEqual } from "node:crypto";
|
|
11975
11975
|
|
|
11976
|
-
// ../../node_modules/.bun/@cortexkit+subc-client@0.
|
|
11976
|
+
// ../../node_modules/.bun/@cortexkit+subc-client@0.13.1/node_modules/@cortexkit/subc-client/dist/socket.js
|
|
11977
11977
|
import net from "node:net";
|
|
11978
11978
|
|
|
11979
|
-
// ../../node_modules/.bun/@cortexkit+subc-client@0.
|
|
11979
|
+
// ../../node_modules/.bun/@cortexkit+subc-client@0.13.1/node_modules/@cortexkit/subc-client/dist/envelope.js
|
|
11980
11980
|
var PROTOCOL_VERSION = 2;
|
|
11981
11981
|
var HEADER_LEN = 21;
|
|
11982
11982
|
var FROZEN_PREFIX_LEN = 5;
|
|
@@ -12018,7 +12018,7 @@ var FLAG_PRIORITY_SHIFT = 1;
|
|
|
12018
12018
|
var FLAG_LAST = 8;
|
|
12019
12019
|
var FLAG_ADMISSION_MASK = 48;
|
|
12020
12020
|
var FLAG_ADMISSION_SHIFT = 4;
|
|
12021
|
-
var FLAG_RESERVED_MASK =
|
|
12021
|
+
var FLAG_RESERVED_MASK = 0;
|
|
12022
12022
|
function buildFlags(binary, priority, last, admissionClass = AdmissionClass.Normal) {
|
|
12023
12023
|
let flags = 0;
|
|
12024
12024
|
if (binary)
|
|
@@ -12029,6 +12029,9 @@ function buildFlags(binary, priority, last, admissionClass = AdmissionClass.Norm
|
|
|
12029
12029
|
flags |= admissionClass << FLAG_ADMISSION_SHIFT;
|
|
12030
12030
|
return flags;
|
|
12031
12031
|
}
|
|
12032
|
+
function hasBinary(flags) {
|
|
12033
|
+
return (flags & FLAG_BINARY) !== 0;
|
|
12034
|
+
}
|
|
12032
12035
|
function encodeHeader(header) {
|
|
12033
12036
|
const buffer = new Uint8Array(HEADER_LEN);
|
|
12034
12037
|
const view = new DataView(buffer.buffer);
|
|
@@ -12145,7 +12148,7 @@ function encodeFrame(frame) {
|
|
|
12145
12148
|
return output;
|
|
12146
12149
|
}
|
|
12147
12150
|
|
|
12148
|
-
// ../../node_modules/.bun/@cortexkit+subc-client@0.
|
|
12151
|
+
// ../../node_modules/.bun/@cortexkit+subc-client@0.13.1/node_modules/@cortexkit/subc-client/dist/socket.js
|
|
12149
12152
|
class SocketClosedError extends Error {
|
|
12150
12153
|
}
|
|
12151
12154
|
|
|
@@ -12378,7 +12381,7 @@ class SubcSocket {
|
|
|
12378
12381
|
}
|
|
12379
12382
|
}
|
|
12380
12383
|
|
|
12381
|
-
// ../../node_modules/.bun/@cortexkit+subc-client@0.
|
|
12384
|
+
// ../../node_modules/.bun/@cortexkit+subc-client@0.13.1/node_modules/@cortexkit/subc-client/dist/auth.js
|
|
12382
12385
|
var NONCE_LEN = 32;
|
|
12383
12386
|
var MAX_AUTH_MESSAGE_LEN = 4096;
|
|
12384
12387
|
var SERVER_PROOF_DOMAIN = "subc-server-v1";
|
|
@@ -12452,7 +12455,7 @@ async function authenticateClient(sock, conn, deadlineMs) {
|
|
|
12452
12455
|
await writeMessage(sock, { client_auth: Array.from(clientAuth) }, deadlineMs);
|
|
12453
12456
|
}
|
|
12454
12457
|
|
|
12455
|
-
// ../../node_modules/.bun/@cortexkit+subc-client@0.
|
|
12458
|
+
// ../../node_modules/.bun/@cortexkit+subc-client@0.13.1/node_modules/@cortexkit/subc-client/dist/connection-file.js
|
|
12456
12459
|
import { promises as fs2 } from "node:fs";
|
|
12457
12460
|
var SCHEMA_VERSION = 1;
|
|
12458
12461
|
var MIN_KEY_LEN = 32;
|
|
@@ -12530,13 +12533,49 @@ async function readConnectionFile(path) {
|
|
|
12530
12533
|
return info;
|
|
12531
12534
|
}
|
|
12532
12535
|
|
|
12533
|
-
// ../../node_modules/.bun/@cortexkit+subc-client@0.
|
|
12536
|
+
// ../../node_modules/.bun/@cortexkit+subc-client@0.13.1/node_modules/@cortexkit/subc-client/dist/route-handle.js
|
|
12534
12537
|
var connectionToken = new WeakMap;
|
|
12538
|
+
var reverseRequests = new WeakMap;
|
|
12539
|
+
|
|
12540
|
+
class ReverseRequestRegistrationError extends Error {
|
|
12541
|
+
methodFamily;
|
|
12542
|
+
code = "reverse_request_capability_not_declared";
|
|
12543
|
+
constructor(methodFamily) {
|
|
12544
|
+
super(`reverse-request capability ${JSON.stringify(methodFamily)} was not registered before route.open`);
|
|
12545
|
+
this.methodFamily = methodFamily;
|
|
12546
|
+
this.name = "ReverseRequestRegistrationError";
|
|
12547
|
+
}
|
|
12548
|
+
}
|
|
12549
|
+
|
|
12550
|
+
class ReverseRequestRegistry {
|
|
12551
|
+
handlers = new Map;
|
|
12552
|
+
declaredFamilies = null;
|
|
12553
|
+
onRequest(methodFamily, handler) {
|
|
12554
|
+
if (!isMethodFamily(methodFamily)) {
|
|
12555
|
+
throw new TypeError(`reverse-request method family must be a capability identifier, got ${JSON.stringify(methodFamily)}`);
|
|
12556
|
+
}
|
|
12557
|
+
if (typeof handler !== "function")
|
|
12558
|
+
throw new TypeError("reverse-request handler must be a function");
|
|
12559
|
+
if (this.declaredFamilies && !this.declaredFamilies.has(methodFamily)) {
|
|
12560
|
+
throw new ReverseRequestRegistrationError(methodFamily);
|
|
12561
|
+
}
|
|
12562
|
+
this.handlers.set(methodFamily, handler);
|
|
12563
|
+
}
|
|
12564
|
+
capabilities() {
|
|
12565
|
+
return [...this.handlers.keys()].sort();
|
|
12566
|
+
}
|
|
12567
|
+
handler(methodFamily) {
|
|
12568
|
+
return this.handlers.get(methodFamily);
|
|
12569
|
+
}
|
|
12570
|
+
seal() {
|
|
12571
|
+
this.declaredFamilies ??= new Set(this.handlers.keys());
|
|
12572
|
+
}
|
|
12573
|
+
}
|
|
12535
12574
|
|
|
12536
12575
|
class RouteHandle {
|
|
12537
12576
|
channel;
|
|
12538
12577
|
epoch;
|
|
12539
|
-
constructor(channel, epoch, token) {
|
|
12578
|
+
constructor(channel, epoch, token, registry) {
|
|
12540
12579
|
if (!Number.isInteger(channel) || channel <= 0 || channel > 65535) {
|
|
12541
12580
|
throw new RangeError(`route channel must be an integer in 1..65535, got ${channel}`);
|
|
12542
12581
|
}
|
|
@@ -12545,16 +12584,27 @@ class RouteHandle {
|
|
|
12545
12584
|
}
|
|
12546
12585
|
this.channel = channel;
|
|
12547
12586
|
this.epoch = epoch;
|
|
12587
|
+
registry.seal();
|
|
12548
12588
|
connectionToken.set(this, token);
|
|
12589
|
+
reverseRequests.set(this, registry);
|
|
12549
12590
|
Object.freeze(this);
|
|
12550
12591
|
}
|
|
12551
|
-
|
|
12552
|
-
|
|
12592
|
+
onRequest(methodFamily, handler) {
|
|
12593
|
+
reverseRequests.get(this).onRequest(methodFamily, handler);
|
|
12594
|
+
}
|
|
12595
|
+
static create(channel, epoch, token, registry) {
|
|
12596
|
+
return new RouteHandle(channel, epoch, token, registry);
|
|
12553
12597
|
}
|
|
12554
12598
|
}
|
|
12555
|
-
function createRouteHandle(channel, epoch, token) {
|
|
12599
|
+
function createRouteHandle(channel, epoch, token, registry = new ReverseRequestRegistry) {
|
|
12556
12600
|
const factory = RouteHandle;
|
|
12557
|
-
return factory.create(channel, epoch, token);
|
|
12601
|
+
return factory.create(channel, epoch, token, registry);
|
|
12602
|
+
}
|
|
12603
|
+
function reverseRequestHandler(handle, methodFamily) {
|
|
12604
|
+
return reverseRequests.get(handle)?.handler(methodFamily);
|
|
12605
|
+
}
|
|
12606
|
+
function isMethodFamily(value) {
|
|
12607
|
+
return /^[a-z][a-z0-9]*(?:[._-][a-z0-9]+)*$/.test(value);
|
|
12558
12608
|
}
|
|
12559
12609
|
|
|
12560
12610
|
class StaleRouteHandleError extends Error {
|
|
@@ -12576,7 +12626,7 @@ function sameRouteHandle(left, right) {
|
|
|
12576
12626
|
return left === right;
|
|
12577
12627
|
}
|
|
12578
12628
|
|
|
12579
|
-
// ../../node_modules/.bun/@cortexkit+subc-client@0.
|
|
12629
|
+
// ../../node_modules/.bun/@cortexkit+subc-client@0.13.1/node_modules/@cortexkit/subc-client/dist/client.js
|
|
12580
12630
|
var debug = debuglog("subc-client");
|
|
12581
12631
|
var DEFAULT_HANDSHAKE_TIMEOUT_MS = 1e4;
|
|
12582
12632
|
var DEFAULT_REQUEST_TIMEOUT_MS = 30000;
|
|
@@ -12607,16 +12657,26 @@ class SubcCallError extends Error {
|
|
|
12607
12657
|
this.cause = cause;
|
|
12608
12658
|
this.name = "SubcCallError";
|
|
12609
12659
|
}
|
|
12660
|
+
get detail() {
|
|
12661
|
+
return this.cause instanceof SubcError ? this.cause.detail : undefined;
|
|
12662
|
+
}
|
|
12610
12663
|
}
|
|
12611
12664
|
|
|
12612
12665
|
class SubcError extends Error {
|
|
12613
12666
|
code;
|
|
12614
|
-
|
|
12667
|
+
detail;
|
|
12668
|
+
constructor(message, code, detail) {
|
|
12615
12669
|
super(message);
|
|
12616
12670
|
this.code = code;
|
|
12671
|
+
this.detail = detail;
|
|
12617
12672
|
}
|
|
12618
12673
|
}
|
|
12619
|
-
|
|
12674
|
+
function requireBinaryBody(body) {
|
|
12675
|
+
if (body instanceof Uint8Array)
|
|
12676
|
+
return body;
|
|
12677
|
+
const type = body === null ? "null" : Array.isArray(body) ? "array" : typeof body;
|
|
12678
|
+
throw new SubcError(`binary request body must be a Uint8Array; got ${type}`, "binary_body_required");
|
|
12679
|
+
}
|
|
12620
12680
|
class SubcClient {
|
|
12621
12681
|
sock;
|
|
12622
12682
|
currentConn;
|
|
@@ -12653,15 +12713,34 @@ class SubcClient {
|
|
|
12653
12713
|
const parsed = this.parseJson(reply);
|
|
12654
12714
|
return parsed.modules ?? [];
|
|
12655
12715
|
}
|
|
12716
|
+
async resolveProvider(capability) {
|
|
12717
|
+
const claimants = await this.resolveProviders(capability);
|
|
12718
|
+
if (claimants.length === 0) {
|
|
12719
|
+
throw new SubcError(`no catalog claimant for capability ${capability}`, "capability_unprovided");
|
|
12720
|
+
}
|
|
12721
|
+
if (claimants.length > 1) {
|
|
12722
|
+
throw new SubcError(`multiple catalog claimants for capability ${capability}: ${claimants.join(", ")}`, "capability_ambiguous");
|
|
12723
|
+
}
|
|
12724
|
+
return claimants[0];
|
|
12725
|
+
}
|
|
12726
|
+
async resolveProviders(capability) {
|
|
12727
|
+
if (!isValidCapabilityIdentifier(capability)) {
|
|
12728
|
+
throw new SubcError(`malformed capability identifier ${JSON.stringify(capability)}`, "invalid_capability_identifier");
|
|
12729
|
+
}
|
|
12730
|
+
const modules = await this.catalogList();
|
|
12731
|
+
return modules.filter((module) => module.capabilities?.provides.includes(capability) ?? false).map((module) => module.module_id).sort();
|
|
12732
|
+
}
|
|
12656
12733
|
async routeOpen(target, identity, opts = {}) {
|
|
12657
12734
|
const consumerIdentity = routeOpenConsumerIdentity(opts);
|
|
12658
|
-
const
|
|
12735
|
+
const reverseRequests = opts.reverseRequests ?? new ReverseRequestRegistry;
|
|
12736
|
+
reverseRequests.seal();
|
|
12737
|
+
const consumerCapabilities = reverseRequests.capabilities();
|
|
12659
12738
|
const body = this.encode({
|
|
12660
12739
|
op: "route.open",
|
|
12661
12740
|
target,
|
|
12662
12741
|
identity,
|
|
12663
12742
|
...consumerIdentity ? { consumer_identity: consumerIdentity } : {},
|
|
12664
|
-
...consumerCapabilities
|
|
12743
|
+
...consumerCapabilities.length > 0 ? { consumer_capabilities: consumerCapabilities } : {}
|
|
12665
12744
|
});
|
|
12666
12745
|
let installed = null;
|
|
12667
12746
|
const install = (frame) => {
|
|
@@ -12671,7 +12750,7 @@ class SubcClient {
|
|
|
12671
12750
|
if (typeof parsed.route_channel !== "number" || typeof parsed.route_epoch !== "number") {
|
|
12672
12751
|
throw new SubcError(`route.open returned no route handle: ${JSON.stringify(parsed)}`);
|
|
12673
12752
|
}
|
|
12674
|
-
installed = this.installRoute(parsed.route_channel, parsed.route_epoch);
|
|
12753
|
+
installed = this.installRoute(parsed.route_channel, parsed.route_epoch, reverseRequests);
|
|
12675
12754
|
return true;
|
|
12676
12755
|
};
|
|
12677
12756
|
const closeLateRoute = (frame) => {
|
|
@@ -12696,14 +12775,25 @@ class SubcClient {
|
|
|
12696
12775
|
}
|
|
12697
12776
|
async request(handle, body, opts = {}) {
|
|
12698
12777
|
this.assertLiveHandle(handle);
|
|
12699
|
-
const
|
|
12778
|
+
const binary = opts.binary ?? false;
|
|
12779
|
+
const bytes = binary ? requireBinaryBody(body) : body instanceof Uint8Array ? body : this.encode(body);
|
|
12700
12780
|
const priority = opts.priority ?? Priority.Interactive;
|
|
12701
12781
|
const admission = opts.admissionClass ?? AdmissionClass.Normal;
|
|
12702
|
-
const reply = await this.send(handle, bytes, priority, admission, opts.timeoutMs, opts.onProgress);
|
|
12703
|
-
return this.
|
|
12782
|
+
const reply = await this.send(handle, bytes, priority, admission, opts.timeoutMs, opts.onProgress, undefined, undefined, binary, opts.signal);
|
|
12783
|
+
return this.decodeReply(reply);
|
|
12704
12784
|
}
|
|
12705
12785
|
async call(moduleId, method, params, opts = {}) {
|
|
12786
|
+
if (opts.binary) {
|
|
12787
|
+
throw new SubcError("call() builds a JSON body and cannot send a binary request; use callBinary(moduleId, body, opts) with a Uint8Array", "binary_call_requires_call_binary");
|
|
12788
|
+
}
|
|
12706
12789
|
const body = params === undefined ? { method } : { method, params };
|
|
12790
|
+
return await this.managedCall(moduleId, body, opts);
|
|
12791
|
+
}
|
|
12792
|
+
async callBinary(moduleId, body, opts = {}) {
|
|
12793
|
+
const bytes = requireBinaryBody(body);
|
|
12794
|
+
return this.managedCall(moduleId, bytes, { ...opts, binary: true });
|
|
12795
|
+
}
|
|
12796
|
+
async managedCall(moduleId, body, opts) {
|
|
12707
12797
|
let retriedUnknownChannel = false;
|
|
12708
12798
|
for (;; ) {
|
|
12709
12799
|
const routeHandle = await this.cachedRouteHandle(moduleId, opts);
|
|
@@ -12781,6 +12871,22 @@ class SubcClient {
|
|
|
12781
12871
|
};
|
|
12782
12872
|
return { unsubscribe, closed };
|
|
12783
12873
|
}
|
|
12874
|
+
attachCancelSignal(signal, key, handle, corr, priority) {
|
|
12875
|
+
if (!handle)
|
|
12876
|
+
return;
|
|
12877
|
+
const emit = () => {
|
|
12878
|
+
if (!this.pending.has(key))
|
|
12879
|
+
return;
|
|
12880
|
+
try {
|
|
12881
|
+
this.cancel(handle, corr, priority);
|
|
12882
|
+
} catch {}
|
|
12883
|
+
};
|
|
12884
|
+
if (signal.aborted) {
|
|
12885
|
+
emit();
|
|
12886
|
+
return;
|
|
12887
|
+
}
|
|
12888
|
+
signal.addEventListener("abort", emit, { once: true });
|
|
12889
|
+
}
|
|
12784
12890
|
cancel(handle, corr, priority = Priority.Interactive) {
|
|
12785
12891
|
this.assertLiveHandle(handle);
|
|
12786
12892
|
const cancel = buildFrame(FrameType.Cancel, buildFlags(false, priority, false), handle.channel, handle.epoch, corr, EMPTY_BODY);
|
|
@@ -12821,7 +12927,7 @@ class SubcClient {
|
|
|
12821
12927
|
this.sendRouteGoodbye(handle);
|
|
12822
12928
|
}
|
|
12823
12929
|
async closeManagedRoute(target, identity, opts = {}) {
|
|
12824
|
-
const key = routeCacheKey(target, identity, routeOpenConsumerIdentity(opts));
|
|
12930
|
+
const key = routeCacheKey(target, identity, routeOpenConsumerIdentity(opts), (opts.reverseRequests ?? new ReverseRequestRegistry).capabilities());
|
|
12825
12931
|
const cached = this.routes.get(key);
|
|
12826
12932
|
if (!cached)
|
|
12827
12933
|
return;
|
|
@@ -12889,7 +12995,7 @@ class SubcClient {
|
|
|
12889
12995
|
async controlRpc(body, acceptFrame, onLateResponse) {
|
|
12890
12996
|
return this.send(null, body, Priority.Interactive, AdmissionClass.Normal, undefined, undefined, acceptFrame, onLateResponse);
|
|
12891
12997
|
}
|
|
12892
|
-
send(handle, body, priority, admission, timeoutMs, onProgress, acceptFrame, onLateResponse) {
|
|
12998
|
+
send(handle, body, priority, admission, timeoutMs, onProgress, acceptFrame, onLateResponse, binary = false, signal) {
|
|
12893
12999
|
if (handle)
|
|
12894
13000
|
this.assertLiveHandle(handle);
|
|
12895
13001
|
if (this.closedErr)
|
|
@@ -12903,7 +13009,7 @@ class SubcClient {
|
|
|
12903
13009
|
const key = pendingKey(handle, corr);
|
|
12904
13010
|
const channel = handle?.channel ?? 0;
|
|
12905
13011
|
const epoch = handle?.epoch ?? 0;
|
|
12906
|
-
const frame = buildFrame(FrameType.Request, buildFlags(
|
|
13012
|
+
const frame = buildFrame(FrameType.Request, buildFlags(binary, priority, false, admission), channel, epoch, corr, body);
|
|
12907
13013
|
return new Promise((resolve, reject) => {
|
|
12908
13014
|
const ms = timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
12909
13015
|
const pending = {
|
|
@@ -12917,6 +13023,8 @@ class SubcClient {
|
|
|
12917
13023
|
};
|
|
12918
13024
|
pending.timer = setTimeout(() => this.arbitrateTimeout(key, pending, channel, corr, ms), ms);
|
|
12919
13025
|
this.pending.set(key, pending);
|
|
13026
|
+
if (signal)
|
|
13027
|
+
this.attachCancelSignal(signal, key, handle, corr, priority);
|
|
12920
13028
|
writeBorrowed(this.sock, encodeFrame(frame), Date.now() + ms).catch((error) => {
|
|
12921
13029
|
const current = this.pending.get(key);
|
|
12922
13030
|
if (current)
|
|
@@ -12944,19 +13052,20 @@ class SubcClient {
|
|
|
12944
13052
|
setImmediate(arbitrate);
|
|
12945
13053
|
}
|
|
12946
13054
|
async managedRequest(handle, body, opts) {
|
|
12947
|
-
const
|
|
13055
|
+
const binary = opts.binary ?? false;
|
|
13056
|
+
const bytes = binary ? requireBinaryBody(body) : body instanceof Uint8Array ? body : this.encode(body);
|
|
12948
13057
|
const priority = opts.priority ?? Priority.Interactive;
|
|
12949
13058
|
const admission = opts.admissionClass ?? AdmissionClass.Normal;
|
|
12950
13059
|
try {
|
|
12951
|
-
const reply = await this.sendManaged(handle, bytes, priority, admission, opts.timeoutMs, opts.onProgress);
|
|
12952
|
-
return this.
|
|
13060
|
+
const reply = await this.sendManaged(handle, bytes, priority, admission, opts.timeoutMs, opts.onProgress, binary, opts.signal);
|
|
13061
|
+
return this.decodeReply(reply);
|
|
12953
13062
|
} catch (error) {
|
|
12954
13063
|
if (error instanceof SubcCallError)
|
|
12955
13064
|
throw error;
|
|
12956
13065
|
throw this.terminalCallError("managed call failed", error);
|
|
12957
13066
|
}
|
|
12958
13067
|
}
|
|
12959
|
-
sendManaged(handle, body, priority, admission, timeoutMs, onProgress) {
|
|
13068
|
+
sendManaged(handle, body, priority, admission, timeoutMs, onProgress, binary = false, signal) {
|
|
12960
13069
|
try {
|
|
12961
13070
|
this.assertLiveHandle(handle);
|
|
12962
13071
|
} catch (error) {
|
|
@@ -12972,7 +13081,7 @@ class SubcClient {
|
|
|
12972
13081
|
return Promise.reject(this.notSentCallError("request correlation allocator was exhausted", error));
|
|
12973
13082
|
}
|
|
12974
13083
|
const key = pendingKey(handle, corr);
|
|
12975
|
-
const frame = buildFrame(FrameType.Request, buildFlags(
|
|
13084
|
+
const frame = buildFrame(FrameType.Request, buildFlags(binary, priority, false, admission), handle.channel, handle.epoch, corr, body);
|
|
12976
13085
|
let handedToSocket = false;
|
|
12977
13086
|
const classifyFailure = (error) => {
|
|
12978
13087
|
if (!handedToSocket)
|
|
@@ -12994,6 +13103,8 @@ class SubcClient {
|
|
|
12994
13103
|
};
|
|
12995
13104
|
pending.timer = setTimeout(() => this.arbitrateTimeout(key, pending, handle.channel, corr, ms), ms);
|
|
12996
13105
|
this.pending.set(key, pending);
|
|
13106
|
+
if (signal)
|
|
13107
|
+
this.attachCancelSignal(signal, key, handle, corr, priority);
|
|
12997
13108
|
const write = writeTrackedBorrowed(this.sock, encodeFrame(frame), Date.now() + ms);
|
|
12998
13109
|
handedToSocket = write.queued;
|
|
12999
13110
|
write.completed.catch((error) => {
|
|
@@ -13010,7 +13121,9 @@ class SubcClient {
|
|
|
13010
13121
|
}
|
|
13011
13122
|
const target = { kind: opts.targetKind ?? this.opts.targetKind, module_id: moduleId };
|
|
13012
13123
|
const consumerIdentity = routeOpenConsumerIdentity(opts);
|
|
13013
|
-
const
|
|
13124
|
+
const reverseRequests = opts.reverseRequests ?? new ReverseRequestRegistry;
|
|
13125
|
+
reverseRequests.seal();
|
|
13126
|
+
const key = routeCacheKey(target, identity, consumerIdentity, reverseRequests.capabilities());
|
|
13014
13127
|
let cached = this.routes.get(key);
|
|
13015
13128
|
if (!cached) {
|
|
13016
13129
|
cached = {
|
|
@@ -13019,6 +13132,7 @@ class SubcClient {
|
|
|
13019
13132
|
target,
|
|
13020
13133
|
identity,
|
|
13021
13134
|
consumerIdentity,
|
|
13135
|
+
reverseRequests,
|
|
13022
13136
|
handle: null,
|
|
13023
13137
|
opening: null
|
|
13024
13138
|
};
|
|
@@ -13034,7 +13148,7 @@ class SubcClient {
|
|
|
13034
13148
|
return cached.opening;
|
|
13035
13149
|
}
|
|
13036
13150
|
async openCachedRoute(cached) {
|
|
13037
|
-
const routeRetryDeadline = Date.now() +
|
|
13151
|
+
const routeRetryDeadline = Date.now() + this.opts.routeOpenRetryDeadlineMs;
|
|
13038
13152
|
let routeRetryDelay = this.opts.reconnectBackoff.baseMs;
|
|
13039
13153
|
let routeRetryAttempt = 0;
|
|
13040
13154
|
for (;; ) {
|
|
@@ -13049,7 +13163,8 @@ class SubcClient {
|
|
|
13049
13163
|
return cached.handle;
|
|
13050
13164
|
try {
|
|
13051
13165
|
const handle = await this.routeOpen(cached.target, cached.identity, {
|
|
13052
|
-
consumerIdentity: cached.consumerIdentity ?? null
|
|
13166
|
+
consumerIdentity: cached.consumerIdentity ?? null,
|
|
13167
|
+
reverseRequests: cached.reverseRequests
|
|
13053
13168
|
});
|
|
13054
13169
|
if (cached.closed) {
|
|
13055
13170
|
this.liveRoutes.delete(handle.channel);
|
|
@@ -13071,12 +13186,12 @@ class SubcClient {
|
|
|
13071
13186
|
}
|
|
13072
13187
|
if (!this.closeStarted && error instanceof SubcError && isRetryableRouteOpenCode(error.code)) {
|
|
13073
13188
|
routeRetryAttempt += 1;
|
|
13074
|
-
if (
|
|
13189
|
+
if (Date.now() < routeRetryDeadline) {
|
|
13075
13190
|
await this.opts.sleep(routeRetryDelay);
|
|
13076
13191
|
routeRetryDelay = Math.min(routeRetryDelay * 2, this.opts.reconnectBackoff.capMs);
|
|
13077
13192
|
continue;
|
|
13078
13193
|
}
|
|
13079
|
-
throw this.notSentCallError(`route.open failed for module ${cached.moduleId}: ${error.code} (retry
|
|
13194
|
+
throw this.notSentCallError(`route.open failed for module ${cached.moduleId}: ${error.code} (retry deadline exhausted after ${routeRetryAttempt} attempts)`, error);
|
|
13080
13195
|
}
|
|
13081
13196
|
throw this.terminalCallError(`route.open failed for module ${cached.moduleId}`, error);
|
|
13082
13197
|
}
|
|
@@ -13188,20 +13303,34 @@ class SubcClient {
|
|
|
13188
13303
|
this.readLoop(opened.sock, this.generation);
|
|
13189
13304
|
}
|
|
13190
13305
|
async reopenCachedRoutes() {
|
|
13191
|
-
|
|
13192
|
-
|
|
13193
|
-
|
|
13194
|
-
if (cached
|
|
13195
|
-
|
|
13196
|
-
|
|
13197
|
-
|
|
13198
|
-
|
|
13199
|
-
if (cached.closed)
|
|
13200
|
-
this.liveRoutes.delete(handle.channel);
|
|
13201
|
-
this.sendRouteGoodbye(handle);
|
|
13306
|
+
const routeKeys = [...this.routes.keys()];
|
|
13307
|
+
for (const key of routeKeys) {
|
|
13308
|
+
const cached = this.routes.get(key);
|
|
13309
|
+
if (cached)
|
|
13310
|
+
cached.handle = null;
|
|
13311
|
+
}
|
|
13312
|
+
for (const key of routeKeys) {
|
|
13313
|
+
const cached = this.routes.get(key);
|
|
13314
|
+
if (!cached || cached.closed)
|
|
13202
13315
|
continue;
|
|
13316
|
+
try {
|
|
13317
|
+
const handle = await this.routeOpen(cached.target, cached.identity, {
|
|
13318
|
+
consumerIdentity: cached.consumerIdentity ?? null,
|
|
13319
|
+
reverseRequests: cached.reverseRequests
|
|
13320
|
+
});
|
|
13321
|
+
if (cached.closed) {
|
|
13322
|
+
this.liveRoutes.delete(handle.channel);
|
|
13323
|
+
this.sendRouteGoodbye(handle);
|
|
13324
|
+
continue;
|
|
13325
|
+
}
|
|
13326
|
+
cached.handle = handle;
|
|
13327
|
+
} catch (error) {
|
|
13328
|
+
if (isRouteOpenRefusal(error)) {
|
|
13329
|
+
this.routes.delete(key);
|
|
13330
|
+
continue;
|
|
13331
|
+
}
|
|
13332
|
+
throw error;
|
|
13203
13333
|
}
|
|
13204
|
-
cached.handle = handle;
|
|
13205
13334
|
}
|
|
13206
13335
|
}
|
|
13207
13336
|
timeoutMessage(channel, corr, ms) {
|
|
@@ -13259,6 +13388,10 @@ class SubcClient {
|
|
|
13259
13388
|
return;
|
|
13260
13389
|
}
|
|
13261
13390
|
}
|
|
13391
|
+
if (frame.header.ty === FrameType.Request && handle) {
|
|
13392
|
+
this.dispatchReverseRequest(frame, handle);
|
|
13393
|
+
return;
|
|
13394
|
+
}
|
|
13262
13395
|
const key = pendingKey(handle, frame.header.corr);
|
|
13263
13396
|
const pending = this.pending.get(key);
|
|
13264
13397
|
if (pending) {
|
|
@@ -13312,10 +13445,49 @@ class SubcClient {
|
|
|
13312
13445
|
rejectPending(key, pending, err) {
|
|
13313
13446
|
this.settle(key, pending, () => pending.reject(pending.classifyFailure?.(err) ?? err));
|
|
13314
13447
|
}
|
|
13448
|
+
dispatchReverseRequest(frame, handle) {
|
|
13449
|
+
const method = reverseRequestMethod(frame.body);
|
|
13450
|
+
const methodFamily = method?.split("/", 1)[0];
|
|
13451
|
+
const handler = methodFamily ? reverseRequestHandler(handle, methodFamily) : undefined;
|
|
13452
|
+
const sock = this.sock;
|
|
13453
|
+
const generation = this.generation;
|
|
13454
|
+
const reply = async () => {
|
|
13455
|
+
if (!handler || !method) {
|
|
13456
|
+
await this.sendReverseError(frame, handle, "reverse_request_unhandled", methodFamily ? `no reverse-request handler is registered for ${methodFamily}` : "reverse request has no valid method", sock, generation);
|
|
13457
|
+
return;
|
|
13458
|
+
}
|
|
13459
|
+
let body;
|
|
13460
|
+
try {
|
|
13461
|
+
body = await handler(frame.body, { corr: frame.header.corr, method });
|
|
13462
|
+
if (!(body instanceof Uint8Array)) {
|
|
13463
|
+
throw new TypeError("reverse-request handler must return a Uint8Array");
|
|
13464
|
+
}
|
|
13465
|
+
} catch (error) {
|
|
13466
|
+
await this.sendReverseError(frame, handle, "reverse_request_unhandled", error instanceof Error ? error.message : String(error), sock, generation);
|
|
13467
|
+
return;
|
|
13468
|
+
}
|
|
13469
|
+
await this.sendReverseReply(frame, handle, FrameType.Response, body, sock, generation);
|
|
13470
|
+
};
|
|
13471
|
+
reply().catch((error) => {
|
|
13472
|
+
if (this.sock === sock && this.generation === generation && !this.closeStarted) {
|
|
13473
|
+
debug("failed to answer reverse request: %s", causeMessage(error));
|
|
13474
|
+
}
|
|
13475
|
+
});
|
|
13476
|
+
}
|
|
13477
|
+
async sendReverseError(request, handle, code, message, sock, generation) {
|
|
13478
|
+
await this.sendReverseReply(request, handle, FrameType.Error, this.encode({ code, message }), sock, generation);
|
|
13479
|
+
}
|
|
13480
|
+
async sendReverseReply(request, handle, type, body, sock, generation) {
|
|
13481
|
+
if (this.sock !== sock || this.generation !== generation || !this.isLiveHandle(handle) || this.closeStarted || this.closedErr) {
|
|
13482
|
+
return;
|
|
13483
|
+
}
|
|
13484
|
+
const frame = buildFrame(type, buildFlags(false, Priority.Interactive, false), handle.channel, handle.epoch, request.header.corr, body);
|
|
13485
|
+
await writeBorrowed(sock, encodeFrame(frame), Date.now() + DEFAULT_REQUEST_TIMEOUT_MS);
|
|
13486
|
+
}
|
|
13315
13487
|
errorFromFrame(frame) {
|
|
13316
13488
|
try {
|
|
13317
13489
|
const parsed = JSON.parse(Buffer.from(frame.body).toString("utf8"));
|
|
13318
|
-
return new SubcError(parsed.message ?? "subc error", parsed.code);
|
|
13490
|
+
return new SubcError(parsed.message ?? "subc error", parsed.code, parsed.detail);
|
|
13319
13491
|
} catch {
|
|
13320
13492
|
return new SubcError(Buffer.from(frame.body).toString("utf8") || "subc error");
|
|
13321
13493
|
}
|
|
@@ -13360,8 +13532,8 @@ class SubcClient {
|
|
|
13360
13532
|
get droppedIngressFrames() {
|
|
13361
13533
|
return this.ingressEpochDropCount;
|
|
13362
13534
|
}
|
|
13363
|
-
installRoute(channel, epoch) {
|
|
13364
|
-
const handle = createRouteHandle(channel, epoch, this.connectionToken);
|
|
13535
|
+
installRoute(channel, epoch, reverseRequests = new ReverseRequestRegistry) {
|
|
13536
|
+
const handle = createRouteHandle(channel, epoch, this.connectionToken, reverseRequests);
|
|
13365
13537
|
this.liveRoutes.set(channel, handle);
|
|
13366
13538
|
return handle;
|
|
13367
13539
|
}
|
|
@@ -13398,6 +13570,9 @@ class SubcClient {
|
|
|
13398
13570
|
encode(value) {
|
|
13399
13571
|
return Buffer.from(JSON.stringify(value), "utf8");
|
|
13400
13572
|
}
|
|
13573
|
+
decodeReply(frame) {
|
|
13574
|
+
return hasBinary(frame.header.flags) ? frame.body : this.parseJson(frame);
|
|
13575
|
+
}
|
|
13401
13576
|
parseJson(frame) {
|
|
13402
13577
|
const b = frame.body;
|
|
13403
13578
|
return JSON.parse(Buffer.from(b.buffer, b.byteOffset, b.byteLength).toString("utf8"));
|
|
@@ -13417,7 +13592,12 @@ function isConsumerReconnectTransient(err) {
|
|
|
13417
13592
|
const code = errorCode(err);
|
|
13418
13593
|
return code === "ECONNREFUSED" || code === "ECONNRESET" || code === "EPIPE" || code === "ETIMEDOUT" || code === "ENOENT";
|
|
13419
13594
|
}
|
|
13595
|
+
function isRouteOpenRefusal(err) {
|
|
13596
|
+
return err instanceof SubcError && typeof err.code === "string";
|
|
13597
|
+
}
|
|
13420
13598
|
function isRetryableRouteOpenCode(code) {
|
|
13599
|
+
if (code === "capability_forbidden")
|
|
13600
|
+
return false;
|
|
13421
13601
|
return code === "unknown_module" || code === "module_reloading" || code === "module_warming" || code === "target_unavailable" || code === "module_timeout";
|
|
13422
13602
|
}
|
|
13423
13603
|
async function connectionFileExists(path) {
|
|
@@ -13436,14 +13616,35 @@ function normalizeConnectOptions(opts) {
|
|
|
13436
13616
|
targetKind: opts.targetKind ?? DEFAULT_MANAGED_TARGET_KIND,
|
|
13437
13617
|
reconnectBackoff: opts.reconnectBackoff ?? DEFAULT_RECONNECT_BACKOFF,
|
|
13438
13618
|
sleep: opts.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms))),
|
|
13619
|
+
routeOpenRetryDeadlineMs: opts.routeOpenRetryDeadlineMs ?? ROUTE_OPEN_RETRY_DEADLINE_MS,
|
|
13439
13620
|
timeoutArbitrationGraceMs: opts.timeoutArbitrationGraceMs ?? TIMEOUT_ARBITRATION_GRACE_MS,
|
|
13440
13621
|
livenessProbeWindowMs: opts.livenessProbeWindowMs ?? LIVENESS_PROBE_WINDOW_MS,
|
|
13441
13622
|
onControlPush: opts.onControlPush
|
|
13442
13623
|
};
|
|
13443
13624
|
}
|
|
13444
|
-
function
|
|
13625
|
+
function isValidCapabilityIdentifier(identifier) {
|
|
13626
|
+
if (/\s/u.test(identifier))
|
|
13627
|
+
return false;
|
|
13628
|
+
const separator = identifier.indexOf("/v");
|
|
13629
|
+
if (separator <= 0 || identifier.indexOf("/v", separator + 1) !== -1)
|
|
13630
|
+
return false;
|
|
13631
|
+
const name = identifier.slice(0, separator);
|
|
13632
|
+
const version = identifier.slice(separator + 2);
|
|
13633
|
+
if (new TextEncoder().encode(name).byteLength > 64 || version.length === 0)
|
|
13634
|
+
return false;
|
|
13635
|
+
if (!/^[a-z][a-z0-9-]*[a-z0-9]$/u.test(name) && !/^[a-z]$/u.test(name))
|
|
13636
|
+
return false;
|
|
13637
|
+
if (name.includes("--"))
|
|
13638
|
+
return false;
|
|
13639
|
+
if (!/^\d+$/u.test(version) || version.length > 1 && version.startsWith("0"))
|
|
13640
|
+
return false;
|
|
13641
|
+
const numericVersion = Number(version);
|
|
13642
|
+
return Number.isSafeInteger(numericVersion) && numericVersion >= 1 && numericVersion <= 4294967295;
|
|
13643
|
+
}
|
|
13644
|
+
function routeCacheKey(target, identity, consumerIdentity, consumerCapabilities) {
|
|
13445
13645
|
const consumerPart = consumerIdentity ? `${consumerIdentity.module_id}\x00${consumerIdentity.launch_nonce}` : "";
|
|
13446
|
-
|
|
13646
|
+
const capabilitiesPart = [...consumerCapabilities].sort().join("\x00");
|
|
13647
|
+
return `${target.kind}\x00${target.module_id}\x00${identity.project_root}\x00${identity.harness}\x00${identity.session}\x00${consumerPart}\x00${capabilitiesPart}`;
|
|
13447
13648
|
}
|
|
13448
13649
|
function routeOpenConsumerIdentity(opts = {}) {
|
|
13449
13650
|
if (opts.consumerIdentity !== undefined)
|
|
@@ -13470,6 +13671,14 @@ function causeMessage(cause) {
|
|
|
13470
13671
|
function pendingKey(handle, corr) {
|
|
13471
13672
|
return handle ? `${handle.channel}:${handle.epoch}:${corr}` : `0:0:${corr}`;
|
|
13472
13673
|
}
|
|
13674
|
+
function reverseRequestMethod(body) {
|
|
13675
|
+
try {
|
|
13676
|
+
const parsed = JSON.parse(Buffer.from(body).toString("utf8"));
|
|
13677
|
+
return typeof parsed.method === "string" && parsed.method.length > 0 ? parsed.method : undefined;
|
|
13678
|
+
} catch {
|
|
13679
|
+
return;
|
|
13680
|
+
}
|
|
13681
|
+
}
|
|
13473
13682
|
// ../aft-bridge/dist/subc-transport.js
|
|
13474
13683
|
import { existsSync as existsSync4, statSync as statSync3 } from "node:fs";
|
|
13475
13684
|
|
|
@@ -13957,8 +14166,16 @@ var AFT_MODULE_ID = "aft";
|
|
|
13957
14166
|
var MAX_CONSECUTIVE_TRANSPORT_FAILURES = 3;
|
|
13958
14167
|
var RECONNECT_RETRY_FLOOR_MS = 100;
|
|
13959
14168
|
var RECONNECT_RETRY_CAP_MS = 2000;
|
|
13960
|
-
var
|
|
13961
|
-
var
|
|
14169
|
+
var SUBC_DEFAULT_REQUEST_TIMEOUT_MS = 30000;
|
|
14170
|
+
var ROUTE_OPEN_RELOAD_WAIT_CEILING_MS = 45000;
|
|
14171
|
+
function reloadWaitExhaustedSuffix(callDeadlineMs) {
|
|
14172
|
+
if (callDeadlineMs > ROUTE_OPEN_RELOAD_WAIT_CEILING_MS) {
|
|
14173
|
+
const ceilingSeconds = ROUTE_OPEN_RELOAD_WAIT_CEILING_MS / 1000;
|
|
14174
|
+
return ` The AFT daemon module did not return within the ${ceilingSeconds}s reload-wait ceiling.`;
|
|
14175
|
+
}
|
|
14176
|
+
const seconds = Math.round(callDeadlineMs / 100) / 10;
|
|
14177
|
+
return ` The AFT daemon module did not return within this call's ${seconds}s deadline.`;
|
|
14178
|
+
}
|
|
13962
14179
|
var BG_STABLE_MS = 5000;
|
|
13963
14180
|
function reconnectBackoffMs(attempt) {
|
|
13964
14181
|
return Math.min(RECONNECT_RETRY_FLOOR_MS * 2 ** Math.min(attempt, 6), RECONNECT_RETRY_CAP_MS);
|
|
@@ -14267,14 +14484,15 @@ function isAbsentRootRouteError(err) {
|
|
|
14267
14484
|
function absentRootError(root) {
|
|
14268
14485
|
return new SubcError(`invalid route project root: project root does not exist: ${root}`, "config_divergence");
|
|
14269
14486
|
}
|
|
14270
|
-
function reloadWindowExhaustedError(error) {
|
|
14487
|
+
function reloadWindowExhaustedError(error, callDeadlineMs) {
|
|
14488
|
+
const suffix = reloadWaitExhaustedSuffix(callDeadlineMs);
|
|
14271
14489
|
if (error instanceof Error) {
|
|
14272
14490
|
try {
|
|
14273
|
-
error.message +=
|
|
14491
|
+
error.message += suffix;
|
|
14274
14492
|
return error;
|
|
14275
14493
|
} catch {}
|
|
14276
14494
|
}
|
|
14277
|
-
return new Error(`${String(error)}${
|
|
14495
|
+
return new Error(`${String(error)}${suffix}`);
|
|
14278
14496
|
}
|
|
14279
14497
|
function safeCloseRoute(client, route) {
|
|
14280
14498
|
try {
|
|
@@ -14879,18 +15097,20 @@ class SubcTransportPool {
|
|
|
14879
15097
|
throw error;
|
|
14880
15098
|
}
|
|
14881
15099
|
};
|
|
15100
|
+
const callDeadlineMs = timeoutMs ?? SUBC_DEFAULT_REQUEST_TIMEOUT_MS;
|
|
15101
|
+
const reloadWaitBudgetMs = Math.min(callDeadlineMs, ROUTE_OPEN_RELOAD_WAIT_CEILING_MS);
|
|
15102
|
+
let reloadWaitedMs = 0;
|
|
14882
15103
|
const openRouteAfterReloadWindow = async () => {
|
|
14883
|
-
let reloadWaitedMs = 0;
|
|
14884
15104
|
while (true) {
|
|
14885
15105
|
try {
|
|
14886
15106
|
return await openRoute();
|
|
14887
15107
|
} catch (error) {
|
|
14888
15108
|
if (!isRouteOpenReloadWindowError(error))
|
|
14889
15109
|
throw error;
|
|
14890
|
-
|
|
14891
|
-
|
|
14892
|
-
throw reloadWindowExhaustedError(error);
|
|
15110
|
+
if (reloadWaitedMs + this.nextRouteReopenDelayMs() >= reloadWaitBudgetMs) {
|
|
15111
|
+
throw reloadWindowExhaustedError(error, callDeadlineMs);
|
|
14893
15112
|
}
|
|
15113
|
+
const { delayMs, wait } = this.waitForRouteReopenBackoff();
|
|
14894
15114
|
reloadWaitedMs += delayMs;
|
|
14895
15115
|
await wait;
|
|
14896
15116
|
}
|
|
@@ -14936,7 +15156,8 @@ class SubcTransportPool {
|
|
|
14936
15156
|
};
|
|
14937
15157
|
abortSignal?.addEventListener("abort", onAbort, { once: true });
|
|
14938
15158
|
try {
|
|
14939
|
-
const
|
|
15159
|
+
const requestTimeoutMs = reloadWaitedMs > 0 ? callDeadlineMs - reloadWaitedMs : timeoutMs;
|
|
15160
|
+
const request = client.request(route, body, { timeoutMs: requestTimeoutMs, onProgress });
|
|
14940
15161
|
const reply = abortSignal ? await Promise.race([request, aborted]) : await request;
|
|
14941
15162
|
if (!this.isCurrentSession(key, record)) {
|
|
14942
15163
|
if (this.isReapInduced(record))
|
|
@@ -14953,28 +15174,41 @@ class SubcTransportPool {
|
|
|
14953
15174
|
}
|
|
14954
15175
|
};
|
|
14955
15176
|
let routeAndEntry = await openRouteAfterReloadWindow();
|
|
14956
|
-
|
|
14957
|
-
|
|
14958
|
-
|
|
14959
|
-
|
|
14960
|
-
|
|
14961
|
-
|
|
14962
|
-
clearRouteEntry(routeAndEntry.entry);
|
|
14963
|
-
await this.waitForRouteReopenBackoff().wait;
|
|
14964
|
-
routeAndEntry = await openRouteAfterReloadWindow();
|
|
14965
|
-
try {
|
|
14966
|
-
const reply = await requestOnRoute(routeAndEntry.route, routeAndEntry.entry);
|
|
15177
|
+
let reopened = false;
|
|
15178
|
+
let retriedAbsentRoute = false;
|
|
15179
|
+
while (true) {
|
|
15180
|
+
try {
|
|
15181
|
+
const reply = await requestOnRoute(routeAndEntry.route, routeAndEntry.entry);
|
|
15182
|
+
if (reopened)
|
|
14967
15183
|
this.resetRouteReopenBackoff();
|
|
14968
|
-
|
|
14969
|
-
|
|
14970
|
-
|
|
14971
|
-
|
|
14972
|
-
|
|
14973
|
-
|
|
15184
|
+
return reply;
|
|
15185
|
+
} catch (error) {
|
|
15186
|
+
if (this.isReapInduced(record))
|
|
15187
|
+
throw this.annotateReapError(error, record);
|
|
15188
|
+
const ownsRoute = this.isCurrentSession(key, record) && this.client === client;
|
|
15189
|
+
if (ownsRoute && isRouteRequestReloadRefusal(error)) {
|
|
15190
|
+
clearRouteEntry(routeAndEntry.entry);
|
|
15191
|
+
if (reloadWaitedMs + this.nextRouteReopenDelayMs() >= reloadWaitBudgetMs) {
|
|
15192
|
+
throw reloadWindowExhaustedError(error, callDeadlineMs);
|
|
15193
|
+
}
|
|
15194
|
+
const { delayMs, wait } = this.waitForRouteReopenBackoff();
|
|
15195
|
+
reloadWaitedMs += delayMs;
|
|
15196
|
+
await wait;
|
|
15197
|
+
routeAndEntry = await openRouteAfterReloadWindow();
|
|
15198
|
+
reopened = true;
|
|
15199
|
+
continue;
|
|
15200
|
+
}
|
|
15201
|
+
if (ownsRoute && !retriedAbsentRoute && isRouteProvenAbsentError(error)) {
|
|
15202
|
+
retriedAbsentRoute = true;
|
|
15203
|
+
clearRouteEntry(routeAndEntry.entry);
|
|
15204
|
+
await this.waitForRouteReopenBackoff().wait;
|
|
15205
|
+
routeAndEntry = await openRouteAfterReloadWindow();
|
|
15206
|
+
reopened = true;
|
|
15207
|
+
continue;
|
|
14974
15208
|
}
|
|
15209
|
+
handleRequestFailure(error, routeAndEntry.entry);
|
|
15210
|
+
throw error;
|
|
14975
15211
|
}
|
|
14976
|
-
handleRequestFailure(error, routeAndEntry.entry);
|
|
14977
|
-
throw error;
|
|
14978
15212
|
}
|
|
14979
15213
|
} catch (error) {
|
|
14980
15214
|
if (this.isReapInduced(record))
|
|
@@ -15003,6 +15237,11 @@ class SubcTransportPool {
|
|
|
15003
15237
|
this.routeReopenRetryMs = delayMs;
|
|
15004
15238
|
return { delayMs, wait: retry };
|
|
15005
15239
|
}
|
|
15240
|
+
nextRouteReopenDelayMs() {
|
|
15241
|
+
if (this.routeReopenRetry && this.routeReopenRetryMs !== null)
|
|
15242
|
+
return this.routeReopenRetryMs;
|
|
15243
|
+
return this.routeReopenRetryDelayMs;
|
|
15244
|
+
}
|
|
15006
15245
|
resetRouteReopenBackoff() {
|
|
15007
15246
|
this.routeReopenRetryDelayMs = RECONNECT_RETRY_FLOOR_MS;
|
|
15008
15247
|
}
|
|
@@ -15294,6 +15533,12 @@ function isRouteOpenReloadWindowError(error) {
|
|
|
15294
15533
|
const code = error.code;
|
|
15295
15534
|
return code === "module_reloading" || code === "module_warming" || code === "target_unavailable";
|
|
15296
15535
|
}
|
|
15536
|
+
function isRouteRequestReloadRefusal(error) {
|
|
15537
|
+
if (error instanceof SubcCallError) {
|
|
15538
|
+
return error.kind === "not_sent" && error.code === "module_reloading";
|
|
15539
|
+
}
|
|
15540
|
+
return error instanceof SubcError && error.code === "module_reloading";
|
|
15541
|
+
}
|
|
15297
15542
|
function hasEngineResponse(error) {
|
|
15298
15543
|
const response = error.response;
|
|
15299
15544
|
if (response !== null && typeof response === "object")
|
|
@@ -23322,6 +23567,13 @@ function sessionWarn(sessionId, message, data) {
|
|
|
23322
23567
|
function sessionError(sessionId, message, data) {
|
|
23323
23568
|
write("ERROR", message, data, sessionId);
|
|
23324
23569
|
}
|
|
23570
|
+
function flushLog() {
|
|
23571
|
+
if (flushTimer) {
|
|
23572
|
+
clearTimeout(flushTimer);
|
|
23573
|
+
flushTimer = null;
|
|
23574
|
+
}
|
|
23575
|
+
flush();
|
|
23576
|
+
}
|
|
23325
23577
|
var bridgeLogger = {
|
|
23326
23578
|
log(message, meta) {
|
|
23327
23579
|
sessionLog(meta?.sessionId, message);
|
|
@@ -42272,6 +42524,7 @@ function coerceAftStatus(response) {
|
|
|
42272
42524
|
},
|
|
42273
42525
|
compression: readCompression(response.compression),
|
|
42274
42526
|
status_bar: readStatusBar(response.status_bar),
|
|
42527
|
+
status_bar_values: readStatusBar(response.status_bar_values),
|
|
42275
42528
|
message: readString(response.message, "")
|
|
42276
42529
|
};
|
|
42277
42530
|
}
|
|
@@ -42615,14 +42868,13 @@ function isSystemTempPath(target) {
|
|
|
42615
42868
|
const normalizedTarget = normalizePath(target);
|
|
42616
42869
|
return systemTempRoots().some((root) => containsPath(normalizePath(root), normalizedTarget));
|
|
42617
42870
|
}
|
|
42618
|
-
function
|
|
42619
|
-
|
|
42620
|
-
|
|
42621
|
-
|
|
42871
|
+
async function isSessionOwnedBashArtifact(ctx, context, target) {
|
|
42872
|
+
try {
|
|
42873
|
+
const response = await callBridge(ctx, context, "bash_artifact_owned", { path: target });
|
|
42874
|
+
return response.success !== false && response.owned === true;
|
|
42875
|
+
} catch {
|
|
42622
42876
|
return false;
|
|
42623
|
-
|
|
42624
|
-
const segments = relative.split(/[/\\]+/);
|
|
42625
|
-
return segments.length === 4 && segments[1] === "bash-tasks";
|
|
42877
|
+
}
|
|
42626
42878
|
}
|
|
42627
42879
|
function windowsPath(p) {
|
|
42628
42880
|
if (process.platform !== "win32")
|
|
@@ -42686,7 +42938,7 @@ async function assertExternalDirectoryPermission(ctx, context, target, options)
|
|
|
42686
42938
|
}
|
|
42687
42939
|
if (isSystemTempPath(absoluteTarget))
|
|
42688
42940
|
return;
|
|
42689
|
-
if (options?.serverValidatedRead === true &&
|
|
42941
|
+
if (options?.serverValidatedRead === true && await isSessionOwnedBashArtifact(ctx, context, absoluteTarget)) {
|
|
42690
42942
|
return;
|
|
42691
42943
|
}
|
|
42692
42944
|
if (typeof context.ask !== "function")
|
|
@@ -43261,6 +43513,9 @@ var z4 = tool.schema;
|
|
|
43261
43513
|
var METADATA_PREVIEW_LIMIT = 30 * 1024;
|
|
43262
43514
|
var DEFAULT_HARD_TIMEOUT_MS = 30 * 60 * 1000;
|
|
43263
43515
|
var BASH_TRANSPORT_MARGIN_MS = 1e4;
|
|
43516
|
+
var ABORT_REGISTRATION_WAIT_MS = 5000;
|
|
43517
|
+
var ABORT_REGISTRATION_POLL_MS = 25;
|
|
43518
|
+
var ABORT_ATTEMPT_TIMEOUT_MS = 1000;
|
|
43264
43519
|
function resolveForegroundWaitMs(configured) {
|
|
43265
43520
|
const override = process.env.AFT_TEST_FOREGROUND_WAIT_MS;
|
|
43266
43521
|
if (override !== undefined) {
|
|
@@ -43274,20 +43529,75 @@ function orchestratedTransportTimeoutMs(blockToCompletion, wait, effectiveTimeou
|
|
|
43274
43529
|
const waitBudget = blockToCompletion || wait ? effectiveTimeout ?? DEFAULT_HARD_TIMEOUT_MS : foregroundWaitMs;
|
|
43275
43530
|
return waitBudget + BASH_TRANSPORT_MARGIN_MS;
|
|
43276
43531
|
}
|
|
43532
|
+
async function abortForegroundWhenRegistered(ctx, runtime, disposed) {
|
|
43533
|
+
const startedAt = Date.now();
|
|
43534
|
+
const deadline = startedAt + ABORT_REGISTRATION_WAIT_MS;
|
|
43535
|
+
const results = [];
|
|
43536
|
+
let attempts = 0;
|
|
43537
|
+
let lastResponse;
|
|
43538
|
+
let lastError;
|
|
43539
|
+
let outcome = "timed_out";
|
|
43540
|
+
while (Date.now() < deadline) {
|
|
43541
|
+
if (disposed()) {
|
|
43542
|
+
outcome = "call_settled";
|
|
43543
|
+
break;
|
|
43544
|
+
}
|
|
43545
|
+
attempts += 1;
|
|
43546
|
+
try {
|
|
43547
|
+
lastResponse = await callBashBridge(ctx, runtime, "bash_abort_inflight", {}, {
|
|
43548
|
+
transportTimeoutMs: Math.max(1, Math.min(ABORT_ATTEMPT_TIMEOUT_MS, deadline - Date.now()))
|
|
43549
|
+
});
|
|
43550
|
+
lastError = undefined;
|
|
43551
|
+
recordAbortAttempt(results, `killed=${String(lastResponse.killed)}`);
|
|
43552
|
+
if (typeof lastResponse.killed === "number" && lastResponse.killed > 0) {
|
|
43553
|
+
outcome = "killed";
|
|
43554
|
+
break;
|
|
43555
|
+
}
|
|
43556
|
+
} catch (error) {
|
|
43557
|
+
lastError = error instanceof Error ? error.message : String(error);
|
|
43558
|
+
recordAbortAttempt(results, `error=${lastError}`);
|
|
43559
|
+
}
|
|
43560
|
+
if (disposed()) {
|
|
43561
|
+
outcome = "call_settled";
|
|
43562
|
+
break;
|
|
43563
|
+
}
|
|
43564
|
+
if (Date.now() >= deadline)
|
|
43565
|
+
break;
|
|
43566
|
+
await sleep(Math.min(ABORT_REGISTRATION_POLL_MS, deadline - Date.now()));
|
|
43567
|
+
}
|
|
43568
|
+
sessionLog(runtime.sessionID, `[bash] foreground abort ${outcome}`, {
|
|
43569
|
+
attempts,
|
|
43570
|
+
elapsed_ms: Date.now() - startedAt,
|
|
43571
|
+
results,
|
|
43572
|
+
...results.length < attempts ? { results_omitted: attempts - results.length } : {},
|
|
43573
|
+
last_response: lastResponse,
|
|
43574
|
+
last_error: lastError
|
|
43575
|
+
});
|
|
43576
|
+
flushLog();
|
|
43577
|
+
}
|
|
43578
|
+
var ABORT_ATTEMPT_RESULTS_KEPT = 20;
|
|
43579
|
+
function recordAbortAttempt(results, result) {
|
|
43580
|
+
if (results.length < ABORT_ATTEMPT_RESULTS_KEPT)
|
|
43581
|
+
results.push(result);
|
|
43582
|
+
}
|
|
43277
43583
|
function listenForForegroundAbort(ctx, runtime, enabled) {
|
|
43278
43584
|
if (!enabled)
|
|
43279
43585
|
return () => {};
|
|
43280
43586
|
let fired = false;
|
|
43587
|
+
let disposed = false;
|
|
43281
43588
|
const onAbort = () => {
|
|
43282
43589
|
if (fired)
|
|
43283
43590
|
return;
|
|
43284
43591
|
fired = true;
|
|
43285
|
-
|
|
43592
|
+
abortForegroundWhenRegistered(ctx, runtime, () => disposed);
|
|
43286
43593
|
};
|
|
43287
43594
|
runtime.abort.addEventListener("abort", onAbort, { once: true });
|
|
43288
43595
|
if (runtime.abort.aborted)
|
|
43289
43596
|
onAbort();
|
|
43290
|
-
return () =>
|
|
43597
|
+
return () => {
|
|
43598
|
+
disposed = true;
|
|
43599
|
+
runtime.abort.removeEventListener("abort", onAbort);
|
|
43600
|
+
};
|
|
43291
43601
|
}
|
|
43292
43602
|
function userMessageDetachDescription(detachOnUserMessage) {
|
|
43293
43603
|
return detachOnUserMessage ? "A new user message detaches this wait. Set `bash.detach_on_user_message: false` to keep it blocking; even then, a message containing the literal `&detach` forces detachment, and the token is stripped before delivery and the rest of the message is preserved; a token-only message becomes `(requested background detach)`." : "Because `bash.detach_on_user_message` is false, a new user message leaves this wait blocking; include the literal `&detach` anywhere to force detachment, and the token is stripped before delivery and the rest of the message is preserved; a token-only message becomes `(requested background detach)`.";
|