@scp-dev/cli 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-AAFHLHXG.js → chunk-BSX24XMZ.js} +7 -3
- package/dist/{chunk-2342GTME.js → chunk-C5PYVRJE.js} +2 -2
- package/dist/{chunk-H2XQXMZU.js → chunk-C7ZUACP7.js} +1 -1
- package/dist/{chunk-7RA7E5WR.js → chunk-CVW3INZO.js} +3 -3
- package/dist/{chunk-UKQBH4AQ.js → chunk-DEK3TE6T.js} +3 -3
- package/dist/{chunk-XQHPDNVG.js → chunk-GG33NSBW.js} +5 -1
- package/dist/claude-NCPNZLIX.js +290 -0
- package/dist/cli.js +1 -1
- package/dist/{codex-OSGHQMK6.js → codex-4GTXURTS.js} +5 -5
- package/dist/{hooks-BZANUJPY.js → hooks-SWVIDONV.js} +2 -2
- package/dist/{install-25J5QB63.js → install-YE7LCGPC.js} +3 -3
- package/dist/{join-EOLHE3LJ.js → join-64BU6SEY.js} +1 -1
- package/dist/{login-6MVD3VLC.js → login-4IF26HH5.js} +2 -2
- package/dist/{main-F2NFQ2KC.js → main-RA3MP25N.js} +36 -26
- package/dist/{mcp-BH526TOG.js → mcp-RERRUUIX.js} +5 -5
- package/dist/{mesh-OZILTV5P.js → mesh-XTMBRJLR.js} +1 -1
- package/dist/{opencode-XV33XTL5.js → opencode-CPNR2G3W.js} +4 -4
- package/dist/{peek-LFQR6TCS.js → peek-GEYQ7SHV.js} +1 -1
- package/dist/{pi-N3DX37PD.js → pi-XHZAUDP4.js} +1 -1
- package/dist/{relay-SF3UWIPM.js → relay-E4JFR33E.js} +1 -1
- package/dist/{remote-UQJ5YYCC.js → remote-3R4GRDGI.js} +2 -2
- package/dist/{setup-UJCIMYU4.js → setup-O45SE5L7.js} +4 -4
- package/dist/{spawn-JYD7NCQT.js → spawn-CJSHYE7E.js} +5 -5
- package/dist/{up-3YJU7YX6.js → up-O2CMDGXP.js} +5 -5
- package/package.json +6 -6
- package/dist/claude-RNH2E4GU.js +0 -130
|
@@ -374,6 +374,7 @@ function hookHarnessPid(env, harness, ppid = process.ppid, parentOf = psParent)
|
|
|
374
374
|
if (Number.isInteger(pid) && pid > 1) return pid;
|
|
375
375
|
return harnessPid(ppid, parentOf);
|
|
376
376
|
}
|
|
377
|
+
var HARNESS_SESSION = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/;
|
|
377
378
|
function relayIdentity(input) {
|
|
378
379
|
const resolved = resolveHarness(input.harness, input.env, input.fallbackHarness);
|
|
379
380
|
const pid = input.harnessPid(resolved);
|
|
@@ -382,6 +383,7 @@ function relayIdentity(input) {
|
|
|
382
383
|
const handle = input.as ?? input.env.SCP_NAME ?? deriveHandle(harness, cwd);
|
|
383
384
|
const harnessProcess = processKey(pid, input.startOf);
|
|
384
385
|
const keys = input.lineageOf ? input.lineageOf(pid) : lineage(pid);
|
|
386
|
+
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
387
|
return {
|
|
386
388
|
handle,
|
|
387
389
|
harness,
|
|
@@ -391,7 +393,8 @@ function relayIdentity(input) {
|
|
|
391
393
|
labels: labelsFor(input.env),
|
|
392
394
|
...input.env.SCP_PARENT ? { parent: input.env.SCP_PARENT } : {},
|
|
393
395
|
...keys.length ? { lineage: keys } : {},
|
|
394
|
-
...input.env.SCP_GRANT ? { grant: input.env.SCP_GRANT } : {}
|
|
396
|
+
...input.env.SCP_GRANT ? { grant: input.env.SCP_GRANT } : {},
|
|
397
|
+
...harnessSession ? { harness_session: harnessSession } : {}
|
|
395
398
|
};
|
|
396
399
|
}
|
|
397
400
|
|
|
@@ -466,6 +469,7 @@ var OPTIONS = {
|
|
|
466
469
|
who: { type: "boolean" },
|
|
467
470
|
peek: { type: "string" },
|
|
468
471
|
endpoint: { type: "string" },
|
|
472
|
+
"take-over": { type: "boolean" },
|
|
469
473
|
live: { type: "boolean" },
|
|
470
474
|
parent: { type: "string" }
|
|
471
475
|
};
|
|
@@ -591,7 +595,7 @@ async function open(verb, values, cwd, bodyFromStdin, walk) {
|
|
|
591
595
|
`${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
596
|
);
|
|
593
597
|
}
|
|
594
|
-
const { machineName, openCloud } = await import("./remote-
|
|
598
|
+
const { machineName, openCloud } = await import("./remote-3R4GRDGI.js");
|
|
595
599
|
const handle2 = named ? localHandle(named) : void 0;
|
|
596
600
|
const claim = handle2 ? {
|
|
597
601
|
handle: handle2,
|
|
@@ -849,7 +853,7 @@ function relayVerb(positionals, asJson, env = process.env) {
|
|
|
849
853
|
}
|
|
850
854
|
async function loginMain(positionals, values) {
|
|
851
855
|
if (positionals.length) throw new RelayUsage(`${CLI_NAME3} login takes only flags`);
|
|
852
|
-
return (await import("./login-
|
|
856
|
+
return (await import("./login-4IF26HH5.js")).login(values);
|
|
853
857
|
}
|
|
854
858
|
function logoutMain(positionals, asJson, env = process.env) {
|
|
855
859
|
if (positionals.length) throw new RelayUsage(`${CLI_NAME3} logout takes no arguments`);
|
|
@@ -10,11 +10,11 @@ import {
|
|
|
10
10
|
mergeHooks,
|
|
11
11
|
musePlugin,
|
|
12
12
|
opencodePlugin
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-GG33NSBW.js";
|
|
14
14
|
import {
|
|
15
15
|
RelayUsage,
|
|
16
16
|
gitToplevel
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-BSX24XMZ.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-
|
|
6
|
+
} from "./chunk-DEK3TE6T.js";
|
|
7
7
|
import {
|
|
8
8
|
steerPrompt
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-GG33NSBW.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-
|
|
21
|
+
} from "./chunk-BSX24XMZ.js";
|
|
22
22
|
import {
|
|
23
23
|
SELF,
|
|
24
24
|
note
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
hooksTarget
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-C5PYVRJE.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-
|
|
15
|
+
} from "./chunk-GG33NSBW.js";
|
|
16
16
|
import {
|
|
17
17
|
RelayUsage,
|
|
18
18
|
gitToplevel,
|
|
19
19
|
setJoinMode
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-BSX24XMZ.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-
|
|
16
|
+
} from "./chunk-BSX24XMZ.js";
|
|
17
17
|
|
|
18
18
|
// src/hooks.ts
|
|
19
19
|
import { Readable } from "stream";
|
|
@@ -445,8 +445,10 @@ async function runHook(args, options) {
|
|
|
445
445
|
)
|
|
446
446
|
);
|
|
447
447
|
if ("dark" in joined) return;
|
|
448
|
+
const harnessSession = event.agent ? void 0 : asString(field(payload, "session_id", "sessionId"));
|
|
448
449
|
const claim = relayIdentity({
|
|
449
450
|
...joined.handle ? { as: joined.handle } : {},
|
|
451
|
+
...harnessSession ? { harnessSession } : {},
|
|
450
452
|
harness,
|
|
451
453
|
fallbackHarness: "hook",
|
|
452
454
|
cwd: event.cwd ?? options.cwd,
|
|
@@ -556,8 +558,10 @@ async function wakeHook(harnessArg, payload, waitS, options) {
|
|
|
556
558
|
)
|
|
557
559
|
);
|
|
558
560
|
if ("dark" in joined) return;
|
|
561
|
+
const harnessSession = asString(field(payload, "session_id", "sessionId"));
|
|
559
562
|
const claim = relayIdentity({
|
|
560
563
|
...joined.handle ? { as: joined.handle } : {},
|
|
564
|
+
...harnessSession ? { harnessSession } : {},
|
|
561
565
|
harness,
|
|
562
566
|
fallbackHarness: "hook",
|
|
563
567
|
cwd: asString(payload.cwd) ?? options.cwd,
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import {
|
|
2
|
+
entryArgv,
|
|
3
|
+
mcpFile,
|
|
4
|
+
mountedEntry,
|
|
5
|
+
whichOnPath
|
|
6
|
+
} from "./chunk-DEK3TE6T.js";
|
|
7
|
+
import "./chunk-C5PYVRJE.js";
|
|
8
|
+
import "./chunk-GG33NSBW.js";
|
|
9
|
+
import "./chunk-YYSLYVNZ.js";
|
|
10
|
+
import {
|
|
11
|
+
CHANNELS_ENV,
|
|
12
|
+
RelayUsage,
|
|
13
|
+
deriveHandle,
|
|
14
|
+
joinMode
|
|
15
|
+
} from "./chunk-BSX24XMZ.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-RA3MP25N.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-
|
|
20
|
+
const { run } = await import("./main-RA3MP25N.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-
|
|
6
|
+
} from "./chunk-CVW3INZO.js";
|
|
7
7
|
import "./chunk-KN7WEIE4.js";
|
|
8
|
-
import "./chunk-
|
|
9
|
-
import "./chunk-
|
|
10
|
-
import "./chunk-
|
|
8
|
+
import "./chunk-DEK3TE6T.js";
|
|
9
|
+
import "./chunk-C5PYVRJE.js";
|
|
10
|
+
import "./chunk-GG33NSBW.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-
|
|
17
|
+
} from "./chunk-BSX24XMZ.js";
|
|
18
18
|
import {
|
|
19
19
|
SELF
|
|
20
20
|
} from "./chunk-MNTIEWKF.js";
|
|
@@ -40,11 +40,11 @@ import {
|
|
|
40
40
|
tldrEvery,
|
|
41
41
|
transcriptTitle,
|
|
42
42
|
unreadPointer
|
|
43
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-GG33NSBW.js";
|
|
44
44
|
import {
|
|
45
45
|
SUBAGENT
|
|
46
46
|
} from "./chunk-YYSLYVNZ.js";
|
|
47
|
-
import "./chunk-
|
|
47
|
+
import "./chunk-BSX24XMZ.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-
|
|
6
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-C5PYVRJE.js";
|
|
6
|
+
import "./chunk-GG33NSBW.js";
|
|
7
7
|
import "./chunk-YYSLYVNZ.js";
|
|
8
|
-
import "./chunk-
|
|
8
|
+
import "./chunk-BSX24XMZ.js";
|
|
9
9
|
import "./chunk-MNTIEWKF.js";
|
|
10
10
|
export {
|
|
11
11
|
hooksTarget,
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
machineName
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-C7ZUACP7.js";
|
|
4
4
|
import {
|
|
5
5
|
RelayUsage,
|
|
6
6
|
activeRelay,
|
|
7
7
|
saveCredential
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-BSX24XMZ.js";
|
|
9
9
|
import {
|
|
10
10
|
note
|
|
11
11
|
} from "./chunk-MNTIEWKF.js";
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
startDaemon,
|
|
17
17
|
terminalAttached,
|
|
18
18
|
time
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-BSX24XMZ.js";
|
|
20
20
|
import {
|
|
21
21
|
FAILED,
|
|
22
22
|
exitFlushed,
|
|
@@ -35,7 +35,7 @@ import { parseArgs } from "util";
|
|
|
35
35
|
// package.json
|
|
36
36
|
var package_default = {
|
|
37
37
|
name: "@scp-dev/cli",
|
|
38
|
-
version: "0.
|
|
38
|
+
version: "0.6.0",
|
|
39
39
|
description: "The swarm command line tool.",
|
|
40
40
|
license: "Apache-2.0",
|
|
41
41
|
homepage: "https://scp.dev",
|
|
@@ -281,6 +281,9 @@ agent sessions:
|
|
|
281
281
|
it while idle (claude --dangerously-load-development-channels server:scp; SCP_NAME=N)
|
|
282
282
|
--channels pushes messages into a Claude Code that ${CLI_NAME} claude started; setup mounts claude's shim with it.
|
|
283
283
|
Without --name, ${CLI_NAME} claude asks the session to pick its own name with ${CLI_NAME} name <name>.
|
|
284
|
+
${CLI_NAME} claude --bg [--name N] [--] [claude args...] the same in the background (claude --bg): an scp mount claims N and
|
|
285
|
+
$SCP_GRANT, so under env $(${CLI_NAME} spawn-env --name N) it links under you; prints its short id
|
|
286
|
+
${CLI_NAME} claude attach <id|name> [--name N] claude attach, renaming its endpoint to N first; --resume of a live bg session attaches
|
|
284
287
|
${CLI_NAME} join [<handle>] put the session that runs this shell on the relay (it then shows in list,
|
|
285
288
|
peers can message it, and its hooks hand it new messages), named <handle>
|
|
286
289
|
when given; on a joined session it renames it in place. Works for a session
|
|
@@ -289,6 +292,9 @@ agent sessions:
|
|
|
289
292
|
and title stay; a handle another endpoint holds, live or offline, is refused;
|
|
290
293
|
a spawned worker is named by its spawner (policy defaults.rename: self lets it);
|
|
291
294
|
--endpoint renames another agent, for the human at a terminal
|
|
295
|
+
${CLI_NAME} name <handle> --take-over [--endpoint EP] take the handle from an offline endpoint: it is retired and its
|
|
296
|
+
children, links and unread mail move over (the same harness session, such as
|
|
297
|
+
a resumed one, needs no flag); for the human at a terminal
|
|
292
298
|
${CLI_NAME} join [<handle>] --under <parent> link the session under the agent <parent> (one it may message), as if
|
|
293
299
|
<parent> had spawned it: it shows under <parent> in list --tree, the dashboard
|
|
294
300
|
and the graph, and takes on a worker's scope (the policy's child_default: by
|
|
@@ -396,7 +402,7 @@ var VERBS = {
|
|
|
396
402
|
link: IDENTITY,
|
|
397
403
|
unlink: IDENTITY,
|
|
398
404
|
leave: [...IDENTITY, "endpoint"],
|
|
399
|
-
name: [...IDENTITY, "endpoint"],
|
|
405
|
+
name: [...IDENTITY, "endpoint", "take-over"],
|
|
400
406
|
inbox: [...IDENTITY, "wait", "ack", "keep"],
|
|
401
407
|
reply: IDENTITY,
|
|
402
408
|
ack: [...IDENTITY, "all"],
|
|
@@ -569,14 +575,14 @@ async function relayMain(argv, cwd = process.cwd()) {
|
|
|
569
575
|
out(cliVersion());
|
|
570
576
|
return 0;
|
|
571
577
|
}
|
|
572
|
-
if (verb === "hook") return (await import("./hooks-
|
|
573
|
-
if (verb === "setup") return (await import("./setup-
|
|
574
|
-
if (verb === "claude") return (await import("./claude-
|
|
575
|
-
if (verb === "pi") return (await import("./pi-
|
|
576
|
-
if (verb === "codex") return (await import("./codex-
|
|
577
|
-
if (verb === "opencode") return (await import("./opencode-
|
|
578
|
+
if (verb === "hook") return (await import("./hooks-SWVIDONV.js")).relayHookCommand(rest, startDaemon);
|
|
579
|
+
if (verb === "setup") return (await import("./setup-O45SE5L7.js")).relaySetupCommand(rest, cwd, out);
|
|
580
|
+
if (verb === "claude") return (await import("./claude-NCPNZLIX.js")).claudeCommand(rest);
|
|
581
|
+
if (verb === "pi") return (await import("./pi-XHZAUDP4.js")).piCommand(rest);
|
|
582
|
+
if (verb === "codex") return (await import("./codex-4GTXURTS.js")).codexCommand(rest);
|
|
583
|
+
if (verb === "opencode") return (await import("./opencode-CPNR2G3W.js")).opencodeCommand(rest, process.env, void 0, cwd);
|
|
578
584
|
if (verb === "spawn") {
|
|
579
|
-
const { splitSpawn, spawnCommand } = await import("./spawn-
|
|
585
|
+
const { splitSpawn, spawnCommand } = await import("./spawn-CJSHYE7E.js");
|
|
580
586
|
const { flags } = splitSpawn(rest);
|
|
581
587
|
if (flags.includes("--help") || flags.includes("-h")) {
|
|
582
588
|
out(flags.includes("--all") ? RELAY_HELP : SPAWN_HELP);
|
|
@@ -584,7 +590,7 @@ async function relayMain(argv, cwd = process.cwd()) {
|
|
|
584
590
|
}
|
|
585
591
|
return spawnCommand(rest, cwd);
|
|
586
592
|
}
|
|
587
|
-
if (verb === "mesh") return (await import("./mesh-
|
|
593
|
+
if (verb === "mesh") return (await import("./mesh-XTMBRJLR.js")).meshCommand(rest);
|
|
588
594
|
const allowed = VERBS[verb];
|
|
589
595
|
if (!allowed) throw new RelayUsage(`unknown command "${verb}"`);
|
|
590
596
|
let parsed;
|
|
@@ -604,11 +610,11 @@ async function relayMain(argv, cwd = process.cwd()) {
|
|
|
604
610
|
return daemon(values.idle, values.policy);
|
|
605
611
|
}
|
|
606
612
|
if (verb === "mcp")
|
|
607
|
-
return (await import("./mcp-
|
|
613
|
+
return (await import("./mcp-RERRUUIX.js")).relayMcpCommand(values, positionals);
|
|
608
614
|
if (verb === "hooks") {
|
|
609
615
|
if (positionals[0] !== "install" || positionals.length > 1) throw new RelayUsage(`${CLI_NAME} hooks takes install --harness claude|codex|opencode|agy|muse`);
|
|
610
616
|
if (values.write && values.print) throw new RelayUsage("--print and --write: pick one");
|
|
611
|
-
return (await import("./install-
|
|
617
|
+
return (await import("./install-YE7LCGPC.js")).installHooks({
|
|
612
618
|
harness: values.harness,
|
|
613
619
|
scope: values.scope,
|
|
614
620
|
write: values.write === true,
|
|
@@ -619,27 +625,27 @@ async function relayMain(argv, cwd = process.cwd()) {
|
|
|
619
625
|
out
|
|
620
626
|
});
|
|
621
627
|
}
|
|
622
|
-
if (verb === "relay") return (await import("./relay-
|
|
623
|
-
if (verb === "up") return (await import("./up-
|
|
628
|
+
if (verb === "relay") return (await import("./relay-E4JFR33E.js")).relayVerb(positionals, values.json === true);
|
|
629
|
+
if (verb === "up") return (await import("./up-O2CMDGXP.js")).up(positionals, values, cwd, relinkBroker);
|
|
624
630
|
if (verb === "login") {
|
|
625
|
-
const code = await (await import("./relay-
|
|
631
|
+
const code = await (await import("./relay-E4JFR33E.js")).loginMain(positionals, values);
|
|
626
632
|
if (code === 0) await relinkRunning();
|
|
627
633
|
return code;
|
|
628
634
|
}
|
|
629
|
-
if (verb === "logout") return (await import("./relay-
|
|
635
|
+
if (verb === "logout") return (await import("./relay-E4JFR33E.js")).logoutMain(positionals, values.json === true);
|
|
630
636
|
if (verb === "cloud") {
|
|
631
|
-
const code = await (await import("./remote-
|
|
637
|
+
const code = await (await import("./remote-3R4GRDGI.js")).cloudMain(positionals, values, cloudStatus);
|
|
632
638
|
if (code === 0 && positionals[0] === "enable") await relinkRunning();
|
|
633
639
|
return code;
|
|
634
640
|
}
|
|
635
|
-
if (verb === "join") return (await import("./join-
|
|
641
|
+
if (verb === "join") return (await import("./join-64BU6SEY.js")).joinCommand(values, positionals, cwd, out);
|
|
636
642
|
if (verb === "holds") holdsArgs(values, positionals);
|
|
637
643
|
const bodyFromStdin = (verb === "send" || verb === "ask" || verb === "reply") && (positionals[1] === void 0 || positionals[1] === "-");
|
|
638
644
|
const humanAdopt = verb === "adopt" && values.parent !== void 0 && values.as === void 0 && terminalAttached(process, false);
|
|
639
645
|
const opened = humanAdopt ? await openAdoptHuman(cwd, values) : await open(verb, values, cwd, bodyFromStdin);
|
|
640
646
|
const { client } = opened;
|
|
641
647
|
try {
|
|
642
|
-
if (verb === "machines") return await (await import("./remote-
|
|
648
|
+
if (verb === "machines") return await (await import("./remote-3R4GRDGI.js")).machinesVerb(client, positionals, values.json === true);
|
|
643
649
|
return await runVerb(opened, verb, values, positionals, cwd);
|
|
644
650
|
} finally {
|
|
645
651
|
client.close();
|
|
@@ -647,7 +653,7 @@ async function relayMain(argv, cwd = process.cwd()) {
|
|
|
647
653
|
}
|
|
648
654
|
async function openAdoptHuman(cwd, values) {
|
|
649
655
|
if (values.cloud || process.env.SCP_TRANSPORT === "cloud") {
|
|
650
|
-
const { openCloud } = await import("./remote-
|
|
656
|
+
const { openCloud } = await import("./remote-3R4GRDGI.js");
|
|
651
657
|
return { ...await openCloud({ tty: true, ...values.machine !== void 0 ? { machine: values.machine } : {} }), broker: null, bound: "human" };
|
|
652
658
|
}
|
|
653
659
|
if (values.machine !== void 0) throw new RelayUsage("--machine names the machine of the cloud transport: add --cloud");
|
|
@@ -832,9 +838,9 @@ async function runVerb({ client, me, broker, where, bound, harnessPid }, verb, v
|
|
|
832
838
|
return 0;
|
|
833
839
|
}
|
|
834
840
|
case "peek":
|
|
835
|
-
return (await import("./peek-
|
|
841
|
+
return (await import("./peek-GEYQ7SHV.js")).peekCommand(localClient(client, broker, verb), values, positionals);
|
|
836
842
|
case "set-peek":
|
|
837
|
-
return (await import("./peek-
|
|
843
|
+
return (await import("./peek-GEYQ7SHV.js")).setPeekCommand(localClient(client, broker, verb), values, positionals);
|
|
838
844
|
case "why": {
|
|
839
845
|
const [from, to] = positionals;
|
|
840
846
|
if (!from || !to || positionals.length > 2) throw new RelayUsage(`${CLI_NAME} why takes <from> <to>`);
|
|
@@ -1058,7 +1064,11 @@ async function runVerb({ client, me, broker, where, bound, harnessPid }, verb, v
|
|
|
1058
1064
|
return 0;
|
|
1059
1065
|
}
|
|
1060
1066
|
const before = endpoint ?? me?.address;
|
|
1061
|
-
const view = await client.request("rename", {
|
|
1067
|
+
const view = await client.request("rename", {
|
|
1068
|
+
handle: positionals[0],
|
|
1069
|
+
...endpoint !== void 0 ? { endpoint } : {},
|
|
1070
|
+
...values["take-over"] === true ? { take_over: true } : {}
|
|
1071
|
+
});
|
|
1062
1072
|
if (asJson) json(view);
|
|
1063
1073
|
else out(before && before !== view.address ? `${before} is now ${view.address}` : `${view.address}`);
|
|
1064
1074
|
return 0;
|
|
@@ -1454,11 +1464,11 @@ async function daemon(idle, policyFile) {
|
|
|
1454
1464
|
});
|
|
1455
1465
|
let broker;
|
|
1456
1466
|
try {
|
|
1457
|
-
const { daemonBridge } = await import("./remote-
|
|
1467
|
+
const { daemonBridge } = await import("./remote-3R4GRDGI.js");
|
|
1458
1468
|
const bridge = await daemonBridge();
|
|
1459
1469
|
broker = await startBroker({
|
|
1460
1470
|
dir: relayDir(),
|
|
1461
|
-
...bridge ? { bridge } : await (await import("./mesh-
|
|
1471
|
+
...bridge ? { bridge } : await (await import("./mesh-XTMBRJLR.js")).meshBrokerOptions(),
|
|
1462
1472
|
bridgeConfig: () => daemonBridge(),
|
|
1463
1473
|
...idleMs !== void 0 ? { idleMs } : {},
|
|
1464
1474
|
...policyFile ? { policyPath: resolve(policyFile) } : {}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
spawnDetached
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-CVW3INZO.js";
|
|
4
4
|
import "./chunk-KN7WEIE4.js";
|
|
5
|
-
import "./chunk-
|
|
5
|
+
import "./chunk-DEK3TE6T.js";
|
|
6
6
|
import {
|
|
7
7
|
mcpInstall
|
|
8
|
-
} from "./chunk-
|
|
9
|
-
import "./chunk-
|
|
8
|
+
} from "./chunk-C5PYVRJE.js";
|
|
9
|
+
import "./chunk-GG33NSBW.js";
|
|
10
10
|
import "./chunk-YYSLYVNZ.js";
|
|
11
11
|
import {
|
|
12
12
|
CHANNELS_ENV,
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
relayIdentity,
|
|
19
19
|
startDaemon,
|
|
20
20
|
writeShimBinding
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-BSX24XMZ.js";
|
|
22
22
|
import "./chunk-MNTIEWKF.js";
|
|
23
23
|
|
|
24
24
|
// src/mcp.ts
|
|
@@ -2,18 +2,18 @@ import {
|
|
|
2
2
|
mcpFile,
|
|
3
3
|
mountedEntry,
|
|
4
4
|
whichOnPath
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-DEK3TE6T.js";
|
|
6
6
|
import {
|
|
7
7
|
hooksTarget
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-C5PYVRJE.js";
|
|
9
9
|
import {
|
|
10
10
|
opencodePlugin
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-GG33NSBW.js";
|
|
12
12
|
import "./chunk-YYSLYVNZ.js";
|
|
13
13
|
import {
|
|
14
14
|
RelayUsage,
|
|
15
15
|
gitToplevel
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-BSX24XMZ.js";
|
|
17
17
|
import "./chunk-MNTIEWKF.js";
|
|
18
18
|
|
|
19
19
|
// src/opencode.ts
|
|
@@ -15,11 +15,11 @@ import {
|
|
|
15
15
|
verifyMount,
|
|
16
16
|
verifyMusePlugin,
|
|
17
17
|
whichOnPath
|
|
18
|
-
} from "./chunk-
|
|
19
|
-
import "./chunk-
|
|
20
|
-
import "./chunk-
|
|
18
|
+
} from "./chunk-DEK3TE6T.js";
|
|
19
|
+
import "./chunk-C5PYVRJE.js";
|
|
20
|
+
import "./chunk-GG33NSBW.js";
|
|
21
21
|
import "./chunk-YYSLYVNZ.js";
|
|
22
|
-
import "./chunk-
|
|
22
|
+
import "./chunk-BSX24XMZ.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-
|
|
34
|
+
} from "./chunk-CVW3INZO.js";
|
|
35
35
|
import {
|
|
36
36
|
SPAWN_HELP
|
|
37
37
|
} from "./chunk-KN7WEIE4.js";
|
|
38
|
-
import "./chunk-
|
|
39
|
-
import "./chunk-
|
|
40
|
-
import "./chunk-
|
|
38
|
+
import "./chunk-DEK3TE6T.js";
|
|
39
|
+
import "./chunk-C5PYVRJE.js";
|
|
40
|
+
import "./chunk-GG33NSBW.js";
|
|
41
41
|
import "./chunk-YYSLYVNZ.js";
|
|
42
|
-
import "./chunk-
|
|
42
|
+
import "./chunk-BSX24XMZ.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-
|
|
5
|
+
} from "./chunk-BSX24XMZ.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-
|
|
32
|
+
const code = await (await import("./login-4IF26HH5.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-
|
|
39
|
+
const enabled = await (await import("./remote-3R4GRDGI.js")).cloudMain(["enable"], values.machine !== void 0 ? { machine: values.machine } : {}, brokerStatus);
|
|
40
40
|
if (enabled !== 0) return enabled;
|
|
41
|
-
const setup = (await import("./setup-
|
|
41
|
+
const setup = (await import("./setup-O45SE5L7.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-
|
|
46
|
+
const { detectHarnesses, whichOnPath } = await import("./setup-O45SE5L7.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.
|
|
3
|
+
"version": "0.6.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.3.
|
|
28
|
-
"@scp-dev/broker": "0.4.
|
|
29
|
-
"@scp-dev/hub": "0.6.
|
|
30
|
-
"@scp-dev/mcp": "0.2.
|
|
27
|
+
"@scp-dev/core": "0.3.1",
|
|
28
|
+
"@scp-dev/broker": "0.4.1",
|
|
29
|
+
"@scp-dev/hub": "0.6.2",
|
|
30
|
+
"@scp-dev/mcp": "0.2.1",
|
|
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.
|
|
35
|
+
"@scp-dev/mesh": "0.0.8",
|
|
36
36
|
"opencode-ai": "1.18.34",
|
|
37
37
|
"tsup": "^8.5.1"
|
|
38
38
|
},
|
package/dist/claude-RNH2E4GU.js
DELETED
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
entryArgv,
|
|
3
|
-
mcpFile,
|
|
4
|
-
mountedEntry,
|
|
5
|
-
whichOnPath
|
|
6
|
-
} from "./chunk-UKQBH4AQ.js";
|
|
7
|
-
import "./chunk-2342GTME.js";
|
|
8
|
-
import "./chunk-XQHPDNVG.js";
|
|
9
|
-
import "./chunk-YYSLYVNZ.js";
|
|
10
|
-
import {
|
|
11
|
-
CHANNELS_ENV,
|
|
12
|
-
RelayUsage,
|
|
13
|
-
deriveHandle,
|
|
14
|
-
joinMode
|
|
15
|
-
} from "./chunk-AAFHLHXG.js";
|
|
16
|
-
import "./chunk-MNTIEWKF.js";
|
|
17
|
-
|
|
18
|
-
// src/claude.ts
|
|
19
|
-
import { spawn } from "child_process";
|
|
20
|
-
import { existsSync, readFileSync } from "fs";
|
|
21
|
-
import { join } from "path";
|
|
22
|
-
import { CLI_NAME, validHandle } from "@scp-dev/core";
|
|
23
|
-
var CHANNEL_FLAGS = ["--dangerously-load-development-channels", "server:scp"];
|
|
24
|
-
function claudeArgv(argv) {
|
|
25
|
-
let name;
|
|
26
|
-
let i = 0;
|
|
27
|
-
for (; ; ) {
|
|
28
|
-
const arg = argv[i];
|
|
29
|
-
if (arg === "--name" || arg === "--as") {
|
|
30
|
-
if (argv[i + 1] === void 0) throw new RelayUsage(`${CLI_NAME} claude ${arg} takes a handle`);
|
|
31
|
-
name = argv[i + 1];
|
|
32
|
-
i += 2;
|
|
33
|
-
} else if (arg?.startsWith("--name=") || arg?.startsWith("--as=")) {
|
|
34
|
-
name = arg.slice(arg.indexOf("=") + 1);
|
|
35
|
-
i++;
|
|
36
|
-
} else break;
|
|
37
|
-
}
|
|
38
|
-
if (argv[i] === "--") i++;
|
|
39
|
-
name = name?.replace(/^me\//, "");
|
|
40
|
-
if (name !== void 0 && !validHandle(name)) throw new RelayUsage(`--name ${JSON.stringify(name)} is not a valid agent handle`);
|
|
41
|
-
return { ...name !== void 0 ? { name } : {}, args: argv.slice(i) };
|
|
42
|
-
}
|
|
43
|
-
function claudeLaunchArgs(args, added) {
|
|
44
|
-
const end = args.indexOf("--");
|
|
45
|
-
const at = end < 0 ? args.length : end;
|
|
46
|
-
const channels = args.some((arg, i) => i < at && (arg === "server:scp" || arg === `${CHANNEL_FLAGS[0]}=server:scp`)) ? [] : CHANNEL_FLAGS;
|
|
47
|
-
return [...args.slice(0, at), ...channels, ...added, ...args.slice(at)];
|
|
48
|
-
}
|
|
49
|
-
var STRICT_HINT = `${CLI_NAME} claude: --strict-mcp-config without --mcp-config drops the scp mount, so messages cannot wake this session`;
|
|
50
|
-
function externalMcp(args) {
|
|
51
|
-
return args.some((arg) => arg === "--mcp-config" || arg.startsWith("--mcp-config="));
|
|
52
|
-
}
|
|
53
|
-
function namePrompt(name, args, env, cwd) {
|
|
54
|
-
if (name !== void 0 || joinMode(env) === "manual" || args.some((arg) => /^--(append-)?system-prompt/.test(arg))) return [];
|
|
55
|
-
const handle = env.SCP_NAME || deriveHandle("claude-code", cwd);
|
|
56
|
-
return [
|
|
57
|
-
"--append-system-prompt",
|
|
58
|
-
`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.`
|
|
59
|
-
];
|
|
60
|
-
}
|
|
61
|
-
function mountHint(env, cwd = process.cwd()) {
|
|
62
|
-
const file = mcpFile("claude", env);
|
|
63
|
-
const entries = [];
|
|
64
|
-
try {
|
|
65
|
-
const user = mountedEntry("claude", file);
|
|
66
|
-
if (user) entries.push(user);
|
|
67
|
-
const config = existsSync(file) ? JSON.parse(readFileSync(file, "utf8")) : {};
|
|
68
|
-
const local = config.projects?.[cwd]?.mcpServers?.scp;
|
|
69
|
-
if (local && typeof local === "object") entries.push(local);
|
|
70
|
-
} catch {
|
|
71
|
-
return `${CLI_NAME} claude: ${file} is unreadable, so the scp mount is unchecked; fix it or run ${CLI_NAME} setup --write`;
|
|
72
|
-
}
|
|
73
|
-
const project = join(cwd, ".mcp.json");
|
|
74
|
-
try {
|
|
75
|
-
const entry = existsSync(project) ? mountedEntry("claude", project) : void 0;
|
|
76
|
-
if (entry) entries.push(entry);
|
|
77
|
-
} catch {
|
|
78
|
-
}
|
|
79
|
-
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`;
|
|
80
|
-
if (!entries.some((entry) => entryArgv("claude", entry).includes("--channels")))
|
|
81
|
-
return `${CLI_NAME} claude: the scp mount lacks --channels, so messages cannot wake this session; run ${CLI_NAME} setup --write`;
|
|
82
|
-
return void 0;
|
|
83
|
-
}
|
|
84
|
-
async function claudeCommand(argv, env = process.env, err = (line) => void process.stderr.write(`${line}
|
|
85
|
-
`), cwd = process.cwd()) {
|
|
86
|
-
if (argv[0] === "--help" || argv[0] === "-h") {
|
|
87
|
-
process.stdout.write(
|
|
88
|
-
`${CLI_NAME} claude [--name N | --as N] [--] [claude args...] start Claude Code with the scp channel loaded, so peer messages wake it
|
|
89
|
-
`
|
|
90
|
-
);
|
|
91
|
-
return 0;
|
|
92
|
-
}
|
|
93
|
-
const { name, args } = claudeArgv(argv);
|
|
94
|
-
const bin = whichOnPath("claude", env);
|
|
95
|
-
if (!bin) throw new RelayUsage("claude is not on PATH");
|
|
96
|
-
const external = externalMcp(args);
|
|
97
|
-
const hint = external ? void 0 : args.includes("--strict-mcp-config") ? STRICT_HINT : mountHint(env, cwd);
|
|
98
|
-
if (hint) throw new RelayUsage(hint);
|
|
99
|
-
if (external) err(`${CLI_NAME} claude: using your --mcp-config; it needs the scp server with --channels for messages to wake this session`);
|
|
100
|
-
const child = spawn(bin, claudeLaunchArgs(args, namePrompt(name, args, env, cwd)), {
|
|
101
|
-
cwd,
|
|
102
|
-
stdio: "inherit",
|
|
103
|
-
env: { ...env, ...name !== void 0 ? { SCP_NAME: name } : {}, [CHANNELS_ENV]: String(process.pid) }
|
|
104
|
-
});
|
|
105
|
-
const forward = (signal) => () => void child.kill(signal);
|
|
106
|
-
const handlers = ["SIGTERM", "SIGHUP"].map((signal) => [signal, forward(signal)]);
|
|
107
|
-
const ignore = () => {
|
|
108
|
-
};
|
|
109
|
-
process.on("SIGINT", ignore);
|
|
110
|
-
for (const [signal, handler] of handlers) process.on(signal, handler);
|
|
111
|
-
try {
|
|
112
|
-
return await new Promise((resolve, reject) => {
|
|
113
|
-
child.once("error", reject);
|
|
114
|
-
child.once("exit", (code, signal) => resolve(code ?? (signal ? 128 + (signalNumber(signal) ?? 1) : 1)));
|
|
115
|
-
});
|
|
116
|
-
} finally {
|
|
117
|
-
process.off("SIGINT", ignore);
|
|
118
|
-
for (const [signal, handler] of handlers) process.off(signal, handler);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
var SIGNALS = { SIGHUP: 1, SIGINT: 2, SIGKILL: 9, SIGTERM: 15 };
|
|
122
|
-
var signalNumber = (signal) => SIGNALS[signal];
|
|
123
|
-
export {
|
|
124
|
-
CHANNEL_FLAGS,
|
|
125
|
-
claudeArgv,
|
|
126
|
-
claudeCommand,
|
|
127
|
-
claudeLaunchArgs,
|
|
128
|
-
mountHint,
|
|
129
|
-
namePrompt
|
|
130
|
-
};
|