@scp-dev/cli 0.1.2 → 0.2.0
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-4QYUPPGV.js → chunk-3RRPUYTE.js} +3 -3
- package/dist/{chunk-7KP6TAJW.js → chunk-3V3DRXB2.js} +9 -5
- package/dist/{chunk-4DNQFATX.js → chunk-5DYFYLAQ.js} +4 -4
- package/dist/{chunk-DA3EB2YF.js → chunk-E53YHYEP.js} +6 -60
- package/dist/{chunk-V5I7KEU7.js → chunk-GH7AXFUL.js} +8 -6
- package/dist/chunk-M2DCR2J4.js +63 -0
- package/dist/{chunk-XWLF7ON2.js → chunk-RXKBND3T.js} +1 -1
- package/dist/{chunk-6UFMKYPH.js → chunk-U2RSSTNW.js} +4 -4
- package/dist/{chunk-N3ZROLFA.js → chunk-WV5FINTW.js} +6 -5
- package/dist/claude-YJLGFQ2P.js +88 -0
- package/dist/cli.js +1 -1
- package/dist/daemon-SUTLTY5U.js +52 -0
- package/dist/{hooks-O3UZXDYG.js → hooks-EI7M3YKY.js} +3 -2
- package/dist/install-MYHVFKT4.js +15 -0
- package/dist/{login-JTRUWG6Q.js → login-V2WT7QX5.js} +5 -4
- package/dist/{main-5CAHHN55.js → main-HPBTO3JK.js} +94 -24
- package/dist/{mcp-P2AZYP5G.js → mcp-DGAQNFKO.js} +15 -6
- package/dist/{peek-YCOWBEPD.js → peek-WLG3ZROU.js} +3 -2
- package/dist/pi-HMESQA64.js +72 -0
- package/dist/{relay-VVJPYVXE.js → relay-5Z7IEXKD.js} +4 -3
- package/dist/{remote-3BWFISXJ.js → remote-FYN5ZXE4.js} +5 -4
- package/dist/{setup-RDPVGE4H.js → setup-LXG346FJ.js} +8 -5
- package/dist/{spawn-TQ3HOZTQ.js → spawn-DLPMAS5M.js} +7 -6
- package/dist/{up-KXOYO7QV.js → up-GPM4LWY3.js} +8 -7
- package/package.json +3 -3
- package/dist/install-HFBSKSTG.js +0 -14
package/README.md
CHANGED
|
@@ -3,21 +3,25 @@
|
|
|
3
3
|
The `swarm` command line tool, the reference binding of SCP for shells, hooks and MCP.
|
|
4
4
|
|
|
5
5
|
```sh
|
|
6
|
-
npm
|
|
6
|
+
npm i -g @scp-dev/cli
|
|
7
7
|
```
|
|
8
8
|
|
|
9
9
|
## Usage
|
|
10
10
|
|
|
11
11
|
```sh
|
|
12
|
-
swarm login
|
|
13
|
-
swarm
|
|
14
|
-
|
|
12
|
+
swarm up # browser login, links this machine to the org hub, installs hooks and MCP
|
|
13
|
+
swarm claude --name lead # start a named orchestrator that wakes on peer messages
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
From the orchestrator's shell:
|
|
17
|
+
|
|
18
|
+
```sh
|
|
19
|
+
swarm spawn --name parser -- claude -p "Fix the parser tests"
|
|
15
20
|
swarm send parser "Also cover the empty-input case."
|
|
16
21
|
swarm list --tree
|
|
17
|
-
swarm inbox --wait 30
|
|
18
22
|
```
|
|
19
23
|
|
|
20
|
-
Headless (CI, cron, cloud runners): `swarm
|
|
24
|
+
Headless (CI, cron, cloud runners): `swarm up --token scp_t_... [--machine NAME]`. The default relay is https://app.scp.dev; `swarm relay use <url>` picks another. Runs on Node 22.13 or later.
|
|
21
25
|
|
|
22
26
|
## Provides
|
|
23
27
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
RelayUsage
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-3V3DRXB2.js";
|
|
4
4
|
import {
|
|
5
5
|
note
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-M2DCR2J4.js";
|
|
7
7
|
|
|
8
8
|
// src/relay.ts
|
|
9
9
|
import { chmodSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "fs";
|
|
@@ -119,7 +119,7 @@ function relayVerb(positionals, asJson, env = process.env) {
|
|
|
119
119
|
}
|
|
120
120
|
async function loginMain(positionals, values) {
|
|
121
121
|
if (positionals.length) throw new RelayUsage(`${CLI_NAME} login takes only flags`);
|
|
122
|
-
return (await import("./login-
|
|
122
|
+
return (await import("./login-V2WT7QX5.js")).login(values);
|
|
123
123
|
}
|
|
124
124
|
function logoutMain(positionals, asJson, env = process.env) {
|
|
125
125
|
if (positionals.length) throw new RelayUsage(`${CLI_NAME} logout takes no arguments`);
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
|
-
SELF,
|
|
3
2
|
harnessLineage,
|
|
4
3
|
hiddenHarness,
|
|
5
4
|
labelsFor,
|
|
6
5
|
lineage,
|
|
7
|
-
parseSeconds,
|
|
8
6
|
readPsTable
|
|
9
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-E53YHYEP.js";
|
|
8
|
+
import {
|
|
9
|
+
SELF,
|
|
10
|
+
parseSeconds
|
|
11
|
+
} from "./chunk-M2DCR2J4.js";
|
|
10
12
|
|
|
11
13
|
// src/common.ts
|
|
12
14
|
import { spawn } from "child_process";
|
|
@@ -184,7 +186,7 @@ async function open(verb, values, cwd, bodyFromStdin, walk) {
|
|
|
184
186
|
`${CLI_NAME} ${verb} needs an identity: --as HANDLE (or $SCP_NAME) for an agent, or --human for your own inbox me/ (no terminal is attached, so me/ is not assumed)`
|
|
185
187
|
);
|
|
186
188
|
}
|
|
187
|
-
const { machineName, openCloud } = await import("./remote-
|
|
189
|
+
const { machineName, openCloud } = await import("./remote-FYN5ZXE4.js");
|
|
188
190
|
const handle2 = named ? localHandle(named) : void 0;
|
|
189
191
|
const claim = handle2 ? {
|
|
190
192
|
handle: handle2,
|
|
@@ -317,6 +319,7 @@ function stamp(iso) {
|
|
|
317
319
|
const at = new Date(iso);
|
|
318
320
|
return Number.isNaN(at.getTime()) ? iso : `${at.getFullYear()}-${pad(at.getMonth() + 1)}-${pad(at.getDate())} ${time(iso)}`;
|
|
319
321
|
}
|
|
322
|
+
var CHANNELS_ENV = "SCP_CHANNELS";
|
|
320
323
|
|
|
321
324
|
export {
|
|
322
325
|
RelayUsage,
|
|
@@ -332,5 +335,6 @@ export {
|
|
|
332
335
|
peekGrant,
|
|
333
336
|
grantParams,
|
|
334
337
|
time,
|
|
335
|
-
stamp
|
|
338
|
+
stamp,
|
|
339
|
+
CHANNELS_ENV
|
|
336
340
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
RelayUsage
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-3V3DRXB2.js";
|
|
4
4
|
import {
|
|
5
5
|
AGY_HOOK_SET,
|
|
6
6
|
AGY_UNVERIFIED,
|
|
@@ -13,10 +13,10 @@ import {
|
|
|
13
13
|
mergeHooks,
|
|
14
14
|
musePlugin,
|
|
15
15
|
opencodePlugin
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-RXKBND3T.js";
|
|
17
17
|
import {
|
|
18
18
|
gitToplevel
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-E53YHYEP.js";
|
|
20
20
|
|
|
21
21
|
// src/install.ts
|
|
22
22
|
import { chmodSync, copyFileSync, existsSync, lstatSync, mkdirSync, readFileSync, realpathSync, renameSync, statSync, unlinkSync, writeFileSync } from "fs";
|
|
@@ -185,7 +185,7 @@ function mcpInstall(harness, as, out) {
|
|
|
185
185
|
const line = (cli, extra = []) => out([...cli, CLI_NAME, ...args(extra)].map(shellWord).join(" "));
|
|
186
186
|
switch (harness) {
|
|
187
187
|
case "claude":
|
|
188
|
-
line(["claude", "mcp", "add", "scp", "--"]);
|
|
188
|
+
line(["claude", "mcp", "add", "scp", "--"], ["--harness", "claude", "--channels"]);
|
|
189
189
|
return 0;
|
|
190
190
|
case "codex":
|
|
191
191
|
line(["codex", "mcp", "add", "scp", "--"], ["--harness", "codex"]);
|
|
@@ -1,56 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
var FAILED = 125;
|
|
5
|
-
var SELF = [process.execPath, ...process.versions.bun ? ["--no-env-file", "--config=/dev/null"] : [], process.argv[1]];
|
|
6
|
-
function capture(argv, env) {
|
|
7
|
-
const result = spawnSync(argv[0], argv.slice(1), { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], ...env ? { env } : {} });
|
|
8
|
-
return result.status === 0 ? result.stdout : void 0;
|
|
9
|
-
}
|
|
10
|
-
function note(message) {
|
|
11
|
-
process.stderr.write(`${message.startsWith(`${CLI_NAME} `) ? "" : `${CLI_NAME}: `}${message}
|
|
12
|
-
`);
|
|
13
|
-
}
|
|
14
|
-
async function exitFlushed(code, waitMs = 1e4) {
|
|
15
|
-
const ended = (stream) => new Promise((resolve2) => {
|
|
16
|
-
try {
|
|
17
|
-
stream.end(() => resolve2());
|
|
18
|
-
} catch {
|
|
19
|
-
resolve2();
|
|
20
|
-
}
|
|
21
|
-
});
|
|
22
|
-
let timer;
|
|
23
|
-
await Promise.race([Promise.all([ended(process.stdout), ended(process.stderr)]), new Promise((resolve2) => timer = setTimeout(resolve2, waitMs))]);
|
|
24
|
-
clearTimeout(timer);
|
|
25
|
-
process.exit(code);
|
|
26
|
-
}
|
|
27
|
-
function printTable(rows) {
|
|
28
|
-
const widths = rows[0].map((_, column) => Math.max(...rows.map((row) => row[column].length)));
|
|
29
|
-
for (const row of rows)
|
|
30
|
-
console.log(
|
|
31
|
-
row.map((cell, column) => cell.padEnd(widths[column])).join(" ").trimEnd()
|
|
32
|
-
);
|
|
33
|
-
}
|
|
34
|
-
var DURATION_PART = /(\d+(?:\.\d+)?)(ms|s|m|h|d)/g;
|
|
35
|
-
var DURATION_UNITS = { ms: 1e-3, s: 1, m: 60, h: 3600, d: 86400 };
|
|
36
|
-
function parseSeconds(text, flag) {
|
|
37
|
-
const trimmed = text.trim();
|
|
38
|
-
let seconds;
|
|
39
|
-
if (/^\d+(?:\.\d+)?$/.test(trimmed)) seconds = Number(trimmed);
|
|
40
|
-
else {
|
|
41
|
-
seconds = 0;
|
|
42
|
-
let consumed = "";
|
|
43
|
-
for (const match of trimmed.matchAll(DURATION_PART)) {
|
|
44
|
-
seconds += Number(match[1]) * DURATION_UNITS[match[2]];
|
|
45
|
-
consumed += match[0];
|
|
46
|
-
}
|
|
47
|
-
if (consumed !== trimmed || consumed === "") {
|
|
48
|
-
throw new Error(`${flag} ${JSON.stringify(text)} is not a duration like 90s, 30m or 1h30m`);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
if (!(seconds > 0)) throw new Error(`${flag} must be more than zero`);
|
|
52
|
-
return Math.max(1, Math.ceil(seconds));
|
|
53
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
capture
|
|
3
|
+
} from "./chunk-M2DCR2J4.js";
|
|
54
4
|
|
|
55
5
|
// src/identity.ts
|
|
56
6
|
import { existsSync, realpathSync } from "fs";
|
|
@@ -182,7 +132,8 @@ var HARNESSES = /* @__PURE__ */ new Set([
|
|
|
182
132
|
"agy",
|
|
183
133
|
"antigravity",
|
|
184
134
|
"gemini",
|
|
185
|
-
"gemini-cli"
|
|
135
|
+
"gemini-cli",
|
|
136
|
+
"pi-coding-agent"
|
|
186
137
|
]);
|
|
187
138
|
var INSTALLED = /(^|\/)(node_modules|site-packages|dist-packages|\.npm|\.bun|\.cache|\.local|\.cargo|\.volta|\.nvm|\.pyenv|\.rbenv|Cellar|Applications)(\/|$)|^\/(opt|usr|Library|nix)\//;
|
|
188
139
|
function command(args) {
|
|
@@ -337,12 +288,6 @@ function relayIdentity(input) {
|
|
|
337
288
|
}
|
|
338
289
|
|
|
339
290
|
export {
|
|
340
|
-
FAILED,
|
|
341
|
-
SELF,
|
|
342
|
-
note,
|
|
343
|
-
exitFlushed,
|
|
344
|
-
printTable,
|
|
345
|
-
parseSeconds,
|
|
346
291
|
shortHostname,
|
|
347
292
|
detectHarness,
|
|
348
293
|
hookHarness,
|
|
@@ -353,6 +298,7 @@ export {
|
|
|
353
298
|
hiddenHarness,
|
|
354
299
|
lineage,
|
|
355
300
|
spawnerKey,
|
|
301
|
+
psParent,
|
|
356
302
|
harnessPid,
|
|
357
303
|
hookHarnessPid,
|
|
358
304
|
relayIdentity
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
agySettingsFile,
|
|
4
4
|
mcpFile,
|
|
5
5
|
mountedEntry
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-WV5FINTW.js";
|
|
7
7
|
import {
|
|
8
8
|
OPTIONS,
|
|
9
9
|
RelayUsage,
|
|
@@ -13,16 +13,18 @@ import {
|
|
|
13
13
|
open,
|
|
14
14
|
selectorList,
|
|
15
15
|
walkNow
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-3V3DRXB2.js";
|
|
17
17
|
import {
|
|
18
18
|
steerPrompt
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-RXKBND3T.js";
|
|
20
20
|
import {
|
|
21
|
-
SELF,
|
|
22
21
|
detectHarness,
|
|
23
|
-
note,
|
|
24
22
|
spawnerKey
|
|
25
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-E53YHYEP.js";
|
|
24
|
+
import {
|
|
25
|
+
SELF,
|
|
26
|
+
note
|
|
27
|
+
} from "./chunk-M2DCR2J4.js";
|
|
26
28
|
|
|
27
29
|
// src/spawn.ts
|
|
28
30
|
import { spawn, spawnSync } from "child_process";
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// src/term.ts
|
|
2
|
+
import { spawnSync } from "child_process";
|
|
3
|
+
import { CLI_NAME } from "@scp-dev/core";
|
|
4
|
+
var FAILED = 125;
|
|
5
|
+
var SELF = [process.execPath, ...process.versions.bun ? ["--no-env-file", "--config=/dev/null"] : [], process.argv[1]];
|
|
6
|
+
function capture(argv, env) {
|
|
7
|
+
const result = spawnSync(argv[0], argv.slice(1), { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], ...env ? { env } : {} });
|
|
8
|
+
return result.status === 0 ? result.stdout : void 0;
|
|
9
|
+
}
|
|
10
|
+
function note(message) {
|
|
11
|
+
process.stderr.write(`${message.startsWith(`${CLI_NAME} `) ? "" : `${CLI_NAME}: `}${message}
|
|
12
|
+
`);
|
|
13
|
+
}
|
|
14
|
+
async function exitFlushed(code, waitMs = 1e4) {
|
|
15
|
+
const ended = (stream) => new Promise((resolve) => {
|
|
16
|
+
try {
|
|
17
|
+
stream.end(() => resolve());
|
|
18
|
+
} catch {
|
|
19
|
+
resolve();
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
let timer;
|
|
23
|
+
await Promise.race([Promise.all([ended(process.stdout), ended(process.stderr)]), new Promise((resolve) => timer = setTimeout(resolve, waitMs))]);
|
|
24
|
+
clearTimeout(timer);
|
|
25
|
+
process.exit(code);
|
|
26
|
+
}
|
|
27
|
+
function printTable(rows) {
|
|
28
|
+
const widths = rows[0].map((_, column) => Math.max(...rows.map((row) => row[column].length)));
|
|
29
|
+
for (const row of rows)
|
|
30
|
+
console.log(
|
|
31
|
+
row.map((cell, column) => cell.padEnd(widths[column])).join(" ").trimEnd()
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
var DURATION_PART = /(\d+(?:\.\d+)?)(ms|s|m|h|d)/g;
|
|
35
|
+
var DURATION_UNITS = { ms: 1e-3, s: 1, m: 60, h: 3600, d: 86400 };
|
|
36
|
+
function parseSeconds(text, flag) {
|
|
37
|
+
const trimmed = text.trim();
|
|
38
|
+
let seconds;
|
|
39
|
+
if (/^\d+(?:\.\d+)?$/.test(trimmed)) seconds = Number(trimmed);
|
|
40
|
+
else {
|
|
41
|
+
seconds = 0;
|
|
42
|
+
let consumed = "";
|
|
43
|
+
for (const match of trimmed.matchAll(DURATION_PART)) {
|
|
44
|
+
seconds += Number(match[1]) * DURATION_UNITS[match[2]];
|
|
45
|
+
consumed += match[0];
|
|
46
|
+
}
|
|
47
|
+
if (consumed !== trimmed || consumed === "") {
|
|
48
|
+
throw new Error(`${flag} ${JSON.stringify(text)} is not a duration like 90s, 30m or 1h30m`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (!(seconds > 0)) throw new Error(`${flag} must be more than zero`);
|
|
52
|
+
return Math.max(1, Math.ceil(seconds));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export {
|
|
56
|
+
FAILED,
|
|
57
|
+
SELF,
|
|
58
|
+
capture,
|
|
59
|
+
note,
|
|
60
|
+
exitFlushed,
|
|
61
|
+
printTable,
|
|
62
|
+
parseSeconds
|
|
63
|
+
};
|
|
@@ -4,14 +4,14 @@ import {
|
|
|
4
4
|
configDir,
|
|
5
5
|
relayCredential,
|
|
6
6
|
writePrivateJson
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-3RRPUYTE.js";
|
|
8
8
|
import {
|
|
9
9
|
RelayUsage
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-3V3DRXB2.js";
|
|
11
11
|
import {
|
|
12
12
|
note,
|
|
13
13
|
printTable
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-M2DCR2J4.js";
|
|
15
15
|
|
|
16
16
|
// src/remote.ts
|
|
17
17
|
import { existsSync, readFileSync, rmSync } from "fs";
|
|
@@ -202,7 +202,7 @@ async function cloudMain(positionals, values, brokerStatus) {
|
|
|
202
202
|
writePrivateJson(path, file);
|
|
203
203
|
if (values.json) json({ file: path, ...file, token: problem ? "missing" : "found" });
|
|
204
204
|
else {
|
|
205
|
-
out(`the relay broker links to ${url} as machine ${machine}
|
|
205
|
+
out(`the relay broker links to ${url} as machine ${machine} (${path})`);
|
|
206
206
|
if (problem) note(problem);
|
|
207
207
|
}
|
|
208
208
|
return 0;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
hooksTarget
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-5DYFYLAQ.js";
|
|
4
4
|
import {
|
|
5
5
|
RelayUsage
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-3V3DRXB2.js";
|
|
7
7
|
import {
|
|
8
8
|
AGY_HOOK_SET,
|
|
9
9
|
BLOCK_STOP,
|
|
@@ -15,10 +15,10 @@ import {
|
|
|
15
15
|
mergeHooks,
|
|
16
16
|
musePlugin,
|
|
17
17
|
opencodePlugin
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-RXKBND3T.js";
|
|
19
19
|
import {
|
|
20
20
|
gitToplevel
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-E53YHYEP.js";
|
|
22
22
|
|
|
23
23
|
// src/setup.ts
|
|
24
24
|
import { spawnSync } from "child_process";
|
|
@@ -179,7 +179,7 @@ function entryRight(harness, entry, argv) {
|
|
|
179
179
|
}
|
|
180
180
|
var withoutRemote = (entry) => Object.fromEntries(Object.entries(entry).filter(([key]) => !REMOTE_KEYS.includes(key)));
|
|
181
181
|
function mountArgv(harness, bin) {
|
|
182
|
-
return [bin, "mcp", "--harness", harness];
|
|
182
|
+
return [bin, "mcp", "--harness", harness, ...harness === "claude" ? ["--channels"] : []];
|
|
183
183
|
}
|
|
184
184
|
function agyRules() {
|
|
185
185
|
return TOOLS.map((tool) => `mcp(${SERVER}/${tool.name})`);
|
|
@@ -1172,6 +1172,7 @@ export {
|
|
|
1172
1172
|
agySettingsFile,
|
|
1173
1173
|
manifestFile,
|
|
1174
1174
|
mountedEntry,
|
|
1175
|
+
entryArgv,
|
|
1175
1176
|
mountArgv,
|
|
1176
1177
|
agyRules,
|
|
1177
1178
|
verifyMount,
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import {
|
|
2
|
+
entryArgv,
|
|
3
|
+
mcpFile,
|
|
4
|
+
mountedEntry,
|
|
5
|
+
whichOnPath
|
|
6
|
+
} from "./chunk-WV5FINTW.js";
|
|
7
|
+
import "./chunk-5DYFYLAQ.js";
|
|
8
|
+
import {
|
|
9
|
+
CHANNELS_ENV,
|
|
10
|
+
RelayUsage
|
|
11
|
+
} from "./chunk-3V3DRXB2.js";
|
|
12
|
+
import "./chunk-RXKBND3T.js";
|
|
13
|
+
import "./chunk-YYSLYVNZ.js";
|
|
14
|
+
import "./chunk-E53YHYEP.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-HPBTO3JK.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-RXKBND3T.js";
|
|
34
34
|
import {
|
|
35
35
|
SUBAGENT
|
|
36
36
|
} from "./chunk-YYSLYVNZ.js";
|
|
37
|
-
import "./chunk-
|
|
37
|
+
import "./chunk-E53YHYEP.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-5DYFYLAQ.js";
|
|
6
|
+
import "./chunk-3V3DRXB2.js";
|
|
7
|
+
import "./chunk-RXKBND3T.js";
|
|
8
|
+
import "./chunk-YYSLYVNZ.js";
|
|
9
|
+
import "./chunk-E53YHYEP.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-U2RSSTNW.js";
|
|
4
4
|
import {
|
|
5
5
|
activeRelay,
|
|
6
6
|
saveCredential
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-3RRPUYTE.js";
|
|
8
8
|
import {
|
|
9
9
|
RelayUsage
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-3V3DRXB2.js";
|
|
11
|
+
import "./chunk-E53YHYEP.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";
|
|
@@ -14,15 +14,17 @@ import {
|
|
|
14
14
|
stamp,
|
|
15
15
|
startDaemon,
|
|
16
16
|
time
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-3V3DRXB2.js";
|
|
18
|
+
import {
|
|
19
|
+
shortHostname
|
|
20
|
+
} from "./chunk-E53YHYEP.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.
|
|
38
|
+
version: "0.2.0",
|
|
37
39
|
description: "The swarm command line tool.",
|
|
38
40
|
license: "Apache-2.0",
|
|
39
41
|
homepage: "https://scp.dev",
|
|
@@ -223,6 +225,8 @@ scopes (selectors are comma-separated, e.g. tree:parent,tree:children,group:team
|
|
|
223
225
|
messages with the relay MCP tools (relay_send, relay_inbox, relay_reply). A
|
|
224
226
|
${CLI_NAME} command from codex's workspace-write sandbox also needs
|
|
225
227
|
-c sandbox_workspace_write.network_access=true (the relay socket counts as network)
|
|
228
|
+
${CLI_NAME} pi [--name N] [--] [pi args...] runs pi with the @scp-dev/pi extension: the relay tools, and each new
|
|
229
|
+
message as a turn (steering a running one, waking an idle session)
|
|
226
230
|
${CLI_NAME} peers [--all] [--roots] who you may message: title, status and the rule that admits each; offline ones and
|
|
227
231
|
sessions nobody spawned that spawned nobody only with --all (--roots: those sessions)
|
|
228
232
|
${CLI_NAME} why <from> <to> whether from may message to, and why
|
|
@@ -230,6 +234,7 @@ scopes (selectors are comma-separated, e.g. tree:parent,tree:children,group:team
|
|
|
230
234
|
other process under an agent they may only narrow. An ancestor always reaches its descendants, and a recipient
|
|
231
235
|
may always reply in the thread to a message it got; a reply to another message of the thread is checked as a send.
|
|
232
236
|
${CLI_NAME} daemon [--idle DURATION] [--policy FILE] run the broker in the foreground (it otherwise starts on demand)
|
|
237
|
+
${CLI_NAME} daemon stop|restart stop the running broker, or replace it with a fresh one
|
|
233
238
|
|
|
234
239
|
agent sessions:
|
|
235
240
|
${CLI_NAME} mcp [--as NAME] [--harness H] [--channels] the MCP shim a harness mounts: relay tools for one agent, never me/
|
|
@@ -254,7 +259,9 @@ agent sessions:
|
|
|
254
259
|
A Claude Code subagent's hooks give it a child endpoint, <session handle>-<type>-<first 6 of its id>, whose messages
|
|
255
260
|
reach it after its tools; its shell is the session's, so it acts as that child with --as.
|
|
256
261
|
Grok runs the Claude Code hooks, labelled grok; Muse takes them as a plugin; Codex runs new hooks after /hooks review.
|
|
257
|
-
--
|
|
262
|
+
${CLI_NAME} claude [--name N] [--] [claude args...] start Claude Code with the scp channel loaded, so peer messages wake
|
|
263
|
+
it while idle (claude --dangerously-load-development-channels server:scp; SCP_NAME=N)
|
|
264
|
+
--channels pushes messages into a Claude Code that ${CLI_NAME} claude started; setup mounts claude's shim with it.
|
|
258
265
|
|
|
259
266
|
relay:
|
|
260
267
|
${CLI_NAME} relay use <url> | show select a relay, or show its source and credential status
|
|
@@ -491,10 +498,12 @@ async function relayMain(argv, cwd = process.cwd()) {
|
|
|
491
498
|
out(package_default.version);
|
|
492
499
|
return 0;
|
|
493
500
|
}
|
|
494
|
-
if (verb === "hook") return (await import("./hooks-
|
|
495
|
-
if (verb === "setup") return (await import("./setup-
|
|
501
|
+
if (verb === "hook") return (await import("./hooks-EI7M3YKY.js")).relayHookCommand(rest, startDaemon);
|
|
502
|
+
if (verb === "setup") return (await import("./setup-LXG346FJ.js")).relaySetupCommand(rest, cwd, out);
|
|
503
|
+
if (verb === "claude") return (await import("./claude-YJLGFQ2P.js")).claudeCommand(rest);
|
|
504
|
+
if (verb === "pi") return (await import("./pi-HMESQA64.js")).piCommand(rest);
|
|
496
505
|
if (verb === "spawn") {
|
|
497
|
-
const { splitSpawn, spawnCommand } = await import("./spawn-
|
|
506
|
+
const { splitSpawn, spawnCommand } = await import("./spawn-DLPMAS5M.js");
|
|
498
507
|
const { flags } = splitSpawn(rest);
|
|
499
508
|
if (flags.includes("--help") || flags.includes("-h")) {
|
|
500
509
|
out(flags.includes("--all") ? RELAY_HELP : SPAWN_HELP);
|
|
@@ -516,13 +525,16 @@ async function relayMain(argv, cwd = process.cwd()) {
|
|
|
516
525
|
return 0;
|
|
517
526
|
}
|
|
518
527
|
for (const key of Object.keys(values)) if (!allowed.includes(key)) throw new RelayUsage(`${CLI_NAME} ${verb} does not take --${key}`);
|
|
519
|
-
if (verb === "daemon")
|
|
528
|
+
if (verb === "daemon") {
|
|
529
|
+
if (positionals.length) return daemonControl(positionals, values);
|
|
530
|
+
return daemon(values.idle, values.policy);
|
|
531
|
+
}
|
|
520
532
|
if (verb === "mcp")
|
|
521
|
-
return (await import("./mcp-
|
|
533
|
+
return (await import("./mcp-DGAQNFKO.js")).relayMcpCommand(values, positionals);
|
|
522
534
|
if (verb === "hooks") {
|
|
523
535
|
if (positionals[0] !== "install" || positionals.length > 1) throw new RelayUsage(`${CLI_NAME} hooks takes install --harness claude|codex|opencode|agy|muse`);
|
|
524
536
|
if (values.write && values.print) throw new RelayUsage("--print and --write: pick one");
|
|
525
|
-
return (await import("./install-
|
|
537
|
+
return (await import("./install-MYHVFKT4.js")).installHooks({
|
|
526
538
|
harness: values.harness,
|
|
527
539
|
scope: values.scope,
|
|
528
540
|
write: values.write === true,
|
|
@@ -533,18 +545,25 @@ async function relayMain(argv, cwd = process.cwd()) {
|
|
|
533
545
|
out
|
|
534
546
|
});
|
|
535
547
|
}
|
|
536
|
-
if (verb === "relay") return (await import("./relay-
|
|
537
|
-
if (verb === "up") return (await import("./up-
|
|
538
|
-
if (verb === "login")
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
548
|
+
if (verb === "relay") return (await import("./relay-5Z7IEXKD.js")).relayVerb(positionals, values.json === true);
|
|
549
|
+
if (verb === "up") return (await import("./up-GPM4LWY3.js")).up(positionals, values, cwd, relinkBroker);
|
|
550
|
+
if (verb === "login") {
|
|
551
|
+
const code = await (await import("./relay-5Z7IEXKD.js")).loginMain(positionals, values);
|
|
552
|
+
if (code === 0) await relinkRunning();
|
|
553
|
+
return code;
|
|
554
|
+
}
|
|
555
|
+
if (verb === "logout") return (await import("./relay-5Z7IEXKD.js")).logoutMain(positionals, values.json === true);
|
|
556
|
+
if (verb === "cloud") {
|
|
557
|
+
const code = await (await import("./remote-FYN5ZXE4.js")).cloudMain(positionals, values, cloudStatus);
|
|
558
|
+
if (code === 0 && positionals[0] === "enable") await relinkRunning();
|
|
559
|
+
return code;
|
|
560
|
+
}
|
|
542
561
|
if (verb === "holds") holdsArgs(values, positionals);
|
|
543
562
|
const bodyFromStdin = (verb === "send" || verb === "ask" || verb === "reply") && (positionals[1] === void 0 || positionals[1] === "-");
|
|
544
563
|
const opened = await open(verb, values, cwd, bodyFromStdin);
|
|
545
564
|
const { client } = opened;
|
|
546
565
|
try {
|
|
547
|
-
if (verb === "machines") return await (await import("./remote-
|
|
566
|
+
if (verb === "machines") return await (await import("./remote-FYN5ZXE4.js")).machinesVerb(client, positionals, values.json === true);
|
|
548
567
|
return await runVerb(opened, verb, values, positionals, cwd);
|
|
549
568
|
} finally {
|
|
550
569
|
client.close();
|
|
@@ -560,6 +579,55 @@ async function cloudStatus() {
|
|
|
560
579
|
client.close();
|
|
561
580
|
}
|
|
562
581
|
}
|
|
582
|
+
async function relinkBroker() {
|
|
583
|
+
const dir = relayDir();
|
|
584
|
+
const client = await connectBroker(dir, () => startDaemon(dir));
|
|
585
|
+
let result;
|
|
586
|
+
let pid;
|
|
587
|
+
try {
|
|
588
|
+
pid = (await client.hello({ observe: true })).broker.pid;
|
|
589
|
+
result = await client.request("bridge_relink");
|
|
590
|
+
} catch (error) {
|
|
591
|
+
if (error instanceof RelayError && error.code === "method_not_found") return cloudStatus();
|
|
592
|
+
throw error;
|
|
593
|
+
} finally {
|
|
594
|
+
client.close();
|
|
595
|
+
}
|
|
596
|
+
if (!result.restarting) return result;
|
|
597
|
+
await (await import("./daemon-SUTLTY5U.js")).exited(pid);
|
|
598
|
+
return cloudStatus();
|
|
599
|
+
}
|
|
600
|
+
async function relinkRunning() {
|
|
601
|
+
try {
|
|
602
|
+
await connectBroker(relayDir()).then((client) => client.close());
|
|
603
|
+
} catch {
|
|
604
|
+
return;
|
|
605
|
+
}
|
|
606
|
+
try {
|
|
607
|
+
await relinkBroker();
|
|
608
|
+
} catch (error) {
|
|
609
|
+
note(`the running broker did not link again (${error instanceof Error ? error.message : String(error)}); run \`${CLI_NAME} daemon restart\``);
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
async function daemonControl(positionals, values) {
|
|
613
|
+
const [action] = positionals;
|
|
614
|
+
if (positionals.length !== 1 || action !== "stop" && action !== "restart" || values.idle !== void 0 || values.policy !== void 0)
|
|
615
|
+
throw new RelayUsage(`${CLI_NAME} daemon takes stop or restart, or --idle and --policy to run in the foreground`);
|
|
616
|
+
const dir = relayDir();
|
|
617
|
+
const pid = await (await import("./daemon-SUTLTY5U.js")).stopBroker(dir);
|
|
618
|
+
if (action === "stop") {
|
|
619
|
+
out(pid === null ? "no relay broker runs" : `stopped the relay broker (pid ${pid}); the next command starts a fresh one`);
|
|
620
|
+
return 0;
|
|
621
|
+
}
|
|
622
|
+
const client = await connectBroker(dir, () => startDaemon(dir));
|
|
623
|
+
try {
|
|
624
|
+
const { broker } = await client.hello({ observe: true });
|
|
625
|
+
out(`${pid === null ? "started" : `replaced the relay broker (pid ${pid}) with`} a fresh one (pid ${broker.pid})`);
|
|
626
|
+
} finally {
|
|
627
|
+
client.close();
|
|
628
|
+
}
|
|
629
|
+
return 0;
|
|
630
|
+
}
|
|
563
631
|
async function runVerb({ client, me, broker, where, bound, harnessPid }, verb, values, positionals, cwd) {
|
|
564
632
|
const asJson = values.json === true;
|
|
565
633
|
const attachments = (values.attach ?? []).map((path) => ({ kind: "path", path: path.startsWith("/") ? path : `${cwd}/${path}` }));
|
|
@@ -672,9 +740,9 @@ async function runVerb({ client, me, broker, where, bound, harnessPid }, verb, v
|
|
|
672
740
|
return 0;
|
|
673
741
|
}
|
|
674
742
|
case "peek":
|
|
675
|
-
return (await import("./peek-
|
|
743
|
+
return (await import("./peek-WLG3ZROU.js")).peekCommand(localClient(client, broker, verb), values, positionals);
|
|
676
744
|
case "set-peek":
|
|
677
|
-
return (await import("./peek-
|
|
745
|
+
return (await import("./peek-WLG3ZROU.js")).setPeekCommand(localClient(client, broker, verb), values, positionals);
|
|
678
746
|
case "why": {
|
|
679
747
|
const [from, to] = positionals;
|
|
680
748
|
if (!from || !to || positionals.length > 2) throw new RelayUsage(`${CLI_NAME} why takes <from> <to>`);
|
|
@@ -747,9 +815,10 @@ async function runVerb({ client, me, broker, where, bound, harnessPid }, verb, v
|
|
|
747
815
|
}
|
|
748
816
|
case "inbox": {
|
|
749
817
|
if (values.ack && values.keep) throw new RelayUsage("--ack and --keep: pick one");
|
|
750
|
-
const
|
|
818
|
+
const waited = waitArg(values.wait, 0);
|
|
819
|
+
const { messages } = await client.request("inbox", { wait_s: waited });
|
|
751
820
|
if (asJson) json({ preamble: PREAMBLE, messages });
|
|
752
|
-
else if (!messages.length) note(
|
|
821
|
+
else if (!messages.length) note(`no unread messages${waited > LIMITS.waitMaxS ? `; waited ${LIMITS.waitMaxS} s (cap)` : ""}`);
|
|
753
822
|
else {
|
|
754
823
|
out(PREAMBLE);
|
|
755
824
|
out();
|
|
@@ -1226,11 +1295,12 @@ async function daemon(idle, policyFile) {
|
|
|
1226
1295
|
});
|
|
1227
1296
|
let broker;
|
|
1228
1297
|
try {
|
|
1229
|
-
const { daemonBridge } = await import("./remote-
|
|
1298
|
+
const { daemonBridge } = await import("./remote-FYN5ZXE4.js");
|
|
1230
1299
|
const bridge = await daemonBridge();
|
|
1231
1300
|
broker = await startBroker({
|
|
1232
1301
|
dir: relayDir(),
|
|
1233
1302
|
...bridge ? { bridge } : {},
|
|
1303
|
+
bridgeConfig: () => daemonBridge(),
|
|
1234
1304
|
...idleMs !== void 0 ? { idleMs } : {},
|
|
1235
1305
|
...policyFile ? { policyPath: resolve(policyFile) } : {}
|
|
1236
1306
|
});
|
|
@@ -1,21 +1,24 @@
|
|
|
1
1
|
import {
|
|
2
2
|
spawnDetached
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-GH7AXFUL.js";
|
|
4
4
|
import "./chunk-KN7WEIE4.js";
|
|
5
|
-
import "./chunk-
|
|
5
|
+
import "./chunk-WV5FINTW.js";
|
|
6
6
|
import {
|
|
7
7
|
mcpInstall
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-5DYFYLAQ.js";
|
|
9
9
|
import {
|
|
10
|
+
CHANNELS_ENV,
|
|
10
11
|
RelayUsage,
|
|
11
12
|
startDaemon
|
|
12
|
-
} from "./chunk-
|
|
13
|
-
import "./chunk-
|
|
13
|
+
} from "./chunk-3V3DRXB2.js";
|
|
14
|
+
import "./chunk-RXKBND3T.js";
|
|
14
15
|
import "./chunk-YYSLYVNZ.js";
|
|
15
16
|
import {
|
|
16
17
|
harnessPid,
|
|
18
|
+
psParent,
|
|
17
19
|
relayIdentity
|
|
18
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-E53YHYEP.js";
|
|
21
|
+
import "./chunk-M2DCR2J4.js";
|
|
19
22
|
|
|
20
23
|
// src/mcp.ts
|
|
21
24
|
import { CLI_NAME, validHandle } from "@scp-dev/core";
|
|
@@ -46,6 +49,7 @@ async function relayMcpCommand(values, positionals) {
|
|
|
46
49
|
output: (line) => void process.stdout.write(line),
|
|
47
50
|
env: process.env,
|
|
48
51
|
channels: values.channels === true,
|
|
52
|
+
launchedWithChannels: values.channels === true && launchedWithChannels(process.env),
|
|
49
53
|
spawn: (request) => spawnDetached(spawnWords(request), request.cwd ?? claim.cwd),
|
|
50
54
|
log: (line) => void process.stderr.write(`${line}
|
|
51
55
|
`)
|
|
@@ -66,7 +70,12 @@ function spawnWords(request) {
|
|
|
66
70
|
...request.command
|
|
67
71
|
];
|
|
68
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
|
+
}
|
|
69
77
|
export {
|
|
78
|
+
launchedWithChannels,
|
|
70
79
|
relayMcpCommand,
|
|
71
80
|
spawnWords
|
|
72
81
|
};
|
|
@@ -2,10 +2,11 @@ import {
|
|
|
2
2
|
RelayUsage,
|
|
3
3
|
peekGrant,
|
|
4
4
|
stamp
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-3V3DRXB2.js";
|
|
6
|
+
import "./chunk-E53YHYEP.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";
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import {
|
|
2
|
+
RelayUsage
|
|
3
|
+
} from "./chunk-3V3DRXB2.js";
|
|
4
|
+
import "./chunk-E53YHYEP.js";
|
|
5
|
+
import "./chunk-M2DCR2J4.js";
|
|
6
|
+
|
|
7
|
+
// src/pi.ts
|
|
8
|
+
import { spawn } from "child_process";
|
|
9
|
+
import { fileURLToPath } from "url";
|
|
10
|
+
import { CLI_NAME, validHandle } from "@scp-dev/core";
|
|
11
|
+
var PI_HELP = `${CLI_NAME} pi [--name NAME | --as NAME] [--] [pi args...]
|
|
12
|
+
runs pi with the @scp-dev/pi extension: the relay tools, and each new message as a turn, waking the session when idle.
|
|
13
|
+
$SCP_PI_BIN picks the pi binary (default pi on PATH), $SCP_PI_EXTENSION the extension file.`;
|
|
14
|
+
function piLaunch(args, env, extension) {
|
|
15
|
+
let name;
|
|
16
|
+
const rest = [];
|
|
17
|
+
for (let i = 0; i < args.length; i++) {
|
|
18
|
+
const arg = args[i];
|
|
19
|
+
if (arg === "--") {
|
|
20
|
+
rest.push(...args.slice(i + 1));
|
|
21
|
+
break;
|
|
22
|
+
}
|
|
23
|
+
if (arg === "--name" || arg === "--as") {
|
|
24
|
+
name = args[++i];
|
|
25
|
+
if (name === void 0) throw new RelayUsage(`${CLI_NAME} pi ${arg} takes a name`);
|
|
26
|
+
} else if (arg.startsWith("--name=") || arg.startsWith("--as=")) name = arg.slice(arg.indexOf("=") + 1);
|
|
27
|
+
else rest.push(arg);
|
|
28
|
+
}
|
|
29
|
+
name = name?.replace(/^me\//, "");
|
|
30
|
+
if (name !== void 0 && !validHandle(name)) throw new RelayUsage(`${JSON.stringify(name)} is not a valid agent handle`);
|
|
31
|
+
return {
|
|
32
|
+
argv: [env.SCP_PI_BIN || "pi", "--extension", extension, ...rest],
|
|
33
|
+
env: { ...env, SCP_HARNESS: "pi", ...name !== void 0 ? { SCP_NAME: name } : {} }
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function extensionPath(env) {
|
|
37
|
+
if (env.SCP_PI_EXTENSION) return env.SCP_PI_EXTENSION;
|
|
38
|
+
try {
|
|
39
|
+
return fileURLToPath(import.meta.resolve("@scp-dev/pi"));
|
|
40
|
+
} catch {
|
|
41
|
+
throw new RelayUsage(`${CLI_NAME} pi needs the @scp-dev/pi extension: install it next to ${CLI_NAME}, or set $SCP_PI_EXTENSION to its file`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
async function piCommand(args) {
|
|
45
|
+
const own = args.includes("--") ? args.slice(0, args.indexOf("--")) : args;
|
|
46
|
+
if (own.includes("--help") || own.includes("-h")) {
|
|
47
|
+
process.stdout.write(`${PI_HELP}
|
|
48
|
+
`);
|
|
49
|
+
return 0;
|
|
50
|
+
}
|
|
51
|
+
const launch = piLaunch(args, process.env, extensionPath(process.env));
|
|
52
|
+
return await new Promise((resolve, reject) => {
|
|
53
|
+
const child = spawn(launch.argv[0], launch.argv.slice(1), { env: launch.env, stdio: "inherit" });
|
|
54
|
+
const forward = (signal) => child.kill(signal);
|
|
55
|
+
const signals = ["SIGTERM", "SIGHUP"];
|
|
56
|
+
const ignore = () => {
|
|
57
|
+
};
|
|
58
|
+
for (const signal of signals) process.on(signal, forward);
|
|
59
|
+
process.on("SIGINT", ignore);
|
|
60
|
+
child.once("error", (error) => reject(new RelayUsage(`could not start ${launch.argv[0]}: ${error.message}`)));
|
|
61
|
+
child.once("exit", (code, signal) => {
|
|
62
|
+
for (const each of signals) process.off(each, forward);
|
|
63
|
+
process.off("SIGINT", ignore);
|
|
64
|
+
resolve(code ?? (signal ? 1 : 0));
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
export {
|
|
69
|
+
PI_HELP,
|
|
70
|
+
piCommand,
|
|
71
|
+
piLaunch
|
|
72
|
+
};
|
|
@@ -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-3RRPUYTE.js";
|
|
15
|
+
import "./chunk-3V3DRXB2.js";
|
|
16
|
+
import "./chunk-E53YHYEP.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-U2RSSTNW.js";
|
|
13
|
+
import "./chunk-3RRPUYTE.js";
|
|
14
|
+
import "./chunk-3V3DRXB2.js";
|
|
15
|
+
import "./chunk-E53YHYEP.js";
|
|
16
|
+
import "./chunk-M2DCR2J4.js";
|
|
16
17
|
export {
|
|
17
18
|
CloudRelayClient,
|
|
18
19
|
CloudUsage,
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
agyRules,
|
|
5
5
|
agySettingsFile,
|
|
6
6
|
detectHarnesses,
|
|
7
|
+
entryArgv,
|
|
7
8
|
manifestFile,
|
|
8
9
|
mcpFile,
|
|
9
10
|
mountArgv,
|
|
@@ -14,18 +15,20 @@ import {
|
|
|
14
15
|
verifyMount,
|
|
15
16
|
verifyMusePlugin,
|
|
16
17
|
whichOnPath
|
|
17
|
-
} from "./chunk-
|
|
18
|
-
import "./chunk-
|
|
19
|
-
import "./chunk-
|
|
20
|
-
import "./chunk-
|
|
18
|
+
} from "./chunk-WV5FINTW.js";
|
|
19
|
+
import "./chunk-5DYFYLAQ.js";
|
|
20
|
+
import "./chunk-3V3DRXB2.js";
|
|
21
|
+
import "./chunk-RXKBND3T.js";
|
|
21
22
|
import "./chunk-YYSLYVNZ.js";
|
|
22
|
-
import "./chunk-
|
|
23
|
+
import "./chunk-E53YHYEP.js";
|
|
24
|
+
import "./chunk-M2DCR2J4.js";
|
|
23
25
|
export {
|
|
24
26
|
SETUP_HARNESSES,
|
|
25
27
|
SETUP_HELP,
|
|
26
28
|
agyRules,
|
|
27
29
|
agySettingsFile,
|
|
28
30
|
detectHarnesses,
|
|
31
|
+
entryArgv,
|
|
29
32
|
manifestFile,
|
|
30
33
|
mcpFile,
|
|
31
34
|
mountArgv,
|
|
@@ -29,16 +29,17 @@ import {
|
|
|
29
29
|
steerArgv,
|
|
30
30
|
transcriptReplies,
|
|
31
31
|
workerName
|
|
32
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-GH7AXFUL.js";
|
|
33
33
|
import {
|
|
34
34
|
SPAWN_HELP
|
|
35
35
|
} from "./chunk-KN7WEIE4.js";
|
|
36
|
-
import "./chunk-
|
|
37
|
-
import "./chunk-
|
|
38
|
-
import "./chunk-
|
|
39
|
-
import "./chunk-
|
|
36
|
+
import "./chunk-WV5FINTW.js";
|
|
37
|
+
import "./chunk-5DYFYLAQ.js";
|
|
38
|
+
import "./chunk-3V3DRXB2.js";
|
|
39
|
+
import "./chunk-RXKBND3T.js";
|
|
40
40
|
import "./chunk-YYSLYVNZ.js";
|
|
41
|
-
import "./chunk-
|
|
41
|
+
import "./chunk-E53YHYEP.js";
|
|
42
|
+
import "./chunk-M2DCR2J4.js";
|
|
42
43
|
export {
|
|
43
44
|
MESSAGING,
|
|
44
45
|
SPAWN_HELP,
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
activeRelay,
|
|
3
3
|
relayCredential
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-3RRPUYTE.js";
|
|
5
5
|
import {
|
|
6
6
|
RelayUsage
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import "./chunk-
|
|
7
|
+
} from "./chunk-3V3DRXB2.js";
|
|
8
|
+
import "./chunk-E53YHYEP.js";
|
|
9
|
+
import "./chunk-M2DCR2J4.js";
|
|
9
10
|
|
|
10
11
|
// src/up.ts
|
|
11
12
|
import { CLI_NAME } from "@scp-dev/core";
|
|
@@ -16,19 +17,19 @@ async function up(positionals, values, cwd, brokerStatus) {
|
|
|
16
17
|
const { url } = activeRelay(process.env);
|
|
17
18
|
const headless = values.token !== void 0 || Boolean(process.env.SCP_TOKEN?.trim());
|
|
18
19
|
if (headless || !relayCredential(process.env, url).token) {
|
|
19
|
-
const code = await (await import("./login-
|
|
20
|
+
const code = await (await import("./login-V2WT7QX5.js")).login({
|
|
20
21
|
...values.token !== void 0 ? { token: values.token } : {},
|
|
21
22
|
...values.label !== void 0 ? { label: values.label } : {},
|
|
22
23
|
...values["no-browser"] ? { "no-browser": true } : {}
|
|
23
24
|
});
|
|
24
25
|
if (code !== 0) return code;
|
|
25
26
|
} else out(`already logged in to ${url}`);
|
|
26
|
-
const enabled = await (await import("./remote-
|
|
27
|
+
const enabled = await (await import("./remote-FYN5ZXE4.js")).cloudMain(["enable"], values.machine !== void 0 ? { machine: values.machine } : {}, brokerStatus);
|
|
27
28
|
if (enabled !== 0) return enabled;
|
|
28
|
-
const setup = (await import("./setup-
|
|
29
|
+
const setup = (await import("./setup-LXG346FJ.js")).relaySetupCommand(["--write"], cwd, out);
|
|
29
30
|
if (setup !== 0) return setup;
|
|
30
31
|
const broker = await brokerStatus();
|
|
31
|
-
if (!broker.enabled) out(`the broker
|
|
32
|
+
if (!broker.enabled) out(`the broker is still local-only; run \`${CLI_NAME} daemon restart\` to link it to ${url}`);
|
|
32
33
|
else out(`broker linked to ${broker.url ?? url}${broker.connected ? "" : " (connecting)"}`);
|
|
33
34
|
return 0;
|
|
34
35
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scp-dev/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "The swarm command line tool.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://scp.dev",
|
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@scp-dev/core": "0.1.1",
|
|
28
|
-
"@scp-dev/broker": "0.1.
|
|
28
|
+
"@scp-dev/broker": "0.1.2",
|
|
29
29
|
"@scp-dev/hub": "0.1.1",
|
|
30
|
-
"@scp-dev/mcp": "0.1.
|
|
30
|
+
"@scp-dev/mcp": "0.1.2",
|
|
31
31
|
"smol-toml": "^1.9.1"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
package/dist/install-HFBSKSTG.js
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
hooksTarget,
|
|
3
|
-
installHooks,
|
|
4
|
-
mcpInstall
|
|
5
|
-
} from "./chunk-4DNQFATX.js";
|
|
6
|
-
import "./chunk-7KP6TAJW.js";
|
|
7
|
-
import "./chunk-XWLF7ON2.js";
|
|
8
|
-
import "./chunk-YYSLYVNZ.js";
|
|
9
|
-
import "./chunk-DA3EB2YF.js";
|
|
10
|
-
export {
|
|
11
|
-
hooksTarget,
|
|
12
|
-
installHooks,
|
|
13
|
-
mcpInstall
|
|
14
|
-
};
|