svamp-cli 0.1.76 → 0.1.79

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.
@@ -144,47 +144,9 @@ async function sessionBroadcast(action, args) {
144
144
  });
145
145
  console.log(`Broadcast sent: ${action}`);
146
146
  }
147
- async function connectToSessionService(sessionId) {
148
- const ENV_FILE = join(SVAMP_HOME, ".env");
149
- if (existsSync(ENV_FILE)) {
150
- const lines = readFileSync(ENV_FILE, "utf-8").split("\n");
151
- for (const line of lines) {
152
- const m = line.match(/^([A-Z_]+)=(.*)/);
153
- if (m && !process.env[m[1]]) process.env[m[1]] = m[2].replace(/^["']|["']$/g, "");
154
- }
155
- }
156
- const serverUrl = process.env.HYPHA_SERVER_URL;
157
- const token = process.env.HYPHA_TOKEN;
158
- if (!serverUrl || !token) {
159
- console.error('No Hypha credentials. Run "svamp login" first.');
160
- process.exit(1);
161
- }
162
- const origLog = console.log;
163
- const origWarn = console.warn;
164
- const origInfo = console.info;
165
- console.log = () => {
166
- };
167
- console.warn = () => {
168
- };
169
- console.info = () => {
170
- };
171
- let server;
172
- try {
173
- const mod = await import('hypha-rpc');
174
- const connectToServer = mod.connectToServer || mod.default?.connectToServer;
175
- server = await connectToServer({ server_url: serverUrl, token, name: "svamp-agent-inbox" });
176
- } catch (err) {
177
- console.log = origLog;
178
- console.warn = origWarn;
179
- console.info = origInfo;
180
- console.error(`Failed to connect to Hypha: ${err.message}`);
181
- process.exit(1);
182
- }
183
- console.log = origLog;
184
- console.warn = origWarn;
185
- console.info = origInfo;
186
- const svc = await server.getService(`svamp-session-${sessionId}`);
187
- return { server, svc };
147
+ async function connectToMachineService() {
148
+ const { connectAndGetMachine } = await import('./commands-B6FEeZeP.mjs');
149
+ return connectAndGetMachine();
188
150
  }
189
151
  async function inboxSend(targetSessionId, opts) {
190
152
  const sessionId = process.env.SVAMP_SESSION_ID;
@@ -197,8 +159,12 @@ async function inboxSend(targetSessionId, opts) {
197
159
  console.error("Message body is required.");
198
160
  process.exit(1);
199
161
  }
200
- const { server, svc } = await connectToSessionService(targetSessionId);
162
+ const { server, machine } = await connectToMachineService();
201
163
  try {
164
+ const { resolveSessionId } = await import('./commands-B6FEeZeP.mjs');
165
+ const sessions = await machine.listSessions();
166
+ const match = resolveSessionId(sessions, targetSessionId);
167
+ const fullTargetId = match.sessionId;
202
168
  const { randomUUID } = await import('node:crypto');
203
169
  const message = {
204
170
  messageId: randomUUID(),
@@ -207,12 +173,12 @@ async function inboxSend(targetSessionId, opts) {
207
173
  read: false,
208
174
  from: `agent:${sessionId}`,
209
175
  fromSession: sessionId,
210
- to: targetSessionId,
176
+ to: fullTargetId,
211
177
  subject: opts?.subject,
212
178
  urgency: opts?.urgency || "normal"
213
179
  };
214
- const result = await svc.sendInboxMessage(message);
215
- console.log(`Inbox message sent to ${targetSessionId.slice(0, 8)} (id: ${result.messageId.slice(0, 8)})`);
180
+ const result = await machine.sessionRPC(fullTargetId, "sendInboxMessage", [message]);
181
+ console.log(`Inbox message sent to ${fullTargetId.slice(0, 8)} (id: ${result.messageId.slice(0, 8)})`);
216
182
  } finally {
217
183
  await server.disconnect();
218
184
  }
@@ -223,9 +189,9 @@ async function inboxList(opts) {
223
189
  console.error("SVAMP_SESSION_ID not set. This command must be run inside a Svamp session.");
224
190
  process.exit(1);
225
191
  }
226
- const { server, svc } = await connectToSessionService(sessionId);
192
+ const { server, machine } = await connectToMachineService();
227
193
  try {
228
- const result = await svc.getInbox({ unread: opts?.unread, limit: opts?.limit });
194
+ const result = await machine.sessionRPC(sessionId, "getInbox", [{ unread: opts?.unread, limit: opts?.limit }]);
229
195
  const messages = result.messages;
230
196
  if (opts?.json) {
231
197
  console.log(JSON.stringify({ messages }, null, 2));
@@ -253,9 +219,9 @@ async function inboxReply(messageId, body) {
253
219
  console.error("SVAMP_SESSION_ID not set. This command must be run inside a Svamp session.");
254
220
  process.exit(1);
255
221
  }
256
- const { server, svc } = await connectToSessionService(sessionId);
222
+ const { server, machine } = await connectToMachineService();
257
223
  try {
258
- const result = await svc.getInbox();
224
+ const result = await machine.sessionRPC(sessionId, "getInbox", []);
259
225
  const original = result.messages.find((m) => m.messageId === messageId || m.messageId.startsWith(messageId));
260
226
  if (!original) {
261
227
  console.error(`Message ${messageId} not found in inbox.`);
@@ -265,7 +231,6 @@ async function inboxReply(messageId, body) {
265
231
  console.error("Cannot reply: original message has no fromSession.");
266
232
  process.exit(1);
267
233
  }
268
- const targetSvc = await server.getService(`svamp-session-${original.fromSession}`);
269
234
  const { randomUUID } = await import('node:crypto');
270
235
  const reply = {
271
236
  messageId: randomUUID(),
@@ -280,7 +245,7 @@ async function inboxReply(messageId, body) {
280
245
  replyTo: original.messageId,
281
246
  threadId: original.threadId || original.messageId
282
247
  };
283
- const sendResult = await targetSvc.sendInboxMessage(reply);
248
+ const sendResult = await machine.sessionRPC(original.fromSession, "sendInboxMessage", [reply]);
284
249
  console.log(`Reply sent to ${original.fromSession.slice(0, 8)} (id: ${sendResult.messageId.slice(0, 8)})`);
285
250
  } finally {
286
251
  await server.disconnect();
package/dist/cli.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { b as stopDaemon, s as startDaemon, d as daemonStatus } from './run-BnFGIK0c.mjs';
1
+ import { b as stopDaemon, s as startDaemon, d as daemonStatus } from './run-DsXDjwLW.mjs';
2
2
  import 'os';
3
3
  import 'fs/promises';
4
4
  import 'fs';
@@ -32,6 +32,8 @@ let daemonSubcommand = args[1];
32
32
  async function main() {
33
33
  if (subcommand === "login") {
34
34
  await loginToHypha();
35
+ } else if (subcommand === "logout") {
36
+ await logoutFromHypha();
35
37
  } else if (subcommand === "daemon") {
36
38
  if (daemonSubcommand === "restart") {
37
39
  await stopDaemon();
@@ -94,6 +96,13 @@ async function main() {
94
96
  } catch {
95
97
  }
96
98
  };
99
+ const supervisorPidFile = pathJoin(svampHome, "supervisor.pid");
100
+ try {
101
+ appendFileSync(supervisorPidFile, "");
102
+ } catch {
103
+ }
104
+ const { writeFileSync: wfs } = await import('fs');
105
+ wfs(supervisorPidFile, String(process.pid), "utf-8");
97
106
  const extraSyncArgs = [];
98
107
  if (args.includes("--no-auto-continue")) extraSyncArgs.push("--no-auto-continue");
99
108
  const BASE_DELAY_MS = 2e3;
@@ -164,6 +173,11 @@ async function main() {
164
173
  setTimeout(() => clearInterval(checkStop), delay + 100);
165
174
  });
166
175
  }
176
+ try {
177
+ const { unlinkSync: us } = await import('fs');
178
+ us(supervisorPidFile);
179
+ } catch {
180
+ }
167
181
  process.exit(0);
168
182
  } else if (daemonSubcommand === "start-sync") {
169
183
  const noAutoContinue = args.includes("--no-auto-continue");
@@ -194,10 +208,10 @@ async function main() {
194
208
  } else if (subcommand === "skills") {
195
209
  await handleSkillsCommand();
196
210
  } else if (subcommand === "service" || subcommand === "svc") {
197
- const { handleServiceCommand } = await import('./commands-CADr1mQg.mjs');
211
+ const { handleServiceCommand } = await import('./commands-BYbuedOK.mjs');
198
212
  await handleServiceCommand();
199
213
  } else if (subcommand === "process" || subcommand === "proc") {
200
- const { processCommand } = await import('./commands-7Iw1nFwf.mjs');
214
+ const { processCommand } = await import('./commands-Cf3mXxPZ.mjs');
201
215
  let machineId;
202
216
  const processArgs = args.slice(1);
203
217
  const mIdx = processArgs.findIndex((a) => a === "--machine" || a === "-m");
@@ -215,7 +229,7 @@ async function main() {
215
229
  } else if (!subcommand || subcommand === "start") {
216
230
  await handleInteractiveCommand();
217
231
  } else if (subcommand === "--version" || subcommand === "-v") {
218
- const pkg = await import('./package-Dpz1MLO4.mjs').catch(() => ({ default: { version: "unknown" } }));
232
+ const pkg = await import('./package-B-yM5uv2.mjs').catch(() => ({ default: { version: "unknown" } }));
219
233
  console.log(`svamp version: ${pkg.default.version}`);
220
234
  } else {
221
235
  console.error(`Unknown command: ${subcommand}`);
@@ -224,7 +238,7 @@ async function main() {
224
238
  }
225
239
  }
226
240
  async function handleInteractiveCommand() {
227
- const { runInteractive } = await import('./run-B29grSMh.mjs');
241
+ const { runInteractive } = await import('./run-DqvxMsWh.mjs');
228
242
  const interactiveArgs = subcommand === "start" ? args.slice(1) : args;
229
243
  let directory = process.cwd();
230
244
  let resumeSessionId;
@@ -269,7 +283,7 @@ async function handleAgentCommand() {
269
283
  return;
270
284
  }
271
285
  if (agentArgs[0] === "list") {
272
- const { KNOWN_ACP_AGENTS, KNOWN_MCP_AGENTS: KNOWN_MCP_AGENTS2 } = await import('./run-BnFGIK0c.mjs').then(function (n) { return n.i; });
286
+ const { KNOWN_ACP_AGENTS, KNOWN_MCP_AGENTS: KNOWN_MCP_AGENTS2 } = await import('./run-DsXDjwLW.mjs').then(function (n) { return n.i; });
273
287
  console.log("Known agents:");
274
288
  for (const [name, config2] of Object.entries(KNOWN_ACP_AGENTS)) {
275
289
  console.log(` ${name.padEnd(12)} ${config2.command} ${config2.args.join(" ")} (ACP)`);
@@ -281,7 +295,7 @@ async function handleAgentCommand() {
281
295
  console.log('Use "svamp agent -- <command> [args]" for a custom ACP agent.');
282
296
  return;
283
297
  }
284
- const { resolveAcpAgentConfig, KNOWN_MCP_AGENTS } = await import('./run-BnFGIK0c.mjs').then(function (n) { return n.i; });
298
+ const { resolveAcpAgentConfig, KNOWN_MCP_AGENTS } = await import('./run-DsXDjwLW.mjs').then(function (n) { return n.i; });
285
299
  let cwd = process.cwd();
286
300
  const filteredArgs = [];
287
301
  for (let i = 0; i < agentArgs.length; i++) {
@@ -305,12 +319,12 @@ async function handleAgentCommand() {
305
319
  console.log(`Starting ${config.agentName} agent in ${cwd}...`);
306
320
  let backend;
307
321
  if (KNOWN_MCP_AGENTS[config.agentName]) {
308
- const { CodexMcpBackend } = await import('./run-BnFGIK0c.mjs').then(function (n) { return n.j; });
322
+ const { CodexMcpBackend } = await import('./run-DsXDjwLW.mjs').then(function (n) { return n.j; });
309
323
  backend = new CodexMcpBackend({ cwd, log: logFn });
310
324
  } else {
311
- const { AcpBackend } = await import('./run-BnFGIK0c.mjs').then(function (n) { return n.h; });
312
- const { GeminiTransport } = await import('./run-BnFGIK0c.mjs').then(function (n) { return n.G; });
313
- const { DefaultTransport } = await import('./run-BnFGIK0c.mjs').then(function (n) { return n.D; });
325
+ const { AcpBackend } = await import('./run-DsXDjwLW.mjs').then(function (n) { return n.h; });
326
+ const { GeminiTransport } = await import('./run-DsXDjwLW.mjs').then(function (n) { return n.G; });
327
+ const { DefaultTransport } = await import('./run-DsXDjwLW.mjs').then(function (n) { return n.D; });
314
328
  const transportHandler = config.agentName === "gemini" ? new GeminiTransport() : new DefaultTransport(config.agentName);
315
329
  backend = new AcpBackend({
316
330
  agentName: config.agentName,
@@ -428,7 +442,7 @@ async function handleSessionCommand() {
428
442
  printSessionHelp();
429
443
  return;
430
444
  }
431
- const { sessionList, sessionSpawn, sessionStop, sessionInfo, sessionMessages, sessionAttach, sessionMachines, sessionSend, sessionWait, sessionShare, sessionRalphStart, sessionRalphCancel, sessionRalphStatus, sessionInboxSend, sessionInboxList, sessionInboxRead, sessionInboxReply, sessionInboxClear } = await import('./commands-lJ8V7MJE.mjs');
445
+ const { sessionList, sessionSpawn, sessionStop, sessionInfo, sessionMessages, sessionAttach, sessionMachines, sessionSend, sessionWait, sessionShare, sessionRalphStart, sessionRalphCancel, sessionRalphStatus, sessionInboxSend, sessionInboxList, sessionInboxRead, sessionInboxReply, sessionInboxClear } = await import('./commands-B6FEeZeP.mjs');
432
446
  const parseFlagStr = (flag, shortFlag) => {
433
447
  for (let i = 1; i < sessionArgs.length; i++) {
434
448
  if ((sessionArgs[i] === flag || shortFlag) && i + 1 < sessionArgs.length) {
@@ -488,7 +502,7 @@ async function handleSessionCommand() {
488
502
  allowDomain.push(sessionArgs[++i]);
489
503
  }
490
504
  }
491
- const { parseShareArg } = await import('./commands-lJ8V7MJE.mjs');
505
+ const { parseShareArg } = await import('./commands-B6FEeZeP.mjs');
492
506
  const shareEntries = share.map((s) => parseShareArg(s));
493
507
  await sessionSpawn(agent, dir, targetMachineId, {
494
508
  message,
@@ -539,13 +553,15 @@ async function handleSessionCommand() {
539
553
  await sessionAttach(sessionArgs[1], targetMachineId);
540
554
  } else if (sessionSubcommand === "send") {
541
555
  if (!sessionArgs[1] || !sessionArgs[2]) {
542
- console.error("Usage: svamp session send <session-id> <message> [--wait] [--timeout N] [--json]");
556
+ console.error('Usage: svamp session send <session-id> <message> [--subject "..."] [--urgency urgent|normal] [--wait] [--timeout N] [--json]');
543
557
  process.exit(1);
544
558
  }
545
559
  await sessionSend(sessionArgs[1], sessionArgs[2], targetMachineId, {
546
560
  wait: hasFlag("--wait"),
547
561
  timeout: parseFlagInt("--timeout"),
548
- json: hasFlag("--json")
562
+ json: hasFlag("--json"),
563
+ subject: parseFlagStr("--subject"),
564
+ urgency: parseFlagStr("--urgency")
549
565
  });
550
566
  } else if (sessionSubcommand === "wait") {
551
567
  if (!sessionArgs[1]) {
@@ -572,7 +588,7 @@ async function handleSessionCommand() {
572
588
  console.error("Usage: svamp session approve <session-id> [request-id] [--json]");
573
589
  process.exit(1);
574
590
  }
575
- const { sessionApprove } = await import('./commands-lJ8V7MJE.mjs');
591
+ const { sessionApprove } = await import('./commands-B6FEeZeP.mjs');
576
592
  const approveReqId = sessionArgs[2] && !sessionArgs[2].startsWith("--") ? sessionArgs[2] : void 0;
577
593
  await sessionApprove(sessionArgs[1], approveReqId, targetMachineId, {
578
594
  json: hasFlag("--json")
@@ -582,7 +598,7 @@ async function handleSessionCommand() {
582
598
  console.error("Usage: svamp session deny <session-id> [request-id] [--json]");
583
599
  process.exit(1);
584
600
  }
585
- const { sessionDeny } = await import('./commands-lJ8V7MJE.mjs');
601
+ const { sessionDeny } = await import('./commands-B6FEeZeP.mjs');
586
602
  const denyReqId = sessionArgs[2] && !sessionArgs[2].startsWith("--") ? sessionArgs[2] : void 0;
587
603
  await sessionDeny(sessionArgs[1], denyReqId, targetMachineId, {
588
604
  json: hasFlag("--json")
@@ -618,7 +634,7 @@ async function handleSessionCommand() {
618
634
  console.error("Usage: svamp session set-title <title>");
619
635
  process.exit(1);
620
636
  }
621
- const { sessionSetTitle } = await import('./agentCommands-NVZzP_Vo.mjs');
637
+ const { sessionSetTitle } = await import('./agentCommands-uNFhhdN1.mjs');
622
638
  await sessionSetTitle(title);
623
639
  } else if (sessionSubcommand === "set-link") {
624
640
  const url = sessionArgs[1];
@@ -627,7 +643,7 @@ async function handleSessionCommand() {
627
643
  process.exit(1);
628
644
  }
629
645
  const label = sessionArgs[2] && !sessionArgs[2].startsWith("--") ? sessionArgs[2] : void 0;
630
- const { sessionSetLink } = await import('./agentCommands-NVZzP_Vo.mjs');
646
+ const { sessionSetLink } = await import('./agentCommands-uNFhhdN1.mjs');
631
647
  await sessionSetLink(url, label);
632
648
  } else if (sessionSubcommand === "notify") {
633
649
  const message = sessionArgs[1];
@@ -636,7 +652,7 @@ async function handleSessionCommand() {
636
652
  process.exit(1);
637
653
  }
638
654
  const level = parseFlagStr("--level") || "info";
639
- const { sessionNotify } = await import('./agentCommands-NVZzP_Vo.mjs');
655
+ const { sessionNotify } = await import('./agentCommands-uNFhhdN1.mjs');
640
656
  await sessionNotify(message, level);
641
657
  } else if (sessionSubcommand === "broadcast") {
642
658
  const action = sessionArgs[1];
@@ -644,7 +660,7 @@ async function handleSessionCommand() {
644
660
  console.error("Usage: svamp session broadcast <action> [args...]\nActions: open-canvas <url> [label], close-canvas, toast <message>");
645
661
  process.exit(1);
646
662
  }
647
- const { sessionBroadcast } = await import('./agentCommands-NVZzP_Vo.mjs');
663
+ const { sessionBroadcast } = await import('./agentCommands-uNFhhdN1.mjs');
648
664
  await sessionBroadcast(action, sessionArgs.slice(2).filter((a) => !a.startsWith("--")));
649
665
  } else if (sessionSubcommand === "inbox") {
650
666
  const inboxSubcmd = sessionArgs[1];
@@ -655,7 +671,7 @@ async function handleSessionCommand() {
655
671
  process.exit(1);
656
672
  }
657
673
  if (agentSessionId) {
658
- const { inboxSend } = await import('./agentCommands-NVZzP_Vo.mjs');
674
+ const { inboxSend } = await import('./agentCommands-uNFhhdN1.mjs');
659
675
  await inboxSend(sessionArgs[2], {
660
676
  body: sessionArgs[3],
661
677
  subject: parseFlagStr("--subject"),
@@ -670,7 +686,7 @@ async function handleSessionCommand() {
670
686
  }
671
687
  } else if (inboxSubcmd === "list" || inboxSubcmd === "ls") {
672
688
  if (agentSessionId && !sessionArgs[2]) {
673
- const { inboxList } = await import('./agentCommands-NVZzP_Vo.mjs');
689
+ const { inboxList } = await import('./agentCommands-uNFhhdN1.mjs');
674
690
  await inboxList({
675
691
  unread: hasFlag("--unread"),
676
692
  limit: parseFlagInt("--limit"),
@@ -692,7 +708,7 @@ async function handleSessionCommand() {
692
708
  process.exit(1);
693
709
  }
694
710
  if (agentSessionId && !sessionArgs[3]) {
695
- const { inboxList } = await import('./agentCommands-NVZzP_Vo.mjs');
711
+ const { inboxList } = await import('./agentCommands-uNFhhdN1.mjs');
696
712
  await sessionInboxRead(agentSessionId, sessionArgs[2], targetMachineId);
697
713
  } else if (sessionArgs[3]) {
698
714
  await sessionInboxRead(sessionArgs[2], sessionArgs[3], targetMachineId);
@@ -702,7 +718,7 @@ async function handleSessionCommand() {
702
718
  }
703
719
  } else if (inboxSubcmd === "reply") {
704
720
  if (agentSessionId && sessionArgs[2] && sessionArgs[3] && !sessionArgs[4]) {
705
- const { inboxReply } = await import('./agentCommands-NVZzP_Vo.mjs');
721
+ const { inboxReply } = await import('./agentCommands-uNFhhdN1.mjs');
706
722
  await inboxReply(sessionArgs[2], sessionArgs[3]);
707
723
  } else if (sessionArgs[2] && sessionArgs[3] && sessionArgs[4]) {
708
724
  await sessionInboxReply(sessionArgs[2], sessionArgs[3], sessionArgs[4], targetMachineId);
@@ -738,7 +754,7 @@ async function handleMachineCommand() {
738
754
  return;
739
755
  }
740
756
  if (machineSubcommand === "share") {
741
- const { machineShare } = await import('./commands-lJ8V7MJE.mjs');
757
+ const { machineShare } = await import('./commands-B6FEeZeP.mjs');
742
758
  let machineId;
743
759
  const shareArgs = [];
744
760
  for (let i = 1; i < machineArgs.length; i++) {
@@ -768,7 +784,7 @@ async function handleMachineCommand() {
768
784
  }
769
785
  await machineShare(machineId, { add, remove, list, configPath, showConfig });
770
786
  } else if (machineSubcommand === "exec") {
771
- const { machineExec } = await import('./commands-lJ8V7MJE.mjs');
787
+ const { machineExec } = await import('./commands-B6FEeZeP.mjs');
772
788
  let machineId;
773
789
  let cwd;
774
790
  const cmdParts = [];
@@ -788,7 +804,7 @@ async function handleMachineCommand() {
788
804
  }
789
805
  await machineExec(machineId, command, cwd);
790
806
  } else if (machineSubcommand === "info") {
791
- const { machineInfo } = await import('./commands-lJ8V7MJE.mjs');
807
+ const { machineInfo } = await import('./commands-B6FEeZeP.mjs');
792
808
  let machineId;
793
809
  for (let i = 1; i < machineArgs.length; i++) {
794
810
  if ((machineArgs[i] === "--machine" || machineArgs[i] === "-m") && i + 1 < machineArgs.length) {
@@ -808,10 +824,10 @@ async function handleMachineCommand() {
808
824
  level = machineArgs[++i];
809
825
  }
810
826
  }
811
- const { machineNotify } = await import('./agentCommands-NVZzP_Vo.mjs');
827
+ const { machineNotify } = await import('./agentCommands-uNFhhdN1.mjs');
812
828
  await machineNotify(message, level);
813
829
  } else if (machineSubcommand === "ls") {
814
- const { machineLs } = await import('./commands-lJ8V7MJE.mjs');
830
+ const { machineLs } = await import('./commands-B6FEeZeP.mjs');
815
831
  let machineId;
816
832
  let showHidden = false;
817
833
  let path;
@@ -965,6 +981,41 @@ You can now start the daemon: svamp daemon start`);
965
981
  process.exit(1);
966
982
  }
967
983
  }
984
+ async function logoutFromHypha() {
985
+ const os = await import('os');
986
+ const { join } = await import('path');
987
+ const fs = await import('fs');
988
+ const homeDir = process.env.SVAMP_HOME || join(os.homedir(), ".svamp");
989
+ const envFile = join(homeDir, ".env");
990
+ console.log("Stopping daemon...");
991
+ try {
992
+ await stopDaemon();
993
+ } catch {
994
+ }
995
+ if (fs.existsSync(envFile)) {
996
+ const existing = fs.readFileSync(envFile, "utf-8").split("\n");
997
+ const kept = [];
998
+ for (const line of existing) {
999
+ const trimmed = line.trim();
1000
+ if (trimmed.startsWith("HYPHA_TOKEN=") || trimmed.startsWith("HYPHA_WORKSPACE=") || trimmed.startsWith("HYPHA_SERVER_URL=")) {
1001
+ continue;
1002
+ }
1003
+ kept.push(line);
1004
+ }
1005
+ while (kept.length > 0 && kept[kept.length - 1].trim() === "") {
1006
+ kept.pop();
1007
+ }
1008
+ if (kept.length > 0) {
1009
+ fs.writeFileSync(envFile, kept.join("\n") + "\n", "utf-8");
1010
+ } else {
1011
+ fs.unlinkSync(envFile);
1012
+ }
1013
+ console.log("Credentials removed");
1014
+ } else {
1015
+ console.log("No credentials found");
1016
+ }
1017
+ console.log("Logged out successfully");
1018
+ }
968
1019
  const LAUNCHD_LABEL = "io.hypha.svamp.daemon";
969
1020
  async function installDaemonService() {
970
1021
  const os = await import('os');
@@ -1159,6 +1210,7 @@ Quick start \u2014 spawn an agent to do a task (use -p bypassPermissions to run
1159
1210
  Commands:
1160
1211
  svamp Start interactive Claude session (synced to cloud)
1161
1212
  svamp login [url] Login to Hypha (opens browser, stores token)
1213
+ svamp logout Logout (stop daemon, remove credentials)
1162
1214
  svamp daemon start Start the background daemon (required for sessions)
1163
1215
  svamp daemon status Show daemon status
1164
1216
  svamp daemon --help Show all daemon commands
@@ -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 { l as loadSecurityContextConfig, e as resolveSecurityContext, f as buildSecurityContextFromFlags, m as mergeSecurityContexts, c as connectToHypha } from './run-BnFGIK0c.mjs';
5
+ import { l as loadSecurityContextConfig, e as resolveSecurityContext, f as buildSecurityContextFromFlags, m as mergeSecurityContexts, c as connectToHypha } from './run-DsXDjwLW.mjs';
6
6
  import 'os';
7
7
  import 'fs/promises';
8
8
  import 'fs';
@@ -613,12 +613,11 @@ function extractMessageText(msg) {
613
613
  createdAt: msg.createdAt || 0
614
614
  };
615
615
  }
616
- async function waitForIdle(server, sessionId, timeoutMs) {
617
- const svc = await server.getService(`svamp-session-${sessionId}`);
616
+ async function waitForIdle(machine, sessionId, timeoutMs) {
618
617
  const pollInterval = 2e3;
619
618
  const deadline = Date.now() + timeoutMs;
620
619
  while (Date.now() < deadline) {
621
- const activity = await svc.getActivityState();
620
+ const activity = await machine.sessionRPC(sessionId, "getActivityState", []);
622
621
  if (activity?.pendingPermissions?.length > 0) {
623
622
  return { idle: false, pendingPermissions: activity.pendingPermissions };
624
623
  }
@@ -629,14 +628,13 @@ async function waitForIdle(server, sessionId, timeoutMs) {
629
628
  }
630
629
  throw new Error("Timeout waiting for agent to become idle");
631
630
  }
632
- async function waitForBusyThenIdle(server, sessionId, timeoutMs = 3e5, busyTimeoutMs = 1e4) {
633
- const svc = await server.getService(`svamp-session-${sessionId}`);
631
+ async function waitForBusyThenIdle(machine, sessionId, timeoutMs = 3e5, busyTimeoutMs = 1e4) {
634
632
  const pollInterval = 2e3;
635
633
  const deadline = Date.now() + timeoutMs;
636
634
  const busyDeadline = Date.now() + busyTimeoutMs;
637
635
  let sawBusy = false;
638
636
  while (Date.now() < deadline) {
639
- const activity = await svc.getActivityState();
637
+ const activity = await machine.sessionRPC(sessionId, "getActivityState", []);
640
638
  if (activity?.pendingPermissions?.length > 0) {
641
639
  return { idle: false, pendingPermissions: activity.pendingPermissions };
642
640
  }
@@ -934,7 +932,7 @@ async function sessionSpawn(agent, directory, machineId, opts) {
934
932
  console.log(`Message sent (seq: ${sendResult.seq})`);
935
933
  if (opts.wait) {
936
934
  console.log("Waiting for agent to become idle...");
937
- await waitForBusyThenIdle(server, result.sessionId);
935
+ await waitForBusyThenIdle(machine, result.sessionId);
938
936
  console.log("Agent is idle.");
939
937
  }
940
938
  }
@@ -1268,18 +1266,22 @@ async function sessionSend(sessionId, message, machineId, opts) {
1268
1266
  const sessions = await machine.listSessions();
1269
1267
  const match = resolveSessionId(sessions, sessionId);
1270
1268
  const fullId = match.sessionId;
1271
- const svc = await server.getService(`svamp-session-${fullId}`);
1272
- const result = await svc.sendMessage(
1273
- JSON.stringify({
1274
- role: "user",
1275
- content: { type: "text", text: message },
1276
- meta: { sentFrom: "svamp-cli" }
1277
- })
1278
- );
1269
+ const { randomUUID } = await import('node:crypto');
1270
+ const inboxMessage = {
1271
+ messageId: randomUUID(),
1272
+ body: message,
1273
+ timestamp: Date.now(),
1274
+ read: false,
1275
+ from: `cli:${os.userInfo().username}`,
1276
+ to: fullId,
1277
+ subject: opts?.subject,
1278
+ urgency: opts?.urgency || "urgent"
1279
+ };
1280
+ const result = await machine.sessionRPC(fullId, "sendInboxMessage", [inboxMessage]);
1279
1281
  let waitResult;
1280
1282
  if (opts?.wait) {
1281
1283
  const timeoutMs = (opts.timeout || 300) * 1e3;
1282
- waitResult = await waitForBusyThenIdle(server, fullId, timeoutMs);
1284
+ waitResult = await waitForBusyThenIdle(machine, fullId, timeoutMs);
1283
1285
  }
1284
1286
  if (waitResult?.pendingPermissions?.length) {
1285
1287
  if (opts?.json) {
@@ -1287,12 +1289,12 @@ async function sessionSend(sessionId, message, machineId, opts) {
1287
1289
  sessionId: fullId,
1288
1290
  message,
1289
1291
  sent: true,
1290
- seq: result.seq,
1292
+ messageId: result.messageId,
1291
1293
  status: "permission-pending",
1292
1294
  pendingPermissions: waitResult.pendingPermissions
1293
1295
  }));
1294
1296
  } else {
1295
- console.log(`Message sent to session ${fullId.slice(0, 8)} (seq: ${result.seq})`);
1297
+ console.log(`Message sent to session ${fullId.slice(0, 8)} (id: ${result.messageId.slice(0, 8)})`);
1296
1298
  console.log("Agent is waiting for permission approval:");
1297
1299
  for (const p of waitResult.pendingPermissions) {
1298
1300
  const argsStr = JSON.stringify(p.arguments || {}).slice(0, 120);
@@ -1307,12 +1309,12 @@ Use: svamp session approve ${fullId.slice(0, 8)}`);
1307
1309
  sessionId: fullId,
1308
1310
  message,
1309
1311
  sent: true,
1310
- seq: result.seq,
1312
+ messageId: result.messageId,
1311
1313
  waited: !!opts.wait,
1312
1314
  status: opts.wait ? "idle" : "sent"
1313
1315
  }));
1314
1316
  } else {
1315
- console.log(`Message sent to session ${fullId.slice(0, 8)} (seq: ${result.seq})`);
1317
+ console.log(`Message sent to session ${fullId.slice(0, 8)} (id: ${result.messageId.slice(0, 8)})`);
1316
1318
  if (opts?.wait) {
1317
1319
  console.log("Agent is idle.");
1318
1320
  }
@@ -1328,7 +1330,7 @@ async function sessionWait(sessionId, machineId, opts) {
1328
1330
  const match = resolveSessionId(sessions, sessionId);
1329
1331
  const fullId = match.sessionId;
1330
1332
  const timeoutMs = (opts?.timeout || 300) * 1e3;
1331
- const result = await waitForIdle(server, fullId, timeoutMs);
1333
+ const result = await waitForIdle(machine, fullId, timeoutMs);
1332
1334
  if (result.pendingPermissions?.length) {
1333
1335
  if (opts?.json) {
1334
1336
  console.log(formatJson({
@@ -1712,7 +1714,6 @@ async function sessionInboxSend(sessionIdPartial, body, machineId, opts) {
1712
1714
  const sessions = await machine.listSessions();
1713
1715
  const match = resolveSessionId(sessions, sessionIdPartial);
1714
1716
  const fullId = match.sessionId;
1715
- const svc = await server.getService(`svamp-session-${fullId}`);
1716
1717
  const { randomUUID } = await import('node:crypto');
1717
1718
  const message = {
1718
1719
  messageId: randomUUID(),
@@ -1726,7 +1727,7 @@ async function sessionInboxSend(sessionIdPartial, body, machineId, opts) {
1726
1727
  replyTo: opts?.replyTo,
1727
1728
  threadId: opts?.threadId
1728
1729
  };
1729
- const result = await svc.sendInboxMessage(message);
1730
+ const result = await machine.sessionRPC(fullId, "sendInboxMessage", [message]);
1730
1731
  if (opts?.json) {
1731
1732
  console.log(formatJson({ sessionId: fullId, messageId: result.messageId, sent: true }));
1732
1733
  } else {
@@ -1742,8 +1743,7 @@ async function sessionInboxList(sessionIdPartial, machineId, opts) {
1742
1743
  const sessions = await machine.listSessions();
1743
1744
  const match = resolveSessionId(sessions, sessionIdPartial);
1744
1745
  const fullId = match.sessionId;
1745
- const svc = await server.getService(`svamp-session-${fullId}`);
1746
- const result = await svc.getInbox({ unread: opts?.unread, limit: opts?.limit });
1746
+ const result = await machine.sessionRPC(fullId, "getInbox", [{ unread: opts?.unread, limit: opts?.limit }]);
1747
1747
  const messages = result.messages;
1748
1748
  if (opts?.json) {
1749
1749
  console.log(formatJson({ sessionId: fullId, messages }));
@@ -1778,15 +1778,14 @@ async function sessionInboxRead(sessionIdPartial, messageId, machineId) {
1778
1778
  const sessions = await machine.listSessions();
1779
1779
  const match = resolveSessionId(sessions, sessionIdPartial);
1780
1780
  const fullId = match.sessionId;
1781
- const svc = await server.getService(`svamp-session-${fullId}`);
1782
- const result = await svc.getInbox();
1781
+ const result = await machine.sessionRPC(fullId, "getInbox", []);
1783
1782
  const msg = result.messages.find((m) => m.messageId === messageId || m.messageId.startsWith(messageId));
1784
1783
  if (!msg) {
1785
1784
  console.error(`Message ${messageId} not found in inbox.`);
1786
1785
  process.exit(1);
1787
1786
  }
1788
1787
  if (!msg.read) {
1789
- await svc.markInboxRead(msg.messageId);
1788
+ await machine.sessionRPC(fullId, "markInboxRead", [msg.messageId]);
1790
1789
  }
1791
1790
  console.log(`From: ${msg.from || "(unknown)"}`);
1792
1791
  if (msg.subject) console.log(`Subject: ${msg.subject}`);
@@ -1806,8 +1805,7 @@ async function sessionInboxReply(sessionIdPartial, messageId, body, machineId) {
1806
1805
  const sessions = await machine.listSessions();
1807
1806
  const match = resolveSessionId(sessions, sessionIdPartial);
1808
1807
  const fullId = match.sessionId;
1809
- const svc = await server.getService(`svamp-session-${fullId}`);
1810
- const result = await svc.getInbox();
1808
+ const result = await machine.sessionRPC(fullId, "getInbox", []);
1811
1809
  const original = result.messages.find((m) => m.messageId === messageId || m.messageId.startsWith(messageId));
1812
1810
  if (!original) {
1813
1811
  console.error(`Message ${messageId} not found in inbox.`);
@@ -1817,7 +1815,6 @@ async function sessionInboxReply(sessionIdPartial, messageId, body, machineId) {
1817
1815
  console.error("Cannot reply: original message has no fromSession.");
1818
1816
  process.exit(1);
1819
1817
  }
1820
- const targetSvc = await server.getService(`svamp-session-${original.fromSession}`);
1821
1818
  const { randomUUID } = await import('node:crypto');
1822
1819
  const reply = {
1823
1820
  messageId: randomUUID(),
@@ -1832,7 +1829,7 @@ async function sessionInboxReply(sessionIdPartial, messageId, body, machineId) {
1832
1829
  replyTo: original.messageId,
1833
1830
  threadId: original.threadId || original.messageId
1834
1831
  };
1835
- const sendResult = await targetSvc.sendInboxMessage(reply);
1832
+ const sendResult = await machine.sessionRPC(original.fromSession, "sendInboxMessage", [reply]);
1836
1833
  console.log(`Reply sent to session ${original.fromSession.slice(0, 8)} (id: ${sendResult.messageId.slice(0, 8)})`);
1837
1834
  } finally {
1838
1835
  await server.disconnect();
@@ -1844,9 +1841,8 @@ async function sessionInboxClear(sessionIdPartial, machineId, opts) {
1844
1841
  const sessions = await machine.listSessions();
1845
1842
  const match = resolveSessionId(sessions, sessionIdPartial);
1846
1843
  const fullId = match.sessionId;
1847
- const svc = await server.getService(`svamp-session-${fullId}`);
1848
- const result = await svc.clearInbox({ all: opts?.all });
1849
- console.log(`Cleared ${result.removed} message(s) from inbox on session ${fullId.slice(0, 8)}`);
1844
+ const result = await machine.sessionRPC(fullId, "clearInbox", [{ all: opts?.all }]);
1845
+ console.log(`Cleared inbox on session ${fullId.slice(0, 8)} (${result.remaining} remaining)`);
1850
1846
  } finally {
1851
1847
  await server.disconnect();
1852
1848
  }