@scp-dev/cli 0.2.4 → 0.3.1

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 (28) hide show
  1. package/dist/{chunk-E7JG5PJB.js → chunk-2LIJXXTL.js} +53 -9
  2. package/dist/{chunk-W3VNCRBX.js → chunk-2OSUVJ2J.js} +3 -3
  3. package/dist/{chunk-IXCHAWOL.js → chunk-3SHVJIXP.js} +5 -3
  4. package/dist/{chunk-ZDU53ZRF.js → chunk-IEFXYBX7.js} +6 -3
  5. package/dist/{chunk-ZMVFN6MU.js → chunk-Q5UI4Z7H.js} +2 -2
  6. package/dist/{chunk-X4ZLEM47.js → chunk-QRWQIHV6.js} +56 -8
  7. package/dist/claude-EQVLST73.js +130 -0
  8. package/dist/cli.js +1 -1
  9. package/dist/{codex-4IIM6ZE2.js → codex-5GZ7YPES.js} +73 -24
  10. package/dist/{hooks-P4J6OZCO.js → hooks-B34E2HIP.js} +6 -2
  11. package/dist/{install-FKGGPT6L.js → install-6KXJY27V.js} +3 -3
  12. package/dist/{join-RGFHOSLE.js → join-FITJVZCA.js} +3 -1
  13. package/dist/{login-IPS75GLQ.js → login-AUMLI4FS.js} +2 -2
  14. package/dist/{main-MCNGHJP2.js → main-ZAYVXFAG.js} +63 -27
  15. package/dist/{mcp-TUWMLGE4.js → mcp-VXBRMQB7.js} +14 -6
  16. package/dist/{mesh-VNZV3POO.js → mesh-H4KL5XAR.js} +1 -1
  17. package/dist/opencode-ORLGNHWR.js +116 -0
  18. package/dist/{peek-4D4VGKOW.js → peek-YTCWVPF7.js} +1 -1
  19. package/dist/{pi-JZ4DXY7V.js → pi-QEZVFDNR.js} +8 -10
  20. package/dist/pi-extension.js +22 -7
  21. package/dist/{relay-U634RHIJ.js → relay-QWJM372C.js} +1 -1
  22. package/dist/{remote-NTHRHVEP.js → remote-P4GFUIAP.js} +2 -2
  23. package/dist/{setup-RO7356M4.js → setup-MGDWKCNU.js} +4 -4
  24. package/dist/{spawn-BYU2X46L.js → spawn-GG7VFZA6.js} +9 -5
  25. package/dist/up-B2NEOOC6.js +57 -0
  26. package/package.json +6 -6
  27. package/dist/claude-JD7WXMAT.js +0 -98
  28. package/dist/up-GDD24GPL.js +0 -35
