svamp-cli 0.2.68 → 0.2.70

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.
@@ -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
  });
@@ -1116,9 +1140,10 @@ async function registerMachineService(server, machineId, metadata, daemonState,
1116
1140
  const { join: join2, resolve } = await import('path');
1117
1141
  const { homedir } = await import('os');
1118
1142
  const targetPath = resolve(path || homedir());
1143
+ const effectiveRole = getEffectiveRole(context, currentMetadata.sharing);
1119
1144
  const home = homedir();
1120
- const isOwner = !currentMetadata.sharing?.enabled || context?.user?.email && currentMetadata.sharing.owner && context.user.email.toLowerCase() === currentMetadata.sharing.owner.toLowerCase();
1121
- if (!isOwner && targetPath !== home && !targetPath.startsWith(home + "/")) {
1145
+ const restrictedToHome = effectiveRole === "view";
1146
+ if (restrictedToHome && targetPath !== home && !targetPath.startsWith(home + "/")) {
1122
1147
  throw new Error(`Access denied: path must be within ${home}`);
1123
1148
  }
1124
1149
  const showHidden = options?.showHidden ?? false;
@@ -1960,9 +1985,9 @@ function createSessionStore(server, sessionId, initialMetadata, initialAgentStat
1960
1985
  authorizeRequest(context, metadata.sharing, "admin");
1961
1986
  return await callbacks.onRestartClaude();
1962
1987
  },
1963
- killSession: async (context) => {
1988
+ archiveSession: async (context) => {
1964
1989
  authorizeRequest(context, metadata.sharing, "admin");
1965
- callbacks.onKillSession();
1990
+ callbacks.onArchiveSession();
1966
1991
  return { success: true };
1967
1992
  },
1968
1993
  // ── Activity ──
@@ -2240,6 +2265,8 @@ function createSessionStore(server, sessionId, initialMetadata, initialAgentStat
2240
2265
  claudeSessionId,
2241
2266
  "--fork-session",
2242
2267
  "--no-session-persistence",
2268
+ "--permission-mode",
2269
+ "bypassPermissions",
2243
2270
  "--output-format",
2244
2271
  "json",
2245
2272
  "--max-turns",
@@ -5729,6 +5756,19 @@ btn.addEventListener('click', async () => {
5729
5756
  return;
5730
5757
  }
5731
5758
 
5759
+ // Open the popup SYNCHRONOUSLY inside the click handler so the browser's
5760
+ // popup blocker treats it as user-initiated. The hypha SDK awaits a
5761
+ // network round-trip before invoking login_callback, by which time the
5762
+ // user-gesture flag has cleared and any window.open() call is silently
5763
+ // blocked \u2014 especially inside sandboxed iframes (canvas, artifact view).
5764
+ // We point it at about:blank first and rewrite the URL once we have it.
5765
+ const popup = window.open('about:blank', '_blank');
5766
+ if (!popup) {
5767
+ setError('Popup was blocked by the browser. Please allow popups for this site and retry.');
5768
+ return;
5769
+ }
5770
+ try { popup.document.write('<html><body style="font-family:system-ui;padding:24px;color:#656d76">Opening Hypha sign-in\u2026</body></html>'); } catch (e) {}
5771
+
5732
5772
  btn.disabled = true;
5733
5773
  statusEl.textContent = 'Opening Hypha sign-in\u2026';
5734
5774
 
@@ -5737,10 +5777,8 @@ btn.addEventListener('click', async () => {
5737
5777
  server_url: hyphaServer,
5738
5778
  login_callback: (context) => {
5739
5779
  statusEl.textContent = 'Waiting for you to sign in\u2026';
5740
- // Open the login URL in a new tab. Called synchronously from
5741
- // inside the SDK's login() after the user's button click, so
5742
- // popup blockers generally allow it.
5743
- window.open(context.login_url, '_blank');
5780
+ try { popup.location.href = context.login_url; }
5781
+ catch (e) { window.open(context.login_url, '_blank'); }
5744
5782
  },
5745
5783
  });
5746
5784
 
@@ -5750,9 +5788,11 @@ btn.addEventListener('click', async () => {
5750
5788
  const secure = location.protocol === 'https:' ? '; Secure' : '';
5751
5789
  document.cookie = cookieName + '=' + token + '; path=/; SameSite=Lax' + secure;
5752
5790
 
5791
+ try { popup.close(); } catch (e) {}
5753
5792
  statusEl.innerHTML = '<span class="ok">Signed in. Redirecting\u2026</span>';
5754
5793
  setTimeout(() => { window.location.replace(redirectUrl); }, 300);
5755
5794
  } catch (err) {
5795
+ try { popup.close(); } catch (e) {}
5756
5796
  setError('Login failed: ' + (err && err.message ? err.message : err));
5757
5797
  }
5758
5798
  });
@@ -7470,6 +7510,43 @@ function deletePersistedSession(sessionId) {
7470
7510
  saveSessionIndex(index);
7471
7511
  }
7472
7512
  }
7513
+ function markSessionAsArchived(sessionId) {
7514
+ const index = loadSessionIndex();
7515
+ const entry = index[sessionId];
7516
+ if (!entry) return false;
7517
+ const filePath = getSessionFilePath(entry.directory, sessionId);
7518
+ if (!existsSync$1(filePath)) return false;
7519
+ try {
7520
+ const data = JSON.parse(readFileSync$1(filePath, "utf-8"));
7521
+ if (data.stopped === true) return true;
7522
+ data.stopped = true;
7523
+ const tmpPath = filePath + ".tmp";
7524
+ writeFileSync(tmpPath, JSON.stringify(data, null, 2), "utf-8");
7525
+ renameSync(tmpPath, filePath);
7526
+ return true;
7527
+ } catch {
7528
+ return false;
7529
+ }
7530
+ }
7531
+ function clearSessionArchivedFlag(sessionId) {
7532
+ const index = loadSessionIndex();
7533
+ const entry = index[sessionId];
7534
+ if (!entry) return null;
7535
+ const filePath = getSessionFilePath(entry.directory, sessionId);
7536
+ if (!existsSync$1(filePath)) return null;
7537
+ try {
7538
+ const data = JSON.parse(readFileSync$1(filePath, "utf-8"));
7539
+ if (data.stopped) {
7540
+ delete data.stopped;
7541
+ const tmpPath = filePath + ".tmp";
7542
+ writeFileSync(tmpPath, JSON.stringify(data, null, 2), "utf-8");
7543
+ renameSync(tmpPath, filePath);
7544
+ }
7545
+ return data;
7546
+ } catch {
7547
+ return null;
7548
+ }
7549
+ }
7473
7550
  function loadPersistedSessions() {
7474
7551
  const sessions = [];
7475
7552
  const index = loadSessionIndex();
@@ -7771,7 +7848,7 @@ async function startDaemon(options) {
7771
7848
  const list = loadExposedTunnels().filter((t) => t.name !== name);
7772
7849
  saveExposedTunnels(list);
7773
7850
  }
7774
- const { ServeManager } = await import('./serveManager-DWQtF8NK.mjs');
7851
+ const { ServeManager } = await import('./serveManager-Dy4afaLH.mjs');
7775
7852
  const serveManager = new ServeManager(SVAMP_HOME, (msg) => logger.log(`[SERVE] ${msg}`), hyphaServerUrl);
7776
7853
  ensureAutoInstalledSkills(logger).catch(() => {
7777
7854
  });
@@ -7956,6 +8033,7 @@ async function startDaemon(options) {
7956
8033
  startedFromDaemon: true,
7957
8034
  startedBy: "daemon",
7958
8035
  lifecycleState: resumeSessionId ? "idle" : "starting",
8036
+ ...resumeSessionId && { claudeSessionId: resumeSessionId },
7959
8037
  sharing: options2.sharing,
7960
8038
  securityContext: options2.securityContext,
7961
8039
  tags: options2.tags,
@@ -7971,7 +8049,7 @@ async function startDaemon(options) {
7971
8049
  const allPersisted = loadPersistedSessions();
7972
8050
  const persisted = allPersisted.find((p) => p.sessionId === sessionId) || (resumeSessionId ? allPersisted.find((p) => p.claudeResumeId === resumeSessionId) : void 0);
7973
8051
  let claudeResumeId = persisted?.claudeResumeId || (resumeSessionId || void 0);
7974
- let currentPermissionMode = options2.permissionMode || persisted?.permissionMode || "default";
8052
+ let currentPermissionMode = options2.permissionMode || persisted?.permissionMode || "bypassPermissions";
7975
8053
  const sessionCreatedAt = persisted?.createdAt || Date.now();
7976
8054
  let lastSpawnMeta = persisted?.spawnMeta || {};
7977
8055
  let sessionWasProcessing = !!options2.wasProcessing;
@@ -8679,7 +8757,16 @@ The automated loop has finished. Review the progress above and let me know if yo
8679
8757
  artifactSync.scheduleDebouncedSync(sessionId, getSessionDir(directory, sessionId), sessionMetadata, machineId);
8680
8758
  }
8681
8759
  if (isResumeFailure) {
8682
- logger.log(`[Session ${sessionId}] Resume failed \u2014 Claude started fresh session (tried: ${persisted?.claudeResumeId ?? "unknown"}, got: ${msg.session_id})`);
8760
+ const triedId = persisted?.claudeResumeId ?? "unknown";
8761
+ logger.log(`[Session ${sessionId}] Resume failed \u2014 Claude started fresh session (tried: ${triedId}, got: ${msg.session_id})`);
8762
+ sessionService.pushMessage(
8763
+ {
8764
+ type: "message",
8765
+ message: `Resume incomplete \u2014 Claude could not restore the previous conversation. A new Claude session was started (expected ${triedId.slice(0, 8)}\u2026, got ${msg.session_id.slice(0, 8)}\u2026). Earlier messages remain in the history above for reference, but Claude does not have them in its context.`,
8766
+ level: "warning"
8767
+ },
8768
+ "event"
8769
+ );
8683
8770
  } else if (isConversationClear) {
8684
8771
  logger.log(`[Session ${sessionId}] Conversation cleared (/clear) \u2014 new Claude session: ${msg.session_id}`);
8685
8772
  sessionService.clearMessages();
@@ -8941,6 +9028,11 @@ The automated loop has finished. Review the progress above and let me know if yo
8941
9028
  claudeResumeId,
8942
9029
  "--fork-session",
8943
9030
  "--no-session-persistence",
9031
+ // /btw is non-interactive; without bypass the
9032
+ // forked Claude pauses on tool prompts and the
9033
+ // user just sees a hanging side-channel.
9034
+ "--permission-mode",
9035
+ "bypassPermissions",
8944
9036
  "--output-format",
8945
9037
  "stream-json",
8946
9038
  "--verbose"
@@ -9075,6 +9167,9 @@ The automated loop has finished. Review the progress above and let me know if yo
9075
9167
  },
9076
9168
  onSwitchMode: async (mode) => {
9077
9169
  const normalizedMode = toClaudePermissionMode(mode);
9170
+ if (currentPermissionMode === normalizedMode) {
9171
+ return;
9172
+ }
9078
9173
  logger.log(`[Session ${sessionId}] Switch mode: ${mode}${mode !== normalizedMode ? ` \u2192 ${normalizedMode}` : ""}`);
9079
9174
  if (isRestartingClaude || isSwitchingMode) {
9080
9175
  logger.log(`[Session ${sessionId}] Switch mode deferred \u2014 restart/switch already in progress`);
@@ -9153,15 +9248,14 @@ The automated loop has finished. Review the progress above and let me know if yo
9153
9248
  lastSpawnMeta = { ...lastSpawnMeta, appendSystemPrompt: prompt };
9154
9249
  return await restartClaudeHandler();
9155
9250
  },
9156
- onKillSession: () => {
9157
- logger.log(`[Session ${sessionId}] Kill session requested`);
9158
- stopSession(sessionId);
9251
+ onArchiveSession: () => {
9252
+ logger.log(`[Session ${sessionId}] Archive session requested`);
9253
+ archiveSession(sessionId);
9159
9254
  },
9160
9255
  onInboxMessage: (message) => {
9161
9256
  if (trackedSession?.stopped) return;
9162
9257
  logger.log(`[Session ${sessionId}] Inbox message received (urgency: ${message.urgency || "normal"}, from: ${message.from || "unknown"})`);
9163
9258
  const formatted = formatInboxMessageXml(message);
9164
- sessionService.markInboxRead(message.messageId);
9165
9259
  if (message.urgency === "urgent") {
9166
9260
  logger.log(`[Session ${sessionId}] Delivering urgent inbox message to agent`);
9167
9261
  sessionService.pushMessage(formatted, "user");
@@ -9511,7 +9605,7 @@ The automated loop has finished. Review the progress above and let me know if yo
9511
9605
  tags: options2.tags,
9512
9606
  parentSessionId: options2.parentSessionId
9513
9607
  };
9514
- let currentPermissionMode = options2.permissionMode || "default";
9608
+ let currentPermissionMode = options2.permissionMode || "bypassPermissions";
9515
9609
  const allowedTools = /* @__PURE__ */ new Set();
9516
9610
  const allowedBashLiterals = /* @__PURE__ */ new Set();
9517
9611
  const allowedBashPrefixes = /* @__PURE__ */ new Set();
@@ -9605,6 +9699,7 @@ The automated loop has finished. Review the progress above and let me know if yo
9605
9699
  agentBackend.respondToPermission?.(requestId, params.approved);
9606
9700
  },
9607
9701
  onSwitchMode: (mode) => {
9702
+ if (currentPermissionMode === mode) return;
9608
9703
  logger.log(`[${agentName} Session ${sessionId}] Switch mode: ${mode}`);
9609
9704
  currentPermissionMode = mode;
9610
9705
  },
@@ -9624,15 +9719,14 @@ The automated loop has finished. Review the progress above and let me know if yo
9624
9719
  onApplySystemPrompt: async () => {
9625
9720
  return { success: false, message: "System prompt updates with restart are not yet supported for this agent type." };
9626
9721
  },
9627
- onKillSession: () => {
9628
- logger.log(`[${agentName} Session ${sessionId}] Kill session requested`);
9629
- stopSession(sessionId);
9722
+ onArchiveSession: () => {
9723
+ logger.log(`[${agentName} Session ${sessionId}] Archive session requested`);
9724
+ archiveSession(sessionId);
9630
9725
  },
9631
9726
  onInboxMessage: (message) => {
9632
9727
  if (acpStopped) return;
9633
9728
  logger.log(`[${agentName} Session ${sessionId}] Inbox message received (urgency: ${message.urgency || "normal"}, from: ${message.from || "unknown"})`);
9634
9729
  const formatted = formatInboxMessageXml(message);
9635
- sessionService.markInboxRead(message.messageId);
9636
9730
  if (message.urgency === "urgent" && acpBackendReady) {
9637
9731
  logger.log(`[${agentName} Session ${sessionId}] Delivering urgent inbox message to agent`);
9638
9732
  sessionService.pushMessage(formatted, "user");
@@ -10082,7 +10176,7 @@ The automated loop has finished. Review the progress above and let me know if yo
10082
10176
  "event"
10083
10177
  );
10084
10178
  sessionService.sendSessionEnd();
10085
- stopSession(sessionId);
10179
+ deleteSession(sessionId);
10086
10180
  });
10087
10181
  return {
10088
10182
  type: "success",
@@ -10097,8 +10191,7 @@ The automated loop has finished. Review the progress above and let me know if yo
10097
10191
  };
10098
10192
  }
10099
10193
  };
10100
- const stopSession = (sessionId) => {
10101
- logger.log(`Stopping session: ${sessionId}`);
10194
+ const teardownTrackedSession = (sessionId) => {
10102
10195
  for (const [pid, session] of pidToTrackedSession) {
10103
10196
  if (session.svampSessionId === sessionId) {
10104
10197
  session.stopped = true;
@@ -10117,16 +10210,64 @@ The automated loop has finished. Review the progress above and let me know if yo
10117
10210
  session.cleanupSvampConfig?.();
10118
10211
  artifactSync.cancelSync(sessionId);
10119
10212
  pidToTrackedSession.delete(pid);
10120
- deletePersistedSession(sessionId);
10121
- logger.log(`Session ${sessionId} stopped`);
10122
10213
  return true;
10123
10214
  }
10124
10215
  }
10125
10216
  artifactSync.cancelSync(sessionId);
10126
- deletePersistedSession(sessionId);
10127
- logger.log(`Session ${sessionId} not found in memory, cleaned up persisted state`);
10128
10217
  return false;
10129
10218
  };
10219
+ const archiveSession = (sessionId) => {
10220
+ logger.log(`Archiving session: ${sessionId}`);
10221
+ const wasInMemory = teardownTrackedSession(sessionId);
10222
+ const markedArchived = markSessionAsArchived(sessionId);
10223
+ if (wasInMemory || markedArchived) {
10224
+ logger.log(`Session ${sessionId} archived (inMemory=${wasInMemory}, persisted=${markedArchived})`);
10225
+ return true;
10226
+ }
10227
+ logger.log(`Session ${sessionId} not found in memory or on disk; nothing to archive`);
10228
+ return false;
10229
+ };
10230
+ const resumeSession = async (sessionId) => {
10231
+ logger.log(`Resuming session: ${sessionId}`);
10232
+ for (const session of pidToTrackedSession.values()) {
10233
+ if (session.svampSessionId === sessionId && !session.stopped) {
10234
+ logger.log(`Session ${sessionId} already running \u2014 resume is a no-op`);
10235
+ return { success: true, sessionId, message: "Session is already running" };
10236
+ }
10237
+ }
10238
+ const persisted = clearSessionArchivedFlag(sessionId);
10239
+ if (!persisted) {
10240
+ return { success: false, message: `Session ${sessionId} has no persisted record to resume` };
10241
+ }
10242
+ try {
10243
+ const result = await spawnSession({
10244
+ directory: persisted.directory,
10245
+ sessionId: persisted.sessionId,
10246
+ resumeSessionId: persisted.claudeResumeId,
10247
+ sharing: persisted.metadata?.sharing,
10248
+ securityContext: persisted.metadata?.securityContext,
10249
+ forceIsolation: !!persisted.metadata?.isolationMethod,
10250
+ parentSessionId: persisted.metadata?.parentSessionId,
10251
+ permissionMode: persisted.permissionMode
10252
+ });
10253
+ if (result.type === "success") {
10254
+ logger.log(`Resumed session ${sessionId} (claudeResumeId=${persisted.claudeResumeId || "none"})`);
10255
+ return { success: true, sessionId: result.sessionId };
10256
+ }
10257
+ markSessionAsArchived(sessionId);
10258
+ return { success: false, message: result.errorMessage || `spawnSession returned ${result.type}` };
10259
+ } catch (err) {
10260
+ markSessionAsArchived(sessionId);
10261
+ return { success: false, message: err.message };
10262
+ }
10263
+ };
10264
+ const deleteSession = (sessionId) => {
10265
+ logger.log(`Deleting session: ${sessionId}`);
10266
+ teardownTrackedSession(sessionId);
10267
+ deletePersistedSession(sessionId);
10268
+ logger.log(`Session ${sessionId} deleted`);
10269
+ return true;
10270
+ };
10130
10271
  const restartSession = async (sessionId) => {
10131
10272
  for (const session of pidToTrackedSession.values()) {
10132
10273
  if (session.svampSessionId === sessionId && !session.stopped) {
@@ -10204,7 +10345,9 @@ The automated loop has finished. Review the progress above and let me know if yo
10204
10345
  initialDaemonState,
10205
10346
  {
10206
10347
  spawnSession,
10207
- stopSession,
10348
+ archiveSession,
10349
+ resumeSession,
10350
+ deleteSession,
10208
10351
  restartSession,
10209
10352
  requestShutdown: () => {
10210
10353
  logger.log("Shutdown requested via hypha-app (ignored \u2014 daemon never self-terminates)");
@@ -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-HuBXfVSz.mjs';
5
+ import { c as connectToHypha, a as registerSessionService, k as generateHookSettings } from './run-BqAe7GgA.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-D5kCHCfX.mjs');
57
+ const { connectAndGetMachine } = await import('./commands-BMOelGYC.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-D5kCHCfX.mjs');
96
+ const { connectAndGetMachine } = await import('./commands-BMOelGYC.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-D5kCHCfX.mjs');
185
+ const { connectAndGetMachine } = await import('./commands-BMOelGYC.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-D5kCHCfX.mjs');
205
+ const { connectAndGetMachine } = await import('./commands-BMOelGYC.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-D5kCHCfX.mjs');
238
+ const { connectAndGetMachine } = await import('./commands-BMOelGYC.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-HuBXfVSz.mjs';
7
+ import { S as ServeAuth, h as hasCookieToken } from './run-BqAe7GgA.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.68",
3
+ "version": "0.2.70",
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 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-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": "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-session-send-query.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",