@scp-dev/cli 0.6.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.
- package/dist/{chunk-GG33NSBW.js → chunk-277BAY7J.js} +19 -3
- package/dist/{chunk-BSX24XMZ.js → chunk-3SOIVANO.js} +45 -4
- package/dist/{chunk-C5PYVRJE.js → chunk-LRQP25RI.js} +2 -2
- package/dist/{chunk-C7ZUACP7.js → chunk-LUDLDWH2.js} +1 -1
- package/dist/{codex-4GTXURTS.js → chunk-LWMTZH36.js} +6 -10
- package/dist/{chunk-CVW3INZO.js → chunk-RZUQ422C.js} +14 -6
- package/dist/{chunk-DEK3TE6T.js → chunk-SNW53KT3.js} +3 -3
- package/dist/{claude-NCPNZLIX.js → claude-WEHOLJ26.js} +5 -5
- package/dist/cli.js +1 -1
- package/dist/codex-54UWPDY5.js +26 -0
- package/dist/{hooks-SWVIDONV.js → hooks-ULKKUHPF.js} +6 -2
- package/dist/{install-YE7LCGPC.js → install-5A3ETGF6.js} +3 -3
- package/dist/{join-64BU6SEY.js → join-FFT7RQRW.js} +1 -1
- package/dist/{login-4IF26HH5.js → login-DCNCC3RS.js} +2 -2
- package/dist/{main-RA3MP25N.js → main-CDLW3MV5.js} +33 -24
- package/dist/{mcp-RERRUUIX.js → mcp-7GB35CTY.js} +7 -6
- package/dist/{mesh-XTMBRJLR.js → mesh-TDOVAHZ3.js} +1 -1
- package/dist/muse-S7FPY4CL.js +429 -0
- package/dist/{opencode-CPNR2G3W.js → opencode-WFMQYCI2.js} +4 -4
- package/dist/{peek-GEYQ7SHV.js → peek-X4QQFMQJ.js} +1 -1
- package/dist/{pi-XHZAUDP4.js → pi-5IPU6GA4.js} +1 -1
- package/dist/{relay-E4JFR33E.js → relay-7WBNUACH.js} +1 -1
- package/dist/{remote-3R4GRDGI.js → remote-YO5B2HQI.js} +2 -2
- package/dist/resume-3ZRDXSTX.js +308 -0
- package/dist/{setup-O45SE5L7.js → setup-U7CWN5QP.js} +4 -4
- package/dist/{spawn-CJSHYE7E.js → spawn-VZK5MD3R.js} +13 -5
- package/dist/{up-O2CMDGXP.js → up-S4KJBWI6.js} +8 -6
- package/package.json +6 -6
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
import {
|
|
2
|
+
connectCodexChannel
|
|
3
|
+
} from "./chunk-LWMTZH36.js";
|
|
4
|
+
import {
|
|
5
|
+
MUSE_MODE,
|
|
6
|
+
MUSE_MODES_ALLOWED,
|
|
7
|
+
museModes
|
|
8
|
+
} from "./chunk-RZUQ422C.js";
|
|
9
|
+
import "./chunk-KN7WEIE4.js";
|
|
10
|
+
import {
|
|
11
|
+
mcpFile,
|
|
12
|
+
mountedEntry
|
|
13
|
+
} from "./chunk-SNW53KT3.js";
|
|
14
|
+
import "./chunk-LRQP25RI.js";
|
|
15
|
+
import "./chunk-277BAY7J.js";
|
|
16
|
+
import "./chunk-YYSLYVNZ.js";
|
|
17
|
+
import {
|
|
18
|
+
RelayUsage,
|
|
19
|
+
processKey,
|
|
20
|
+
relayIdentity,
|
|
21
|
+
startDaemon,
|
|
22
|
+
writeMuseLaunch
|
|
23
|
+
} from "./chunk-3SOIVANO.js";
|
|
24
|
+
import "./chunk-MNTIEWKF.js";
|
|
25
|
+
|
|
26
|
+
// src/muse.ts
|
|
27
|
+
import { spawn } from "child_process";
|
|
28
|
+
import { randomBytes } from "crypto";
|
|
29
|
+
import { homedir } from "os";
|
|
30
|
+
import { PassThrough } from "stream";
|
|
31
|
+
import { connectBroker, relayDir } from "@scp-dev/broker";
|
|
32
|
+
import { CLI_NAME, validHandle } from "@scp-dev/core";
|
|
33
|
+
import { MCP_PROTOCOLS, runRelayMcp } from "@scp-dev/mcp";
|
|
34
|
+
var MUSE_HELP = `${CLI_NAME} muse [--name N | --as N] [--resume SESSION] [--approval-mode never|on-request|untrusted] [--] [muse serve args...]
|
|
35
|
+
runs a headless Muse session (muse serve) that relay messages wake: a message starts a turn on the idle session or steers a running one.
|
|
36
|
+
every other argument goes to muse serve (--provider, --model, -c, sandbox flags); it runs with --contributor-mode off unless you pass on.
|
|
37
|
+
prints the agent's messages; approvals the mode leaves to a human are declined. --resume SESSION reopens a stored session.
|
|
38
|
+
needs the scp mount and plugin ${CLI_NAME} setup --write installs. $SCP_MUSE_BIN picks the muse binary (default muse on PATH).`;
|
|
39
|
+
var APPROVAL = { never: "allowAll", "on-request": "onRequest", untrusted: "promptUnmatched" };
|
|
40
|
+
var NO_USER_INPUT = "--disable-request-user-input";
|
|
41
|
+
function museLaunch(args, env) {
|
|
42
|
+
let name;
|
|
43
|
+
let resume;
|
|
44
|
+
let approval = "on-request";
|
|
45
|
+
const serveArgs = [];
|
|
46
|
+
const value = (flag, next) => {
|
|
47
|
+
if (next === void 0) throw new RelayUsage(`${CLI_NAME} muse ${flag} takes a value`);
|
|
48
|
+
return next;
|
|
49
|
+
};
|
|
50
|
+
for (let i = 0; i < args.length; i++) {
|
|
51
|
+
const arg = args[i];
|
|
52
|
+
if (arg === "--") {
|
|
53
|
+
serveArgs.push(...args.slice(i + 1));
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
const eq = arg.startsWith("--") ? arg.indexOf("=") : -1;
|
|
57
|
+
const flag = eq > 0 ? arg.slice(0, eq) : arg;
|
|
58
|
+
const take = () => eq > 0 ? arg.slice(eq + 1) : value(flag, args[++i]);
|
|
59
|
+
if (flag === "--name" || flag === "--as") name = take();
|
|
60
|
+
else if (flag === "--resume") resume = take();
|
|
61
|
+
else if (flag === "--approval-mode") approval = take();
|
|
62
|
+
else serveArgs.push(arg);
|
|
63
|
+
}
|
|
64
|
+
name = name?.replace(/^me\//, "");
|
|
65
|
+
if (name !== void 0 && !validHandle(name)) throw new RelayUsage(`${JSON.stringify(name)} is not a valid agent handle`);
|
|
66
|
+
const approvalMode = APPROVAL[approval];
|
|
67
|
+
if (!approvalMode) throw new RelayUsage(`${CLI_NAME} muse --approval-mode takes never, on-request or untrusted, not ${JSON.stringify(approval)}`);
|
|
68
|
+
const modes = museModes(serveArgs);
|
|
69
|
+
for (const mode of modes) {
|
|
70
|
+
if (mode === void 0 || !MUSE_MODES_ALLOWED.has(mode))
|
|
71
|
+
throw new RelayUsage(`${CLI_NAME} muse: muse runs with ${MUSE_MODE} off or on, not ${mode === void 0 ? "a bare flag" : JSON.stringify(mode)}`);
|
|
72
|
+
}
|
|
73
|
+
const { SCP_SESSION: _session, SCP_PARENT: _parent, ...clean } = env;
|
|
74
|
+
return {
|
|
75
|
+
...name !== void 0 ? { name } : {},
|
|
76
|
+
...resume !== void 0 ? { resume } : {},
|
|
77
|
+
approvalMode,
|
|
78
|
+
serveArgs: [...modes.length ? [] : [MUSE_MODE, "off"], ...serveArgs.includes(NO_USER_INPUT) ? [] : [NO_USER_INPUT], ...serveArgs],
|
|
79
|
+
env: { ...clean, SCP_HARNESS: "muse", ...name !== void 0 ? { SCP_NAME: name } : {} }
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
function museBroker(env) {
|
|
83
|
+
return relayDir({ HOME: env.HOME || homedir() });
|
|
84
|
+
}
|
|
85
|
+
function uuidv7(now = Date.now()) {
|
|
86
|
+
const bytes = randomBytes(16);
|
|
87
|
+
for (let i = 0; i < 6; i++) bytes[i] = Math.floor(now / 2 ** (8 * (5 - i))) & 255;
|
|
88
|
+
bytes[6] = bytes[6] & 15 | 112;
|
|
89
|
+
bytes[8] = bytes[8] & 63 | 128;
|
|
90
|
+
const hex = bytes.toString("hex");
|
|
91
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
92
|
+
}
|
|
93
|
+
var MuseHost = class {
|
|
94
|
+
constructor(input, output, onMessage = () => {
|
|
95
|
+
}, timeoutMs = 3e4) {
|
|
96
|
+
this.input = input;
|
|
97
|
+
this.onMessage = onMessage;
|
|
98
|
+
this.timeoutMs = timeoutMs;
|
|
99
|
+
output.setEncoding("utf8");
|
|
100
|
+
output.on("data", (chunk) => {
|
|
101
|
+
this.buffer += chunk;
|
|
102
|
+
for (; ; ) {
|
|
103
|
+
const end = this.buffer.indexOf("\n");
|
|
104
|
+
if (end < 0) break;
|
|
105
|
+
const line = this.buffer.slice(0, end).trim();
|
|
106
|
+
this.buffer = this.buffer.slice(end + 1);
|
|
107
|
+
if (line) this.receive(line);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
output.on("close", () => this.close(new Error("muse serve closed")));
|
|
111
|
+
input.on("error", (error) => this.close(error));
|
|
112
|
+
}
|
|
113
|
+
input;
|
|
114
|
+
onMessage;
|
|
115
|
+
timeoutMs;
|
|
116
|
+
next = 1;
|
|
117
|
+
buffer = "";
|
|
118
|
+
closed;
|
|
119
|
+
pending = /* @__PURE__ */ new Map();
|
|
120
|
+
receive(line) {
|
|
121
|
+
let message;
|
|
122
|
+
try {
|
|
123
|
+
message = JSON.parse(line);
|
|
124
|
+
} catch {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
const pending = typeof message.id === "number" && message.method === void 0 ? this.pending.get(message.id) : void 0;
|
|
128
|
+
if (!pending) {
|
|
129
|
+
this.onMessage(message);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
this.pending.delete(message.id);
|
|
133
|
+
clearTimeout(pending.timer);
|
|
134
|
+
if (message.error) pending.reject(new Error(JSON.stringify(message.error)));
|
|
135
|
+
else pending.resolve(message.result ?? {});
|
|
136
|
+
}
|
|
137
|
+
send(message) {
|
|
138
|
+
if (this.closed) throw this.closed;
|
|
139
|
+
this.input.write(`${JSON.stringify({ jsonrpc: "2.0", ...message })}
|
|
140
|
+
`);
|
|
141
|
+
}
|
|
142
|
+
request(method, params) {
|
|
143
|
+
if (this.closed) return Promise.reject(this.closed);
|
|
144
|
+
const id = this.next++;
|
|
145
|
+
return new Promise((resolve, reject) => {
|
|
146
|
+
const timer = setTimeout(() => {
|
|
147
|
+
this.pending.delete(id);
|
|
148
|
+
reject(new Error(`muse ${method} timed out`));
|
|
149
|
+
}, this.timeoutMs);
|
|
150
|
+
this.pending.set(id, { resolve, reject, timer });
|
|
151
|
+
try {
|
|
152
|
+
this.send({ id, method, params });
|
|
153
|
+
} catch (error) {
|
|
154
|
+
this.pending.delete(id);
|
|
155
|
+
clearTimeout(timer);
|
|
156
|
+
reject(error);
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
close(error = new Error("muse serve closed")) {
|
|
161
|
+
this.closed ??= error;
|
|
162
|
+
for (const pending of this.pending.values()) {
|
|
163
|
+
clearTimeout(pending.timer);
|
|
164
|
+
pending.reject(this.closed);
|
|
165
|
+
}
|
|
166
|
+
this.pending.clear();
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
var MuseWaker = class {
|
|
170
|
+
constructor(transport, sessionId, retryMs = 2e3) {
|
|
171
|
+
this.transport = transport;
|
|
172
|
+
this.sessionId = sessionId;
|
|
173
|
+
this.retryMs = retryMs;
|
|
174
|
+
}
|
|
175
|
+
transport;
|
|
176
|
+
sessionId;
|
|
177
|
+
retryMs;
|
|
178
|
+
queue = [];
|
|
179
|
+
serial;
|
|
180
|
+
timer;
|
|
181
|
+
stopped = false;
|
|
182
|
+
push(text) {
|
|
183
|
+
this.queue.push(text);
|
|
184
|
+
void this.flush();
|
|
185
|
+
}
|
|
186
|
+
flush() {
|
|
187
|
+
if (this.serial) return this.serial;
|
|
188
|
+
if (this.stopped || !this.queue.length) return Promise.resolve();
|
|
189
|
+
clearTimeout(this.timer);
|
|
190
|
+
this.timer = void 0;
|
|
191
|
+
const count = this.queue.length;
|
|
192
|
+
this.serial = this.transport.request("turn/start", {
|
|
193
|
+
commandId: uuidv7(),
|
|
194
|
+
sessionId: this.sessionId,
|
|
195
|
+
input: [{ type: "text", text: this.queue.slice(0, count).join("\n\n") }],
|
|
196
|
+
ifBusy: "steer"
|
|
197
|
+
}).then(
|
|
198
|
+
(result) => {
|
|
199
|
+
if (result.status !== "accepted") return false;
|
|
200
|
+
this.queue.splice(0, count);
|
|
201
|
+
return true;
|
|
202
|
+
},
|
|
203
|
+
() => false
|
|
204
|
+
).then((ok) => {
|
|
205
|
+
this.serial = void 0;
|
|
206
|
+
if (this.stopped || !this.queue.length) return;
|
|
207
|
+
if (ok) return this.flush();
|
|
208
|
+
this.timer ??= setTimeout(() => {
|
|
209
|
+
this.timer = void 0;
|
|
210
|
+
void this.flush();
|
|
211
|
+
}, this.retryMs);
|
|
212
|
+
});
|
|
213
|
+
return this.serial;
|
|
214
|
+
}
|
|
215
|
+
close() {
|
|
216
|
+
this.stopped = true;
|
|
217
|
+
clearTimeout(this.timer);
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
function answerRequest(host, message, log) {
|
|
221
|
+
const params = message.params ?? {};
|
|
222
|
+
if (message.method !== "approval/request") {
|
|
223
|
+
host.send({ id: message.id, error: { code: -32601, message: `${String(message.method)} is unsupported in a headless session` } });
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
host.send({ id: message.id, result: {} });
|
|
227
|
+
const choices = Array.isArray(params.availableChoices) ? params.availableChoices : [];
|
|
228
|
+
const choice = choices.find((c) => c.decision === "denied") ?? choices.find((c) => c.decision === "abort");
|
|
229
|
+
const subject = params.subject ?? {};
|
|
230
|
+
log(`${CLI_NAME} muse: declined ${String(subject.command ?? subject.kind ?? "an approval")}`);
|
|
231
|
+
if (!choice) return;
|
|
232
|
+
void host.request("approval/decide", {
|
|
233
|
+
approvalId: params.approvalId,
|
|
234
|
+
choiceId: choice.choiceId,
|
|
235
|
+
commandId: uuidv7(),
|
|
236
|
+
requirementId: params.currentRequirementId,
|
|
237
|
+
sessionId: params.sessionId
|
|
238
|
+
}).catch((error) => log(`${CLI_NAME} muse: could not decline: ${String(error)}`));
|
|
239
|
+
}
|
|
240
|
+
async function terminate(child) {
|
|
241
|
+
if (child.exitCode !== null || child.signalCode !== null || !child.pid) return;
|
|
242
|
+
await new Promise((resolve) => {
|
|
243
|
+
const timer = setTimeout(() => child.kill("SIGKILL"), 3e3);
|
|
244
|
+
child.once("exit", () => {
|
|
245
|
+
clearTimeout(timer);
|
|
246
|
+
resolve();
|
|
247
|
+
});
|
|
248
|
+
child.kill("SIGTERM");
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
var BIND_TIMEOUT_MS = 3e4;
|
|
252
|
+
async function museCommand(args) {
|
|
253
|
+
if (args[0] === "--help" || args[0] === "-h") {
|
|
254
|
+
process.stdout.write(`${MUSE_HELP}
|
|
255
|
+
`);
|
|
256
|
+
return 0;
|
|
257
|
+
}
|
|
258
|
+
const launch = museLaunch(args, process.env);
|
|
259
|
+
const cwd = process.cwd();
|
|
260
|
+
const log = (line) => void process.stderr.write(`${line}
|
|
261
|
+
`);
|
|
262
|
+
try {
|
|
263
|
+
if (!mountedEntry("muse", mcpFile("muse", launch.env)))
|
|
264
|
+
throw new RelayUsage(`${CLI_NAME} muse: Muse has no scp MCP mount, so messages cannot wake this session; run ${CLI_NAME} setup --write`);
|
|
265
|
+
} catch (error) {
|
|
266
|
+
if (error instanceof RelayUsage) throw error;
|
|
267
|
+
throw new RelayUsage(
|
|
268
|
+
`${CLI_NAME} muse: ${mcpFile("muse", launch.env)} is unreadable, so the scp mount is unchecked; fix it or run ${CLI_NAME} setup --write`
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
const broker = museBroker(launch.env);
|
|
272
|
+
if (relayDir(launch.env) !== broker) log(`${CLI_NAME} muse: Muse starts its shim and hooks without SCP_DIR or XDG_STATE_HOME, so this session uses ${broker}`);
|
|
273
|
+
const env = { ...launch.env, SCP_DIR: broker };
|
|
274
|
+
const bin = env.SCP_MUSE_BIN || "muse";
|
|
275
|
+
const server = spawn(bin, ["serve", ...launch.serveArgs], { env: launch.env, stdio: ["pipe", "pipe", "pipe"] });
|
|
276
|
+
let stderr = Buffer.alloc(0);
|
|
277
|
+
server.stderr.on("data", (data) => {
|
|
278
|
+
stderr = Buffer.concat([stderr, data]).subarray(-8192);
|
|
279
|
+
});
|
|
280
|
+
let serverError;
|
|
281
|
+
let died = false;
|
|
282
|
+
let finish;
|
|
283
|
+
const done = new Promise((resolve) => {
|
|
284
|
+
finish = resolve;
|
|
285
|
+
});
|
|
286
|
+
server.on("error", (error) => {
|
|
287
|
+
serverError = error;
|
|
288
|
+
died = true;
|
|
289
|
+
finish(1);
|
|
290
|
+
});
|
|
291
|
+
server.on("exit", () => {
|
|
292
|
+
died = true;
|
|
293
|
+
finish(1);
|
|
294
|
+
});
|
|
295
|
+
const failure = () => new RelayUsage(`${CLI_NAME} muse: muse serve failed${serverError ? `: ${serverError.message}` : ""}${stderr.length ? `
|
|
296
|
+
${stderr.toString().trim()}` : ""}`);
|
|
297
|
+
let waker;
|
|
298
|
+
let channel;
|
|
299
|
+
let unlaunch = () => {
|
|
300
|
+
};
|
|
301
|
+
const input = new PassThrough();
|
|
302
|
+
let stopping = false;
|
|
303
|
+
const stop = () => {
|
|
304
|
+
stopping = true;
|
|
305
|
+
finish(0);
|
|
306
|
+
};
|
|
307
|
+
process.on("SIGINT", stop);
|
|
308
|
+
process.on("SIGTERM", stop);
|
|
309
|
+
process.on("SIGHUP", stop);
|
|
310
|
+
const host = new MuseHost(server.stdin, server.stdout, (message) => {
|
|
311
|
+
if (message.id !== void 0 && typeof message.method === "string") {
|
|
312
|
+
answerRequest(host, message, log);
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
if (message.method !== "item/completed") return;
|
|
316
|
+
const item = message.params?.item ?? {};
|
|
317
|
+
if (item.kind === "agentMessage" && typeof item.text === "string" && item.text) process.stdout.write(`${item.text}
|
|
318
|
+
`);
|
|
319
|
+
});
|
|
320
|
+
try {
|
|
321
|
+
if (!server.pid) await new Promise((resolve) => setImmediate(resolve));
|
|
322
|
+
if (died || !server.pid) throw failure();
|
|
323
|
+
const key = processKey(server.pid);
|
|
324
|
+
unlaunch = writeMuseLaunch(key, { ...env.SCP_NAME ? { name: env.SCP_NAME } : {}, ...env.SCP_GRANT ? { grant: env.SCP_GRANT } : {} }, env);
|
|
325
|
+
const started = await Promise.race([
|
|
326
|
+
(async () => {
|
|
327
|
+
await host.request("initialize", { clientInfo: { name: "scp_waker", version: "0.1.0" } });
|
|
328
|
+
host.send({ method: "initialized" });
|
|
329
|
+
const result = launch.resume ? await host.request("session/resume", { commandId: uuidv7(), sessionId: launch.resume, excludeItems: true }) : await host.request("session/start", { commandId: uuidv7(), approvalMode: launch.approvalMode, workspaceRoot: cwd });
|
|
330
|
+
return result.session.sessionId;
|
|
331
|
+
})(),
|
|
332
|
+
done.then(() => void 0)
|
|
333
|
+
]);
|
|
334
|
+
if (stopping) return 0;
|
|
335
|
+
if (!started || died) throw failure();
|
|
336
|
+
const claim = relayIdentity({ harness: "muse", fallbackHarness: "muse", cwd, env, harnessPid: () => server.pid });
|
|
337
|
+
const deadline = Date.now() + BIND_TIMEOUT_MS;
|
|
338
|
+
const bind = (until) => connectCodexChannel(
|
|
339
|
+
() => connectBroker(broker, () => startDaemon(broker)),
|
|
340
|
+
claim,
|
|
341
|
+
cwd,
|
|
342
|
+
() => input.writableEnded || until()
|
|
343
|
+
);
|
|
344
|
+
let bindError;
|
|
345
|
+
let first = await Promise.race([
|
|
346
|
+
bind(() => stopping || died || Date.now() > deadline).catch((error) => {
|
|
347
|
+
bindError = error;
|
|
348
|
+
return void 0;
|
|
349
|
+
}),
|
|
350
|
+
done.then(() => void 0)
|
|
351
|
+
]);
|
|
352
|
+
if (stopping) return 0;
|
|
353
|
+
if (died) throw failure();
|
|
354
|
+
if (!first) {
|
|
355
|
+
const why = Date.now() > deadline ? "the session's scp shim never joined" : `its channel could not bind (${bindError instanceof Error ? bindError.message : String(bindError)})`;
|
|
356
|
+
throw new RelayUsage(`${CLI_NAME} muse: ${why}, so messages cannot wake it; check the mount ${CLI_NAME} setup --write installs`);
|
|
357
|
+
}
|
|
358
|
+
waker = new MuseWaker(host, started);
|
|
359
|
+
let lines = "";
|
|
360
|
+
channel = runRelayMcp({
|
|
361
|
+
connect: async () => {
|
|
362
|
+
const client = first ?? await bind(() => false);
|
|
363
|
+
first = void 0;
|
|
364
|
+
return client;
|
|
365
|
+
},
|
|
366
|
+
claim,
|
|
367
|
+
channels: true,
|
|
368
|
+
wake: "muse-serve",
|
|
369
|
+
input,
|
|
370
|
+
env,
|
|
371
|
+
output: (chunk) => {
|
|
372
|
+
lines += chunk;
|
|
373
|
+
for (; ; ) {
|
|
374
|
+
const end = lines.indexOf("\n");
|
|
375
|
+
if (end < 0) break;
|
|
376
|
+
const message = JSON.parse(lines.slice(0, end));
|
|
377
|
+
lines = lines.slice(end + 1);
|
|
378
|
+
if (message.method === "notifications/claude/channel") {
|
|
379
|
+
const content = message.params.content;
|
|
380
|
+
if (typeof content === "string") waker.push(content);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
},
|
|
384
|
+
log
|
|
385
|
+
});
|
|
386
|
+
void channel.catch((error) => {
|
|
387
|
+
log(error instanceof Error ? error.message : String(error));
|
|
388
|
+
finish(1);
|
|
389
|
+
});
|
|
390
|
+
input.write(
|
|
391
|
+
`${JSON.stringify({ id: 1, method: "initialize", params: { protocolVersion: MCP_PROTOCOLS[0], capabilities: { experimental: { "claude/channel": {} } }, clientInfo: { name: "scp-waker", version: "0.1.0" } } })}
|
|
392
|
+
`
|
|
393
|
+
);
|
|
394
|
+
input.write(`${JSON.stringify({ method: "notifications/initialized" })}
|
|
395
|
+
`);
|
|
396
|
+
log(`${CLI_NAME} muse: ${claim.handle} waiting for messages (session ${started})`);
|
|
397
|
+
const code = await done;
|
|
398
|
+
if (died && !stopping) {
|
|
399
|
+
log(failure().message);
|
|
400
|
+
return 1;
|
|
401
|
+
}
|
|
402
|
+
return code;
|
|
403
|
+
} catch (error) {
|
|
404
|
+
if (died) throw failure();
|
|
405
|
+
throw error;
|
|
406
|
+
} finally {
|
|
407
|
+
process.off("SIGINT", stop);
|
|
408
|
+
process.off("SIGTERM", stop);
|
|
409
|
+
process.off("SIGHUP", stop);
|
|
410
|
+
waker?.close();
|
|
411
|
+
input.end();
|
|
412
|
+
await channel?.catch(() => {
|
|
413
|
+
});
|
|
414
|
+
host.close();
|
|
415
|
+
server.stdin?.end();
|
|
416
|
+
await terminate(server);
|
|
417
|
+
unlaunch();
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
export {
|
|
421
|
+
MUSE_HELP,
|
|
422
|
+
MuseHost,
|
|
423
|
+
MuseWaker,
|
|
424
|
+
answerRequest,
|
|
425
|
+
museBroker,
|
|
426
|
+
museCommand,
|
|
427
|
+
museLaunch,
|
|
428
|
+
uuidv7
|
|
429
|
+
};
|
|
@@ -2,18 +2,18 @@ import {
|
|
|
2
2
|
mcpFile,
|
|
3
3
|
mountedEntry,
|
|
4
4
|
whichOnPath
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-SNW53KT3.js";
|
|
6
6
|
import {
|
|
7
7
|
hooksTarget
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-LRQP25RI.js";
|
|
9
9
|
import {
|
|
10
10
|
opencodePlugin
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-277BAY7J.js";
|
|
12
12
|
import "./chunk-YYSLYVNZ.js";
|
|
13
13
|
import {
|
|
14
14
|
RelayUsage,
|
|
15
15
|
gitToplevel
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-3SOIVANO.js";
|
|
17
17
|
import "./chunk-MNTIEWKF.js";
|
|
18
18
|
|
|
19
19
|
// src/opencode.ts
|