@scp-dev/cli 0.6.0 → 0.8.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.
Files changed (30) hide show
  1. package/dist/{chunk-BSX24XMZ.js → chunk-6S3V5ZGU.js} +59 -6
  2. package/dist/{chunk-DEK3TE6T.js → chunk-77NUOWQ4.js} +3 -3
  3. package/dist/{chunk-KN7WEIE4.js → chunk-FPNFRDXG.js} +1 -0
  4. package/dist/{chunk-C7ZUACP7.js → chunk-GTU3EWEY.js} +1 -1
  5. package/dist/{chunk-C5PYVRJE.js → chunk-MHBWDAXO.js} +2 -2
  6. package/dist/{codex-4GTXURTS.js → chunk-S5KEVIGO.js} +6 -10
  7. package/dist/{chunk-GG33NSBW.js → chunk-UUFTEXDU.js} +19 -3
  8. package/dist/{chunk-CVW3INZO.js → chunk-ZEWZBRVM.js} +33 -8
  9. package/dist/{claude-NCPNZLIX.js → claude-7BA4PGK3.js} +16 -6
  10. package/dist/cli.js +1 -1
  11. package/dist/codex-KQNXVGTE.js +26 -0
  12. package/dist/{hooks-SWVIDONV.js → hooks-DRIUG546.js} +6 -2
  13. package/dist/{install-YE7LCGPC.js → install-MZC4PAIC.js} +3 -3
  14. package/dist/{join-64BU6SEY.js → join-JW7C2IDC.js} +1 -1
  15. package/dist/{login-4IF26HH5.js → login-22BLC7KI.js} +2 -2
  16. package/dist/{main-RA3MP25N.js → main-6BPNG53C.js} +99 -26
  17. package/dist/{mcp-RERRUUIX.js → mcp-4VAPXGF6.js} +8 -7
  18. package/dist/{mesh-XTMBRJLR.js → mesh-P3EQXYLH.js} +1 -1
  19. package/dist/muse-QWCI627T.js +429 -0
  20. package/dist/{opencode-CPNR2G3W.js → opencode-7XYA7E3Q.js} +4 -4
  21. package/dist/{peek-GEYQ7SHV.js → peek-G6RLQGKO.js} +1 -1
  22. package/dist/{pi-XHZAUDP4.js → pi-QUW4MSVZ.js} +1 -1
  23. package/dist/{relay-E4JFR33E.js → relay-7VBBQCFB.js} +1 -1
  24. package/dist/{remote-3R4GRDGI.js → remote-VRVONVET.js} +2 -2
  25. package/dist/remote-spawn-7Z2FLG33.js +309 -0
  26. package/dist/resume-B5BOZO2G.js +308 -0
  27. package/dist/{setup-O45SE5L7.js → setup-NK2HRFZN.js} +4 -4
  28. package/dist/{spawn-CJSHYE7E.js → spawn-3IYGUBG6.js} +14 -6
  29. package/dist/{up-O2CMDGXP.js → up-QL3FLYUK.js} +8 -6
  30. package/package.json +6 -6
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  SPAWN_HELP
3
- } from "./chunk-KN7WEIE4.js";
3
+ } from "./chunk-FPNFRDXG.js";
4
4
  import {
5
5
  OPTIONS,
6
6
  RelayUsage,
@@ -16,7 +16,7 @@ import {
16
16
  startDaemon,
17
17
  terminalAttached,
18
18
  time
19
- } from "./chunk-BSX24XMZ.js";
19
+ } from "./chunk-6S3V5ZGU.js";
20
20
  import {
21
21
  FAILED,
22
22
  exitFlushed,
@@ -35,7 +35,7 @@ import { parseArgs } from "util";
35
35
  // package.json
36
36
  var package_default = {
37
37
  name: "@scp-dev/cli",
38
- version: "0.6.0",
38
+ version: "0.8.0",
39
39
  description: "The swarm command line tool.",
40
40
  license: "Apache-2.0",
41
41
  homepage: "https://scp.dev",
@@ -238,13 +238,28 @@ scopes (selectors are comma-separated, e.g. tree:parent,tree:children,group:team
238
238
  messages with the relay MCP tools (relay_send, relay_inbox, relay_reply). A
239
239
  ${CLI_NAME} command from codex's workspace-write sandbox also needs
240
240
  -c sandbox_workspace_write.network_access=true (the relay socket counts as network)
241
+ ${CLI_NAME} spawn --via R [--name N] [--title T] [--labels K=V,...] [--json] [--] <harness cmd...>
242
+ hands the spawn to runner R of ~/.config/scp/runners.json ($SCP_RUNNERS_FILE):
243
+ it gets the spawn as one JSON line on stdin and starts the worker on another
244
+ machine logged in to your account, whose ${CLI_NAME} spawn --under me/<this
245
+ machine>/<you> runs it linked under you, without a grant; it hands back as a
246
+ relay message. Needs this broker linked to a hub; returns once the runner exits 0,
247
+ naming the worker's address and attach command when the runner prints them
248
+ (--json: as JSON)
241
249
  ${CLI_NAME} pi [--name N] [--] [pi args...] runs pi with the bundled SCP extension: the relay tools, and each new
242
250
  message as a turn (steering a running one, waking an idle session)
243
251
  ${CLI_NAME} codex [--name N] [--headless] [--] [codex args...]
244
252
  runs codex with relay messages waking an idle thread or steering a running turn
253
+ ${CLI_NAME} muse [--name N] [--resume S] [--] [muse serve args...]
254
+ runs a headless Muse session that relay messages wake, printing its replies
245
255
  ${CLI_NAME} opencode [--name N] [--] [opencode args...]
246
256
  runs OpenCode with your own config and arguments, wake on: the plugin wakes an
247
257
  idle session, or opens one; refuses to start without the current plugin
258
+ ${CLI_NAME} agy [--name N] [--] [agy args...]
259
+ runs agy headless: each new message resumes its conversation as a turn;
260
+ refuses interactive flags and starts only with the scp hooks installed
261
+ ${CLI_NAME} grok [--name N] [--] [grok args...]
262
+ runs grok headless: each new message resumes its session as a turn
248
263
  ${CLI_NAME} peers [--all] [--roots] who you may message: title, status and the rule that admits each; offline ones and
249
264
  sessions nobody spawned that spawned nobody only with --all (--roots: those sessions)
250
265
  ${CLI_NAME} why <from> <to> whether from may message to, and why
@@ -315,6 +330,15 @@ agent sessions:
315
330
  (a cycle) is refused; both are audited, as adopt and unlink
316
331
  ${CLI_NAME} leave [--endpoint EP] take this session off the relay: offline, no messages pushed, mail kept until
317
332
  ${CLI_NAME} join; a spawned worker stays joined while it runs
333
+ ${CLI_NAME} hibernate --wake <provider> [--ref R] [<endpoint>] mark this session (or, for the human, <endpoint>) hibernated:
334
+ suspended but wakeable. A message to it runs the provider's wake hook from
335
+ ~/.config/scp/wakers.json with R and the message's metadata (never its body),
336
+ at most once a minute; the session drains its queue once it is back
337
+ ${CLI_NAME} hibernate --wake none [<endpoint>] the session resumed or is gone: hibernation clears (--gone is the same); it also
338
+ clears when the session claims its endpoint again
339
+ ${CLI_NAME} hibernate --all --wake <provider> [--ref R] [--eta S] the human marks every live agent of this machine hibernated
340
+ (--eta: how long a wake takes, shown to senders); it waits until the hub has it
341
+ ("the hub has it"), so the machine can be suspended right after
318
342
  With setup --join manual a session stays off the relay until it runs ${CLI_NAME} join; the default, auto, joins every
319
343
  hooked session when it starts.
320
344
 
@@ -326,6 +350,9 @@ relay:
326
350
  ${CLI_NAME} logout remove the stored credential for the active relay
327
351
  ${CLI_NAME} cloud enable [--machine NAME] | disable | status link the local broker to the hub, or inspect its link
328
352
  ${CLI_NAME} machines [rm NAME] list the hub's machines, or release one
353
+ ${CLI_NAME} machine wake-url <url> [--secret-env VAR] | --clear the URL the hub POSTs to, signed with the secret in $VAR
354
+ (default $SCP_MACHINE_WAKE_SECRET), when a message reaches a hibernated agent of
355
+ this machine while its broker is not linked; for the human
329
356
  --cloud (or $SCP_TRANSPORT=cloud) sends messaging commands directly to the hub using the active relay's login.
330
357
  --machine NAME ($SCP_MACHINE, else the short hostname) names this machine on the hub; it requires --cloud.
331
358
 
@@ -402,6 +429,8 @@ var VERBS = {
402
429
  link: IDENTITY,
403
430
  unlink: IDENTITY,
404
431
  leave: [...IDENTITY, "endpoint"],
432
+ hibernate: [...IDENTITY, "wake", "ref", "gone", "all", "eta"],
433
+ machine: [...IDENTITY, "secret-env", "clear"],
405
434
  name: [...IDENTITY, "endpoint", "take-over"],
406
435
  inbox: [...IDENTITY, "wait", "ack", "keep"],
407
436
  reply: IDENTITY,
@@ -575,14 +604,16 @@ async function relayMain(argv, cwd = process.cwd()) {
575
604
  out(cliVersion());
576
605
  return 0;
577
606
  }
578
- if (verb === "hook") return (await import("./hooks-SWVIDONV.js")).relayHookCommand(rest, startDaemon);
579
- if (verb === "setup") return (await import("./setup-O45SE5L7.js")).relaySetupCommand(rest, cwd, out);
580
- if (verb === "claude") return (await import("./claude-NCPNZLIX.js")).claudeCommand(rest);
581
- if (verb === "pi") return (await import("./pi-XHZAUDP4.js")).piCommand(rest);
582
- if (verb === "codex") return (await import("./codex-4GTXURTS.js")).codexCommand(rest);
583
- if (verb === "opencode") return (await import("./opencode-CPNR2G3W.js")).opencodeCommand(rest, process.env, void 0, cwd);
607
+ if (verb === "hook") return (await import("./hooks-DRIUG546.js")).relayHookCommand(rest, startDaemon);
608
+ if (verb === "setup") return (await import("./setup-NK2HRFZN.js")).relaySetupCommand(rest, cwd, out);
609
+ if (verb === "claude") return (await import("./claude-7BA4PGK3.js")).claudeCommand(rest);
610
+ if (verb === "pi") return (await import("./pi-QUW4MSVZ.js")).piCommand(rest);
611
+ if (verb === "codex") return (await import("./codex-KQNXVGTE.js")).codexCommand(rest);
612
+ if (verb === "muse") return (await import("./muse-QWCI627T.js")).museCommand(rest);
613
+ if (verb === "opencode") return (await import("./opencode-7XYA7E3Q.js")).opencodeCommand(rest, process.env, void 0, cwd);
614
+ if (verb === "agy" || verb === "grok") return (await import("./resume-B5BOZO2G.js")).resumeCommand(verb, rest, process.env, cwd);
584
615
  if (verb === "spawn") {
585
- const { splitSpawn, spawnCommand } = await import("./spawn-CJSHYE7E.js");
616
+ const { splitSpawn, spawnCommand } = await import("./spawn-3IYGUBG6.js");
586
617
  const { flags } = splitSpawn(rest);
587
618
  if (flags.includes("--help") || flags.includes("-h")) {
588
619
  out(flags.includes("--all") ? RELAY_HELP : SPAWN_HELP);
@@ -590,7 +621,7 @@ async function relayMain(argv, cwd = process.cwd()) {
590
621
  }
591
622
  return spawnCommand(rest, cwd);
592
623
  }
593
- if (verb === "mesh") return (await import("./mesh-XTMBRJLR.js")).meshCommand(rest);
624
+ if (verb === "mesh") return (await import("./mesh-P3EQXYLH.js")).meshCommand(rest);
594
625
  const allowed = VERBS[verb];
595
626
  if (!allowed) throw new RelayUsage(`unknown command "${verb}"`);
596
627
  let parsed;
@@ -610,11 +641,11 @@ async function relayMain(argv, cwd = process.cwd()) {
610
641
  return daemon(values.idle, values.policy);
611
642
  }
612
643
  if (verb === "mcp")
613
- return (await import("./mcp-RERRUUIX.js")).relayMcpCommand(values, positionals);
644
+ return (await import("./mcp-4VAPXGF6.js")).relayMcpCommand(values, positionals);
614
645
  if (verb === "hooks") {
615
646
  if (positionals[0] !== "install" || positionals.length > 1) throw new RelayUsage(`${CLI_NAME} hooks takes install --harness claude|codex|opencode|agy|muse`);
616
647
  if (values.write && values.print) throw new RelayUsage("--print and --write: pick one");
617
- return (await import("./install-YE7LCGPC.js")).installHooks({
648
+ return (await import("./install-MZC4PAIC.js")).installHooks({
618
649
  harness: values.harness,
619
650
  scope: values.scope,
620
651
  write: values.write === true,
@@ -625,27 +656,27 @@ async function relayMain(argv, cwd = process.cwd()) {
625
656
  out
626
657
  });
627
658
  }
628
- if (verb === "relay") return (await import("./relay-E4JFR33E.js")).relayVerb(positionals, values.json === true);
629
- if (verb === "up") return (await import("./up-O2CMDGXP.js")).up(positionals, values, cwd, relinkBroker);
659
+ if (verb === "relay") return (await import("./relay-7VBBQCFB.js")).relayVerb(positionals, values.json === true);
660
+ if (verb === "up") return (await import("./up-QL3FLYUK.js")).up(positionals, values, cwd, relinkBroker);
630
661
  if (verb === "login") {
631
- const code = await (await import("./relay-E4JFR33E.js")).loginMain(positionals, values);
662
+ const code = await (await import("./relay-7VBBQCFB.js")).loginMain(positionals, values);
632
663
  if (code === 0) await relinkRunning();
633
664
  return code;
634
665
  }
635
- if (verb === "logout") return (await import("./relay-E4JFR33E.js")).logoutMain(positionals, values.json === true);
666
+ if (verb === "logout") return (await import("./relay-7VBBQCFB.js")).logoutMain(positionals, values.json === true);
636
667
  if (verb === "cloud") {
637
- const code = await (await import("./remote-3R4GRDGI.js")).cloudMain(positionals, values, cloudStatus);
668
+ const code = await (await import("./remote-VRVONVET.js")).cloudMain(positionals, values, cloudStatus);
638
669
  if (code === 0 && positionals[0] === "enable") await relinkRunning();
639
670
  return code;
640
671
  }
641
- if (verb === "join") return (await import("./join-64BU6SEY.js")).joinCommand(values, positionals, cwd, out);
672
+ if (verb === "join") return (await import("./join-JW7C2IDC.js")).joinCommand(values, positionals, cwd, out);
642
673
  if (verb === "holds") holdsArgs(values, positionals);
643
674
  const bodyFromStdin = (verb === "send" || verb === "ask" || verb === "reply") && (positionals[1] === void 0 || positionals[1] === "-");
644
675
  const humanAdopt = verb === "adopt" && values.parent !== void 0 && values.as === void 0 && terminalAttached(process, false);
645
676
  const opened = humanAdopt ? await openAdoptHuman(cwd, values) : await open(verb, values, cwd, bodyFromStdin);
646
677
  const { client } = opened;
647
678
  try {
648
- if (verb === "machines") return await (await import("./remote-3R4GRDGI.js")).machinesVerb(client, positionals, values.json === true);
679
+ if (verb === "machines") return await (await import("./remote-VRVONVET.js")).machinesVerb(client, positionals, values.json === true);
649
680
  return await runVerb(opened, verb, values, positionals, cwd);
650
681
  } finally {
651
682
  client.close();
@@ -653,7 +684,7 @@ async function relayMain(argv, cwd = process.cwd()) {
653
684
  }
654
685
  async function openAdoptHuman(cwd, values) {
655
686
  if (values.cloud || process.env.SCP_TRANSPORT === "cloud") {
656
- const { openCloud } = await import("./remote-3R4GRDGI.js");
687
+ const { openCloud } = await import("./remote-VRVONVET.js");
657
688
  return { ...await openCloud({ tty: true, ...values.machine !== void 0 ? { machine: values.machine } : {} }), broker: null, bound: "human" };
658
689
  }
659
690
  if (values.machine !== void 0) throw new RelayUsage("--machine names the machine of the cloud transport: add --cloud");
@@ -838,9 +869,9 @@ async function runVerb({ client, me, broker, where, bound, harnessPid }, verb, v
838
869
  return 0;
839
870
  }
840
871
  case "peek":
841
- return (await import("./peek-GEYQ7SHV.js")).peekCommand(localClient(client, broker, verb), values, positionals);
872
+ return (await import("./peek-G6RLQGKO.js")).peekCommand(localClient(client, broker, verb), values, positionals);
842
873
  case "set-peek":
843
- return (await import("./peek-GEYQ7SHV.js")).setPeekCommand(localClient(client, broker, verb), values, positionals);
874
+ return (await import("./peek-G6RLQGKO.js")).setPeekCommand(localClient(client, broker, verb), values, positionals);
844
875
  case "why": {
845
876
  const [from, to] = positionals;
846
877
  if (!from || !to || positionals.length > 2) throw new RelayUsage(`${CLI_NAME} why takes <from> <to>`);
@@ -1103,6 +1134,47 @@ async function runVerb({ client, me, broker, where, bound, harnessPid }, verb, v
1103
1134
  else out(`${result.endpoint.address} is a root again (was under ${result.parent})`);
1104
1135
  return 0;
1105
1136
  }
1137
+ case "hibernate": {
1138
+ if (positionals.length > 1) throw new RelayUsage(`${CLI_NAME} hibernate takes at most one endpoint`);
1139
+ if (values.gone === true && values.wake !== void 0) throw new RelayUsage("--gone and --wake: pick one");
1140
+ const wake = values.gone === true ? "none" : values.wake;
1141
+ if (wake === void 0) throw new RelayUsage(`${CLI_NAME} hibernate takes --wake <provider>, or --wake none (--gone) to clear it`);
1142
+ if (wake === "none" && (values.ref !== void 0 || values.eta !== void 0))
1143
+ throw new RelayUsage("--ref and --eta go with a provider, not with --wake none");
1144
+ if (values.all === true && positionals.length) throw new RelayUsage(`${CLI_NAME} hibernate --all names no endpoint`);
1145
+ const eta = values.eta === void 0 ? void 0 : Math.round(parseSeconds(values.eta, "--eta"));
1146
+ const result = await client.request("hibernate", {
1147
+ ...values.all === true ? { all: true } : positionals.length ? { endpoint: positionals[0] } : {},
1148
+ wake,
1149
+ ...values.ref !== void 0 ? { ref: values.ref } : {},
1150
+ ...eta !== void 0 ? { eta_s: eta } : {}
1151
+ });
1152
+ if (asJson) json(result);
1153
+ else {
1154
+ for (const e of result.endpoints ?? (result.endpoint ? [result.endpoint] : []))
1155
+ out(`${e.address} ${presenceText(e)}${e.presence === "hibernated" ? `, woken by ${wakeText(e)}` : ""}`);
1156
+ if (result.mirrored) note("the hub has it: the machine may be suspended now");
1157
+ }
1158
+ return 0;
1159
+ }
1160
+ case "machine": {
1161
+ if (positionals[0] !== "wake-url") throw new RelayUsage(`${CLI_NAME} machine takes wake-url <url> [--secret-env VAR] | wake-url --clear`);
1162
+ if (values.clear === true) {
1163
+ if (positionals.length > 1 || values["secret-env"] !== void 0) throw new RelayUsage(`${CLI_NAME} machine wake-url --clear takes no url`);
1164
+ const result2 = await client.request("machine_wake", { url: null });
1165
+ if (asJson) json(result2);
1166
+ else out("machine waker cleared");
1167
+ return 0;
1168
+ }
1169
+ if (positionals.length !== 2) throw new RelayUsage(`${CLI_NAME} machine wake-url takes one url, or --clear`);
1170
+ const name = values["secret-env"] ?? "SCP_MACHINE_WAKE_SECRET";
1171
+ const secret = process.env[name];
1172
+ if (!secret) throw new RelayUsage(`set $${name} to the waker's secret (16 to 256 characters); it is never read from the command line`);
1173
+ const result = await client.request("machine_wake", { url: positionals[1], secret });
1174
+ if (asJson) json(result);
1175
+ else out("machine waker set; the hub signs each call with the secret");
1176
+ return 0;
1177
+ }
1106
1178
  case "leave": {
1107
1179
  if (positionals.length) throw new RelayUsage(`${CLI_NAME} leave takes no arguments (--endpoint EP for the human at a terminal)`);
1108
1180
  const endpoint = values.endpoint;
@@ -1337,7 +1409,8 @@ function printSummary(snapshot, me, all) {
1337
1409
  const agents = snapshot.endpoints.filter((e) => e.kind !== "human");
1338
1410
  const count = (presence) => agents.filter((e) => e.presence === presence).length;
1339
1411
  out();
1340
- out(`agents: ${count("online")} online, ${count("idle")} idle, ${count("offline")} offline`);
1412
+ const hibernated = count("hibernated");
1413
+ out(`agents: ${count("online")} online, ${count("idle")} idle, ${hibernated ? `${hibernated} hibernated, ` : ""}${count("offline")} offline`);
1341
1414
  const counted = all ? agents : agents.filter((e) => e.presence !== "offline");
1342
1415
  const harnesses = /* @__PURE__ */ new Map();
1343
1416
  for (const e of counted) harnesses.set(e.harness ?? "?", [...harnesses.get(e.harness ?? "?") ?? [], e]);
@@ -1464,11 +1537,11 @@ async function daemon(idle, policyFile) {
1464
1537
  });
1465
1538
  let broker;
1466
1539
  try {
1467
- const { daemonBridge } = await import("./remote-3R4GRDGI.js");
1540
+ const { daemonBridge } = await import("./remote-VRVONVET.js");
1468
1541
  const bridge = await daemonBridge();
1469
1542
  broker = await startBroker({
1470
1543
  dir: relayDir(),
1471
- ...bridge ? { bridge } : await (await import("./mesh-XTMBRJLR.js")).meshBrokerOptions(),
1544
+ ...bridge ? { bridge } : await (await import("./mesh-P3EQXYLH.js")).meshBrokerOptions(),
1472
1545
  bridgeConfig: () => daemonBridge(),
1473
1546
  ...idleMs !== void 0 ? { idleMs } : {},
1474
1547
  ...policyFile ? { policyPath: resolve(policyFile) } : {}
@@ -1,24 +1,25 @@
1
1
  import {
2
2
  spawnDetached
3
- } from "./chunk-CVW3INZO.js";
4
- import "./chunk-KN7WEIE4.js";
5
- import "./chunk-DEK3TE6T.js";
3
+ } from "./chunk-ZEWZBRVM.js";
4
+ import "./chunk-FPNFRDXG.js";
5
+ import "./chunk-77NUOWQ4.js";
6
6
  import {
7
7
  mcpInstall
8
- } from "./chunk-C5PYVRJE.js";
9
- import "./chunk-GG33NSBW.js";
8
+ } from "./chunk-MHBWDAXO.js";
9
+ import "./chunk-UUFTEXDU.js";
10
10
  import "./chunk-YYSLYVNZ.js";
11
11
  import {
12
12
  CHANNELS_ENV,
13
13
  RelayUsage,
14
14
  harnessAt,
15
15
  harnessPid,
16
+ launcherPid,
16
17
  membership,
17
18
  psParent,
18
19
  relayIdentity,
19
20
  startDaemon,
20
21
  writeShimBinding
21
- } from "./chunk-BSX24XMZ.js";
22
+ } from "./chunk-6S3V5ZGU.js";
22
23
  import "./chunk-MNTIEWKF.js";
23
24
 
24
25
  // src/mcp.ts
@@ -40,7 +41,7 @@ async function relayMcpCommand(values, positionals) {
40
41
  fallbackHarness: "mcp",
41
42
  cwd: process.cwd(),
42
43
  env: process.env,
43
- harnessPid: () => harnessPid(),
44
+ harnessPid: () => launcherPid(process.env) ?? harnessPid(),
44
45
  inferHarness: (pid) => harnessAt(pid)
45
46
  });
46
47
  if (!validHandle(claim.handle)) throw new RelayUsage(`${JSON.stringify(claim.handle)} is not a valid agent handle (me, user and relay are reserved)`);
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  RelayUsage
3
- } from "./chunk-BSX24XMZ.js";
3
+ } from "./chunk-6S3V5ZGU.js";
4
4
  import "./chunk-MNTIEWKF.js";
5
5
 
6
6
  // src/mesh.ts