svamp-cli 0.2.63 → 0.2.66

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.
@@ -148,7 +148,7 @@ async function sessionBroadcast(action, args) {
148
148
  console.log(`Broadcast sent: ${action}`);
149
149
  }
150
150
  async function connectToMachineService() {
151
- const { connectAndGetMachine } = await import('./commands-CEazgqvj.mjs');
151
+ const { connectAndGetMachine } = await import('./commands-Dcb26Zu0.mjs');
152
152
  return connectAndGetMachine();
153
153
  }
154
154
  async function inboxSend(targetSessionId, opts) {
@@ -165,7 +165,7 @@ async function inboxSend(targetSessionId, opts) {
165
165
  }
166
166
  const { server, machine } = await connectToMachineService();
167
167
  try {
168
- const { resolveSessionId } = await import('./commands-CEazgqvj.mjs');
168
+ const { resolveSessionId } = await import('./commands-Dcb26Zu0.mjs');
169
169
  const sessions = await machine.listSessions();
170
170
  const match = resolveSessionId(sessions, targetSessionId);
171
171
  const fullTargetId = match.sessionId;
package/dist/cli.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { s as startDaemon, b as stopDaemon, d as daemonStatus } from './run-DypcS01S.mjs';
1
+ import { s as startDaemon, b as stopDaemon, d as daemonStatus } from './run-Bcz2Dpyc.mjs';
2
2
  import 'os';
3
3
  import 'fs/promises';
4
4
  import 'fs';
@@ -44,7 +44,7 @@ async function main() {
44
44
  console.error(`svamp daemon restart: ${err.message || err}`);
45
45
  process.exit(1);
46
46
  }
47
- const { restartDaemon } = await import('./run-DypcS01S.mjs').then(function (n) { return n.u; });
47
+ const { restartDaemon } = await import('./run-Bcz2Dpyc.mjs').then(function (n) { return n.u; });
48
48
  await restartDaemon();
49
49
  process.exit(0);
50
50
  }
@@ -280,7 +280,7 @@ async function main() {
280
280
  console.error("svamp service: Service commands are not available in sandboxed sessions.");
281
281
  process.exit(1);
282
282
  }
283
- const { handleServiceCommand } = await import('./commands-CY-HbTVN.mjs');
283
+ const { handleServiceCommand } = await import('./commands-BmQQgxLZ.mjs');
284
284
  await handleServiceCommand();
285
285
  } else if (subcommand === "serve") {
286
286
  const { isSandboxed: isSandboxedServe } = await import('./sandboxDetect-DNTcbgWD.mjs');
@@ -288,7 +288,7 @@ async function main() {
288
288
  console.error("svamp serve: Serve commands are not available in sandboxed sessions.");
289
289
  process.exit(1);
290
290
  }
291
- const { handleServeCommand } = await import('./serveCommands-CtAX-CMI.mjs');
291
+ const { handleServeCommand } = await import('./serveCommands-pQMyiqPh.mjs');
292
292
  await handleServeCommand();
293
293
  process.exit(0);
294
294
  } else if (subcommand === "process" || subcommand === "proc") {
@@ -297,7 +297,7 @@ async function main() {
297
297
  console.error("svamp process: Process commands are not available in sandboxed sessions.");
298
298
  process.exit(1);
299
299
  }
300
- const { processCommand } = await import('./commands-BFeHwsR-.mjs');
300
+ const { processCommand } = await import('./commands-C2ePBKc_.mjs');
301
301
  let machineId;
302
302
  const processArgs = args.slice(1);
303
303
  const mIdx = processArgs.findIndex((a) => a === "--machine" || a === "-m");
@@ -315,7 +315,7 @@ async function main() {
315
315
  } else if (!subcommand || subcommand === "start") {
316
316
  await handleInteractiveCommand();
317
317
  } else if (subcommand === "--version" || subcommand === "-v") {
318
- const pkg = await import('./package-QQovcM_B.mjs').catch(() => ({ default: { version: "unknown" } }));
318
+ const pkg = await import('./package-CsXMkPql.mjs').catch(() => ({ default: { version: "unknown" } }));
319
319
  console.log(`svamp version: ${pkg.default.version}`);
320
320
  } else {
321
321
  console.error(`Unknown command: ${subcommand}`);
@@ -324,7 +324,7 @@ async function main() {
324
324
  }
325
325
  }
326
326
  async function handleInteractiveCommand() {
327
- const { runInteractive } = await import('./run-DB2WIjmZ.mjs');
327
+ const { runInteractive } = await import('./run-IqvcJfA9.mjs');
328
328
  const interactiveArgs = subcommand === "start" ? args.slice(1) : args;
329
329
  let directory = process.cwd();
330
330
  let resumeSessionId;
@@ -369,7 +369,7 @@ async function handleAgentCommand() {
369
369
  return;
370
370
  }
371
371
  if (agentArgs[0] === "list") {
372
- const { KNOWN_ACP_AGENTS, KNOWN_MCP_AGENTS: KNOWN_MCP_AGENTS2 } = await import('./run-DypcS01S.mjs').then(function (n) { return n.p; });
372
+ const { KNOWN_ACP_AGENTS, KNOWN_MCP_AGENTS: KNOWN_MCP_AGENTS2 } = await import('./run-Bcz2Dpyc.mjs').then(function (n) { return n.p; });
373
373
  console.log("Known agents:");
374
374
  for (const [name, config2] of Object.entries(KNOWN_ACP_AGENTS)) {
375
375
  console.log(` ${name.padEnd(12)} ${config2.command} ${config2.args.join(" ")} (ACP)`);
@@ -381,7 +381,7 @@ async function handleAgentCommand() {
381
381
  console.log('Use "svamp agent -- <command> [args]" for a custom ACP agent.');
382
382
  return;
383
383
  }
384
- const { resolveAcpAgentConfig, KNOWN_MCP_AGENTS } = await import('./run-DypcS01S.mjs').then(function (n) { return n.p; });
384
+ const { resolveAcpAgentConfig, KNOWN_MCP_AGENTS } = await import('./run-Bcz2Dpyc.mjs').then(function (n) { return n.p; });
385
385
  let cwd = process.cwd();
386
386
  const filteredArgs = [];
387
387
  for (let i = 0; i < agentArgs.length; i++) {
@@ -405,12 +405,12 @@ async function handleAgentCommand() {
405
405
  console.log(`Starting ${config.agentName} agent in ${cwd}...`);
406
406
  let backend;
407
407
  if (KNOWN_MCP_AGENTS[config.agentName]) {
408
- const { CodexMcpBackend } = await import('./run-DypcS01S.mjs').then(function (n) { return n.q; });
408
+ const { CodexMcpBackend } = await import('./run-Bcz2Dpyc.mjs').then(function (n) { return n.q; });
409
409
  backend = new CodexMcpBackend({ cwd, log: logFn });
410
410
  } else {
411
- const { AcpBackend } = await import('./run-DypcS01S.mjs').then(function (n) { return n.o; });
412
- const { GeminiTransport } = await import('./run-DypcS01S.mjs').then(function (n) { return n.G; });
413
- const { DefaultTransport } = await import('./run-DypcS01S.mjs').then(function (n) { return n.D; });
411
+ const { AcpBackend } = await import('./run-Bcz2Dpyc.mjs').then(function (n) { return n.o; });
412
+ const { GeminiTransport } = await import('./run-Bcz2Dpyc.mjs').then(function (n) { return n.G; });
413
+ const { DefaultTransport } = await import('./run-Bcz2Dpyc.mjs').then(function (n) { return n.D; });
414
414
  const transportHandler = config.agentName === "gemini" ? new GeminiTransport() : new DefaultTransport(config.agentName);
415
415
  backend = new AcpBackend({
416
416
  agentName: config.agentName,
@@ -537,7 +537,7 @@ async function handleSessionCommand() {
537
537
  process.exit(1);
538
538
  }
539
539
  }
540
- const { sessionList, sessionSpawn, sessionStop, sessionInfo, sessionMessages, sessionAttach, sessionMachines, sessionSend, sessionWait, sessionShare, sessionRalphStart, sessionRalphCancel, sessionRalphStatus, sessionInboxSend, sessionInboxList, sessionInboxRead, sessionInboxReply, sessionInboxClear } = await import('./commands-CEazgqvj.mjs');
540
+ const { sessionList, sessionSpawn, sessionArchive, sessionResume, sessionDelete, sessionInfo, sessionMessages, sessionAttach, sessionMachines, sessionSend, sessionWait, sessionShare, sessionRalphStart, sessionRalphCancel, sessionRalphStatus, sessionInboxSend, sessionInboxList, sessionInboxRead, sessionInboxReply, sessionInboxClear } = await import('./commands-Dcb26Zu0.mjs');
541
541
  const parseFlagStr = (flag, shortFlag) => {
542
542
  for (let i = 1; i < sessionArgs.length; i++) {
543
543
  if ((sessionArgs[i] === flag || shortFlag) && i + 1 < sessionArgs.length) {
@@ -597,7 +597,7 @@ async function handleSessionCommand() {
597
597
  allowDomain.push(sessionArgs[++i]);
598
598
  }
599
599
  }
600
- const { parseShareArg } = await import('./commands-CEazgqvj.mjs');
600
+ const { parseShareArg } = await import('./commands-Dcb26Zu0.mjs');
601
601
  const shareEntries = share.map((s) => parseShareArg(s));
602
602
  await sessionSpawn(agent, dir, targetMachineId, {
603
603
  message,
@@ -614,12 +614,24 @@ async function handleSessionCommand() {
614
614
  tags: tags.length > 0 ? tags : void 0,
615
615
  parentSessionId
616
616
  });
617
- } else if (sessionSubcommand === "stop") {
617
+ } else if (sessionSubcommand === "archive") {
618
618
  if (!sessionArgs[1]) {
619
- console.error("Usage: svamp session stop <session-id>");
619
+ console.error("Usage: svamp session archive <session-id>");
620
620
  process.exit(1);
621
621
  }
622
- await sessionStop(sessionArgs[1], targetMachineId);
622
+ await sessionArchive(sessionArgs[1], targetMachineId);
623
+ } else if (sessionSubcommand === "resume") {
624
+ if (!sessionArgs[1]) {
625
+ console.error("Usage: svamp session resume <session-id>");
626
+ process.exit(1);
627
+ }
628
+ await sessionResume(sessionArgs[1], targetMachineId);
629
+ } else if (sessionSubcommand === "delete" || sessionSubcommand === "rm") {
630
+ if (!sessionArgs[1]) {
631
+ console.error("Usage: svamp session delete <session-id>");
632
+ process.exit(1);
633
+ }
634
+ await sessionDelete(sessionArgs[1], targetMachineId);
623
635
  } else if (sessionSubcommand === "info") {
624
636
  if (!sessionArgs[1]) {
625
637
  console.error("Usage: svamp session info <session-id>");
@@ -683,7 +695,7 @@ async function handleSessionCommand() {
683
695
  console.error("Usage: svamp session approve <session-id> [request-id] [--json]");
684
696
  process.exit(1);
685
697
  }
686
- const { sessionApprove } = await import('./commands-CEazgqvj.mjs');
698
+ const { sessionApprove } = await import('./commands-Dcb26Zu0.mjs');
687
699
  const approveReqId = sessionArgs[2] && !sessionArgs[2].startsWith("--") ? sessionArgs[2] : void 0;
688
700
  await sessionApprove(sessionArgs[1], approveReqId, targetMachineId, {
689
701
  json: hasFlag("--json")
@@ -693,7 +705,7 @@ async function handleSessionCommand() {
693
705
  console.error("Usage: svamp session deny <session-id> [request-id] [--json]");
694
706
  process.exit(1);
695
707
  }
696
- const { sessionDeny } = await import('./commands-CEazgqvj.mjs');
708
+ const { sessionDeny } = await import('./commands-Dcb26Zu0.mjs');
697
709
  const denyReqId = sessionArgs[2] && !sessionArgs[2].startsWith("--") ? sessionArgs[2] : void 0;
698
710
  await sessionDeny(sessionArgs[1], denyReqId, targetMachineId, {
699
711
  json: hasFlag("--json")
@@ -729,7 +741,7 @@ async function handleSessionCommand() {
729
741
  console.error("Usage: svamp session set-title <title>");
730
742
  process.exit(1);
731
743
  }
732
- const { sessionSetTitle } = await import('./agentCommands-BH6CIqc7.mjs');
744
+ const { sessionSetTitle } = await import('./agentCommands-C8Qd8G_t.mjs');
733
745
  await sessionSetTitle(title);
734
746
  } else if (sessionSubcommand === "set-link") {
735
747
  const url = sessionArgs[1];
@@ -738,7 +750,7 @@ async function handleSessionCommand() {
738
750
  process.exit(1);
739
751
  }
740
752
  const label = sessionArgs[2] && !sessionArgs[2].startsWith("--") ? sessionArgs[2] : void 0;
741
- const { sessionSetLink } = await import('./agentCommands-BH6CIqc7.mjs');
753
+ const { sessionSetLink } = await import('./agentCommands-C8Qd8G_t.mjs');
742
754
  await sessionSetLink(url, label);
743
755
  } else if (sessionSubcommand === "notify") {
744
756
  const message = sessionArgs[1];
@@ -747,7 +759,7 @@ async function handleSessionCommand() {
747
759
  process.exit(1);
748
760
  }
749
761
  const level = parseFlagStr("--level") || "info";
750
- const { sessionNotify } = await import('./agentCommands-BH6CIqc7.mjs');
762
+ const { sessionNotify } = await import('./agentCommands-C8Qd8G_t.mjs');
751
763
  await sessionNotify(message, level);
752
764
  } else if (sessionSubcommand === "broadcast") {
753
765
  const action = sessionArgs[1];
@@ -755,7 +767,7 @@ async function handleSessionCommand() {
755
767
  console.error("Usage: svamp session broadcast <action> [args...]\nActions: open-canvas <url> [label], close-canvas, toast <message>");
756
768
  process.exit(1);
757
769
  }
758
- const { sessionBroadcast } = await import('./agentCommands-BH6CIqc7.mjs');
770
+ const { sessionBroadcast } = await import('./agentCommands-C8Qd8G_t.mjs');
759
771
  await sessionBroadcast(action, sessionArgs.slice(2).filter((a) => !a.startsWith("--")));
760
772
  } else if (sessionSubcommand === "inbox") {
761
773
  const inboxSubcmd = sessionArgs[1];
@@ -766,7 +778,7 @@ async function handleSessionCommand() {
766
778
  process.exit(1);
767
779
  }
768
780
  if (agentSessionId) {
769
- const { inboxSend } = await import('./agentCommands-BH6CIqc7.mjs');
781
+ const { inboxSend } = await import('./agentCommands-C8Qd8G_t.mjs');
770
782
  await inboxSend(sessionArgs[2], {
771
783
  body: sessionArgs[3],
772
784
  subject: parseFlagStr("--subject"),
@@ -781,7 +793,7 @@ async function handleSessionCommand() {
781
793
  }
782
794
  } else if (inboxSubcmd === "list" || inboxSubcmd === "ls") {
783
795
  if (agentSessionId && !sessionArgs[2]) {
784
- const { inboxList } = await import('./agentCommands-BH6CIqc7.mjs');
796
+ const { inboxList } = await import('./agentCommands-C8Qd8G_t.mjs');
785
797
  await inboxList({
786
798
  unread: hasFlag("--unread"),
787
799
  limit: parseFlagInt("--limit"),
@@ -803,7 +815,7 @@ async function handleSessionCommand() {
803
815
  process.exit(1);
804
816
  }
805
817
  if (agentSessionId && !sessionArgs[3]) {
806
- const { inboxList } = await import('./agentCommands-BH6CIqc7.mjs');
818
+ const { inboxList } = await import('./agentCommands-C8Qd8G_t.mjs');
807
819
  await sessionInboxRead(agentSessionId, sessionArgs[2], targetMachineId);
808
820
  } else if (sessionArgs[3]) {
809
821
  await sessionInboxRead(sessionArgs[2], sessionArgs[3], targetMachineId);
@@ -813,7 +825,7 @@ async function handleSessionCommand() {
813
825
  }
814
826
  } else if (inboxSubcmd === "reply") {
815
827
  if (agentSessionId && sessionArgs[2] && sessionArgs[3] && !sessionArgs[4]) {
816
- const { inboxReply } = await import('./agentCommands-BH6CIqc7.mjs');
828
+ const { inboxReply } = await import('./agentCommands-C8Qd8G_t.mjs');
817
829
  await inboxReply(sessionArgs[2], sessionArgs[3]);
818
830
  } else if (sessionArgs[2] && sessionArgs[3] && sessionArgs[4]) {
819
831
  await sessionInboxReply(sessionArgs[2], sessionArgs[3], sessionArgs[4], targetMachineId);
@@ -849,7 +861,7 @@ async function handleMachineCommand() {
849
861
  return;
850
862
  }
851
863
  if (machineSubcommand === "share") {
852
- const { machineShare } = await import('./commands-CEazgqvj.mjs');
864
+ const { machineShare } = await import('./commands-Dcb26Zu0.mjs');
853
865
  let machineId;
854
866
  const shareArgs = [];
855
867
  for (let i = 1; i < machineArgs.length; i++) {
@@ -879,7 +891,7 @@ async function handleMachineCommand() {
879
891
  }
880
892
  await machineShare(machineId, { add, remove, list, configPath, showConfig });
881
893
  } else if (machineSubcommand === "exec") {
882
- const { machineExec } = await import('./commands-CEazgqvj.mjs');
894
+ const { machineExec } = await import('./commands-Dcb26Zu0.mjs');
883
895
  let machineId;
884
896
  let cwd;
885
897
  const cmdParts = [];
@@ -899,7 +911,7 @@ async function handleMachineCommand() {
899
911
  }
900
912
  await machineExec(machineId, command, cwd);
901
913
  } else if (machineSubcommand === "info") {
902
- const { machineInfo } = await import('./commands-CEazgqvj.mjs');
914
+ const { machineInfo } = await import('./commands-Dcb26Zu0.mjs');
903
915
  let machineId;
904
916
  for (let i = 1; i < machineArgs.length; i++) {
905
917
  if ((machineArgs[i] === "--machine" || machineArgs[i] === "-m") && i + 1 < machineArgs.length) {
@@ -919,10 +931,10 @@ async function handleMachineCommand() {
919
931
  level = machineArgs[++i];
920
932
  }
921
933
  }
922
- const { machineNotify } = await import('./agentCommands-BH6CIqc7.mjs');
934
+ const { machineNotify } = await import('./agentCommands-C8Qd8G_t.mjs');
923
935
  await machineNotify(message, level);
924
936
  } else if (machineSubcommand === "ls") {
925
- const { machineLs } = await import('./commands-CEazgqvj.mjs');
937
+ const { machineLs } = await import('./commands-Dcb26Zu0.mjs');
926
938
  let machineId;
927
939
  let showHidden = false;
928
940
  let path;
@@ -1317,7 +1329,9 @@ Commands:
1317
1329
  svamp session messages <id> Show message history (--last N, --json, --raw)
1318
1330
  svamp session info <id> Show session status & pending permissions
1319
1331
  svamp session list List sessions
1320
- svamp session stop <id> Stop a session
1332
+ svamp session archive <id> Archive a session (preserves history, resumable later)
1333
+ svamp session resume <id> Resume an archived session
1334
+ svamp session delete <id> Permanently delete a session (cannot be undone)
1321
1335
  svamp session attach <id> Attach interactive terminal (stdin/stdout)
1322
1336
  svamp session approve/deny <id> Approve or deny pending permission requests
1323
1337
  svamp session --help Show ALL session commands and detailed options
@@ -1389,7 +1403,7 @@ async function applyClaudeAuthFlags(argv) {
1389
1403
  "--use-hypha-proxy, --use-claude-login, and --anthropic-base-url/--anthropic-api-key are mutually exclusive"
1390
1404
  );
1391
1405
  }
1392
- const mod = await import('./run-DypcS01S.mjs').then(function (n) { return n.t; });
1406
+ const mod = await import('./run-Bcz2Dpyc.mjs').then(function (n) { return n.t; });
1393
1407
  if (hasHypha) {
1394
1408
  mod.setClaudeAuthHyphaProxy();
1395
1409
  console.log("Claude auth configured: hypha-proxy (uses HYPHA_TOKEN live at each spawn).");
@@ -1427,7 +1441,7 @@ async function applyDaemonShareFlag(argv) {
1427
1441
  }
1428
1442
  }
1429
1443
  if (collected.length === 0) return;
1430
- const { updateEnvFile } = await import('./run-DypcS01S.mjs').then(function (n) { return n.t; });
1444
+ const { updateEnvFile } = await import('./run-Bcz2Dpyc.mjs').then(function (n) { return n.t; });
1431
1445
  const seen = /* @__PURE__ */ new Set();
1432
1446
  const deduped = collected.filter((e) => {
1433
1447
  const k = e.toLowerCase();
@@ -1440,7 +1454,7 @@ async function applyDaemonShareFlag(argv) {
1440
1454
  }
1441
1455
  async function handleDaemonAuthCommand(argv) {
1442
1456
  const sub = (argv[0] || "status").toLowerCase();
1443
- const mod = await import('./run-DypcS01S.mjs').then(function (n) { return n.t; });
1457
+ const mod = await import('./run-Bcz2Dpyc.mjs').then(function (n) { return n.t; });
1444
1458
  if (sub === "--help" || sub === "-h" || sub === "help") {
1445
1459
  console.log(`
1446
1460
  svamp daemon auth \u2014 Configure how Claude subprocesses authenticate
@@ -1513,7 +1527,8 @@ QUICK START \u2014 Spawn a session, give it a task, get results:
1513
1527
  # The command prints the session ID (e.g., "abc12345-..."). Use it to:
1514
1528
  svamp session messages abc1 --last 10 # read output (prefix match on ID)
1515
1529
  svamp session send abc1 "now run lint" --wait # send follow-up, wait for done
1516
- svamp session stop abc1 # stop when finished
1530
+ svamp session archive abc1 # archive when finished (resumable)
1531
+ svamp session resume abc1 # bring an archived session back
1517
1532
 
1518
1533
  # Spawn on a remote/cloud machine:
1519
1534
  svamp session spawn claude -d /workspace -m cloud-box --message "deploy" --wait
@@ -1530,7 +1545,9 @@ COMMANDS:
1530
1545
 
1531
1546
  Lifecycle:
1532
1547
  spawn <agent> [-d <path>] [options] Spawn a new agent session
1533
- stop <id> Stop a running session
1548
+ archive <id> Archive a session (resumable; preserves --resume token)
1549
+ resume <id> Resume an archived session (spawns agent with --resume)
1550
+ delete <id> Permanently delete a session (cannot be undone)
1534
1551
  list [--active] [--json] List sessions (alias: ls)
1535
1552
  machines List discoverable machines
1536
1553
  info <id> [--json] Show status & pending permissions
@@ -68,7 +68,7 @@ async function serviceExpose(args) {
68
68
  });
69
69
  return;
70
70
  }
71
- const { connectAndGetMachine } = await import('./commands-CEazgqvj.mjs');
71
+ const { connectAndGetMachine } = await import('./commands-Dcb26Zu0.mjs');
72
72
  const { server, machine } = await connectAndGetMachine();
73
73
  try {
74
74
  const status = await machine.tunnelStart({
@@ -132,7 +132,7 @@ async function serviceServe(args) {
132
132
  }
133
133
  async function serviceList(_args) {
134
134
  try {
135
- const { connectAndGetMachine } = await import('./commands-CEazgqvj.mjs');
135
+ const { connectAndGetMachine } = await import('./commands-Dcb26Zu0.mjs');
136
136
  const { server, machine } = await connectAndGetMachine();
137
137
  try {
138
138
  const tunnels = await machine.tunnelList({});
@@ -161,7 +161,7 @@ async function serviceDelete(args) {
161
161
  process.exit(1);
162
162
  }
163
163
  try {
164
- const { connectAndGetMachine } = await import('./commands-CEazgqvj.mjs');
164
+ const { connectAndGetMachine } = await import('./commands-Dcb26Zu0.mjs');
165
165
  const { server, machine } = await connectAndGetMachine();
166
166
  try {
167
167
  await machine.tunnelStop({ name });
@@ -1,11 +1,11 @@
1
1
  import { writeFileSync, readFileSync } from 'fs';
2
2
  import { resolve } from 'path';
3
- import { connectAndGetMachine } from './commands-CEazgqvj.mjs';
3
+ import { connectAndGetMachine } from './commands-Dcb26Zu0.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-DypcS01S.mjs';
8
+ import './run-Bcz2Dpyc.mjs';
9
9
  import 'os';
10
10
  import 'fs/promises';
11
11
  import 'url';
@@ -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 { n as normalizeAllowedUser, l as loadSecurityContextConfig, e as resolveSecurityContext, f as buildSecurityContextFromFlags, m as mergeSecurityContexts, c as connectToHypha, i as buildSessionShareUrl, j as buildMachineShareUrl } from './run-DypcS01S.mjs';
5
+ import { n as normalizeAllowedUser, l as loadSecurityContextConfig, e as resolveSecurityContext, f as buildSecurityContextFromFlags, m as mergeSecurityContexts, c as connectToHypha, i as buildSessionShareUrl, j as buildMachineShareUrl } from './run-Bcz2Dpyc.mjs';
6
6
  import 'os';
7
7
  import 'fs/promises';
8
8
  import 'fs';
@@ -83,7 +83,7 @@ const SESSION_RPC_PARAMS = {
83
83
  permissionResponse: ["params"],
84
84
  switchMode: ["mode"],
85
85
  restartClaude: [],
86
- killSession: [],
86
+ archiveSession: [],
87
87
  keepAlive: ["thinking", "mode"],
88
88
  sessionEnd: [],
89
89
  getActivityState: [],
@@ -1033,14 +1033,42 @@ async function sessionSpawn(agent, directory, machineId, opts) {
1033
1033
  await server.disconnect();
1034
1034
  }
1035
1035
  }
1036
- async function sessionStop(sessionId, machineId) {
1036
+ async function sessionArchive(sessionId, machineId) {
1037
1037
  const { server, machine, fullId } = await connectAndResolveSession(sessionId, machineId);
1038
1038
  try {
1039
- const success = await machine.stopSession(fullId);
1039
+ const success = await machine.archiveSession(fullId);
1040
1040
  if (success) {
1041
- console.log(`Session ${fullId.slice(0, 8)} stopped.`);
1041
+ console.log(`Session ${fullId.slice(0, 8)} archived. Run \`svamp session resume ${fullId.slice(0, 8)}\` to bring it back.`);
1042
1042
  } else {
1043
- console.error("Failed to stop session (not found on daemon).");
1043
+ console.error("Failed to archive session (not found on daemon).");
1044
+ process.exit(1);
1045
+ }
1046
+ } finally {
1047
+ await server.disconnect();
1048
+ }
1049
+ }
1050
+ async function sessionResume(sessionId, machineId) {
1051
+ const { server, machine, fullId } = await connectAndResolveSession(sessionId, machineId);
1052
+ try {
1053
+ const result = await machine.resumeSession(fullId);
1054
+ if (result?.success) {
1055
+ console.log(`Session ${fullId.slice(0, 8)} resumed.`);
1056
+ } else {
1057
+ console.error(`Failed to resume session: ${result?.message || "unknown error"}`);
1058
+ process.exit(1);
1059
+ }
1060
+ } finally {
1061
+ await server.disconnect();
1062
+ }
1063
+ }
1064
+ async function sessionDelete(sessionId, machineId) {
1065
+ const { server, machine, fullId } = await connectAndResolveSession(sessionId, machineId);
1066
+ try {
1067
+ const success = await machine.deleteSession(fullId);
1068
+ if (success) {
1069
+ console.log(`Session ${fullId.slice(0, 8)} deleted.`);
1070
+ } else {
1071
+ console.error("Failed to delete session.");
1044
1072
  process.exit(1);
1045
1073
  }
1046
1074
  } finally {
@@ -1284,12 +1312,12 @@ async function sessionAttach(sessionId, machineId) {
1284
1312
  process.stdout.write("> ");
1285
1313
  return;
1286
1314
  }
1287
- if (trimmed === "/kill") {
1315
+ if (trimmed === "/archive") {
1288
1316
  try {
1289
- await svc.killSession();
1290
- console.log("Session killed.");
1317
+ await svc.archiveSession();
1318
+ console.log("Session archived. Run `svamp session resume <id>` to bring it back.");
1291
1319
  } catch (err) {
1292
- console.error(`Kill failed: ${err.message}`);
1320
+ console.error(`Archive failed: ${err.message}`);
1293
1321
  }
1294
1322
  rl.close();
1295
1323
  await server.disconnect();
@@ -1896,4 +1924,4 @@ async function sessionInboxClear(sessionIdPartial, machineId, opts) {
1896
1924
  }
1897
1925
  }
1898
1926
 
1899
- export { connectAndGetMachine, connectAndResolveSession, createWorktree, generateWorktreeName, machineExec, machineInfo, machineLs, machineShare, parseShareArg, renderMessage, resolveSessionId, sessionApprove, sessionAttach, sessionDeny, sessionInboxClear, sessionInboxList, sessionInboxRead, sessionInboxReply, sessionInboxSend, sessionInfo, sessionList, sessionMachines, sessionMessages, sessionRalphCancel, sessionRalphStart, sessionRalphStatus, sessionSend, sessionShare, sessionSpawn, sessionStop, sessionWait };
1927
+ export { connectAndGetMachine, connectAndResolveSession, createWorktree, generateWorktreeName, machineExec, machineInfo, machineLs, machineShare, parseShareArg, renderMessage, resolveSessionId, sessionApprove, sessionArchive, sessionAttach, sessionDelete, sessionDeny, sessionInboxClear, sessionInboxList, sessionInboxRead, sessionInboxReply, sessionInboxSend, sessionInfo, sessionList, sessionMachines, sessionMessages, sessionRalphCancel, sessionRalphStart, sessionRalphStatus, sessionResume, sessionSend, sessionShare, sessionSpawn, sessionWait };
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-DypcS01S.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-Bcz2Dpyc.mjs';
2
2
  import 'os';
3
3
  import 'fs/promises';
4
4
  import 'fs';
@@ -0,0 +1,64 @@
1
+ var name = "svamp-cli";
2
+ var version = "0.2.66";
3
+ var description = "Svamp CLI — AI workspace daemon on Hypha Cloud";
4
+ var author = "Amun AI AB";
5
+ var license = "SEE LICENSE IN LICENSE";
6
+ var type = "module";
7
+ var bin = {
8
+ svamp: "./bin/svamp.mjs"
9
+ };
10
+ var files = [
11
+ "dist",
12
+ "bin"
13
+ ];
14
+ var main = "./dist/index.mjs";
15
+ var exports$1 = {
16
+ ".": "./dist/index.mjs",
17
+ "./cli": "./dist/cli.mjs"
18
+ };
19
+ var scripts = {
20
+ build: "rm -rf dist bin/skills && mkdir -p bin/skills && cp -r ../../skills/artifact bin/skills/artifact && tsc --noEmit && pkgroll",
21
+ typecheck: "tsc --noEmit",
22
+ test: "npx tsx test/test-context-window.mjs && npx tsx test/test-authorize.mjs && npx tsx test/test-normalize-allowed-user.mjs && npx tsx test/test-share-url.mjs && npx tsx test/test-update-sharing-normalization.mjs && npx tsx test/test-staged-homes-sweep.mjs && npx tsx test/test-session-helpers.mjs && npx tsx test/test-cli-routing.mjs && npx tsx test/test-security-context.mjs && npx tsx test/test-isolation-decision.mjs && npx tsx test/test-ralph-loop.mjs && npx tsx test/test-message-helpers.mjs && npx tsx test/test-agent-config.mjs && npx tsx test/test-wrap-command.mjs && npx tsx test/test-credential-staging.mjs && npx tsx test/test-claude-auth.mjs && npx tsx test/test-output-formatters.mjs && npx tsx test/test-agent-types.mjs && npx tsx test/test-transport.mjs && npx tsx test/test-session-update-handlers.mjs && npx tsx test/test-session-scanner.mjs && npx tsx test/test-hypha-client.mjs && npx tsx test/test-hook-settings.mjs && npx tsx test/test-session-service-logic.mjs && npx tsx test/test-daemon-persistence.mjs && npx tsx test/test-detect-isolation.mjs && npx tsx test/test-machine-service-logic.mjs && npx tsx test/test-interactive-helpers.mjs && npx tsx test/test-codex-backend.mjs && npx tsx test/test-acp-backend.mjs && npx tsx test/test-acp-bridge.mjs && npx tsx test/test-hook-server.mjs && npx tsx test/test-session-commands.mjs && npx tsx test/test-interactive-console.mjs && npx tsx test/test-session-messages.mjs && npx tsx test/test-skills.mjs && npx tsx test/test-agent-grouping.mjs && npx tsx test/test-ralph-loop-integration.mjs && npx tsx test/test-ralph-loop-modes.mjs && npx tsx test/test-machine-list-directory.mjs && npx tsx test/test-service-commands.mjs && npx tsx test/test-supervisor.mjs && npx tsx test/test-supervisor-lock.mjs && npx tsx test/test-clear-detection.mjs && npx tsx test/test-session-consolidation.mjs && npx tsx test/test-inbox.mjs && npx tsx test/test-session-rpc-dispatch.mjs && npx tsx test/test-sandbox-cli.mjs && npx tsx test/test-serve-manager.mjs && npx tsx test/test-serve-stability.mjs && npx tsx test/test-frpc-e2e.mjs --unit-only",
23
+ "test:hypha": "node --no-warnings test/test-hypha-service.mjs",
24
+ dev: "tsx src/cli.ts",
25
+ "dev:daemon": "tsx src/cli.ts daemon start-sync",
26
+ "test:e2e": "node --no-warnings test/e2e-session-tests.mjs",
27
+ "test:archive-resume": "node --no-warnings test/test-session-archive-resume.mjs",
28
+ "test:frpc": "npx tsx test/test-frpc-e2e.mjs"
29
+ };
30
+ var dependencies = {
31
+ "@agentclientprotocol/sdk": "^0.14.1",
32
+ "@modelcontextprotocol/sdk": "^1.25.3",
33
+ "hypha-rpc": "0.21.40",
34
+ "node-pty": "1.2.0-beta.11",
35
+ ws: "^8.18.0",
36
+ yaml: "^2.8.2",
37
+ zod: "^3.24.4"
38
+ };
39
+ var devDependencies = {
40
+ "@types/node": ">=20",
41
+ "@types/ws": "^8.5.14",
42
+ pkgroll: "^2.14.2",
43
+ tsx: "^4.20.6",
44
+ typescript: "5.9.3"
45
+ };
46
+ var packageManager = "yarn@1.22.22";
47
+ var _package = {
48
+ name: name,
49
+ version: version,
50
+ description: description,
51
+ author: author,
52
+ license: license,
53
+ type: type,
54
+ bin: bin,
55
+ files: files,
56
+ main: main,
57
+ exports: exports$1,
58
+ scripts: scripts,
59
+ dependencies: dependencies,
60
+ devDependencies: devDependencies,
61
+ packageManager: packageManager
62
+ };
63
+
64
+ export { author, bin, _package as default, dependencies, description, devDependencies, exports$1 as exports, files, license, main, name, packageManager, scripts, type, version };
@@ -754,12 +754,36 @@ async function registerMachineService(server, machineId, metadata, daemonState,
754
754
  }
755
755
  return result;
756
756
  },
757
- // Stop a session
758
- stopSession: async (sessionId, context) => {
757
+ // Archive a session (non-destructive — preserves claudeResumeId for resume)
758
+ archiveSession: async (sessionId, context) => {
759
759
  authorizeRequest(context, currentMetadata.sharing, "admin");
760
- const result = handlers.stopSession(sessionId);
760
+ const result = handlers.archiveSession(sessionId);
761
761
  notifyListeners({
762
- type: "session-stopped",
762
+ type: "session-archived",
763
+ sessionId,
764
+ machineId
765
+ });
766
+ return result;
767
+ },
768
+ // Resume an archived session (spawns the agent with --resume <claudeResumeId>)
769
+ resumeSession: async (sessionId, context) => {
770
+ authorizeRequest(context, currentMetadata.sharing, "admin");
771
+ const result = await handlers.resumeSession(sessionId);
772
+ if (result.success) {
773
+ notifyListeners({
774
+ type: "session-resumed",
775
+ sessionId,
776
+ machineId
777
+ });
778
+ }
779
+ return result;
780
+ },
781
+ // Permanently delete a session (wipes session.json + messages.jsonl + .svamp/{id}/)
782
+ deleteSession: async (sessionId, context) => {
783
+ authorizeRequest(context, currentMetadata.sharing, "admin");
784
+ const result = handlers.deleteSession(sessionId);
785
+ notifyListeners({
786
+ type: "session-deleted",
763
787
  sessionId,
764
788
  machineId
765
789
  });
@@ -1960,9 +1984,9 @@ function createSessionStore(server, sessionId, initialMetadata, initialAgentStat
1960
1984
  authorizeRequest(context, metadata.sharing, "admin");
1961
1985
  return await callbacks.onRestartClaude();
1962
1986
  },
1963
- killSession: async (context) => {
1987
+ archiveSession: async (context) => {
1964
1988
  authorizeRequest(context, metadata.sharing, "admin");
1965
- callbacks.onKillSession();
1989
+ callbacks.onArchiveSession();
1966
1990
  return { success: true };
1967
1991
  },
1968
1992
  // ── Activity ──
@@ -6405,6 +6429,71 @@ You may be running in parallel with other agents \u2014 possibly sharing the sam
6405
6429
  `;
6406
6430
  }
6407
6431
 
6432
+ const STANDARD_WINDOWS = [2e5, 1e6];
6433
+ function readWindow(entry) {
6434
+ if (!entry) return 0;
6435
+ const cw = entry.contextWindow ?? entry.context_window;
6436
+ return typeof cw === "number" && cw > 0 && Number.isFinite(cw) ? cw : 0;
6437
+ }
6438
+ function computeObservedContext(usage) {
6439
+ if (!usage) return 0;
6440
+ return (usage.input_tokens || 0) + (usage.cache_creation_input_tokens || 0) + (usage.cache_read_input_tokens || 0);
6441
+ }
6442
+ function inferWindowFromModelName(model) {
6443
+ if (!model) return 0;
6444
+ if (/\[1m\]/i.test(model)) return 1e6;
6445
+ if (/opus-?4-?[7-9]/i.test(model)) return 1e6;
6446
+ if (/opus-?[5-9]/i.test(model)) return 1e6;
6447
+ if (/sonnet-?4-?[5-9]/i.test(model)) return 1e6;
6448
+ if (/sonnet-?[5-9]/i.test(model)) return 1e6;
6449
+ if (/opus|sonnet/i.test(model)) return 2e5;
6450
+ if (/haiku/i.test(model)) return 2e5;
6451
+ return 0;
6452
+ }
6453
+ function matchedMainModel(modelUsage, mainModel) {
6454
+ if (!modelUsage || !mainModel) return { window: 0, matched: false };
6455
+ const variants = [
6456
+ mainModel,
6457
+ `${mainModel}[1m]`,
6458
+ mainModel.replace(/\[1m\]$/i, "")
6459
+ ];
6460
+ for (const k of variants) {
6461
+ const cw = readWindow(modelUsage[k]);
6462
+ if (cw > 0) return { window: cw, matched: true };
6463
+ }
6464
+ return { window: 0, matched: false };
6465
+ }
6466
+ function maxAcrossModelUsage(modelUsage) {
6467
+ if (!modelUsage) return 0;
6468
+ let best = 0;
6469
+ for (const v of Object.values(modelUsage)) {
6470
+ const cw = readWindow(v);
6471
+ if (cw > best) best = cw;
6472
+ }
6473
+ return best;
6474
+ }
6475
+ function selfHealForObserved(candidate, observed) {
6476
+ if (observed <= candidate) return candidate;
6477
+ const next = STANDARD_WINDOWS.find((w) => w >= observed);
6478
+ if (next) return Math.max(candidate, next);
6479
+ return Math.max(candidate, Math.ceil(observed * 1.25));
6480
+ }
6481
+ function resolveContextWindow(opts) {
6482
+ const { modelUsage, usage, mainModel, currentWindow } = opts;
6483
+ const observed = computeObservedContext(usage);
6484
+ const main = matchedMainModel(modelUsage, mainModel);
6485
+ let candidate = main.window;
6486
+ const definitiveMatch = main.matched;
6487
+ if (!candidate) candidate = maxAcrossModelUsage(modelUsage);
6488
+ if (!candidate) candidate = inferWindowFromModelName(mainModel);
6489
+ candidate = selfHealForObserved(candidate, observed);
6490
+ const current = typeof currentWindow === "number" && currentWindow > 0 ? currentWindow : 0;
6491
+ if (current > 0 && candidate > 0 && candidate < current && !definitiveMatch) {
6492
+ candidate = current;
6493
+ }
6494
+ return candidate;
6495
+ }
6496
+
6408
6497
  const SVAMP_HOME$1 = process.env.SVAMP_HOME || join$1(os.homedir(), ".svamp");
6409
6498
  function generateHookSettings(portOrOptions = {}) {
6410
6499
  const opts = typeof portOrOptions === "number" ? { sessionStartPort: portOrOptions } : portOrOptions;
@@ -7389,6 +7478,43 @@ function deletePersistedSession(sessionId) {
7389
7478
  saveSessionIndex(index);
7390
7479
  }
7391
7480
  }
7481
+ function markSessionAsArchived(sessionId) {
7482
+ const index = loadSessionIndex();
7483
+ const entry = index[sessionId];
7484
+ if (!entry) return false;
7485
+ const filePath = getSessionFilePath(entry.directory, sessionId);
7486
+ if (!existsSync$1(filePath)) return false;
7487
+ try {
7488
+ const data = JSON.parse(readFileSync$1(filePath, "utf-8"));
7489
+ if (data.stopped === true) return true;
7490
+ data.stopped = true;
7491
+ const tmpPath = filePath + ".tmp";
7492
+ writeFileSync(tmpPath, JSON.stringify(data, null, 2), "utf-8");
7493
+ renameSync(tmpPath, filePath);
7494
+ return true;
7495
+ } catch {
7496
+ return false;
7497
+ }
7498
+ }
7499
+ function clearSessionArchivedFlag(sessionId) {
7500
+ const index = loadSessionIndex();
7501
+ const entry = index[sessionId];
7502
+ if (!entry) return null;
7503
+ const filePath = getSessionFilePath(entry.directory, sessionId);
7504
+ if (!existsSync$1(filePath)) return null;
7505
+ try {
7506
+ const data = JSON.parse(readFileSync$1(filePath, "utf-8"));
7507
+ if (data.stopped) {
7508
+ delete data.stopped;
7509
+ const tmpPath = filePath + ".tmp";
7510
+ writeFileSync(tmpPath, JSON.stringify(data, null, 2), "utf-8");
7511
+ renameSync(tmpPath, filePath);
7512
+ }
7513
+ return data;
7514
+ } catch {
7515
+ return null;
7516
+ }
7517
+ }
7392
7518
  function loadPersistedSessions() {
7393
7519
  const sessions = [];
7394
7520
  const index = loadSessionIndex();
@@ -7690,7 +7816,7 @@ async function startDaemon(options) {
7690
7816
  const list = loadExposedTunnels().filter((t) => t.name !== name);
7691
7817
  saveExposedTunnels(list);
7692
7818
  }
7693
- const { ServeManager } = await import('./serveManager-G9PiLNKm.mjs');
7819
+ const { ServeManager } = await import('./serveManager-DhJ3TJ2a.mjs');
7694
7820
  const serveManager = new ServeManager(SVAMP_HOME, (msg) => logger.log(`[SERVE] ${msg}`), hyphaServerUrl);
7695
7821
  ensureAutoInstalledSkills(logger).catch(() => {
7696
7822
  });
@@ -7894,6 +8020,7 @@ async function startDaemon(options) {
7894
8020
  let lastSpawnMeta = persisted?.spawnMeta || {};
7895
8021
  let sessionWasProcessing = !!options2.wasProcessing;
7896
8022
  let lastAssistantText = "";
8023
+ let lastMainModel;
7897
8024
  let consecutiveRalphErrors = 0;
7898
8025
  const MAX_RALPH_ERRORS = 3;
7899
8026
  let spawnHasReceivedInit = false;
@@ -8221,6 +8348,12 @@ async function startDaemon(options) {
8221
8348
  "event"
8222
8349
  );
8223
8350
  }
8351
+ if (msg.type === "assistant") {
8352
+ const assistantModel = msg.message?.model;
8353
+ if (typeof assistantModel === "string" && assistantModel.length > 0) {
8354
+ lastMainModel = assistantModel;
8355
+ }
8356
+ }
8224
8357
  const assistantContent = msg.type === "assistant" ? msg.message?.content ?? msg.content : void 0;
8225
8358
  if (Array.isArray(assistantContent)) {
8226
8359
  for (const block of assistantContent) {
@@ -8324,15 +8457,15 @@ async function startDaemon(options) {
8324
8457
  }
8325
8458
  signalProcessing(false);
8326
8459
  sessionWasProcessing = false;
8327
- if (msg.modelUsage && typeof msg.modelUsage === "object") {
8328
- const modelKeys = Object.keys(msg.modelUsage);
8329
- if (modelKeys.length > 0) {
8330
- const firstModel = msg.modelUsage[modelKeys[0]];
8331
- if (firstModel?.contextWindow && firstModel.contextWindow !== sessionMetadata.contextWindow) {
8332
- sessionMetadata = { ...sessionMetadata, contextWindow: firstModel.contextWindow };
8333
- sessionService.updateMetadata(sessionMetadata);
8334
- }
8335
- }
8460
+ const resolvedWindow = resolveContextWindow({
8461
+ modelUsage: msg.modelUsage,
8462
+ usage: msg.usage,
8463
+ mainModel: lastMainModel,
8464
+ currentWindow: sessionMetadata.contextWindow
8465
+ });
8466
+ if (resolvedWindow > 0 && resolvedWindow !== sessionMetadata.contextWindow) {
8467
+ sessionMetadata = { ...sessionMetadata, contextWindow: resolvedWindow };
8468
+ sessionService.updateMetadata(sessionMetadata);
8336
8469
  }
8337
8470
  if (claudeResumeId && !trackedSession.stopped) {
8338
8471
  saveSession({
@@ -8557,6 +8690,9 @@ The automated loop has finished. Review the progress above and let me know if yo
8557
8690
  if (msg.slash_commands && Array.isArray(msg.slash_commands)) {
8558
8691
  sessionMetadata = { ...sessionMetadata, slashCommands: msg.slash_commands };
8559
8692
  }
8693
+ if (typeof msg.model === "string" && msg.model.length > 0) {
8694
+ lastMainModel = msg.model;
8695
+ }
8560
8696
  if (msg.session_id) {
8561
8697
  const isResumeFailure = !spawnHasReceivedInit && claudeResumeId && msg.session_id !== claudeResumeId;
8562
8698
  const isConversationClear = spawnHasReceivedInit && claudeResumeId && msg.session_id !== claudeResumeId;
@@ -9036,9 +9172,9 @@ The automated loop has finished. Review the progress above and let me know if yo
9036
9172
  lastSpawnMeta = { ...lastSpawnMeta, appendSystemPrompt: prompt };
9037
9173
  return await restartClaudeHandler();
9038
9174
  },
9039
- onKillSession: () => {
9040
- logger.log(`[Session ${sessionId}] Kill session requested`);
9041
- stopSession(sessionId);
9175
+ onArchiveSession: () => {
9176
+ logger.log(`[Session ${sessionId}] Archive session requested`);
9177
+ archiveSession(sessionId);
9042
9178
  },
9043
9179
  onInboxMessage: (message) => {
9044
9180
  if (trackedSession?.stopped) return;
@@ -9507,9 +9643,9 @@ The automated loop has finished. Review the progress above and let me know if yo
9507
9643
  onApplySystemPrompt: async () => {
9508
9644
  return { success: false, message: "System prompt updates with restart are not yet supported for this agent type." };
9509
9645
  },
9510
- onKillSession: () => {
9511
- logger.log(`[${agentName} Session ${sessionId}] Kill session requested`);
9512
- stopSession(sessionId);
9646
+ onArchiveSession: () => {
9647
+ logger.log(`[${agentName} Session ${sessionId}] Archive session requested`);
9648
+ archiveSession(sessionId);
9513
9649
  },
9514
9650
  onInboxMessage: (message) => {
9515
9651
  if (acpStopped) return;
@@ -9965,7 +10101,7 @@ The automated loop has finished. Review the progress above and let me know if yo
9965
10101
  "event"
9966
10102
  );
9967
10103
  sessionService.sendSessionEnd();
9968
- stopSession(sessionId);
10104
+ deleteSession(sessionId);
9969
10105
  });
9970
10106
  return {
9971
10107
  type: "success",
@@ -9980,8 +10116,7 @@ The automated loop has finished. Review the progress above and let me know if yo
9980
10116
  };
9981
10117
  }
9982
10118
  };
9983
- const stopSession = (sessionId) => {
9984
- logger.log(`Stopping session: ${sessionId}`);
10119
+ const teardownTrackedSession = (sessionId) => {
9985
10120
  for (const [pid, session] of pidToTrackedSession) {
9986
10121
  if (session.svampSessionId === sessionId) {
9987
10122
  session.stopped = true;
@@ -10000,16 +10135,64 @@ The automated loop has finished. Review the progress above and let me know if yo
10000
10135
  session.cleanupSvampConfig?.();
10001
10136
  artifactSync.cancelSync(sessionId);
10002
10137
  pidToTrackedSession.delete(pid);
10003
- deletePersistedSession(sessionId);
10004
- logger.log(`Session ${sessionId} stopped`);
10005
10138
  return true;
10006
10139
  }
10007
10140
  }
10008
10141
  artifactSync.cancelSync(sessionId);
10009
- deletePersistedSession(sessionId);
10010
- logger.log(`Session ${sessionId} not found in memory, cleaned up persisted state`);
10011
10142
  return false;
10012
10143
  };
10144
+ const archiveSession = (sessionId) => {
10145
+ logger.log(`Archiving session: ${sessionId}`);
10146
+ const wasInMemory = teardownTrackedSession(sessionId);
10147
+ const markedArchived = markSessionAsArchived(sessionId);
10148
+ if (wasInMemory || markedArchived) {
10149
+ logger.log(`Session ${sessionId} archived (inMemory=${wasInMemory}, persisted=${markedArchived})`);
10150
+ return true;
10151
+ }
10152
+ logger.log(`Session ${sessionId} not found in memory or on disk; nothing to archive`);
10153
+ return false;
10154
+ };
10155
+ const resumeSession = async (sessionId) => {
10156
+ logger.log(`Resuming session: ${sessionId}`);
10157
+ for (const session of pidToTrackedSession.values()) {
10158
+ if (session.svampSessionId === sessionId && !session.stopped) {
10159
+ logger.log(`Session ${sessionId} already running \u2014 resume is a no-op`);
10160
+ return { success: true, sessionId, message: "Session is already running" };
10161
+ }
10162
+ }
10163
+ const persisted = clearSessionArchivedFlag(sessionId);
10164
+ if (!persisted) {
10165
+ return { success: false, message: `Session ${sessionId} has no persisted record to resume` };
10166
+ }
10167
+ try {
10168
+ const result = await spawnSession({
10169
+ directory: persisted.directory,
10170
+ sessionId: persisted.sessionId,
10171
+ resumeSessionId: persisted.claudeResumeId,
10172
+ sharing: persisted.metadata?.sharing,
10173
+ securityContext: persisted.metadata?.securityContext,
10174
+ forceIsolation: !!persisted.metadata?.isolationMethod,
10175
+ parentSessionId: persisted.metadata?.parentSessionId,
10176
+ permissionMode: persisted.permissionMode
10177
+ });
10178
+ if (result.type === "success") {
10179
+ logger.log(`Resumed session ${sessionId} (claudeResumeId=${persisted.claudeResumeId || "none"})`);
10180
+ return { success: true, sessionId: result.sessionId };
10181
+ }
10182
+ markSessionAsArchived(sessionId);
10183
+ return { success: false, message: result.errorMessage || `spawnSession returned ${result.type}` };
10184
+ } catch (err) {
10185
+ markSessionAsArchived(sessionId);
10186
+ return { success: false, message: err.message };
10187
+ }
10188
+ };
10189
+ const deleteSession = (sessionId) => {
10190
+ logger.log(`Deleting session: ${sessionId}`);
10191
+ teardownTrackedSession(sessionId);
10192
+ deletePersistedSession(sessionId);
10193
+ logger.log(`Session ${sessionId} deleted`);
10194
+ return true;
10195
+ };
10013
10196
  const restartSession = async (sessionId) => {
10014
10197
  for (const session of pidToTrackedSession.values()) {
10015
10198
  if (session.svampSessionId === sessionId && !session.stopped) {
@@ -10087,7 +10270,9 @@ The automated loop has finished. Review the progress above and let me know if yo
10087
10270
  initialDaemonState,
10088
10271
  {
10089
10272
  spawnSession,
10090
- stopSession,
10273
+ archiveSession,
10274
+ resumeSession,
10275
+ deleteSession,
10091
10276
  restartSession,
10092
10277
  requestShutdown: () => {
10093
10278
  logger.log("Shutdown requested via hypha-app (ignored \u2014 daemon never self-terminates)");
@@ -10113,7 +10298,7 @@ The automated loop has finished. Review the progress above and let me know if yo
10113
10298
  getSessionPid: (sessionId) => {
10114
10299
  for (const [, session] of pidToTrackedSession) {
10115
10300
  if (session.svampSessionId === sessionId && !session.stopped) {
10116
- return session.childProcess?.pid;
10301
+ return session.pid;
10117
10302
  }
10118
10303
  }
10119
10304
  return void 0;
@@ -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 { resolve, join } from 'node:path';
4
4
  import { existsSync, readFileSync, watch } from 'node:fs';
5
- import { c as connectToHypha, a as registerSessionService, k as generateHookSettings } from './run-DypcS01S.mjs';
5
+ import { c as connectToHypha, a as registerSessionService, k as generateHookSettings } from './run-Bcz2Dpyc.mjs';
6
6
  import { createServer } from 'node:http';
7
7
  import { spawn } from 'node:child_process';
8
8
  import { createInterface } from 'node:readline';
@@ -684,8 +684,8 @@ async function runInteractive(options) {
684
684
  log("[hypha] Restart requested");
685
685
  return { success: false, message: "Restart not supported in interactive mode" };
686
686
  },
687
- onKillSession: async () => {
688
- log("[hypha] Kill requested");
687
+ onArchiveSession: async () => {
688
+ log("[hypha] Archive requested");
689
689
  await cleanup();
690
690
  process.exit(0);
691
691
  },
@@ -54,7 +54,7 @@ async function handleServeCommand() {
54
54
  }
55
55
  }
56
56
  async function serveAdd(args, machineId) {
57
- const { connectAndGetMachine } = await import('./commands-CEazgqvj.mjs');
57
+ const { connectAndGetMachine } = await import('./commands-Dcb26Zu0.mjs');
58
58
  const pos = positionalArgs(args);
59
59
  const name = pos[0];
60
60
  if (!name) {
@@ -93,7 +93,7 @@ async function serveAdd(args, machineId) {
93
93
  }
94
94
  }
95
95
  async function serveApply(args, machineId) {
96
- const { connectAndGetMachine } = await import('./commands-CEazgqvj.mjs');
96
+ const { connectAndGetMachine } = await import('./commands-Dcb26Zu0.mjs');
97
97
  const fs = await import('fs');
98
98
  const yaml = await import('yaml');
99
99
  const file = positionalArgs(args)[0];
@@ -182,7 +182,7 @@ async function serveApply(args, machineId) {
182
182
  }
183
183
  }
184
184
  async function serveRemove(args, machineId) {
185
- const { connectAndGetMachine } = await import('./commands-CEazgqvj.mjs');
185
+ const { connectAndGetMachine } = await import('./commands-Dcb26Zu0.mjs');
186
186
  const pos = positionalArgs(args);
187
187
  const name = pos[0];
188
188
  if (!name) {
@@ -202,7 +202,7 @@ async function serveRemove(args, machineId) {
202
202
  }
203
203
  }
204
204
  async function serveList(args, machineId) {
205
- const { connectAndGetMachine } = await import('./commands-CEazgqvj.mjs');
205
+ const { connectAndGetMachine } = await import('./commands-Dcb26Zu0.mjs');
206
206
  const all = hasFlag(args, "--all", "-a");
207
207
  const json = hasFlag(args, "--json");
208
208
  const sessionId = getFlag(args, "--session");
@@ -235,7 +235,7 @@ async function serveList(args, machineId) {
235
235
  }
236
236
  }
237
237
  async function serveInfo(machineId) {
238
- const { connectAndGetMachine } = await import('./commands-CEazgqvj.mjs');
238
+ const { connectAndGetMachine } = await import('./commands-Dcb26Zu0.mjs');
239
239
  const { machine, server } = await connectAndGetMachine(machineId);
240
240
  try {
241
241
  const info = await machine.serveInfo();
@@ -4,7 +4,7 @@ import * as fs from 'fs';
4
4
  import * as http from 'http';
5
5
  import * as net from 'net';
6
6
  import * as path from 'path';
7
- import { S as ServeAuth, h as hasCookieToken } from './run-DypcS01S.mjs';
7
+ import { S as ServeAuth, h as hasCookieToken } from './run-Bcz2Dpyc.mjs';
8
8
  import 'os';
9
9
  import 'fs/promises';
10
10
  import 'url';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svamp-cli",
3
- "version": "0.2.63",
3
+ "version": "0.2.66",
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,11 +20,12 @@
20
20
  "scripts": {
21
21
  "build": "rm -rf dist bin/skills && mkdir -p bin/skills && cp -r ../../skills/artifact bin/skills/artifact && tsc --noEmit && pkgroll",
22
22
  "typecheck": "tsc --noEmit",
23
- "test": "npx tsx test/test-authorize.mjs && npx tsx test/test-normalize-allowed-user.mjs && npx tsx test/test-share-url.mjs && npx tsx test/test-update-sharing-normalization.mjs && npx tsx test/test-staged-homes-sweep.mjs && npx tsx test/test-session-helpers.mjs && npx tsx test/test-cli-routing.mjs && npx tsx test/test-security-context.mjs && npx tsx test/test-isolation-decision.mjs && npx tsx test/test-ralph-loop.mjs && npx tsx test/test-message-helpers.mjs && npx tsx test/test-agent-config.mjs && npx tsx test/test-wrap-command.mjs && npx tsx test/test-credential-staging.mjs && npx tsx test/test-claude-auth.mjs && npx tsx test/test-output-formatters.mjs && npx tsx test/test-agent-types.mjs && npx tsx test/test-transport.mjs && npx tsx test/test-session-update-handlers.mjs && npx tsx test/test-session-scanner.mjs && npx tsx test/test-hypha-client.mjs && npx tsx test/test-hook-settings.mjs && npx tsx test/test-session-service-logic.mjs && npx tsx test/test-daemon-persistence.mjs && npx tsx test/test-detect-isolation.mjs && npx tsx test/test-machine-service-logic.mjs && npx tsx test/test-interactive-helpers.mjs && npx tsx test/test-codex-backend.mjs && npx tsx test/test-acp-backend.mjs && npx tsx test/test-acp-bridge.mjs && npx tsx test/test-hook-server.mjs && npx tsx test/test-session-commands.mjs && npx tsx test/test-interactive-console.mjs && npx tsx test/test-session-messages.mjs && npx tsx test/test-skills.mjs && npx tsx test/test-agent-grouping.mjs && npx tsx test/test-ralph-loop-integration.mjs && npx tsx test/test-ralph-loop-modes.mjs && npx tsx test/test-machine-list-directory.mjs && npx tsx test/test-service-commands.mjs && npx tsx test/test-supervisor.mjs && npx tsx test/test-supervisor-lock.mjs && npx tsx test/test-clear-detection.mjs && npx tsx test/test-session-consolidation.mjs && npx tsx test/test-inbox.mjs && npx tsx test/test-session-rpc-dispatch.mjs && npx tsx test/test-sandbox-cli.mjs && npx tsx test/test-serve-manager.mjs && npx tsx test/test-serve-stability.mjs && npx tsx test/test-frpc-e2e.mjs --unit-only",
23
+ "test": "npx tsx test/test-context-window.mjs && npx tsx test/test-authorize.mjs && npx tsx test/test-normalize-allowed-user.mjs && npx tsx test/test-share-url.mjs && npx tsx test/test-update-sharing-normalization.mjs && npx tsx test/test-staged-homes-sweep.mjs && npx tsx test/test-session-helpers.mjs && npx tsx test/test-cli-routing.mjs && npx tsx test/test-security-context.mjs && npx tsx test/test-isolation-decision.mjs && npx tsx test/test-ralph-loop.mjs && npx tsx test/test-message-helpers.mjs && npx tsx test/test-agent-config.mjs && npx tsx test/test-wrap-command.mjs && npx tsx test/test-credential-staging.mjs && npx tsx test/test-claude-auth.mjs && npx tsx test/test-output-formatters.mjs && npx tsx test/test-agent-types.mjs && npx tsx test/test-transport.mjs && npx tsx test/test-session-update-handlers.mjs && npx tsx test/test-session-scanner.mjs && npx tsx test/test-hypha-client.mjs && npx tsx test/test-hook-settings.mjs && npx tsx test/test-session-service-logic.mjs && npx tsx test/test-daemon-persistence.mjs && npx tsx test/test-detect-isolation.mjs && npx tsx test/test-machine-service-logic.mjs && npx tsx test/test-interactive-helpers.mjs && npx tsx test/test-codex-backend.mjs && npx tsx test/test-acp-backend.mjs && npx tsx test/test-acp-bridge.mjs && npx tsx test/test-hook-server.mjs && npx tsx test/test-session-commands.mjs && npx tsx test/test-interactive-console.mjs && npx tsx test/test-session-messages.mjs && npx tsx test/test-skills.mjs && npx tsx test/test-agent-grouping.mjs && npx tsx test/test-ralph-loop-integration.mjs && npx tsx test/test-ralph-loop-modes.mjs && npx tsx test/test-machine-list-directory.mjs && npx tsx test/test-service-commands.mjs && npx tsx test/test-supervisor.mjs && npx tsx test/test-supervisor-lock.mjs && npx tsx test/test-clear-detection.mjs && npx tsx test/test-session-consolidation.mjs && npx tsx test/test-inbox.mjs && npx tsx test/test-session-rpc-dispatch.mjs && npx tsx test/test-sandbox-cli.mjs && npx tsx test/test-serve-manager.mjs && npx tsx test/test-serve-stability.mjs && npx tsx test/test-frpc-e2e.mjs --unit-only",
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",
27
27
  "test:e2e": "node --no-warnings test/e2e-session-tests.mjs",
28
+ "test:archive-resume": "node --no-warnings test/test-session-archive-resume.mjs",
28
29
  "test:frpc": "npx tsx test/test-frpc-e2e.mjs"
29
30
  },
30
31
  "dependencies": {
@@ -1,63 +0,0 @@
1
- var name = "svamp-cli";
2
- var version = "0.2.63";
3
- var description = "Svamp CLI — AI workspace daemon on Hypha Cloud";
4
- var author = "Amun AI AB";
5
- var license = "SEE LICENSE IN LICENSE";
6
- var type = "module";
7
- var bin = {
8
- svamp: "./bin/svamp.mjs"
9
- };
10
- var files = [
11
- "dist",
12
- "bin"
13
- ];
14
- var main = "./dist/index.mjs";
15
- var exports$1 = {
16
- ".": "./dist/index.mjs",
17
- "./cli": "./dist/cli.mjs"
18
- };
19
- var scripts = {
20
- build: "rm -rf dist bin/skills && mkdir -p bin/skills && cp -r ../../skills/artifact bin/skills/artifact && tsc --noEmit && pkgroll",
21
- typecheck: "tsc --noEmit",
22
- test: "npx tsx test/test-authorize.mjs && npx tsx test/test-normalize-allowed-user.mjs && npx tsx test/test-share-url.mjs && npx tsx test/test-update-sharing-normalization.mjs && npx tsx test/test-staged-homes-sweep.mjs && npx tsx test/test-session-helpers.mjs && npx tsx test/test-cli-routing.mjs && npx tsx test/test-security-context.mjs && npx tsx test/test-isolation-decision.mjs && npx tsx test/test-ralph-loop.mjs && npx tsx test/test-message-helpers.mjs && npx tsx test/test-agent-config.mjs && npx tsx test/test-wrap-command.mjs && npx tsx test/test-credential-staging.mjs && npx tsx test/test-claude-auth.mjs && npx tsx test/test-output-formatters.mjs && npx tsx test/test-agent-types.mjs && npx tsx test/test-transport.mjs && npx tsx test/test-session-update-handlers.mjs && npx tsx test/test-session-scanner.mjs && npx tsx test/test-hypha-client.mjs && npx tsx test/test-hook-settings.mjs && npx tsx test/test-session-service-logic.mjs && npx tsx test/test-daemon-persistence.mjs && npx tsx test/test-detect-isolation.mjs && npx tsx test/test-machine-service-logic.mjs && npx tsx test/test-interactive-helpers.mjs && npx tsx test/test-codex-backend.mjs && npx tsx test/test-acp-backend.mjs && npx tsx test/test-acp-bridge.mjs && npx tsx test/test-hook-server.mjs && npx tsx test/test-session-commands.mjs && npx tsx test/test-interactive-console.mjs && npx tsx test/test-session-messages.mjs && npx tsx test/test-skills.mjs && npx tsx test/test-agent-grouping.mjs && npx tsx test/test-ralph-loop-integration.mjs && npx tsx test/test-ralph-loop-modes.mjs && npx tsx test/test-machine-list-directory.mjs && npx tsx test/test-service-commands.mjs && npx tsx test/test-supervisor.mjs && npx tsx test/test-supervisor-lock.mjs && npx tsx test/test-clear-detection.mjs && npx tsx test/test-session-consolidation.mjs && npx tsx test/test-inbox.mjs && npx tsx test/test-session-rpc-dispatch.mjs && npx tsx test/test-sandbox-cli.mjs && npx tsx test/test-serve-manager.mjs && npx tsx test/test-serve-stability.mjs && npx tsx test/test-frpc-e2e.mjs --unit-only",
23
- "test:hypha": "node --no-warnings test/test-hypha-service.mjs",
24
- dev: "tsx src/cli.ts",
25
- "dev:daemon": "tsx src/cli.ts daemon start-sync",
26
- "test:e2e": "node --no-warnings test/e2e-session-tests.mjs",
27
- "test:frpc": "npx tsx test/test-frpc-e2e.mjs"
28
- };
29
- var dependencies = {
30
- "@agentclientprotocol/sdk": "^0.14.1",
31
- "@modelcontextprotocol/sdk": "^1.25.3",
32
- "hypha-rpc": "0.21.40",
33
- "node-pty": "1.2.0-beta.11",
34
- ws: "^8.18.0",
35
- yaml: "^2.8.2",
36
- zod: "^3.24.4"
37
- };
38
- var devDependencies = {
39
- "@types/node": ">=20",
40
- "@types/ws": "^8.5.14",
41
- pkgroll: "^2.14.2",
42
- tsx: "^4.20.6",
43
- typescript: "5.9.3"
44
- };
45
- var packageManager = "yarn@1.22.22";
46
- var _package = {
47
- name: name,
48
- version: version,
49
- description: description,
50
- author: author,
51
- license: license,
52
- type: type,
53
- bin: bin,
54
- files: files,
55
- main: main,
56
- exports: exports$1,
57
- scripts: scripts,
58
- dependencies: dependencies,
59
- devDependencies: devDependencies,
60
- packageManager: packageManager
61
- };
62
-
63
- export { author, bin, _package as default, dependencies, description, devDependencies, exports$1 as exports, files, license, main, name, packageManager, scripts, type, version };