@scp-dev/cli 0.5.0 → 0.7.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 (29) hide show
  1. package/dist/{chunk-XQHPDNVG.js → chunk-277BAY7J.js} +23 -3
  2. package/dist/{chunk-AAFHLHXG.js → chunk-3SOIVANO.js} +49 -4
  3. package/dist/{chunk-2342GTME.js → chunk-LRQP25RI.js} +2 -2
  4. package/dist/{chunk-H2XQXMZU.js → chunk-LUDLDWH2.js} +1 -1
  5. package/dist/{codex-OSGHQMK6.js → chunk-LWMTZH36.js} +6 -10
  6. package/dist/{chunk-7RA7E5WR.js → chunk-RZUQ422C.js} +14 -6
  7. package/dist/{chunk-UKQBH4AQ.js → chunk-SNW53KT3.js} +3 -3
  8. package/dist/claude-WEHOLJ26.js +290 -0
  9. package/dist/cli.js +1 -1
  10. package/dist/codex-54UWPDY5.js +26 -0
  11. package/dist/{hooks-BZANUJPY.js → hooks-ULKKUHPF.js} +6 -2
  12. package/dist/{install-25J5QB63.js → install-5A3ETGF6.js} +3 -3
  13. package/dist/{join-EOLHE3LJ.js → join-FFT7RQRW.js} +1 -1
  14. package/dist/{login-6MVD3VLC.js → login-DCNCC3RS.js} +2 -2
  15. package/dist/{main-F2NFQ2KC.js → main-CDLW3MV5.js} +45 -26
  16. package/dist/{mcp-BH526TOG.js → mcp-7GB35CTY.js} +7 -6
  17. package/dist/{mesh-OZILTV5P.js → mesh-TDOVAHZ3.js} +1 -1
  18. package/dist/muse-S7FPY4CL.js +429 -0
  19. package/dist/{opencode-XV33XTL5.js → opencode-WFMQYCI2.js} +4 -4
  20. package/dist/{peek-LFQR6TCS.js → peek-X4QQFMQJ.js} +1 -1
  21. package/dist/{pi-N3DX37PD.js → pi-5IPU6GA4.js} +1 -1
  22. package/dist/{relay-SF3UWIPM.js → relay-7WBNUACH.js} +1 -1
  23. package/dist/{remote-UQJ5YYCC.js → remote-YO5B2HQI.js} +2 -2
  24. package/dist/resume-3ZRDXSTX.js +308 -0
  25. package/dist/{setup-UJCIMYU4.js → setup-U7CWN5QP.js} +4 -4
  26. package/dist/{spawn-JYD7NCQT.js → spawn-VZK5MD3R.js} +13 -5
  27. package/dist/{up-3YJU7YX6.js → up-S4KJBWI6.js} +8 -6
  28. package/package.json +6 -6
  29. package/dist/claude-RNH2E4GU.js +0 -130
@@ -13,11 +13,11 @@ import {
13
13
  psStart,
14
14
  relayIdentity,
15
15
  sessionKey
16
- } from "./chunk-AAFHLHXG.js";
16
+ } from "./chunk-3SOIVANO.js";
17
17
 
18
18
  // src/hooks.ts
19
19
  import { Readable } from "stream";
20
- import { closeSync, fstatSync, openSync, readFileSync, readSync, writeSync } from "fs";
20
+ import { closeSync, fstatSync, openSync, readFileSync, readSync, writeFileSync, writeSync } from "fs";
21
21
  import { homedir } from "os";
22
22
  import { basename, join } from "path";
