commonswarm 0.1.30 → 0.1.32
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 +494 -77
- package/package.json +1 -1
package/cswarm.cjs
CHANGED
|
@@ -28271,8 +28271,8 @@ function relativeMagnitude(milliseconds) {
|
|
|
28271
28271
|
const amount = magnitude < 6e4 ? "under 1m" : magnitude < 36e5 ? `${Math.ceil(magnitude / 6e4)}m` : magnitude < 864e5 ? `${Math.ceil(magnitude / 36e5)}h` : `${Math.ceil(magnitude / 864e5)}d`;
|
|
28272
28272
|
return amount;
|
|
28273
28273
|
}
|
|
28274
|
-
function relativeAge(
|
|
28275
|
-
return `${relativeMagnitude(Math.max(0, now - Date.parse(
|
|
28274
|
+
function relativeAge(timestamp3, now = Date.now()) {
|
|
28275
|
+
return `${relativeMagnitude(Math.max(0, now - Date.parse(timestamp3)))} ago`;
|
|
28276
28276
|
}
|
|
28277
28277
|
function relativeExpiry(expiry, now = Date.now()) {
|
|
28278
28278
|
const remaining = Date.parse(expiry) - now;
|
|
@@ -29571,6 +29571,318 @@ async function runInboxFollow(options) {
|
|
|
29571
29571
|
}
|
|
29572
29572
|
}
|
|
29573
29573
|
|
|
29574
|
+
// src/cloud/delivery-receipts.ts
|
|
29575
|
+
var UUID_RE8 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
29576
|
+
var DeliveryReceiptReadError = class extends Error {
|
|
29577
|
+
constructor(code, message, status = null) {
|
|
29578
|
+
super(message);
|
|
29579
|
+
this.code = code;
|
|
29580
|
+
this.status = status;
|
|
29581
|
+
this.name = "DeliveryReceiptReadError";
|
|
29582
|
+
}
|
|
29583
|
+
code;
|
|
29584
|
+
status;
|
|
29585
|
+
};
|
|
29586
|
+
var ACK_OUTCOMES = /* @__PURE__ */ new Set([
|
|
29587
|
+
"replied",
|
|
29588
|
+
"observed",
|
|
29589
|
+
"expired",
|
|
29590
|
+
"failed_terminal"
|
|
29591
|
+
]);
|
|
29592
|
+
function uuid3(value, field) {
|
|
29593
|
+
if (typeof value !== "string" || !UUID_RE8.test(value)) {
|
|
29594
|
+
throw new DeliveryReceiptReadError(
|
|
29595
|
+
"protocol",
|
|
29596
|
+
`delivery receipt returned a malformed ${field}`
|
|
29597
|
+
);
|
|
29598
|
+
}
|
|
29599
|
+
return value.toLowerCase();
|
|
29600
|
+
}
|
|
29601
|
+
function timestamp2(value, field) {
|
|
29602
|
+
if (typeof value !== "string" || !Number.isFinite(Date.parse(value))) {
|
|
29603
|
+
throw new DeliveryReceiptReadError(
|
|
29604
|
+
"protocol",
|
|
29605
|
+
`delivery receipt returned a malformed ${field}`
|
|
29606
|
+
);
|
|
29607
|
+
}
|
|
29608
|
+
return value;
|
|
29609
|
+
}
|
|
29610
|
+
function nullableTimestamp(value, field) {
|
|
29611
|
+
return value === null ? null : timestamp2(value, field);
|
|
29612
|
+
}
|
|
29613
|
+
function nonNegativeInteger(value, field) {
|
|
29614
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
|
|
29615
|
+
throw new DeliveryReceiptReadError(
|
|
29616
|
+
"protocol",
|
|
29617
|
+
`delivery receipt returned a malformed ${field}`
|
|
29618
|
+
);
|
|
29619
|
+
}
|
|
29620
|
+
return value;
|
|
29621
|
+
}
|
|
29622
|
+
function parseDeliveryReceipt(value) {
|
|
29623
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
29624
|
+
throw new DeliveryReceiptReadError(
|
|
29625
|
+
"protocol",
|
|
29626
|
+
"delivery receipt returned a malformed row"
|
|
29627
|
+
);
|
|
29628
|
+
}
|
|
29629
|
+
const row = value;
|
|
29630
|
+
const ackedAt = nullableTimestamp(row.acked_at, "acked_at");
|
|
29631
|
+
const ackOutcome = row.ack_outcome === null ? null : typeof row.ack_outcome === "string" && ACK_OUTCOMES.has(row.ack_outcome) ? row.ack_outcome : (() => {
|
|
29632
|
+
throw new DeliveryReceiptReadError(
|
|
29633
|
+
"protocol",
|
|
29634
|
+
"delivery receipt returned a malformed ack_outcome"
|
|
29635
|
+
);
|
|
29636
|
+
})();
|
|
29637
|
+
if (ackedAt === null !== (ackOutcome === null)) {
|
|
29638
|
+
throw new DeliveryReceiptReadError(
|
|
29639
|
+
"protocol",
|
|
29640
|
+
"delivery receipt returned an inconsistent acknowledgement"
|
|
29641
|
+
);
|
|
29642
|
+
}
|
|
29643
|
+
return {
|
|
29644
|
+
recipient_agent_principal_id: uuid3(
|
|
29645
|
+
row.recipient_agent_principal_id,
|
|
29646
|
+
"recipient_agent_principal_id"
|
|
29647
|
+
),
|
|
29648
|
+
enqueued_at: timestamp2(row.enqueued_at, "enqueued_at"),
|
|
29649
|
+
delivered_at: nullableTimestamp(row.delivered_at, "delivered_at"),
|
|
29650
|
+
leased_until: nullableTimestamp(row.leased_until, "leased_until"),
|
|
29651
|
+
acked_at: ackedAt,
|
|
29652
|
+
ack_outcome: ackOutcome,
|
|
29653
|
+
attempt_count: nonNegativeInteger(row.attempt_count, "attempt_count"),
|
|
29654
|
+
lease_expiry_count: nonNegativeInteger(
|
|
29655
|
+
row.lease_expiry_count,
|
|
29656
|
+
"lease_expiry_count"
|
|
29657
|
+
),
|
|
29658
|
+
last_error_code: row.last_error_code === null ? null : typeof row.last_error_code === "string" && /^[a-z][a-z0-9_]{0,63}$/.test(row.last_error_code) ? row.last_error_code : (() => {
|
|
29659
|
+
throw new DeliveryReceiptReadError(
|
|
29660
|
+
"protocol",
|
|
29661
|
+
"delivery receipt returned a malformed last_error_code"
|
|
29662
|
+
);
|
|
29663
|
+
})()
|
|
29664
|
+
};
|
|
29665
|
+
}
|
|
29666
|
+
function parseDeliveryReceiptResult(value) {
|
|
29667
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
29668
|
+
throw new DeliveryReceiptReadError(
|
|
29669
|
+
"protocol",
|
|
29670
|
+
"delivery receipt read returned malformed JSON"
|
|
29671
|
+
);
|
|
29672
|
+
}
|
|
29673
|
+
const body = value;
|
|
29674
|
+
if (!(body.addressed === null || typeof body.addressed === "boolean") || !Array.isArray(body.receipts)) {
|
|
29675
|
+
throw new DeliveryReceiptReadError(
|
|
29676
|
+
"protocol",
|
|
29677
|
+
"delivery receipt read returned malformed JSON"
|
|
29678
|
+
);
|
|
29679
|
+
}
|
|
29680
|
+
const receipts = body.receipts.map(parseDeliveryReceipt);
|
|
29681
|
+
if (body.addressed === false && receipts.length !== 0) {
|
|
29682
|
+
throw new DeliveryReceiptReadError(
|
|
29683
|
+
"protocol",
|
|
29684
|
+
"delivery receipt read returned recipients for a broadcast"
|
|
29685
|
+
);
|
|
29686
|
+
}
|
|
29687
|
+
if (body.addressed === true && receipts.length === 0) {
|
|
29688
|
+
throw new DeliveryReceiptReadError(
|
|
29689
|
+
"protocol",
|
|
29690
|
+
"delivery receipt read returned no recipient for an addressed signal"
|
|
29691
|
+
);
|
|
29692
|
+
}
|
|
29693
|
+
const recipientIds = new Set(
|
|
29694
|
+
receipts.map((row) => row.recipient_agent_principal_id)
|
|
29695
|
+
);
|
|
29696
|
+
if (recipientIds.size !== receipts.length) {
|
|
29697
|
+
throw new DeliveryReceiptReadError(
|
|
29698
|
+
"protocol",
|
|
29699
|
+
"delivery receipt read returned duplicate recipients"
|
|
29700
|
+
);
|
|
29701
|
+
}
|
|
29702
|
+
return { addressed: body.addressed, receipts };
|
|
29703
|
+
}
|
|
29704
|
+
function deliveryReceiptState(receipt, nowMs = Date.now()) {
|
|
29705
|
+
if (receipt.ack_outcome !== null) return receipt.ack_outcome;
|
|
29706
|
+
if (receipt.leased_until !== null && Date.parse(receipt.leased_until) > nowMs) {
|
|
29707
|
+
return "leased";
|
|
29708
|
+
}
|
|
29709
|
+
if (receipt.delivered_at !== null) return "delivered";
|
|
29710
|
+
return "enqueued";
|
|
29711
|
+
}
|
|
29712
|
+
async function readAgentDeliveryReceipts(target2, token, workspaceId2, signalId, options = {}) {
|
|
29713
|
+
const readOptions = typeof options === "function" ? { fetcher: options } : options;
|
|
29714
|
+
const now = readOptions.now ?? Date.now;
|
|
29715
|
+
const timeoutMs = readOptions.deadlineMs === void 0 ? SIGNAL_READ_TIMEOUT_MS : Math.min(SIGNAL_READ_TIMEOUT_MS, readOptions.deadlineMs - now());
|
|
29716
|
+
if (timeoutMs <= 0) {
|
|
29717
|
+
throw new SignalReadTimeoutError("receipt read timed out");
|
|
29718
|
+
}
|
|
29719
|
+
const deadlineController = new AbortController();
|
|
29720
|
+
const signal = readOptions.signal === void 0 ? deadlineController.signal : AbortSignal.any([readOptions.signal, deadlineController.signal]);
|
|
29721
|
+
let onAbort = () => {
|
|
29722
|
+
};
|
|
29723
|
+
const aborted = new Promise((_resolve, reject) => {
|
|
29724
|
+
onAbort = () => reject(new SignalReadTimeoutError("receipt read timed out"));
|
|
29725
|
+
if (signal.aborted) onAbort();
|
|
29726
|
+
else signal.addEventListener("abort", onAbort, { once: true });
|
|
29727
|
+
});
|
|
29728
|
+
const timer2 = setTimeout(() => deadlineController.abort(), timeoutMs);
|
|
29729
|
+
try {
|
|
29730
|
+
let response;
|
|
29731
|
+
try {
|
|
29732
|
+
response = await Promise.race([
|
|
29733
|
+
(readOptions.fetcher ?? fetch)(readEndpoint(target2), {
|
|
29734
|
+
method: "POST",
|
|
29735
|
+
headers: {
|
|
29736
|
+
authorization: `Bearer ${token}`,
|
|
29737
|
+
apikey: target2.anonKey,
|
|
29738
|
+
"content-type": "application/json"
|
|
29739
|
+
},
|
|
29740
|
+
body: JSON.stringify({
|
|
29741
|
+
resource: "delivery_receipts",
|
|
29742
|
+
workspace_id: uuid3(workspaceId2, "workspace_id"),
|
|
29743
|
+
signal_id: uuid3(signalId, "signal_id")
|
|
29744
|
+
}),
|
|
29745
|
+
signal
|
|
29746
|
+
}),
|
|
29747
|
+
aborted
|
|
29748
|
+
]);
|
|
29749
|
+
} catch (error) {
|
|
29750
|
+
if (error instanceof SignalReadTimeoutError || signal.aborted || error?.name === "AbortError") {
|
|
29751
|
+
throw new SignalReadTimeoutError("receipt read timed out");
|
|
29752
|
+
}
|
|
29753
|
+
if (error instanceof DeliveryReceiptReadError) throw error;
|
|
29754
|
+
throw new DeliveryReceiptReadError(
|
|
29755
|
+
"transport",
|
|
29756
|
+
"delivery receipt read could not reach the cloud service"
|
|
29757
|
+
);
|
|
29758
|
+
}
|
|
29759
|
+
let body;
|
|
29760
|
+
try {
|
|
29761
|
+
body = await Promise.race([response.json(), aborted]);
|
|
29762
|
+
} catch (error) {
|
|
29763
|
+
if (error instanceof SignalReadTimeoutError || signal.aborted) {
|
|
29764
|
+
throw new SignalReadTimeoutError("receipt read timed out");
|
|
29765
|
+
}
|
|
29766
|
+
throw new DeliveryReceiptReadError(
|
|
29767
|
+
"protocol",
|
|
29768
|
+
"delivery receipt read returned malformed JSON"
|
|
29769
|
+
);
|
|
29770
|
+
}
|
|
29771
|
+
if (!response.ok) {
|
|
29772
|
+
throw new DeliveryReceiptReadError(
|
|
29773
|
+
"http",
|
|
29774
|
+
`delivery receipt read failed (HTTP ${response.status})`,
|
|
29775
|
+
response.status
|
|
29776
|
+
);
|
|
29777
|
+
}
|
|
29778
|
+
const result = parseDeliveryReceiptResult(body);
|
|
29779
|
+
if (result.addressed === null) {
|
|
29780
|
+
throw new DeliveryReceiptReadError(
|
|
29781
|
+
"not_author",
|
|
29782
|
+
"delivery receipt read did not establish that this caller authored the signal"
|
|
29783
|
+
);
|
|
29784
|
+
}
|
|
29785
|
+
return { addressed: result.addressed, receipts: result.receipts };
|
|
29786
|
+
} finally {
|
|
29787
|
+
clearTimeout(timer2);
|
|
29788
|
+
signal.removeEventListener("abort", onAbort);
|
|
29789
|
+
}
|
|
29790
|
+
}
|
|
29791
|
+
|
|
29792
|
+
// src/cloud/receipts.ts
|
|
29793
|
+
function signalReceiptCliState(receipt, nowMs) {
|
|
29794
|
+
const state = deliveryReceiptState(receipt, nowMs);
|
|
29795
|
+
if (state === "enqueued") return "not_delivered";
|
|
29796
|
+
if (state === "leased") return "working";
|
|
29797
|
+
if (state === "delivered") return "delivered";
|
|
29798
|
+
return "finished";
|
|
29799
|
+
}
|
|
29800
|
+
function receiptCheckCommand(report) {
|
|
29801
|
+
return `cswarm receipt ${report.signalId} --workspace-id ${report.workspaceId}`;
|
|
29802
|
+
}
|
|
29803
|
+
function listenerStatusCommand(report, receipt) {
|
|
29804
|
+
return `cswarm listen status --workspace-id ${report.workspaceId} --principal-id ${receipt.recipient_agent_principal_id}`;
|
|
29805
|
+
}
|
|
29806
|
+
function newAskCommand(report, receipt) {
|
|
29807
|
+
return `cswarm ask "<question>" --to ${receipt.recipient_agent_principal_id} --workspace-id ${report.workspaceId}`;
|
|
29808
|
+
}
|
|
29809
|
+
function renderSignalReceiptReport(report, nowMs = Date.now()) {
|
|
29810
|
+
if (!report.addressed) {
|
|
29811
|
+
return [
|
|
29812
|
+
"This was a broadcast; no agent was addressed and none was woken.",
|
|
29813
|
+
`To wake an agent, send a new ask with: cswarm ask "<text>" --to <agent> --workspace-id ${report.workspaceId}`
|
|
29814
|
+
].join("\n");
|
|
29815
|
+
}
|
|
29816
|
+
const sections = report.receipts.map((receipt) => {
|
|
29817
|
+
const state = deliveryReceiptState(receipt, nowMs);
|
|
29818
|
+
if (state === "enqueued") {
|
|
29819
|
+
return [
|
|
29820
|
+
`Not yet delivered to agent ${receipt.recipient_agent_principal_id}. CommonSwarm accepted it ${relativeAge(receipt.enqueued_at, nowMs)}.`,
|
|
29821
|
+
`Ask the agent's operator to check its listener with: ${listenerStatusCommand(report, receipt)}`,
|
|
29822
|
+
`Then check again with: ${receiptCheckCommand(report)}`
|
|
29823
|
+
].join("\n");
|
|
29824
|
+
}
|
|
29825
|
+
if (state === "delivered") {
|
|
29826
|
+
return [
|
|
29827
|
+
`Delivered to agent ${receipt.recipient_agent_principal_id} ${relativeAge(receipt.delivered_at, nowMs)}, and the agent has not acted on it.`,
|
|
29828
|
+
`Check again with: ${receiptCheckCommand(report)}`
|
|
29829
|
+
].join("\n");
|
|
29830
|
+
}
|
|
29831
|
+
if (state === "leased") {
|
|
29832
|
+
return [
|
|
29833
|
+
`Agent ${receipt.recipient_agent_principal_id} is working on it right now; its current lease ${relativeExpiry(receipt.leased_until, nowMs)}.`,
|
|
29834
|
+
`Check for the outcome with: ${receiptCheckCommand(report)}`
|
|
29835
|
+
].join("\n");
|
|
29836
|
+
}
|
|
29837
|
+
const finished = `Agent ${receipt.recipient_agent_principal_id} finished with outcome ${state} ${relativeAge(receipt.acked_at, nowMs)}.`;
|
|
29838
|
+
if (state === "replied") {
|
|
29839
|
+
return [
|
|
29840
|
+
finished,
|
|
29841
|
+
`Read the reply with: cswarm inbox --workspace-id ${report.workspaceId} --include-stale`
|
|
29842
|
+
].join("\n");
|
|
29843
|
+
}
|
|
29844
|
+
if (state === "observed") {
|
|
29845
|
+
return [
|
|
29846
|
+
finished,
|
|
29847
|
+
"The agent acknowledged the signal without sending a reply.",
|
|
29848
|
+
`If you need an answer, send a new ask with: ${newAskCommand(report, receipt)}`
|
|
29849
|
+
].join("\n");
|
|
29850
|
+
}
|
|
29851
|
+
if (state === "expired") {
|
|
29852
|
+
return [
|
|
29853
|
+
finished,
|
|
29854
|
+
"The signal expired before the agent completed it.",
|
|
29855
|
+
`Send a new ask with: ${newAskCommand(report, receipt)}`
|
|
29856
|
+
].join("\n");
|
|
29857
|
+
}
|
|
29858
|
+
return [
|
|
29859
|
+
finished,
|
|
29860
|
+
`Delivery will not retry${receipt.last_error_code === null ? "." : `; the last error code was ${receipt.last_error_code}.`}`,
|
|
29861
|
+
`Ask the agent's operator to check its listener with: ${listenerStatusCommand(report, receipt)}`
|
|
29862
|
+
].join("\n");
|
|
29863
|
+
});
|
|
29864
|
+
return sections.join("\n\n");
|
|
29865
|
+
}
|
|
29866
|
+
function signalReceiptJsonPayload(report, nowMs = Date.now()) {
|
|
29867
|
+
return {
|
|
29868
|
+
workspace_id: report.workspaceId,
|
|
29869
|
+
signal_id: report.signalId,
|
|
29870
|
+
broadcast: !report.addressed,
|
|
29871
|
+
receipts: report.receipts.map((receipt) => ({
|
|
29872
|
+
recipient_agent_principal_id: receipt.recipient_agent_principal_id,
|
|
29873
|
+
state: signalReceiptCliState(receipt, nowMs),
|
|
29874
|
+
outcome: receipt.ack_outcome,
|
|
29875
|
+
enqueued_at: receipt.enqueued_at,
|
|
29876
|
+
delivered_at: receipt.delivered_at,
|
|
29877
|
+
leased_until: receipt.leased_until,
|
|
29878
|
+
acked_at: receipt.acked_at,
|
|
29879
|
+
attempt_count: receipt.attempt_count,
|
|
29880
|
+
lease_expiry_count: receipt.lease_expiry_count,
|
|
29881
|
+
last_error_code: receipt.last_error_code
|
|
29882
|
+
}))
|
|
29883
|
+
};
|
|
29884
|
+
}
|
|
29885
|
+
|
|
29574
29886
|
// src/host/opencode.ts
|
|
29575
29887
|
var import_node_child_process3 = require("node:child_process");
|
|
29576
29888
|
var import_node_crypto12 = require("node:crypto");
|
|
@@ -32160,7 +32472,7 @@ async function resolveBudgetAndPrompt(session, prompt, budget) {
|
|
|
32160
32472
|
}
|
|
32161
32473
|
|
|
32162
32474
|
// src/listener/engine.ts
|
|
32163
|
-
var
|
|
32475
|
+
var UUID_RE9 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
32164
32476
|
var TERMINAL_STATES = /* @__PURE__ */ new Set(["done", "expired", "failed"]);
|
|
32165
32477
|
var REPLY_MAX_CODE_UNITS = 2e3;
|
|
32166
32478
|
var TRUNCATION_SUFFIX = "\n[Reply truncated by CommonSwarm]";
|
|
@@ -32168,7 +32480,7 @@ var UNSAFE_CONTROLS_RE = /[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f-\u009f\u
|
|
|
32168
32480
|
var LISTENER_MAX_PROMPT_ATTEMPTS = 3;
|
|
32169
32481
|
var LISTENER_MAX_POST_ATTEMPTS = 5;
|
|
32170
32482
|
function listenerReplyCommandId(signalId, effectOrdinal = 0) {
|
|
32171
|
-
if (!
|
|
32483
|
+
if (!UUID_RE9.test(signalId)) {
|
|
32172
32484
|
throw new Error("listener signal id must be a UUID");
|
|
32173
32485
|
}
|
|
32174
32486
|
if (!Number.isSafeInteger(effectOrdinal) || effectOrdinal < 0) {
|
|
@@ -32632,7 +32944,7 @@ var import_node_crypto13 = require("node:crypto");
|
|
|
32632
32944
|
var import_node_os5 = require("node:os");
|
|
32633
32945
|
var import_node_path8 = require("node:path");
|
|
32634
32946
|
var import_node_util = require("node:util");
|
|
32635
|
-
var
|
|
32947
|
+
var UUID_RE10 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
32636
32948
|
var COMMAND_ID_RE2 = /^[A-Za-z0-9_-]{8,72}$/;
|
|
32637
32949
|
var MAX_EFFECT_BYTES = 1024 * 1024;
|
|
32638
32950
|
var STATES = /* @__PURE__ */ new Set([
|
|
@@ -32670,7 +32982,7 @@ function defaultListenerStateDirectory() {
|
|
|
32670
32982
|
return process.env.XDG_STATE_HOME ? (0, import_node_path8.join)(process.env.XDG_STATE_HOME, "cswarm", "listeners") : (0, import_node_path8.join)((0, import_node_os5.homedir)(), ".cswarm", "listeners");
|
|
32671
32983
|
}
|
|
32672
32984
|
function listenerInstanceKey(input) {
|
|
32673
|
-
if (!
|
|
32985
|
+
if (!UUID_RE10.test(input.workspaceId) || !UUID_RE10.test(input.principalId)) {
|
|
32674
32986
|
throw new Error("listener workspace and principal ids must be UUIDs");
|
|
32675
32987
|
}
|
|
32676
32988
|
if (!input.profileId || input.profileId.includes("\0")) {
|
|
@@ -32702,7 +33014,7 @@ function parseListenerEffectRecord(raw, expectedId) {
|
|
|
32702
33014
|
throw new Error("stored listener effect is malformed");
|
|
32703
33015
|
}
|
|
32704
33016
|
const row = value;
|
|
32705
|
-
if (typeof row.version !== "number" || row.version !== 1 && row.version !== 2 || typeof row.signalId !== "string" || row.signalId.toLowerCase() !== expectedId || !
|
|
33017
|
+
if (typeof row.version !== "number" || row.version !== 1 && row.version !== 2 || typeof row.signalId !== "string" || row.signalId.toLowerCase() !== expectedId || !UUID_RE10.test(row.signalId)) {
|
|
32706
33018
|
throw new Error("stored listener effect is malformed");
|
|
32707
33019
|
}
|
|
32708
33020
|
if (row.version === 1) {
|
|
@@ -32719,7 +33031,7 @@ function upcastV1Ask(row) {
|
|
|
32719
33031
|
if (row.effectOrdinal !== 0 || typeof row.commandId !== "string" || !COMMAND_ID_RE2.test(row.commandId) || typeof row.askBody !== "string" || row.askBody.length < 1 || typeof row.askUntil !== "string" || !Number.isFinite(Date.parse(row.askUntil)) || typeof row.senderOwnerRelation !== "string" || !RELATIONS.has(row.senderOwnerRelation) || typeof row.state !== "string" || !STATES.has(row.state) || !integer(row.promptAttempts) || !integer(row.postAttempts) || !nullableString(row.replyBody, 2e3) || typeof row.replyTruncated !== "boolean" || !nullableString(row.replySignalId, 64) || !nullableString(row.failureCode, 96) || typeof row.updatedAt !== "string" || !Number.isFinite(Date.parse(row.updatedAt))) {
|
|
32720
33032
|
throw new Error("stored listener effect is malformed");
|
|
32721
33033
|
}
|
|
32722
|
-
if (row.replySignalId !== null && !
|
|
33034
|
+
if (row.replySignalId !== null && !UUID_RE10.test(row.replySignalId)) {
|
|
32723
33035
|
throw new Error("stored listener effect is malformed");
|
|
32724
33036
|
}
|
|
32725
33037
|
return {
|
|
@@ -32758,7 +33070,7 @@ function parseV2Record(row) {
|
|
|
32758
33070
|
if (typeof row.commandId !== "string" || !COMMAND_ID_RE2.test(row.commandId) || row.state === "observed") {
|
|
32759
33071
|
throw new Error("stored listener effect is malformed");
|
|
32760
33072
|
}
|
|
32761
|
-
if (row.replySignalId !== null && !
|
|
33073
|
+
if (row.replySignalId !== null && !UUID_RE10.test(row.replySignalId)) {
|
|
32762
33074
|
throw new Error("stored listener effect is malformed");
|
|
32763
33075
|
}
|
|
32764
33076
|
}
|
|
@@ -32782,7 +33094,7 @@ function parseV2Record(row) {
|
|
|
32782
33094
|
};
|
|
32783
33095
|
}
|
|
32784
33096
|
function newObservedNoteRecord(input) {
|
|
32785
|
-
if (!
|
|
33097
|
+
if (!UUID_RE10.test(input.signalId)) {
|
|
32786
33098
|
throw new Error("listener note signal id must be a UUID");
|
|
32787
33099
|
}
|
|
32788
33100
|
if (input.body.length < 1) {
|
|
@@ -32916,7 +33228,7 @@ var FileListenerEffectStore = class {
|
|
|
32916
33228
|
);
|
|
32917
33229
|
}
|
|
32918
33230
|
checkedId(signalId) {
|
|
32919
|
-
if (!
|
|
33231
|
+
if (!UUID_RE10.test(signalId)) {
|
|
32920
33232
|
throw new Error("listener signal id must be a UUID");
|
|
32921
33233
|
}
|
|
32922
33234
|
return signalId.toLowerCase();
|
|
@@ -34007,7 +34319,7 @@ var CodexListenerModel = class {
|
|
|
34007
34319
|
var import_node_crypto17 = require("node:crypto");
|
|
34008
34320
|
|
|
34009
34321
|
// src/cloud/delivery.ts
|
|
34010
|
-
var
|
|
34322
|
+
var UUID_RE11 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
34011
34323
|
var RFC3339_TIMESTAMP_RE = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.\d+)?(?:Z|([+-]\d{2}):(\d{2}))$/i;
|
|
34012
34324
|
var DELIVERY_KINDS = /* @__PURE__ */ new Set(["ask", "note"]);
|
|
34013
34325
|
var SENDER_OWNER_RELATIONS2 = /* @__PURE__ */ new Set([
|
|
@@ -34089,7 +34401,7 @@ var DeliveryProtocolError = class extends Error {
|
|
|
34089
34401
|
}
|
|
34090
34402
|
};
|
|
34091
34403
|
function checkedUuid3(value, field) {
|
|
34092
|
-
if (typeof value !== "string" || !
|
|
34404
|
+
if (typeof value !== "string" || !UUID_RE11.test(value)) {
|
|
34093
34405
|
throw new DeliveryProtocolError(
|
|
34094
34406
|
`delivery response returned a malformed ${field}`
|
|
34095
34407
|
);
|
|
@@ -34200,7 +34512,7 @@ function checkedClaimCapabilities(value) {
|
|
|
34200
34512
|
}
|
|
34201
34513
|
function checkedOptionalUuidArray(value, field) {
|
|
34202
34514
|
if (value === void 0) return;
|
|
34203
|
-
if (!Array.isArray(value) || value.some((item) => typeof item !== "string" || !
|
|
34515
|
+
if (!Array.isArray(value) || value.some((item) => typeof item !== "string" || !UUID_RE11.test(item))) {
|
|
34204
34516
|
throw new DeliveryProtocolError(
|
|
34205
34517
|
`delivery response returned a malformed ${field}`
|
|
34206
34518
|
);
|
|
@@ -34347,7 +34659,7 @@ function checkedCommandId(value) {
|
|
|
34347
34659
|
return value;
|
|
34348
34660
|
}
|
|
34349
34661
|
function checkedUuidRequest(value, field) {
|
|
34350
|
-
if (!
|
|
34662
|
+
if (!UUID_RE11.test(value)) {
|
|
34351
34663
|
throw new Error(`${field} must be a UUID for an agent delivery command`);
|
|
34352
34664
|
}
|
|
34353
34665
|
}
|
|
@@ -34556,7 +34868,7 @@ var DeliveryCommandClient = class {
|
|
|
34556
34868
|
|
|
34557
34869
|
// src/listener/main-routing.ts
|
|
34558
34870
|
var import_node_path14 = require("node:path");
|
|
34559
|
-
var
|
|
34871
|
+
var UUID_RE12 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
34560
34872
|
var MAX_QUEUE_BYTES = 1024 * 1024;
|
|
34561
34873
|
var QUEUE_FILE = "pending-for-main.json";
|
|
34562
34874
|
var QUEUE_LOCK = "pending-for-main";
|
|
@@ -34610,7 +34922,7 @@ function parseEntry(value) {
|
|
|
34610
34922
|
if (Object.keys(row).some((key2) => !allowed.has(key2))) {
|
|
34611
34923
|
throw new Error("stored pending-for-main entry is malformed");
|
|
34612
34924
|
}
|
|
34613
|
-
if (typeof row.signalId !== "string" || !
|
|
34925
|
+
if (typeof row.signalId !== "string" || !UUID_RE12.test(row.signalId) || typeof row.workspaceId !== "string" || !UUID_RE12.test(row.workspaceId) || typeof row.principalId !== "string" || !UUID_RE12.test(row.principalId) || typeof row.fromId !== "string" || !UUID_RE12.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 || !checkedTimestamp2(row.createdAt) || !checkedTimestamp2(row.queuedAt)) {
|
|
34614
34926
|
throw new Error("stored pending-for-main entry is malformed");
|
|
34615
34927
|
}
|
|
34616
34928
|
return {
|
|
@@ -34746,7 +35058,7 @@ var LISTENER_REPLY_ONLY_MINIMUM_MS = SIGNAL_REQUEST_TIMEOUT_MS + LISTENER_ACK_ON
|
|
|
34746
35058
|
var LISTENER_PROMPT_START_MINIMUM_MS = SIGNAL_READ_TIMEOUT_MS + ACP_DEFAULT_REQUEST_TIMEOUT_MS + LISTENER_REPLY_ONLY_MINIMUM_MS;
|
|
34747
35059
|
var LISTENER_DELIVERY_RETRY_INITIAL_MS = 500;
|
|
34748
35060
|
var LISTENER_DELIVERY_RETRY_MAX_MS = 3e4;
|
|
34749
|
-
var
|
|
35061
|
+
var UUID_RE13 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
34750
35062
|
var ListenerCapabilityError = class extends Error {
|
|
34751
35063
|
code;
|
|
34752
35064
|
constructor(code, message) {
|
|
@@ -35021,7 +35333,7 @@ async function runListenerRuntime(options) {
|
|
|
35021
35333
|
new Error("listener instance id and delivery journal must be configured together")
|
|
35022
35334
|
);
|
|
35023
35335
|
}
|
|
35024
|
-
if (hasInstanceId && !
|
|
35336
|
+
if (hasInstanceId && !UUID_RE13.test(options.listenerInstanceId)) {
|
|
35025
35337
|
return await closeBeforeStart(
|
|
35026
35338
|
options.model,
|
|
35027
35339
|
new Error("listener instance id must be a UUID")
|
|
@@ -35844,7 +36156,7 @@ async function runListenerRuntime(options) {
|
|
|
35844
36156
|
var import_node_net = require("node:net");
|
|
35845
36157
|
var import_promises9 = require("node:fs/promises");
|
|
35846
36158
|
var import_node_path15 = require("node:path");
|
|
35847
|
-
var
|
|
36159
|
+
var UUID_RE14 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
35848
36160
|
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-]+)*)?$/;
|
|
35849
36161
|
var MAX_STATUS_BYTES = 16 * 1024;
|
|
35850
36162
|
var MAX_CONTROL_BYTES = 8 * 1024;
|
|
@@ -35950,10 +36262,10 @@ function parseStatus(raw) {
|
|
|
35950
36262
|
throw new Error("stored listener status is malformed");
|
|
35951
36263
|
}
|
|
35952
36264
|
}
|
|
35953
|
-
const nullableUuid2 = (candidate) => candidate === null || typeof candidate === "string" &&
|
|
36265
|
+
const nullableUuid2 = (candidate) => candidate === null || typeof candidate === "string" && UUID_RE14.test(candidate);
|
|
35954
36266
|
const nullableCount = (candidate) => candidate === null || typeof candidate === "number" && Number.isSafeInteger(candidate) && candidate >= 0;
|
|
35955
|
-
const
|
|
35956
|
-
if (row.version !== 1 || typeof row.instanceId !== "string" || !
|
|
36267
|
+
const nullableTimestamp2 = (candidate) => candidate === null || typeof candidate === "string" && Number.isFinite(Date.parse(candidate));
|
|
36268
|
+
if (row.version !== 1 || typeof row.instanceId !== "string" || !UUID_RE14.test(row.instanceId) || row.provider !== "grok" && row.provider !== "opencode" && row.provider !== "claude" && row.provider !== "codex" || typeof row.profileId !== "string" || typeof row.workspaceId !== "string" || !UUID_RE14.test(row.workspaceId) || typeof row.principalId !== "string" || !UUID_RE14.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))) || !nullableUuid2(row.lastSignalId) || !(row.lastErrorCode === null || typeof row.lastErrorCode === "string" && /^[a-z0-9_-]{1,96}$/.test(row.lastErrorCode)) || !(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.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_path15.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 || nullableTimestamp2(row.lastTerminalDeliveryFailureAt)) || !(row.lastClaimAt === void 0 || nullableTimestamp2(row.lastClaimAt)) || !(row.lastAckAt === void 0 || nullableTimestamp2(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)) {
|
|
35957
36269
|
throw new Error("stored listener status is malformed");
|
|
35958
36270
|
}
|
|
35959
36271
|
const routeMode = row.routeMode ?? "worker";
|
|
@@ -36302,7 +36614,7 @@ async function queryListenerControl(paths, command2, timeoutMs = CONTROL_TIMEOUT
|
|
|
36302
36614
|
|
|
36303
36615
|
// src/listener/supervisor.ts
|
|
36304
36616
|
var import_node_crypto18 = require("node:crypto");
|
|
36305
|
-
var
|
|
36617
|
+
var UUID_RE15 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
36306
36618
|
var LISTENER_RESTART_MAX_ATTEMPTS = 5;
|
|
36307
36619
|
var LISTENER_RESTART_INITIAL_MS = 1e3;
|
|
36308
36620
|
var LISTENER_RESTART_MAX_MS = 6e4;
|
|
@@ -36431,7 +36743,7 @@ async function runListenerSupervisor(options) {
|
|
|
36431
36743
|
// before the socket can answer, before any status/event persistence.
|
|
36432
36744
|
initialize: prepare ? async () => {
|
|
36433
36745
|
const selected = await prepare(proposedInstanceId);
|
|
36434
|
-
if (!selected || typeof selected !== "object" || typeof selected.instanceId !== "string" || !
|
|
36746
|
+
if (!selected || typeof selected !== "object" || typeof selected.instanceId !== "string" || !UUID_RE15.test(selected.instanceId)) {
|
|
36435
36747
|
throw new Error("listener prepare returned an invalid instance id");
|
|
36436
36748
|
}
|
|
36437
36749
|
status = { ...status, instanceId: selected.instanceId };
|
|
@@ -36789,7 +37101,7 @@ async function waitForListenerReady(paths, options = {}) {
|
|
|
36789
37101
|
// src/listener/delivery-journal.ts
|
|
36790
37102
|
var import_node_path16 = require("node:path");
|
|
36791
37103
|
var import_node_util2 = require("node:util");
|
|
36792
|
-
var
|
|
37104
|
+
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}$/;
|
|
36793
37105
|
var COMMAND_ID_RE3 = /^[A-Za-z0-9_-]{8,72}$/;
|
|
36794
37106
|
var SIGNAL_FINGERPRINT_RE = /^[0-9a-f]{64}$/;
|
|
36795
37107
|
var MAX_JOURNAL_BYTES = 8192;
|
|
@@ -36883,7 +37195,7 @@ var ALLOWED_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
|
36883
37195
|
"credential_unavailable"
|
|
36884
37196
|
]);
|
|
36885
37197
|
function claimCommandId(listenerInstanceId, claimOrdinal) {
|
|
36886
|
-
if (!
|
|
37198
|
+
if (!UUID_RE16.test(listenerInstanceId)) {
|
|
36887
37199
|
throw new Error("stored delivery journal is malformed");
|
|
36888
37200
|
}
|
|
36889
37201
|
if (!Number.isSafeInteger(claimOrdinal) || claimOrdinal < 0) {
|
|
@@ -36898,7 +37210,7 @@ function claimCommandId(listenerInstanceId, claimOrdinal) {
|
|
|
36898
37210
|
return id;
|
|
36899
37211
|
}
|
|
36900
37212
|
function ackCommandId(leaseId) {
|
|
36901
|
-
if (!
|
|
37213
|
+
if (!UUID_RE16.test(leaseId)) {
|
|
36902
37214
|
throw new Error("stored delivery journal is malformed");
|
|
36903
37215
|
}
|
|
36904
37216
|
const cleanLease = leaseId.toLowerCase().replace(/-/g, "");
|
|
@@ -36981,19 +37293,19 @@ function parseJournalRecord(raw, expectedWorkspaceId, expectedPrincipalId) {
|
|
|
36981
37293
|
if (row.version !== 1) {
|
|
36982
37294
|
throw new Error("stored delivery journal is malformed");
|
|
36983
37295
|
}
|
|
36984
|
-
if (typeof row.workspaceId !== "string" || !
|
|
37296
|
+
if (typeof row.workspaceId !== "string" || !UUID_RE16.test(row.workspaceId) || row.workspaceId !== row.workspaceId.toLowerCase()) {
|
|
36985
37297
|
throw new Error("stored delivery journal is malformed");
|
|
36986
37298
|
}
|
|
36987
37299
|
if (expectedWorkspaceId && row.workspaceId !== expectedWorkspaceId.toLowerCase()) {
|
|
36988
37300
|
throw new Error("stored delivery journal is malformed");
|
|
36989
37301
|
}
|
|
36990
|
-
if (typeof row.principalId !== "string" || !
|
|
37302
|
+
if (typeof row.principalId !== "string" || !UUID_RE16.test(row.principalId) || row.principalId !== row.principalId.toLowerCase()) {
|
|
36991
37303
|
throw new Error("stored delivery journal is malformed");
|
|
36992
37304
|
}
|
|
36993
37305
|
if (expectedPrincipalId && row.principalId !== expectedPrincipalId.toLowerCase()) {
|
|
36994
37306
|
throw new Error("stored delivery journal is malformed");
|
|
36995
37307
|
}
|
|
36996
|
-
if (typeof row.listenerInstanceId !== "string" || !
|
|
37308
|
+
if (typeof row.listenerInstanceId !== "string" || !UUID_RE16.test(row.listenerInstanceId) || row.listenerInstanceId !== row.listenerInstanceId.toLowerCase()) {
|
|
36997
37309
|
throw new Error("stored delivery journal is malformed");
|
|
36998
37310
|
}
|
|
36999
37311
|
if (!Number.isSafeInteger(row.nextClaimOrdinal) || row.nextClaimOrdinal < 0) {
|
|
@@ -37057,10 +37369,10 @@ function parseJournalRecord(raw, expectedWorkspaceId, expectedPrincipalId) {
|
|
|
37057
37369
|
if (active.claimLastAttemptAt === null) {
|
|
37058
37370
|
throw new Error("stored delivery journal is malformed");
|
|
37059
37371
|
}
|
|
37060
|
-
if (typeof active.signalId !== "string" || !
|
|
37372
|
+
if (typeof active.signalId !== "string" || !UUID_RE16.test(active.signalId) || active.signalId !== active.signalId.toLowerCase()) {
|
|
37061
37373
|
throw new Error("stored delivery journal is malformed");
|
|
37062
37374
|
}
|
|
37063
|
-
if (typeof active.leaseId !== "string" || !
|
|
37375
|
+
if (typeof active.leaseId !== "string" || !UUID_RE16.test(active.leaseId) || active.leaseId !== active.leaseId.toLowerCase()) {
|
|
37064
37376
|
throw new Error("stored delivery journal is malformed");
|
|
37065
37377
|
}
|
|
37066
37378
|
if (!isValidIsoTimestamp(active.leasedUntil) || Date.parse(active.leasedUntil) <= Date.parse(active.claimCreatedAt)) {
|
|
@@ -37132,7 +37444,7 @@ var FileListenerDeliveryJournal = class {
|
|
|
37132
37444
|
["profileId", "workspaceId", "principalId"],
|
|
37133
37445
|
"delivery journal configuration rejected"
|
|
37134
37446
|
);
|
|
37135
|
-
if (typeof options.profileId !== "string" || !options.profileId || options.profileId.includes("\0") || typeof options.workspaceId !== "string" || !
|
|
37447
|
+
if (typeof options.profileId !== "string" || !options.profileId || options.profileId.includes("\0") || typeof options.workspaceId !== "string" || !UUID_RE16.test(options.workspaceId) || typeof options.principalId !== "string" || !UUID_RE16.test(options.principalId)) {
|
|
37136
37448
|
throw new Error("delivery journal configuration rejected");
|
|
37137
37449
|
}
|
|
37138
37450
|
if (options.stateDirectory !== void 0) {
|
|
@@ -37253,7 +37565,7 @@ var FileListenerDeliveryJournal = class {
|
|
|
37253
37565
|
["signalId", "leaseId", "leasedUntil"],
|
|
37254
37566
|
"delivery journal mutation rejected"
|
|
37255
37567
|
);
|
|
37256
|
-
if (typeof input.signalId !== "string" || !
|
|
37568
|
+
if (typeof input.signalId !== "string" || !UUID_RE16.test(input.signalId) || typeof input.leaseId !== "string" || !UUID_RE16.test(input.leaseId) || !isValidIsoTimestamp(input.leasedUntil) || input.signalFingerprint !== void 0 && (typeof input.signalFingerprint !== "string" || !SIGNAL_FINGERPRINT_RE.test(input.signalFingerprint))) {
|
|
37257
37569
|
throw new Error("delivery journal mutation rejected");
|
|
37258
37570
|
}
|
|
37259
37571
|
const canonicalSignalId = input.signalId.toLowerCase();
|
|
@@ -37385,7 +37697,7 @@ async function openListenerDeliveryJournal(options) {
|
|
|
37385
37697
|
["profileId", "workspaceId", "principalId", "proposedListenerInstanceId"],
|
|
37386
37698
|
"delivery journal configuration rejected"
|
|
37387
37699
|
);
|
|
37388
|
-
if (typeof options.profileId !== "string" || !options.profileId || options.profileId.includes("\0") || typeof options.workspaceId !== "string" || !
|
|
37700
|
+
if (typeof options.profileId !== "string" || !options.profileId || options.profileId.includes("\0") || typeof options.workspaceId !== "string" || !UUID_RE16.test(options.workspaceId) || typeof options.principalId !== "string" || !UUID_RE16.test(options.principalId) || typeof options.proposedListenerInstanceId !== "string" || !UUID_RE16.test(options.proposedListenerInstanceId)) {
|
|
37389
37701
|
throw new Error("delivery journal configuration rejected");
|
|
37390
37702
|
}
|
|
37391
37703
|
if (options.stateDirectory !== void 0) {
|
|
@@ -37600,7 +37912,7 @@ async function spawnDetachedListener(options) {
|
|
|
37600
37912
|
// src/listener/hook.ts
|
|
37601
37913
|
var import_promises10 = require("node:fs/promises");
|
|
37602
37914
|
var import_node_path18 = require("node:path");
|
|
37603
|
-
var
|
|
37915
|
+
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;
|
|
37604
37916
|
var TOKEN_RE = /^swm_agt_[A-Za-z0-9_-]{43}$/;
|
|
37605
37917
|
var INSTANCE_KEY_RE = /^[0-9a-f]{64}$/;
|
|
37606
37918
|
var MAX_HOOK_CREDENTIAL_BYTES = 8 * 1024;
|
|
@@ -37641,7 +37953,7 @@ function parseListenerCredential(raw) {
|
|
|
37641
37953
|
"principalId",
|
|
37642
37954
|
"credential",
|
|
37643
37955
|
"updatedAt"
|
|
37644
|
-
]) || 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" || !
|
|
37956
|
+
]) || 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_RE17.test(row.workspaceId) || typeof row.principalId !== "string" || !UUID_RE17.test(row.principalId) || typeof row.credential !== "string" || !TOKEN_RE.test(row.credential) || typeof row.updatedAt !== "string" || !Number.isFinite(Date.parse(row.updatedAt))) {
|
|
37645
37957
|
throw new Error("stored listener hook credential is malformed");
|
|
37646
37958
|
}
|
|
37647
37959
|
const target2 = cloudTarget(row.targetUrl, row.anonKey);
|
|
@@ -37701,7 +38013,7 @@ function parseSurface(raw) {
|
|
|
37701
38013
|
const row = value;
|
|
37702
38014
|
if (Object.keys(row).some(
|
|
37703
38015
|
(key2) => key2 !== "version" && key2 !== "surfacedSignalIds" && key2 !== "reportedDroppedCount" && key2 !== "credentialFailureReported"
|
|
37704
|
-
) || row.version !== 1 || !Array.isArray(row.surfacedSignalIds) || row.surfacedSignalIds.length > HOOK_SURFACED_IDS_MAX || row.surfacedSignalIds.some((id) => typeof id !== "string" || !
|
|
38016
|
+
) || row.version !== 1 || !Array.isArray(row.surfacedSignalIds) || row.surfacedSignalIds.length > HOOK_SURFACED_IDS_MAX || row.surfacedSignalIds.some((id) => typeof id !== "string" || !UUID_RE17.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")) {
|
|
37705
38017
|
throw new Error("stored listener hook surface state is malformed");
|
|
37706
38018
|
}
|
|
37707
38019
|
const ids = row.surfacedSignalIds.map((id) => String(id).toLowerCase());
|
|
@@ -37738,7 +38050,7 @@ var FileHookSurfaceStore = class {
|
|
|
37738
38050
|
const unseen = [];
|
|
37739
38051
|
for (const item of items) {
|
|
37740
38052
|
const signalId = item.signalId.toLowerCase();
|
|
37741
|
-
if (!
|
|
38053
|
+
if (!UUID_RE17.test(signalId) || seen.has(signalId)) continue;
|
|
37742
38054
|
seen.add(signalId);
|
|
37743
38055
|
unseen.push(item);
|
|
37744
38056
|
}
|
|
@@ -37761,7 +38073,7 @@ var FileHookSurfaceStore = class {
|
|
|
37761
38073
|
const seen = new Set(state.surfacedSignalIds);
|
|
37762
38074
|
for (const signalId of options.signalIds ?? []) {
|
|
37763
38075
|
const checked = signalId.toLowerCase();
|
|
37764
|
-
if (
|
|
38076
|
+
if (UUID_RE17.test(checked)) seen.add(checked);
|
|
37765
38077
|
}
|
|
37766
38078
|
await writeSecureJsonFile(
|
|
37767
38079
|
this.path,
|
|
@@ -37864,7 +38176,17 @@ async function discoverContexts(stateDirectory2, isListenerLive = listenerIsLive
|
|
|
37864
38176
|
instanceDirectory
|
|
37865
38177
|
);
|
|
37866
38178
|
const statusIsLive = storedStatus === null ? null : await isListenerLive(storedStatus);
|
|
37867
|
-
if (statusIsLive === false)
|
|
38179
|
+
if (statusIsLive === false) {
|
|
38180
|
+
contexts.push({
|
|
38181
|
+
instanceDirectory,
|
|
38182
|
+
paths: storedStatus.paths,
|
|
38183
|
+
status: storedStatus.status,
|
|
38184
|
+
listenerLive: false,
|
|
38185
|
+
credential: null,
|
|
38186
|
+
credentialReadFailed: false
|
|
38187
|
+
});
|
|
38188
|
+
continue;
|
|
38189
|
+
}
|
|
37868
38190
|
await deleteSecureJsonFile(
|
|
37869
38191
|
(0, import_node_path18.join)(instanceDirectory, RETIRED_HOOK_CREDENTIAL_FILE)
|
|
37870
38192
|
).catch(() => void 0);
|
|
@@ -37874,6 +38196,7 @@ async function discoverContexts(stateDirectory2, isListenerLive = listenerIsLive
|
|
|
37874
38196
|
instanceDirectory,
|
|
37875
38197
|
paths: storedStatus?.paths ?? null,
|
|
37876
38198
|
status: storedStatus?.status ?? null,
|
|
38199
|
+
listenerLive: statusIsLive,
|
|
37877
38200
|
credential,
|
|
37878
38201
|
credentialReadFailed: credential === null && storedStatus !== null
|
|
37879
38202
|
});
|
|
@@ -37883,6 +38206,7 @@ async function discoverContexts(stateDirectory2, isListenerLive = listenerIsLive
|
|
|
37883
38206
|
instanceDirectory,
|
|
37884
38207
|
paths: storedStatus.paths,
|
|
37885
38208
|
status: storedStatus.status,
|
|
38209
|
+
listenerLive: statusIsLive,
|
|
37886
38210
|
credential: null,
|
|
37887
38211
|
credentialReadFailed: true
|
|
37888
38212
|
});
|
|
@@ -37923,6 +38247,24 @@ function renderHookSignal(item) {
|
|
|
37923
38247
|
`${replyLabel} cswarm reply ${item.signalId} "<answer>" --workspace-id ${item.workspaceId}`
|
|
37924
38248
|
].join("\n");
|
|
37925
38249
|
}
|
|
38250
|
+
function listenerRestartCommand(status) {
|
|
38251
|
+
const routeMode = status.routeMode ?? "worker";
|
|
38252
|
+
return [
|
|
38253
|
+
"cswarm listen start",
|
|
38254
|
+
"--agent-token-stdin",
|
|
38255
|
+
`--workspace-id ${status.workspaceId}`,
|
|
38256
|
+
`--provider ${status.provider}`,
|
|
38257
|
+
...status.permissionMode ? [`--permissions ${status.permissionMode}`] : [],
|
|
38258
|
+
`--route ${routeMode}`,
|
|
38259
|
+
...routeMode === "split" && status.deferOverChars !== null && status.deferOverChars !== void 0 ? [`--defer-over ${status.deferOverChars}`] : []
|
|
38260
|
+
].join(" ");
|
|
38261
|
+
}
|
|
38262
|
+
function renderStrandedQueue(context, count2) {
|
|
38263
|
+
const status = context.status;
|
|
38264
|
+
const noun = count2 === 1 ? "message" : "messages";
|
|
38265
|
+
const verb = count2 === 1 ? "was" : "were";
|
|
38266
|
+
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);
|
|
38267
|
+
}
|
|
37926
38268
|
async function inboxItems(context, options) {
|
|
37927
38269
|
const stored = context.credential;
|
|
37928
38270
|
const target2 = cloudTarget(stored.targetUrl, stored.anonKey);
|
|
@@ -37982,11 +38324,11 @@ async function checkListenerHooks(options) {
|
|
|
37982
38324
|
options.isListenerLive ?? listenerIsLive
|
|
37983
38325
|
);
|
|
37984
38326
|
if (contexts.length === 0) return "";
|
|
37985
|
-
const networkAllowed = await reserveCheck(
|
|
38327
|
+
const networkAllowed = contexts.some((context) => context.listenerLive !== false) ? await reserveCheck(
|
|
37986
38328
|
stateDirectory2,
|
|
37987
38329
|
cooldownSeconds * 1e3,
|
|
37988
38330
|
now()
|
|
37989
|
-
);
|
|
38331
|
+
) : false;
|
|
37990
38332
|
const checks = await Promise.all(contexts.map(async (context) => {
|
|
37991
38333
|
const queue = new FilePendingMainQueue(context.instanceDirectory);
|
|
37992
38334
|
const pending = await queue.read();
|
|
@@ -38011,7 +38353,7 @@ async function checkListenerHooks(options) {
|
|
|
38011
38353
|
context,
|
|
38012
38354
|
queue,
|
|
38013
38355
|
pending,
|
|
38014
|
-
droppedCount: stats.droppedCount,
|
|
38356
|
+
droppedCount: context.listenerLive === false ? 0 : stats.droppedCount,
|
|
38015
38357
|
network,
|
|
38016
38358
|
credentialFailure,
|
|
38017
38359
|
credentialHealthy
|
|
@@ -38027,6 +38369,11 @@ async function checkListenerHooks(options) {
|
|
|
38027
38369
|
check.droppedCount
|
|
38028
38370
|
);
|
|
38029
38371
|
blocks.push(...staged.unseen.map(renderHookSignal));
|
|
38372
|
+
const pendingSignalIds = new Set(check.pending.map((entry) => entry.signalId));
|
|
38373
|
+
const unseenPending = staged.unseen.filter((item) => pendingSignalIds.has(item.signalId));
|
|
38374
|
+
if (check.context.listenerLive === false && unseenPending.length > 0) {
|
|
38375
|
+
blocks.push(renderStrandedQueue(check.context, unseenPending.length));
|
|
38376
|
+
}
|
|
38030
38377
|
const reportDrops = staged.droppedSinceLastCheck > 0;
|
|
38031
38378
|
if (reportDrops) blocks.push(renderDroppedAsks(staged.droppedSinceLastCheck));
|
|
38032
38379
|
const reportCredentialFailure = check.credentialFailure !== null && !staged.credentialFailureReported;
|
|
@@ -38037,12 +38384,14 @@ async function checkListenerHooks(options) {
|
|
|
38037
38384
|
blocks.push(warning);
|
|
38038
38385
|
}
|
|
38039
38386
|
}
|
|
38040
|
-
const pendingSignalIds = new Set(check.pending.map((entry) => entry.signalId));
|
|
38041
38387
|
commits.push({
|
|
38042
38388
|
check,
|
|
38043
38389
|
store: store2,
|
|
38044
38390
|
signalIds: staged.unseen.map((item) => item.signalId),
|
|
38045
|
-
|
|
38391
|
+
// Every staged queue entry is either written by this run or was committed
|
|
38392
|
+
// after an earlier successful write. Removing both keeps the queue bounded
|
|
38393
|
+
// without re-printing entries below the exactly-once high-water.
|
|
38394
|
+
settledPendingSignalIds: check.pending.map((item) => item.signalId),
|
|
38046
38395
|
reportDrops,
|
|
38047
38396
|
reportCredentialFailure
|
|
38048
38397
|
});
|
|
@@ -38056,7 +38405,7 @@ async function checkListenerHooks(options) {
|
|
|
38056
38405
|
...commit.reportCredentialFailure ? { credentialFailureReported: true } : commit.check.credentialHealthy ? { credentialFailureReported: false } : {}
|
|
38057
38406
|
});
|
|
38058
38407
|
const remainingCount = await commit.check.queue.remove(
|
|
38059
|
-
new Set(commit.
|
|
38408
|
+
new Set(commit.settledPendingSignalIds),
|
|
38060
38409
|
HOOK_LOCK_TIMEOUT_MS
|
|
38061
38410
|
);
|
|
38062
38411
|
if (commit.check.context.paths !== null && commit.check.context.status !== null) {
|
|
@@ -38181,7 +38530,7 @@ var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
|
|
|
38181
38530
|
"reveal-anon-key",
|
|
38182
38531
|
"write"
|
|
38183
38532
|
]);
|
|
38184
|
-
var
|
|
38533
|
+
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;
|
|
38185
38534
|
var AGENT_CREDENTIAL_MESSAGE = "Agent credential minted. It is bound to this task and run so the agent's work stays scoped and attributable.";
|
|
38186
38535
|
var AGENT_CREDENTIAL_MESSAGE_D088 = "Agent credential minted. It is bound to this run, so the agent's work is attributable to it.";
|
|
38187
38536
|
var ACCEPTED_AGENT_CREDENTIAL_MESSAGES = [
|
|
@@ -38189,8 +38538,8 @@ var ACCEPTED_AGENT_CREDENTIAL_MESSAGES = [
|
|
|
38189
38538
|
AGENT_CREDENTIAL_MESSAGE_D088
|
|
38190
38539
|
];
|
|
38191
38540
|
function packageVersion() {
|
|
38192
|
-
if ("0.1.
|
|
38193
|
-
return "0.1.
|
|
38541
|
+
if ("0.1.32".length > 0) {
|
|
38542
|
+
return "0.1.32";
|
|
38194
38543
|
}
|
|
38195
38544
|
try {
|
|
38196
38545
|
const value = JSON.parse(
|
|
@@ -38309,6 +38658,7 @@ Usage:
|
|
|
38309
38658
|
cswarm note "<text>" [--url <url> --anon-key <key>] [--workspace-id <uuid>] [--to <member|agent>] [--about <ref>] [--until <dur>] [--json] # text: 1..8000 characters
|
|
38310
38659
|
cswarm ask "<text>" [--url <url> --anon-key <key>] [--workspace-id <uuid>] [--to <member|agent>] [--about <ref>] [--until <dur>] [--wait <seconds>] [--json] # text: 1..8000 characters
|
|
38311
38660
|
cswarm reply <signal-id> "<text>" [--url <url> --anon-key <key>] [--workspace-id <uuid>] [--until <dur>] [--json]
|
|
38661
|
+
cswarm receipt <signal-id> --agent-token-stdin [--url <url> --anon-key <key>] --workspace-id <uuid> [--json]
|
|
38312
38662
|
cswarm feed [--url <url> --anon-key <key>] [--workspace-id <uuid>] [--about <ref>] [--kind <kind>] [--since <timestamp>] [--limit <n>] [--include-stale] [--json]
|
|
38313
38663
|
cswarm inbox [--url <url> --anon-key <key>] [--workspace-id <uuid>] [--kind <kind>] [--about <ref>] [--since <timestamp>] [--limit <n>] [--include-stale] [--wait <seconds>] [--json]
|
|
38314
38664
|
cswarm inbox --follow --ndjson [--url <url> --anon-key <key>] [--workspace-id <uuid>] [--kind <kind>] [--about <ref>] [--since <timestamp>] [--limit <n>] [--include-stale]
|
|
@@ -38355,6 +38705,7 @@ Credential selection for command/dogfood:
|
|
|
38355
38705
|
One that persists or references the credential needs the complete
|
|
38356
38706
|
JSON artifact, because it needs a field a bare secret does not carry:
|
|
38357
38707
|
members reads only -- either form
|
|
38708
|
+
receipt reads only -- either form
|
|
38358
38709
|
file put, file ls, file get, file rm, file restore
|
|
38359
38710
|
read and command, nothing persisted -- either form
|
|
38360
38711
|
feedback command only, nothing persisted -- either form
|
|
@@ -38524,7 +38875,7 @@ function parsedAgentCredential(value) {
|
|
|
38524
38875
|
const withExpiry = [...requiredKeys, "expires_at"].sort();
|
|
38525
38876
|
const actualKeys = Object.keys(artifact).sort();
|
|
38526
38877
|
const shape = actualKeys.length === requiredKeys.length ? requiredKeys : withExpiry;
|
|
38527
|
-
if (actualKeys.length !== shape.length || !actualKeys.every((key2, index) => key2 === shape[index]) || !ACCEPTED_AGENT_CREDENTIAL_MESSAGES.includes(artifact.message) || artifact.status !== "accepted" || typeof artifact.principal_id !== "string" || !
|
|
38878
|
+
if (actualKeys.length !== shape.length || !actualKeys.every((key2, index) => key2 === shape[index]) || !ACCEPTED_AGENT_CREDENTIAL_MESSAGES.includes(artifact.message) || artifact.status !== "accepted" || typeof artifact.principal_id !== "string" || !UUID_RE18.test(artifact.principal_id) || typeof artifact.token_id !== "string" || !UUID_RE18.test(artifact.token_id) || typeof artifact.run_id !== "string" || !UUID_RE18.test(artifact.run_id) || typeof artifact.agent_token !== "string") {
|
|
38528
38879
|
throw new Error("agent credential JSON is malformed");
|
|
38529
38880
|
}
|
|
38530
38881
|
let expiresAt = null;
|
|
@@ -38641,7 +38992,7 @@ async function workspaceId(args, cloud, human, options = {}) {
|
|
|
38641
38992
|
warn: options.warn ?? writeWorkspaceWarning
|
|
38642
38993
|
});
|
|
38643
38994
|
}
|
|
38644
|
-
function
|
|
38995
|
+
function uuid4(value, field) {
|
|
38645
38996
|
if (value === void 0 || !/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value)) {
|
|
38646
38997
|
throw new Error(`server returned a malformed ${field}`);
|
|
38647
38998
|
}
|
|
@@ -38746,7 +39097,7 @@ async function runNew(args) {
|
|
|
38746
39097
|
throw error;
|
|
38747
39098
|
}
|
|
38748
39099
|
const response = acceptedConnect("workspace creation", result);
|
|
38749
|
-
const created =
|
|
39100
|
+
const created = uuid4(response.workspace_id, "workspace_id");
|
|
38750
39101
|
if (created !== proposedId) {
|
|
38751
39102
|
throw new Error(
|
|
38752
39103
|
"the server confirmed a different workspace than this command created; run cswarm workspaces before doing anything else"
|
|
@@ -38762,7 +39113,7 @@ async function runNew(args) {
|
|
|
38762
39113
|
project: {
|
|
38763
39114
|
workspace_id: created,
|
|
38764
39115
|
name,
|
|
38765
|
-
stream_id: typeof response.stream_id === "string" &&
|
|
39116
|
+
stream_id: typeof response.stream_id === "string" && UUID_RE18.test(response.stream_id) ? response.stream_id : null
|
|
38766
39117
|
}
|
|
38767
39118
|
});
|
|
38768
39119
|
return;
|
|
@@ -39019,7 +39370,7 @@ async function runInvite(args) {
|
|
|
39019
39370
|
);
|
|
39020
39371
|
}
|
|
39021
39372
|
assertInvitationToken(response.invitation_token);
|
|
39022
|
-
const responseWorkspaceId =
|
|
39373
|
+
const responseWorkspaceId = uuid4(response.workspace_id, "workspace_id");
|
|
39023
39374
|
if (typeof response.workspace_name !== "string" || typeof response.inviter_display_name !== "string") {
|
|
39024
39375
|
throw new Error(
|
|
39025
39376
|
"the invitation was created without its fresh display labels; run invite again to issue a complete link"
|
|
@@ -39039,7 +39390,7 @@ async function runInvite(args) {
|
|
|
39039
39390
|
printJson({
|
|
39040
39391
|
message: "Invitation created. Share the one-time link below with its intended recipient. It can be accepted once before it expires; use a GitHub account with a distinct verified email for a second person.",
|
|
39041
39392
|
status: response.status,
|
|
39042
|
-
invitation_id:
|
|
39393
|
+
invitation_id: uuid4(response.invitation_id, "invitation_id"),
|
|
39043
39394
|
invite_link: inviteLink
|
|
39044
39395
|
});
|
|
39045
39396
|
}
|
|
@@ -39151,7 +39502,7 @@ async function runLegacyAccept(args) {
|
|
|
39151
39502
|
{ kind: "accept_invitation", token: invitationToken }
|
|
39152
39503
|
)
|
|
39153
39504
|
);
|
|
39154
|
-
const acceptedWorkspace =
|
|
39505
|
+
const acceptedWorkspace = uuid4(response.workspace_id, "workspace_id");
|
|
39155
39506
|
await writeWorkspaceDefault(human.store, human.userId, acceptedWorkspace);
|
|
39156
39507
|
await writeCurrentTarget(cloud);
|
|
39157
39508
|
printJson({
|
|
@@ -39297,7 +39648,7 @@ async function runPrincipal(args) {
|
|
|
39297
39648
|
"Agent identity created. It makes this machine's agent auditable inside the shared workspace. Its name is visible to everyone in the workspace, so avoid naming it after anything private."
|
|
39298
39649
|
),
|
|
39299
39650
|
status: response.status,
|
|
39300
|
-
principal_id:
|
|
39651
|
+
principal_id: uuid4(response.principal_id, "principal_id")
|
|
39301
39652
|
});
|
|
39302
39653
|
return;
|
|
39303
39654
|
}
|
|
@@ -39405,8 +39756,8 @@ async function runToken(args) {
|
|
|
39405
39756
|
);
|
|
39406
39757
|
printJson(agentCredentialArtifact({
|
|
39407
39758
|
principalId,
|
|
39408
|
-
tokenId:
|
|
39409
|
-
runId:
|
|
39759
|
+
tokenId: uuid4(response.token_id, "token_id"),
|
|
39760
|
+
runId: uuid4(response.run_id, "run_id"),
|
|
39410
39761
|
token: response.agent_token,
|
|
39411
39762
|
expiresAt
|
|
39412
39763
|
}));
|
|
@@ -39536,7 +39887,7 @@ async function runLinkNew(args) {
|
|
|
39536
39887
|
2
|
|
39537
39888
|
);
|
|
39538
39889
|
const taskId = args.required("task-id");
|
|
39539
|
-
if (!
|
|
39890
|
+
if (!UUID_RE18.test(taskId)) {
|
|
39540
39891
|
throw new Error("--task-id must be the work item's UUID");
|
|
39541
39892
|
}
|
|
39542
39893
|
const site = capabilitySiteOrigin(
|
|
@@ -39566,11 +39917,11 @@ async function runLinkNew(args) {
|
|
|
39566
39917
|
);
|
|
39567
39918
|
if (response.capability_token === void 0) {
|
|
39568
39919
|
throw new Error(
|
|
39569
|
-
`this link was created on a prior attempt, and its credential is shown only in a fresh response \u2014 the server keeps just a hash, so it cannot be shown again; run cswarm link new to issue another, then run cswarm link revoke --capability-id ${
|
|
39920
|
+
`this link was created on a prior attempt, and its credential is shown only in a fresh response \u2014 the server keeps just a hash, so it cannot be shown again; run cswarm link new to issue another, then run cswarm link revoke --capability-id ${uuid4(response.capability_id, "capability_id")} to withdraw the one you cannot see`
|
|
39570
39921
|
);
|
|
39571
39922
|
}
|
|
39572
39923
|
assertCapabilityToken(response.capability_token);
|
|
39573
|
-
const capabilityId =
|
|
39924
|
+
const capabilityId = uuid4(response.capability_id, "capability_id");
|
|
39574
39925
|
const expiresAt = capabilityTimestamp(response.expires_at, "expires_at");
|
|
39575
39926
|
const url = capabilityUrl(site, response.capability_token);
|
|
39576
39927
|
if (args.has("json")) {
|
|
@@ -39596,7 +39947,7 @@ async function runLinkRevoke(args) {
|
|
|
39596
39947
|
2
|
|
39597
39948
|
);
|
|
39598
39949
|
const capabilityId = args.required("capability-id");
|
|
39599
|
-
if (!
|
|
39950
|
+
if (!UUID_RE18.test(capabilityId)) {
|
|
39600
39951
|
throw new Error(
|
|
39601
39952
|
"--capability-id must be the id printed when the link was created"
|
|
39602
39953
|
);
|
|
@@ -39614,7 +39965,7 @@ async function runLinkRevoke(args) {
|
|
|
39614
39965
|
{ kind: "revoke_capability_url", capability_id: capabilityId }
|
|
39615
39966
|
)
|
|
39616
39967
|
);
|
|
39617
|
-
const revoked =
|
|
39968
|
+
const revoked = uuid4(response.capability_id, "capability_id");
|
|
39618
39969
|
const revokedAt = capabilityTimestamp(response.revoked_at, "revoked_at");
|
|
39619
39970
|
const message = renderCapabilityRevoke(revoked, revokedAt);
|
|
39620
39971
|
if (args.has("json")) {
|
|
@@ -40175,7 +40526,7 @@ async function runReply(args) {
|
|
|
40175
40526
|
"json"
|
|
40176
40527
|
], 3);
|
|
40177
40528
|
const signalId = args.positionals[1];
|
|
40178
|
-
if (signalId === void 0 || !
|
|
40529
|
+
if (signalId === void 0 || !UUID_RE18.test(signalId)) {
|
|
40179
40530
|
throw new Error("reply requires the signal UUID being answered");
|
|
40180
40531
|
}
|
|
40181
40532
|
const body = args.positionals[2];
|
|
@@ -40405,6 +40756,52 @@ async function runSignalRead(args, inbox) {
|
|
|
40405
40756
|
})}
|
|
40406
40757
|
`);
|
|
40407
40758
|
}
|
|
40759
|
+
async function runReceipt(args) {
|
|
40760
|
+
args.assertShape([
|
|
40761
|
+
...TARGET_FLAGS,
|
|
40762
|
+
"workspace-id",
|
|
40763
|
+
...CREDENTIAL_FLAGS,
|
|
40764
|
+
"json"
|
|
40765
|
+
], 2);
|
|
40766
|
+
const signalId = args.positionals[1];
|
|
40767
|
+
if (!UUID_RE18.test(signalId)) {
|
|
40768
|
+
throw new Error("signal-id must be a UUID");
|
|
40769
|
+
}
|
|
40770
|
+
if (!args.has("agent-token-stdin")) {
|
|
40771
|
+
throw new Error(
|
|
40772
|
+
"receipt reads signals sent by an agent; provide --agent-token-stdin and --workspace-id"
|
|
40773
|
+
);
|
|
40774
|
+
}
|
|
40775
|
+
const cloud = await target(args);
|
|
40776
|
+
const selected = await commandWorkspaceAndCredential(args, cloud, {
|
|
40777
|
+
validateHumanWorkspace: true
|
|
40778
|
+
});
|
|
40779
|
+
let result;
|
|
40780
|
+
try {
|
|
40781
|
+
result = await readAgentDeliveryReceipts(
|
|
40782
|
+
cloud,
|
|
40783
|
+
selected.bearer,
|
|
40784
|
+
selected.selectedWorkspace,
|
|
40785
|
+
signalId
|
|
40786
|
+
);
|
|
40787
|
+
} catch (error) {
|
|
40788
|
+
const reason = error instanceof SignalReadTimeoutError ? `the read reached its ${SIGNAL_READ_TIMEOUT_MS / 1e3}-second deadline` : error instanceof DeliveryReceiptReadError && error.status !== null ? `the read service refused it with HTTP ${error.status}` : error instanceof DeliveryReceiptReadError && error.code === "not_author" ? "the service could not verify that this agent sent the signal" : error instanceof DeliveryReceiptReadError && error.code === "protocol" ? "the read service returned an invalid receipt response" : "the read service could not be reached";
|
|
40789
|
+
throw new Error(
|
|
40790
|
+
`Delivery receipt lookup failed because ${reason}. No delivery state was shown, so do not treat this signal as pending, delivered, or failed. Retry with: cswarm receipt ${signalId.toLowerCase()} --workspace-id ${selected.selectedWorkspace}`
|
|
40791
|
+
);
|
|
40792
|
+
}
|
|
40793
|
+
const report = {
|
|
40794
|
+
...result,
|
|
40795
|
+
workspaceId: selected.selectedWorkspace,
|
|
40796
|
+
signalId: signalId.toLowerCase()
|
|
40797
|
+
};
|
|
40798
|
+
if (args.has("json")) {
|
|
40799
|
+
printJson(signalReceiptJsonPayload(report));
|
|
40800
|
+
return;
|
|
40801
|
+
}
|
|
40802
|
+
process.stdout.write(`${renderSignalReceiptReport(report)}
|
|
40803
|
+
`);
|
|
40804
|
+
}
|
|
40408
40805
|
async function runInboxFollowCommand(args) {
|
|
40409
40806
|
const cloud = await target(args);
|
|
40410
40807
|
const selected = await commandWorkspaceAndCredential(args, cloud, {
|
|
@@ -40505,7 +40902,7 @@ async function runInboxFollowCommand(args) {
|
|
|
40505
40902
|
}
|
|
40506
40903
|
}
|
|
40507
40904
|
function listenerUuid(value, flag) {
|
|
40508
|
-
if (!value || !
|
|
40905
|
+
if (!value || !UUID_RE18.test(value)) {
|
|
40509
40906
|
throw new Error(`--${flag} must be a UUID`);
|
|
40510
40907
|
}
|
|
40511
40908
|
return value.toLowerCase();
|
|
@@ -40741,7 +41138,7 @@ function renderListenerStatus(status) {
|
|
|
40741
41138
|
}
|
|
40742
41139
|
if (pendingForMainCount > 0) {
|
|
40743
41140
|
lines.push(
|
|
40744
|
-
`${pendingForMainCount} asks waiting for this session; they surface at your next prompt, or run cswarm hook check.`
|
|
41141
|
+
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.`
|
|
40745
41142
|
);
|
|
40746
41143
|
}
|
|
40747
41144
|
}
|
|
@@ -40757,6 +41154,20 @@ function renderListenerStatus(status) {
|
|
|
40757
41154
|
}
|
|
40758
41155
|
return lines.join("\n");
|
|
40759
41156
|
}
|
|
41157
|
+
async function unsurfacedPendingMainStats(instanceDirectory, fallback) {
|
|
41158
|
+
try {
|
|
41159
|
+
const queue = new FilePendingMainQueue(instanceDirectory);
|
|
41160
|
+
const pending = await queue.read();
|
|
41161
|
+
const stats = await queue.stats();
|
|
41162
|
+
const staged = await new FileHookSurfaceStore(instanceDirectory).stage(
|
|
41163
|
+
pending,
|
|
41164
|
+
stats.droppedCount
|
|
41165
|
+
);
|
|
41166
|
+
return { count: staged.unseen.length, droppedCount: stats.droppedCount };
|
|
41167
|
+
} catch {
|
|
41168
|
+
return fallback;
|
|
41169
|
+
}
|
|
41170
|
+
}
|
|
40760
41171
|
function listenerFailureMessage(code, provider) {
|
|
40761
41172
|
if (code === "version_below_floor") {
|
|
40762
41173
|
if (provider === "codex") {
|
|
@@ -41231,9 +41642,10 @@ async function runListenStart(args) {
|
|
|
41231
41642
|
if ((status.routeMode ?? "worker") !== "worker") {
|
|
41232
41643
|
const recordedPending = status.pendingForMainCount ?? 0;
|
|
41233
41644
|
const recordedDropped = status.droppedForMainCount ?? 0;
|
|
41234
|
-
const queueStats = await
|
|
41235
|
-
paths.instanceDirectory
|
|
41236
|
-
|
|
41645
|
+
const queueStats = await unsurfacedPendingMainStats(
|
|
41646
|
+
paths.instanceDirectory,
|
|
41647
|
+
{ count: recordedPending, droppedCount: recordedDropped }
|
|
41648
|
+
);
|
|
41237
41649
|
status = {
|
|
41238
41650
|
...status,
|
|
41239
41651
|
pendingForMainCount: queueStats.count,
|
|
@@ -41348,9 +41760,10 @@ async function runListenStatusOrStop(args, command2) {
|
|
|
41348
41760
|
if ((status.routeMode ?? "worker") !== "worker") {
|
|
41349
41761
|
const recordedPending = status.pendingForMainCount ?? 0;
|
|
41350
41762
|
const recordedDropped = status.droppedForMainCount ?? 0;
|
|
41351
|
-
const queueStats = await
|
|
41352
|
-
paths.instanceDirectory
|
|
41353
|
-
|
|
41763
|
+
const queueStats = await unsurfacedPendingMainStats(
|
|
41764
|
+
paths.instanceDirectory,
|
|
41765
|
+
{ count: recordedPending, droppedCount: recordedDropped }
|
|
41766
|
+
);
|
|
41354
41767
|
status = {
|
|
41355
41768
|
...status,
|
|
41356
41769
|
pendingForMainCount: queueStats.count,
|
|
@@ -41552,7 +41965,7 @@ async function fileRows(context) {
|
|
|
41552
41965
|
);
|
|
41553
41966
|
}
|
|
41554
41967
|
async function resolveFileSelector(context, selector) {
|
|
41555
|
-
if (
|
|
41968
|
+
if (UUID_RE18.test(selector)) return selector.toLowerCase();
|
|
41556
41969
|
const rows3 = await fileRows(context);
|
|
41557
41970
|
const match = rows3.find(
|
|
41558
41971
|
(row) => row.name.toLowerCase() === selector.toLowerCase()
|
|
@@ -42064,6 +42477,10 @@ async function main() {
|
|
|
42064
42477
|
await runReply(args);
|
|
42065
42478
|
return;
|
|
42066
42479
|
}
|
|
42480
|
+
if (verb === "receipt") {
|
|
42481
|
+
await runReceipt(args);
|
|
42482
|
+
return;
|
|
42483
|
+
}
|
|
42067
42484
|
if (verb === "feed" || verb === "inbox") {
|
|
42068
42485
|
await runSignalRead(args, verb === "inbox");
|
|
42069
42486
|
return;
|
|
@@ -42140,7 +42557,7 @@ main().catch((error) => {
|
|
|
42140
42557
|
if (error instanceof WorkspaceCliError) {
|
|
42141
42558
|
const structured = error.structured();
|
|
42142
42559
|
const verb = process.argv[2];
|
|
42143
|
-
const json = process.argv.includes("--json") && (verb === "status" || verb === "workspaces" || verb === "use" || verb === "working-on" || verb === "note" || verb === "ask" || verb === "reply" || verb === "feed" || verb === "inbox");
|
|
42560
|
+
const json = process.argv.includes("--json") && (verb === "status" || verb === "workspaces" || verb === "use" || verb === "working-on" || verb === "note" || verb === "ask" || verb === "reply" || verb === "receipt" || verb === "feed" || verb === "inbox");
|
|
42144
42561
|
if (json) {
|
|
42145
42562
|
process.stdout.write(`${JSON.stringify(structured, null, 2)}
|
|
42146
42563
|
`);
|