commonswarm 0.1.34 → 0.1.35
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 +464 -179
- package/package.json +1 -1
package/cswarm.cjs
CHANGED
|
@@ -4381,8 +4381,8 @@ var require_RealtimeChannel = __commonJS({
|
|
|
4381
4381
|
}
|
|
4382
4382
|
/** @internal */
|
|
4383
4383
|
_notThisChannelEvent(event, ref) {
|
|
4384
|
-
const { close, error, leave, join:
|
|
4385
|
-
const events = [close, error, leave,
|
|
4384
|
+
const { close, error, leave, join: join18 } = constants_1.CHANNEL_EVENTS;
|
|
4385
|
+
const events = [close, error, leave, join18];
|
|
4386
4386
|
return ref && events.includes(event) && ref !== this.joinPush.ref;
|
|
4387
4387
|
}
|
|
4388
4388
|
/** @internal */
|
|
@@ -13523,7 +13523,7 @@ module.exports = __toCommonJS(cli_exports);
|
|
|
13523
13523
|
var import_node_crypto19 = require("node:crypto");
|
|
13524
13524
|
var import_node_fs7 = require("node:fs");
|
|
13525
13525
|
var import_promises11 = require("node:fs/promises");
|
|
13526
|
-
var
|
|
13526
|
+
var import_node_path20 = require("node:path");
|
|
13527
13527
|
var import_promises12 = require("node:readline/promises");
|
|
13528
13528
|
|
|
13529
13529
|
// src/cloud/auth.ts
|
|
@@ -29571,8 +29571,195 @@ async function runInboxFollow(options) {
|
|
|
29571
29571
|
}
|
|
29572
29572
|
}
|
|
29573
29573
|
|
|
29574
|
-
// src/cloud/
|
|
29574
|
+
// src/cloud/arrival-watch.ts
|
|
29575
|
+
var import_node_os4 = require("node:os");
|
|
29576
|
+
var import_node_path4 = require("node:path");
|
|
29575
29577
|
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;
|
|
29578
|
+
var CURSOR_MAX_BYTES = 4 * 1024;
|
|
29579
|
+
var ARRIVAL_SNIPPET_MAX = 180;
|
|
29580
|
+
var ARRIVAL_WATCH_POLL_MS = 25e3;
|
|
29581
|
+
function stateRoot() {
|
|
29582
|
+
return process.env.XDG_STATE_HOME ? (0, import_node_path4.join)(process.env.XDG_STATE_HOME, "cswarm", "arrival-cursors") : (0, import_node_path4.join)((0, import_node_os4.homedir)(), ".cswarm", "arrival-cursors");
|
|
29583
|
+
}
|
|
29584
|
+
function arrivalCursorPath(target2, workspaceId2, principalId, root = stateRoot()) {
|
|
29585
|
+
return (0, import_node_path4.join)(
|
|
29586
|
+
root,
|
|
29587
|
+
`${target2.profileId}-${workspaceId2.toLowerCase()}-${principalId.toLowerCase()}.json`
|
|
29588
|
+
);
|
|
29589
|
+
}
|
|
29590
|
+
function parseCursor(raw, workspaceId2, principalId) {
|
|
29591
|
+
let value;
|
|
29592
|
+
try {
|
|
29593
|
+
value = JSON.parse(raw);
|
|
29594
|
+
} catch {
|
|
29595
|
+
throw new Error("stored arrival cursor is malformed");
|
|
29596
|
+
}
|
|
29597
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
29598
|
+
throw new Error("stored arrival cursor is malformed");
|
|
29599
|
+
}
|
|
29600
|
+
const row = value;
|
|
29601
|
+
const keys = Object.keys(row).sort();
|
|
29602
|
+
const cursor = row.cursor;
|
|
29603
|
+
if (keys.join(",") !== "cursor,principal_id,version,workspace_id" || row.version !== 1 || row.workspace_id !== workspaceId2.toLowerCase() || row.principal_id !== principalId.toLowerCase() || !(cursor === null || typeof cursor === "object" && !Array.isArray(cursor) && Object.keys(cursor).sort().join(",") === "created_at,id" && typeof cursor.created_at === "string" && Number.isFinite(Date.parse(cursor.created_at)) && typeof cursor.id === "string" && UUID_RE8.test(cursor.id))) {
|
|
29604
|
+
throw new Error("stored arrival cursor is malformed");
|
|
29605
|
+
}
|
|
29606
|
+
if (cursor === null) return null;
|
|
29607
|
+
return {
|
|
29608
|
+
created_at: cursor.created_at,
|
|
29609
|
+
id: cursor.id.toLowerCase()
|
|
29610
|
+
};
|
|
29611
|
+
}
|
|
29612
|
+
function fileArrivalCursorStore(options) {
|
|
29613
|
+
const workspaceId2 = options.workspaceId.toLowerCase();
|
|
29614
|
+
const principalId = options.principalId.toLowerCase();
|
|
29615
|
+
if (!UUID_RE8.test(workspaceId2) || !UUID_RE8.test(principalId)) {
|
|
29616
|
+
throw new Error("arrival cursor identity must use workspace and principal UUIDs");
|
|
29617
|
+
}
|
|
29618
|
+
const location2 = arrivalCursorPath(
|
|
29619
|
+
options.target,
|
|
29620
|
+
workspaceId2,
|
|
29621
|
+
principalId,
|
|
29622
|
+
options.stateDirectory
|
|
29623
|
+
);
|
|
29624
|
+
return {
|
|
29625
|
+
location: location2,
|
|
29626
|
+
async read() {
|
|
29627
|
+
const raw = await readSecureJsonFile(location2, CURSOR_MAX_BYTES);
|
|
29628
|
+
return raw === null ? void 0 : parseCursor(raw, workspaceId2, principalId);
|
|
29629
|
+
},
|
|
29630
|
+
async write(cursor) {
|
|
29631
|
+
const record = {
|
|
29632
|
+
version: 1,
|
|
29633
|
+
workspace_id: workspaceId2,
|
|
29634
|
+
principal_id: principalId,
|
|
29635
|
+
cursor
|
|
29636
|
+
};
|
|
29637
|
+
await writeSecureJsonFile(location2, JSON.stringify(record));
|
|
29638
|
+
}
|
|
29639
|
+
};
|
|
29640
|
+
}
|
|
29641
|
+
function arrivalSnippet(body) {
|
|
29642
|
+
const oneLine = body.replace(/[\u0000-\u001f\u007f-\u009f]/g, " ").replace(/\s+/g, " ").trim();
|
|
29643
|
+
if (oneLine.length <= ARRIVAL_SNIPPET_MAX) return oneLine;
|
|
29644
|
+
return `${oneLine.slice(0, ARRIVAL_SNIPPET_MAX - 1).trimEnd()}\u2026`;
|
|
29645
|
+
}
|
|
29646
|
+
function arrivalReplyCommand(signalId, workspaceId2, target2) {
|
|
29647
|
+
return `cswarm reply ${signalId} "<answer>" --agent-token-stdin --url ${target2.url} --anon-key ${target2.anonKey} --workspace-id ${workspaceId2}`;
|
|
29648
|
+
}
|
|
29649
|
+
function arrivalNotification(signal, workspaceId2, target2) {
|
|
29650
|
+
return {
|
|
29651
|
+
type: "arrival",
|
|
29652
|
+
workspace_id: workspaceId2,
|
|
29653
|
+
signal_id: signal.id,
|
|
29654
|
+
sender: signal.from,
|
|
29655
|
+
sender_kind: signal.from_kind,
|
|
29656
|
+
kind: signal.kind,
|
|
29657
|
+
snippet: arrivalSnippet(signal.body),
|
|
29658
|
+
reply_command: arrivalReplyCommand(signal.id, workspaceId2, target2)
|
|
29659
|
+
};
|
|
29660
|
+
}
|
|
29661
|
+
function formatArrivalNotification(notification) {
|
|
29662
|
+
return `CommonSwarm from ${notification.sender_kind} ${notification.sender}: ${notification.snippet} \u2014 reply: ${notification.reply_command}`;
|
|
29663
|
+
}
|
|
29664
|
+
function cursorOf(signal) {
|
|
29665
|
+
return { created_at: signal.created_at, id: signal.id };
|
|
29666
|
+
}
|
|
29667
|
+
function assertCursorPage(page) {
|
|
29668
|
+
if (!page.capabilities.cursorAfter || page.legacyCursorFallback) {
|
|
29669
|
+
throw new Error(
|
|
29670
|
+
"arrival watch needs a read service with durable cursor support"
|
|
29671
|
+
);
|
|
29672
|
+
}
|
|
29673
|
+
}
|
|
29674
|
+
async function runArrivalWatch(options) {
|
|
29675
|
+
const pollMs = options.pollMs ?? ARRIVAL_WATCH_POLL_MS;
|
|
29676
|
+
const random = options.random ?? Math.random;
|
|
29677
|
+
let cursor = await options.store.read();
|
|
29678
|
+
let baseline = cursor === void 0;
|
|
29679
|
+
let attempt = 0;
|
|
29680
|
+
const cancelled = () => options.signal?.aborted === true;
|
|
29681
|
+
const wait = async (ms) => {
|
|
29682
|
+
if (options.sleep) {
|
|
29683
|
+
await options.sleep(ms);
|
|
29684
|
+
return;
|
|
29685
|
+
}
|
|
29686
|
+
await new Promise((resolve) => {
|
|
29687
|
+
let timer2;
|
|
29688
|
+
const finish = () => {
|
|
29689
|
+
if (timer2 !== void 0) clearTimeout(timer2);
|
|
29690
|
+
options.signal?.removeEventListener("abort", finish);
|
|
29691
|
+
resolve();
|
|
29692
|
+
};
|
|
29693
|
+
if (cancelled() || ms <= 0) {
|
|
29694
|
+
resolve();
|
|
29695
|
+
return;
|
|
29696
|
+
}
|
|
29697
|
+
options.signal?.addEventListener("abort", finish, { once: true });
|
|
29698
|
+
timer2 = setTimeout(finish, ms);
|
|
29699
|
+
});
|
|
29700
|
+
};
|
|
29701
|
+
while (!cancelled()) {
|
|
29702
|
+
try {
|
|
29703
|
+
const page = await options.readPage({
|
|
29704
|
+
after: cursor ?? null,
|
|
29705
|
+
baseline,
|
|
29706
|
+
limit: baseline ? 1 : SIGNAL_FOLLOW_PAGE_LIMIT
|
|
29707
|
+
});
|
|
29708
|
+
assertCursorPage(page);
|
|
29709
|
+
if (page.signals.some(
|
|
29710
|
+
(row) => row.workspace_id !== options.workspaceId || row.to_agent !== options.principalId
|
|
29711
|
+
)) {
|
|
29712
|
+
throw new Error(
|
|
29713
|
+
"arrival read returned a message directed to another workspace or agent"
|
|
29714
|
+
);
|
|
29715
|
+
}
|
|
29716
|
+
attempt = 0;
|
|
29717
|
+
if (baseline) {
|
|
29718
|
+
if (page.rawCount > 0 && page.nextCursor === null) {
|
|
29719
|
+
throw new Error("arrival baseline returned no safe terminal cursor");
|
|
29720
|
+
}
|
|
29721
|
+
cursor = page.nextCursor;
|
|
29722
|
+
await options.store.write(cursor);
|
|
29723
|
+
baseline = false;
|
|
29724
|
+
if (cancelled()) break;
|
|
29725
|
+
await wait(pollMs);
|
|
29726
|
+
continue;
|
|
29727
|
+
}
|
|
29728
|
+
for (const row of page.signals) {
|
|
29729
|
+
if (cancelled()) break;
|
|
29730
|
+
await options.emit(row);
|
|
29731
|
+
cursor = cursorOf(row);
|
|
29732
|
+
await options.store.write(cursor);
|
|
29733
|
+
}
|
|
29734
|
+
if (cancelled()) break;
|
|
29735
|
+
const fullPage = page.rawCount >= SIGNAL_FOLLOW_PAGE_LIMIT;
|
|
29736
|
+
await wait(fullPage ? 0 : pollMs);
|
|
29737
|
+
} catch (error) {
|
|
29738
|
+
if (cancelled()) break;
|
|
29739
|
+
const http = followHttpDetails(error);
|
|
29740
|
+
const retryable = isRetryableFollowError(error) || http?.status === 429 || http !== null && http.status >= 500;
|
|
29741
|
+
if (!retryable) {
|
|
29742
|
+
return {
|
|
29743
|
+
reason: "error",
|
|
29744
|
+
error: error instanceof Error ? error : new Error(String(error))
|
|
29745
|
+
};
|
|
29746
|
+
}
|
|
29747
|
+
attempt += 1;
|
|
29748
|
+
const delayMs = nextFollowBackoffMs(
|
|
29749
|
+
attempt,
|
|
29750
|
+
http?.retryAfterMs ?? null,
|
|
29751
|
+
random
|
|
29752
|
+
);
|
|
29753
|
+
const typed = error instanceof Error ? error : new Error(String(error));
|
|
29754
|
+
options.onRetry?.(typed, delayMs);
|
|
29755
|
+
await wait(delayMs);
|
|
29756
|
+
}
|
|
29757
|
+
}
|
|
29758
|
+
return { reason: "cancelled" };
|
|
29759
|
+
}
|
|
29760
|
+
|
|
29761
|
+
// src/cloud/delivery-receipts.ts
|
|
29762
|
+
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;
|
|
29576
29763
|
var DeliveryReceiptReadError = class extends Error {
|
|
29577
29764
|
constructor(code, message, status = null) {
|
|
29578
29765
|
super(message);
|
|
@@ -29591,7 +29778,7 @@ var ACK_OUTCOMES = /* @__PURE__ */ new Set([
|
|
|
29591
29778
|
"failed_terminal"
|
|
29592
29779
|
]);
|
|
29593
29780
|
function uuid3(value, field) {
|
|
29594
|
-
if (typeof value !== "string" || !
|
|
29781
|
+
if (typeof value !== "string" || !UUID_RE9.test(value)) {
|
|
29595
29782
|
throw new DeliveryReceiptReadError(
|
|
29596
29783
|
"protocol",
|
|
29597
29784
|
`delivery receipt returned a malformed ${field}`
|
|
@@ -29980,8 +30167,8 @@ function attachStderrTailExitObserver(child, onStderrTail) {
|
|
|
29980
30167
|
// src/host/opencode.ts
|
|
29981
30168
|
var import_node_fs3 = require("node:fs");
|
|
29982
30169
|
var import_promises4 = require("node:fs/promises");
|
|
29983
|
-
var
|
|
29984
|
-
var
|
|
30170
|
+
var import_node_os5 = require("node:os");
|
|
30171
|
+
var import_node_path6 = require("node:path");
|
|
29985
30172
|
|
|
29986
30173
|
// src/host/bounds.ts
|
|
29987
30174
|
var ACP_MAX_LINE_BYTES = 1048576;
|
|
@@ -30063,7 +30250,7 @@ function sanitizeChildEnv(parent = process.env) {
|
|
|
30063
30250
|
|
|
30064
30251
|
// src/host/session.ts
|
|
30065
30252
|
var import_node_fs2 = require("node:fs");
|
|
30066
|
-
var
|
|
30253
|
+
var import_node_path5 = require("node:path");
|
|
30067
30254
|
|
|
30068
30255
|
// src/host/permission.ts
|
|
30069
30256
|
function allowOnceOrDeny(request) {
|
|
@@ -30544,7 +30731,7 @@ function assertAbsoluteExistingCwd(cwd) {
|
|
|
30544
30731
|
if (!cwd || typeof cwd !== "string") {
|
|
30545
30732
|
throw new AcpProtocolError("cwd is required", "invalid_cwd");
|
|
30546
30733
|
}
|
|
30547
|
-
if (!(0,
|
|
30734
|
+
if (!(0, import_node_path5.isAbsolute)(cwd)) {
|
|
30548
30735
|
throw new AcpProtocolError("cwd must be an absolute path", "invalid_cwd");
|
|
30549
30736
|
}
|
|
30550
30737
|
let st;
|
|
@@ -31254,8 +31441,8 @@ function isProcessAlive(pid) {
|
|
|
31254
31441
|
}
|
|
31255
31442
|
}
|
|
31256
31443
|
function resolveOpenCodeExecutable(executable = "opencode", pathEnv) {
|
|
31257
|
-
if ((0,
|
|
31258
|
-
const abs = (0,
|
|
31444
|
+
if ((0, import_node_path6.isAbsolute)(executable) || executable.includes("/")) {
|
|
31445
|
+
const abs = (0, import_node_path6.resolve)(executable);
|
|
31259
31446
|
try {
|
|
31260
31447
|
(0, import_node_fs3.accessSync)(abs, import_node_fs3.constants.X_OK);
|
|
31261
31448
|
} catch {
|
|
@@ -31273,7 +31460,7 @@ function resolveOpenCodeExecutable(executable = "opencode", pathEnv) {
|
|
|
31273
31460
|
const pathValue = pathEnv ?? process.env.PATH ?? "";
|
|
31274
31461
|
for (const dir of pathValue.split(":")) {
|
|
31275
31462
|
if (!dir) continue;
|
|
31276
|
-
const candidate = (0,
|
|
31463
|
+
const candidate = (0, import_node_path6.join)(dir, executable);
|
|
31277
31464
|
try {
|
|
31278
31465
|
(0, import_node_fs3.accessSync)(candidate, import_node_fs3.constants.X_OK);
|
|
31279
31466
|
try {
|
|
@@ -31305,7 +31492,7 @@ function buildOpenCodeHomeOwner(options) {
|
|
|
31305
31492
|
};
|
|
31306
31493
|
}
|
|
31307
31494
|
async function writeOpenCodeHomeOwner(home, owner) {
|
|
31308
|
-
const path = (0,
|
|
31495
|
+
const path = (0, import_node_path6.join)(home, OPENCODE_HOME_OWNER_FILE);
|
|
31309
31496
|
await (0, import_promises4.writeFile)(path, `${JSON.stringify(owner)}
|
|
31310
31497
|
`, {
|
|
31311
31498
|
flag: "wx",
|
|
@@ -31314,7 +31501,7 @@ async function writeOpenCodeHomeOwner(home, owner) {
|
|
|
31314
31501
|
await (0, import_promises4.chmod)(path, 384);
|
|
31315
31502
|
}
|
|
31316
31503
|
async function readOpenCodeHomeOwner(home) {
|
|
31317
|
-
const path = (0,
|
|
31504
|
+
const path = (0, import_node_path6.join)(home, OPENCODE_HOME_OWNER_FILE);
|
|
31318
31505
|
let raw;
|
|
31319
31506
|
try {
|
|
31320
31507
|
raw = await (0, import_promises4.readFile)(path, "utf8");
|
|
@@ -31332,7 +31519,7 @@ async function readOpenCodeHomeOwner(home) {
|
|
|
31332
31519
|
}
|
|
31333
31520
|
}
|
|
31334
31521
|
async function releaseOpenCodeHome(home, instanceId) {
|
|
31335
|
-
if (!(0,
|
|
31522
|
+
if (!(0, import_node_path6.isAbsolute)(home)) return;
|
|
31336
31523
|
const owner = await readOpenCodeHomeOwner(home);
|
|
31337
31524
|
if (owner && owner.instanceId !== instanceId) {
|
|
31338
31525
|
return;
|
|
@@ -31457,15 +31644,15 @@ async function readValidatedOpenCodeAuth(sourceAuthPath, options) {
|
|
|
31457
31644
|
}
|
|
31458
31645
|
function resolveOpenCodeAuthSourcePath(parent = process.env) {
|
|
31459
31646
|
const xdgData = parent.XDG_DATA_HOME;
|
|
31460
|
-
if (typeof xdgData === "string" && (0,
|
|
31461
|
-
return (0,
|
|
31647
|
+
if (typeof xdgData === "string" && (0, import_node_path6.isAbsolute)(xdgData)) {
|
|
31648
|
+
return (0, import_node_path6.join)(xdgData, "opencode", "auth.json");
|
|
31462
31649
|
}
|
|
31463
|
-
const home = parent.HOME ?? (0,
|
|
31464
|
-
return (0,
|
|
31650
|
+
const home = parent.HOME ?? (0, import_node_os5.homedir)();
|
|
31651
|
+
return (0, import_node_path6.join)(home, ".local", "share", "opencode", "auth.json");
|
|
31465
31652
|
}
|
|
31466
31653
|
async function prepareOpenCodeIsolatedHome(options) {
|
|
31467
|
-
const home = options.home ?? await (0, import_promises4.mkdtemp)((0,
|
|
31468
|
-
if (!(0,
|
|
31654
|
+
const home = options.home ?? await (0, import_promises4.mkdtemp)((0, import_node_path6.join)((0, import_node_os5.tmpdir)(), OPENCODE_HOME_PREFIX));
|
|
31655
|
+
if (!(0, import_node_path6.isAbsolute)(home)) {
|
|
31469
31656
|
throw new AcpHostError(
|
|
31470
31657
|
"isolated_home_invalid",
|
|
31471
31658
|
"isolated OpenCode home must be absolute"
|
|
@@ -31473,21 +31660,21 @@ async function prepareOpenCodeIsolatedHome(options) {
|
|
|
31473
31660
|
}
|
|
31474
31661
|
await (0, import_promises4.chmod)(home, 448);
|
|
31475
31662
|
try {
|
|
31476
|
-
const xdgConfig = (0,
|
|
31477
|
-
const xdgData = (0,
|
|
31478
|
-
const xdgCache = (0,
|
|
31479
|
-
const xdgState = (0,
|
|
31663
|
+
const xdgConfig = (0, import_node_path6.join)(home, "xdg-config");
|
|
31664
|
+
const xdgData = (0, import_node_path6.join)(home, "xdg-data");
|
|
31665
|
+
const xdgCache = (0, import_node_path6.join)(home, "xdg-cache");
|
|
31666
|
+
const xdgState = (0, import_node_path6.join)(home, "xdg-state");
|
|
31480
31667
|
for (const dir of [xdgConfig, xdgData, xdgCache, xdgState]) {
|
|
31481
31668
|
await (0, import_promises4.mkdir)(dir, { recursive: true, mode: 448 });
|
|
31482
31669
|
await (0, import_promises4.chmod)(dir, 448);
|
|
31483
31670
|
}
|
|
31484
|
-
const configDir = (0,
|
|
31485
|
-
const dataDir = (0,
|
|
31671
|
+
const configDir = (0, import_node_path6.join)(xdgConfig, "opencode");
|
|
31672
|
+
const dataDir = (0, import_node_path6.join)(xdgData, "opencode");
|
|
31486
31673
|
await (0, import_promises4.mkdir)(configDir, { recursive: true, mode: 448 });
|
|
31487
31674
|
await (0, import_promises4.mkdir)(dataDir, { recursive: true, mode: 448 });
|
|
31488
31675
|
await (0, import_promises4.chmod)(configDir, 448);
|
|
31489
31676
|
await (0, import_promises4.chmod)(dataDir, 448);
|
|
31490
|
-
const configPath = (0,
|
|
31677
|
+
const configPath = (0, import_node_path6.join)(configDir, "opencode.json");
|
|
31491
31678
|
await (0, import_promises4.writeFile)(
|
|
31492
31679
|
configPath,
|
|
31493
31680
|
buildOpenCodeSafeConfigJson(
|
|
@@ -31501,7 +31688,7 @@ async function prepareOpenCodeIsolatedHome(options) {
|
|
|
31501
31688
|
allowMissing: options.allowMissingAuth === true
|
|
31502
31689
|
});
|
|
31503
31690
|
if (authBytes) {
|
|
31504
|
-
const destAuth = (0,
|
|
31691
|
+
const destAuth = (0, import_node_path6.join)(dataDir, "auth.json");
|
|
31505
31692
|
await (0, import_promises4.writeFile)(destAuth, authBytes, { flag: "wx", mode: 384 });
|
|
31506
31693
|
await (0, import_promises4.chmod)(destAuth, 384);
|
|
31507
31694
|
}
|
|
@@ -31516,7 +31703,7 @@ async function prepareOpenCodeIsolatedHome(options) {
|
|
|
31516
31703
|
}
|
|
31517
31704
|
}
|
|
31518
31705
|
function buildOpenCodeChildEnv(parent, home) {
|
|
31519
|
-
if (!(0,
|
|
31706
|
+
if (!(0, import_node_path6.isAbsolute)(home)) {
|
|
31520
31707
|
throw new AcpHostError(
|
|
31521
31708
|
"isolated_home_invalid",
|
|
31522
31709
|
"isolated OpenCode home must be absolute"
|
|
@@ -31526,20 +31713,20 @@ function buildOpenCodeChildEnv(parent, home) {
|
|
|
31526
31713
|
return {
|
|
31527
31714
|
...base,
|
|
31528
31715
|
HOME: home,
|
|
31529
|
-
XDG_CONFIG_HOME: (0,
|
|
31530
|
-
XDG_DATA_HOME: (0,
|
|
31531
|
-
XDG_CACHE_HOME: (0,
|
|
31532
|
-
XDG_STATE_HOME: (0,
|
|
31716
|
+
XDG_CONFIG_HOME: (0, import_node_path6.join)(home, "xdg-config"),
|
|
31717
|
+
XDG_DATA_HOME: (0, import_node_path6.join)(home, "xdg-data"),
|
|
31718
|
+
XDG_CACHE_HOME: (0, import_node_path6.join)(home, "xdg-cache"),
|
|
31719
|
+
XDG_STATE_HOME: (0, import_node_path6.join)(home, "xdg-state"),
|
|
31533
31720
|
// Measured 1.18.10: private home alone still merges project opencode.json.
|
|
31534
31721
|
OPENCODE_DISABLE_PROJECT_CONFIG: "1"
|
|
31535
31722
|
};
|
|
31536
31723
|
}
|
|
31537
31724
|
async function assertOpenCodeEffectiveConfig(options) {
|
|
31538
|
-
const hostile = await (0, import_promises4.mkdtemp)((0,
|
|
31725
|
+
const hostile = await (0, import_promises4.mkdtemp)((0, import_node_path6.join)((0, import_node_os5.tmpdir)(), "cswarm-opencode-hostile-"));
|
|
31539
31726
|
try {
|
|
31540
31727
|
await (0, import_promises4.chmod)(hostile, 448);
|
|
31541
31728
|
await (0, import_promises4.writeFile)(
|
|
31542
|
-
(0,
|
|
31729
|
+
(0, import_node_path6.join)(hostile, "opencode.json"),
|
|
31543
31730
|
`${JSON.stringify({
|
|
31544
31731
|
permission: {
|
|
31545
31732
|
bash: "allow",
|
|
@@ -31647,7 +31834,7 @@ async function sweepStaleOpenCodeHomes(options) {
|
|
|
31647
31834
|
const maxAgeMs = options?.maxAgeMs ?? STALE_HOME_MAX_AGE_MS;
|
|
31648
31835
|
const now = options?.now ?? Date.now();
|
|
31649
31836
|
const alive = options?.isAlive ?? isProcessAlive;
|
|
31650
|
-
const root = options?.root ?? (0,
|
|
31837
|
+
const root = options?.root ?? (0, import_node_os5.tmpdir)();
|
|
31651
31838
|
const selfUid = typeof process.getuid === "function" ? process.getuid() : null;
|
|
31652
31839
|
let removed = 0;
|
|
31653
31840
|
let entries;
|
|
@@ -31658,7 +31845,7 @@ async function sweepStaleOpenCodeHomes(options) {
|
|
|
31658
31845
|
}
|
|
31659
31846
|
for (const name of entries) {
|
|
31660
31847
|
if (!name.startsWith(OPENCODE_HOME_PREFIX)) continue;
|
|
31661
|
-
const full = (0,
|
|
31848
|
+
const full = (0, import_node_path6.join)(root, name);
|
|
31662
31849
|
try {
|
|
31663
31850
|
const st = await (0, import_promises4.lstat)(full);
|
|
31664
31851
|
if (!st.isDirectory() || st.isSymbolicLink()) continue;
|
|
@@ -31836,7 +32023,7 @@ async function openOpenCodeAcpSession(options) {
|
|
|
31836
32023
|
// src/host/claude.ts
|
|
31837
32024
|
var import_node_child_process4 = require("node:child_process");
|
|
31838
32025
|
var import_node_fs4 = require("node:fs");
|
|
31839
|
-
var
|
|
32026
|
+
var import_node_path7 = require("node:path");
|
|
31840
32027
|
var CHILD_EXIT_WAIT_MS2 = 3e3;
|
|
31841
32028
|
var CHILD_KILL_WAIT_MS2 = 1e3;
|
|
31842
32029
|
var WINDOWS_NPM_SHIM_MAX_BYTES = 64 * 1024;
|
|
@@ -31856,11 +32043,11 @@ function isPackagedClaudeBridge(executable) {
|
|
|
31856
32043
|
function resolvePackagedClaudeBridge(pathEnv, platform = process.platform) {
|
|
31857
32044
|
const pathValue = pathEnv ?? process.env.PATH ?? "";
|
|
31858
32045
|
const names = platform === "win32" ? ["claude-agent-acp.cmd"] : ["claude-agent-acp"];
|
|
31859
|
-
for (const dir of pathValue.split(
|
|
32046
|
+
for (const dir of pathValue.split(import_node_path7.delimiter)) {
|
|
31860
32047
|
if (!dir) continue;
|
|
31861
32048
|
for (const name of names) {
|
|
31862
32049
|
try {
|
|
31863
|
-
const candidate = resolvedClaudeCandidate((0,
|
|
32050
|
+
const candidate = resolvedClaudeCandidate((0, import_node_path7.join)(dir, name), platform);
|
|
31864
32051
|
if (isPackagedClaudeBridge(candidate)) return candidate;
|
|
31865
32052
|
} catch {
|
|
31866
32053
|
}
|
|
@@ -31889,7 +32076,7 @@ function resolveWindowsNpmShim(shim) {
|
|
|
31889
32076
|
`unrecognized claude-agent-acp npm shim: ${shim}`
|
|
31890
32077
|
);
|
|
31891
32078
|
}
|
|
31892
|
-
const target2 = (0,
|
|
32079
|
+
const target2 = (0, import_node_path7.join)((0, import_node_path7.dirname)(shim), ...WINDOWS_NPM_ENTRYPOINT);
|
|
31893
32080
|
try {
|
|
31894
32081
|
(0, import_node_fs4.accessSync)(target2, import_node_fs4.constants.R_OK);
|
|
31895
32082
|
return (0, import_node_fs4.realpathSync)(target2);
|
|
@@ -31903,12 +32090,12 @@ function resolveWindowsNpmShim(shim) {
|
|
|
31903
32090
|
function resolvedClaudeCandidate(candidate, platform) {
|
|
31904
32091
|
(0, import_node_fs4.accessSync)(candidate, import_node_fs4.constants.X_OK);
|
|
31905
32092
|
const real = (0, import_node_fs4.realpathSync)(candidate);
|
|
31906
|
-
return platform === "win32" && (0,
|
|
32093
|
+
return platform === "win32" && (0, import_node_path7.extname)(real).toLowerCase() === ".cmd" ? resolveWindowsNpmShim(real) : real;
|
|
31907
32094
|
}
|
|
31908
32095
|
function resolveClaudeExecutable(executable = "claude-agent-acp", pathEnv, platform = process.platform) {
|
|
31909
|
-
if ((0,
|
|
31910
|
-
const abs = (0,
|
|
31911
|
-
const candidates = platform === "win32" && (0,
|
|
32096
|
+
if ((0, import_node_path7.isAbsolute)(executable) || executable.includes("/") || executable.includes("\\")) {
|
|
32097
|
+
const abs = (0, import_node_path7.resolve)(executable);
|
|
32098
|
+
const candidates = platform === "win32" && (0, import_node_path7.extname)(abs) === "" ? [`${abs}.cmd`] : [abs];
|
|
31912
32099
|
for (const candidate of candidates) {
|
|
31913
32100
|
try {
|
|
31914
32101
|
return resolvedClaudeCandidate(candidate, platform);
|
|
@@ -31919,11 +32106,11 @@ function resolveClaudeExecutable(executable = "claude-agent-acp", pathEnv, platf
|
|
|
31919
32106
|
throw new AcpHostError("executable_missing", `not executable: ${abs}`);
|
|
31920
32107
|
}
|
|
31921
32108
|
const pathValue = pathEnv ?? process.env.PATH ?? "";
|
|
31922
|
-
const names = platform === "win32" && (0,
|
|
31923
|
-
for (const dir of pathValue.split(
|
|
32109
|
+
const names = platform === "win32" && (0, import_node_path7.extname)(executable) === "" ? [`${executable}.cmd`] : [executable];
|
|
32110
|
+
for (const dir of pathValue.split(import_node_path7.delimiter)) {
|
|
31924
32111
|
if (!dir) continue;
|
|
31925
32112
|
for (const name of names) {
|
|
31926
|
-
const candidate = (0,
|
|
32113
|
+
const candidate = (0, import_node_path7.join)(dir, name);
|
|
31927
32114
|
try {
|
|
31928
32115
|
return resolvedClaudeCandidate(candidate, platform);
|
|
31929
32116
|
} catch (error) {
|
|
@@ -31937,7 +32124,7 @@ function resolveClaudeExecutable(executable = "claude-agent-acp", pathEnv, platf
|
|
|
31937
32124
|
);
|
|
31938
32125
|
}
|
|
31939
32126
|
function buildClaudeLaunch(executable, args, platform = process.platform) {
|
|
31940
|
-
return platform === "win32" && (0,
|
|
32127
|
+
return platform === "win32" && (0, import_node_path7.extname)(executable).toLowerCase() === ".js" ? { command: process.execPath, args: [executable, ...args] } : { command: executable, args: [...args] };
|
|
31941
32128
|
}
|
|
31942
32129
|
function parseClaudeVersionOutput(stdout) {
|
|
31943
32130
|
return parseProviderVersionOutput(stdout, /\bclaude-agent-acp\b/i);
|
|
@@ -32190,7 +32377,7 @@ async function openClaudeAcpSession(options) {
|
|
|
32190
32377
|
// src/host/codex.ts
|
|
32191
32378
|
var import_node_child_process5 = require("node:child_process");
|
|
32192
32379
|
var import_node_fs5 = require("node:fs");
|
|
32193
|
-
var
|
|
32380
|
+
var import_node_path8 = require("node:path");
|
|
32194
32381
|
var CHILD_EXIT_WAIT_MS3 = 3e3;
|
|
32195
32382
|
var CHILD_KILL_WAIT_MS3 = 1e3;
|
|
32196
32383
|
var WINDOWS_NPM_SHIM_MAX_BYTES2 = 64 * 1024;
|
|
@@ -32219,7 +32406,7 @@ function resolveWindowsNpmShim2(shim) {
|
|
|
32219
32406
|
`unrecognized codex-acp npm shim: ${shim}`
|
|
32220
32407
|
);
|
|
32221
32408
|
}
|
|
32222
|
-
const target2 = (0,
|
|
32409
|
+
const target2 = (0, import_node_path8.join)((0, import_node_path8.dirname)(shim), ...WINDOWS_NPM_ENTRYPOINT2);
|
|
32223
32410
|
try {
|
|
32224
32411
|
(0, import_node_fs5.accessSync)(target2, import_node_fs5.constants.R_OK);
|
|
32225
32412
|
return (0, import_node_fs5.realpathSync)(target2);
|
|
@@ -32233,12 +32420,12 @@ function resolveWindowsNpmShim2(shim) {
|
|
|
32233
32420
|
function resolvedCodexCandidate(candidate, platform) {
|
|
32234
32421
|
(0, import_node_fs5.accessSync)(candidate, import_node_fs5.constants.X_OK);
|
|
32235
32422
|
const real = (0, import_node_fs5.realpathSync)(candidate);
|
|
32236
|
-
return platform === "win32" && (0,
|
|
32423
|
+
return platform === "win32" && (0, import_node_path8.extname)(real).toLowerCase() === ".cmd" ? resolveWindowsNpmShim2(real) : real;
|
|
32237
32424
|
}
|
|
32238
32425
|
function resolveCodexExecutable(executable = "codex-acp", pathEnv, platform = process.platform) {
|
|
32239
|
-
if ((0,
|
|
32240
|
-
const abs = (0,
|
|
32241
|
-
const candidates = platform === "win32" && (0,
|
|
32426
|
+
if ((0, import_node_path8.isAbsolute)(executable) || executable.includes("/") || executable.includes("\\")) {
|
|
32427
|
+
const abs = (0, import_node_path8.resolve)(executable);
|
|
32428
|
+
const candidates = platform === "win32" && (0, import_node_path8.extname)(abs) === "" ? [`${abs}.cmd`] : [abs];
|
|
32242
32429
|
for (const candidate of candidates) {
|
|
32243
32430
|
try {
|
|
32244
32431
|
return resolvedCodexCandidate(candidate, platform);
|
|
@@ -32249,11 +32436,11 @@ function resolveCodexExecutable(executable = "codex-acp", pathEnv, platform = pr
|
|
|
32249
32436
|
throw new AcpHostError("executable_missing", `not executable: ${abs}`);
|
|
32250
32437
|
}
|
|
32251
32438
|
const pathValue = pathEnv ?? process.env.PATH ?? "";
|
|
32252
|
-
const names = platform === "win32" && (0,
|
|
32253
|
-
for (const dir of pathValue.split(
|
|
32439
|
+
const names = platform === "win32" && (0, import_node_path8.extname)(executable) === "" ? [`${executable}.cmd`] : [executable];
|
|
32440
|
+
for (const dir of pathValue.split(import_node_path8.delimiter)) {
|
|
32254
32441
|
if (!dir) continue;
|
|
32255
32442
|
for (const name of names) {
|
|
32256
|
-
const candidate = (0,
|
|
32443
|
+
const candidate = (0, import_node_path8.join)(dir, name);
|
|
32257
32444
|
try {
|
|
32258
32445
|
return resolvedCodexCandidate(candidate, platform);
|
|
32259
32446
|
} catch (error) {
|
|
@@ -32267,7 +32454,7 @@ function resolveCodexExecutable(executable = "codex-acp", pathEnv, platform = pr
|
|
|
32267
32454
|
);
|
|
32268
32455
|
}
|
|
32269
32456
|
function buildCodexLaunch(executable, args, platform = process.platform) {
|
|
32270
|
-
return platform === "win32" && (0,
|
|
32457
|
+
return platform === "win32" && (0, import_node_path8.extname)(executable).toLowerCase() === ".js" ? { command: process.execPath, args: [executable, ...args] } : { command: executable, args: [...args] };
|
|
32271
32458
|
}
|
|
32272
32459
|
function parseCodexVersionOutput(stdout) {
|
|
32273
32460
|
return parseProviderVersionOutput(stdout, /@agentclientprotocol\/codex-acp\b/i);
|
|
@@ -32481,7 +32668,7 @@ async function resolveBudgetAndPrompt(session, prompt, budget) {
|
|
|
32481
32668
|
}
|
|
32482
32669
|
|
|
32483
32670
|
// src/listener/engine.ts
|
|
32484
|
-
var
|
|
32671
|
+
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;
|
|
32485
32672
|
var TERMINAL_STATES = /* @__PURE__ */ new Set(["done", "expired", "failed"]);
|
|
32486
32673
|
var REPLY_MAX_CODE_UNITS = 2e3;
|
|
32487
32674
|
var TRUNCATION_SUFFIX = "\n[Reply truncated by CommonSwarm]";
|
|
@@ -32489,7 +32676,7 @@ var UNSAFE_CONTROLS_RE = /[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f-\u009f\u
|
|
|
32489
32676
|
var LISTENER_MAX_PROMPT_ATTEMPTS = 3;
|
|
32490
32677
|
var LISTENER_MAX_POST_ATTEMPTS = 5;
|
|
32491
32678
|
function listenerReplyCommandId(signalId, effectOrdinal = 0) {
|
|
32492
|
-
if (!
|
|
32679
|
+
if (!UUID_RE10.test(signalId)) {
|
|
32493
32680
|
throw new Error("listener signal id must be a UUID");
|
|
32494
32681
|
}
|
|
32495
32682
|
if (!Number.isSafeInteger(effectOrdinal) || effectOrdinal < 0) {
|
|
@@ -32950,10 +33137,10 @@ var ListenerEngine = class {
|
|
|
32950
33137
|
|
|
32951
33138
|
// src/listener/file-store.ts
|
|
32952
33139
|
var import_node_crypto13 = require("node:crypto");
|
|
32953
|
-
var
|
|
32954
|
-
var
|
|
33140
|
+
var import_node_os6 = require("node:os");
|
|
33141
|
+
var import_node_path9 = require("node:path");
|
|
32955
33142
|
var import_node_util = require("node:util");
|
|
32956
|
-
var
|
|
33143
|
+
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;
|
|
32957
33144
|
var COMMAND_ID_RE2 = /^[A-Za-z0-9_-]{8,72}$/;
|
|
32958
33145
|
var MAX_EFFECT_BYTES = 1024 * 1024;
|
|
32959
33146
|
var STATES = /* @__PURE__ */ new Set([
|
|
@@ -32988,10 +33175,10 @@ var V1_EFFECT_KEYS = /* @__PURE__ */ new Set([
|
|
|
32988
33175
|
]);
|
|
32989
33176
|
var V2_EFFECT_KEYS = /* @__PURE__ */ new Set([...V1_EFFECT_KEYS, "signalKind"]);
|
|
32990
33177
|
function defaultListenerStateDirectory() {
|
|
32991
|
-
return process.env.XDG_STATE_HOME ? (0,
|
|
33178
|
+
return process.env.XDG_STATE_HOME ? (0, import_node_path9.join)(process.env.XDG_STATE_HOME, "cswarm", "listeners") : (0, import_node_path9.join)((0, import_node_os6.homedir)(), ".cswarm", "listeners");
|
|
32992
33179
|
}
|
|
32993
33180
|
function listenerInstanceKey(input) {
|
|
32994
|
-
if (!
|
|
33181
|
+
if (!UUID_RE11.test(input.workspaceId) || !UUID_RE11.test(input.principalId)) {
|
|
32995
33182
|
throw new Error("listener workspace and principal ids must be UUIDs");
|
|
32996
33183
|
}
|
|
32997
33184
|
if (!input.profileId || input.profileId.includes("\0")) {
|
|
@@ -33023,7 +33210,7 @@ function parseListenerEffectRecord(raw, expectedId) {
|
|
|
33023
33210
|
throw new Error("stored listener effect is malformed");
|
|
33024
33211
|
}
|
|
33025
33212
|
const row = value;
|
|
33026
|
-
if (typeof row.version !== "number" || row.version !== 1 && row.version !== 2 || typeof row.signalId !== "string" || row.signalId.toLowerCase() !== expectedId || !
|
|
33213
|
+
if (typeof row.version !== "number" || row.version !== 1 && row.version !== 2 || typeof row.signalId !== "string" || row.signalId.toLowerCase() !== expectedId || !UUID_RE11.test(row.signalId)) {
|
|
33027
33214
|
throw new Error("stored listener effect is malformed");
|
|
33028
33215
|
}
|
|
33029
33216
|
if (row.version === 1) {
|
|
@@ -33040,7 +33227,7 @@ function upcastV1Ask(row) {
|
|
|
33040
33227
|
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))) {
|
|
33041
33228
|
throw new Error("stored listener effect is malformed");
|
|
33042
33229
|
}
|
|
33043
|
-
if (row.replySignalId !== null && !
|
|
33230
|
+
if (row.replySignalId !== null && !UUID_RE11.test(row.replySignalId)) {
|
|
33044
33231
|
throw new Error("stored listener effect is malformed");
|
|
33045
33232
|
}
|
|
33046
33233
|
return {
|
|
@@ -33079,7 +33266,7 @@ function parseV2Record(row) {
|
|
|
33079
33266
|
if (typeof row.commandId !== "string" || !COMMAND_ID_RE2.test(row.commandId) || row.state === "observed") {
|
|
33080
33267
|
throw new Error("stored listener effect is malformed");
|
|
33081
33268
|
}
|
|
33082
|
-
if (row.replySignalId !== null && !
|
|
33269
|
+
if (row.replySignalId !== null && !UUID_RE11.test(row.replySignalId)) {
|
|
33083
33270
|
throw new Error("stored listener effect is malformed");
|
|
33084
33271
|
}
|
|
33085
33272
|
}
|
|
@@ -33103,7 +33290,7 @@ function parseV2Record(row) {
|
|
|
33103
33290
|
};
|
|
33104
33291
|
}
|
|
33105
33292
|
function newObservedNoteRecord(input) {
|
|
33106
|
-
if (!
|
|
33293
|
+
if (!UUID_RE11.test(input.signalId)) {
|
|
33107
33294
|
throw new Error("listener note signal id must be a UUID");
|
|
33108
33295
|
}
|
|
33109
33296
|
if (input.body.length < 1) {
|
|
@@ -33210,16 +33397,16 @@ var FileListenerEffectStore = class {
|
|
|
33210
33397
|
effectsDirectory;
|
|
33211
33398
|
constructor(options) {
|
|
33212
33399
|
const root = options.stateDirectory ?? defaultListenerStateDirectory();
|
|
33213
|
-
if (!(0,
|
|
33400
|
+
if (!(0, import_node_path9.isAbsolute)(root)) {
|
|
33214
33401
|
throw new Error("listener state directory must be absolute");
|
|
33215
33402
|
}
|
|
33216
|
-
this.instanceDirectory = (0,
|
|
33217
|
-
this.effectsDirectory = (0,
|
|
33403
|
+
this.instanceDirectory = (0, import_node_path9.join)(root, listenerInstanceKey(options));
|
|
33404
|
+
this.effectsDirectory = (0, import_node_path9.join)(this.instanceDirectory, "effects");
|
|
33218
33405
|
}
|
|
33219
33406
|
async read(signalId) {
|
|
33220
33407
|
const id = this.checkedId(signalId);
|
|
33221
33408
|
const raw = await readSecureJsonFile(
|
|
33222
|
-
(0,
|
|
33409
|
+
(0, import_node_path9.join)(this.effectsDirectory, `${id}.json`),
|
|
33223
33410
|
MAX_EFFECT_BYTES
|
|
33224
33411
|
);
|
|
33225
33412
|
return raw === null ? null : parseListenerEffectRecord(raw, id);
|
|
@@ -33232,12 +33419,12 @@ var FileListenerEffectStore = class {
|
|
|
33232
33419
|
throw new Error("listener effect is too large");
|
|
33233
33420
|
}
|
|
33234
33421
|
await writeSecureJsonFile(
|
|
33235
|
-
(0,
|
|
33422
|
+
(0, import_node_path9.join)(this.effectsDirectory, `${id}.json`),
|
|
33236
33423
|
serialized
|
|
33237
33424
|
);
|
|
33238
33425
|
}
|
|
33239
33426
|
checkedId(signalId) {
|
|
33240
|
-
if (!
|
|
33427
|
+
if (!UUID_RE11.test(signalId)) {
|
|
33241
33428
|
throw new Error("listener signal id must be a UUID");
|
|
33242
33429
|
}
|
|
33243
33430
|
return signalId.toLowerCase();
|
|
@@ -33246,18 +33433,18 @@ var FileListenerEffectStore = class {
|
|
|
33246
33433
|
|
|
33247
33434
|
// src/listener/grok-model.ts
|
|
33248
33435
|
var import_promises5 = require("node:fs/promises");
|
|
33249
|
-
var
|
|
33250
|
-
var
|
|
33436
|
+
var import_node_os7 = require("node:os");
|
|
33437
|
+
var import_node_path11 = require("node:path");
|
|
33251
33438
|
|
|
33252
33439
|
// src/host/grok.ts
|
|
33253
33440
|
var import_node_child_process6 = require("node:child_process");
|
|
33254
33441
|
var import_node_fs6 = require("node:fs");
|
|
33255
|
-
var
|
|
33442
|
+
var import_node_path10 = require("node:path");
|
|
33256
33443
|
var CHILD_EXIT_WAIT_MS4 = 3e3;
|
|
33257
33444
|
var CHILD_KILL_WAIT_MS4 = 1e3;
|
|
33258
33445
|
function resolveGrokExecutable(executable = "grok") {
|
|
33259
|
-
if ((0,
|
|
33260
|
-
const abs = (0,
|
|
33446
|
+
if ((0, import_node_path10.isAbsolute)(executable) || executable.includes("/")) {
|
|
33447
|
+
const abs = (0, import_node_path10.resolve)(executable);
|
|
33261
33448
|
try {
|
|
33262
33449
|
(0, import_node_fs6.accessSync)(abs, import_node_fs6.constants.X_OK);
|
|
33263
33450
|
} catch {
|
|
@@ -33502,11 +33689,11 @@ var GrokListenerModel = class {
|
|
|
33502
33689
|
async validateLocalAuth() {
|
|
33503
33690
|
if (this.options.open) return;
|
|
33504
33691
|
const parent = this.options.env ?? process.env;
|
|
33505
|
-
const sourceHome = parent.GROK_HOME ?? (0,
|
|
33506
|
-
if (!(0,
|
|
33692
|
+
const sourceHome = parent.GROK_HOME ?? (0, import_node_path11.join)(parent.HOME ?? (0, import_node_os7.homedir)(), ".grok");
|
|
33693
|
+
if (!(0, import_node_path11.isAbsolute)(sourceHome)) {
|
|
33507
33694
|
throw new Error("Grok home must be an absolute path");
|
|
33508
33695
|
}
|
|
33509
|
-
const sourceAuth = (0,
|
|
33696
|
+
const sourceAuth = (0, import_node_path11.join)(sourceHome, "auth.json");
|
|
33510
33697
|
let info;
|
|
33511
33698
|
try {
|
|
33512
33699
|
info = await (0, import_promises5.lstat)(sourceAuth);
|
|
@@ -33556,7 +33743,7 @@ var GrokListenerModel = class {
|
|
|
33556
33743
|
// src/listener/opencode-model.ts
|
|
33557
33744
|
var import_node_crypto14 = require("node:crypto");
|
|
33558
33745
|
var import_promises6 = require("node:fs/promises");
|
|
33559
|
-
var
|
|
33746
|
+
var import_node_path12 = require("node:path");
|
|
33560
33747
|
function asError(error) {
|
|
33561
33748
|
return error instanceof Error ? error : new Error(String(error));
|
|
33562
33749
|
}
|
|
@@ -33567,7 +33754,7 @@ var OpenCodeListenerModel = class {
|
|
|
33567
33754
|
this.openSession = options.open ?? openOpenCodeAcpSession;
|
|
33568
33755
|
this.prepareHome = options.prepareHome ?? prepareOpenCodeIsolatedHome;
|
|
33569
33756
|
this.prepareWorkerCwd = options.prepareWorkerCwd ?? (async (home) => {
|
|
33570
|
-
const cwd = await (0, import_promises6.mkdtemp)((0,
|
|
33757
|
+
const cwd = await (0, import_promises6.mkdtemp)((0, import_node_path12.join)(home, "canary-cwd-"));
|
|
33571
33758
|
await (0, import_promises6.chmod)(cwd, 448);
|
|
33572
33759
|
return cwd;
|
|
33573
33760
|
});
|
|
@@ -33989,8 +34176,8 @@ var OpenCodeListenerModel = class {
|
|
|
33989
34176
|
// src/listener/claude-model.ts
|
|
33990
34177
|
var import_node_crypto15 = require("node:crypto");
|
|
33991
34178
|
var import_promises7 = require("node:fs/promises");
|
|
33992
|
-
var
|
|
33993
|
-
var
|
|
34179
|
+
var import_node_os8 = require("node:os");
|
|
34180
|
+
var import_node_path13 = require("node:path");
|
|
33994
34181
|
var ClaudeListenerClosedDuringOpen = class extends Error {
|
|
33995
34182
|
constructor() {
|
|
33996
34183
|
super("listener model closed while the Claude worker was opening");
|
|
@@ -34128,8 +34315,8 @@ var ClaudeListenerModel = class {
|
|
|
34128
34315
|
}
|
|
34129
34316
|
/** Force Claude's measured Write permission path without changing worker cwd. */
|
|
34130
34317
|
async enablePromptsAfterClaudeCanary(handle) {
|
|
34131
|
-
const sentinelPath = (0,
|
|
34132
|
-
(0,
|
|
34318
|
+
const sentinelPath = (0, import_node_path13.join)(
|
|
34319
|
+
(0, import_node_os8.tmpdir)(),
|
|
34133
34320
|
`cswarm-claude-permission-canary-${process.pid}-${(0, import_node_crypto15.randomUUID)()}`
|
|
34134
34321
|
);
|
|
34135
34322
|
let sentinelCreated = false;
|
|
@@ -34158,8 +34345,8 @@ var ClaudeListenerModel = class {
|
|
|
34158
34345
|
// src/listener/codex-model.ts
|
|
34159
34346
|
var import_node_crypto16 = require("node:crypto");
|
|
34160
34347
|
var import_promises8 = require("node:fs/promises");
|
|
34161
|
-
var
|
|
34162
|
-
var
|
|
34348
|
+
var import_node_os9 = require("node:os");
|
|
34349
|
+
var import_node_path14 = require("node:path");
|
|
34163
34350
|
var CodexListenerClosedDuringOpen = class extends Error {
|
|
34164
34351
|
constructor() {
|
|
34165
34352
|
super("listener model closed while the Codex worker was opening");
|
|
@@ -34297,8 +34484,8 @@ var CodexListenerModel = class {
|
|
|
34297
34484
|
}
|
|
34298
34485
|
/** Force Codex's measured shell permission path without changing worker cwd. */
|
|
34299
34486
|
async enablePromptsAfterCodexCanary(handle) {
|
|
34300
|
-
const sentinelPath = (0,
|
|
34301
|
-
(0,
|
|
34487
|
+
const sentinelPath = (0, import_node_path14.join)(
|
|
34488
|
+
(0, import_node_os9.tmpdir)(),
|
|
34302
34489
|
`cswarm-codex-permission-canary-${process.pid}-${(0, import_node_crypto16.randomUUID)()}`
|
|
34303
34490
|
);
|
|
34304
34491
|
let sentinelCreated = false;
|
|
@@ -34328,7 +34515,7 @@ var CodexListenerModel = class {
|
|
|
34328
34515
|
var import_node_crypto17 = require("node:crypto");
|
|
34329
34516
|
|
|
34330
34517
|
// src/cloud/delivery.ts
|
|
34331
|
-
var
|
|
34518
|
+
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;
|
|
34332
34519
|
var RFC3339_TIMESTAMP_RE = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.\d+)?(?:Z|([+-]\d{2}):(\d{2}))$/i;
|
|
34333
34520
|
var DELIVERY_KINDS = /* @__PURE__ */ new Set(["ask", "note"]);
|
|
34334
34521
|
var SENDER_OWNER_RELATIONS2 = /* @__PURE__ */ new Set([
|
|
@@ -34415,7 +34602,7 @@ var DeliveryProtocolError = class extends Error {
|
|
|
34415
34602
|
}
|
|
34416
34603
|
};
|
|
34417
34604
|
function checkedUuid3(value, field) {
|
|
34418
|
-
if (typeof value !== "string" || !
|
|
34605
|
+
if (typeof value !== "string" || !UUID_RE12.test(value)) {
|
|
34419
34606
|
throw new DeliveryProtocolError(
|
|
34420
34607
|
`delivery response returned a malformed ${field}`
|
|
34421
34608
|
);
|
|
@@ -34526,7 +34713,7 @@ function checkedClaimCapabilities(value) {
|
|
|
34526
34713
|
}
|
|
34527
34714
|
function checkedOptionalUuidArray(value, field) {
|
|
34528
34715
|
if (value === void 0) return;
|
|
34529
|
-
if (!Array.isArray(value) || value.some((item) => typeof item !== "string" || !
|
|
34716
|
+
if (!Array.isArray(value) || value.some((item) => typeof item !== "string" || !UUID_RE12.test(item))) {
|
|
34530
34717
|
throw new DeliveryProtocolError(
|
|
34531
34718
|
`delivery response returned a malformed ${field}`
|
|
34532
34719
|
);
|
|
@@ -34673,7 +34860,7 @@ function checkedCommandId(value) {
|
|
|
34673
34860
|
return value;
|
|
34674
34861
|
}
|
|
34675
34862
|
function checkedUuidRequest(value, field) {
|
|
34676
|
-
if (!
|
|
34863
|
+
if (!UUID_RE12.test(value)) {
|
|
34677
34864
|
throw new Error(`${field} must be a UUID for an agent delivery command`);
|
|
34678
34865
|
}
|
|
34679
34866
|
}
|
|
@@ -34909,8 +35096,8 @@ var DeliveryCommandClient = class {
|
|
|
34909
35096
|
};
|
|
34910
35097
|
|
|
34911
35098
|
// src/listener/main-routing.ts
|
|
34912
|
-
var
|
|
34913
|
-
var
|
|
35099
|
+
var import_node_path15 = require("node:path");
|
|
35100
|
+
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;
|
|
34914
35101
|
var MAX_QUEUE_BYTES = 1024 * 1024;
|
|
34915
35102
|
var QUEUE_FILE = "pending-for-main.json";
|
|
34916
35103
|
var QUEUE_LOCK = "pending-for-main";
|
|
@@ -34965,7 +35152,7 @@ function parseEntry(value) {
|
|
|
34965
35152
|
if (Object.keys(row).some((key2) => !allowed.has(key2))) {
|
|
34966
35153
|
throw new Error("stored pending-for-main entry is malformed");
|
|
34967
35154
|
}
|
|
34968
|
-
if (typeof row.signalId !== "string" || !
|
|
35155
|
+
if (typeof row.signalId !== "string" || !UUID_RE13.test(row.signalId) || typeof row.workspaceId !== "string" || !UUID_RE13.test(row.workspaceId) || typeof row.principalId !== "string" || !UUID_RE13.test(row.principalId) || typeof row.fromId !== "string" || !UUID_RE13.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)) {
|
|
34969
35156
|
throw new Error("stored pending-for-main entry is malformed");
|
|
34970
35157
|
}
|
|
34971
35158
|
return {
|
|
@@ -35008,11 +35195,11 @@ var FilePendingMainQueue = class {
|
|
|
35008
35195
|
path;
|
|
35009
35196
|
directory;
|
|
35010
35197
|
constructor(instanceDirectory) {
|
|
35011
|
-
if (!(0,
|
|
35198
|
+
if (!(0, import_node_path15.isAbsolute)(instanceDirectory)) {
|
|
35012
35199
|
throw new Error("pending-for-main directory must be absolute");
|
|
35013
35200
|
}
|
|
35014
35201
|
this.directory = instanceDirectory;
|
|
35015
|
-
this.path = (0,
|
|
35202
|
+
this.path = (0, import_node_path15.join)(instanceDirectory, QUEUE_FILE);
|
|
35016
35203
|
}
|
|
35017
35204
|
async readUnlocked() {
|
|
35018
35205
|
const raw = await readSecureJsonFile(this.path, MAX_QUEUE_BYTES);
|
|
@@ -35104,7 +35291,7 @@ var LISTENER_REPLY_ONLY_MINIMUM_MS = SIGNAL_REQUEST_TIMEOUT_MS + LISTENER_ACK_ON
|
|
|
35104
35291
|
var LISTENER_PROMPT_START_MINIMUM_MS = SIGNAL_READ_TIMEOUT_MS + ACP_DEFAULT_REQUEST_TIMEOUT_MS + LISTENER_REPLY_ONLY_MINIMUM_MS;
|
|
35105
35292
|
var LISTENER_DELIVERY_RETRY_INITIAL_MS = 500;
|
|
35106
35293
|
var LISTENER_DELIVERY_RETRY_MAX_MS = 3e4;
|
|
35107
|
-
var
|
|
35294
|
+
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;
|
|
35108
35295
|
var ListenerCapabilityError = class extends Error {
|
|
35109
35296
|
code;
|
|
35110
35297
|
constructor(code, message) {
|
|
@@ -35382,7 +35569,7 @@ async function runListenerRuntime(options) {
|
|
|
35382
35569
|
new Error("listener instance id and delivery journal must be configured together")
|
|
35383
35570
|
);
|
|
35384
35571
|
}
|
|
35385
|
-
if (hasInstanceId && !
|
|
35572
|
+
if (hasInstanceId && !UUID_RE14.test(options.listenerInstanceId)) {
|
|
35386
35573
|
return await closeBeforeStart(
|
|
35387
35574
|
options.model,
|
|
35388
35575
|
new Error("listener instance id must be a UUID")
|
|
@@ -36222,8 +36409,8 @@ async function runListenerRuntime(options) {
|
|
|
36222
36409
|
// src/listener/control.ts
|
|
36223
36410
|
var import_node_net = require("node:net");
|
|
36224
36411
|
var import_promises9 = require("node:fs/promises");
|
|
36225
|
-
var
|
|
36226
|
-
var
|
|
36412
|
+
var import_node_path16 = require("node:path");
|
|
36413
|
+
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;
|
|
36227
36414
|
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-]+)*)?$/;
|
|
36228
36415
|
var MAX_STATUS_BYTES = 16 * 1024;
|
|
36229
36416
|
var MAX_CONTROL_BYTES = 8 * 1024;
|
|
@@ -36238,19 +36425,19 @@ var ListenerAlreadyRunningError = class extends Error {
|
|
|
36238
36425
|
};
|
|
36239
36426
|
function listenerPaths(options) {
|
|
36240
36427
|
const root = options.stateDirectory ?? defaultListenerStateDirectory();
|
|
36241
|
-
if (!(0,
|
|
36428
|
+
if (!(0, import_node_path16.isAbsolute)(root)) {
|
|
36242
36429
|
throw new Error("listener state directory must be absolute");
|
|
36243
36430
|
}
|
|
36244
36431
|
const key2 = listenerInstanceKey(options);
|
|
36245
|
-
const instanceDirectory = (0,
|
|
36432
|
+
const instanceDirectory = (0, import_node_path16.join)(root, key2);
|
|
36246
36433
|
const uid2 = typeof process.getuid === "function" ? process.getuid() : process.pid;
|
|
36247
|
-
const controlDirectory = process.platform === "win32" ? "" : (0,
|
|
36248
|
-
const socketPath = process.platform === "win32" ? `\\\\.\\pipe\\cswarm-${key2}` : (0,
|
|
36434
|
+
const controlDirectory = process.platform === "win32" ? "" : (0, import_node_path16.join)("/tmp", `cswarm-control-${uid2}`);
|
|
36435
|
+
const socketPath = process.platform === "win32" ? `\\\\.\\pipe\\cswarm-${key2}` : (0, import_node_path16.join)(controlDirectory, `${key2.slice(0, 32)}.sock`);
|
|
36249
36436
|
return {
|
|
36250
36437
|
key: key2,
|
|
36251
36438
|
instanceDirectory,
|
|
36252
|
-
statusPath: (0,
|
|
36253
|
-
logPath: (0,
|
|
36439
|
+
statusPath: (0, import_node_path16.join)(instanceDirectory, "status.json"),
|
|
36440
|
+
logPath: (0, import_node_path16.join)(instanceDirectory, "events.ndjson"),
|
|
36254
36441
|
socketPath
|
|
36255
36442
|
};
|
|
36256
36443
|
}
|
|
@@ -36329,10 +36516,10 @@ function parseStatus(raw) {
|
|
|
36329
36516
|
throw new Error("stored listener status is malformed");
|
|
36330
36517
|
}
|
|
36331
36518
|
}
|
|
36332
|
-
const nullableUuid2 = (candidate) => candidate === null || typeof candidate === "string" &&
|
|
36519
|
+
const nullableUuid2 = (candidate) => candidate === null || typeof candidate === "string" && UUID_RE15.test(candidate);
|
|
36333
36520
|
const nullableCount = (candidate) => candidate === null || typeof candidate === "number" && Number.isSafeInteger(candidate) && candidate >= 0;
|
|
36334
36521
|
const nullableTimestamp2 = (candidate) => candidate === null || typeof candidate === "string" && Number.isFinite(Date.parse(candidate));
|
|
36335
|
-
if (row.version !== 1 || typeof row.instanceId !== "string" || !
|
|
36522
|
+
if (row.version !== 1 || typeof row.instanceId !== "string" || !UUID_RE15.test(row.instanceId) || row.provider !== "grok" && row.provider !== "opencode" && row.provider !== "claude" && row.provider !== "codex" || typeof row.profileId !== "string" || typeof row.workspaceId !== "string" || !UUID_RE15.test(row.workspaceId) || typeof row.principalId !== "string" || !UUID_RE15.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_path16.isAbsolute)(row.logPath) || !(row.deliveryMode === void 0 || row.deliveryMode === null || typeof row.deliveryMode === "string" && STATUS_DELIVERY_MODES.has(row.deliveryMode)) || !(row.pendingDeliveryCount === void 0 || nullableCount(row.pendingDeliveryCount)) || !(row.lastTerminalDeliveryFailureCount === void 0 || nullableCount(row.lastTerminalDeliveryFailureCount)) || !(row.lastTerminalDeliveryFailureAt === void 0 || 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)) {
|
|
36336
36523
|
throw new Error("stored listener status is malformed");
|
|
36337
36524
|
}
|
|
36338
36525
|
const routeMode = row.routeMode ?? "worker";
|
|
@@ -36506,7 +36693,7 @@ function writeResponse(socket, response) {
|
|
|
36506
36693
|
}
|
|
36507
36694
|
async function startupLock(paths) {
|
|
36508
36695
|
await ensureSecureStateDirectory(paths.instanceDirectory);
|
|
36509
|
-
const lockPath = (0,
|
|
36696
|
+
const lockPath = (0, import_node_path16.join)(paths.instanceDirectory, "starting.lock");
|
|
36510
36697
|
const deadline = Date.now() + START_LOCK_WAIT_MS;
|
|
36511
36698
|
while (Date.now() < deadline) {
|
|
36512
36699
|
let handle;
|
|
@@ -36547,7 +36734,7 @@ async function startupLock(paths) {
|
|
|
36547
36734
|
async function prepareSocket(paths) {
|
|
36548
36735
|
if (process.platform !== "win32") {
|
|
36549
36736
|
const uid2 = typeof process.getuid === "function" ? process.getuid() : process.pid;
|
|
36550
|
-
const directory = (0,
|
|
36737
|
+
const directory = (0, import_node_path16.join)("/tmp", `cswarm-control-${uid2}`);
|
|
36551
36738
|
await ensureSecureStateDirectory(directory);
|
|
36552
36739
|
}
|
|
36553
36740
|
try {
|
|
@@ -36682,7 +36869,7 @@ async function queryListenerControl(paths, command2, timeoutMs = CONTROL_TIMEOUT
|
|
|
36682
36869
|
|
|
36683
36870
|
// src/listener/supervisor.ts
|
|
36684
36871
|
var import_node_crypto18 = require("node:crypto");
|
|
36685
|
-
var
|
|
36872
|
+
var UUID_RE16 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
36686
36873
|
var LISTENER_RESTART_MAX_ATTEMPTS = 5;
|
|
36687
36874
|
var LISTENER_RESTART_INITIAL_MS = 1e3;
|
|
36688
36875
|
var LISTENER_RESTART_MAX_MS = 6e4;
|
|
@@ -36811,7 +36998,7 @@ async function runListenerSupervisor(options) {
|
|
|
36811
36998
|
// before the socket can answer, before any status/event persistence.
|
|
36812
36999
|
initialize: prepare ? async () => {
|
|
36813
37000
|
const selected = await prepare(proposedInstanceId);
|
|
36814
|
-
if (!selected || typeof selected !== "object" || typeof selected.instanceId !== "string" || !
|
|
37001
|
+
if (!selected || typeof selected !== "object" || typeof selected.instanceId !== "string" || !UUID_RE16.test(selected.instanceId)) {
|
|
36815
37002
|
throw new Error("listener prepare returned an invalid instance id");
|
|
36816
37003
|
}
|
|
36817
37004
|
status = { ...status, instanceId: selected.instanceId };
|
|
@@ -37167,9 +37354,9 @@ async function waitForListenerReady(paths, options = {}) {
|
|
|
37167
37354
|
}
|
|
37168
37355
|
|
|
37169
37356
|
// src/listener/delivery-journal.ts
|
|
37170
|
-
var
|
|
37357
|
+
var import_node_path17 = require("node:path");
|
|
37171
37358
|
var import_node_util2 = require("node:util");
|
|
37172
|
-
var
|
|
37359
|
+
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}$/;
|
|
37173
37360
|
var COMMAND_ID_RE3 = /^[A-Za-z0-9_-]{8,72}$/;
|
|
37174
37361
|
var SIGNAL_FINGERPRINT_RE = /^[0-9a-f]{64}$/;
|
|
37175
37362
|
var MAX_JOURNAL_BYTES = 8192;
|
|
@@ -37264,7 +37451,7 @@ var ALLOWED_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
|
37264
37451
|
"credential_unavailable"
|
|
37265
37452
|
]);
|
|
37266
37453
|
function claimCommandId(listenerInstanceId, claimOrdinal) {
|
|
37267
|
-
if (!
|
|
37454
|
+
if (!UUID_RE17.test(listenerInstanceId)) {
|
|
37268
37455
|
throw new Error("stored delivery journal is malformed");
|
|
37269
37456
|
}
|
|
37270
37457
|
if (!Number.isSafeInteger(claimOrdinal) || claimOrdinal < 0) {
|
|
@@ -37279,7 +37466,7 @@ function claimCommandId(listenerInstanceId, claimOrdinal) {
|
|
|
37279
37466
|
return id;
|
|
37280
37467
|
}
|
|
37281
37468
|
function ackCommandId(leaseId) {
|
|
37282
|
-
if (!
|
|
37469
|
+
if (!UUID_RE17.test(leaseId)) {
|
|
37283
37470
|
throw new Error("stored delivery journal is malformed");
|
|
37284
37471
|
}
|
|
37285
37472
|
const cleanLease = leaseId.toLowerCase().replace(/-/g, "");
|
|
@@ -37362,19 +37549,19 @@ function parseJournalRecord(raw, expectedWorkspaceId, expectedPrincipalId) {
|
|
|
37362
37549
|
if (row.version !== 1) {
|
|
37363
37550
|
throw new Error("stored delivery journal is malformed");
|
|
37364
37551
|
}
|
|
37365
|
-
if (typeof row.workspaceId !== "string" || !
|
|
37552
|
+
if (typeof row.workspaceId !== "string" || !UUID_RE17.test(row.workspaceId) || row.workspaceId !== row.workspaceId.toLowerCase()) {
|
|
37366
37553
|
throw new Error("stored delivery journal is malformed");
|
|
37367
37554
|
}
|
|
37368
37555
|
if (expectedWorkspaceId && row.workspaceId !== expectedWorkspaceId.toLowerCase()) {
|
|
37369
37556
|
throw new Error("stored delivery journal is malformed");
|
|
37370
37557
|
}
|
|
37371
|
-
if (typeof row.principalId !== "string" || !
|
|
37558
|
+
if (typeof row.principalId !== "string" || !UUID_RE17.test(row.principalId) || row.principalId !== row.principalId.toLowerCase()) {
|
|
37372
37559
|
throw new Error("stored delivery journal is malformed");
|
|
37373
37560
|
}
|
|
37374
37561
|
if (expectedPrincipalId && row.principalId !== expectedPrincipalId.toLowerCase()) {
|
|
37375
37562
|
throw new Error("stored delivery journal is malformed");
|
|
37376
37563
|
}
|
|
37377
|
-
if (typeof row.listenerInstanceId !== "string" || !
|
|
37564
|
+
if (typeof row.listenerInstanceId !== "string" || !UUID_RE17.test(row.listenerInstanceId) || row.listenerInstanceId !== row.listenerInstanceId.toLowerCase()) {
|
|
37378
37565
|
throw new Error("stored delivery journal is malformed");
|
|
37379
37566
|
}
|
|
37380
37567
|
if (!Number.isSafeInteger(row.nextClaimOrdinal) || row.nextClaimOrdinal < 0) {
|
|
@@ -37438,10 +37625,10 @@ function parseJournalRecord(raw, expectedWorkspaceId, expectedPrincipalId) {
|
|
|
37438
37625
|
if (active.claimLastAttemptAt === null) {
|
|
37439
37626
|
throw new Error("stored delivery journal is malformed");
|
|
37440
37627
|
}
|
|
37441
|
-
if (typeof active.signalId !== "string" || !
|
|
37628
|
+
if (typeof active.signalId !== "string" || !UUID_RE17.test(active.signalId) || active.signalId !== active.signalId.toLowerCase()) {
|
|
37442
37629
|
throw new Error("stored delivery journal is malformed");
|
|
37443
37630
|
}
|
|
37444
|
-
if (typeof active.leaseId !== "string" || !
|
|
37631
|
+
if (typeof active.leaseId !== "string" || !UUID_RE17.test(active.leaseId) || active.leaseId !== active.leaseId.toLowerCase()) {
|
|
37445
37632
|
throw new Error("stored delivery journal is malformed");
|
|
37446
37633
|
}
|
|
37447
37634
|
if (!isValidIsoTimestamp(active.leasedUntil) || Date.parse(active.leasedUntil) <= Date.parse(active.claimCreatedAt)) {
|
|
@@ -37513,7 +37700,7 @@ var FileListenerDeliveryJournal = class {
|
|
|
37513
37700
|
["profileId", "workspaceId", "principalId"],
|
|
37514
37701
|
"delivery journal configuration rejected"
|
|
37515
37702
|
);
|
|
37516
|
-
if (typeof options.profileId !== "string" || !options.profileId || options.profileId.includes("\0") || typeof options.workspaceId !== "string" || !
|
|
37703
|
+
if (typeof options.profileId !== "string" || !options.profileId || options.profileId.includes("\0") || typeof options.workspaceId !== "string" || !UUID_RE17.test(options.workspaceId) || typeof options.principalId !== "string" || !UUID_RE17.test(options.principalId)) {
|
|
37517
37704
|
throw new Error("delivery journal configuration rejected");
|
|
37518
37705
|
}
|
|
37519
37706
|
if (options.stateDirectory !== void 0) {
|
|
@@ -37528,11 +37715,11 @@ var FileListenerDeliveryJournal = class {
|
|
|
37528
37715
|
stateDirectory: options.stateDirectory
|
|
37529
37716
|
});
|
|
37530
37717
|
const root = this.options.stateDirectory ?? defaultListenerStateDirectory();
|
|
37531
|
-
if (!(0,
|
|
37718
|
+
if (!(0, import_node_path17.isAbsolute)(root)) {
|
|
37532
37719
|
throw new Error("delivery journal configuration rejected");
|
|
37533
37720
|
}
|
|
37534
|
-
this.instanceDirectory = (0,
|
|
37535
|
-
this.journalPath = (0,
|
|
37721
|
+
this.instanceDirectory = (0, import_node_path17.join)(root, listenerInstanceKey(this.options));
|
|
37722
|
+
this.journalPath = (0, import_node_path17.join)(this.instanceDirectory, "delivery-journal.json");
|
|
37536
37723
|
}
|
|
37537
37724
|
async readRecordUnlocked() {
|
|
37538
37725
|
let raw;
|
|
@@ -37634,7 +37821,7 @@ var FileListenerDeliveryJournal = class {
|
|
|
37634
37821
|
["signalId", "leaseId", "leasedUntil"],
|
|
37635
37822
|
"delivery journal mutation rejected"
|
|
37636
37823
|
);
|
|
37637
|
-
if (typeof input.signalId !== "string" || !
|
|
37824
|
+
if (typeof input.signalId !== "string" || !UUID_RE17.test(input.signalId) || typeof input.leaseId !== "string" || !UUID_RE17.test(input.leaseId) || !isValidIsoTimestamp(input.leasedUntil) || input.signalFingerprint !== void 0 && (typeof input.signalFingerprint !== "string" || !SIGNAL_FINGERPRINT_RE.test(input.signalFingerprint))) {
|
|
37638
37825
|
throw new Error("delivery journal mutation rejected");
|
|
37639
37826
|
}
|
|
37640
37827
|
const canonicalSignalId = input.signalId.toLowerCase();
|
|
@@ -37766,7 +37953,7 @@ async function openListenerDeliveryJournal(options) {
|
|
|
37766
37953
|
["profileId", "workspaceId", "principalId", "proposedListenerInstanceId"],
|
|
37767
37954
|
"delivery journal configuration rejected"
|
|
37768
37955
|
);
|
|
37769
|
-
if (typeof options.profileId !== "string" || !options.profileId || options.profileId.includes("\0") || typeof options.workspaceId !== "string" || !
|
|
37956
|
+
if (typeof options.profileId !== "string" || !options.profileId || options.profileId.includes("\0") || typeof options.workspaceId !== "string" || !UUID_RE17.test(options.workspaceId) || typeof options.principalId !== "string" || !UUID_RE17.test(options.principalId) || typeof options.proposedListenerInstanceId !== "string" || !UUID_RE17.test(options.proposedListenerInstanceId)) {
|
|
37770
37957
|
throw new Error("delivery journal configuration rejected");
|
|
37771
37958
|
}
|
|
37772
37959
|
if (options.stateDirectory !== void 0) {
|
|
@@ -37861,9 +38048,9 @@ async function openListenerDeliveryJournal(options) {
|
|
|
37861
38048
|
|
|
37862
38049
|
// src/listener/detach.ts
|
|
37863
38050
|
var import_node_child_process7 = require("node:child_process");
|
|
37864
|
-
var
|
|
38051
|
+
var import_node_path18 = require("node:path");
|
|
37865
38052
|
function isNativeAbsolutePath(value, platform = process.platform) {
|
|
37866
|
-
return platform === "win32" ?
|
|
38053
|
+
return platform === "win32" ? import_node_path18.win32.isAbsolute(value) : import_node_path18.posix.isAbsolute(value);
|
|
37867
38054
|
}
|
|
37868
38055
|
function listenerNodeExecArgv(values2) {
|
|
37869
38056
|
const safe = [];
|
|
@@ -37980,8 +38167,8 @@ async function spawnDetachedListener(options) {
|
|
|
37980
38167
|
|
|
37981
38168
|
// src/listener/hook.ts
|
|
37982
38169
|
var import_promises10 = require("node:fs/promises");
|
|
37983
|
-
var
|
|
37984
|
-
var
|
|
38170
|
+
var import_node_path19 = require("node:path");
|
|
38171
|
+
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;
|
|
37985
38172
|
var TOKEN_RE = /^swm_agt_[A-Za-z0-9_-]{43}$/;
|
|
37986
38173
|
var INSTANCE_KEY_RE = /^[0-9a-f]{64}$/;
|
|
37987
38174
|
var MAX_HOOK_CREDENTIAL_BYTES = 8 * 1024;
|
|
@@ -38022,7 +38209,7 @@ function parseListenerCredential(raw) {
|
|
|
38022
38209
|
"principalId",
|
|
38023
38210
|
"credential",
|
|
38024
38211
|
"updatedAt"
|
|
38025
|
-
]) || 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" || !
|
|
38212
|
+
]) || 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_RE18.test(row.workspaceId) || typeof row.principalId !== "string" || !UUID_RE18.test(row.principalId) || typeof row.credential !== "string" || !TOKEN_RE.test(row.credential) || typeof row.updatedAt !== "string" || !Number.isFinite(Date.parse(row.updatedAt))) {
|
|
38026
38213
|
throw new Error("stored listener hook credential is malformed");
|
|
38027
38214
|
}
|
|
38028
38215
|
const target2 = cloudTarget(row.targetUrl, row.anonKey);
|
|
@@ -38041,7 +38228,7 @@ function parseListenerCredential(raw) {
|
|
|
38041
38228
|
};
|
|
38042
38229
|
}
|
|
38043
38230
|
async function writeListenerCredentialState(instanceDirectory, input) {
|
|
38044
|
-
if (!(0,
|
|
38231
|
+
if (!(0, import_node_path19.isAbsolute)(instanceDirectory)) {
|
|
38045
38232
|
throw new Error("listener hook state directory must be absolute");
|
|
38046
38233
|
}
|
|
38047
38234
|
const record = parseListenerCredential(JSON.stringify({
|
|
@@ -38055,16 +38242,16 @@ async function writeListenerCredentialState(instanceDirectory, input) {
|
|
|
38055
38242
|
updatedAt: new Date(input.now ?? Date.now()).toISOString()
|
|
38056
38243
|
}));
|
|
38057
38244
|
await writeSecureJsonFile(
|
|
38058
|
-
(0,
|
|
38245
|
+
(0, import_node_path19.join)(instanceDirectory, LISTENER_CREDENTIAL_FILE),
|
|
38059
38246
|
JSON.stringify(record)
|
|
38060
38247
|
);
|
|
38061
38248
|
await deleteSecureJsonFile(
|
|
38062
|
-
(0,
|
|
38249
|
+
(0, import_node_path19.join)(instanceDirectory, RETIRED_HOOK_CREDENTIAL_FILE)
|
|
38063
38250
|
).catch(() => void 0);
|
|
38064
38251
|
}
|
|
38065
38252
|
async function readListenerCredentialState(instanceDirectory) {
|
|
38066
38253
|
const raw = await readSecureJsonFile(
|
|
38067
|
-
(0,
|
|
38254
|
+
(0, import_node_path19.join)(instanceDirectory, LISTENER_CREDENTIAL_FILE),
|
|
38068
38255
|
MAX_HOOK_CREDENTIAL_BYTES
|
|
38069
38256
|
);
|
|
38070
38257
|
return raw === null ? null : parseListenerCredential(raw);
|
|
@@ -38082,7 +38269,7 @@ function parseSurface(raw) {
|
|
|
38082
38269
|
const row = value;
|
|
38083
38270
|
if (Object.keys(row).some(
|
|
38084
38271
|
(key2) => key2 !== "version" && key2 !== "surfacedSignalIds" && key2 !== "reportedDroppedCount" && key2 !== "credentialFailureReported"
|
|
38085
|
-
) || row.version !== 1 || !Array.isArray(row.surfacedSignalIds) || row.surfacedSignalIds.length > HOOK_SURFACED_IDS_MAX || row.surfacedSignalIds.some((id) => typeof id !== "string" || !
|
|
38272
|
+
) || row.version !== 1 || !Array.isArray(row.surfacedSignalIds) || row.surfacedSignalIds.length > HOOK_SURFACED_IDS_MAX || row.surfacedSignalIds.some((id) => typeof id !== "string" || !UUID_RE18.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")) {
|
|
38086
38273
|
throw new Error("stored listener hook surface state is malformed");
|
|
38087
38274
|
}
|
|
38088
38275
|
const ids = row.surfacedSignalIds.map((id) => String(id).toLowerCase());
|
|
@@ -38099,10 +38286,10 @@ function parseSurface(raw) {
|
|
|
38099
38286
|
var FileHookSurfaceStore = class {
|
|
38100
38287
|
constructor(instanceDirectory) {
|
|
38101
38288
|
this.instanceDirectory = instanceDirectory;
|
|
38102
|
-
if (!(0,
|
|
38289
|
+
if (!(0, import_node_path19.isAbsolute)(instanceDirectory)) {
|
|
38103
38290
|
throw new Error("listener hook surface directory must be absolute");
|
|
38104
38291
|
}
|
|
38105
|
-
this.path = (0,
|
|
38292
|
+
this.path = (0, import_node_path19.join)(instanceDirectory, HOOK_SURFACE_FILE);
|
|
38106
38293
|
}
|
|
38107
38294
|
instanceDirectory;
|
|
38108
38295
|
path;
|
|
@@ -38119,7 +38306,7 @@ var FileHookSurfaceStore = class {
|
|
|
38119
38306
|
const unseen = [];
|
|
38120
38307
|
for (const item of items) {
|
|
38121
38308
|
const signalId = item.signalId.toLowerCase();
|
|
38122
|
-
if (!
|
|
38309
|
+
if (!UUID_RE18.test(signalId) || seen.has(signalId)) continue;
|
|
38123
38310
|
seen.add(signalId);
|
|
38124
38311
|
unseen.push(item);
|
|
38125
38312
|
}
|
|
@@ -38142,7 +38329,7 @@ var FileHookSurfaceStore = class {
|
|
|
38142
38329
|
const seen = new Set(state.surfacedSignalIds);
|
|
38143
38330
|
for (const signalId of options.signalIds ?? []) {
|
|
38144
38331
|
const checked = signalId.toLowerCase();
|
|
38145
|
-
if (
|
|
38332
|
+
if (UUID_RE18.test(checked)) seen.add(checked);
|
|
38146
38333
|
}
|
|
38147
38334
|
await writeSecureJsonFile(
|
|
38148
38335
|
this.path,
|
|
@@ -38181,7 +38368,7 @@ function parseGlobalState(raw) {
|
|
|
38181
38368
|
}
|
|
38182
38369
|
async function reserveCheck(stateDirectory2, cooldownMs, now) {
|
|
38183
38370
|
return await withFileLock(stateDirectory2, GLOBAL_STATE_LOCK, async () => {
|
|
38184
|
-
const path = (0,
|
|
38371
|
+
const path = (0, import_node_path19.join)(stateDirectory2, GLOBAL_STATE_FILE);
|
|
38185
38372
|
const raw = await readSecureJsonFile(path, MAX_GLOBAL_STATE_BYTES);
|
|
38186
38373
|
const previous = raw === null ? null : parseGlobalState(raw);
|
|
38187
38374
|
if (previous !== null && now - previous.lastCheckAt < cooldownMs) return false;
|
|
@@ -38201,8 +38388,8 @@ async function statusContext(stateDirectory2, key2, instanceDirectory) {
|
|
|
38201
38388
|
const provisional = {
|
|
38202
38389
|
key: key2,
|
|
38203
38390
|
instanceDirectory,
|
|
38204
|
-
statusPath: (0,
|
|
38205
|
-
logPath: (0,
|
|
38391
|
+
statusPath: (0, import_node_path19.join)(instanceDirectory, "status.json"),
|
|
38392
|
+
logPath: (0, import_node_path19.join)(instanceDirectory, "events.ndjson"),
|
|
38206
38393
|
socketPath: ""
|
|
38207
38394
|
};
|
|
38208
38395
|
const status = await readListenerStatus(provisional).catch(() => null);
|
|
@@ -38238,7 +38425,7 @@ async function discoverContexts(stateDirectory2, isListenerLive = listenerIsLive
|
|
|
38238
38425
|
const contexts = [];
|
|
38239
38426
|
for (const entry of entries) {
|
|
38240
38427
|
if (!entry.isDirectory() || !INSTANCE_KEY_RE.test(entry.name)) continue;
|
|
38241
|
-
const instanceDirectory = (0,
|
|
38428
|
+
const instanceDirectory = (0, import_node_path19.join)(stateDirectory2, entry.name);
|
|
38242
38429
|
const storedStatus = await statusContext(
|
|
38243
38430
|
stateDirectory2,
|
|
38244
38431
|
entry.name,
|
|
@@ -38257,7 +38444,7 @@ async function discoverContexts(stateDirectory2, isListenerLive = listenerIsLive
|
|
|
38257
38444
|
continue;
|
|
38258
38445
|
}
|
|
38259
38446
|
await deleteSecureJsonFile(
|
|
38260
|
-
(0,
|
|
38447
|
+
(0, import_node_path19.join)(instanceDirectory, RETIRED_HOOK_CREDENTIAL_FILE)
|
|
38261
38448
|
).catch(() => void 0);
|
|
38262
38449
|
try {
|
|
38263
38450
|
const credential = await readListenerCredentialState(instanceDirectory);
|
|
@@ -38408,7 +38595,7 @@ async function recordQueuedObservations(check, signalIds, options, now) {
|
|
|
38408
38595
|
async function checkListenerHooks(options) {
|
|
38409
38596
|
try {
|
|
38410
38597
|
const stateDirectory2 = options.stateDirectory ?? defaultListenerStateDirectory();
|
|
38411
|
-
if (!(0,
|
|
38598
|
+
if (!(0, import_node_path19.isAbsolute)(stateDirectory2)) return "";
|
|
38412
38599
|
const now = options.now ?? Date.now;
|
|
38413
38600
|
const cooldownSeconds = options.cooldownSeconds ?? HOOK_DEFAULT_COOLDOWN_SECONDS;
|
|
38414
38601
|
if (!Number.isSafeInteger(cooldownSeconds) || cooldownSeconds < 0 || cooldownSeconds > 86400) {
|
|
@@ -38589,6 +38776,7 @@ var KNOWN_FLAGS = /* @__PURE__ */ new Set([
|
|
|
38589
38776
|
"name",
|
|
38590
38777
|
"ndjson",
|
|
38591
38778
|
"no-browser",
|
|
38779
|
+
"notify",
|
|
38592
38780
|
"opencode-executable",
|
|
38593
38781
|
"out",
|
|
38594
38782
|
"permissions",
|
|
@@ -38628,11 +38816,12 @@ var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
|
|
|
38628
38816
|
"link-stdin",
|
|
38629
38817
|
"local",
|
|
38630
38818
|
"ndjson",
|
|
38819
|
+
"notify",
|
|
38631
38820
|
"no-browser",
|
|
38632
38821
|
"reveal-anon-key",
|
|
38633
38822
|
"write"
|
|
38634
38823
|
]);
|
|
38635
|
-
var
|
|
38824
|
+
var UUID_RE19 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
38636
38825
|
var AGENT_CREDENTIAL_MESSAGE = "Agent credential minted. It is bound to this task and run so the agent's work stays scoped and attributable.";
|
|
38637
38826
|
var AGENT_CREDENTIAL_MESSAGE_D088 = "Agent credential minted. It is bound to this run, so the agent's work is attributable to it.";
|
|
38638
38827
|
var ACCEPTED_AGENT_CREDENTIAL_MESSAGES = [
|
|
@@ -38640,8 +38829,8 @@ var ACCEPTED_AGENT_CREDENTIAL_MESSAGES = [
|
|
|
38640
38829
|
AGENT_CREDENTIAL_MESSAGE_D088
|
|
38641
38830
|
];
|
|
38642
38831
|
function packageVersion() {
|
|
38643
|
-
if ("0.1.
|
|
38644
|
-
return "0.1.
|
|
38832
|
+
if ("0.1.35".length > 0) {
|
|
38833
|
+
return "0.1.35";
|
|
38645
38834
|
}
|
|
38646
38835
|
try {
|
|
38647
38836
|
const value = JSON.parse(
|
|
@@ -38763,6 +38952,7 @@ Usage:
|
|
|
38763
38952
|
cswarm receipt <signal-id> --agent-token-stdin [--url <url> --anon-key <key>] --workspace-id <uuid> [--json]
|
|
38764
38953
|
cswarm feed [--url <url> --anon-key <key>] [--workspace-id <uuid>] [--about <ref>] [--kind <kind>] [--since <timestamp>] [--limit <n>] [--include-stale] [--json]
|
|
38765
38954
|
cswarm inbox [--url <url> --anon-key <key>] [--workspace-id <uuid>] [--kind <kind>] [--about <ref>] [--since <timestamp>] [--limit <n>] [--include-stale] [--wait <seconds>] [--json]
|
|
38955
|
+
cswarm inbox --notify --agent-token-stdin [--url <url> --anon-key <key>] --workspace-id <uuid> [--json]
|
|
38766
38956
|
cswarm inbox --follow --ndjson [--url <url> --anon-key <key>] [--workspace-id <uuid>] [--kind <kind>] [--about <ref>] [--since <timestamp>] [--limit <n>] [--include-stale]
|
|
38767
38957
|
cswarm file put <local-path> [--name <name>] [--url <url> --anon-key <key>] [--workspace-id <uuid>] [--agent-token-stdin] [--json]
|
|
38768
38958
|
cswarm file ls [--include-tombstoned] [--url <url> --anon-key <key>] [--workspace-id <uuid>] [--agent-token-stdin] [--json]
|
|
@@ -38808,6 +38998,7 @@ Credential selection for command/dogfood:
|
|
|
38808
38998
|
JSON artifact, because it needs a field a bare secret does not carry:
|
|
38809
38999
|
members reads only -- either form
|
|
38810
39000
|
receipt reads only -- either form
|
|
39001
|
+
inbox --notify persists a per-agent cursor -- needs principal_id
|
|
38811
39002
|
file put, file ls, file get, file rm, file restore
|
|
38812
39003
|
read and command, nothing persisted -- either form
|
|
38813
39004
|
feedback command only, nothing persisted -- either form
|
|
@@ -38977,7 +39168,7 @@ function parsedAgentCredential(value) {
|
|
|
38977
39168
|
const withExpiry = [...requiredKeys, "expires_at"].sort();
|
|
38978
39169
|
const actualKeys = Object.keys(artifact).sort();
|
|
38979
39170
|
const shape = actualKeys.length === requiredKeys.length ? requiredKeys : withExpiry;
|
|
38980
|
-
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" || !
|
|
39171
|
+
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_RE19.test(artifact.principal_id) || typeof artifact.token_id !== "string" || !UUID_RE19.test(artifact.token_id) || typeof artifact.run_id !== "string" || !UUID_RE19.test(artifact.run_id) || typeof artifact.agent_token !== "string") {
|
|
38981
39172
|
throw new Error("agent credential JSON is malformed");
|
|
38982
39173
|
}
|
|
38983
39174
|
let expiresAt = null;
|
|
@@ -39215,7 +39406,7 @@ async function runNew(args) {
|
|
|
39215
39406
|
project: {
|
|
39216
39407
|
workspace_id: created,
|
|
39217
39408
|
name,
|
|
39218
|
-
stream_id: typeof response.stream_id === "string" &&
|
|
39409
|
+
stream_id: typeof response.stream_id === "string" && UUID_RE19.test(response.stream_id) ? response.stream_id : null
|
|
39219
39410
|
}
|
|
39220
39411
|
});
|
|
39221
39412
|
return;
|
|
@@ -39989,7 +40180,7 @@ async function runLinkNew(args) {
|
|
|
39989
40180
|
2
|
|
39990
40181
|
);
|
|
39991
40182
|
const taskId = args.required("task-id");
|
|
39992
|
-
if (!
|
|
40183
|
+
if (!UUID_RE19.test(taskId)) {
|
|
39993
40184
|
throw new Error("--task-id must be the work item's UUID");
|
|
39994
40185
|
}
|
|
39995
40186
|
const site = capabilitySiteOrigin(
|
|
@@ -40049,7 +40240,7 @@ async function runLinkRevoke(args) {
|
|
|
40049
40240
|
2
|
|
40050
40241
|
);
|
|
40051
40242
|
const capabilityId = args.required("capability-id");
|
|
40052
|
-
if (!
|
|
40243
|
+
if (!UUID_RE19.test(capabilityId)) {
|
|
40053
40244
|
throw new Error(
|
|
40054
40245
|
"--capability-id must be the id printed when the link was created"
|
|
40055
40246
|
);
|
|
@@ -40628,7 +40819,7 @@ async function runReply(args) {
|
|
|
40628
40819
|
"json"
|
|
40629
40820
|
], 3);
|
|
40630
40821
|
const signalId = args.positionals[1];
|
|
40631
|
-
if (signalId === void 0 || !
|
|
40822
|
+
if (signalId === void 0 || !UUID_RE19.test(signalId)) {
|
|
40632
40823
|
throw new Error("reply requires the signal UUID being answered");
|
|
40633
40824
|
}
|
|
40634
40825
|
const body = args.positionals[2];
|
|
@@ -40770,18 +40961,29 @@ async function runMembers(args) {
|
|
|
40770
40961
|
process.stdout.write(renderRoster(directory, memberNames));
|
|
40771
40962
|
}
|
|
40772
40963
|
async function runSignalRead(args, inbox) {
|
|
40773
|
-
args.
|
|
40964
|
+
const notify = inbox && args.has("notify");
|
|
40965
|
+
args.assertShape(notify ? [
|
|
40966
|
+
...TARGET_FLAGS,
|
|
40967
|
+
"workspace-id",
|
|
40968
|
+
...CREDENTIAL_FLAGS,
|
|
40969
|
+
"notify",
|
|
40970
|
+
"json"
|
|
40971
|
+
] : [
|
|
40774
40972
|
...TARGET_FLAGS,
|
|
40775
40973
|
"workspace-id",
|
|
40776
40974
|
...CREDENTIAL_FLAGS,
|
|
40777
40975
|
"about",
|
|
40778
40976
|
"kind",
|
|
40779
|
-
...inbox ? ["wait", "follow", "ndjson"] : [],
|
|
40977
|
+
...inbox ? ["wait", "follow", "ndjson", "notify"] : [],
|
|
40780
40978
|
"since",
|
|
40781
40979
|
"limit",
|
|
40782
40980
|
"include-stale",
|
|
40783
40981
|
"json"
|
|
40784
40982
|
], 1);
|
|
40983
|
+
if (notify) {
|
|
40984
|
+
await runInboxNotifyCommand(args);
|
|
40985
|
+
return;
|
|
40986
|
+
}
|
|
40785
40987
|
if (inbox && args.has("follow")) {
|
|
40786
40988
|
if (!args.has("ndjson")) {
|
|
40787
40989
|
throw new Error("inbox --follow requires --ndjson");
|
|
@@ -40858,6 +41060,89 @@ async function runSignalRead(args, inbox) {
|
|
|
40858
41060
|
})}
|
|
40859
41061
|
`);
|
|
40860
41062
|
}
|
|
41063
|
+
async function writeMonitorLine(line) {
|
|
41064
|
+
await new Promise((resolve, reject) => {
|
|
41065
|
+
process.stdout.write(`${line}
|
|
41066
|
+
`, (error) => {
|
|
41067
|
+
if (error) reject(error);
|
|
41068
|
+
else resolve();
|
|
41069
|
+
});
|
|
41070
|
+
});
|
|
41071
|
+
}
|
|
41072
|
+
async function runInboxNotifyCommand(args) {
|
|
41073
|
+
if (!args.has("agent-token-stdin")) {
|
|
41074
|
+
throw new Error(
|
|
41075
|
+
"inbox --notify is for one agent; provide its JSON credential with --agent-token-stdin"
|
|
41076
|
+
);
|
|
41077
|
+
}
|
|
41078
|
+
const cloud = await target(args);
|
|
41079
|
+
const selected = await commandWorkspaceAndCredential(args, cloud, {
|
|
41080
|
+
validateHumanWorkspace: true
|
|
41081
|
+
});
|
|
41082
|
+
const principalId = selected.agent?.principalId ?? null;
|
|
41083
|
+
if (selected.kind !== "agent" || principalId === null) {
|
|
41084
|
+
throw new Error(
|
|
41085
|
+
"inbox --notify needs the full JSON agent credential so its durable cursor is tied to one agent"
|
|
41086
|
+
);
|
|
41087
|
+
}
|
|
41088
|
+
const controller = new AbortController();
|
|
41089
|
+
const stop = () => controller.abort();
|
|
41090
|
+
process.on("SIGINT", stop);
|
|
41091
|
+
process.on("SIGTERM", stop);
|
|
41092
|
+
try {
|
|
41093
|
+
const cursorStore = fileArrivalCursorStore({
|
|
41094
|
+
target: cloud,
|
|
41095
|
+
workspaceId: selected.selectedWorkspace,
|
|
41096
|
+
principalId
|
|
41097
|
+
});
|
|
41098
|
+
const result = await runArrivalWatch({
|
|
41099
|
+
workspaceId: selected.selectedWorkspace,
|
|
41100
|
+
principalId,
|
|
41101
|
+
store: cursorStore,
|
|
41102
|
+
signal: controller.signal,
|
|
41103
|
+
readPage: async ({ after, baseline, limit }) => {
|
|
41104
|
+
const token = selected.session ? await selected.session.bearer() : selected.bearer;
|
|
41105
|
+
return await readAgentSignalPage(
|
|
41106
|
+
cloud,
|
|
41107
|
+
{ kind: "agent", token },
|
|
41108
|
+
{
|
|
41109
|
+
workspaceId: selected.selectedWorkspace,
|
|
41110
|
+
inbox: true,
|
|
41111
|
+
limit,
|
|
41112
|
+
includeStale: false,
|
|
41113
|
+
...baseline ? {} : {
|
|
41114
|
+
ascending: true,
|
|
41115
|
+
...after === null ? {} : { after }
|
|
41116
|
+
}
|
|
41117
|
+
},
|
|
41118
|
+
{ signal: controller.signal }
|
|
41119
|
+
);
|
|
41120
|
+
},
|
|
41121
|
+
emit: async (signal) => {
|
|
41122
|
+
const notification = arrivalNotification(
|
|
41123
|
+
signal,
|
|
41124
|
+
selected.selectedWorkspace,
|
|
41125
|
+
cloud
|
|
41126
|
+
);
|
|
41127
|
+
await writeMonitorLine(
|
|
41128
|
+
args.has("json") ? JSON.stringify(notification) : formatArrivalNotification(notification)
|
|
41129
|
+
);
|
|
41130
|
+
},
|
|
41131
|
+
onRetry: (_error, delayMs) => {
|
|
41132
|
+
process.stderr.write(
|
|
41133
|
+
`cswarm: arrival read failed; still watching and retrying in ${delayMs}ms.
|
|
41134
|
+
`
|
|
41135
|
+
);
|
|
41136
|
+
}
|
|
41137
|
+
});
|
|
41138
|
+
if (result.reason === "error") {
|
|
41139
|
+
throw result.error ?? new Error("arrival watch stopped");
|
|
41140
|
+
}
|
|
41141
|
+
} finally {
|
|
41142
|
+
process.off("SIGINT", stop);
|
|
41143
|
+
process.off("SIGTERM", stop);
|
|
41144
|
+
}
|
|
41145
|
+
}
|
|
40861
41146
|
async function runReceipt(args) {
|
|
40862
41147
|
args.assertShape([
|
|
40863
41148
|
...TARGET_FLAGS,
|
|
@@ -40866,7 +41151,7 @@ async function runReceipt(args) {
|
|
|
40866
41151
|
"json"
|
|
40867
41152
|
], 2);
|
|
40868
41153
|
const signalId = args.positionals[1];
|
|
40869
|
-
if (!
|
|
41154
|
+
if (!UUID_RE19.test(signalId)) {
|
|
40870
41155
|
throw new Error("signal-id must be a UUID");
|
|
40871
41156
|
}
|
|
40872
41157
|
if (!args.has("agent-token-stdin")) {
|
|
@@ -41004,7 +41289,7 @@ async function runInboxFollowCommand(args) {
|
|
|
41004
41289
|
}
|
|
41005
41290
|
}
|
|
41006
41291
|
function listenerUuid(value, flag) {
|
|
41007
|
-
if (!value || !
|
|
41292
|
+
if (!value || !UUID_RE19.test(value)) {
|
|
41008
41293
|
throw new Error(`--${flag} must be a UUID`);
|
|
41009
41294
|
}
|
|
41010
41295
|
return value.toLowerCase();
|
|
@@ -41017,7 +41302,7 @@ function listenerPermissionMode(value) {
|
|
|
41017
41302
|
function listenerStateDirectory(args) {
|
|
41018
41303
|
const value = args.optional("state-dir");
|
|
41019
41304
|
if (value === void 0) return void 0;
|
|
41020
|
-
if (!(0,
|
|
41305
|
+
if (!(0, import_node_path20.isAbsolute)(value)) {
|
|
41021
41306
|
throw new Error("--state-dir must be an absolute path");
|
|
41022
41307
|
}
|
|
41023
41308
|
return value;
|
|
@@ -41348,7 +41633,7 @@ function resolveDetachedClaudeExecutable(executable = "claude-agent-acp", pathEn
|
|
|
41348
41633
|
} catch (error) {
|
|
41349
41634
|
const code = error.code;
|
|
41350
41635
|
if (typeof code === "string") {
|
|
41351
|
-
if ((0,
|
|
41636
|
+
if ((0, import_node_path20.isAbsolute)(executable) || executable.includes("/") || executable.includes("\\")) {
|
|
41352
41637
|
const detail = error instanceof Error ? error.message : code;
|
|
41353
41638
|
throw new Error(
|
|
41354
41639
|
`could not use --claude-executable: ${detail}; install the current bridge with npm install -g @agentclientprotocol/claude-agent-acp@latest if this path should be replaced`
|
|
@@ -41365,7 +41650,7 @@ function resolveDetachedCodexExecutable(executable = "codex-acp", pathEnv = proc
|
|
|
41365
41650
|
} catch (error) {
|
|
41366
41651
|
const code = error.code;
|
|
41367
41652
|
if (typeof code === "string") {
|
|
41368
|
-
if ((0,
|
|
41653
|
+
if ((0, import_node_path20.isAbsolute)(executable) || executable.includes("/") || executable.includes("\\")) {
|
|
41369
41654
|
const detail = error instanceof Error ? error.message : code;
|
|
41370
41655
|
throw new Error(
|
|
41371
41656
|
`could not use --codex-executable: ${detail}; install the current bridge with npm install -g @agentclientprotocol/codex-acp@latest if this path should be replaced`
|
|
@@ -41632,7 +41917,7 @@ async function runListenStart(args) {
|
|
|
41632
41917
|
assertDurableListenerCredential(agent);
|
|
41633
41918
|
const principalId = agent.principalId;
|
|
41634
41919
|
const cwd = args.optional("cwd") ?? process.cwd();
|
|
41635
|
-
if (!(0,
|
|
41920
|
+
if (!(0, import_node_path20.isAbsolute)(cwd)) throw new Error("--cwd must be an absolute path");
|
|
41636
41921
|
const permissionMode = listenerPermissionMode(args.optional("permissions"));
|
|
41637
41922
|
const stateDirectory2 = listenerStateDirectory(args);
|
|
41638
41923
|
const paths = listenerPaths({
|
|
@@ -41669,7 +41954,7 @@ async function runListenStart(args) {
|
|
|
41669
41954
|
});
|
|
41670
41955
|
} else {
|
|
41671
41956
|
const entrypoint = process.argv[1];
|
|
41672
|
-
if (!entrypoint || !(0,
|
|
41957
|
+
if (!entrypoint || !(0, import_node_path20.isAbsolute)(entrypoint)) {
|
|
41673
41958
|
throw new Error("cannot locate the cswarm executable for detached start");
|
|
41674
41959
|
}
|
|
41675
41960
|
const artifact = JSON.stringify(agentCredentialArtifact({
|
|
@@ -41807,7 +42092,7 @@ async function runListenSupervisor(args) {
|
|
|
41807
42092
|
const agent = await stdinCredential();
|
|
41808
42093
|
assertDurableListenerCredential(agent, principalId);
|
|
41809
42094
|
const cwd = args.required("cwd");
|
|
41810
|
-
if (!(0,
|
|
42095
|
+
if (!(0, import_node_path20.isAbsolute)(cwd)) throw new Error("--cwd must be an absolute path");
|
|
41811
42096
|
const status = await runConfiguredListener({
|
|
41812
42097
|
cloud,
|
|
41813
42098
|
workspaceId: workspaceId2,
|
|
@@ -41909,7 +42194,7 @@ function claudeUserPromptHookSnippet() {
|
|
|
41909
42194
|
};
|
|
41910
42195
|
}
|
|
41911
42196
|
function projectClaudeSettingsPath() {
|
|
41912
|
-
return (0,
|
|
42197
|
+
return (0, import_node_path20.join)(process.cwd(), ".claude", "settings.json");
|
|
41913
42198
|
}
|
|
41914
42199
|
function readProjectSettings(path) {
|
|
41915
42200
|
let raw;
|
|
@@ -42021,7 +42306,7 @@ async function runHook(args) {
|
|
|
42021
42306
|
const path = projectClaudeSettingsPath();
|
|
42022
42307
|
const settings = readProjectSettings(path);
|
|
42023
42308
|
const updated = command2 === "install" ? installClaudeHook(settings) : uninstallClaudeHook(settings);
|
|
42024
|
-
(0, import_node_fs7.mkdirSync)((0,
|
|
42309
|
+
(0, import_node_fs7.mkdirSync)((0, import_node_path20.dirname)(path), { recursive: true });
|
|
42025
42310
|
(0, import_node_fs7.writeFileSync)(path, `${JSON.stringify(updated, null, 2)}
|
|
42026
42311
|
`, {
|
|
42027
42312
|
encoding: "utf8",
|
|
@@ -42067,7 +42352,7 @@ async function fileRows(context) {
|
|
|
42067
42352
|
);
|
|
42068
42353
|
}
|
|
42069
42354
|
async function resolveFileSelector(context, selector) {
|
|
42070
|
-
if (
|
|
42355
|
+
if (UUID_RE19.test(selector)) return selector.toLowerCase();
|
|
42071
42356
|
const rows3 = await fileRows(context);
|
|
42072
42357
|
const match = rows3.find(
|
|
42073
42358
|
(row) => row.name.toLowerCase() === selector.toLowerCase()
|
|
@@ -42089,7 +42374,7 @@ async function runFilePut(args) {
|
|
|
42089
42374
|
} catch {
|
|
42090
42375
|
throw new Error(`could not read ${localPath}; check the path and permissions`);
|
|
42091
42376
|
}
|
|
42092
|
-
const name = args.optional("name") ?? (0,
|
|
42377
|
+
const name = args.optional("name") ?? (0, import_node_path20.basename)(localPath);
|
|
42093
42378
|
if (bytes.byteLength > FILE_MAX_VERSION_BYTES) {
|
|
42094
42379
|
throw new Error(
|
|
42095
42380
|
`this file is ${formatFileSize(bytes.byteLength)}; the per-file limit is ${formatFileSize(FILE_MAX_VERSION_BYTES)}, so the upload was not started`
|
|
@@ -42191,7 +42476,7 @@ async function runFileGet(args) {
|
|
|
42191
42476
|
credential: context.selected.bearer
|
|
42192
42477
|
};
|
|
42193
42478
|
const grant = await fileDownloadUrl(send, { fileId, versionN });
|
|
42194
|
-
const destination = args.optional("out") ?? (0,
|
|
42479
|
+
const destination = args.optional("out") ?? (0, import_node_path20.basename)(grant.name);
|
|
42195
42480
|
const bytes = await getObject(context.cloud, grant.download_path);
|
|
42196
42481
|
writeDestination(destination, bytes, args.has("force"), import_node_fs7.writeFileSync);
|
|
42197
42482
|
if (args.has("json")) {
|
|
@@ -42407,7 +42692,7 @@ async function runSeed(args) {
|
|
|
42407
42692
|
throw new Error("DATABASE_URL is required for the fixture bridge");
|
|
42408
42693
|
}
|
|
42409
42694
|
const tokenOut = process.env.SEED_TOKEN_OUT;
|
|
42410
|
-
if (!tokenOut || !(0,
|
|
42695
|
+
if (!tokenOut || !(0, import_node_path20.isAbsolute)(tokenOut)) {
|
|
42411
42696
|
throw new Error("SEED_TOKEN_OUT must be an absolute path");
|
|
42412
42697
|
}
|
|
42413
42698
|
const tokenFile = await (0, import_promises11.open)(tokenOut, "wx", 384).catch((error) => {
|