svamp-cli 0.2.72 → 0.2.74
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/bin/skills/artifact/SKILL.md +2 -2
- package/dist/{agentCommands-C1Q4jqOT.mjs → agentCommands-BXQNGfyi.mjs} +2 -2
- package/dist/cli.mjs +101 -34
- package/dist/{commands-DV0URNXH.mjs → commands--SLXTrkN.mjs} +1 -1
- package/dist/{commands-Cyp2k10B.mjs → commands-BTZCHV-Z.mjs} +2 -2
- package/dist/{commands-DJVdDzTe.mjs → commands-yzpViN29.mjs} +3 -3
- package/dist/fleet-DMajjqRV.mjs +339 -0
- package/dist/index.mjs +1 -1
- package/dist/{package-hpa4sCE_.mjs → package-C__x7TGc.mjs} +2 -2
- package/dist/{run-CC-0bNTe.mjs → run-Br90om8R.mjs} +20 -4
- package/dist/{run-D4yrAi1I.mjs → run-DO_Axr2M.mjs} +1 -1
- package/dist/{serveCommands-BeQKrUIn.mjs → serveCommands-Cu_2l3vg.mjs} +5 -5
- package/dist/{serveManager-B9cemdRt.mjs → serveManager-ClzowUXI.mjs} +1 -1
- package/package.json +2 -2
|
@@ -47,7 +47,7 @@ While the agent is still emitting the body content (closing `</artifact>` not ye
|
|
|
47
47
|
src="./outputs/viz.html" <!-- file path OR absolute URL; OR omit and use inline body -->
|
|
48
48
|
title="Dashboard" <!-- header label -->
|
|
49
49
|
height="540" <!-- fixed pixel height (10..4000); default = auto-size for files -->
|
|
50
|
-
|
|
50
|
+
width="80%" <!-- px number (10..4000) or percentage; default = full chat-column width -->
|
|
51
51
|
mode="default" <!-- "default" | "bare" | "immersive" | "card" -->
|
|
52
52
|
description="..." <!-- card mode: summary text -->
|
|
53
53
|
poster="./outputs/thumb.png" <!-- card mode: thumbnail image -->
|
|
@@ -69,7 +69,7 @@ Either `src` or an inline body is required. All other attributes optional.
|
|
|
69
69
|
|
|
70
70
|
- `title` — short artifact name ("3D scene", "Sales dashboard"). Surfaced in the header, the new-tab title, and the singleton "Newer version of …" pill.
|
|
71
71
|
- `height` — for content with no natural document height (Three.js scenes, video, fullscreen apps, URL embeds). For URL `src`, defaults to 540 px because auto-resize can't work cross-origin.
|
|
72
|
-
- `
|
|
72
|
+
- `width` — rarely needed. Artifacts span the **full chat-column width by default**. Set a px value or percentage (e.g. `width="400"`, `width="60%"`) only to deliberately shrink an artifact — a small widget that shouldn't be column-wide. The chat-column cap still applies, so this only narrows, never widens past the column.
|
|
73
73
|
- `description` / `poster` — only used in card mode.
|
|
74
74
|
|
|
75
75
|
### Header / menu
|
|
@@ -148,7 +148,7 @@ async function sessionBroadcast(action, args) {
|
|
|
148
148
|
console.log(`Broadcast sent: ${action}`);
|
|
149
149
|
}
|
|
150
150
|
async function connectToMachineService() {
|
|
151
|
-
const { connectAndGetMachine } = await import('./commands
|
|
151
|
+
const { connectAndGetMachine } = await import('./commands--SLXTrkN.mjs');
|
|
152
152
|
return connectAndGetMachine();
|
|
153
153
|
}
|
|
154
154
|
async function inboxSend(targetSessionId, opts) {
|
|
@@ -165,7 +165,7 @@ async function inboxSend(targetSessionId, opts) {
|
|
|
165
165
|
}
|
|
166
166
|
const { server, machine } = await connectToMachineService();
|
|
167
167
|
try {
|
|
168
|
-
const { resolveSessionId } = await import('./commands
|
|
168
|
+
const { resolveSessionId } = await import('./commands--SLXTrkN.mjs');
|
|
169
169
|
const sessions = await machine.listSessions();
|
|
170
170
|
const match = resolveSessionId(sessions, targetSessionId);
|
|
171
171
|
const fullTargetId = match.sessionId;
|
package/dist/cli.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { s as startDaemon, b as stopDaemon, d as daemonStatus } from './run-
|
|
1
|
+
import { s as startDaemon, b as stopDaemon, d as daemonStatus } from './run-Br90om8R.mjs';
|
|
2
2
|
import 'os';
|
|
3
3
|
import 'fs/promises';
|
|
4
4
|
import 'fs';
|
|
@@ -44,7 +44,7 @@ async function main() {
|
|
|
44
44
|
console.error(`svamp daemon restart: ${err.message || err}`);
|
|
45
45
|
process.exit(1);
|
|
46
46
|
}
|
|
47
|
-
const { restartDaemon } = await import('./run-
|
|
47
|
+
const { restartDaemon } = await import('./run-Br90om8R.mjs').then(function (n) { return n.u; });
|
|
48
48
|
await restartDaemon();
|
|
49
49
|
process.exit(0);
|
|
50
50
|
}
|
|
@@ -267,6 +267,13 @@ async function main() {
|
|
|
267
267
|
process.exit(1);
|
|
268
268
|
}
|
|
269
269
|
await handleMachineCommand();
|
|
270
|
+
} else if (subcommand === "fleet") {
|
|
271
|
+
const { isSandboxed } = await import('./sandboxDetect-DNTcbgWD.mjs');
|
|
272
|
+
if (isSandboxed()) {
|
|
273
|
+
console.error("svamp fleet: Fleet commands are not available in sandboxed sessions.");
|
|
274
|
+
process.exit(1);
|
|
275
|
+
}
|
|
276
|
+
await handleFleetCommand();
|
|
270
277
|
} else if (subcommand === "skills") {
|
|
271
278
|
const { isSandboxed } = await import('./sandboxDetect-DNTcbgWD.mjs');
|
|
272
279
|
if (isSandboxed()) {
|
|
@@ -280,7 +287,7 @@ async function main() {
|
|
|
280
287
|
console.error("svamp service: Service commands are not available in sandboxed sessions.");
|
|
281
288
|
process.exit(1);
|
|
282
289
|
}
|
|
283
|
-
const { handleServiceCommand } = await import('./commands-
|
|
290
|
+
const { handleServiceCommand } = await import('./commands-yzpViN29.mjs');
|
|
284
291
|
await handleServiceCommand();
|
|
285
292
|
} else if (subcommand === "serve") {
|
|
286
293
|
const { isSandboxed: isSandboxedServe } = await import('./sandboxDetect-DNTcbgWD.mjs');
|
|
@@ -288,7 +295,7 @@ async function main() {
|
|
|
288
295
|
console.error("svamp serve: Serve commands are not available in sandboxed sessions.");
|
|
289
296
|
process.exit(1);
|
|
290
297
|
}
|
|
291
|
-
const { handleServeCommand } = await import('./serveCommands-
|
|
298
|
+
const { handleServeCommand } = await import('./serveCommands-Cu_2l3vg.mjs');
|
|
292
299
|
await handleServeCommand();
|
|
293
300
|
process.exit(0);
|
|
294
301
|
} else if (subcommand === "process" || subcommand === "proc") {
|
|
@@ -297,7 +304,7 @@ async function main() {
|
|
|
297
304
|
console.error("svamp process: Process commands are not available in sandboxed sessions.");
|
|
298
305
|
process.exit(1);
|
|
299
306
|
}
|
|
300
|
-
const { processCommand } = await import('./commands-
|
|
307
|
+
const { processCommand } = await import('./commands-BTZCHV-Z.mjs');
|
|
301
308
|
let machineId;
|
|
302
309
|
const processArgs = args.slice(1);
|
|
303
310
|
const mIdx = processArgs.findIndex((a) => a === "--machine" || a === "-m");
|
|
@@ -315,7 +322,7 @@ async function main() {
|
|
|
315
322
|
} else if (!subcommand || subcommand === "start") {
|
|
316
323
|
await handleInteractiveCommand();
|
|
317
324
|
} else if (subcommand === "--version" || subcommand === "-v") {
|
|
318
|
-
const pkg = await import('./package-
|
|
325
|
+
const pkg = await import('./package-C__x7TGc.mjs').catch(() => ({ default: { version: "unknown" } }));
|
|
319
326
|
console.log(`svamp version: ${pkg.default.version}`);
|
|
320
327
|
} else {
|
|
321
328
|
console.error(`Unknown command: ${subcommand}`);
|
|
@@ -324,7 +331,7 @@ async function main() {
|
|
|
324
331
|
}
|
|
325
332
|
}
|
|
326
333
|
async function handleInteractiveCommand() {
|
|
327
|
-
const { runInteractive } = await import('./run-
|
|
334
|
+
const { runInteractive } = await import('./run-DO_Axr2M.mjs');
|
|
328
335
|
const interactiveArgs = subcommand === "start" ? args.slice(1) : args;
|
|
329
336
|
let directory = process.cwd();
|
|
330
337
|
let resumeSessionId;
|
|
@@ -369,7 +376,7 @@ async function handleAgentCommand() {
|
|
|
369
376
|
return;
|
|
370
377
|
}
|
|
371
378
|
if (agentArgs[0] === "list") {
|
|
372
|
-
const { KNOWN_ACP_AGENTS, KNOWN_MCP_AGENTS: KNOWN_MCP_AGENTS2 } = await import('./run-
|
|
379
|
+
const { KNOWN_ACP_AGENTS, KNOWN_MCP_AGENTS: KNOWN_MCP_AGENTS2 } = await import('./run-Br90om8R.mjs').then(function (n) { return n.p; });
|
|
373
380
|
console.log("Known agents:");
|
|
374
381
|
for (const [name, config2] of Object.entries(KNOWN_ACP_AGENTS)) {
|
|
375
382
|
console.log(` ${name.padEnd(12)} ${config2.command} ${config2.args.join(" ")} (ACP)`);
|
|
@@ -381,7 +388,7 @@ async function handleAgentCommand() {
|
|
|
381
388
|
console.log('Use "svamp agent -- <command> [args]" for a custom ACP agent.');
|
|
382
389
|
return;
|
|
383
390
|
}
|
|
384
|
-
const { resolveAcpAgentConfig, KNOWN_MCP_AGENTS } = await import('./run-
|
|
391
|
+
const { resolveAcpAgentConfig, KNOWN_MCP_AGENTS } = await import('./run-Br90om8R.mjs').then(function (n) { return n.p; });
|
|
385
392
|
let cwd = process.cwd();
|
|
386
393
|
const filteredArgs = [];
|
|
387
394
|
for (let i = 0; i < agentArgs.length; i++) {
|
|
@@ -405,12 +412,12 @@ async function handleAgentCommand() {
|
|
|
405
412
|
console.log(`Starting ${config.agentName} agent in ${cwd}...`);
|
|
406
413
|
let backend;
|
|
407
414
|
if (KNOWN_MCP_AGENTS[config.agentName]) {
|
|
408
|
-
const { CodexMcpBackend } = await import('./run-
|
|
415
|
+
const { CodexMcpBackend } = await import('./run-Br90om8R.mjs').then(function (n) { return n.q; });
|
|
409
416
|
backend = new CodexMcpBackend({ cwd, log: logFn });
|
|
410
417
|
} else {
|
|
411
|
-
const { AcpBackend } = await import('./run-
|
|
412
|
-
const { GeminiTransport } = await import('./run-
|
|
413
|
-
const { DefaultTransport } = await import('./run-
|
|
418
|
+
const { AcpBackend } = await import('./run-Br90om8R.mjs').then(function (n) { return n.o; });
|
|
419
|
+
const { GeminiTransport } = await import('./run-Br90om8R.mjs').then(function (n) { return n.G; });
|
|
420
|
+
const { DefaultTransport } = await import('./run-Br90om8R.mjs').then(function (n) { return n.D; });
|
|
414
421
|
const transportHandler = config.agentName === "gemini" ? new GeminiTransport() : new DefaultTransport(config.agentName);
|
|
415
422
|
backend = new AcpBackend({
|
|
416
423
|
agentName: config.agentName,
|
|
@@ -537,7 +544,7 @@ async function handleSessionCommand() {
|
|
|
537
544
|
process.exit(1);
|
|
538
545
|
}
|
|
539
546
|
}
|
|
540
|
-
const { sessionList, sessionSpawn, sessionArchive, sessionResume, sessionDelete, sessionInfo, sessionMessages, sessionAttach, sessionMachines, sessionSend, sessionWait, sessionShare, sessionRalphStart, sessionRalphCancel, sessionRalphStatus, sessionInboxSend, sessionInboxList, sessionInboxRead, sessionInboxReply, sessionInboxClear } = await import('./commands
|
|
547
|
+
const { sessionList, sessionSpawn, sessionArchive, sessionResume, sessionDelete, sessionInfo, sessionMessages, sessionAttach, sessionMachines, sessionSend, sessionWait, sessionShare, sessionRalphStart, sessionRalphCancel, sessionRalphStatus, sessionInboxSend, sessionInboxList, sessionInboxRead, sessionInboxReply, sessionInboxClear } = await import('./commands--SLXTrkN.mjs');
|
|
541
548
|
const parseFlagStr = (flag, shortFlag) => {
|
|
542
549
|
for (let i = 1; i < sessionArgs.length; i++) {
|
|
543
550
|
if ((sessionArgs[i] === flag || shortFlag) && i + 1 < sessionArgs.length) {
|
|
@@ -603,7 +610,7 @@ async function handleSessionCommand() {
|
|
|
603
610
|
allowDomain.push(sessionArgs[++i]);
|
|
604
611
|
}
|
|
605
612
|
}
|
|
606
|
-
const { parseShareArg } = await import('./commands
|
|
613
|
+
const { parseShareArg } = await import('./commands--SLXTrkN.mjs');
|
|
607
614
|
const shareEntries = share.map((s) => parseShareArg(s));
|
|
608
615
|
await sessionSpawn(agent, dir, targetMachineId, {
|
|
609
616
|
message,
|
|
@@ -687,7 +694,7 @@ async function handleSessionCommand() {
|
|
|
687
694
|
console.error(" Spawns a stateless Claude session in <directory>, sends <prompt>, prints the answer, then deletes the session.");
|
|
688
695
|
process.exit(1);
|
|
689
696
|
}
|
|
690
|
-
const { sessionQuery } = await import('./commands
|
|
697
|
+
const { sessionQuery } = await import('./commands--SLXTrkN.mjs');
|
|
691
698
|
await sessionQuery(dir, prompt, targetMachineId, {
|
|
692
699
|
timeout: parseFlagInt("--timeout"),
|
|
693
700
|
json: hasFlag("--json"),
|
|
@@ -720,7 +727,7 @@ async function handleSessionCommand() {
|
|
|
720
727
|
console.error("Usage: svamp session approve <session-id> [request-id] [--json]");
|
|
721
728
|
process.exit(1);
|
|
722
729
|
}
|
|
723
|
-
const { sessionApprove } = await import('./commands
|
|
730
|
+
const { sessionApprove } = await import('./commands--SLXTrkN.mjs');
|
|
724
731
|
const approveReqId = sessionArgs[2] && !sessionArgs[2].startsWith("--") ? sessionArgs[2] : void 0;
|
|
725
732
|
await sessionApprove(sessionArgs[1], approveReqId, targetMachineId, {
|
|
726
733
|
json: hasFlag("--json")
|
|
@@ -730,7 +737,7 @@ async function handleSessionCommand() {
|
|
|
730
737
|
console.error("Usage: svamp session deny <session-id> [request-id] [--json]");
|
|
731
738
|
process.exit(1);
|
|
732
739
|
}
|
|
733
|
-
const { sessionDeny } = await import('./commands
|
|
740
|
+
const { sessionDeny } = await import('./commands--SLXTrkN.mjs');
|
|
734
741
|
const denyReqId = sessionArgs[2] && !sessionArgs[2].startsWith("--") ? sessionArgs[2] : void 0;
|
|
735
742
|
await sessionDeny(sessionArgs[1], denyReqId, targetMachineId, {
|
|
736
743
|
json: hasFlag("--json")
|
|
@@ -766,7 +773,7 @@ async function handleSessionCommand() {
|
|
|
766
773
|
console.error("Usage: svamp session set-title <title>");
|
|
767
774
|
process.exit(1);
|
|
768
775
|
}
|
|
769
|
-
const { sessionSetTitle } = await import('./agentCommands-
|
|
776
|
+
const { sessionSetTitle } = await import('./agentCommands-BXQNGfyi.mjs');
|
|
770
777
|
await sessionSetTitle(title);
|
|
771
778
|
} else if (sessionSubcommand === "set-link") {
|
|
772
779
|
const url = sessionArgs[1];
|
|
@@ -775,7 +782,7 @@ async function handleSessionCommand() {
|
|
|
775
782
|
process.exit(1);
|
|
776
783
|
}
|
|
777
784
|
const label = sessionArgs[2] && !sessionArgs[2].startsWith("--") ? sessionArgs[2] : void 0;
|
|
778
|
-
const { sessionSetLink } = await import('./agentCommands-
|
|
785
|
+
const { sessionSetLink } = await import('./agentCommands-BXQNGfyi.mjs');
|
|
779
786
|
await sessionSetLink(url, label);
|
|
780
787
|
} else if (sessionSubcommand === "notify") {
|
|
781
788
|
const message = sessionArgs[1];
|
|
@@ -784,7 +791,7 @@ async function handleSessionCommand() {
|
|
|
784
791
|
process.exit(1);
|
|
785
792
|
}
|
|
786
793
|
const level = parseFlagStr("--level") || "info";
|
|
787
|
-
const { sessionNotify } = await import('./agentCommands-
|
|
794
|
+
const { sessionNotify } = await import('./agentCommands-BXQNGfyi.mjs');
|
|
788
795
|
await sessionNotify(message, level);
|
|
789
796
|
} else if (sessionSubcommand === "broadcast") {
|
|
790
797
|
const action = sessionArgs[1];
|
|
@@ -792,7 +799,7 @@ async function handleSessionCommand() {
|
|
|
792
799
|
console.error("Usage: svamp session broadcast <action> [args...]\nActions: open-canvas <url> [label], close-canvas, toast <message>");
|
|
793
800
|
process.exit(1);
|
|
794
801
|
}
|
|
795
|
-
const { sessionBroadcast } = await import('./agentCommands-
|
|
802
|
+
const { sessionBroadcast } = await import('./agentCommands-BXQNGfyi.mjs');
|
|
796
803
|
await sessionBroadcast(action, sessionArgs.slice(2).filter((a) => !a.startsWith("--")));
|
|
797
804
|
} else if (sessionSubcommand === "inbox") {
|
|
798
805
|
const inboxSubcmd = sessionArgs[1];
|
|
@@ -803,7 +810,7 @@ async function handleSessionCommand() {
|
|
|
803
810
|
process.exit(1);
|
|
804
811
|
}
|
|
805
812
|
if (agentSessionId) {
|
|
806
|
-
const { inboxSend } = await import('./agentCommands-
|
|
813
|
+
const { inboxSend } = await import('./agentCommands-BXQNGfyi.mjs');
|
|
807
814
|
await inboxSend(sessionArgs[2], {
|
|
808
815
|
body: sessionArgs[3],
|
|
809
816
|
subject: parseFlagStr("--subject"),
|
|
@@ -818,7 +825,7 @@ async function handleSessionCommand() {
|
|
|
818
825
|
}
|
|
819
826
|
} else if (inboxSubcmd === "list" || inboxSubcmd === "ls") {
|
|
820
827
|
if (agentSessionId && !sessionArgs[2]) {
|
|
821
|
-
const { inboxList } = await import('./agentCommands-
|
|
828
|
+
const { inboxList } = await import('./agentCommands-BXQNGfyi.mjs');
|
|
822
829
|
await inboxList({
|
|
823
830
|
unread: hasFlag("--unread"),
|
|
824
831
|
limit: parseFlagInt("--limit"),
|
|
@@ -840,7 +847,7 @@ async function handleSessionCommand() {
|
|
|
840
847
|
process.exit(1);
|
|
841
848
|
}
|
|
842
849
|
if (agentSessionId && !sessionArgs[3]) {
|
|
843
|
-
const { inboxList } = await import('./agentCommands-
|
|
850
|
+
const { inboxList } = await import('./agentCommands-BXQNGfyi.mjs');
|
|
844
851
|
await sessionInboxRead(agentSessionId, sessionArgs[2], targetMachineId);
|
|
845
852
|
} else if (sessionArgs[3]) {
|
|
846
853
|
await sessionInboxRead(sessionArgs[2], sessionArgs[3], targetMachineId);
|
|
@@ -850,7 +857,7 @@ async function handleSessionCommand() {
|
|
|
850
857
|
}
|
|
851
858
|
} else if (inboxSubcmd === "reply") {
|
|
852
859
|
if (agentSessionId && sessionArgs[2] && sessionArgs[3] && !sessionArgs[4]) {
|
|
853
|
-
const { inboxReply } = await import('./agentCommands-
|
|
860
|
+
const { inboxReply } = await import('./agentCommands-BXQNGfyi.mjs');
|
|
854
861
|
await inboxReply(sessionArgs[2], sessionArgs[3]);
|
|
855
862
|
} else if (sessionArgs[2] && sessionArgs[3] && sessionArgs[4]) {
|
|
856
863
|
await sessionInboxReply(sessionArgs[2], sessionArgs[3], sessionArgs[4], targetMachineId);
|
|
@@ -886,7 +893,7 @@ async function handleMachineCommand() {
|
|
|
886
893
|
return;
|
|
887
894
|
}
|
|
888
895
|
if (machineSubcommand === "share") {
|
|
889
|
-
const { machineShare } = await import('./commands
|
|
896
|
+
const { machineShare } = await import('./commands--SLXTrkN.mjs');
|
|
890
897
|
let machineId;
|
|
891
898
|
const shareArgs = [];
|
|
892
899
|
for (let i = 1; i < machineArgs.length; i++) {
|
|
@@ -916,7 +923,7 @@ async function handleMachineCommand() {
|
|
|
916
923
|
}
|
|
917
924
|
await machineShare(machineId, { add, remove, list, configPath, showConfig });
|
|
918
925
|
} else if (machineSubcommand === "exec") {
|
|
919
|
-
const { machineExec } = await import('./commands
|
|
926
|
+
const { machineExec } = await import('./commands--SLXTrkN.mjs');
|
|
920
927
|
let machineId;
|
|
921
928
|
let cwd;
|
|
922
929
|
const cmdParts = [];
|
|
@@ -936,7 +943,7 @@ async function handleMachineCommand() {
|
|
|
936
943
|
}
|
|
937
944
|
await machineExec(machineId, command, cwd);
|
|
938
945
|
} else if (machineSubcommand === "info") {
|
|
939
|
-
const { machineInfo } = await import('./commands
|
|
946
|
+
const { machineInfo } = await import('./commands--SLXTrkN.mjs');
|
|
940
947
|
let machineId;
|
|
941
948
|
for (let i = 1; i < machineArgs.length; i++) {
|
|
942
949
|
if ((machineArgs[i] === "--machine" || machineArgs[i] === "-m") && i + 1 < machineArgs.length) {
|
|
@@ -956,10 +963,10 @@ async function handleMachineCommand() {
|
|
|
956
963
|
level = machineArgs[++i];
|
|
957
964
|
}
|
|
958
965
|
}
|
|
959
|
-
const { machineNotify } = await import('./agentCommands-
|
|
966
|
+
const { machineNotify } = await import('./agentCommands-BXQNGfyi.mjs');
|
|
960
967
|
await machineNotify(message, level);
|
|
961
968
|
} else if (machineSubcommand === "ls") {
|
|
962
|
-
const { machineLs } = await import('./commands
|
|
969
|
+
const { machineLs } = await import('./commands--SLXTrkN.mjs');
|
|
963
970
|
let machineId;
|
|
964
971
|
let showHidden = false;
|
|
965
972
|
let path;
|
|
@@ -980,6 +987,65 @@ async function handleMachineCommand() {
|
|
|
980
987
|
}
|
|
981
988
|
process.exit(0);
|
|
982
989
|
}
|
|
990
|
+
async function handleFleetCommand() {
|
|
991
|
+
const fleetArgs = args.slice(1);
|
|
992
|
+
const sub = fleetArgs[0];
|
|
993
|
+
if (!sub || sub === "--help" || sub === "-h") {
|
|
994
|
+
console.log(`Usage: svamp fleet <subcommand>
|
|
995
|
+
|
|
996
|
+
Subcommands (fan out across every machine in your workspace):
|
|
997
|
+
status Show svamp + claude-code version per machine
|
|
998
|
+
exec "<command>" Run a shell command on every machine
|
|
999
|
+
upgrade-claude [-v X] Install Claude Code (defaults to svamp-cli's pinned version)
|
|
1000
|
+
upgrade-svamp [-v X] npm install -g svamp-cli@X + svamp daemon restart
|
|
1001
|
+
daemon-restart [--cleanup] Restart daemons (default graceful)
|
|
1002
|
+
push-skill <name> Install/force-refresh a skill on all machines
|
|
1003
|
+
|
|
1004
|
+
Each row reports OK / FAIL / SKIP. Failures don't sink the batch; exit code 1
|
|
1005
|
+
only if at least one machine failed.
|
|
1006
|
+
|
|
1007
|
+
Examples:
|
|
1008
|
+
svamp fleet status
|
|
1009
|
+
svamp fleet exec "uptime"
|
|
1010
|
+
svamp fleet upgrade-claude
|
|
1011
|
+
svamp fleet upgrade-svamp -v 0.2.73
|
|
1012
|
+
svamp fleet push-skill hypha`);
|
|
1013
|
+
process.exit(0);
|
|
1014
|
+
}
|
|
1015
|
+
const flag = (name, short) => {
|
|
1016
|
+
for (let i = 1; i < fleetArgs.length; i++) {
|
|
1017
|
+
if (fleetArgs[i] === `--${name}` || short && fleetArgs[i] === short) return fleetArgs[i + 1];
|
|
1018
|
+
}
|
|
1019
|
+
return void 0;
|
|
1020
|
+
};
|
|
1021
|
+
const hasFlag = (name) => fleetArgs.includes(`--${name}`);
|
|
1022
|
+
if (sub === "status") {
|
|
1023
|
+
const { fleetStatus } = await import('./fleet-DMajjqRV.mjs');
|
|
1024
|
+
await fleetStatus();
|
|
1025
|
+
} else if (sub === "exec") {
|
|
1026
|
+
const command = fleetArgs.slice(1).filter((a) => !a.startsWith("--")).join(" ");
|
|
1027
|
+
const { fleetExec } = await import('./fleet-DMajjqRV.mjs');
|
|
1028
|
+
await fleetExec(command, { cwd: flag("cwd") });
|
|
1029
|
+
} else if (sub === "upgrade-claude") {
|
|
1030
|
+
const { fleetUpgradeClaude } = await import('./fleet-DMajjqRV.mjs');
|
|
1031
|
+
await fleetUpgradeClaude({ version: flag("version", "-v") });
|
|
1032
|
+
} else if (sub === "upgrade-svamp") {
|
|
1033
|
+
const { fleetUpgradeSvamp } = await import('./fleet-DMajjqRV.mjs');
|
|
1034
|
+
await fleetUpgradeSvamp({ version: flag("version", "-v") });
|
|
1035
|
+
} else if (sub === "daemon-restart") {
|
|
1036
|
+
const { fleetDaemonRestart } = await import('./fleet-DMajjqRV.mjs');
|
|
1037
|
+
await fleetDaemonRestart({ graceful: !hasFlag("cleanup") });
|
|
1038
|
+
} else if (sub === "push-skill") {
|
|
1039
|
+
const name = fleetArgs[1];
|
|
1040
|
+
const { fleetPushSkill } = await import('./fleet-DMajjqRV.mjs');
|
|
1041
|
+
await fleetPushSkill(name);
|
|
1042
|
+
} else {
|
|
1043
|
+
console.error(`Unknown fleet subcommand: ${sub}`);
|
|
1044
|
+
console.error('Run "svamp fleet --help" to see available subcommands.');
|
|
1045
|
+
process.exit(1);
|
|
1046
|
+
}
|
|
1047
|
+
process.exit(process.exitCode || 0);
|
|
1048
|
+
}
|
|
983
1049
|
async function handleSkillsCommand() {
|
|
984
1050
|
const skillsArgs = args.slice(1);
|
|
985
1051
|
const skillsSubcommand = skillsArgs[0];
|
|
@@ -1371,6 +1437,7 @@ Commands:
|
|
|
1371
1437
|
|
|
1372
1438
|
Other:
|
|
1373
1439
|
svamp machine --help Machine sharing & security contexts
|
|
1440
|
+
svamp fleet --help Fan-out commands across all your machines (status, upgrade, exec, push-skill)
|
|
1374
1441
|
svamp skills --help Skills marketplace (find, install, publish)
|
|
1375
1442
|
svamp service --help Service exposure (HTTP services from sandboxes)
|
|
1376
1443
|
svamp agent <name> Start local agent session (no daemon needed)
|
|
@@ -1429,7 +1496,7 @@ async function applyClaudeAuthFlags(argv) {
|
|
|
1429
1496
|
"--use-hypha-proxy, --use-claude-login, and --anthropic-base-url/--anthropic-api-key are mutually exclusive"
|
|
1430
1497
|
);
|
|
1431
1498
|
}
|
|
1432
|
-
const mod = await import('./run-
|
|
1499
|
+
const mod = await import('./run-Br90om8R.mjs').then(function (n) { return n.t; });
|
|
1433
1500
|
if (hasHypha) {
|
|
1434
1501
|
mod.setClaudeAuthHyphaProxy();
|
|
1435
1502
|
console.log("Claude auth configured: hypha-proxy (uses HYPHA_TOKEN live at each spawn).");
|
|
@@ -1467,7 +1534,7 @@ async function applyDaemonShareFlag(argv) {
|
|
|
1467
1534
|
}
|
|
1468
1535
|
}
|
|
1469
1536
|
if (collected.length === 0) return;
|
|
1470
|
-
const { updateEnvFile } = await import('./run-
|
|
1537
|
+
const { updateEnvFile } = await import('./run-Br90om8R.mjs').then(function (n) { return n.t; });
|
|
1471
1538
|
const seen = /* @__PURE__ */ new Set();
|
|
1472
1539
|
const deduped = collected.filter((e) => {
|
|
1473
1540
|
const k = e.toLowerCase();
|
|
@@ -1480,7 +1547,7 @@ async function applyDaemonShareFlag(argv) {
|
|
|
1480
1547
|
}
|
|
1481
1548
|
async function handleDaemonAuthCommand(argv) {
|
|
1482
1549
|
const sub = (argv[0] || "status").toLowerCase();
|
|
1483
|
-
const mod = await import('./run-
|
|
1550
|
+
const mod = await import('./run-Br90om8R.mjs').then(function (n) { return n.t; });
|
|
1484
1551
|
if (sub === "--help" || sub === "-h" || sub === "help") {
|
|
1485
1552
|
console.log(`
|
|
1486
1553
|
svamp daemon auth \u2014 Configure how Claude subprocesses authenticate
|
|
@@ -2,7 +2,7 @@ import { existsSync, readFileSync } from 'node:fs';
|
|
|
2
2
|
import { execSync } from 'node:child_process';
|
|
3
3
|
import { resolve, join } from 'node:path';
|
|
4
4
|
import os from 'node:os';
|
|
5
|
-
import { n as normalizeAllowedUser, l as loadSecurityContextConfig, e as resolveSecurityContext, f as buildSecurityContextFromFlags, m as mergeSecurityContexts, c as connectToHypha, i as buildSessionShareUrl, j as buildMachineShareUrl } from './run-
|
|
5
|
+
import { n as normalizeAllowedUser, l as loadSecurityContextConfig, e as resolveSecurityContext, f as buildSecurityContextFromFlags, m as mergeSecurityContexts, c as connectToHypha, i as buildSessionShareUrl, j as buildMachineShareUrl } from './run-Br90om8R.mjs';
|
|
6
6
|
import 'os';
|
|
7
7
|
import 'fs/promises';
|
|
8
8
|
import 'fs';
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { writeFileSync, readFileSync } from 'fs';
|
|
2
2
|
import { resolve } from 'path';
|
|
3
|
-
import { connectAndGetMachine } from './commands
|
|
3
|
+
import { connectAndGetMachine } from './commands--SLXTrkN.mjs';
|
|
4
4
|
import 'node:fs';
|
|
5
5
|
import 'node:child_process';
|
|
6
6
|
import 'node:path';
|
|
7
7
|
import 'node:os';
|
|
8
|
-
import './run-
|
|
8
|
+
import './run-Br90om8R.mjs';
|
|
9
9
|
import 'os';
|
|
10
10
|
import 'fs/promises';
|
|
11
11
|
import 'url';
|
|
@@ -68,7 +68,7 @@ async function serviceExpose(args) {
|
|
|
68
68
|
});
|
|
69
69
|
return;
|
|
70
70
|
}
|
|
71
|
-
const { connectAndGetMachine } = await import('./commands
|
|
71
|
+
const { connectAndGetMachine } = await import('./commands--SLXTrkN.mjs');
|
|
72
72
|
const { server, machine } = await connectAndGetMachine();
|
|
73
73
|
try {
|
|
74
74
|
const status = await machine.tunnelStart({
|
|
@@ -132,7 +132,7 @@ async function serviceServe(args) {
|
|
|
132
132
|
}
|
|
133
133
|
async function serviceList(_args) {
|
|
134
134
|
try {
|
|
135
|
-
const { connectAndGetMachine } = await import('./commands
|
|
135
|
+
const { connectAndGetMachine } = await import('./commands--SLXTrkN.mjs');
|
|
136
136
|
const { server, machine } = await connectAndGetMachine();
|
|
137
137
|
try {
|
|
138
138
|
const tunnels = await machine.tunnelList({});
|
|
@@ -161,7 +161,7 @@ async function serviceDelete(args) {
|
|
|
161
161
|
process.exit(1);
|
|
162
162
|
}
|
|
163
163
|
try {
|
|
164
|
-
const { connectAndGetMachine } = await import('./commands
|
|
164
|
+
const { connectAndGetMachine } = await import('./commands--SLXTrkN.mjs');
|
|
165
165
|
const { server, machine } = await connectAndGetMachine();
|
|
166
166
|
try {
|
|
167
167
|
await machine.tunnelStop({ name });
|
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import { c as connectToHypha } from './run-Br90om8R.mjs';
|
|
5
|
+
import { PINNED_CLAUDE_CODE_VERSION } from './pinnedClaudeCode-HydRNEt7.mjs';
|
|
6
|
+
import 'os';
|
|
7
|
+
import 'fs/promises';
|
|
8
|
+
import 'fs';
|
|
9
|
+
import 'path';
|
|
10
|
+
import 'url';
|
|
11
|
+
import 'child_process';
|
|
12
|
+
import 'crypto';
|
|
13
|
+
import 'util';
|
|
14
|
+
import 'node:crypto';
|
|
15
|
+
import 'node:child_process';
|
|
16
|
+
import '@agentclientprotocol/sdk';
|
|
17
|
+
import '@modelcontextprotocol/sdk/client/index.js';
|
|
18
|
+
import '@modelcontextprotocol/sdk/client/stdio.js';
|
|
19
|
+
import '@modelcontextprotocol/sdk/types.js';
|
|
20
|
+
import 'zod';
|
|
21
|
+
import 'node:fs/promises';
|
|
22
|
+
import 'node:util';
|
|
23
|
+
|
|
24
|
+
const SVAMP_HOME = process.env.SVAMP_HOME || join(os.homedir(), ".svamp");
|
|
25
|
+
const DAEMON_STATE_FILE = join(SVAMP_HOME, "daemon.state.json");
|
|
26
|
+
const ENV_FILE = join(SVAMP_HOME, ".env");
|
|
27
|
+
function loadDotEnv() {
|
|
28
|
+
if (!existsSync(ENV_FILE)) return;
|
|
29
|
+
for (const raw of readFileSync(ENV_FILE, "utf-8").split("\n")) {
|
|
30
|
+
const line = raw.trim();
|
|
31
|
+
if (!line || line.startsWith("#")) continue;
|
|
32
|
+
const eq = line.indexOf("=");
|
|
33
|
+
if (eq === -1) continue;
|
|
34
|
+
const k = line.slice(0, eq).trim();
|
|
35
|
+
const v = line.slice(eq + 1).trim().replace(/^["']|["']$/g, "");
|
|
36
|
+
if (!process.env[k]) process.env[k] = v;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function readDaemonState() {
|
|
40
|
+
if (!existsSync(DAEMON_STATE_FILE)) return null;
|
|
41
|
+
try {
|
|
42
|
+
return JSON.parse(readFileSync(DAEMON_STATE_FILE, "utf-8"));
|
|
43
|
+
} catch {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function suppressHyphaLogs() {
|
|
48
|
+
const ol = console.log, ow = console.warn, oi = console.info, oe = console.error;
|
|
49
|
+
const sw = process.stdout.write.bind(process.stdout);
|
|
50
|
+
const ew = process.stderr.write.bind(process.stderr);
|
|
51
|
+
const isLog = (chunk) => typeof chunk === "string" && (chunk.includes("WebSocket connection") || chunk.includes("Connection established") || chunk.includes("registering service built-in") || chunk.includes("registered service") || chunk.includes("registered all") || chunk.includes("Subscribing to client_") || chunk.includes("subscribed to client_") || chunk.includes("subscribe to client_") || chunk.includes("Cleaning up all sessions") || chunk.includes("WebSocket connection disconnected") || chunk.includes("local RPC disconnection"));
|
|
52
|
+
console.log = () => {
|
|
53
|
+
};
|
|
54
|
+
console.warn = () => {
|
|
55
|
+
};
|
|
56
|
+
console.info = () => {
|
|
57
|
+
};
|
|
58
|
+
console.error = (...args) => {
|
|
59
|
+
if (args.some((a) => isLog(a))) return;
|
|
60
|
+
oe(...args);
|
|
61
|
+
};
|
|
62
|
+
process.stdout.write = (c, ...a) => isLog(c) ? true : sw(c, ...a);
|
|
63
|
+
process.stderr.write = (c, ...a) => isLog(c) ? true : ew(c, ...a);
|
|
64
|
+
return () => {
|
|
65
|
+
console.log = ol;
|
|
66
|
+
console.warn = ow;
|
|
67
|
+
console.info = oi;
|
|
68
|
+
console.error = oe;
|
|
69
|
+
process.stdout.write = sw;
|
|
70
|
+
process.stderr.write = ew;
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
function truncate(s, n) {
|
|
74
|
+
if (!s) return s;
|
|
75
|
+
return s.length <= n ? s : s.slice(0, Math.max(1, n - 1)) + "\u2026";
|
|
76
|
+
}
|
|
77
|
+
async function discoverMachines() {
|
|
78
|
+
loadDotEnv();
|
|
79
|
+
const state = readDaemonState();
|
|
80
|
+
const serverUrl = process.env.HYPHA_SERVER_URL || state?.hyphaServerUrl;
|
|
81
|
+
const token = process.env.HYPHA_TOKEN;
|
|
82
|
+
if (!serverUrl) {
|
|
83
|
+
console.error('No Hypha server URL. Run "svamp login <url>" first.');
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
const restore = suppressHyphaLogs();
|
|
87
|
+
let server;
|
|
88
|
+
try {
|
|
89
|
+
server = await connectToHypha({ serverUrl, token, name: "svamp-fleet-cli" });
|
|
90
|
+
} catch (err) {
|
|
91
|
+
restore();
|
|
92
|
+
console.error(`Failed to connect to Hypha: ${err.message}`);
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
const services = await server.listServices({ query: { type: "svamp-machine" }, include_unlisted: true, _rkwargs: true });
|
|
96
|
+
restore();
|
|
97
|
+
const machines = await Promise.all(services.map(async (svc) => {
|
|
98
|
+
const serviceId = svc.id || svc.name;
|
|
99
|
+
try {
|
|
100
|
+
const rpc = await server.getService(serviceId);
|
|
101
|
+
const info = await rpc.getMachineInfo();
|
|
102
|
+
const label = info.metadata?.displayName || info.metadata?.host || info.metadata?.hostname || serviceId;
|
|
103
|
+
return { serviceId, machineId: info.machineId || serviceId, label, rpc };
|
|
104
|
+
} catch {
|
|
105
|
+
return { serviceId, machineId: serviceId, label: "-", rpc: null };
|
|
106
|
+
}
|
|
107
|
+
}));
|
|
108
|
+
return { server, machines };
|
|
109
|
+
}
|
|
110
|
+
async function fanOut(machines, fn) {
|
|
111
|
+
return Promise.all(machines.map(async (m) => {
|
|
112
|
+
if (!m.rpc) return { machine: m, ok: false, error: "unreachable" };
|
|
113
|
+
try {
|
|
114
|
+
const result = await fn(m);
|
|
115
|
+
return { machine: m, ok: true, result };
|
|
116
|
+
} catch (e) {
|
|
117
|
+
return { machine: m, ok: false, error: e?.message || String(e) };
|
|
118
|
+
}
|
|
119
|
+
}));
|
|
120
|
+
}
|
|
121
|
+
function printResultRow(m, status, detail) {
|
|
122
|
+
const id = truncate(m.machineId, 18).padEnd(20);
|
|
123
|
+
const label = truncate(m.label, 22).padEnd(24);
|
|
124
|
+
const color = status === "OK" ? "\x1B[32m" : status === "SKIP" ? "\x1B[33m" : "\x1B[31m";
|
|
125
|
+
console.log(`${id} ${label} ${color}${status.padEnd(5)}\x1B[0m ${truncate(detail, 60)}`);
|
|
126
|
+
}
|
|
127
|
+
function printHeader(headers, widths) {
|
|
128
|
+
const line = headers.map((h, i) => h.padEnd(widths[i])).join(" ");
|
|
129
|
+
console.log(line);
|
|
130
|
+
console.log("-".repeat(line.length));
|
|
131
|
+
}
|
|
132
|
+
async function fleetStatus() {
|
|
133
|
+
const { server, machines } = await discoverMachines();
|
|
134
|
+
if (machines.length === 0) {
|
|
135
|
+
console.log("No machines found.");
|
|
136
|
+
await server.disconnect();
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
try {
|
|
140
|
+
printHeader(["MACHINE ID", "LABEL", "CLAUDE", "SVAMP", "STATUS"], [20, 24, 12, 10, 12]);
|
|
141
|
+
const rows = await fanOut(machines, async (m) => {
|
|
142
|
+
const [claudeRes, svampRes] = await Promise.all([
|
|
143
|
+
m.rpc.bash("claude --version 2>/dev/null || echo unknown").catch(() => null),
|
|
144
|
+
m.rpc.bash("svamp --version 2>/dev/null || echo unknown").catch(() => null)
|
|
145
|
+
]);
|
|
146
|
+
const claude = (claudeRes?.stdout || "unknown").trim().split(/\s+/)[0] || "unknown";
|
|
147
|
+
const svamp = (svampRes?.stdout || "unknown").trim().split(/\s+/)[0] || "unknown";
|
|
148
|
+
const info = await m.rpc.getMachineInfo();
|
|
149
|
+
return { claude, svamp, status: info.daemonState?.status || "unknown" };
|
|
150
|
+
});
|
|
151
|
+
for (const r of rows) {
|
|
152
|
+
const id = truncate(r.machine.machineId, 18).padEnd(20);
|
|
153
|
+
const label = truncate(r.machine.label, 22).padEnd(24);
|
|
154
|
+
const claude = (r.ok ? r.result.claude : "-").padEnd(12);
|
|
155
|
+
const svamp = (r.ok ? r.result.svamp : "-").padEnd(10);
|
|
156
|
+
const status = r.ok ? r.result.status : r.error || "fail";
|
|
157
|
+
const color = r.ok && r.result.status === "running" ? "\x1B[32m" : "\x1B[31m";
|
|
158
|
+
console.log(`${id} ${label} ${claude} ${svamp} ${color}${status}\x1B[0m`);
|
|
159
|
+
}
|
|
160
|
+
console.log(`
|
|
161
|
+
${machines.length} machine(s).`);
|
|
162
|
+
} finally {
|
|
163
|
+
await server.disconnect();
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
async function fleetExec(command, opts) {
|
|
167
|
+
if (!command) {
|
|
168
|
+
console.error('Usage: svamp fleet exec "<command>"');
|
|
169
|
+
process.exit(1);
|
|
170
|
+
}
|
|
171
|
+
const { server, machines } = await discoverMachines();
|
|
172
|
+
if (machines.length === 0) {
|
|
173
|
+
console.log("No machines found.");
|
|
174
|
+
await server.disconnect();
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
try {
|
|
178
|
+
printHeader(["MACHINE ID", "LABEL", "EXIT", "OUTPUT"], [20, 24, 6, 60]);
|
|
179
|
+
const rows = await fanOut(machines, async (m) => {
|
|
180
|
+
return await m.rpc.bash(command, opts?.cwd || void 0);
|
|
181
|
+
});
|
|
182
|
+
let failures = 0;
|
|
183
|
+
for (const r of rows) {
|
|
184
|
+
const id = truncate(r.machine.machineId, 18).padEnd(20);
|
|
185
|
+
const label = truncate(r.machine.label, 22).padEnd(24);
|
|
186
|
+
if (!r.ok) {
|
|
187
|
+
console.log(`${id} ${label} ${"-".padEnd(6)} \x1B[31m${truncate(r.error || "error", 60)}\x1B[0m`);
|
|
188
|
+
failures += 1;
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
const exit = String(r.result.exitCode).padEnd(6);
|
|
192
|
+
const out = (r.result.stdout?.trim() || r.result.stderr?.trim() || "").replace(/\s+/g, " ");
|
|
193
|
+
const color = r.result.exitCode === 0 ? "" : "\x1B[31m";
|
|
194
|
+
const reset = color ? "\x1B[0m" : "";
|
|
195
|
+
console.log(`${id} ${label} ${exit} ${color}${truncate(out, 60)}${reset}`);
|
|
196
|
+
if (r.result.exitCode !== 0) failures += 1;
|
|
197
|
+
}
|
|
198
|
+
console.log(`
|
|
199
|
+
${rows.length - failures}/${rows.length} succeeded.`);
|
|
200
|
+
if (failures > 0) process.exitCode = 1;
|
|
201
|
+
} finally {
|
|
202
|
+
await server.disconnect();
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
async function fleetUpgradeClaude(opts) {
|
|
206
|
+
const version = opts?.version || PINNED_CLAUDE_CODE_VERSION;
|
|
207
|
+
const { server, machines } = await discoverMachines();
|
|
208
|
+
if (machines.length === 0) {
|
|
209
|
+
console.log("No machines found.");
|
|
210
|
+
await server.disconnect();
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
console.log(`Upgrading Claude Code to ${version} on ${machines.length} machine(s)...
|
|
214
|
+
`);
|
|
215
|
+
try {
|
|
216
|
+
printHeader(["MACHINE ID", "LABEL", "STATE", "DETAIL"], [20, 24, 6, 60]);
|
|
217
|
+
const cmd = `claude install ${version} 2>&1 || claude update 2>&1`;
|
|
218
|
+
const rows = await fanOut(machines, async (m) => await m.rpc.bash(cmd, void 0));
|
|
219
|
+
let failures = 0;
|
|
220
|
+
for (const r of rows) {
|
|
221
|
+
if (!r.ok) {
|
|
222
|
+
printResultRow(r.machine, "FAIL", r.error || "");
|
|
223
|
+
failures += 1;
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
const ok = r.result.exitCode === 0;
|
|
227
|
+
const detail = (r.result.stdout?.trim().split("\n").slice(-1)[0] || r.result.stderr?.trim().slice(-200) || "").replace(/\s+/g, " ");
|
|
228
|
+
printResultRow(r.machine, ok ? "OK" : "FAIL", detail);
|
|
229
|
+
if (!ok) failures += 1;
|
|
230
|
+
}
|
|
231
|
+
console.log(`
|
|
232
|
+
${rows.length - failures}/${rows.length} machines on ${version}.`);
|
|
233
|
+
if (failures > 0) process.exitCode = 1;
|
|
234
|
+
} finally {
|
|
235
|
+
await server.disconnect();
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
async function fleetUpgradeSvamp(opts) {
|
|
239
|
+
const version = opts?.version || "latest";
|
|
240
|
+
const { server, machines } = await discoverMachines();
|
|
241
|
+
if (machines.length === 0) {
|
|
242
|
+
console.log("No machines found.");
|
|
243
|
+
await server.disconnect();
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
console.log(`Upgrading svamp-cli to ${version} on ${machines.length} machine(s)...
|
|
247
|
+
`);
|
|
248
|
+
try {
|
|
249
|
+
printHeader(["MACHINE ID", "LABEL", "STATE", "DETAIL"], [20, 24, 6, 60]);
|
|
250
|
+
const cmd = `bash -lc 'npm install -g svamp-cli@${version} 2>&1 | tail -5 && svamp daemon restart 2>&1 | tail -5'`;
|
|
251
|
+
const rows = await fanOut(machines, async (m) => await m.rpc.bash(cmd, void 0));
|
|
252
|
+
let failures = 0;
|
|
253
|
+
for (const r of rows) {
|
|
254
|
+
if (!r.ok) {
|
|
255
|
+
printResultRow(r.machine, "FAIL", r.error || "");
|
|
256
|
+
failures += 1;
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
const ok = r.result.exitCode === 0;
|
|
260
|
+
const detail = (r.result.stdout?.trim().split("\n").slice(-1)[0] || r.result.stderr?.trim().slice(-200) || "").replace(/\s+/g, " ");
|
|
261
|
+
printResultRow(r.machine, ok ? "OK" : "FAIL", detail);
|
|
262
|
+
if (!ok) failures += 1;
|
|
263
|
+
}
|
|
264
|
+
console.log(`
|
|
265
|
+
${rows.length - failures}/${rows.length} machines upgraded.`);
|
|
266
|
+
console.log("Note: daemons will auto-converge Claude Code to the pinned version on restart.");
|
|
267
|
+
if (failures > 0) process.exitCode = 1;
|
|
268
|
+
} finally {
|
|
269
|
+
await server.disconnect();
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
async function fleetDaemonRestart(opts) {
|
|
273
|
+
const { server, machines } = await discoverMachines();
|
|
274
|
+
if (machines.length === 0) {
|
|
275
|
+
console.log("No machines found.");
|
|
276
|
+
await server.disconnect();
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
try {
|
|
280
|
+
printHeader(["MACHINE ID", "LABEL", "STATE", "DETAIL"], [20, 24, 6, 60]);
|
|
281
|
+
const cmd = opts?.graceful === false ? `svamp daemon stop --cleanup 2>&1 && svamp daemon start 2>&1` : `svamp daemon restart 2>&1`;
|
|
282
|
+
const rows = await fanOut(machines, async (m) => await m.rpc.bash(cmd, void 0));
|
|
283
|
+
let failures = 0;
|
|
284
|
+
for (const r of rows) {
|
|
285
|
+
if (!r.ok) {
|
|
286
|
+
printResultRow(r.machine, "FAIL", r.error || "");
|
|
287
|
+
failures += 1;
|
|
288
|
+
continue;
|
|
289
|
+
}
|
|
290
|
+
const ok = r.result.exitCode === 0;
|
|
291
|
+
const detail = (r.result.stdout?.trim().split("\n").slice(-1)[0] || r.result.stderr?.trim().slice(-200) || "").replace(/\s+/g, " ");
|
|
292
|
+
printResultRow(r.machine, ok ? "OK" : "FAIL", detail);
|
|
293
|
+
if (!ok) failures += 1;
|
|
294
|
+
}
|
|
295
|
+
console.log(`
|
|
296
|
+
${rows.length - failures}/${rows.length} restarted.`);
|
|
297
|
+
if (failures > 0) process.exitCode = 1;
|
|
298
|
+
} finally {
|
|
299
|
+
await server.disconnect();
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
async function fleetPushSkill(name) {
|
|
303
|
+
if (!name) {
|
|
304
|
+
console.error("Usage: svamp fleet push-skill <name>");
|
|
305
|
+
process.exit(1);
|
|
306
|
+
}
|
|
307
|
+
const { server, machines } = await discoverMachines();
|
|
308
|
+
if (machines.length === 0) {
|
|
309
|
+
console.log("No machines found.");
|
|
310
|
+
await server.disconnect();
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
console.log(`Pushing skill "${name}" to ${machines.length} machine(s)...
|
|
314
|
+
`);
|
|
315
|
+
try {
|
|
316
|
+
printHeader(["MACHINE ID", "LABEL", "STATE", "DETAIL"], [20, 24, 6, 60]);
|
|
317
|
+
const cmd = `svamp skills install ${name} --force 2>&1`;
|
|
318
|
+
const rows = await fanOut(machines, async (m) => await m.rpc.bash(cmd, void 0));
|
|
319
|
+
let failures = 0;
|
|
320
|
+
for (const r of rows) {
|
|
321
|
+
if (!r.ok) {
|
|
322
|
+
printResultRow(r.machine, "FAIL", r.error || "");
|
|
323
|
+
failures += 1;
|
|
324
|
+
continue;
|
|
325
|
+
}
|
|
326
|
+
const ok = r.result.exitCode === 0;
|
|
327
|
+
const detail = (r.result.stdout?.trim().split("\n").slice(-1)[0] || r.result.stderr?.trim().slice(-200) || "").replace(/\s+/g, " ");
|
|
328
|
+
printResultRow(r.machine, ok ? "OK" : "FAIL", detail);
|
|
329
|
+
if (!ok) failures += 1;
|
|
330
|
+
}
|
|
331
|
+
console.log(`
|
|
332
|
+
${rows.length - failures}/${rows.length} updated.`);
|
|
333
|
+
if (failures > 0) process.exitCode = 1;
|
|
334
|
+
} finally {
|
|
335
|
+
await server.disconnect();
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
export { fleetDaemonRestart, fleetExec, fleetPushSkill, fleetStatus, fleetUpgradeClaude, fleetUpgradeSvamp };
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { c as connectToHypha, d as daemonStatus, g as getHyphaServerUrl, r as registerMachineService, a as registerSessionService, s as startDaemon, b as stopDaemon } from './run-
|
|
1
|
+
export { c as connectToHypha, d as daemonStatus, g as getHyphaServerUrl, r as registerMachineService, a as registerSessionService, s as startDaemon, b as stopDaemon } from './run-Br90om8R.mjs';
|
|
2
2
|
import 'os';
|
|
3
3
|
import 'fs/promises';
|
|
4
4
|
import 'fs';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
var name = "svamp-cli";
|
|
2
|
-
var version = "0.2.
|
|
2
|
+
var version = "0.2.74";
|
|
3
3
|
var description = "Svamp CLI — AI workspace daemon on Hypha Cloud";
|
|
4
4
|
var author = "Amun AI AB";
|
|
5
5
|
var license = "SEE LICENSE IN LICENSE";
|
|
@@ -19,7 +19,7 @@ var exports$1 = {
|
|
|
19
19
|
var scripts = {
|
|
20
20
|
build: "rm -rf dist bin/skills && mkdir -p bin/skills && cp -r ../../skills/artifact bin/skills/artifact && tsc --noEmit && pkgroll",
|
|
21
21
|
typecheck: "tsc --noEmit",
|
|
22
|
-
test: "npx tsx test/test-context-window.mjs && npx tsx test/test-authorize.mjs && npx tsx test/test-normalize-allowed-user.mjs && npx tsx test/test-share-url.mjs && npx tsx test/test-update-sharing-normalization.mjs && npx tsx test/test-staged-homes-sweep.mjs && npx tsx test/test-session-helpers.mjs && npx tsx test/test-cli-routing.mjs && npx tsx test/test-security-context.mjs && npx tsx test/test-isolation-decision.mjs && npx tsx test/test-ralph-loop.mjs && npx tsx test/test-message-helpers.mjs && npx tsx test/test-agent-config.mjs && npx tsx test/test-wrap-command.mjs && npx tsx test/test-credential-staging.mjs && npx tsx test/test-claude-auth.mjs && npx tsx test/test-output-formatters.mjs && npx tsx test/test-agent-types.mjs && npx tsx test/test-transport.mjs && npx tsx test/test-session-update-handlers.mjs && npx tsx test/test-session-scanner.mjs && npx tsx test/test-hypha-client.mjs && npx tsx test/test-hook-settings.mjs && npx tsx test/test-session-service-logic.mjs && npx tsx test/test-daemon-persistence.mjs && npx tsx test/test-detect-isolation.mjs && npx tsx test/test-machine-service-logic.mjs && npx tsx test/test-interactive-helpers.mjs && npx tsx test/test-codex-backend.mjs && npx tsx test/test-acp-backend.mjs && npx tsx test/test-acp-bridge.mjs && npx tsx test/test-hook-server.mjs && npx tsx test/test-session-commands.mjs && npx tsx test/test-interactive-console.mjs && npx tsx test/test-session-messages.mjs && npx tsx test/test-session-send-query.mjs && npx tsx test/test-skills.mjs && npx tsx test/test-agent-grouping.mjs && npx tsx test/test-ralph-loop-integration.mjs && npx tsx test/test-ralph-loop-modes.mjs && npx tsx test/test-machine-list-directory.mjs && npx tsx test/test-service-commands.mjs && npx tsx test/test-supervisor.mjs && npx tsx test/test-supervisor-lock.mjs && npx tsx test/test-clear-detection.mjs && npx tsx test/test-session-consolidation.mjs && npx tsx test/test-inbox.mjs && npx tsx test/test-session-rpc-dispatch.mjs && npx tsx test/test-sandbox-cli.mjs && npx tsx test/test-serve-manager.mjs && npx tsx test/test-serve-stability.mjs && npx tsx test/test-frpc-e2e.mjs --unit-only && node test/pinnedClaudeCode.test.mjs",
|
|
22
|
+
test: "npx tsx test/test-context-window.mjs && npx tsx test/test-authorize.mjs && npx tsx test/test-normalize-allowed-user.mjs && npx tsx test/test-share-url.mjs && npx tsx test/test-update-sharing-normalization.mjs && npx tsx test/test-staged-homes-sweep.mjs && npx tsx test/test-session-helpers.mjs && npx tsx test/test-cli-routing.mjs && npx tsx test/test-security-context.mjs && npx tsx test/test-isolation-decision.mjs && npx tsx test/test-ralph-loop.mjs && npx tsx test/test-message-helpers.mjs && npx tsx test/test-agent-config.mjs && npx tsx test/test-wrap-command.mjs && npx tsx test/test-credential-staging.mjs && npx tsx test/test-claude-auth.mjs && npx tsx test/test-output-formatters.mjs && npx tsx test/test-agent-types.mjs && npx tsx test/test-transport.mjs && npx tsx test/test-session-update-handlers.mjs && npx tsx test/test-session-scanner.mjs && npx tsx test/test-hypha-client.mjs && npx tsx test/test-hook-settings.mjs && npx tsx test/test-session-service-logic.mjs && npx tsx test/test-daemon-persistence.mjs && npx tsx test/test-detect-isolation.mjs && npx tsx test/test-machine-service-logic.mjs && npx tsx test/test-interactive-helpers.mjs && npx tsx test/test-codex-backend.mjs && npx tsx test/test-acp-backend.mjs && npx tsx test/test-acp-bridge.mjs && npx tsx test/test-hook-server.mjs && npx tsx test/test-session-commands.mjs && npx tsx test/test-interactive-console.mjs && npx tsx test/test-session-messages.mjs && npx tsx test/test-session-send-query.mjs && npx tsx test/test-skills.mjs && npx tsx test/test-agent-grouping.mjs && npx tsx test/test-ralph-loop-integration.mjs && npx tsx test/test-ralph-loop-modes.mjs && npx tsx test/test-machine-list-directory.mjs && npx tsx test/test-service-commands.mjs && npx tsx test/test-supervisor.mjs && npx tsx test/test-supervisor-lock.mjs && npx tsx test/test-clear-detection.mjs && npx tsx test/test-session-consolidation.mjs && npx tsx test/test-inbox.mjs && npx tsx test/test-session-rpc-dispatch.mjs && npx tsx test/test-sandbox-cli.mjs && npx tsx test/test-serve-manager.mjs && npx tsx test/test-serve-stability.mjs && npx tsx test/test-frpc-e2e.mjs --unit-only && node test/pinnedClaudeCode.test.mjs && node test/fleet.test.mjs",
|
|
23
23
|
"test:hypha": "node --no-warnings test/test-hypha-service.mjs",
|
|
24
24
|
dev: "tsx src/cli.ts",
|
|
25
25
|
"dev:daemon": "tsx src/cli.ts daemon start-sync",
|
|
@@ -5804,12 +5804,28 @@ btn.addEventListener('click', async () => {
|
|
|
5804
5804
|
if (!token) throw new Error('Timed out waiting for sign-in. Please try again.');
|
|
5805
5805
|
|
|
5806
5806
|
// 4. Set the cookie so subsequent requests to this origin are authenticated.
|
|
5807
|
-
|
|
5808
|
-
|
|
5807
|
+
// Over HTTPS use SameSite=None; Secure so the cookie is still sent when
|
|
5808
|
+
// this page is framed cross-site (e.g. embedded as an <artifact> iframe
|
|
5809
|
+
// in the Svamp app) \u2014 SameSite=Lax would be dropped in that third-party
|
|
5810
|
+
// context. Fall back to Lax on plain HTTP (SameSite=None requires Secure).
|
|
5811
|
+
const isHttps = location.protocol === 'https:';
|
|
5812
|
+
const sameSite = isHttps ? '; SameSite=None; Secure' : '; SameSite=Lax';
|
|
5813
|
+
document.cookie = cookieName + '=' + token + '; path=/' + sameSite;
|
|
5814
|
+
|
|
5815
|
+
// Also carry the token in the redirect URL as a fallback: browsers that
|
|
5816
|
+
// block third-party cookies entirely (Safari ITP, Chrome 3p-cookie
|
|
5817
|
+
// phaseout) won't send the cookie above when we're framed cross-site, but
|
|
5818
|
+
// the proxy also accepts ?token= on the request. Harmless when the cookie
|
|
5819
|
+
// does work \u2014 extractToken() prefers the cookie.
|
|
5820
|
+
let dest = redirectUrl;
|
|
5821
|
+
try {
|
|
5822
|
+
const sep = dest.indexOf('?') === -1 ? '?' : '&';
|
|
5823
|
+
dest = dest + sep + 'token=' + encodeURIComponent(token);
|
|
5824
|
+
} catch (e) {}
|
|
5809
5825
|
|
|
5810
5826
|
try { popup.close(); } catch (e) {}
|
|
5811
5827
|
statusEl.innerHTML = '<span class="ok">Signed in. Redirecting\u2026</span>';
|
|
5812
|
-
setTimeout(() => { window.location.replace(
|
|
5828
|
+
setTimeout(() => { window.location.replace(dest); }, 300);
|
|
5813
5829
|
} catch (err) {
|
|
5814
5830
|
try { popup.close(); } catch (e) {}
|
|
5815
5831
|
setError('Login failed: ' + (err && err.message ? err.message : err));
|
|
@@ -7869,7 +7885,7 @@ async function startDaemon(options) {
|
|
|
7869
7885
|
const list = loadExposedTunnels().filter((t) => t.name !== name);
|
|
7870
7886
|
saveExposedTunnels(list);
|
|
7871
7887
|
}
|
|
7872
|
-
const { ServeManager } = await import('./serveManager-
|
|
7888
|
+
const { ServeManager } = await import('./serveManager-ClzowUXI.mjs');
|
|
7873
7889
|
const serveManager = new ServeManager(SVAMP_HOME, (msg) => logger.log(`[SERVE] ${msg}`), hyphaServerUrl);
|
|
7874
7890
|
ensureAutoInstalledSkills(logger).catch(() => {
|
|
7875
7891
|
});
|
|
@@ -2,7 +2,7 @@ import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(im
|
|
|
2
2
|
import os from 'node:os';
|
|
3
3
|
import { resolve, join } from 'node:path';
|
|
4
4
|
import { existsSync, readFileSync, watch } from 'node:fs';
|
|
5
|
-
import { c as connectToHypha, a as registerSessionService, k as generateHookSettings } from './run-
|
|
5
|
+
import { c as connectToHypha, a as registerSessionService, k as generateHookSettings } from './run-Br90om8R.mjs';
|
|
6
6
|
import { createServer } from 'node:http';
|
|
7
7
|
import { spawn } from 'node:child_process';
|
|
8
8
|
import { createInterface } from 'node:readline';
|
|
@@ -54,7 +54,7 @@ async function handleServeCommand() {
|
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
async function serveAdd(args, machineId) {
|
|
57
|
-
const { connectAndGetMachine } = await import('./commands
|
|
57
|
+
const { connectAndGetMachine } = await import('./commands--SLXTrkN.mjs');
|
|
58
58
|
const pos = positionalArgs(args);
|
|
59
59
|
const name = pos[0];
|
|
60
60
|
if (!name) {
|
|
@@ -93,7 +93,7 @@ async function serveAdd(args, machineId) {
|
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
95
|
async function serveApply(args, machineId) {
|
|
96
|
-
const { connectAndGetMachine } = await import('./commands
|
|
96
|
+
const { connectAndGetMachine } = await import('./commands--SLXTrkN.mjs');
|
|
97
97
|
const fs = await import('fs');
|
|
98
98
|
const yaml = await import('yaml');
|
|
99
99
|
const file = positionalArgs(args)[0];
|
|
@@ -182,7 +182,7 @@ async function serveApply(args, machineId) {
|
|
|
182
182
|
}
|
|
183
183
|
}
|
|
184
184
|
async function serveRemove(args, machineId) {
|
|
185
|
-
const { connectAndGetMachine } = await import('./commands
|
|
185
|
+
const { connectAndGetMachine } = await import('./commands--SLXTrkN.mjs');
|
|
186
186
|
const pos = positionalArgs(args);
|
|
187
187
|
const name = pos[0];
|
|
188
188
|
if (!name) {
|
|
@@ -202,7 +202,7 @@ async function serveRemove(args, machineId) {
|
|
|
202
202
|
}
|
|
203
203
|
}
|
|
204
204
|
async function serveList(args, machineId) {
|
|
205
|
-
const { connectAndGetMachine } = await import('./commands
|
|
205
|
+
const { connectAndGetMachine } = await import('./commands--SLXTrkN.mjs');
|
|
206
206
|
const all = hasFlag(args, "--all", "-a");
|
|
207
207
|
const json = hasFlag(args, "--json");
|
|
208
208
|
const sessionId = getFlag(args, "--session");
|
|
@@ -235,7 +235,7 @@ async function serveList(args, machineId) {
|
|
|
235
235
|
}
|
|
236
236
|
}
|
|
237
237
|
async function serveInfo(machineId) {
|
|
238
|
-
const { connectAndGetMachine } = await import('./commands
|
|
238
|
+
const { connectAndGetMachine } = await import('./commands--SLXTrkN.mjs');
|
|
239
239
|
const { machine, server } = await connectAndGetMachine(machineId);
|
|
240
240
|
try {
|
|
241
241
|
const info = await machine.serveInfo();
|
|
@@ -4,7 +4,7 @@ import * as fs from 'fs';
|
|
|
4
4
|
import * as http from 'http';
|
|
5
5
|
import * as net from 'net';
|
|
6
6
|
import * as path from 'path';
|
|
7
|
-
import { S as ServeAuth, h as hasCookieToken } from './run-
|
|
7
|
+
import { S as ServeAuth, h as hasCookieToken } from './run-Br90om8R.mjs';
|
|
8
8
|
import 'os';
|
|
9
9
|
import 'fs/promises';
|
|
10
10
|
import 'url';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "svamp-cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.74",
|
|
4
4
|
"description": "Svamp CLI — AI workspace daemon on Hypha Cloud",
|
|
5
5
|
"author": "Amun AI AB",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"scripts": {
|
|
21
21
|
"build": "rm -rf dist bin/skills && mkdir -p bin/skills && cp -r ../../skills/artifact bin/skills/artifact && tsc --noEmit && pkgroll",
|
|
22
22
|
"typecheck": "tsc --noEmit",
|
|
23
|
-
"test": "npx tsx test/test-context-window.mjs && npx tsx test/test-authorize.mjs && npx tsx test/test-normalize-allowed-user.mjs && npx tsx test/test-share-url.mjs && npx tsx test/test-update-sharing-normalization.mjs && npx tsx test/test-staged-homes-sweep.mjs && npx tsx test/test-session-helpers.mjs && npx tsx test/test-cli-routing.mjs && npx tsx test/test-security-context.mjs && npx tsx test/test-isolation-decision.mjs && npx tsx test/test-ralph-loop.mjs && npx tsx test/test-message-helpers.mjs && npx tsx test/test-agent-config.mjs && npx tsx test/test-wrap-command.mjs && npx tsx test/test-credential-staging.mjs && npx tsx test/test-claude-auth.mjs && npx tsx test/test-output-formatters.mjs && npx tsx test/test-agent-types.mjs && npx tsx test/test-transport.mjs && npx tsx test/test-session-update-handlers.mjs && npx tsx test/test-session-scanner.mjs && npx tsx test/test-hypha-client.mjs && npx tsx test/test-hook-settings.mjs && npx tsx test/test-session-service-logic.mjs && npx tsx test/test-daemon-persistence.mjs && npx tsx test/test-detect-isolation.mjs && npx tsx test/test-machine-service-logic.mjs && npx tsx test/test-interactive-helpers.mjs && npx tsx test/test-codex-backend.mjs && npx tsx test/test-acp-backend.mjs && npx tsx test/test-acp-bridge.mjs && npx tsx test/test-hook-server.mjs && npx tsx test/test-session-commands.mjs && npx tsx test/test-interactive-console.mjs && npx tsx test/test-session-messages.mjs && npx tsx test/test-session-send-query.mjs && npx tsx test/test-skills.mjs && npx tsx test/test-agent-grouping.mjs && npx tsx test/test-ralph-loop-integration.mjs && npx tsx test/test-ralph-loop-modes.mjs && npx tsx test/test-machine-list-directory.mjs && npx tsx test/test-service-commands.mjs && npx tsx test/test-supervisor.mjs && npx tsx test/test-supervisor-lock.mjs && npx tsx test/test-clear-detection.mjs && npx tsx test/test-session-consolidation.mjs && npx tsx test/test-inbox.mjs && npx tsx test/test-session-rpc-dispatch.mjs && npx tsx test/test-sandbox-cli.mjs && npx tsx test/test-serve-manager.mjs && npx tsx test/test-serve-stability.mjs && npx tsx test/test-frpc-e2e.mjs --unit-only && node test/pinnedClaudeCode.test.mjs",
|
|
23
|
+
"test": "npx tsx test/test-context-window.mjs && npx tsx test/test-authorize.mjs && npx tsx test/test-normalize-allowed-user.mjs && npx tsx test/test-share-url.mjs && npx tsx test/test-update-sharing-normalization.mjs && npx tsx test/test-staged-homes-sweep.mjs && npx tsx test/test-session-helpers.mjs && npx tsx test/test-cli-routing.mjs && npx tsx test/test-security-context.mjs && npx tsx test/test-isolation-decision.mjs && npx tsx test/test-ralph-loop.mjs && npx tsx test/test-message-helpers.mjs && npx tsx test/test-agent-config.mjs && npx tsx test/test-wrap-command.mjs && npx tsx test/test-credential-staging.mjs && npx tsx test/test-claude-auth.mjs && npx tsx test/test-output-formatters.mjs && npx tsx test/test-agent-types.mjs && npx tsx test/test-transport.mjs && npx tsx test/test-session-update-handlers.mjs && npx tsx test/test-session-scanner.mjs && npx tsx test/test-hypha-client.mjs && npx tsx test/test-hook-settings.mjs && npx tsx test/test-session-service-logic.mjs && npx tsx test/test-daemon-persistence.mjs && npx tsx test/test-detect-isolation.mjs && npx tsx test/test-machine-service-logic.mjs && npx tsx test/test-interactive-helpers.mjs && npx tsx test/test-codex-backend.mjs && npx tsx test/test-acp-backend.mjs && npx tsx test/test-acp-bridge.mjs && npx tsx test/test-hook-server.mjs && npx tsx test/test-session-commands.mjs && npx tsx test/test-interactive-console.mjs && npx tsx test/test-session-messages.mjs && npx tsx test/test-session-send-query.mjs && npx tsx test/test-skills.mjs && npx tsx test/test-agent-grouping.mjs && npx tsx test/test-ralph-loop-integration.mjs && npx tsx test/test-ralph-loop-modes.mjs && npx tsx test/test-machine-list-directory.mjs && npx tsx test/test-service-commands.mjs && npx tsx test/test-supervisor.mjs && npx tsx test/test-supervisor-lock.mjs && npx tsx test/test-clear-detection.mjs && npx tsx test/test-session-consolidation.mjs && npx tsx test/test-inbox.mjs && npx tsx test/test-session-rpc-dispatch.mjs && npx tsx test/test-sandbox-cli.mjs && npx tsx test/test-serve-manager.mjs && npx tsx test/test-serve-stability.mjs && npx tsx test/test-frpc-e2e.mjs --unit-only && node test/pinnedClaudeCode.test.mjs && node test/fleet.test.mjs",
|
|
24
24
|
"test:hypha": "node --no-warnings test/test-hypha-service.mjs",
|
|
25
25
|
"dev": "tsx src/cli.ts",
|
|
26
26
|
"dev:daemon": "tsx src/cli.ts daemon start-sync",
|