commonswarm 0.1.31 → 0.1.33
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 +521 -75
- 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,327 @@ 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
|
+
"queued",
|
|
29590
|
+
"expired",
|
|
29591
|
+
"failed_terminal"
|
|
29592
|
+
]);
|
|
29593
|
+
function uuid3(value, field) {
|
|
29594
|
+
if (typeof value !== "string" || !UUID_RE8.test(value)) {
|
|
29595
|
+
throw new DeliveryReceiptReadError(
|
|
29596
|
+
"protocol",
|
|
29597
|
+
`delivery receipt returned a malformed ${field}`
|
|
29598
|
+
);
|
|
29599
|
+
}
|
|
29600
|
+
return value.toLowerCase();
|
|
29601
|
+
}
|
|
29602
|
+
function timestamp2(value, field) {
|
|
29603
|
+
if (typeof value !== "string" || !Number.isFinite(Date.parse(value))) {
|
|
29604
|
+
throw new DeliveryReceiptReadError(
|
|
29605
|
+
"protocol",
|
|
29606
|
+
`delivery receipt returned a malformed ${field}`
|
|
29607
|
+
);
|
|
29608
|
+
}
|
|
29609
|
+
return value;
|
|
29610
|
+
}
|
|
29611
|
+
function nullableTimestamp(value, field) {
|
|
29612
|
+
return value === null ? null : timestamp2(value, field);
|
|
29613
|
+
}
|
|
29614
|
+
function nonNegativeInteger(value, field) {
|
|
29615
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
|
|
29616
|
+
throw new DeliveryReceiptReadError(
|
|
29617
|
+
"protocol",
|
|
29618
|
+
`delivery receipt returned a malformed ${field}`
|
|
29619
|
+
);
|
|
29620
|
+
}
|
|
29621
|
+
return value;
|
|
29622
|
+
}
|
|
29623
|
+
function parseDeliveryReceipt(value) {
|
|
29624
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
29625
|
+
throw new DeliveryReceiptReadError(
|
|
29626
|
+
"protocol",
|
|
29627
|
+
"delivery receipt returned a malformed row"
|
|
29628
|
+
);
|
|
29629
|
+
}
|
|
29630
|
+
const row = value;
|
|
29631
|
+
const ackedAt = nullableTimestamp(row.acked_at, "acked_at");
|
|
29632
|
+
const ackOutcome = row.ack_outcome === null ? null : typeof row.ack_outcome === "string" && ACK_OUTCOMES.has(row.ack_outcome) ? row.ack_outcome : (() => {
|
|
29633
|
+
throw new DeliveryReceiptReadError(
|
|
29634
|
+
"protocol",
|
|
29635
|
+
"delivery receipt returned a malformed ack_outcome"
|
|
29636
|
+
);
|
|
29637
|
+
})();
|
|
29638
|
+
if (ackedAt === null !== (ackOutcome === null)) {
|
|
29639
|
+
throw new DeliveryReceiptReadError(
|
|
29640
|
+
"protocol",
|
|
29641
|
+
"delivery receipt returned an inconsistent acknowledgement"
|
|
29642
|
+
);
|
|
29643
|
+
}
|
|
29644
|
+
return {
|
|
29645
|
+
recipient_agent_principal_id: uuid3(
|
|
29646
|
+
row.recipient_agent_principal_id,
|
|
29647
|
+
"recipient_agent_principal_id"
|
|
29648
|
+
),
|
|
29649
|
+
enqueued_at: timestamp2(row.enqueued_at, "enqueued_at"),
|
|
29650
|
+
delivered_at: nullableTimestamp(row.delivered_at, "delivered_at"),
|
|
29651
|
+
leased_until: nullableTimestamp(row.leased_until, "leased_until"),
|
|
29652
|
+
acked_at: ackedAt,
|
|
29653
|
+
ack_outcome: ackOutcome,
|
|
29654
|
+
attempt_count: nonNegativeInteger(row.attempt_count, "attempt_count"),
|
|
29655
|
+
lease_expiry_count: nonNegativeInteger(
|
|
29656
|
+
row.lease_expiry_count,
|
|
29657
|
+
"lease_expiry_count"
|
|
29658
|
+
),
|
|
29659
|
+
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 : (() => {
|
|
29660
|
+
throw new DeliveryReceiptReadError(
|
|
29661
|
+
"protocol",
|
|
29662
|
+
"delivery receipt returned a malformed last_error_code"
|
|
29663
|
+
);
|
|
29664
|
+
})()
|
|
29665
|
+
};
|
|
29666
|
+
}
|
|
29667
|
+
function parseDeliveryReceiptResult(value) {
|
|
29668
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
29669
|
+
throw new DeliveryReceiptReadError(
|
|
29670
|
+
"protocol",
|
|
29671
|
+
"delivery receipt read returned malformed JSON"
|
|
29672
|
+
);
|
|
29673
|
+
}
|
|
29674
|
+
const body = value;
|
|
29675
|
+
if (!(body.addressed === null || typeof body.addressed === "boolean") || !Array.isArray(body.receipts)) {
|
|
29676
|
+
throw new DeliveryReceiptReadError(
|
|
29677
|
+
"protocol",
|
|
29678
|
+
"delivery receipt read returned malformed JSON"
|
|
29679
|
+
);
|
|
29680
|
+
}
|
|
29681
|
+
const receipts = body.receipts.map(parseDeliveryReceipt);
|
|
29682
|
+
if (body.addressed === false && receipts.length !== 0) {
|
|
29683
|
+
throw new DeliveryReceiptReadError(
|
|
29684
|
+
"protocol",
|
|
29685
|
+
"delivery receipt read returned recipients for a broadcast"
|
|
29686
|
+
);
|
|
29687
|
+
}
|
|
29688
|
+
if (body.addressed === true && receipts.length === 0) {
|
|
29689
|
+
throw new DeliveryReceiptReadError(
|
|
29690
|
+
"protocol",
|
|
29691
|
+
"delivery receipt read returned no recipient for an addressed signal"
|
|
29692
|
+
);
|
|
29693
|
+
}
|
|
29694
|
+
const recipientIds = new Set(
|
|
29695
|
+
receipts.map((row) => row.recipient_agent_principal_id)
|
|
29696
|
+
);
|
|
29697
|
+
if (recipientIds.size !== receipts.length) {
|
|
29698
|
+
throw new DeliveryReceiptReadError(
|
|
29699
|
+
"protocol",
|
|
29700
|
+
"delivery receipt read returned duplicate recipients"
|
|
29701
|
+
);
|
|
29702
|
+
}
|
|
29703
|
+
return { addressed: body.addressed, receipts };
|
|
29704
|
+
}
|
|
29705
|
+
function deliveryReceiptState(receipt, nowMs = Date.now()) {
|
|
29706
|
+
if (receipt.ack_outcome !== null) return receipt.ack_outcome;
|
|
29707
|
+
if (receipt.leased_until !== null && Date.parse(receipt.leased_until) > nowMs) {
|
|
29708
|
+
return "leased";
|
|
29709
|
+
}
|
|
29710
|
+
if (receipt.delivered_at !== null) return "delivered";
|
|
29711
|
+
return "enqueued";
|
|
29712
|
+
}
|
|
29713
|
+
async function readAgentDeliveryReceipts(target2, token, workspaceId2, signalId, options = {}) {
|
|
29714
|
+
const readOptions = typeof options === "function" ? { fetcher: options } : options;
|
|
29715
|
+
const now = readOptions.now ?? Date.now;
|
|
29716
|
+
const timeoutMs = readOptions.deadlineMs === void 0 ? SIGNAL_READ_TIMEOUT_MS : Math.min(SIGNAL_READ_TIMEOUT_MS, readOptions.deadlineMs - now());
|
|
29717
|
+
if (timeoutMs <= 0) {
|
|
29718
|
+
throw new SignalReadTimeoutError("receipt read timed out");
|
|
29719
|
+
}
|
|
29720
|
+
const deadlineController = new AbortController();
|
|
29721
|
+
const signal = readOptions.signal === void 0 ? deadlineController.signal : AbortSignal.any([readOptions.signal, deadlineController.signal]);
|
|
29722
|
+
let onAbort = () => {
|
|
29723
|
+
};
|
|
29724
|
+
const aborted = new Promise((_resolve, reject) => {
|
|
29725
|
+
onAbort = () => reject(new SignalReadTimeoutError("receipt read timed out"));
|
|
29726
|
+
if (signal.aborted) onAbort();
|
|
29727
|
+
else signal.addEventListener("abort", onAbort, { once: true });
|
|
29728
|
+
});
|
|
29729
|
+
const timer2 = setTimeout(() => deadlineController.abort(), timeoutMs);
|
|
29730
|
+
try {
|
|
29731
|
+
let response;
|
|
29732
|
+
try {
|
|
29733
|
+
response = await Promise.race([
|
|
29734
|
+
(readOptions.fetcher ?? fetch)(readEndpoint(target2), {
|
|
29735
|
+
method: "POST",
|
|
29736
|
+
headers: {
|
|
29737
|
+
authorization: `Bearer ${token}`,
|
|
29738
|
+
apikey: target2.anonKey,
|
|
29739
|
+
"content-type": "application/json"
|
|
29740
|
+
},
|
|
29741
|
+
body: JSON.stringify({
|
|
29742
|
+
resource: "delivery_receipts",
|
|
29743
|
+
workspace_id: uuid3(workspaceId2, "workspace_id"),
|
|
29744
|
+
signal_id: uuid3(signalId, "signal_id")
|
|
29745
|
+
}),
|
|
29746
|
+
signal
|
|
29747
|
+
}),
|
|
29748
|
+
aborted
|
|
29749
|
+
]);
|
|
29750
|
+
} catch (error) {
|
|
29751
|
+
if (error instanceof SignalReadTimeoutError || signal.aborted || error?.name === "AbortError") {
|
|
29752
|
+
throw new SignalReadTimeoutError("receipt read timed out");
|
|
29753
|
+
}
|
|
29754
|
+
if (error instanceof DeliveryReceiptReadError) throw error;
|
|
29755
|
+
throw new DeliveryReceiptReadError(
|
|
29756
|
+
"transport",
|
|
29757
|
+
"delivery receipt read could not reach the cloud service"
|
|
29758
|
+
);
|
|
29759
|
+
}
|
|
29760
|
+
let body;
|
|
29761
|
+
try {
|
|
29762
|
+
body = await Promise.race([response.json(), aborted]);
|
|
29763
|
+
} catch (error) {
|
|
29764
|
+
if (error instanceof SignalReadTimeoutError || signal.aborted) {
|
|
29765
|
+
throw new SignalReadTimeoutError("receipt read timed out");
|
|
29766
|
+
}
|
|
29767
|
+
throw new DeliveryReceiptReadError(
|
|
29768
|
+
"protocol",
|
|
29769
|
+
"delivery receipt read returned malformed JSON"
|
|
29770
|
+
);
|
|
29771
|
+
}
|
|
29772
|
+
if (!response.ok) {
|
|
29773
|
+
throw new DeliveryReceiptReadError(
|
|
29774
|
+
"http",
|
|
29775
|
+
`delivery receipt read failed (HTTP ${response.status})`,
|
|
29776
|
+
response.status
|
|
29777
|
+
);
|
|
29778
|
+
}
|
|
29779
|
+
const result = parseDeliveryReceiptResult(body);
|
|
29780
|
+
if (result.addressed === null) {
|
|
29781
|
+
throw new DeliveryReceiptReadError(
|
|
29782
|
+
"not_author",
|
|
29783
|
+
"delivery receipt read did not establish that this caller authored the signal"
|
|
29784
|
+
);
|
|
29785
|
+
}
|
|
29786
|
+
return { addressed: result.addressed, receipts: result.receipts };
|
|
29787
|
+
} finally {
|
|
29788
|
+
clearTimeout(timer2);
|
|
29789
|
+
signal.removeEventListener("abort", onAbort);
|
|
29790
|
+
}
|
|
29791
|
+
}
|
|
29792
|
+
|
|
29793
|
+
// src/cloud/receipts.ts
|
|
29794
|
+
function signalReceiptCliState(receipt, nowMs) {
|
|
29795
|
+
const state = deliveryReceiptState(receipt, nowMs);
|
|
29796
|
+
if (state === "enqueued") return "not_delivered";
|
|
29797
|
+
if (state === "leased") return "working";
|
|
29798
|
+
if (state === "delivered") return "delivered";
|
|
29799
|
+
if (state === "queued") return "queued";
|
|
29800
|
+
return "finished";
|
|
29801
|
+
}
|
|
29802
|
+
function receiptCheckCommand(report) {
|
|
29803
|
+
return `cswarm receipt ${report.signalId} --workspace-id ${report.workspaceId}`;
|
|
29804
|
+
}
|
|
29805
|
+
function listenerStatusCommand(report, receipt) {
|
|
29806
|
+
return `cswarm listen status --workspace-id ${report.workspaceId} --principal-id ${receipt.recipient_agent_principal_id}`;
|
|
29807
|
+
}
|
|
29808
|
+
function newAskCommand(report, receipt) {
|
|
29809
|
+
return `cswarm ask "<question>" --to ${receipt.recipient_agent_principal_id} --workspace-id ${report.workspaceId}`;
|
|
29810
|
+
}
|
|
29811
|
+
function renderSignalReceiptReport(report, nowMs = Date.now()) {
|
|
29812
|
+
if (!report.addressed) {
|
|
29813
|
+
return [
|
|
29814
|
+
"This was a broadcast; no agent was addressed and none was woken.",
|
|
29815
|
+
`To wake an agent, send a new ask with: cswarm ask "<text>" --to <agent> --workspace-id ${report.workspaceId}`
|
|
29816
|
+
].join("\n");
|
|
29817
|
+
}
|
|
29818
|
+
const sections = report.receipts.map((receipt) => {
|
|
29819
|
+
const state = deliveryReceiptState(receipt, nowMs);
|
|
29820
|
+
if (state === "enqueued") {
|
|
29821
|
+
return [
|
|
29822
|
+
`Not yet delivered to agent ${receipt.recipient_agent_principal_id}. CommonSwarm accepted it ${relativeAge(receipt.enqueued_at, nowMs)}.`,
|
|
29823
|
+
`Ask the agent's operator to check its listener with: ${listenerStatusCommand(report, receipt)}`,
|
|
29824
|
+
`Then check again with: ${receiptCheckCommand(report)}`
|
|
29825
|
+
].join("\n");
|
|
29826
|
+
}
|
|
29827
|
+
if (state === "delivered") {
|
|
29828
|
+
return [
|
|
29829
|
+
`Delivered to agent ${receipt.recipient_agent_principal_id} ${relativeAge(receipt.delivered_at, nowMs)}, and the agent has not acted on it.`,
|
|
29830
|
+
`Check again with: ${receiptCheckCommand(report)}`
|
|
29831
|
+
].join("\n");
|
|
29832
|
+
}
|
|
29833
|
+
if (state === "leased") {
|
|
29834
|
+
return [
|
|
29835
|
+
`Agent ${receipt.recipient_agent_principal_id} is working on it right now; its current lease ${relativeExpiry(receipt.leased_until, nowMs)}.`,
|
|
29836
|
+
`Check for the outcome with: ${receiptCheckCommand(report)}`
|
|
29837
|
+
].join("\n");
|
|
29838
|
+
}
|
|
29839
|
+
if (state === "queued") {
|
|
29840
|
+
return [
|
|
29841
|
+
`Queued for agent ${receipt.recipient_agent_principal_id}'s interactive session ${relativeAge(receipt.acked_at, nowMs)}. The agent has not seen it yet.`,
|
|
29842
|
+
"It will appear at the agent's next prompt.",
|
|
29843
|
+
`Check again with: ${receiptCheckCommand(report)}`
|
|
29844
|
+
].join("\n");
|
|
29845
|
+
}
|
|
29846
|
+
const finished = `Agent ${receipt.recipient_agent_principal_id} finished with outcome ${state} ${relativeAge(receipt.acked_at, nowMs)}.`;
|
|
29847
|
+
if (state === "replied") {
|
|
29848
|
+
return [
|
|
29849
|
+
finished,
|
|
29850
|
+
`Read the reply with: cswarm inbox --workspace-id ${report.workspaceId} --include-stale`
|
|
29851
|
+
].join("\n");
|
|
29852
|
+
}
|
|
29853
|
+
if (state === "observed") {
|
|
29854
|
+
return [
|
|
29855
|
+
finished,
|
|
29856
|
+
"The agent saw the signal without sending a reply.",
|
|
29857
|
+
`If you need an answer, send a new ask with: ${newAskCommand(report, receipt)}`
|
|
29858
|
+
].join("\n");
|
|
29859
|
+
}
|
|
29860
|
+
if (state === "expired") {
|
|
29861
|
+
return [
|
|
29862
|
+
finished,
|
|
29863
|
+
"The signal expired before the agent completed it.",
|
|
29864
|
+
`Send a new ask with: ${newAskCommand(report, receipt)}`
|
|
29865
|
+
].join("\n");
|
|
29866
|
+
}
|
|
29867
|
+
return [
|
|
29868
|
+
finished,
|
|
29869
|
+
`Delivery will not retry${receipt.last_error_code === null ? "." : `; the last error code was ${receipt.last_error_code}.`}`,
|
|
29870
|
+
`Ask the agent's operator to check its listener with: ${listenerStatusCommand(report, receipt)}`
|
|
29871
|
+
].join("\n");
|
|
29872
|
+
});
|
|
29873
|
+
return sections.join("\n\n");
|
|
29874
|
+
}
|
|
29875
|
+
function signalReceiptJsonPayload(report, nowMs = Date.now()) {
|
|
29876
|
+
return {
|
|
29877
|
+
workspace_id: report.workspaceId,
|
|
29878
|
+
signal_id: report.signalId,
|
|
29879
|
+
broadcast: !report.addressed,
|
|
29880
|
+
receipts: report.receipts.map((receipt) => ({
|
|
29881
|
+
recipient_agent_principal_id: receipt.recipient_agent_principal_id,
|
|
29882
|
+
state: signalReceiptCliState(receipt, nowMs),
|
|
29883
|
+
outcome: receipt.ack_outcome,
|
|
29884
|
+
enqueued_at: receipt.enqueued_at,
|
|
29885
|
+
delivered_at: receipt.delivered_at,
|
|
29886
|
+
leased_until: receipt.leased_until,
|
|
29887
|
+
acked_at: receipt.acked_at,
|
|
29888
|
+
attempt_count: receipt.attempt_count,
|
|
29889
|
+
lease_expiry_count: receipt.lease_expiry_count,
|
|
29890
|
+
last_error_code: receipt.last_error_code
|
|
29891
|
+
}))
|
|
29892
|
+
};
|
|
29893
|
+
}
|
|
29894
|
+
|
|
29574
29895
|
// src/host/opencode.ts
|
|
29575
29896
|
var import_node_child_process3 = require("node:child_process");
|
|
29576
29897
|
var import_node_crypto12 = require("node:crypto");
|
|
@@ -32160,7 +32481,7 @@ async function resolveBudgetAndPrompt(session, prompt, budget) {
|
|
|
32160
32481
|
}
|
|
32161
32482
|
|
|
32162
32483
|
// src/listener/engine.ts
|
|
32163
|
-
var
|
|
32484
|
+
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
32485
|
var TERMINAL_STATES = /* @__PURE__ */ new Set(["done", "expired", "failed"]);
|
|
32165
32486
|
var REPLY_MAX_CODE_UNITS = 2e3;
|
|
32166
32487
|
var TRUNCATION_SUFFIX = "\n[Reply truncated by CommonSwarm]";
|
|
@@ -32168,7 +32489,7 @@ var UNSAFE_CONTROLS_RE = /[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f-\u009f\u
|
|
|
32168
32489
|
var LISTENER_MAX_PROMPT_ATTEMPTS = 3;
|
|
32169
32490
|
var LISTENER_MAX_POST_ATTEMPTS = 5;
|
|
32170
32491
|
function listenerReplyCommandId(signalId, effectOrdinal = 0) {
|
|
32171
|
-
if (!
|
|
32492
|
+
if (!UUID_RE9.test(signalId)) {
|
|
32172
32493
|
throw new Error("listener signal id must be a UUID");
|
|
32173
32494
|
}
|
|
32174
32495
|
if (!Number.isSafeInteger(effectOrdinal) || effectOrdinal < 0) {
|
|
@@ -32632,7 +32953,7 @@ var import_node_crypto13 = require("node:crypto");
|
|
|
32632
32953
|
var import_node_os5 = require("node:os");
|
|
32633
32954
|
var import_node_path8 = require("node:path");
|
|
32634
32955
|
var import_node_util = require("node:util");
|
|
32635
|
-
var
|
|
32956
|
+
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
32957
|
var COMMAND_ID_RE2 = /^[A-Za-z0-9_-]{8,72}$/;
|
|
32637
32958
|
var MAX_EFFECT_BYTES = 1024 * 1024;
|
|
32638
32959
|
var STATES = /* @__PURE__ */ new Set([
|
|
@@ -32670,7 +32991,7 @@ function defaultListenerStateDirectory() {
|
|
|
32670
32991
|
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
32992
|
}
|
|
32672
32993
|
function listenerInstanceKey(input) {
|
|
32673
|
-
if (!
|
|
32994
|
+
if (!UUID_RE10.test(input.workspaceId) || !UUID_RE10.test(input.principalId)) {
|
|
32674
32995
|
throw new Error("listener workspace and principal ids must be UUIDs");
|
|
32675
32996
|
}
|
|
32676
32997
|
if (!input.profileId || input.profileId.includes("\0")) {
|
|
@@ -32702,7 +33023,7 @@ function parseListenerEffectRecord(raw, expectedId) {
|
|
|
32702
33023
|
throw new Error("stored listener effect is malformed");
|
|
32703
33024
|
}
|
|
32704
33025
|
const row = value;
|
|
32705
|
-
if (typeof row.version !== "number" || row.version !== 1 && row.version !== 2 || typeof row.signalId !== "string" || row.signalId.toLowerCase() !== expectedId || !
|
|
33026
|
+
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
33027
|
throw new Error("stored listener effect is malformed");
|
|
32707
33028
|
}
|
|
32708
33029
|
if (row.version === 1) {
|
|
@@ -32719,7 +33040,7 @@ function upcastV1Ask(row) {
|
|
|
32719
33040
|
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
33041
|
throw new Error("stored listener effect is malformed");
|
|
32721
33042
|
}
|
|
32722
|
-
if (row.replySignalId !== null && !
|
|
33043
|
+
if (row.replySignalId !== null && !UUID_RE10.test(row.replySignalId)) {
|
|
32723
33044
|
throw new Error("stored listener effect is malformed");
|
|
32724
33045
|
}
|
|
32725
33046
|
return {
|
|
@@ -32758,7 +33079,7 @@ function parseV2Record(row) {
|
|
|
32758
33079
|
if (typeof row.commandId !== "string" || !COMMAND_ID_RE2.test(row.commandId) || row.state === "observed") {
|
|
32759
33080
|
throw new Error("stored listener effect is malformed");
|
|
32760
33081
|
}
|
|
32761
|
-
if (row.replySignalId !== null && !
|
|
33082
|
+
if (row.replySignalId !== null && !UUID_RE10.test(row.replySignalId)) {
|
|
32762
33083
|
throw new Error("stored listener effect is malformed");
|
|
32763
33084
|
}
|
|
32764
33085
|
}
|
|
@@ -32782,7 +33103,7 @@ function parseV2Record(row) {
|
|
|
32782
33103
|
};
|
|
32783
33104
|
}
|
|
32784
33105
|
function newObservedNoteRecord(input) {
|
|
32785
|
-
if (!
|
|
33106
|
+
if (!UUID_RE10.test(input.signalId)) {
|
|
32786
33107
|
throw new Error("listener note signal id must be a UUID");
|
|
32787
33108
|
}
|
|
32788
33109
|
if (input.body.length < 1) {
|
|
@@ -32916,7 +33237,7 @@ var FileListenerEffectStore = class {
|
|
|
32916
33237
|
);
|
|
32917
33238
|
}
|
|
32918
33239
|
checkedId(signalId) {
|
|
32919
|
-
if (!
|
|
33240
|
+
if (!UUID_RE10.test(signalId)) {
|
|
32920
33241
|
throw new Error("listener signal id must be a UUID");
|
|
32921
33242
|
}
|
|
32922
33243
|
return signalId.toLowerCase();
|
|
@@ -34007,7 +34328,7 @@ var CodexListenerModel = class {
|
|
|
34007
34328
|
var import_node_crypto17 = require("node:crypto");
|
|
34008
34329
|
|
|
34009
34330
|
// src/cloud/delivery.ts
|
|
34010
|
-
var
|
|
34331
|
+
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
34332
|
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
34333
|
var DELIVERY_KINDS = /* @__PURE__ */ new Set(["ask", "note"]);
|
|
34013
34334
|
var SENDER_OWNER_RELATIONS2 = /* @__PURE__ */ new Set([
|
|
@@ -34018,6 +34339,7 @@ var SENDER_OWNER_RELATIONS2 = /* @__PURE__ */ new Set([
|
|
|
34018
34339
|
var DELIVERY_ACK_OUTCOMES = /* @__PURE__ */ new Set([
|
|
34019
34340
|
"replied",
|
|
34020
34341
|
"observed",
|
|
34342
|
+
"queued",
|
|
34021
34343
|
"expired",
|
|
34022
34344
|
"failed_terminal"
|
|
34023
34345
|
]);
|
|
@@ -34064,6 +34386,10 @@ var DELIVERY_SERVER_ERROR_CODES = Object.freeze([
|
|
|
34064
34386
|
"internal_error"
|
|
34065
34387
|
]);
|
|
34066
34388
|
var DELIVERY_UNKNOWN_ERROR_CODE = "unknown_error";
|
|
34389
|
+
function observationCommandId(signalId) {
|
|
34390
|
+
checkedUuidRequest(signalId, "signalId");
|
|
34391
|
+
return `observe_${signalId.toLowerCase().replaceAll("-", "")}`;
|
|
34392
|
+
}
|
|
34067
34393
|
var DeliveryTransportError = class extends Error {
|
|
34068
34394
|
constructor(message) {
|
|
34069
34395
|
super(message);
|
|
@@ -34089,7 +34415,7 @@ var DeliveryProtocolError = class extends Error {
|
|
|
34089
34415
|
}
|
|
34090
34416
|
};
|
|
34091
34417
|
function checkedUuid3(value, field) {
|
|
34092
|
-
if (typeof value !== "string" || !
|
|
34418
|
+
if (typeof value !== "string" || !UUID_RE11.test(value)) {
|
|
34093
34419
|
throw new DeliveryProtocolError(
|
|
34094
34420
|
`delivery response returned a malformed ${field}`
|
|
34095
34421
|
);
|
|
@@ -34200,7 +34526,7 @@ function checkedClaimCapabilities(value) {
|
|
|
34200
34526
|
}
|
|
34201
34527
|
function checkedOptionalUuidArray(value, field) {
|
|
34202
34528
|
if (value === void 0) return;
|
|
34203
|
-
if (!Array.isArray(value) || value.some((item) => typeof item !== "string" || !
|
|
34529
|
+
if (!Array.isArray(value) || value.some((item) => typeof item !== "string" || !UUID_RE11.test(item))) {
|
|
34204
34530
|
throw new DeliveryProtocolError(
|
|
34205
34531
|
`delivery response returned a malformed ${field}`
|
|
34206
34532
|
);
|
|
@@ -34347,7 +34673,7 @@ function checkedCommandId(value) {
|
|
|
34347
34673
|
return value;
|
|
34348
34674
|
}
|
|
34349
34675
|
function checkedUuidRequest(value, field) {
|
|
34350
|
-
if (!
|
|
34676
|
+
if (!UUID_RE11.test(value)) {
|
|
34351
34677
|
throw new Error(`${field} must be a UUID for an agent delivery command`);
|
|
34352
34678
|
}
|
|
34353
34679
|
}
|
|
@@ -34360,7 +34686,7 @@ function assertAckRequest(request) {
|
|
|
34360
34686
|
checkedUuidRequest(request.listenerInstanceId, "listenerInstanceId");
|
|
34361
34687
|
if (!DELIVERY_ACK_OUTCOMES.has(request.outcome)) {
|
|
34362
34688
|
throw new Error(
|
|
34363
|
-
"a delivery outcome must be replied, observed, expired, or failed_terminal"
|
|
34689
|
+
"a delivery outcome must be replied, observed, queued, expired, or failed_terminal"
|
|
34364
34690
|
);
|
|
34365
34691
|
}
|
|
34366
34692
|
if (request.outcome === "failed_terminal") {
|
|
@@ -34552,11 +34878,39 @@ var DeliveryCommandClient = class {
|
|
|
34552
34878
|
outcome: request.outcome
|
|
34553
34879
|
};
|
|
34554
34880
|
}
|
|
34881
|
+
/** Mark a queued delivery observed only after the interactive hook surfaced it. */
|
|
34882
|
+
async observeQueuedAgentDelivery(request) {
|
|
34883
|
+
checkedCommandId(request.commandId);
|
|
34884
|
+
assertAgentToken(request.credential);
|
|
34885
|
+
checkedUuidRequest(request.workspaceId, "workspaceId");
|
|
34886
|
+
checkedUuidRequest(request.signalId, "signalId");
|
|
34887
|
+
const { response, text } = await this.post(request, {
|
|
34888
|
+
kind: "ack_agent_delivery",
|
|
34889
|
+
signal_id: request.signalId.toLowerCase(),
|
|
34890
|
+
lease_id: null,
|
|
34891
|
+
listener_instance_id: null,
|
|
34892
|
+
outcome: "observed",
|
|
34893
|
+
last_error_code: null
|
|
34894
|
+
}, "delivery observation");
|
|
34895
|
+
if (!response.ok) throw refusal(response, text);
|
|
34896
|
+
parseAckSuccess(
|
|
34897
|
+
successBody(response, text, "delivery observation"),
|
|
34898
|
+
{
|
|
34899
|
+
signalId: request.signalId.toLowerCase(),
|
|
34900
|
+
outcome: "observed"
|
|
34901
|
+
}
|
|
34902
|
+
);
|
|
34903
|
+
return {
|
|
34904
|
+
httpStatus: response.status,
|
|
34905
|
+
signalId: request.signalId.toLowerCase(),
|
|
34906
|
+
outcome: "observed"
|
|
34907
|
+
};
|
|
34908
|
+
}
|
|
34555
34909
|
};
|
|
34556
34910
|
|
|
34557
34911
|
// src/listener/main-routing.ts
|
|
34558
34912
|
var import_node_path14 = require("node:path");
|
|
34559
|
-
var
|
|
34913
|
+
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
34914
|
var MAX_QUEUE_BYTES = 1024 * 1024;
|
|
34561
34915
|
var QUEUE_FILE = "pending-for-main.json";
|
|
34562
34916
|
var QUEUE_LOCK = "pending-for-main";
|
|
@@ -34605,12 +34959,13 @@ function parseEntry(value) {
|
|
|
34605
34959
|
"senderName",
|
|
34606
34960
|
"body",
|
|
34607
34961
|
"createdAt",
|
|
34608
|
-
"queuedAt"
|
|
34962
|
+
"queuedAt",
|
|
34963
|
+
"observationPending"
|
|
34609
34964
|
]);
|
|
34610
34965
|
if (Object.keys(row).some((key2) => !allowed.has(key2))) {
|
|
34611
34966
|
throw new Error("stored pending-for-main entry is malformed");
|
|
34612
34967
|
}
|
|
34613
|
-
if (typeof row.signalId !== "string" || !
|
|
34968
|
+
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) || !(row.observationPending === void 0 || row.observationPending === true)) {
|
|
34614
34969
|
throw new Error("stored pending-for-main entry is malformed");
|
|
34615
34970
|
}
|
|
34616
34971
|
return {
|
|
@@ -34623,7 +34978,8 @@ function parseEntry(value) {
|
|
|
34623
34978
|
senderName: row.senderName,
|
|
34624
34979
|
body: row.body,
|
|
34625
34980
|
createdAt: row.createdAt,
|
|
34626
|
-
queuedAt: row.queuedAt
|
|
34981
|
+
queuedAt: row.queuedAt,
|
|
34982
|
+
...row.observationPending === true ? { observationPending: true } : {}
|
|
34627
34983
|
};
|
|
34628
34984
|
}
|
|
34629
34985
|
function parseFile(raw) {
|
|
@@ -34719,7 +35075,7 @@ var FilePendingMainQueue = class {
|
|
|
34719
35075
|
}, lockTimeoutMs === void 0 ? {} : { timeoutMs: lockTimeoutMs });
|
|
34720
35076
|
}
|
|
34721
35077
|
};
|
|
34722
|
-
function pendingMainEntry(signal, principalId, provenance, now) {
|
|
35078
|
+
function pendingMainEntry(signal, principalId, provenance, now, options = {}) {
|
|
34723
35079
|
if (signal.kind !== "ask") {
|
|
34724
35080
|
throw new Error("only directed asks can enter the pending-for-main queue");
|
|
34725
35081
|
}
|
|
@@ -34732,7 +35088,8 @@ function pendingMainEntry(signal, principalId, provenance, now) {
|
|
|
34732
35088
|
senderName: provenance.senderName,
|
|
34733
35089
|
body: signal.body,
|
|
34734
35090
|
createdAt: signal.created_at,
|
|
34735
|
-
queuedAt: new Date(now).toISOString()
|
|
35091
|
+
queuedAt: new Date(now).toISOString(),
|
|
35092
|
+
...options.observationPending ? { observationPending: true } : {}
|
|
34736
35093
|
});
|
|
34737
35094
|
}
|
|
34738
35095
|
|
|
@@ -34746,7 +35103,7 @@ var LISTENER_REPLY_ONLY_MINIMUM_MS = SIGNAL_REQUEST_TIMEOUT_MS + LISTENER_ACK_ON
|
|
|
34746
35103
|
var LISTENER_PROMPT_START_MINIMUM_MS = SIGNAL_READ_TIMEOUT_MS + ACP_DEFAULT_REQUEST_TIMEOUT_MS + LISTENER_REPLY_ONLY_MINIMUM_MS;
|
|
34747
35104
|
var LISTENER_DELIVERY_RETRY_INITIAL_MS = 500;
|
|
34748
35105
|
var LISTENER_DELIVERY_RETRY_MAX_MS = 3e4;
|
|
34749
|
-
var
|
|
35106
|
+
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
35107
|
var ListenerCapabilityError = class extends Error {
|
|
34751
35108
|
code;
|
|
34752
35109
|
constructor(code, message) {
|
|
@@ -34826,7 +35183,7 @@ function ackForTerminalEffect(record, now) {
|
|
|
34826
35183
|
return { outcome: "observed", lastErrorCode: null };
|
|
34827
35184
|
}
|
|
34828
35185
|
if (record.state === "routed_main" && record.signalKind === "ask") {
|
|
34829
|
-
return { outcome: "
|
|
35186
|
+
return { outcome: "queued", lastErrorCode: null };
|
|
34830
35187
|
}
|
|
34831
35188
|
if (record.state === "expired" && record.signalKind === "ask" && Date.parse(record.askUntil) <= now()) {
|
|
34832
35189
|
return { outcome: "expired", lastErrorCode: null };
|
|
@@ -35021,7 +35378,7 @@ async function runListenerRuntime(options) {
|
|
|
35021
35378
|
new Error("listener instance id and delivery journal must be configured together")
|
|
35022
35379
|
);
|
|
35023
35380
|
}
|
|
35024
|
-
if (hasInstanceId && !
|
|
35381
|
+
if (hasInstanceId && !UUID_RE13.test(options.listenerInstanceId)) {
|
|
35025
35382
|
return await closeBeforeStart(
|
|
35026
35383
|
options.model,
|
|
35027
35384
|
new Error("listener instance id must be a UUID")
|
|
@@ -35109,7 +35466,9 @@ async function runListenerRuntime(options) {
|
|
|
35109
35466
|
}
|
|
35110
35467
|
}
|
|
35111
35468
|
const queued = await options.pendingMainQueue.enqueue(
|
|
35112
|
-
pendingMainEntry(signal, options.principalId, provenance, now()
|
|
35469
|
+
pendingMainEntry(signal, options.principalId, provenance, now(), {
|
|
35470
|
+
observationPending: deliveryMode === "durable_claim"
|
|
35471
|
+
})
|
|
35113
35472
|
);
|
|
35114
35473
|
options.onEvent?.({
|
|
35115
35474
|
type: "main_queue",
|
|
@@ -35844,7 +36203,7 @@ async function runListenerRuntime(options) {
|
|
|
35844
36203
|
var import_node_net = require("node:net");
|
|
35845
36204
|
var import_promises9 = require("node:fs/promises");
|
|
35846
36205
|
var import_node_path15 = require("node:path");
|
|
35847
|
-
var
|
|
36206
|
+
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
36207
|
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
36208
|
var MAX_STATUS_BYTES = 16 * 1024;
|
|
35850
36209
|
var MAX_CONTROL_BYTES = 8 * 1024;
|
|
@@ -35950,10 +36309,10 @@ function parseStatus(raw) {
|
|
|
35950
36309
|
throw new Error("stored listener status is malformed");
|
|
35951
36310
|
}
|
|
35952
36311
|
}
|
|
35953
|
-
const nullableUuid2 = (candidate) => candidate === null || typeof candidate === "string" &&
|
|
36312
|
+
const nullableUuid2 = (candidate) => candidate === null || typeof candidate === "string" && UUID_RE14.test(candidate);
|
|
35954
36313
|
const nullableCount = (candidate) => candidate === null || typeof candidate === "number" && Number.isSafeInteger(candidate) && candidate >= 0;
|
|
35955
|
-
const
|
|
35956
|
-
if (row.version !== 1 || typeof row.instanceId !== "string" || !
|
|
36314
|
+
const nullableTimestamp2 = (candidate) => candidate === null || typeof candidate === "string" && Number.isFinite(Date.parse(candidate));
|
|
36315
|
+
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
36316
|
throw new Error("stored listener status is malformed");
|
|
35958
36317
|
}
|
|
35959
36318
|
const routeMode = row.routeMode ?? "worker";
|
|
@@ -36029,6 +36388,7 @@ async function appendListenerEvent(paths, event) {
|
|
|
36029
36388
|
const deliveryOutcomes = /* @__PURE__ */ new Set([
|
|
36030
36389
|
"replied",
|
|
36031
36390
|
"observed",
|
|
36391
|
+
"queued",
|
|
36032
36392
|
"expired",
|
|
36033
36393
|
"failed_terminal"
|
|
36034
36394
|
]);
|
|
@@ -36302,7 +36662,7 @@ async function queryListenerControl(paths, command2, timeoutMs = CONTROL_TIMEOUT
|
|
|
36302
36662
|
|
|
36303
36663
|
// src/listener/supervisor.ts
|
|
36304
36664
|
var import_node_crypto18 = require("node:crypto");
|
|
36305
|
-
var
|
|
36665
|
+
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
36666
|
var LISTENER_RESTART_MAX_ATTEMPTS = 5;
|
|
36307
36667
|
var LISTENER_RESTART_INITIAL_MS = 1e3;
|
|
36308
36668
|
var LISTENER_RESTART_MAX_MS = 6e4;
|
|
@@ -36431,7 +36791,7 @@ async function runListenerSupervisor(options) {
|
|
|
36431
36791
|
// before the socket can answer, before any status/event persistence.
|
|
36432
36792
|
initialize: prepare ? async () => {
|
|
36433
36793
|
const selected = await prepare(proposedInstanceId);
|
|
36434
|
-
if (!selected || typeof selected !== "object" || typeof selected.instanceId !== "string" || !
|
|
36794
|
+
if (!selected || typeof selected !== "object" || typeof selected.instanceId !== "string" || !UUID_RE15.test(selected.instanceId)) {
|
|
36435
36795
|
throw new Error("listener prepare returned an invalid instance id");
|
|
36436
36796
|
}
|
|
36437
36797
|
status = { ...status, instanceId: selected.instanceId };
|
|
@@ -36789,7 +37149,7 @@ async function waitForListenerReady(paths, options = {}) {
|
|
|
36789
37149
|
// src/listener/delivery-journal.ts
|
|
36790
37150
|
var import_node_path16 = require("node:path");
|
|
36791
37151
|
var import_node_util2 = require("node:util");
|
|
36792
|
-
var
|
|
37152
|
+
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
37153
|
var COMMAND_ID_RE3 = /^[A-Za-z0-9_-]{8,72}$/;
|
|
36794
37154
|
var SIGNAL_FINGERPRINT_RE = /^[0-9a-f]{64}$/;
|
|
36795
37155
|
var MAX_JOURNAL_BYTES = 8192;
|
|
@@ -36873,6 +37233,7 @@ var ALLOWED_PHASES = /* @__PURE__ */ new Set(["claim_pending", "leased", "ack_pe
|
|
|
36873
37233
|
var ALLOWED_OUTCOMES = /* @__PURE__ */ new Set([
|
|
36874
37234
|
"replied",
|
|
36875
37235
|
"observed",
|
|
37236
|
+
"queued",
|
|
36876
37237
|
"expired",
|
|
36877
37238
|
"failed_terminal"
|
|
36878
37239
|
]);
|
|
@@ -36883,7 +37244,7 @@ var ALLOWED_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
|
36883
37244
|
"credential_unavailable"
|
|
36884
37245
|
]);
|
|
36885
37246
|
function claimCommandId(listenerInstanceId, claimOrdinal) {
|
|
36886
|
-
if (!
|
|
37247
|
+
if (!UUID_RE16.test(listenerInstanceId)) {
|
|
36887
37248
|
throw new Error("stored delivery journal is malformed");
|
|
36888
37249
|
}
|
|
36889
37250
|
if (!Number.isSafeInteger(claimOrdinal) || claimOrdinal < 0) {
|
|
@@ -36898,7 +37259,7 @@ function claimCommandId(listenerInstanceId, claimOrdinal) {
|
|
|
36898
37259
|
return id;
|
|
36899
37260
|
}
|
|
36900
37261
|
function ackCommandId(leaseId) {
|
|
36901
|
-
if (!
|
|
37262
|
+
if (!UUID_RE16.test(leaseId)) {
|
|
36902
37263
|
throw new Error("stored delivery journal is malformed");
|
|
36903
37264
|
}
|
|
36904
37265
|
const cleanLease = leaseId.toLowerCase().replace(/-/g, "");
|
|
@@ -36981,19 +37342,19 @@ function parseJournalRecord(raw, expectedWorkspaceId, expectedPrincipalId) {
|
|
|
36981
37342
|
if (row.version !== 1) {
|
|
36982
37343
|
throw new Error("stored delivery journal is malformed");
|
|
36983
37344
|
}
|
|
36984
|
-
if (typeof row.workspaceId !== "string" || !
|
|
37345
|
+
if (typeof row.workspaceId !== "string" || !UUID_RE16.test(row.workspaceId) || row.workspaceId !== row.workspaceId.toLowerCase()) {
|
|
36985
37346
|
throw new Error("stored delivery journal is malformed");
|
|
36986
37347
|
}
|
|
36987
37348
|
if (expectedWorkspaceId && row.workspaceId !== expectedWorkspaceId.toLowerCase()) {
|
|
36988
37349
|
throw new Error("stored delivery journal is malformed");
|
|
36989
37350
|
}
|
|
36990
|
-
if (typeof row.principalId !== "string" || !
|
|
37351
|
+
if (typeof row.principalId !== "string" || !UUID_RE16.test(row.principalId) || row.principalId !== row.principalId.toLowerCase()) {
|
|
36991
37352
|
throw new Error("stored delivery journal is malformed");
|
|
36992
37353
|
}
|
|
36993
37354
|
if (expectedPrincipalId && row.principalId !== expectedPrincipalId.toLowerCase()) {
|
|
36994
37355
|
throw new Error("stored delivery journal is malformed");
|
|
36995
37356
|
}
|
|
36996
|
-
if (typeof row.listenerInstanceId !== "string" || !
|
|
37357
|
+
if (typeof row.listenerInstanceId !== "string" || !UUID_RE16.test(row.listenerInstanceId) || row.listenerInstanceId !== row.listenerInstanceId.toLowerCase()) {
|
|
36997
37358
|
throw new Error("stored delivery journal is malformed");
|
|
36998
37359
|
}
|
|
36999
37360
|
if (!Number.isSafeInteger(row.nextClaimOrdinal) || row.nextClaimOrdinal < 0) {
|
|
@@ -37057,10 +37418,10 @@ function parseJournalRecord(raw, expectedWorkspaceId, expectedPrincipalId) {
|
|
|
37057
37418
|
if (active.claimLastAttemptAt === null) {
|
|
37058
37419
|
throw new Error("stored delivery journal is malformed");
|
|
37059
37420
|
}
|
|
37060
|
-
if (typeof active.signalId !== "string" || !
|
|
37421
|
+
if (typeof active.signalId !== "string" || !UUID_RE16.test(active.signalId) || active.signalId !== active.signalId.toLowerCase()) {
|
|
37061
37422
|
throw new Error("stored delivery journal is malformed");
|
|
37062
37423
|
}
|
|
37063
|
-
if (typeof active.leaseId !== "string" || !
|
|
37424
|
+
if (typeof active.leaseId !== "string" || !UUID_RE16.test(active.leaseId) || active.leaseId !== active.leaseId.toLowerCase()) {
|
|
37064
37425
|
throw new Error("stored delivery journal is malformed");
|
|
37065
37426
|
}
|
|
37066
37427
|
if (!isValidIsoTimestamp(active.leasedUntil) || Date.parse(active.leasedUntil) <= Date.parse(active.claimCreatedAt)) {
|
|
@@ -37132,7 +37493,7 @@ var FileListenerDeliveryJournal = class {
|
|
|
37132
37493
|
["profileId", "workspaceId", "principalId"],
|
|
37133
37494
|
"delivery journal configuration rejected"
|
|
37134
37495
|
);
|
|
37135
|
-
if (typeof options.profileId !== "string" || !options.profileId || options.profileId.includes("\0") || typeof options.workspaceId !== "string" || !
|
|
37496
|
+
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
37497
|
throw new Error("delivery journal configuration rejected");
|
|
37137
37498
|
}
|
|
37138
37499
|
if (options.stateDirectory !== void 0) {
|
|
@@ -37253,7 +37614,7 @@ var FileListenerDeliveryJournal = class {
|
|
|
37253
37614
|
["signalId", "leaseId", "leasedUntil"],
|
|
37254
37615
|
"delivery journal mutation rejected"
|
|
37255
37616
|
);
|
|
37256
|
-
if (typeof input.signalId !== "string" || !
|
|
37617
|
+
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
37618
|
throw new Error("delivery journal mutation rejected");
|
|
37258
37619
|
}
|
|
37259
37620
|
const canonicalSignalId = input.signalId.toLowerCase();
|
|
@@ -37385,7 +37746,7 @@ async function openListenerDeliveryJournal(options) {
|
|
|
37385
37746
|
["profileId", "workspaceId", "principalId", "proposedListenerInstanceId"],
|
|
37386
37747
|
"delivery journal configuration rejected"
|
|
37387
37748
|
);
|
|
37388
|
-
if (typeof options.profileId !== "string" || !options.profileId || options.profileId.includes("\0") || typeof options.workspaceId !== "string" || !
|
|
37749
|
+
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
37750
|
throw new Error("delivery journal configuration rejected");
|
|
37390
37751
|
}
|
|
37391
37752
|
if (options.stateDirectory !== void 0) {
|
|
@@ -37600,7 +37961,7 @@ async function spawnDetachedListener(options) {
|
|
|
37600
37961
|
// src/listener/hook.ts
|
|
37601
37962
|
var import_promises10 = require("node:fs/promises");
|
|
37602
37963
|
var import_node_path18 = require("node:path");
|
|
37603
|
-
var
|
|
37964
|
+
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
37965
|
var TOKEN_RE = /^swm_agt_[A-Za-z0-9_-]{43}$/;
|
|
37605
37966
|
var INSTANCE_KEY_RE = /^[0-9a-f]{64}$/;
|
|
37606
37967
|
var MAX_HOOK_CREDENTIAL_BYTES = 8 * 1024;
|
|
@@ -37641,7 +38002,7 @@ function parseListenerCredential(raw) {
|
|
|
37641
38002
|
"principalId",
|
|
37642
38003
|
"credential",
|
|
37643
38004
|
"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" || !
|
|
38005
|
+
]) || 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
38006
|
throw new Error("stored listener hook credential is malformed");
|
|
37646
38007
|
}
|
|
37647
38008
|
const target2 = cloudTarget(row.targetUrl, row.anonKey);
|
|
@@ -37701,7 +38062,7 @@ function parseSurface(raw) {
|
|
|
37701
38062
|
const row = value;
|
|
37702
38063
|
if (Object.keys(row).some(
|
|
37703
38064
|
(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" || !
|
|
38065
|
+
) || 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
38066
|
throw new Error("stored listener hook surface state is malformed");
|
|
37706
38067
|
}
|
|
37707
38068
|
const ids = row.surfacedSignalIds.map((id) => String(id).toLowerCase());
|
|
@@ -37738,7 +38099,7 @@ var FileHookSurfaceStore = class {
|
|
|
37738
38099
|
const unseen = [];
|
|
37739
38100
|
for (const item of items) {
|
|
37740
38101
|
const signalId = item.signalId.toLowerCase();
|
|
37741
|
-
if (!
|
|
38102
|
+
if (!UUID_RE17.test(signalId) || seen.has(signalId)) continue;
|
|
37742
38103
|
seen.add(signalId);
|
|
37743
38104
|
unseen.push(item);
|
|
37744
38105
|
}
|
|
@@ -37761,7 +38122,7 @@ var FileHookSurfaceStore = class {
|
|
|
37761
38122
|
const seen = new Set(state.surfacedSignalIds);
|
|
37762
38123
|
for (const signalId of options.signalIds ?? []) {
|
|
37763
38124
|
const checked = signalId.toLowerCase();
|
|
37764
|
-
if (
|
|
38125
|
+
if (UUID_RE17.test(checked)) seen.add(checked);
|
|
37765
38126
|
}
|
|
37766
38127
|
await writeSecureJsonFile(
|
|
37767
38128
|
this.path,
|
|
@@ -37998,6 +38359,32 @@ function renderDroppedAsks(count2) {
|
|
|
37998
38359
|
}
|
|
37999
38360
|
var CREDENTIAL_READ_WARNING = "CommonSwarm could not read the configured listener credential safely. The hook is not checking routed asks. Restart the listener with a fresh credential; any credential state file must be mode 0600. Then run cswarm listen status.";
|
|
38000
38361
|
var CREDENTIAL_401_WARNING = "CommonSwarm could not authenticate a listener credential (HTTP 401). The hook is not checking routed asks. Restart the listener with a fresh credential, then run cswarm listen status.";
|
|
38362
|
+
async function recordQueuedObservations(check, signalIds, options, now) {
|
|
38363
|
+
const stored = check.context.credential;
|
|
38364
|
+
const remainingMs = options.deadlineMs - now();
|
|
38365
|
+
if (signalIds.length === 0 || stored === null || options.signal.aborted || remainingMs <= 0) {
|
|
38366
|
+
return /* @__PURE__ */ new Set();
|
|
38367
|
+
}
|
|
38368
|
+
const client = new DeliveryCommandClient(
|
|
38369
|
+
cloudTarget(stored.targetUrl, stored.anonKey),
|
|
38370
|
+
options.fetcher ?? fetch,
|
|
38371
|
+
{ deadlineMs: remainingMs, now }
|
|
38372
|
+
);
|
|
38373
|
+
const results = await Promise.all(signalIds.map(async (signalId) => {
|
|
38374
|
+
try {
|
|
38375
|
+
await client.observeQueuedAgentDelivery({
|
|
38376
|
+
workspaceId: stored.workspaceId,
|
|
38377
|
+
credential: stored.credential,
|
|
38378
|
+
commandId: observationCommandId(signalId),
|
|
38379
|
+
signalId
|
|
38380
|
+
});
|
|
38381
|
+
return signalId;
|
|
38382
|
+
} catch {
|
|
38383
|
+
return null;
|
|
38384
|
+
}
|
|
38385
|
+
}));
|
|
38386
|
+
return new Set(results.filter((signalId) => signalId !== null));
|
|
38387
|
+
}
|
|
38001
38388
|
async function checkListenerHooks(options) {
|
|
38002
38389
|
try {
|
|
38003
38390
|
const stateDirectory2 = options.stateDirectory ?? defaultListenerStateDirectory();
|
|
@@ -38076,10 +38463,8 @@ async function checkListenerHooks(options) {
|
|
|
38076
38463
|
check,
|
|
38077
38464
|
store: store2,
|
|
38078
38465
|
signalIds: staged.unseen.map((item) => item.signalId),
|
|
38079
|
-
|
|
38080
|
-
|
|
38081
|
-
// without re-printing entries below the exactly-once high-water.
|
|
38082
|
-
settledPendingSignalIds: check.pending.map((item) => item.signalId),
|
|
38466
|
+
plainPendingSignalIds: check.pending.filter((item) => item.observationPending !== true).map((item) => item.signalId),
|
|
38467
|
+
observationPendingSignalIds: check.pending.filter((item) => item.observationPending === true).map((item) => item.signalId),
|
|
38083
38468
|
reportDrops,
|
|
38084
38469
|
reportCredentialFailure
|
|
38085
38470
|
});
|
|
@@ -38092,8 +38477,17 @@ async function checkListenerHooks(options) {
|
|
|
38092
38477
|
...commit.reportDrops ? { droppedCount: commit.check.droppedCount } : {},
|
|
38093
38478
|
...commit.reportCredentialFailure ? { credentialFailureReported: true } : commit.check.credentialHealthy ? { credentialFailureReported: false } : {}
|
|
38094
38479
|
});
|
|
38480
|
+
const observedSignalIds = await recordQueuedObservations(
|
|
38481
|
+
commit.check,
|
|
38482
|
+
commit.observationPendingSignalIds,
|
|
38483
|
+
options,
|
|
38484
|
+
now
|
|
38485
|
+
);
|
|
38095
38486
|
const remainingCount = await commit.check.queue.remove(
|
|
38096
|
-
new Set(
|
|
38487
|
+
/* @__PURE__ */ new Set([
|
|
38488
|
+
...commit.plainPendingSignalIds,
|
|
38489
|
+
...observedSignalIds
|
|
38490
|
+
]),
|
|
38097
38491
|
HOOK_LOCK_TIMEOUT_MS
|
|
38098
38492
|
);
|
|
38099
38493
|
if (commit.check.context.paths !== null && commit.check.context.status !== null) {
|
|
@@ -38218,7 +38612,7 @@ var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
|
|
|
38218
38612
|
"reveal-anon-key",
|
|
38219
38613
|
"write"
|
|
38220
38614
|
]);
|
|
38221
|
-
var
|
|
38615
|
+
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;
|
|
38222
38616
|
var AGENT_CREDENTIAL_MESSAGE = "Agent credential minted. It is bound to this task and run so the agent's work stays scoped and attributable.";
|
|
38223
38617
|
var AGENT_CREDENTIAL_MESSAGE_D088 = "Agent credential minted. It is bound to this run, so the agent's work is attributable to it.";
|
|
38224
38618
|
var ACCEPTED_AGENT_CREDENTIAL_MESSAGES = [
|
|
@@ -38226,8 +38620,8 @@ var ACCEPTED_AGENT_CREDENTIAL_MESSAGES = [
|
|
|
38226
38620
|
AGENT_CREDENTIAL_MESSAGE_D088
|
|
38227
38621
|
];
|
|
38228
38622
|
function packageVersion() {
|
|
38229
|
-
if ("0.1.
|
|
38230
|
-
return "0.1.
|
|
38623
|
+
if ("0.1.33".length > 0) {
|
|
38624
|
+
return "0.1.33";
|
|
38231
38625
|
}
|
|
38232
38626
|
try {
|
|
38233
38627
|
const value = JSON.parse(
|
|
@@ -38346,6 +38740,7 @@ Usage:
|
|
|
38346
38740
|
cswarm note "<text>" [--url <url> --anon-key <key>] [--workspace-id <uuid>] [--to <member|agent>] [--about <ref>] [--until <dur>] [--json] # text: 1..8000 characters
|
|
38347
38741
|
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
|
|
38348
38742
|
cswarm reply <signal-id> "<text>" [--url <url> --anon-key <key>] [--workspace-id <uuid>] [--until <dur>] [--json]
|
|
38743
|
+
cswarm receipt <signal-id> --agent-token-stdin [--url <url> --anon-key <key>] --workspace-id <uuid> [--json]
|
|
38349
38744
|
cswarm feed [--url <url> --anon-key <key>] [--workspace-id <uuid>] [--about <ref>] [--kind <kind>] [--since <timestamp>] [--limit <n>] [--include-stale] [--json]
|
|
38350
38745
|
cswarm inbox [--url <url> --anon-key <key>] [--workspace-id <uuid>] [--kind <kind>] [--about <ref>] [--since <timestamp>] [--limit <n>] [--include-stale] [--wait <seconds>] [--json]
|
|
38351
38746
|
cswarm inbox --follow --ndjson [--url <url> --anon-key <key>] [--workspace-id <uuid>] [--kind <kind>] [--about <ref>] [--since <timestamp>] [--limit <n>] [--include-stale]
|
|
@@ -38392,6 +38787,7 @@ Credential selection for command/dogfood:
|
|
|
38392
38787
|
One that persists or references the credential needs the complete
|
|
38393
38788
|
JSON artifact, because it needs a field a bare secret does not carry:
|
|
38394
38789
|
members reads only -- either form
|
|
38790
|
+
receipt reads only -- either form
|
|
38395
38791
|
file put, file ls, file get, file rm, file restore
|
|
38396
38792
|
read and command, nothing persisted -- either form
|
|
38397
38793
|
feedback command only, nothing persisted -- either form
|
|
@@ -38561,7 +38957,7 @@ function parsedAgentCredential(value) {
|
|
|
38561
38957
|
const withExpiry = [...requiredKeys, "expires_at"].sort();
|
|
38562
38958
|
const actualKeys = Object.keys(artifact).sort();
|
|
38563
38959
|
const shape = actualKeys.length === requiredKeys.length ? requiredKeys : withExpiry;
|
|
38564
|
-
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" || !
|
|
38960
|
+
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") {
|
|
38565
38961
|
throw new Error("agent credential JSON is malformed");
|
|
38566
38962
|
}
|
|
38567
38963
|
let expiresAt = null;
|
|
@@ -38678,7 +39074,7 @@ async function workspaceId(args, cloud, human, options = {}) {
|
|
|
38678
39074
|
warn: options.warn ?? writeWorkspaceWarning
|
|
38679
39075
|
});
|
|
38680
39076
|
}
|
|
38681
|
-
function
|
|
39077
|
+
function uuid4(value, field) {
|
|
38682
39078
|
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)) {
|
|
38683
39079
|
throw new Error(`server returned a malformed ${field}`);
|
|
38684
39080
|
}
|
|
@@ -38783,7 +39179,7 @@ async function runNew(args) {
|
|
|
38783
39179
|
throw error;
|
|
38784
39180
|
}
|
|
38785
39181
|
const response = acceptedConnect("workspace creation", result);
|
|
38786
|
-
const created =
|
|
39182
|
+
const created = uuid4(response.workspace_id, "workspace_id");
|
|
38787
39183
|
if (created !== proposedId) {
|
|
38788
39184
|
throw new Error(
|
|
38789
39185
|
"the server confirmed a different workspace than this command created; run cswarm workspaces before doing anything else"
|
|
@@ -38799,7 +39195,7 @@ async function runNew(args) {
|
|
|
38799
39195
|
project: {
|
|
38800
39196
|
workspace_id: created,
|
|
38801
39197
|
name,
|
|
38802
|
-
stream_id: typeof response.stream_id === "string" &&
|
|
39198
|
+
stream_id: typeof response.stream_id === "string" && UUID_RE18.test(response.stream_id) ? response.stream_id : null
|
|
38803
39199
|
}
|
|
38804
39200
|
});
|
|
38805
39201
|
return;
|
|
@@ -39056,7 +39452,7 @@ async function runInvite(args) {
|
|
|
39056
39452
|
);
|
|
39057
39453
|
}
|
|
39058
39454
|
assertInvitationToken(response.invitation_token);
|
|
39059
|
-
const responseWorkspaceId =
|
|
39455
|
+
const responseWorkspaceId = uuid4(response.workspace_id, "workspace_id");
|
|
39060
39456
|
if (typeof response.workspace_name !== "string" || typeof response.inviter_display_name !== "string") {
|
|
39061
39457
|
throw new Error(
|
|
39062
39458
|
"the invitation was created without its fresh display labels; run invite again to issue a complete link"
|
|
@@ -39076,7 +39472,7 @@ async function runInvite(args) {
|
|
|
39076
39472
|
printJson({
|
|
39077
39473
|
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.",
|
|
39078
39474
|
status: response.status,
|
|
39079
|
-
invitation_id:
|
|
39475
|
+
invitation_id: uuid4(response.invitation_id, "invitation_id"),
|
|
39080
39476
|
invite_link: inviteLink
|
|
39081
39477
|
});
|
|
39082
39478
|
}
|
|
@@ -39188,7 +39584,7 @@ async function runLegacyAccept(args) {
|
|
|
39188
39584
|
{ kind: "accept_invitation", token: invitationToken }
|
|
39189
39585
|
)
|
|
39190
39586
|
);
|
|
39191
|
-
const acceptedWorkspace =
|
|
39587
|
+
const acceptedWorkspace = uuid4(response.workspace_id, "workspace_id");
|
|
39192
39588
|
await writeWorkspaceDefault(human.store, human.userId, acceptedWorkspace);
|
|
39193
39589
|
await writeCurrentTarget(cloud);
|
|
39194
39590
|
printJson({
|
|
@@ -39334,7 +39730,7 @@ async function runPrincipal(args) {
|
|
|
39334
39730
|
"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."
|
|
39335
39731
|
),
|
|
39336
39732
|
status: response.status,
|
|
39337
|
-
principal_id:
|
|
39733
|
+
principal_id: uuid4(response.principal_id, "principal_id")
|
|
39338
39734
|
});
|
|
39339
39735
|
return;
|
|
39340
39736
|
}
|
|
@@ -39442,8 +39838,8 @@ async function runToken(args) {
|
|
|
39442
39838
|
);
|
|
39443
39839
|
printJson(agentCredentialArtifact({
|
|
39444
39840
|
principalId,
|
|
39445
|
-
tokenId:
|
|
39446
|
-
runId:
|
|
39841
|
+
tokenId: uuid4(response.token_id, "token_id"),
|
|
39842
|
+
runId: uuid4(response.run_id, "run_id"),
|
|
39447
39843
|
token: response.agent_token,
|
|
39448
39844
|
expiresAt
|
|
39449
39845
|
}));
|
|
@@ -39573,7 +39969,7 @@ async function runLinkNew(args) {
|
|
|
39573
39969
|
2
|
|
39574
39970
|
);
|
|
39575
39971
|
const taskId = args.required("task-id");
|
|
39576
|
-
if (!
|
|
39972
|
+
if (!UUID_RE18.test(taskId)) {
|
|
39577
39973
|
throw new Error("--task-id must be the work item's UUID");
|
|
39578
39974
|
}
|
|
39579
39975
|
const site = capabilitySiteOrigin(
|
|
@@ -39603,11 +39999,11 @@ async function runLinkNew(args) {
|
|
|
39603
39999
|
);
|
|
39604
40000
|
if (response.capability_token === void 0) {
|
|
39605
40001
|
throw new Error(
|
|
39606
|
-
`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 ${
|
|
40002
|
+
`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`
|
|
39607
40003
|
);
|
|
39608
40004
|
}
|
|
39609
40005
|
assertCapabilityToken(response.capability_token);
|
|
39610
|
-
const capabilityId =
|
|
40006
|
+
const capabilityId = uuid4(response.capability_id, "capability_id");
|
|
39611
40007
|
const expiresAt = capabilityTimestamp(response.expires_at, "expires_at");
|
|
39612
40008
|
const url = capabilityUrl(site, response.capability_token);
|
|
39613
40009
|
if (args.has("json")) {
|
|
@@ -39633,7 +40029,7 @@ async function runLinkRevoke(args) {
|
|
|
39633
40029
|
2
|
|
39634
40030
|
);
|
|
39635
40031
|
const capabilityId = args.required("capability-id");
|
|
39636
|
-
if (!
|
|
40032
|
+
if (!UUID_RE18.test(capabilityId)) {
|
|
39637
40033
|
throw new Error(
|
|
39638
40034
|
"--capability-id must be the id printed when the link was created"
|
|
39639
40035
|
);
|
|
@@ -39651,7 +40047,7 @@ async function runLinkRevoke(args) {
|
|
|
39651
40047
|
{ kind: "revoke_capability_url", capability_id: capabilityId }
|
|
39652
40048
|
)
|
|
39653
40049
|
);
|
|
39654
|
-
const revoked =
|
|
40050
|
+
const revoked = uuid4(response.capability_id, "capability_id");
|
|
39655
40051
|
const revokedAt = capabilityTimestamp(response.revoked_at, "revoked_at");
|
|
39656
40052
|
const message = renderCapabilityRevoke(revoked, revokedAt);
|
|
39657
40053
|
if (args.has("json")) {
|
|
@@ -40212,7 +40608,7 @@ async function runReply(args) {
|
|
|
40212
40608
|
"json"
|
|
40213
40609
|
], 3);
|
|
40214
40610
|
const signalId = args.positionals[1];
|
|
40215
|
-
if (signalId === void 0 || !
|
|
40611
|
+
if (signalId === void 0 || !UUID_RE18.test(signalId)) {
|
|
40216
40612
|
throw new Error("reply requires the signal UUID being answered");
|
|
40217
40613
|
}
|
|
40218
40614
|
const body = args.positionals[2];
|
|
@@ -40442,6 +40838,52 @@ async function runSignalRead(args, inbox) {
|
|
|
40442
40838
|
})}
|
|
40443
40839
|
`);
|
|
40444
40840
|
}
|
|
40841
|
+
async function runReceipt(args) {
|
|
40842
|
+
args.assertShape([
|
|
40843
|
+
...TARGET_FLAGS,
|
|
40844
|
+
"workspace-id",
|
|
40845
|
+
...CREDENTIAL_FLAGS,
|
|
40846
|
+
"json"
|
|
40847
|
+
], 2);
|
|
40848
|
+
const signalId = args.positionals[1];
|
|
40849
|
+
if (!UUID_RE18.test(signalId)) {
|
|
40850
|
+
throw new Error("signal-id must be a UUID");
|
|
40851
|
+
}
|
|
40852
|
+
if (!args.has("agent-token-stdin")) {
|
|
40853
|
+
throw new Error(
|
|
40854
|
+
"receipt reads signals sent by an agent; provide --agent-token-stdin and --workspace-id"
|
|
40855
|
+
);
|
|
40856
|
+
}
|
|
40857
|
+
const cloud = await target(args);
|
|
40858
|
+
const selected = await commandWorkspaceAndCredential(args, cloud, {
|
|
40859
|
+
validateHumanWorkspace: true
|
|
40860
|
+
});
|
|
40861
|
+
let result;
|
|
40862
|
+
try {
|
|
40863
|
+
result = await readAgentDeliveryReceipts(
|
|
40864
|
+
cloud,
|
|
40865
|
+
selected.bearer,
|
|
40866
|
+
selected.selectedWorkspace,
|
|
40867
|
+
signalId
|
|
40868
|
+
);
|
|
40869
|
+
} catch (error) {
|
|
40870
|
+
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";
|
|
40871
|
+
throw new Error(
|
|
40872
|
+
`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}`
|
|
40873
|
+
);
|
|
40874
|
+
}
|
|
40875
|
+
const report = {
|
|
40876
|
+
...result,
|
|
40877
|
+
workspaceId: selected.selectedWorkspace,
|
|
40878
|
+
signalId: signalId.toLowerCase()
|
|
40879
|
+
};
|
|
40880
|
+
if (args.has("json")) {
|
|
40881
|
+
printJson(signalReceiptJsonPayload(report));
|
|
40882
|
+
return;
|
|
40883
|
+
}
|
|
40884
|
+
process.stdout.write(`${renderSignalReceiptReport(report)}
|
|
40885
|
+
`);
|
|
40886
|
+
}
|
|
40445
40887
|
async function runInboxFollowCommand(args) {
|
|
40446
40888
|
const cloud = await target(args);
|
|
40447
40889
|
const selected = await commandWorkspaceAndCredential(args, cloud, {
|
|
@@ -40542,7 +40984,7 @@ async function runInboxFollowCommand(args) {
|
|
|
40542
40984
|
}
|
|
40543
40985
|
}
|
|
40544
40986
|
function listenerUuid(value, flag) {
|
|
40545
|
-
if (!value || !
|
|
40987
|
+
if (!value || !UUID_RE18.test(value)) {
|
|
40546
40988
|
throw new Error(`--${flag} must be a UUID`);
|
|
40547
40989
|
}
|
|
40548
40990
|
return value.toLowerCase();
|
|
@@ -41605,7 +42047,7 @@ async function fileRows(context) {
|
|
|
41605
42047
|
);
|
|
41606
42048
|
}
|
|
41607
42049
|
async function resolveFileSelector(context, selector) {
|
|
41608
|
-
if (
|
|
42050
|
+
if (UUID_RE18.test(selector)) return selector.toLowerCase();
|
|
41609
42051
|
const rows3 = await fileRows(context);
|
|
41610
42052
|
const match = rows3.find(
|
|
41611
42053
|
(row) => row.name.toLowerCase() === selector.toLowerCase()
|
|
@@ -42117,6 +42559,10 @@ async function main() {
|
|
|
42117
42559
|
await runReply(args);
|
|
42118
42560
|
return;
|
|
42119
42561
|
}
|
|
42562
|
+
if (verb === "receipt") {
|
|
42563
|
+
await runReceipt(args);
|
|
42564
|
+
return;
|
|
42565
|
+
}
|
|
42120
42566
|
if (verb === "feed" || verb === "inbox") {
|
|
42121
42567
|
await runSignalRead(args, verb === "inbox");
|
|
42122
42568
|
return;
|
|
@@ -42193,7 +42639,7 @@ main().catch((error) => {
|
|
|
42193
42639
|
if (error instanceof WorkspaceCliError) {
|
|
42194
42640
|
const structured = error.structured();
|
|
42195
42641
|
const verb = process.argv[2];
|
|
42196
|
-
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");
|
|
42642
|
+
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");
|
|
42197
42643
|
if (json) {
|
|
42198
42644
|
process.stdout.write(`${JSON.stringify(structured, null, 2)}
|
|
42199
42645
|
`);
|