@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 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 install -g @scp-dev/cli
6
+ npm i -g @scp-dev/cli
7
7
  ```
8
8
 
9
9
  ## Usage
10
10
 
11
11
  ```sh
12
- swarm login
13
- swarm setup --write
14
- swarm spawn --name parser -- claude "Fix the parser tests"
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 login --token scp_t_...` or `SCP_TOKEN`. `swarm up --token ...` logs in, links the broker to the hub and runs setup in one step. The default relay is https://app.scp.dev; `swarm relay use <url>` picks another. Runs on Node 22.13 or later.
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-7KP6TAJW.js";
3
+ } from "./chunk-3V3DRXB2.js";
4
4
  import {
5
5
  note
6
- } from "./chunk-DA3EB2YF.js";
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-JTRUWG6Q.js")).login(values);
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-DA3EB2YF.js";
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-3BWFISXJ.js");
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-7KP6TAJW.js";
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-XWLF7ON2.js";
16
+ } from "./chunk-RXKBND3T.js";
17
17
  import {
18
18
  gitToplevel
19
- } from "./chunk-DA3EB2YF.js";
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
- // 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((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-N3ZROLFA.js";
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-7KP6TAJW.js";
16
+ } from "./chunk-3V3DRXB2.js";
17
17
  import {
18
18
  steerPrompt
19
- } from "./chunk-XWLF7ON2.js";
19
+ } from "./chunk-RXKBND3T.js";
20
20
  import {
21
- SELF,
22
21
  detectHarness,
23
- note,
24
22
  spawnerKey
25
- } from "./chunk-DA3EB2YF.js";
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
+ };
@@ -7,7 +7,7 @@ import {
7
7
  hookHarness,
8
8
  hookHarnessPid,
9
9
  relayIdentity
10
- } from "./chunk-DA3EB2YF.js";
10
+ } from "./chunk-E53YHYEP.js";
11
11
 
12
12
  // src/hooks.ts
13
13
  import { Readable } from "stream";
@@ -4,14 +4,14 @@ import {
4
4
  configDir,
5
5
  relayCredential,
6
6
  writePrivateJson
7
- } from "./chunk-4QYUPPGV.js";
7
+ } from "./chunk-3RRPUYTE.js";
8
8
  import {
9
9
  RelayUsage
10
- } from "./chunk-7KP6TAJW.js";
10
+ } from "./chunk-3V3DRXB2.js";
11
11
  import {
12
12
  note,
13
13
  printTable
14
- } from "./chunk-DA3EB2YF.js";
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} the next time it starts (${path})`);
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-4DNQFATX.js";
3
+ } from "./chunk-5DYFYLAQ.js";
4
4
  import {
5
5
  RelayUsage
6
- } from "./chunk-7KP6TAJW.js";
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-XWLF7ON2.js";
18
+ } from "./chunk-RXKBND3T.js";
19
19
  import {
20
20
  gitToplevel
21
- } from "./chunk-DA3EB2YF.js";
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-5CAHHN55.js");
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-XWLF7ON2.js";
33
+ } from "./chunk-RXKBND3T.js";
34
34
  import {
35
35
  SUBAGENT
36
36
  } from "./chunk-YYSLYVNZ.js";
37
- import "./chunk-DA3EB2YF.js";
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-6UFMKYPH.js";
3
+ } from "./chunk-U2RSSTNW.js";
4
4
  import {
5
5
  activeRelay,
6
6
  saveCredential
7
- } from "./chunk-4QYUPPGV.js";
7
+ } from "./chunk-3RRPUYTE.js";
8
8
  import {
9
9
  RelayUsage
10
- } from "./chunk-7KP6TAJW.js";
10
+ } from "./chunk-3V3DRXB2.js";
11
+ import "./chunk-E53YHYEP.js";
11
12
  import {
12
13
  note
13
- } from "./chunk-DA3EB2YF.js";
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-7KP6TAJW.js";
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
- shortHostname
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.2",
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
- --channels pushes messages into Claude Code started with --dangerously-load-development-channels server:scp.
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-O3UZXDYG.js")).relayHookCommand(rest, startDaemon);
495
- if (verb === "setup") return (await import("./setup-RDPVGE4H.js")).relaySetupCommand(rest, cwd, out);
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-TQ3HOZTQ.js");
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") return daemon(values.idle, values.policy);
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-P2AZYP5G.js")).relayMcpCommand(values, positionals);
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-HFBSKSTG.js")).installHooks({
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-VVJPYVXE.js")).relayVerb(positionals, values.json === true);
537
- if (verb === "up") return (await import("./up-KXOYO7QV.js")).up(positionals, values, cwd, cloudStatus);
538
- if (verb === "login")
539
- return (await import("./relay-VVJPYVXE.js")).loginMain(positionals, values);
540
- if (verb === "logout") return (await import("./relay-VVJPYVXE.js")).logoutMain(positionals, values.json === true);
541
- if (verb === "cloud") return (await import("./remote-3BWFISXJ.js")).cloudMain(positionals, values, cloudStatus);
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-3BWFISXJ.js")).machinesVerb(client, positionals, values.json === true);
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-YCOWBEPD.js")).peekCommand(localClient(client, broker, verb), values, positionals);
743
+ return (await import("./peek-WLG3ZROU.js")).peekCommand(localClient(client, broker, verb), values, positionals);
676
744
  case "set-peek":
