svamp-cli 0.1.30 → 0.1.32

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
@@ -1,4 +1,4 @@
1
- import { s as startDaemon, b as stopDaemon, d as daemonStatus } from './run-dBWhjQRf.mjs';
1
+ import { s as startDaemon, b as stopDaemon, d as daemonStatus } from './run-fEuWMTdD.mjs';
2
2
  import 'os';
3
3
  import 'fs/promises';
4
4
  import 'fs';
@@ -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-CMmjP_vD.mjs').catch(() => ({ default: { version: "unknown" } }));
93
93
  console.log(`svamp version: ${pkg.default.version}`);
94
94
  } else {
95
95
  console.error(`Unknown command: ${subcommand}`);
@@ -104,19 +104,19 @@ async function handleAgentCommand() {
104
104
  return;
105
105
  }
106
106
  if (agentArgs[0] === "list") {
107
- const { KNOWN_ACP_AGENTS } = await import('./run-dBWhjQRf.mjs').then(function (n) { return n.f; });
108
- console.log("Known ACP agents:");
107
+ const { KNOWN_ACP_AGENTS, KNOWN_MCP_AGENTS: KNOWN_MCP_AGENTS2 } = await import('./run-fEuWMTdD.mjs').then(function (n) { return n.f; });
108
+ console.log("Known agents:");
109
109
  for (const [name, config2] of Object.entries(KNOWN_ACP_AGENTS)) {
110
- console.log(` ${name.padEnd(12)} ${config2.command} ${config2.args.join(" ")}`);
110
+ console.log(` ${name.padEnd(12)} ${config2.command} ${config2.args.join(" ")} (ACP)`);
111
+ }
112
+ for (const [name, config2] of Object.entries(KNOWN_MCP_AGENTS2)) {
113
+ console.log(` ${name.padEnd(12)} ${config2.command} ${config2.args.join(" ")} (MCP)`);
111
114
  }
112
115
  console.log('\nUse "svamp agent <name>" to start an interactive session.');
113
116
  console.log('Use "svamp agent -- <command> [args]" for a custom ACP agent.');
114
117
  return;
115
118
  }
116
- const { resolveAcpAgentConfig } = await import('./run-dBWhjQRf.mjs').then(function (n) { return n.f; });
117
- const { AcpBackend } = await import('./run-dBWhjQRf.mjs').then(function (n) { return n.e; });
118
- const { GeminiTransport } = await import('./run-dBWhjQRf.mjs').then(function (n) { return n.G; });
119
- const { DefaultTransport } = await import('./run-dBWhjQRf.mjs').then(function (n) { return n.D; });
119
+ const { resolveAcpAgentConfig, KNOWN_MCP_AGENTS } = await import('./run-fEuWMTdD.mjs').then(function (n) { return n.f; });
120
120
  let cwd = process.cwd();
121
121
  const filteredArgs = [];
122
122
  for (let i = 0; i < agentArgs.length; i++) {
@@ -134,20 +134,28 @@ async function handleAgentCommand() {
134
134
  console.error(err.message);
135
135
  process.exit(1);
136
136
  }
137
+ const logFn = (...logArgs) => {
138
+ if (process.env.DEBUG) console.error("[debug]", ...logArgs);
139
+ };
137
140
  console.log(`Starting ${config.agentName} agent in ${cwd}...`);
138
- const transportHandler = config.agentName === "gemini" ? new GeminiTransport() : new DefaultTransport(config.agentName);
139
- const backend = new AcpBackend({
140
- agentName: config.agentName,
141
- cwd,
142
- command: config.command,
143
- args: config.args,
144
- transportHandler,
145
- log: (...logArgs) => {
146
- if (process.env.DEBUG) {
147
- console.error("[debug]", ...logArgs);
148
- }
149
- }
150
- });
141
+ let backend;
142
+ if (KNOWN_MCP_AGENTS[config.agentName]) {
143
+ const { CodexMcpBackend } = await import('./run-fEuWMTdD.mjs').then(function (n) { return n.h; });
144
+ backend = new CodexMcpBackend({ cwd, log: logFn });
145
+ } else {
146
+ const { AcpBackend } = await import('./run-fEuWMTdD.mjs').then(function (n) { return n.e; });
147
+ const { GeminiTransport } = await import('./run-fEuWMTdD.mjs').then(function (n) { return n.G; });
148
+ const { DefaultTransport } = await import('./run-fEuWMTdD.mjs').then(function (n) { return n.D; });
149
+ const transportHandler = config.agentName === "gemini" ? new GeminiTransport() : new DefaultTransport(config.agentName);
150
+ backend = new AcpBackend({
151
+ agentName: config.agentName,
152
+ cwd,
153
+ command: config.command,
154
+ args: config.args,
155
+ transportHandler,
156
+ log: logFn
157
+ });
158
+ }
151
159
  let currentText = "";
152
160
  backend.onMessage((msg) => {
153
161
  switch (msg.type) {
@@ -255,7 +263,7 @@ async function handleSessionCommand() {
255
263
  printSessionHelp();
256
264
  return;
257
265
  }
258
- const { sessionList, sessionSpawn, sessionStop, sessionInfo, sessionMessages, sessionAttach, sessionMachines, sessionSend, sessionWait } = await import('./commands-C5pW2VmI.mjs');
266
+ const { sessionList, sessionSpawn, sessionStop, sessionInfo, sessionMessages, sessionAttach, sessionMachines, sessionSend, sessionWait } = await import('./commands-EjpBlIl0.mjs');
259
267
  const parseFlagStr = (flag, shortFlag) => {
260
268
  for (let i = 1; i < sessionArgs.length; i++) {
261
269
  if ((sessionArgs[i] === flag || shortFlag) && i + 1 < sessionArgs.length) {
@@ -660,8 +668,8 @@ Usage:
660
668
  svamp session spawn Spawn a new session on the daemon
661
669
  svamp session attach <id> Attach to a session (interactive)
662
670
  svamp session --help Show all session commands
663
- svamp agent list List known ACP agents
664
- svamp agent <name> Start local ACP agent session
671
+ svamp agent list List known agents
672
+ svamp agent <name> Start local agent session (gemini, codex)
665
673
  svamp agent -- <cmd> Start custom ACP agent
666
674
  svamp --version Show version
667
675
  svamp --help Show this help
@@ -689,7 +697,7 @@ Usage:
689
697
  }
690
698
  function printSessionHelp() {
691
699
  console.log(`
692
- svamp session \u2014 Manage daemon sessions (Claude, Gemini, OpenCode)
700
+ svamp session \u2014 Manage daemon sessions (Claude, Gemini, Codex)
693
701
 
694
702
  Usage:
695
703
  svamp session list [--active] [--json] List sessions (alias: ls)
@@ -708,7 +716,7 @@ Usage:
708
716
  Options:
709
717
  --machine <id>, -m <id> Target a specific machine (prefix match supported)
710
718
 
711
- Agents: claude (default), gemini, opencode
719
+ Agents: claude (default), gemini, codex
712
720
 
713
721
  Session and machine IDs can be abbreviated (prefix match, like Docker).
714
722
 
@@ -730,20 +738,20 @@ Examples:
730
738
  }
731
739
  function printAgentHelp() {
732
740
  console.log(`
733
- svamp agent \u2014 Interactive ACP agent sessions
741
+ svamp agent \u2014 Interactive agent sessions (local, no daemon required)
734
742
 
735
743
  Usage:
736
- svamp agent list List known ACP agents
744
+ svamp agent list List known agents
737
745
  svamp agent <name> [-d <path>] Start interactive agent session
738
746
  svamp agent -- <cmd> [args] Start custom ACP agent
739
747
 
740
748
  Examples:
741
749
  svamp agent gemini Start Gemini agent in current directory
742
750
  svamp agent gemini -d /tmp/proj Start Gemini agent in /tmp/proj
743
- svamp agent opencode Start OpenCode agent
751
+ svamp agent codex Start Codex agent
744
752
  svamp agent -- mycli --acp Start custom ACP-compatible agent
745
753
 
746
- Known agents: gemini, opencode
754
+ Known agents: gemini (ACP), codex (MCP)
747
755
  `);
748
756
  }
749
757
  main().catch((err) => {
@@ -1,7 +1,7 @@
1
1
  import { existsSync, readFileSync } from 'node:fs';
2
2
  import { join } from 'node:path';
3
3
  import os from 'node:os';
4
- import { c as connectToHypha } from './run-CtCTd6if.mjs';
4
+ import { c as connectToHypha } from './run-fEuWMTdD.mjs';
5
5
  import 'os';
6
6
  import 'fs/promises';
7
7
  import 'fs';
@@ -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) {
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-dBWhjQRf.mjs';
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-fEuWMTdD.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.1.29";
2
+ var version = "0.1.32";
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";
@@ -2172,8 +2172,7 @@ var acpBackend = /*#__PURE__*/Object.freeze({
2172
2172
  });
2173
2173
 
2174
2174
  const KNOWN_ACP_AGENTS = {
2175
- gemini: { command: "gemini", args: ["--experimental-acp"] },
2176
- opencode: { command: "opencode", args: ["acp"] }
2175
+ gemini: { command: "gemini", args: ["--experimental-acp"] }
2177
2176
  };
2178
2177
  const KNOWN_MCP_AGENTS = {
2179
2178
  codex: { command: "codex", args: ["mcp-server"] }
@@ -2196,7 +2195,7 @@ function resolveAcpAgentConfig(cliArgs) {
2196
2195
  const agentName = cliArgs[0];
2197
2196
  const knownAcp = KNOWN_ACP_AGENTS[agentName];
2198
2197
  if (knownAcp) {
2199
- const passthroughArgs = cliArgs.slice(1).filter((arg) => !(agentName === "opencode" && arg === "--acp"));
2198
+ const passthroughArgs = cliArgs.slice(1).filter(Boolean);
2200
2199
  return {
2201
2200
  agentName,
2202
2201
  command: knownAcp.command,
@@ -2818,6 +2817,11 @@ class CodexMcpBackend {
2818
2817
  }
2819
2818
  }
2820
2819
 
2820
+ var codexMcpBackend = /*#__PURE__*/Object.freeze({
2821
+ __proto__: null,
2822
+ CodexMcpBackend: CodexMcpBackend
2823
+ });
2824
+
2821
2825
  const GEMINI_TIMEOUTS = {
2822
2826
  init: 12e4,
2823
2827
  toolCall: 12e4,
@@ -4974,4 +4978,4 @@ function daemonStatus() {
4974
4978
  }
4975
4979
  }
4976
4980
 
4977
- export { DefaultTransport$1 as D, GeminiTransport$1 as G, registerSessionService as a, stopDaemon as b, connectToHypha as c, daemonStatus as d, acpBackend as e, acpAgentConfig as f, getHyphaServerUrl as g, registerMachineService as r, startDaemon as s };
4981
+ export { DefaultTransport$1 as D, GeminiTransport$1 as G, registerSessionService as a, stopDaemon as b, connectToHypha as c, daemonStatus as d, acpBackend as e, acpAgentConfig as f, getHyphaServerUrl as g, codexMcpBackend as h, registerMachineService as r, startDaemon as s };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svamp-cli",
3
- "version": "0.1.30",
3
+ "version": "0.1.32",
4
4
  "description": "Svamp CLI — AI workspace daemon on Hypha Cloud",
5
5
  "author": "Amun AI AB",
6
6
  "license": "SEE LICENSE IN LICENSE",