23
23
  import {
@@ -304,7 +304,9 @@ function titleText(text) {
304
304
  return line || void 0;
305
305
  }
306
306
  function promptTitle(prompt) {
307
- return titleText(prompt?.split("\n").find((line) => line.trim()));
307
+ const first = prompt?.split("\n").find((line) => line.trim());
308
+ if (first?.startsWith(PREAMBLE) || first?.startsWith(PREAMBLE_BRIEF)) return void 0;
309
+ return titleText(first);
308
310
  }
309
311
  function transcriptTitle(path, session) {
310
312
  if (!path || !session || !path.startsWith("/") || !path.endsWith(`/${session}.jsonl`)) return void 0;
@@ -409,6 +411,17 @@ function tldrEvery(env) {
409
411
  return raw && /^\d{1,6}$/.test(raw) ? Number(raw) : TLDR_EVERY_DEFAULT;
410
412
  }
411
413
  var NUDGE = `${CLI_NAME} (optional): a title and a one-line now (relay_set_title / relay_set_now) help peers find you; skip it when you only run workers.`;
414
+ var AGY_CONVERSATION = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/;
415
+ function recordAgyConversation(payload, env) {
416
+ const file = env.SCP_AGY_CONVERSATION_FILE;
417
+ if (!file || field(payload, "parentConversationId", "parent_conversation_id") !== void 0) return;
418
+ const id = asString(field(payload, "conversationId", "conversation_id")) ?? env.ANTIGRAVITY_CONVERSATION_ID;
419
+ if (!id || !AGY_CONVERSATION.test(id)) return;
420
+ try {
421
+ writeFileSync(file, id, { flag: "wx", mode: 384 });
422
+ } catch {
423
+ }
424
+ }
412
425
  async function runHook(args, options) {
413
426
  const began = Date.now();
414
427
  const blockStop = args.includes(BLOCK_STOP);
@@ -427,6 +440,7 @@ async function runHook(args, options) {
427
440
  } catch {
428
441
  payload = {};
429
442
  }
443
+ if (harnessArg === "agy") recordAgyConversation(payload, options.env);
430
444
  if (Number.isFinite(wakeS) && wakeS > 0) return wakeHook(harnessArg, payload, wakeS, options);
431
445
  const event = mapHookPayload(payload, eventArg);
432
446
  if (!event || options.env.SCP_TRANSPORT === "cloud") return;
@@ -445,8 +459,10 @@ async function runHook(args, options) {
445
459
  )
446
460
  );
447
461
  if ("dark" in joined) return;
462
+ const harnessSession = event.agent ? void 0 : asString(field(payload, "session_id", "sessionId"));
448
463
  const claim = relayIdentity({
449
464
  ...joined.handle ? { as: joined.handle } : {},
465
+ ...harnessSession ? { harnessSession } : {},
450
466
  harness,
451
467
  fallbackHarness: "hook",
452
468
  cwd: event.cwd ?? options.cwd,
@@ -556,8 +572,10 @@ async function wakeHook(harnessArg, payload, waitS, options) {
556
572
  )
557
573
  );
558
574
  if ("dark" in joined) return;
575
+ const harnessSession = asString(field(payload, "session_id", "sessionId"));
559
576
  const claim = relayIdentity({
560
577
  ...joined.handle ? { as: joined.handle } : {},
578
+ ...harnessSession ? { harnessSession } : {},
561
579
  harness,
562
580
  fallbackHarness: "hook",
563
581
  cwd: asString(payload.cwd) ?? options.cwd,
@@ -1034,6 +1052,8 @@ export {
1034
1052
  TLDR_EVERY_DEFAULT,
1035
1053
  TLDR,
1036
1054
  tldrEvery,
1055
+ AGY_CONVERSATION,
1056
+ recordAgyConversation,
1037
1057
  runHook,
1038
1058
  subagentIntro,
1039
1059
  relayHookCommand,
@@ -67,6 +67,38 @@ function writeShimBinding(claim, env) {
67
67
  }
68
68
  };
69
69
  }
70
+ function museLaunchFile(key, env) {
71
+ const pid = BINDING_PROCESS.exec(key)?.[1];
72
+ return pid ? join(relayDir(env), "launch", `muse-${pid}.json`) : void 0;
73
+ }
74
+ function writeMuseLaunch(key, launch, env) {
75
+ const pid = BINDING_PROCESS.exec(key)?.[1];
76
+ if (!pid) throw new Error(`muse serve has no process key (${key})`);
77
+ const path = join(privateDir(join(relayDir(env), "launch")), `muse-${pid}.json`);
78
+ const text = JSON.stringify({ process: key, ...launch });
79
+ writeFileSync(path, text, { mode: 384 });
80
+ chmodSync(path, 384);
81
+ return () => {
82
+ try {
83
+ if (readFileSync(path, "utf8") === text) rmSync(path);
84
+ } catch {
85
+ }
86
+ };
87
+ }
88
+ function readMuseLaunch(key, env) {
89
+ const path = museLaunchFile(key, env);
90
+ if (!path) return void 0;
91
+ try {
92
+ const launch = JSON.parse(readFileSync(path, "utf8"));
93
+ if (launch.process !== key) return void 0;
94
+ return {
95
+ ...typeof launch.name === "string" && validHandle(launch.name) ? { name: launch.name } : {},
96
+ ...typeof launch.grant === "string" && launch.grant ? { grant: launch.grant } : {}
97
+ };
98
+ } catch {
99
+ return void 0;
100
+ }
101
+ }
70
102
  function readShimBinding(env, pid, table) {
71
103
  const read = (name, expectedPid) => {
72
104
  try {
@@ -374,14 +406,23 @@ function hookHarnessPid(env, harness, ppid = process.ppid, parentOf = psParent)
374
406
  if (Number.isInteger(pid) && pid > 1) return pid;
375
407
  return harnessPid(ppid, parentOf);
376
408
  }
409
+ function launcherPid(env, harness = harnessPid, parentOf = psParent) {
410
+ const pid = Number(env.SCP_HARNESS_PID);
411
+ if (!Number.isInteger(pid) || pid <= 1) return void 0;
412
+ return parentOf(harness())?.ppid === pid ? pid : void 0;
413
+ }
414
+ var HARNESS_SESSION = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/;
377
415
  function relayIdentity(input) {
378
416
  const resolved = resolveHarness(input.harness, input.env, input.fallbackHarness);
379
417
  const pid = input.harnessPid(resolved);
380
418
  const harness = GENERIC_HARNESSES.has(resolved) && input.inferHarness?.(pid) || resolved;
381
419
  const cwd = isAbsolute(input.cwd) ? input.cwd : resolve(input.cwd);
382
- const handle = input.as ?? input.env.SCP_NAME ?? deriveHandle(harness, cwd);
383
420
  const harnessProcess = processKey(pid, input.startOf);
421
+ const launched = harness === "muse" && !input.env.SCP_NAME && !input.env.SCP_GRANT ? readMuseLaunch(harnessProcess, input.env) : void 0;
422
+ const handle = input.as ?? input.env.SCP_NAME ?? launched?.name ?? deriveHandle(harness, cwd);
423
+ const grant = input.env.SCP_GRANT || launched?.grant;
384
424
  const keys = input.lineageOf ? input.lineageOf(pid) : lineage(pid);
425
+ const harnessSession = harness === "claude-code" ? [input.harnessSession, input.env.CLAUDE_CODE_SESSION_ID].find((id) => id !== void 0 && HARNESS_SESSION.test(id)) : void 0;
385
426
  return {
386
427
  handle,
387
428
  harness,
@@ -391,7 +432,8 @@ function relayIdentity(input) {
391
432
  labels: labelsFor(input.env),
392
433
  ...input.env.SCP_PARENT ? { parent: input.env.SCP_PARENT } : {},
393
434
  ...keys.length ? { lineage: keys } : {},
394
- ...input.env.SCP_GRANT ? { grant: input.env.SCP_GRANT } : {}
435
+ ...grant ? { grant } : {},
436
+ ...harnessSession ? { harness_session: harnessSession } : {}
395
437
  };
396
438
  }
397
439
 
@@ -466,6 +508,7 @@ var OPTIONS = {
466
508
  who: { type: "boolean" },
467
509
  peek: { type: "string" },
468
510
  endpoint: { type: "string" },
511
+ "take-over": { type: "boolean" },
469
512
  live: { type: "boolean" },
470
513
  parent: { type: "string" }
471
514
  };
@@ -591,7 +634,7 @@ async function open(verb, values, cwd, bodyFromStdin, walk) {
591
634
  `${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)`
592
635
  );
593
636
  }
594
- const { machineName, openCloud } = await import("./remote-UQJ5YYCC.js");
637
+ const { machineName, openCloud } = await import("./remote-YO5B2HQI.js");
595
638
  const handle2 = named ? localHandle(named) : void 0;
596
639
  const claim = handle2 ? {
597
640
  handle: handle2,
@@ -849,7 +892,7 @@ function relayVerb(positionals, asJson, env = process.env) {
849
892
  }
850
893
  async function loginMain(positionals, values) {
851
894
  if (positionals.length) throw new RelayUsage(`${CLI_NAME3} login takes only flags`);
852
- return (await import("./login-6MVD3VLC.js")).login(values);
895
+ return (await import("./login-DCNCC3RS.js")).login(values);
853
896
  }
854
897
  function logoutMain(positionals, asJson, env = process.env) {
855
898
  if (positionals.length) throw new RelayUsage(`${CLI_NAME3} logout takes no arguments`);
@@ -866,6 +909,7 @@ export {
866
909
  detectHarness,
867
910
  codexShell,
868
911
  writeShimBinding,
912
+ writeMuseLaunch,
869
913
  normalizeHarness,
870
914
  hookHarness,
871
915
  gitToplevel,
@@ -879,6 +923,7 @@ export {
879
923
  psParent,
880
924
  harnessPid,
881
925
  hookHarnessPid,
926
+ launcherPid,
882
927
  relayIdentity,
883
928
  DEFAULT_RELAY,
884
929
  configDir,
@@ -10,11 +10,11 @@ import {
10
10
  mergeHooks,
11
11
  musePlugin,
12
12
  opencodePlugin
13
- } from "./chunk-XQHPDNVG.js";
13
+ } from "./chunk-277BAY7J.js";
14
14
  import {
15
15
  RelayUsage,
16
16
  gitToplevel
17
- } from "./chunk-AAFHLHXG.js";
17
+ } from "./chunk-3SOIVANO.js";
18
18
 
19
19
  // src/install.ts
20
20
  import { chmodSync, copyFileSync, existsSync, lstatSync, mkdirSync, readFileSync, realpathSync, renameSync, statSync, unlinkSync, writeFileSync } from "fs";
@@ -5,7 +5,7 @@ import {
5
5
  configDir,
6
6
  relayCredential,
7
7
  writePrivateJson
8
- } from "./chunk-AAFHLHXG.js";
8
+ } from "./chunk-3SOIVANO.js";
9
9
  import {
10
10
  note,
11
11
  printTable
@@ -3,18 +3,13 @@ import {
3
3
  codexMount,
4
4
  codexOverrides,
5
5
  toml
6
- } from "./chunk-7RA7E5WR.js";
7
- import "./chunk-KN7WEIE4.js";
8
- import "./chunk-UKQBH4AQ.js";
9
- import "./chunk-2342GTME.js";
10
- import "./chunk-XQHPDNVG.js";
11
- import "./chunk-YYSLYVNZ.js";
6
+ } from "./chunk-RZUQ422C.js";
12
7
  import {
13
8
  RelayUsage,
14
9
  readPsTable,
15
10
  relayIdentity,
16
11
  startDaemon
17
- } from "./chunk-AAFHLHXG.js";
12
+ } from "./chunk-3SOIVANO.js";
18
13
  import {
19
14
  SELF
20
15
  } from "./chunk-MNTIEWKF.js";
@@ -611,12 +606,13 @@ ${stderr.toString().trim()}` : ""}`
611
606
  rmSync(dir, { recursive: true, force: true });
612
607
  }
613
608
  }
609
+
614
610
  export {
615
611
  CODEX_HELP,
612
+ codexLaunch,
616
613
  CodexSocket,
617
614
  CodexWaker,
618
- codexCommand,
619
- codexLaunch,
615
+ serverOptions,
620
616
  connectCodexChannel,
621
- serverOptions
617
+ codexCommand
622
618
  };
@@ -3,10 +3,10 @@ import {
3
3
  agySettingsFile,
4
4
  mcpFile,
5
5
  mountedEntry
6
- } from "./chunk-UKQBH4AQ.js";
6
+ } from "./chunk-SNW53KT3.js";
7
7
  import {
8
8
  steerPrompt
9
- } from "./chunk-XQHPDNVG.js";
9
+ } from "./chunk-277BAY7J.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-AAFHLHXG.js";
21
+ } from "./chunk-3SOIVANO.js";
22
22
  import {
23
23
  SELF,
24
24
  note
@@ -44,7 +44,7 @@ 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", "SCP_SHIM_BINDING", SPAWN_RUNNER];
47
+ var SPAWNER_IDENTITY = ["SCP_NAME", "SCP_SESSION", "SCP_GRANT", "SCP_PARENT", "SCP_HARNESS", "SCP_SHIM_BINDING", "SCP_HARNESS_PID", SPAWN_RUNNER];
48
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 = {};
@@ -164,6 +164,10 @@ var PRESETS = {
164
164
  allow: MESSAGING.flatMap((tool) => ["--allow", tool])
165
165
  }
166
166
  };
167
+ function messagingAllow(harness, args) {
168
+ const preset = PRESETS[harness];
169
+ return preset && !hasFlag(args, preset.own) ? preset.allow : [];
170
+ }
167
171
  var MUSE_VALUED = /* @__PURE__ */ new Set([
168
172
  "--agents",
169
173
  "--provider",
@@ -477,7 +481,7 @@ function workerName(command, random = nameSuffix) {
477
481
  const harness = (program === void 0 ? "" : basename(program)).toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^[^a-z0-9]+|[^a-z0-9]+$/g, "").slice(0, 57);
478
482
  return `${harness || "worker"}-${random()}`;
479
483
  }
480
- function agyNote(command, env) {
484
+ function agyNote(command, env, verb = "spawn") {
481
485
  const at = programAt(command);
482
486
  const args = command.slice(at + 1);
483
487
  if (command[at] === void 0 || basename(command[at]) !== "agy" || !hasFlag(args, ["-p", "--print", "--prompt"]) || hasFlag(args, ["--dangerously-skip-permissions"]))
@@ -488,7 +492,7 @@ function agyNote(command, env) {
488
492
  } catch {
489
493
  }
490
494
  if (Array.isArray(allow) && agyRules().every((rule) => allow.includes(rule))) return null;
491
- return `${CLI_NAME} spawn: headless agy denies the relay tools without the permission rules ${CLI_NAME} setup writes to ${agySettingsFile(env)}; run ${CLI_NAME} setup`;
495
+ return `${CLI_NAME} ${verb}: headless agy denies the relay tools without the permission rules ${CLI_NAME} setup writes to ${agySettingsFile(env)}; run ${CLI_NAME} setup`;
492
496
  }
493
497
  var FORWARDED = ["SIGINT", "SIGQUIT", "SIGTERM", "SIGHUP"];
494
498
  var TAIL_BYTES = 16 * 1024;
@@ -924,6 +928,10 @@ export {
924
928
  codexOverrideAt,
925
929
  programAt,
926
930
  MESSAGING,
931
+ messagingAllow,
932
+ MUSE_MODE,
933
+ MUSE_MODES_ALLOWED,
934
+ museModes,
927
935
  contributorRefusal,
928
936
  codexSkipsGitCheck,
929
937
  closedStdin,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  hooksTarget
3
- } from "./chunk-2342GTME.js";
3
+ } from "./chunk-LRQP25RI.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-XQHPDNVG.js";
15
+ } from "./chunk-277BAY7J.js";
16
16
  import {
17
17
  RelayUsage,
18
18
  gitToplevel,
19
19
  setJoinMode
20
- } from "./chunk-AAFHLHXG.js";
20
+ } from "./chunk-3SOIVANO.js";
21
21
 
