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.
- package/dist/{agentCommands-QnPGJFY-.mjs → agentCommands-BaQIO1T2.mjs} +2 -2
- package/dist/cli.mjs +127 -68
- package/dist/{commands-D5kCHCfX.mjs → commands-BMOelGYC.mjs} +369 -45
- package/dist/{commands-tUjBdy54.mjs → commands-CB03m9-Z.mjs} +2 -2
- package/dist/{commands-Cxb6tsha.mjs → commands-CdGLuwtQ.mjs} +3 -3
- package/dist/index.mjs +1 -1
- package/dist/{package-DhOTD1Ln.mjs → package-Cw40xKCx.mjs} +2 -2
- package/dist/{run-HuBXfVSz.mjs → run-BqAe7GgA.mjs} +175 -32
- package/dist/{run-BvcwFt_g.mjs → run-Di-48dsY.mjs} +3 -3
- package/dist/{serveCommands-DDlHXpPe.mjs → serveCommands-DpKi_PuD.mjs} +5 -5
- package/dist/{serveManager-DWQtF8NK.mjs → serveManager-Dy4afaLH.mjs} +1 -1
- package/package.json +2 -2
|
@@ -754,12 +754,36 @@ async function registerMachineService(server, machineId, metadata, daemonState,
|
|
|
754
754
|
}
|
|
755
755
|
return result;
|
|
756
756
|
},
|
|
757
|
-
//
|
|
758
|
-
|
|
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.
|
|
760
|
+
const result = handlers.archiveSession(sessionId);
|
|
761
761
|
notifyListeners({
|
|
762
|
-
type: "session-
|
|
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
|
|
1121
|
-
if (
|
|
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
|
-
|
|
1988
|
+
archiveSession: async (context) => {
|
|
1964
1989
|
authorizeRequest(context, metadata.sharing, "admin");
|
|
1965
|
-
callbacks.
|
|
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
|
-
|
|
5741
|
-
|
|
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-
|
|
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 || "
|
|
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
|
-
|
|
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
|
-
|
|
9157
|
-
logger.log(`[Session ${sessionId}]
|
|
9158
|
-
|
|
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 || "
|
|
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
|
-
|
|
9628
|
-
logger.log(`[${agentName} Session ${sessionId}]
|
|
9629
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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-
|
|
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
|
-
|
|
688
|
-
log("[hypha]
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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.
|
|
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",
|