@@ -0,0 +1,116 @@
1
+ import {
2
+ mcpFile,
3
+ mountedEntry,
4
+ whichOnPath
5
+ } from "./chunk-2OSUVJ2J.js";
6
+ import {
7
+ hooksTarget
8
+ } from "./chunk-Q5UI4Z7H.js";
9
+ import {
10
+ opencodePlugin
11
+ } from "./chunk-QRWQIHV6.js";
12
+ import "./chunk-YYSLYVNZ.js";
13
+ import {
14
+ RelayUsage,
15
+ gitToplevel
16
+ } from "./chunk-2LIJXXTL.js";
17
+ import "./chunk-MNTIEWKF.js";
18
+
19
+ // src/opencode.ts
20
+ import { spawn } from "child_process";
21
+ import { existsSync, readFileSync } from "fs";
22
+ import { join } from "path";
23
+ import { CLI_NAME, validHandle } from "@scp-dev/core";
24
+ var OPENCODE_HELP = `${CLI_NAME} opencode [--name N | --as N] [--] [opencode args...]
25
+ runs OpenCode with your own config and arguments, wake on: the ${CLI_NAME} plugin wakes the session on a new message, and opens
26
+ one when none is open yet. Refuses to start without the current plugin; ${CLI_NAME} setup --write installs it.
27
+ $SCP_OPENCODE_BIN picks the opencode binary (default opencode on PATH).`;
28
+ function opencodeLaunch(args, env, bin) {
29
+ let name;
30
+ const rest = [];
31
+ for (let i = 0; i < args.length; i++) {
32
+ const arg = args[i];
33
+ if (arg === "--") {
34
+ rest.push(...args.slice(i + 1));
35
+ break;
36
+ }
37
+ if (arg === "--name" || arg === "--as") {
38
+ name = args[++i];
39
+ if (name === void 0) throw new RelayUsage(`${CLI_NAME} opencode ${arg} takes a name`);
40
+ } else if (arg.startsWith("--name=") || arg.startsWith("--as=")) name = arg.slice(arg.indexOf("=") + 1);
41
+ else rest.push(arg);
42
+ }
43
+ name = name?.replace(/^me\//, "");
44
+ if (name !== void 0 && !validHandle(name)) throw new RelayUsage(`${JSON.stringify(name)} is not a valid agent handle`);
45
+ return {
46
+ argv: [bin, ...rest],
47
+ env: { ...env, SCP_HARNESS: "opencode", SCP_WAKE: "1", ...name !== void 0 ? { SCP_NAME: name } : {} }
48
+ };
49
+ }
50
+ function pluginState(env, cwd) {
51
+ const current = /* @__PURE__ */ new Set([opencodePlugin({ blockStop: false }), opencodePlugin({ blockStop: true })]);
52
+ const files = [hooksTarget("opencode", "project", env, cwd), hooksTarget("opencode", "user", env, cwd)].filter((file) => existsSync(file));
53
+ for (const file of files) {
54
+ try {
55
+ if (current.has(readFileSync(file, "utf8"))) return { file, current: true };
56
+ } catch {
57
+ }
58
+ }
59
+ return { ...files[0] ? { file: files[0] } : {}, current: false };
60
+ }
61
+ function pluginProblem(env, cwd) {
62
+ const plugin = pluginState(env, cwd);
63
+ if (plugin.current) return void 0;
64
+ const fix = `run ${CLI_NAME} setup --write (or ${CLI_NAME} hooks install --harness opencode --scope user --write)`;
65
+ return plugin.file ? `${CLI_NAME} opencode: ${plugin.file} is not this ${CLI_NAME}'s plugin, so wake is not guaranteed; ${fix}` : `${CLI_NAME} opencode: OpenCode has no ${CLI_NAME} plugin, so messages would not wake it; ${fix}`;
66
+ }
67
+ function opencodeMountHint(env, cwd) {
68
+ const project = gitToplevel(cwd) ?? cwd;
69
+ const files = [mcpFile("opencode", env), ...["opencode.json", "opencode.jsonc"].map((name) => join(project, name))];
70
+ for (const file of files) {
71
+ try {
72
+ if (existsSync(file) && mountedEntry("opencode", file)) return void 0;
73
+ } catch {
74
+ }
75
+ }
76
+ return `${CLI_NAME} opencode: OpenCode has no scp MCP mount, so the session has no relay tools; run ${CLI_NAME} setup --write`;
77
+ }
78
+ async function opencodeCommand(args, env = process.env, err = (line) => void process.stderr.write(`${line}
79
+ `), cwd = process.cwd()) {
80
+ const own = args.includes("--") ? args.slice(0, args.indexOf("--")) : args;
81
+ if (own.includes("--help") || own.includes("-h")) {
82
+ process.stdout.write(`${OPENCODE_HELP}
83
+ `);
84
+ return 0;
85
+ }
86
+ const bin = env.SCP_OPENCODE_BIN || whichOnPath("opencode", env);
87
+ if (!bin) throw new RelayUsage(`opencode is not on PATH: install it with npm i -g opencode-ai, then run ${CLI_NAME} setup --write`);
88
+ const launch = opencodeLaunch(args, env, bin);
89
+ const problem = pluginProblem(env, cwd);
90
+ if (problem) throw new RelayUsage(problem);
91
+ const hint = opencodeMountHint(env, cwd);
92
+ if (hint) err(hint);
93
+ return await new Promise((resolve, reject) => {
94
+ const child = spawn(launch.argv[0], launch.argv.slice(1), { env: launch.env, stdio: "inherit" });
95
+ const forward = (signal) => child.kill(signal);
96
+ const signals = ["SIGTERM", "SIGHUP"];
97
+ const ignore = () => {
98
+ };
99
+ for (const signal of signals) process.on(signal, forward);
100
+ process.on("SIGINT", ignore);
101
+ child.once("error", (error) => reject(new RelayUsage(`could not start ${launch.argv[0]}: ${error.message}`)));
102
+ child.once("exit", (code, signal) => {
103
+ for (const each of signals) process.off(each, forward);
104
+ process.off("SIGINT", ignore);
105
+ resolve(code ?? (signal ? 1 : 0));
106
+ });
107
+ });
108
+ }
109
+ export {
110
+ OPENCODE_HELP,
111
+ opencodeCommand,
112
+ opencodeLaunch,
113
+ opencodeMountHint,
114
+ pluginProblem,
115
+ pluginState
116
+ };
@@ -2,7 +2,7 @@ import {
2
2
  RelayUsage,
3
3
  peekGrant,
4
4
  stamp
5
- } from "./chunk-E7JG5PJB.js";
5
+ } from "./chunk-2LIJXXTL.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-E7JG5PJB.js";
3
+ } from "./chunk-2LIJXXTL.js";
4
4
  import "./chunk-MNTIEWKF.js";
