svamp-cli 0.2.37 → 0.2.39
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-C88l82pM.mjs → agentCommands-BvmStLoh.mjs} +2 -2
- package/dist/cli.mjs +149 -39
- package/dist/{commands-CrTDsMDZ.mjs → commands-CWKFZm9s.mjs} +1 -1
- package/dist/{commands-Dz_JXrcs.mjs → commands-DVXppwx2.mjs} +2 -2
- package/dist/index.mjs +1 -1
- package/dist/package-CPiu8-uW.mjs +63 -0
- package/dist/{run-BckEhiLq.mjs → run--6SzG2CH.mjs} +1 -1
- package/dist/{run-Dz0TkCj6.mjs → run-CRwkPQDW.mjs} +224 -18
- package/dist/{serveCommands-FnBtBifV.mjs → serveCommands-B9Dq2loo.mjs} +4 -4
- package/dist/supervisorLock-DwNAn0VN.mjs +157 -0
- package/package.json +2 -2
- package/dist/package-DRX_LQ92.mjs +0 -63
|
@@ -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-
|
|
151
|
+
const { connectAndGetMachine } = await import('./commands-CWKFZm9s.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-
|
|
168
|
+
const { resolveSessionId } = await import('./commands-CWKFZm9s.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-
|
|
1
|
+
import { s as startDaemon, b as stopDaemon, d as daemonStatus } from './run-CRwkPQDW.mjs';
|
|
2
2
|
import 'os';
|
|
3
3
|
import 'fs/promises';
|
|
4
4
|
import 'fs';
|
|
@@ -36,11 +36,23 @@ async function main() {
|
|
|
36
36
|
await logoutFromHypha();
|
|
37
37
|
} else if (subcommand === "daemon") {
|
|
38
38
|
if (daemonSubcommand === "restart") {
|
|
39
|
-
|
|
39
|
+
try {
|
|
40
|
+
await applyClaudeAuthFlags(args);
|
|
41
|
+
} catch (err) {
|
|
42
|
+
console.error(`svamp daemon restart: ${err.message || err}`);
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
const { restartDaemon } = await import('./run-CRwkPQDW.mjs').then(function (n) { return n.n; });
|
|
40
46
|
await restartDaemon();
|
|
41
47
|
process.exit(0);
|
|
42
48
|
}
|
|
43
49
|
if (daemonSubcommand === "start") {
|
|
50
|
+
try {
|
|
51
|
+
await applyClaudeAuthFlags(args);
|
|
52
|
+
} catch (err) {
|
|
53
|
+
console.error(`svamp daemon start: ${err.message || err}`);
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
44
56
|
const { spawn } = await import('child_process');
|
|
45
57
|
const extraArgs = [];
|
|
46
58
|
if (args.includes("--no-auto-continue")) extraArgs.push("--no-auto-continue");
|
|
@@ -82,10 +94,11 @@ async function main() {
|
|
|
82
94
|
process.exit(0);
|
|
83
95
|
} else if (daemonSubcommand === "start-supervised") {
|
|
84
96
|
const { spawn: spawnChild } = await import('child_process');
|
|
85
|
-
const { appendFileSync, mkdirSync
|
|
97
|
+
const { appendFileSync, mkdirSync } = await import('fs');
|
|
86
98
|
const { join: pathJoin } = await import('path');
|
|
87
99
|
const osModule = await import('os');
|
|
88
100
|
const svampHome = process.env.SVAMP_HOME || pathJoin(osModule.homedir(), ".svamp");
|
|
101
|
+
mkdirSync(svampHome, { recursive: true });
|
|
89
102
|
const logsDir = pathJoin(svampHome, "logs");
|
|
90
103
|
mkdirSync(logsDir, { recursive: true });
|
|
91
104
|
const logFile = pathJoin(logsDir, "daemon-supervised.log");
|
|
@@ -97,13 +110,27 @@ async function main() {
|
|
|
97
110
|
} catch {
|
|
98
111
|
}
|
|
99
112
|
};
|
|
113
|
+
const {
|
|
114
|
+
acquireSupervisorLockWithRetry,
|
|
115
|
+
releaseSupervisorLock,
|
|
116
|
+
findOrphanedSyncPids,
|
|
117
|
+
killOrphanedSyncs
|
|
118
|
+
} = await import('./supervisorLock-DwNAn0VN.mjs');
|
|
100
119
|
const supervisorPidFile = pathJoin(svampHome, "supervisor.pid");
|
|
120
|
+
const lock = acquireSupervisorLockWithRetry(supervisorPidFile, process.pid);
|
|
121
|
+
if (!lock.acquired) {
|
|
122
|
+
log(`Another supervisor is already running (PID ${lock.heldBy}) \u2014 exiting`);
|
|
123
|
+
console.error(`svamp daemon: another supervisor is already running (PID ${lock.heldBy}).`);
|
|
124
|
+
process.exit(0);
|
|
125
|
+
}
|
|
101
126
|
try {
|
|
102
|
-
|
|
103
|
-
|
|
127
|
+
const orphans = findOrphanedSyncPids(process.pid);
|
|
128
|
+
if (orphans.length > 0) {
|
|
129
|
+
await killOrphanedSyncs(orphans, { log, gracePeriodMs: 3e3 });
|
|
130
|
+
}
|
|
131
|
+
} catch (err) {
|
|
132
|
+
log(`Orphan scan failed (non-fatal): ${err?.message || err}`);
|
|
104
133
|
}
|
|
105
|
-
const { writeFileSync: wfs } = await import('fs');
|
|
106
|
-
wfs(supervisorPidFile, String(process.pid), "utf-8");
|
|
107
134
|
const extraSyncArgs = [];
|
|
108
135
|
if (args.includes("--no-auto-continue")) extraSyncArgs.push("--no-auto-continue");
|
|
109
136
|
const BASE_DELAY_MS = 2e3;
|
|
@@ -188,11 +215,7 @@ async function main() {
|
|
|
188
215
|
setTimeout(() => clearInterval(checkStop), delay + 100);
|
|
189
216
|
});
|
|
190
217
|
}
|
|
191
|
-
|
|
192
|
-
const { unlinkSync: us } = await import('fs');
|
|
193
|
-
us(supervisorPidFile);
|
|
194
|
-
} catch {
|
|
195
|
-
}
|
|
218
|
+
releaseSupervisorLock(supervisorPidFile, process.pid);
|
|
196
219
|
process.exit(0);
|
|
197
220
|
} else if (daemonSubcommand === "start-sync") {
|
|
198
221
|
const noAutoContinue = args.includes("--no-auto-continue");
|
|
@@ -211,6 +234,9 @@ async function main() {
|
|
|
211
234
|
} else if (daemonSubcommand === "uninstall") {
|
|
212
235
|
await uninstallDaemonService();
|
|
213
236
|
process.exit(0);
|
|
237
|
+
} else if (daemonSubcommand === "auth") {
|
|
238
|
+
await handleDaemonAuthCommand(args.slice(2));
|
|
239
|
+
process.exit(0);
|
|
214
240
|
} else {
|
|
215
241
|
printDaemonHelp();
|
|
216
242
|
}
|
|
@@ -246,7 +272,7 @@ async function main() {
|
|
|
246
272
|
console.error("svamp serve: Serve commands are not available in sandboxed sessions.");
|
|
247
273
|
process.exit(1);
|
|
248
274
|
}
|
|
249
|
-
const { handleServeCommand } = await import('./serveCommands-
|
|
275
|
+
const { handleServeCommand } = await import('./serveCommands-B9Dq2loo.mjs');
|
|
250
276
|
await handleServeCommand();
|
|
251
277
|
process.exit(0);
|
|
252
278
|
} else if (subcommand === "process" || subcommand === "proc") {
|
|
@@ -255,7 +281,7 @@ async function main() {
|
|
|
255
281
|
console.error("svamp process: Process commands are not available in sandboxed sessions.");
|
|
256
282
|
process.exit(1);
|
|
257
283
|
}
|
|
258
|
-
const { processCommand } = await import('./commands-
|
|
284
|
+
const { processCommand } = await import('./commands-DVXppwx2.mjs');
|
|
259
285
|
let machineId;
|
|
260
286
|
const processArgs = args.slice(1);
|
|
261
287
|
const mIdx = processArgs.findIndex((a) => a === "--machine" || a === "-m");
|
|
@@ -273,7 +299,7 @@ async function main() {
|
|
|
273
299
|
} else if (!subcommand || subcommand === "start") {
|
|
274
300
|
await handleInteractiveCommand();
|
|
275
301
|
} else if (subcommand === "--version" || subcommand === "-v") {
|
|
276
|
-
const pkg = await import('./package-
|
|
302
|
+
const pkg = await import('./package-CPiu8-uW.mjs').catch(() => ({ default: { version: "unknown" } }));
|
|
277
303
|
console.log(`svamp version: ${pkg.default.version}`);
|
|
278
304
|
} else {
|
|
279
305
|
console.error(`Unknown command: ${subcommand}`);
|
|
@@ -282,7 +308,7 @@ async function main() {
|
|
|
282
308
|
}
|
|
283
309
|
}
|
|
284
310
|
async function handleInteractiveCommand() {
|
|
285
|
-
const { runInteractive } = await import('./run
|
|
311
|
+
const { runInteractive } = await import('./run--6SzG2CH.mjs');
|
|
286
312
|
const interactiveArgs = subcommand === "start" ? args.slice(1) : args;
|
|
287
313
|
let directory = process.cwd();
|
|
288
314
|
let resumeSessionId;
|
|
@@ -327,7 +353,7 @@ async function handleAgentCommand() {
|
|
|
327
353
|
return;
|
|
328
354
|
}
|
|
329
355
|
if (agentArgs[0] === "list") {
|
|
330
|
-
const { KNOWN_ACP_AGENTS, KNOWN_MCP_AGENTS: KNOWN_MCP_AGENTS2 } = await import('./run-
|
|
356
|
+
const { KNOWN_ACP_AGENTS, KNOWN_MCP_AGENTS: KNOWN_MCP_AGENTS2 } = await import('./run-CRwkPQDW.mjs').then(function (n) { return n.i; });
|
|
331
357
|
console.log("Known agents:");
|
|
332
358
|
for (const [name, config2] of Object.entries(KNOWN_ACP_AGENTS)) {
|
|
333
359
|
console.log(` ${name.padEnd(12)} ${config2.command} ${config2.args.join(" ")} (ACP)`);
|
|
@@ -339,7 +365,7 @@ async function handleAgentCommand() {
|
|
|
339
365
|
console.log('Use "svamp agent -- <command> [args]" for a custom ACP agent.');
|
|
340
366
|
return;
|
|
341
367
|
}
|
|
342
|
-
const { resolveAcpAgentConfig, KNOWN_MCP_AGENTS } = await import('./run-
|
|
368
|
+
const { resolveAcpAgentConfig, KNOWN_MCP_AGENTS } = await import('./run-CRwkPQDW.mjs').then(function (n) { return n.i; });
|
|
343
369
|
let cwd = process.cwd();
|
|
344
370
|
const filteredArgs = [];
|
|
345
371
|
for (let i = 0; i < agentArgs.length; i++) {
|
|
@@ -363,12 +389,12 @@ async function handleAgentCommand() {
|
|
|
363
389
|
console.log(`Starting ${config.agentName} agent in ${cwd}...`);
|
|
364
390
|
let backend;
|
|
365
391
|
if (KNOWN_MCP_AGENTS[config.agentName]) {
|
|
366
|
-
const { CodexMcpBackend } = await import('./run-
|
|
392
|
+
const { CodexMcpBackend } = await import('./run-CRwkPQDW.mjs').then(function (n) { return n.j; });
|
|
367
393
|
backend = new CodexMcpBackend({ cwd, log: logFn });
|
|
368
394
|
} else {
|
|
369
|
-
const { AcpBackend } = await import('./run-
|
|
370
|
-
const { GeminiTransport } = await import('./run-
|
|
371
|
-
const { DefaultTransport } = await import('./run-
|
|
395
|
+
const { AcpBackend } = await import('./run-CRwkPQDW.mjs').then(function (n) { return n.h; });
|
|
396
|
+
const { GeminiTransport } = await import('./run-CRwkPQDW.mjs').then(function (n) { return n.G; });
|
|
397
|
+
const { DefaultTransport } = await import('./run-CRwkPQDW.mjs').then(function (n) { return n.D; });
|
|
372
398
|
const transportHandler = config.agentName === "gemini" ? new GeminiTransport() : new DefaultTransport(config.agentName);
|
|
373
399
|
backend = new AcpBackend({
|
|
374
400
|
agentName: config.agentName,
|
|
@@ -495,7 +521,7 @@ async function handleSessionCommand() {
|
|
|
495
521
|
process.exit(1);
|
|
496
522
|
}
|
|
497
523
|
}
|
|
498
|
-
const { sessionList, sessionSpawn, sessionStop, sessionInfo, sessionMessages, sessionAttach, sessionMachines, sessionSend, sessionWait, sessionShare, sessionRalphStart, sessionRalphCancel, sessionRalphStatus, sessionInboxSend, sessionInboxList, sessionInboxRead, sessionInboxReply, sessionInboxClear } = await import('./commands-
|
|
524
|
+
const { sessionList, sessionSpawn, sessionStop, sessionInfo, sessionMessages, sessionAttach, sessionMachines, sessionSend, sessionWait, sessionShare, sessionRalphStart, sessionRalphCancel, sessionRalphStatus, sessionInboxSend, sessionInboxList, sessionInboxRead, sessionInboxReply, sessionInboxClear } = await import('./commands-CWKFZm9s.mjs');
|
|
499
525
|
const parseFlagStr = (flag, shortFlag) => {
|
|
500
526
|
for (let i = 1; i < sessionArgs.length; i++) {
|
|
501
527
|
if ((sessionArgs[i] === flag || shortFlag) && i + 1 < sessionArgs.length) {
|
|
@@ -555,7 +581,7 @@ async function handleSessionCommand() {
|
|
|
555
581
|
allowDomain.push(sessionArgs[++i]);
|
|
556
582
|
}
|
|
557
583
|
}
|
|
558
|
-
const { parseShareArg } = await import('./commands-
|
|
584
|
+
const { parseShareArg } = await import('./commands-CWKFZm9s.mjs');
|
|
559
585
|
const shareEntries = share.map((s) => parseShareArg(s));
|
|
560
586
|
await sessionSpawn(agent, dir, targetMachineId, {
|
|
561
587
|
message,
|
|
@@ -641,7 +667,7 @@ async function handleSessionCommand() {
|
|
|
641
667
|
console.error("Usage: svamp session approve <session-id> [request-id] [--json]");
|
|
642
668
|
process.exit(1);
|
|
643
669
|
}
|
|
644
|
-
const { sessionApprove } = await import('./commands-
|
|
670
|
+
const { sessionApprove } = await import('./commands-CWKFZm9s.mjs');
|
|
645
671
|
const approveReqId = sessionArgs[2] && !sessionArgs[2].startsWith("--") ? sessionArgs[2] : void 0;
|
|
646
672
|
await sessionApprove(sessionArgs[1], approveReqId, targetMachineId, {
|
|
647
673
|
json: hasFlag("--json")
|
|
@@ -651,7 +677,7 @@ async function handleSessionCommand() {
|
|
|
651
677
|
console.error("Usage: svamp session deny <session-id> [request-id] [--json]");
|
|
652
678
|
process.exit(1);
|
|
653
679
|
}
|
|
654
|
-
const { sessionDeny } = await import('./commands-
|
|
680
|
+
const { sessionDeny } = await import('./commands-CWKFZm9s.mjs');
|
|
655
681
|
const denyReqId = sessionArgs[2] && !sessionArgs[2].startsWith("--") ? sessionArgs[2] : void 0;
|
|
656
682
|
await sessionDeny(sessionArgs[1], denyReqId, targetMachineId, {
|
|
657
683
|
json: hasFlag("--json")
|
|
@@ -687,7 +713,7 @@ async function handleSessionCommand() {
|
|
|
687
713
|
console.error("Usage: svamp session set-title <title>");
|
|
688
714
|
process.exit(1);
|
|
689
715
|
}
|
|
690
|
-
const { sessionSetTitle } = await import('./agentCommands-
|
|
716
|
+
const { sessionSetTitle } = await import('./agentCommands-BvmStLoh.mjs');
|
|
691
717
|
await sessionSetTitle(title);
|
|
692
718
|
} else if (sessionSubcommand === "set-link") {
|
|
693
719
|
const url = sessionArgs[1];
|
|
@@ -696,7 +722,7 @@ async function handleSessionCommand() {
|
|
|
696
722
|
process.exit(1);
|
|
697
723
|
}
|
|
698
724
|
const label = sessionArgs[2] && !sessionArgs[2].startsWith("--") ? sessionArgs[2] : void 0;
|
|
699
|
-
const { sessionSetLink } = await import('./agentCommands-
|
|
725
|
+
const { sessionSetLink } = await import('./agentCommands-BvmStLoh.mjs');
|
|
700
726
|
await sessionSetLink(url, label);
|
|
701
727
|
} else if (sessionSubcommand === "notify") {
|
|
702
728
|
const message = sessionArgs[1];
|
|
@@ -705,7 +731,7 @@ async function handleSessionCommand() {
|
|
|
705
731
|
process.exit(1);
|
|
706
732
|
}
|
|
707
733
|
const level = parseFlagStr("--level") || "info";
|
|
708
|
-
const { sessionNotify } = await import('./agentCommands-
|
|
734
|
+
const { sessionNotify } = await import('./agentCommands-BvmStLoh.mjs');
|
|
709
735
|
await sessionNotify(message, level);
|
|
710
736
|
} else if (sessionSubcommand === "broadcast") {
|
|
711
737
|
const action = sessionArgs[1];
|
|
@@ -713,7 +739,7 @@ async function handleSessionCommand() {
|
|
|
713
739
|
console.error("Usage: svamp session broadcast <action> [args...]\nActions: open-canvas <url> [label], close-canvas, toast <message>");
|
|
714
740
|
process.exit(1);
|
|
715
741
|
}
|
|
716
|
-
const { sessionBroadcast } = await import('./agentCommands-
|
|
742
|
+
const { sessionBroadcast } = await import('./agentCommands-BvmStLoh.mjs');
|
|
717
743
|
await sessionBroadcast(action, sessionArgs.slice(2).filter((a) => !a.startsWith("--")));
|
|
718
744
|
} else if (sessionSubcommand === "inbox") {
|
|
719
745
|
const inboxSubcmd = sessionArgs[1];
|
|
@@ -724,7 +750,7 @@ async function handleSessionCommand() {
|
|
|
724
750
|
process.exit(1);
|
|
725
751
|
}
|
|
726
752
|
if (agentSessionId) {
|
|
727
|
-
const { inboxSend } = await import('./agentCommands-
|
|
753
|
+
const { inboxSend } = await import('./agentCommands-BvmStLoh.mjs');
|
|
728
754
|
await inboxSend(sessionArgs[2], {
|
|
729
755
|
body: sessionArgs[3],
|
|
730
756
|
subject: parseFlagStr("--subject"),
|
|
@@ -739,7 +765,7 @@ async function handleSessionCommand() {
|
|
|
739
765
|
}
|
|
740
766
|
} else if (inboxSubcmd === "list" || inboxSubcmd === "ls") {
|
|
741
767
|
if (agentSessionId && !sessionArgs[2]) {
|
|
742
|
-
const { inboxList } = await import('./agentCommands-
|
|
768
|
+
const { inboxList } = await import('./agentCommands-BvmStLoh.mjs');
|
|
743
769
|
await inboxList({
|
|
744
770
|
unread: hasFlag("--unread"),
|
|
745
771
|
limit: parseFlagInt("--limit"),
|
|
@@ -761,7 +787,7 @@ async function handleSessionCommand() {
|
|
|
761
787
|
process.exit(1);
|
|
762
788
|
}
|
|
763
789
|
if (agentSessionId && !sessionArgs[3]) {
|
|
764
|
-
const { inboxList } = await import('./agentCommands-
|
|
790
|
+
const { inboxList } = await import('./agentCommands-BvmStLoh.mjs');
|
|
765
791
|
await sessionInboxRead(agentSessionId, sessionArgs[2], targetMachineId);
|
|
766
792
|
} else if (sessionArgs[3]) {
|
|
767
793
|
await sessionInboxRead(sessionArgs[2], sessionArgs[3], targetMachineId);
|
|
@@ -771,7 +797,7 @@ async function handleSessionCommand() {
|
|
|
771
797
|
}
|
|
772
798
|
} else if (inboxSubcmd === "reply") {
|
|
773
799
|
if (agentSessionId && sessionArgs[2] && sessionArgs[3] && !sessionArgs[4]) {
|
|
774
|
-
const { inboxReply } = await import('./agentCommands-
|
|
800
|
+
const { inboxReply } = await import('./agentCommands-BvmStLoh.mjs');
|
|
775
801
|
await inboxReply(sessionArgs[2], sessionArgs[3]);
|
|
776
802
|
} else if (sessionArgs[2] && sessionArgs[3] && sessionArgs[4]) {
|
|
777
803
|
await sessionInboxReply(sessionArgs[2], sessionArgs[3], sessionArgs[4], targetMachineId);
|
|
@@ -807,7 +833,7 @@ async function handleMachineCommand() {
|
|
|
807
833
|
return;
|
|
808
834
|
}
|
|
809
835
|
if (machineSubcommand === "share") {
|
|
810
|
-
const { machineShare } = await import('./commands-
|
|
836
|
+
const { machineShare } = await import('./commands-CWKFZm9s.mjs');
|
|
811
837
|
let machineId;
|
|
812
838
|
const shareArgs = [];
|
|
813
839
|
for (let i = 1; i < machineArgs.length; i++) {
|
|
@@ -837,7 +863,7 @@ async function handleMachineCommand() {
|
|
|
837
863
|
}
|
|
838
864
|
await machineShare(machineId, { add, remove, list, configPath, showConfig });
|
|
839
865
|
} else if (machineSubcommand === "exec") {
|
|
840
|
-
const { machineExec } = await import('./commands-
|
|
866
|
+
const { machineExec } = await import('./commands-CWKFZm9s.mjs');
|
|
841
867
|
let machineId;
|
|
842
868
|
let cwd;
|
|
843
869
|
const cmdParts = [];
|
|
@@ -857,7 +883,7 @@ async function handleMachineCommand() {
|
|
|
857
883
|
}
|
|
858
884
|
await machineExec(machineId, command, cwd);
|
|
859
885
|
} else if (machineSubcommand === "info") {
|
|
860
|
-
const { machineInfo } = await import('./commands-
|
|
886
|
+
const { machineInfo } = await import('./commands-CWKFZm9s.mjs');
|
|
861
887
|
let machineId;
|
|
862
888
|
for (let i = 1; i < machineArgs.length; i++) {
|
|
863
889
|
if ((machineArgs[i] === "--machine" || machineArgs[i] === "-m") && i + 1 < machineArgs.length) {
|
|
@@ -877,10 +903,10 @@ async function handleMachineCommand() {
|
|
|
877
903
|
level = machineArgs[++i];
|
|
878
904
|
}
|
|
879
905
|
}
|
|
880
|
-
const { machineNotify } = await import('./agentCommands-
|
|
906
|
+
const { machineNotify } = await import('./agentCommands-BvmStLoh.mjs');
|
|
881
907
|
await machineNotify(message, level);
|
|
882
908
|
} else if (machineSubcommand === "ls") {
|
|
883
|
-
const { machineLs } = await import('./commands-
|
|
909
|
+
const { machineLs } = await import('./commands-CWKFZm9s.mjs');
|
|
884
910
|
let machineId;
|
|
885
911
|
let showHidden = false;
|
|
886
912
|
let path;
|
|
@@ -1318,8 +1344,92 @@ Usage:
|
|
|
1318
1344
|
svamp daemon status Show daemon status
|
|
1319
1345
|
svamp daemon install Install as login service (macOS/Linux) \u2014 auto-start at login
|
|
1320
1346
|
svamp daemon uninstall Remove login service
|
|
1347
|
+
svamp daemon auth Show Claude API auth mode used for spawned sessions
|
|
1348
|
+
svamp daemon auth use-hypha-proxy Route Claude through https://proxy.hypha.aicell.io with HYPHA_TOKEN
|
|
1349
|
+
svamp daemon auth use-login Use ~/.claude credentials (run "claude login" to set them)
|
|
1350
|
+
svamp daemon auth set <URL> <KEY> Use a custom Anthropic gateway (base URL must not end in /v1)
|
|
1351
|
+
|
|
1352
|
+
Claude auth flags (take effect on next start/restart):
|
|
1353
|
+
svamp daemon start --use-hypha-proxy
|
|
1354
|
+
svamp daemon start --use-claude-login
|
|
1355
|
+
svamp daemon start --anthropic-base-url URL --anthropic-api-key KEY
|
|
1321
1356
|
`);
|
|
1322
1357
|
}
|
|
1358
|
+
async function applyClaudeAuthFlags(argv) {
|
|
1359
|
+
const hasHypha = argv.includes("--use-hypha-proxy");
|
|
1360
|
+
const hasLogin = argv.includes("--use-claude-login") || argv.includes("--use-login");
|
|
1361
|
+
const baseUrlIdx = argv.indexOf("--anthropic-base-url");
|
|
1362
|
+
const apiKeyIdx = argv.indexOf("--anthropic-api-key");
|
|
1363
|
+
const hasCustom = baseUrlIdx !== -1 || apiKeyIdx !== -1;
|
|
1364
|
+
const chosen = [hasHypha, hasLogin, hasCustom].filter(Boolean).length;
|
|
1365
|
+
if (chosen === 0) return;
|
|
1366
|
+
if (chosen > 1) {
|
|
1367
|
+
throw new Error(
|
|
1368
|
+
"--use-hypha-proxy, --use-claude-login, and --anthropic-base-url/--anthropic-api-key are mutually exclusive"
|
|
1369
|
+
);
|
|
1370
|
+
}
|
|
1371
|
+
const mod = await import('./run-CRwkPQDW.mjs').then(function (n) { return n.k; });
|
|
1372
|
+
if (hasHypha) {
|
|
1373
|
+
mod.setClaudeAuthHyphaProxy();
|
|
1374
|
+
console.log("Claude auth configured: hypha-proxy (uses HYPHA_TOKEN live at each spawn).");
|
|
1375
|
+
return;
|
|
1376
|
+
}
|
|
1377
|
+
if (hasLogin) {
|
|
1378
|
+
mod.setClaudeAuthLogin();
|
|
1379
|
+
console.log('Claude auth configured: login (uses ~/.claude credentials \u2014 run "claude login" if needed).');
|
|
1380
|
+
return;
|
|
1381
|
+
}
|
|
1382
|
+
if (baseUrlIdx === -1 || apiKeyIdx === -1) {
|
|
1383
|
+
throw new Error("--anthropic-base-url and --anthropic-api-key must be passed together");
|
|
1384
|
+
}
|
|
1385
|
+
const baseUrl = argv[baseUrlIdx + 1];
|
|
1386
|
+
const apiKey = argv[apiKeyIdx + 1];
|
|
1387
|
+
if (!baseUrl || baseUrl.startsWith("--")) throw new Error("--anthropic-base-url requires a value");
|
|
1388
|
+
if (!apiKey || apiKey.startsWith("--")) throw new Error("--anthropic-api-key requires a value");
|
|
1389
|
+
mod.setClaudeAuthCustom(baseUrl, apiKey);
|
|
1390
|
+
console.log(`Claude auth configured: custom (base URL ${baseUrl}).`);
|
|
1391
|
+
}
|
|
1392
|
+
async function handleDaemonAuthCommand(argv) {
|
|
1393
|
+
const sub = (argv[0] || "status").toLowerCase();
|
|
1394
|
+
const mod = await import('./run-CRwkPQDW.mjs').then(function (n) { return n.k; });
|
|
1395
|
+
if (sub === "status" || sub === "show") {
|
|
1396
|
+
const s = mod.getClaudeAuthStatus();
|
|
1397
|
+
console.log(`Claude auth mode: ${s.mode}`);
|
|
1398
|
+
if (s.baseUrl) console.log(` ANTHROPIC_BASE_URL: ${s.baseUrl}`);
|
|
1399
|
+
if (s.apiKeyPreview) console.log(` ANTHROPIC_API_KEY : ${s.apiKeyPreview}`);
|
|
1400
|
+
if (s.mode === "login") {
|
|
1401
|
+
console.log(' (Claude subprocesses will use credentials from ~/.claude \u2014 run "claude login" to set them.)');
|
|
1402
|
+
}
|
|
1403
|
+
if (s.hyphaTokenMissing) {
|
|
1404
|
+
console.log(' WARNING: mode=hypha but HYPHA_TOKEN is not set \u2014 run "svamp login" first.');
|
|
1405
|
+
}
|
|
1406
|
+
return;
|
|
1407
|
+
}
|
|
1408
|
+
if (sub === "use-hypha-proxy") {
|
|
1409
|
+
mod.setClaudeAuthHyphaProxy();
|
|
1410
|
+
console.log('Claude auth set to hypha-proxy. Run "svamp daemon restart" to apply.');
|
|
1411
|
+
return;
|
|
1412
|
+
}
|
|
1413
|
+
if (sub === "use-login" || sub === "use-claude-login") {
|
|
1414
|
+
mod.setClaudeAuthLogin();
|
|
1415
|
+
console.log('Claude auth set to login (~/.claude credentials). Run "svamp daemon restart" to apply.');
|
|
1416
|
+
return;
|
|
1417
|
+
}
|
|
1418
|
+
if (sub === "set") {
|
|
1419
|
+
const baseUrl = argv[1];
|
|
1420
|
+
const apiKey = argv[2];
|
|
1421
|
+
if (!baseUrl || !apiKey) {
|
|
1422
|
+
console.error("Usage: svamp daemon auth set <base-url> <api-key>");
|
|
1423
|
+
process.exit(1);
|
|
1424
|
+
}
|
|
1425
|
+
mod.setClaudeAuthCustom(baseUrl, apiKey);
|
|
1426
|
+
console.log(`Claude auth set to custom (${baseUrl}). Run "svamp daemon restart" to apply.`);
|
|
1427
|
+
return;
|
|
1428
|
+
}
|
|
1429
|
+
console.error(`Unknown subcommand: svamp daemon auth ${sub}`);
|
|
1430
|
+
console.error("Available: status, use-hypha-proxy, use-login, set <URL> <KEY>");
|
|
1431
|
+
process.exit(1);
|
|
1432
|
+
}
|
|
1323
1433
|
function printSessionHelp() {
|
|
1324
1434
|
console.log(`
|
|
1325
1435
|
svamp session \u2014 Spawn and manage AI agent sessions
|
|
@@ -2,7 +2,7 @@ import { existsSync, readFileSync } from 'node:fs';
|
|
|
2
2
|
import { execSync } from 'node:child_process';
|
|
3
3
|
import { resolve, join } from 'node:path';
|
|
4
4
|
import os from 'node:os';
|
|
5
|
-
import { l as loadSecurityContextConfig, e as resolveSecurityContext, f as buildSecurityContextFromFlags, m as mergeSecurityContexts, c as connectToHypha } from './run-
|
|
5
|
+
import { l as loadSecurityContextConfig, e as resolveSecurityContext, f as buildSecurityContextFromFlags, m as mergeSecurityContexts, c as connectToHypha } from './run-CRwkPQDW.mjs';
|
|
6
6
|
import 'os';
|
|
7
7
|
import 'fs/promises';
|
|
8
8
|
import 'fs';
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { writeFileSync, readFileSync } from 'fs';
|
|
2
2
|
import { resolve } from 'path';
|
|
3
|
-
import { connectAndGetMachine } from './commands-
|
|
3
|
+
import { connectAndGetMachine } from './commands-CWKFZm9s.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-
|
|
8
|
+
import './run-CRwkPQDW.mjs';
|
|
9
9
|
import 'os';
|
|
10
10
|
import 'fs/promises';
|
|
11
11
|
import 'url';
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { c as connectToHypha, d as daemonStatus, g as getHyphaServerUrl, r as registerMachineService, a as registerSessionService, s as startDaemon, b as stopDaemon } from './run-
|
|
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-CRwkPQDW.mjs';
|
|
2
2
|
import 'os';
|
|
3
3
|
import 'fs/promises';
|
|
4
4
|
import 'fs';
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
var name = "svamp-cli";
|
|
2
|
+
var version = "0.2.39";
|
|
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 && tsc --noEmit && pkgroll",
|
|
21
|
+
typecheck: "tsc --noEmit",
|
|
22
|
+
test: "npx tsx test/test-authorize.mjs && npx tsx test/test-session-helpers.mjs && npx tsx test/test-cli-routing.mjs && npx tsx test/test-security-context.mjs && npx tsx test/test-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.36",
|
|
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 };
|
|
@@ -2,7 +2,7 @@ import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(im
|
|
|
2
2
|
import os from 'node:os';
|
|
3
3
|
import { join, resolve } from 'node:path';
|
|
4
4
|
import { mkdirSync, writeFileSync, existsSync, unlinkSync, readFileSync, watch } from 'node:fs';
|
|
5
|
-
import { c as connectToHypha, a as registerSessionService } from './run-
|
|
5
|
+
import { c as connectToHypha, a as registerSessionService } from './run-CRwkPQDW.mjs';
|
|
6
6
|
import { createServer } from 'node:http';
|
|
7
7
|
import { spawn } from 'node:child_process';
|
|
8
8
|
import { createInterface } from 'node:readline';
|
|
@@ -4922,6 +4922,170 @@ var credentialStaging = /*#__PURE__*/Object.freeze({
|
|
|
4922
4922
|
stageCredentialsForSharing: stageCredentialsForSharing
|
|
4923
4923
|
});
|
|
4924
4924
|
|
|
4925
|
+
function shouldIsolate(input) {
|
|
4926
|
+
if (input.forceIsolation) return true;
|
|
4927
|
+
const sessionCtx = input.sessionSecurityContext;
|
|
4928
|
+
if (sessionCtx === null) return false;
|
|
4929
|
+
if (sessionCtx !== void 0) return true;
|
|
4930
|
+
return input.optionsSecurityContext !== null && input.optionsSecurityContext !== void 0;
|
|
4931
|
+
}
|
|
4932
|
+
|
|
4933
|
+
const HYPHA_PROXY_BASE_URL = "https://proxy.hypha.aicell.io";
|
|
4934
|
+
const MODE_KEY = "SVAMP_CLAUDE_PROXY";
|
|
4935
|
+
const MANAGED_KEYS = /* @__PURE__ */ new Set([
|
|
4936
|
+
MODE_KEY,
|
|
4937
|
+
"ANTHROPIC_BASE_URL",
|
|
4938
|
+
"ANTHROPIC_API_KEY"
|
|
4939
|
+
]);
|
|
4940
|
+
function envFilePath() {
|
|
4941
|
+
const svampHome = process.env.SVAMP_HOME || join$1(homedir(), ".svamp");
|
|
4942
|
+
return join$1(svampHome, ".env");
|
|
4943
|
+
}
|
|
4944
|
+
function readEnvLines() {
|
|
4945
|
+
const file = envFilePath();
|
|
4946
|
+
if (!existsSync(file)) return [];
|
|
4947
|
+
return readFileSync(file, "utf-8").split("\n");
|
|
4948
|
+
}
|
|
4949
|
+
function writeEnvLines(lines) {
|
|
4950
|
+
const file = envFilePath();
|
|
4951
|
+
const dir = join$1(file, "..");
|
|
4952
|
+
if (!existsSync(dir)) mkdirSync$1(dir, { recursive: true });
|
|
4953
|
+
while (lines.length > 0 && lines[lines.length - 1].trim() === "") {
|
|
4954
|
+
lines.pop();
|
|
4955
|
+
}
|
|
4956
|
+
writeFileSync$1(file, lines.join("\n") + "\n", "utf-8");
|
|
4957
|
+
}
|
|
4958
|
+
function updateEnvFile(updates) {
|
|
4959
|
+
const lines = readEnvLines();
|
|
4960
|
+
const kept = [];
|
|
4961
|
+
const remainingUpdates = new Map(Object.entries(updates));
|
|
4962
|
+
for (const line of lines) {
|
|
4963
|
+
const trimmed = line.trim();
|
|
4964
|
+
if (!trimmed || trimmed.startsWith("#")) {
|
|
4965
|
+
kept.push(line);
|
|
4966
|
+
continue;
|
|
4967
|
+
}
|
|
4968
|
+
const eq = trimmed.indexOf("=");
|
|
4969
|
+
const key = eq === -1 ? trimmed : trimmed.slice(0, eq);
|
|
4970
|
+
if (remainingUpdates.has(key)) {
|
|
4971
|
+
const v = remainingUpdates.get(key);
|
|
4972
|
+
remainingUpdates.delete(key);
|
|
4973
|
+
if (v === void 0) continue;
|
|
4974
|
+
kept.push(`${key}=${v}`);
|
|
4975
|
+
continue;
|
|
4976
|
+
}
|
|
4977
|
+
kept.push(line);
|
|
4978
|
+
}
|
|
4979
|
+
for (const [key, v] of remainingUpdates) {
|
|
4980
|
+
if (v === void 0) continue;
|
|
4981
|
+
kept.push(`${key}=${v}`);
|
|
4982
|
+
}
|
|
4983
|
+
writeEnvLines(kept);
|
|
4984
|
+
}
|
|
4985
|
+
function currentMode() {
|
|
4986
|
+
const raw = (process.env[MODE_KEY] || "").trim().toLowerCase();
|
|
4987
|
+
if (raw === "hypha" || raw === "hypha-proxy") return "hypha";
|
|
4988
|
+
if (raw === "custom") return "custom";
|
|
4989
|
+
return "login";
|
|
4990
|
+
}
|
|
4991
|
+
function redactKey(key) {
|
|
4992
|
+
if (!key) return void 0;
|
|
4993
|
+
if (key.length <= 12) return "***";
|
|
4994
|
+
return `${key.slice(0, 8)}\u2026${key.slice(-4)}`;
|
|
4995
|
+
}
|
|
4996
|
+
function getClaudeAuthStatus() {
|
|
4997
|
+
const mode = currentMode();
|
|
4998
|
+
if (mode === "hypha") {
|
|
4999
|
+
const token = process.env.HYPHA_TOKEN;
|
|
5000
|
+
return {
|
|
5001
|
+
mode,
|
|
5002
|
+
baseUrl: HYPHA_PROXY_BASE_URL,
|
|
5003
|
+
apiKeyPreview: redactKey(token),
|
|
5004
|
+
hyphaTokenMissing: !token
|
|
5005
|
+
};
|
|
5006
|
+
}
|
|
5007
|
+
if (mode === "custom") {
|
|
5008
|
+
return {
|
|
5009
|
+
mode,
|
|
5010
|
+
baseUrl: process.env.ANTHROPIC_BASE_URL,
|
|
5011
|
+
apiKeyPreview: redactKey(process.env.ANTHROPIC_API_KEY)
|
|
5012
|
+
};
|
|
5013
|
+
}
|
|
5014
|
+
return { mode: "login" };
|
|
5015
|
+
}
|
|
5016
|
+
function setClaudeAuthHyphaProxy() {
|
|
5017
|
+
updateEnvFile({
|
|
5018
|
+
[MODE_KEY]: "hypha",
|
|
5019
|
+
// Hypha mode resolves token live at spawn — no stored copy.
|
|
5020
|
+
ANTHROPIC_BASE_URL: void 0,
|
|
5021
|
+
ANTHROPIC_API_KEY: void 0
|
|
5022
|
+
});
|
|
5023
|
+
}
|
|
5024
|
+
function setClaudeAuthLogin() {
|
|
5025
|
+
updateEnvFile({
|
|
5026
|
+
[MODE_KEY]: void 0,
|
|
5027
|
+
ANTHROPIC_BASE_URL: void 0,
|
|
5028
|
+
ANTHROPIC_API_KEY: void 0
|
|
5029
|
+
});
|
|
5030
|
+
}
|
|
5031
|
+
function setClaudeAuthCustom(baseUrl, apiKey) {
|
|
5032
|
+
if (!baseUrl) throw new Error("ANTHROPIC_BASE_URL is required for custom mode");
|
|
5033
|
+
if (!apiKey) throw new Error("ANTHROPIC_API_KEY is required for custom mode");
|
|
5034
|
+
const trimmed = baseUrl.replace(/\/+$/, "");
|
|
5035
|
+
if (trimmed.endsWith("/v1")) {
|
|
5036
|
+
throw new Error(
|
|
5037
|
+
"ANTHROPIC_BASE_URL must not end in /v1 \u2014 the SDK appends it, producing double /v1/v1/messages"
|
|
5038
|
+
);
|
|
5039
|
+
}
|
|
5040
|
+
updateEnvFile({
|
|
5041
|
+
[MODE_KEY]: "custom",
|
|
5042
|
+
ANTHROPIC_BASE_URL: trimmed,
|
|
5043
|
+
ANTHROPIC_API_KEY: apiKey
|
|
5044
|
+
});
|
|
5045
|
+
}
|
|
5046
|
+
function applyClaudeProxyEnv(spawnEnv) {
|
|
5047
|
+
const mode = currentMode();
|
|
5048
|
+
if (mode === "hypha") {
|
|
5049
|
+
const token = process.env.HYPHA_TOKEN;
|
|
5050
|
+
if (!token) {
|
|
5051
|
+
delete spawnEnv.ANTHROPIC_BASE_URL;
|
|
5052
|
+
delete spawnEnv.ANTHROPIC_API_KEY;
|
|
5053
|
+
return "hypha mode but HYPHA_TOKEN missing \u2014 falling back to login";
|
|
5054
|
+
}
|
|
5055
|
+
spawnEnv.ANTHROPIC_BASE_URL = HYPHA_PROXY_BASE_URL;
|
|
5056
|
+
spawnEnv.ANTHROPIC_API_KEY = token;
|
|
5057
|
+
return `hypha proxy (${HYPHA_PROXY_BASE_URL})`;
|
|
5058
|
+
}
|
|
5059
|
+
if (mode === "custom") {
|
|
5060
|
+
const url = process.env.ANTHROPIC_BASE_URL;
|
|
5061
|
+
const key = process.env.ANTHROPIC_API_KEY;
|
|
5062
|
+
if (!url || !key) {
|
|
5063
|
+
delete spawnEnv.ANTHROPIC_BASE_URL;
|
|
5064
|
+
delete spawnEnv.ANTHROPIC_API_KEY;
|
|
5065
|
+
return "custom mode but ANTHROPIC_BASE_URL/API_KEY missing \u2014 falling back to login";
|
|
5066
|
+
}
|
|
5067
|
+
spawnEnv.ANTHROPIC_BASE_URL = url;
|
|
5068
|
+
spawnEnv.ANTHROPIC_API_KEY = key;
|
|
5069
|
+
return `custom proxy (${url})`;
|
|
5070
|
+
}
|
|
5071
|
+
delete spawnEnv.ANTHROPIC_BASE_URL;
|
|
5072
|
+
delete spawnEnv.ANTHROPIC_API_KEY;
|
|
5073
|
+
return null;
|
|
5074
|
+
}
|
|
5075
|
+
const MANAGED_ENV_KEYS = Array.from(MANAGED_KEYS);
|
|
5076
|
+
|
|
5077
|
+
var claudeAuth = /*#__PURE__*/Object.freeze({
|
|
5078
|
+
__proto__: null,
|
|
5079
|
+
HYPHA_PROXY_BASE_URL: HYPHA_PROXY_BASE_URL,
|
|
5080
|
+
MANAGED_ENV_KEYS: MANAGED_ENV_KEYS,
|
|
5081
|
+
applyClaudeProxyEnv: applyClaudeProxyEnv,
|
|
5082
|
+
getClaudeAuthStatus: getClaudeAuthStatus,
|
|
5083
|
+
setClaudeAuthCustom: setClaudeAuthCustom,
|
|
5084
|
+
setClaudeAuthHyphaProxy: setClaudeAuthHyphaProxy,
|
|
5085
|
+
setClaudeAuthLogin: setClaudeAuthLogin,
|
|
5086
|
+
updateEnvFile: updateEnvFile
|
|
5087
|
+
});
|
|
5088
|
+
|
|
4925
5089
|
const DEFAULT_PROBE_INTERVAL_S = 10;
|
|
4926
5090
|
const DEFAULT_PROBE_TIMEOUT_S = 5;
|
|
4927
5091
|
const DEFAULT_PROBE_FAILURE_THRESHOLD = 3;
|
|
@@ -6300,6 +6464,20 @@ async function startDaemon(options) {
|
|
|
6300
6464
|
process.on("SIGINT", () => requestShutdown("os-signal"));
|
|
6301
6465
|
process.on("SIGTERM", () => requestShutdown("os-signal"));
|
|
6302
6466
|
process.on("SIGUSR1", () => requestShutdown("os-signal-cleanup"));
|
|
6467
|
+
const { watchParentLiveness } = await import('./supervisorLock-DwNAn0VN.mjs');
|
|
6468
|
+
const cancelParentWatchdog = watchParentLiveness({
|
|
6469
|
+
intervalMs: 5e3,
|
|
6470
|
+
onParentDeath: () => {
|
|
6471
|
+
logger.log("Supervisor process died \u2014 sync daemon shutting down to avoid orphan state");
|
|
6472
|
+
requestShutdown("supervisor-died");
|
|
6473
|
+
}
|
|
6474
|
+
});
|
|
6475
|
+
process.on("exit", () => {
|
|
6476
|
+
try {
|
|
6477
|
+
cancelParentWatchdog();
|
|
6478
|
+
} catch {
|
|
6479
|
+
}
|
|
6480
|
+
});
|
|
6303
6481
|
process.on("uncaughtException", (error) => {
|
|
6304
6482
|
if (shutdownRequested) return;
|
|
6305
6483
|
logger.error("Uncaught exception (non-fatal, daemon continues):", error);
|
|
@@ -6585,8 +6763,7 @@ async function startDaemon(options) {
|
|
|
6585
6763
|
}
|
|
6586
6764
|
});
|
|
6587
6765
|
}, buildIsolationConfig2 = function(dir) {
|
|
6588
|
-
if (!
|
|
6589
|
-
if (sessionMetadata.securityContext === null) return null;
|
|
6766
|
+
if (!shouldIsolateSession()) return null;
|
|
6590
6767
|
const method = isolationCapabilities.preferred;
|
|
6591
6768
|
if (!method) return null;
|
|
6592
6769
|
const detail = isolationCapabilities.details[method];
|
|
@@ -6603,10 +6780,10 @@ async function startDaemon(options) {
|
|
|
6603
6780
|
trustOverride: true
|
|
6604
6781
|
};
|
|
6605
6782
|
}
|
|
6606
|
-
if (
|
|
6783
|
+
if (stagedCredentials) {
|
|
6607
6784
|
config.credentialStagingPath = stagedCredentials.homePath;
|
|
6608
6785
|
}
|
|
6609
|
-
const activeSecurityContext =
|
|
6786
|
+
const activeSecurityContext = getActiveSecurityContext();
|
|
6610
6787
|
if (activeSecurityContext) {
|
|
6611
6788
|
config = applySecurityContext(config, activeSecurityContext);
|
|
6612
6789
|
}
|
|
@@ -6743,6 +6920,12 @@ async function startDaemon(options) {
|
|
|
6743
6920
|
"auto-approve-all": "bypassPermissions"
|
|
6744
6921
|
};
|
|
6745
6922
|
const toClaudePermissionMode = (mode) => CLAUDE_PERMISSION_MODE_MAP[mode] || mode;
|
|
6923
|
+
const getActiveSecurityContext = () => sessionMetadata.securityContext ?? options2.securityContext;
|
|
6924
|
+
const shouldIsolateSession = () => shouldIsolate({
|
|
6925
|
+
forceIsolation: options2.forceIsolation,
|
|
6926
|
+
sessionSecurityContext: sessionMetadata.securityContext,
|
|
6927
|
+
optionsSecurityContext: options2.securityContext
|
|
6928
|
+
});
|
|
6746
6929
|
let isolationCleanupFiles = [];
|
|
6747
6930
|
const spawnClaude = (initialMessage, meta) => {
|
|
6748
6931
|
const effectiveMeta = { ...lastSpawnMeta, ...meta };
|
|
@@ -6786,7 +6969,7 @@ async function startDaemon(options) {
|
|
|
6786
6969
|
if (wrapped.cleanupFiles) isolationCleanupFiles = wrapped.cleanupFiles;
|
|
6787
6970
|
sessionMetadata = { ...sessionMetadata, isolationMethod: isoConfig.method };
|
|
6788
6971
|
logger.log(`[Session ${sessionId}] Isolation: ${isoConfig.method} (binary: ${isoConfig.binaryPath})`);
|
|
6789
|
-
} else if (
|
|
6972
|
+
} else if (shouldIsolateSession()) {
|
|
6790
6973
|
logger.log(`[Session ${sessionId}] WARNING: No isolation runtime (nono/docker/podman) available. Session is NOT sandboxed.`);
|
|
6791
6974
|
sessionMetadata = { ...sessionMetadata, isolationMethod: void 0 };
|
|
6792
6975
|
} else {
|
|
@@ -6797,18 +6980,19 @@ async function startDaemon(options) {
|
|
|
6797
6980
|
delete spawnEnv.CLAUDECODE;
|
|
6798
6981
|
spawnEnv.SVAMP_SESSION_ID = sessionId;
|
|
6799
6982
|
delete spawnEnv.SVAMP_SANDBOXED;
|
|
6800
|
-
|
|
6983
|
+
const proxyDesc = applyClaudeProxyEnv(spawnEnv);
|
|
6984
|
+
if (proxyDesc) {
|
|
6985
|
+
logger.log(`[Session ${sessionId}] Claude auth: ${proxyDesc}`);
|
|
6986
|
+
}
|
|
6987
|
+
if (isoConfig && stagedCredentials) {
|
|
6801
6988
|
Object.assign(spawnEnv, stagedCredentials.env);
|
|
6802
6989
|
const filtered = {};
|
|
6803
6990
|
for (const [k, v] of Object.entries(spawnEnv)) {
|
|
6804
6991
|
if (v !== void 0) filtered[k] = v;
|
|
6805
6992
|
}
|
|
6806
6993
|
spawnEnv = sanitizeEnvForSharing(filtered);
|
|
6807
|
-
|
|
6808
|
-
|
|
6809
|
-
spawnEnv.SVAMP_SANDBOXED = "1";
|
|
6810
|
-
logger.log(`[Session ${sessionId}] Sandbox mode: ON (securityContext present)`);
|
|
6811
|
-
}
|
|
6994
|
+
spawnEnv.SVAMP_SANDBOXED = "1";
|
|
6995
|
+
logger.log(`[Session ${sessionId}] Credential staging: HOME=${stagedCredentials.homePath}, SVAMP_SANDBOXED=1`);
|
|
6812
6996
|
}
|
|
6813
6997
|
const child = spawn$1(spawnCommand, spawnArgs, {
|
|
6814
6998
|
cwd: directory,
|
|
@@ -7419,6 +7603,14 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
7419
7603
|
return { success: false, message: "Session was stopped during restart." };
|
|
7420
7604
|
}
|
|
7421
7605
|
if (claudeResumeId) {
|
|
7606
|
+
if (!stagedCredentials && shouldIsolateSession()) {
|
|
7607
|
+
try {
|
|
7608
|
+
stagedCredentials = await stageCredentialsForSharing(sessionId);
|
|
7609
|
+
logger.log(`[Session ${sessionId}] Credentials staged at ${stagedCredentials.homePath} (runtime enable)`);
|
|
7610
|
+
} catch (err) {
|
|
7611
|
+
logger.log(`[Session ${sessionId}] WARNING: Runtime credential staging failed: ${err.message}.`);
|
|
7612
|
+
}
|
|
7613
|
+
}
|
|
7422
7614
|
spawnClaude(void 0, { permissionMode: currentPermissionMode });
|
|
7423
7615
|
sessionService.updateMetadata(sessionMetadata);
|
|
7424
7616
|
logger.log(`[Session ${sessionId}] Claude respawned with --resume ${claudeResumeId}`);
|
|
@@ -7435,12 +7627,12 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
7435
7627
|
isRestartingClaude = false;
|
|
7436
7628
|
}
|
|
7437
7629
|
};
|
|
7438
|
-
if (
|
|
7630
|
+
if (shouldIsolateSession()) {
|
|
7439
7631
|
try {
|
|
7440
7632
|
stagedCredentials = await stageCredentialsForSharing(sessionId);
|
|
7441
7633
|
logger.log(`[Session ${sessionId}] Credentials staged at ${stagedCredentials.homePath}`);
|
|
7442
7634
|
} catch (err) {
|
|
7443
|
-
logger.log(`[Session ${sessionId}] WARNING: Credential staging failed: ${err.message}
|
|
7635
|
+
logger.log(`[Session ${sessionId}] WARNING: Credential staging failed: ${err.message}.`);
|
|
7444
7636
|
}
|
|
7445
7637
|
}
|
|
7446
7638
|
let processMessageQueueRef;
|
|
@@ -8357,7 +8549,8 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
8357
8549
|
const writeSvampConfigPatchAcp = svampConfigChecker.writeConfig;
|
|
8358
8550
|
const permissionHandler = new HyphaPermissionHandler(shouldAutoAllow2, logger.log);
|
|
8359
8551
|
let agentIsoConfig;
|
|
8360
|
-
|
|
8552
|
+
const agentShouldIsolate = Boolean(options2.forceIsolation) || Boolean(options2.securityContext);
|
|
8553
|
+
if (agentShouldIsolate && isolationCapabilities.preferred) {
|
|
8361
8554
|
const method = isolationCapabilities.preferred;
|
|
8362
8555
|
const detail = isolationCapabilities.details[method];
|
|
8363
8556
|
if (detail.found && detail.verified !== false) {
|
|
@@ -9014,18 +9207,31 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
9014
9207
|
}, HEARTBEAT_INTERVAL_MS);
|
|
9015
9208
|
const PROXY_TOKEN_REFRESH_INTERVAL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
9016
9209
|
let proxyTokenRefreshInterval;
|
|
9017
|
-
|
|
9210
|
+
const proxyMode = (process.env.SVAMP_CLAUDE_PROXY || "").toLowerCase();
|
|
9211
|
+
if (proxyMode === "hypha" || proxyMode === "hypha-proxy") {
|
|
9212
|
+
const refreshProxyToken = async () => {
|
|
9213
|
+
try {
|
|
9214
|
+
const freshToken = await server.generateToken({ expires_in: 30 * 24 * 3600 });
|
|
9215
|
+
process.env.HYPHA_TOKEN = freshToken;
|
|
9216
|
+
logger.log("Hypha proxy token refreshed (30-day expiry)");
|
|
9217
|
+
} catch (err) {
|
|
9218
|
+
logger.log(`Hypha proxy token refresh failed (will retry in 7 days): ${err}`);
|
|
9219
|
+
}
|
|
9220
|
+
};
|
|
9221
|
+
proxyTokenRefreshInterval = setInterval(refreshProxyToken, PROXY_TOKEN_REFRESH_INTERVAL_MS);
|
|
9222
|
+
logger.log("Hypha proxy token auto-refresh enabled (every 7 days)");
|
|
9223
|
+
} else if (process.env.ANTHROPIC_BASE_URL && !process.env.SVAMP_CLAUDE_PROXY) {
|
|
9018
9224
|
const refreshProxyToken = async () => {
|
|
9019
9225
|
try {
|
|
9020
9226
|
const freshToken = await server.generateToken({ expires_in: 30 * 24 * 3600 });
|
|
9021
9227
|
process.env.ANTHROPIC_API_KEY = freshToken;
|
|
9022
|
-
logger.log("Proxy token refreshed (30-day expiry)");
|
|
9228
|
+
logger.log("Proxy token refreshed (legacy, 30-day expiry)");
|
|
9023
9229
|
} catch (err) {
|
|
9024
9230
|
logger.log(`Proxy token refresh failed (will retry in 7 days): ${err}`);
|
|
9025
9231
|
}
|
|
9026
9232
|
};
|
|
9027
9233
|
proxyTokenRefreshInterval = setInterval(refreshProxyToken, PROXY_TOKEN_REFRESH_INTERVAL_MS);
|
|
9028
|
-
logger.log("Proxy token auto-refresh enabled (every 7 days)");
|
|
9234
|
+
logger.log("Proxy token auto-refresh enabled (legacy mode, every 7 days)");
|
|
9029
9235
|
}
|
|
9030
9236
|
let oauthRefreshInterval;
|
|
9031
9237
|
const refreshOAuthAndRestageCredentials = async () => {
|
|
@@ -9363,4 +9569,4 @@ var run = /*#__PURE__*/Object.freeze({
|
|
|
9363
9569
|
stopDaemon: stopDaemon
|
|
9364
9570
|
});
|
|
9365
9571
|
|
|
9366
|
-
export { DefaultTransport$1 as D, GeminiTransport$1 as G, registerSessionService as a, stopDaemon as b, connectToHypha as c, daemonStatus as d, resolveSecurityContext as e, buildSecurityContextFromFlags as f, getHyphaServerUrl as g, acpBackend as h, acpAgentConfig as i, codexMcpBackend as j,
|
|
9572
|
+
export { DefaultTransport$1 as D, GeminiTransport$1 as G, registerSessionService as a, stopDaemon as b, connectToHypha as c, daemonStatus as d, resolveSecurityContext as e, buildSecurityContextFromFlags as f, getHyphaServerUrl as g, acpBackend as h, acpAgentConfig as i, codexMcpBackend as j, claudeAuth as k, loadSecurityContextConfig as l, mergeSecurityContexts as m, run as n, registerMachineService as r, startDaemon as s };
|
|
@@ -52,7 +52,7 @@ async function handleServeCommand() {
|
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
async function serveAdd(args, machineId) {
|
|
55
|
-
const { connectAndGetMachine } = await import('./commands-
|
|
55
|
+
const { connectAndGetMachine } = await import('./commands-CWKFZm9s.mjs');
|
|
56
56
|
const pos = positionalArgs(args);
|
|
57
57
|
const name = pos[0];
|
|
58
58
|
if (!name) {
|
|
@@ -84,7 +84,7 @@ async function serveAdd(args, machineId) {
|
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
86
|
async function serveRemove(args, machineId) {
|
|
87
|
-
const { connectAndGetMachine } = await import('./commands-
|
|
87
|
+
const { connectAndGetMachine } = await import('./commands-CWKFZm9s.mjs');
|
|
88
88
|
const pos = positionalArgs(args);
|
|
89
89
|
const name = pos[0];
|
|
90
90
|
if (!name) {
|
|
@@ -104,7 +104,7 @@ async function serveRemove(args, machineId) {
|
|
|
104
104
|
}
|
|
105
105
|
}
|
|
106
106
|
async function serveList(args, machineId) {
|
|
107
|
-
const { connectAndGetMachine } = await import('./commands-
|
|
107
|
+
const { connectAndGetMachine } = await import('./commands-CWKFZm9s.mjs');
|
|
108
108
|
const all = hasFlag(args, "--all", "-a");
|
|
109
109
|
const json = hasFlag(args, "--json");
|
|
110
110
|
const sessionId = getFlag(args, "--session");
|
|
@@ -137,7 +137,7 @@ async function serveList(args, machineId) {
|
|
|
137
137
|
}
|
|
138
138
|
}
|
|
139
139
|
async function serveInfo(machineId) {
|
|
140
|
-
const { connectAndGetMachine } = await import('./commands-
|
|
140
|
+
const { connectAndGetMachine } = await import('./commands-CWKFZm9s.mjs');
|
|
141
141
|
const { machine, server } = await connectAndGetMachine(machineId);
|
|
142
142
|
try {
|
|
143
143
|
const info = await machine.serveInfo();
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { existsSync, readFileSync, unlinkSync, openSync, writeSync, closeSync } from 'node:fs';
|
|
2
|
+
import { execFileSync } from 'node:child_process';
|
|
3
|
+
|
|
4
|
+
function acquireSupervisorLock(pidFile, pid = process.pid) {
|
|
5
|
+
try {
|
|
6
|
+
const fd = openSync(pidFile, "wx");
|
|
7
|
+
try {
|
|
8
|
+
writeSync(fd, String(pid));
|
|
9
|
+
} finally {
|
|
10
|
+
closeSync(fd);
|
|
11
|
+
}
|
|
12
|
+
return { acquired: true };
|
|
13
|
+
} catch (err) {
|
|
14
|
+
if (err?.code !== "EEXIST") throw err;
|
|
15
|
+
}
|
|
16
|
+
let existingPid = 0;
|
|
17
|
+
try {
|
|
18
|
+
existingPid = parseInt(readFileSync(pidFile, "utf-8").trim(), 10);
|
|
19
|
+
} catch {
|
|
20
|
+
}
|
|
21
|
+
if (!existingPid || Number.isNaN(existingPid) || existingPid <= 0) {
|
|
22
|
+
try {
|
|
23
|
+
unlinkSync(pidFile);
|
|
24
|
+
} catch {
|
|
25
|
+
}
|
|
26
|
+
return { acquired: false, staleCleaned: true };
|
|
27
|
+
}
|
|
28
|
+
if (isPidAlive(existingPid)) {
|
|
29
|
+
return { acquired: false, heldBy: existingPid };
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
unlinkSync(pidFile);
|
|
33
|
+
} catch {
|
|
34
|
+
}
|
|
35
|
+
return { acquired: false, staleCleaned: true };
|
|
36
|
+
}
|
|
37
|
+
function acquireSupervisorLockWithRetry(pidFile, pid = process.pid) {
|
|
38
|
+
let result = acquireSupervisorLock(pidFile, pid);
|
|
39
|
+
if (!result.acquired && result.staleCleaned) {
|
|
40
|
+
result = acquireSupervisorLock(pidFile, pid);
|
|
41
|
+
}
|
|
42
|
+
return { acquired: result.acquired, heldBy: result.heldBy };
|
|
43
|
+
}
|
|
44
|
+
function releaseSupervisorLock(pidFile, pid = process.pid) {
|
|
45
|
+
try {
|
|
46
|
+
if (!existsSync(pidFile)) return;
|
|
47
|
+
const content = parseInt(readFileSync(pidFile, "utf-8").trim(), 10);
|
|
48
|
+
if (content === pid) unlinkSync(pidFile);
|
|
49
|
+
} catch {
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function isPidAlive(pid) {
|
|
53
|
+
if (!pid || Number.isNaN(pid) || pid <= 0) return false;
|
|
54
|
+
try {
|
|
55
|
+
process.kill(pid, 0);
|
|
56
|
+
return true;
|
|
57
|
+
} catch {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function findOrphanedSyncPids(currentSupervisorPid = process.pid) {
|
|
62
|
+
if (process.platform === "win32") return [];
|
|
63
|
+
const pids = [];
|
|
64
|
+
try {
|
|
65
|
+
const output = execFileSync("pgrep", ["-af", "svamp daemon start-sync"], {
|
|
66
|
+
encoding: "utf-8",
|
|
67
|
+
timeout: 5e3
|
|
68
|
+
});
|
|
69
|
+
for (const line of output.split("\n")) {
|
|
70
|
+
const trimmed = line.trim();
|
|
71
|
+
if (!trimmed) continue;
|
|
72
|
+
const match = trimmed.match(/^(\d+)\s/);
|
|
73
|
+
if (!match) continue;
|
|
74
|
+
const pid = parseInt(match[1], 10);
|
|
75
|
+
if (Number.isNaN(pid) || pid <= 0) continue;
|
|
76
|
+
if (pid === process.pid) continue;
|
|
77
|
+
const ppid = getPpid(pid);
|
|
78
|
+
if (ppid === currentSupervisorPid) continue;
|
|
79
|
+
pids.push(pid);
|
|
80
|
+
}
|
|
81
|
+
} catch (err) {
|
|
82
|
+
if (err?.status !== 1) ;
|
|
83
|
+
}
|
|
84
|
+
return pids;
|
|
85
|
+
}
|
|
86
|
+
function getPpid(pid) {
|
|
87
|
+
if (process.platform === "win32") return 0;
|
|
88
|
+
try {
|
|
89
|
+
const out = execFileSync("ps", ["-o", "ppid=", "-p", String(pid)], {
|
|
90
|
+
encoding: "utf-8",
|
|
91
|
+
timeout: 2e3
|
|
92
|
+
}).trim();
|
|
93
|
+
const ppid = parseInt(out, 10);
|
|
94
|
+
return Number.isNaN(ppid) ? 0 : ppid;
|
|
95
|
+
} catch {
|
|
96
|
+
return 0;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
async function killOrphanedSyncs(pids, opts = {}) {
|
|
100
|
+
if (pids.length === 0) return;
|
|
101
|
+
const log = opts.log || (() => {
|
|
102
|
+
});
|
|
103
|
+
const gracePeriodMs = opts.gracePeriodMs ?? 3e3;
|
|
104
|
+
log(`Killing ${pids.length} orphan sync daemon(s): ${pids.join(", ")}`);
|
|
105
|
+
for (const pid of pids) {
|
|
106
|
+
try {
|
|
107
|
+
process.kill(pid, "SIGTERM");
|
|
108
|
+
} catch {
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
const pollStep = 100;
|
|
112
|
+
const steps = Math.max(1, Math.ceil(gracePeriodMs / pollStep));
|
|
113
|
+
for (let i = 0; i < steps; i++) {
|
|
114
|
+
await new Promise((r) => setTimeout(r, pollStep));
|
|
115
|
+
if (pids.every((p) => !isPidAlive(p))) {
|
|
116
|
+
log("All orphan daemons exited cleanly");
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
const survivors = pids.filter(isPidAlive);
|
|
121
|
+
if (survivors.length > 0) {
|
|
122
|
+
log(`Force-killing survivors: ${survivors.join(", ")}`);
|
|
123
|
+
for (const pid of survivors) {
|
|
124
|
+
try {
|
|
125
|
+
process.kill(pid, "SIGKILL");
|
|
126
|
+
} catch {
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
function watchParentLiveness(opts) {
|
|
132
|
+
if (process.env.SVAMP_SUPERVISED !== "1") {
|
|
133
|
+
return () => {
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
const supervisorPid = process.ppid;
|
|
137
|
+
if (!supervisorPid || supervisorPid === 1) {
|
|
138
|
+
return () => {
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
const intervalMs = opts.intervalMs ?? 5e3;
|
|
142
|
+
let fired = false;
|
|
143
|
+
const timer = setInterval(() => {
|
|
144
|
+
if (fired) return;
|
|
145
|
+
if (!isPidAlive(supervisorPid)) {
|
|
146
|
+
fired = true;
|
|
147
|
+
clearInterval(timer);
|
|
148
|
+
opts.onParentDeath();
|
|
149
|
+
}
|
|
150
|
+
}, intervalMs);
|
|
151
|
+
timer.unref?.();
|
|
152
|
+
return () => {
|
|
153
|
+
clearInterval(timer);
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export { acquireSupervisorLock, acquireSupervisorLockWithRetry, findOrphanedSyncPids, getPpid, isPidAlive, killOrphanedSyncs, releaseSupervisorLock, watchParentLiveness };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "svamp-cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.39",
|
|
4
4
|
"description": "Svamp CLI — AI workspace daemon on Hypha Cloud",
|
|
5
5
|
"author": "Amun AI AB",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"scripts": {
|
|
21
21
|
"build": "rm -rf dist && tsc --noEmit && pkgroll",
|
|
22
22
|
"typecheck": "tsc --noEmit",
|
|
23
|
-
"test": "npx tsx test/test-authorize.mjs && npx tsx test/test-session-helpers.mjs && npx tsx test/test-cli-routing.mjs && npx tsx test/test-security-context.mjs && npx tsx test/test-ralph-loop.mjs && npx tsx test/test-message-helpers.mjs && npx tsx test/test-agent-config.mjs && npx tsx test/test-wrap-command.mjs && npx tsx test/test-credential-staging.mjs && npx tsx test/test-output-formatters.mjs && npx tsx test/test-agent-types.mjs && npx tsx test/test-transport.mjs && npx tsx test/test-session-update-handlers.mjs && npx tsx test/test-session-scanner.mjs && npx tsx test/test-hypha-client.mjs && npx tsx test/test-hook-settings.mjs && npx tsx test/test-session-service-logic.mjs && npx tsx test/test-daemon-persistence.mjs && npx tsx test/test-detect-isolation.mjs && npx tsx test/test-machine-service-logic.mjs && npx tsx test/test-interactive-helpers.mjs && npx tsx test/test-codex-backend.mjs && npx tsx test/test-acp-backend.mjs && npx tsx test/test-acp-bridge.mjs && npx tsx test/test-hook-server.mjs && npx tsx test/test-session-commands.mjs && npx tsx test/test-interactive-console.mjs && npx tsx test/test-session-messages.mjs && npx tsx test/test-skills.mjs && npx tsx test/test-agent-grouping.mjs && npx tsx test/test-ralph-loop-integration.mjs && npx tsx test/test-ralph-loop-modes.mjs && npx tsx test/test-machine-list-directory.mjs && npx tsx test/test-service-commands.mjs && npx tsx test/test-supervisor.mjs && npx tsx test/test-clear-detection.mjs && npx tsx test/test-session-consolidation.mjs && npx tsx test/test-inbox.mjs && 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-authorize.mjs && npx tsx test/test-session-helpers.mjs && npx tsx test/test-cli-routing.mjs && npx tsx test/test-security-context.mjs && npx tsx test/test-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",
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
var name = "svamp-cli";
|
|
2
|
-
var version = "0.2.37";
|
|
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 && tsc --noEmit && pkgroll",
|
|
21
|
-
typecheck: "tsc --noEmit",
|
|
22
|
-
test: "npx tsx test/test-authorize.mjs && npx tsx test/test-session-helpers.mjs && npx tsx test/test-cli-routing.mjs && npx tsx test/test-security-context.mjs && npx tsx test/test-ralph-loop.mjs && npx tsx test/test-message-helpers.mjs && npx tsx test/test-agent-config.mjs && npx tsx test/test-wrap-command.mjs && npx tsx test/test-credential-staging.mjs && npx tsx test/test-output-formatters.mjs && npx tsx test/test-agent-types.mjs && npx tsx test/test-transport.mjs && npx tsx test/test-session-update-handlers.mjs && npx tsx test/test-session-scanner.mjs && npx tsx test/test-hypha-client.mjs && npx tsx test/test-hook-settings.mjs && npx tsx test/test-session-service-logic.mjs && npx tsx test/test-daemon-persistence.mjs && npx tsx test/test-detect-isolation.mjs && npx tsx test/test-machine-service-logic.mjs && npx tsx test/test-interactive-helpers.mjs && npx tsx test/test-codex-backend.mjs && npx tsx test/test-acp-backend.mjs && npx tsx test/test-acp-bridge.mjs && npx tsx test/test-hook-server.mjs && npx tsx test/test-session-commands.mjs && npx tsx test/test-interactive-console.mjs && npx tsx test/test-session-messages.mjs && npx tsx test/test-skills.mjs && npx tsx test/test-agent-grouping.mjs && npx tsx test/test-ralph-loop-integration.mjs && npx tsx test/test-ralph-loop-modes.mjs && npx tsx test/test-machine-list-directory.mjs && npx tsx test/test-service-commands.mjs && npx tsx test/test-supervisor.mjs && npx tsx test/test-clear-detection.mjs && npx tsx test/test-session-consolidation.mjs && npx tsx test/test-inbox.mjs && 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.36",
|
|
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 };
|