@scp-dev/cli 0.1.0 → 0.1.3
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/README.md +10 -6
- package/dist/{chunk-DA3EB2YF.js → chunk-3PGDKPRN.js} +4 -59
- package/dist/{chunk-6UFMKYPH.js → chunk-5UWLTO2Y.js} +4 -4
- package/dist/{spawn-7P4EMSVB.js → chunk-ABP5AKFH.js} +119 -54
- package/dist/{chunk-RO7CUOOH.js → chunk-ABR5UABL.js} +16 -7
- package/dist/{chunk-4QYUPPGV.js → chunk-BUC5G5PY.js} +3 -3
- package/dist/{chunk-O4J5G2X7.js → chunk-IH2RJRIW.js} +6 -5
- package/dist/{chunk-IE5VI25P.js → chunk-KN7WEIE4.js} +1 -1
- package/dist/chunk-M2DCR2J4.js +63 -0
- package/dist/{chunk-WSLKRAB7.js → chunk-QQZF5TQD.js} +4 -4
- package/dist/{chunk-7KP6TAJW.js → chunk-URSBFDR6.js} +9 -5
- package/dist/claude-5WTICOYS.js +88 -0
- package/dist/cli.js +1 -1
- package/dist/daemon-SUTLTY5U.js +52 -0
- package/dist/{hooks-MBKU56HG.js → hooks-4YVIPZKE.js} +3 -2
- package/dist/install-4KQQWGGB.js +15 -0
- package/dist/{login-JTRUWG6Q.js → login-5Y3HPSVC.js} +5 -4
- package/dist/{main-QP32TYTL.js → main-PZQAJGHQ.js} +124 -31
- package/dist/{mcp-EQCSCD3X.js → mcp-GI5OMTUT.js} +35 -5
- package/dist/{peek-YCOWBEPD.js → peek-X4SEGEUB.js} +3 -2
- package/dist/{relay-VVJPYVXE.js → relay-W2NFUE2U.js} +4 -3
- package/dist/{remote-3BWFISXJ.js → remote-GC4XN44U.js} +5 -4
- package/dist/{setup-T4ZZKV7K.js → setup-UF4AA6RO.js} +8 -5
- package/dist/spawn-KT5235WX.js +75 -0
- package/dist/{up-Z4RSJMED.js → up-VA54QWA6.js} +8 -7
- package/package.json +5 -5
- package/dist/install-4HATFIFI.js +0 -14
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import {
|
|
2
|
+
entryArgv,
|
|
3
|
+
mcpFile,
|
|
4
|
+
mountedEntry,
|
|
5
|
+
whichOnPath
|
|
6
|
+
} from "./chunk-IH2RJRIW.js";
|
|
7
|
+
import "./chunk-QQZF5TQD.js";
|
|
8
|
+
import {
|
|
9
|
+
CHANNELS_ENV,
|
|
10
|
+
RelayUsage
|
|
11
|
+
} from "./chunk-URSBFDR6.js";
|
|
12
|
+
import "./chunk-ABR5UABL.js";
|
|
13
|
+
import "./chunk-YYSLYVNZ.js";
|
|
14
|
+
import "./chunk-3PGDKPRN.js";
|
|
15
|
+
import "./chunk-M2DCR2J4.js";
|
|
16
|
+
|
|
17
|
+
// src/claude.ts
|
|
18
|
+
import { spawn } from "child_process";
|
|
19
|
+
import { CLI_NAME, validHandle } from "@scp-dev/core";
|
|
20
|
+
var CHANNEL_FLAGS = ["--dangerously-load-development-channels", "server:scp"];
|
|
21
|
+
function claudeArgv(argv) {
|
|
22
|
+
let name;
|
|
23
|
+
let i = 0;
|
|
24
|
+
if (argv[0] === "--name") {
|
|
25
|
+
if (argv[1] === void 0) throw new RelayUsage(`${CLI_NAME} claude --name takes a handle`);
|
|
26
|
+
name = argv[1];
|
|
27
|
+
i = 2;
|
|
28
|
+
} else if (argv[0]?.startsWith("--name=")) {
|
|
29
|
+
name = argv[0].slice("--name=".length);
|
|
30
|
+
i = 1;
|
|
31
|
+
}
|
|
32
|
+
if (argv[i] === "--") i++;
|
|
33
|
+
if (name !== void 0 && !validHandle(name)) throw new RelayUsage(`--name ${JSON.stringify(name)} is not a valid agent handle`);
|
|
34
|
+
return { ...name !== void 0 ? { name } : {}, args: argv.slice(i) };
|
|
35
|
+
}
|
|
36
|
+
function mountHint(env) {
|
|
37
|
+
const file = mcpFile("claude", env);
|
|
38
|
+
let entry;
|
|
39
|
+
try {
|
|
40
|
+
entry = mountedEntry("claude", file);
|
|
41
|
+
} catch {
|
|
42
|
+
return `${CLI_NAME} claude: ${file} is unreadable, so the scp mount is unchecked`;
|
|
43
|
+
}
|
|
44
|
+
if (!entry) return `${CLI_NAME} claude: Claude Code has no scp MCP mount; run ${CLI_NAME} setup --write`;
|
|
45
|
+
if (!entryArgv("claude", entry).includes("--channels"))
|
|
46
|
+
return `${CLI_NAME} claude: the scp mount lacks --channels, so messages will not wake this session; re-run ${CLI_NAME} setup --write`;
|
|
47
|
+
return void 0;
|
|
48
|
+
}
|
|
49
|
+
async function claudeCommand(argv, env = process.env, err = (line) => void process.stderr.write(`${line}
|
|
50
|
+
`)) {
|
|
51
|
+
if (argv[0] === "--help" || argv[0] === "-h") {
|
|
52
|
+
process.stdout.write(`${CLI_NAME} claude [--name N] [--] [claude args...] start Claude Code with the scp channel loaded, so peer messages wake it
|
|
53
|
+
`);
|
|
54
|
+
return 0;
|
|
55
|
+
}
|
|
56
|
+
const { name, args } = claudeArgv(argv);
|
|
57
|
+
const bin = whichOnPath("claude", env);
|
|
58
|
+
if (!bin) throw new RelayUsage("claude is not on PATH");
|
|
59
|
+
const hint = mountHint(env);
|
|
60
|
+
if (hint) err(hint);
|
|
61
|
+
const child = spawn(bin, [...CHANNEL_FLAGS, ...args], {
|
|
62
|
+
stdio: "inherit",
|
|
63
|
+
env: { ...env, ...name !== void 0 ? { SCP_NAME: name } : {}, [CHANNELS_ENV]: String(process.pid) }
|
|
64
|
+
});
|
|
65
|
+
const forward = (signal) => () => void child.kill(signal);
|
|
66
|
+
const handlers = ["SIGTERM", "SIGHUP"].map((signal) => [signal, forward(signal)]);
|
|
67
|
+
const ignore = () => {
|
|
68
|
+
};
|
|
69
|
+
process.on("SIGINT", ignore);
|
|
70
|
+
for (const [signal, handler] of handlers) process.on(signal, handler);
|
|
71
|
+
try {
|
|
72
|
+
return await new Promise((resolve, reject) => {
|
|
73
|
+
child.once("error", reject);
|
|
74
|
+
child.once("exit", (code, signal) => resolve(code ?? (signal ? 128 + (signalNumber(signal) ?? 1) : 1)));
|
|
75
|
+
});
|
|
76
|
+
} finally {
|
|
77
|
+
process.off("SIGINT", ignore);
|
|
78
|
+
for (const [signal, handler] of handlers) process.off(signal, handler);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
var SIGNALS = { SIGHUP: 1, SIGINT: 2, SIGKILL: 9, SIGTERM: 15 };
|
|
82
|
+
var signalNumber = (signal) => SIGNALS[signal];
|
|
83
|
+
export {
|
|
84
|
+
CHANNEL_FLAGS,
|
|
85
|
+
claudeArgv,
|
|
86
|
+
claudeCommand,
|
|
87
|
+
mountHint
|
|
88
|
+
};
|
package/dist/cli.js
CHANGED
|
@@ -17,6 +17,6 @@ function quietSqliteWarning() {
|
|
|
17
17
|
// src/cli.ts
|
|
18
18
|
if (!await subagentFastPath(process.argv.slice(2))) {
|
|
19
19
|
quietSqliteWarning();
|
|
20
|
-
const { run } = await import("./main-
|
|
20
|
+
const { run } = await import("./main-PZQAJGHQ.js");
|
|
21
21
|
await run(process.argv.slice(2));
|
|
22
22
|
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import {
|
|
2
|
+
capture
|
|
3
|
+
} from "./chunk-M2DCR2J4.js";
|
|
4
|
+
|
|
5
|
+
// src/daemon.ts
|
|
6
|
+
import { readFileSync } from "fs";
|
|
7
|
+
import { join } from "path";
|
|
8
|
+
import { setTimeout as sleep } from "timers/promises";
|
|
9
|
+
function brokerPid(dir) {
|
|
10
|
+
let pid;
|
|
11
|
+
try {
|
|
12
|
+
pid = Number(readFileSync(join(dir, "broker.lock"), "utf8").split(":")[0]);
|
|
13
|
+
} catch {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
if (!Number.isInteger(pid) || pid <= 0) return null;
|
|
17
|
+
const command = capture(["ps", "-p", String(pid), "-o", "command="])?.trim() ?? "";
|
|
18
|
+
return /(^|\s)daemon(\s|$)/.test(command) && (/scp|swarm/.test(command) || command.includes(process.argv[1] ?? "\0")) ? pid : null;
|
|
19
|
+
}
|
|
20
|
+
function alive(pid) {
|
|
21
|
+
try {
|
|
22
|
+
process.kill(pid, 0);
|
|
23
|
+
return true;
|
|
24
|
+
} catch (error) {
|
|
25
|
+
return error.code === "EPERM";
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
async function exited(pid, ms = 5e3) {
|
|
29
|
+
const deadline = Date.now() + ms;
|
|
30
|
+
while (alive(pid)) {
|
|
31
|
+
if (Date.now() >= deadline) return false;
|
|
32
|
+
await sleep(50);
|
|
33
|
+
}
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
async function stopBroker(dir) {
|
|
37
|
+
const pid = brokerPid(dir);
|
|
38
|
+
if (pid === null) return null;
|
|
39
|
+
try {
|
|
40
|
+
process.kill(pid, "SIGTERM");
|
|
41
|
+
} catch (error) {
|
|
42
|
+
if (error.code === "ESRCH") return null;
|
|
43
|
+
throw error;
|
|
44
|
+
}
|
|
45
|
+
if (!await exited(pid)) throw new Error(`the relay broker (pid ${pid}) did not stop within 5 s`);
|
|
46
|
+
return pid;
|
|
47
|
+
}
|
|
48
|
+
export {
|
|
49
|
+
brokerPid,
|
|
50
|
+
exited,
|
|
51
|
+
stopBroker
|
|
52
|
+
};
|
|
@@ -30,11 +30,12 @@ import {
|
|
|
30
30
|
subagentIntro,
|
|
31
31
|
summarize,
|
|
32
32
|
unreadPointer
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-ABR5UABL.js";
|
|
34
34
|
import {
|
|
35
35
|
SUBAGENT
|
|
36
36
|
} from "./chunk-YYSLYVNZ.js";
|
|
37
|
-
import "./chunk-
|
|
37
|
+
import "./chunk-3PGDKPRN.js";
|
|
38
|
+
import "./chunk-M2DCR2J4.js";
|
|
38
39
|
export {
|
|
39
40
|
AGY_HOOK_SET,
|
|
40
41
|
AGY_UNVERIFIED,
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import {
|
|
2
|
+
hooksTarget,
|
|
3
|
+
installHooks,
|
|
4
|
+
mcpInstall
|
|
5
|
+
} from "./chunk-QQZF5TQD.js";
|
|
6
|
+
import "./chunk-URSBFDR6.js";
|
|
7
|
+
import "./chunk-ABR5UABL.js";
|
|
8
|
+
import "./chunk-YYSLYVNZ.js";
|
|
9
|
+
import "./chunk-3PGDKPRN.js";
|
|
10
|
+
import "./chunk-M2DCR2J4.js";
|
|
11
|
+
export {
|
|
12
|
+
hooksTarget,
|
|
13
|
+
installHooks,
|
|
14
|
+
mcpInstall
|
|
15
|
+
};
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import {
|
|
2
2
|
machineName
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-5UWLTO2Y.js";
|
|
4
4
|
import {
|
|
5
5
|
activeRelay,
|
|
6
6
|
saveCredential
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-BUC5G5PY.js";
|
|
8
8
|
import {
|
|
9
9
|
RelayUsage
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-URSBFDR6.js";
|
|
11
|
+
import "./chunk-3PGDKPRN.js";
|
|
11
12
|
import {
|
|
12
13
|
note
|
|
13
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-M2DCR2J4.js";
|
|
14
15
|
|
|
15
16
|
// src/login.ts
|
|
16
17
|
import { spawn } from "child_process";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
SPAWN_HELP
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-KN7WEIE4.js";
|
|
4
4
|
import {
|
|
5
5
|
OPTIONS,
|
|
6
6
|
RelayUsage,
|
|
@@ -14,15 +14,17 @@ import {
|
|
|
14
14
|
stamp,
|
|
15
15
|
startDaemon,
|
|
16
16
|
time
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-URSBFDR6.js";
|
|
18
|
+
import {
|
|
19
|
+
shortHostname
|
|
20
|
+
} from "./chunk-3PGDKPRN.js";
|
|
18
21
|
import {
|
|
19
22
|
FAILED,
|
|
20
23
|
exitFlushed,
|
|
21
24
|
note,
|
|
22
25
|
parseSeconds,
|
|
23
|
-
printTable
|
|
24
|
-
|
|
25
|
-
} from "./chunk-DA3EB2YF.js";
|
|
26
|
+
printTable
|
|
27
|
+
} from "./chunk-M2DCR2J4.js";
|
|
26
28
|
|
|
27
29
|
// src/main.ts
|
|
28
30
|
import { text as readAll } from "stream/consumers";
|
|
@@ -33,7 +35,7 @@ import { parseArgs } from "util";
|
|
|
33
35
|
// package.json
|
|
34
36
|
var package_default = {
|
|
35
37
|
name: "@scp-dev/cli",
|
|
36
|
-
version: "0.1.
|
|
38
|
+
version: "0.1.3",
|
|
37
39
|
description: "The swarm command line tool.",
|
|
38
40
|
license: "Apache-2.0",
|
|
39
41
|
homepage: "https://scp.dev",
|
|
@@ -78,6 +80,7 @@ import {
|
|
|
78
80
|
LIMITS,
|
|
79
81
|
PREAMBLE,
|
|
80
82
|
reachLines,
|
|
83
|
+
receiptLines,
|
|
81
84
|
RelayError,
|
|
82
85
|
shortId,
|
|
83
86
|
stripControl,
|
|
@@ -96,14 +99,16 @@ results back, as with native subagents.
|
|
|
96
99
|
${CLI_NAME} ask <to> [text|-] [--wait S] send a request and wait for its reply: ${CLI_NAME} ask lead "which branch?"
|
|
97
100
|
${CLI_NAME} inbox [--wait S] your unread messages, then marked read: ${CLI_NAME} inbox
|
|
98
101
|
${CLI_NAME} list [--all] agents on the relay: address, title, presence, status
|
|
99
|
-
${CLI_NAME} status
|
|
102
|
+
${CLI_NAME} status [id] the fleet in short; with the id of a message you sent: who read it when
|
|
100
103
|
${CLI_NAME} peek <ep> a short, redacted view of a peekable agent's last turns: ${CLI_NAME} peek rev
|
|
101
104
|
${CLI_NAME} set-status <state> [note] working, waiting, blocked or done: ${CLI_NAME} set-status done "PR open"
|
|
102
105
|
|
|
103
106
|
- spawn returns at once with the worker's name: do not background it (no &, no run_in_background).
|
|
104
107
|
- A worker's messages and its handback (exit code and its whole reply) arrive by themselves: when you stop, your stop
|
|
105
108
|
waits for them and continues with them, and new messages also reach you after your tool calls. No polling needed.
|
|
106
|
-
- Address a worker by the name spawn printed. Steer it meanwhile with ${CLI_NAME} send <name> <text
|
|
109
|
+
- Address a worker by the name spawn printed. Steer it meanwhile with ${CLI_NAME} send <name> <text>: it gets
|
|
110
|
+
the message after its next tool call or before it finishes, so its task need not tell it to check an inbox.
|
|
111
|
+
- With the relay MCP tools: relay_spawn starts a worker in one call, relay_send steers it, relay_status reads receipts.
|
|
107
112
|
- --no-push: a worker your stop does not wait on; its messages and handback still reach you after your tool calls
|
|
108
113
|
or with another worker's push.
|
|
109
114
|
- An <id> is a message id, its short id (the last 6 characters, shown with every message) or last.
|
|
@@ -132,6 +137,9 @@ usage:
|
|
|
132
137
|
${CLI_NAME} ask-wait <id> [--wait S] keep waiting for the reply to a request
|
|
133
138
|
${CLI_NAME} status [--all] [--activity] the fleet in short: you, agents by presence and status, who waits or is blocked,
|
|
134
139
|
unread counts; --activity adds the latest activity, --all counts offline agents
|
|
140
|
+
${CLI_NAME} status <id> a message you sent, a line per recipient: read at HH:MM:SS, delivered at
|
|
141
|
+
HH:MM:SS (a background hook handed it over; it reaches the model with its next
|
|
142
|
+
request), shown by a hook at HH:MM:SS (in its context, not yet marked read), or unread
|
|
135
143
|
${CLI_NAME} watch a live tail of the fleet: presence, messages, status, activity
|
|
136
144
|
${CLI_NAME} set-status <state> [note] your status line: working, waiting, blocked or done
|
|
137
145
|
${CLI_NAME} set-title <text> what you work on, shown in list, peers and whoami ("" clears it)
|
|
@@ -188,8 +196,10 @@ scopes (selectors are comma-separated, e.g. tree:parent,tree:children,group:team
|
|
|
188
196
|
still reach you after your tool calls, with another worker's push, or in your inbox.
|
|
189
197
|
codex gets -c overrides that hand the grant to its scp MCP server
|
|
190
198
|
(also behind env, VAR=value, timeout, nohup or nice). codex exec outside a git
|
|
191
|
-
repo gets --skip-git-repo-check when its codex has it
|
|
192
|
-
runs on /dev/null for stdin
|
|
199
|
+
repo gets --skip-git-repo-check when its codex has it. With its prompt in argv it
|
|
200
|
+
runs on /dev/null for stdin, except in the foreground (--fg), where piped context
|
|
201
|
+
or a file reaches it (from an agent's shell only a pipe with data within 300 ms);
|
|
202
|
+
a - prompt, or none, keeps stdin.
|
|
193
203
|
claude -p and grok -p get the relay messaging tools allowed (--allowedTools,
|
|
194
204
|
grok --allow) unless you pass a permission flag. muse runs with
|
|
195
205
|
--contributor-mode off unless you pass --contributor-mode on (or a -c contributor
|
|
@@ -222,6 +232,7 @@ scopes (selectors are comma-separated, e.g. tree:parent,tree:children,group:team
|
|
|
222
232
|
other process under an agent they may only narrow. An ancestor always reaches its descendants, and a recipient
|
|
223
233
|
may always reply in the thread to a message it got; a reply to another message of the thread is checked as a send.
|
|
224
234
|
${CLI_NAME} daemon [--idle DURATION] [--policy FILE] run the broker in the foreground (it otherwise starts on demand)
|
|
235
|
+
${CLI_NAME} daemon stop|restart stop the running broker, or replace it with a fresh one
|
|
225
236
|
|
|
226
237
|
agent sessions:
|
|
227
238
|
${CLI_NAME} mcp [--as NAME] [--harness H] [--channels] the MCP shim a harness mounts: relay tools for one agent, never me/
|
|
@@ -246,7 +257,9 @@ agent sessions:
|
|
|
246
257
|
A Claude Code subagent's hooks give it a child endpoint, <session handle>-<type>-<first 6 of its id>, whose messages
|
|
247
258
|
reach it after its tools; its shell is the session's, so it acts as that child with --as.
|
|
248
259
|
Grok runs the Claude Code hooks, labelled grok; Muse takes them as a plugin; Codex runs new hooks after /hooks review.
|
|
249
|
-
--
|
|
260
|
+
${CLI_NAME} claude [--name N] [--] [claude args...] start Claude Code with the scp channel loaded, so peer messages wake
|
|
261
|
+
it while idle (claude --dangerously-load-development-channels server:scp; SCP_NAME=N)
|
|
262
|
+
--channels pushes messages into a Claude Code that ${CLI_NAME} claude started; setup mounts claude's shim with it.
|
|
250
263
|
|
|
251
264
|
relay:
|
|
252
265
|
${CLI_NAME} relay use <url> | show select a relay, or show its source and credential status
|
|
@@ -348,6 +361,7 @@ var VERBS = {
|
|
|
348
361
|
machines: IDENTITY
|
|
349
362
|
};
|
|
350
363
|
var MESSAGE_REF = /^(last|[0-9a-z]{4,})$/;
|
|
364
|
+
var ACK_ALL_PAGES = Math.ceil(2 * LIMITS.inboxMax / LIMITS.inboxPage) + 1;
|
|
351
365
|
async function lookup(client, id, member = false) {
|
|
352
366
|
try {
|
|
353
367
|
return (await client.request("message", { id, ...member ? { member: true } : {} })).message;
|
|
@@ -386,6 +400,7 @@ function printMessage(message) {
|
|
|
386
400
|
out(
|
|
387
401
|
`#${message.seq} ${message.kind} from ${message.from.address} (${harness}) ${time(message.created_at)} id ${shortId(message.id)} (${message.id})${message.reply_to ? ` reply to ${message.reply_to}` : ""}`
|
|
388
402
|
);
|
|
403
|
+
if (message.shown_at) out(`(a hook already showed you this at ${time(message.shown_at)}; that copy may reach you after this command)`);
|
|
389
404
|
out(wrapMessage(message));
|
|
390
405
|
out();
|
|
391
406
|
}
|
|
@@ -481,10 +496,11 @@ async function relayMain(argv, cwd = process.cwd()) {
|
|
|
481
496
|
out(package_default.version);
|
|
482
497
|
return 0;
|
|
483
498
|
}
|
|
484
|
-
if (verb === "hook") return (await import("./hooks-
|
|
485
|
-
if (verb === "setup") return (await import("./setup-
|
|
499
|
+
if (verb === "hook") return (await import("./hooks-4YVIPZKE.js")).relayHookCommand(rest, startDaemon);
|
|
500
|
+
if (verb === "setup") return (await import("./setup-UF4AA6RO.js")).relaySetupCommand(rest, cwd, out);
|
|
501
|
+
if (verb === "claude") return (await import("./claude-5WTICOYS.js")).claudeCommand(rest);
|
|
486
502
|
if (verb === "spawn") {
|
|
487
|
-
const { splitSpawn, spawnCommand } = await import("./spawn-
|
|
503
|
+
const { splitSpawn, spawnCommand } = await import("./spawn-KT5235WX.js");
|
|
488
504
|
const { flags } = splitSpawn(rest);
|
|
489
505
|
if (flags.includes("--help") || flags.includes("-h")) {
|
|
490
506
|
out(flags.includes("--all") ? RELAY_HELP : SPAWN_HELP);
|
|
@@ -506,13 +522,16 @@ async function relayMain(argv, cwd = process.cwd()) {
|
|
|
506
522
|
return 0;
|
|
507
523
|
}
|
|
508
524
|
for (const key of Object.keys(values)) if (!allowed.includes(key)) throw new RelayUsage(`${CLI_NAME} ${verb} does not take --${key}`);
|
|
509
|
-
if (verb === "daemon")
|
|
525
|
+
if (verb === "daemon") {
|
|
526
|
+
if (positionals.length) return daemonControl(positionals, values);
|
|
527
|
+
return daemon(values.idle, values.policy);
|
|
528
|
+
}
|
|
510
529
|
if (verb === "mcp")
|
|
511
|
-
return (await import("./mcp-
|
|
530
|
+
return (await import("./mcp-GI5OMTUT.js")).relayMcpCommand(values, positionals);
|
|
512
531
|
if (verb === "hooks") {
|
|
513
532
|
if (positionals[0] !== "install" || positionals.length > 1) throw new RelayUsage(`${CLI_NAME} hooks takes install --harness claude|codex|opencode|agy|muse`);
|
|
514
533
|
if (values.write && values.print) throw new RelayUsage("--print and --write: pick one");
|
|
515
|
-
return (await import("./install-
|
|
534
|
+
return (await import("./install-4KQQWGGB.js")).installHooks({
|
|
516
535
|
harness: values.harness,
|
|
517
536
|
scope: values.scope,
|
|
518
537
|
write: values.write === true,
|
|
@@ -523,18 +542,25 @@ async function relayMain(argv, cwd = process.cwd()) {
|
|
|
523
542
|
out
|
|
524
543
|
});
|
|
525
544
|
}
|
|
526
|
-
if (verb === "relay") return (await import("./relay-
|
|
527
|
-
if (verb === "up") return (await import("./up-
|
|
528
|
-
if (verb === "login")
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
545
|
+
if (verb === "relay") return (await import("./relay-W2NFUE2U.js")).relayVerb(positionals, values.json === true);
|
|
546
|
+
if (verb === "up") return (await import("./up-VA54QWA6.js")).up(positionals, values, cwd, relinkBroker);
|
|
547
|
+
if (verb === "login") {
|
|
548
|
+
const code = await (await import("./relay-W2NFUE2U.js")).loginMain(positionals, values);
|
|
549
|
+
if (code === 0) await relinkRunning();
|
|
550
|
+
return code;
|
|
551
|
+
}
|
|
552
|
+
if (verb === "logout") return (await import("./relay-W2NFUE2U.js")).logoutMain(positionals, values.json === true);
|
|
553
|
+
if (verb === "cloud") {
|
|
554
|
+
const code = await (await import("./remote-GC4XN44U.js")).cloudMain(positionals, values, cloudStatus);
|
|
555
|
+
if (code === 0 && positionals[0] === "enable") await relinkRunning();
|
|
556
|
+
return code;
|
|
557
|
+
}
|
|
532
558
|
if (verb === "holds") holdsArgs(values, positionals);
|
|
533
559
|
const bodyFromStdin = (verb === "send" || verb === "ask" || verb === "reply") && (positionals[1] === void 0 || positionals[1] === "-");
|
|
534
560
|
const opened = await open(verb, values, cwd, bodyFromStdin);
|
|
535
561
|
const { client } = opened;
|
|
536
562
|
try {
|
|
537
|
-
if (verb === "machines") return await (await import("./remote-
|
|
563
|
+
if (verb === "machines") return await (await import("./remote-GC4XN44U.js")).machinesVerb(client, positionals, values.json === true);
|
|
538
564
|
return await runVerb(opened, verb, values, positionals, cwd);
|
|
539
565
|
} finally {
|
|
540
566
|
client.close();
|
|
@@ -550,6 +576,55 @@ async function cloudStatus() {
|
|
|
550
576
|
client.close();
|
|
551
577
|
}
|
|
552
578
|
}
|
|
579
|
+
async function relinkBroker() {
|
|
580
|
+
const dir = relayDir();
|
|
581
|
+
const client = await connectBroker(dir, () => startDaemon(dir));
|
|
582
|
+
let result;
|
|
583
|
+
let pid;
|
|
584
|
+
try {
|
|
585
|
+
pid = (await client.hello({ observe: true })).broker.pid;
|
|
586
|
+
result = await client.request("bridge_relink");
|
|
587
|
+
} catch (error) {
|
|
588
|
+
if (error instanceof RelayError && error.code === "method_not_found") return cloudStatus();
|
|
589
|
+
throw error;
|
|
590
|
+
} finally {
|
|
591
|
+
client.close();
|
|
592
|
+
}
|
|
593
|
+
if (!result.restarting) return result;
|
|
594
|
+
await (await import("./daemon-SUTLTY5U.js")).exited(pid);
|
|
595
|
+
return cloudStatus();
|
|
596
|
+
}
|
|
597
|
+
async function relinkRunning() {
|
|
598
|
+
try {
|
|
599
|
+
await connectBroker(relayDir()).then((client) => client.close());
|
|
600
|
+
} catch {
|
|
601
|
+
return;
|
|
602
|
+
}
|
|
603
|
+
try {
|
|
604
|
+
await relinkBroker();
|
|
605
|
+
} catch (error) {
|
|
606
|
+
note(`the running broker did not link again (${error instanceof Error ? error.message : String(error)}); run \`${CLI_NAME} daemon restart\``);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
async function daemonControl(positionals, values) {
|
|
610
|
+
const [action] = positionals;
|
|
611
|
+
if (positionals.length !== 1 || action !== "stop" && action !== "restart" || values.idle !== void 0 || values.policy !== void 0)
|
|
612
|
+
throw new RelayUsage(`${CLI_NAME} daemon takes stop or restart, or --idle and --policy to run in the foreground`);
|
|
613
|
+
const dir = relayDir();
|
|
614
|
+
const pid = await (await import("./daemon-SUTLTY5U.js")).stopBroker(dir);
|
|
615
|
+
if (action === "stop") {
|
|
616
|
+
out(pid === null ? "no relay broker runs" : `stopped the relay broker (pid ${pid}); the next command starts a fresh one`);
|
|
617
|
+
return 0;
|
|
618
|
+
}
|
|
619
|
+
const client = await connectBroker(dir, () => startDaemon(dir));
|
|
620
|
+
try {
|
|
621
|
+
const { broker } = await client.hello({ observe: true });
|
|
622
|
+
out(`${pid === null ? "started" : `replaced the relay broker (pid ${pid}) with`} a fresh one (pid ${broker.pid})`);
|
|
623
|
+
} finally {
|
|
624
|
+
client.close();
|
|
625
|
+
}
|
|
626
|
+
return 0;
|
|
627
|
+
}
|
|
553
628
|
async function runVerb({ client, me, broker, where, bound, harnessPid }, verb, values, positionals, cwd) {
|
|
554
629
|
const asJson = values.json === true;
|
|
555
630
|
const attachments = (values.attach ?? []).map((path) => ({ kind: "path", path: path.startsWith("/") ? path : `${cwd}/${path}` }));
|
|
@@ -662,9 +737,9 @@ async function runVerb({ client, me, broker, where, bound, harnessPid }, verb, v
|
|
|
662
737
|
return 0;
|
|
663
738
|
}
|
|
664
739
|
case "peek":
|
|
665
|
-
return (await import("./peek-
|
|
740
|
+
return (await import("./peek-X4SEGEUB.js")).peekCommand(localClient(client, broker, verb), values, positionals);
|
|
666
741
|
case "set-peek":
|
|
667
|
-
return (await import("./peek-
|
|
742
|
+
return (await import("./peek-X4SEGEUB.js")).setPeekCommand(localClient(client, broker, verb), values, positionals);
|
|
668
743
|
case "why": {
|
|
669
744
|
const [from, to] = positionals;
|
|
670
745
|
if (!from || !to || positionals.length > 2) throw new RelayUsage(`${CLI_NAME} why takes <from> <to>`);
|
|
@@ -697,6 +772,8 @@ async function runVerb({ client, me, broker, where, bound, harnessPid }, verb, v
|
|
|
697
772
|
const lines = reachLines(result2.deliveries);
|
|
698
773
|
out(`sent ${result2.id} to ${result2.deliveries.map((d) => lines.length ? d.address : deliveryText(d)).join(", ")}${redactedText(result2.redacted)}`);
|
|
699
774
|
for (const line of lines) out(` ${line}`);
|
|
775
|
+
if (result2.deliveries.some((d) => d.state === "running" || d.state === "starting"))
|
|
776
|
+
out(` ${CLI_NAME} status ${shortId(result2.id)} shows when it is read`);
|
|
700
777
|
}
|
|
701
778
|
return 0;
|
|
702
779
|
}
|
|
@@ -735,9 +812,10 @@ async function runVerb({ client, me, broker, where, bound, harnessPid }, verb, v
|
|
|
735
812
|
}
|
|
736
813
|
case "inbox": {
|
|
737
814
|
if (values.ack && values.keep) throw new RelayUsage("--ack and --keep: pick one");
|
|
738
|
-
const
|
|
815
|
+
const waited = waitArg(values.wait, 0);
|
|
816
|
+
const { messages } = await client.request("inbox", { wait_s: waited });
|
|
739
817
|
if (asJson) json({ preamble: PREAMBLE, messages });
|
|
740
|
-
else if (!messages.length) note(
|
|
818
|
+
else if (!messages.length) note(`no unread messages${waited > LIMITS.waitMaxS ? `; waited ${LIMITS.waitMaxS} s (cap)` : ""}`);
|
|
741
819
|
else {
|
|
742
820
|
out(PREAMBLE);
|
|
743
821
|
out();
|
|
@@ -757,9 +835,9 @@ async function runVerb({ client, me, broker, where, bound, harnessPid }, verb, v
|
|
|
757
835
|
result.acked += (await client.request("ack", { seqs: seqs.slice(i, i + LIMITS.inboxPage) })).acked;
|
|
758
836
|
};
|
|
759
837
|
if (values.all) {
|
|
760
|
-
for (let
|
|
761
|
-
before = result.acked;
|
|
838
|
+
for (let page = 0; page < ACK_ALL_PAGES; page++) {
|
|
762
839
|
const { messages } = await client.request("inbox", { wait_s: 0 });
|
|
840
|
+
if (!messages.length) break;
|
|
763
841
|
await ack(messages.flatMap((m) => m.seq === void 0 ? [] : [m.seq]));
|
|
764
842
|
}
|
|
765
843
|
} else {
|
|
@@ -778,6 +856,20 @@ async function runVerb({ client, me, broker, where, bound, harnessPid }, verb, v
|
|
|
778
856
|
return 0;
|
|
779
857
|
}
|
|
780
858
|
case "status": {
|
|
859
|
+
if (positionals.length) {
|
|
860
|
+
if (positionals.length > 1 || values.all || values.activity)
|
|
861
|
+
throw new RelayUsage(`${CLI_NAME} status takes one message id, or --all and --activity for the fleet`);
|
|
862
|
+
if (!broker) throw new RelayUsage(`${CLI_NAME} status <id> is the local broker's; it has no --cloud form`);
|
|
863
|
+
if (!me) throw new RelayUsage(`${CLI_NAME} status <id> reads a message you sent: pass --as HANDLE, or run it from the agent's shell or your terminal`);
|
|
864
|
+
const receipts = await client.request("receipts", { id: positionals[0] });
|
|
865
|
+
if (asJson) json(receipts);
|
|
866
|
+
else {
|
|
867
|
+
out(`${receipts.id}:`);
|
|
868
|
+
const lines = receiptLines(receipts);
|
|
869
|
+
for (const line of lines.length ? lines : ["no deliveries of it are kept any more"]) out(` ${line}`);
|
|
870
|
+
}
|
|
871
|
+
return 0;
|
|
872
|
+
}
|
|
781
873
|
const snapshot = await client.request("snapshot", { all: values.all === true });
|
|
782
874
|
if (asJson) {
|
|
783
875
|
json(snapshot);
|
|
@@ -1200,11 +1292,12 @@ async function daemon(idle, policyFile) {
|
|
|
1200
1292
|
});
|
|
1201
1293
|
let broker;
|
|
1202
1294
|
try {
|
|
1203
|
-
const { daemonBridge } = await import("./remote-
|
|
1295
|
+
const { daemonBridge } = await import("./remote-GC4XN44U.js");
|
|
1204
1296
|
const bridge = await daemonBridge();
|
|
1205
1297
|
broker = await startBroker({
|
|
1206
1298
|
dir: relayDir(),
|
|
1207
1299
|
...bridge ? { bridge } : {},
|
|
1300
|
+
bridgeConfig: () => daemonBridge(),
|
|
1208
1301
|
...idleMs !== void 0 ? { idleMs } : {},
|
|
1209
1302
|
...policyFile ? { policyPath: resolve(policyFile) } : {}
|
|
1210
1303
|
});
|
|
@@ -1,16 +1,24 @@
|
|
|
1
|
+
import {
|
|
2
|
+
spawnDetached
|
|
3
|
+
} from "./chunk-ABP5AKFH.js";
|
|
4
|
+
import "./chunk-KN7WEIE4.js";
|
|
5
|
+
import "./chunk-IH2RJRIW.js";
|
|
1
6
|
import {
|
|
2
7
|
mcpInstall
|
|
3
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-QQZF5TQD.js";
|
|
4
9
|
import {
|
|
10
|
+
CHANNELS_ENV,
|
|
5
11
|
RelayUsage,
|
|
6
12
|
startDaemon
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import "./chunk-
|
|
13
|
+
} from "./chunk-URSBFDR6.js";
|
|
14
|
+
import "./chunk-ABR5UABL.js";
|
|
9
15
|
import "./chunk-YYSLYVNZ.js";
|
|
10
16
|
import {
|
|
11
17
|
harnessPid,
|
|
18
|
+
psParent,
|
|
12
19
|
relayIdentity
|
|
13
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-3PGDKPRN.js";
|
|
21
|
+
import "./chunk-M2DCR2J4.js";
|
|
14
22
|
|
|
15
23
|
// src/mcp.ts
|
|
16
24
|
import { CLI_NAME, validHandle } from "@scp-dev/core";
|
|
@@ -41,11 +49,33 @@ async function relayMcpCommand(values, positionals) {
|
|
|
41
49
|
output: (line) => void process.stdout.write(line),
|
|
42
50
|
env: process.env,
|
|
43
51
|
channels: values.channels === true,
|
|
52
|
+
launchedWithChannels: values.channels === true && launchedWithChannels(process.env),
|
|
53
|
+
spawn: (request) => spawnDetached(spawnWords(request), request.cwd ?? claim.cwd),
|
|
44
54
|
log: (line) => void process.stderr.write(`${line}
|
|
45
55
|
`)
|
|
46
56
|
});
|
|
47
57
|
return 0;
|
|
48
58
|
}
|
|
59
|
+
function spawnWords(request) {
|
|
60
|
+
return [
|
|
61
|
+
"--bg",
|
|
62
|
+
"--as",
|
|
63
|
+
request.as,
|
|
64
|
+
...request.harness !== void 0 ? ["--harness", request.harness] : [],
|
|
65
|
+
...request.name !== void 0 ? ["--name", request.name] : [],
|
|
66
|
+
...request.title !== void 0 ? ["--title", request.title] : [],
|
|
67
|
+
...request.no_push ? ["--no-push"] : [],
|
|
68
|
+
...request.handback_bytes !== void 0 ? ["--handback-bytes", String(request.handback_bytes)] : [],
|
|
69
|
+
"--",
|
|
70
|
+
...request.command
|
|
71
|
+
];
|
|
72
|
+
}
|
|
73
|
+
function launchedWithChannels(env, harness = harnessPid, parentOf = psParent) {
|
|
74
|
+
const launcher = Number(env[CHANNELS_ENV]);
|
|
75
|
+
return Number.isInteger(launcher) && launcher > 1 && parentOf(harness())?.ppid === launcher;
|
|
76
|
+
}
|
|
49
77
|
export {
|
|
50
|
-
|
|
78
|
+
launchedWithChannels,
|
|
79
|
+
relayMcpCommand,
|
|
80
|
+
spawnWords
|
|
51
81
|
};
|
|
@@ -2,10 +2,11 @@ import {
|
|
|
2
2
|
RelayUsage,
|
|
3
3
|
peekGrant,
|
|
4
4
|
stamp
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-URSBFDR6.js";
|
|
6
|
+
import "./chunk-3PGDKPRN.js";
|
|
6
7
|
import {
|
|
7
8
|
note
|
|
8
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-M2DCR2J4.js";
|
|
9
10
|
|
|
10
11
|
// src/peek.ts
|
|
11
12
|
import { PREAMBLE, wrapPeek, CLI_NAME } from "@scp-dev/core";
|
|
@@ -11,9 +11,10 @@ import {
|
|
|
11
11
|
removeCredential,
|
|
12
12
|
saveCredential,
|
|
13
13
|
writePrivateJson
|
|
14
|
-
} from "./chunk-
|
|
15
|
-
import "./chunk-
|
|
16
|
-
import "./chunk-
|
|
14
|
+
} from "./chunk-BUC5G5PY.js";
|
|
15
|
+
import "./chunk-URSBFDR6.js";
|
|
16
|
+
import "./chunk-3PGDKPRN.js";
|
|
17
|
+
import "./chunk-M2DCR2J4.js";
|
|
17
18
|
export {
|
|
18
19
|
DEFAULT_RELAY,
|
|
19
20
|
activeRelay,
|
|
@@ -9,10 +9,11 @@ import {
|
|
|
9
9
|
machinesVerb,
|
|
10
10
|
openCloud,
|
|
11
11
|
readCloudFile
|
|
12
|
-
} from "./chunk-
|
|
13
|
-
import "./chunk-
|
|
14
|
-
import "./chunk-
|
|
15
|
-
import "./chunk-
|
|
12
|
+
} from "./chunk-5UWLTO2Y.js";
|
|
13
|
+
import "./chunk-BUC5G5PY.js";
|
|
14
|
+
import "./chunk-URSBFDR6.js";
|
|
15
|
+
import "./chunk-3PGDKPRN.js";
|
|
16
|
+
import "./chunk-M2DCR2J4.js";
|
|
16
17
|
export {
|
|
17
18
|
CloudRelayClient,
|
|
18
19
|
CloudUsage,
|