commonswarm 0.1.45 → 0.1.47
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/cswarm.cjs +1866 -348
- package/package.json +1 -1
package/cswarm.cjs
CHANGED
|
@@ -163,11 +163,11 @@ function __metadata(metadataKey, metadataValue) {
|
|
|
163
163
|
}
|
|
164
164
|
function __awaiter(thisArg, _arguments, P, generator) {
|
|
165
165
|
function adopt(value) {
|
|
166
|
-
return value instanceof P ? value : new P(function(
|
|
167
|
-
|
|
166
|
+
return value instanceof P ? value : new P(function(resolve3) {
|
|
167
|
+
resolve3(value);
|
|
168
168
|
});
|
|
169
169
|
}
|
|
170
|
-
return new (P || (P = Promise))(function(
|
|
170
|
+
return new (P || (P = Promise))(function(resolve3, reject) {
|
|
171
171
|
function fulfilled(value) {
|
|
172
172
|
try {
|
|
173
173
|
step(generator.next(value));
|
|
@@ -183,7 +183,7 @@ function __awaiter(thisArg, _arguments, P, generator) {
|
|
|
183
183
|
}
|
|
184
184
|
}
|
|
185
185
|
function step(result) {
|
|
186
|
-
result.done ?
|
|
186
|
+
result.done ? resolve3(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
187
187
|
}
|
|
188
188
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
189
189
|
});
|
|
@@ -374,14 +374,14 @@ function __asyncValues(o) {
|
|
|
374
374
|
}, i);
|
|
375
375
|
function verb(n) {
|
|
376
376
|
i[n] = o[n] && function(v) {
|
|
377
|
-
return new Promise(function(
|
|
378
|
-
v = o[n](v), settle(
|
|
377
|
+
return new Promise(function(resolve3, reject) {
|
|
378
|
+
v = o[n](v), settle(resolve3, reject, v.done, v.value);
|
|
379
379
|
});
|
|
380
380
|
};
|
|
381
381
|
}
|
|
382
|
-
function settle(
|
|
382
|
+
function settle(resolve3, reject, d, v) {
|
|
383
383
|
Promise.resolve(v).then(function(v2) {
|
|
384
|
-
|
|
384
|
+
resolve3({ value: v2, done: d });
|
|
385
385
|
}, reject);
|
|
386
386
|
}
|
|
387
387
|
}
|
|
@@ -4262,15 +4262,15 @@ var require_RealtimeChannel = __commonJS({
|
|
|
4262
4262
|
}
|
|
4263
4263
|
}
|
|
4264
4264
|
} else {
|
|
4265
|
-
return new Promise((
|
|
4265
|
+
return new Promise((resolve3) => {
|
|
4266
4266
|
var _a2, _b2, _c;
|
|
4267
4267
|
const push = this.channelAdapter.push(args.type, args, opts.timeout || this.timeout);
|
|
4268
4268
|
if (args.type === "broadcast" && !((_c = (_b2 = (_a2 = this.params) === null || _a2 === void 0 ? void 0 : _a2.config) === null || _b2 === void 0 ? void 0 : _b2.broadcast) === null || _c === void 0 ? void 0 : _c.ack)) {
|
|
4269
|
-
|
|
4269
|
+
resolve3("ok");
|
|
4270
4270
|
}
|
|
4271
|
-
push.receive("ok", () =>
|
|
4272
|
-
push.receive("error", () =>
|
|
4273
|
-
push.receive("timeout", () =>
|
|
4271
|
+
push.receive("ok", () => resolve3("ok"));
|
|
4272
|
+
push.receive("error", () => resolve3("error"));
|
|
4273
|
+
push.receive("timeout", () => resolve3("timed out"));
|
|
4274
4274
|
});
|
|
4275
4275
|
}
|
|
4276
4276
|
}
|
|
@@ -4295,8 +4295,8 @@ var require_RealtimeChannel = __commonJS({
|
|
|
4295
4295
|
* @category Realtime
|
|
4296
4296
|
*/
|
|
4297
4297
|
async unsubscribe(timeout = this.timeout) {
|
|
4298
|
-
return new Promise((
|
|
4299
|
-
this.channelAdapter.unsubscribe(timeout).receive("ok", () =>
|
|
4298
|
+
return new Promise((resolve3) => {
|
|
4299
|
+
this.channelAdapter.unsubscribe(timeout).receive("ok", () => resolve3("ok")).receive("timeout", () => resolve3("timed out")).receive("error", () => resolve3("error"));
|
|
4300
4300
|
});
|
|
4301
4301
|
}
|
|
4302
4302
|
/**
|
|
@@ -4504,11 +4504,11 @@ var require_socketAdapter = __commonJS({
|
|
|
4504
4504
|
this.socket.connect();
|
|
4505
4505
|
}
|
|
4506
4506
|
disconnect(callback, code, reason, timeout = 1e4) {
|
|
4507
|
-
return new Promise((
|
|
4508
|
-
setTimeout(() =>
|
|
4507
|
+
return new Promise((resolve3) => {
|
|
4508
|
+
setTimeout(() => resolve3("timeout"), timeout);
|
|
4509
4509
|
this.socket.disconnect(() => {
|
|
4510
4510
|
callback();
|
|
4511
|
-
|
|
4511
|
+
resolve3("ok");
|
|
4512
4512
|
}, code, reason);
|
|
4513
4513
|
});
|
|
4514
4514
|
}
|
|
@@ -13511,6 +13511,7 @@ __export(cli_exports, {
|
|
|
13511
13511
|
listenerFailureMessage: () => listenerFailureMessage,
|
|
13512
13512
|
listenerHostLimits: () => listenerHostLimits,
|
|
13513
13513
|
listenerPermissionMode: () => listenerPermissionMode,
|
|
13514
|
+
listenerProviderInstallEvidence: () => listenerProviderInstallEvidence,
|
|
13514
13515
|
listenerRouteConfiguration: () => listenerRouteConfiguration,
|
|
13515
13516
|
listenerStatusJson: () => listenerStatusJson,
|
|
13516
13517
|
renderListenerStatus: () => renderListenerStatus,
|
|
@@ -13521,7 +13522,7 @@ __export(cli_exports, {
|
|
|
13521
13522
|
resolveTurnBudgetOrDefer: () => resolveTurnBudgetOrDefer
|
|
13522
13523
|
});
|
|
13523
13524
|
module.exports = __toCommonJS(cli_exports);
|
|
13524
|
-
var
|
|
13525
|
+
var import_node_crypto22 = require("node:crypto");
|
|
13525
13526
|
var import_node_child_process9 = require("node:child_process");
|
|
13526
13527
|
var import_node_fs7 = require("node:fs");
|
|
13527
13528
|
var import_promises12 = require("node:fs/promises");
|
|
@@ -13590,18 +13591,18 @@ var PostgrestError = class extends Error {
|
|
|
13590
13591
|
}
|
|
13591
13592
|
};
|
|
13592
13593
|
function sleep(ms, signal) {
|
|
13593
|
-
return new Promise((
|
|
13594
|
+
return new Promise((resolve3) => {
|
|
13594
13595
|
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
13595
|
-
|
|
13596
|
+
resolve3();
|
|
13596
13597
|
return;
|
|
13597
13598
|
}
|
|
13598
13599
|
const id = setTimeout(() => {
|
|
13599
13600
|
signal === null || signal === void 0 || signal.removeEventListener("abort", onAbort);
|
|
13600
|
-
|
|
13601
|
+
resolve3();
|
|
13601
13602
|
}, ms);
|
|
13602
13603
|
function onAbort() {
|
|
13603
13604
|
clearTimeout(id);
|
|
13604
|
-
|
|
13605
|
+
resolve3();
|
|
13605
13606
|
}
|
|
13606
13607
|
signal === null || signal === void 0 || signal.addEventListener("abort", onAbort);
|
|
13607
13608
|
});
|
|
@@ -18039,7 +18040,7 @@ var _getRequestParams = (method, options, parameters, body) => {
|
|
|
18039
18040
|
return _objectSpread22(_objectSpread22({}, params), parameters);
|
|
18040
18041
|
};
|
|
18041
18042
|
async function _handleRequest(fetcher, method, url, options, parameters, body, namespace) {
|
|
18042
|
-
return new Promise((
|
|
18043
|
+
return new Promise((resolve3, reject) => {
|
|
18043
18044
|
fetcher(url, _getRequestParams(method, options, parameters, body)).then((result) => {
|
|
18044
18045
|
if (!result.ok) throw result;
|
|
18045
18046
|
if (options === null || options === void 0 ? void 0 : options.noResolveJson) return result;
|
|
@@ -18049,7 +18050,7 @@ async function _handleRequest(fetcher, method, url, options, parameters, body, n
|
|
|
18049
18050
|
if (!contentType || !contentType.includes("application/json")) return {};
|
|
18050
18051
|
}
|
|
18051
18052
|
return result.json();
|
|
18052
|
-
}).then((data) =>
|
|
18053
|
+
}).then((data) => resolve3(data)).catch((error) => handleError(error, reject, options, namespace));
|
|
18053
18054
|
});
|
|
18054
18055
|
}
|
|
18055
18056
|
function createFetchApi(namespace = "storage") {
|
|
@@ -20692,11 +20693,11 @@ var DEFAULT_TRACE_PROPAGATION_OPTIONS = {
|
|
|
20692
20693
|
};
|
|
20693
20694
|
function __awaiter2(thisArg, _arguments, P, generator) {
|
|
20694
20695
|
function adopt(value) {
|
|
20695
|
-
return value instanceof P ? value : new P(function(
|
|
20696
|
-
|
|
20696
|
+
return value instanceof P ? value : new P(function(resolve3) {
|
|
20697
|
+
resolve3(value);
|
|
20697
20698
|
});
|
|
20698
20699
|
}
|
|
20699
|
-
return new (P || (P = Promise))(function(
|
|
20700
|
+
return new (P || (P = Promise))(function(resolve3, reject) {
|
|
20700
20701
|
function fulfilled(value) {
|
|
20701
20702
|
try {
|
|
20702
20703
|
step(generator.next(value));
|
|
@@ -20712,7 +20713,7 @@ function __awaiter2(thisArg, _arguments, P, generator) {
|
|
|
20712
20713
|
}
|
|
20713
20714
|
}
|
|
20714
20715
|
function step(result) {
|
|
20715
|
-
result.done ?
|
|
20716
|
+
result.done ? resolve3(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
20716
20717
|
}
|
|
20717
20718
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
20718
20719
|
});
|
|
@@ -21500,14 +21501,14 @@ function validateCallbackUrl(raw, expectedOrigin, expectedState) {
|
|
|
21500
21501
|
return code;
|
|
21501
21502
|
}
|
|
21502
21503
|
function listen(server, port) {
|
|
21503
|
-
return new Promise((
|
|
21504
|
+
return new Promise((resolve3, reject) => {
|
|
21504
21505
|
const onError = (error) => {
|
|
21505
21506
|
server.off("listening", onListening);
|
|
21506
21507
|
reject(error);
|
|
21507
21508
|
};
|
|
21508
21509
|
const onListening = () => {
|
|
21509
21510
|
server.off("error", onError);
|
|
21510
|
-
|
|
21511
|
+
resolve3();
|
|
21511
21512
|
};
|
|
21512
21513
|
server.once("error", onError);
|
|
21513
21514
|
server.once("listening", onListening);
|
|
@@ -21516,8 +21517,8 @@ function listen(server, port) {
|
|
|
21516
21517
|
}
|
|
21517
21518
|
function closeServer(server) {
|
|
21518
21519
|
if (!server.listening) return Promise.resolve();
|
|
21519
|
-
const closed = new Promise((
|
|
21520
|
-
server.close((error) => error ? reject(error) :
|
|
21520
|
+
const closed = new Promise((resolve3, reject) => {
|
|
21521
|
+
server.close((error) => error ? reject(error) : resolve3());
|
|
21521
21522
|
});
|
|
21522
21523
|
server.closeAllConnections();
|
|
21523
21524
|
return closed;
|
|
@@ -21525,8 +21526,8 @@ function closeServer(server) {
|
|
|
21525
21526
|
async function callbackReceiver(expectedState) {
|
|
21526
21527
|
let resolveCode;
|
|
21527
21528
|
let rejectCode;
|
|
21528
|
-
const result = new Promise((
|
|
21529
|
-
resolveCode =
|
|
21529
|
+
const result = new Promise((resolve3, reject) => {
|
|
21530
|
+
resolveCode = resolve3;
|
|
21530
21531
|
rejectCode = reject;
|
|
21531
21532
|
});
|
|
21532
21533
|
let origin = "";
|
|
@@ -21611,23 +21612,23 @@ function authClient(target2, storage) {
|
|
|
21611
21612
|
async function openExternalBrowser(url) {
|
|
21612
21613
|
const command2 = process.platform === "darwin" ? { executable: "open", args: [url] } : process.platform === "linux" ? { executable: "xdg-open", args: [url] } : null;
|
|
21613
21614
|
if (!command2) return false;
|
|
21614
|
-
return await new Promise((
|
|
21615
|
+
return await new Promise((resolve3) => {
|
|
21615
21616
|
const child = (0, import_node_child_process.spawn)(command2.executable, command2.args, {
|
|
21616
21617
|
detached: true,
|
|
21617
21618
|
stdio: "ignore"
|
|
21618
21619
|
});
|
|
21619
|
-
child.once("error", () =>
|
|
21620
|
+
child.once("error", () => resolve3(false));
|
|
21620
21621
|
child.once("spawn", () => {
|
|
21621
21622
|
child.unref();
|
|
21622
|
-
|
|
21623
|
+
resolve3(true);
|
|
21623
21624
|
});
|
|
21624
21625
|
});
|
|
21625
21626
|
}
|
|
21626
21627
|
function pastedCallback(input, output, origin, state) {
|
|
21627
21628
|
if (!input) return null;
|
|
21628
21629
|
let resolveCode;
|
|
21629
|
-
const promise = new Promise((
|
|
21630
|
-
resolveCode =
|
|
21630
|
+
const promise = new Promise((resolve3) => {
|
|
21631
|
+
resolveCode = resolve3;
|
|
21631
21632
|
});
|
|
21632
21633
|
let pending = "";
|
|
21633
21634
|
const onData = (chunk) => {
|
|
@@ -21658,14 +21659,14 @@ function pastedCallback(input, output, origin, state) {
|
|
|
21658
21659
|
async function waitForCode(receiver, state, input, output, timeoutMs, pasteFallbackDelayMs) {
|
|
21659
21660
|
const activePastes = [];
|
|
21660
21661
|
let pasteTimer = null;
|
|
21661
|
-
const paste = input ? new Promise((
|
|
21662
|
+
const paste = input ? new Promise((resolve3) => {
|
|
21662
21663
|
pasteTimer = setTimeout(() => {
|
|
21663
21664
|
output.write(
|
|
21664
21665
|
"If the browser cannot reach the loopback callback, paste the complete callback URL here:\n"
|
|
21665
21666
|
);
|
|
21666
21667
|
const pasted = pastedCallback(input, output, receiver.origin, state);
|
|
21667
21668
|
if (pasted) activePastes.push(pasted);
|
|
21668
|
-
pasted?.promise.then(
|
|
21669
|
+
pasted?.promise.then(resolve3);
|
|
21669
21670
|
}, pasteFallbackDelayMs);
|
|
21670
21671
|
}) : null;
|
|
21671
21672
|
let timer2 = null;
|
|
@@ -22393,8 +22394,8 @@ function signalRetryDelayMs(retry, baseMs, random) {
|
|
|
22393
22394
|
async function waitForSignalRetry(delayMs, deadline, callerAbort) {
|
|
22394
22395
|
if (delayMs === 0) return "elapsed";
|
|
22395
22396
|
let timer2;
|
|
22396
|
-
const elapsed = new Promise((
|
|
22397
|
-
timer2 = setTimeout(() =>
|
|
22397
|
+
const elapsed = new Promise((resolve3) => {
|
|
22398
|
+
timer2 = setTimeout(() => resolve3("elapsed"), delayMs);
|
|
22398
22399
|
});
|
|
22399
22400
|
try {
|
|
22400
22401
|
const outcome = await raceSignalDeadline(elapsed, deadline, callerAbort);
|
|
@@ -22703,12 +22704,12 @@ var ThinCommandClient = class {
|
|
|
22703
22704
|
}
|
|
22704
22705
|
const controller = new AbortController();
|
|
22705
22706
|
let releaseDeadline;
|
|
22706
|
-
const deadline = new Promise((
|
|
22707
|
-
releaseDeadline =
|
|
22707
|
+
const deadline = new Promise((resolve3) => {
|
|
22708
|
+
releaseDeadline = resolve3;
|
|
22708
22709
|
});
|
|
22709
22710
|
let releaseCallerAbort;
|
|
22710
|
-
const callerAbort = new Promise((
|
|
22711
|
-
releaseCallerAbort =
|
|
22711
|
+
const callerAbort = new Promise((resolve3) => {
|
|
22712
|
+
releaseCallerAbort = resolve3;
|
|
22712
22713
|
});
|
|
22713
22714
|
let deadlineReached = false;
|
|
22714
22715
|
const timer2 = setTimeout(() => {
|
|
@@ -23581,7 +23582,7 @@ async function deleteSecureJsonFile(path) {
|
|
|
23581
23582
|
}
|
|
23582
23583
|
}
|
|
23583
23584
|
async function run(executable, args, input, detached = false) {
|
|
23584
|
-
return await new Promise((
|
|
23585
|
+
return await new Promise((resolve3, reject) => {
|
|
23585
23586
|
const child = (0, import_node_child_process2.spawn)(executable, args, {
|
|
23586
23587
|
stdio: ["pipe", "pipe", "pipe"],
|
|
23587
23588
|
env: process.env,
|
|
@@ -23598,7 +23599,7 @@ async function run(executable, args, input, detached = false) {
|
|
|
23598
23599
|
stderr += chunk;
|
|
23599
23600
|
});
|
|
23600
23601
|
child.on("error", reject);
|
|
23601
|
-
child.on("close", (code) =>
|
|
23602
|
+
child.on("close", (code) => resolve3({ code: code ?? 1, stdout, stderr }));
|
|
23602
23603
|
if (input !== void 0) child.stdin.end(`${input}
|
|
23603
23604
|
`);
|
|
23604
23605
|
else child.stdin.end();
|
|
@@ -23848,8 +23849,7 @@ function parseStoredCurrentTarget(raw) {
|
|
|
23848
23849
|
throw new Error("stored current target is malformed");
|
|
23849
23850
|
}
|
|
23850
23851
|
const record = value;
|
|
23851
|
-
|
|
23852
|
-
if (keys.length !== 3 || keys[0] !== "anonKey" || keys[1] !== "url" || keys[2] !== "version" || record.version !== 1 || typeof record.url !== "string" || typeof record.anonKey !== "string") {
|
|
23852
|
+
if (record.version !== 1 || typeof record.url !== "string" || typeof record.anonKey !== "string") {
|
|
23853
23853
|
throw new Error("stored current target is malformed");
|
|
23854
23854
|
}
|
|
23855
23855
|
try {
|
|
@@ -24028,9 +24028,9 @@ var originError = /* @__PURE__ */ Symbol("OriginError");
|
|
|
24028
24028
|
var CLOSE = {};
|
|
24029
24029
|
var Query = class extends Promise {
|
|
24030
24030
|
constructor(strings, args, handler, canceller, options = {}) {
|
|
24031
|
-
let
|
|
24031
|
+
let resolve3, reject;
|
|
24032
24032
|
super((a, b2) => {
|
|
24033
|
-
|
|
24033
|
+
resolve3 = a;
|
|
24034
24034
|
reject = b2;
|
|
24035
24035
|
});
|
|
24036
24036
|
this.tagged = Array.isArray(strings.raw);
|
|
@@ -24041,7 +24041,7 @@ var Query = class extends Promise {
|
|
|
24041
24041
|
this.options = options;
|
|
24042
24042
|
this.state = null;
|
|
24043
24043
|
this.statement = null;
|
|
24044
|
-
this.resolve = (x) => (this.active = false,
|
|
24044
|
+
this.resolve = (x) => (this.active = false, resolve3(x));
|
|
24045
24045
|
this.reject = (x) => (this.active = false, reject(x));
|
|
24046
24046
|
this.active = false;
|
|
24047
24047
|
this.cancelled = null;
|
|
@@ -24089,12 +24089,12 @@ var Query = class extends Promise {
|
|
|
24089
24089
|
if (this.executed && !this.active)
|
|
24090
24090
|
return { done: true };
|
|
24091
24091
|
prev && prev();
|
|
24092
|
-
const promise = new Promise((
|
|
24092
|
+
const promise = new Promise((resolve3, reject) => {
|
|
24093
24093
|
this.cursorFn = (value) => {
|
|
24094
|
-
|
|
24094
|
+
resolve3({ value, done: false });
|
|
24095
24095
|
return new Promise((r) => prev = r);
|
|
24096
24096
|
};
|
|
24097
|
-
this.resolve = () => (this.active = false,
|
|
24097
|
+
this.resolve = () => (this.active = false, resolve3({ done: true }));
|
|
24098
24098
|
this.reject = (x) => (this.active = false, reject(x));
|
|
24099
24099
|
});
|
|
24100
24100
|
this.execute();
|
|
@@ -24721,12 +24721,12 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
24721
24721
|
x.on("drain", drain);
|
|
24722
24722
|
return x;
|
|
24723
24723
|
}
|
|
24724
|
-
async function cancel({ pid, secret },
|
|
24724
|
+
async function cancel({ pid, secret }, resolve3, reject) {
|
|
24725
24725
|
try {
|
|
24726
24726
|
cancelMessage = bytes_default().i32(16).i32(80877102).i32(pid).i32(secret).end(16);
|
|
24727
24727
|
await connect();
|
|
24728
24728
|
socket.once("error", reject);
|
|
24729
|
-
socket.once("close",
|
|
24729
|
+
socket.once("close", resolve3);
|
|
24730
24730
|
} catch (error2) {
|
|
24731
24731
|
reject(error2);
|
|
24732
24732
|
}
|
|
@@ -25673,7 +25673,7 @@ function parseEvent(x) {
|
|
|
25673
25673
|
// node_modules/postgres/src/large.js
|
|
25674
25674
|
var import_stream2 = __toESM(require("stream"), 1);
|
|
25675
25675
|
function largeObject(sql, oid, mode3 = 131072 | 262144) {
|
|
25676
|
-
return new Promise(async (
|
|
25676
|
+
return new Promise(async (resolve3, reject) => {
|
|
25677
25677
|
await sql.begin(async (sql2) => {
|
|
25678
25678
|
let finish;
|
|
25679
25679
|
!oid && ([{ oid }] = await sql2`select lo_creat(-1) as oid`);
|
|
@@ -25699,7 +25699,7 @@ function largeObject(sql, oid, mode3 = 131072 | 262144) {
|
|
|
25699
25699
|
) seek
|
|
25700
25700
|
`
|
|
25701
25701
|
};
|
|
25702
|
-
|
|
25702
|
+
resolve3(lo);
|
|
25703
25703
|
return new Promise(async (r) => finish = r);
|
|
25704
25704
|
async function readable({
|
|
25705
25705
|
highWaterMark = 2048 * 8,
|
|
@@ -25873,8 +25873,8 @@ function Postgres(a, b2) {
|
|
|
25873
25873
|
}
|
|
25874
25874
|
async function reserve() {
|
|
25875
25875
|
const queue = queue_default();
|
|
25876
|
-
const c = open6.length ? open6.shift() : await new Promise((
|
|
25877
|
-
const query = { reserve:
|
|
25876
|
+
const c = open6.length ? open6.shift() : await new Promise((resolve3, reject) => {
|
|
25877
|
+
const query = { reserve: resolve3, reject };
|
|
25878
25878
|
queries.push(query);
|
|
25879
25879
|
closed.length && connect(closed.shift(), query);
|
|
25880
25880
|
});
|
|
@@ -25911,9 +25911,9 @@ function Postgres(a, b2) {
|
|
|
25911
25911
|
let uncaughtError, result;
|
|
25912
25912
|
name && await sql2`savepoint ${sql2(name)}`;
|
|
25913
25913
|
try {
|
|
25914
|
-
result = await new Promise((
|
|
25914
|
+
result = await new Promise((resolve3, reject) => {
|
|
25915
25915
|
const x = fn2(sql2);
|
|
25916
|
-
Promise.resolve(Array.isArray(x) ? Promise.all(x) : x).then(
|
|
25916
|
+
Promise.resolve(Array.isArray(x) ? Promise.all(x) : x).then(resolve3, reject);
|
|
25917
25917
|
});
|
|
25918
25918
|
if (uncaughtError)
|
|
25919
25919
|
throw uncaughtError;
|
|
@@ -25970,8 +25970,8 @@ function Postgres(a, b2) {
|
|
|
25970
25970
|
return c.execute(query) ? move(c, busy) : move(c, full);
|
|
25971
25971
|
}
|
|
25972
25972
|
function cancel(query) {
|
|
25973
|
-
return new Promise((
|
|
25974
|
-
query.state ? query.active ? connection_default(options).cancel(query.state,
|
|
25973
|
+
return new Promise((resolve3, reject) => {
|
|
25974
|
+
query.state ? query.active ? connection_default(options).cancel(query.state, resolve3, reject) : query.cancelled = { resolve: resolve3, reject } : (queries.remove(query), query.cancelled = true, query.reject(Errors.generic("57014", "canceling statement due to user request")), resolve3());
|
|
25975
25975
|
});
|
|
25976
25976
|
}
|
|
25977
25977
|
async function end({ timeout = null } = {}) {
|
|
@@ -25990,11 +25990,11 @@ function Postgres(a, b2) {
|
|
|
25990
25990
|
async function close() {
|
|
25991
25991
|
await Promise.all(connections.map((c) => c.end()));
|
|
25992
25992
|
}
|
|
25993
|
-
async function destroy(
|
|
25993
|
+
async function destroy(resolve3) {
|
|
25994
25994
|
await Promise.all(connections.map((c) => c.terminate()));
|
|
25995
25995
|
while (queries.length)
|
|
25996
25996
|
queries.shift().reject(Errors.connection("CONNECTION_DESTROYED", options));
|
|
25997
|
-
|
|
25997
|
+
resolve3();
|
|
25998
25998
|
}
|
|
25999
25999
|
function connect(c, query) {
|
|
26000
26000
|
move(c, connecting);
|
|
@@ -28750,10 +28750,19 @@ var SIGNAL_BODY_DISPLAY_MAX = 8e3;
|
|
|
28750
28750
|
var SIGNAL_ABOUT_DISPLAY_MAX = 500;
|
|
28751
28751
|
var SIGNAL_READ_TIMEOUT_MS = 3e4;
|
|
28752
28752
|
var SignalReadTimeoutError = class extends Error {
|
|
28753
|
-
constructor(message = "signal read timed out") {
|
|
28753
|
+
constructor(message = "signal read timed out", phase = "response") {
|
|
28754
28754
|
super(message);
|
|
28755
|
+
this.phase = phase;
|
|
28755
28756
|
this.name = "SignalReadTimeoutError";
|
|
28756
28757
|
}
|
|
28758
|
+
phase;
|
|
28759
|
+
};
|
|
28760
|
+
var SignalHostPortsExhaustedError = class extends Error {
|
|
28761
|
+
code = "EADDRNOTAVAIL";
|
|
28762
|
+
constructor() {
|
|
28763
|
+
super("the host could not allocate an outbound source port");
|
|
28764
|
+
this.name = "SignalHostPortsExhaustedError";
|
|
28765
|
+
}
|
|
28757
28766
|
};
|
|
28758
28767
|
var SIGNAL_WAIT_MIN_SECONDS = 1;
|
|
28759
28768
|
var SIGNAL_WAIT_MAX_SECONDS = 300;
|
|
@@ -28792,9 +28801,17 @@ var plainHttpRetryAfterMs = /* @__PURE__ */ new WeakMap();
|
|
|
28792
28801
|
var plainHttpStatus = /* @__PURE__ */ new WeakMap();
|
|
28793
28802
|
var plainHttpEnvelope = /* @__PURE__ */ new WeakMap();
|
|
28794
28803
|
var plainTransportErrors = /* @__PURE__ */ new WeakSet();
|
|
28795
|
-
|
|
28804
|
+
var plainTransportFailureCodes = /* @__PURE__ */ new WeakMap();
|
|
28805
|
+
var plainMalformedErrors = /* @__PURE__ */ new WeakSet();
|
|
28806
|
+
function plainTransportError(failureCode2 = "no_response") {
|
|
28796
28807
|
const error = new Error("signal read could not reach the cloud service");
|
|
28797
28808
|
plainTransportErrors.add(error);
|
|
28809
|
+
plainTransportFailureCodes.set(error, failureCode2);
|
|
28810
|
+
return error;
|
|
28811
|
+
}
|
|
28812
|
+
function plainMalformedError(message) {
|
|
28813
|
+
const error = new Error(message);
|
|
28814
|
+
plainMalformedErrors.add(error);
|
|
28798
28815
|
return error;
|
|
28799
28816
|
}
|
|
28800
28817
|
function checkedUuid2(value, field) {
|
|
@@ -28999,7 +29016,62 @@ function followErrorEnvelope(error) {
|
|
|
28999
29016
|
return EMPTY_SERVER_ERROR_ENVELOPE;
|
|
29000
29017
|
}
|
|
29001
29018
|
function isTransportFollowMessage(error) {
|
|
29002
|
-
return error instanceof SignalTransportError || error instanceof Error && plainTransportErrors.has(error);
|
|
29019
|
+
return error instanceof SignalTransportError || error instanceof SignalHostPortsExhaustedError || error instanceof Error && plainTransportErrors.has(error);
|
|
29020
|
+
}
|
|
29021
|
+
function safeConstructorName(error) {
|
|
29022
|
+
if (error === null || typeof error !== "object") return typeof error;
|
|
29023
|
+
const name = error.constructor?.name;
|
|
29024
|
+
if (typeof name !== "string" || name.length === 0) return "Unknown";
|
|
29025
|
+
return name.replace(/[^A-Za-z0-9_$-]+/g, "_").slice(0, 96) || "Unknown";
|
|
29026
|
+
}
|
|
29027
|
+
function classifySignalReadFailure(error) {
|
|
29028
|
+
if (error instanceof SignalHostPortsExhaustedError || error !== null && typeof error === "object" && error.code === "EADDRNOTAVAIL") {
|
|
29029
|
+
return {
|
|
29030
|
+
code: "host_ports_exhausted",
|
|
29031
|
+
httpStatus: null,
|
|
29032
|
+
errorConstructor: null
|
|
29033
|
+
};
|
|
29034
|
+
}
|
|
29035
|
+
const http = followHttpDetails(error);
|
|
29036
|
+
if (http !== null) {
|
|
29037
|
+
return {
|
|
29038
|
+
code: "http_status",
|
|
29039
|
+
httpStatus: http.status,
|
|
29040
|
+
errorConstructor: null
|
|
29041
|
+
};
|
|
29042
|
+
}
|
|
29043
|
+
if (error instanceof SignalReadTimeoutError) {
|
|
29044
|
+
return {
|
|
29045
|
+
code: error.phase === "body" ? "body_timeout" : "no_response",
|
|
29046
|
+
httpStatus: null,
|
|
29047
|
+
errorConstructor: null
|
|
29048
|
+
};
|
|
29049
|
+
}
|
|
29050
|
+
if (error instanceof Error && plainTransportErrors.has(error)) {
|
|
29051
|
+
return {
|
|
29052
|
+
code: plainTransportFailureCodes.get(error) ?? "no_response",
|
|
29053
|
+
httpStatus: null,
|
|
29054
|
+
errorConstructor: null
|
|
29055
|
+
};
|
|
29056
|
+
}
|
|
29057
|
+
if (error instanceof SignalTransportError) {
|
|
29058
|
+
return { code: "no_response", httpStatus: null, errorConstructor: null };
|
|
29059
|
+
}
|
|
29060
|
+
if (error instanceof SignalMalformedError || error instanceof Error && plainMalformedErrors.has(error)) {
|
|
29061
|
+
return {
|
|
29062
|
+
code: "malformed_response",
|
|
29063
|
+
httpStatus: null,
|
|
29064
|
+
errorConstructor: null
|
|
29065
|
+
};
|
|
29066
|
+
}
|
|
29067
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
29068
|
+
return { code: "aborted", httpStatus: null, errorConstructor: null };
|
|
29069
|
+
}
|
|
29070
|
+
return {
|
|
29071
|
+
code: "unclassified",
|
|
29072
|
+
httpStatus: null,
|
|
29073
|
+
errorConstructor: safeConstructorName(error)
|
|
29074
|
+
};
|
|
29003
29075
|
}
|
|
29004
29076
|
function isRestartableReadError(error) {
|
|
29005
29077
|
if (error instanceof SignalReadTimeoutError) return true;
|
|
@@ -29051,11 +29123,12 @@ async function fetchSignalRead(fetcher, input, init, timeoutMs = SIGNAL_READ_TIM
|
|
|
29051
29123
|
}
|
|
29052
29124
|
const deadlineController = new AbortController();
|
|
29053
29125
|
let timedOut = false;
|
|
29126
|
+
let responseReceived = false;
|
|
29054
29127
|
const signal = init.signal ? AbortSignal.any([init.signal, deadlineController.signal]) : deadlineController.signal;
|
|
29055
29128
|
let onAbort = () => {
|
|
29056
29129
|
};
|
|
29057
|
-
const aborted = new Promise((
|
|
29058
|
-
onAbort = () =>
|
|
29130
|
+
const aborted = new Promise((resolve3) => {
|
|
29131
|
+
onAbort = () => resolve3("timeout");
|
|
29059
29132
|
if (signal.aborted) {
|
|
29060
29133
|
onAbort();
|
|
29061
29134
|
} else {
|
|
@@ -29078,22 +29151,31 @@ async function fetchSignalRead(fetcher, input, init, timeoutMs = SIGNAL_READ_TIM
|
|
|
29078
29151
|
signal
|
|
29079
29152
|
});
|
|
29080
29153
|
} catch (error) {
|
|
29081
|
-
if (signal.aborted || timedOut
|
|
29154
|
+
if (signal.aborted || timedOut) {
|
|
29082
29155
|
return "timeout";
|
|
29083
29156
|
}
|
|
29157
|
+
if (error instanceof Error && error.name === "AbortError") throw error;
|
|
29158
|
+
if (error !== null && typeof error === "object" && error.code === "EADDRNOTAVAIL") {
|
|
29159
|
+
throw new SignalHostPortsExhaustedError();
|
|
29160
|
+
}
|
|
29084
29161
|
return null;
|
|
29085
29162
|
}
|
|
29163
|
+
responseReceived = true;
|
|
29086
29164
|
if (signal.aborted || timedOut) return "timeout";
|
|
29087
29165
|
try {
|
|
29088
29166
|
return { response, body: await response.json() };
|
|
29089
|
-
} catch {
|
|
29167
|
+
} catch (error) {
|
|
29090
29168
|
if (signal.aborted || timedOut) return "timeout";
|
|
29169
|
+
if (error instanceof Error && error.name === "AbortError") throw error;
|
|
29091
29170
|
return { response, body: null };
|
|
29092
29171
|
}
|
|
29093
29172
|
})();
|
|
29094
29173
|
const raced = await Promise.race([read, aborted]);
|
|
29095
29174
|
if (raced === "timeout") {
|
|
29096
|
-
throw new SignalReadTimeoutError(
|
|
29175
|
+
throw new SignalReadTimeoutError(
|
|
29176
|
+
"signal read timed out",
|
|
29177
|
+
responseReceived ? "body" : "response"
|
|
29178
|
+
);
|
|
29097
29179
|
}
|
|
29098
29180
|
return raced;
|
|
29099
29181
|
} finally {
|
|
@@ -29103,7 +29185,7 @@ async function fetchSignalRead(fetcher, input, init, timeoutMs = SIGNAL_READ_TIM
|
|
|
29103
29185
|
}
|
|
29104
29186
|
var READ_RETRY_ATTEMPTS = 2;
|
|
29105
29187
|
var READ_RETRY_BASE_MS = 250;
|
|
29106
|
-
async function fetchSignalReadRetrying(fetcher, input, init, timeoutMs = SIGNAL_READ_TIMEOUT_MS, sleep2 = (ms) => new Promise((
|
|
29188
|
+
async function fetchSignalReadRetrying(fetcher, input, init, timeoutMs = SIGNAL_READ_TIMEOUT_MS, sleep2 = (ms) => new Promise((resolve3) => setTimeout(resolve3, ms))) {
|
|
29107
29189
|
let result = await fetchSignalRead(fetcher, input, init, timeoutMs);
|
|
29108
29190
|
for (let attempt = 1; attempt <= READ_RETRY_ATTEMPTS; attempt += 1) {
|
|
29109
29191
|
if (result === null || result.response.ok) return result;
|
|
@@ -29122,7 +29204,9 @@ async function fetchSignalReadRetrying(fetcher, input, init, timeoutMs = SIGNAL_
|
|
|
29122
29204
|
function mapReadFailure(error, waitBound) {
|
|
29123
29205
|
if (error instanceof SignalReadTimeoutError) {
|
|
29124
29206
|
if (waitBound) throw error;
|
|
29125
|
-
throw plainTransportError(
|
|
29207
|
+
throw plainTransportError(
|
|
29208
|
+
error.phase === "body" ? "body_timeout" : "no_response"
|
|
29209
|
+
);
|
|
29126
29210
|
}
|
|
29127
29211
|
throw error;
|
|
29128
29212
|
}
|
|
@@ -29178,7 +29262,7 @@ async function humanSignals(target2, credential, query, options) {
|
|
|
29178
29262
|
throwSignalHttp(response, body);
|
|
29179
29263
|
}
|
|
29180
29264
|
if (!Array.isArray(body)) {
|
|
29181
|
-
throw
|
|
29265
|
+
throw plainMalformedError("signal read returned malformed JSON");
|
|
29182
29266
|
}
|
|
29183
29267
|
const parsed = body.map((value) => parseSignalRecord(value));
|
|
29184
29268
|
return sortSignals(rowsAfterCursor(parsed, query.after), ascending);
|
|
@@ -29246,7 +29330,7 @@ async function agentSignalPage(target2, credential, query, options, allowLegacyC
|
|
|
29246
29330
|
const { response, body } = result;
|
|
29247
29331
|
if (!response.ok) throwSignalHttp(response, body);
|
|
29248
29332
|
if (!body || typeof body !== "object" || Array.isArray(body) || !Array.isArray(body.signals)) {
|
|
29249
|
-
throw
|
|
29333
|
+
throw plainMalformedError("signal read returned malformed JSON");
|
|
29250
29334
|
}
|
|
29251
29335
|
const capabilities = signalReadCapabilities(
|
|
29252
29336
|
body.capabilities
|
|
@@ -29423,7 +29507,7 @@ function nextWaitSleepMs(nowMs, deadlineMs, pollMs = SIGNAL_WAIT_POLL_MS) {
|
|
|
29423
29507
|
}
|
|
29424
29508
|
async function pollForSignals(options) {
|
|
29425
29509
|
const now = options.now ?? Date.now;
|
|
29426
|
-
const sleep2 = options.sleep ?? ((ms) => new Promise((
|
|
29510
|
+
const sleep2 = options.sleep ?? ((ms) => new Promise((resolve3) => setTimeout(resolve3, ms)));
|
|
29427
29511
|
const pollMs = options.pollMs ?? SIGNAL_WAIT_POLL_MS;
|
|
29428
29512
|
const probe = async () => {
|
|
29429
29513
|
try {
|
|
@@ -29736,6 +29820,7 @@ function resolveRefusalToleranceMs(raw, warn = () => {
|
|
|
29736
29820
|
}
|
|
29737
29821
|
function isRetryableFollowError(error) {
|
|
29738
29822
|
if (serverRefusedRetry(followErrorEnvelope(error))) return false;
|
|
29823
|
+
if (error instanceof SignalHostPortsExhaustedError) return true;
|
|
29739
29824
|
if (error instanceof SignalReadTimeoutError) return true;
|
|
29740
29825
|
if (isTransportFollowMessage(error)) return true;
|
|
29741
29826
|
const http = followHttpDetails(error);
|
|
@@ -29800,14 +29885,14 @@ async function runInboxFollow(options) {
|
|
|
29800
29885
|
let timer2;
|
|
29801
29886
|
let onAbort;
|
|
29802
29887
|
try {
|
|
29803
|
-
await new Promise((
|
|
29888
|
+
await new Promise((resolve3) => {
|
|
29804
29889
|
let settled = false;
|
|
29805
29890
|
const finish = () => {
|
|
29806
29891
|
if (settled) return;
|
|
29807
29892
|
settled = true;
|
|
29808
29893
|
if (timer2 !== void 0) clearTimeout(timer2);
|
|
29809
29894
|
if (onAbort && abort) abort.removeEventListener("abort", onAbort);
|
|
29810
|
-
|
|
29895
|
+
resolve3();
|
|
29811
29896
|
};
|
|
29812
29897
|
if (abort) {
|
|
29813
29898
|
if (abort.aborted) {
|
|
@@ -30026,9 +30111,8 @@ function parseCursor(raw, workspaceId2, principalId) {
|
|
|
30026
30111
|
throw new Error("stored arrival cursor is malformed");
|
|
30027
30112
|
}
|
|
30028
30113
|
const row = value;
|
|
30029
|
-
const keys = Object.keys(row).sort();
|
|
30030
30114
|
const cursor = row.cursor;
|
|
30031
|
-
if (
|
|
30115
|
+
if (row.version !== 1 || row.workspace_id !== workspaceId2.toLowerCase() || row.principal_id !== principalId.toLowerCase() || !(cursor === null || typeof cursor === "object" && !Array.isArray(cursor) && typeof cursor.created_at === "string" && Number.isFinite(Date.parse(cursor.created_at)) && typeof cursor.id === "string" && UUID_RE10.test(cursor.id))) {
|
|
30032
30116
|
throw new Error("stored arrival cursor is malformed");
|
|
30033
30117
|
}
|
|
30034
30118
|
if (cursor === null) return null;
|
|
@@ -30095,7 +30179,7 @@ function notifyWriteError(error) {
|
|
|
30095
30179
|
return error.code === "EPIPE" ? new NotifyStdoutClosedError() : error;
|
|
30096
30180
|
}
|
|
30097
30181
|
async function writeArrivalMonitorLine(line, stream2 = process.stdout) {
|
|
30098
|
-
await new Promise((
|
|
30182
|
+
await new Promise((resolve3, reject) => {
|
|
30099
30183
|
let settled = false;
|
|
30100
30184
|
const finish = (error) => {
|
|
30101
30185
|
if (settled) return;
|
|
@@ -30105,7 +30189,7 @@ async function writeArrivalMonitorLine(line, stream2 = process.stdout) {
|
|
|
30105
30189
|
reject(notifyWriteError(error));
|
|
30106
30190
|
} else {
|
|
30107
30191
|
stream2.off("error", onError);
|
|
30108
|
-
|
|
30192
|
+
resolve3();
|
|
30109
30193
|
}
|
|
30110
30194
|
};
|
|
30111
30195
|
const onError = (error) => finish(error);
|
|
@@ -30140,15 +30224,15 @@ async function runArrivalWatch(options) {
|
|
|
30140
30224
|
await options.sleep(ms);
|
|
30141
30225
|
return;
|
|
30142
30226
|
}
|
|
30143
|
-
await new Promise((
|
|
30227
|
+
await new Promise((resolve3) => {
|
|
30144
30228
|
let timer2;
|
|
30145
30229
|
const finish = () => {
|
|
30146
30230
|
if (timer2 !== void 0) clearTimeout(timer2);
|
|
30147
30231
|
options.signal?.removeEventListener("abort", finish);
|
|
30148
|
-
|
|
30232
|
+
resolve3();
|
|
30149
30233
|
};
|
|
30150
30234
|
if (cancelled() || ms <= 0) {
|
|
30151
|
-
|
|
30235
|
+
resolve3();
|
|
30152
30236
|
return;
|
|
30153
30237
|
}
|
|
30154
30238
|
options.signal?.addEventListener("abort", finish, { once: true });
|
|
@@ -30755,11 +30839,7 @@ function signalReceiptJsonPayload(report, nowMs = Date.now()) {
|
|
|
30755
30839
|
var import_node_child_process3 = require("node:child_process");
|
|
30756
30840
|
var import_node_crypto12 = require("node:crypto");
|
|
30757
30841
|
|
|
30758
|
-
// src/host/
|
|
30759
|
-
var RING_CAPACITY_BYTES = 4096;
|
|
30760
|
-
var TAIL_MAX_CHARS = 2048;
|
|
30761
|
-
var STDERR_EXIT_GRACE_MS = 100;
|
|
30762
|
-
var STDERR_READABLE_END_GRACE_MS = STDERR_EXIT_GRACE_MS + 50;
|
|
30842
|
+
// src/host/credential-redaction.ts
|
|
30763
30843
|
var EXOTIC_SEPARATORS = "\\u00a0\\u1680\\u2000-\\u200d\\u2028\\u2029\\u202a-\\u202e\\u2060\\u2066-\\u2069\\u202f\\u205f\\u3000\\ufeff";
|
|
30764
30844
|
var SEPARATOR_CLASS_SOURCE = "\\t\\n\\x0b\\f\\r " + EXOTIC_SEPARATORS;
|
|
30765
30845
|
var ANSI_ESCAPE_GLOBAL_RE2 = new RegExp("\\u001b\\[[0-?]*[ -\\/]*[@-~]", "g");
|
|
@@ -30771,8 +30851,17 @@ var CREDENTIAL_PREFIX_RE = new RegExp(
|
|
|
30771
30851
|
`swm_(?:agt|inv|cap)_[^${SEPARATOR_CLASS_SOURCE}]*`,
|
|
30772
30852
|
"gi"
|
|
30773
30853
|
);
|
|
30854
|
+
function redactCredentialText(value) {
|
|
30855
|
+
return value.replace(ANSI_ESCAPE_GLOBAL_RE2, "").replace(CONTROL_AND_SEPARATOR_STRIP_RE, "").replace(CREDENTIAL_PREFIX_RE, "[redacted-credential]");
|
|
30856
|
+
}
|
|
30857
|
+
|
|
30858
|
+
// src/host/stderr-tail.ts
|
|
30859
|
+
var RING_CAPACITY_BYTES = 4096;
|
|
30860
|
+
var TAIL_MAX_CHARS = 2048;
|
|
30861
|
+
var STDERR_EXIT_GRACE_MS = 100;
|
|
30862
|
+
var STDERR_READABLE_END_GRACE_MS = STDERR_EXIT_GRACE_MS + 50;
|
|
30774
30863
|
function sanitizeStderrTail(raw) {
|
|
30775
|
-
return raw
|
|
30864
|
+
return redactCredentialText(raw).slice(-TAIL_MAX_CHARS).trim();
|
|
30776
30865
|
}
|
|
30777
30866
|
function attachStderrTailRing(stderr) {
|
|
30778
30867
|
const chunks = [];
|
|
@@ -30984,7 +31073,7 @@ function permissionDecisionToResult(decision) {
|
|
|
30984
31073
|
var SECRET_VALUE_RE = /(?:(?:api[_-]?key|token|secret|password|authorization|bearer)\s*[:=]\s*)(["']?)([^\s"'\\]{8,})\1/gi;
|
|
30985
31074
|
var JWT_RE = /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b/g;
|
|
30986
31075
|
function redactString(value) {
|
|
30987
|
-
return value.replace(SECRET_VALUE_RE, (_m, q) => `redacted=${q}***${q}`).replace(JWT_RE, "[redacted-jwt]");
|
|
31076
|
+
return redactCredentialText(value).replace(SECRET_VALUE_RE, (_m, q) => `redacted=${q}***${q}`).replace(JWT_RE, "[redacted-jwt]");
|
|
30988
31077
|
}
|
|
30989
31078
|
function redactUnknown(value, depth = 0) {
|
|
30990
31079
|
if (depth > 6) return "[truncated]";
|
|
@@ -31100,12 +31189,14 @@ var AcpVersionBelowFloorError = class extends AcpVersionError {
|
|
|
31100
31189
|
actual;
|
|
31101
31190
|
};
|
|
31102
31191
|
var AcpPermissionCanaryError = class extends AcpHostError {
|
|
31103
|
-
constructor(message, reasonCode = null) {
|
|
31192
|
+
constructor(message, reasonCode = null, minimumRequiredVersion = null) {
|
|
31104
31193
|
super("permission_canary_failed", message);
|
|
31105
31194
|
this.reasonCode = reasonCode;
|
|
31195
|
+
this.minimumRequiredVersion = minimumRequiredVersion;
|
|
31106
31196
|
this.name = "AcpPermissionCanaryError";
|
|
31107
31197
|
}
|
|
31108
31198
|
reasonCode;
|
|
31199
|
+
minimumRequiredVersion;
|
|
31109
31200
|
};
|
|
31110
31201
|
var AcpPromptsBlockedError = class extends AcpHostError {
|
|
31111
31202
|
constructor() {
|
|
@@ -31205,12 +31296,12 @@ var AcpTransport = class extends import_node_events.EventEmitter {
|
|
|
31205
31296
|
method,
|
|
31206
31297
|
...params !== void 0 ? { params } : {}
|
|
31207
31298
|
};
|
|
31208
|
-
return new Promise((
|
|
31299
|
+
return new Promise((resolve3, reject) => {
|
|
31209
31300
|
const timer2 = setTimeout(() => {
|
|
31210
31301
|
this.pending.delete(key2);
|
|
31211
31302
|
reject(new AcpTimeoutError(`ACP request timed out: ${method}`));
|
|
31212
31303
|
}, timeoutMs ?? this.requestTimeoutMs);
|
|
31213
|
-
this.pending.set(key2, { resolve:
|
|
31304
|
+
this.pending.set(key2, { resolve: resolve3, reject, timer: timer2, method });
|
|
31214
31305
|
try {
|
|
31215
31306
|
this.writeFrame(frame);
|
|
31216
31307
|
} catch (err) {
|
|
@@ -32215,7 +32306,7 @@ async function assertOpenCodeVersionFloor(executable, options) {
|
|
|
32215
32306
|
const lastMeasuredVersion = options?.lastMeasuredVersion ?? OPENCODE_LAST_MEASURED_VERSION;
|
|
32216
32307
|
const timeoutMs = options?.timeoutMs ?? ACP_VERSION_CHECK_TIMEOUT_MS;
|
|
32217
32308
|
const env = sanitizeChildEnv(options?.env ?? process.env);
|
|
32218
|
-
const stdout = await new Promise((
|
|
32309
|
+
const stdout = await new Promise((resolve3, reject) => {
|
|
32219
32310
|
(0, import_node_child_process3.execFile)(
|
|
32220
32311
|
executable,
|
|
32221
32312
|
["--version"],
|
|
@@ -32229,7 +32320,7 @@ async function assertOpenCodeVersionFloor(executable, options) {
|
|
|
32229
32320
|
);
|
|
32230
32321
|
return;
|
|
32231
32322
|
}
|
|
32232
|
-
|
|
32323
|
+
resolve3(out);
|
|
32233
32324
|
}
|
|
32234
32325
|
);
|
|
32235
32326
|
});
|
|
@@ -32414,7 +32505,7 @@ async function assertOpenCodeEffectiveConfig(options) {
|
|
|
32414
32505
|
`,
|
|
32415
32506
|
{ mode: 384 }
|
|
32416
32507
|
);
|
|
32417
|
-
const stdout = await new Promise((
|
|
32508
|
+
const stdout = await new Promise((resolve3, reject) => {
|
|
32418
32509
|
(0, import_node_child_process3.execFile)(
|
|
32419
32510
|
options.executable,
|
|
32420
32511
|
["debug", "config", "--pure"],
|
|
@@ -32434,7 +32525,7 @@ async function assertOpenCodeEffectiveConfig(options) {
|
|
|
32434
32525
|
);
|
|
32435
32526
|
return;
|
|
32436
32527
|
}
|
|
32437
|
-
|
|
32528
|
+
resolve3(out);
|
|
32438
32529
|
}
|
|
32439
32530
|
);
|
|
32440
32531
|
});
|
|
@@ -32553,11 +32644,11 @@ function waitForChildExit(child, timeoutMs) {
|
|
|
32553
32644
|
if (child.exitCode !== null || child.signalCode !== null) {
|
|
32554
32645
|
return Promise.resolve();
|
|
32555
32646
|
}
|
|
32556
|
-
return new Promise((
|
|
32557
|
-
const timer2 = setTimeout(() =>
|
|
32647
|
+
return new Promise((resolve3) => {
|
|
32648
|
+
const timer2 = setTimeout(() => resolve3(), timeoutMs);
|
|
32558
32649
|
child.once("exit", () => {
|
|
32559
32650
|
clearTimeout(timer2);
|
|
32560
|
-
|
|
32651
|
+
resolve3();
|
|
32561
32652
|
});
|
|
32562
32653
|
});
|
|
32563
32654
|
}
|
|
@@ -32698,6 +32789,7 @@ async function openOpenCodeAcpSession(options) {
|
|
|
32698
32789
|
|
|
32699
32790
|
// src/host/claude.ts
|
|
32700
32791
|
var import_node_child_process4 = require("node:child_process");
|
|
32792
|
+
var import_node_module = require("node:module");
|
|
32701
32793
|
var import_node_fs4 = require("node:fs");
|
|
32702
32794
|
var import_node_path7 = require("node:path");
|
|
32703
32795
|
var CHILD_EXIT_WAIT_MS2 = 3e3;
|
|
@@ -32808,11 +32900,56 @@ function parseClaudeVersionOutput(stdout) {
|
|
|
32808
32900
|
function parseClaudeCodeVersionOutput(stdout) {
|
|
32809
32901
|
return parseProviderVersionOutput(stdout, /\bClaude Code\b/i, false);
|
|
32810
32902
|
}
|
|
32903
|
+
function semanticVersion(value) {
|
|
32904
|
+
if (typeof value !== "string") return null;
|
|
32905
|
+
return parseProviderVersionOutput(`${value}
|
|
32906
|
+
`, /\bnever-a-product-name\b/i);
|
|
32907
|
+
}
|
|
32908
|
+
function readPackageAtOrAbove(entrypoint, expectedName) {
|
|
32909
|
+
let directory = (0, import_node_path7.dirname)(entrypoint);
|
|
32910
|
+
for (let depth = 0; depth < 5; depth += 1) {
|
|
32911
|
+
const path = (0, import_node_path7.join)(directory, "package.json");
|
|
32912
|
+
try {
|
|
32913
|
+
const row = JSON.parse((0, import_node_fs4.readFileSync)(path, "utf8"));
|
|
32914
|
+
if (row && typeof row === "object" && !Array.isArray(row) && row.name === expectedName) {
|
|
32915
|
+
return { path, row };
|
|
32916
|
+
}
|
|
32917
|
+
} catch {
|
|
32918
|
+
}
|
|
32919
|
+
const parent = (0, import_node_path7.dirname)(directory);
|
|
32920
|
+
if (parent === directory) break;
|
|
32921
|
+
directory = parent;
|
|
32922
|
+
}
|
|
32923
|
+
return null;
|
|
32924
|
+
}
|
|
32925
|
+
function measureClaudeBundleVersions(executable) {
|
|
32926
|
+
const adapter = readPackageAtOrAbove(
|
|
32927
|
+
executable,
|
|
32928
|
+
"@agentclientprotocol/claude-agent-acp"
|
|
32929
|
+
);
|
|
32930
|
+
if (!adapter) return { agentSdkVersion: null, claudeCodeVersion: null };
|
|
32931
|
+
try {
|
|
32932
|
+
const sdkEntrypoint = (0, import_node_module.createRequire)(adapter.path).resolve(
|
|
32933
|
+
"@anthropic-ai/claude-agent-sdk"
|
|
32934
|
+
);
|
|
32935
|
+
const sdk = readPackageAtOrAbove(
|
|
32936
|
+
sdkEntrypoint,
|
|
32937
|
+
"@anthropic-ai/claude-agent-sdk"
|
|
32938
|
+
);
|
|
32939
|
+
if (!sdk) return { agentSdkVersion: null, claudeCodeVersion: null };
|
|
32940
|
+
return {
|
|
32941
|
+
agentSdkVersion: semanticVersion(sdk.row.version),
|
|
32942
|
+
claudeCodeVersion: semanticVersion(sdk.row.claudeCodeVersion)
|
|
32943
|
+
};
|
|
32944
|
+
} catch {
|
|
32945
|
+
return { agentSdkVersion: null, claudeCodeVersion: null };
|
|
32946
|
+
}
|
|
32947
|
+
}
|
|
32811
32948
|
async function readClaudeVersionOutput(executable, options) {
|
|
32812
32949
|
const timeoutMs = options?.timeoutMs ?? ACP_VERSION_CHECK_TIMEOUT_MS;
|
|
32813
32950
|
const env = options?.env ?? sanitizeChildEnv(process.env);
|
|
32814
32951
|
const launch = buildClaudeLaunch(executable, ["--version"], options?.platform);
|
|
32815
|
-
return await new Promise((
|
|
32952
|
+
return await new Promise((resolve3, reject) => {
|
|
32816
32953
|
(0, import_node_child_process4.execFile)(
|
|
32817
32954
|
launch.command,
|
|
32818
32955
|
launch.args,
|
|
@@ -32826,29 +32963,26 @@ async function readClaudeVersionOutput(executable, options) {
|
|
|
32826
32963
|
);
|
|
32827
32964
|
return;
|
|
32828
32965
|
}
|
|
32829
|
-
|
|
32966
|
+
resolve3(out);
|
|
32830
32967
|
}
|
|
32831
32968
|
);
|
|
32832
32969
|
});
|
|
32833
32970
|
}
|
|
32834
|
-
async function
|
|
32835
|
-
const
|
|
32836
|
-
|
|
32837
|
-
|
|
32838
|
-
|
|
32839
|
-
|
|
32840
|
-
|
|
32841
|
-
|
|
32842
|
-
|
|
32843
|
-
|
|
32844
|
-
|
|
32845
|
-
|
|
32846
|
-
|
|
32847
|
-
|
|
32848
|
-
|
|
32849
|
-
...options?.onNewerVersion ? { onNewerVersion: options.onNewerVersion } : {}
|
|
32850
|
-
});
|
|
32851
|
-
return version3;
|
|
32971
|
+
async function inspectClaudeBridgeExecutable(executable = "claude-agent-acp", options) {
|
|
32972
|
+
const resolved = resolveClaudeExecutable(
|
|
32973
|
+
executable,
|
|
32974
|
+
options?.pathEnv,
|
|
32975
|
+
options?.platform
|
|
32976
|
+
);
|
|
32977
|
+
const output = await readClaudeVersionOutput(resolved, options);
|
|
32978
|
+
const bundle = measureClaudeBundleVersions(resolved);
|
|
32979
|
+
return {
|
|
32980
|
+
executable: resolved,
|
|
32981
|
+
providerVersion: parseClaudeVersionOutput(output),
|
|
32982
|
+
lastMeasuredVersion: CLAUDE_ACP_LAST_MEASURED_VERSION,
|
|
32983
|
+
bundledAgentSdkVersion: bundle.agentSdkVersion,
|
|
32984
|
+
bundledClaudeCodeVersion: bundle.claudeCodeVersion
|
|
32985
|
+
};
|
|
32852
32986
|
}
|
|
32853
32987
|
function buildClaudeAcpArgs() {
|
|
32854
32988
|
return [];
|
|
@@ -32864,11 +32998,11 @@ function waitForChildExit2(child, timeoutMs) {
|
|
|
32864
32998
|
if (child.exitCode !== null || child.signalCode !== null) {
|
|
32865
32999
|
return Promise.resolve();
|
|
32866
33000
|
}
|
|
32867
|
-
return new Promise((
|
|
32868
|
-
const timer2 = setTimeout(
|
|
33001
|
+
return new Promise((resolve3) => {
|
|
33002
|
+
const timer2 = setTimeout(resolve3, timeoutMs);
|
|
32869
33003
|
child.once("exit", () => {
|
|
32870
33004
|
clearTimeout(timer2);
|
|
32871
|
-
|
|
33005
|
+
resolve3();
|
|
32872
33006
|
});
|
|
32873
33007
|
});
|
|
32874
33008
|
}
|
|
@@ -32913,29 +33047,57 @@ async function openClaudeAcpSession(options) {
|
|
|
32913
33047
|
let executable;
|
|
32914
33048
|
let env = baseEnv;
|
|
32915
33049
|
let claudeCodeExecutable;
|
|
33050
|
+
let providerVersion;
|
|
33051
|
+
let bundleVersions = {
|
|
33052
|
+
agentSdkVersion: null,
|
|
33053
|
+
claudeCodeVersion: null
|
|
33054
|
+
};
|
|
33055
|
+
const reportRuntime = (resolved, version3) => {
|
|
33056
|
+
bundleVersions = measureClaudeBundleVersions(resolved);
|
|
33057
|
+
options.onRuntimeNotice?.({
|
|
33058
|
+
executable: resolved,
|
|
33059
|
+
providerVersion: version3,
|
|
33060
|
+
lastMeasuredVersion: CLAUDE_ACP_LAST_MEASURED_VERSION,
|
|
33061
|
+
bundledAgentSdkVersion: bundleVersions.agentSdkVersion,
|
|
33062
|
+
bundledClaudeCodeVersion: bundleVersions.claudeCodeVersion
|
|
33063
|
+
});
|
|
33064
|
+
};
|
|
33065
|
+
const admitBridgeVersion = (resolved, version3) => {
|
|
33066
|
+
providerVersion = version3;
|
|
33067
|
+
reportRuntime(resolved, version3);
|
|
33068
|
+
assertProviderVersionFloor({
|
|
33069
|
+
provider: "claude-agent-acp",
|
|
33070
|
+
version: version3,
|
|
33071
|
+
minimumVersion: CLAUDE_ACP_MIN_VERSION,
|
|
33072
|
+
lastMeasuredVersion: CLAUDE_ACP_LAST_MEASURED_VERSION,
|
|
33073
|
+
...options.onVersionNotice ? { onNewerVersion: options.onVersionNotice } : {}
|
|
33074
|
+
});
|
|
33075
|
+
};
|
|
32916
33076
|
if (requestedExecutable) {
|
|
32917
33077
|
const output = await readClaudeVersionOutput(requestedExecutable, {
|
|
32918
33078
|
env: baseEnv
|
|
32919
33079
|
});
|
|
32920
33080
|
const bridgeVersion = parseClaudeVersionOutput(output);
|
|
32921
33081
|
if (bridgeVersion) {
|
|
32922
|
-
assertProviderVersionFloor({
|
|
32923
|
-
provider: "claude-agent-acp",
|
|
32924
|
-
version: bridgeVersion,
|
|
32925
|
-
minimumVersion: CLAUDE_ACP_MIN_VERSION,
|
|
32926
|
-
lastMeasuredVersion: CLAUDE_ACP_LAST_MEASURED_VERSION,
|
|
32927
|
-
...options.onVersionNotice ? { onNewerVersion: options.onVersionNotice } : {}
|
|
32928
|
-
});
|
|
32929
33082
|
executable = requestedExecutable;
|
|
33083
|
+
admitBridgeVersion(executable, bridgeVersion);
|
|
32930
33084
|
} else if (parseClaudeCodeVersionOutput(output)) {
|
|
32931
33085
|
claudeCodeExecutable = requestedExecutable;
|
|
32932
33086
|
executable = resolvePackagedClaudeBridge(resolvedPathEnv);
|
|
32933
33087
|
env = buildClaudeChildEnv(parentEnv, claudeCodeExecutable);
|
|
32934
|
-
await
|
|
32935
|
-
env
|
|
32936
|
-
...options.onVersionNotice ? { onNewerVersion: options.onVersionNotice } : {}
|
|
33088
|
+
const bridgeOutput = await readClaudeVersionOutput(executable, {
|
|
33089
|
+
env
|
|
32937
33090
|
});
|
|
33091
|
+
const packagedVersion = parseClaudeVersionOutput(bridgeOutput);
|
|
33092
|
+
if (!packagedVersion) {
|
|
33093
|
+
reportRuntime(executable, null);
|
|
33094
|
+
throw new AcpVersionParseError(
|
|
33095
|
+
`could not parse claude-agent-acp version from: ${bridgeOutput.trim().slice(0, 200)}`
|
|
33096
|
+
);
|
|
33097
|
+
}
|
|
33098
|
+
admitBridgeVersion(executable, packagedVersion);
|
|
32938
33099
|
} else {
|
|
33100
|
+
reportRuntime(requestedExecutable, null);
|
|
32939
33101
|
throw new AcpVersionError(
|
|
32940
33102
|
`could not identify Claude executable from: ${output.trim().slice(0, 200)}`
|
|
32941
33103
|
);
|
|
@@ -32946,10 +33108,19 @@ async function openClaudeAcpSession(options) {
|
|
|
32946
33108
|
resolvedPathEnv
|
|
32947
33109
|
);
|
|
32948
33110
|
if (!options.skipVersionCheck) {
|
|
32949
|
-
await
|
|
32950
|
-
env: baseEnv
|
|
32951
|
-
...options.onVersionNotice ? { onNewerVersion: options.onVersionNotice } : {}
|
|
33111
|
+
const output = await readClaudeVersionOutput(executable, {
|
|
33112
|
+
env: baseEnv
|
|
32952
33113
|
});
|
|
33114
|
+
const version3 = parseClaudeVersionOutput(output);
|
|
33115
|
+
if (!version3) {
|
|
33116
|
+
reportRuntime(executable, null);
|
|
33117
|
+
throw new AcpVersionParseError(
|
|
33118
|
+
`could not parse claude-agent-acp version from: ${output.trim().slice(0, 200)}`
|
|
33119
|
+
);
|
|
33120
|
+
}
|
|
33121
|
+
admitBridgeVersion(executable, version3);
|
|
33122
|
+
} else {
|
|
33123
|
+
reportRuntime(executable, null);
|
|
32953
33124
|
}
|
|
32954
33125
|
}
|
|
32955
33126
|
if (options.signal?.aborted) {
|
|
@@ -33041,7 +33212,17 @@ async function openClaudeAcpSession(options) {
|
|
|
33041
33212
|
})();
|
|
33042
33213
|
return closePromise;
|
|
33043
33214
|
};
|
|
33044
|
-
return {
|
|
33215
|
+
return {
|
|
33216
|
+
session,
|
|
33217
|
+
child,
|
|
33218
|
+
executable,
|
|
33219
|
+
args,
|
|
33220
|
+
env,
|
|
33221
|
+
...providerVersion ? { providerVersion } : {},
|
|
33222
|
+
...bundleVersions.agentSdkVersion ? { bundledAgentSdkVersion: bundleVersions.agentSdkVersion } : {},
|
|
33223
|
+
...bundleVersions.claudeCodeVersion ? { bundledClaudeCodeVersion: bundleVersions.claudeCodeVersion } : {},
|
|
33224
|
+
close
|
|
33225
|
+
};
|
|
33045
33226
|
} catch (error) {
|
|
33046
33227
|
removeAbortListener();
|
|
33047
33228
|
transport.close();
|
|
@@ -33141,7 +33322,7 @@ async function assertCodexVersionFloor(executable, options) {
|
|
|
33141
33322
|
const timeoutMs = options?.timeoutMs ?? ACP_VERSION_CHECK_TIMEOUT_MS;
|
|
33142
33323
|
const env = options?.env ?? sanitizeChildEnv(process.env);
|
|
33143
33324
|
const launch = buildCodexLaunch(executable, ["--version"], options?.platform);
|
|
33144
|
-
const stdout = await new Promise((
|
|
33325
|
+
const stdout = await new Promise((resolve3, reject) => {
|
|
33145
33326
|
(0, import_node_child_process5.execFile)(
|
|
33146
33327
|
launch.command,
|
|
33147
33328
|
launch.args,
|
|
@@ -33155,7 +33336,7 @@ async function assertCodexVersionFloor(executable, options) {
|
|
|
33155
33336
|
);
|
|
33156
33337
|
return;
|
|
33157
33338
|
}
|
|
33158
|
-
|
|
33339
|
+
resolve3(out);
|
|
33159
33340
|
}
|
|
33160
33341
|
);
|
|
33161
33342
|
});
|
|
@@ -33195,11 +33376,11 @@ function waitForChildExit3(child, timeoutMs) {
|
|
|
33195
33376
|
if (child.exitCode !== null || child.signalCode !== null) {
|
|
33196
33377
|
return Promise.resolve();
|
|
33197
33378
|
}
|
|
33198
|
-
return new Promise((
|
|
33199
|
-
const timer2 = setTimeout(
|
|
33379
|
+
return new Promise((resolve3) => {
|
|
33380
|
+
const timer2 = setTimeout(resolve3, timeoutMs);
|
|
33200
33381
|
child.once("exit", () => {
|
|
33201
33382
|
clearTimeout(timer2);
|
|
33202
|
-
|
|
33383
|
+
resolve3();
|
|
33203
33384
|
});
|
|
33204
33385
|
});
|
|
33205
33386
|
}
|
|
@@ -33893,6 +34074,18 @@ var V1_EFFECT_KEYS = /* @__PURE__ */ new Set([
|
|
|
33893
34074
|
"updatedAt"
|
|
33894
34075
|
]);
|
|
33895
34076
|
var V2_EFFECT_KEYS = /* @__PURE__ */ new Set([...V1_EFFECT_KEYS, "signalKind"]);
|
|
34077
|
+
var EFFECT_SENSITIVE_KEYS = /* @__PURE__ */ new Set([
|
|
34078
|
+
"lease_id",
|
|
34079
|
+
"leaseId",
|
|
34080
|
+
"listenerBearer",
|
|
34081
|
+
"bearer",
|
|
34082
|
+
"token",
|
|
34083
|
+
"prompt",
|
|
34084
|
+
"ackCommandId",
|
|
34085
|
+
"ack_command_id",
|
|
34086
|
+
"claimCommandId",
|
|
34087
|
+
"claim_command_id"
|
|
34088
|
+
]);
|
|
33896
34089
|
function defaultListenerStateDirectory() {
|
|
33897
34090
|
return process.env.XDG_STATE_HOME ? (0, import_node_path9.join)(process.env.XDG_STATE_HOME, "cswarm", "listeners") : (0, import_node_path9.join)((0, import_node_os6.homedir)(), ".cswarm", "listeners");
|
|
33898
34091
|
}
|
|
@@ -33911,9 +34104,9 @@ function integer(value) {
|
|
|
33911
34104
|
function nullableString2(value, max) {
|
|
33912
34105
|
return value === null || typeof value === "string" && value.length <= max;
|
|
33913
34106
|
}
|
|
33914
|
-
function
|
|
34107
|
+
function rejectSensitiveKeys(row) {
|
|
33915
34108
|
for (const key2 of Object.keys(row)) {
|
|
33916
|
-
if (
|
|
34109
|
+
if (EFFECT_SENSITIVE_KEYS.has(key2)) {
|
|
33917
34110
|
throw new Error("stored listener effect is malformed");
|
|
33918
34111
|
}
|
|
33919
34112
|
}
|
|
@@ -33929,17 +34122,16 @@ function parseListenerEffectRecord(raw, expectedId) {
|
|
|
33929
34122
|
throw new Error("stored listener effect is malformed");
|
|
33930
34123
|
}
|
|
33931
34124
|
const row = value;
|
|
34125
|
+
rejectSensitiveKeys(row);
|
|
33932
34126
|
if (typeof row.version !== "number" || row.version !== 1 && row.version !== 2 || typeof row.signalId !== "string" || row.signalId.toLowerCase() !== expectedId || !UUID_RE13.test(row.signalId)) {
|
|
33933
34127
|
throw new Error("stored listener effect is malformed");
|
|
33934
34128
|
}
|
|
33935
34129
|
if (row.version === 1) {
|
|
33936
|
-
rejectUnknownKeys(row, V1_EFFECT_KEYS);
|
|
33937
34130
|
if ("signalKind" in row || row.state === "observed" || row.state === "routed_main") {
|
|
33938
34131
|
throw new Error("stored listener effect is malformed");
|
|
33939
34132
|
}
|
|
33940
34133
|
return upcastV1Ask(row);
|
|
33941
34134
|
}
|
|
33942
|
-
rejectUnknownKeys(row, V2_EFFECT_KEYS);
|
|
33943
34135
|
return parseV2Record(row);
|
|
33944
34136
|
}
|
|
33945
34137
|
function upcastV1Ask(row) {
|
|
@@ -34181,7 +34373,7 @@ async function assertGrokVersionFloor(executable, options) {
|
|
|
34181
34373
|
const minimumVersion = options?.minimumVersion ?? GROK_MIN_VERSION;
|
|
34182
34374
|
const lastMeasuredVersion = options?.lastMeasuredVersion ?? GROK_LAST_MEASURED_VERSION;
|
|
34183
34375
|
const timeoutMs = options?.timeoutMs ?? ACP_VERSION_CHECK_TIMEOUT_MS;
|
|
34184
|
-
const stdout = await new Promise((
|
|
34376
|
+
const stdout = await new Promise((resolve3, reject) => {
|
|
34185
34377
|
(0, import_node_child_process6.execFile)(
|
|
34186
34378
|
executable,
|
|
34187
34379
|
["--version"],
|
|
@@ -34195,7 +34387,7 @@ async function assertGrokVersionFloor(executable, options) {
|
|
|
34195
34387
|
);
|
|
34196
34388
|
return;
|
|
34197
34389
|
}
|
|
34198
|
-
|
|
34390
|
+
resolve3(out);
|
|
34199
34391
|
}
|
|
34200
34392
|
);
|
|
34201
34393
|
});
|
|
@@ -34238,11 +34430,11 @@ function waitForChildExit4(child, timeoutMs) {
|
|
|
34238
34430
|
if (child.exitCode !== null || child.signalCode !== null) {
|
|
34239
34431
|
return Promise.resolve();
|
|
34240
34432
|
}
|
|
34241
|
-
return new Promise((
|
|
34242
|
-
const timer2 = setTimeout(
|
|
34433
|
+
return new Promise((resolve3) => {
|
|
34434
|
+
const timer2 = setTimeout(resolve3, timeoutMs);
|
|
34243
34435
|
child.once("exit", () => {
|
|
34244
34436
|
clearTimeout(timer2);
|
|
34245
|
-
|
|
34437
|
+
resolve3();
|
|
34246
34438
|
});
|
|
34247
34439
|
});
|
|
34248
34440
|
}
|
|
@@ -34392,6 +34584,7 @@ var GrokListenerModel = class {
|
|
|
34392
34584
|
...this.options.effort ? { effort: this.options.effort } : {},
|
|
34393
34585
|
...this.options.env ? { env: this.options.env } : {},
|
|
34394
34586
|
...this.options.onVersionNotice ? { onVersionNotice: this.options.onVersionNotice } : {},
|
|
34587
|
+
...this.options.events ? { events: this.options.events } : {},
|
|
34395
34588
|
...this.options.onWorkerStderrTail ? { onStderrTail: this.options.onWorkerStderrTail } : {},
|
|
34396
34589
|
clientName: "cswarm-listener"
|
|
34397
34590
|
});
|
|
@@ -34652,10 +34845,10 @@ var OpenCodeListenerModel = class {
|
|
|
34652
34845
|
try {
|
|
34653
34846
|
await Promise.race([
|
|
34654
34847
|
entry.settlePromise,
|
|
34655
|
-
new Promise((
|
|
34848
|
+
new Promise((resolve3) => {
|
|
34656
34849
|
entry.timer = setTimeout(() => {
|
|
34657
34850
|
timedOut = true;
|
|
34658
|
-
|
|
34851
|
+
resolve3();
|
|
34659
34852
|
}, this.pendingOpenWaitMs);
|
|
34660
34853
|
})
|
|
34661
34854
|
]);
|
|
@@ -34763,10 +34956,10 @@ var OpenCodeListenerModel = class {
|
|
|
34763
34956
|
});
|
|
34764
34957
|
this.workerHome = home;
|
|
34765
34958
|
let markSettled;
|
|
34766
|
-
const settlePromise = new Promise((
|
|
34959
|
+
const settlePromise = new Promise((resolve3, reject) => {
|
|
34767
34960
|
markSettled = (err) => {
|
|
34768
34961
|
if (err) reject(err);
|
|
34769
|
-
else
|
|
34962
|
+
else resolve3();
|
|
34770
34963
|
};
|
|
34771
34964
|
});
|
|
34772
34965
|
void settlePromise.catch(() => void 0);
|
|
@@ -34832,6 +35025,7 @@ var OpenCodeListenerModel = class {
|
|
|
34832
35025
|
...this.options.model ? { model: this.options.model } : {},
|
|
34833
35026
|
...this.options.env ? { env: this.options.env } : {},
|
|
34834
35027
|
...this.options.onVersionNotice ? { onVersionNotice: this.options.onVersionNotice } : {},
|
|
35028
|
+
...this.options.events ? { events: this.options.events } : {},
|
|
34835
35029
|
...this.options.allowMissingAuth === true ? { allowMissingAuth: true } : {},
|
|
34836
35030
|
...this.options.onWorkerStderrTail ? { onStderrTail: this.options.onWorkerStderrTail } : {},
|
|
34837
35031
|
clientName: "cswarm-listener"
|
|
@@ -34935,6 +35129,35 @@ var import_node_crypto16 = require("node:crypto");
|
|
|
34935
35129
|
var import_promises7 = require("node:fs/promises");
|
|
34936
35130
|
var import_node_os8 = require("node:os");
|
|
34937
35131
|
var import_node_path13 = require("node:path");
|
|
35132
|
+
var CLAUDE_CODE_VERSION_REQUIRED_RE = /\bClaude Code (\d+\.\d+\.\d+) does not support this model; version (\d+\.\d+\.\d+) or newer is required\b/;
|
|
35133
|
+
var CLAUDE_AUTH_FAILURE_RE = /\b(?:authentication failed|authentication required|not authenticated|OAuth (?:sign-in|login|token)|keychain\/OAuth|please (?:log|sign) in)\b/i;
|
|
35134
|
+
var CLAUDE_CANARY_TIMEOUT_RE = /^ACP request timed out: session\/prompt(?: \(failed \d+ attempts\))?$/;
|
|
35135
|
+
function classifyClaudeCanaryFailure(detail, typedReasonCode) {
|
|
35136
|
+
const recorded = detail?.trim() ?? "";
|
|
35137
|
+
const demanded = CLAUDE_CODE_VERSION_REQUIRED_RE.exec(recorded);
|
|
35138
|
+
if (demanded?.[2]) {
|
|
35139
|
+
return {
|
|
35140
|
+
code: "claude_bridge_version_required",
|
|
35141
|
+
minimumRequiredVersion: demanded[2]
|
|
35142
|
+
};
|
|
35143
|
+
}
|
|
35144
|
+
if (typedReasonCode === "claude_canary_timeout" || typedReasonCode === "timeout" || (typedReasonCode === null || typedReasonCode === void 0) && CLAUDE_CANARY_TIMEOUT_RE.test(recorded)) {
|
|
35145
|
+
return { code: "claude_canary_timeout", minimumRequiredVersion: null };
|
|
35146
|
+
}
|
|
35147
|
+
if (typedReasonCode === "claude_canary_auth_failed") {
|
|
35148
|
+
return { code: "claude_canary_auth_failed", minimumRequiredVersion: null };
|
|
35149
|
+
}
|
|
35150
|
+
if (typedReasonCode === "claude_bridge_version_required") {
|
|
35151
|
+
return {
|
|
35152
|
+
code: "claude_bridge_version_required",
|
|
35153
|
+
minimumRequiredVersion: demanded?.[2] ?? null
|
|
35154
|
+
};
|
|
35155
|
+
}
|
|
35156
|
+
if ((typedReasonCode === "rpc_error" || typedReasonCode === null || typedReasonCode === void 0) && CLAUDE_AUTH_FAILURE_RE.test(recorded)) {
|
|
35157
|
+
return { code: "claude_canary_auth_failed", minimumRequiredVersion: null };
|
|
35158
|
+
}
|
|
35159
|
+
return { code: "claude_canary_unknown", minimumRequiredVersion: null };
|
|
35160
|
+
}
|
|
34938
35161
|
var ClaudeListenerClosedDuringOpen = class extends Error {
|
|
34939
35162
|
constructor() {
|
|
34940
35163
|
super("listener model closed while the Claude worker was opening");
|
|
@@ -35048,6 +35271,8 @@ var ClaudeListenerModel = class {
|
|
|
35048
35271
|
...this.options.executable ? { executable: this.options.executable } : {},
|
|
35049
35272
|
...this.options.env ? { env: this.options.env } : {},
|
|
35050
35273
|
...this.options.onVersionNotice ? { onVersionNotice: this.options.onVersionNotice } : {},
|
|
35274
|
+
...this.options.onRuntimeNotice ? { onRuntimeNotice: this.options.onRuntimeNotice } : {},
|
|
35275
|
+
...this.options.events ? { events: this.options.events } : {},
|
|
35051
35276
|
signal: controller.signal,
|
|
35052
35277
|
...this.options.onWorkerStderrTail ? { onStderrTail: this.options.onWorkerStderrTail } : {},
|
|
35053
35278
|
clientName: "cswarm-listener"
|
|
@@ -35076,6 +35301,7 @@ var ClaudeListenerModel = class {
|
|
|
35076
35301
|
(0, import_node_os8.tmpdir)(),
|
|
35077
35302
|
`cswarm-claude-permission-canary-${process.pid}-${(0, import_node_crypto16.randomUUID)()}`
|
|
35078
35303
|
);
|
|
35304
|
+
let canaryError;
|
|
35079
35305
|
let sentinelCreated = false;
|
|
35080
35306
|
try {
|
|
35081
35307
|
await handle.session.enablePromptsAfterCanary({
|
|
@@ -35083,6 +35309,8 @@ var ClaudeListenerModel = class {
|
|
|
35083
35309
|
probeText: `Create the file ${sentinelPath} using the Write tool with content CSWARM_CANARY_NOOP. You must use the Write tool. Do nothing else.`,
|
|
35084
35310
|
...this.options.onCanaryAttempt ? { onAttempt: this.options.onCanaryAttempt } : {}
|
|
35085
35311
|
});
|
|
35312
|
+
} catch (error) {
|
|
35313
|
+
canaryError = error;
|
|
35086
35314
|
} finally {
|
|
35087
35315
|
try {
|
|
35088
35316
|
await (0, import_promises7.lstat)(sentinelPath);
|
|
@@ -35094,9 +35322,22 @@ var ClaudeListenerModel = class {
|
|
|
35094
35322
|
}
|
|
35095
35323
|
if (sentinelCreated) {
|
|
35096
35324
|
throw new AcpPermissionCanaryError(
|
|
35097
|
-
"Claude bridge wrote the permission canary sentinel before denial"
|
|
35325
|
+
"Claude bridge wrote the permission canary sentinel before denial",
|
|
35326
|
+
"claude_canary_write_not_blocked"
|
|
35098
35327
|
);
|
|
35099
35328
|
}
|
|
35329
|
+
if (canaryError instanceof AcpPermissionCanaryError) {
|
|
35330
|
+
const shape = classifyClaudeCanaryFailure(
|
|
35331
|
+
canaryError.message,
|
|
35332
|
+
canaryError.reasonCode
|
|
35333
|
+
);
|
|
35334
|
+
throw new AcpPermissionCanaryError(
|
|
35335
|
+
canaryError.message,
|
|
35336
|
+
shape.code,
|
|
35337
|
+
shape.minimumRequiredVersion
|
|
35338
|
+
);
|
|
35339
|
+
}
|
|
35340
|
+
if (canaryError !== void 0) throw canaryError;
|
|
35100
35341
|
}
|
|
35101
35342
|
};
|
|
35102
35343
|
|
|
@@ -35222,6 +35463,7 @@ var CodexListenerModel = class {
|
|
|
35222
35463
|
...this.options.executable ? { executable: this.options.executable } : {},
|
|
35223
35464
|
...this.options.env ? { env: this.options.env } : {},
|
|
35224
35465
|
...this.options.onVersionNotice ? { onVersionNotice: this.options.onVersionNotice } : {},
|
|
35466
|
+
...this.options.events ? { events: this.options.events } : {},
|
|
35225
35467
|
signal: controller.signal,
|
|
35226
35468
|
...this.options.onWorkerStderrTail ? { onStderrTail: this.options.onWorkerStderrTail } : {},
|
|
35227
35469
|
clientName: "cswarm-listener"
|
|
@@ -35753,8 +35995,8 @@ var DeliveryCommandClient = class {
|
|
|
35753
35995
|
const signal = deadlineController.signal;
|
|
35754
35996
|
let onAbort = () => {
|
|
35755
35997
|
};
|
|
35756
|
-
const aborted = new Promise((
|
|
35757
|
-
onAbort = () =>
|
|
35998
|
+
const aborted = new Promise((resolve3) => {
|
|
35999
|
+
onAbort = () => resolve3("timeout");
|
|
35758
36000
|
if (signal.aborted) {
|
|
35759
36001
|
onAbort();
|
|
35760
36002
|
} else {
|
|
@@ -35909,6 +36151,21 @@ var UUID_RE15 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-
|
|
|
35909
36151
|
var MAX_QUEUE_BYTES = 1024 * 1024;
|
|
35910
36152
|
var QUEUE_FILE = "pending-for-main.json";
|
|
35911
36153
|
var QUEUE_LOCK = "pending-for-main";
|
|
36154
|
+
var QUEUE_KEYS = /* @__PURE__ */ new Set(["version", "entries", "droppedCount"]);
|
|
36155
|
+
var ENTRY_KEYS = /* @__PURE__ */ new Set([
|
|
36156
|
+
"signalId",
|
|
36157
|
+
"workspaceId",
|
|
36158
|
+
"principalId",
|
|
36159
|
+
"fromId",
|
|
36160
|
+
"fromKind",
|
|
36161
|
+
"kind",
|
|
36162
|
+
"senderName",
|
|
36163
|
+
"body",
|
|
36164
|
+
"attachmentCount",
|
|
36165
|
+
"createdAt",
|
|
36166
|
+
"queuedAt",
|
|
36167
|
+
"observationPending"
|
|
36168
|
+
]);
|
|
35912
36169
|
var LISTENER_MAIN_QUEUE_MAX = 200;
|
|
35913
36170
|
var LISTENER_DEFER_OVER_MIN = 1;
|
|
35914
36171
|
var LISTENER_DEFER_OVER_MAX = 1e4;
|
|
@@ -35939,26 +36196,12 @@ function decideListenerRoute(route, threshold, bodyLength) {
|
|
|
35939
36196
|
function checkedTimestamp2(value) {
|
|
35940
36197
|
return typeof value === "string" && Number.isFinite(Date.parse(value));
|
|
35941
36198
|
}
|
|
35942
|
-
function parseEntry(value) {
|
|
36199
|
+
function parseEntry(value, rejectUnknownKeys) {
|
|
35943
36200
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
35944
36201
|
throw new Error("stored pending-for-main entry is malformed");
|
|
35945
36202
|
}
|
|
35946
36203
|
const row = value;
|
|
35947
|
-
|
|
35948
|
-
"signalId",
|
|
35949
|
-
"workspaceId",
|
|
35950
|
-
"principalId",
|
|
35951
|
-
"fromId",
|
|
35952
|
-
"fromKind",
|
|
35953
|
-
"kind",
|
|
35954
|
-
"senderName",
|
|
35955
|
-
"body",
|
|
35956
|
-
"attachmentCount",
|
|
35957
|
-
"createdAt",
|
|
35958
|
-
"queuedAt",
|
|
35959
|
-
"observationPending"
|
|
35960
|
-
]);
|
|
35961
|
-
if (Object.keys(row).some((key2) => !allowed.has(key2))) {
|
|
36204
|
+
if (rejectUnknownKeys && Object.keys(row).some((key2) => !ENTRY_KEYS.has(key2))) {
|
|
35962
36205
|
throw new Error("stored pending-for-main entry is malformed");
|
|
35963
36206
|
}
|
|
35964
36207
|
if (typeof row.signalId !== "string" || !UUID_RE15.test(row.signalId) || typeof row.workspaceId !== "string" || !UUID_RE15.test(row.workspaceId) || typeof row.principalId !== "string" || !UUID_RE15.test(row.principalId) || typeof row.fromId !== "string" || !UUID_RE15.test(row.fromId) || row.fromKind !== "user" && row.fromKind !== "agent" || !(row.kind === void 0 || row.kind === "ask" || row.kind === "note") || !(row.senderName === null || typeof row.senderName === "string" && row.senderName.length <= 200) || typeof row.body !== "string" || row.body.length < 1 || !(row.attachmentCount === void 0 || typeof row.attachmentCount === "number" && Number.isSafeInteger(row.attachmentCount) && row.attachmentCount >= 1 && row.attachmentCount <= 8) || !checkedTimestamp2(row.createdAt) || !checkedTimestamp2(row.queuedAt) || !(row.observationPending === void 0 || row.observationPending === true)) {
|
|
@@ -35979,7 +36222,7 @@ function parseEntry(value) {
|
|
|
35979
36222
|
...row.observationPending === true ? { observationPending: true } : {}
|
|
35980
36223
|
};
|
|
35981
36224
|
}
|
|
35982
|
-
function parseFile(raw) {
|
|
36225
|
+
function parseFile(raw, rejectUnknownKeys = false) {
|
|
35983
36226
|
let value;
|
|
35984
36227
|
try {
|
|
35985
36228
|
value = JSON.parse(raw);
|
|
@@ -35990,12 +36233,10 @@ function parseFile(raw) {
|
|
|
35990
36233
|
throw new Error("stored pending-for-main queue is malformed");
|
|
35991
36234
|
}
|
|
35992
36235
|
const row = value;
|
|
35993
|
-
if (Object.keys(row).some(
|
|
35994
|
-
(key2) => key2 !== "version" && key2 !== "entries" && key2 !== "droppedCount"
|
|
35995
|
-
) || row.version !== 1 || !Array.isArray(row.entries) || row.entries.length > LISTENER_MAIN_QUEUE_MAX || !(row.droppedCount === void 0 || typeof row.droppedCount === "number" && Number.isSafeInteger(row.droppedCount) && row.droppedCount >= 0)) {
|
|
36236
|
+
if (rejectUnknownKeys && Object.keys(row).some((key2) => !QUEUE_KEYS.has(key2)) || row.version !== 1 || !Array.isArray(row.entries) || row.entries.length > LISTENER_MAIN_QUEUE_MAX || !(row.droppedCount === void 0 || typeof row.droppedCount === "number" && Number.isSafeInteger(row.droppedCount) && row.droppedCount >= 0)) {
|
|
35996
36237
|
throw new Error("stored pending-for-main queue is malformed");
|
|
35997
36238
|
}
|
|
35998
|
-
const entries = row.entries.map(parseEntry);
|
|
36239
|
+
const entries = row.entries.map((entry) => parseEntry(entry, rejectUnknownKeys));
|
|
35999
36240
|
if (new Set(entries.map((entry) => entry.signalId)).size !== entries.length) {
|
|
36000
36241
|
throw new Error("stored pending-for-main queue repeats a signal");
|
|
36001
36242
|
}
|
|
@@ -36016,7 +36257,7 @@ var FilePendingMainQueue = class {
|
|
|
36016
36257
|
return raw === null ? { version: 1, entries: [], droppedCount: 0 } : parseFile(raw);
|
|
36017
36258
|
}
|
|
36018
36259
|
async writeUnlocked(file) {
|
|
36019
|
-
const canonical = parseFile(JSON.stringify(file));
|
|
36260
|
+
const canonical = parseFile(JSON.stringify(file), true);
|
|
36020
36261
|
await writeSecureJsonFile(this.path, JSON.stringify(canonical));
|
|
36021
36262
|
}
|
|
36022
36263
|
async read() {
|
|
@@ -36030,7 +36271,7 @@ var FilePendingMainQueue = class {
|
|
|
36030
36271
|
return { count: file.entries.length, droppedCount: file.droppedCount };
|
|
36031
36272
|
}
|
|
36032
36273
|
async enqueue(entry) {
|
|
36033
|
-
const checked = parseEntry(entry);
|
|
36274
|
+
const checked = parseEntry(entry, true);
|
|
36034
36275
|
return await withFileLock(this.directory, QUEUE_LOCK, async () => {
|
|
36035
36276
|
const file = await this.readUnlocked();
|
|
36036
36277
|
if (file.entries.some((item) => item.signalId === checked.signalId)) {
|
|
@@ -36089,7 +36330,7 @@ function pendingMainEntry(signal, principalId, provenance, now, options = {}) {
|
|
|
36089
36330
|
createdAt: signal.created_at,
|
|
36090
36331
|
queuedAt: new Date(now).toISOString(),
|
|
36091
36332
|
...options.observationPending ? { observationPending: true } : {}
|
|
36092
|
-
});
|
|
36333
|
+
}, true);
|
|
36093
36334
|
}
|
|
36094
36335
|
|
|
36095
36336
|
// src/listener/runtime.ts
|
|
@@ -36102,6 +36343,7 @@ var LISTENER_REPLY_ONLY_MINIMUM_MS = SIGNAL_REQUEST_TIMEOUT_MS + LISTENER_ACK_ON
|
|
|
36102
36343
|
var LISTENER_PROMPT_START_MINIMUM_MS = SIGNAL_READ_TIMEOUT_MS + ACP_DEFAULT_REQUEST_TIMEOUT_MS + LISTENER_REPLY_ONLY_MINIMUM_MS;
|
|
36103
36344
|
var LISTENER_DELIVERY_RETRY_INITIAL_MS = 500;
|
|
36104
36345
|
var LISTENER_DELIVERY_RETRY_MAX_MS = 3e4;
|
|
36346
|
+
var LISTENER_HOST_PORTS_PROBE_MS = 6e4;
|
|
36105
36347
|
var UUID_RE16 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
36106
36348
|
var ListenerCapabilityError = class extends Error {
|
|
36107
36349
|
code;
|
|
@@ -36234,12 +36476,12 @@ function eventTime(now) {
|
|
|
36234
36476
|
}
|
|
36235
36477
|
async function defaultSleep(ms, signal) {
|
|
36236
36478
|
if (signal?.aborted) return;
|
|
36237
|
-
await new Promise((
|
|
36479
|
+
await new Promise((resolve3) => {
|
|
36238
36480
|
let timer2;
|
|
36239
36481
|
const finish = () => {
|
|
36240
36482
|
if (timer2 !== void 0) clearTimeout(timer2);
|
|
36241
36483
|
signal?.removeEventListener("abort", finish);
|
|
36242
|
-
|
|
36484
|
+
resolve3();
|
|
36243
36485
|
};
|
|
36244
36486
|
signal?.addEventListener("abort", finish, { once: true });
|
|
36245
36487
|
timer2 = setTimeout(finish, ms);
|
|
@@ -36536,6 +36778,8 @@ async function runListenerRuntime(options) {
|
|
|
36536
36778
|
let ready = false;
|
|
36537
36779
|
let deliveryMode = null;
|
|
36538
36780
|
let readAttempt = 0;
|
|
36781
|
+
let readEpisodeStartedAtMs = null;
|
|
36782
|
+
let readEpisodeAttempts = 0;
|
|
36539
36783
|
const onAbort = () => {
|
|
36540
36784
|
options.model.cancel();
|
|
36541
36785
|
};
|
|
@@ -36633,6 +36877,18 @@ async function runListenerRuntime(options) {
|
|
|
36633
36877
|
}
|
|
36634
36878
|
});
|
|
36635
36879
|
requireCapabilities(page);
|
|
36880
|
+
if (ready && readEpisodeStartedAtMs !== null) {
|
|
36881
|
+
const recoveredAtMs = now();
|
|
36882
|
+
options.onEvent?.({
|
|
36883
|
+
type: "read_recovered",
|
|
36884
|
+
attempts: readEpisodeAttempts,
|
|
36885
|
+
durationMs: Math.max(0, recoveredAtMs - readEpisodeStartedAtMs),
|
|
36886
|
+
startedAt: new Date(readEpisodeStartedAtMs).toISOString(),
|
|
36887
|
+
ts: new Date(recoveredAtMs).toISOString()
|
|
36888
|
+
});
|
|
36889
|
+
readEpisodeStartedAtMs = null;
|
|
36890
|
+
readEpisodeAttempts = 0;
|
|
36891
|
+
}
|
|
36636
36892
|
const nextMode = classifyDeliveryMode(page, durableConfigured);
|
|
36637
36893
|
if (nextMode !== deliveryMode) {
|
|
36638
36894
|
deliveryMode = nextMode;
|
|
@@ -36653,19 +36909,25 @@ async function runListenerRuntime(options) {
|
|
|
36653
36909
|
stop = { reason: "credential", error: asError2(error) };
|
|
36654
36910
|
break;
|
|
36655
36911
|
}
|
|
36656
|
-
|
|
36657
|
-
|
|
36658
|
-
break;
|
|
36659
|
-
}
|
|
36660
|
-
if (isRetryableFollowError(error)) {
|
|
36912
|
+
const failure = classifySignalReadFailure(error);
|
|
36913
|
+
if (isRetryableFollowError(error) || failure.code === "aborted" || failure.code === "host_ports_exhausted") {
|
|
36661
36914
|
readAttempt += 1;
|
|
36662
|
-
const delayMs = nextFollowBackoffMs(readAttempt, null, random);
|
|
36915
|
+
const delayMs = failure.code === "host_ports_exhausted" ? LISTENER_HOST_PORTS_PROBE_MS : nextFollowBackoffMs(readAttempt, null, random);
|
|
36663
36916
|
if (ready) {
|
|
36917
|
+
const failedAtMs = now();
|
|
36918
|
+
if (readEpisodeStartedAtMs === null) {
|
|
36919
|
+
readEpisodeStartedAtMs = failedAtMs;
|
|
36920
|
+
readEpisodeAttempts = 0;
|
|
36921
|
+
}
|
|
36922
|
+
readEpisodeAttempts += 1;
|
|
36664
36923
|
options.onEvent?.({
|
|
36665
36924
|
type: "read_retry",
|
|
36666
36925
|
attempt: readAttempt,
|
|
36926
|
+
episodeAttempt: readEpisodeAttempts,
|
|
36927
|
+
episodeStartedAt: new Date(readEpisodeStartedAtMs).toISOString(),
|
|
36928
|
+
failure,
|
|
36667
36929
|
delayMs,
|
|
36668
|
-
ts:
|
|
36930
|
+
ts: new Date(failedAtMs).toISOString()
|
|
36669
36931
|
});
|
|
36670
36932
|
}
|
|
36671
36933
|
await sleep2(delayMs, abort);
|
|
@@ -36688,6 +36950,7 @@ async function runListenerRuntime(options) {
|
|
|
36688
36950
|
type: "ready",
|
|
36689
36951
|
workspaceId: options.workspaceId,
|
|
36690
36952
|
principalId: options.principalId,
|
|
36953
|
+
cadenceMs: pollMs,
|
|
36691
36954
|
ts: eventTime(now)
|
|
36692
36955
|
});
|
|
36693
36956
|
if (options.declareModel !== void 0) {
|
|
@@ -37217,13 +37480,262 @@ async function runListenerRuntime(options) {
|
|
|
37217
37480
|
return stop ?? { reason: "cancelled" };
|
|
37218
37481
|
}
|
|
37219
37482
|
|
|
37483
|
+
// src/listener/read-health.ts
|
|
37484
|
+
var HOUR_MS = 60 * 6e4;
|
|
37485
|
+
var MINUTE_MS = 6e4;
|
|
37486
|
+
var HEALTH_WINDOW_MS = 24 * HOUR_MS;
|
|
37487
|
+
var LISTENER_READ_RETRY_HOUR_CAP = 25;
|
|
37488
|
+
var LISTENER_READ_RETRY_MINUTE_CAP = 61;
|
|
37489
|
+
var LISTENER_CLAIM_HOUR_CAP = 25;
|
|
37490
|
+
var LISTENER_THROUGHPUT_LAPSE_RATIO = 0.5;
|
|
37491
|
+
var FAILURE_CODES = /* @__PURE__ */ new Set([
|
|
37492
|
+
"http_status",
|
|
37493
|
+
"no_response",
|
|
37494
|
+
"body_timeout",
|
|
37495
|
+
"malformed_response",
|
|
37496
|
+
"aborted",
|
|
37497
|
+
"host_ports_exhausted",
|
|
37498
|
+
"unclassified"
|
|
37499
|
+
]);
|
|
37500
|
+
function emptyListenerReadHealth() {
|
|
37501
|
+
return {
|
|
37502
|
+
currentEpisodeStartedAt: null,
|
|
37503
|
+
currentEpisodeAttempts: 0,
|
|
37504
|
+
currentReasonCode: null,
|
|
37505
|
+
currentHttpStatus: null,
|
|
37506
|
+
currentErrorConstructor: null,
|
|
37507
|
+
retryHours: [],
|
|
37508
|
+
retryMinutes: [],
|
|
37509
|
+
claimCadenceMs: null,
|
|
37510
|
+
claimHours: []
|
|
37511
|
+
};
|
|
37512
|
+
}
|
|
37513
|
+
function bucketStart(ts, sizeMs) {
|
|
37514
|
+
const time = Date.parse(ts);
|
|
37515
|
+
return new Date(Math.floor(time / sizeMs) * sizeMs).toISOString();
|
|
37516
|
+
}
|
|
37517
|
+
function trimNewest(rows3, cap) {
|
|
37518
|
+
return rows3.sort((left, right) => Date.parse(left.hourStart) - Date.parse(right.hourStart)).slice(-cap);
|
|
37519
|
+
}
|
|
37520
|
+
function recordRetryHour(rows3, ts, episodeStarted) {
|
|
37521
|
+
const hourStart = bucketStart(ts, HOUR_MS);
|
|
37522
|
+
const next = rows3.map((row) => ({ ...row }));
|
|
37523
|
+
const existing = next.find((row) => row.hourStart === hourStart);
|
|
37524
|
+
if (existing) {
|
|
37525
|
+
existing.retries += 1;
|
|
37526
|
+
if (episodeStarted) existing.episodes += 1;
|
|
37527
|
+
} else {
|
|
37528
|
+
next.push({
|
|
37529
|
+
hourStart,
|
|
37530
|
+
retries: 1,
|
|
37531
|
+
episodes: episodeStarted ? 1 : 0,
|
|
37532
|
+
longestEpisodeAttempts: 0,
|
|
37533
|
+
longestEpisodeDurationMs: 0
|
|
37534
|
+
});
|
|
37535
|
+
}
|
|
37536
|
+
return trimNewest(next, LISTENER_READ_RETRY_HOUR_CAP);
|
|
37537
|
+
}
|
|
37538
|
+
function recordRetryMinute(rows3, ts) {
|
|
37539
|
+
const minuteStart = bucketStart(ts, MINUTE_MS);
|
|
37540
|
+
const next = rows3.map((row) => ({ ...row }));
|
|
37541
|
+
const existing = next.find((row) => row.minuteStart === minuteStart);
|
|
37542
|
+
if (existing) {
|
|
37543
|
+
existing.retries += 1;
|
|
37544
|
+
} else {
|
|
37545
|
+
next.push({ minuteStart, retries: 1 });
|
|
37546
|
+
}
|
|
37547
|
+
return next.sort(
|
|
37548
|
+
(left, right) => Date.parse(left.minuteStart) - Date.parse(right.minuteStart)
|
|
37549
|
+
).slice(-LISTENER_READ_RETRY_MINUTE_CAP);
|
|
37550
|
+
}
|
|
37551
|
+
function recordListenerReadRetry(health, input) {
|
|
37552
|
+
return {
|
|
37553
|
+
...health,
|
|
37554
|
+
currentEpisodeStartedAt: input.episodeStartedAt,
|
|
37555
|
+
currentEpisodeAttempts: input.episodeAttempt,
|
|
37556
|
+
currentReasonCode: input.failure.code,
|
|
37557
|
+
currentHttpStatus: input.failure.httpStatus,
|
|
37558
|
+
currentErrorConstructor: input.failure.errorConstructor,
|
|
37559
|
+
retryHours: recordRetryHour(
|
|
37560
|
+
health.retryHours,
|
|
37561
|
+
input.ts,
|
|
37562
|
+
input.episodeAttempt === 1
|
|
37563
|
+
),
|
|
37564
|
+
retryMinutes: recordRetryMinute(health.retryMinutes, input.ts)
|
|
37565
|
+
};
|
|
37566
|
+
}
|
|
37567
|
+
function recordListenerReadRecovery(health, input) {
|
|
37568
|
+
const hourStart = bucketStart(input.startedAt, HOUR_MS);
|
|
37569
|
+
const retryHours = health.retryHours.map((row) => ({ ...row }));
|
|
37570
|
+
const hour = retryHours.find((row) => row.hourStart === hourStart);
|
|
37571
|
+
if (hour) {
|
|
37572
|
+
if (input.durationMs > hour.longestEpisodeDurationMs || input.durationMs === hour.longestEpisodeDurationMs && input.attempts > hour.longestEpisodeAttempts) {
|
|
37573
|
+
hour.longestEpisodeAttempts = input.attempts;
|
|
37574
|
+
hour.longestEpisodeDurationMs = input.durationMs;
|
|
37575
|
+
}
|
|
37576
|
+
}
|
|
37577
|
+
return {
|
|
37578
|
+
...health,
|
|
37579
|
+
currentEpisodeStartedAt: null,
|
|
37580
|
+
currentEpisodeAttempts: 0,
|
|
37581
|
+
currentReasonCode: null,
|
|
37582
|
+
currentHttpStatus: null,
|
|
37583
|
+
currentErrorConstructor: null,
|
|
37584
|
+
retryHours: trimNewest(retryHours, LISTENER_READ_RETRY_HOUR_CAP)
|
|
37585
|
+
};
|
|
37586
|
+
}
|
|
37587
|
+
function recordListenerClaimCadence(health, cadenceMs) {
|
|
37588
|
+
return { ...health, claimCadenceMs: cadenceMs };
|
|
37589
|
+
}
|
|
37590
|
+
function recordListenerClaim(health, ts) {
|
|
37591
|
+
const hourStart = bucketStart(ts, HOUR_MS);
|
|
37592
|
+
const claimHours = health.claimHours.map((row) => ({ ...row }));
|
|
37593
|
+
const hour = claimHours.find((row) => row.hourStart === hourStart);
|
|
37594
|
+
if (hour) hour.claims += 1;
|
|
37595
|
+
else claimHours.push({ hourStart, claims: 1 });
|
|
37596
|
+
return {
|
|
37597
|
+
...health,
|
|
37598
|
+
claimHours: trimNewest(claimHours, LISTENER_CLAIM_HOUR_CAP)
|
|
37599
|
+
};
|
|
37600
|
+
}
|
|
37601
|
+
function hasExpectedKeys(value, expected, rejectUnknownKeys) {
|
|
37602
|
+
const actual = Object.keys(value);
|
|
37603
|
+
const allowed = new Set(expected);
|
|
37604
|
+
return expected.every((key2) => actual.includes(key2)) && (!rejectUnknownKeys || actual.every((key2) => allowed.has(key2)));
|
|
37605
|
+
}
|
|
37606
|
+
function validTimestamp(value) {
|
|
37607
|
+
return typeof value === "string" && Number.isFinite(Date.parse(value));
|
|
37608
|
+
}
|
|
37609
|
+
function validCount(value) {
|
|
37610
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
37611
|
+
}
|
|
37612
|
+
function parseListenerReadHealth(value, rejectUnknownKeys = false) {
|
|
37613
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
37614
|
+
const row = value;
|
|
37615
|
+
if (!hasExpectedKeys(row, [
|
|
37616
|
+
"currentEpisodeStartedAt",
|
|
37617
|
+
"currentEpisodeAttempts",
|
|
37618
|
+
"currentReasonCode",
|
|
37619
|
+
"currentHttpStatus",
|
|
37620
|
+
"currentErrorConstructor",
|
|
37621
|
+
"retryHours",
|
|
37622
|
+
"retryMinutes",
|
|
37623
|
+
"claimCadenceMs",
|
|
37624
|
+
"claimHours"
|
|
37625
|
+
], rejectUnknownKeys)) return null;
|
|
37626
|
+
if (!(row.currentEpisodeStartedAt === null || validTimestamp(row.currentEpisodeStartedAt)) || !validCount(row.currentEpisodeAttempts) || !(row.currentReasonCode === null || typeof row.currentReasonCode === "string" && FAILURE_CODES.has(row.currentReasonCode)) || !(row.currentHttpStatus === null || typeof row.currentHttpStatus === "number" && Number.isSafeInteger(row.currentHttpStatus) && row.currentHttpStatus >= 100 && row.currentHttpStatus <= 599) || !(row.currentErrorConstructor === null || typeof row.currentErrorConstructor === "string" && /^[A-Za-z0-9_$-]{1,96}$/.test(row.currentErrorConstructor)) || !(row.claimCadenceMs === null || typeof row.claimCadenceMs === "number" && Number.isSafeInteger(row.claimCadenceMs) && row.claimCadenceMs >= 1) || !Array.isArray(row.retryHours) || row.retryHours.length > LISTENER_READ_RETRY_HOUR_CAP || !Array.isArray(row.retryMinutes) || row.retryMinutes.length > LISTENER_READ_RETRY_MINUTE_CAP || !Array.isArray(row.claimHours) || row.claimHours.length > LISTENER_CLAIM_HOUR_CAP) return null;
|
|
37627
|
+
if (row.currentEpisodeStartedAt === null !== (row.currentEpisodeAttempts === 0) || row.currentEpisodeStartedAt === null !== (row.currentReasonCode === null) || row.currentReasonCode === "http_status" !== (row.currentHttpStatus !== null) || row.currentReasonCode === "unclassified" !== (row.currentErrorConstructor !== null)) return null;
|
|
37628
|
+
for (const value2 of row.retryHours) {
|
|
37629
|
+
if (!value2 || typeof value2 !== "object" || Array.isArray(value2)) return null;
|
|
37630
|
+
const hour = value2;
|
|
37631
|
+
if (!hasExpectedKeys(hour, [
|
|
37632
|
+
"hourStart",
|
|
37633
|
+
"retries",
|
|
37634
|
+
"episodes",
|
|
37635
|
+
"longestEpisodeAttempts",
|
|
37636
|
+
"longestEpisodeDurationMs"
|
|
37637
|
+
], rejectUnknownKeys) || !validTimestamp(hour.hourStart) || !validCount(hour.retries) || !validCount(hour.episodes) || !validCount(hour.longestEpisodeAttempts) || !validCount(hour.longestEpisodeDurationMs)) return null;
|
|
37638
|
+
}
|
|
37639
|
+
for (const value2 of row.retryMinutes) {
|
|
37640
|
+
if (!value2 || typeof value2 !== "object" || Array.isArray(value2)) return null;
|
|
37641
|
+
const minute = value2;
|
|
37642
|
+
if (!hasExpectedKeys(minute, ["minuteStart", "retries"], rejectUnknownKeys) || !validTimestamp(minute.minuteStart) || !validCount(minute.retries)) return null;
|
|
37643
|
+
}
|
|
37644
|
+
for (const value2 of row.claimHours) {
|
|
37645
|
+
if (!value2 || typeof value2 !== "object" || Array.isArray(value2)) return null;
|
|
37646
|
+
const hour = value2;
|
|
37647
|
+
if (!hasExpectedKeys(hour, ["hourStart", "claims"], rejectUnknownKeys) || !validTimestamp(hour.hourStart) || !validCount(hour.claims)) return null;
|
|
37648
|
+
}
|
|
37649
|
+
return {
|
|
37650
|
+
currentEpisodeStartedAt: row.currentEpisodeStartedAt,
|
|
37651
|
+
currentEpisodeAttempts: row.currentEpisodeAttempts,
|
|
37652
|
+
currentReasonCode: row.currentReasonCode,
|
|
37653
|
+
currentHttpStatus: row.currentHttpStatus,
|
|
37654
|
+
currentErrorConstructor: row.currentErrorConstructor,
|
|
37655
|
+
retryHours: row.retryHours.map((hour) => ({
|
|
37656
|
+
hourStart: hour.hourStart,
|
|
37657
|
+
retries: hour.retries,
|
|
37658
|
+
episodes: hour.episodes,
|
|
37659
|
+
longestEpisodeAttempts: hour.longestEpisodeAttempts,
|
|
37660
|
+
longestEpisodeDurationMs: hour.longestEpisodeDurationMs
|
|
37661
|
+
})),
|
|
37662
|
+
retryMinutes: row.retryMinutes.map((minute) => ({
|
|
37663
|
+
minuteStart: minute.minuteStart,
|
|
37664
|
+
retries: minute.retries
|
|
37665
|
+
})),
|
|
37666
|
+
claimCadenceMs: row.claimCadenceMs,
|
|
37667
|
+
claimHours: row.claimHours.map((hour) => ({
|
|
37668
|
+
hourStart: hour.hourStart,
|
|
37669
|
+
claims: hour.claims
|
|
37670
|
+
}))
|
|
37671
|
+
};
|
|
37672
|
+
}
|
|
37673
|
+
function summarizeListenerReadHealth(health, readyAt, nowMs) {
|
|
37674
|
+
const windowStart = nowMs - HEALTH_WINDOW_MS;
|
|
37675
|
+
const retryHours = health.retryHours.filter(
|
|
37676
|
+
(row) => Date.parse(row.hourStart) + HOUR_MS > windowStart && Date.parse(row.hourStart) <= nowMs
|
|
37677
|
+
);
|
|
37678
|
+
let episodesLast24h = retryHours.reduce((sum, row) => sum + row.episodes, 0);
|
|
37679
|
+
let longestEpisodeAttemptsLast24h = 0;
|
|
37680
|
+
let longestEpisodeDurationMsLast24h = 0;
|
|
37681
|
+
for (const row of retryHours) {
|
|
37682
|
+
if (row.longestEpisodeDurationMs > longestEpisodeDurationMsLast24h || row.longestEpisodeDurationMs === longestEpisodeDurationMsLast24h && row.longestEpisodeAttempts > longestEpisodeAttemptsLast24h) {
|
|
37683
|
+
longestEpisodeAttemptsLast24h = row.longestEpisodeAttempts;
|
|
37684
|
+
longestEpisodeDurationMsLast24h = row.longestEpisodeDurationMs;
|
|
37685
|
+
}
|
|
37686
|
+
}
|
|
37687
|
+
const currentStartedMs = health.currentEpisodeStartedAt === null ? null : Date.parse(health.currentEpisodeStartedAt);
|
|
37688
|
+
const currentEpisodeDurationMs = currentStartedMs === null ? null : Math.max(0, nowMs - currentStartedMs);
|
|
37689
|
+
if (currentStartedMs !== null && currentStartedMs >= windowStart && currentEpisodeDurationMs !== null && (currentEpisodeDurationMs > longestEpisodeDurationMsLast24h || currentEpisodeDurationMs === longestEpisodeDurationMsLast24h && health.currentEpisodeAttempts > longestEpisodeAttemptsLast24h)) {
|
|
37690
|
+
longestEpisodeAttemptsLast24h = health.currentEpisodeAttempts;
|
|
37691
|
+
longestEpisodeDurationMsLast24h = currentEpisodeDurationMs;
|
|
37692
|
+
}
|
|
37693
|
+
const rollingMinuteStart = Math.floor((nowMs - HOUR_MS) / MINUTE_MS) * MINUTE_MS;
|
|
37694
|
+
const retriesLastHour = health.retryMinutes.reduce((sum, row) => Date.parse(row.minuteStart) >= rollingMinuteStart && Date.parse(row.minuteStart) <= nowMs ? sum + row.retries : sum, 0);
|
|
37695
|
+
const claimThroughputHours = [];
|
|
37696
|
+
if (health.claimCadenceMs !== null && readyAt !== null) {
|
|
37697
|
+
const readyMs = Date.parse(readyAt);
|
|
37698
|
+
const firstFullHour = Math.ceil(readyMs / HOUR_MS) * HOUR_MS;
|
|
37699
|
+
const currentHour = Math.floor(nowMs / HOUR_MS) * HOUR_MS;
|
|
37700
|
+
const first = Math.max(firstFullHour, currentHour - HEALTH_WINDOW_MS);
|
|
37701
|
+
const claimsByHour = new Map(
|
|
37702
|
+
health.claimHours.map((row) => [row.hourStart, row.claims])
|
|
37703
|
+
);
|
|
37704
|
+
const expectedClaims = HOUR_MS / health.claimCadenceMs;
|
|
37705
|
+
for (let hour = first; hour < currentHour; hour += HOUR_MS) {
|
|
37706
|
+
const hourStart = new Date(hour).toISOString();
|
|
37707
|
+
const claims = claimsByHour.get(hourStart) ?? 0;
|
|
37708
|
+
claimThroughputHours.push({
|
|
37709
|
+
hourStart,
|
|
37710
|
+
claims,
|
|
37711
|
+
expectedClaims,
|
|
37712
|
+
ratio: claims / expectedClaims
|
|
37713
|
+
});
|
|
37714
|
+
}
|
|
37715
|
+
}
|
|
37716
|
+
const throughputLapseHours = claimThroughputHours.filter(
|
|
37717
|
+
(hour) => hour.ratio < LISTENER_THROUGHPUT_LAPSE_RATIO
|
|
37718
|
+
);
|
|
37719
|
+
return {
|
|
37720
|
+
currentEpisodeDurationMs,
|
|
37721
|
+
episodesLast24h,
|
|
37722
|
+
longestEpisodeAttemptsLast24h,
|
|
37723
|
+
longestEpisodeDurationMsLast24h,
|
|
37724
|
+
retriesLastHour,
|
|
37725
|
+
retryHours,
|
|
37726
|
+
claimThroughputHours,
|
|
37727
|
+
throughputLapseHours
|
|
37728
|
+
};
|
|
37729
|
+
}
|
|
37730
|
+
|
|
37220
37731
|
// src/listener/control.ts
|
|
37732
|
+
var import_node_crypto19 = require("node:crypto");
|
|
37221
37733
|
var import_node_net = require("node:net");
|
|
37222
37734
|
var import_promises9 = require("node:fs/promises");
|
|
37223
37735
|
var import_node_path16 = require("node:path");
|
|
37224
37736
|
var UUID_RE17 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
37225
37737
|
var SEMVER_RE2 = /^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-(?:0|[1-9]\d*|[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|[A-Za-z-][0-9A-Za-z-]*))*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
|
|
37226
|
-
var MAX_STATUS_BYTES =
|
|
37738
|
+
var MAX_STATUS_BYTES = 32 * 1024;
|
|
37227
37739
|
var MAX_CONTROL_BYTES = 8 * 1024;
|
|
37228
37740
|
var CONTROL_TIMEOUT_MS = 2e3;
|
|
37229
37741
|
var START_LOCK_WAIT_MS = 2e3;
|
|
@@ -37235,15 +37747,19 @@ var ListenerAlreadyRunningError = class extends Error {
|
|
|
37235
37747
|
}
|
|
37236
37748
|
};
|
|
37237
37749
|
function listenerPaths(options) {
|
|
37238
|
-
const
|
|
37750
|
+
const defaultRoot = defaultListenerStateDirectory();
|
|
37751
|
+
const root = options.stateDirectory ?? defaultRoot;
|
|
37239
37752
|
if (!(0, import_node_path16.isAbsolute)(root)) {
|
|
37240
37753
|
throw new Error("listener state directory must be absolute");
|
|
37241
37754
|
}
|
|
37242
37755
|
const key2 = listenerInstanceKey(options);
|
|
37243
37756
|
const instanceDirectory = (0, import_node_path16.join)(root, key2);
|
|
37244
37757
|
const uid2 = typeof process.getuid === "function" ? process.getuid() : process.pid;
|
|
37245
|
-
const
|
|
37246
|
-
const
|
|
37758
|
+
const stateNamespace = (0, import_node_path16.resolve)(root) === (0, import_node_path16.resolve)(defaultRoot) ? "" : `-${(0, import_node_crypto19.createHash)("sha256").update((0, import_node_path16.resolve)(root)).digest("hex").slice(0, 16)}`;
|
|
37759
|
+
const platform = options.platform ?? process.platform;
|
|
37760
|
+
const socketKey = stateNamespace.length === 0 ? platform === "win32" ? key2 : key2.slice(0, 32) : `${key2.slice(0, 32)}${stateNamespace}`;
|
|
37761
|
+
const controlDirectory = platform === "win32" ? "" : (0, import_node_path16.join)("/tmp", `cswarm-control-${uid2}`);
|
|
37762
|
+
const socketPath = platform === "win32" ? `\\\\.\\pipe\\cswarm-${socketKey}` : (0, import_node_path16.join)(controlDirectory, `${socketKey}.sock`);
|
|
37247
37763
|
return {
|
|
37248
37764
|
key: key2,
|
|
37249
37765
|
instanceDirectory,
|
|
@@ -37270,8 +37786,13 @@ var STATUS_ALLOWED_KEYS = /* @__PURE__ */ new Set([
|
|
|
37270
37786
|
"lastSignalId",
|
|
37271
37787
|
"lastErrorCode",
|
|
37272
37788
|
"lastErrorDetail",
|
|
37789
|
+
"lastErrorReasonCode",
|
|
37790
|
+
"providerExecutable",
|
|
37273
37791
|
"providerVersion",
|
|
37274
37792
|
"providerLastMeasuredVersion",
|
|
37793
|
+
"providerBundledAgentSdkVersion",
|
|
37794
|
+
"providerBundledClaudeCodeVersion",
|
|
37795
|
+
"providerMinimumRequiredVersion",
|
|
37275
37796
|
"cswarmVersion",
|
|
37276
37797
|
"lastWorkerStderrTail",
|
|
37277
37798
|
"logPath",
|
|
@@ -37284,7 +37805,19 @@ var STATUS_ALLOWED_KEYS = /* @__PURE__ */ new Set([
|
|
|
37284
37805
|
"routeMode",
|
|
37285
37806
|
"deferOverChars",
|
|
37286
37807
|
"pendingForMainCount",
|
|
37287
|
-
"droppedForMainCount"
|
|
37808
|
+
"droppedForMainCount",
|
|
37809
|
+
"readHealth",
|
|
37810
|
+
"connectionsOpened",
|
|
37811
|
+
"connectionReuseRatio",
|
|
37812
|
+
"activityPublishFailures",
|
|
37813
|
+
"activityLastErrorCode"
|
|
37814
|
+
]);
|
|
37815
|
+
var STATUS_ACTIVITY_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
37816
|
+
"activity_credential_failed",
|
|
37817
|
+
"activity_request_timeout",
|
|
37818
|
+
"activity_transport_failed",
|
|
37819
|
+
"activity_http_rejected",
|
|
37820
|
+
"activity_publish_unknown"
|
|
37288
37821
|
]);
|
|
37289
37822
|
var STATUS_SENSITIVE_KEYS = /* @__PURE__ */ new Set([
|
|
37290
37823
|
"leaseId",
|
|
@@ -37310,7 +37843,7 @@ var STATUS_DELIVERY_KEYS = [
|
|
|
37310
37843
|
"lastClaimAt",
|
|
37311
37844
|
"lastAckAt"
|
|
37312
37845
|
];
|
|
37313
|
-
function parseStatus(raw) {
|
|
37846
|
+
function parseStatus(raw, rejectUnknownKeys = false) {
|
|
37314
37847
|
let value;
|
|
37315
37848
|
try {
|
|
37316
37849
|
value = JSON.parse(raw);
|
|
@@ -37325,14 +37858,17 @@ function parseStatus(raw) {
|
|
|
37325
37858
|
if (STATUS_SENSITIVE_KEYS.has(key2)) {
|
|
37326
37859
|
throw new Error("stored listener status contains a forbidden field");
|
|
37327
37860
|
}
|
|
37328
|
-
if (!STATUS_ALLOWED_KEYS.has(key2)) {
|
|
37861
|
+
if (rejectUnknownKeys && !STATUS_ALLOWED_KEYS.has(key2)) {
|
|
37329
37862
|
throw new Error("stored listener status is malformed");
|
|
37330
37863
|
}
|
|
37331
37864
|
}
|
|
37332
37865
|
const nullableUuid3 = (candidate) => candidate === null || typeof candidate === "string" && UUID_RE17.test(candidate);
|
|
37333
37866
|
const nullableCount = (candidate) => candidate === null || typeof candidate === "number" && Number.isSafeInteger(candidate) && candidate >= 0;
|
|
37334
37867
|
const nullableTimestamp3 = (candidate) => candidate === null || typeof candidate === "string" && Number.isFinite(Date.parse(candidate));
|
|
37335
|
-
|
|
37868
|
+
const readHealth = row.readHealth === void 0 ? void 0 : parseListenerReadHealth(row.readHealth, rejectUnknownKeys);
|
|
37869
|
+
if (row.version !== 1 || typeof row.instanceId !== "string" || !UUID_RE17.test(row.instanceId) || row.provider !== "grok" && row.provider !== "opencode" && row.provider !== "claude" && row.provider !== "codex" || typeof row.profileId !== "string" || typeof row.workspaceId !== "string" || !UUID_RE17.test(row.workspaceId) || typeof row.principalId !== "string" || !UUID_RE17.test(row.principalId) || !Number.isSafeInteger(row.pid) || row.pid < 1 || typeof row.state !== "string" || !["starting", "ready", "stopping", "stopped", "failed"].includes(row.state) || typeof row.startedAt !== "string" || !Number.isFinite(Date.parse(row.startedAt)) || !(row.readyAt === null || typeof row.readyAt === "string" && Number.isFinite(Date.parse(row.readyAt))) || typeof row.updatedAt !== "string" || !Number.isFinite(Date.parse(row.updatedAt)) || !(row.stoppedAt === null || typeof row.stoppedAt === "string" && Number.isFinite(Date.parse(row.stoppedAt))) || !nullableUuid3(row.lastSignalId) || !(row.lastErrorCode === null || typeof row.lastErrorCode === "string" && /^[a-z0-9_-]{1,96}$/.test(row.lastErrorCode)) || !(row.lastErrorDetail === void 0 || row.lastErrorDetail === null || typeof row.lastErrorDetail === "string" && row.lastErrorDetail.length > 0 && row.lastErrorDetail.length <= 2048 && !/swm_(?:agt|inv|cap)_/i.test(row.lastErrorDetail)) || !(row.lastErrorReasonCode === void 0 || row.lastErrorReasonCode === null || typeof row.lastErrorReasonCode === "string" && /^[a-z0-9_-]{1,96}$/.test(row.lastErrorReasonCode)) || !(row.providerExecutable === void 0 || row.providerExecutable === null || typeof row.providerExecutable === "string" && (0, import_node_path16.isAbsolute)(row.providerExecutable)) || !(row.providerVersion === void 0 || row.providerVersion === null || typeof row.providerVersion === "string" && SEMVER_RE2.test(row.providerVersion)) || !(row.providerLastMeasuredVersion === void 0 || row.providerLastMeasuredVersion === null || typeof row.providerLastMeasuredVersion === "string" && SEMVER_RE2.test(row.providerLastMeasuredVersion)) || !(row.providerBundledAgentSdkVersion === void 0 || row.providerBundledAgentSdkVersion === null || typeof row.providerBundledAgentSdkVersion === "string" && SEMVER_RE2.test(row.providerBundledAgentSdkVersion)) || !(row.providerBundledClaudeCodeVersion === void 0 || row.providerBundledClaudeCodeVersion === null || typeof row.providerBundledClaudeCodeVersion === "string" && SEMVER_RE2.test(row.providerBundledClaudeCodeVersion)) || !(row.providerMinimumRequiredVersion === void 0 || row.providerMinimumRequiredVersion === null || typeof row.providerMinimumRequiredVersion === "string" && SEMVER_RE2.test(row.providerMinimumRequiredVersion)) || !(row.cswarmVersion === void 0 || row.cswarmVersion === null || typeof row.cswarmVersion === "string" && SEMVER_RE2.test(row.cswarmVersion)) || (row.providerVersion === null || row.providerVersion === void 0) !== (row.providerLastMeasuredVersion === null || row.providerLastMeasuredVersion === void 0) || !(row.lastWorkerStderrTail === void 0 || row.lastWorkerStderrTail === null || typeof row.lastWorkerStderrTail === "string" && row.lastWorkerStderrTail.length > 0 && row.lastWorkerStderrTail.length <= 2048 && !/swm_(?:agt|inv|cap)_/i.test(row.lastWorkerStderrTail)) || typeof row.logPath !== "string" || !(0, import_node_path16.isAbsolute)(row.logPath) || !(row.deliveryMode === void 0 || row.deliveryMode === null || typeof row.deliveryMode === "string" && STATUS_DELIVERY_MODES.has(row.deliveryMode)) || !(row.pendingDeliveryCount === void 0 || nullableCount(row.pendingDeliveryCount)) || !(row.lastTerminalDeliveryFailureCount === void 0 || nullableCount(row.lastTerminalDeliveryFailureCount)) || !(row.lastTerminalDeliveryFailureAt === void 0 || nullableTimestamp3(row.lastTerminalDeliveryFailureAt)) || !(row.lastClaimAt === void 0 || nullableTimestamp3(row.lastClaimAt)) || !(row.lastAckAt === void 0 || nullableTimestamp3(row.lastAckAt)) || !(row.routeMode === void 0 || row.routeMode === "worker" || row.routeMode === "main" || row.routeMode === "split") || !(row.deferOverChars === void 0 || row.deferOverChars === null || typeof row.deferOverChars === "number" && Number.isSafeInteger(row.deferOverChars) && row.deferOverChars >= 1 && row.deferOverChars <= 1e4) || !(row.pendingForMainCount === void 0 || typeof row.pendingForMainCount === "number" && Number.isSafeInteger(row.pendingForMainCount) && row.pendingForMainCount >= 0) || !(row.droppedForMainCount === void 0 || typeof row.droppedForMainCount === "number" && Number.isSafeInteger(row.droppedForMainCount) && row.droppedForMainCount >= 0) || readHealth === null || !(row.connectionsOpened === void 0 || typeof row.connectionsOpened === "number" && Number.isSafeInteger(row.connectionsOpened) && row.connectionsOpened >= 0) || !(row.connectionReuseRatio === void 0 || typeof row.connectionReuseRatio === "number" && Number.isFinite(row.connectionReuseRatio) && row.connectionReuseRatio >= 0) || !(row.activityPublishFailures === void 0 || typeof row.activityPublishFailures === "number" && Number.isSafeInteger(row.activityPublishFailures) && row.activityPublishFailures >= 0) || !(row.activityLastErrorCode === void 0 || row.activityLastErrorCode === null || typeof row.activityLastErrorCode === "string" && STATUS_ACTIVITY_ERROR_CODES.has(
|
|
37870
|
+
row.activityLastErrorCode
|
|
37871
|
+
))) {
|
|
37336
37872
|
throw new Error("stored listener status is malformed");
|
|
37337
37873
|
}
|
|
37338
37874
|
const routeMode = row.routeMode ?? "worker";
|
|
@@ -37340,8 +37876,11 @@ function parseStatus(raw) {
|
|
|
37340
37876
|
if (routeMode === "split" && deferOverChars === null || routeMode !== "split" && deferOverChars !== null) {
|
|
37341
37877
|
throw new Error("stored listener status routing fields are malformed");
|
|
37342
37878
|
}
|
|
37879
|
+
const knownRow = Object.fromEntries(
|
|
37880
|
+
Object.entries(row).filter(([key2]) => STATUS_ALLOWED_KEYS.has(key2))
|
|
37881
|
+
);
|
|
37343
37882
|
return {
|
|
37344
|
-
...
|
|
37883
|
+
...knownRow,
|
|
37345
37884
|
deliveryMode: row.deliveryMode ?? null,
|
|
37346
37885
|
pendingDeliveryCount: row.pendingDeliveryCount ?? null,
|
|
37347
37886
|
lastTerminalDeliveryFailureCount: row.lastTerminalDeliveryFailureCount ?? null,
|
|
@@ -37356,11 +37895,15 @@ function parseStatus(raw) {
|
|
|
37356
37895
|
routeMode,
|
|
37357
37896
|
deferOverChars,
|
|
37358
37897
|
pendingForMainCount: row.pendingForMainCount ?? 0,
|
|
37359
|
-
droppedForMainCount: row.droppedForMainCount ?? 0
|
|
37898
|
+
droppedForMainCount: row.droppedForMainCount ?? 0,
|
|
37899
|
+
...readHealth === void 0 ? {} : { readHealth }
|
|
37360
37900
|
};
|
|
37361
37901
|
}
|
|
37362
37902
|
async function writeListenerStatus(paths, status) {
|
|
37363
37903
|
const serialized = JSON.stringify(status);
|
|
37904
|
+
if (Buffer.byteLength(serialized, "utf8") > MAX_STATUS_BYTES) {
|
|
37905
|
+
throw new Error("listener status is too large");
|
|
37906
|
+
}
|
|
37364
37907
|
const parsed = JSON.parse(serialized);
|
|
37365
37908
|
for (const key2 of STATUS_DELIVERY_KEYS) {
|
|
37366
37909
|
if (!(key2 in parsed)) {
|
|
@@ -37370,7 +37913,7 @@ async function writeListenerStatus(paths, status) {
|
|
|
37370
37913
|
if (!("lastErrorDetail" in parsed)) {
|
|
37371
37914
|
throw new Error("listener status is missing local error detail metadata");
|
|
37372
37915
|
}
|
|
37373
|
-
parseStatus(serialized);
|
|
37916
|
+
parseStatus(serialized, true);
|
|
37374
37917
|
await writeSecureJsonFile(paths.statusPath, serialized);
|
|
37375
37918
|
}
|
|
37376
37919
|
async function readListenerStatus(paths) {
|
|
@@ -37395,6 +37938,12 @@ async function appendListenerEvent(paths, event) {
|
|
|
37395
37938
|
"passed",
|
|
37396
37939
|
"reason",
|
|
37397
37940
|
"delay_ms",
|
|
37941
|
+
"reason_code",
|
|
37942
|
+
"http_status",
|
|
37943
|
+
"error_constructor",
|
|
37944
|
+
"episode_attempt",
|
|
37945
|
+
"attempts",
|
|
37946
|
+
"duration_ms",
|
|
37398
37947
|
"index",
|
|
37399
37948
|
"delivery_mode",
|
|
37400
37949
|
"pending_delivery_count",
|
|
@@ -37433,6 +37982,29 @@ async function appendListenerEvent(paths, event) {
|
|
|
37433
37982
|
if ((key2 === "attempt" || key2 === "total") && !(typeof value === "number" && Number.isSafeInteger(value) && value >= 1)) {
|
|
37434
37983
|
throw new Error("listener event attempt count is not allowed");
|
|
37435
37984
|
}
|
|
37985
|
+
if ((key2 === "episode_attempt" || key2 === "attempts") && !(typeof value === "number" && Number.isSafeInteger(value) && value >= 1)) {
|
|
37986
|
+
throw new Error("listener event episode count is not allowed");
|
|
37987
|
+
}
|
|
37988
|
+
if (key2 === "duration_ms" && !(typeof value === "number" && Number.isSafeInteger(value) && value >= 0)) {
|
|
37989
|
+
throw new Error("listener event episode duration is not allowed");
|
|
37990
|
+
}
|
|
37991
|
+
if (key2 === "http_status" && !(typeof value === "number" && Number.isSafeInteger(value) && value >= 100 && value <= 599)) {
|
|
37992
|
+
throw new Error("listener event HTTP status is not allowed");
|
|
37993
|
+
}
|
|
37994
|
+
if (key2 === "reason_code" && !(typeof value === "string" && [
|
|
37995
|
+
"http_status",
|
|
37996
|
+
"no_response",
|
|
37997
|
+
"body_timeout",
|
|
37998
|
+
"malformed_response",
|
|
37999
|
+
"aborted",
|
|
38000
|
+
"host_ports_exhausted",
|
|
38001
|
+
"unclassified"
|
|
38002
|
+
].includes(value))) {
|
|
38003
|
+
throw new Error("listener event read reason code is not allowed");
|
|
38004
|
+
}
|
|
38005
|
+
if (key2 === "error_constructor" && !(typeof value === "string" && /^[A-Za-z0-9_$-]{1,96}$/.test(value))) {
|
|
38006
|
+
throw new Error("listener event error constructor is not allowed");
|
|
38007
|
+
}
|
|
37436
38008
|
if (key2 === "passed" && typeof value !== "boolean") {
|
|
37437
38009
|
throw new Error("listener event canary result is not allowed");
|
|
37438
38010
|
}
|
|
@@ -37476,6 +38048,12 @@ async function appendListenerEvent(paths, event) {
|
|
|
37476
38048
|
if (event.event === "listener_canary_attempt" && (typeof event.attempt !== "number" || typeof event.total !== "number" || event.attempt > event.total || typeof event.passed !== "boolean" || !(event.reason === null || typeof event.reason === "string"))) {
|
|
37477
38049
|
throw new Error("listener canary attempt event is incomplete");
|
|
37478
38050
|
}
|
|
38051
|
+
if (event.event === "listener_read_retry" && (typeof event.reason_code !== "string" || typeof event.episode_attempt !== "number" || event.reason_code === "http_status" !== (typeof event.http_status === "number") || event.reason_code === "unclassified" !== (typeof event.error_constructor === "string"))) {
|
|
38052
|
+
throw new Error("listener read retry event is incomplete");
|
|
38053
|
+
}
|
|
38054
|
+
if (event.event === "listener_read_recovered" && (typeof event.attempts !== "number" || typeof event.duration_ms !== "number")) {
|
|
38055
|
+
throw new Error("listener read recovery event is incomplete");
|
|
38056
|
+
}
|
|
37479
38057
|
await ensureSecureStateDirectory(paths.instanceDirectory);
|
|
37480
38058
|
const serialized = `${JSON.stringify(event)}
|
|
37481
38059
|
`;
|
|
@@ -37549,7 +38127,7 @@ async function startupLock(paths) {
|
|
|
37549
38127
|
await (0, import_promises9.unlink)(lockPath).catch(() => void 0);
|
|
37550
38128
|
continue;
|
|
37551
38129
|
}
|
|
37552
|
-
await new Promise((
|
|
38130
|
+
await new Promise((resolve3) => setTimeout(resolve3, 25));
|
|
37553
38131
|
continue;
|
|
37554
38132
|
}
|
|
37555
38133
|
try {
|
|
@@ -37623,14 +38201,14 @@ async function startListenerControlServer(options) {
|
|
|
37623
38201
|
if (options.initialize) {
|
|
37624
38202
|
await options.initialize();
|
|
37625
38203
|
}
|
|
37626
|
-
await new Promise((
|
|
38204
|
+
await new Promise((resolve3, reject) => {
|
|
37627
38205
|
const onError = (error) => {
|
|
37628
38206
|
server.off("listening", onListening);
|
|
37629
38207
|
reject(error);
|
|
37630
38208
|
};
|
|
37631
38209
|
const onListening = () => {
|
|
37632
38210
|
server.off("error", onError);
|
|
37633
|
-
|
|
38211
|
+
resolve3();
|
|
37634
38212
|
};
|
|
37635
38213
|
server.once("error", onError);
|
|
37636
38214
|
server.once("listening", onListening);
|
|
@@ -37641,7 +38219,7 @@ async function startListenerControlServer(options) {
|
|
|
37641
38219
|
}
|
|
37642
38220
|
} catch (error) {
|
|
37643
38221
|
if (server.listening) {
|
|
37644
|
-
await new Promise((
|
|
38222
|
+
await new Promise((resolve3) => server.close(() => resolve3()));
|
|
37645
38223
|
if (process.platform !== "win32") {
|
|
37646
38224
|
await (0, import_promises9.unlink)(options.paths.socketPath).catch(() => void 0);
|
|
37647
38225
|
}
|
|
@@ -37652,7 +38230,7 @@ async function startListenerControlServer(options) {
|
|
|
37652
38230
|
}
|
|
37653
38231
|
return {
|
|
37654
38232
|
close: async () => {
|
|
37655
|
-
await new Promise((
|
|
38233
|
+
await new Promise((resolve3) => server.close(() => resolve3()));
|
|
37656
38234
|
if (process.platform !== "win32") {
|
|
37657
38235
|
await (0, import_promises9.unlink)(options.paths.socketPath).catch(() => void 0);
|
|
37658
38236
|
}
|
|
@@ -37660,7 +38238,7 @@ async function startListenerControlServer(options) {
|
|
|
37660
38238
|
};
|
|
37661
38239
|
}
|
|
37662
38240
|
async function queryListenerControl(paths, command2, timeoutMs = CONTROL_TIMEOUT_MS) {
|
|
37663
|
-
return await new Promise((
|
|
38241
|
+
return await new Promise((resolve3, reject) => {
|
|
37664
38242
|
const socket = (0, import_node_net.createConnection)(paths.socketPath);
|
|
37665
38243
|
let input = "";
|
|
37666
38244
|
let settled = false;
|
|
@@ -37674,7 +38252,7 @@ async function queryListenerControl(paths, command2, timeoutMs = CONTROL_TIMEOUT
|
|
|
37674
38252
|
clearTimeout(timer2);
|
|
37675
38253
|
socket.destroy();
|
|
37676
38254
|
if (error) reject(error);
|
|
37677
|
-
else
|
|
38255
|
+
else resolve3(status);
|
|
37678
38256
|
};
|
|
37679
38257
|
socket.setEncoding("utf8");
|
|
37680
38258
|
socket.once("error", (error) => finish(error));
|
|
@@ -37705,7 +38283,7 @@ async function queryListenerControl(paths, command2, timeoutMs = CONTROL_TIMEOUT
|
|
|
37705
38283
|
}
|
|
37706
38284
|
|
|
37707
38285
|
// src/listener/supervisor.ts
|
|
37708
|
-
var
|
|
38286
|
+
var import_node_crypto20 = require("node:crypto");
|
|
37709
38287
|
var UUID_RE18 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
37710
38288
|
var LISTENER_RESTART_MAX_ATTEMPTS = 5;
|
|
37711
38289
|
var LISTENER_RESTART_INITIAL_MS = 1e3;
|
|
@@ -37719,11 +38297,11 @@ function nextListenerRestartMs(attempt, policy = {}, random = Math.random) {
|
|
|
37719
38297
|
}
|
|
37720
38298
|
async function defaultRestartSleep(ms, signal) {
|
|
37721
38299
|
if (ms <= 0 || signal.aborted) return;
|
|
37722
|
-
await new Promise((
|
|
38300
|
+
await new Promise((resolve3) => {
|
|
37723
38301
|
const finish = () => {
|
|
37724
38302
|
clearTimeout(timer2);
|
|
37725
38303
|
signal.removeEventListener("abort", finish);
|
|
37726
|
-
|
|
38304
|
+
resolve3();
|
|
37727
38305
|
};
|
|
37728
38306
|
const timer2 = setTimeout(finish, ms);
|
|
37729
38307
|
signal.addEventListener("abort", finish, { once: true });
|
|
@@ -37760,6 +38338,28 @@ function localDiagnostic(message, maxChars) {
|
|
|
37760
38338
|
function safeErrorDetail(error) {
|
|
37761
38339
|
return localDiagnostic(error.message, 2048);
|
|
37762
38340
|
}
|
|
38341
|
+
function providerStatusFields(notice) {
|
|
38342
|
+
if (!notice) return {};
|
|
38343
|
+
return {
|
|
38344
|
+
providerExecutable: notice.executable ?? null,
|
|
38345
|
+
providerVersion: notice.runningVersion,
|
|
38346
|
+
providerLastMeasuredVersion: notice.runningVersion === null ? null : notice.lastMeasuredVersion,
|
|
38347
|
+
providerBundledAgentSdkVersion: notice.bundledAgentSdkVersion ?? null,
|
|
38348
|
+
providerBundledClaudeCodeVersion: notice.bundledClaudeCodeVersion ?? null
|
|
38349
|
+
};
|
|
38350
|
+
}
|
|
38351
|
+
function providerFailureFields(error) {
|
|
38352
|
+
if (!(error instanceof AcpPermissionCanaryError)) {
|
|
38353
|
+
return {
|
|
38354
|
+
lastErrorReasonCode: null,
|
|
38355
|
+
providerMinimumRequiredVersion: null
|
|
38356
|
+
};
|
|
38357
|
+
}
|
|
38358
|
+
return {
|
|
38359
|
+
lastErrorReasonCode: error.reasonCode,
|
|
38360
|
+
providerMinimumRequiredVersion: error.minimumRequiredVersion
|
|
38361
|
+
};
|
|
38362
|
+
}
|
|
37763
38363
|
var TAIL_SERIALIZED_BUDGET_BYTES = 3e3;
|
|
37764
38364
|
function fitWorkerStderrTailForLog(tail) {
|
|
37765
38365
|
let fitted = tail.trim();
|
|
@@ -37781,7 +38381,7 @@ async function runListenerSupervisor(options) {
|
|
|
37781
38381
|
const now = options.now ?? Date.now;
|
|
37782
38382
|
const startedAt = iso2(now);
|
|
37783
38383
|
const controller = new AbortController();
|
|
37784
|
-
const proposedInstanceId = (0,
|
|
38384
|
+
const proposedInstanceId = (0, import_node_crypto20.randomUUID)();
|
|
37785
38385
|
let status = {
|
|
37786
38386
|
version: 1,
|
|
37787
38387
|
instanceId: proposedInstanceId,
|
|
@@ -37800,8 +38400,13 @@ async function runListenerSupervisor(options) {
|
|
|
37800
38400
|
lastSignalId: null,
|
|
37801
38401
|
lastErrorCode: null,
|
|
37802
38402
|
lastErrorDetail: null,
|
|
38403
|
+
lastErrorReasonCode: null,
|
|
38404
|
+
providerExecutable: null,
|
|
37803
38405
|
providerVersion: null,
|
|
37804
38406
|
providerLastMeasuredVersion: null,
|
|
38407
|
+
providerBundledAgentSdkVersion: null,
|
|
38408
|
+
providerBundledClaudeCodeVersion: null,
|
|
38409
|
+
providerMinimumRequiredVersion: null,
|
|
37805
38410
|
lastWorkerStderrTail: null,
|
|
37806
38411
|
deliveryMode: null,
|
|
37807
38412
|
pendingDeliveryCount: null,
|
|
@@ -37813,14 +38418,29 @@ async function runListenerSupervisor(options) {
|
|
|
37813
38418
|
deferOverChars: options.deferOverChars ?? null,
|
|
37814
38419
|
pendingForMainCount: 0,
|
|
37815
38420
|
droppedForMainCount: 0,
|
|
38421
|
+
readHealth: emptyListenerReadHealth(),
|
|
38422
|
+
connectionsOpened: 0,
|
|
38423
|
+
connectionReuseRatio: 0,
|
|
38424
|
+
activityPublishFailures: 0,
|
|
38425
|
+
activityLastErrorCode: null,
|
|
37816
38426
|
logPath: options.paths.logPath
|
|
37817
38427
|
};
|
|
37818
38428
|
let writes = Promise.resolve();
|
|
37819
38429
|
const chain = (work) => {
|
|
37820
38430
|
writes = writes.then(work).catch(() => void 0);
|
|
37821
38431
|
};
|
|
38432
|
+
const statusSnapshot = () => {
|
|
38433
|
+
const metrics = options.getConnectionMetrics?.();
|
|
38434
|
+
return {
|
|
38435
|
+
...structuredClone(status),
|
|
38436
|
+
...metrics ? {
|
|
38437
|
+
connectionsOpened: metrics.connectionsOpened,
|
|
38438
|
+
connectionReuseRatio: metrics.connectionReuseRatio
|
|
38439
|
+
} : {}
|
|
38440
|
+
};
|
|
38441
|
+
};
|
|
37822
38442
|
const persist = () => {
|
|
37823
|
-
const snapshot =
|
|
38443
|
+
const snapshot = statusSnapshot();
|
|
37824
38444
|
chain(() => writeListenerStatus(options.paths, snapshot));
|
|
37825
38445
|
};
|
|
37826
38446
|
const log = (event) => {
|
|
@@ -37838,7 +38458,7 @@ async function runListenerSupervisor(options) {
|
|
|
37838
38458
|
const prepare = options.prepare;
|
|
37839
38459
|
const control = await startListenerControlServer({
|
|
37840
38460
|
paths: options.paths,
|
|
37841
|
-
status:
|
|
38461
|
+
status: statusSnapshot,
|
|
37842
38462
|
stop: () => {
|
|
37843
38463
|
if (status.state === "stopped" || status.state === "failed") return;
|
|
37844
38464
|
transition("stopping");
|
|
@@ -37876,9 +38496,16 @@ async function runListenerSupervisor(options) {
|
|
|
37876
38496
|
readyAt: event.ts,
|
|
37877
38497
|
lastErrorCode: null,
|
|
37878
38498
|
lastErrorDetail: null,
|
|
38499
|
+
lastErrorReasonCode: null,
|
|
37879
38500
|
lastWorkerStderrTail: null,
|
|
37880
|
-
|
|
37881
|
-
|
|
38501
|
+
providerMinimumRequiredVersion: null,
|
|
38502
|
+
...providerStatusFields(versionNotice),
|
|
38503
|
+
...event.cadenceMs === void 0 ? {} : {
|
|
38504
|
+
readHealth: recordListenerClaimCadence(
|
|
38505
|
+
status.readHealth ?? emptyListenerReadHealth(),
|
|
38506
|
+
event.cadenceMs
|
|
38507
|
+
)
|
|
38508
|
+
}
|
|
37882
38509
|
});
|
|
37883
38510
|
log({ ts: event.ts, event: "listener_ready" });
|
|
37884
38511
|
return;
|
|
@@ -37920,14 +38547,54 @@ async function runListenerSupervisor(options) {
|
|
|
37920
38547
|
return;
|
|
37921
38548
|
}
|
|
37922
38549
|
if (event.type === "read_retry") {
|
|
38550
|
+
status = {
|
|
38551
|
+
...status,
|
|
38552
|
+
readHealth: recordListenerReadRetry(
|
|
38553
|
+
status.readHealth ?? emptyListenerReadHealth(),
|
|
38554
|
+
{
|
|
38555
|
+
ts: event.ts,
|
|
38556
|
+
episodeStartedAt: event.episodeStartedAt,
|
|
38557
|
+
episodeAttempt: event.episodeAttempt,
|
|
38558
|
+
failure: event.failure
|
|
38559
|
+
}
|
|
38560
|
+
),
|
|
38561
|
+
updatedAt: event.ts
|
|
38562
|
+
};
|
|
38563
|
+
persist();
|
|
37923
38564
|
log({
|
|
37924
38565
|
ts: event.ts,
|
|
37925
38566
|
event: "listener_read_retry",
|
|
37926
38567
|
attempt: event.attempt,
|
|
38568
|
+
episode_attempt: event.episodeAttempt,
|
|
38569
|
+
reason_code: event.failure.code,
|
|
38570
|
+
...event.failure.httpStatus === null ? {} : { http_status: event.failure.httpStatus },
|
|
38571
|
+
...event.failure.errorConstructor === null ? {} : { error_constructor: event.failure.errorConstructor },
|
|
37927
38572
|
delay_ms: event.delayMs
|
|
37928
38573
|
});
|
|
37929
38574
|
return;
|
|
37930
38575
|
}
|
|
38576
|
+
if (event.type === "read_recovered") {
|
|
38577
|
+
status = {
|
|
38578
|
+
...status,
|
|
38579
|
+
readHealth: recordListenerReadRecovery(
|
|
38580
|
+
status.readHealth ?? emptyListenerReadHealth(),
|
|
38581
|
+
{
|
|
38582
|
+
startedAt: event.startedAt,
|
|
38583
|
+
attempts: event.attempts,
|
|
38584
|
+
durationMs: event.durationMs
|
|
38585
|
+
}
|
|
38586
|
+
),
|
|
38587
|
+
updatedAt: event.ts
|
|
38588
|
+
};
|
|
38589
|
+
persist();
|
|
38590
|
+
log({
|
|
38591
|
+
ts: event.ts,
|
|
38592
|
+
event: "listener_read_recovered",
|
|
38593
|
+
attempts: event.attempts,
|
|
38594
|
+
duration_ms: event.durationMs
|
|
38595
|
+
});
|
|
38596
|
+
return;
|
|
38597
|
+
}
|
|
37931
38598
|
if (event.type === "malformed_row") {
|
|
37932
38599
|
log({
|
|
37933
38600
|
ts: event.ts,
|
|
@@ -37936,6 +38603,16 @@ async function runListenerSupervisor(options) {
|
|
|
37936
38603
|
});
|
|
37937
38604
|
return;
|
|
37938
38605
|
}
|
|
38606
|
+
if (event.type === "activity_publish_failure") {
|
|
38607
|
+
status = {
|
|
38608
|
+
...status,
|
|
38609
|
+
activityPublishFailures: (status.activityPublishFailures ?? 0) + 1,
|
|
38610
|
+
activityLastErrorCode: event.code,
|
|
38611
|
+
updatedAt: event.ts
|
|
38612
|
+
};
|
|
38613
|
+
persist();
|
|
38614
|
+
return;
|
|
38615
|
+
}
|
|
37939
38616
|
if (event.type === "model_declared") {
|
|
37940
38617
|
log({
|
|
37941
38618
|
ts: event.ts,
|
|
@@ -37964,6 +38641,10 @@ async function runListenerSupervisor(options) {
|
|
|
37964
38641
|
if (event.type === "delivery_claim") {
|
|
37965
38642
|
status = {
|
|
37966
38643
|
...status,
|
|
38644
|
+
readHealth: recordListenerClaim(
|
|
38645
|
+
status.readHealth ?? emptyListenerReadHealth(),
|
|
38646
|
+
event.ts
|
|
38647
|
+
),
|
|
37967
38648
|
pendingDeliveryCount: event.pendingDeliveryCount,
|
|
37968
38649
|
lastClaimAt: event.ts,
|
|
37969
38650
|
updatedAt: event.ts
|
|
@@ -38088,9 +38769,9 @@ async function runListenerSupervisor(options) {
|
|
|
38088
38769
|
readyAt: null,
|
|
38089
38770
|
lastErrorCode: restartCode,
|
|
38090
38771
|
lastErrorDetail: safeErrorDetail(stop.error),
|
|
38772
|
+
...providerFailureFields(stop.error),
|
|
38091
38773
|
lastWorkerStderrTail: restartStderrTail,
|
|
38092
|
-
|
|
38093
|
-
providerLastMeasuredVersion: null
|
|
38774
|
+
...providerStatusFields(options.getProviderVersionNotice?.() ?? null)
|
|
38094
38775
|
});
|
|
38095
38776
|
await restartSleep(delayMs, controller.signal);
|
|
38096
38777
|
if (controller.signal.aborted) {
|
|
@@ -38104,7 +38785,9 @@ async function runListenerSupervisor(options) {
|
|
|
38104
38785
|
stoppedAt,
|
|
38105
38786
|
lastErrorCode: null,
|
|
38106
38787
|
lastErrorDetail: null,
|
|
38107
|
-
|
|
38788
|
+
lastErrorReasonCode: null,
|
|
38789
|
+
lastWorkerStderrTail: null,
|
|
38790
|
+
providerMinimumRequiredVersion: null
|
|
38108
38791
|
});
|
|
38109
38792
|
log({ ts: stoppedAt, event: "listener_stopped" });
|
|
38110
38793
|
} else {
|
|
@@ -38114,6 +38797,8 @@ async function runListenerSupervisor(options) {
|
|
|
38114
38797
|
stoppedAt,
|
|
38115
38798
|
lastErrorCode: code,
|
|
38116
38799
|
lastErrorDetail: safeErrorDetail(stop.error),
|
|
38800
|
+
...providerFailureFields(stop.error),
|
|
38801
|
+
...providerStatusFields(options.getProviderVersionNotice?.() ?? null),
|
|
38117
38802
|
lastWorkerStderrTail: failedStderrTail
|
|
38118
38803
|
});
|
|
38119
38804
|
log({
|
|
@@ -38138,6 +38823,10 @@ async function runListenerSupervisor(options) {
|
|
|
38138
38823
|
lastErrorDetail: safeErrorDetail(
|
|
38139
38824
|
error instanceof Error ? error : new Error(String(error))
|
|
38140
38825
|
),
|
|
38826
|
+
...providerFailureFields(
|
|
38827
|
+
error instanceof Error ? error : new Error(String(error))
|
|
38828
|
+
),
|
|
38829
|
+
...providerStatusFields(options.getProviderVersionNotice?.() ?? null),
|
|
38141
38830
|
lastWorkerStderrTail: failedStderrTail
|
|
38142
38831
|
});
|
|
38143
38832
|
log({
|
|
@@ -38150,7 +38839,7 @@ async function runListenerSupervisor(options) {
|
|
|
38150
38839
|
await writes.catch(() => void 0);
|
|
38151
38840
|
await control.close().catch(() => void 0);
|
|
38152
38841
|
}
|
|
38153
|
-
return
|
|
38842
|
+
return statusSnapshot();
|
|
38154
38843
|
}
|
|
38155
38844
|
async function effectiveListenerStatus(paths) {
|
|
38156
38845
|
try {
|
|
@@ -38182,7 +38871,7 @@ async function waitForListenerReady(paths, options = {}) {
|
|
|
38182
38871
|
const timeoutMs = options.timeoutMs ?? 12e4;
|
|
38183
38872
|
const pollMs = options.pollMs ?? 100;
|
|
38184
38873
|
const now = options.now ?? Date.now;
|
|
38185
|
-
const sleep2 = options.sleep ?? ((ms) => new Promise((
|
|
38874
|
+
const sleep2 = options.sleep ?? ((ms) => new Promise((resolve3) => setTimeout(resolve3, ms)));
|
|
38186
38875
|
const deadline = now() + timeoutMs;
|
|
38187
38876
|
let last = null;
|
|
38188
38877
|
let processExitObservedAt = null;
|
|
@@ -38383,7 +39072,7 @@ function assertPlainObject(input, allowedKeys, requiredKeys, errMessage = "deliv
|
|
|
38383
39072
|
throw new Error(errMessage);
|
|
38384
39073
|
}
|
|
38385
39074
|
}
|
|
38386
|
-
function parseJournalRecord(raw, expectedWorkspaceId, expectedPrincipalId) {
|
|
39075
|
+
function parseJournalRecord(raw, expectedWorkspaceId, expectedPrincipalId, rejectUnknownKeys = false) {
|
|
38387
39076
|
if (Buffer.byteLength(raw, "utf8") > MAX_JOURNAL_BYTES) {
|
|
38388
39077
|
throw new Error("stored delivery journal is malformed");
|
|
38389
39078
|
}
|
|
@@ -38404,7 +39093,7 @@ function parseJournalRecord(raw, expectedWorkspaceId, expectedPrincipalId) {
|
|
|
38404
39093
|
throw new Error("stored delivery journal is malformed");
|
|
38405
39094
|
}
|
|
38406
39095
|
const ownProps = Object.getOwnPropertyNames(value);
|
|
38407
|
-
if (
|
|
39096
|
+
if ([...ALLOWED_TOP_KEYS].some((key2) => !ownProps.includes(key2)) || rejectUnknownKeys && !ownProps.every((key2) => ALLOWED_TOP_KEYS.has(key2))) {
|
|
38408
39097
|
throw new Error("stored delivery journal is malformed");
|
|
38409
39098
|
}
|
|
38410
39099
|
for (const prop of ownProps) {
|
|
@@ -38438,8 +39127,16 @@ function parseJournalRecord(raw, expectedWorkspaceId, expectedPrincipalId) {
|
|
|
38438
39127
|
if (!isValidIsoTimestamp(row.updatedAt)) {
|
|
38439
39128
|
throw new Error("stored delivery journal is malformed");
|
|
38440
39129
|
}
|
|
39130
|
+
const base = {
|
|
39131
|
+
version: 1,
|
|
39132
|
+
workspaceId: row.workspaceId,
|
|
39133
|
+
principalId: row.principalId,
|
|
39134
|
+
listenerInstanceId: row.listenerInstanceId,
|
|
39135
|
+
nextClaimOrdinal: row.nextClaimOrdinal,
|
|
39136
|
+
updatedAt: row.updatedAt
|
|
39137
|
+
};
|
|
38441
39138
|
if (row.active === null) {
|
|
38442
|
-
return
|
|
39139
|
+
return { ...base, active: null };
|
|
38443
39140
|
}
|
|
38444
39141
|
if (typeof row.active !== "object" || row.active === null || Array.isArray(row.active)) {
|
|
38445
39142
|
throw new Error("stored delivery journal is malformed");
|
|
@@ -38452,8 +39149,10 @@ function parseJournalRecord(raw, expectedWorkspaceId, expectedPrincipalId) {
|
|
|
38452
39149
|
throw new Error("stored delivery journal is malformed");
|
|
38453
39150
|
}
|
|
38454
39151
|
const activeProps = Object.getOwnPropertyNames(row.active);
|
|
38455
|
-
const
|
|
38456
|
-
|
|
39152
|
+
const requiredActiveKeys = [...ALLOWED_ACTIVE_KEYS].filter(
|
|
39153
|
+
(key2) => key2 !== "signalFingerprint"
|
|
39154
|
+
);
|
|
39155
|
+
if (requiredActiveKeys.some((key2) => !activeProps.includes(key2)) || rejectUnknownKeys && !activeProps.every((key2) => ALLOWED_ACTIVE_KEYS.has(key2))) {
|
|
38457
39156
|
throw new Error("stored delivery journal is malformed");
|
|
38458
39157
|
}
|
|
38459
39158
|
for (const prop of activeProps) {
|
|
@@ -38521,7 +39220,7 @@ function parseJournalRecord(raw, expectedWorkspaceId, expectedPrincipalId) {
|
|
|
38521
39220
|
throw new Error("stored delivery journal is malformed");
|
|
38522
39221
|
}
|
|
38523
39222
|
const ackProps = Object.getOwnPropertyNames(active.ack);
|
|
38524
|
-
if (
|
|
39223
|
+
if ([...ALLOWED_ACK_KEYS].some((key2) => !ackProps.includes(key2)) || rejectUnknownKeys && !ackProps.every((key2) => ALLOWED_ACK_KEYS.has(key2))) {
|
|
38525
39224
|
throw new Error("stored delivery journal is malformed");
|
|
38526
39225
|
}
|
|
38527
39226
|
for (const prop of ackProps) {
|
|
@@ -38530,32 +39229,52 @@ function parseJournalRecord(raw, expectedWorkspaceId, expectedPrincipalId) {
|
|
|
38530
39229
|
throw new Error("stored delivery journal is malformed");
|
|
38531
39230
|
}
|
|
38532
39231
|
}
|
|
38533
|
-
const
|
|
38534
|
-
if (typeof
|
|
39232
|
+
const ack2 = active.ack;
|
|
39233
|
+
if (typeof ack2.commandId !== "string" || !COMMAND_ID_RE3.test(ack2.commandId)) {
|
|
38535
39234
|
throw new Error("stored delivery journal is malformed");
|
|
38536
39235
|
}
|
|
38537
39236
|
const expectedAckCmdId = ackCommandId(active.leaseId);
|
|
38538
|
-
if (
|
|
39237
|
+
if (ack2.commandId !== expectedAckCmdId) {
|
|
38539
39238
|
throw new Error("stored delivery journal is malformed");
|
|
38540
39239
|
}
|
|
38541
|
-
if (typeof
|
|
39240
|
+
if (typeof ack2.outcome !== "string" || !ALLOWED_OUTCOMES.has(ack2.outcome)) {
|
|
38542
39241
|
throw new Error("stored delivery journal is malformed");
|
|
38543
39242
|
}
|
|
38544
|
-
if (
|
|
38545
|
-
if (typeof
|
|
39243
|
+
if (ack2.outcome === "failed_terminal") {
|
|
39244
|
+
if (typeof ack2.lastErrorCode !== "string" || !ALLOWED_ERROR_CODES.has(ack2.lastErrorCode)) {
|
|
38546
39245
|
throw new Error("stored delivery journal is malformed");
|
|
38547
39246
|
}
|
|
38548
39247
|
} else {
|
|
38549
|
-
if (
|
|
39248
|
+
if (ack2.lastErrorCode !== null) {
|
|
38550
39249
|
throw new Error("stored delivery journal is malformed");
|
|
38551
39250
|
}
|
|
38552
39251
|
}
|
|
38553
|
-
if (!isValidIsoTimestamp(
|
|
39252
|
+
if (!isValidIsoTimestamp(ack2.preparedAt)) {
|
|
38554
39253
|
throw new Error("stored delivery journal is malformed");
|
|
38555
39254
|
}
|
|
38556
39255
|
}
|
|
38557
39256
|
}
|
|
38558
|
-
|
|
39257
|
+
const ack = active.ack;
|
|
39258
|
+
return {
|
|
39259
|
+
...base,
|
|
39260
|
+
active: {
|
|
39261
|
+
phase: active.phase,
|
|
39262
|
+
claimOrdinal: active.claimOrdinal,
|
|
39263
|
+
claimCommandId: active.claimCommandId,
|
|
39264
|
+
claimCreatedAt: active.claimCreatedAt,
|
|
39265
|
+
claimLastAttemptAt: active.claimLastAttemptAt,
|
|
39266
|
+
signalId: active.signalId,
|
|
39267
|
+
leaseId: active.leaseId,
|
|
39268
|
+
leasedUntil: active.leasedUntil,
|
|
39269
|
+
...active.signalFingerprint === void 0 ? {} : { signalFingerprint: active.signalFingerprint },
|
|
39270
|
+
ack: ack === null ? null : {
|
|
39271
|
+
commandId: ack.commandId,
|
|
39272
|
+
outcome: ack.outcome,
|
|
39273
|
+
lastErrorCode: ack.lastErrorCode,
|
|
39274
|
+
preparedAt: ack.preparedAt
|
|
39275
|
+
}
|
|
39276
|
+
}
|
|
39277
|
+
};
|
|
38559
39278
|
}
|
|
38560
39279
|
var FileListenerDeliveryJournal = class {
|
|
38561
39280
|
instanceDirectory;
|
|
@@ -38619,7 +39338,8 @@ var FileListenerDeliveryJournal = class {
|
|
|
38619
39338
|
parseJournalRecord(
|
|
38620
39339
|
serialized,
|
|
38621
39340
|
this.options.workspaceId,
|
|
38622
|
-
this.options.principalId
|
|
39341
|
+
this.options.principalId,
|
|
39342
|
+
true
|
|
38623
39343
|
);
|
|
38624
39344
|
await writeSecureJsonFile(this.journalPath, serialized);
|
|
38625
39345
|
}
|
|
@@ -38869,7 +39589,8 @@ async function openListenerDeliveryJournal(options) {
|
|
|
38869
39589
|
parseJournalRecord(
|
|
38870
39590
|
serialized2,
|
|
38871
39591
|
workspaceIdSnapshot,
|
|
38872
|
-
principalIdSnapshot
|
|
39592
|
+
principalIdSnapshot,
|
|
39593
|
+
true
|
|
38873
39594
|
);
|
|
38874
39595
|
await writeSecureJsonFile(journal.journalPath, serialized2);
|
|
38875
39596
|
return {
|
|
@@ -38903,7 +39624,8 @@ async function openListenerDeliveryJournal(options) {
|
|
|
38903
39624
|
parseJournalRecord(
|
|
38904
39625
|
serialized,
|
|
38905
39626
|
workspaceIdSnapshot,
|
|
38906
|
-
principalIdSnapshot
|
|
39627
|
+
principalIdSnapshot,
|
|
39628
|
+
true
|
|
38907
39629
|
);
|
|
38908
39630
|
await writeSecureJsonFile(journal.journalPath, serialized);
|
|
38909
39631
|
return {
|
|
@@ -39021,12 +39743,12 @@ async function spawnDetachedListener(options) {
|
|
|
39021
39743
|
child.kill();
|
|
39022
39744
|
throw new Error("detached listener child has no credential pipe");
|
|
39023
39745
|
}
|
|
39024
|
-
await new Promise((
|
|
39746
|
+
await new Promise((resolve3, reject) => {
|
|
39025
39747
|
const onError = (error) => reject(error);
|
|
39026
39748
|
child.once("error", onError);
|
|
39027
39749
|
child.stdin.end(options.credentialArtifact, "utf8", () => {
|
|
39028
39750
|
child.off("error", onError);
|
|
39029
|
-
|
|
39751
|
+
resolve3();
|
|
39030
39752
|
});
|
|
39031
39753
|
});
|
|
39032
39754
|
child.unref();
|
|
@@ -39059,7 +39781,7 @@ function parseState(raw) {
|
|
|
39059
39781
|
}
|
|
39060
39782
|
const row = value;
|
|
39061
39783
|
const topicVersions = row.topicVersions;
|
|
39062
|
-
if (
|
|
39784
|
+
if (row.version !== 1 || typeof row.principalId !== "string" || !UUID_RE20.test(row.principalId) || !topicVersions || typeof topicVersions !== "object" || Array.isArray(topicVersions) || Object.keys(topicVersions).length > MAX_BRAIN_DIGEST_TOPICS) {
|
|
39063
39785
|
throw new Error("stored brain digest state is malformed");
|
|
39064
39786
|
}
|
|
39065
39787
|
for (const [topic, version3] of Object.entries(topicVersions)) {
|
|
@@ -39171,7 +39893,26 @@ function exactKeys2(row, keys) {
|
|
|
39171
39893
|
const expected = new Set(keys);
|
|
39172
39894
|
return Object.keys(row).length === expected.size && Object.keys(row).every((key2) => expected.has(key2));
|
|
39173
39895
|
}
|
|
39174
|
-
function
|
|
39896
|
+
function hasRequiredKeys(row, keys) {
|
|
39897
|
+
return keys.every((key2) => Object.hasOwn(row, key2));
|
|
39898
|
+
}
|
|
39899
|
+
var LISTENER_CREDENTIAL_KEYS = [
|
|
39900
|
+
"version",
|
|
39901
|
+
"profileId",
|
|
39902
|
+
"targetUrl",
|
|
39903
|
+
"anonKey",
|
|
39904
|
+
"workspaceId",
|
|
39905
|
+
"principalId",
|
|
39906
|
+
"credential",
|
|
39907
|
+
"updatedAt"
|
|
39908
|
+
];
|
|
39909
|
+
var HOOK_SURFACE_KEYS = /* @__PURE__ */ new Set([
|
|
39910
|
+
"version",
|
|
39911
|
+
"surfacedSignalIds",
|
|
39912
|
+
"reportedDroppedCount",
|
|
39913
|
+
"credentialFailureReported"
|
|
39914
|
+
]);
|
|
39915
|
+
function parseListenerCredential(raw, rejectUnknownKeys = false) {
|
|
39175
39916
|
let value;
|
|
39176
39917
|
try {
|
|
39177
39918
|
value = JSON.parse(raw);
|
|
@@ -39182,16 +39923,7 @@ function parseListenerCredential(raw) {
|
|
|
39182
39923
|
throw new Error("stored listener hook credential is malformed");
|
|
39183
39924
|
}
|
|
39184
39925
|
const row = value;
|
|
39185
|
-
if (!exactKeys2(row, [
|
|
39186
|
-
"version",
|
|
39187
|
-
"profileId",
|
|
39188
|
-
"targetUrl",
|
|
39189
|
-
"anonKey",
|
|
39190
|
-
"workspaceId",
|
|
39191
|
-
"principalId",
|
|
39192
|
-
"credential",
|
|
39193
|
-
"updatedAt"
|
|
39194
|
-
]) || row.version !== 1 || typeof row.profileId !== "string" || !/^[0-9a-f]{24}$/.test(row.profileId) || typeof row.targetUrl !== "string" || typeof row.anonKey !== "string" || row.anonKey.length < 1 || row.anonKey.length > 4096 || typeof row.workspaceId !== "string" || !UUID_RE21.test(row.workspaceId) || typeof row.principalId !== "string" || !UUID_RE21.test(row.principalId) || typeof row.credential !== "string" || !TOKEN_RE.test(row.credential) || typeof row.updatedAt !== "string" || !Number.isFinite(Date.parse(row.updatedAt))) {
|
|
39926
|
+
if (!(rejectUnknownKeys ? exactKeys2(row, LISTENER_CREDENTIAL_KEYS) : hasRequiredKeys(row, LISTENER_CREDENTIAL_KEYS)) || row.version !== 1 || typeof row.profileId !== "string" || !/^[0-9a-f]{24}$/.test(row.profileId) || typeof row.targetUrl !== "string" || typeof row.anonKey !== "string" || row.anonKey.length < 1 || row.anonKey.length > 4096 || typeof row.workspaceId !== "string" || !UUID_RE21.test(row.workspaceId) || typeof row.principalId !== "string" || !UUID_RE21.test(row.principalId) || typeof row.credential !== "string" || !TOKEN_RE.test(row.credential) || typeof row.updatedAt !== "string" || !Number.isFinite(Date.parse(row.updatedAt))) {
|
|
39195
39927
|
throw new Error("stored listener hook credential is malformed");
|
|
39196
39928
|
}
|
|
39197
39929
|
const target2 = cloudTarget(row.targetUrl, row.anonKey);
|
|
@@ -39222,7 +39954,7 @@ async function writeListenerCredentialState(instanceDirectory, input) {
|
|
|
39222
39954
|
principalId: input.principalId,
|
|
39223
39955
|
credential: input.credential,
|
|
39224
39956
|
updatedAt: new Date(input.now ?? Date.now()).toISOString()
|
|
39225
|
-
}));
|
|
39957
|
+
}), true);
|
|
39226
39958
|
await writeSecureJsonFile(
|
|
39227
39959
|
(0, import_node_path20.join)(instanceDirectory, LISTENER_CREDENTIAL_FILE),
|
|
39228
39960
|
JSON.stringify(record)
|
|
@@ -39238,7 +39970,7 @@ async function readListenerCredentialState(instanceDirectory) {
|
|
|
39238
39970
|
);
|
|
39239
39971
|
return raw === null ? null : parseListenerCredential(raw);
|
|
39240
39972
|
}
|
|
39241
|
-
function parseSurface(raw) {
|
|
39973
|
+
function parseSurface(raw, rejectUnknownKeys = false) {
|
|
39242
39974
|
let value;
|
|
39243
39975
|
try {
|
|
39244
39976
|
value = JSON.parse(raw);
|
|
@@ -39249,9 +39981,7 @@ function parseSurface(raw) {
|
|
|
39249
39981
|
throw new Error("stored listener hook surface state is malformed");
|
|
39250
39982
|
}
|
|
39251
39983
|
const row = value;
|
|
39252
|
-
if (Object.keys(row).some(
|
|
39253
|
-
(key2) => key2 !== "version" && key2 !== "surfacedSignalIds" && key2 !== "reportedDroppedCount" && key2 !== "credentialFailureReported"
|
|
39254
|
-
) || row.version !== 1 || !Array.isArray(row.surfacedSignalIds) || row.surfacedSignalIds.length > HOOK_SURFACED_IDS_MAX || row.surfacedSignalIds.some((id) => typeof id !== "string" || !UUID_RE21.test(id)) || !(row.reportedDroppedCount === void 0 || typeof row.reportedDroppedCount === "number" && Number.isSafeInteger(row.reportedDroppedCount) && row.reportedDroppedCount >= 0) || !(row.credentialFailureReported === void 0 || typeof row.credentialFailureReported === "boolean")) {
|
|
39984
|
+
if (rejectUnknownKeys && Object.keys(row).some((key2) => !HOOK_SURFACE_KEYS.has(key2)) || row.version !== 1 || !Array.isArray(row.surfacedSignalIds) || row.surfacedSignalIds.length > HOOK_SURFACED_IDS_MAX || row.surfacedSignalIds.some((id) => typeof id !== "string" || !UUID_RE21.test(id)) || !(row.reportedDroppedCount === void 0 || typeof row.reportedDroppedCount === "number" && Number.isSafeInteger(row.reportedDroppedCount) && row.reportedDroppedCount >= 0) || !(row.credentialFailureReported === void 0 || typeof row.credentialFailureReported === "boolean")) {
|
|
39255
39985
|
throw new Error("stored listener hook surface state is malformed");
|
|
39256
39986
|
}
|
|
39257
39987
|
const ids = row.surfacedSignalIds.map((id) => String(id).toLowerCase());
|
|
@@ -39345,7 +40075,7 @@ var FileHookSurfaceStore = class {
|
|
|
39345
40075
|
surfacedSignalIds: [...seen].slice(-HOOK_SURFACED_IDS_MAX),
|
|
39346
40076
|
reportedDroppedCount: options.droppedCount ?? state.reportedDroppedCount,
|
|
39347
40077
|
credentialFailureReported: options.credentialFailureReported ?? state.credentialFailureReported
|
|
39348
|
-
})))
|
|
40078
|
+
}), true))
|
|
39349
40079
|
);
|
|
39350
40080
|
}, { timeoutMs: HOOK_LOCK_TIMEOUT_MS });
|
|
39351
40081
|
}
|
|
@@ -39368,7 +40098,7 @@ function parseGlobalState(raw) {
|
|
|
39368
40098
|
throw new Error("stored hook cooldown state is malformed");
|
|
39369
40099
|
}
|
|
39370
40100
|
const row = value;
|
|
39371
|
-
if (!
|
|
40101
|
+
if (!hasRequiredKeys(row, ["version", "lastCheckAt"]) || row.version !== 1 || typeof row.lastCheckAt !== "number" || !Number.isSafeInteger(row.lastCheckAt) || row.lastCheckAt < 0) {
|
|
39372
40102
|
throw new Error("stored hook cooldown state is malformed");
|
|
39373
40103
|
}
|
|
39374
40104
|
return { version: 1, lastCheckAt: row.lastCheckAt };
|
|
@@ -39809,10 +40539,10 @@ async function runListenerHookCheck(options = {}) {
|
|
|
39809
40539
|
signal: controller.signal,
|
|
39810
40540
|
deadlineMs
|
|
39811
40541
|
});
|
|
39812
|
-
const timedOut = new Promise((
|
|
40542
|
+
const timedOut = new Promise((resolve3) => {
|
|
39813
40543
|
timer2 = setTimeout(() => {
|
|
39814
40544
|
controller.abort();
|
|
39815
|
-
|
|
40545
|
+
resolve3("");
|
|
39816
40546
|
}, HOOK_CHECK_TIMEOUT_MS);
|
|
39817
40547
|
});
|
|
39818
40548
|
return await Promise.race([checking, timedOut]);
|
|
@@ -39882,7 +40612,7 @@ async function logEvidence(path, signalId) {
|
|
|
39882
40612
|
}
|
|
39883
40613
|
async function runListenerAttendanceCanary(options) {
|
|
39884
40614
|
const now = options.now ?? Date.now;
|
|
39885
|
-
const sleep2 = options.sleep ?? ((milliseconds) => new Promise((
|
|
40615
|
+
const sleep2 = options.sleep ?? ((milliseconds) => new Promise((resolve3) => setTimeout(resolve3, milliseconds)));
|
|
39886
40616
|
const startedAt = now();
|
|
39887
40617
|
const deadlineMs = startedAt + options.waitMs;
|
|
39888
40618
|
const client = new ThinCommandClient(options.target, options.fetcher, {
|
|
@@ -39995,16 +40725,508 @@ function renderListenerAttendanceCanary(result, workspaceId2, principalId) {
|
|
|
39995
40725
|
return lines.join("\n");
|
|
39996
40726
|
}
|
|
39997
40727
|
|
|
40728
|
+
// src/listener/activity.ts
|
|
40729
|
+
var import_node_crypto21 = require("node:crypto");
|
|
40730
|
+
var ACTIVITY_FRAME_INTERVAL_MS = 750;
|
|
40731
|
+
var ACTIVITY_HEARTBEAT_MS = 15e3;
|
|
40732
|
+
var ACTIVITY_TOOL_TITLE_MAX = 160;
|
|
40733
|
+
var ACTIVITY_REQUEST_TIMEOUT_MS = 5e3;
|
|
40734
|
+
var AgentActivityPublishError = class extends Error {
|
|
40735
|
+
constructor(code, cause) {
|
|
40736
|
+
super("activity frame publish failed", { cause });
|
|
40737
|
+
this.code = code;
|
|
40738
|
+
this.name = "AgentActivityPublishError";
|
|
40739
|
+
}
|
|
40740
|
+
code;
|
|
40741
|
+
};
|
|
40742
|
+
function activityPublishErrorCode(error) {
|
|
40743
|
+
return error instanceof AgentActivityPublishError ? error.code : "activity_publish_unknown";
|
|
40744
|
+
}
|
|
40745
|
+
var SYSTEM_CLOCK = {
|
|
40746
|
+
now: Date.now,
|
|
40747
|
+
setTimer: (callback, delayMs) => setTimeout(callback, delayMs),
|
|
40748
|
+
clearTimer: (timer2) => clearTimeout(timer2)
|
|
40749
|
+
};
|
|
40750
|
+
var TERMINAL_TOOL_STATUSES = /* @__PURE__ */ new Set([
|
|
40751
|
+
"cancelled",
|
|
40752
|
+
"completed",
|
|
40753
|
+
"done",
|
|
40754
|
+
"failed",
|
|
40755
|
+
"rejected"
|
|
40756
|
+
]);
|
|
40757
|
+
var AgentActivityEndpointTransport = class {
|
|
40758
|
+
constructor(target2, credentialSession, fetcher, requestTimeoutMs = ACTIVITY_REQUEST_TIMEOUT_MS) {
|
|
40759
|
+
this.target = target2;
|
|
40760
|
+
this.credentialSession = credentialSession;
|
|
40761
|
+
this.requestTimeoutMs = requestTimeoutMs;
|
|
40762
|
+
this.fetcher = fetcher ?? fetch;
|
|
40763
|
+
}
|
|
40764
|
+
target;
|
|
40765
|
+
credentialSession;
|
|
40766
|
+
requestTimeoutMs;
|
|
40767
|
+
fetcher;
|
|
40768
|
+
async publish(frame) {
|
|
40769
|
+
let credential;
|
|
40770
|
+
try {
|
|
40771
|
+
credential = await this.credentialSession.bearer();
|
|
40772
|
+
} catch (error) {
|
|
40773
|
+
throw new AgentActivityPublishError("activity_credential_failed", error);
|
|
40774
|
+
}
|
|
40775
|
+
const timeoutSignal = AbortSignal.timeout(this.requestTimeoutMs);
|
|
40776
|
+
let response;
|
|
40777
|
+
try {
|
|
40778
|
+
response = await this.fetcher(
|
|
40779
|
+
`${this.target.url}/functions/v1/activity`,
|
|
40780
|
+
{
|
|
40781
|
+
method: "POST",
|
|
40782
|
+
headers: {
|
|
40783
|
+
authorization: `Bearer ${credential}`,
|
|
40784
|
+
apikey: this.target.anonKey,
|
|
40785
|
+
"content-type": "application/json"
|
|
40786
|
+
},
|
|
40787
|
+
body: JSON.stringify({
|
|
40788
|
+
version: frame.version,
|
|
40789
|
+
workspace_id: frame.workspaceId,
|
|
40790
|
+
stream_id: frame.streamId,
|
|
40791
|
+
sequence: frame.sequence,
|
|
40792
|
+
phase: frame.phase,
|
|
40793
|
+
signal_id: frame.signalId,
|
|
40794
|
+
tool_title: frame.toolTitle,
|
|
40795
|
+
elapsed_ms: frame.elapsedMs
|
|
40796
|
+
}),
|
|
40797
|
+
signal: timeoutSignal
|
|
40798
|
+
}
|
|
40799
|
+
);
|
|
40800
|
+
} catch (error) {
|
|
40801
|
+
throw new AgentActivityPublishError(
|
|
40802
|
+
timeoutSignal.aborted ? "activity_request_timeout" : "activity_transport_failed",
|
|
40803
|
+
error
|
|
40804
|
+
);
|
|
40805
|
+
}
|
|
40806
|
+
await response.body?.cancel().catch(() => void 0);
|
|
40807
|
+
if (!response.ok) {
|
|
40808
|
+
throw new AgentActivityPublishError("activity_http_rejected");
|
|
40809
|
+
}
|
|
40810
|
+
}
|
|
40811
|
+
};
|
|
40812
|
+
var ListenerActivityController = class {
|
|
40813
|
+
constructor(options) {
|
|
40814
|
+
this.options = options;
|
|
40815
|
+
this.clock = options.clock ?? SYSTEM_CLOCK;
|
|
40816
|
+
this.streamId = options.streamId ?? (0, import_node_crypto21.randomUUID)();
|
|
40817
|
+
this.events = { update: (update) => this.onSessionUpdate(update) };
|
|
40818
|
+
}
|
|
40819
|
+
options;
|
|
40820
|
+
events;
|
|
40821
|
+
clock;
|
|
40822
|
+
streamId;
|
|
40823
|
+
sequence = 0;
|
|
40824
|
+
phase = "idle";
|
|
40825
|
+
signalId = null;
|
|
40826
|
+
signalStartedAt = null;
|
|
40827
|
+
runningTools = /* @__PURE__ */ new Map();
|
|
40828
|
+
latestToolId = null;
|
|
40829
|
+
dirty = false;
|
|
40830
|
+
sending = false;
|
|
40831
|
+
closed = false;
|
|
40832
|
+
lastSentAt = Number.NEGATIVE_INFINITY;
|
|
40833
|
+
timer = null;
|
|
40834
|
+
heartbeatTimer = null;
|
|
40835
|
+
/** Observe the listener state machine without changing its durable effect path. */
|
|
40836
|
+
onRuntimeEvent(event) {
|
|
40837
|
+
if (event.type === "ready") {
|
|
40838
|
+
this.setIdle();
|
|
40839
|
+
} else if (event.type === "delivery_claim" && event.signalId !== null) {
|
|
40840
|
+
this.beginSignal(event.signalId);
|
|
40841
|
+
} else if (event.type === "routing_decision") {
|
|
40842
|
+
this.beginSignal(event.signalId);
|
|
40843
|
+
} else if (event.type === "effect") {
|
|
40844
|
+
this.setIdle();
|
|
40845
|
+
}
|
|
40846
|
+
}
|
|
40847
|
+
/** Wrap one provider model so prompt and reply phases are visible. */
|
|
40848
|
+
instrumentModel(model) {
|
|
40849
|
+
return {
|
|
40850
|
+
start: async () => await model.start(),
|
|
40851
|
+
prompt: async (signal, mode3, prompt, attempt) => {
|
|
40852
|
+
this.beginSignal(signal.id);
|
|
40853
|
+
this.setPhase("prompting");
|
|
40854
|
+
const result = await model.prompt(signal, mode3, prompt, attempt);
|
|
40855
|
+
this.runningTools.clear();
|
|
40856
|
+
this.latestToolId = null;
|
|
40857
|
+
this.setPhase("replying");
|
|
40858
|
+
return result;
|
|
40859
|
+
},
|
|
40860
|
+
cancel: () => model.cancel(),
|
|
40861
|
+
close: async () => await model.close()
|
|
40862
|
+
};
|
|
40863
|
+
}
|
|
40864
|
+
/** Stop pending local timers; a missing next frame becomes stale in the panel. */
|
|
40865
|
+
close() {
|
|
40866
|
+
this.closed = true;
|
|
40867
|
+
if (this.timer !== null) this.clock.clearTimer(this.timer);
|
|
40868
|
+
if (this.heartbeatTimer !== null) this.clock.clearTimer(this.heartbeatTimer);
|
|
40869
|
+
this.timer = null;
|
|
40870
|
+
this.heartbeatTimer = null;
|
|
40871
|
+
}
|
|
40872
|
+
onSessionUpdate(update) {
|
|
40873
|
+
if (this.signalId === null) return;
|
|
40874
|
+
if (update.kind !== "tool_call" && update.kind !== "tool_call_update") return;
|
|
40875
|
+
const id = update.toolCallId;
|
|
40876
|
+
if (!id) return;
|
|
40877
|
+
const status = update.status?.toLowerCase();
|
|
40878
|
+
if (status && TERMINAL_TOOL_STATUSES.has(status)) {
|
|
40879
|
+
this.runningTools.delete(id);
|
|
40880
|
+
if (this.latestToolId === id) {
|
|
40881
|
+
this.latestToolId = [...this.runningTools.keys()].at(-1) ?? null;
|
|
40882
|
+
}
|
|
40883
|
+
this.setPhase(this.runningTools.size > 0 ? "tool-running" : "prompting");
|
|
40884
|
+
return;
|
|
40885
|
+
}
|
|
40886
|
+
const sanitizedTitle = update.title === void 0 ? this.runningTools.get(id) : sanitizeText(update.title).slice(0, ACTIVITY_TOOL_TITLE_MAX);
|
|
40887
|
+
const title = sanitizedTitle && sanitizedTitle.length > 0 ? sanitizedTitle : "Tool";
|
|
40888
|
+
this.runningTools.set(id, title);
|
|
40889
|
+
this.latestToolId = id;
|
|
40890
|
+
this.setPhase("tool-running");
|
|
40891
|
+
}
|
|
40892
|
+
beginSignal(signalId) {
|
|
40893
|
+
if (this.signalId === signalId) return;
|
|
40894
|
+
this.signalId = signalId;
|
|
40895
|
+
this.signalStartedAt = this.clock.now();
|
|
40896
|
+
this.runningTools.clear();
|
|
40897
|
+
this.latestToolId = null;
|
|
40898
|
+
this.setPhase("claimed");
|
|
40899
|
+
}
|
|
40900
|
+
setIdle() {
|
|
40901
|
+
this.signalId = null;
|
|
40902
|
+
this.signalStartedAt = null;
|
|
40903
|
+
this.runningTools.clear();
|
|
40904
|
+
this.latestToolId = null;
|
|
40905
|
+
this.setPhase("idle");
|
|
40906
|
+
}
|
|
40907
|
+
setPhase(phase) {
|
|
40908
|
+
this.phase = phase;
|
|
40909
|
+
if (this.heartbeatTimer !== null) {
|
|
40910
|
+
this.clock.clearTimer(this.heartbeatTimer);
|
|
40911
|
+
this.heartbeatTimer = null;
|
|
40912
|
+
}
|
|
40913
|
+
this.dirty = true;
|
|
40914
|
+
this.schedule();
|
|
40915
|
+
}
|
|
40916
|
+
armHeartbeat() {
|
|
40917
|
+
if (this.closed || this.heartbeatTimer !== null) return;
|
|
40918
|
+
this.heartbeatTimer = this.clock.setTimer(() => {
|
|
40919
|
+
this.heartbeatTimer = null;
|
|
40920
|
+
this.dirty = true;
|
|
40921
|
+
this.schedule();
|
|
40922
|
+
}, ACTIVITY_HEARTBEAT_MS);
|
|
40923
|
+
}
|
|
40924
|
+
schedule() {
|
|
40925
|
+
if (this.closed || this.timer !== null || this.sending) return;
|
|
40926
|
+
const delay2 = Math.max(
|
|
40927
|
+
0,
|
|
40928
|
+
this.lastSentAt + ACTIVITY_FRAME_INTERVAL_MS - this.clock.now()
|
|
40929
|
+
);
|
|
40930
|
+
if (delay2 === 0) {
|
|
40931
|
+
void this.flush();
|
|
40932
|
+
return;
|
|
40933
|
+
}
|
|
40934
|
+
this.timer = this.clock.setTimer(() => {
|
|
40935
|
+
this.timer = null;
|
|
40936
|
+
void this.flush();
|
|
40937
|
+
}, delay2);
|
|
40938
|
+
}
|
|
40939
|
+
async flush() {
|
|
40940
|
+
if (this.closed || this.sending || !this.dirty) return;
|
|
40941
|
+
this.dirty = false;
|
|
40942
|
+
this.sending = true;
|
|
40943
|
+
this.lastSentAt = this.clock.now();
|
|
40944
|
+
const toolTitle = this.latestToolId === null ? null : this.runningTools.get(this.latestToolId) ?? null;
|
|
40945
|
+
const frame = {
|
|
40946
|
+
version: 1,
|
|
40947
|
+
workspaceId: this.options.workspaceId,
|
|
40948
|
+
streamId: this.streamId,
|
|
40949
|
+
sequence: ++this.sequence,
|
|
40950
|
+
phase: this.phase,
|
|
40951
|
+
signalId: this.signalId,
|
|
40952
|
+
toolTitle,
|
|
40953
|
+
elapsedMs: this.signalStartedAt === null ? 0 : Math.max(0, Math.round(this.clock.now() - this.signalStartedAt))
|
|
40954
|
+
};
|
|
40955
|
+
try {
|
|
40956
|
+
await this.options.transport.publish(frame);
|
|
40957
|
+
} catch (error) {
|
|
40958
|
+
this.options.onPublishFailure?.(activityPublishErrorCode(error));
|
|
40959
|
+
} finally {
|
|
40960
|
+
this.sending = false;
|
|
40961
|
+
if (this.dirty) this.schedule();
|
|
40962
|
+
else this.armHeartbeat();
|
|
40963
|
+
}
|
|
40964
|
+
}
|
|
40965
|
+
};
|
|
40966
|
+
|
|
40967
|
+
// src/listener/http-client.ts
|
|
40968
|
+
var import_node_http2 = require("node:http");
|
|
40969
|
+
var import_node_https = require("node:https");
|
|
40970
|
+
var import_node_zlib = require("node:zlib");
|
|
40971
|
+
var LISTENER_HTTP_IDLE_TIMEOUT_MS = 6e4;
|
|
40972
|
+
function responseHeaders(message) {
|
|
40973
|
+
const headers = new Headers();
|
|
40974
|
+
for (let index = 0; index < message.rawHeaders.length; index += 2) {
|
|
40975
|
+
const name = message.rawHeaders[index];
|
|
40976
|
+
const value = message.rawHeaders[index + 1];
|
|
40977
|
+
if (name !== void 0 && value !== void 0) headers.append(name, value);
|
|
40978
|
+
}
|
|
40979
|
+
return headers;
|
|
40980
|
+
}
|
|
40981
|
+
function decodeResponseBody(bytes, headers) {
|
|
40982
|
+
const codings = (headers.get("content-encoding") ?? "").split(",").map((coding) => coding.trim().toLowerCase()).filter((coding) => coding !== "" && coding !== "identity");
|
|
40983
|
+
if (!codings.every((coding) => ["br", "deflate", "gzip", "x-gzip"].includes(coding))) {
|
|
40984
|
+
return Uint8Array.from(bytes).buffer;
|
|
40985
|
+
}
|
|
40986
|
+
let decoded = bytes;
|
|
40987
|
+
for (const coding of codings.reverse()) {
|
|
40988
|
+
if (coding === "br") decoded = (0, import_node_zlib.brotliDecompressSync)(decoded);
|
|
40989
|
+
else if (coding === "deflate") decoded = (0, import_node_zlib.inflateSync)(decoded);
|
|
40990
|
+
else decoded = (0, import_node_zlib.gunzipSync)(decoded);
|
|
40991
|
+
}
|
|
40992
|
+
return Uint8Array.from(decoded).buffer;
|
|
40993
|
+
}
|
|
40994
|
+
var ListenerHttpClient = class {
|
|
40995
|
+
fetch;
|
|
40996
|
+
httpAgent = new import_node_http2.Agent({
|
|
40997
|
+
keepAlive: true,
|
|
40998
|
+
maxSockets: 1,
|
|
40999
|
+
maxFreeSockets: 1,
|
|
41000
|
+
scheduling: "fifo"
|
|
41001
|
+
});
|
|
41002
|
+
httpsAgent = new import_node_https.Agent({
|
|
41003
|
+
keepAlive: true,
|
|
41004
|
+
maxSockets: 1,
|
|
41005
|
+
maxFreeSockets: 1,
|
|
41006
|
+
scheduling: "fifo"
|
|
41007
|
+
});
|
|
41008
|
+
idleTimeoutMs;
|
|
41009
|
+
sockets = /* @__PURE__ */ new WeakSet();
|
|
41010
|
+
requestCount = 0;
|
|
41011
|
+
openedCount = 0;
|
|
41012
|
+
activeRequests = 0;
|
|
41013
|
+
idleTimer = null;
|
|
41014
|
+
closed = false;
|
|
41015
|
+
constructor(options = {}) {
|
|
41016
|
+
const idleTimeoutMs = options.idleTimeoutMs ?? LISTENER_HTTP_IDLE_TIMEOUT_MS;
|
|
41017
|
+
if (!Number.isSafeInteger(idleTimeoutMs) || idleTimeoutMs <= 0) {
|
|
41018
|
+
throw new Error("listener HTTP idle timeout must be a positive integer");
|
|
41019
|
+
}
|
|
41020
|
+
this.idleTimeoutMs = idleTimeoutMs;
|
|
41021
|
+
this.fetch = this.request.bind(this);
|
|
41022
|
+
}
|
|
41023
|
+
/** Snapshot process-local counts without exposing the agents themselves. */
|
|
41024
|
+
metrics() {
|
|
41025
|
+
return {
|
|
41026
|
+
requests: this.requestCount,
|
|
41027
|
+
connectionsOpened: this.openedCount,
|
|
41028
|
+
connectionReuseRatio: this.openedCount === 0 ? 0 : this.requestCount / this.openedCount
|
|
41029
|
+
};
|
|
41030
|
+
}
|
|
41031
|
+
/** Close every idle or active socket when the listener process stops. */
|
|
41032
|
+
close() {
|
|
41033
|
+
if (this.closed) return;
|
|
41034
|
+
this.closed = true;
|
|
41035
|
+
this.clearIdleTimer();
|
|
41036
|
+
this.destroyAgents();
|
|
41037
|
+
}
|
|
41038
|
+
clearIdleTimer() {
|
|
41039
|
+
if (this.idleTimer === null) return;
|
|
41040
|
+
clearTimeout(this.idleTimer);
|
|
41041
|
+
this.idleTimer = null;
|
|
41042
|
+
}
|
|
41043
|
+
destroyAgents() {
|
|
41044
|
+
this.httpAgent.destroy();
|
|
41045
|
+
this.httpsAgent.destroy();
|
|
41046
|
+
}
|
|
41047
|
+
beginRequest() {
|
|
41048
|
+
if (this.closed) throw new Error("listener HTTP client is closed");
|
|
41049
|
+
this.clearIdleTimer();
|
|
41050
|
+
this.requestCount += 1;
|
|
41051
|
+
this.activeRequests += 1;
|
|
41052
|
+
}
|
|
41053
|
+
finishRequest() {
|
|
41054
|
+
this.activeRequests -= 1;
|
|
41055
|
+
if (this.activeRequests !== 0 || this.closed) return;
|
|
41056
|
+
this.idleTimer = setTimeout(() => {
|
|
41057
|
+
this.idleTimer = null;
|
|
41058
|
+
if (this.activeRequests === 0 && !this.closed) this.destroyAgents();
|
|
41059
|
+
}, this.idleTimeoutMs);
|
|
41060
|
+
this.idleTimer.unref?.();
|
|
41061
|
+
}
|
|
41062
|
+
trackSocket(request) {
|
|
41063
|
+
request.once("socket", (socket) => {
|
|
41064
|
+
if (this.sockets.has(socket)) return;
|
|
41065
|
+
this.sockets.add(socket);
|
|
41066
|
+
const opened = () => {
|
|
41067
|
+
this.openedCount += 1;
|
|
41068
|
+
};
|
|
41069
|
+
if (socket.connecting) socket.once("connect", opened);
|
|
41070
|
+
else opened();
|
|
41071
|
+
});
|
|
41072
|
+
}
|
|
41073
|
+
async request(input, init) {
|
|
41074
|
+
const webRequest = new Request(input, init);
|
|
41075
|
+
const body = webRequest.method === "GET" || webRequest.method === "HEAD" ? null : Buffer.from(await webRequest.arrayBuffer());
|
|
41076
|
+
let url = new URL(webRequest.url);
|
|
41077
|
+
let method = webRequest.method;
|
|
41078
|
+
let headers = new Headers(webRequest.headers);
|
|
41079
|
+
let redirected = false;
|
|
41080
|
+
for (let redirects = 0; ; redirects += 1) {
|
|
41081
|
+
const response = await this.sendOnce({
|
|
41082
|
+
url,
|
|
41083
|
+
method,
|
|
41084
|
+
headers,
|
|
41085
|
+
body: method === "GET" || method === "HEAD" ? null : body,
|
|
41086
|
+
signal: webRequest.signal,
|
|
41087
|
+
redirected
|
|
41088
|
+
});
|
|
41089
|
+
const location2 = response.headers.get("location");
|
|
41090
|
+
if (location2 === null || ![301, 302, 303, 307, 308].includes(response.status) || webRequest.redirect === "manual") {
|
|
41091
|
+
return response;
|
|
41092
|
+
}
|
|
41093
|
+
if (webRequest.redirect === "error" || redirects >= 20) {
|
|
41094
|
+
throw new TypeError("fetch failed while following a redirect");
|
|
41095
|
+
}
|
|
41096
|
+
const nextUrl = new URL(location2, url);
|
|
41097
|
+
if (nextUrl.protocol !== "http:" && nextUrl.protocol !== "https:") {
|
|
41098
|
+
throw new TypeError("listener HTTP client accepts only http and https URLs");
|
|
41099
|
+
}
|
|
41100
|
+
const rewriteToGet = response.status === 303 && method !== "HEAD" || (response.status === 301 || response.status === 302) && method === "POST";
|
|
41101
|
+
if (rewriteToGet) {
|
|
41102
|
+
method = "GET";
|
|
41103
|
+
for (const name of [
|
|
41104
|
+
"content-encoding",
|
|
41105
|
+
"content-language",
|
|
41106
|
+
"content-length",
|
|
41107
|
+
"content-location",
|
|
41108
|
+
"content-type",
|
|
41109
|
+
"transfer-encoding"
|
|
41110
|
+
]) {
|
|
41111
|
+
headers.delete(name);
|
|
41112
|
+
}
|
|
41113
|
+
}
|
|
41114
|
+
if (nextUrl.origin !== url.origin) {
|
|
41115
|
+
for (const name of [
|
|
41116
|
+
"apikey",
|
|
41117
|
+
"authorization",
|
|
41118
|
+
"cookie",
|
|
41119
|
+
"host",
|
|
41120
|
+
"proxy-authorization"
|
|
41121
|
+
]) {
|
|
41122
|
+
headers.delete(name);
|
|
41123
|
+
}
|
|
41124
|
+
}
|
|
41125
|
+
url = nextUrl;
|
|
41126
|
+
redirected = true;
|
|
41127
|
+
}
|
|
41128
|
+
}
|
|
41129
|
+
async sendOnce(options) {
|
|
41130
|
+
if (options.url.protocol !== "http:" && options.url.protocol !== "https:") {
|
|
41131
|
+
throw new TypeError("listener HTTP client accepts only http and https URLs");
|
|
41132
|
+
}
|
|
41133
|
+
const headers = Object.fromEntries(options.headers.entries());
|
|
41134
|
+
if (!("accept-encoding" in headers)) headers["accept-encoding"] = "gzip, deflate";
|
|
41135
|
+
if (options.body !== null && !("content-length" in headers) && !("transfer-encoding" in headers)) {
|
|
41136
|
+
headers["content-length"] = String(options.body.byteLength);
|
|
41137
|
+
}
|
|
41138
|
+
this.beginRequest();
|
|
41139
|
+
let finished = false;
|
|
41140
|
+
const finish = () => {
|
|
41141
|
+
if (finished) return;
|
|
41142
|
+
finished = true;
|
|
41143
|
+
this.finishRequest();
|
|
41144
|
+
};
|
|
41145
|
+
return await new Promise((resolve3, reject) => {
|
|
41146
|
+
const send = options.url.protocol === "https:" ? import_node_https.request : import_node_http2.request;
|
|
41147
|
+
const agent = options.url.protocol === "https:" ? this.httpsAgent : this.httpAgent;
|
|
41148
|
+
let request;
|
|
41149
|
+
try {
|
|
41150
|
+
request = send(options.url, {
|
|
41151
|
+
agent,
|
|
41152
|
+
method: options.method,
|
|
41153
|
+
headers,
|
|
41154
|
+
signal: options.signal
|
|
41155
|
+
});
|
|
41156
|
+
} catch (error) {
|
|
41157
|
+
finish();
|
|
41158
|
+
reject(error);
|
|
41159
|
+
return;
|
|
41160
|
+
}
|
|
41161
|
+
this.trackSocket(request);
|
|
41162
|
+
request.once("error", (error) => {
|
|
41163
|
+
finish();
|
|
41164
|
+
reject(error);
|
|
41165
|
+
});
|
|
41166
|
+
request.once("response", (message) => {
|
|
41167
|
+
const chunks = [];
|
|
41168
|
+
let settled = false;
|
|
41169
|
+
const rejectResponse = (error) => {
|
|
41170
|
+
if (settled) return;
|
|
41171
|
+
settled = true;
|
|
41172
|
+
finish();
|
|
41173
|
+
reject(error);
|
|
41174
|
+
};
|
|
41175
|
+
message.on("data", (chunk) => {
|
|
41176
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
41177
|
+
});
|
|
41178
|
+
message.once("aborted", () => {
|
|
41179
|
+
rejectResponse(new TypeError("response body was aborted"));
|
|
41180
|
+
});
|
|
41181
|
+
message.once("error", rejectResponse);
|
|
41182
|
+
message.once("end", () => {
|
|
41183
|
+
if (settled) return;
|
|
41184
|
+
settled = true;
|
|
41185
|
+
finish();
|
|
41186
|
+
const status = message.statusCode ?? 0;
|
|
41187
|
+
const bytes = Buffer.concat(chunks);
|
|
41188
|
+
const webHeaders = responseHeaders(message);
|
|
41189
|
+
const responseBody2 = status === 204 || status === 205 || status === 304 ? null : decodeResponseBody(bytes, webHeaders);
|
|
41190
|
+
try {
|
|
41191
|
+
const response = new Response(responseBody2, {
|
|
41192
|
+
status,
|
|
41193
|
+
statusText: message.statusMessage,
|
|
41194
|
+
headers: webHeaders
|
|
41195
|
+
});
|
|
41196
|
+
Object.defineProperties(response, {
|
|
41197
|
+
redirected: { value: options.redirected },
|
|
41198
|
+
url: { value: options.url.href }
|
|
41199
|
+
});
|
|
41200
|
+
resolve3(response);
|
|
41201
|
+
} catch (error) {
|
|
41202
|
+
reject(error);
|
|
41203
|
+
}
|
|
41204
|
+
});
|
|
41205
|
+
});
|
|
41206
|
+
try {
|
|
41207
|
+
if (options.body !== null && options.body.byteLength > 0) {
|
|
41208
|
+
request.write(options.body);
|
|
41209
|
+
}
|
|
41210
|
+
request.end();
|
|
41211
|
+
} catch (error) {
|
|
41212
|
+
request.destroy();
|
|
41213
|
+
finish();
|
|
41214
|
+
reject(error);
|
|
41215
|
+
}
|
|
41216
|
+
});
|
|
41217
|
+
}
|
|
41218
|
+
};
|
|
41219
|
+
|
|
39998
41220
|
// src/resume.ts
|
|
39999
41221
|
var import_node_child_process8 = require("node:child_process");
|
|
40000
41222
|
function execFileText(file, args) {
|
|
40001
|
-
return new Promise((
|
|
41223
|
+
return new Promise((resolve3, reject) => {
|
|
40002
41224
|
(0, import_node_child_process8.execFile)(file, [...args], {
|
|
40003
41225
|
encoding: "utf8",
|
|
40004
41226
|
maxBuffer: 4 * 1024 * 1024
|
|
40005
41227
|
}, (error, stdout) => {
|
|
40006
41228
|
if (error) reject(error);
|
|
40007
|
-
else
|
|
41229
|
+
else resolve3(stdout);
|
|
40008
41230
|
});
|
|
40009
41231
|
});
|
|
40010
41232
|
}
|
|
@@ -40410,8 +41632,8 @@ var ACCEPTED_AGENT_CREDENTIAL_MESSAGES = [
|
|
|
40410
41632
|
AGENT_CREDENTIAL_MESSAGE_D088
|
|
40411
41633
|
];
|
|
40412
41634
|
function packageVersion() {
|
|
40413
|
-
if ("0.1.
|
|
40414
|
-
return "0.1.
|
|
41635
|
+
if ("0.1.47".length > 0) {
|
|
41636
|
+
return "0.1.47";
|
|
40415
41637
|
}
|
|
40416
41638
|
try {
|
|
40417
41639
|
const value = JSON.parse(
|
|
@@ -41035,7 +42257,7 @@ async function runNew(args) {
|
|
|
41035
42257
|
assertWorkspaceName(name);
|
|
41036
42258
|
const cloud = await target(args);
|
|
41037
42259
|
const human = await humanCredential(args, cloud);
|
|
41038
|
-
const proposedId = (0,
|
|
42260
|
+
const proposedId = (0, import_node_crypto22.randomUUID)();
|
|
41039
42261
|
let result;
|
|
41040
42262
|
try {
|
|
41041
42263
|
result = await new ThinCommandClient(cloud).sendConnect({
|
|
@@ -42058,7 +43280,7 @@ function accepted(label, result) {
|
|
|
42058
43280
|
);
|
|
42059
43281
|
}
|
|
42060
43282
|
}
|
|
42061
|
-
async function agentSession(cloud, workspaceId2, agent) {
|
|
43283
|
+
async function agentSession(cloud, workspaceId2, agent, fetcher) {
|
|
42062
43284
|
let store2 = null;
|
|
42063
43285
|
try {
|
|
42064
43286
|
const candidate = await agentCredentialStore({
|
|
@@ -42084,7 +43306,8 @@ async function agentSession(cloud, workspaceId2, agent) {
|
|
|
42084
43306
|
runId: agent.runId,
|
|
42085
43307
|
expiresAt: agent.expiresAt
|
|
42086
43308
|
},
|
|
42087
|
-
store: store2
|
|
43309
|
+
store: store2,
|
|
43310
|
+
...fetcher ? { fetcher } : {}
|
|
42088
43311
|
});
|
|
42089
43312
|
}
|
|
42090
43313
|
async function commandWorkspaceAndCredential(args, cloud, options = {}) {
|
|
@@ -42366,8 +43589,8 @@ function prepareSignalAttachments(localPaths) {
|
|
|
42366
43589
|
name,
|
|
42367
43590
|
bytes,
|
|
42368
43591
|
contentType,
|
|
42369
|
-
fileId: (0,
|
|
42370
|
-
versionId: (0,
|
|
43592
|
+
fileId: (0, import_node_crypto22.randomUUID)(),
|
|
43593
|
+
versionId: (0, import_node_crypto22.randomUUID)(),
|
|
42371
43594
|
createCommandId: newCommandId(),
|
|
42372
43595
|
commitCommandId: newCommandId()
|
|
42373
43596
|
};
|
|
@@ -43052,6 +44275,7 @@ async function runInboxNotifyCommand(args) {
|
|
|
43052
44275
|
);
|
|
43053
44276
|
}
|
|
43054
44277
|
const controller = new AbortController();
|
|
44278
|
+
const httpClient = new ListenerHttpClient();
|
|
43055
44279
|
const stop = () => controller.abort();
|
|
43056
44280
|
process.on("SIGINT", stop);
|
|
43057
44281
|
process.on("SIGTERM", stop);
|
|
@@ -43082,7 +44306,7 @@ async function runInboxNotifyCommand(args) {
|
|
|
43082
44306
|
...after === null ? {} : { after }
|
|
43083
44307
|
}
|
|
43084
44308
|
},
|
|
43085
|
-
{ signal: controller.signal }
|
|
44309
|
+
{ signal: controller.signal, fetcher: httpClient.fetch }
|
|
43086
44310
|
);
|
|
43087
44311
|
},
|
|
43088
44312
|
emit: async (signal) => {
|
|
@@ -43116,6 +44340,7 @@ async function runInboxNotifyCommand(args) {
|
|
|
43116
44340
|
} finally {
|
|
43117
44341
|
process.off("SIGINT", stop);
|
|
43118
44342
|
process.off("SIGTERM", stop);
|
|
44343
|
+
httpClient.close();
|
|
43119
44344
|
}
|
|
43120
44345
|
}
|
|
43121
44346
|
async function runReceipt(args) {
|
|
@@ -43188,6 +44413,7 @@ async function runInboxFollowCommand(args) {
|
|
|
43188
44413
|
includeStale: args.has("include-stale")
|
|
43189
44414
|
};
|
|
43190
44415
|
const controller = new AbortController();
|
|
44416
|
+
const httpClient = new ListenerHttpClient();
|
|
43191
44417
|
let legacyCursorWarned = false;
|
|
43192
44418
|
let malformedRowWarnings = 0;
|
|
43193
44419
|
const onAbortSignal = () => controller.abort();
|
|
@@ -43219,7 +44445,7 @@ async function runInboxFollowCommand(args) {
|
|
|
43219
44445
|
cloud,
|
|
43220
44446
|
credential,
|
|
43221
44447
|
query,
|
|
43222
|
-
{ signal: controller.signal },
|
|
44448
|
+
{ signal: controller.signal, fetcher: httpClient.fetch },
|
|
43223
44449
|
{
|
|
43224
44450
|
allowLegacyCursorFallback: true,
|
|
43225
44451
|
tolerateMalformedRows: true,
|
|
@@ -43251,7 +44477,7 @@ async function runInboxFollowCommand(args) {
|
|
|
43251
44477
|
cloud,
|
|
43252
44478
|
credential,
|
|
43253
44479
|
query,
|
|
43254
|
-
{ signal: controller.signal }
|
|
44480
|
+
{ signal: controller.signal, fetcher: httpClient.fetch }
|
|
43255
44481
|
);
|
|
43256
44482
|
},
|
|
43257
44483
|
emit: (frame) => {
|
|
@@ -43269,6 +44495,7 @@ async function runInboxFollowCommand(args) {
|
|
|
43269
44495
|
} finally {
|
|
43270
44496
|
process.off("SIGINT", onAbortSignal);
|
|
43271
44497
|
process.off("SIGTERM", onAbortSignal);
|
|
44498
|
+
httpClient.close();
|
|
43272
44499
|
}
|
|
43273
44500
|
}
|
|
43274
44501
|
function listenerUuid(value, flag) {
|
|
@@ -43453,16 +44680,107 @@ function listenerAttendanceState(status, evidence) {
|
|
|
43453
44680
|
function listenerAttendanceRemedy(principalId) {
|
|
43454
44681
|
return `cswarm hook install claude --principal-id ${principalId} --write, then start a fresh session. Or restart the listener with --route worker.`;
|
|
43455
44682
|
}
|
|
44683
|
+
function listenerReadHealthSummary(status, nowMs) {
|
|
44684
|
+
return summarizeListenerReadHealth(
|
|
44685
|
+
status.readHealth ?? emptyListenerReadHealth(),
|
|
44686
|
+
status.readyAt,
|
|
44687
|
+
nowMs
|
|
44688
|
+
);
|
|
44689
|
+
}
|
|
44690
|
+
function listenerLapseNotices(status, summary) {
|
|
44691
|
+
const health = status.readHealth ?? emptyListenerReadHealth();
|
|
44692
|
+
const notices = [];
|
|
44693
|
+
if (health.currentReasonCode === "host_ports_exhausted") {
|
|
44694
|
+
notices.push({
|
|
44695
|
+
code: "listener_host_ports_exhausted",
|
|
44696
|
+
message: "This host has run out of outbound ports. The listener is probing only once per minute so it does not amplify the outage.",
|
|
44697
|
+
nextStep: "Find the consumer: lsof -nP -iTCP | awk '{print $1}' | sort | uniq -c | sort -rn"
|
|
44698
|
+
});
|
|
44699
|
+
} else if (
|
|
44700
|
+
// Reuse arrival-watch.ts's 60s loud-lapse transition. The listener keeps
|
|
44701
|
+
// the episode in durable status instead of the monitor's process-local machine.
|
|
44702
|
+
summary.currentEpisodeDurationMs !== null && summary.currentEpisodeDurationMs >= ARRIVAL_RETRY_NOTICE_THRESHOLD_MS
|
|
44703
|
+
) {
|
|
44704
|
+
notices.push({
|
|
44705
|
+
code: "listener_read_retry_persisting",
|
|
44706
|
+
message: `Listener reads have failed continuously for ${Math.floor(summary.currentEpisodeDurationMs / 1e3)}s. This is still in progress.`,
|
|
44707
|
+
nextStep: "Check cswarm status and the CommonSwarm service. If both are healthy, restart the listener."
|
|
44708
|
+
});
|
|
44709
|
+
}
|
|
44710
|
+
if (summary.throughputLapseHours.length > 0) {
|
|
44711
|
+
const latest = summary.throughputLapseHours.at(-1);
|
|
44712
|
+
notices.push({
|
|
44713
|
+
code: "listener_claim_throughput_lapse",
|
|
44714
|
+
message: `Claim throughput fell below 0.50 for the full hour at ${latest.hourStart}: ${latest.claims}/${Math.round(latest.expectedClaims)} expected (${latest.ratio.toFixed(3)}).`,
|
|
44715
|
+
nextStep: "This host is starving the listener \u2014 check load/memory pressure (sysctl kern.memorystatus_vm_pressure_level), or move the listener."
|
|
44716
|
+
});
|
|
44717
|
+
}
|
|
44718
|
+
return notices;
|
|
44719
|
+
}
|
|
44720
|
+
async function listenerProviderInstallEvidence(status) {
|
|
44721
|
+
if (status.provider !== "claude") return null;
|
|
44722
|
+
try {
|
|
44723
|
+
const notice = await inspectClaudeBridgeExecutable(
|
|
44724
|
+
status.providerExecutable ?? "claude-agent-acp",
|
|
44725
|
+
{ pathEnv: process.env.PATH, env: process.env }
|
|
44726
|
+
);
|
|
44727
|
+
return {
|
|
44728
|
+
executable: notice.executable,
|
|
44729
|
+
providerVersion: notice.providerVersion,
|
|
44730
|
+
bundledAgentSdkVersion: notice.bundledAgentSdkVersion,
|
|
44731
|
+
bundledClaudeCodeVersion: notice.bundledClaudeCodeVersion
|
|
44732
|
+
};
|
|
44733
|
+
} catch {
|
|
44734
|
+
return {
|
|
44735
|
+
executable: null,
|
|
44736
|
+
providerVersion: null,
|
|
44737
|
+
bundledAgentSdkVersion: null,
|
|
44738
|
+
bundledClaudeCodeVersion: null
|
|
44739
|
+
};
|
|
44740
|
+
}
|
|
44741
|
+
}
|
|
44742
|
+
function versionIsBelow(left, right) {
|
|
44743
|
+
if (!left || !right) return false;
|
|
44744
|
+
try {
|
|
44745
|
+
return compareSemVer(left, right) < 0;
|
|
44746
|
+
} catch {
|
|
44747
|
+
return false;
|
|
44748
|
+
}
|
|
44749
|
+
}
|
|
44750
|
+
function providerRestartRequired(status, installed) {
|
|
44751
|
+
if (!installed) return false;
|
|
44752
|
+
return status.providerVersion !== null && status.providerVersion !== void 0 && installed.providerVersion !== null && status.providerVersion !== installed.providerVersion || status.providerBundledClaudeCodeVersion !== null && status.providerBundledClaudeCodeVersion !== void 0 && installed.bundledClaudeCodeVersion !== null && status.providerBundledClaudeCodeVersion !== installed.bundledClaudeCodeVersion;
|
|
44753
|
+
}
|
|
43456
44754
|
function listenerStatusJson(status, permissionMode, evidence = {
|
|
43457
44755
|
pendingForMainOldestAt: null,
|
|
43458
44756
|
hookSurfaceExists: false,
|
|
43459
44757
|
hookSurfaceAdvanced: false
|
|
43460
|
-
}, nowMs = Date.now()) {
|
|
44758
|
+
}, nowMs = Date.now(), installed = null) {
|
|
43461
44759
|
const mode3 = permissionMode ?? status.permissionMode;
|
|
43462
44760
|
const attendance = listenerAttendanceState(status, evidence);
|
|
43463
44761
|
const pending = status.pendingForMainCount ?? 0;
|
|
44762
|
+
const readHealth = status.readHealth ?? emptyListenerReadHealth();
|
|
44763
|
+
const readSummary = listenerReadHealthSummary(status, nowMs);
|
|
44764
|
+
const lapseNotices = listenerLapseNotices(status, readSummary);
|
|
43464
44765
|
return {
|
|
43465
44766
|
...status,
|
|
44767
|
+
providerExecutable: status.providerExecutable ?? null,
|
|
44768
|
+
providerExecutableMeasured: typeof status.providerExecutable === "string",
|
|
44769
|
+
providerVersion: status.providerVersion ?? null,
|
|
44770
|
+
providerVersionMeasured: typeof status.providerVersion === "string",
|
|
44771
|
+
providerBundledAgentSdkVersion: status.providerBundledAgentSdkVersion ?? null,
|
|
44772
|
+
providerBundledClaudeCodeVersion: status.providerBundledClaudeCodeVersion ?? null,
|
|
44773
|
+
providerMinimumRequiredVersion: status.providerMinimumRequiredVersion ?? null,
|
|
44774
|
+
lastErrorReasonCode: status.lastErrorReasonCode ?? null,
|
|
44775
|
+
providerBelowDemandedMinimum: versionIsBelow(
|
|
44776
|
+
status.providerBundledClaudeCodeVersion,
|
|
44777
|
+
status.providerMinimumRequiredVersion
|
|
44778
|
+
),
|
|
44779
|
+
providerOnDiskExecutable: installed?.executable ?? null,
|
|
44780
|
+
providerOnDiskVersion: installed?.providerVersion ?? null,
|
|
44781
|
+
providerOnDiskBundledAgentSdkVersion: installed?.bundledAgentSdkVersion ?? null,
|
|
44782
|
+
providerOnDiskBundledClaudeCodeVersion: installed?.bundledClaudeCodeVersion ?? null,
|
|
44783
|
+
providerRestartRequired: providerRestartRequired(status, installed),
|
|
43466
44784
|
...attendance,
|
|
43467
44785
|
hookSurfaceExists: evidence.hookSurfaceExists,
|
|
43468
44786
|
hookSurfaceAdvanced: evidence.hookSurfaceAdvanced,
|
|
@@ -43470,6 +44788,22 @@ function listenerStatusJson(status, permissionMode, evidence = {
|
|
|
43470
44788
|
pendingForMainOldestAgeMs: evidence.pendingForMainOldestAt === null ? null : Math.max(0, nowMs - Date.parse(evidence.pendingForMainOldestAt)),
|
|
43471
44789
|
attendanceWarningCode: pending > 0 ? "listener_unattended_main_queue" : null,
|
|
43472
44790
|
attendanceNextStep: pending > 0 ? listenerAttendanceRemedy(status.principalId) : null,
|
|
44791
|
+
readRetryCurrentEpisodeStartedAt: readHealth.currentEpisodeStartedAt,
|
|
44792
|
+
readRetryCurrentEpisodeAttempts: readHealth.currentEpisodeAttempts,
|
|
44793
|
+
readRetryCurrentReasonCode: readHealth.currentReasonCode,
|
|
44794
|
+
readRetryCurrentHttpStatus: readHealth.currentHttpStatus,
|
|
44795
|
+
readRetryCurrentErrorConstructor: readHealth.currentErrorConstructor,
|
|
44796
|
+
readRetryCurrentEpisodeDurationMs: readSummary.currentEpisodeDurationMs,
|
|
44797
|
+
readRetryEpisodesLast24h: readSummary.episodesLast24h,
|
|
44798
|
+
readRetryLongestEpisodeAttemptsLast24h: readSummary.longestEpisodeAttemptsLast24h,
|
|
44799
|
+
readRetryLongestEpisodeDurationMsLast24h: readSummary.longestEpisodeDurationMsLast24h,
|
|
44800
|
+
readRetriesLastHour: readSummary.retriesLastHour,
|
|
44801
|
+
readRetryHours: readSummary.retryHours,
|
|
44802
|
+
claimCadenceMs: readHealth.claimCadenceMs,
|
|
44803
|
+
claimThroughputHours: readSummary.claimThroughputHours,
|
|
44804
|
+
listenerLapse: lapseNotices.length > 0,
|
|
44805
|
+
listenerLapseCodes: lapseNotices.map((notice) => notice.code),
|
|
44806
|
+
listenerLapseNextSteps: lapseNotices.map((notice) => notice.nextStep),
|
|
43473
44807
|
deliveryMode: status.deliveryMode ?? null,
|
|
43474
44808
|
pendingDeliveryCount: status.pendingDeliveryCount ?? null,
|
|
43475
44809
|
lastTerminalDeliveryFailureCount: status.lastTerminalDeliveryFailureCount ?? null,
|
|
@@ -43480,6 +44814,10 @@ function listenerStatusJson(status, permissionMode, evidence = {
|
|
|
43480
44814
|
deferOverChars: status.deferOverChars ?? null,
|
|
43481
44815
|
pendingForMainCount: status.pendingForMainCount ?? 0,
|
|
43482
44816
|
droppedForMainCount: status.droppedForMainCount ?? 0,
|
|
44817
|
+
connectionsOpened: status.connectionsOpened ?? null,
|
|
44818
|
+
connectionReuseRatio: status.connectionReuseRatio ?? null,
|
|
44819
|
+
activityPublishFailures: status.activityPublishFailures ?? null,
|
|
44820
|
+
activityLastErrorCode: status.activityLastErrorCode ?? null,
|
|
43483
44821
|
...mode3 ? {
|
|
43484
44822
|
permission_mode: mode3,
|
|
43485
44823
|
/* "allowed once" alone overstates it: allowOnceOrDeny selects allow_once only when the
|
|
@@ -43495,27 +44833,58 @@ function renderListenerStatus(status, evidence = {
|
|
|
43495
44833
|
pendingForMainOldestAt: null,
|
|
43496
44834
|
hookSurfaceExists: false,
|
|
43497
44835
|
hookSurfaceAdvanced: false
|
|
43498
|
-
}, nowMs = Date.now()) {
|
|
44836
|
+
}, nowMs = Date.now(), installed = null) {
|
|
43499
44837
|
const routeMode = status.routeMode ?? "worker";
|
|
43500
44838
|
const pendingForMainCount = status.pendingForMainCount ?? 0;
|
|
43501
44839
|
const droppedForMainCount = status.droppedForMainCount ?? 0;
|
|
43502
44840
|
const unattendedCount = `${pendingForMainCount} ${pendingForMainCount === 1 ? "message is" : "messages are"} unattended`;
|
|
43503
44841
|
const attendance = listenerAttendanceState(status, evidence);
|
|
44842
|
+
const readHealth = status.readHealth ?? emptyListenerReadHealth();
|
|
44843
|
+
const readSummary = listenerReadHealthSummary(status, nowMs);
|
|
44844
|
+
const lapseNotices = listenerLapseNotices(status, readSummary);
|
|
43504
44845
|
const lines = [
|
|
43505
|
-
pendingForMainCount > 0 ? `Listener WARNING for agent ${status.principalId}: ${unattendedCount}.` : `Listener ${status.state} for agent ${status.principalId}.`,
|
|
44846
|
+
lapseNotices.length > 0 ? `Listener LAPSE for agent ${status.principalId}: ${lapseNotices.map((notice) => notice.code).join(", ")}.` : pendingForMainCount > 0 ? `Listener WARNING for agent ${status.principalId}: ${unattendedCount}.` : `Listener ${status.state} for agent ${status.principalId}.`,
|
|
43506
44847
|
`CONNECTED: ${attendance.connected ? "yes" : "no"}. Transport state is ${status.state}.`,
|
|
43507
44848
|
`ATTENDED: ${attendance.attendanceState === "attended" ? "yes. The session hook has surfaced messages on this host" : attendance.attendanceState === "unattended" ? "no. The main-session queue is not draining" : attendance.attendanceState === "not_required" ? "not required for the worker route" : "not yet proven on this host"}.`,
|
|
43508
44849
|
`HANDLED: ${attendance.handledState === "handled" ? "yes. A delivery acknowledgement is recorded" : attendance.handledState === "not_handled" ? "no. Queued messages have not reached the session hook" : "not yet measured"}.`,
|
|
43509
44850
|
`Provider: ${status.provider}; process: ${status.pid}; started: ${status.startedAt}.`,
|
|
44851
|
+
`Provider executable: ${status.providerExecutable ?? "not measured"}.`,
|
|
44852
|
+
`Connections opened: ${status.connectionsOpened ?? "not measured"}.`,
|
|
44853
|
+
`Connection reuse ratio: ${status.connectionReuseRatio ?? "not measured"}.`,
|
|
44854
|
+
...status.activityPublishFailures !== void 0 && status.activityPublishFailures > 0 ? [`Activity publish failures: ${status.activityPublishFailures}.`] : [],
|
|
44855
|
+
...status.activityLastErrorCode ? [`Last activity publish error code: ${status.activityLastErrorCode}.`] : [],
|
|
43510
44856
|
status.readyAt ? `Ready since: ${status.readyAt}.` : "Not ready yet.",
|
|
43511
44857
|
status.lastSignalId ? pendingForMainCount > 0 ? `Last claimed and queued signal: ${status.lastSignalId}. It is not handled yet.` : routeMode === "worker" ? `Last handled signal: ${status.lastSignalId}.` : `Last listener signal: ${status.lastSignalId}. Local status does not prove its final observed receipt.` : "No signal has been handled yet.",
|
|
43512
|
-
status.lastErrorCode ? `Last status code: ${status.lastErrorCode}.` : "No listener process error is recorded."
|
|
44858
|
+
status.lastErrorCode ? `Last status code: ${status.lastErrorCode}.` : "No listener process error is recorded.",
|
|
44859
|
+
readHealth.currentEpisodeStartedAt === null ? "Current read retry episode: none." : `Current read retry episode: ${readHealth.currentEpisodeAttempts} attempt${readHealth.currentEpisodeAttempts === 1 ? "" : "s"} since ${readHealth.currentEpisodeStartedAt}; reason ${readHealth.currentReasonCode}${readHealth.currentHttpStatus === null ? "" : ` (HTTP ${readHealth.currentHttpStatus})`}${readHealth.currentErrorConstructor === null ? "" : ` (${readHealth.currentErrorConstructor})`}.`,
|
|
44860
|
+
`Read retry episodes in the last 24h: ${readSummary.episodesLast24h}; retries in the rolling hour: ${readSummary.retriesLastHour}.`,
|
|
44861
|
+
readSummary.longestEpisodeAttemptsLast24h === 0 ? "Longest read retry episode in the last 24h: none recorded." : `Longest read retry episode in the last 24h: ${readSummary.longestEpisodeAttemptsLast24h} attempts over ${Math.floor(readSummary.longestEpisodeDurationMsLast24h / 1e3)}s.`,
|
|
44862
|
+
readSummary.retryHours.length === 0 ? "Read retries by hour in the last 24h: none." : `Read retries by hour in the last 24h: ${readSummary.retryHours.map((hour) => `${hour.hourStart}=${hour.retries}`).join("; ")}.`,
|
|
44863
|
+
readSummary.claimThroughputHours.length === 0 ? "Claim throughput by full hour: no complete listener hour is available yet." : `Claim throughput by full hour: ${readSummary.claimThroughputHours.map((hour) => `${hour.hourStart} ${hour.claims}/${Math.round(hour.expectedClaims)} (${hour.ratio.toFixed(3)})`).join("; ")}.`
|
|
43513
44864
|
];
|
|
44865
|
+
for (const notice of lapseNotices) {
|
|
44866
|
+
lines.push(`WARNING [${notice.code}]: ${notice.message}`);
|
|
44867
|
+
lines.push(`Next: ${notice.nextStep}`);
|
|
44868
|
+
}
|
|
43514
44869
|
if (status.lastErrorDetail) {
|
|
43515
44870
|
const [first, ...rest] = status.lastErrorDetail.split("\n");
|
|
43516
44871
|
lines.push(`Last error detail (local only): ${first}`);
|
|
43517
44872
|
for (const line of rest) lines.push(` ${line}`);
|
|
43518
44873
|
}
|
|
44874
|
+
if (status.lastErrorReasonCode) {
|
|
44875
|
+
lines.push(`Last provider reason code: ${status.lastErrorReasonCode}.`);
|
|
44876
|
+
}
|
|
44877
|
+
if (status.provider === "claude" && status.lastErrorCode === "permission_canary_failed") {
|
|
44878
|
+
lines.push(
|
|
44879
|
+
`Canary diagnosis: ${listenerFailureMessage(
|
|
44880
|
+
status.lastErrorCode,
|
|
44881
|
+
status.provider,
|
|
44882
|
+
status.lastErrorDetail,
|
|
44883
|
+
status.lastErrorReasonCode,
|
|
44884
|
+
status.providerMinimumRequiredVersion
|
|
44885
|
+
)}.`
|
|
44886
|
+
);
|
|
44887
|
+
}
|
|
43519
44888
|
if (status.lastWorkerStderrTail) {
|
|
43520
44889
|
const tailLines = status.lastWorkerStderrTail.split("\n").filter((line) => line.trim().length > 0);
|
|
43521
44890
|
lines.push("Worker stderr (local log only):");
|
|
@@ -43525,8 +44894,34 @@ function renderListenerStatus(status, evidence = {
|
|
|
43525
44894
|
}
|
|
43526
44895
|
if (status.providerVersion && status.providerLastMeasuredVersion) {
|
|
43527
44896
|
lines.push(
|
|
43528
|
-
status.providerVersion === status.providerLastMeasuredVersion ? `Provider version: ${status.providerVersion} (last measured: ${status.providerLastMeasuredVersion}).` : `Provider version ${status.providerVersion} is newer than the last measured version ${status.providerLastMeasuredVersion}. It is unverified but allowed because the startup permission canary passed. Next: verify this provider release with CommonSwarm and update the last-measured version.`
|
|
44897
|
+
status.providerVersion === status.providerLastMeasuredVersion ? `Provider version: ${status.providerVersion} (last measured: ${status.providerLastMeasuredVersion}).` : status.state === "ready" ? `Provider version ${status.providerVersion} is newer than the last measured version ${status.providerLastMeasuredVersion}. It is unverified but allowed because the startup permission canary passed. Next: verify this provider release with CommonSwarm and update the last-measured version.` : `Provider version ${status.providerVersion} is newer than the last measured version ${status.providerLastMeasuredVersion}. It was measured before startup failed; compatibility was not established. Next: resolve the startup failure before verifying this provider release.`
|
|
44898
|
+
);
|
|
44899
|
+
} else {
|
|
44900
|
+
lines.push("Provider version: not measured.");
|
|
44901
|
+
}
|
|
44902
|
+
if (status.provider === "claude") {
|
|
44903
|
+
lines.push(
|
|
44904
|
+
`Bundled Claude Code version: ${status.providerBundledClaudeCodeVersion ?? "not measured"}.`,
|
|
44905
|
+
`Bundled Claude agent SDK version: ${status.providerBundledAgentSdkVersion ?? "not measured"}.`
|
|
43529
44906
|
);
|
|
44907
|
+
if (status.providerMinimumRequiredVersion) {
|
|
44908
|
+
lines.push(
|
|
44909
|
+
`Last API minimum demanded: Claude Code ${status.providerMinimumRequiredVersion}.`
|
|
44910
|
+
);
|
|
44911
|
+
}
|
|
44912
|
+
if (versionIsBelow(
|
|
44913
|
+
status.providerBundledClaudeCodeVersion,
|
|
44914
|
+
status.providerMinimumRequiredVersion
|
|
44915
|
+
)) {
|
|
44916
|
+
lines.push(
|
|
44917
|
+
`WARNING [claude_bridge_below_api_minimum]: this listener has bundled Claude Code ${status.providerBundledClaudeCodeVersion}, below the API minimum ${status.providerMinimumRequiredVersion}. Install the current bridge (npm i -g @agentclientprotocol/claude-agent-acp@latest), restart the listener, then run cswarm listen status and confirm that the bundled Claude Code version meets the API minimum ${status.providerMinimumRequiredVersion}.`
|
|
44918
|
+
);
|
|
44919
|
+
}
|
|
44920
|
+
if (providerRestartRequired(status, installed)) {
|
|
44921
|
+
lines.push(
|
|
44922
|
+
`A different Claude bridge is on disk: ${installed?.providerVersion ?? "version not measured"}${installed?.bundledClaudeCodeVersion ? ` (bundled Claude Code ${installed.bundledClaudeCodeVersion})` : ""}. Restart to pick up ${installed?.providerVersion ?? "the on-disk bridge"}.`
|
|
44923
|
+
);
|
|
44924
|
+
}
|
|
43530
44925
|
}
|
|
43531
44926
|
if (status.deliveryMode === "durable_claim") {
|
|
43532
44927
|
lines.push("Delivery mode: durable claim and acknowledgement.");
|
|
@@ -43603,7 +44998,26 @@ async function unsurfacedPendingMainStats(instanceDirectory, fallback) {
|
|
|
43603
44998
|
};
|
|
43604
44999
|
}
|
|
43605
45000
|
}
|
|
43606
|
-
function
|
|
45001
|
+
function quotedListenerFailureDetail(detail) {
|
|
45002
|
+
const recorded = detail?.trim();
|
|
45003
|
+
if (!recorded) return "not recorded";
|
|
45004
|
+
const bounded = recorded.length > 600 ? `${recorded.slice(0, 599)}\u2026` : recorded;
|
|
45005
|
+
return JSON.stringify(bounded);
|
|
45006
|
+
}
|
|
45007
|
+
function listenerProviderIdentitySummary(status) {
|
|
45008
|
+
const parts = [
|
|
45009
|
+
`Provider executable: ${status.providerExecutable ?? "not measured"}`,
|
|
45010
|
+
`provider version: ${status.providerVersion ?? "not measured"}`
|
|
45011
|
+
];
|
|
45012
|
+
if (status.provider === "claude") {
|
|
45013
|
+
parts.push(
|
|
45014
|
+
`bundled Claude Code: ${status.providerBundledClaudeCodeVersion ?? "not measured"}`,
|
|
45015
|
+
`bundled Claude agent SDK: ${status.providerBundledAgentSdkVersion ?? "not measured"}`
|
|
45016
|
+
);
|
|
45017
|
+
}
|
|
45018
|
+
return parts.join("; ");
|
|
45019
|
+
}
|
|
45020
|
+
function listenerFailureMessage(code, provider, detail, reasonCode, minimumRequiredVersion) {
|
|
43607
45021
|
if (code === "version_below_floor") {
|
|
43608
45022
|
if (provider === "codex") {
|
|
43609
45023
|
return "the Codex listener requires codex-acp 1.1.9 or newer; update the bridge, then retry";
|
|
@@ -43663,11 +45077,25 @@ function listenerFailureMessage(code, provider, detail) {
|
|
|
43663
45077
|
}
|
|
43664
45078
|
if (code === "permission_canary_failed") {
|
|
43665
45079
|
if (provider === "claude") {
|
|
43666
|
-
|
|
45080
|
+
const shape = classifyClaudeCanaryFailure(detail, reasonCode);
|
|
45081
|
+
const ran = "the Claude ACP permission canary ran, but no workspace signal prompt was delivered";
|
|
45082
|
+
const response = `bridge response [${shape.code}]: ${quotedListenerFailureDetail(detail)}`;
|
|
45083
|
+
if (shape.code === "claude_bridge_version_required") {
|
|
45084
|
+
const minimum = minimumRequiredVersion ?? shape.minimumRequiredVersion;
|
|
45085
|
+
return `${ran}. ${response}. Next: install the current bridge (npm i -g @agentclientprotocol/claude-agent-acp@latest), restart the listener, then run cswarm listen status and confirm that the bundled Claude Code version meets the API minimum ${minimum ?? "reported there"}`;
|
|
45086
|
+
}
|
|
45087
|
+
if (shape.code === "claude_canary_timeout") {
|
|
45088
|
+
return `${ran}. ${response}. Next: run claude -p and check for session-limit text, check host load, then retry`;
|
|
45089
|
+
}
|
|
45090
|
+
if (shape.code === "claude_canary_auth_failed") {
|
|
45091
|
+
return `${ran}. ${response}. Next: confirm Claude Code keychain/OAuth sign-in, then retry`;
|
|
45092
|
+
}
|
|
45093
|
+
return `${ran}. ${response}. The cause was not determined. Next: inspect the quoted bridge response and local worker stderr, then retry only after the cause is known or the failure appears transient`;
|
|
43667
45094
|
}
|
|
43668
45095
|
if (provider === "codex") {
|
|
43669
45096
|
const recorded = detail?.trim();
|
|
43670
|
-
|
|
45097
|
+
const gate = "the Codex listener did not pass the read-only ACP permission safety gate; no workspace signal prompt was delivered";
|
|
45098
|
+
return recorded ? `${gate}. Recorded reason: ${JSON.stringify(recorded)}` : `${gate}. The recorded reason was unavailable. Next: run cswarm listen status, then retry`;
|
|
43671
45099
|
}
|
|
43672
45100
|
if (provider === "grok") {
|
|
43673
45101
|
return "the Grok bridge did not complete the ACP permission canary; no workspace signal prompt was delivered. The local cswarm listen status output includes the final error detail; read it, then retry";
|
|
@@ -43750,11 +45178,19 @@ async function runConfiguredListener(options) {
|
|
|
43750
45178
|
principalId: options.principalId,
|
|
43751
45179
|
...options.stateDirectory ? { stateDirectory: options.stateDirectory } : {}
|
|
43752
45180
|
});
|
|
43753
|
-
const
|
|
43754
|
-
|
|
43755
|
-
|
|
43756
|
-
|
|
43757
|
-
|
|
45181
|
+
const httpClient = new ListenerHttpClient();
|
|
45182
|
+
let liveCredentialSession;
|
|
45183
|
+
try {
|
|
45184
|
+
liveCredentialSession = await agentSession(
|
|
45185
|
+
options.cloud,
|
|
45186
|
+
options.workspaceId,
|
|
45187
|
+
options.agent,
|
|
45188
|
+
httpClient.fetch
|
|
45189
|
+
);
|
|
45190
|
+
} catch (error) {
|
|
45191
|
+
httpClient.close();
|
|
45192
|
+
throw error;
|
|
45193
|
+
}
|
|
43758
45194
|
let storedCredential = null;
|
|
43759
45195
|
const credentialSession = {
|
|
43760
45196
|
bearer: async () => {
|
|
@@ -43782,7 +45218,7 @@ async function runConfiguredListener(options) {
|
|
|
43782
45218
|
options.cloud,
|
|
43783
45219
|
credential,
|
|
43784
45220
|
options.workspaceId,
|
|
43785
|
-
context
|
|
45221
|
+
{ ...context, fetcher: httpClient.fetch }
|
|
43786
45222
|
);
|
|
43787
45223
|
const provenance = listenerSenderProvenance(signal, senderDirectory);
|
|
43788
45224
|
if (context.includeBrainDigest !== true) return provenance;
|
|
@@ -43793,7 +45229,8 @@ async function runConfiguredListener(options) {
|
|
|
43793
45229
|
options.workspaceId,
|
|
43794
45230
|
{
|
|
43795
45231
|
...context.signal ? { signal: context.signal } : {},
|
|
43796
|
-
deadlineMs: context.deadlineMs
|
|
45232
|
+
deadlineMs: context.deadlineMs,
|
|
45233
|
+
fetcher: httpClient.fetch
|
|
43797
45234
|
}
|
|
43798
45235
|
);
|
|
43799
45236
|
const brainDigest = await new FileBrainDigestStore(
|
|
@@ -43833,7 +45270,20 @@ async function runConfiguredListener(options) {
|
|
|
43833
45270
|
let workerStderrGeneration = 0;
|
|
43834
45271
|
let providerVersionNotice = null;
|
|
43835
45272
|
const onVersionNotice = (notice) => {
|
|
43836
|
-
providerVersionNotice =
|
|
45273
|
+
providerVersionNotice = {
|
|
45274
|
+
...providerVersionNotice ?? {},
|
|
45275
|
+
runningVersion: notice.runningVersion,
|
|
45276
|
+
lastMeasuredVersion: notice.lastMeasuredVersion
|
|
45277
|
+
};
|
|
45278
|
+
};
|
|
45279
|
+
const onClaudeRuntimeNotice = (notice) => {
|
|
45280
|
+
providerVersionNotice = {
|
|
45281
|
+
runningVersion: notice.providerVersion,
|
|
45282
|
+
lastMeasuredVersion: notice.lastMeasuredVersion,
|
|
45283
|
+
executable: notice.executable,
|
|
45284
|
+
bundledAgentSdkVersion: notice.bundledAgentSdkVersion,
|
|
45285
|
+
bundledClaudeCodeVersion: notice.bundledClaudeCodeVersion
|
|
45286
|
+
};
|
|
43837
45287
|
};
|
|
43838
45288
|
const newWorkerStderrTailSink = () => {
|
|
43839
45289
|
const generation = ++workerStderrGeneration;
|
|
@@ -43843,7 +45293,7 @@ async function runConfiguredListener(options) {
|
|
|
43843
45293
|
lastWorkerStderrTail = tail.length > 0 ? tail : null;
|
|
43844
45294
|
};
|
|
43845
45295
|
};
|
|
43846
|
-
const newModel = (onCanaryAttempt) => {
|
|
45296
|
+
const newModel = (onCanaryAttempt, events) => {
|
|
43847
45297
|
providerVersionNotice = null;
|
|
43848
45298
|
return options.provider === "opencode" ? new OpenCodeListenerModel({
|
|
43849
45299
|
cwd: options.cwd,
|
|
@@ -43852,6 +45302,7 @@ async function runConfiguredListener(options) {
|
|
|
43852
45302
|
onWorkerStderrTail: newWorkerStderrTailSink(),
|
|
43853
45303
|
onCanaryAttempt,
|
|
43854
45304
|
onVersionNotice,
|
|
45305
|
+
events,
|
|
43855
45306
|
...options.model ? { model: options.model } : {},
|
|
43856
45307
|
...options.opencodeExecutable ? { executable: options.opencodeExecutable } : options.executable ? { executable: options.executable } : {}
|
|
43857
45308
|
}) : options.provider === "claude" ? new ClaudeListenerModel({
|
|
@@ -43860,7 +45311,9 @@ async function runConfiguredListener(options) {
|
|
|
43860
45311
|
promptTimeoutMs: resolveTurnBudgetMs,
|
|
43861
45312
|
onWorkerStderrTail: newWorkerStderrTailSink(),
|
|
43862
45313
|
onCanaryAttempt,
|
|
45314
|
+
onRuntimeNotice: onClaudeRuntimeNotice,
|
|
43863
45315
|
onVersionNotice,
|
|
45316
|
+
events,
|
|
43864
45317
|
...options.claudeExecutable ? { executable: options.claudeExecutable } : options.executable ? { executable: options.executable } : {}
|
|
43865
45318
|
}) : options.provider === "codex" ? new CodexListenerModel({
|
|
43866
45319
|
cwd: options.cwd,
|
|
@@ -43869,6 +45322,7 @@ async function runConfiguredListener(options) {
|
|
|
43869
45322
|
onWorkerStderrTail: newWorkerStderrTailSink(),
|
|
43870
45323
|
onCanaryAttempt,
|
|
43871
45324
|
onVersionNotice,
|
|
45325
|
+
events,
|
|
43872
45326
|
...options.codexExecutable ? { executable: options.codexExecutable } : options.executable ? { executable: options.executable } : {}
|
|
43873
45327
|
}) : new GrokListenerModel({
|
|
43874
45328
|
cwd: options.cwd,
|
|
@@ -43877,6 +45331,7 @@ async function runConfiguredListener(options) {
|
|
|
43877
45331
|
onWorkerStderrTail: newWorkerStderrTailSink(),
|
|
43878
45332
|
onCanaryAttempt,
|
|
43879
45333
|
onVersionNotice,
|
|
45334
|
+
events,
|
|
43880
45335
|
...options.model ? { model: options.model } : {},
|
|
43881
45336
|
...options.effort ? { effort: options.effort } : {},
|
|
43882
45337
|
...options.executable ? { executable: options.executable } : {}
|
|
@@ -43907,6 +45362,7 @@ async function runConfiguredListener(options) {
|
|
|
43907
45362
|
// one has run, else the configured cap.
|
|
43908
45363
|
getTurnBudgetMs: () => lastAppliedTurnBudgetMs ?? turnBudgetMs,
|
|
43909
45364
|
getProviderVersionNotice: () => providerVersionNotice,
|
|
45365
|
+
getConnectionMetrics: () => httpClient.metrics(),
|
|
43910
45366
|
takeWorkerStderrTail: () => {
|
|
43911
45367
|
const tail = lastWorkerStderrTail;
|
|
43912
45368
|
lastWorkerStderrTail = null;
|
|
@@ -43940,28 +45396,53 @@ async function runConfiguredListener(options) {
|
|
|
43940
45396
|
ts: (/* @__PURE__ */ new Date()).toISOString()
|
|
43941
45397
|
});
|
|
43942
45398
|
};
|
|
43943
|
-
|
|
43944
|
-
target: options.cloud,
|
|
45399
|
+
const activity = new ListenerActivityController({
|
|
43945
45400
|
workspaceId: options.workspaceId,
|
|
43946
|
-
|
|
43947
|
-
|
|
43948
|
-
|
|
43949
|
-
|
|
43950
|
-
|
|
43951
|
-
onEvent
|
|
43952
|
-
|
|
43953
|
-
|
|
43954
|
-
|
|
43955
|
-
|
|
43956
|
-
routeMode,
|
|
43957
|
-
deferOverChars,
|
|
43958
|
-
pendingMainQueue
|
|
45401
|
+
transport: new AgentActivityEndpointTransport(
|
|
45402
|
+
options.cloud,
|
|
45403
|
+
credentialSession,
|
|
45404
|
+
httpClient.fetch
|
|
45405
|
+
),
|
|
45406
|
+
onPublishFailure: (code) => onEvent({
|
|
45407
|
+
type: "activity_publish_failure",
|
|
45408
|
+
code,
|
|
45409
|
+
ts: (/* @__PURE__ */ new Date()).toISOString()
|
|
45410
|
+
})
|
|
43959
45411
|
});
|
|
45412
|
+
const instrumentedModel = activity.instrumentModel(
|
|
45413
|
+
newModel(onCanaryAttempt, activity.events)
|
|
45414
|
+
);
|
|
45415
|
+
try {
|
|
45416
|
+
return await runListenerRuntime({
|
|
45417
|
+
target: options.cloud,
|
|
45418
|
+
workspaceId: options.workspaceId,
|
|
45419
|
+
principalId: options.principalId,
|
|
45420
|
+
credentialSession,
|
|
45421
|
+
store: effectStore,
|
|
45422
|
+
model: instrumentedModel,
|
|
45423
|
+
signal,
|
|
45424
|
+
onEvent: (event) => {
|
|
45425
|
+
activity.onRuntimeEvent(event);
|
|
45426
|
+
onEvent(event);
|
|
45427
|
+
},
|
|
45428
|
+
declareModel: listenerModelLabel(options.provider),
|
|
45429
|
+
listenerInstanceId,
|
|
45430
|
+
deliveryJournal: selectedJournal,
|
|
45431
|
+
resolveSenderProvenance,
|
|
45432
|
+
routeMode,
|
|
45433
|
+
deferOverChars,
|
|
45434
|
+
pendingMainQueue,
|
|
45435
|
+
fetcher: httpClient.fetch
|
|
45436
|
+
});
|
|
45437
|
+
} finally {
|
|
45438
|
+
activity.close();
|
|
45439
|
+
}
|
|
43960
45440
|
}
|
|
43961
45441
|
});
|
|
43962
45442
|
} finally {
|
|
43963
45443
|
process.off("SIGINT", onProcessSignal);
|
|
43964
45444
|
process.off("SIGTERM", onProcessSignal);
|
|
45445
|
+
httpClient.close();
|
|
43965
45446
|
}
|
|
43966
45447
|
}
|
|
43967
45448
|
async function runListenStart(args) {
|
|
@@ -44111,18 +45592,30 @@ async function runListenStart(args) {
|
|
|
44111
45592
|
if (error instanceof ListenerStartupError) {
|
|
44112
45593
|
const failedStatus = await effectiveListenerStatus(paths).catch(() => null);
|
|
44113
45594
|
const detail = failedStatus?.lastErrorCode === error.code ? failedStatus.lastErrorDetail : null;
|
|
44114
|
-
|
|
45595
|
+
const reasonCode = failedStatus?.lastErrorCode === error.code ? failedStatus.lastErrorReasonCode : null;
|
|
45596
|
+
const message = listenerFailureMessage(
|
|
45597
|
+
error.code,
|
|
45598
|
+
provider,
|
|
45599
|
+
detail,
|
|
45600
|
+
reasonCode,
|
|
45601
|
+
failedStatus?.providerMinimumRequiredVersion
|
|
45602
|
+
);
|
|
45603
|
+
throw new Error(
|
|
45604
|
+
failedStatus === null ? message : `${message}. ${listenerProviderIdentitySummary(failedStatus)}`
|
|
45605
|
+
);
|
|
44115
45606
|
}
|
|
44116
45607
|
throw error;
|
|
44117
45608
|
}
|
|
44118
45609
|
}
|
|
44119
45610
|
if (status.state === "failed") {
|
|
44120
45611
|
throw new Error(
|
|
44121
|
-
listenerFailureMessage(
|
|
45612
|
+
`${listenerFailureMessage(
|
|
44122
45613
|
status.lastErrorCode ?? "unknown_error",
|
|
44123
45614
|
provider,
|
|
44124
|
-
status.lastErrorDetail
|
|
44125
|
-
|
|
45615
|
+
status.lastErrorDetail,
|
|
45616
|
+
status.lastErrorReasonCode,
|
|
45617
|
+
status.providerMinimumRequiredVersion
|
|
45618
|
+
)}. ${listenerProviderIdentitySummary(status)}`
|
|
44126
45619
|
);
|
|
44127
45620
|
}
|
|
44128
45621
|
let attendanceEvidence = {
|
|
@@ -44304,11 +45797,22 @@ async function runListenStatusOrStop(args, command2) {
|
|
|
44304
45797
|
hookSurfaceAdvanced: queueStats.hookSurfaceAdvanced
|
|
44305
45798
|
};
|
|
44306
45799
|
}
|
|
45800
|
+
const installed = command2 === "status" ? await listenerProviderInstallEvidence(status) : null;
|
|
44307
45801
|
if (args.has("json")) {
|
|
44308
|
-
printJson(
|
|
45802
|
+
printJson(
|
|
45803
|
+
listenerStatusJson(
|
|
45804
|
+
status,
|
|
45805
|
+
void 0,
|
|
45806
|
+
attendanceEvidence,
|
|
45807
|
+
Date.now(),
|
|
45808
|
+
installed
|
|
45809
|
+
)
|
|
45810
|
+
);
|
|
44309
45811
|
} else {
|
|
44310
|
-
process.stdout.write(
|
|
44311
|
-
|
|
45812
|
+
process.stdout.write(
|
|
45813
|
+
`${renderListenerStatus(status, attendanceEvidence, Date.now(), installed)}
|
|
45814
|
+
`
|
|
45815
|
+
);
|
|
44312
45816
|
}
|
|
44313
45817
|
}
|
|
44314
45818
|
async function runListenCanary(args) {
|
|
@@ -44345,16 +45849,23 @@ async function runListenCanary(args) {
|
|
|
44345
45849
|
...stateDirectory2 ? { stateDirectory: stateDirectory2 } : {}
|
|
44346
45850
|
});
|
|
44347
45851
|
const waitMs = parseWaitSeconds(args.optional("wait") ?? "10") * 1e3;
|
|
44348
|
-
const
|
|
44349
|
-
|
|
44350
|
-
|
|
44351
|
-
|
|
44352
|
-
|
|
44353
|
-
|
|
44354
|
-
|
|
44355
|
-
|
|
44356
|
-
|
|
44357
|
-
|
|
45852
|
+
const httpClient = new ListenerHttpClient();
|
|
45853
|
+
let result;
|
|
45854
|
+
try {
|
|
45855
|
+
result = await runListenerAttendanceCanary({
|
|
45856
|
+
target: cloud,
|
|
45857
|
+
workspaceId: workspaceId2,
|
|
45858
|
+
principalId,
|
|
45859
|
+
paths,
|
|
45860
|
+
waitMs,
|
|
45861
|
+
fetcher: httpClient.fetch,
|
|
45862
|
+
// Canary must remain read-only apart from its one self-note. It therefore
|
|
45863
|
+
// uses the presented token and never enters the renewal/mint path.
|
|
45864
|
+
credential: async () => agent.token
|
|
45865
|
+
});
|
|
45866
|
+
} finally {
|
|
45867
|
+
httpClient.close();
|
|
45868
|
+
}
|
|
44358
45869
|
if (args.has("json")) {
|
|
44359
45870
|
printJson({
|
|
44360
45871
|
workspaceId: workspaceId2,
|
|
@@ -44620,19 +46131,25 @@ async function runHook(args) {
|
|
|
44620
46131
|
process.exit(0);
|
|
44621
46132
|
}, 3e3);
|
|
44622
46133
|
hardExit.unref();
|
|
44623
|
-
|
|
44624
|
-
|
|
44625
|
-
|
|
44626
|
-
|
|
44627
|
-
|
|
44628
|
-
|
|
46134
|
+
const httpClient = new ListenerHttpClient();
|
|
46135
|
+
try {
|
|
46136
|
+
await runListenerHookCheck({
|
|
46137
|
+
...cooldownSeconds === void 0 ? {} : { cooldownSeconds },
|
|
46138
|
+
...principalIds.length === 0 ? {} : { principalIds },
|
|
46139
|
+
fetcher: httpClient.fetch,
|
|
46140
|
+
write: async (output) => {
|
|
46141
|
+
await new Promise((resolve3, reject) => {
|
|
46142
|
+
process.stdout.write(`${output}
|
|
44629
46143
|
`, (error) => {
|
|
44630
|
-
|
|
44631
|
-
|
|
46144
|
+
if (error) reject(error);
|
|
46145
|
+
else resolve3();
|
|
46146
|
+
});
|
|
44632
46147
|
});
|
|
44633
|
-
}
|
|
44634
|
-
}
|
|
44635
|
-
}
|
|
46148
|
+
}
|
|
46149
|
+
});
|
|
46150
|
+
} finally {
|
|
46151
|
+
httpClient.close();
|
|
46152
|
+
}
|
|
44636
46153
|
return;
|
|
44637
46154
|
}
|
|
44638
46155
|
if (command2 !== "install" && command2 !== "uninstall") {
|
|
@@ -44758,8 +46275,8 @@ async function uploadNamedFile(context, name, bytes) {
|
|
|
44758
46275
|
workspaceId: context.selected.selectedWorkspace,
|
|
44759
46276
|
credential: context.selected.bearer
|
|
44760
46277
|
};
|
|
44761
|
-
const fileId = (0,
|
|
44762
|
-
const versionId = (0,
|
|
46278
|
+
const fileId = (0, import_node_crypto22.randomUUID)();
|
|
46279
|
+
const versionId = (0, import_node_crypto22.randomUUID)();
|
|
44763
46280
|
const createCommandId = newCommandId();
|
|
44764
46281
|
const commitCommandId = newCommandId();
|
|
44765
46282
|
const created = await onceRetried(
|
|
@@ -45170,7 +46687,7 @@ async function runDogfood(args) {
|
|
|
45170
46687
|
const { selectedWorkspace, bearer } = await commandWorkspaceAndCredential(args, cloud);
|
|
45171
46688
|
const client = new ThinCommandClient(cloud);
|
|
45172
46689
|
const route = stream(args);
|
|
45173
|
-
const taskId = args.optional("task-id") ?? (0,
|
|
46690
|
+
const taskId = args.optional("task-id") ?? (0, import_node_crypto22.randomUUID)();
|
|
45174
46691
|
const ttl = Number(args.optional("ttl-ms") ?? "3600000");
|
|
45175
46692
|
if (!Number.isSafeInteger(ttl) || ttl <= 0 || ttl > 144e5) {
|
|
45176
46693
|
throw new Error("--ttl-ms must be an integer in 1..14400000");
|
|
@@ -45543,6 +47060,7 @@ ${usage()}
|
|
|
45543
47060
|
listenerFailureMessage,
|
|
45544
47061
|
listenerHostLimits,
|
|
45545
47062
|
listenerPermissionMode,
|
|
47063
|
+
listenerProviderInstallEvidence,
|
|
45546
47064
|
listenerRouteConfiguration,
|
|
45547
47065
|
listenerStatusJson,
|
|
45548
47066
|
renderListenerStatus,
|