22
22
  // src/setup.ts
23
23
  import { spawnSync } from "child_process";
@@ -0,0 +1,290 @@
1
+ import {
2
+ entryArgv,
3
+ mcpFile,
4
+ mountedEntry,
5
+ whichOnPath
6
+ } from "./chunk-SNW53KT3.js";
7
+ import "./chunk-LRQP25RI.js";
8
+ import "./chunk-277BAY7J.js";
9
+ import "./chunk-YYSLYVNZ.js";
10
+ import {
11
+ CHANNELS_ENV,
12
+ RelayUsage,
13
+ deriveHandle,
14
+ joinMode
15
+ } from "./chunk-3SOIVANO.js";
16
+ import {
17
+ SELF
18
+ } from "./chunk-MNTIEWKF.js";
19
+
20
+ // src/claude.ts
21
+ import { spawn, spawnSync } from "child_process";
22
+ import { randomBytes } from "crypto";
23
+ import { existsSync, readFileSync, symlinkSync, unlinkSync, writeFileSync } from "fs";
24
+ import { basename, join } from "path";
25
+ import { privateDir, relayDir } from "@scp-dev/broker";
26
+ import { CLI_NAME, validHandle } from "@scp-dev/core";
27
+ var CHANNEL_FLAGS = ["--dangerously-load-development-channels", "server:scp"];
28
+ function claudeArgv(argv) {
29
+ let name;
30
+ let bg = false;
31
+ let i = 0;
32
+ for (; ; ) {
33
+ const arg = argv[i];
34
+ if (arg === "--bg" || arg === "--background") {
35
+ bg = true;
36
+ i++;
37
+ } else if (arg === "--name" || arg === "--as") {
38
+ if (argv[i + 1] === void 0) throw new RelayUsage(`${CLI_NAME} claude ${arg} takes a handle`);
39
+ name = argv[i + 1];
40
+ i += 2;
41
+ } else if (arg?.startsWith("--name=") || arg?.startsWith("--as=")) {
42
+ name = arg.slice(arg.indexOf("=") + 1);
43
+ i++;
44
+ } else break;
45
+ }
46
+ if (argv[i] === "--") i++;
47
+ name = name?.replace(/^me\//, "");
48
+ if (name !== void 0 && !validHandle(name)) throw new RelayUsage(`--name ${JSON.stringify(name)} is not a valid agent handle`);
49
+ const args = argv.slice(i);
50
+ if (!bg) bg = optionsOf(args).some((arg) => arg === "--bg" || arg === "--background");
51
+ return { ...name !== void 0 ? { name } : {}, ...bg ? { bg: true } : {}, args };
52
+ }
53
+ var optionsOf = (args) => args.includes("--") ? args.slice(0, args.indexOf("--")) : args;
54
+ function beforeDashes(args, added) {
55
+ const at = optionsOf(args).length;
56
+ return [...args.slice(0, at), ...added, ...args.slice(at)];
57
+ }
58
+ function claudeLaunchArgs(args, added) {
59
+ const channels = optionsOf(args).some((arg) => arg === "server:scp" || arg === `${CHANNEL_FLAGS[0]}=server:scp`) ? [] : CHANNEL_FLAGS;
60
+ return beforeDashes(args, [...channels, ...added]);
61
+ }
62
+ var LAUNCHER_IDENTITY = ["SCP_NAME", "SCP_GRANT", "SCP_SESSION", "SCP_PARENT", "SCP_HARNESS", "SCP_SHIM_BINDING", "SCP_SPAWN_RUNNER", CHANNELS_ENV];
63
+ var SHIM_VARS = ["SCP_LABELS", "SCP_DIR", "XDG_STATE_HOME"];
64
+ var bgDir = (env) => join(relayDir(env), "claude-bg");
65
+ function bgMount(env, name) {
66
+ let entry;
67
+ try {
68
+ entry = mountedEntry("claude", mcpFile("claude", env));
69
+ } catch {
70
+ }
71
+ const mounted = entry ? entryArgv("claude", entry) : [];
72
+ const argv = mounted.includes("--channels") ? mounted : [...SELF, "mcp", "--harness", "claude", "--channels"];
73
+ const base = entry?.env && typeof entry.env === "object" ? entry.env : {};
74
+ const vars = Object.fromEntries(SHIM_VARS.flatMap((key) => env[key] ? [[key, env[key]]] : []));
75
+ return {
76
+ type: "stdio",
77
+ command: argv[0],
78
+ args: argv.slice(1),
79
+ env: { ...base, ...vars, ...name !== void 0 ? { SCP_NAME: name } : {}, SCP_GRANT: env.SCP_GRANT ?? "" }
80
+ };
81
+ }
82
+ var STRICT_HINT = `${CLI_NAME} claude: --strict-mcp-config without --mcp-config drops the scp mount, so messages cannot wake this session`;
83
+ function externalMcp(args) {
84
+ return args.some((arg) => arg === "--mcp-config" || arg.startsWith("--mcp-config="));
85
+ }
86
+ function namePrompt(name, args, env, cwd) {
87
+ if (name !== void 0 || joinMode(env) === "manual" || args.some((arg) => /^--(append-)?system-prompt/.test(arg))) return [];
88
+ const handle = env.SCP_NAME || deriveHandle("claude-code", cwd);
89
+ return [
90
+ "--append-system-prompt",
91
+ `You are on the SCP network as ${handle}. Pick a short descriptive name for yourself with \`${CLI_NAME} name <name>\` when you know what you're working on.`
92
+ ];
93
+ }
94
+ function mountHint(env, cwd = process.cwd()) {
95
+ const file = mcpFile("claude", env);
96
+ const entries = [];
97
+ try {
98
+ const user = mountedEntry("claude", file);
99
+ if (user) entries.push(user);
100
+ const config = existsSync(file) ? JSON.parse(readFileSync(file, "utf8")) : {};
101
+ const local = config.projects?.[cwd]?.mcpServers?.scp;
102
+ if (local && typeof local === "object") entries.push(local);
103
+ } catch {
104
+ return `${CLI_NAME} claude: ${file} is unreadable, so the scp mount is unchecked; fix it or run ${CLI_NAME} setup --write`;
105
+ }
106
+ const project = join(cwd, ".mcp.json");
107
+ try {
108
+ const entry = existsSync(project) ? mountedEntry("claude", project) : void 0;
109
+ if (entry) entries.push(entry);
110
+ } catch {
111
+ }
112
+ if (!entries.length) return `${CLI_NAME} claude: Claude Code has no scp MCP mount, so messages cannot wake this session; run ${CLI_NAME} setup --write`;
113
+ if (!entries.some((entry) => entryArgv("claude", entry).includes("--channels")))
114
+ return `${CLI_NAME} claude: the scp mount lacks --channels, so messages cannot wake this session; run ${CLI_NAME} setup --write`;
115
+ return void 0;
116
+ }
117
+ var SHORT_ID = /^[0-9a-f]{8}$/;
118
+ var BACKGROUNDED = /backgrounded\s*\S\s*([0-9a-f]{8})/;
119
+ function liveAgents(bin, env) {
120
+ const run = spawnSync(bin, ["agents", "--json"], { env, encoding: "utf8", timeout: 15e3 });
121
+ try {
122
+ const listed = JSON.parse(run.stdout);
123
+ return Array.isArray(listed) ? listed.filter((agent) => typeof agent?.id === "string" && agent.state !== "failed") : [];
124
+ } catch {
125
+ return [];
126
+ }
127
+ }
128
+ function resumeTarget(args) {
129
+ const options = optionsOf(args);
130
+ for (const [i, arg] of options.entries()) {
131
+ if (arg.startsWith("--resume=")) return arg.slice("--resume=".length);
132
+ if ((arg === "--resume" || arg === "-r") && options[i + 1] && !options[i + 1].startsWith("-")) return options[i + 1];
133
+ }
134
+ return void 0;
135
+ }
136
+ async function runClaude(bin, args, env, cwd, stdout = "inherit", onOut) {
137
+ const child = spawn(bin, args, { cwd, stdio: ["inherit", stdout, "inherit"], env });
138
+ child.stdout?.on("data", (chunk) => {
139
+ process.stdout.write(chunk);
140
+ onOut?.(chunk.toString("utf8"));
141
+ });
142
+ const forward = (signal) => () => void child.kill(signal);
143
+ const handlers = ["SIGTERM", "SIGHUP"].map((signal) => [signal, forward(signal)]);
144
+ const ignore = () => {
145
+ };
146
+ process.on("SIGINT", ignore);
147
+ for (const [signal, handler] of handlers) process.on(signal, handler);
148
+ try {
149
+ return await new Promise((resolve, reject) => {
150
+ child.once("error", reject);
151
+ child.once("close", (code, signal) => resolve(code ?? (signal ? 128 + (signalNumber(signal) ?? 1) : 1)));
152
+ });
153
+ } finally {
154
+ process.off("SIGINT", ignore);
155
+ for (const [signal, handler] of handlers) process.off(signal, handler);
156
+ }
157
+ }
158
+ async function backgroundCommand(name, args, env, cwd, bin, out) {
159
+ const handle = name ?? (env.SCP_NAME || void 0);
160
+ const dir = privateDir(bgDir(env));
161
+ const file = join(dir, `${randomBytes(8).toString("hex")}.json`);
162
+ writeFileSync(file, `${JSON.stringify({ mcpServers: { scp: bgMount(env, handle) } }, null, 2)}
163
+ `, { mode: 384 });
164
+ const options = optionsOf(args);
165
+ const added = [
166
+ ...options.includes("--bg") || options.includes("--background") ? [] : ["--bg"],
167
+ ...handle !== void 0 && !options.some((arg) => arg === "-n" || arg === "--name" || arg.startsWith("--name=")) ? ["--name", handle] : [],
168
+ ...namePrompt(handle, args, env, cwd),
169
+ "--mcp-config",
170
+ file
171
+ ];
172
+ const clean = Object.fromEntries(Object.entries(env).filter(([key]) => !LAUNCHER_IDENTITY.includes(key)));
173
+ let printed = "";
174
+ const code = await runClaude(bin, beforeDashes(args, added), clean, cwd, "pipe", (text) => {
175
+ printed += text;
176
+ });
177
+ const id = BACKGROUNDED.exec(printed)?.[1];
178
+ if (!id) {
179
+ unlinkSync(file);
180
+ return code || 1;
181
+ }
182
+ try {
183
+ unlinkSync(join(dir, `${id}.json`));
184
+ } catch {
185
+ }
186
+ symlinkSync(basename(file), join(dir, `${id}.json`));
187
+ const address = `me/${handle ?? deriveHandle("claude-code", cwd)}`;
188
+ out(`${CLI_NAME} claude: background session ${id} is ${address} on SCP; messages wake it through its inbox. ${CLI_NAME} claude attach ${id} opens it`);
189
+ return code;
190
+ }
191
+ async function attachCommand(argv, env, err, cwd, bin, deps) {
192
+ let target;
193
+ let rename;
194
+ for (let i = 0; i < argv.length; i++) {
195
+ const arg = argv[i];
196
+ if (arg === "--name" || arg === "--as") {
197
+ rename = argv[++i];
198
+ if (rename === void 0) throw new RelayUsage(`${CLI_NAME} claude attach ${arg} takes a handle`);
199
+ } else if (arg.startsWith("--name=") || arg.startsWith("--as=")) rename = arg.slice(arg.indexOf("=") + 1);
200
+ else if (target === void 0) target = arg;
201
+ else throw new RelayUsage(`${CLI_NAME} claude attach takes one session: <id|name> [--name N]`);
202
+ }
203
+ if (target === void 0) throw new RelayUsage(`${CLI_NAME} claude attach takes a background session: <id|name> [--name N]`);
204
+ rename = rename?.replace(/^me\//, "");
205
+ if (rename !== void 0) {
206
+ if (!validHandle(rename)) throw new RelayUsage(`--name ${JSON.stringify(rename)} is not a valid agent handle`);
207
+ await renameBackground(target, rename, env, err, bin, deps);
208
+ }
209
+ return runClaude(bin, ["attach", target], env, cwd);
210
+ }
211
+ async function renameBackground(target, to, env, err, bin, deps) {
212
+ const agent = SHORT_ID.test(target) ? void 0 : liveAgents(bin, env).find((a) => a.name === target || a.sessionId === target);
213
+ const id = SHORT_ID.test(target) ? target : agent?.id;
214
+ const link = id ? join(bgDir(env), `${id}.json`) : void 0;
215
+ let config;
216
+ try {
217
+ config = link ? JSON.parse(readFileSync(link, "utf8")) : void 0;
218
+ } catch {
219
+ }
220
+ const from = config?.mcpServers?.scp?.env?.SCP_NAME ?? (SHORT_ID.test(target) ? void 0 : target);
221
+ if (!link || !config?.mcpServers?.scp?.env || from === void 0) {
222
+ err(`${CLI_NAME} claude: ${target} was not started by ${CLI_NAME} claude --bg --name, so its name is unknown; run ${CLI_NAME} name ${to} in it`);
223
+ return;
224
+ }
225
+ if (from === to) return;
226
+ const code = await (deps.rename ?? renameEndpoint)(from, to);
227
+ if (code !== 0) {
228
+ err(`${CLI_NAME} claude: me/${from} keeps its name`);
229
+ return;
230
+ }
231
+ config.mcpServers.scp.env.SCP_NAME = to;
232
+ writeFileSync(link, `${JSON.stringify(config, null, 2)}
233
+ `, { mode: 384 });
234
+ }
235
+ async function renameEndpoint(from, to) {
236
+ return (await import("./main-CDLW3MV5.js")).relayMain(["name", "--endpoint", `me/${from}`, to]);
237
+ }
238
+ async function claudeCommand(argv, env = process.env, err = (line) => void process.stderr.write(`${line}
239
+ `), cwd = process.cwd(), deps = {}) {
240
+ if (argv[0] === "--help" || argv[0] === "-h") {
241
+ process.stdout.write(CLAUDE_HELP);
242
+ return 0;
243
+ }
244
+ const out = deps.out ?? ((line) => void process.stdout.write(`${line}
245
+ `));
246
+ const bin = whichOnPath("claude", env);
247
+ if (argv[0] === "attach") {
248
+ if (!bin) throw new RelayUsage("claude is not on PATH");
249
+ return attachCommand(argv.slice(1), env, err, cwd, bin, deps);
250
+ }
251
+ const { name, bg, args } = claudeArgv(argv);
252
+ if (!bin) throw new RelayUsage("claude is not on PATH");
253
+ if (bg) return backgroundCommand(name, args, env, cwd, bin, out);
254
+ const resume = resumeTarget(args);
255
+ const live = resume === void 0 ? void 0 : liveAgents(bin, env).find((agent) => agent.id === resume || agent.sessionId === resume);
256
+ if (live) {
257
+ err(`${CLI_NAME} claude: ${resume} is a live background session, already woken through claude-inbox; attaching to it (claude attach ${live.id})`);
258
+ return runClaude(bin, ["attach", live.id], env, cwd);
259
+ }
260
+ const external = externalMcp(args);
261
+ const hint = external ? void 0 : args.includes("--strict-mcp-config") ? STRICT_HINT : mountHint(env, cwd);
262
+ if (hint) throw new RelayUsage(hint);
263
+ if (external) err(`${CLI_NAME} claude: using your --mcp-config; it needs the scp server with --channels for messages to wake this session`);
264
+ return runClaude(
265
+ bin,
266
+ claudeLaunchArgs(args, namePrompt(name, args, env, cwd)),
267
+ { ...env, ...name !== void 0 ? { SCP_NAME: name } : {}, [CHANNELS_ENV]: String(process.pid) },
268
+ cwd
269
+ );
270
+ }
271
+ var CLAUDE_HELP = `${CLI_NAME} claude [--name N | --as N] [--] [claude args...] start Claude Code with the scp channel loaded, so peer messages wake it
272
+ ${CLI_NAME} claude --bg [--name N] [--] [claude args...] start it in the background (claude --bg) with an scp mount that claims N and
273
+ $SCP_GRANT, so env $(${CLI_NAME} spawn-env --name N) links it under you; messages wake it
274
+ through its inbox. Prints its short id and address
275
+ ${CLI_NAME} claude attach <id|name> [--name N] claude attach, renaming its endpoint to N first
276
+ --resume <id> of a live background session attaches to it: it is already woken through claude-inbox
277
+ `;
278
+ var SIGNALS = { SIGHUP: 1, SIGINT: 2, SIGKILL: 9, SIGTERM: 15 };
279
+ var signalNumber = (signal) => SIGNALS[signal];
280
+ export {
281
+ CHANNEL_FLAGS,
282
+ bgDir,
283
+ bgMount,
284
+ claudeArgv,
285
+ claudeCommand,
286
+ claudeLaunchArgs,
287
+ mountHint,
288
+ namePrompt,
289
+ resumeTarget
290
+ };
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-F2NFQ2KC.js");
20
+ const { run } = await import("./main-CDLW3MV5.js");
21
21
  await run(process.argv.slice(2));
22
22
  }
@@ -0,0 +1,26 @@
1
+ import {
2
+ CODEX_HELP,
3
+ CodexSocket,
4
+ CodexWaker,
5
+ codexCommand,
6
+ codexLaunch,
7
+ connectCodexChannel,
8
+ serverOptions
9
+ } from "./chunk-LWMTZH36.js";
10
+ import "./chunk-RZUQ422C.js";
11
+ import "./chunk-KN7WEIE4.js";
12
+ import "./chunk-SNW53KT3.js";
13
+ import "./chunk-LRQP25RI.js";
14
+ import "./chunk-277BAY7J.js";
15
+ import "./chunk-YYSLYVNZ.js";
16
+ import "./chunk-3SOIVANO.js";
17
+ import "./chunk-MNTIEWKF.js";
18
+ export {
19
+ CODEX_HELP,
20
+ CodexSocket,
21
+ CodexWaker,
22
+ codexCommand,
23
+ codexLaunch,
24
+ connectCodexChannel,
25
+ serverOptions
26
+ };