svamp-cli 0.2.72 → 0.2.73

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/cli.mjs CHANGED
@@ -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()) {
@@ -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-hpa4sCE_.mjs').catch(() => ({ default: { version: "unknown" } }));
325
+ const pkg = await import('./package-O54lUaPi.mjs').catch(() => ({ default: { version: "unknown" } }));
319
326
  console.log(`svamp version: ${pkg.default.version}`);
320
327
  } else {
321
328
  console.error(`Unknown command: ${subcommand}`);
@@ -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-B9CWHUv1.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-B9CWHUv1.mjs');
1028
+ await fleetExec(command, { cwd: flag("cwd") });
1029
+ } else if (sub === "upgrade-claude") {
1030
+ const { fleetUpgradeClaude } = await import('./fleet-B9CWHUv1.mjs');
1031
+ await fleetUpgradeClaude({ version: flag("version", "-v") });
1032
+ } else if (sub === "upgrade-svamp") {
1033
+ const { fleetUpgradeSvamp } = await import('./fleet-B9CWHUv1.mjs');
1034
+ await fleetUpgradeSvamp({ version: flag("version", "-v") });
1035
+ } else if (sub === "daemon-restart") {
1036
+ const { fleetDaemonRestart } = await import('./fleet-B9CWHUv1.mjs');
1037
+ await fleetDaemonRestart({ graceful: !hasFlag("cleanup") });
1038
+ } else if (sub === "push-skill") {
1039
+ const name = fleetArgs[1];
1040
+ const { fleetPushSkill } = await import('./fleet-B9CWHUv1.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)
@@ -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-CC-0bNTe.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 };
@@ -1,5 +1,5 @@
1
1
  var name = "svamp-cli";
2
- var version = "0.2.72";
2
+ var version = "0.2.73";
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",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svamp-cli",
3
- "version": "0.2.72",
3
+ "version": "0.2.73",
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",