commonswarm 0.1.29 → 0.1.31
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 +270 -171
- package/package.json +1 -1
package/cswarm.cjs
CHANGED
|
@@ -22125,6 +22125,8 @@ var WORKSPACE_NAME_MAX_LENGTH = 80;
|
|
|
22125
22125
|
var CAPABILITY_MIN_TTL_MS = 6e4;
|
|
22126
22126
|
var CAPABILITY_MAX_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
22127
22127
|
var SIGNAL_REQUEST_TIMEOUT_MS = 3e4;
|
|
22128
|
+
var SIGNAL_WRITE_MAX_ATTEMPTS = 3;
|
|
22129
|
+
var SIGNAL_WRITE_RETRY_BASE_MS = 500;
|
|
22128
22130
|
var CommandTransportError = class extends Error {
|
|
22129
22131
|
constructor(message) {
|
|
22130
22132
|
super(message);
|
|
@@ -22380,6 +22382,27 @@ async function raceSignalDeadline(work, deadline, callerAbort) {
|
|
|
22380
22382
|
}
|
|
22381
22383
|
return await Promise.race(arms);
|
|
22382
22384
|
}
|
|
22385
|
+
function signalRetryDelayMs(retry, baseMs, random) {
|
|
22386
|
+
const exponential = baseMs * 2 ** (retry - 1);
|
|
22387
|
+
const jitter = 0.5 + Math.min(1, Math.max(0, random()));
|
|
22388
|
+
return Math.round(exponential * jitter);
|
|
22389
|
+
}
|
|
22390
|
+
async function waitForSignalRetry(delayMs, deadline, callerAbort) {
|
|
22391
|
+
if (delayMs === 0) return "elapsed";
|
|
22392
|
+
let timer2;
|
|
22393
|
+
const elapsed = new Promise((resolve) => {
|
|
22394
|
+
timer2 = setTimeout(() => resolve("elapsed"), delayMs);
|
|
22395
|
+
});
|
|
22396
|
+
try {
|
|
22397
|
+
const outcome = await raceSignalDeadline(elapsed, deadline, callerAbort);
|
|
22398
|
+
if (outcome.kind === "value") return outcome.value;
|
|
22399
|
+
if (outcome.kind === "callerAbort") return "callerAbort";
|
|
22400
|
+
if (outcome.kind === "deadline") return "deadline";
|
|
22401
|
+
throw outcome.error;
|
|
22402
|
+
} finally {
|
|
22403
|
+
if (timer2 !== void 0) clearTimeout(timer2);
|
|
22404
|
+
}
|
|
22405
|
+
}
|
|
22383
22406
|
async function declareAgentModel(target2, request, fetcher = fetch) {
|
|
22384
22407
|
const controller = new AbortController();
|
|
22385
22408
|
const timer2 = setTimeout(() => controller.abort(), 3e4);
|
|
@@ -22416,12 +22439,14 @@ async function declareAgentModel(target2, request, fetcher = fetch) {
|
|
|
22416
22439
|
return { httpStatus: response.status };
|
|
22417
22440
|
}
|
|
22418
22441
|
var ThinCommandClient = class {
|
|
22419
|
-
constructor(target2, fetcher = fetch) {
|
|
22442
|
+
constructor(target2, fetcher = fetch, options = {}) {
|
|
22420
22443
|
this.target = target2;
|
|
22421
22444
|
this.fetcher = fetcher;
|
|
22445
|
+
this.options = options;
|
|
22422
22446
|
}
|
|
22423
22447
|
target;
|
|
22424
22448
|
fetcher;
|
|
22449
|
+
options;
|
|
22425
22450
|
projections = /* @__PURE__ */ new Map();
|
|
22426
22451
|
projection(taskId) {
|
|
22427
22452
|
return this.projections.get(taskId) ?? null;
|
|
@@ -22681,10 +22706,12 @@ var ThinCommandClient = class {
|
|
|
22681
22706
|
const callerAbort = new Promise((resolve) => {
|
|
22682
22707
|
releaseCallerAbort = resolve;
|
|
22683
22708
|
});
|
|
22709
|
+
let deadlineReached = false;
|
|
22684
22710
|
const timer2 = setTimeout(() => {
|
|
22711
|
+
deadlineReached = true;
|
|
22685
22712
|
releaseDeadline?.();
|
|
22686
22713
|
controller.abort();
|
|
22687
|
-
}, SIGNAL_REQUEST_TIMEOUT_MS);
|
|
22714
|
+
}, this.options.signalRequestTimeoutMs ?? SIGNAL_REQUEST_TIMEOUT_MS);
|
|
22688
22715
|
const onCallerAbort = () => {
|
|
22689
22716
|
releaseCallerAbort?.();
|
|
22690
22717
|
controller.abort();
|
|
@@ -22695,90 +22722,117 @@ var ThinCommandClient = class {
|
|
|
22695
22722
|
controller.abort();
|
|
22696
22723
|
}
|
|
22697
22724
|
try {
|
|
22698
|
-
let
|
|
22699
|
-
|
|
22700
|
-
|
|
22701
|
-
|
|
22702
|
-
method: "POST",
|
|
22703
|
-
headers: {
|
|
22704
|
-
authorization: `Bearer ${request.credential}`,
|
|
22705
|
-
apikey: this.target.anonKey,
|
|
22706
|
-
"content-type": "application/json"
|
|
22707
|
-
},
|
|
22708
|
-
body: JSON.stringify({
|
|
22709
|
-
command_id: commandId,
|
|
22710
|
-
client_version: CLIENT_PROTOCOL_VERSION,
|
|
22711
|
-
workspace_id: request.workspaceId,
|
|
22712
|
-
stream: { kind: "workspace" },
|
|
22713
|
-
command: command2
|
|
22714
|
-
}),
|
|
22715
|
-
signal: controller.signal
|
|
22716
|
-
})
|
|
22717
|
-
);
|
|
22718
|
-
} catch (error) {
|
|
22719
|
-
fetchWork = Promise.reject(error);
|
|
22720
|
-
}
|
|
22721
|
-
const fetchOutcome = await raceSignalDeadline(
|
|
22722
|
-
fetchWork,
|
|
22723
|
-
deadline,
|
|
22724
|
-
callerSignal === void 0 ? void 0 : callerAbort
|
|
22725
|
-
);
|
|
22726
|
-
if (fetchOutcome.kind === "callerAbort") {
|
|
22727
|
-
throw signalAbortError();
|
|
22728
|
-
}
|
|
22729
|
-
if (fetchOutcome.kind === "deadline") {
|
|
22730
|
-
throw new CommandTransportError("signal request timed out");
|
|
22731
|
-
}
|
|
22732
|
-
if (fetchOutcome.kind === "error") {
|
|
22733
|
-
throw new CommandTransportError(
|
|
22734
|
-
"signal request failed before a response"
|
|
22735
|
-
);
|
|
22736
|
-
}
|
|
22737
|
-
const response = fetchOutcome.value;
|
|
22738
|
-
const bodyOutcome = await raceSignalDeadline(
|
|
22739
|
-
parsedJson(response),
|
|
22740
|
-
deadline,
|
|
22741
|
-
callerSignal === void 0 ? void 0 : callerAbort
|
|
22742
|
-
);
|
|
22743
|
-
if (bodyOutcome.kind === "callerAbort") {
|
|
22744
|
-
throw signalAbortError();
|
|
22745
|
-
}
|
|
22746
|
-
if (bodyOutcome.kind === "deadline") {
|
|
22747
|
-
throw new CommandTransportError("signal request timed out");
|
|
22748
|
-
}
|
|
22749
|
-
if (bodyOutcome.kind === "error") {
|
|
22750
|
-
if (response.status >= 400) {
|
|
22751
|
-
throw new CommandHttpError(
|
|
22752
|
-
response.status,
|
|
22753
|
-
`signal failed (HTTP ${response.status})`
|
|
22754
|
-
);
|
|
22755
|
-
}
|
|
22756
|
-
throw bodyOutcome.error;
|
|
22757
|
-
}
|
|
22758
|
-
const raw = bodyOutcome.value;
|
|
22759
|
-
if (!response.ok) {
|
|
22760
|
-
const error = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
|
|
22761
|
-
throw new CommandHttpError(
|
|
22762
|
-
response.status,
|
|
22763
|
-
typeof error.message === "string" ? error.message : `signal failed (HTTP ${response.status}): ${typeof error.error === "string" ? error.error : "unknown_error"}`
|
|
22764
|
-
);
|
|
22765
|
-
}
|
|
22766
|
-
const body = responseBody(raw);
|
|
22767
|
-
if (body.status !== "accepted" || body.signal === void 0) {
|
|
22768
|
-
throw new Error("signal endpoint accepted without a signal receipt");
|
|
22769
|
-
}
|
|
22770
|
-
if (body.min_client_version !== void 0) {
|
|
22771
|
-
const order = compareVersion(CLIENT_PROTOCOL_VERSION, body.min_client_version);
|
|
22772
|
-
if (order === null) {
|
|
22773
|
-
throw new Error("server returned a malformed min_client_version");
|
|
22725
|
+
for (let attempt = 1; attempt <= SIGNAL_WRITE_MAX_ATTEMPTS; attempt += 1) {
|
|
22726
|
+
if (callerSignal?.aborted) throw signalAbortError();
|
|
22727
|
+
if (deadlineReached) {
|
|
22728
|
+
throw new CommandTransportError("signal request timed out");
|
|
22774
22729
|
}
|
|
22775
|
-
|
|
22776
|
-
|
|
22777
|
-
|
|
22730
|
+
try {
|
|
22731
|
+
let fetchWork;
|
|
22732
|
+
try {
|
|
22733
|
+
fetchWork = Promise.resolve(
|
|
22734
|
+
this.fetcher(commandEndpoint(this.target), {
|
|
22735
|
+
method: "POST",
|
|
22736
|
+
headers: {
|
|
22737
|
+
authorization: `Bearer ${request.credential}`,
|
|
22738
|
+
apikey: this.target.anonKey,
|
|
22739
|
+
"content-type": "application/json"
|
|
22740
|
+
},
|
|
22741
|
+
body: JSON.stringify({
|
|
22742
|
+
// One id is minted outside the loop. Every retry is a replay.
|
|
22743
|
+
command_id: commandId,
|
|
22744
|
+
client_version: CLIENT_PROTOCOL_VERSION,
|
|
22745
|
+
workspace_id: request.workspaceId,
|
|
22746
|
+
stream: { kind: "workspace" },
|
|
22747
|
+
command: command2
|
|
22748
|
+
}),
|
|
22749
|
+
signal: controller.signal
|
|
22750
|
+
})
|
|
22751
|
+
);
|
|
22752
|
+
} catch (error) {
|
|
22753
|
+
fetchWork = Promise.reject(error);
|
|
22754
|
+
}
|
|
22755
|
+
const fetchOutcome = await raceSignalDeadline(
|
|
22756
|
+
fetchWork,
|
|
22757
|
+
deadline,
|
|
22758
|
+
callerSignal === void 0 ? void 0 : callerAbort
|
|
22759
|
+
);
|
|
22760
|
+
if (fetchOutcome.kind === "callerAbort") throw signalAbortError();
|
|
22761
|
+
if (fetchOutcome.kind === "deadline") {
|
|
22762
|
+
throw new CommandTransportError("signal request timed out");
|
|
22763
|
+
}
|
|
22764
|
+
if (fetchOutcome.kind === "error") {
|
|
22765
|
+
throw new CommandTransportError(
|
|
22766
|
+
"signal request failed before a response"
|
|
22767
|
+
);
|
|
22768
|
+
}
|
|
22769
|
+
const response = fetchOutcome.value;
|
|
22770
|
+
const bodyOutcome = await raceSignalDeadline(
|
|
22771
|
+
parsedJson(response),
|
|
22772
|
+
deadline,
|
|
22773
|
+
callerSignal === void 0 ? void 0 : callerAbort
|
|
22774
|
+
);
|
|
22775
|
+
if (bodyOutcome.kind === "callerAbort") throw signalAbortError();
|
|
22776
|
+
if (bodyOutcome.kind === "deadline") {
|
|
22777
|
+
throw new CommandTransportError("signal request timed out");
|
|
22778
|
+
}
|
|
22779
|
+
if (bodyOutcome.kind === "error") {
|
|
22780
|
+
if (response.status >= 400) {
|
|
22781
|
+
throw new CommandHttpError(
|
|
22782
|
+
response.status,
|
|
22783
|
+
`signal failed (HTTP ${response.status})`
|
|
22784
|
+
);
|
|
22785
|
+
}
|
|
22786
|
+
throw bodyOutcome.error;
|
|
22787
|
+
}
|
|
22788
|
+
const raw = bodyOutcome.value;
|
|
22789
|
+
if (!response.ok) {
|
|
22790
|
+
const error = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
|
|
22791
|
+
throw new CommandHttpError(
|
|
22792
|
+
response.status,
|
|
22793
|
+
typeof error.message === "string" ? error.message : `signal failed (HTTP ${response.status}): ${typeof error.error === "string" ? error.error : "unknown_error"}`
|
|
22794
|
+
);
|
|
22795
|
+
}
|
|
22796
|
+
const body = responseBody(raw);
|
|
22797
|
+
if (body.status !== "accepted" || body.signal === void 0) {
|
|
22798
|
+
throw new Error("signal endpoint accepted without a signal receipt");
|
|
22799
|
+
}
|
|
22800
|
+
if (body.min_client_version !== void 0) {
|
|
22801
|
+
const order = compareVersion(CLIENT_PROTOCOL_VERSION, body.min_client_version);
|
|
22802
|
+
if (order === null) {
|
|
22803
|
+
throw new Error("server returned a malformed min_client_version");
|
|
22804
|
+
}
|
|
22805
|
+
if (order < 0) {
|
|
22806
|
+
throw new Error(
|
|
22807
|
+
`client upgrade required (minimum ${body.min_client_version})`
|
|
22808
|
+
);
|
|
22809
|
+
}
|
|
22810
|
+
}
|
|
22811
|
+
return {
|
|
22812
|
+
httpStatus: response.status,
|
|
22813
|
+
response: body,
|
|
22814
|
+
attempts: attempt,
|
|
22815
|
+
retried: attempt > 1
|
|
22816
|
+
};
|
|
22817
|
+
} catch (error) {
|
|
22818
|
+
const transient = error instanceof CommandTransportError || error instanceof CommandHttpError && error.status >= 500;
|
|
22819
|
+
if (!transient || attempt === SIGNAL_WRITE_MAX_ATTEMPTS) throw error;
|
|
22820
|
+
const waitOutcome = await waitForSignalRetry(
|
|
22821
|
+
signalRetryDelayMs(
|
|
22822
|
+
attempt,
|
|
22823
|
+
this.options.signalRetryBaseMs ?? SIGNAL_WRITE_RETRY_BASE_MS,
|
|
22824
|
+
this.options.signalRetryRandom ?? Math.random
|
|
22825
|
+
),
|
|
22826
|
+
deadline,
|
|
22827
|
+
callerSignal === void 0 ? void 0 : callerAbort
|
|
22778
22828
|
);
|
|
22829
|
+
if (waitOutcome === "callerAbort") throw signalAbortError();
|
|
22830
|
+
if (waitOutcome === "deadline") {
|
|
22831
|
+
throw new CommandTransportError("signal request timed out");
|
|
22832
|
+
}
|
|
22779
22833
|
}
|
|
22780
22834
|
}
|
|
22781
|
-
|
|
22835
|
+
throw new Error("signal retry loop ended without an outcome");
|
|
22782
22836
|
} finally {
|
|
22783
22837
|
clearTimeout(timer2);
|
|
22784
22838
|
callerSignal?.removeEventListener("abort", onCallerAbort);
|
|
@@ -29524,6 +29578,8 @@ var import_node_crypto12 = require("node:crypto");
|
|
|
29524
29578
|
// src/host/stderr-tail.ts
|
|
29525
29579
|
var RING_CAPACITY_BYTES = 4096;
|
|
29526
29580
|
var TAIL_MAX_CHARS = 2048;
|
|
29581
|
+
var STDERR_EXIT_GRACE_MS = 100;
|
|
29582
|
+
var STDERR_READABLE_END_GRACE_MS = STDERR_EXIT_GRACE_MS + 50;
|
|
29527
29583
|
var EXOTIC_SEPARATORS = "\\u00a0\\u1680\\u2000-\\u200d\\u2028\\u2029\\u202a-\\u202e\\u2060\\u2066-\\u2069\\u202f\\u205f\\u3000\\ufeff";
|
|
29528
29584
|
var SEPARATOR_CLASS_SOURCE = "\\t\\n\\x0b\\f\\r " + EXOTIC_SEPARATORS;
|
|
29529
29585
|
var ANSI_ESCAPE_GLOBAL_RE2 = new RegExp("\\u001b\\[[0-?]*[ -\\/]*[@-~]", "g");
|
|
@@ -29571,6 +29627,34 @@ function attachStderrTailRing(stderr) {
|
|
|
29571
29627
|
}
|
|
29572
29628
|
};
|
|
29573
29629
|
}
|
|
29630
|
+
function attachStderrTailExitObserver(child, onStderrTail) {
|
|
29631
|
+
const stderrTail = attachStderrTailRing(child.stderr);
|
|
29632
|
+
return (handler) => {
|
|
29633
|
+
const observeExit = (code, signal) => {
|
|
29634
|
+
let completed = false;
|
|
29635
|
+
let timer2 = null;
|
|
29636
|
+
const complete = () => {
|
|
29637
|
+
if (completed) return;
|
|
29638
|
+
completed = true;
|
|
29639
|
+
if (timer2) clearTimeout(timer2);
|
|
29640
|
+
child.removeListener("close", complete);
|
|
29641
|
+
try {
|
|
29642
|
+
onStderrTail?.(stderrTail.read());
|
|
29643
|
+
} finally {
|
|
29644
|
+
handler(code, signal);
|
|
29645
|
+
}
|
|
29646
|
+
};
|
|
29647
|
+
child.once("close", complete);
|
|
29648
|
+
timer2 = setTimeout(complete, STDERR_EXIT_GRACE_MS);
|
|
29649
|
+
timer2.unref();
|
|
29650
|
+
};
|
|
29651
|
+
if (child.exitCode !== null || child.signalCode !== null) {
|
|
29652
|
+
observeExit(child.exitCode, child.signalCode);
|
|
29653
|
+
} else {
|
|
29654
|
+
child.once("exit", observeExit);
|
|
29655
|
+
}
|
|
29656
|
+
};
|
|
29657
|
+
}
|
|
29574
29658
|
|
|
29575
29659
|
// src/host/opencode.ts
|
|
29576
29660
|
var import_node_fs3 = require("node:fs");
|
|
@@ -31367,27 +31451,18 @@ async function openOpenCodeAcpSession(options) {
|
|
|
31367
31451
|
await disposeHome();
|
|
31368
31452
|
throw new AcpHostError("spawn_failed", "child missing stdio pipes");
|
|
31369
31453
|
}
|
|
31370
|
-
const
|
|
31371
|
-
|
|
31372
|
-
|
|
31373
|
-
|
|
31374
|
-
const publishTail = () => {
|
|
31375
|
-
if (tailDelivered) return;
|
|
31376
|
-
tailDelivered = true;
|
|
31377
|
-
deliverTail(stderrTail.read());
|
|
31378
|
-
};
|
|
31379
|
-
child.once("exit", publishTail);
|
|
31380
|
-
child.once("close", publishTail);
|
|
31381
|
-
}
|
|
31454
|
+
const observeStderrTailOnExit = attachStderrTailExitObserver(
|
|
31455
|
+
child,
|
|
31456
|
+
options.onStderrTail
|
|
31457
|
+
);
|
|
31382
31458
|
let sessionRef = null;
|
|
31383
31459
|
const transport = createBoundTransport({
|
|
31384
31460
|
readable: child.stdout,
|
|
31385
31461
|
writable: child.stdin,
|
|
31386
31462
|
requestTimeoutMs: options.requestTimeoutMs ?? ACP_DEFAULT_REQUEST_TIMEOUT_MS,
|
|
31463
|
+
readableEndGraceMs: STDERR_READABLE_END_GRACE_MS,
|
|
31387
31464
|
getSession: () => sessionRef,
|
|
31388
|
-
onChildExit:
|
|
31389
|
-
child.on("exit", (code, signal) => handler(code, signal));
|
|
31390
|
-
}
|
|
31465
|
+
onChildExit: observeStderrTailOnExit
|
|
31391
31466
|
});
|
|
31392
31467
|
try {
|
|
31393
31468
|
const session = await AcpHostSession.connect({
|
|
@@ -31443,8 +31518,6 @@ var import_node_fs4 = require("node:fs");
|
|
|
31443
31518
|
var import_node_path6 = require("node:path");
|
|
31444
31519
|
var CHILD_EXIT_WAIT_MS2 = 3e3;
|
|
31445
31520
|
var CHILD_KILL_WAIT_MS2 = 1e3;
|
|
31446
|
-
var STDERR_EXIT_GRACE_MS = 100;
|
|
31447
|
-
var READABLE_END_GRACE_MS = STDERR_EXIT_GRACE_MS + 50;
|
|
31448
31521
|
var WINDOWS_NPM_SHIM_MAX_BYTES = 64 * 1024;
|
|
31449
31522
|
var WINDOWS_NPM_ENTRYPOINT = [
|
|
31450
31523
|
"node_modules",
|
|
@@ -31741,35 +31814,18 @@ async function openClaudeAcpSession(options) {
|
|
|
31741
31814
|
await terminateClaudeChild(child);
|
|
31742
31815
|
throw new AcpHostError("spawn_failed", "child missing stdio pipes");
|
|
31743
31816
|
}
|
|
31744
|
-
const
|
|
31817
|
+
const observeStderrTailOnExit = attachStderrTailExitObserver(
|
|
31818
|
+
child,
|
|
31819
|
+
options.onStderrTail
|
|
31820
|
+
);
|
|
31745
31821
|
let sessionRef = null;
|
|
31746
31822
|
const transport = createBoundTransport({
|
|
31747
31823
|
readable: child.stdout,
|
|
31748
31824
|
writable: child.stdin,
|
|
31749
31825
|
requestTimeoutMs: options.requestTimeoutMs ?? ACP_DEFAULT_REQUEST_TIMEOUT_MS,
|
|
31750
|
-
readableEndGraceMs:
|
|
31826
|
+
readableEndGraceMs: STDERR_READABLE_END_GRACE_MS,
|
|
31751
31827
|
getSession: () => sessionRef,
|
|
31752
|
-
onChildExit:
|
|
31753
|
-
const observeExit = (code, signal) => {
|
|
31754
|
-
let completed = false;
|
|
31755
|
-
let timer2 = null;
|
|
31756
|
-
const complete = () => {
|
|
31757
|
-
if (completed) return;
|
|
31758
|
-
completed = true;
|
|
31759
|
-
if (timer2) clearTimeout(timer2);
|
|
31760
|
-
child.removeListener("close", complete);
|
|
31761
|
-
options.onStderrTail?.(stderrTail.read());
|
|
31762
|
-
handler(code, signal);
|
|
31763
|
-
};
|
|
31764
|
-
child.once("close", complete);
|
|
31765
|
-
timer2 = setTimeout(complete, STDERR_EXIT_GRACE_MS);
|
|
31766
|
-
};
|
|
31767
|
-
if (child.exitCode !== null || child.signalCode !== null) {
|
|
31768
|
-
observeExit(child.exitCode, child.signalCode);
|
|
31769
|
-
} else {
|
|
31770
|
-
child.once("exit", observeExit);
|
|
31771
|
-
}
|
|
31772
|
-
}
|
|
31828
|
+
onChildExit: observeStderrTailOnExit
|
|
31773
31829
|
});
|
|
31774
31830
|
try {
|
|
31775
31831
|
const session = await Promise.race([
|
|
@@ -32038,27 +32094,18 @@ async function openCodexAcpSession(options) {
|
|
|
32038
32094
|
await terminateCodexChild(child);
|
|
32039
32095
|
throw new AcpHostError("spawn_failed", "child missing stdio pipes");
|
|
32040
32096
|
}
|
|
32041
|
-
const
|
|
32042
|
-
|
|
32043
|
-
|
|
32044
|
-
|
|
32045
|
-
const publishTail = () => {
|
|
32046
|
-
if (tailDelivered) return;
|
|
32047
|
-
tailDelivered = true;
|
|
32048
|
-
deliverTail(stderrTail.read());
|
|
32049
|
-
};
|
|
32050
|
-
child.once("exit", publishTail);
|
|
32051
|
-
child.once("close", publishTail);
|
|
32052
|
-
}
|
|
32097
|
+
const observeStderrTailOnExit = attachStderrTailExitObserver(
|
|
32098
|
+
child,
|
|
32099
|
+
options.onStderrTail
|
|
32100
|
+
);
|
|
32053
32101
|
let sessionRef = null;
|
|
32054
32102
|
const transport = createBoundTransport({
|
|
32055
32103
|
readable: child.stdout,
|
|
32056
32104
|
writable: child.stdin,
|
|
32057
32105
|
requestTimeoutMs: options.requestTimeoutMs ?? ACP_DEFAULT_REQUEST_TIMEOUT_MS,
|
|
32106
|
+
readableEndGraceMs: STDERR_READABLE_END_GRACE_MS,
|
|
32058
32107
|
getSession: () => sessionRef,
|
|
32059
|
-
onChildExit:
|
|
32060
|
-
child.on("exit", (code, signal) => handler(code, signal));
|
|
32061
|
-
}
|
|
32108
|
+
onChildExit: observeStderrTailOnExit
|
|
32062
32109
|
});
|
|
32063
32110
|
try {
|
|
32064
32111
|
const session = await Promise.race([
|
|
@@ -33012,27 +33059,18 @@ async function openGrokAcpSession(options) {
|
|
|
33012
33059
|
child.kill("SIGKILL");
|
|
33013
33060
|
throw new AcpHostError("spawn_failed", "child missing stdio pipes");
|
|
33014
33061
|
}
|
|
33015
|
-
const
|
|
33016
|
-
|
|
33017
|
-
|
|
33018
|
-
|
|
33019
|
-
const publishTail = () => {
|
|
33020
|
-
if (tailDelivered) return;
|
|
33021
|
-
tailDelivered = true;
|
|
33022
|
-
deliverTail(stderrTail.read());
|
|
33023
|
-
};
|
|
33024
|
-
child.once("exit", publishTail);
|
|
33025
|
-
child.once("close", publishTail);
|
|
33026
|
-
}
|
|
33062
|
+
const observeStderrTailOnExit = attachStderrTailExitObserver(
|
|
33063
|
+
child,
|
|
33064
|
+
options.onStderrTail
|
|
33065
|
+
);
|
|
33027
33066
|
let sessionRef = null;
|
|
33028
33067
|
const transport = createBoundTransport({
|
|
33029
33068
|
readable: child.stdout,
|
|
33030
33069
|
writable: child.stdin,
|
|
33031
33070
|
requestTimeoutMs: options.requestTimeoutMs ?? ACP_DEFAULT_REQUEST_TIMEOUT_MS,
|
|
33071
|
+
readableEndGraceMs: STDERR_READABLE_END_GRACE_MS,
|
|
33032
33072
|
getSession: () => sessionRef,
|
|
33033
|
-
onChildExit:
|
|
33034
|
-
child.on("exit", (code, signal) => handler(code, signal));
|
|
33035
|
-
}
|
|
33073
|
+
onChildExit: observeStderrTailOnExit
|
|
33036
33074
|
});
|
|
33037
33075
|
try {
|
|
33038
33076
|
const session = await AcpHostSession.connect({
|
|
@@ -37826,7 +37864,17 @@ async function discoverContexts(stateDirectory2, isListenerLive = listenerIsLive
|
|
|
37826
37864
|
instanceDirectory
|
|
37827
37865
|
);
|
|
37828
37866
|
const statusIsLive = storedStatus === null ? null : await isListenerLive(storedStatus);
|
|
37829
|
-
if (statusIsLive === false)
|
|
37867
|
+
if (statusIsLive === false) {
|
|
37868
|
+
contexts.push({
|
|
37869
|
+
instanceDirectory,
|
|
37870
|
+
paths: storedStatus.paths,
|
|
37871
|
+
status: storedStatus.status,
|
|
37872
|
+
listenerLive: false,
|
|
37873
|
+
credential: null,
|
|
37874
|
+
credentialReadFailed: false
|
|
37875
|
+
});
|
|
37876
|
+
continue;
|
|
37877
|
+
}
|
|
37830
37878
|
await deleteSecureJsonFile(
|
|
37831
37879
|
(0, import_node_path18.join)(instanceDirectory, RETIRED_HOOK_CREDENTIAL_FILE)
|
|
37832
37880
|
).catch(() => void 0);
|
|
@@ -37836,6 +37884,7 @@ async function discoverContexts(stateDirectory2, isListenerLive = listenerIsLive
|
|
|
37836
37884
|
instanceDirectory,
|
|
37837
37885
|
paths: storedStatus?.paths ?? null,
|
|
37838
37886
|
status: storedStatus?.status ?? null,
|
|
37887
|
+
listenerLive: statusIsLive,
|
|
37839
37888
|
credential,
|
|
37840
37889
|
credentialReadFailed: credential === null && storedStatus !== null
|
|
37841
37890
|
});
|
|
@@ -37845,6 +37894,7 @@ async function discoverContexts(stateDirectory2, isListenerLive = listenerIsLive
|
|
|
37845
37894
|
instanceDirectory,
|
|
37846
37895
|
paths: storedStatus.paths,
|
|
37847
37896
|
status: storedStatus.status,
|
|
37897
|
+
listenerLive: statusIsLive,
|
|
37848
37898
|
credential: null,
|
|
37849
37899
|
credentialReadFailed: true
|
|
37850
37900
|
});
|
|
@@ -37885,6 +37935,24 @@ function renderHookSignal(item) {
|
|
|
37885
37935
|
`${replyLabel} cswarm reply ${item.signalId} "<answer>" --workspace-id ${item.workspaceId}`
|
|
37886
37936
|
].join("\n");
|
|
37887
37937
|
}
|
|
37938
|
+
function listenerRestartCommand(status) {
|
|
37939
|
+
const routeMode = status.routeMode ?? "worker";
|
|
37940
|
+
return [
|
|
37941
|
+
"cswarm listen start",
|
|
37942
|
+
"--agent-token-stdin",
|
|
37943
|
+
`--workspace-id ${status.workspaceId}`,
|
|
37944
|
+
`--provider ${status.provider}`,
|
|
37945
|
+
...status.permissionMode ? [`--permissions ${status.permissionMode}`] : [],
|
|
37946
|
+
`--route ${routeMode}`,
|
|
37947
|
+
...routeMode === "split" && status.deferOverChars !== null && status.deferOverChars !== void 0 ? [`--defer-over ${status.deferOverChars}`] : []
|
|
37948
|
+
].join(" ");
|
|
37949
|
+
}
|
|
37950
|
+
function renderStrandedQueue(context, count2) {
|
|
37951
|
+
const status = context.status;
|
|
37952
|
+
const noun = count2 === 1 ? "message" : "messages";
|
|
37953
|
+
const verb = count2 === 1 ? "was" : "were";
|
|
37954
|
+
return `[CommonSwarm] ${count2} ${noun} ${verb} waiting for agent ${status.principalId} in listener ${status.instanceId}, but that listener is no longer running. Restart it by piping the same agent credential into: ` + listenerRestartCommand(status);
|
|
37955
|
+
}
|
|
37888
37956
|
async function inboxItems(context, options) {
|
|
37889
37957
|
const stored = context.credential;
|
|
37890
37958
|
const target2 = cloudTarget(stored.targetUrl, stored.anonKey);
|
|
@@ -37944,11 +38012,11 @@ async function checkListenerHooks(options) {
|
|
|
37944
38012
|
options.isListenerLive ?? listenerIsLive
|
|
37945
38013
|
);
|
|
37946
38014
|
if (contexts.length === 0) return "";
|
|
37947
|
-
const networkAllowed = await reserveCheck(
|
|
38015
|
+
const networkAllowed = contexts.some((context) => context.listenerLive !== false) ? await reserveCheck(
|
|
37948
38016
|
stateDirectory2,
|
|
37949
38017
|
cooldownSeconds * 1e3,
|
|
37950
38018
|
now()
|
|
37951
|
-
);
|
|
38019
|
+
) : false;
|
|
37952
38020
|
const checks = await Promise.all(contexts.map(async (context) => {
|
|
37953
38021
|
const queue = new FilePendingMainQueue(context.instanceDirectory);
|
|
37954
38022
|
const pending = await queue.read();
|
|
@@ -37973,7 +38041,7 @@ async function checkListenerHooks(options) {
|
|
|
37973
38041
|
context,
|
|
37974
38042
|
queue,
|
|
37975
38043
|
pending,
|
|
37976
|
-
droppedCount: stats.droppedCount,
|
|
38044
|
+
droppedCount: context.listenerLive === false ? 0 : stats.droppedCount,
|
|
37977
38045
|
network,
|
|
37978
38046
|
credentialFailure,
|
|
37979
38047
|
credentialHealthy
|
|
@@ -37989,6 +38057,11 @@ async function checkListenerHooks(options) {
|
|
|
37989
38057
|
check.droppedCount
|
|
37990
38058
|
);
|
|
37991
38059
|
blocks.push(...staged.unseen.map(renderHookSignal));
|
|
38060
|
+
const pendingSignalIds = new Set(check.pending.map((entry) => entry.signalId));
|
|
38061
|
+
const unseenPending = staged.unseen.filter((item) => pendingSignalIds.has(item.signalId));
|
|
38062
|
+
if (check.context.listenerLive === false && unseenPending.length > 0) {
|
|
38063
|
+
blocks.push(renderStrandedQueue(check.context, unseenPending.length));
|
|
38064
|
+
}
|
|
37992
38065
|
const reportDrops = staged.droppedSinceLastCheck > 0;
|
|
37993
38066
|
if (reportDrops) blocks.push(renderDroppedAsks(staged.droppedSinceLastCheck));
|
|
37994
38067
|
const reportCredentialFailure = check.credentialFailure !== null && !staged.credentialFailureReported;
|
|
@@ -37999,12 +38072,14 @@ async function checkListenerHooks(options) {
|
|
|
37999
38072
|
blocks.push(warning);
|
|
38000
38073
|
}
|
|
38001
38074
|
}
|
|
38002
|
-
const pendingSignalIds = new Set(check.pending.map((entry) => entry.signalId));
|
|
38003
38075
|
commits.push({
|
|
38004
38076
|
check,
|
|
38005
38077
|
store: store2,
|
|
38006
38078
|
signalIds: staged.unseen.map((item) => item.signalId),
|
|
38007
|
-
|
|
38079
|
+
// Every staged queue entry is either written by this run or was committed
|
|
38080
|
+
// after an earlier successful write. Removing both keeps the queue bounded
|
|
38081
|
+
// without re-printing entries below the exactly-once high-water.
|
|
38082
|
+
settledPendingSignalIds: check.pending.map((item) => item.signalId),
|
|
38008
38083
|
reportDrops,
|
|
38009
38084
|
reportCredentialFailure
|
|
38010
38085
|
});
|
|
@@ -38018,7 +38093,7 @@ async function checkListenerHooks(options) {
|
|
|
38018
38093
|
...commit.reportCredentialFailure ? { credentialFailureReported: true } : commit.check.credentialHealthy ? { credentialFailureReported: false } : {}
|
|
38019
38094
|
});
|
|
38020
38095
|
const remainingCount = await commit.check.queue.remove(
|
|
38021
|
-
new Set(commit.
|
|
38096
|
+
new Set(commit.settledPendingSignalIds),
|
|
38022
38097
|
HOOK_LOCK_TIMEOUT_MS
|
|
38023
38098
|
);
|
|
38024
38099
|
if (commit.check.context.paths !== null && commit.check.context.status !== null) {
|
|
@@ -38151,8 +38226,8 @@ var ACCEPTED_AGENT_CREDENTIAL_MESSAGES = [
|
|
|
38151
38226
|
AGENT_CREDENTIAL_MESSAGE_D088
|
|
38152
38227
|
];
|
|
38153
38228
|
function packageVersion() {
|
|
38154
|
-
if ("0.1.
|
|
38155
|
-
return "0.1.
|
|
38229
|
+
if ("0.1.31".length > 0) {
|
|
38230
|
+
return "0.1.31";
|
|
38156
38231
|
}
|
|
38157
38232
|
try {
|
|
38158
38233
|
const value = JSON.parse(
|
|
@@ -40039,7 +40114,11 @@ async function runPostSignal(args, kind) {
|
|
|
40039
40114
|
}
|
|
40040
40115
|
const reply = waitResult.signals[0] ?? null;
|
|
40041
40116
|
if (args.has("json")) {
|
|
40042
|
-
printJson(
|
|
40117
|
+
printJson({
|
|
40118
|
+
...askWaitJsonPayload(signal, reply, waitResult.timedOut),
|
|
40119
|
+
retried: result.retried,
|
|
40120
|
+
attempts: result.attempts
|
|
40121
|
+
});
|
|
40043
40122
|
return;
|
|
40044
40123
|
}
|
|
40045
40124
|
const authors2 = await settleSignalAuthorLabels(
|
|
@@ -40076,7 +40155,9 @@ ${renderSignals([signal, reply], {
|
|
|
40076
40155
|
printJson({
|
|
40077
40156
|
status: result.response.status,
|
|
40078
40157
|
message: "Signal shared. It is immutable, tenancy-scoped, and will quietly expire at its horizon.",
|
|
40079
|
-
signal
|
|
40158
|
+
signal,
|
|
40159
|
+
retried: result.retried,
|
|
40160
|
+
attempts: result.attempts
|
|
40080
40161
|
});
|
|
40081
40162
|
return;
|
|
40082
40163
|
}
|
|
@@ -40166,7 +40247,9 @@ async function runReply(args) {
|
|
|
40166
40247
|
printJson({
|
|
40167
40248
|
status: result.response.status,
|
|
40168
40249
|
message: "Reply shared. It is immutable, tenancy-scoped, and will quietly expire at its horizon.",
|
|
40169
|
-
signal
|
|
40250
|
+
signal,
|
|
40251
|
+
retried: result.retried,
|
|
40252
|
+
attempts: result.attempts
|
|
40170
40253
|
});
|
|
40171
40254
|
return;
|
|
40172
40255
|
}
|
|
@@ -40695,7 +40778,7 @@ function renderListenerStatus(status) {
|
|
|
40695
40778
|
}
|
|
40696
40779
|
if (pendingForMainCount > 0) {
|
|
40697
40780
|
lines.push(
|
|
40698
|
-
`${pendingForMainCount} asks waiting for this session; they surface at your next prompt, or run cswarm hook check.`
|
|
40781
|
+
status.state === "stopped" || status.state === "failed" ? `${pendingForMainCount} asks are stranded because this listener is not running. Restart it by piping the same agent credential into: ${listenerRestartCommand(status)}` : `${pendingForMainCount} asks waiting for this session; they surface at your next prompt, or run cswarm hook check.`
|
|
40699
40782
|
);
|
|
40700
40783
|
}
|
|
40701
40784
|
}
|
|
@@ -40711,6 +40794,20 @@ function renderListenerStatus(status) {
|
|
|
40711
40794
|
}
|
|
40712
40795
|
return lines.join("\n");
|
|
40713
40796
|
}
|
|
40797
|
+
async function unsurfacedPendingMainStats(instanceDirectory, fallback) {
|
|
40798
|
+
try {
|
|
40799
|
+
const queue = new FilePendingMainQueue(instanceDirectory);
|
|
40800
|
+
const pending = await queue.read();
|
|
40801
|
+
const stats = await queue.stats();
|
|
40802
|
+
const staged = await new FileHookSurfaceStore(instanceDirectory).stage(
|
|
40803
|
+
pending,
|
|
40804
|
+
stats.droppedCount
|
|
40805
|
+
);
|
|
40806
|
+
return { count: staged.unseen.length, droppedCount: stats.droppedCount };
|
|
40807
|
+
} catch {
|
|
40808
|
+
return fallback;
|
|
40809
|
+
}
|
|
40810
|
+
}
|
|
40714
40811
|
function listenerFailureMessage(code, provider) {
|
|
40715
40812
|
if (code === "version_below_floor") {
|
|
40716
40813
|
if (provider === "codex") {
|
|
@@ -41185,9 +41282,10 @@ async function runListenStart(args) {
|
|
|
41185
41282
|
if ((status.routeMode ?? "worker") !== "worker") {
|
|
41186
41283
|
const recordedPending = status.pendingForMainCount ?? 0;
|
|
41187
41284
|
const recordedDropped = status.droppedForMainCount ?? 0;
|
|
41188
|
-
const queueStats = await
|
|
41189
|
-
paths.instanceDirectory
|
|
41190
|
-
|
|
41285
|
+
const queueStats = await unsurfacedPendingMainStats(
|
|
41286
|
+
paths.instanceDirectory,
|
|
41287
|
+
{ count: recordedPending, droppedCount: recordedDropped }
|
|
41288
|
+
);
|
|
41191
41289
|
status = {
|
|
41192
41290
|
...status,
|
|
41193
41291
|
pendingForMainCount: queueStats.count,
|
|
@@ -41302,9 +41400,10 @@ async function runListenStatusOrStop(args, command2) {
|
|
|
41302
41400
|
if ((status.routeMode ?? "worker") !== "worker") {
|
|
41303
41401
|
const recordedPending = status.pendingForMainCount ?? 0;
|
|
41304
41402
|
const recordedDropped = status.droppedForMainCount ?? 0;
|
|
41305
|
-
const queueStats = await
|
|
41306
|
-
paths.instanceDirectory
|
|
41307
|
-
|
|
41403
|
+
const queueStats = await unsurfacedPendingMainStats(
|
|
41404
|
+
paths.instanceDirectory,
|
|
41405
|
+
{ count: recordedPending, droppedCount: recordedDropped }
|
|
41406
|
+
);
|
|
41308
41407
|
status = {
|
|
41309
41408
|
...status,
|
|
41310
41409
|
pendingForMainCount: queueStats.count,
|