@scp-dev/cli 0.4.0 → 0.5.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.
@@ -10,11 +10,11 @@ import {
10
10
  mergeHooks,
11
11
  musePlugin,
12
12
  opencodePlugin
13
- } from "./chunk-B2G3XTW7.js";
13
+ } from "./chunk-XQHPDNVG.js";
14
14
  import {
15
15
  RelayUsage,
16
16
  gitToplevel
17
- } from "./chunk-2LIJXXTL.js";
17
+ } from "./chunk-AAFHLHXG.js";
18
18
 
19
19
  // src/install.ts
20
20
  import { chmodSync, copyFileSync, existsSync, lstatSync, mkdirSync, readFileSync, realpathSync, renameSync, statSync, unlinkSync, writeFileSync } from "fs";
@@ -3,10 +3,10 @@ import {
3
3
  agySettingsFile,
4
4
  mcpFile,
5
5
  mountedEntry
6
- } from "./chunk-VW7DYSGM.js";
6
+ } from "./chunk-UKQBH4AQ.js";
7
7
  import {
8
8
  steerPrompt
9
- } from "./chunk-B2G3XTW7.js";
9
+ } from "./chunk-XQHPDNVG.js";
10
10
  import {
11
11
  OPTIONS,
12
12
  RelayUsage,
@@ -18,7 +18,7 @@ import {
18
18
  selectorList,
19
19
  spawnerKey,
20
20
  walkNow
21
- } from "./chunk-2LIJXXTL.js";
21
+ } from "./chunk-AAFHLHXG.js";
22
22
  import {
23
23
  SELF,
24
24
  note
@@ -44,8 +44,8 @@ import {
44
44
  } from "@scp-dev/core";
45
45
  var SERVER = "scp";
46
46
  var SPAWN_RUNNER = "SCP_SPAWN_RUNNER";
47
- var SPAWNER_IDENTITY = ["SCP_NAME", "SCP_SESSION", "SCP_GRANT", "SCP_PARENT", "SCP_HARNESS", SPAWN_RUNNER];
48
- var SHIM_ENV = ["SCP_GRANT", "SCP_NAME", "SCP_LABELS", "SCP_DIR", "XDG_STATE_HOME"];
47
+ var SPAWNER_IDENTITY = ["SCP_NAME", "SCP_SESSION", "SCP_GRANT", "SCP_PARENT", "SCP_HARNESS", "SCP_SHIM_BINDING", SPAWN_RUNNER];
48
+ var SHIM_ENV = ["SCP_GRANT", "SCP_NAME", "SCP_LABELS", "SCP_DIR", "XDG_STATE_HOME", "SCP_SHIM_BINDING"];
49
49
  function spawnEnvironment(parent, grant, labels) {
50
50
  const env = {};
51
51
  for (const [key, value] of Object.entries(parent)) if (value !== void 0 && !SPAWNER_IDENTITY.includes(key)) env[key] = value;
@@ -6,7 +6,7 @@ import {
6
6
  } from "./chunk-MNTIEWKF.js";
7
7
 
8
8
  // src/relay.ts
9
- import { chmodSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "fs";
9
+ import { chmodSync as chmodSync2, mkdirSync, readFileSync as readFileSync2, renameSync, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "fs";
10
10
  import { join as join3, dirname as dirname2 } from "path";
11
11
  import { randomUUID } from "crypto";
12
12
  import { CLI_NAME as CLI_NAME3 } from "@scp-dev/core";
@@ -16,13 +16,13 @@ import { spawn } from "child_process";
16
16
  import { closeSync, openSync, statSync, truncateSync } from "fs";
17
17
  import { join as join2 } from "path";
18
18
  import { CLI_NAME as CLI_NAME2 } from "@scp-dev/core";
19
- import { connectBroker, privateDir, relayDir as relayDir2 } from "@scp-dev/broker";
19
+ import { connectBroker, privateDir as privateDir2, relayDir as relayDir3 } from "@scp-dev/broker";
20
20
 
21
21
  // src/identity.ts
22
- import { existsSync, realpathSync } from "fs";
22
+ import { chmodSync, existsSync, readFileSync, realpathSync, rmSync, writeFileSync } from "fs";
23
23
  import { tmpdir } from "os";
24
24
  import { basename, dirname, isAbsolute, join, resolve } from "path";
25
- import { shortHostname } from "@scp-dev/broker";
25
+ import { privateDir, relayDir, shortHostname } from "@scp-dev/broker";
26
26
  import { GENERIC_HARNESSES, LIMITS, validHandle, validHarness } from "@scp-dev/core";
27
27
  var SHORT = { "claude-code": "claude" };
28
28
  var SHELLS = /* @__PURE__ */ new Set(["sh", "bash", "zsh", "dash", "fish"]);
@@ -34,6 +34,61 @@ function detectHarness(env) {
34
34
  if (env.ANTIGRAVITY_AGENT === "1" || env.ANTIGRAVITY_CONVERSATION_ID) return "agy";
35
35
  if (env.CLAUDECODE === "1") return "claude-code";
36
36
  if (env.CODEX_THREAD_ID) return "codex";
37
+ if (inferring(env) && (env.CODEX_SANDBOX || env.CODEX_SANDBOX_NETWORK_DISABLED)) return "codex";
38
+ return void 0;
39
+ }
40
+ var BINDING_KEY = /^[0-9a-f]{1,128}$/;
41
+ var BINDING_PROCESS = /^pid:([1-9][0-9]*):[A-Za-z0-9:-]{1,64}$/;
42
+ function codexShell(env) {
43
+ return env.SCP_HARNESS === "codex" || inferring(env) && detectHarness(env) === "codex";
44
+ }
45
+ function writeShimBinding(claim, env) {
46
+ const pid = BINDING_PROCESS.exec(claim.process)?.[1];
47
+ if (claim.harness !== "codex" || !pid) return () => {
48
+ };
49
+ const text = JSON.stringify({ process: claim.process, handle: claim.handle, harness: claim.harness });
50
+ const names = [`pid-${pid}`, ...BINDING_KEY.test(env.SCP_SHIM_BINDING ?? "") ? [`key-${env.SCP_SHIM_BINDING}`] : []];
51
+ const paths = [];
52
+ for (const name of names) {
53
+ try {
54
+ const path = join(privateDir(join(relayDir(env), "bindings")), `${name}.json`);
55
+ writeFileSync(path, text, { mode: 384 });
56
+ chmodSync(path, 384);
57
+ paths.push(path);
58
+ } catch {
59
+ }
60
+ }
61
+ return () => {
62
+ for (const path of paths) {
63
+ try {
64
+ if (readFileSync(path, "utf8") === text) rmSync(path);
65
+ } catch {
66
+ }
67
+ }
68
+ };
69
+ }
70
+ function readShimBinding(env, pid, table) {
71
+ const read = (name, expectedPid) => {
72
+ try {
73
+ const binding = JSON.parse(readFileSync(join(relayDir(env), "bindings", `${name}.json`), "utf8"));
74
+ const match = typeof binding.process === "string" ? BINDING_PROCESS.exec(binding.process) : null;
75
+ if (match && Number(match[1]) > 1 && (expectedPid === void 0 || Number(match[1]) === expectedPid) && binding.harness === "codex" && typeof binding.handle === "string" && validHandle(binding.handle))
76
+ return binding;
77
+ } catch {
78
+ }
79
+ return void 0;
80
+ };
81
+ if (BINDING_KEY.test(env.SCP_SHIM_BINDING ?? "")) {
82
+ const binding = read(`key-${env.SCP_SHIM_BINDING}`);
83
+ if (binding) return binding;
84
+ }
85
+ const seen = /* @__PURE__ */ new Set();
86
+ while (pid > 1 && !seen.has(pid)) {
87
+ seen.add(pid);
88
+ const entry = table?.get(pid);
89
+ if (!entry) return read(`pid-${pid}`, pid);
90
+ pid = entry.ppid;
91
+ }
37
92
  return void 0;
38
93
  }
39
94
  function normalizeHarness(raw, fallback) {
@@ -342,9 +397,9 @@ function relayIdentity(input) {
342
397
 
343
398
  // src/session.ts
344
399
  import { CLI_NAME } from "@scp-dev/core";
345
- import { readSessionMarker, relayDir } from "@scp-dev/broker";
400
+ import { readSessionMarker, relayDir as relayDir2 } from "@scp-dev/broker";
346
401
  function membership(env, session) {
347
- const marker = readSessionMarker(relayDir(env), session);
402
+ const marker = readSessionMarker(relayDir2(env), session);
348
403
  if (marker?.joined === false) return { dark: `this session left the relay; ${CLI_NAME} join (or relay_join) joins it again` };
349
404
  if (!marker?.joined && joinMode(env) === "manual") return { dark: `this session has not joined the relay; ${CLI_NAME} join <name> (or relay_join) joins it` };
350
405
  return marker?.handle ? { handle: marker.handle } : {};
@@ -471,7 +526,7 @@ var DAEMON_ENV = [
471
526
  ];
472
527
  var LOG_MAX_BYTES = 1024 * 1024;
473
528
  function startDaemon(dir) {
474
- privateDir(dir);
529
+ privateDir2(dir);
475
530
  const logFile = join2(dir, "broker.log");
476
531
  if ((statSync(logFile, { throwIfNoEntry: false })?.size ?? 0) > LOG_MAX_BYTES) truncateSync(logFile, 0);
477
532
  const log = openSync(logFile, "a", 384);
@@ -499,11 +554,18 @@ function localHandle(raw) {
499
554
  if (handle.includes("/")) throw new RelayUsage(`--as names a local handle, not ${JSON.stringify(raw)}`);
500
555
  return handle;
501
556
  }
502
- function walkNow() {
503
- const table = readPsTable();
504
- const self = harnessLineage(process.ppid, table);
557
+ function walkNow(env = process.env, pid = process.ppid, table = readPsTable()) {
558
+ const keys = lineage(pid, table);
559
+ const self = harnessLineage(pid, table);
560
+ if (!self.length && codexShell(env)) {
561
+ const binding = readShimBinding(env, pid, table);
562
+ if (binding) {
563
+ const bound = [...keys, binding.process];
564
+ return { keys: bound, self: bound, harness: "codex" };
565
+ }
566
+ }
505
567
  const harness = self.length ? harnessAt(Number(/^pid:(\d+)/.exec(self.at(-1))?.[1]), table) : void 0;
506
- return { keys: lineage(process.ppid, table), self, ...harness ? { harness } : {} };
568
+ return { keys, self, ...harness ? { harness } : {} };
507
569
  }
508
570
  function claimHarness(values, env, walk) {
509
571
  return values.harness ?? env.SCP_HARNESS ?? (inferring(env) ? walk?.harness ?? detectHarness(env) : void 0) ?? "cli";
@@ -529,7 +591,7 @@ async function open(verb, values, cwd, bodyFromStdin, walk) {
529
591
  `${CLI_NAME2} ${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)`
530
592
  );
531
593
  }
532
- const { machineName, openCloud } = await import("./remote-P4GFUIAP.js");
594
+ const { machineName, openCloud } = await import("./remote-UQJ5YYCC.js");
533
595
  const handle2 = named ? localHandle(named) : void 0;
534
596
  const claim = handle2 ? {
535
597
  handle: handle2,
@@ -558,7 +620,7 @@ async function open(verb, values, cwd, bodyFromStdin, walk) {
558
620
  const handle = "handle" in joined && joined.handle ? joined.handle : named ? localHandle(named) : void 0;
559
621
  const harnessPid2 = self.length ? Number(/^pid:(\d+)/.exec(self.at(-1))?.[1]) : void 0;
560
622
  const lineageClaim = keys.length ? { lineage: keys } : {};
561
- const dir = relayDir2();
623
+ const dir = relayDir3();
562
624
  const client = await connectBroker(dir, () => startDaemon(dir));
563
625
  try {
564
626
  let bound;
@@ -688,7 +750,7 @@ function checkRelayUrl(text, what = "relay URL") {
688
750
  function readObject(path) {
689
751
  let text;
690
752
  try {
691
- text = readFileSync(path, "utf8");
753
+ text = readFileSync2(path, "utf8");
692
754
  } catch (error) {
693
755
  if (error.code === "ENOENT") return void 0;
694
756
  throw new RelayUsage(`could not read ${path}`);
@@ -704,15 +766,15 @@ function readObject(path) {
704
766
  function writePrivateJson(path, value) {
705
767
  const dir = dirname2(path);
706
768
  mkdirSync(dir, { recursive: true, mode: 448 });
707
- chmodSync(dir, 448);
769
+ chmodSync2(dir, 448);
708
770
  const temp = join3(dir, `.${randomUUID()}.tmp`);
709
771
  try {
710
- writeFileSync(temp, `${JSON.stringify(value, null, 2)}
772
+ writeFileSync2(temp, `${JSON.stringify(value, null, 2)}
711
773
  `, { mode: 384, flag: "wx" });
712
- chmodSync(temp, 384);
774
+ chmodSync2(temp, 384);
713
775
  renameSync(temp, path);
714
776
  } finally {
715
- rmSync(temp, { force: true });
777
+ rmSync2(temp, { force: true });
716
778
  }
717
779
  }
718
780
  function activeRelay(env = process.env) {
@@ -787,7 +849,7 @@ function relayVerb(positionals, asJson, env = process.env) {
787
849
  }
788
850
  async function loginMain(positionals, values) {
789
851
  if (positionals.length) throw new RelayUsage(`${CLI_NAME3} login takes only flags`);
790
- return (await import("./login-AUMLI4FS.js")).login(values);
852
+ return (await import("./login-6MVD3VLC.js")).login(values);
791
853
  }
792
854
  function logoutMain(positionals, asJson, env = process.env) {
793
855
  if (positionals.length) throw new RelayUsage(`${CLI_NAME3} logout takes no arguments`);
@@ -802,6 +864,8 @@ function logoutMain(positionals, asJson, env = process.env) {
802
864
  export {
803
865
  shortHostname,
804
866
  detectHarness,
867
+ codexShell,
868
+ writeShimBinding,
805
869
  normalizeHarness,
806
870
  hookHarness,
807
871
  gitToplevel,
@@ -835,6 +899,7 @@ export {
835
899
  OPTIONS,
836
900
  SPAWN_OPTIONS,
837
901
  startDaemon,
902
+ terminalAttached,
838
903
  localHandle,
839
904
  walkNow,
840
905
  open,
@@ -5,7 +5,7 @@ import {
5
5
  configDir,
6
6
  relayCredential,
7
7
  writePrivateJson
8
- } from "./chunk-2LIJXXTL.js";
8
+ } from "./chunk-AAFHLHXG.js";
9
9
  import {
10
10
  note,
11
11
  printTable
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  hooksTarget
3
- } from "./chunk-VQU5CPE4.js";
3
+ } from "./chunk-2342GTME.js";
4
4
  import {
5
5
  AGY_HOOK_SET,
6
6
  BLOCK_STOP,
@@ -12,12 +12,12 @@ import {
12
12
  mergeHooks,
13
13
  musePlugin,
14
14
  opencodePlugin
15
- } from "./chunk-B2G3XTW7.js";
15
+ } from "./chunk-XQHPDNVG.js";
16
16
  import {
17
17
  RelayUsage,
18
18
  gitToplevel,
19
19
  setJoinMode
20
- } from "./chunk-2LIJXXTL.js";
20
+ } from "./chunk-AAFHLHXG.js";
21
21
 
22
22
  // src/setup.ts
23
23
  import { spawnSync } from "child_process";
@@ -13,7 +13,7 @@ import {
13
13
  psStart,
14
14
  relayIdentity,
15
15
  sessionKey
16
- } from "./chunk-2LIJXXTL.js";
16
+ } from "./chunk-AAFHLHXG.js";
17
17
 
18
18
  // src/hooks.ts
19
19
  import { Readable } from "stream";
@@ -3,16 +3,16 @@ import {
3
3
  mcpFile,
4
4
  mountedEntry,
5
5
  whichOnPath
6
- } from "./chunk-VW7DYSGM.js";
7
- import "./chunk-VQU5CPE4.js";
8
- import "./chunk-B2G3XTW7.js";
6
+ } from "./chunk-UKQBH4AQ.js";
7
+ import "./chunk-2342GTME.js";
8
+ import "./chunk-XQHPDNVG.js";
9
9
  import "./chunk-YYSLYVNZ.js";
10
10
  import {
11
11
  CHANNELS_ENV,
12
12
  RelayUsage,
13
13
  deriveHandle,
14
14
  joinMode
15
- } from "./chunk-2LIJXXTL.js";
15
+ } from "./chunk-AAFHLHXG.js";
16
16
  import "./chunk-MNTIEWKF.js";
17
17
 
18
18
  // src/claude.ts
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-STUKDZ5L.js");
20
+ const { run } = await import("./main-F2NFQ2KC.js");
21
21
  await run(process.argv.slice(2));
22
22
  }
@@ -3,18 +3,18 @@ import {
3
3
  codexMount,
4
4
  codexOverrides,
5
5
  toml
6
- } from "./chunk-HHVNSHGB.js";
6
+ } from "./chunk-7RA7E5WR.js";
7
7
  import "./chunk-KN7WEIE4.js";
8
- import "./chunk-VW7DYSGM.js";
9
- import "./chunk-VQU5CPE4.js";
10
- import "./chunk-B2G3XTW7.js";
8
+ import "./chunk-UKQBH4AQ.js";
9
+ import "./chunk-2342GTME.js";
10
+ import "./chunk-XQHPDNVG.js";
11
11
  import "./chunk-YYSLYVNZ.js";
12
12
  import {
13
13
  RelayUsage,
14
14
  readPsTable,
15
15
  relayIdentity,
16
16
  startDaemon
17
- } from "./chunk-2LIJXXTL.js";
17
+ } from "./chunk-AAFHLHXG.js";
18
18
  import {
19
19
  SELF
20
20
  } from "./chunk-MNTIEWKF.js";
@@ -29,7 +29,7 @@ import { join } from "path";
29
29
  import { PassThrough } from "stream";
30
30
  import { setTimeout as sleep } from "timers/promises";
31
31
  import { connectBroker, relayDir } from "@scp-dev/broker";
32
- import { CLI_NAME, validHandle } from "@scp-dev/core";
32
+ import { CLI_NAME, RelayError, validHandle } from "@scp-dev/core";
33
33
  import { MCP_PROTOCOLS, runRelayMcp } from "@scp-dev/mcp";
34
34
  import { parse } from "smol-toml";
35
35
  var CODEX_HELP = `${CLI_NAME} codex [--name N | --as N] [--headless] [--resume THREAD] [--] [codex args...]
@@ -61,13 +61,13 @@ function codexLaunch(args, env, _self) {
61
61
  }
62
62
  name = name?.replace(/^me\//, "");
63
63
  if (name !== void 0 && !validHandle(name)) throw new RelayUsage(`${JSON.stringify(name)} is not a valid agent handle`);
64
- const { SCP_SESSION: _session, SCP_GRANT: _grant, SCP_PARENT: _parent, ...clean } = env;
64
+ const { SCP_SESSION: _session, SCP_PARENT: _parent, ...clean } = env;
65
65
  return {
66
66
  ...name !== void 0 ? { name } : {},
67
67
  headless,
68
68
  ...resume !== void 0 ? { resume } : {},
69
69
  codexArgs: resume !== void 0 && !headless ? ["resume", resume, ...codexArgs] : codexArgs,
70
- env: { ...clean, SCP_HARNESS: "codex", ...name !== void 0 ? { SCP_NAME: name } : {} }
70
+ env: { ...clean, SCP_HARNESS: "codex", SCP_SHIM_BINDING: randomBytes(16).toString("hex"), ...name !== void 0 ? { SCP_NAME: name } : {} }
71
71
  };
72
72
  }
73
73
  var CodexSocket = class {
@@ -398,6 +398,24 @@ function appServerPid(pid) {
398
398
  }
399
399
  return pid;
400
400
  }
401
+ async function connectCodexChannel(connect2, claim, cwd, stopped) {
402
+ while (!stopped()) {
403
+ const client = await connect2();
404
+ try {
405
+ const hello = await client.hello({ observe: true, self: [claim.process], ...claim.grant ? { grant: claim.grant } : {}, cwd });
406
+ if (hello.endpoint) {
407
+ client.hello = async () => hello;
408
+ return client;
409
+ }
410
+ } catch (error) {
411
+ client.close();
412
+ if (!claim.grant || !(error instanceof RelayError) || error.code !== "unauthorized") throw error;
413
+ }
414
+ client.close();
415
+ await sleep(100);
416
+ }
417
+ throw new Error("codex channel stopped");
418
+ }
401
419
  async function codexCommand(args) {
402
420
  if (args[0] === "--help" || args[0] === "-h") {
403
421
  process.stdout.write(`${CODEX_HELP}
@@ -514,24 +532,12 @@ ${stderr.toString().trim()}` : ""}`
514
532
  const broker = relayDir(launch.env);
515
533
  let lines = "";
516
534
  channel = runRelayMcp({
517
- connect: async () => {
518
- while (!input.writableEnded) {
519
- const client = await connectBroker(broker, () => startDaemon(broker));
520
- try {
521
- const hello = await client.hello({ observe: true, self: [claim.process], cwd });
522
- if (hello.endpoint) {
523
- client.hello = async () => hello;
524
- return client;
525
- }
526
- } catch (error) {
527
- client.close();
528
- throw error;
529
- }
530
- client.close();
531
- await sleep(100);
532
- }
533
- throw new Error("codex channel stopped");
534
- },
535
+ connect: () => connectCodexChannel(
536
+ () => connectBroker(broker, () => startDaemon(broker)),
537
+ claim,
538
+ cwd,
539
+ () => input.writableEnded
540
+ ),
535
541
  claim,
536
542
  channels: true,
537
543
  wake: "codex-app-server",
@@ -611,5 +617,6 @@ export {
611
617
  CodexWaker,
612
618
  codexCommand,
613
619
  codexLaunch,
620
+ connectCodexChannel,
614
621
  serverOptions
615
622
  };
@@ -40,11 +40,11 @@ import {
40
40
  tldrEvery,
41
41
  transcriptTitle,
42
42
  unreadPointer
43
- } from "./chunk-B2G3XTW7.js";
43
+ } from "./chunk-XQHPDNVG.js";
44
44
  import {
45
45
  SUBAGENT
46
46
  } from "./chunk-YYSLYVNZ.js";
47
- import "./chunk-2LIJXXTL.js";
47
+ import "./chunk-AAFHLHXG.js";
48
48
  import "./chunk-MNTIEWKF.js";
49
49
  export {
50
50
  AGY_HOOK_SET,
@@ -2,10 +2,10 @@ import {
2
2
  hooksTarget,
3
3
  installHooks,
4
4
  mcpInstall
5
- } from "./chunk-VQU5CPE4.js";
6
- import "./chunk-B2G3XTW7.js";
5
+ } from "./chunk-2342GTME.js";
6
+ import "./chunk-XQHPDNVG.js";
7
7
  import "./chunk-YYSLYVNZ.js";
8
- import "./chunk-2LIJXXTL.js";
8
+ import "./chunk-AAFHLHXG.js";
9
9
  import "./chunk-MNTIEWKF.js";
10
10
  export {
11
11
  hooksTarget,
@@ -1,12 +1,13 @@
1
1
  import {
2
2
  RelayUsage,
3
+ codexShell,
3
4
  harnessAt,
4
5
  localHandle,
5
6
  relayIdentity,
6
7
  sessionKey,
7
8
  startDaemon,
8
9
  walkNow
9
- } from "./chunk-2LIJXXTL.js";
10
+ } from "./chunk-AAFHLHXG.js";
10
11
  import "./chunk-MNTIEWKF.js";
11
12
 
12
13
  // src/join.ts
@@ -18,7 +19,10 @@ async function joinCommand(values, positionals, cwd, out) {
18
19
  const { keys, self } = walkNow();
19
20
  const key = self.at(-1);
20
21
  const match = key === void 0 ? null : /^pid:(\d+):(.+)$/.exec(key);
21
- if (!match) throw new RelayUsage(`${CLI_NAME} join runs in an agent session's shell: no harness process runs this shell`);
22
+ if (!match) {
23
+ if (codexShell(process.env)) throw new RelayUsage(`${CLI_NAME} join: the codex sandbox hides the harness; use relay_join (MCP) instead`);
24
+ throw new RelayUsage(`${CLI_NAME} join runs in an agent session's shell: no harness process runs this shell`);
25
+ }
22
26
  const dir = relayDir();
23
27
  const known = readSessionMarker(dir, sessionKey(process.env, key))?.handle;
24
28
  const claim = relayIdentity({
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  machineName
3
- } from "./chunk-IEFXYBX7.js";
3
+ } from "./chunk-H2XQXMZU.js";
4
4
  import {
5
5
  RelayUsage,
6
6
  activeRelay,
7
7
  saveCredential
8
- } from "./chunk-2LIJXXTL.js";
8
+ } from "./chunk-AAFHLHXG.js";
9
9
  import {
10
10
  note
11
11
  } from "./chunk-MNTIEWKF.js";
@@ -14,8 +14,9 @@ import {
14
14
  shortHostname,
15
15
  stamp,
16
16
  startDaemon,
17
+ terminalAttached,
17
18
  time
18
- } from "./chunk-2LIJXXTL.js";
19
+ } from "./chunk-AAFHLHXG.js";
19
20
  import {
20
21
  FAILED,
21
22
  exitFlushed,
@@ -34,7 +35,7 @@ import { parseArgs } from "util";
34
35
  // package.json
35
36
  var package_default = {
36
37
  name: "@scp-dev/cli",
37
- version: "0.4.0",
38
+ version: "0.5.0",
38
39
  description: "The swarm command line tool.",
39
40
  license: "Apache-2.0",
40
41
  homepage: "https://scp.dev",
@@ -105,6 +106,8 @@ results back, as with native subagents.
105
106
  ${CLI_NAME} list [--all] agents on the relay: address, title, presence, wake, status; --all adds offline ones
106
107
  ${CLI_NAME} join [name] put this session on the relay, named once: ${CLI_NAME} join lead (${CLI_NAME} name renames it)
107
108
  ${CLI_NAME} join --under <parent> link this session under an orchestrator, as a spawned worker sits: ${CLI_NAME} join --under lead
109
+ ${CLI_NAME} adopt <child> ask a local root agent to link under you; it accepts with ${CLI_NAME} link accept <id>
110
+ ${CLI_NAME} link accept <id> accept a link request and sit under its sender as a worker
108
111
  ${CLI_NAME} status [id] the fleet in short; with the id of a message you sent: who read it when
109
112
  ${CLI_NAME} peek <ep> a short, redacted view of a peekable agent's last turns: ${CLI_NAME} peek rev
110
113
  ${CLI_NAME} set-status <state> [note] working, waiting, blocked or done: ${CLI_NAME} set-status done "PR open"
@@ -295,8 +298,11 @@ agent sessions:
295
298
  each other both ways
296
299
  ${CLI_NAME} adopt <child> [--parent <p>] link a local root agent and its subtree under <p>, for the human at a terminal;
297
300
  <p> may be on another machine of the account (me/<machine>/<handle>).
298
- From an agent's shell with a terminal attached <p> defaults to that agent.
299
- An agent without a terminal is refused: the session joins with --under itself
301
+ With --parent and a terminal, inherited $SCP_NAME and $SCP_GRANT are ignored
302
+ unless --as is explicit. An agent without a terminal asks the child to consent,
303
+ under itself only; the child accepts with link accept or join --under
304
+ ${CLI_NAME} link accept <id> accept a link request delivered to this session and sit under its sender as a worker;
305
+ <id> is the full or short message id. Only the session itself may accept
300
306
  ${CLI_NAME} unlink [<child>] put a linked agent back at the root, its subtree along and the child scope off;
301
307
  widening, so the human at a terminal only (policy defaults.unlink: self lets
302
308
  an agent unlink itself). A link that would put a parent under its own child
@@ -387,6 +393,7 @@ var VERBS = {
387
393
  send: [...IDENTITY, "reply-to", "thread", "private", "attach", "live"],
388
394
  join: ["harness", "json", "under"],
389
395
  adopt: [...IDENTITY, "parent"],
396
+ link: IDENTITY,
390
397
  unlink: IDENTITY,
391
398
  leave: [...IDENTITY, "endpoint"],
392
399
  name: [...IDENTITY, "endpoint"],
@@ -562,14 +569,14 @@ async function relayMain(argv, cwd = process.cwd()) {
562
569
  out(cliVersion());
563
570
  return 0;
564
571
  }
565
- if (verb === "hook") return (await import("./hooks-ISZTCOLZ.js")).relayHookCommand(rest, startDaemon);
566
- if (verb === "setup") return (await import("./setup-R5SNWVVF.js")).relaySetupCommand(rest, cwd, out);
567
- if (verb === "claude") return (await import("./claude-L2I5ZM2B.js")).claudeCommand(rest);
568
- if (verb === "pi") return (await import("./pi-QEZVFDNR.js")).piCommand(rest);
569
- if (verb === "codex") return (await import("./codex-4WPBAFAT.js")).codexCommand(rest);
570
- if (verb === "opencode") return (await import("./opencode-WFP57BZD.js")).opencodeCommand(rest, process.env, void 0, cwd);
572
+ if (verb === "hook") return (await import("./hooks-BZANUJPY.js")).relayHookCommand(rest, startDaemon);
573
+ if (verb === "setup") return (await import("./setup-UJCIMYU4.js")).relaySetupCommand(rest, cwd, out);
574
+ if (verb === "claude") return (await import("./claude-RNH2E4GU.js")).claudeCommand(rest);
575
+ if (verb === "pi") return (await import("./pi-N3DX37PD.js")).piCommand(rest);
576
+ if (verb === "codex") return (await import("./codex-OSGHQMK6.js")).codexCommand(rest);
577
+ if (verb === "opencode") return (await import("./opencode-XV33XTL5.js")).opencodeCommand(rest, process.env, void 0, cwd);
571
578
  if (verb === "spawn") {
572
- const { splitSpawn, spawnCommand } = await import("./spawn-WJYOTAKI.js");
579
+ const { splitSpawn, spawnCommand } = await import("./spawn-JYD7NCQT.js");
573
580
  const { flags } = splitSpawn(rest);
574
581
  if (flags.includes("--help") || flags.includes("-h")) {
575
582
  out(flags.includes("--all") ? RELAY_HELP : SPAWN_HELP);
@@ -577,7 +584,7 @@ async function relayMain(argv, cwd = process.cwd()) {
577
584
  }
578
585
  return spawnCommand(rest, cwd);
579
586
  }
580
- if (verb === "mesh") return (await import("./mesh-UG6VO7ZO.js")).meshCommand(rest);
587
+ if (verb === "mesh") return (await import("./mesh-OZILTV5P.js")).meshCommand(rest);
581
588
  const allowed = VERBS[verb];
582
589
  if (!allowed) throw new RelayUsage(`unknown command "${verb}"`);
583
590
  let parsed;
@@ -597,11 +604,11 @@ async function relayMain(argv, cwd = process.cwd()) {
597
604
  return daemon(values.idle, values.policy);
598
605
  }
599
606
  if (verb === "mcp")
600
- return (await import("./mcp-J2CL6A4R.js")).relayMcpCommand(values, positionals);
607
+ return (await import("./mcp-BH526TOG.js")).relayMcpCommand(values, positionals);
601
608
  if (verb === "hooks") {
602
609
  if (positionals[0] !== "install" || positionals.length > 1) throw new RelayUsage(`${CLI_NAME} hooks takes install --harness claude|codex|opencode|agy|muse`);
603
610
  if (values.write && values.print) throw new RelayUsage("--print and --write: pick one");
604
- return (await import("./install-SDLWXW32.js")).installHooks({
611
+ return (await import("./install-25J5QB63.js")).installHooks({
605
612
  harness: values.harness,
606
613
  scope: values.scope,
607
614
  write: values.write === true,
@@ -612,31 +619,48 @@ async function relayMain(argv, cwd = process.cwd()) {
612
619
  out
613
620
  });
614
621
  }
615
- if (verb === "relay") return (await import("./relay-QWJM372C.js")).relayVerb(positionals, values.json === true);
616
- if (verb === "up") return (await import("./up-UWV5BQUH.js")).up(positionals, values, cwd, relinkBroker);
622
+ if (verb === "relay") return (await import("./relay-SF3UWIPM.js")).relayVerb(positionals, values.json === true);
623
+ if (verb === "up") return (await import("./up-3YJU7YX6.js")).up(positionals, values, cwd, relinkBroker);
617
624
  if (verb === "login") {
618
- const code = await (await import("./relay-QWJM372C.js")).loginMain(positionals, values);
625
+ const code = await (await import("./relay-SF3UWIPM.js")).loginMain(positionals, values);
619
626
  if (code === 0) await relinkRunning();
620
627
  return code;
621
628
  }
622
- if (verb === "logout") return (await import("./relay-QWJM372C.js")).logoutMain(positionals, values.json === true);
629
+ if (verb === "logout") return (await import("./relay-SF3UWIPM.js")).logoutMain(positionals, values.json === true);
623
630
  if (verb === "cloud") {
624
- const code = await (await import("./remote-P4GFUIAP.js")).cloudMain(positionals, values, cloudStatus);
631
+ const code = await (await import("./remote-UQJ5YYCC.js")).cloudMain(positionals, values, cloudStatus);
625
632
  if (code === 0 && positionals[0] === "enable") await relinkRunning();
626
633
  return code;
627
634
  }
628
- if (verb === "join") return (await import("./join-FITJVZCA.js")).joinCommand(values, positionals, cwd, out);
635
+ if (verb === "join") return (await import("./join-EOLHE3LJ.js")).joinCommand(values, positionals, cwd, out);
629
636
  if (verb === "holds") holdsArgs(values, positionals);
630
637
  const bodyFromStdin = (verb === "send" || verb === "ask" || verb === "reply") && (positionals[1] === void 0 || positionals[1] === "-");
631
- const opened = await open(verb, values, cwd, bodyFromStdin);
638
+ const humanAdopt = verb === "adopt" && values.parent !== void 0 && values.as === void 0 && terminalAttached(process, false);
639
+ const opened = humanAdopt ? await openAdoptHuman(cwd, values) : await open(verb, values, cwd, bodyFromStdin);
632
640
  const { client } = opened;
633
641
  try {
634
- if (verb === "machines") return await (await import("./remote-P4GFUIAP.js")).machinesVerb(client, positionals, values.json === true);
642
+ if (verb === "machines") return await (await import("./remote-UQJ5YYCC.js")).machinesVerb(client, positionals, values.json === true);
635
643
  return await runVerb(opened, verb, values, positionals, cwd);
636
644
  } finally {
637
645
  client.close();
638
646
  }
639
647
  }
648
+ async function openAdoptHuman(cwd, values) {
649
+ if (values.cloud || process.env.SCP_TRANSPORT === "cloud") {
650
+ const { openCloud } = await import("./remote-UQJ5YYCC.js");
651
+ return { ...await openCloud({ tty: true, ...values.machine !== void 0 ? { machine: values.machine } : {} }), broker: null, bound: "human" };
652
+ }
653
+ if (values.machine !== void 0) throw new RelayUsage("--machine names the machine of the cloud transport: add --cloud");
654
+ const dir = relayDir();
655
+ const client = await connectBroker(dir, () => startDaemon(dir));
656
+ try {
657
+ const hello = await client.hello({ human: true, tty: true, cwd, brief: true });
658
+ return { client, me: hello.endpoint, broker: hello.broker, where: brokerLine(hello.broker), bound: "human" };
659
+ } catch (error) {
660
+ client.close();
661
+ throw error;
662
+ }
663
+ }
640
664
  async function cloudStatus() {
641
665
  const dir = relayDir();
642
666
  const client = await connectBroker(dir, () => startDaemon(dir));
@@ -808,9 +832,9 @@ async function runVerb({ client, me, broker, where, bound, harnessPid }, verb, v
808
832
  return 0;
809
833
  }
810
834
  case "peek":
811
- return (await import("./peek-YTCWVPF7.js")).peekCommand(localClient(client, broker, verb), values, positionals);
835
+ return (await import("./peek-LFQR6TCS.js")).peekCommand(localClient(client, broker, verb), values, positionals);
812
836
  case "set-peek":
813
- return (await import("./peek-YTCWVPF7.js")).setPeekCommand(localClient(client, broker, verb), values, positionals);
837
+ return (await import("./peek-LFQR6TCS.js")).setPeekCommand(localClient(client, broker, verb), values, positionals);
814
838
  case "why": {
815
839
  const [from, to] = positionals;
816
840
  if (!from || !to || positionals.length > 2) throw new RelayUsage(`${CLI_NAME} why takes <from> <to>`);
@@ -1049,6 +1073,16 @@ async function runVerb({ client, me, broker, where, bound, harnessPid }, verb, v
1049
1073
  ...parent !== void 0 ? { parent } : {}
1050
1074
  });
1051
1075
  if (asJson) json(result);
1076
+ else if (result.held) out(heldText(result.held));
1077
+ else if (result.requested)
1078
+ out(`asked ${result.endpoint.address} to link under ${result.parent}; it accepts with ${CLI_NAME} link accept ${shortId(result.requested)}`);
1079
+ else out(`${result.endpoint.address} now sits under ${result.parent}`);
1080
+ return 0;
1081
+ }
1082
+ case "link": {
1083
+ if (positionals.length !== 2 || positionals[0] !== "accept") throw new RelayUsage(`${CLI_NAME} link takes accept <id>`);
1084
+ const result = await client.request("link_accept", { id: positionals[1] });
1085
+ if (asJson) json(result);
1052
1086
  else out(`${result.endpoint.address} now sits under ${result.parent}`);
1053
1087
  return 0;
1054
1088
  }
@@ -1420,11 +1454,11 @@ async function daemon(idle, policyFile) {
1420
1454
  });
1421
1455
  let broker;
1422
1456
  try {
1423
- const { daemonBridge } = await import("./remote-P4GFUIAP.js");
1457
+ const { daemonBridge } = await import("./remote-UQJ5YYCC.js");
1424
1458
  const bridge = await daemonBridge();
1425
1459
  broker = await startBroker({
1426
1460
  dir: relayDir(),
1427
- ...bridge ? { bridge } : await (await import("./mesh-UG6VO7ZO.js")).meshBrokerOptions(),
1461
+ ...bridge ? { bridge } : await (await import("./mesh-OZILTV5P.js")).meshBrokerOptions(),
1428
1462
  bridgeConfig: () => daemonBridge(),
1429
1463
  ...idleMs !== void 0 ? { idleMs } : {},
1430
1464
  ...policyFile ? { policyPath: resolve(policyFile) } : {}
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  spawnDetached
3
- } from "./chunk-HHVNSHGB.js";
3
+ } from "./chunk-7RA7E5WR.js";
4
4
  import "./chunk-KN7WEIE4.js";
5
- import "./chunk-VW7DYSGM.js";
5
+ import "./chunk-UKQBH4AQ.js";
6
6
  import {
7
7
  mcpInstall
8
- } from "./chunk-VQU5CPE4.js";
9
- import "./chunk-B2G3XTW7.js";
8
+ } from "./chunk-2342GTME.js";
9
+ import "./chunk-XQHPDNVG.js";
10
10
  import "./chunk-YYSLYVNZ.js";
11
11
  import {
12
12
  CHANNELS_ENV,
@@ -16,14 +16,15 @@ import {
16
16
  membership,
17
17
  psParent,
18
18
  relayIdentity,
19
- startDaemon
20
- } from "./chunk-2LIJXXTL.js";
19
+ startDaemon,
20
+ writeShimBinding
21
+ } from "./chunk-AAFHLHXG.js";
21
22
  import "./chunk-MNTIEWKF.js";
22
23
 
23
24
  // src/mcp.ts
24
25
  import { CLI_NAME, validHandle } from "@scp-dev/core";
25
26
  import { connectBroker, relayDir } from "@scp-dev/broker";
26
- import { runRelayMcp } from "@scp-dev/mcp";
27
+ import { runRelayMcp, sessionInboxOf } from "@scp-dev/mcp";
27
28
  var ORPHAN_CHECK_MS = 5e3;
28
29
  async function relayMcpCommand(values, positionals) {
29
30
  if (positionals[0] === "install") {
@@ -43,25 +44,35 @@ async function relayMcpCommand(values, positionals) {
43
44
  inferHarness: (pid) => harnessAt(pid)
44
45
  });
45
46
  if (!validHandle(claim.handle)) throw new RelayUsage(`${JSON.stringify(claim.handle)} is not a valid agent handle (me, user and relay are reserved)`);
46
- const dir = relayDir();
47
+ const dir = relayDir(process.env);
48
+ const unbind = writeShimBinding(claim, process.env);
49
+ process.on("exit", unbind);
47
50
  const parent = process.ppid;
48
51
  const orphaned = setInterval(() => {
49
52
  if (process.ppid !== parent) process.exit(0);
50
53
  }, ORPHAN_CHECK_MS);
51
54
  orphaned.unref();
52
- await runRelayMcp({
53
- connect: () => connectBroker(dir, () => startDaemon(dir)),
54
- claim,
55
- membership: () => membership(process.env, claim.session),
56
- input: process.stdin,
57
- output: (line) => void process.stdout.write(line),
58
- env: process.env,
59
- channels: values.channels === true,
60
- launchedWithChannels: values.channels === true && launchedWithChannels(process.env),
61
- spawn: (request) => spawnDetached(spawnWords(request), request.cwd ?? claim.cwd),
62
- log: (line) => void process.stderr.write(`${line}
55
+ const inbox = sessionInboxOf(process.env);
56
+ try {
57
+ await runRelayMcp({
58
+ connect: () => connectBroker(dir, () => startDaemon(dir)),
59
+ claim,
60
+ membership: () => membership(process.env, claim.session),
61
+ input: process.stdin,
62
+ output: (line) => void process.stdout.write(line),
63
+ env: process.env,
64
+ channels: values.channels === true,
65
+ launchedWithChannels: values.channels === true && launchedWithChannels(process.env),
66
+ ...inbox ? { sessionInbox: inbox } : {},
67
+ spawn: (request) => spawnDetached(spawnWords(request), request.cwd ?? claim.cwd),
68
+ log: (line) => void process.stderr.write(`${line}
63
69
  `)
64
- });
70
+ });
71
+ } finally {
72
+ clearInterval(orphaned);
73
+ process.off("exit", unbind);
74
+ unbind();
75
+ }
65
76
  return 0;
66
77
  }
67
78
  function spawnWords(request) {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  RelayUsage
3
- } from "./chunk-2LIJXXTL.js";
3
+ } from "./chunk-AAFHLHXG.js";
4
4
  import "./chunk-MNTIEWKF.js";
5
5
 
6
6
  // src/mesh.ts
@@ -2,18 +2,18 @@ import {
2
2
  mcpFile,
3
3
  mountedEntry,
4
4
  whichOnPath
5
- } from "./chunk-VW7DYSGM.js";
5
+ } from "./chunk-UKQBH4AQ.js";
6
6
  import {
7
7
  hooksTarget
8
- } from "./chunk-VQU5CPE4.js";
8
+ } from "./chunk-2342GTME.js";
9
9
  import {
10
10
  opencodePlugin
11
- } from "./chunk-B2G3XTW7.js";
11
+ } from "./chunk-XQHPDNVG.js";
12
12
  import "./chunk-YYSLYVNZ.js";
13
13
  import {
14
14
  RelayUsage,
15
15
  gitToplevel
16
- } from "./chunk-2LIJXXTL.js";
16
+ } from "./chunk-AAFHLHXG.js";
17
17
  import "./chunk-MNTIEWKF.js";
18
18
 
19
19
  // src/opencode.ts
@@ -2,7 +2,7 @@ import {
2
2
  RelayUsage,
3
3
  peekGrant,
4
4
  stamp
5
- } from "./chunk-2LIJXXTL.js";
5
+ } from "./chunk-AAFHLHXG.js";
6
6
  import {
7
7
  note
8
8
  } from "./chunk-MNTIEWKF.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  RelayUsage
3
- } from "./chunk-2LIJXXTL.js";
3
+ } from "./chunk-AAFHLHXG.js";
4
4
  import "./chunk-MNTIEWKF.js";
5
5
 
6
6
  // src/pi.ts
@@ -13,7 +13,7 @@ import {
13
13
  saveCredential,
14
14
  setJoinMode,
15
15
  writePrivateJson
16
- } from "./chunk-2LIJXXTL.js";
16
+ } from "./chunk-AAFHLHXG.js";
17
17
  import "./chunk-MNTIEWKF.js";
18
18
  export {
19
19
  DEFAULT_RELAY,
@@ -9,8 +9,8 @@ import {
9
9
  machinesVerb,
10
10
  openCloud,
11
11
  readCloudFile
12
- } from "./chunk-IEFXYBX7.js";
13
- import "./chunk-2LIJXXTL.js";
12
+ } from "./chunk-H2XQXMZU.js";
13
+ import "./chunk-AAFHLHXG.js";
14
14
  import "./chunk-MNTIEWKF.js";
15
15
  export {
16
16
  CloudRelayClient,
@@ -15,11 +15,11 @@ import {
15
15
  verifyMount,
16
16
  verifyMusePlugin,
17
17
  whichOnPath
18
- } from "./chunk-VW7DYSGM.js";
19
- import "./chunk-VQU5CPE4.js";
20
- import "./chunk-B2G3XTW7.js";
18
+ } from "./chunk-UKQBH4AQ.js";
19
+ import "./chunk-2342GTME.js";
20
+ import "./chunk-XQHPDNVG.js";
21
21
  import "./chunk-YYSLYVNZ.js";
22
- import "./chunk-2LIJXXTL.js";
22
+ import "./chunk-AAFHLHXG.js";
23
23
  import "./chunk-MNTIEWKF.js";
24
24
  export {
25
25
  SETUP_HARNESSES,
@@ -31,15 +31,15 @@ import {
31
31
  toml,
32
32
  transcriptReplies,
33
33
  workerName
34
- } from "./chunk-HHVNSHGB.js";
34
+ } from "./chunk-7RA7E5WR.js";
35
35
  import {
36
36
  SPAWN_HELP
37
37
  } from "./chunk-KN7WEIE4.js";
38
- import "./chunk-VW7DYSGM.js";
39
- import "./chunk-VQU5CPE4.js";
40
- import "./chunk-B2G3XTW7.js";
38
+ import "./chunk-UKQBH4AQ.js";
39
+ import "./chunk-2342GTME.js";
40
+ import "./chunk-XQHPDNVG.js";
41
41
  import "./chunk-YYSLYVNZ.js";
42
- import "./chunk-2LIJXXTL.js";
42
+ import "./chunk-AAFHLHXG.js";
43
43
  import "./chunk-MNTIEWKF.js";
44
44
  export {
45
45
  CODEX_VALUED,
@@ -2,7 +2,7 @@ import {
2
2
  RelayUsage,
3
3
  activeRelay,
4
4
  relayCredential
5
- } from "./chunk-2LIJXXTL.js";
5
+ } from "./chunk-AAFHLHXG.js";
6
6
  import "./chunk-MNTIEWKF.js";
7
7
 
8
8
  // src/up.ts
@@ -29,21 +29,21 @@ async function up(positionals, values, cwd, brokerStatus) {
29
29
  const { url } = activeRelay(process.env);
30
30
  const headless = values.token !== void 0 || Boolean(process.env.SCP_TOKEN?.trim());
31
31
  if (headless || !relayCredential(process.env, url).token) {
32
- const code = await (await import("./login-AUMLI4FS.js")).login({
32
+ const code = await (await import("./login-6MVD3VLC.js")).login({
33
33
  ...values.token !== void 0 ? { token: values.token } : {},
34
34
  ...values.label !== void 0 ? { label: values.label } : {},
35
35
  ...values["no-browser"] ? { "no-browser": true } : {}
36
36
  });
37
37
  if (code !== 0) return code;
38
38
  } else out(`already logged in to ${url}`);
39
- const enabled = await (await import("./remote-P4GFUIAP.js")).cloudMain(["enable"], values.machine !== void 0 ? { machine: values.machine } : {}, brokerStatus);
39
+ const enabled = await (await import("./remote-UQJ5YYCC.js")).cloudMain(["enable"], values.machine !== void 0 ? { machine: values.machine } : {}, brokerStatus);
40
40
  if (enabled !== 0) return enabled;
41
- const setup = (await import("./setup-R5SNWVVF.js")).relaySetupCommand(["--write"], cwd, out);
41
+ const setup = (await import("./setup-UJCIMYU4.js")).relaySetupCommand(["--write"], cwd, out);
42
42
  if (setup !== 0) return setup;
43
43
  const broker = await brokerStatus();
44
44
  if (!broker.enabled) out(`the broker is still local-only; run \`${CLI_NAME} daemon restart\` to link it to ${url}`);
45
45
  else out(`broker linked to ${broker.url ?? url}${broker.connected ? "" : " (connecting)"}`);
46
- const { detectHarnesses, whichOnPath } = await import("./setup-R5SNWVVF.js");
46
+ const { detectHarnesses, whichOnPath } = await import("./setup-UJCIMYU4.js");
47
47
  const which = (name) => whichOnPath(name, process.env);
48
48
  const installed = new Set(detectHarnesses(process.env, which).keys());
49
49
  if (which("pi")) installed.add("pi");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scp-dev/cli",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "The swarm command line tool.",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://scp.dev",
@@ -24,15 +24,15 @@
24
24
  "typecheck": "tsc -p ."
25
25
  },
26
26
  "dependencies": {
27
- "@scp-dev/core": "0.2.0",
28
- "@scp-dev/broker": "0.3.0",
29
- "@scp-dev/hub": "0.6.0",
30
- "@scp-dev/mcp": "0.1.9",
27
+ "@scp-dev/core": "0.3.0",
28
+ "@scp-dev/broker": "0.4.0",
29
+ "@scp-dev/hub": "0.6.1",
30
+ "@scp-dev/mcp": "0.2.0",
31
31
  "smol-toml": "^1.9.1"
32
32
  },
33
33
  "devDependencies": {
34
34
  "@openai/codex": "0.159.0",
35
- "@scp-dev/mesh": "0.0.6",
35
+ "@scp-dev/mesh": "0.0.7",
36
36
  "opencode-ai": "1.18.34",
37
37
  "tsup": "^8.5.1"
38
38
  },