svamp-cli 0.1.80 → 0.1.82

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.
@@ -145,7 +145,7 @@ async function sessionBroadcast(action, args) {
145
145
  console.log(`Broadcast sent: ${action}`);
146
146
  }
147
147
  async function connectToMachineService() {
148
- const { connectAndGetMachine } = await import('./commands-C06J5fW3.mjs');
148
+ const { connectAndGetMachine } = await import('./commands-BkDj4wWg.mjs');
149
149
  return connectAndGetMachine();
150
150
  }
151
151
  async function inboxSend(targetSessionId, opts) {
@@ -161,7 +161,7 @@ async function inboxSend(targetSessionId, opts) {
161
161
  }
162
162
  const { server, machine } = await connectToMachineService();
163
163
  try {
164
- const { resolveSessionId } = await import('./commands-C06J5fW3.mjs');
164
+ const { resolveSessionId } = await import('./commands-BkDj4wWg.mjs');
165
165
  const sessions = await machine.listSessions();
166
166
  const match = resolveSessionId(sessions, targetSessionId);
167
167
  const fullTargetId = match.sessionId;
package/dist/cli.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { b as stopDaemon, s as startDaemon, d as daemonStatus } from './run-Dm7UViwQ.mjs';
1
+ import { b as stopDaemon, s as startDaemon, d as daemonStatus } from './run-RO50yndI.mjs';
2
2
  import 'os';
3
3
  import 'fs/promises';
4
4
  import 'fs';
@@ -211,7 +211,7 @@ async function main() {
211
211
  const { handleServiceCommand } = await import('./commands-BYbuedOK.mjs');
212
212
  await handleServiceCommand();
213
213
  } else if (subcommand === "process" || subcommand === "proc") {
214
- const { processCommand } = await import('./commands-CphOj2pR.mjs');
214
+ const { processCommand } = await import('./commands-D6pOaahW.mjs');
215
215
  let machineId;
216
216
  const processArgs = args.slice(1);
217
217
  const mIdx = processArgs.findIndex((a) => a === "--machine" || a === "-m");
@@ -229,7 +229,7 @@ async function main() {
229
229
  } else if (!subcommand || subcommand === "start") {
230
230
  await handleInteractiveCommand();
231
231
  } else if (subcommand === "--version" || subcommand === "-v") {
232
- const pkg = await import('./package-CSxyijZF.mjs').catch(() => ({ default: { version: "unknown" } }));
232
+ const pkg = await import('./package-B9nxDOIr.mjs').catch(() => ({ default: { version: "unknown" } }));
233
233
  console.log(`svamp version: ${pkg.default.version}`);
234
234
  } else {
235
235
  console.error(`Unknown command: ${subcommand}`);
@@ -238,7 +238,7 @@ async function main() {
238
238
  }
239
239
  }
240
240
  async function handleInteractiveCommand() {
241
- const { runInteractive } = await import('./run-DsSVL5N4.mjs');
241
+ const { runInteractive } = await import('./run-Ceop6nDB.mjs');
242
242
  const interactiveArgs = subcommand === "start" ? args.slice(1) : args;
243
243
  let directory = process.cwd();
244
244
  let resumeSessionId;
@@ -283,7 +283,7 @@ async function handleAgentCommand() {
283
283
  return;
284
284
  }
285
285
  if (agentArgs[0] === "list") {
286
- const { KNOWN_ACP_AGENTS, KNOWN_MCP_AGENTS: KNOWN_MCP_AGENTS2 } = await import('./run-Dm7UViwQ.mjs').then(function (n) { return n.i; });
286
+ const { KNOWN_ACP_AGENTS, KNOWN_MCP_AGENTS: KNOWN_MCP_AGENTS2 } = await import('./run-RO50yndI.mjs').then(function (n) { return n.i; });
287
287
  console.log("Known agents:");
288
288
  for (const [name, config2] of Object.entries(KNOWN_ACP_AGENTS)) {
289
289
  console.log(` ${name.padEnd(12)} ${config2.command} ${config2.args.join(" ")} (ACP)`);
@@ -295,7 +295,7 @@ async function handleAgentCommand() {
295
295
  console.log('Use "svamp agent -- <command> [args]" for a custom ACP agent.');
296
296
  return;
297
297
  }
298
- const { resolveAcpAgentConfig, KNOWN_MCP_AGENTS } = await import('./run-Dm7UViwQ.mjs').then(function (n) { return n.i; });
298
+ const { resolveAcpAgentConfig, KNOWN_MCP_AGENTS } = await import('./run-RO50yndI.mjs').then(function (n) { return n.i; });
299
299
  let cwd = process.cwd();
300
300
  const filteredArgs = [];
301
301
  for (let i = 0; i < agentArgs.length; i++) {
@@ -319,12 +319,12 @@ async function handleAgentCommand() {
319
319
  console.log(`Starting ${config.agentName} agent in ${cwd}...`);
320
320
  let backend;
321
321
  if (KNOWN_MCP_AGENTS[config.agentName]) {
322
- const { CodexMcpBackend } = await import('./run-Dm7UViwQ.mjs').then(function (n) { return n.j; });
322
+ const { CodexMcpBackend } = await import('./run-RO50yndI.mjs').then(function (n) { return n.j; });
323
323
  backend = new CodexMcpBackend({ cwd, log: logFn });
324
324
  } else {
325
- const { AcpBackend } = await import('./run-Dm7UViwQ.mjs').then(function (n) { return n.h; });
326
- const { GeminiTransport } = await import('./run-Dm7UViwQ.mjs').then(function (n) { return n.G; });
327
- const { DefaultTransport } = await import('./run-Dm7UViwQ.mjs').then(function (n) { return n.D; });
325
+ const { AcpBackend } = await import('./run-RO50yndI.mjs').then(function (n) { return n.h; });
326
+ const { GeminiTransport } = await import('./run-RO50yndI.mjs').then(function (n) { return n.G; });
327
+ const { DefaultTransport } = await import('./run-RO50yndI.mjs').then(function (n) { return n.D; });
328
328
  const transportHandler = config.agentName === "gemini" ? new GeminiTransport() : new DefaultTransport(config.agentName);
329
329
  backend = new AcpBackend({
330
330
  agentName: config.agentName,
@@ -442,7 +442,7 @@ async function handleSessionCommand() {
442
442
  printSessionHelp();
443
443
  return;
444
444
  }
445
- const { sessionList, sessionSpawn, sessionStop, sessionInfo, sessionMessages, sessionAttach, sessionMachines, sessionSend, sessionWait, sessionShare, sessionRalphStart, sessionRalphCancel, sessionRalphStatus, sessionInboxSend, sessionInboxList, sessionInboxRead, sessionInboxReply, sessionInboxClear } = await import('./commands-C06J5fW3.mjs');
445
+ const { sessionList, sessionSpawn, sessionStop, sessionInfo, sessionMessages, sessionAttach, sessionMachines, sessionSend, sessionWait, sessionShare, sessionRalphStart, sessionRalphCancel, sessionRalphStatus, sessionInboxSend, sessionInboxList, sessionInboxRead, sessionInboxReply, sessionInboxClear } = await import('./commands-BkDj4wWg.mjs');
446
446
  const parseFlagStr = (flag, shortFlag) => {
447
447
  for (let i = 1; i < sessionArgs.length; i++) {
448
448
  if ((sessionArgs[i] === flag || shortFlag) && i + 1 < sessionArgs.length) {
@@ -502,7 +502,7 @@ async function handleSessionCommand() {
502
502
  allowDomain.push(sessionArgs[++i]);
503
503
  }
504
504
  }
505
- const { parseShareArg } = await import('./commands-C06J5fW3.mjs');
505
+ const { parseShareArg } = await import('./commands-BkDj4wWg.mjs');
506
506
  const shareEntries = share.map((s) => parseShareArg(s));
507
507
  await sessionSpawn(agent, dir, targetMachineId, {
508
508
  message,
@@ -588,7 +588,7 @@ async function handleSessionCommand() {
588
588
  console.error("Usage: svamp session approve <session-id> [request-id] [--json]");
589
589
  process.exit(1);
590
590
  }
591
- const { sessionApprove } = await import('./commands-C06J5fW3.mjs');
591
+ const { sessionApprove } = await import('./commands-BkDj4wWg.mjs');
592
592
  const approveReqId = sessionArgs[2] && !sessionArgs[2].startsWith("--") ? sessionArgs[2] : void 0;
593
593
  await sessionApprove(sessionArgs[1], approveReqId, targetMachineId, {
594
594
  json: hasFlag("--json")
@@ -598,7 +598,7 @@ async function handleSessionCommand() {
598
598
  console.error("Usage: svamp session deny <session-id> [request-id] [--json]");
599
599
  process.exit(1);
600
600
  }
601
- const { sessionDeny } = await import('./commands-C06J5fW3.mjs');
601
+ const { sessionDeny } = await import('./commands-BkDj4wWg.mjs');
602
602
  const denyReqId = sessionArgs[2] && !sessionArgs[2].startsWith("--") ? sessionArgs[2] : void 0;
603
603
  await sessionDeny(sessionArgs[1], denyReqId, targetMachineId, {
604
604
  json: hasFlag("--json")
@@ -634,7 +634,7 @@ async function handleSessionCommand() {
634
634
  console.error("Usage: svamp session set-title <title>");
635
635
  process.exit(1);
636
636
  }
637
- const { sessionSetTitle } = await import('./agentCommands-WLRw5gAP.mjs');
637
+ const { sessionSetTitle } = await import('./agentCommands-DJQZraQK.mjs');
638
638
  await sessionSetTitle(title);
639
639
  } else if (sessionSubcommand === "set-link") {
640
640
  const url = sessionArgs[1];
@@ -643,7 +643,7 @@ async function handleSessionCommand() {
643
643
  process.exit(1);
644
644
  }
645
645
  const label = sessionArgs[2] && !sessionArgs[2].startsWith("--") ? sessionArgs[2] : void 0;
646
- const { sessionSetLink } = await import('./agentCommands-WLRw5gAP.mjs');
646
+ const { sessionSetLink } = await import('./agentCommands-DJQZraQK.mjs');
647
647
  await sessionSetLink(url, label);
648
648
  } else if (sessionSubcommand === "notify") {
649
649
  const message = sessionArgs[1];
@@ -652,7 +652,7 @@ async function handleSessionCommand() {
652
652
  process.exit(1);
653
653
  }
654
654
  const level = parseFlagStr("--level") || "info";
655
- const { sessionNotify } = await import('./agentCommands-WLRw5gAP.mjs');
655
+ const { sessionNotify } = await import('./agentCommands-DJQZraQK.mjs');
656
656
  await sessionNotify(message, level);
657
657
  } else if (sessionSubcommand === "broadcast") {
658
658
  const action = sessionArgs[1];
@@ -660,7 +660,7 @@ async function handleSessionCommand() {
660
660
  console.error("Usage: svamp session broadcast <action> [args...]\nActions: open-canvas <url> [label], close-canvas, toast <message>");
661
661
  process.exit(1);
662
662
  }
663
- const { sessionBroadcast } = await import('./agentCommands-WLRw5gAP.mjs');
663
+ const { sessionBroadcast } = await import('./agentCommands-DJQZraQK.mjs');
664
664
  await sessionBroadcast(action, sessionArgs.slice(2).filter((a) => !a.startsWith("--")));
665
665
  } else if (sessionSubcommand === "inbox") {
666
666
  const inboxSubcmd = sessionArgs[1];
@@ -671,7 +671,7 @@ async function handleSessionCommand() {
671
671
  process.exit(1);
672
672
  }
673
673
  if (agentSessionId) {
674
- const { inboxSend } = await import('./agentCommands-WLRw5gAP.mjs');
674
+ const { inboxSend } = await import('./agentCommands-DJQZraQK.mjs');
675
675
  await inboxSend(sessionArgs[2], {
676
676
  body: sessionArgs[3],
677
677
  subject: parseFlagStr("--subject"),
@@ -686,7 +686,7 @@ async function handleSessionCommand() {
686
686
  }
687
687
  } else if (inboxSubcmd === "list" || inboxSubcmd === "ls") {
688
688
  if (agentSessionId && !sessionArgs[2]) {
689
- const { inboxList } = await import('./agentCommands-WLRw5gAP.mjs');
689
+ const { inboxList } = await import('./agentCommands-DJQZraQK.mjs');
690
690
  await inboxList({
691
691
  unread: hasFlag("--unread"),
692
692
  limit: parseFlagInt("--limit"),
@@ -708,7 +708,7 @@ async function handleSessionCommand() {
708
708
  process.exit(1);
709
709
  }
710
710
  if (agentSessionId && !sessionArgs[3]) {
711
- const { inboxList } = await import('./agentCommands-WLRw5gAP.mjs');
711
+ const { inboxList } = await import('./agentCommands-DJQZraQK.mjs');
712
712
  await sessionInboxRead(agentSessionId, sessionArgs[2], targetMachineId);
713
713
  } else if (sessionArgs[3]) {
714
714
  await sessionInboxRead(sessionArgs[2], sessionArgs[3], targetMachineId);
@@ -718,7 +718,7 @@ async function handleSessionCommand() {
718
718
  }
719
719
  } else if (inboxSubcmd === "reply") {
720
720
  if (agentSessionId && sessionArgs[2] && sessionArgs[3] && !sessionArgs[4]) {
721
- const { inboxReply } = await import('./agentCommands-WLRw5gAP.mjs');
721
+ const { inboxReply } = await import('./agentCommands-DJQZraQK.mjs');
722
722
  await inboxReply(sessionArgs[2], sessionArgs[3]);
723
723
  } else if (sessionArgs[2] && sessionArgs[3] && sessionArgs[4]) {
724
724
  await sessionInboxReply(sessionArgs[2], sessionArgs[3], sessionArgs[4], targetMachineId);
@@ -754,7 +754,7 @@ async function handleMachineCommand() {
754
754
  return;
755
755
  }
756
756
  if (machineSubcommand === "share") {
757
- const { machineShare } = await import('./commands-C06J5fW3.mjs');
757
+ const { machineShare } = await import('./commands-BkDj4wWg.mjs');
758
758
  let machineId;
759
759
  const shareArgs = [];
760
760
  for (let i = 1; i < machineArgs.length; i++) {
@@ -784,7 +784,7 @@ async function handleMachineCommand() {
784
784
  }
785
785
  await machineShare(machineId, { add, remove, list, configPath, showConfig });
786
786
  } else if (machineSubcommand === "exec") {
787
- const { machineExec } = await import('./commands-C06J5fW3.mjs');
787
+ const { machineExec } = await import('./commands-BkDj4wWg.mjs');
788
788
  let machineId;
789
789
  let cwd;
790
790
  const cmdParts = [];
@@ -804,7 +804,7 @@ async function handleMachineCommand() {
804
804
  }
805
805
  await machineExec(machineId, command, cwd);
806
806
  } else if (machineSubcommand === "info") {
807
- const { machineInfo } = await import('./commands-C06J5fW3.mjs');
807
+ const { machineInfo } = await import('./commands-BkDj4wWg.mjs');
808
808
  let machineId;
809
809
  for (let i = 1; i < machineArgs.length; i++) {
810
810
  if ((machineArgs[i] === "--machine" || machineArgs[i] === "-m") && i + 1 < machineArgs.length) {
@@ -824,10 +824,10 @@ async function handleMachineCommand() {
824
824
  level = machineArgs[++i];
825
825
  }
826
826
  }
827
- const { machineNotify } = await import('./agentCommands-WLRw5gAP.mjs');
827
+ const { machineNotify } = await import('./agentCommands-DJQZraQK.mjs');
828
828
  await machineNotify(message, level);
829
829
  } else if (machineSubcommand === "ls") {
830
- const { machineLs } = await import('./commands-C06J5fW3.mjs');
830
+ const { machineLs } = await import('./commands-BkDj4wWg.mjs');
831
831
  let machineId;
832
832
  let showHidden = false;
833
833
  let path;
@@ -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-Dm7UViwQ.mjs';
5
+ import { l as loadSecurityContextConfig, e as resolveSecurityContext, f as buildSecurityContextFromFlags, m as mergeSecurityContexts, c as connectToHypha } from './run-RO50yndI.mjs';
6
6
  import 'os';
7
7
  import 'fs/promises';
8
8
  import 'fs';
@@ -70,6 +70,58 @@ function formatJson(data) {
70
70
  return JSON.stringify(data, null, 2);
71
71
  }
72
72
 
73
+ const SESSION_RPC_PARAMS = {
74
+ getMessages: ["afterSeq", "limit"],
75
+ sendMessage: ["content", "localId", "meta"],
76
+ getMetadata: [],
77
+ updateMetadata: ["newMetadata", "expectedVersion"],
78
+ updateConfig: ["patch"],
79
+ getAgentState: [],
80
+ updateAgentState: ["newState", "expectedVersion"],
81
+ abort: [],
82
+ permissionResponse: ["params"],
83
+ switchMode: ["mode"],
84
+ restartClaude: [],
85
+ killSession: [],
86
+ keepAlive: ["thinking", "mode"],
87
+ sessionEnd: [],
88
+ getActivityState: [],
89
+ readFile: ["path"],
90
+ writeFile: ["path", "content"],
91
+ listDirectory: ["path"],
92
+ bash: ["command", "cwd", "timeout"],
93
+ ripgrep: ["args", "cwd"],
94
+ getDirectoryTree: ["path", "maxDepth"],
95
+ getSharing: [],
96
+ getEffectiveRole: [],
97
+ updateSharing: ["newSharing"],
98
+ updateSecurityContext: ["newSecurityContext"],
99
+ applySystemPrompt: ["prompt"],
100
+ sendInboxMessage: ["message"],
101
+ getInbox: ["opts"],
102
+ markInboxRead: ["messageId"],
103
+ clearInbox: ["opts"],
104
+ registerListener: ["callback"]
105
+ };
106
+ function getSessionProxy(machine, sessionId) {
107
+ return new Proxy({}, {
108
+ get(_target, method) {
109
+ return (...args) => {
110
+ const paramNames = SESSION_RPC_PARAMS[method];
111
+ if (paramNames) {
112
+ const kwargs = {};
113
+ for (let i = 0; i < paramNames.length && i < args.length; i++) {
114
+ if (args[i] !== void 0) {
115
+ kwargs[paramNames[i]] = args[i];
116
+ }
117
+ }
118
+ return machine.sessionRPC(sessionId, method, kwargs);
119
+ }
120
+ return machine.sessionRPC(sessionId, method, {});
121
+ };
122
+ }
123
+ });
124
+ }
73
125
  const SVAMP_HOME = process.env.SVAMP_HOME || join(os.homedir(), ".svamp");
74
126
  const DAEMON_STATE_FILE = join(SVAMP_HOME, "daemon.state.json");
75
127
  const ENV_FILE = join(SVAMP_HOME, ".env");
@@ -318,12 +370,11 @@ async function connectAndGetAllMachines() {
318
370
  const machines = [];
319
371
  try {
320
372
  const services = await server.listServices({ query: { type: "svamp-machine" }, include_unlisted: true, _rkwargs: true });
321
- for (const svc of services) {
322
- try {
323
- const svcId = svc.id || svc.name;
324
- machines.push(await server.getService(svcId));
325
- } catch {
326
- }
373
+ const results = await Promise.allSettled(
374
+ services.map((svc) => server.getService(svc.id || svc.name))
375
+ );
376
+ for (const r of results) {
377
+ if (r.status === "fulfilled") machines.push(r.value);
327
378
  }
328
379
  } catch (err) {
329
380
  restoreConsole();
@@ -402,34 +453,37 @@ async function sessionMachines() {
402
453
  console.log("No machines found.");
403
454
  return;
404
455
  }
405
- const machines = [];
406
- for (const svc of services) {
407
- const svcId = svc.id || svc.name;
408
- try {
409
- const machineSvc = await server.getService(svcId);
410
- const info = await machineSvc.getMachineInfo();
411
- const sessions = await machineSvc.listSessions();
412
- machines.push({
413
- serviceId: svcId,
414
- machineId: info.machineId || svcId,
415
- displayName: info.metadata?.displayName || info.metadata?.host || "-",
416
- platform: info.metadata?.platform || "-",
417
- host: info.metadata?.host || "-",
418
- sessions: sessions.length,
419
- status: info.daemonState?.status || "unknown"
420
- });
421
- } catch {
422
- machines.push({
423
- serviceId: svcId,
424
- machineId: svcId,
425
- displayName: "-",
426
- platform: "-",
427
- host: "-",
428
- sessions: -1,
429
- status: "unreachable"
430
- });
431
- }
432
- }
456
+ const machines = await Promise.all(
457
+ services.map(async (svc) => {
458
+ const svcId = svc.id || svc.name;
459
+ try {
460
+ const machineSvc = await server.getService(svcId);
461
+ const [info, sessions] = await Promise.all([
462
+ machineSvc.getMachineInfo(),
463
+ machineSvc.listSessions()
464
+ ]);
465
+ return {
466
+ serviceId: svcId,
467
+ machineId: info.machineId || svcId,
468
+ displayName: info.metadata?.displayName || info.metadata?.host || "-",
469
+ platform: info.metadata?.platform || "-",
470
+ host: info.metadata?.host || "-",
471
+ sessions: sessions.length,
472
+ status: info.daemonState?.status || "unknown"
473
+ };
474
+ } catch {
475
+ return {
476
+ serviceId: svcId,
477
+ machineId: svcId,
478
+ displayName: "-",
479
+ platform: "-",
480
+ host: "-",
481
+ sessions: -1,
482
+ status: "unreachable"
483
+ };
484
+ }
485
+ })
486
+ );
433
487
  const header = `${"MACHINE ID".padEnd(20)} ${"NAME".padEnd(20)} ${"PLATFORM".padEnd(12)} ${"HOST".padEnd(25)} ${"SESSIONS".padEnd(10)} ${"STATUS"}`;
434
488
  console.log(header);
435
489
  console.log("-".repeat(header.length));
@@ -672,18 +726,23 @@ async function sessionList(machineId, opts) {
672
726
  }
673
727
  }
674
728
  }
675
- async function listSessionsFromMachines(server, machines, opts) {
729
+ async function listSessionsFromMachines(_server, machines, opts) {
676
730
  const allSessions = [];
677
- for (const machine of machines) {
678
- try {
679
- const info = await machine.getMachineInfo();
680
- const sessions = await machine.listSessions();
731
+ const machineResults = await Promise.allSettled(
732
+ machines.map(async (machine) => {
733
+ const [info, sessions] = await Promise.all([
734
+ machine.getMachineInfo(),
735
+ machine.listSessions()
736
+ ]);
737
+ const host = info.metadata?.displayName || info.metadata?.host || info.machineId;
681
738
  for (const s of sessions) {
682
- s.machineHost = info.metadata?.displayName || info.metadata?.host || info.machineId;
739
+ s.machineHost = host;
683
740
  }
684
- allSessions.push(...sessions);
685
- } catch {
686
- }
741
+ return sessions;
742
+ })
743
+ );
744
+ for (const r of machineResults) {
745
+ if (r.status === "fulfilled") allSessions.push(...r.value);
687
746
  }
688
747
  const filtered = opts?.active ? allSessions.filter((s) => s.active) : allSessions;
689
748
  if (filtered.length === 0) {
@@ -694,29 +753,16 @@ async function listSessionsFromMachines(server, machines, opts) {
694
753
  }
695
754
  return;
696
755
  }
697
- const enriched = [];
698
- for (const s of filtered) {
699
- let flavor = "claude";
700
- let name = "";
701
- let path = s.directory || "";
702
- let host = s.machineHost || "";
703
- if (s.metadata) {
704
- flavor = s.metadata.flavor || "claude";
705
- name = s.metadata.name || "";
706
- }
707
- if (s.active) {
708
- try {
709
- const svc = await server.getService(`svamp-session-${s.sessionId}`);
710
- const { metadata } = await svc.getMetadata();
711
- flavor = metadata?.flavor || flavor;
712
- name = metadata?.name || name;
713
- path = metadata?.path || path;
714
- host = metadata?.host || host;
715
- } catch {
716
- }
717
- }
718
- enriched.push({ ...s, flavor, name, path, host });
719
- }
756
+ const enriched = filtered.map((s) => {
757
+ const m = s.metadata || {};
758
+ return {
759
+ ...s,
760
+ flavor: m.flavor || "claude",
761
+ name: m.name || "",
762
+ path: m.path || s.directory || "",
763
+ host: m.host || s.machineHost || ""
764
+ };
765
+ });
720
766
  if (opts?.json) {
721
767
  console.log(formatJson(enriched.map((s) => ({
722
768
  sessionId: s.sessionId,
@@ -874,12 +920,14 @@ async function sessionSpawn(agent, directory, machineId, opts) {
874
920
  let effectiveParentSessionId = opts?.parentSessionId || process.env.SVAMP_SESSION_ID || void 0;
875
921
  if (effectiveParentSessionId) {
876
922
  try {
923
+ const sessions = await machine.listSessions();
877
924
  if (opts?.parentSessionId) {
878
- const sessions = await machine.listSessions();
879
925
  const match = resolveSessionId(sessions, effectiveParentSessionId);
880
926
  effectiveParentSessionId = match.sessionId;
927
+ } else {
928
+ const found = sessions.find((s) => s.sessionId === effectiveParentSessionId);
929
+ if (!found) throw new Error("not found");
881
930
  }
882
- await server.getService(`svamp-session-${effectiveParentSessionId}`);
883
931
  } catch (err) {
884
932
  const source = opts?.parentSessionId ? "--parent" : "SVAMP_SESSION_ID";
885
933
  console.error(`Error: Parent session ${effectiveParentSessionId} not found (from ${source}).`);
@@ -921,7 +969,7 @@ async function sessionSpawn(agent, directory, machineId, opts) {
921
969
  console.log(`\x1B[33m Use -p bypassPermissions to run without approval prompts.\x1B[0m`);
922
970
  }
923
971
  if (opts?.message && result.sessionId) {
924
- const svc = await server.getService(`svamp-session-${result.sessionId}`);
972
+ const svc = getSessionProxy(machine, result.sessionId);
925
973
  const sendResult = await svc.sendMessage(
926
974
  JSON.stringify({
927
975
  role: "user",
@@ -972,7 +1020,7 @@ async function sessionInfo(sessionId, machineId, opts) {
972
1020
  let metadata = {};
973
1021
  let activity = {};
974
1022
  try {
975
- const svc = await server.getService(`svamp-session-${fullId}`);
1023
+ const svc = getSessionProxy(machine, fullId);
976
1024
  const metaResult = await svc.getMetadata();
977
1025
  metadata = metaResult.metadata || {};
978
1026
  activity = await svc.getActivityState();
@@ -1012,7 +1060,7 @@ async function sessionMessages(sessionId, machineId, opts) {
1012
1060
  const sessions = await machine.listSessions();
1013
1061
  const match = resolveSessionId(sessions, sessionId);
1014
1062
  const fullId = match.sessionId;
1015
- const svc = await server.getService(`svamp-session-${fullId}`);
1063
+ const svc = getSessionProxy(machine, fullId);
1016
1064
  const afterSeq = opts?.after ?? 0;
1017
1065
  const apiLimit = opts?.limit ?? 1e3;
1018
1066
  const { messages } = await svc.getMessages(afterSeq, apiLimit);
@@ -1052,7 +1100,7 @@ async function sessionApprove(sessionId, requestId, machineId, opts) {
1052
1100
  const sessions = await machine.listSessions();
1053
1101
  const match = resolveSessionId(sessions, sessionId);
1054
1102
  const fullId = match.sessionId;
1055
- const svc = await server.getService(`svamp-session-${fullId}`);
1103
+ const svc = getSessionProxy(machine, fullId);
1056
1104
  if (requestId) {
1057
1105
  const activity = await svc.getActivityState();
1058
1106
  const pending = activity.pendingPermissions || [];
@@ -1101,7 +1149,7 @@ async function sessionDeny(sessionId, requestId, machineId, opts) {
1101
1149
  const sessions = await machine.listSessions();
1102
1150
  const match = resolveSessionId(sessions, sessionId);
1103
1151
  const fullId = match.sessionId;
1104
- const svc = await server.getService(`svamp-session-${fullId}`);
1152
+ const svc = getSessionProxy(machine, fullId);
1105
1153
  if (requestId) {
1106
1154
  const activity = await svc.getActivityState();
1107
1155
  const pending = activity.pendingPermissions || [];
@@ -1151,7 +1199,7 @@ async function sessionAttach(sessionId, machineId) {
1151
1199
  const fullId = match.sessionId;
1152
1200
  let svc;
1153
1201
  try {
1154
- svc = await server.getService(`svamp-session-${fullId}`);
1202
+ svc = getSessionProxy(machine, fullId);
1155
1203
  } catch (err) {
1156
1204
  console.error(`Could not find session service: ${err.message}`);
1157
1205
  await server.disconnect();
@@ -1369,7 +1417,7 @@ async function sessionShare(sessionIdPartial, machineId, opts) {
1369
1417
  const sessions = await machine.listSessions();
1370
1418
  const match = resolveSessionId(sessions, sessionIdPartial);
1371
1419
  const fullId = match.sessionId;
1372
- const svc = await server.getService(`svamp-session-${fullId}`);
1420
+ const svc = getSessionProxy(machine, fullId);
1373
1421
  if (opts.list) {
1374
1422
  const metaResult = await svc.getMetadata();
1375
1423
  const sharing = metaResult.metadata?.sharing;
@@ -1638,7 +1686,7 @@ async function sessionRalphStart(sessionIdPartial, task, machineId, opts) {
1638
1686
  const sessions = await machine.listSessions();
1639
1687
  const match = resolveSessionId(sessions, sessionIdPartial);
1640
1688
  const fullId = match.sessionId;
1641
- const svc = await server.getService(`svamp-session-${fullId}`);
1689
+ const svc = getSessionProxy(machine, fullId);
1642
1690
  const { metadata } = await svc.getMetadata();
1643
1691
  if (metadata?.ralphLoop?.active) {
1644
1692
  console.error(`Ralph loop is already active (iteration ${metadata.ralphLoop.currentIteration}). Cancel it first with: svamp session ralph-cancel ${sessionIdPartial}`);
@@ -1672,7 +1720,7 @@ async function sessionRalphCancel(sessionIdPartial, machineId) {
1672
1720
  const sessions = await machine.listSessions();
1673
1721
  const match = resolveSessionId(sessions, sessionIdPartial);
1674
1722
  const fullId = match.sessionId;
1675
- const svc = await server.getService(`svamp-session-${fullId}`);
1723
+ const svc = getSessionProxy(machine, fullId);
1676
1724
  const { metadata } = await svc.getMetadata();
1677
1725
  if (!metadata?.ralphLoop?.active) {
1678
1726
  console.log("No active Ralph loop on this session.");
@@ -1691,7 +1739,7 @@ async function sessionRalphStatus(sessionIdPartial, machineId) {
1691
1739
  const sessions = await machine.listSessions();
1692
1740
  const match = resolveSessionId(sessions, sessionIdPartial);
1693
1741
  const fullId = match.sessionId;
1694
- const svc = await server.getService(`svamp-session-${fullId}`);
1742
+ const svc = getSessionProxy(machine, fullId);
1695
1743
  const { metadata } = await svc.getMetadata();
1696
1744
  const ralph = metadata?.ralphLoop;
1697
1745
  if (!ralph || !ralph.active) {
@@ -1,11 +1,11 @@
1
1
  import { writeFileSync, readFileSync } from 'fs';
2
2
  import { resolve } from 'path';
3
- import { connectAndGetMachine } from './commands-C06J5fW3.mjs';
3
+ import { connectAndGetMachine } from './commands-BkDj4wWg.mjs';
4
4
  import 'node:fs';
5
5
  import 'node:child_process';
6
6
  import 'node:path';
7
7
  import 'node:os';
8
- import './run-Dm7UViwQ.mjs';
8
+ import './run-RO50yndI.mjs';
9
9
  import 'os';
10
10
  import 'fs/promises';
11
11
  import 'url';
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-Dm7UViwQ.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-RO50yndI.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.80";
2
+ var version = "0.1.82";
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 && tsc --noEmit && pkgroll",
21
21
  typecheck: "tsc --noEmit",
22
- test: "npx tsx test/test-authorize.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-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-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-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-clear-detection.mjs && npx tsx test/test-session-consolidation.mjs && npx tsx test/test-inbox.mjs",
22
+ test: "npx tsx test/test-authorize.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-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-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-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-clear-detection.mjs && npx tsx test/test-session-consolidation.mjs && npx tsx test/test-inbox.mjs && npx tsx test/test-session-rpc-dispatch.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",
@@ -2,7 +2,7 @@ import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(im
2
2
  import os from 'node:os';
3
3
  import { join, resolve } from 'node:path';
4
4
  import { mkdirSync, writeFileSync, existsSync, unlinkSync, readFileSync, watch } from 'node:fs';
5
- import { c as connectToHypha, a as registerSessionService } from './run-Dm7UViwQ.mjs';
5
+ import { c as connectToHypha, a as registerSessionService } from './run-RO50yndI.mjs';
6
6
  import { createServer } from 'node:http';
7
7
  import { spawn } from 'node:child_process';
8
8
  import { createInterface } from 'node:readline';
@@ -294,6 +294,12 @@ function applySecurityContext(baseConfig, context) {
294
294
  return config;
295
295
  }
296
296
 
297
+ function getParamNames(fn) {
298
+ const src = fn.toString();
299
+ const match = src.match(/^(?:async\s+)?(?:function\s*\w*)?\s*\(([^)]*)\)/);
300
+ if (!match) return [];
301
+ return match[1].split(",").map((p) => p.trim().replace(/\s*=.*$/, "").replace(/^\.\.\.\s*/, "")).filter(Boolean);
302
+ }
297
303
  const terminalSessions = /* @__PURE__ */ new Map();
298
304
  let ptyModule = null;
299
305
  async function getPtyModule() {
@@ -439,7 +445,7 @@ async function registerMachineService(server, machineId, metadata, daemonState,
439
445
  * This consolidates all session RPCs through the machine service,
440
446
  * eliminating the need for per-session Hypha service registration.
441
447
  */
442
- sessionRPC: async (sessionId, method, args, context) => {
448
+ sessionRPC: async (sessionId, method, kwargs, context) => {
443
449
  authorizeRequest(context, currentMetadata.sharing, "view");
444
450
  const rpc = handlers.getSessionRPCHandlers?.(sessionId);
445
451
  if (!rpc) {
@@ -449,8 +455,11 @@ async function registerMachineService(server, machineId, metadata, daemonState,
449
455
  if (typeof handler !== "function") {
450
456
  throw new Error(`Unknown session method: ${method}`);
451
457
  }
452
- const argArray = Array.isArray(args) ? args : args !== void 0 ? [args] : [];
453
- return await handler(...argArray, context);
458
+ const paramNames = getParamNames(handler);
459
+ const callArgs = paramNames.map(
460
+ (name) => name === "context" ? context : kwargs?.[name] ?? void 0
461
+ );
462
+ return await handler(...callArgs);
454
463
  },
455
464
  /**
456
465
  * Register a listener for a specific session's real-time updates.
@@ -836,6 +845,11 @@ async function registerMachineService(server, machineId, metadata, daemonState,
836
845
  const session = terminalSessions.get(params.sessionId);
837
846
  if (!session) throw new Error(`Terminal session ${params.sessionId} not found`);
838
847
  const scrollback = session.outputBuffer.join("");
848
+ if (params.cols && params.rows) {
849
+ session.pty.resize(params.cols, params.rows);
850
+ session.cols = params.cols;
851
+ session.rows = params.rows;
852
+ }
839
853
  return { sessionId: session.id, cols: session.cols, rows: session.rows, scrollback, exited: session.exited };
840
854
  },
841
855
  // Machine-level directory listing (read-only, view role)
@@ -1599,6 +1613,7 @@ function createSessionStore(server, sessionId, initialMetadata, initialAgentStat
1599
1613
  const store = {
1600
1614
  serviceInfo: { id: `svamp-session-${sessionId}` },
1601
1615
  pushMessage,
1616
+ getMetadata: () => ({ ...metadata }),
1602
1617
  get _agentState() {
1603
1618
  return agentState;
1604
1619
  },
@@ -5572,8 +5587,7 @@ async function startDaemon(options) {
5572
5587
  process.on("SIGUSR1", () => requestShutdown("os-signal-cleanup"));
5573
5588
  process.on("uncaughtException", (error) => {
5574
5589
  if (shutdownRequested) return;
5575
- logger.error("Uncaught exception:", error);
5576
- requestShutdown("exception", error.message);
5590
+ logger.error("Uncaught exception (non-fatal, daemon continues):", error);
5577
5591
  });
5578
5592
  const TRANSIENT_REJECTION_PATTERNS = [
5579
5593
  "_rintf",
@@ -5604,8 +5618,12 @@ async function startDaemon(options) {
5604
5618
  // Fetch API errors during reconnect
5605
5619
  "already exists in the cache store",
5606
5620
  // hypha-rpc: stale in-flight RPC calls after reconnect try to resolve with duplicate message keys
5607
- "Failed to send the request when calling method"
5621
+ "Failed to send the request when calling method",
5608
5622
  // hypha-rpc: RPC call failed after reconnect (often wraps the cache store error)
5623
+ "Rate limit",
5624
+ // Hypha server 429 rate limiting — transient, will resolve on its own
5625
+ "status 429"
5626
+ // HTTP 429 status code
5609
5627
  ];
5610
5628
  let unhandledRejectionCount = 0;
5611
5629
  let unhandledRejectionResetTimer = null;
@@ -5628,10 +5646,9 @@ async function startDaemon(options) {
5628
5646
  }, UNHANDLED_REJECTION_WINDOW_MS);
5629
5647
  }
5630
5648
  if (unhandledRejectionCount >= UNHANDLED_REJECTION_THRESHOLD) {
5631
- logger.log(`Too many unhandled rejections (${unhandledRejectionCount} in ${UNHANDLED_REJECTION_WINDOW_MS / 1e3}s), shutting down`);
5632
- requestShutdown("exception", msg);
5649
+ logger.log(`Too many unhandled rejections (${unhandledRejectionCount} in ${UNHANDLED_REJECTION_WINDOW_MS / 1e3}s) \u2014 logging only, daemon continues`);
5633
5650
  } else {
5634
- logger.log(`Unhandled rejection ${unhandledRejectionCount}/${UNHANDLED_REJECTION_THRESHOLD} (not crashing yet): ${msg.slice(0, 200)}`);
5651
+ logger.log(`Unhandled rejection ${unhandledRejectionCount}/${UNHANDLED_REJECTION_THRESHOLD}: ${msg.slice(0, 200)}`);
5635
5652
  }
5636
5653
  });
5637
5654
  if (isDaemonAlive()) {
@@ -5713,8 +5730,7 @@ async function startDaemon(options) {
5713
5730
  });
5714
5731
  logger.log(`Connected to Hypha (workspace: ${server.config.workspace})`);
5715
5732
  server.on("disconnected", (reason) => {
5716
- logger.log(`Hypha connection permanently lost: ${reason}`);
5717
- requestShutdown("hypha-disconnected", String(reason));
5733
+ logger.log(`Hypha connection permanently lost: ${reason}. Daemon continues running \u2014 restart manually to reconnect.`);
5718
5734
  });
5719
5735
  const pidToTrackedSession = /* @__PURE__ */ new Map();
5720
5736
  server.on("services_registered", () => {
@@ -5725,13 +5741,33 @@ async function startDaemon(options) {
5725
5741
  }
5726
5742
  });
5727
5743
  const getCurrentChildren = () => {
5728
- return Array.from(pidToTrackedSession.values()).map((s) => ({
5729
- sessionId: s.svampSessionId || `PID-${s.pid}`,
5730
- pid: s.pid,
5731
- startedBy: s.startedBy,
5732
- directory: s.directory,
5733
- active: !s.stopped && s.hyphaService != null
5734
- }));
5744
+ return Array.from(pidToTrackedSession.values()).map((s) => {
5745
+ const active = !s.stopped && s.hyphaService != null;
5746
+ let metadata;
5747
+ if (active && s.hyphaService) {
5748
+ try {
5749
+ const m = s.hyphaService.getMetadata();
5750
+ metadata = {
5751
+ flavor: m.flavor,
5752
+ name: m.name,
5753
+ path: m.path,
5754
+ host: m.host,
5755
+ lifecycleState: m.lifecycleState,
5756
+ parentSessionId: m.parentSessionId,
5757
+ tags: m.tags
5758
+ };
5759
+ } catch {
5760
+ }
5761
+ }
5762
+ return {
5763
+ sessionId: s.svampSessionId || `PID-${s.pid}`,
5764
+ pid: s.pid,
5765
+ startedBy: s.startedBy,
5766
+ directory: s.directory,
5767
+ active,
5768
+ metadata
5769
+ };
5770
+ });
5735
5771
  };
5736
5772
  let machineServiceRef = null;
5737
5773
  const spawnSession = async (options2) => {
@@ -6767,6 +6803,10 @@ The automated loop has finished. Review the progress above and let me know if yo
6767
6803
  if (message.urgency === "urgent") {
6768
6804
  const formatted = formatInboxMessageXml(message);
6769
6805
  logger.log(`[Session ${sessionId}] Delivering urgent inbox message to agent`);
6806
+ sessionService.pushMessage(
6807
+ { role: "user", content: { type: "text", text: formatted } },
6808
+ "user"
6809
+ );
6770
6810
  if (!claudeProcess || claudeProcess.exitCode !== null) {
6771
6811
  spawnClaude(formatted);
6772
6812
  } else {
@@ -7191,6 +7231,10 @@ The automated loop has finished. Review the progress above and let me know if yo
7191
7231
  if (message.urgency === "urgent" && acpBackendReady) {
7192
7232
  const formatted = formatInboxMessageXml(message);
7193
7233
  logger.log(`[${agentName} Session ${sessionId}] Delivering urgent inbox message to agent`);
7234
+ sessionService.pushMessage(
7235
+ { role: "user", content: { type: "text", text: formatted } },
7236
+ "user"
7237
+ );
7194
7238
  sessionMetadata = { ...sessionMetadata, lifecycleState: "running" };
7195
7239
  sessionService.updateMetadata(sessionMetadata);
7196
7240
  sessionService.sendKeepAlive(true);
@@ -7679,7 +7723,9 @@ The automated loop has finished. Review the progress above and let me know if yo
7679
7723
  spawnSession,
7680
7724
  stopSession,
7681
7725
  restartSession,
7682
- requestShutdown: () => requestShutdown("hypha-app"),
7726
+ requestShutdown: () => {
7727
+ logger.log("Shutdown requested via hypha-app (ignored \u2014 daemon never self-terminates)");
7728
+ },
7683
7729
  getTrackedSessions: getCurrentChildren,
7684
7730
  getSessionRPCHandlers: (sessionId) => {
7685
7731
  for (const [, session] of pidToTrackedSession) {
@@ -7785,20 +7831,16 @@ The automated loop has finished. Review the progress above and let me know if yo
7785
7831
  for (const sessionId of sessionsToAutoContinue) {
7786
7832
  setTimeout(async () => {
7787
7833
  try {
7788
- const svc = await Promise.race([
7789
- server.getService(`svamp-session-${sessionId}`),
7790
- new Promise((_, reject) => setTimeout(() => reject(new Error("getService timeout")), 1e4))
7791
- ]);
7792
- await Promise.race([
7793
- svc.sendMessage(
7794
- JSON.stringify({
7795
- role: "user",
7796
- content: { type: "text", text: 'The svamp daemon was restarted, which interrupted this session. Please continue where you left off. IMPORTANT: Do not run any command that would stop or restart the svamp daemon (e.g. "svamp daemon stop") \u2014 that would interrupt the session again.' },
7797
- meta: { sentFrom: "svamp-daemon-auto-continue" }
7798
- })
7799
- ),
7800
- new Promise((_, reject) => setTimeout(() => reject(new Error("sendMessage timeout")), 3e4))
7801
- ]);
7834
+ const tracked = Array.from(pidToTrackedSession.values()).find((s) => s.svampSessionId === sessionId);
7835
+ const rpc = tracked?.sessionRPCHandlers;
7836
+ if (!rpc) throw new Error(`Session ${sessionId} RPC handlers not found`);
7837
+ await rpc.sendMessage(
7838
+ JSON.stringify({
7839
+ role: "user",
7840
+ content: { type: "text", text: 'The svamp daemon was restarted, which interrupted this session. Please continue where you left off. IMPORTANT: Do not run any command that would stop or restart the svamp daemon (e.g. "svamp daemon stop") \u2014 that would interrupt the session again.' },
7841
+ meta: { sentFrom: "svamp-daemon-auto-continue" }
7842
+ })
7843
+ );
7802
7844
  logger.log(`Auto-continued session ${sessionId}`);
7803
7845
  } catch (err) {
7804
7846
  logger.log(`Failed to auto-continue session ${sessionId}: ${err.message}`);
@@ -7812,10 +7854,12 @@ The automated loop has finished. Review the progress above and let me know if yo
7812
7854
  logger.log(`Resuming Ralph loop for ${sessionsToRalphResume.length} session(s)...`);
7813
7855
  for (const { sessionId, directory: sessDir } of sessionsToRalphResume) {
7814
7856
  try {
7815
- const svc = await Promise.race([
7816
- server.getService(`svamp-session-${sessionId}`),
7817
- new Promise((_, reject) => setTimeout(() => reject(new Error("getService timeout")), 1e4))
7818
- ]);
7857
+ const tracked = Array.from(pidToTrackedSession.values()).find((s) => s.svampSessionId === sessionId);
7858
+ const rpc = tracked?.sessionRPCHandlers;
7859
+ if (!rpc) {
7860
+ logger.log(`Session ${sessionId} RPC handlers not found for Ralph resume`);
7861
+ continue;
7862
+ }
7819
7863
  const rlState = readRalphState(getRalphStateFilePath(sessDir, sessionId));
7820
7864
  if (!rlState) continue;
7821
7865
  const initDelayMs = 2e3;
@@ -7836,20 +7880,17 @@ The automated loop has finished. Review the progress above and let me know if yo
7836
7880
  const progressRelPath = `.svamp/${sessionId}/ralph-progress.md`;
7837
7881
  const prompt = buildRalphPrompt(currentState.task, currentState);
7838
7882
  const ralphSysPrompt = buildRalphSystemPrompt(currentState, progressRelPath);
7839
- await Promise.race([
7840
- svc.sendMessage(
7841
- JSON.stringify({
7842
- role: "user",
7843
- content: { type: "text", text: prompt },
7844
- meta: {
7845
- sentFrom: "svamp-daemon-ralph-resume",
7846
- appendSystemPrompt: ralphSysPrompt,
7847
- ...isFreshMode ? { ralphFreshContext: true } : {}
7848
- }
7849
- })
7850
- ),
7851
- new Promise((_, reject) => setTimeout(() => reject(new Error("sendMessage timeout")), 3e4))
7852
- ]);
7883
+ await rpc.sendMessage(
7884
+ JSON.stringify({
7885
+ role: "user",
7886
+ content: { type: "text", text: prompt },
7887
+ meta: {
7888
+ sentFrom: "svamp-daemon-ralph-resume",
7889
+ appendSystemPrompt: ralphSysPrompt,
7890
+ ...isFreshMode ? { ralphFreshContext: true } : {}
7891
+ }
7892
+ })
7893
+ );
7853
7894
  logger.log(`Resumed Ralph loop for session ${sessionId} at iteration ${currentState.iteration} (${isFreshMode ? "fresh" : "continue"})`);
7854
7895
  } catch (err) {
7855
7896
  logger.log(`Failed to resume Ralph loop for session ${sessionId}: ${err.message}`);
@@ -7913,20 +7954,6 @@ The automated loop has finished. Review the progress above and let me know if yo
7913
7954
  }
7914
7955
  } catch {
7915
7956
  }
7916
- try {
7917
- const installedVersion = readPackageVersion();
7918
- if (installedVersion !== "unknown" && installedVersion !== DAEMON_VERSION) {
7919
- const supervised2 = process.env.SVAMP_SUPERVISED === "1";
7920
- if (supervised2) {
7921
- logger.log(`svamp-cli version changed on disk: ${DAEMON_VERSION} \u2192 ${installedVersion}. Exiting for launchd restart...`);
7922
- requestShutdown("version-update", `Updated ${DAEMON_VERSION} \u2192 ${installedVersion}`);
7923
- return;
7924
- } else {
7925
- logger.log(`svamp-cli version changed on disk: ${DAEMON_VERSION} \u2192 ${installedVersion}. Run 'svamp daemon stop && svamp daemon start' to apply the update.`);
7926
- }
7927
- }
7928
- } catch {
7929
- }
7930
7957
  for (const [key, session] of pidToTrackedSession) {
7931
7958
  const child = session.childProcess;
7932
7959
  if (child && child.pid) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svamp-cli",
3
- "version": "0.1.80",
3
+ "version": "0.1.82",
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 && tsc --noEmit && pkgroll",
22
22
  "typecheck": "tsc --noEmit",
23
- "test": "npx tsx test/test-authorize.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-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-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-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-clear-detection.mjs && npx tsx test/test-session-consolidation.mjs && npx tsx test/test-inbox.mjs",
23
+ "test": "npx tsx test/test-authorize.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-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-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-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-clear-detection.mjs && npx tsx test/test-session-consolidation.mjs && npx tsx test/test-inbox.mjs && npx tsx test/test-session-rpc-dispatch.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",