@cortexkit/aft-opencode 0.57.0 → 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/index.js
CHANGED
|
@@ -10270,17 +10270,17 @@ async function renameIfPresent(from, to) {
|
|
|
10270
10270
|
throw error;
|
|
10271
10271
|
}
|
|
10272
10272
|
}
|
|
10273
|
-
// ../../node_modules/.bun/@cortexkit+subc-client@0.
|
|
10273
|
+
// ../../node_modules/.bun/@cortexkit+subc-client@0.13.1/node_modules/@cortexkit/subc-client/dist/client.js
|
|
10274
10274
|
import { promises as fs3 } from "node:fs";
|
|
10275
10275
|
import { debuglog } from "node:util";
|
|
10276
10276
|
|
|
10277
|
-
// ../../node_modules/.bun/@cortexkit+subc-client@0.
|
|
10277
|
+
// ../../node_modules/.bun/@cortexkit+subc-client@0.13.1/node_modules/@cortexkit/subc-client/dist/auth.js
|
|
10278
10278
|
import { createHmac, randomBytes, timingSafeEqual } from "node:crypto";
|
|
10279
10279
|
|
|
10280
|
-
// ../../node_modules/.bun/@cortexkit+subc-client@0.
|
|
10280
|
+
// ../../node_modules/.bun/@cortexkit+subc-client@0.13.1/node_modules/@cortexkit/subc-client/dist/socket.js
|
|
10281
10281
|
import net from "node:net";
|
|
10282
10282
|
|
|
10283
|
-
// ../../node_modules/.bun/@cortexkit+subc-client@0.
|
|
10283
|
+
// ../../node_modules/.bun/@cortexkit+subc-client@0.13.1/node_modules/@cortexkit/subc-client/dist/envelope.js
|
|
10284
10284
|
var PROTOCOL_VERSION = 2;
|
|
10285
10285
|
var HEADER_LEN = 21;
|
|
10286
10286
|
var FROZEN_PREFIX_LEN = 5;
|
|
@@ -10322,7 +10322,7 @@ var FLAG_PRIORITY_SHIFT = 1;
|
|
|
10322
10322
|
var FLAG_LAST = 8;
|
|
10323
10323
|
var FLAG_ADMISSION_MASK = 48;
|
|
10324
10324
|
var FLAG_ADMISSION_SHIFT = 4;
|
|
10325
|
-
var FLAG_RESERVED_MASK =
|
|
10325
|
+
var FLAG_RESERVED_MASK = 0;
|
|
10326
10326
|
function buildFlags(binary, priority, last, admissionClass = AdmissionClass.Normal) {
|
|
10327
10327
|
let flags = 0;
|
|
10328
10328
|
if (binary)
|
|
@@ -10333,6 +10333,9 @@ function buildFlags(binary, priority, last, admissionClass = AdmissionClass.Norm
|
|
|
10333
10333
|
flags |= admissionClass << FLAG_ADMISSION_SHIFT;
|
|
10334
10334
|
return flags;
|
|
10335
10335
|
}
|
|
10336
|
+
function hasBinary(flags) {
|
|
10337
|
+
return (flags & FLAG_BINARY) !== 0;
|
|
10338
|
+
}
|
|
10336
10339
|
function encodeHeader(header) {
|
|
10337
10340
|
const buffer = new Uint8Array(HEADER_LEN);
|
|
10338
10341
|
const view = new DataView(buffer.buffer);
|
|
@@ -10449,7 +10452,7 @@ function encodeFrame(frame) {
|
|
|
10449
10452
|
return output;
|
|
10450
10453
|
}
|
|
10451
10454
|
|
|
10452
|
-
// ../../node_modules/.bun/@cortexkit+subc-client@0.
|
|
10455
|
+
// ../../node_modules/.bun/@cortexkit+subc-client@0.13.1/node_modules/@cortexkit/subc-client/dist/socket.js
|
|
10453
10456
|
class SocketClosedError extends Error {
|
|
10454
10457
|
}
|
|
10455
10458
|
|
|
@@ -10682,7 +10685,7 @@ class SubcSocket {
|
|
|
10682
10685
|
}
|
|
10683
10686
|
}
|
|
10684
10687
|
|
|
10685
|
-
// ../../node_modules/.bun/@cortexkit+subc-client@0.
|
|
10688
|
+
// ../../node_modules/.bun/@cortexkit+subc-client@0.13.1/node_modules/@cortexkit/subc-client/dist/auth.js
|
|
10686
10689
|
var NONCE_LEN = 32;
|
|
10687
10690
|
var MAX_AUTH_MESSAGE_LEN = 4096;
|
|
10688
10691
|
var SERVER_PROOF_DOMAIN = "subc-server-v1";
|
|
@@ -10756,7 +10759,7 @@ async function authenticateClient(sock, conn, deadlineMs) {
|
|
|
10756
10759
|
await writeMessage(sock, { client_auth: Array.from(clientAuth) }, deadlineMs);
|
|
10757
10760
|
}
|
|
10758
10761
|
|
|
10759
|
-
// ../../node_modules/.bun/@cortexkit+subc-client@0.
|
|
10762
|
+
// ../../node_modules/.bun/@cortexkit+subc-client@0.13.1/node_modules/@cortexkit/subc-client/dist/connection-file.js
|
|
10760
10763
|
import { promises as fs2 } from "node:fs";
|
|
10761
10764
|
var SCHEMA_VERSION = 1;
|
|
10762
10765
|
var MIN_KEY_LEN = 32;
|
|
@@ -10834,13 +10837,49 @@ async function readConnectionFile(path) {
|
|
|
10834
10837
|
return info;
|
|
10835
10838
|
}
|
|
10836
10839
|
|
|
10837
|
-
// ../../node_modules/.bun/@cortexkit+subc-client@0.
|
|
10840
|
+
// ../../node_modules/.bun/@cortexkit+subc-client@0.13.1/node_modules/@cortexkit/subc-client/dist/route-handle.js
|
|
10838
10841
|
var connectionToken = new WeakMap;
|
|
10842
|
+
var reverseRequests = new WeakMap;
|
|
10843
|
+
|
|
10844
|
+
class ReverseRequestRegistrationError extends Error {
|
|
10845
|
+
methodFamily;
|
|
10846
|
+
code = "reverse_request_capability_not_declared";
|
|
10847
|
+
constructor(methodFamily) {
|
|
10848
|
+
super(`reverse-request capability ${JSON.stringify(methodFamily)} was not registered before route.open`);
|
|
10849
|
+
this.methodFamily = methodFamily;
|
|
10850
|
+
this.name = "ReverseRequestRegistrationError";
|
|
10851
|
+
}
|
|
10852
|
+
}
|
|
10853
|
+
|
|
10854
|
+
class ReverseRequestRegistry {
|
|
10855
|
+
handlers = new Map;
|
|
10856
|
+
declaredFamilies = null;
|
|
10857
|
+
onRequest(methodFamily, handler) {
|
|
10858
|
+
if (!isMethodFamily(methodFamily)) {
|
|
10859
|
+
throw new TypeError(`reverse-request method family must be a capability identifier, got ${JSON.stringify(methodFamily)}`);
|
|
10860
|
+
}
|
|
10861
|
+
if (typeof handler !== "function")
|
|
10862
|
+
throw new TypeError("reverse-request handler must be a function");
|
|
10863
|
+
if (this.declaredFamilies && !this.declaredFamilies.has(methodFamily)) {
|
|
10864
|
+
throw new ReverseRequestRegistrationError(methodFamily);
|
|
10865
|
+
}
|
|
10866
|
+
this.handlers.set(methodFamily, handler);
|
|
10867
|
+
}
|
|
10868
|
+
capabilities() {
|
|
10869
|
+
return [...this.handlers.keys()].sort();
|
|
10870
|
+
}
|
|
10871
|
+
handler(methodFamily) {
|
|
10872
|
+
return this.handlers.get(methodFamily);
|
|
10873
|
+
}
|
|
10874
|
+
seal() {
|
|
10875
|
+
this.declaredFamilies ??= new Set(this.handlers.keys());
|
|
10876
|
+
}
|
|
10877
|
+
}
|
|
10839
10878
|
|
|
10840
10879
|
class RouteHandle {
|
|
10841
10880
|
channel;
|
|
10842
10881
|
epoch;
|
|
10843
|
-
constructor(channel, epoch, token) {
|
|
10882
|
+
constructor(channel, epoch, token, registry) {
|
|
10844
10883
|
if (!Number.isInteger(channel) || channel <= 0 || channel > 65535) {
|
|
10845
10884
|
throw new RangeError(`route channel must be an integer in 1..65535, got ${channel}`);
|
|
10846
10885
|
}
|
|
@@ -10849,16 +10888,27 @@ class RouteHandle {
|
|
|
10849
10888
|
}
|
|
10850
10889
|
this.channel = channel;
|
|
10851
10890
|
this.epoch = epoch;
|
|
10891
|
+
registry.seal();
|
|
10852
10892
|
connectionToken.set(this, token);
|
|
10893
|
+
reverseRequests.set(this, registry);
|
|
10853
10894
|
Object.freeze(this);
|
|
10854
10895
|
}
|
|
10855
|
-
|
|
10856
|
-
|
|
10896
|
+
onRequest(methodFamily, handler) {
|
|
10897
|
+
reverseRequests.get(this).onRequest(methodFamily, handler);
|
|
10898
|
+
}
|
|
10899
|
+
static create(channel, epoch, token, registry) {
|
|
10900
|
+
return new RouteHandle(channel, epoch, token, registry);
|
|
10857
10901
|
}
|
|
10858
10902
|
}
|
|
10859
|
-
function createRouteHandle(channel, epoch, token) {
|
|
10903
|
+
function createRouteHandle(channel, epoch, token, registry = new ReverseRequestRegistry) {
|
|
10860
10904
|
const factory = RouteHandle;
|
|
10861
|
-
return factory.create(channel, epoch, token);
|
|
10905
|
+
return factory.create(channel, epoch, token, registry);
|
|
10906
|
+
}
|
|
10907
|
+
function reverseRequestHandler(handle, methodFamily) {
|
|
10908
|
+
return reverseRequests.get(handle)?.handler(methodFamily);
|
|
10909
|
+
}
|
|
10910
|
+
function isMethodFamily(value) {
|
|
10911
|
+
return /^[a-z][a-z0-9]*(?:[._-][a-z0-9]+)*$/.test(value);
|
|
10862
10912
|
}
|
|
10863
10913
|
|
|
10864
10914
|
class StaleRouteHandleError extends Error {
|
|
@@ -10880,7 +10930,7 @@ function sameRouteHandle(left, right) {
|
|
|
10880
10930
|
return left === right;
|
|
10881
10931
|
}
|
|
10882
10932
|
|
|
10883
|
-
// ../../node_modules/.bun/@cortexkit+subc-client@0.
|
|
10933
|
+
// ../../node_modules/.bun/@cortexkit+subc-client@0.13.1/node_modules/@cortexkit/subc-client/dist/client.js
|
|
10884
10934
|
var debug = debuglog("subc-client");
|
|
10885
10935
|
var DEFAULT_HANDSHAKE_TIMEOUT_MS = 1e4;
|
|
10886
10936
|
var DEFAULT_REQUEST_TIMEOUT_MS = 30000;
|
|
@@ -10911,16 +10961,26 @@ class SubcCallError extends Error {
|
|
|
10911
10961
|
this.cause = cause;
|
|
10912
10962
|
this.name = "SubcCallError";
|
|
10913
10963
|
}
|
|
10964
|
+
get detail() {
|
|
10965
|
+
return this.cause instanceof SubcError ? this.cause.detail : undefined;
|
|
10966
|
+
}
|
|
10914
10967
|
}
|
|
10915
10968
|
|
|
10916
10969
|
class SubcError extends Error {
|
|
10917
10970
|
code;
|
|
10918
|
-
|
|
10971
|
+
detail;
|
|
10972
|
+
constructor(message, code, detail) {
|
|
10919
10973
|
super(message);
|
|
10920
10974
|
this.code = code;
|
|
10975
|
+
this.detail = detail;
|
|
10921
10976
|
}
|
|
10922
10977
|
}
|
|
10923
|
-
|
|
10978
|
+
function requireBinaryBody(body) {
|
|
10979
|
+
if (body instanceof Uint8Array)
|
|
10980
|
+
return body;
|
|
10981
|
+
const type = body === null ? "null" : Array.isArray(body) ? "array" : typeof body;
|
|
10982
|
+
throw new SubcError(`binary request body must be a Uint8Array; got ${type}`, "binary_body_required");
|
|
10983
|
+
}
|
|
10924
10984
|
class SubcClient {
|
|
10925
10985
|
sock;
|
|
10926
10986
|
currentConn;
|
|
@@ -10957,15 +11017,34 @@ class SubcClient {
|
|
|
10957
11017
|
const parsed = this.parseJson(reply);
|
|
10958
11018
|
return parsed.modules ?? [];
|
|
10959
11019
|
}
|
|
11020
|
+
async resolveProvider(capability) {
|
|
11021
|
+
const claimants = await this.resolveProviders(capability);
|
|
11022
|
+
if (claimants.length === 0) {
|
|
11023
|
+
throw new SubcError(`no catalog claimant for capability ${capability}`, "capability_unprovided");
|
|
11024
|
+
}
|
|
11025
|
+
if (claimants.length > 1) {
|
|
11026
|
+
throw new SubcError(`multiple catalog claimants for capability ${capability}: ${claimants.join(", ")}`, "capability_ambiguous");
|
|
11027
|
+
}
|
|
11028
|
+
return claimants[0];
|
|
11029
|
+
}
|
|
11030
|
+
async resolveProviders(capability) {
|
|
11031
|
+
if (!isValidCapabilityIdentifier(capability)) {
|
|
11032
|
+
throw new SubcError(`malformed capability identifier ${JSON.stringify(capability)}`, "invalid_capability_identifier");
|
|
11033
|
+
}
|
|
11034
|
+
const modules = await this.catalogList();
|
|
11035
|
+
return modules.filter((module) => module.capabilities?.provides.includes(capability) ?? false).map((module) => module.module_id).sort();
|
|
11036
|
+
}
|
|
10960
11037
|
async routeOpen(target, identity, opts = {}) {
|
|
10961
11038
|
const consumerIdentity = routeOpenConsumerIdentity(opts);
|
|
10962
|
-
const
|
|
11039
|
+
const reverseRequests = opts.reverseRequests ?? new ReverseRequestRegistry;
|
|
11040
|
+
reverseRequests.seal();
|
|
11041
|
+
const consumerCapabilities = reverseRequests.capabilities();
|
|
10963
11042
|
const body = this.encode({
|
|
10964
11043
|
op: "route.open",
|
|
10965
11044
|
target,
|
|
10966
11045
|
identity,
|
|
10967
11046
|
...consumerIdentity ? { consumer_identity: consumerIdentity } : {},
|
|
10968
|
-
...consumerCapabilities
|
|
11047
|
+
...consumerCapabilities.length > 0 ? { consumer_capabilities: consumerCapabilities } : {}
|
|
10969
11048
|
});
|
|
10970
11049
|
let installed = null;
|
|
10971
11050
|
const install = (frame) => {
|
|
@@ -10975,7 +11054,7 @@ class SubcClient {
|
|
|
10975
11054
|
if (typeof parsed.route_channel !== "number" || typeof parsed.route_epoch !== "number") {
|
|
10976
11055
|
throw new SubcError(`route.open returned no route handle: ${JSON.stringify(parsed)}`);
|
|
10977
11056
|
}
|
|
10978
|
-
installed = this.installRoute(parsed.route_channel, parsed.route_epoch);
|
|
11057
|
+
installed = this.installRoute(parsed.route_channel, parsed.route_epoch, reverseRequests);
|
|
10979
11058
|
return true;
|
|
10980
11059
|
};
|
|
10981
11060
|
const closeLateRoute = (frame) => {
|
|
@@ -11000,14 +11079,25 @@ class SubcClient {
|
|
|
11000
11079
|
}
|
|
11001
11080
|
async request(handle, body, opts = {}) {
|
|
11002
11081
|
this.assertLiveHandle(handle);
|
|
11003
|
-
const
|
|
11082
|
+
const binary = opts.binary ?? false;
|
|
11083
|
+
const bytes = binary ? requireBinaryBody(body) : body instanceof Uint8Array ? body : this.encode(body);
|
|
11004
11084
|
const priority = opts.priority ?? Priority.Interactive;
|
|
11005
11085
|
const admission = opts.admissionClass ?? AdmissionClass.Normal;
|
|
11006
|
-
const reply = await this.send(handle, bytes, priority, admission, opts.timeoutMs, opts.onProgress);
|
|
11007
|
-
return this.
|
|
11086
|
+
const reply = await this.send(handle, bytes, priority, admission, opts.timeoutMs, opts.onProgress, undefined, undefined, binary, opts.signal);
|
|
11087
|
+
return this.decodeReply(reply);
|
|
11008
11088
|
}
|
|
11009
11089
|
async call(moduleId, method, params, opts = {}) {
|
|
11090
|
+
if (opts.binary) {
|
|
11091
|
+
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");
|
|
11092
|
+
}
|
|
11010
11093
|
const body = params === undefined ? { method } : { method, params };
|
|
11094
|
+
return await this.managedCall(moduleId, body, opts);
|
|
11095
|
+
}
|
|
11096
|
+
async callBinary(moduleId, body, opts = {}) {
|
|
11097
|
+
const bytes = requireBinaryBody(body);
|
|
11098
|
+
return this.managedCall(moduleId, bytes, { ...opts, binary: true });
|
|
11099
|
+
}
|
|
11100
|
+
async managedCall(moduleId, body, opts) {
|
|
11011
11101
|
let retriedUnknownChannel = false;
|
|
11012
11102
|
for (;; ) {
|
|
11013
11103
|
const routeHandle = await this.cachedRouteHandle(moduleId, opts);
|
|
@@ -11085,6 +11175,22 @@ class SubcClient {
|
|
|
11085
11175
|
};
|
|
11086
11176
|
return { unsubscribe, closed };
|
|
11087
11177
|
}
|
|
11178
|
+
attachCancelSignal(signal, key, handle, corr, priority) {
|
|
11179
|
+
if (!handle)
|
|
11180
|
+
return;
|
|
11181
|
+
const emit = () => {
|
|
11182
|
+
if (!this.pending.has(key))
|
|
11183
|
+
return;
|
|
11184
|
+
try {
|
|
11185
|
+
this.cancel(handle, corr, priority);
|
|
11186
|
+
} catch {}
|
|
11187
|
+
};
|
|
11188
|
+
if (signal.aborted) {
|
|
11189
|
+
emit();
|
|
11190
|
+
return;
|
|
11191
|
+
}
|
|
11192
|
+
signal.addEventListener("abort", emit, { once: true });
|
|
11193
|
+
}
|
|
11088
11194
|
cancel(handle, corr, priority = Priority.Interactive) {
|
|
11089
11195
|
this.assertLiveHandle(handle);
|
|
11090
11196
|
const cancel = buildFrame(FrameType.Cancel, buildFlags(false, priority, false), handle.channel, handle.epoch, corr, EMPTY_BODY);
|
|
@@ -11125,7 +11231,7 @@ class SubcClient {
|
|
|
11125
11231
|
this.sendRouteGoodbye(handle);
|
|
11126
11232
|
}
|
|
11127
11233
|
async closeManagedRoute(target, identity, opts = {}) {
|
|
11128
|
-
const key = routeCacheKey(target, identity, routeOpenConsumerIdentity(opts));
|
|
11234
|
+
const key = routeCacheKey(target, identity, routeOpenConsumerIdentity(opts), (opts.reverseRequests ?? new ReverseRequestRegistry).capabilities());
|
|
11129
11235
|
const cached = this.routes.get(key);
|
|
11130
11236
|
if (!cached)
|
|
11131
11237
|
return;
|
|
@@ -11193,7 +11299,7 @@ class SubcClient {
|
|
|
11193
11299
|
async controlRpc(body, acceptFrame, onLateResponse) {
|
|
11194
11300
|
return this.send(null, body, Priority.Interactive, AdmissionClass.Normal, undefined, undefined, acceptFrame, onLateResponse);
|
|
11195
11301
|
}
|
|
11196
|
-
send(handle, body, priority, admission, timeoutMs, onProgress, acceptFrame, onLateResponse) {
|
|
11302
|
+
send(handle, body, priority, admission, timeoutMs, onProgress, acceptFrame, onLateResponse, binary = false, signal) {
|
|
11197
11303
|
if (handle)
|
|
11198
11304
|
this.assertLiveHandle(handle);
|
|
11199
11305
|
if (this.closedErr)
|
|
@@ -11207,7 +11313,7 @@ class SubcClient {
|
|
|
11207
11313
|
const key = pendingKey(handle, corr);
|
|
11208
11314
|
const channel = handle?.channel ?? 0;
|
|
11209
11315
|
const epoch = handle?.epoch ?? 0;
|
|
11210
|
-
const frame = buildFrame(FrameType.Request, buildFlags(
|
|
11316
|
+
const frame = buildFrame(FrameType.Request, buildFlags(binary, priority, false, admission), channel, epoch, corr, body);
|
|
11211
11317
|
return new Promise((resolve, reject) => {
|
|
11212
11318
|
const ms = timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
11213
11319
|
const pending = {
|
|
@@ -11221,6 +11327,8 @@ class SubcClient {
|
|
|
11221
11327
|
};
|
|
11222
11328
|
pending.timer = setTimeout(() => this.arbitrateTimeout(key, pending, channel, corr, ms), ms);
|
|
11223
11329
|
this.pending.set(key, pending);
|
|
11330
|
+
if (signal)
|
|
11331
|
+
this.attachCancelSignal(signal, key, handle, corr, priority);
|
|
11224
11332
|
writeBorrowed(this.sock, encodeFrame(frame), Date.now() + ms).catch((error) => {
|
|
11225
11333
|
const current = this.pending.get(key);
|
|
11226
11334
|
if (current)
|
|
@@ -11248,19 +11356,20 @@ class SubcClient {
|
|
|
11248
11356
|
setImmediate(arbitrate);
|
|
11249
11357
|
}
|
|
11250
11358
|
async managedRequest(handle, body, opts) {
|
|
11251
|
-
const
|
|
11359
|
+
const binary = opts.binary ?? false;
|
|
11360
|
+
const bytes = binary ? requireBinaryBody(body) : body instanceof Uint8Array ? body : this.encode(body);
|
|
11252
11361
|
const priority = opts.priority ?? Priority.Interactive;
|
|
11253
11362
|
const admission = opts.admissionClass ?? AdmissionClass.Normal;
|
|
11254
11363
|
try {
|
|
11255
|
-
const reply = await this.sendManaged(handle, bytes, priority, admission, opts.timeoutMs, opts.onProgress);
|
|
11256
|
-
return this.
|
|
11364
|
+
const reply = await this.sendManaged(handle, bytes, priority, admission, opts.timeoutMs, opts.onProgress, binary, opts.signal);
|
|
11365
|
+
return this.decodeReply(reply);
|
|
11257
11366
|
} catch (error) {
|
|
11258
11367
|
if (error instanceof SubcCallError)
|
|
11259
11368
|
throw error;
|
|
11260
11369
|
throw this.terminalCallError("managed call failed", error);
|
|
11261
11370
|
}
|
|
11262
11371
|
}
|
|
11263
|
-
sendManaged(handle, body, priority, admission, timeoutMs, onProgress) {
|
|
11372
|
+
sendManaged(handle, body, priority, admission, timeoutMs, onProgress, binary = false, signal) {
|
|
11264
11373
|
try {
|
|
11265
11374
|
this.assertLiveHandle(handle);
|
|
11266
11375
|
} catch (error) {
|
|
@@ -11276,7 +11385,7 @@ class SubcClient {
|
|
|
11276
11385
|
return Promise.reject(this.notSentCallError("request correlation allocator was exhausted", error));
|
|
11277
11386
|
}
|
|
11278
11387
|
const key = pendingKey(handle, corr);
|
|
11279
|
-
const frame = buildFrame(FrameType.Request, buildFlags(
|
|
11388
|
+
const frame = buildFrame(FrameType.Request, buildFlags(binary, priority, false, admission), handle.channel, handle.epoch, corr, body);
|
|
11280
11389
|
let handedToSocket = false;
|
|
11281
11390
|
const classifyFailure = (error) => {
|
|
11282
11391
|
if (!handedToSocket)
|
|
@@ -11298,6 +11407,8 @@ class SubcClient {
|
|
|
11298
11407
|
};
|
|
11299
11408
|
pending.timer = setTimeout(() => this.arbitrateTimeout(key, pending, handle.channel, corr, ms), ms);
|
|
11300
11409
|
this.pending.set(key, pending);
|
|
11410
|
+
if (signal)
|
|
11411
|
+
this.attachCancelSignal(signal, key, handle, corr, priority);
|
|
11301
11412
|
const write = writeTrackedBorrowed(this.sock, encodeFrame(frame), Date.now() + ms);
|
|
11302
11413
|
handedToSocket = write.queued;
|
|
11303
11414
|
write.completed.catch((error) => {
|
|
@@ -11314,7 +11425,9 @@ class SubcClient {
|
|
|
11314
11425
|
}
|
|
11315
11426
|
const target = { kind: opts.targetKind ?? this.opts.targetKind, module_id: moduleId };
|
|
11316
11427
|
const consumerIdentity = routeOpenConsumerIdentity(opts);
|
|
11317
|
-
const
|
|
11428
|
+
const reverseRequests = opts.reverseRequests ?? new ReverseRequestRegistry;
|
|
11429
|
+
reverseRequests.seal();
|
|
11430
|
+
const key = routeCacheKey(target, identity, consumerIdentity, reverseRequests.capabilities());
|
|
11318
11431
|
let cached = this.routes.get(key);
|
|
11319
11432
|
if (!cached) {
|
|
11320
11433
|
cached = {
|
|
@@ -11323,6 +11436,7 @@ class SubcClient {
|
|
|
11323
11436
|
target,
|
|
11324
11437
|
identity,
|
|
11325
11438
|
consumerIdentity,
|
|
11439
|
+
reverseRequests,
|
|
11326
11440
|
handle: null,
|
|
11327
11441
|
opening: null
|
|
11328
11442
|
};
|
|
@@ -11338,7 +11452,7 @@ class SubcClient {
|
|
|
11338
11452
|
return cached.opening;
|
|
11339
11453
|
}
|
|
11340
11454
|
async openCachedRoute(cached) {
|
|
11341
|
-
const routeRetryDeadline = Date.now() +
|
|
11455
|
+
const routeRetryDeadline = Date.now() + this.opts.routeOpenRetryDeadlineMs;
|
|
11342
11456
|
let routeRetryDelay = this.opts.reconnectBackoff.baseMs;
|
|
11343
11457
|
let routeRetryAttempt = 0;
|
|
11344
11458
|
for (;; ) {
|
|
@@ -11353,7 +11467,8 @@ class SubcClient {
|
|
|
11353
11467
|
return cached.handle;
|
|
11354
11468
|
try {
|
|
11355
11469
|
const handle = await this.routeOpen(cached.target, cached.identity, {
|
|
11356
|
-
consumerIdentity: cached.consumerIdentity ?? null
|
|
11470
|
+
consumerIdentity: cached.consumerIdentity ?? null,
|
|
11471
|
+
reverseRequests: cached.reverseRequests
|
|
11357
11472
|
});
|
|
11358
11473
|
if (cached.closed) {
|
|
11359
11474
|
this.liveRoutes.delete(handle.channel);
|
|
@@ -11375,12 +11490,12 @@ class SubcClient {
|
|
|
11375
11490
|
}
|
|
11376
11491
|
if (!this.closeStarted && error instanceof SubcError && isRetryableRouteOpenCode(error.code)) {
|
|
11377
11492
|
routeRetryAttempt += 1;
|
|
11378
|
-
if (
|
|
11493
|
+
if (Date.now() < routeRetryDeadline) {
|
|
11379
11494
|
await this.opts.sleep(routeRetryDelay);
|
|
11380
11495
|
routeRetryDelay = Math.min(routeRetryDelay * 2, this.opts.reconnectBackoff.capMs);
|
|
11381
11496
|
continue;
|
|
11382
11497
|
}
|
|
11383
|
-
throw this.notSentCallError(`route.open failed for module ${cached.moduleId}: ${error.code} (retry
|
|
11498
|
+
throw this.notSentCallError(`route.open failed for module ${cached.moduleId}: ${error.code} (retry deadline exhausted after ${routeRetryAttempt} attempts)`, error);
|
|
11384
11499
|
}
|
|
11385
11500
|
throw this.terminalCallError(`route.open failed for module ${cached.moduleId}`, error);
|
|
11386
11501
|
}
|
|
@@ -11492,20 +11607,34 @@ class SubcClient {
|
|
|
11492
11607
|
this.readLoop(opened.sock, this.generation);
|
|
11493
11608
|
}
|
|
11494
11609
|
async reopenCachedRoutes() {
|
|
11495
|
-
|
|
11496
|
-
|
|
11497
|
-
|
|
11498
|
-
if (cached
|
|
11499
|
-
|
|
11500
|
-
|
|
11501
|
-
|
|
11502
|
-
|
|
11503
|
-
if (cached.closed)
|
|
11504
|
-
this.liveRoutes.delete(handle.channel);
|
|
11505
|
-
this.sendRouteGoodbye(handle);
|
|
11610
|
+
const routeKeys = [...this.routes.keys()];
|
|
11611
|
+
for (const key of routeKeys) {
|
|
11612
|
+
const cached = this.routes.get(key);
|
|
11613
|
+
if (cached)
|
|
11614
|
+
cached.handle = null;
|
|
11615
|
+
}
|
|
11616
|
+
for (const key of routeKeys) {
|
|
11617
|
+
const cached = this.routes.get(key);
|
|
11618
|
+
if (!cached || cached.closed)
|
|
11506
11619
|
continue;
|
|
11620
|
+
try {
|
|
11621
|
+
const handle = await this.routeOpen(cached.target, cached.identity, {
|
|
11622
|
+
consumerIdentity: cached.consumerIdentity ?? null,
|
|
11623
|
+
reverseRequests: cached.reverseRequests
|
|
11624
|
+
});
|
|
11625
|
+
if (cached.closed) {
|
|
11626
|
+
this.liveRoutes.delete(handle.channel);
|
|
11627
|
+
this.sendRouteGoodbye(handle);
|
|
11628
|
+
continue;
|
|
11629
|
+
}
|
|
11630
|
+
cached.handle = handle;
|
|
11631
|
+
} catch (error) {
|
|
11632
|
+
if (isRouteOpenRefusal(error)) {
|
|
11633
|
+
this.routes.delete(key);
|
|
11634
|
+
continue;
|
|
11635
|
+
}
|
|
11636
|
+
throw error;
|
|
11507
11637
|
}
|
|
11508
|
-
cached.handle = handle;
|
|
11509
11638
|
}
|
|
11510
11639
|
}
|
|
11511
11640
|
timeoutMessage(channel, corr, ms) {
|
|
@@ -11563,6 +11692,10 @@ class SubcClient {
|
|
|
11563
11692
|
return;
|
|
11564
11693
|
}
|
|
11565
11694
|
}
|
|
11695
|
+
if (frame.header.ty === FrameType.Request && handle) {
|
|
11696
|
+
this.dispatchReverseRequest(frame, handle);
|
|
11697
|
+
return;
|
|
11698
|
+
}
|
|
11566
11699
|
const key = pendingKey(handle, frame.header.corr);
|
|
11567
11700
|
const pending = this.pending.get(key);
|
|
11568
11701
|
if (pending) {
|
|
@@ -11616,10 +11749,49 @@ class SubcClient {
|
|
|
11616
11749
|
rejectPending(key, pending, err) {
|
|
11617
11750
|
this.settle(key, pending, () => pending.reject(pending.classifyFailure?.(err) ?? err));
|
|
11618
11751
|
}
|
|
11752
|
+
dispatchReverseRequest(frame, handle) {
|
|
11753
|
+
const method = reverseRequestMethod(frame.body);
|
|
11754
|
+
const methodFamily = method?.split("/", 1)[0];
|
|
11755
|
+
const handler = methodFamily ? reverseRequestHandler(handle, methodFamily) : undefined;
|
|
11756
|
+
const sock = this.sock;
|
|
11757
|
+
const generation = this.generation;
|
|
11758
|
+
const reply = async () => {
|
|
11759
|
+
if (!handler || !method) {
|
|
11760
|
+
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);
|
|
11761
|
+
return;
|
|
11762
|
+
}
|
|
11763
|
+
let body;
|
|
11764
|
+
try {
|
|
11765
|
+
body = await handler(frame.body, { corr: frame.header.corr, method });
|
|
11766
|
+
if (!(body instanceof Uint8Array)) {
|
|
11767
|
+
throw new TypeError("reverse-request handler must return a Uint8Array");
|
|
11768
|
+
}
|
|
11769
|
+
} catch (error) {
|
|
11770
|
+
await this.sendReverseError(frame, handle, "reverse_request_unhandled", error instanceof Error ? error.message : String(error), sock, generation);
|
|
11771
|
+
return;
|
|
11772
|
+
}
|
|
11773
|
+
await this.sendReverseReply(frame, handle, FrameType.Response, body, sock, generation);
|
|
11774
|
+
};
|
|
11775
|
+
reply().catch((error) => {
|
|
11776
|
+
if (this.sock === sock && this.generation === generation && !this.closeStarted) {
|
|
11777
|
+
debug("failed to answer reverse request: %s", causeMessage(error));
|
|
11778
|
+
}
|
|
11779
|
+
});
|
|
11780
|
+
}
|
|
11781
|
+
async sendReverseError(request, handle, code, message, sock, generation) {
|
|
11782
|
+
await this.sendReverseReply(request, handle, FrameType.Error, this.encode({ code, message }), sock, generation);
|
|
11783
|
+
}
|
|
11784
|
+
async sendReverseReply(request, handle, type, body, sock, generation) {
|
|
11785
|
+
if (this.sock !== sock || this.generation !== generation || !this.isLiveHandle(handle) || this.closeStarted || this.closedErr) {
|
|
11786
|
+
return;
|
|
11787
|
+
}
|
|
11788
|
+
const frame = buildFrame(type, buildFlags(false, Priority.Interactive, false), handle.channel, handle.epoch, request.header.corr, body);
|
|
11789
|
+
await writeBorrowed(sock, encodeFrame(frame), Date.now() + DEFAULT_REQUEST_TIMEOUT_MS);
|
|
11790
|
+
}
|
|
11619
11791
|
errorFromFrame(frame) {
|
|
11620
11792
|
try {
|
|
11621
11793
|
const parsed = JSON.parse(Buffer.from(frame.body).toString("utf8"));
|
|
11622
|
-
return new SubcError(parsed.message ?? "subc error", parsed.code);
|
|
11794
|
+
return new SubcError(parsed.message ?? "subc error", parsed.code, parsed.detail);
|
|
11623
11795
|
} catch {
|
|
11624
11796
|
return new SubcError(Buffer.from(frame.body).toString("utf8") || "subc error");
|
|
11625
11797
|
}
|
|
@@ -11664,8 +11836,8 @@ class SubcClient {
|
|
|
11664
11836
|
get droppedIngressFrames() {
|
|
11665
11837
|
return this.ingressEpochDropCount;
|
|
11666
11838
|
}
|
|
11667
|
-
installRoute(channel, epoch) {
|
|
11668
|
-
const handle = createRouteHandle(channel, epoch, this.connectionToken);
|
|
11839
|
+
installRoute(channel, epoch, reverseRequests = new ReverseRequestRegistry) {
|
|
11840
|
+
const handle = createRouteHandle(channel, epoch, this.connectionToken, reverseRequests);
|
|
11669
11841
|
this.liveRoutes.set(channel, handle);
|
|
11670
11842
|
return handle;
|
|
11671
11843
|
}
|
|
@@ -11702,6 +11874,9 @@ class SubcClient {
|
|
|
11702
11874
|
encode(value) {
|
|
11703
11875
|
return Buffer.from(JSON.stringify(value), "utf8");
|
|
11704
11876
|
}
|
|
11877
|
+
decodeReply(frame) {
|
|
11878
|
+
return hasBinary(frame.header.flags) ? frame.body : this.parseJson(frame);
|
|
11879
|
+
}
|
|
11705
11880
|
parseJson(frame) {
|
|
11706
11881
|
const b = frame.body;
|
|
11707
11882
|
return JSON.parse(Buffer.from(b.buffer, b.byteOffset, b.byteLength).toString("utf8"));
|
|
@@ -11721,7 +11896,12 @@ function isConsumerReconnectTransient(err) {
|
|
|
11721
11896
|
const code = errorCode(err);
|
|
11722
11897
|
return code === "ECONNREFUSED" || code === "ECONNRESET" || code === "EPIPE" || code === "ETIMEDOUT" || code === "ENOENT";
|
|
11723
11898
|
}
|
|
11899
|
+
function isRouteOpenRefusal(err) {
|
|
11900
|
+
return err instanceof SubcError && typeof err.code === "string";
|
|
11901
|
+
}
|
|
11724
11902
|
function isRetryableRouteOpenCode(code) {
|
|
11903
|
+
if (code === "capability_forbidden")
|
|
11904
|
+
return false;
|
|
11725
11905
|
return code === "unknown_module" || code === "module_reloading" || code === "module_warming" || code === "target_unavailable" || code === "module_timeout";
|
|
11726
11906
|
}
|
|
11727
11907
|
async function connectionFileExists(path) {
|
|
@@ -11740,14 +11920,35 @@ function normalizeConnectOptions(opts) {
|
|
|
11740
11920
|
targetKind: opts.targetKind ?? DEFAULT_MANAGED_TARGET_KIND,
|
|
11741
11921
|
reconnectBackoff: opts.reconnectBackoff ?? DEFAULT_RECONNECT_BACKOFF,
|
|
11742
11922
|
sleep: opts.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms))),
|
|
11923
|
+
routeOpenRetryDeadlineMs: opts.routeOpenRetryDeadlineMs ?? ROUTE_OPEN_RETRY_DEADLINE_MS,
|
|
11743
11924
|
timeoutArbitrationGraceMs: opts.timeoutArbitrationGraceMs ?? TIMEOUT_ARBITRATION_GRACE_MS,
|
|
11744
11925
|
livenessProbeWindowMs: opts.livenessProbeWindowMs ?? LIVENESS_PROBE_WINDOW_MS,
|
|
11745
11926
|
onControlPush: opts.onControlPush
|
|
11746
11927
|
};
|
|
11747
11928
|
}
|
|
11748
|
-
function
|
|
11929
|
+
function isValidCapabilityIdentifier(identifier) {
|
|
11930
|
+
if (/\s/u.test(identifier))
|
|
11931
|
+
return false;
|
|
11932
|
+
const separator = identifier.indexOf("/v");
|
|
11933
|
+
if (separator <= 0 || identifier.indexOf("/v", separator + 1) !== -1)
|
|
11934
|
+
return false;
|
|
11935
|
+
const name = identifier.slice(0, separator);
|
|
11936
|
+
const version = identifier.slice(separator + 2);
|
|
11937
|
+
if (new TextEncoder().encode(name).byteLength > 64 || version.length === 0)
|
|
11938
|
+
return false;
|
|
11939
|
+
if (!/^[a-z][a-z0-9-]*[a-z0-9]$/u.test(name) && !/^[a-z]$/u.test(name))
|
|
11940
|
+
return false;
|
|
11941
|
+
if (name.includes("--"))
|
|
11942
|
+
return false;
|
|
11943
|
+
if (!/^\d+$/u.test(version) || version.length > 1 && version.startsWith("0"))
|
|
11944
|
+
return false;
|
|
11945
|
+
const numericVersion = Number(version);
|
|
11946
|
+
return Number.isSafeInteger(numericVersion) && numericVersion >= 1 && numericVersion <= 4294967295;
|
|
11947
|
+
}
|
|
11948
|
+
function routeCacheKey(target, identity, consumerIdentity, consumerCapabilities) {
|
|
11749
11949
|
const consumerPart = consumerIdentity ? `${consumerIdentity.module_id}\x00${consumerIdentity.launch_nonce}` : "";
|
|
11750
|
-
|
|
11950
|
+
const capabilitiesPart = [...consumerCapabilities].sort().join("\x00");
|
|
11951
|
+
return `${target.kind}\x00${target.module_id}\x00${identity.project_root}\x00${identity.harness}\x00${identity.session}\x00${consumerPart}\x00${capabilitiesPart}`;
|
|
11751
11952
|
}
|
|
11752
11953
|
function routeOpenConsumerIdentity(opts = {}) {
|
|
11753
11954
|
if (opts.consumerIdentity !== undefined)
|
|
@@ -11774,6 +11975,14 @@ function causeMessage(cause) {
|
|
|
11774
11975
|
function pendingKey(handle, corr) {
|
|
11775
11976
|
return handle ? `${handle.channel}:${handle.epoch}:${corr}` : `0:0:${corr}`;
|
|
11776
11977
|
}
|
|
11978
|
+
function reverseRequestMethod(body) {
|
|
11979
|
+
try {
|
|
11980
|
+
const parsed = JSON.parse(Buffer.from(body).toString("utf8"));
|
|
11981
|
+
return typeof parsed.method === "string" && parsed.method.length > 0 ? parsed.method : undefined;
|
|
11982
|
+
} catch {
|
|
11983
|
+
return;
|
|
11984
|
+
}
|
|
11985
|
+
}
|
|
11777
11986
|
// ../aft-bridge/dist/subc-transport.js
|
|
11778
11987
|
import { existsSync as existsSync4, statSync as statSync3 } from "node:fs";
|
|
11779
11988
|
|
|
@@ -12261,8 +12470,16 @@ var AFT_MODULE_ID = "aft";
|
|
|
12261
12470
|
var MAX_CONSECUTIVE_TRANSPORT_FAILURES = 3;
|
|
12262
12471
|
var RECONNECT_RETRY_FLOOR_MS = 100;
|
|
12263
12472
|
var RECONNECT_RETRY_CAP_MS = 2000;
|
|
12264
|
-
var
|
|
12265
|
-
var
|
|
12473
|
+
var SUBC_DEFAULT_REQUEST_TIMEOUT_MS = 30000;
|
|
12474
|
+
var ROUTE_OPEN_RELOAD_WAIT_CEILING_MS = 45000;
|
|
12475
|
+
function reloadWaitExhaustedSuffix(callDeadlineMs) {
|
|
12476
|
+
if (callDeadlineMs > ROUTE_OPEN_RELOAD_WAIT_CEILING_MS) {
|
|
12477
|
+
const ceilingSeconds = ROUTE_OPEN_RELOAD_WAIT_CEILING_MS / 1000;
|
|
12478
|
+
return ` The AFT daemon module did not return within the ${ceilingSeconds}s reload-wait ceiling.`;
|
|
12479
|
+
}
|
|
12480
|
+
const seconds = Math.round(callDeadlineMs / 100) / 10;
|
|
12481
|
+
return ` The AFT daemon module did not return within this call's ${seconds}s deadline.`;
|
|
12482
|
+
}
|
|
12266
12483
|
var BG_STABLE_MS = 5000;
|
|
12267
12484
|
function reconnectBackoffMs(attempt) {
|
|
12268
12485
|
return Math.min(RECONNECT_RETRY_FLOOR_MS * 2 ** Math.min(attempt, 6), RECONNECT_RETRY_CAP_MS);
|
|
@@ -12571,14 +12788,15 @@ function isAbsentRootRouteError(err) {
|
|
|
12571
12788
|
function absentRootError(root) {
|
|
12572
12789
|
return new SubcError(`invalid route project root: project root does not exist: ${root}`, "config_divergence");
|
|
12573
12790
|
}
|
|
12574
|
-
function reloadWindowExhaustedError(error) {
|
|
12791
|
+
function reloadWindowExhaustedError(error, callDeadlineMs) {
|
|
12792
|
+
const suffix = reloadWaitExhaustedSuffix(callDeadlineMs);
|
|
12575
12793
|
if (error instanceof Error) {
|
|
12576
12794
|
try {
|
|
12577
|
-
error.message +=
|
|
12795
|
+
error.message += suffix;
|
|
12578
12796
|
return error;
|
|
12579
12797
|
} catch {}
|
|
12580
12798
|
}
|
|
12581
|
-
return new Error(`${String(error)}${
|
|
12799
|
+
return new Error(`${String(error)}${suffix}`);
|
|
12582
12800
|
}
|
|
12583
12801
|
function safeCloseRoute(client, route) {
|
|
12584
12802
|
try {
|
|
@@ -13183,18 +13401,20 @@ class SubcTransportPool {
|
|
|
13183
13401
|
throw error;
|
|
13184
13402
|
}
|
|
13185
13403
|
};
|
|
13404
|
+
const callDeadlineMs = timeoutMs ?? SUBC_DEFAULT_REQUEST_TIMEOUT_MS;
|
|
13405
|
+
const reloadWaitBudgetMs = Math.min(callDeadlineMs, ROUTE_OPEN_RELOAD_WAIT_CEILING_MS);
|
|
13406
|
+
let reloadWaitedMs = 0;
|
|
13186
13407
|
const openRouteAfterReloadWindow = async () => {
|
|
13187
|
-
let reloadWaitedMs = 0;
|
|
13188
13408
|
while (true) {
|
|
13189
13409
|
try {
|
|
13190
13410
|
return await openRoute();
|
|
13191
13411
|
} catch (error) {
|
|
13192
13412
|
if (!isRouteOpenReloadWindowError(error))
|
|
13193
13413
|
throw error;
|
|
13194
|
-
|
|
13195
|
-
|
|
13196
|
-
throw reloadWindowExhaustedError(error);
|
|
13414
|
+
if (reloadWaitedMs + this.nextRouteReopenDelayMs() >= reloadWaitBudgetMs) {
|
|
13415
|
+
throw reloadWindowExhaustedError(error, callDeadlineMs);
|
|
13197
13416
|
}
|
|
13417
|
+
const { delayMs, wait } = this.waitForRouteReopenBackoff();
|
|
13198
13418
|
reloadWaitedMs += delayMs;
|
|
13199
13419
|
await wait;
|
|
13200
13420
|
}
|
|
@@ -13240,7 +13460,8 @@ class SubcTransportPool {
|
|
|
13240
13460
|
};
|
|
13241
13461
|
abortSignal?.addEventListener("abort", onAbort, { once: true });
|
|
13242
13462
|
try {
|
|
13243
|
-
const
|
|
13463
|
+
const requestTimeoutMs = reloadWaitedMs > 0 ? callDeadlineMs - reloadWaitedMs : timeoutMs;
|
|
13464
|
+
const request = client.request(route, body, { timeoutMs: requestTimeoutMs, onProgress });
|
|
13244
13465
|
const reply = abortSignal ? await Promise.race([request, aborted]) : await request;
|
|
13245
13466
|
if (!this.isCurrentSession(key, record)) {
|
|
13246
13467
|
if (this.isReapInduced(record))
|
|
@@ -13257,28 +13478,41 @@ class SubcTransportPool {
|
|
|
13257
13478
|
}
|
|
13258
13479
|
};
|
|
13259
13480
|
let routeAndEntry = await openRouteAfterReloadWindow();
|
|
13260
|
-
|
|
13261
|
-
|
|
13262
|
-
|
|
13263
|
-
|
|
13264
|
-
|
|
13265
|
-
|
|
13266
|
-
clearRouteEntry(routeAndEntry.entry);
|
|
13267
|
-
await this.waitForRouteReopenBackoff().wait;
|
|
13268
|
-
routeAndEntry = await openRouteAfterReloadWindow();
|
|
13269
|
-
try {
|
|
13270
|
-
const reply = await requestOnRoute(routeAndEntry.route, routeAndEntry.entry);
|
|
13481
|
+
let reopened = false;
|
|
13482
|
+
let retriedAbsentRoute = false;
|
|
13483
|
+
while (true) {
|
|
13484
|
+
try {
|
|
13485
|
+
const reply = await requestOnRoute(routeAndEntry.route, routeAndEntry.entry);
|
|
13486
|
+
if (reopened)
|
|
13271
13487
|
this.resetRouteReopenBackoff();
|
|
13272
|
-
|
|
13273
|
-
|
|
13274
|
-
|
|
13275
|
-
|
|
13276
|
-
|
|
13277
|
-
|
|
13488
|
+
return reply;
|
|
13489
|
+
} catch (error) {
|
|
13490
|
+
if (this.isReapInduced(record))
|
|
13491
|
+
throw this.annotateReapError(error, record);
|
|
13492
|
+
const ownsRoute = this.isCurrentSession(key, record) && this.client === client;
|
|
13493
|
+
if (ownsRoute && isRouteRequestReloadRefusal(error)) {
|
|
13494
|
+
clearRouteEntry(routeAndEntry.entry);
|
|
13495
|
+
if (reloadWaitedMs + this.nextRouteReopenDelayMs() >= reloadWaitBudgetMs) {
|
|
13496
|
+
throw reloadWindowExhaustedError(error, callDeadlineMs);
|
|
13497
|
+
}
|
|
13498
|
+
const { delayMs, wait } = this.waitForRouteReopenBackoff();
|
|
13499
|
+
reloadWaitedMs += delayMs;
|
|
13500
|
+
await wait;
|
|
13501
|
+
routeAndEntry = await openRouteAfterReloadWindow();
|
|
13502
|
+
reopened = true;
|
|
13503
|
+
continue;
|
|
13504
|
+
}
|
|
13505
|
+
if (ownsRoute && !retriedAbsentRoute && isRouteProvenAbsentError(error)) {
|
|
13506
|
+
retriedAbsentRoute = true;
|
|
13507
|
+
clearRouteEntry(routeAndEntry.entry);
|
|
13508
|
+
await this.waitForRouteReopenBackoff().wait;
|
|
13509
|
+
routeAndEntry = await openRouteAfterReloadWindow();
|
|
13510
|
+
reopened = true;
|
|
13511
|
+
continue;
|
|
13278
13512
|
}
|
|
13513
|
+
handleRequestFailure(error, routeAndEntry.entry);
|
|
13514
|
+
throw error;
|
|
13279
13515
|
}
|
|
13280
|
-
handleRequestFailure(error, routeAndEntry.entry);
|
|
13281
|
-
throw error;
|
|
13282
13516
|
}
|
|
13283
13517
|
} catch (error) {
|
|
13284
13518
|
if (this.isReapInduced(record))
|
|
@@ -13307,6 +13541,11 @@ class SubcTransportPool {
|
|
|
13307
13541
|
this.routeReopenRetryMs = delayMs;
|
|
13308
13542
|
return { delayMs, wait: retry };
|
|
13309
13543
|
}
|
|
13544
|
+
nextRouteReopenDelayMs() {
|
|
13545
|
+
if (this.routeReopenRetry && this.routeReopenRetryMs !== null)
|
|
13546
|
+
return this.routeReopenRetryMs;
|
|
13547
|
+
return this.routeReopenRetryDelayMs;
|
|
13548
|
+
}
|
|
13310
13549
|
resetRouteReopenBackoff() {
|
|
13311
13550
|
this.routeReopenRetryDelayMs = RECONNECT_RETRY_FLOOR_MS;
|
|
13312
13551
|
}
|
|
@@ -13598,6 +13837,12 @@ function isRouteOpenReloadWindowError(error) {
|
|
|
13598
13837
|
const code = error.code;
|
|
13599
13838
|
return code === "module_reloading" || code === "module_warming" || code === "target_unavailable";
|
|
13600
13839
|
}
|
|
13840
|
+
function isRouteRequestReloadRefusal(error) {
|
|
13841
|
+
if (error instanceof SubcCallError) {
|
|
13842
|
+
return error.kind === "not_sent" && error.code === "module_reloading";
|
|
13843
|
+
}
|
|
13844
|
+
return error instanceof SubcError && error.code === "module_reloading";
|
|
13845
|
+
}
|
|
13601
13846
|
function hasEngineResponse(error) {
|
|
13602
13847
|
const response = error.response;
|
|
13603
13848
|
if (response !== null && typeof response === "object")
|
|
@@ -21626,6 +21871,13 @@ function sessionWarn(sessionId, message, data) {
|
|
|
21626
21871
|
function sessionError(sessionId, message, data) {
|
|
21627
21872
|
write("ERROR", message, data, sessionId);
|
|
21628
21873
|
}
|
|
21874
|
+
function flushLog() {
|
|
21875
|
+
if (flushTimer) {
|
|
21876
|
+
clearTimeout(flushTimer);
|
|
21877
|
+
flushTimer = null;
|
|
21878
|
+
}
|
|
21879
|
+
flush();
|
|
21880
|
+
}
|
|
21629
21881
|
var bridgeLogger = {
|
|
21630
21882
|
log(message, meta) {
|
|
21631
21883
|
sessionLog(meta?.sessionId, message);
|
|
@@ -40576,6 +40828,7 @@ function coerceAftStatus(response) {
|
|
|
40576
40828
|
},
|
|
40577
40829
|
compression: readCompression(response.compression),
|
|
40578
40830
|
status_bar: readStatusBar(response.status_bar),
|
|
40831
|
+
status_bar_values: readStatusBar(response.status_bar_values),
|
|
40579
40832
|
message: readString(response.message, "")
|
|
40580
40833
|
};
|
|
40581
40834
|
}
|
|
@@ -40919,14 +41172,13 @@ function isSystemTempPath(target) {
|
|
|
40919
41172
|
const normalizedTarget = normalizePath(target);
|
|
40920
41173
|
return systemTempRoots().some((root) => containsPath(normalizePath(root), normalizedTarget));
|
|
40921
41174
|
}
|
|
40922
|
-
function
|
|
40923
|
-
|
|
40924
|
-
|
|
40925
|
-
|
|
41175
|
+
async function isSessionOwnedBashArtifact(ctx, context, target) {
|
|
41176
|
+
try {
|
|
41177
|
+
const response = await callBridge(ctx, context, "bash_artifact_owned", { path: target });
|
|
41178
|
+
return response.success !== false && response.owned === true;
|
|
41179
|
+
} catch {
|
|
40926
41180
|
return false;
|
|
40927
|
-
|
|
40928
|
-
const segments = relative.split(/[/\\]+/);
|
|
40929
|
-
return segments.length === 4 && segments[1] === "bash-tasks";
|
|
41181
|
+
}
|
|
40930
41182
|
}
|
|
40931
41183
|
function windowsPath(p) {
|
|
40932
41184
|
if (process.platform !== "win32")
|
|
@@ -40990,7 +41242,7 @@ async function assertExternalDirectoryPermission(ctx, context, target, options)
|
|
|
40990
41242
|
}
|
|
40991
41243
|
if (isSystemTempPath(absoluteTarget))
|
|
40992
41244
|
return;
|
|
40993
|
-
if (options?.serverValidatedRead === true &&
|
|
41245
|
+
if (options?.serverValidatedRead === true && await isSessionOwnedBashArtifact(ctx, context, absoluteTarget)) {
|
|
40994
41246
|
return;
|
|
40995
41247
|
}
|
|
40996
41248
|
if (typeof context.ask !== "function")
|
|
@@ -41565,6 +41817,9 @@ var z4 = tool.schema;
|
|
|
41565
41817
|
var METADATA_PREVIEW_LIMIT = 30 * 1024;
|
|
41566
41818
|
var DEFAULT_HARD_TIMEOUT_MS = 30 * 60 * 1000;
|
|
41567
41819
|
var BASH_TRANSPORT_MARGIN_MS = 1e4;
|
|
41820
|
+
var ABORT_REGISTRATION_WAIT_MS = 5000;
|
|
41821
|
+
var ABORT_REGISTRATION_POLL_MS = 25;
|
|
41822
|
+
var ABORT_ATTEMPT_TIMEOUT_MS = 1000;
|
|
41568
41823
|
function resolveForegroundWaitMs(configured) {
|
|
41569
41824
|
const override = process.env.AFT_TEST_FOREGROUND_WAIT_MS;
|
|
41570
41825
|
if (override !== undefined) {
|
|
@@ -41578,20 +41833,75 @@ function orchestratedTransportTimeoutMs(blockToCompletion, wait, effectiveTimeou
|
|
|
41578
41833
|
const waitBudget = blockToCompletion || wait ? effectiveTimeout ?? DEFAULT_HARD_TIMEOUT_MS : foregroundWaitMs;
|
|
41579
41834
|
return waitBudget + BASH_TRANSPORT_MARGIN_MS;
|
|
41580
41835
|
}
|
|
41836
|
+
async function abortForegroundWhenRegistered(ctx, runtime, disposed) {
|
|
41837
|
+
const startedAt = Date.now();
|
|
41838
|
+
const deadline = startedAt + ABORT_REGISTRATION_WAIT_MS;
|
|
41839
|
+
const results = [];
|
|
41840
|
+
let attempts = 0;
|
|
41841
|
+
let lastResponse;
|
|
41842
|
+
let lastError;
|
|
41843
|
+
let outcome = "timed_out";
|
|
41844
|
+
while (Date.now() < deadline) {
|
|
41845
|
+
if (disposed()) {
|
|
41846
|
+
outcome = "call_settled";
|
|
41847
|
+
break;
|
|
41848
|
+
}
|
|
41849
|
+
attempts += 1;
|
|
41850
|
+
try {
|
|
41851
|
+
lastResponse = await callBashBridge(ctx, runtime, "bash_abort_inflight", {}, {
|
|
41852
|
+
transportTimeoutMs: Math.max(1, Math.min(ABORT_ATTEMPT_TIMEOUT_MS, deadline - Date.now()))
|
|
41853
|
+
});
|
|
41854
|
+
lastError = undefined;
|
|
41855
|
+
recordAbortAttempt(results, `killed=${String(lastResponse.killed)}`);
|
|
41856
|
+
if (typeof lastResponse.killed === "number" && lastResponse.killed > 0) {
|
|
41857
|
+
outcome = "killed";
|
|
41858
|
+
break;
|
|
41859
|
+
}
|
|
41860
|
+
} catch (error) {
|
|
41861
|
+
lastError = error instanceof Error ? error.message : String(error);
|
|
41862
|
+
recordAbortAttempt(results, `error=${lastError}`);
|
|
41863
|
+
}
|
|
41864
|
+
if (disposed()) {
|
|
41865
|
+
outcome = "call_settled";
|
|
41866
|
+
break;
|
|
41867
|
+
}
|
|
41868
|
+
if (Date.now() >= deadline)
|
|
41869
|
+
break;
|
|
41870
|
+
await sleep(Math.min(ABORT_REGISTRATION_POLL_MS, deadline - Date.now()));
|
|
41871
|
+
}
|
|
41872
|
+
sessionLog(runtime.sessionID, `[bash] foreground abort ${outcome}`, {
|
|
41873
|
+
attempts,
|
|
41874
|
+
elapsed_ms: Date.now() - startedAt,
|
|
41875
|
+
results,
|
|
41876
|
+
...results.length < attempts ? { results_omitted: attempts - results.length } : {},
|
|
41877
|
+
last_response: lastResponse,
|
|
41878
|
+
last_error: lastError
|
|
41879
|
+
});
|
|
41880
|
+
flushLog();
|
|
41881
|
+
}
|
|
41882
|
+
var ABORT_ATTEMPT_RESULTS_KEPT = 20;
|
|
41883
|
+
function recordAbortAttempt(results, result) {
|
|
41884
|
+
if (results.length < ABORT_ATTEMPT_RESULTS_KEPT)
|
|
41885
|
+
results.push(result);
|
|
41886
|
+
}
|
|
41581
41887
|
function listenForForegroundAbort(ctx, runtime, enabled) {
|
|
41582
41888
|
if (!enabled)
|
|
41583
41889
|
return () => {};
|
|
41584
41890
|
let fired = false;
|
|
41891
|
+
let disposed = false;
|
|
41585
41892
|
const onAbort = () => {
|
|
41586
41893
|
if (fired)
|
|
41587
41894
|
return;
|
|
41588
41895
|
fired = true;
|
|
41589
|
-
|
|
41896
|
+
abortForegroundWhenRegistered(ctx, runtime, () => disposed);
|
|
41590
41897
|
};
|
|
41591
41898
|
runtime.abort.addEventListener("abort", onAbort, { once: true });
|
|
41592
41899
|
if (runtime.abort.aborted)
|
|
41593
41900
|
onAbort();
|
|
41594
|
-
return () =>
|
|
41901
|
+
return () => {
|
|
41902
|
+
disposed = true;
|
|
41903
|
+
runtime.abort.removeEventListener("abort", onAbort);
|
|
41904
|
+
};
|
|
41595
41905
|
}
|
|
41596
41906
|
function userMessageDetachDescription(detachOnUserMessage) {
|
|
41597
41907
|
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)`.";
|