5
5
 
6
6
  // src/pi.ts
@@ -10,22 +10,21 @@ import { fileURLToPath } from "url";
10
10
  import { CLI_NAME, validHandle } from "@scp-dev/core";
11
11
  var PI_HELP = `${CLI_NAME} pi [--name NAME | --as NAME] [--] [pi args...]
12
12
  runs pi with the bundled SCP extension: the relay tools, and each new message as a turn, waking the session when idle.
13
+ pi's own --name and every other argument after the leading launcher flags go to pi untouched.
13
14
  $SCP_PI_BIN picks the pi binary (default pi on PATH), $SCP_PI_EXTENSION the extension file.`;
14
15
  function piLaunch(args, env, extension) {
15
16
  let name;
16
- const rest = [];
17
- for (let i = 0; i < args.length; i++) {
17
+ let i = 0;
18
+ for (; i < args.length; i++) {
18
19
  const arg = args[i];
19
- if (arg === "--") {
20
- rest.push(...args.slice(i + 1));
21
- break;
22
- }
23
20
  if (arg === "--name" || arg === "--as") {
24
21
  name = args[++i];
25
22
  if (name === void 0) throw new RelayUsage(`${CLI_NAME} pi ${arg} takes a name`);
26
23
  } else if (arg.startsWith("--name=") || arg.startsWith("--as=")) name = arg.slice(arg.indexOf("=") + 1);
27
- else rest.push(arg);
24
+ else break;
28
25
  }
26
+ if (args[i] === "--") i++;
27
+ const rest = args.slice(i);
29
28
  name = name?.replace(/^me\//, "");
30
29
  if (name !== void 0 && !validHandle(name)) throw new RelayUsage(`${JSON.stringify(name)} is not a valid agent handle`);
31
30
  return {
@@ -42,8 +41,7 @@ function extensionPath(env, base = import.meta.url) {
42
41
  throw new RelayUsage(`${CLI_NAME} pi found no pi extension next to ${CLI_NAME}: reinstall it, or set $SCP_PI_EXTENSION to the extension file`);
43
42
  }
44
43
  async function piCommand(args) {
45
- const own = args.includes("--") ? args.slice(0, args.indexOf("--")) : args;
46
- if (own.includes("--help") || own.includes("-h")) {
44
+ if (args[0] === "--help" || args[0] === "-h") {
47
45
  process.stdout.write(`${PI_HELP}
48
46
  `);
49
47
  return 0;
@@ -19,8 +19,14 @@ var McpLink = class {
19
19
  pending = /* @__PURE__ */ new Map();
20
20
  next = 1;
21
21
  closed = false;
22
+ /** resolves once the shim process is gone */
23
+ exited;
22
24
  constructor(argv, env, onPush, onExit) {
23
25
  this.child = spawn(argv[0], argv.slice(1), { env, stdio: ["pipe", "pipe", "ignore"] });
26
+ this.exited = new Promise((resolve) => {
27
+ this.child.once("exit", () => resolve());
28
+ this.child.once("error", () => resolve());
29
+ });
24
30
  this.child.stdin.on("error", () => {
25
31
  });
26
32
  createInterface({ input: this.child.stdout }).on("line", (line) => {
@@ -66,11 +72,15 @@ var McpLink = class {
66
72
  if (!this.closed) this.child.stdin.write(`${JSON.stringify({ jsonrpc: "2.0", method, params })}
67
73
  `);
68
74
  }
69
- close() {
70
- if (this.closed) return;
71
- this.closed = true;
72
- this.child.stdin.end();
73
- this.child.kill();
75
+ /** ends the shim, resolving once it exited (or after `ms`), so a shim started next never races it for the endpoint */
76
+ close(ms = 3e3) {
77
+ if (!this.closed) {
78
+ this.closed = true;
79
+ this.child.stdin.end();
80
+ this.child.kill();
81
+ }
82
+ let timer;
83
+ return Promise.race([this.exited, new Promise((resolve) => timer = setTimeout(resolve, ms))]).finally(() => clearTimeout(timer));
74
84
  }
75
85
  };
76
86
  function toolResult(result) {
@@ -87,7 +97,9 @@ function scp(pi) {
87
97
  };
88
98
  pi.on("session_start", async (_event, ctx) => {
89
99
  if (process.env.SCP_PI === "0") return;
90
- link?.close();
100
+ const previous = link;
101
+ link = void 0;
102
+ await previous?.close();
91
103
  const current = new McpLink(
92
104
  shimArgv(process.env),
93
105
  process.env,
@@ -119,13 +131,16 @@ function scp(pi) {
119
131
  });
120
132
  }
121
133
  current.notify("notifications/initialized");
134
+ const whoami = await current.request("tools/call", { name: "relay_whoami", arguments: {} });
135
+ if (whoami.isError) warn(ctx, `scp: not on the relay: ${(whoami.content ?? []).map((part) => part.text ?? "").join(" ")}`);
122
136
  } catch (error) {
123
137
  warn(ctx, `scp: could not start the relay shim: ${error instanceof Error ? error.message : String(error)}`);
124
138
  }
125
139
  });
126
140
  pi.on("session_shutdown", async () => {
127
- link?.close();
141
+ const current = link;
128
142
  link = void 0;
143
+ await current?.close();
129
144
  });
130
145
  }
131
146
  export {
@@ -13,7 +13,7 @@ import {
13
13
  saveCredential,
14
14
  setJoinMode,
15
15
  writePrivateJson
16
- } from "./chunk-E7JG5PJB.js";
16
+ } from "./chunk-2LIJXXTL.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-ZDU53ZRF.js";
13
- import "./chunk-E7JG5PJB.js";
12
+ } from "./chunk-IEFXYBX7.js";
13
+ import "./chunk-2LIJXXTL.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-W3VNCRBX.js";
19
- import "./chunk-ZMVFN6MU.js";
20
- import "./chunk-X4ZLEM47.js";
18
+ } from "./chunk-2OSUVJ2J.js";
19
+ import "./chunk-Q5UI4Z7H.js";
20
+ import "./chunk-QRWQIHV6.js";
21
21
  import "./chunk-YYSLYVNZ.js";
22
- import "./chunk-E7JG5PJB.js";
22
+ import "./chunk-2LIJXXTL.js";
23
23
  import "./chunk-MNTIEWKF.js";
24
24
  export {
25
25
  SETUP_HARNESSES,
@@ -1,4 +1,5 @@
1
1
  import {
2
+ CODEX_VALUED,
2
3
  MESSAGING,
3
4
  SPAWN_RUNNER,
4
5
  STDIN_WAIT_MS,
@@ -27,19 +28,21 @@ import {
27
28
  splitSpawn,
28
29
  stderrOutput,
29
30
  steerArgv,
31
+ toml,
30
32
  transcriptReplies,
31
33
  workerName
32
- } from "./chunk-IXCHAWOL.js";
34
+ } from "./chunk-3SHVJIXP.js";
33
35
  import {
34
36
  SPAWN_HELP
35
37
  } from "./chunk-KN7WEIE4.js";
36
- import "./chunk-W3VNCRBX.js";
37
- import "./chunk-ZMVFN6MU.js";
38
- import "./chunk-X4ZLEM47.js";
38
+ import "./chunk-2OSUVJ2J.js";
39
+ import "./chunk-Q5UI4Z7H.js";
40
+ import "./chunk-QRWQIHV6.js";
39
41
  import "./chunk-YYSLYVNZ.js";
40
- import "./chunk-E7JG5PJB.js";
42
+ import "./chunk-2LIJXXTL.js";
41
43
  import "./chunk-MNTIEWKF.js";
42
44
  export {
45
+ CODEX_VALUED,
43
46
  MESSAGING,
44
47
  SPAWN_HELP,
45
48
  SPAWN_RUNNER,
@@ -69,6 +72,7 @@ export {
69
72
  splitSpawn,
70
73
  stderrOutput,
71
74
  steerArgv,
75
+ toml,
72
76
  transcriptReplies,
73
77
  workerName
74
78
  };
@@ -0,0 +1,57 @@
1
+ import {
2
+ RelayUsage,
3
+ activeRelay,
4
+ relayCredential
5
+ } from "./chunk-2LIJXXTL.js";
6
+ import "./chunk-MNTIEWKF.js";
7
+
8
+ // src/up.ts
9
+ import { CLI_NAME } from "@scp-dev/core";
10
+ var WAKE_LAUNCH = [
11
+ ["claude", `${CLI_NAME} claude --name <name> Claude Code with the scp channel: messages wake it`],
12
+ ["codex", `${CLI_NAME} codex --name <name> messages start or steer its turns`],
13
+ ["pi", `${CLI_NAME} pi --name <name> messages arrive as turns`],
14
+ ["opencode", "opencode its scp plugin wakes an idle session (on by default)"]
15
+ ];
16
+ function nextSteps(installed) {
17
+ const launches = WAKE_LAUNCH.filter(([harness]) => installed.has(harness)).map(([, line]) => ` ${line}`);
18
+ return [
19
+ "next: start each agent session wake-enabled:",
20
+ ...launches,
21
+ ` ${CLI_NAME} join <name> in a session already running: it sees messages only at turn boundaries until relaunched as above`,
22
+ ` ${CLI_NAME} setup checks the hooks and MCP mounts (it lists nothing to do once they are installed)`
23
+ ];
24
+ }
25
+ async function up(positionals, values, cwd, brokerStatus) {
26
+ if (positionals.length) throw new RelayUsage(`${CLI_NAME} up takes only flags`);
27
+ const out = (line) => process.stdout.write(`${line}
28
+ `);
29
+ const { url } = activeRelay(process.env);
30
+ const headless = values.token !== void 0 || Boolean(process.env.SCP_TOKEN?.trim());
31
+ if (headless || !relayCredential(process.env, url).token) {
32
+ const code = await (await import("./login-AUMLI4FS.js")).login({
33
+ ...values.token !== void 0 ? { token: values.token } : {},
34
+ ...values.label !== void 0 ? { label: values.label } : {},
35
+ ...values["no-browser"] ? { "no-browser": true } : {}
36
+ });
37
+ if (code !== 0) return code;
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);
40
+ if (enabled !== 0) return enabled;
41
+ const setup = (await import("./setup-MGDWKCNU.js")).relaySetupCommand(["--write"], cwd, out);
42
+ if (setup !== 0) return setup;
43
+ const broker = await brokerStatus();
44
+ if (!broker.enabled) out(`the broker is still local-only; run \`${CLI_NAME} daemon restart\` to link it to ${url}`);
45
+ else out(`broker linked to ${broker.url ?? url}${broker.connected ? "" : " (connecting)"}`);
46
+ const { detectHarnesses, whichOnPath } = await import("./setup-MGDWKCNU.js");
47
+ const which = (name) => whichOnPath(name, process.env);
48
+ const installed = new Set(detectHarnesses(process.env, which).keys());
49
+ if (which("pi")) installed.add("pi");
50
+ out("");
51
+ for (const line of nextSteps(installed)) out(line);
52
+ return 0;
53
+ }
54
+ export {
55
+ nextSteps,
56
+ up
57
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scp-dev/cli",
3
- "version": "0.2.4",
3
+ "version": "0.3.1",
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.1.4",
28
- "@scp-dev/broker": "0.1.6",
29
- "@scp-dev/hub": "0.4.0",
30
- "@scp-dev/mcp": "0.1.6",
27
+ "@scp-dev/core": "0.1.6",
28
+ "@scp-dev/broker": "0.2.1",
29
+ "@scp-dev/hub": "0.5.1",
30
+ "@scp-dev/mcp": "0.1.8",
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.3",
35
+ "@scp-dev/mesh": "0.0.5",
36
36
  "opencode-ai": "1.18.34",
37
37
  "tsup": "^8.5.1"
38
38
  },
@@ -1,98 +0,0 @@
1
- import {
2
- entryArgv,
3
- mcpFile,
4
- mountedEntry,
5
- whichOnPath
6
- } from "./chunk-W3VNCRBX.js";
7
- import "./chunk-ZMVFN6MU.js";
8
- import "./chunk-X4ZLEM47.js";
9
- import "./chunk-YYSLYVNZ.js";
10
- import {
11
- CHANNELS_ENV,
12
- RelayUsage,
13
- deriveHandle,
14
- joinMode
15
- } from "./chunk-E7JG5PJB.js";
16
- import "./chunk-MNTIEWKF.js";
17
-
18
- // src/claude.ts
19
- import { spawn } from "child_process";
20
- import { CLI_NAME, validHandle } from "@scp-dev/core";
21
- var CHANNEL_FLAGS = ["--dangerously-load-development-channels", "server:scp"];
22
- function claudeArgv(argv) {
23
- let name;
24
- let i = 0;
25
- if (argv[0] === "--name") {
26
- if (argv[1] === void 0) throw new RelayUsage(`${CLI_NAME} claude --name takes a handle`);
27
- name = argv[1];
28
- i = 2;
29
- } else if (argv[0]?.startsWith("--name=")) {
30
- name = argv[0].slice("--name=".length);
31
- i = 1;
32
- }
33
- if (argv[i] === "--") i++;
34
- if (name !== void 0 && !validHandle(name)) throw new RelayUsage(`--name ${JSON.stringify(name)} is not a valid agent handle`);
35
- return { ...name !== void 0 ? { name } : {}, args: argv.slice(i) };
36
- }
37
- function namePrompt(name, args, env, cwd) {
38
- if (name !== void 0 || joinMode(env) === "manual" || args.some((arg) => /^--(append-)?system-prompt/.test(arg))) return [];
39
- const handle = env.SCP_NAME || deriveHandle("claude-code", cwd);
40
- return [
41
- "--append-system-prompt",
42
- `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.`
43
- ];
44
- }
45
- function mountHint(env) {
46
- const file = mcpFile("claude", env);
47
- let entry;
48
- try {
49
- entry = mountedEntry("claude", file);
50
- } catch {
51
- return `${CLI_NAME} claude: ${file} is unreadable, so the scp mount is unchecked`;
52
- }
53
- if (!entry) return `${CLI_NAME} claude: Claude Code has no scp MCP mount; run ${CLI_NAME} setup --write`;
54
- if (!entryArgv("claude", entry).includes("--channels"))
55
- return `${CLI_NAME} claude: the scp mount lacks --channels, so messages will not wake this session; re-run ${CLI_NAME} setup --write`;
56
- return void 0;
57
- }
58
- async function claudeCommand(argv, env = process.env, err = (line) => void process.stderr.write(`${line}
59
- `), cwd = process.cwd()) {
60
- if (argv[0] === "--help" || argv[0] === "-h") {
61
- process.stdout.write(`${CLI_NAME} claude [--name N] [--] [claude args...] start Claude Code with the scp channel loaded, so peer messages wake it
62
- `);
63
- return 0;
64
- }
65
- const { name, args } = claudeArgv(argv);
66
- const bin = whichOnPath("claude", env);
67
- if (!bin) throw new RelayUsage("claude is not on PATH");
68
- const hint = mountHint(env);
69
- if (hint) err(hint);
70
- const child = spawn(bin, [...CHANNEL_FLAGS, ...namePrompt(name, args, env, cwd), ...args], {
71
- stdio: "inherit",
72
- env: { ...env, ...name !== void 0 ? { SCP_NAME: name } : {}, [CHANNELS_ENV]: String(process.pid) }
73
- });
74
- const forward = (signal) => () => void child.kill(signal);
75
- const handlers = ["SIGTERM", "SIGHUP"].map((signal) => [signal, forward(signal)]);
76
- const ignore = () => {
77
- };
78
- process.on("SIGINT", ignore);
79
- for (const [signal, handler] of handlers) process.on(signal, handler);
80
- try {
81
- return await new Promise((resolve, reject) => {
82
- child.once("error", reject);
83
- child.once("exit", (code, signal) => resolve(code ?? (signal ? 128 + (signalNumber(signal) ?? 1) : 1)));
84
- });
85
- } finally {
86
- process.off("SIGINT", ignore);
87
- for (const [signal, handler] of handlers) process.off(signal, handler);
88
- }
89
- }
90
- var SIGNALS = { SIGHUP: 1, SIGINT: 2, SIGKILL: 9, SIGTERM: 15 };
91
- var signalNumber = (signal) => SIGNALS[signal];
92
- export {
93
- CHANNEL_FLAGS,
94
- claudeArgv,
95
- claudeCommand,
96
- mountHint,
97
- namePrompt
98
- };
@@ -1,35 +0,0 @@
1
- import {
2
- RelayUsage,
3
- activeRelay,
4
- relayCredential
5
- } from "./chunk-E7JG5PJB.js";
6
- import "./chunk-MNTIEWKF.js";
7
-
8
- // src/up.ts
9
- import { CLI_NAME } from "@scp-dev/core";
10
- async function up(positionals, values, cwd, brokerStatus) {
11
- if (positionals.length) throw new RelayUsage(`${CLI_NAME} up takes only flags`);
12
- const out = (line) => process.stdout.write(`${line}
13
- `);
14
- const { url } = activeRelay(process.env);
15
- const headless = values.token !== void 0 || Boolean(process.env.SCP_TOKEN?.trim());
16
- if (headless || !relayCredential(process.env, url).token) {
17
- const code = await (await import("./login-IPS75GLQ.js")).login({
18
- ...values.token !== void 0 ? { token: values.token } : {},
19
- ...values.label !== void 0 ? { label: values.label } : {},
20
- ...values["no-browser"] ? { "no-browser": true } : {}
21
- });
22
- if (code !== 0) return code;
23
- } else out(`already logged in to ${url}`);
24
- const enabled = await (await import("./remote-NTHRHVEP.js")).cloudMain(["enable"], values.machine !== void 0 ? { machine: values.machine } : {}, brokerStatus);
25
- if (enabled !== 0) return enabled;
26
- const setup = (await import("./setup-RO7356M4.js")).relaySetupCommand(["--write"], cwd, out);
27
- if (setup !== 0) return setup;
28
- const broker = await brokerStatus();
29
- if (!broker.enabled) out(`the broker is still local-only; run \`${CLI_NAME} daemon restart\` to link it to ${url}`);
30
- else out(`broker linked to ${broker.url ?? url}${broker.connected ? "" : " (connecting)"}`);
31
- return 0;
32
- }
33
- export {
34
- up
35
- };