svamp-cli 0.1.30 → 0.1.31

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
@@ -89,7 +89,7 @@ async function main() {
89
89
  } else if (subcommand === "--help" || subcommand === "-h" || !subcommand) {
90
90
  printHelp();
91
91
  } else if (subcommand === "--version" || subcommand === "-v") {
92
- const pkg = await import('./package-CKOQ5lA7.mjs').catch(() => ({ default: { version: "unknown" } }));
92
+ const pkg = await import('./package-BtoCHVOd.mjs').catch(() => ({ default: { version: "unknown" } }));
93
93
  console.log(`svamp version: ${pkg.default.version}`);
94
94
  } else {
95
95
  console.error(`Unknown command: ${subcommand}`);
@@ -255,7 +255,7 @@ async function handleSessionCommand() {
255
255
  printSessionHelp();
256
256
  return;
257
257
  }
258
- const { sessionList, sessionSpawn, sessionStop, sessionInfo, sessionMessages, sessionAttach, sessionMachines, sessionSend, sessionWait } = await import('./commands-C5pW2VmI.mjs');
258
+ const { sessionList, sessionSpawn, sessionStop, sessionInfo, sessionMessages, sessionAttach, sessionMachines, sessionSend, sessionWait } = await import('./commands-78RHC879.mjs');
259
259
  const parseFlagStr = (flag, shortFlag) => {
260
260
  for (let i = 1; i < sessionArgs.length; i++) {
261
261
  if ((sessionArgs[i] === flag || shortFlag) && i + 1 < sessionArgs.length) {
@@ -186,7 +186,15 @@ async function connectAndGetMachine(machineId) {
186
186
  }
187
187
  }
188
188
  } else {
189
- selectedService = services[0];
189
+ if (state.machineId) {
190
+ const localMatch = services.find((s) => {
191
+ const id = s.id || s.name || "";
192
+ return id.includes(state.machineId);
193
+ });
194
+ selectedService = localMatch || services[0];
195
+ } else {
196
+ selectedService = services[0];
197
+ }
190
198
  }
191
199
  const svcId = selectedService.id || selectedService.name;
192
200
  machine = await server.getService(svcId);
@@ -199,6 +207,81 @@ async function connectAndGetMachine(machineId) {
199
207
  restoreConsole();
200
208
  return { server, machine };
201
209
  }
210
+ async function connectAndGetAllMachines() {
211
+ loadDotEnv();
212
+ const state = readDaemonState();
213
+ if (!state || !isDaemonAlive(state)) {
214
+ console.error('Daemon is not running. Start it with "svamp daemon start".');
215
+ process.exit(1);
216
+ }
217
+ const serverUrl = process.env.HYPHA_SERVER_URL || state.hyphaServerUrl;
218
+ const token = process.env.HYPHA_TOKEN;
219
+ if (!serverUrl) {
220
+ console.error('No Hypha server URL. Run "svamp login <url>" first.');
221
+ process.exit(1);
222
+ }
223
+ const origLog = console.log;
224
+ const origWarn = console.warn;
225
+ const origInfo = console.info;
226
+ const origError = console.error;
227
+ const stdoutWrite = process.stdout.write.bind(process.stdout);
228
+ const stderrWrite = process.stderr.write.bind(process.stderr);
229
+ const isHyphaLog = (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") || chunk.includes("Timeout registering service") || chunk.includes("Failed to subscribe to client_disconnected") || chunk.includes("Timeout subscribing to client_disconnected"));
230
+ console.log = () => {
231
+ };
232
+ console.warn = () => {
233
+ };
234
+ console.info = () => {
235
+ };
236
+ console.error = (...args) => {
237
+ if (!args.some((a) => isHyphaLog(a))) origError(...args);
238
+ };
239
+ process.stdout.write = (chunk, ...args) => {
240
+ if (isHyphaLog(chunk)) return true;
241
+ return stdoutWrite(chunk, ...args);
242
+ };
243
+ process.stderr.write = (chunk, ...args) => {
244
+ if (isHyphaLog(chunk)) return true;
245
+ return stderrWrite(chunk, ...args);
246
+ };
247
+ const restoreConsole = () => {
248
+ console.log = origLog;
249
+ console.warn = origWarn;
250
+ console.info = origInfo;
251
+ console.error = origError;
252
+ };
253
+ let server;
254
+ try {
255
+ server = await connectToHypha({ serverUrl, token, name: "svamp-session-cli" });
256
+ } catch (err) {
257
+ restoreConsole();
258
+ console.error(`Failed to connect to Hypha: ${err.message}`);
259
+ process.exit(1);
260
+ }
261
+ const machines = [];
262
+ try {
263
+ const services = await server.listServices({ type: "svamp-machine" });
264
+ for (const svc of services) {
265
+ try {
266
+ const svcId = svc.id || svc.name;
267
+ machines.push(await server.getService(svcId));
268
+ } catch {
269
+ }
270
+ }
271
+ } catch (err) {
272
+ restoreConsole();
273
+ console.error(`Failed to discover machine services: ${err.message}`);
274
+ await server.disconnect();
275
+ process.exit(1);
276
+ }
277
+ restoreConsole();
278
+ if (machines.length === 0) {
279
+ console.error("No machine service found. Is the daemon registered on Hypha?");
280
+ await server.disconnect();
281
+ process.exit(1);
282
+ }
283
+ return { server, machines };
284
+ }
202
285
  async function sessionMachines() {
203
286
  loadDotEnv();
204
287
  const state = readDaemonState();
@@ -497,66 +580,90 @@ async function waitForBusyThenIdle(server, sessionId, timeoutMs = 3e5, busyTimeo
497
580
  throw new Error("Timeout waiting for agent to become idle");
498
581
  }
499
582
  async function sessionList(machineId, opts) {
500
- const { server, machine } = await connectAndGetMachine(machineId);
501
- try {
502
- const sessions = await machine.listSessions();
503
- const filtered = opts?.active ? sessions.filter((s) => s.active) : sessions;
504
- if (filtered.length === 0) {
505
- if (opts?.json) {
506
- console.log(formatJson([]));
507
- } else {
508
- console.log("No active sessions.");
509
- }
510
- return;
583
+ if (machineId) {
584
+ const { server, machine } = await connectAndGetMachine(machineId);
585
+ try {
586
+ await listSessionsFromMachines(server, [machine], opts);
587
+ } finally {
588
+ await server.disconnect();
511
589
  }
512
- const enriched = [];
513
- for (const s of filtered) {
514
- let flavor = "claude";
515
- let name = "";
516
- let path = s.directory || "";
517
- let host = "";
518
- if (s.metadata) {
519
- flavor = s.metadata.flavor || "claude";
520
- name = s.metadata.name || "";
521
- }
522
- if (s.active) {
523
- try {
524
- const svc = await server.getService(`svamp-session-${s.sessionId}`);
525
- const { metadata } = await svc.getMetadata();
526
- flavor = metadata?.flavor || flavor;
527
- name = metadata?.name || name;
528
- path = metadata?.path || path;
529
- host = metadata?.host || "";
530
- } catch {
531
- }
590
+ } else {
591
+ const { server, machines } = await connectAndGetAllMachines();
592
+ try {
593
+ await listSessionsFromMachines(server, machines, opts);
594
+ } finally {
595
+ await server.disconnect();
596
+ }
597
+ }
598
+ }
599
+ async function listSessionsFromMachines(server, machines, opts) {
600
+ const allSessions = [];
601
+ for (const machine of machines) {
602
+ try {
603
+ const info = await machine.getMachineInfo();
604
+ const sessions = await machine.listSessions();
605
+ for (const s of sessions) {
606
+ s.machineHost = info.metadata?.displayName || info.metadata?.host || info.machineId;
532
607
  }
533
- enriched.push({ ...s, flavor, name, path, host });
608
+ allSessions.push(...sessions);
609
+ } catch {
534
610
  }
611
+ }
612
+ const filtered = opts?.active ? allSessions.filter((s) => s.active) : allSessions;
613
+ if (filtered.length === 0) {
535
614
  if (opts?.json) {
536
- console.log(formatJson(enriched.map((s) => ({
537
- sessionId: s.sessionId,
538
- agent: s.flavor,
539
- name: s.name,
540
- path: s.path,
541
- host: s.host,
542
- active: s.active,
543
- directory: s.directory
544
- }))));
615
+ console.log(formatJson([]));
545
616
  } else {
546
- const header = `${"ID".padEnd(10)} ${"AGENT".padEnd(10)} ${"STATUS".padEnd(9)} ${"NAME".padEnd(25)} ${"DIRECTORY".padEnd(35)}`;
547
- console.log(header);
548
- console.log("-".repeat(header.length));
549
- for (const s of enriched) {
550
- const id = s.sessionId.slice(0, 8);
551
- const agent = (s.flavor || "claude").padEnd(10);
552
- const status = s.active ? "\x1B[32mactive\x1B[0m " : "\x1B[90minactive\x1B[0m";
553
- const name = truncate(s.name || "-", 25).padEnd(25);
554
- const dir = truncate(s.directory || "-", 33).padEnd(35);
555
- console.log(`${id.padEnd(10)} ${agent} ${status} ${name} ${dir}`);
617
+ console.log("No active sessions.");
618
+ }
619
+ return;
620
+ }
621
+ const enriched = [];
622
+ for (const s of filtered) {
623
+ let flavor = "claude";
624
+ let name = "";
625
+ let path = s.directory || "";
626
+ let host = s.machineHost || "";
627
+ if (s.metadata) {
628
+ flavor = s.metadata.flavor || "claude";
629
+ name = s.metadata.name || "";
630
+ }
631
+ if (s.active) {
632
+ try {
633
+ const svc = await server.getService(`svamp-session-${s.sessionId}`);
634
+ const { metadata } = await svc.getMetadata();
635
+ flavor = metadata?.flavor || flavor;
636
+ name = metadata?.name || name;
637
+ path = metadata?.path || path;
638
+ host = metadata?.host || host;
639
+ } catch {
556
640
  }
557
641
  }
558
- } finally {
559
- await server.disconnect();
642
+ enriched.push({ ...s, flavor, name, path, host });
643
+ }
644
+ if (opts?.json) {
645
+ console.log(formatJson(enriched.map((s) => ({
646
+ sessionId: s.sessionId,
647
+ agent: s.flavor,
648
+ name: s.name,
649
+ path: s.path,
650
+ host: s.host,
651
+ active: s.active,
652
+ directory: s.directory
653
+ }))));
654
+ } else {
655
+ const header = `${"ID".padEnd(10)} ${"AGENT".padEnd(10)} ${"STATUS".padEnd(9)} ${"NAME".padEnd(25)} ${"MACHINE".padEnd(18)} ${"DIRECTORY".padEnd(35)}`;
656
+ console.log(header);
657
+ console.log("-".repeat(header.length));
658
+ for (const s of enriched) {
659
+ const id = s.sessionId.slice(0, 8);
660
+ const agent = (s.flavor || "claude").padEnd(10);
661
+ const status = s.active ? "\x1B[32mactive\x1B[0m " : "\x1B[90minactive\x1B[0m";
662
+ const name = truncate(s.name || "-", 25).padEnd(25);
663
+ const machine = truncate(s.host || "-", 16).padEnd(18);
664
+ const dir = truncate(s.directory || "-", 33).padEnd(35);
665
+ console.log(`${id.padEnd(10)} ${agent} ${status} ${name} ${machine} ${dir}`);
666
+ }
560
667
  }
561
668
  }
562
669
  async function sessionSpawn(agent, directory, machineId, opts) {
@@ -1,5 +1,5 @@
1
1
  var name = "svamp-cli";
2
- var version = "0.1.29";
2
+ var version = "0.1.31";
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";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svamp-cli",
3
- "version": "0.1.30",
3
+ "version": "0.1.31",
4
4
  "description": "Svamp CLI — AI workspace daemon on Hypha Cloud",
5
5
  "author": "Amun AI AB",
6
6
  "license": "SEE LICENSE IN LICENSE",