677
- return (await import("./peek-YCOWBEPD.js")).setPeekCommand(localClient(client, broker, verb), values, positionals);
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 { messages } = await client.request("inbox", { wait_s: waitArg(values.wait, 0) });
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("no unread messages");
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-3BWFISXJ.js");
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-V5I7KEU7.js";
3
+ } from "./chunk-GH7AXFUL.js";
4
4
  import "./chunk-KN7WEIE4.js";
5
- import "./chunk-N3ZROLFA.js";
5
+ import "./chunk-WV5FINTW.js";
6
6
  import {
7
7
  mcpInstall
8
- } from "./chunk-4DNQFATX.js";
8
+ } from "./chunk-5DYFYLAQ.js";
9
9
  import {
10
+ CHANNELS_ENV,
10
11
  RelayUsage,
11
12
  startDaemon
12
- } from "./chunk-7KP6TAJW.js";
13
- import "./chunk-XWLF7ON2.js";
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-DA3EB2YF.js";
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-7KP6TAJW.js";
5
+ } from "./chunk-3V3DRXB2.js";
6
+ import "./chunk-E53YHYEP.js";
6
7
  import {
7
8
  note
8
- } from "./chunk-DA3EB2YF.js";
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-4QYUPPGV.js";
15
- import "./chunk-7KP6TAJW.js";
16
- import "./chunk-DA3EB2YF.js";
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-6UFMKYPH.js";
13
- import "./chunk-4QYUPPGV.js";
14
- import "./chunk-7KP6TAJW.js";
15
- import "./chunk-DA3EB2YF.js";
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-N3ZROLFA.js";
18
- import "./chunk-4DNQFATX.js";
19
- import "./chunk-7KP6TAJW.js";
20
- import "./chunk-XWLF7ON2.js";
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-DA3EB2YF.js";
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-V5I7KEU7.js";
32
+ } from "./chunk-GH7AXFUL.js";
33
33
  import {
34
34
  SPAWN_HELP
35
35
  } from "./chunk-KN7WEIE4.js";
36
- import "./chunk-N3ZROLFA.js";
37
- import "./chunk-4DNQFATX.js";
38
- import "./chunk-7KP6TAJW.js";
39
- import "./chunk-XWLF7ON2.js";
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-DA3EB2YF.js";
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-4QYUPPGV.js";
4
+ } from "./chunk-3RRPUYTE.js";
5
5
  import {
6
6
  RelayUsage
7
- } from "./chunk-7KP6TAJW.js";
8
- import "./chunk-DA3EB2YF.js";
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-JTRUWG6Q.js")).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-3BWFISXJ.js")).cloudMain(["enable"], values.machine !== void 0 ? { machine: values.machine } : {}, brokerStatus);
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-RDPVGE4H.js")).relaySetupCommand(["--write"], cwd, out);
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 that was already running stays local-only until it exits (it stops when idle); the next one links to ${url}`);
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.1.2",
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.1",
28
+ "@scp-dev/broker": "0.1.2",
29
29
  "@scp-dev/hub": "0.1.1",
30
- "@scp-dev/mcp": "0.1.1",
30
+ "@scp-dev/mcp": "0.1.2",
31
31
  "smol-toml": "^1.9.1"
32
32
  },
33
33
  "devDependencies": {
@@ -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
- };