svamp-cli 0.2.67 → 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-CVmNxFdC.mjs → agentCommands-BaQIO1T2.mjs} +2 -2
- package/dist/cli.mjs +104 -62
- package/dist/{commands-BO8gl_-u.mjs → commands-BMOelGYC.mjs} +333 -36
- package/dist/{commands-D7A1aWC1.mjs → commands-CB03m9-Z.mjs} +2 -2
- package/dist/{commands-B6yUtg85.mjs → commands-CdGLuwtQ.mjs} +3 -3
- package/dist/index.mjs +1 -1
- package/dist/{package-wAsRM-Wx.mjs → package-Cw40xKCx.mjs} +2 -3
- package/dist/{run-DZq12r28.mjs → run-BqAe7GgA.mjs} +77 -12
- package/dist/{run-B4a6wAxf.mjs → run-Di-48dsY.mjs} +1 -1
- package/dist/{serveCommands-B-Ij7oce.mjs → serveCommands-DpKi_PuD.mjs} +5 -5
- package/dist/{serveManager-D4f3wiSO.mjs → serveManager-Dy4afaLH.mjs} +1 -1
- package/package.json +2 -3
|
@@ -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-BMOelGYC.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-BMOelGYC.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-BqAe7GgA.mjs';
|
|
2
2
|
import 'os';
|
|
3
3
|
import 'fs/promises';
|
|
4
4
|
import 'fs';
|
|
@@ -44,7 +44,7 @@ async function main() {
|
|
|
44
44
|
console.error(`svamp daemon restart: ${err.message || err}`);
|
|
45
45
|
process.exit(1);
|
|
46
46
|
}
|
|
47
|
-
const { restartDaemon } = await import('./run-
|
|
47
|
+
const { restartDaemon } = await import('./run-BqAe7GgA.mjs').then(function (n) { return n.u; });
|
|
48
48
|
await restartDaemon();
|
|
49
49
|
process.exit(0);
|
|
50
50
|
}
|
|
@@ -280,7 +280,7 @@ async function main() {
|
|
|
280
280
|
console.error("svamp service: Service commands are not available in sandboxed sessions.");
|
|
281
281
|
process.exit(1);
|
|
282
282
|
}
|
|
283
|
-
const { handleServiceCommand } = await import('./commands-
|
|
283
|
+
const { handleServiceCommand } = await import('./commands-CdGLuwtQ.mjs');
|
|
284
284
|
await handleServiceCommand();
|
|
285
285
|
} else if (subcommand === "serve") {
|
|
286
286
|
const { isSandboxed: isSandboxedServe } = await import('./sandboxDetect-DNTcbgWD.mjs');
|
|
@@ -288,7 +288,7 @@ async function main() {
|
|
|
288
288
|
console.error("svamp serve: Serve commands are not available in sandboxed sessions.");
|
|
289
289
|
process.exit(1);
|
|
290
290
|
}
|
|
291
|
-
const { handleServeCommand } = await import('./serveCommands-
|
|
291
|
+
const { handleServeCommand } = await import('./serveCommands-DpKi_PuD.mjs');
|
|
292
292
|
await handleServeCommand();
|
|
293
293
|
process.exit(0);
|
|
294
294
|
} else if (subcommand === "process" || subcommand === "proc") {
|
|
@@ -297,7 +297,7 @@ async function main() {
|
|
|
297
297
|
console.error("svamp process: Process commands are not available in sandboxed sessions.");
|
|
298
298
|
process.exit(1);
|
|
299
299
|
}
|
|
300
|
-
const { processCommand } = await import('./commands-
|
|
300
|
+
const { processCommand } = await import('./commands-CB03m9-Z.mjs');
|
|
301
301
|
let machineId;
|
|
302
302
|
const processArgs = args.slice(1);
|
|
303
303
|
const mIdx = processArgs.findIndex((a) => a === "--machine" || a === "-m");
|
|
@@ -315,7 +315,7 @@ async function main() {
|
|
|
315
315
|
} else if (!subcommand || subcommand === "start") {
|
|
316
316
|
await handleInteractiveCommand();
|
|
317
317
|
} else if (subcommand === "--version" || subcommand === "-v") {
|
|
318
|
-
const pkg = await import('./package-
|
|
318
|
+
const pkg = await import('./package-Cw40xKCx.mjs').catch(() => ({ default: { version: "unknown" } }));
|
|
319
319
|
console.log(`svamp version: ${pkg.default.version}`);
|
|
320
320
|
} else {
|
|
321
321
|
console.error(`Unknown command: ${subcommand}`);
|
|
@@ -324,7 +324,7 @@ async function main() {
|
|
|
324
324
|
}
|
|
325
325
|
}
|
|
326
326
|
async function handleInteractiveCommand() {
|
|
327
|
-
const { runInteractive } = await import('./run-
|
|
327
|
+
const { runInteractive } = await import('./run-Di-48dsY.mjs');
|
|
328
328
|
const interactiveArgs = subcommand === "start" ? args.slice(1) : args;
|
|
329
329
|
let directory = process.cwd();
|
|
330
330
|
let resumeSessionId;
|
|
@@ -369,7 +369,7 @@ async function handleAgentCommand() {
|
|
|
369
369
|
return;
|
|
370
370
|
}
|
|
371
371
|
if (agentArgs[0] === "list") {
|
|
372
|
-
const { KNOWN_ACP_AGENTS, KNOWN_MCP_AGENTS: KNOWN_MCP_AGENTS2 } = await import('./run-
|
|
372
|
+
const { KNOWN_ACP_AGENTS, KNOWN_MCP_AGENTS: KNOWN_MCP_AGENTS2 } = await import('./run-BqAe7GgA.mjs').then(function (n) { return n.p; });
|
|
373
373
|
console.log("Known agents:");
|
|
374
374
|
for (const [name, config2] of Object.entries(KNOWN_ACP_AGENTS)) {
|
|
375
375
|
console.log(` ${name.padEnd(12)} ${config2.command} ${config2.args.join(" ")} (ACP)`);
|
|
@@ -381,7 +381,7 @@ async function handleAgentCommand() {
|
|
|
381
381
|
console.log('Use "svamp agent -- <command> [args]" for a custom ACP agent.');
|
|
382
382
|
return;
|
|
383
383
|
}
|
|
384
|
-
const { resolveAcpAgentConfig, KNOWN_MCP_AGENTS } = await import('./run-
|
|
384
|
+
const { resolveAcpAgentConfig, KNOWN_MCP_AGENTS } = await import('./run-BqAe7GgA.mjs').then(function (n) { return n.p; });
|
|
385
385
|
let cwd = process.cwd();
|
|
386
386
|
const filteredArgs = [];
|
|
387
387
|
for (let i = 0; i < agentArgs.length; i++) {
|
|
@@ -405,12 +405,12 @@ async function handleAgentCommand() {
|
|
|
405
405
|
console.log(`Starting ${config.agentName} agent in ${cwd}...`);
|
|
406
406
|
let backend;
|
|
407
407
|
if (KNOWN_MCP_AGENTS[config.agentName]) {
|
|
408
|
-
const { CodexMcpBackend } = await import('./run-
|
|
408
|
+
const { CodexMcpBackend } = await import('./run-BqAe7GgA.mjs').then(function (n) { return n.q; });
|
|
409
409
|
backend = new CodexMcpBackend({ cwd, log: logFn });
|
|
410
410
|
} else {
|
|
411
|
-
const { AcpBackend } = await import('./run-
|
|
412
|
-
const { GeminiTransport } = await import('./run-
|
|
413
|
-
const { DefaultTransport } = await import('./run-
|
|
411
|
+
const { AcpBackend } = await import('./run-BqAe7GgA.mjs').then(function (n) { return n.o; });
|
|
412
|
+
const { GeminiTransport } = await import('./run-BqAe7GgA.mjs').then(function (n) { return n.G; });
|
|
413
|
+
const { DefaultTransport } = await import('./run-BqAe7GgA.mjs').then(function (n) { return n.D; });
|
|
414
414
|
const transportHandler = config.agentName === "gemini" ? new GeminiTransport() : new DefaultTransport(config.agentName);
|
|
415
415
|
backend = new AcpBackend({
|
|
416
416
|
agentName: config.agentName,
|
|
@@ -537,7 +537,7 @@ async function handleSessionCommand() {
|
|
|
537
537
|
process.exit(1);
|
|
538
538
|
}
|
|
539
539
|
}
|
|
540
|
-
const { sessionList, sessionSpawn, sessionArchive, sessionResume, sessionDelete, sessionInfo, sessionMessages, sessionAttach, sessionMachines, sessionSend, sessionWait, sessionShare, sessionRalphStart, sessionRalphCancel, sessionRalphStatus, sessionInboxSend, sessionInboxList, sessionInboxRead, sessionInboxReply, sessionInboxClear } = await import('./commands-
|
|
540
|
+
const { sessionList, sessionSpawn, sessionArchive, sessionResume, sessionDelete, sessionInfo, sessionMessages, sessionAttach, sessionMachines, sessionSend, sessionWait, sessionShare, sessionRalphStart, sessionRalphCancel, sessionRalphStatus, sessionInboxSend, sessionInboxList, sessionInboxRead, sessionInboxReply, sessionInboxClear } = await import('./commands-BMOelGYC.mjs');
|
|
541
541
|
const parseFlagStr = (flag, shortFlag) => {
|
|
542
542
|
for (let i = 1; i < sessionArgs.length; i++) {
|
|
543
543
|
if ((sessionArgs[i] === flag || shortFlag) && i + 1 < sessionArgs.length) {
|
|
@@ -573,7 +573,13 @@ async function handleSessionCommand() {
|
|
|
573
573
|
const wait = hasFlag("--wait");
|
|
574
574
|
const worktree = hasFlag("--worktree");
|
|
575
575
|
const isolate = hasFlag("--isolate");
|
|
576
|
-
|
|
576
|
+
let permissionMode = parseFlagStr("--permission-mode") || parseFlagStr("-p");
|
|
577
|
+
if (!permissionMode && hasFlag("--require-approval")) {
|
|
578
|
+
permissionMode = "default";
|
|
579
|
+
}
|
|
580
|
+
if (!permissionMode) {
|
|
581
|
+
permissionMode = "bypassPermissions";
|
|
582
|
+
}
|
|
577
583
|
const securityContextPath = parseFlagStr("--security-context");
|
|
578
584
|
const denyNetwork = hasFlag("--deny-network");
|
|
579
585
|
const parentSessionId = parseFlagStr("--parent");
|
|
@@ -597,7 +603,7 @@ async function handleSessionCommand() {
|
|
|
597
603
|
allowDomain.push(sessionArgs[++i]);
|
|
598
604
|
}
|
|
599
605
|
}
|
|
600
|
-
const { parseShareArg } = await import('./commands-
|
|
606
|
+
const { parseShareArg } = await import('./commands-BMOelGYC.mjs');
|
|
601
607
|
const shareEntries = share.map((s) => parseShareArg(s));
|
|
602
608
|
await sessionSpawn(agent, dir, targetMachineId, {
|
|
603
609
|
message,
|
|
@@ -660,16 +666,35 @@ async function handleSessionCommand() {
|
|
|
660
666
|
await sessionAttach(sessionArgs[1], targetMachineId);
|
|
661
667
|
} else if (sessionSubcommand === "send") {
|
|
662
668
|
if (!sessionArgs[1] || !sessionArgs[2]) {
|
|
663
|
-
console.error('Usage: svamp session send <session-id> <message> [--subject "..."] [--urgency urgent|normal] [--wait] [--timeout N] [--json]');
|
|
669
|
+
console.error('Usage: svamp session send <session-id> <message> [--subject "..."] [--urgency urgent|normal] [--wait] [--response] [--btw] [--require-approval] [--timeout N] [--json]');
|
|
664
670
|
process.exit(1);
|
|
665
671
|
}
|
|
666
672
|
await sessionSend(sessionArgs[1], sessionArgs[2], targetMachineId, {
|
|
667
673
|
wait: hasFlag("--wait"),
|
|
674
|
+
response: hasFlag("--response"),
|
|
675
|
+
btw: hasFlag("--btw"),
|
|
676
|
+
requireApproval: hasFlag("--require-approval"),
|
|
668
677
|
timeout: parseFlagInt("--timeout"),
|
|
669
678
|
json: hasFlag("--json"),
|
|
670
679
|
subject: parseFlagStr("--subject"),
|
|
671
680
|
urgency: parseFlagStr("--urgency")
|
|
672
681
|
});
|
|
682
|
+
} else if (sessionSubcommand === "query") {
|
|
683
|
+
const dir = sessionArgs[1];
|
|
684
|
+
const prompt = sessionArgs[2];
|
|
685
|
+
if (!dir || !prompt) {
|
|
686
|
+
console.error("Usage: svamp session query <directory> <prompt> [--timeout N] [--keep] [--json] [--permission-mode MODE] [--tag NAME]");
|
|
687
|
+
console.error(" Spawns a stateless Claude session in <directory>, sends <prompt>, prints the answer, then deletes the session.");
|
|
688
|
+
process.exit(1);
|
|
689
|
+
}
|
|
690
|
+
const { sessionQuery } = await import('./commands-BMOelGYC.mjs');
|
|
691
|
+
await sessionQuery(dir, prompt, targetMachineId, {
|
|
692
|
+
timeout: parseFlagInt("--timeout"),
|
|
693
|
+
json: hasFlag("--json"),
|
|
694
|
+
keep: hasFlag("--keep"),
|
|
695
|
+
permissionMode: parseFlagStr("--permission-mode"),
|
|
696
|
+
tag: parseFlagStr("--tag")
|
|
697
|
+
});
|
|
673
698
|
} else if (sessionSubcommand === "wait") {
|
|
674
699
|
if (!sessionArgs[1]) {
|
|
675
700
|
console.error("Usage: svamp session wait <session-id> [--timeout N] [--json]");
|
|
@@ -695,7 +720,7 @@ async function handleSessionCommand() {
|
|
|
695
720
|
console.error("Usage: svamp session approve <session-id> [request-id] [--json]");
|
|
696
721
|
process.exit(1);
|
|
697
722
|
}
|
|
698
|
-
const { sessionApprove } = await import('./commands-
|
|
723
|
+
const { sessionApprove } = await import('./commands-BMOelGYC.mjs');
|
|
699
724
|
const approveReqId = sessionArgs[2] && !sessionArgs[2].startsWith("--") ? sessionArgs[2] : void 0;
|
|
700
725
|
await sessionApprove(sessionArgs[1], approveReqId, targetMachineId, {
|
|
701
726
|
json: hasFlag("--json")
|
|
@@ -705,7 +730,7 @@ async function handleSessionCommand() {
|
|
|
705
730
|
console.error("Usage: svamp session deny <session-id> [request-id] [--json]");
|
|
706
731
|
process.exit(1);
|
|
707
732
|
}
|
|
708
|
-
const { sessionDeny } = await import('./commands-
|
|
733
|
+
const { sessionDeny } = await import('./commands-BMOelGYC.mjs');
|
|
709
734
|
const denyReqId = sessionArgs[2] && !sessionArgs[2].startsWith("--") ? sessionArgs[2] : void 0;
|
|
710
735
|
await sessionDeny(sessionArgs[1], denyReqId, targetMachineId, {
|
|
711
736
|
json: hasFlag("--json")
|
|
@@ -741,7 +766,7 @@ async function handleSessionCommand() {
|
|
|
741
766
|
console.error("Usage: svamp session set-title <title>");
|
|
742
767
|
process.exit(1);
|
|
743
768
|
}
|
|
744
|
-
const { sessionSetTitle } = await import('./agentCommands-
|
|
769
|
+
const { sessionSetTitle } = await import('./agentCommands-BaQIO1T2.mjs');
|
|
745
770
|
await sessionSetTitle(title);
|
|
746
771
|
} else if (sessionSubcommand === "set-link") {
|
|
747
772
|
const url = sessionArgs[1];
|
|
@@ -750,7 +775,7 @@ async function handleSessionCommand() {
|
|
|
750
775
|
process.exit(1);
|
|
751
776
|
}
|
|
752
777
|
const label = sessionArgs[2] && !sessionArgs[2].startsWith("--") ? sessionArgs[2] : void 0;
|
|
753
|
-
const { sessionSetLink } = await import('./agentCommands-
|
|
778
|
+
const { sessionSetLink } = await import('./agentCommands-BaQIO1T2.mjs');
|
|
754
779
|
await sessionSetLink(url, label);
|
|
755
780
|
} else if (sessionSubcommand === "notify") {
|
|
756
781
|
const message = sessionArgs[1];
|
|
@@ -759,7 +784,7 @@ async function handleSessionCommand() {
|
|
|
759
784
|
process.exit(1);
|
|
760
785
|
}
|
|
761
786
|
const level = parseFlagStr("--level") || "info";
|
|
762
|
-
const { sessionNotify } = await import('./agentCommands-
|
|
787
|
+
const { sessionNotify } = await import('./agentCommands-BaQIO1T2.mjs');
|
|
763
788
|
await sessionNotify(message, level);
|
|
764
789
|
} else if (sessionSubcommand === "broadcast") {
|
|
765
790
|
const action = sessionArgs[1];
|
|
@@ -767,7 +792,7 @@ async function handleSessionCommand() {
|
|
|
767
792
|
console.error("Usage: svamp session broadcast <action> [args...]\nActions: open-canvas <url> [label], close-canvas, toast <message>");
|
|
768
793
|
process.exit(1);
|
|
769
794
|
}
|
|
770
|
-
const { sessionBroadcast } = await import('./agentCommands-
|
|
795
|
+
const { sessionBroadcast } = await import('./agentCommands-BaQIO1T2.mjs');
|
|
771
796
|
await sessionBroadcast(action, sessionArgs.slice(2).filter((a) => !a.startsWith("--")));
|
|
772
797
|
} else if (sessionSubcommand === "inbox") {
|
|
773
798
|
const inboxSubcmd = sessionArgs[1];
|
|
@@ -778,7 +803,7 @@ async function handleSessionCommand() {
|
|
|
778
803
|
process.exit(1);
|
|
779
804
|
}
|
|
780
805
|
if (agentSessionId) {
|
|
781
|
-
const { inboxSend } = await import('./agentCommands-
|
|
806
|
+
const { inboxSend } = await import('./agentCommands-BaQIO1T2.mjs');
|
|
782
807
|
await inboxSend(sessionArgs[2], {
|
|
783
808
|
body: sessionArgs[3],
|
|
784
809
|
subject: parseFlagStr("--subject"),
|
|
@@ -793,7 +818,7 @@ async function handleSessionCommand() {
|
|
|
793
818
|
}
|
|
794
819
|
} else if (inboxSubcmd === "list" || inboxSubcmd === "ls") {
|
|
795
820
|
if (agentSessionId && !sessionArgs[2]) {
|
|
796
|
-
const { inboxList } = await import('./agentCommands-
|
|
821
|
+
const { inboxList } = await import('./agentCommands-BaQIO1T2.mjs');
|
|
797
822
|
await inboxList({
|
|
798
823
|
unread: hasFlag("--unread"),
|
|
799
824
|
limit: parseFlagInt("--limit"),
|
|
@@ -815,7 +840,7 @@ async function handleSessionCommand() {
|
|
|
815
840
|
process.exit(1);
|
|
816
841
|
}
|
|
817
842
|
if (agentSessionId && !sessionArgs[3]) {
|
|
818
|
-
const { inboxList } = await import('./agentCommands-
|
|
843
|
+
const { inboxList } = await import('./agentCommands-BaQIO1T2.mjs');
|
|
819
844
|
await sessionInboxRead(agentSessionId, sessionArgs[2], targetMachineId);
|
|
820
845
|
} else if (sessionArgs[3]) {
|
|
821
846
|
await sessionInboxRead(sessionArgs[2], sessionArgs[3], targetMachineId);
|
|
@@ -825,7 +850,7 @@ async function handleSessionCommand() {
|
|
|
825
850
|
}
|
|
826
851
|
} else if (inboxSubcmd === "reply") {
|
|
827
852
|
if (agentSessionId && sessionArgs[2] && sessionArgs[3] && !sessionArgs[4]) {
|
|
828
|
-
const { inboxReply } = await import('./agentCommands-
|
|
853
|
+
const { inboxReply } = await import('./agentCommands-BaQIO1T2.mjs');
|
|
829
854
|
await inboxReply(sessionArgs[2], sessionArgs[3]);
|
|
830
855
|
} else if (sessionArgs[2] && sessionArgs[3] && sessionArgs[4]) {
|
|
831
856
|
await sessionInboxReply(sessionArgs[2], sessionArgs[3], sessionArgs[4], targetMachineId);
|
|
@@ -861,7 +886,7 @@ async function handleMachineCommand() {
|
|
|
861
886
|
return;
|
|
862
887
|
}
|
|
863
888
|
if (machineSubcommand === "share") {
|
|
864
|
-
const { machineShare } = await import('./commands-
|
|
889
|
+
const { machineShare } = await import('./commands-BMOelGYC.mjs');
|
|
865
890
|
let machineId;
|
|
866
891
|
const shareArgs = [];
|
|
867
892
|
for (let i = 1; i < machineArgs.length; i++) {
|
|
@@ -891,7 +916,7 @@ async function handleMachineCommand() {
|
|
|
891
916
|
}
|
|
892
917
|
await machineShare(machineId, { add, remove, list, configPath, showConfig });
|
|
893
918
|
} else if (machineSubcommand === "exec") {
|
|
894
|
-
const { machineExec } = await import('./commands-
|
|
919
|
+
const { machineExec } = await import('./commands-BMOelGYC.mjs');
|
|
895
920
|
let machineId;
|
|
896
921
|
let cwd;
|
|
897
922
|
const cmdParts = [];
|
|
@@ -911,7 +936,7 @@ async function handleMachineCommand() {
|
|
|
911
936
|
}
|
|
912
937
|
await machineExec(machineId, command, cwd);
|
|
913
938
|
} else if (machineSubcommand === "info") {
|
|
914
|
-
const { machineInfo } = await import('./commands-
|
|
939
|
+
const { machineInfo } = await import('./commands-BMOelGYC.mjs');
|
|
915
940
|
let machineId;
|
|
916
941
|
for (let i = 1; i < machineArgs.length; i++) {
|
|
917
942
|
if ((machineArgs[i] === "--machine" || machineArgs[i] === "-m") && i + 1 < machineArgs.length) {
|
|
@@ -931,10 +956,10 @@ async function handleMachineCommand() {
|
|
|
931
956
|
level = machineArgs[++i];
|
|
932
957
|
}
|
|
933
958
|
}
|
|
934
|
-
const { machineNotify } = await import('./agentCommands-
|
|
959
|
+
const { machineNotify } = await import('./agentCommands-BaQIO1T2.mjs');
|
|
935
960
|
await machineNotify(message, level);
|
|
936
961
|
} else if (machineSubcommand === "ls") {
|
|
937
|
-
const { machineLs } = await import('./commands-
|
|
962
|
+
const { machineLs } = await import('./commands-BMOelGYC.mjs');
|
|
938
963
|
let machineId;
|
|
939
964
|
let showHidden = false;
|
|
940
965
|
let path;
|
|
@@ -1307,12 +1332,12 @@ function printHelp() {
|
|
|
1307
1332
|
console.log(`
|
|
1308
1333
|
svamp \u2014 AI workspace on Hypha Cloud
|
|
1309
1334
|
|
|
1310
|
-
Quick start \u2014 spawn an agent to do a task (
|
|
1311
|
-
svamp session spawn claude -d ./project
|
|
1335
|
+
Quick start \u2014 spawn an agent to do a task (autonomous by default):
|
|
1336
|
+
svamp session spawn claude -d ./project --message "fix tests" --wait
|
|
1312
1337
|
|
|
1313
|
-
Note:
|
|
1314
|
-
|
|
1315
|
-
|
|
1338
|
+
Note: as of 0.2.69 spawn defaults to permission mode "bypassPermissions" so the
|
|
1339
|
+
child agent doesn't get stuck on tool-approval prompts. Pass --require-approval
|
|
1340
|
+
(or -p default / -p acceptEdits) when you want a human to gate tool use.
|
|
1316
1341
|
|
|
1317
1342
|
Commands:
|
|
1318
1343
|
svamp Start interactive Claude session (synced to cloud)
|
|
@@ -1324,7 +1349,8 @@ Commands:
|
|
|
1324
1349
|
|
|
1325
1350
|
Session management (requires daemon running):
|
|
1326
1351
|
svamp session spawn <agent> [opts] Spawn a new agent session (agents: claude, gemini, codex)
|
|
1327
|
-
svamp session send <id> <message> Send message to a session (--wait
|
|
1352
|
+
svamp session send <id> <message> Send message to a session (--wait, --response, --btw)
|
|
1353
|
+
svamp session query <dir> <prompt> Stateless one-shot: spawn \u2192 ask \u2192 answer \u2192 delete
|
|
1328
1354
|
svamp session wait <id> Wait for agent to become idle
|
|
1329
1355
|
svamp session messages <id> Show message history (--last N, --json, --raw)
|
|
1330
1356
|
svamp session info <id> Show session status & pending permissions
|
|
@@ -1403,7 +1429,7 @@ async function applyClaudeAuthFlags(argv) {
|
|
|
1403
1429
|
"--use-hypha-proxy, --use-claude-login, and --anthropic-base-url/--anthropic-api-key are mutually exclusive"
|
|
1404
1430
|
);
|
|
1405
1431
|
}
|
|
1406
|
-
const mod = await import('./run-
|
|
1432
|
+
const mod = await import('./run-BqAe7GgA.mjs').then(function (n) { return n.t; });
|
|
1407
1433
|
if (hasHypha) {
|
|
1408
1434
|
mod.setClaudeAuthHyphaProxy();
|
|
1409
1435
|
console.log("Claude auth configured: hypha-proxy (uses HYPHA_TOKEN live at each spawn).");
|
|
@@ -1441,7 +1467,7 @@ async function applyDaemonShareFlag(argv) {
|
|
|
1441
1467
|
}
|
|
1442
1468
|
}
|
|
1443
1469
|
if (collected.length === 0) return;
|
|
1444
|
-
const { updateEnvFile } = await import('./run-
|
|
1470
|
+
const { updateEnvFile } = await import('./run-BqAe7GgA.mjs').then(function (n) { return n.t; });
|
|
1445
1471
|
const seen = /* @__PURE__ */ new Set();
|
|
1446
1472
|
const deduped = collected.filter((e) => {
|
|
1447
1473
|
const k = e.toLowerCase();
|
|
@@ -1454,7 +1480,7 @@ async function applyDaemonShareFlag(argv) {
|
|
|
1454
1480
|
}
|
|
1455
1481
|
async function handleDaemonAuthCommand(argv) {
|
|
1456
1482
|
const sub = (argv[0] || "status").toLowerCase();
|
|
1457
|
-
const mod = await import('./run-
|
|
1483
|
+
const mod = await import('./run-BqAe7GgA.mjs').then(function (n) { return n.t; });
|
|
1458
1484
|
if (sub === "--help" || sub === "-h" || sub === "help") {
|
|
1459
1485
|
console.log(`
|
|
1460
1486
|
svamp daemon auth \u2014 Configure how Claude subprocesses authenticate
|
|
@@ -1520,9 +1546,8 @@ svamp session \u2014 Spawn and manage AI agent sessions
|
|
|
1520
1546
|
|
|
1521
1547
|
QUICK START \u2014 Spawn a session, give it a task, get results:
|
|
1522
1548
|
|
|
1523
|
-
# One-liner: spawn agent, send task, wait for completion
|
|
1524
|
-
svamp session spawn claude -d ./my-project
|
|
1525
|
-
--message "fix the failing tests" --wait
|
|
1549
|
+
# One-liner: spawn agent, send task, wait for completion (autonomous by default)
|
|
1550
|
+
svamp session spawn claude -d ./my-project --message "fix the failing tests" --wait
|
|
1526
1551
|
|
|
1527
1552
|
# The command prints the session ID (e.g., "abc12345-..."). Use it to:
|
|
1528
1553
|
svamp session messages abc1 --last 10 # read output (prefix match on ID)
|
|
@@ -1553,8 +1578,24 @@ COMMANDS:
|
|
|
1553
1578
|
info <id> [--json] Show status & pending permissions
|
|
1554
1579
|
|
|
1555
1580
|
Communicate:
|
|
1556
|
-
send <id> <message> [--wait] [--timeout N] [--json]
|
|
1557
|
-
Send a message to a running session
|
|
1581
|
+
send <id> <message> [--wait] [--response] [--btw] [--require-approval] [--timeout N] [--json]
|
|
1582
|
+
Send a message to a running session.
|
|
1583
|
+
--wait block until the agent goes idle
|
|
1584
|
+
--response block AND print the agent's
|
|
1585
|
+
text answer (implies --wait)
|
|
1586
|
+
--btw side-channel one-shot query via
|
|
1587
|
+
/btw \u2014 does NOT touch the
|
|
1588
|
+
running session's context window
|
|
1589
|
+
--require-approval do NOT pre-flight the target to
|
|
1590
|
+
bypassPermissions. Without this,
|
|
1591
|
+
send with --wait/--response auto-
|
|
1592
|
+
ensures bypass so the agent does
|
|
1593
|
+
not stall on tool prompts.
|
|
1594
|
+
query <directory> <prompt> [--timeout N] [--keep] [--json] [--permission-mode MODE] [--tag NAME]
|
|
1595
|
+
Stateless one-shot: spawn fresh Claude in
|
|
1596
|
+
<directory>, send <prompt>, print answer,
|
|
1597
|
+
delete the session. No existing session is
|
|
1598
|
+
affected. Use for reproducible Q&A.
|
|
1558
1599
|
messages <id> [--last N] [--json] Read message history (alias: msgs)
|
|
1559
1600
|
wait <id> [--timeout N] [--json] Wait for agent to become idle
|
|
1560
1601
|
attach <id> Attach interactive terminal (stdin/stdout)
|
|
@@ -1583,7 +1624,9 @@ COMMANDS:
|
|
|
1583
1624
|
|
|
1584
1625
|
SPAWN OPTIONS:
|
|
1585
1626
|
-d, --directory <path> Working directory (REQUIRED for meaningful work)
|
|
1586
|
-
-p, --permission-mode <mode> Permission mode (see below). Default: "
|
|
1627
|
+
-p, --permission-mode <mode> Permission mode (see below). Default: "bypassPermissions"
|
|
1628
|
+
--require-approval Opt into human-in-the-loop approval (alias for -p default).
|
|
1629
|
+
Without this flag, the agent runs autonomously.
|
|
1587
1630
|
--message <msg> Send this message to the agent immediately after spawn
|
|
1588
1631
|
--wait Block until agent finishes (idle). Combine with --message
|
|
1589
1632
|
for fire-and-forget: spawn \u2192 task \u2192 wait \u2192 done.
|
|
@@ -1593,15 +1636,14 @@ SPAWN OPTIONS:
|
|
|
1593
1636
|
--parent <sessionId> Set parent session (auto-set from SVAMP_SESSION_ID env)
|
|
1594
1637
|
|
|
1595
1638
|
PERMISSION MODES:
|
|
1639
|
+
bypassPermissions \u2605 Default. Auto-approve everything. No prompts, no pauses.
|
|
1640
|
+
Right choice for automation, CI, agent-spawning-agent.
|
|
1641
|
+
acceptEdits Auto-approve file edits. Still pauses for bash & dangerous tools.
|
|
1596
1642
|
default \u26A0 Agent PAUSES and waits for human approval before each tool use.
|
|
1597
1643
|
The agent will be stuck (exit code 2) until you run approve/deny.
|
|
1598
|
-
|
|
1599
|
-
acceptEdits Auto-approve file edits. Still pauses for bash & dangerous tools.
|
|
1600
|
-
bypassPermissions Auto-approve everything. No prompts, no pauses. Fully autonomous.
|
|
1601
|
-
Use this for automation, CI, or when spawning from another agent.
|
|
1644
|
+
Use only when a human is actively watching the session.
|
|
1602
1645
|
|
|
1603
|
-
|
|
1604
|
-
monitoring the session who can approve/deny tool requests in real time.
|
|
1646
|
+
Tip: pass --require-approval (or -p default) when you want a human gate.
|
|
1605
1647
|
|
|
1606
1648
|
PERMISSION WORKFLOW (only relevant for "default" and "acceptEdits" modes):
|
|
1607
1649
|
1. svamp session wait <id> --json \u2192 exit code 2 means permission pending
|
|
@@ -1652,32 +1694,32 @@ ID MATCHING:
|
|
|
1652
1694
|
EXAMPLES:
|
|
1653
1695
|
|
|
1654
1696
|
# === Common: Spawn agent to do a task and wait ===
|
|
1655
|
-
|
|
1697
|
+
# Default is bypassPermissions \u2014 no -p flag needed for autonomous runs.
|
|
1698
|
+
svamp session spawn claude -d ./my-project \\
|
|
1656
1699
|
--message "fix all TypeScript errors, run tsc to verify" --wait
|
|
1657
1700
|
|
|
1658
1701
|
# === Multi-step: Spawn, then send messages interactively ===
|
|
1659
|
-
ID=$(svamp session spawn claude -d ./proj
|
|
1702
|
+
ID=$(svamp session spawn claude -d ./proj)
|
|
1660
1703
|
svamp session send $ID "first, read the README" --wait
|
|
1661
1704
|
svamp session send $ID "now implement the feature described there" --wait
|
|
1662
1705
|
svamp session messages $ID --last 20
|
|
1663
1706
|
|
|
1664
1707
|
# === Spawn child session from another agent (e.g., in a bash tool) ===
|
|
1665
|
-
#
|
|
1666
|
-
|
|
1667
|
-
svamp session spawn claude -d /tmp/test-project -p bypassPermissions \\
|
|
1708
|
+
# bypassPermissions is the default; --wait blocks until done.
|
|
1709
|
+
svamp session spawn claude -d /tmp/test-project \\
|
|
1668
1710
|
--message "run the test suite and report results" --wait
|
|
1669
|
-
# Then read the child's output:
|
|
1670
1711
|
svamp session messages <child-id> --last 5
|
|
1671
1712
|
|
|
1672
|
-
# ===
|
|
1673
|
-
svamp session spawn claude -d ./proj --
|
|
1713
|
+
# === Human-in-the-loop: require approval for every tool ===
|
|
1714
|
+
svamp session spawn claude -d ./proj --require-approval \\
|
|
1715
|
+
--message "refactor auth module"
|
|
1674
1716
|
svamp session wait abc1 --json # exit code 2 = permission pending
|
|
1675
1717
|
svamp session approve abc1 # approve all pending
|
|
1676
1718
|
svamp session wait abc1 # wait for completion
|
|
1677
1719
|
|
|
1678
1720
|
# === Spawn on a remote machine ===
|
|
1679
1721
|
svamp session spawn claude -d /workspace -m my-cloud-box \\
|
|
1680
|
-
|
|
1722
|
+
--message "deploy to staging" --wait
|
|
1681
1723
|
|
|
1682
1724
|
# === Isolated session with network restrictions ===
|
|
1683
1725
|
svamp session spawn claude -d /tmp/sandbox --isolate --deny-network
|
|
@@ -2,7 +2,7 @@ import { existsSync, readFileSync } from 'node:fs';
|
|
|
2
2
|
import { execSync } from 'node:child_process';
|
|
3
3
|
import { resolve, join } from 'node:path';
|
|
4
4
|
import os from 'node:os';
|
|
5
|
-
import { n as normalizeAllowedUser, l as loadSecurityContextConfig, e as resolveSecurityContext, f as buildSecurityContextFromFlags, m as mergeSecurityContexts, c as connectToHypha, i as buildSessionShareUrl, j as buildMachineShareUrl } from './run-
|
|
5
|
+
import { n as normalizeAllowedUser, l as loadSecurityContextConfig, e as resolveSecurityContext, f as buildSecurityContextFromFlags, m as mergeSecurityContexts, c as connectToHypha, i as buildSessionShareUrl, j as buildMachineShareUrl } from './run-BqAe7GgA.mjs';
|
|
6
6
|
import 'os';
|
|
7
7
|
import 'fs/promises';
|
|
8
8
|
import 'fs';
|
|
@@ -73,7 +73,10 @@ function formatJson(data) {
|
|
|
73
73
|
|
|
74
74
|
const SESSION_RPC_PARAMS = {
|
|
75
75
|
getMessages: ["afterSeq", "limit"],
|
|
76
|
+
getMessageCount: [],
|
|
77
|
+
getLatestMessages: ["beforeSeq", "limit"],
|
|
76
78
|
sendMessage: ["content", "localId", "meta"],
|
|
79
|
+
btw: ["question"],
|
|
77
80
|
getMetadata: [],
|
|
78
81
|
updateMetadata: ["newMetadata", "expectedVersion"],
|
|
79
82
|
updateConfig: ["patch"],
|
|
@@ -97,6 +100,7 @@ const SESSION_RPC_PARAMS = {
|
|
|
97
100
|
getEffectiveRole: [],
|
|
98
101
|
updateSharing: ["newSharing"],
|
|
99
102
|
updateSecurityContext: ["newSecurityContext"],
|
|
103
|
+
setClaudeChrome: ["enabled"],
|
|
100
104
|
applySystemPrompt: ["prompt"],
|
|
101
105
|
sendInboxMessage: ["message"],
|
|
102
106
|
getInbox: ["opts"],
|
|
@@ -1001,10 +1005,10 @@ async function sessionSpawn(agent, directory, machineId, opts) {
|
|
|
1001
1005
|
if (result.type === "success") {
|
|
1002
1006
|
console.log(`Session started: ${result.sessionId}`);
|
|
1003
1007
|
if (result.message) console.log(` ${result.message}`);
|
|
1004
|
-
const
|
|
1005
|
-
if (
|
|
1006
|
-
console.log(`\x1B[33m\u26A0 Permission mode: ${
|
|
1007
|
-
console.log(`\x1B[33m Use
|
|
1008
|
+
const explicitPermMode = opts?.permissionMode;
|
|
1009
|
+
if (explicitPermMode && explicitPermMode !== "bypassPermissions") {
|
|
1010
|
+
console.log(`\x1B[33m\u26A0 Permission mode: ${explicitPermMode}. Agent will pause for tool approval.\x1B[0m`);
|
|
1011
|
+
console.log(`\x1B[33m Use \`svamp session approve <id>\` to unblock, or drop the flag to run autonomously.\x1B[0m`);
|
|
1008
1012
|
}
|
|
1009
1013
|
if (opts?.message && result.sessionId) {
|
|
1010
1014
|
const svc = getSessionProxy(machine, result.sessionId);
|
|
@@ -1357,63 +1361,356 @@ async function sessionAttach(sessionId, machineId) {
|
|
|
1357
1361
|
process.exit(0);
|
|
1358
1362
|
});
|
|
1359
1363
|
}
|
|
1364
|
+
async function snapshotLatestSeq(machine, fullId) {
|
|
1365
|
+
try {
|
|
1366
|
+
const r = await machine.sessionRPC(fullId, "getMessageCount", {});
|
|
1367
|
+
return Math.max(0, Number(r?.latestSeq ?? 0));
|
|
1368
|
+
} catch {
|
|
1369
|
+
try {
|
|
1370
|
+
const r = await machine.sessionRPC(fullId, "getLatestMessages", { limit: 1 });
|
|
1371
|
+
const msgs = r?.messages || [];
|
|
1372
|
+
return msgs.length > 0 ? Number(msgs[msgs.length - 1].seq || 0) : 0;
|
|
1373
|
+
} catch {
|
|
1374
|
+
return 0;
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
async function collectAssistantResponse(machine, fullId, afterSeq) {
|
|
1379
|
+
const pageLimit = 500;
|
|
1380
|
+
let cursor = afterSeq;
|
|
1381
|
+
const collected = [];
|
|
1382
|
+
const seqs = [];
|
|
1383
|
+
for (let i = 0; i < 20; i++) {
|
|
1384
|
+
const { messages, hasMore } = await machine.sessionRPC(
|
|
1385
|
+
fullId,
|
|
1386
|
+
"getMessages",
|
|
1387
|
+
{ afterSeq: cursor, limit: pageLimit }
|
|
1388
|
+
);
|
|
1389
|
+
if (!messages || messages.length === 0) break;
|
|
1390
|
+
for (const msg of messages) {
|
|
1391
|
+
const role = msg?.content?.role;
|
|
1392
|
+
if (role === "agent" || role === "assistant") {
|
|
1393
|
+
const data = msg.content?.content?.data || msg.content?.content;
|
|
1394
|
+
if (!data) continue;
|
|
1395
|
+
let blocks = null;
|
|
1396
|
+
if (data.type === "assistant") {
|
|
1397
|
+
const b = data.message?.content || data.content;
|
|
1398
|
+
blocks = Array.isArray(b) ? b : null;
|
|
1399
|
+
} else if (data.type === "output" && data.data?.type === "assistant") {
|
|
1400
|
+
const b = data.data.message?.content || data.data.content;
|
|
1401
|
+
blocks = Array.isArray(b) ? b : null;
|
|
1402
|
+
}
|
|
1403
|
+
if (blocks) {
|
|
1404
|
+
for (const block of blocks) {
|
|
1405
|
+
if (block.type === "text" && typeof block.text === "string" && block.text) {
|
|
1406
|
+
collected.push(block.text);
|
|
1407
|
+
if (!seqs.includes(msg.seq)) seqs.push(msg.seq);
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1410
|
+
} else if (data.type === "result" && typeof data.result === "string" && data.result) {
|
|
1411
|
+
collected.push(data.result);
|
|
1412
|
+
if (!seqs.includes(msg.seq)) seqs.push(msg.seq);
|
|
1413
|
+
} else if (data.type === "output" && data.data?.type === "result" && typeof data.data.result === "string" && data.data.result) {
|
|
1414
|
+
collected.push(data.data.result);
|
|
1415
|
+
if (!seqs.includes(msg.seq)) seqs.push(msg.seq);
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
cursor = Math.max(cursor, Number(msg.seq || 0));
|
|
1419
|
+
}
|
|
1420
|
+
if (!hasMore) break;
|
|
1421
|
+
}
|
|
1422
|
+
return { text: collected.join("\n").trim(), messageSeqs: seqs };
|
|
1423
|
+
}
|
|
1424
|
+
function validateSendOptions(opts) {
|
|
1425
|
+
if (!opts?.btw) return [];
|
|
1426
|
+
const incompatible = [];
|
|
1427
|
+
if (opts.subject) incompatible.push("--subject");
|
|
1428
|
+
if (opts.urgency) incompatible.push("--urgency");
|
|
1429
|
+
if (opts.wait) incompatible.push("--wait");
|
|
1430
|
+
if (opts.response) incompatible.push("--response");
|
|
1431
|
+
return incompatible;
|
|
1432
|
+
}
|
|
1433
|
+
async function sendCore(machine, fullId, message, opts) {
|
|
1434
|
+
if (opts?.btw) {
|
|
1435
|
+
const btwResult = await machine.sessionRPC(fullId, "btw", { question: message });
|
|
1436
|
+
if (!btwResult?.success) {
|
|
1437
|
+
return {
|
|
1438
|
+
sessionId: fullId,
|
|
1439
|
+
mode: "btw",
|
|
1440
|
+
sent: false,
|
|
1441
|
+
waited: false,
|
|
1442
|
+
status: "error",
|
|
1443
|
+
error: btwResult?.error || "btw failed"
|
|
1444
|
+
};
|
|
1445
|
+
}
|
|
1446
|
+
return {
|
|
1447
|
+
sessionId: fullId,
|
|
1448
|
+
mode: "btw",
|
|
1449
|
+
sent: true,
|
|
1450
|
+
waited: true,
|
|
1451
|
+
status: "idle",
|
|
1452
|
+
response: String(btwResult.answer || "")
|
|
1453
|
+
};
|
|
1454
|
+
}
|
|
1455
|
+
const wantResponse = !!opts?.response;
|
|
1456
|
+
const shouldWait = !!opts?.wait || wantResponse;
|
|
1457
|
+
let bypassEnsured = false;
|
|
1458
|
+
if (shouldWait && !opts?.requireApproval) {
|
|
1459
|
+
try {
|
|
1460
|
+
await machine.sessionRPC(fullId, "switchMode", { mode: "bypassPermissions" });
|
|
1461
|
+
bypassEnsured = true;
|
|
1462
|
+
} catch {
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
const preSeq = wantResponse ? await snapshotLatestSeq(machine, fullId) : 0;
|
|
1466
|
+
const { randomUUID } = await import('node:crypto');
|
|
1467
|
+
const inboxMessage = {
|
|
1468
|
+
messageId: randomUUID(),
|
|
1469
|
+
body: message,
|
|
1470
|
+
timestamp: Date.now(),
|
|
1471
|
+
read: false,
|
|
1472
|
+
from: `cli:${os.userInfo().username}`,
|
|
1473
|
+
to: fullId,
|
|
1474
|
+
subject: opts?.subject,
|
|
1475
|
+
urgency: opts?.urgency || "urgent"
|
|
1476
|
+
};
|
|
1477
|
+
const result = await machine.sessionRPC(fullId, "sendInboxMessage", { message: inboxMessage });
|
|
1478
|
+
let waitResult;
|
|
1479
|
+
if (shouldWait) {
|
|
1480
|
+
const timeoutMs = (opts?.timeout || 300) * 1e3;
|
|
1481
|
+
waitResult = await waitForBusyThenIdle(machine, fullId, timeoutMs);
|
|
1482
|
+
}
|
|
1483
|
+
if (waitResult?.pendingPermissions?.length) {
|
|
1484
|
+
return {
|
|
1485
|
+
sessionId: fullId,
|
|
1486
|
+
mode: "send",
|
|
1487
|
+
sent: true,
|
|
1488
|
+
messageId: result.messageId,
|
|
1489
|
+
waited: true,
|
|
1490
|
+
status: "permission-pending",
|
|
1491
|
+
pendingPermissions: waitResult.pendingPermissions,
|
|
1492
|
+
bypassEnsured
|
|
1493
|
+
};
|
|
1494
|
+
}
|
|
1495
|
+
let response;
|
|
1496
|
+
if (wantResponse) {
|
|
1497
|
+
response = await collectAssistantResponse(machine, fullId, preSeq);
|
|
1498
|
+
}
|
|
1499
|
+
return {
|
|
1500
|
+
sessionId: fullId,
|
|
1501
|
+
mode: "send",
|
|
1502
|
+
sent: true,
|
|
1503
|
+
messageId: result.messageId,
|
|
1504
|
+
waited: shouldWait,
|
|
1505
|
+
status: shouldWait ? "idle" : "sent",
|
|
1506
|
+
bypassEnsured,
|
|
1507
|
+
...wantResponse && response ? { response: response.text, responseSeqs: response.messageSeqs } : {}
|
|
1508
|
+
};
|
|
1509
|
+
}
|
|
1360
1510
|
async function sessionSend(sessionId, message, machineId, opts) {
|
|
1511
|
+
const incompatible = validateSendOptions(opts);
|
|
1512
|
+
if (incompatible.length) {
|
|
1513
|
+
console.error(`Error: --btw is incompatible with: ${incompatible.join(", ")}`);
|
|
1514
|
+
console.error(" --btw runs as a one-shot forked query that returns the answer directly.");
|
|
1515
|
+
process.exit(1);
|
|
1516
|
+
}
|
|
1361
1517
|
const { server, machine, fullId } = await connectAndResolveSession(sessionId, machineId);
|
|
1362
1518
|
try {
|
|
1363
|
-
const
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1519
|
+
const r = await sendCore(machine, fullId, message, opts);
|
|
1520
|
+
if (r.mode === "btw") {
|
|
1521
|
+
if (r.status === "error") {
|
|
1522
|
+
if (opts?.json) {
|
|
1523
|
+
console.log(formatJson({
|
|
1524
|
+
sessionId: r.sessionId,
|
|
1525
|
+
mode: "btw",
|
|
1526
|
+
message,
|
|
1527
|
+
success: false,
|
|
1528
|
+
error: r.error
|
|
1529
|
+
}));
|
|
1530
|
+
} else {
|
|
1531
|
+
console.error(`btw failed: ${r.error || "unknown error"}`);
|
|
1532
|
+
}
|
|
1533
|
+
process.exitCode = 1;
|
|
1534
|
+
return;
|
|
1535
|
+
}
|
|
1536
|
+
if (opts?.json) {
|
|
1537
|
+
console.log(formatJson({
|
|
1538
|
+
sessionId: r.sessionId,
|
|
1539
|
+
mode: "btw",
|
|
1540
|
+
message,
|
|
1541
|
+
success: true,
|
|
1542
|
+
response: r.response || ""
|
|
1543
|
+
}));
|
|
1544
|
+
} else if (r.response) {
|
|
1545
|
+
console.log(r.response);
|
|
1546
|
+
}
|
|
1547
|
+
return;
|
|
1379
1548
|
}
|
|
1380
|
-
if (
|
|
1549
|
+
if (r.status === "permission-pending") {
|
|
1381
1550
|
if (opts?.json) {
|
|
1382
1551
|
console.log(formatJson({
|
|
1383
|
-
sessionId:
|
|
1552
|
+
sessionId: r.sessionId,
|
|
1384
1553
|
message,
|
|
1385
1554
|
sent: true,
|
|
1386
|
-
messageId:
|
|
1555
|
+
messageId: r.messageId,
|
|
1387
1556
|
status: "permission-pending",
|
|
1388
|
-
pendingPermissions:
|
|
1557
|
+
pendingPermissions: r.pendingPermissions
|
|
1389
1558
|
}));
|
|
1390
1559
|
} else {
|
|
1391
|
-
console.log(`Message sent to session ${
|
|
1560
|
+
console.log(`Message sent to session ${r.sessionId.slice(0, 8)} (id: ${(r.messageId || "").slice(0, 8)})`);
|
|
1392
1561
|
console.log("Agent is waiting for permission approval:");
|
|
1393
|
-
for (const p of
|
|
1562
|
+
for (const p of r.pendingPermissions || []) {
|
|
1394
1563
|
const argsStr = JSON.stringify(p.arguments || {}).slice(0, 120);
|
|
1395
1564
|
console.log(` [${p.id.slice(0, 8)}] ${p.tool}(${argsStr})`);
|
|
1396
1565
|
}
|
|
1397
1566
|
console.log(`
|
|
1398
|
-
Use: svamp session approve ${
|
|
1567
|
+
Use: svamp session approve ${r.sessionId.slice(0, 8)}`);
|
|
1399
1568
|
}
|
|
1400
1569
|
process.exitCode = 2;
|
|
1401
|
-
|
|
1570
|
+
return;
|
|
1571
|
+
}
|
|
1572
|
+
if (opts?.json) {
|
|
1402
1573
|
console.log(formatJson({
|
|
1403
|
-
sessionId:
|
|
1574
|
+
sessionId: r.sessionId,
|
|
1404
1575
|
message,
|
|
1405
1576
|
sent: true,
|
|
1406
|
-
messageId:
|
|
1407
|
-
waited:
|
|
1408
|
-
status:
|
|
1577
|
+
messageId: r.messageId,
|
|
1578
|
+
waited: r.waited,
|
|
1579
|
+
status: r.status,
|
|
1580
|
+
...r.bypassEnsured ? { bypassEnsured: true } : {},
|
|
1581
|
+
...opts.response ? { response: r.response || "", responseSeqs: r.responseSeqs || [] } : {}
|
|
1409
1582
|
}));
|
|
1410
1583
|
} else {
|
|
1411
|
-
console.log(`Message sent to session ${
|
|
1412
|
-
if (
|
|
1584
|
+
console.log(`Message sent to session ${r.sessionId.slice(0, 8)} (id: ${(r.messageId || "").slice(0, 8)})`);
|
|
1585
|
+
if (r.waited) {
|
|
1413
1586
|
console.log("Agent is idle.");
|
|
1414
1587
|
}
|
|
1588
|
+
if (opts?.response) {
|
|
1589
|
+
if (r.response) {
|
|
1590
|
+
console.log("");
|
|
1591
|
+
console.log(r.response);
|
|
1592
|
+
} else {
|
|
1593
|
+
console.log("(no text response captured)");
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
} finally {
|
|
1598
|
+
await server.disconnect();
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
async function queryCore(machine, directory, prompt, opts) {
|
|
1602
|
+
const absDir = resolve(directory);
|
|
1603
|
+
const spawnOpts = {
|
|
1604
|
+
directory: absDir,
|
|
1605
|
+
agent: "claude",
|
|
1606
|
+
permissionMode: opts?.permissionMode || "bypassPermissions",
|
|
1607
|
+
tags: opts?.tag ? [opts.tag] : ["svamp-query"]
|
|
1608
|
+
};
|
|
1609
|
+
const spawn = await machine.spawnSession(spawnOpts);
|
|
1610
|
+
if (spawn.type !== "success" || !spawn.sessionId) {
|
|
1611
|
+
return {
|
|
1612
|
+
sessionId: "",
|
|
1613
|
+
mode: "query",
|
|
1614
|
+
sent: false,
|
|
1615
|
+
waited: false,
|
|
1616
|
+
status: "error",
|
|
1617
|
+
error: spawn.errorMessage || `spawn returned type=${spawn.type}`,
|
|
1618
|
+
directory: absDir
|
|
1619
|
+
};
|
|
1620
|
+
}
|
|
1621
|
+
const spawnedId = spawn.sessionId;
|
|
1622
|
+
const svc = getSessionProxy(machine, spawnedId);
|
|
1623
|
+
await svc.sendMessage(
|
|
1624
|
+
JSON.stringify({
|
|
1625
|
+
role: "user",
|
|
1626
|
+
content: { type: "text", text: prompt },
|
|
1627
|
+
meta: { sentFrom: "svamp-cli-query" }
|
|
1628
|
+
})
|
|
1629
|
+
);
|
|
1630
|
+
const timeoutMs = (opts?.timeout || 300) * 1e3;
|
|
1631
|
+
const waitResult = await waitForBusyThenIdle(machine, spawnedId, timeoutMs);
|
|
1632
|
+
if (waitResult.pendingPermissions?.length) {
|
|
1633
|
+
return {
|
|
1634
|
+
sessionId: spawnedId,
|
|
1635
|
+
mode: "query",
|
|
1636
|
+
sent: true,
|
|
1637
|
+
waited: true,
|
|
1638
|
+
status: "permission-pending",
|
|
1639
|
+
pendingPermissions: waitResult.pendingPermissions,
|
|
1640
|
+
error: `Agent paused for tool approval (${waitResult.pendingPermissions.length} pending). Pass --permission-mode bypassPermissions or approve the request manually.`,
|
|
1641
|
+
directory: absDir
|
|
1642
|
+
};
|
|
1643
|
+
}
|
|
1644
|
+
const response = await collectAssistantResponse(machine, spawnedId, 0);
|
|
1645
|
+
return {
|
|
1646
|
+
sessionId: spawnedId,
|
|
1647
|
+
mode: "query",
|
|
1648
|
+
sent: true,
|
|
1649
|
+
waited: true,
|
|
1650
|
+
status: "idle",
|
|
1651
|
+
response: response.text,
|
|
1652
|
+
responseSeqs: response.messageSeqs,
|
|
1653
|
+
directory: absDir
|
|
1654
|
+
};
|
|
1655
|
+
}
|
|
1656
|
+
async function sessionQuery(directory, prompt, machineId, opts) {
|
|
1657
|
+
const { server, machine } = await connectAndGetMachine(machineId);
|
|
1658
|
+
let spawnedId;
|
|
1659
|
+
try {
|
|
1660
|
+
const r = await queryCore(machine, directory, prompt, opts);
|
|
1661
|
+
spawnedId = r.sessionId || void 0;
|
|
1662
|
+
if (r.status === "error") {
|
|
1663
|
+
if (opts?.json) {
|
|
1664
|
+
console.log(formatJson({
|
|
1665
|
+
success: false,
|
|
1666
|
+
error: r.error,
|
|
1667
|
+
directory: r.directory
|
|
1668
|
+
}));
|
|
1669
|
+
} else {
|
|
1670
|
+
console.error(`Failed to spawn query session: ${r.error}`);
|
|
1671
|
+
}
|
|
1672
|
+
process.exitCode = 1;
|
|
1673
|
+
return;
|
|
1674
|
+
}
|
|
1675
|
+
if (r.status === "permission-pending") {
|
|
1676
|
+
if (opts?.json) {
|
|
1677
|
+
console.log(formatJson({
|
|
1678
|
+
success: false,
|
|
1679
|
+
sessionId: r.sessionId,
|
|
1680
|
+
directory: r.directory,
|
|
1681
|
+
error: r.error,
|
|
1682
|
+
pendingPermissions: r.pendingPermissions
|
|
1683
|
+
}));
|
|
1684
|
+
} else {
|
|
1685
|
+
console.error(r.error);
|
|
1686
|
+
}
|
|
1687
|
+
process.exitCode = 2;
|
|
1688
|
+
return;
|
|
1689
|
+
}
|
|
1690
|
+
if (opts?.json) {
|
|
1691
|
+
console.log(formatJson({
|
|
1692
|
+
success: true,
|
|
1693
|
+
sessionId: r.sessionId,
|
|
1694
|
+
directory: r.directory,
|
|
1695
|
+
prompt,
|
|
1696
|
+
response: r.response || "",
|
|
1697
|
+
responseSeqs: r.responseSeqs || []
|
|
1698
|
+
}));
|
|
1699
|
+
} else {
|
|
1700
|
+
if (r.response) {
|
|
1701
|
+
console.log(r.response);
|
|
1702
|
+
} else {
|
|
1703
|
+
console.log("(no text response captured)");
|
|
1704
|
+
}
|
|
1415
1705
|
}
|
|
1416
1706
|
} finally {
|
|
1707
|
+
if (spawnedId && !opts?.keep) {
|
|
1708
|
+
try {
|
|
1709
|
+
await machine.deleteSession(spawnedId);
|
|
1710
|
+
} catch (err) {
|
|
1711
|
+
console.error(`Warning: failed to delete query session ${spawnedId}: ${err?.message || err}`);
|
|
1712
|
+
}
|
|
1713
|
+
}
|
|
1417
1714
|
await server.disconnect();
|
|
1418
1715
|
}
|
|
1419
1716
|
}
|
|
@@ -1924,4 +2221,4 @@ async function sessionInboxClear(sessionIdPartial, machineId, opts) {
|
|
|
1924
2221
|
}
|
|
1925
2222
|
}
|
|
1926
2223
|
|
|
1927
|
-
export { connectAndGetMachine, connectAndResolveSession, createWorktree, generateWorktreeName, machineExec, machineInfo, machineLs, machineShare, parseShareArg, renderMessage, resolveSessionId, sessionApprove, sessionArchive, sessionAttach, sessionDelete, sessionDeny, sessionInboxClear, sessionInboxList, sessionInboxRead, sessionInboxReply, sessionInboxSend, sessionInfo, sessionList, sessionMachines, sessionMessages, sessionRalphCancel, sessionRalphStart, sessionRalphStatus, sessionResume, sessionSend, sessionShare, sessionSpawn, sessionWait };
|
|
2224
|
+
export { collectAssistantResponse, connectAndGetMachine, connectAndResolveSession, createWorktree, generateWorktreeName, machineExec, machineInfo, machineLs, machineShare, parseShareArg, queryCore, renderMessage, resolveSessionId, sendCore, sessionApprove, sessionArchive, sessionAttach, sessionDelete, sessionDeny, sessionInboxClear, sessionInboxList, sessionInboxRead, sessionInboxReply, sessionInboxSend, sessionInfo, sessionList, sessionMachines, sessionMessages, sessionQuery, sessionRalphCancel, sessionRalphStart, sessionRalphStatus, sessionResume, sessionSend, sessionShare, sessionSpawn, sessionWait, snapshotLatestSeq, validateSendOptions };
|
|
@@ -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-BMOelGYC.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-BqAe7GgA.mjs';
|
|
9
9
|
import 'os';
|
|
10
10
|
import 'fs/promises';
|
|
11
11
|
import 'url';
|
|
@@ -68,7 +68,7 @@ async function serviceExpose(args) {
|
|
|
68
68
|
});
|
|
69
69
|
return;
|
|
70
70
|
}
|
|
71
|
-
const { connectAndGetMachine } = await import('./commands-
|
|
71
|
+
const { connectAndGetMachine } = await import('./commands-BMOelGYC.mjs');
|
|
72
72
|
const { server, machine } = await connectAndGetMachine();
|
|
73
73
|
try {
|
|
74
74
|
const status = await machine.tunnelStart({
|
|
@@ -132,7 +132,7 @@ async function serviceServe(args) {
|
|
|
132
132
|
}
|
|
133
133
|
async function serviceList(_args) {
|
|
134
134
|
try {
|
|
135
|
-
const { connectAndGetMachine } = await import('./commands-
|
|
135
|
+
const { connectAndGetMachine } = await import('./commands-BMOelGYC.mjs');
|
|
136
136
|
const { server, machine } = await connectAndGetMachine();
|
|
137
137
|
try {
|
|
138
138
|
const tunnels = await machine.tunnelList({});
|
|
@@ -161,7 +161,7 @@ async function serviceDelete(args) {
|
|
|
161
161
|
process.exit(1);
|
|
162
162
|
}
|
|
163
163
|
try {
|
|
164
|
-
const { connectAndGetMachine } = await import('./commands-
|
|
164
|
+
const { connectAndGetMachine } = await import('./commands-BMOelGYC.mjs');
|
|
165
165
|
const { server, machine } = await connectAndGetMachine();
|
|
166
166
|
try {
|
|
167
167
|
await machine.tunnelStop({ name });
|
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-BqAe7GgA.mjs';
|
|
2
2
|
import 'os';
|
|
3
3
|
import 'fs/promises';
|
|
4
4
|
import 'fs';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
var name = "svamp-cli";
|
|
2
|
-
var version = "0.2.
|
|
2
|
+
var version = "0.2.70";
|
|
3
3
|
var description = "Svamp CLI — AI workspace daemon on Hypha Cloud";
|
|
4
4
|
var author = "Amun AI AB";
|
|
5
5
|
var license = "SEE LICENSE IN LICENSE";
|
|
@@ -19,12 +19,11 @@ var exports$1 = {
|
|
|
19
19
|
var scripts = {
|
|
20
20
|
build: "rm -rf dist bin/skills && mkdir -p bin/skills && cp -r ../../skills/artifact bin/skills/artifact && tsc --noEmit && pkgroll",
|
|
21
21
|
typecheck: "tsc --noEmit",
|
|
22
|
-
test: "npx tsx test/test-context-window.mjs && npx tsx test/test-authorize.mjs && npx tsx test/test-normalize-allowed-user.mjs && npx tsx test/test-share-url.mjs && npx tsx test/test-update-sharing-normalization.mjs && npx tsx test/test-staged-homes-sweep.mjs && npx tsx test/test-session-helpers.mjs && npx tsx test/test-cli-routing.mjs && npx tsx test/test-security-context.mjs && npx tsx test/test-isolation-decision.mjs && npx tsx test/test-ralph-loop.mjs && npx tsx test/test-message-helpers.mjs && npx tsx test/test-agent-config.mjs && npx tsx test/test-wrap-command.mjs && npx tsx test/test-credential-staging.mjs && npx tsx test/test-claude-auth.mjs && npx tsx test/test-output-formatters.mjs && npx tsx test/test-agent-types.mjs && npx tsx test/test-transport.mjs && npx tsx test/test-session-update-handlers.mjs && npx tsx test/test-session-scanner.mjs && npx tsx test/test-hypha-client.mjs && npx tsx test/test-hook-settings.mjs && npx tsx test/test-session-service-logic.mjs && npx tsx test/test-daemon-persistence.mjs && npx tsx test/test-detect-isolation.mjs && npx tsx test/test-machine-service-logic.mjs && npx tsx test/test-interactive-helpers.mjs && npx tsx test/test-codex-backend.mjs && npx tsx test/test-acp-backend.mjs && npx tsx test/test-acp-bridge.mjs && npx tsx test/test-hook-server.mjs && npx tsx test/test-session-commands.mjs && npx tsx test/test-interactive-console.mjs && npx tsx test/test-session-messages.mjs && npx tsx test/test-skills.mjs && npx tsx test/test-agent-grouping.mjs && npx tsx test/test-ralph-loop-integration.mjs && npx tsx test/test-ralph-loop-modes.mjs && npx tsx test/test-machine-list-directory.mjs && npx tsx test/test-service-commands.mjs && npx tsx test/test-supervisor.mjs && npx tsx test/test-supervisor-lock.mjs && npx tsx test/test-clear-detection.mjs && npx tsx test/test-session-consolidation.mjs && npx tsx test/test-inbox.mjs && npx tsx test/test-session-rpc-dispatch.mjs && npx tsx test/test-sandbox-cli.mjs && npx tsx test/test-serve-manager.mjs && npx tsx test/test-serve-stability.mjs && npx tsx test/test-frpc-e2e.mjs --unit-only",
|
|
22
|
+
test: "npx tsx test/test-context-window.mjs && npx tsx test/test-authorize.mjs && npx tsx test/test-normalize-allowed-user.mjs && npx tsx test/test-share-url.mjs && npx tsx test/test-update-sharing-normalization.mjs && npx tsx test/test-staged-homes-sweep.mjs && npx tsx test/test-session-helpers.mjs && npx tsx test/test-cli-routing.mjs && npx tsx test/test-security-context.mjs && npx tsx test/test-isolation-decision.mjs && npx tsx test/test-ralph-loop.mjs && npx tsx test/test-message-helpers.mjs && npx tsx test/test-agent-config.mjs && npx tsx test/test-wrap-command.mjs && npx tsx test/test-credential-staging.mjs && npx tsx test/test-claude-auth.mjs && npx tsx test/test-output-formatters.mjs && npx tsx test/test-agent-types.mjs && npx tsx test/test-transport.mjs && npx tsx test/test-session-update-handlers.mjs && npx tsx test/test-session-scanner.mjs && npx tsx test/test-hypha-client.mjs && npx tsx test/test-hook-settings.mjs && npx tsx test/test-session-service-logic.mjs && npx tsx test/test-daemon-persistence.mjs && npx tsx test/test-detect-isolation.mjs && npx tsx test/test-machine-service-logic.mjs && npx tsx test/test-interactive-helpers.mjs && npx tsx test/test-codex-backend.mjs && npx tsx test/test-acp-backend.mjs && npx tsx test/test-acp-bridge.mjs && npx tsx test/test-hook-server.mjs && npx tsx test/test-session-commands.mjs && npx tsx test/test-interactive-console.mjs && npx tsx test/test-session-messages.mjs && npx tsx test/test-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",
|
|
23
23
|
"test:hypha": "node --no-warnings test/test-hypha-service.mjs",
|
|
24
24
|
dev: "tsx src/cli.ts",
|
|
25
25
|
"dev:daemon": "tsx src/cli.ts daemon start-sync",
|
|
26
26
|
"test:e2e": "node --no-warnings test/e2e-session-tests.mjs",
|
|
27
|
-
"test:archive-resume": "node --no-warnings test/test-session-archive-resume.mjs",
|
|
28
27
|
"test:frpc": "npx tsx test/test-frpc-e2e.mjs"
|
|
29
28
|
};
|
|
30
29
|
var dependencies = {
|
|
@@ -1140,9 +1140,10 @@ async function registerMachineService(server, machineId, metadata, daemonState,
|
|
|
1140
1140
|
const { join: join2, resolve } = await import('path');
|
|
1141
1141
|
const { homedir } = await import('os');
|
|
1142
1142
|
const targetPath = resolve(path || homedir());
|
|
1143
|
+
const effectiveRole = getEffectiveRole(context, currentMetadata.sharing);
|
|
1143
1144
|
const home = homedir();
|
|
1144
|
-
const
|
|
1145
|
-
if (
|
|
1145
|
+
const restrictedToHome = effectiveRole === "view";
|
|
1146
|
+
if (restrictedToHome && targetPath !== home && !targetPath.startsWith(home + "/")) {
|
|
1146
1147
|
throw new Error(`Access denied: path must be within ${home}`);
|
|
1147
1148
|
}
|
|
1148
1149
|
const showHidden = options?.showHidden ?? false;
|
|
@@ -2116,6 +2117,22 @@ function createSessionStore(server, sessionId, initialMetadata, initialAgentStat
|
|
|
2116
2117
|
});
|
|
2117
2118
|
return await callbacks.onUpdateSecurityContext(resolvedContext);
|
|
2118
2119
|
},
|
|
2120
|
+
/** Toggle the Claude --chrome flag and restart the agent process.
|
|
2121
|
+
* Admin tier (owner or admin-shared user) can perform this. */
|
|
2122
|
+
setClaudeChrome: async (enabled, context) => {
|
|
2123
|
+
authorizeRequest(context, metadata.sharing, "admin");
|
|
2124
|
+
if (!callbacks.onSetClaudeChrome) {
|
|
2125
|
+
throw new Error("Chrome integration toggle is not supported for this session");
|
|
2126
|
+
}
|
|
2127
|
+
metadata = { ...metadata, claudeChrome: !!enabled };
|
|
2128
|
+
metadataVersion++;
|
|
2129
|
+
notifyListeners({
|
|
2130
|
+
type: "update-session",
|
|
2131
|
+
sessionId,
|
|
2132
|
+
metadata: { value: metadata, version: metadataVersion }
|
|
2133
|
+
});
|
|
2134
|
+
return await callbacks.onSetClaudeChrome(!!enabled);
|
|
2135
|
+
},
|
|
2119
2136
|
/** Apply a new system prompt and restart the agent process */
|
|
2120
2137
|
applySystemPrompt: async (prompt, context) => {
|
|
2121
2138
|
authorizeRequest(context, metadata.sharing, "admin");
|
|
@@ -2248,6 +2265,8 @@ function createSessionStore(server, sessionId, initialMetadata, initialAgentStat
|
|
|
2248
2265
|
claudeSessionId,
|
|
2249
2266
|
"--fork-session",
|
|
2250
2267
|
"--no-session-persistence",
|
|
2268
|
+
"--permission-mode",
|
|
2269
|
+
"bypassPermissions",
|
|
2251
2270
|
"--output-format",
|
|
2252
2271
|
"json",
|
|
2253
2272
|
"--max-turns",
|
|
@@ -5737,6 +5756,19 @@ btn.addEventListener('click', async () => {
|
|
|
5737
5756
|
return;
|
|
5738
5757
|
}
|
|
5739
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
|
+
|
|
5740
5772
|
btn.disabled = true;
|
|
5741
5773
|
statusEl.textContent = 'Opening Hypha sign-in\u2026';
|
|
5742
5774
|
|
|
@@ -5745,10 +5777,8 @@ btn.addEventListener('click', async () => {
|
|
|
5745
5777
|
server_url: hyphaServer,
|
|
5746
5778
|
login_callback: (context) => {
|
|
5747
5779
|
statusEl.textContent = 'Waiting for you to sign in\u2026';
|
|
5748
|
-
|
|
5749
|
-
|
|
5750
|
-
// popup blockers generally allow it.
|
|
5751
|
-
window.open(context.login_url, '_blank');
|
|
5780
|
+
try { popup.location.href = context.login_url; }
|
|
5781
|
+
catch (e) { window.open(context.login_url, '_blank'); }
|
|
5752
5782
|
},
|
|
5753
5783
|
});
|
|
5754
5784
|
|
|
@@ -5758,9 +5788,11 @@ btn.addEventListener('click', async () => {
|
|
|
5758
5788
|
const secure = location.protocol === 'https:' ? '; Secure' : '';
|
|
5759
5789
|
document.cookie = cookieName + '=' + token + '; path=/; SameSite=Lax' + secure;
|
|
5760
5790
|
|
|
5791
|
+
try { popup.close(); } catch (e) {}
|
|
5761
5792
|
statusEl.innerHTML = '<span class="ok">Signed in. Redirecting\u2026</span>';
|
|
5762
5793
|
setTimeout(() => { window.location.replace(redirectUrl); }, 300);
|
|
5763
5794
|
} catch (err) {
|
|
5795
|
+
try { popup.close(); } catch (e) {}
|
|
5764
5796
|
setError('Login failed: ' + (err && err.message ? err.message : err));
|
|
5765
5797
|
}
|
|
5766
5798
|
});
|
|
@@ -7816,7 +7848,7 @@ async function startDaemon(options) {
|
|
|
7816
7848
|
const list = loadExposedTunnels().filter((t) => t.name !== name);
|
|
7817
7849
|
saveExposedTunnels(list);
|
|
7818
7850
|
}
|
|
7819
|
-
const { ServeManager } = await import('./serveManager-
|
|
7851
|
+
const { ServeManager } = await import('./serveManager-Dy4afaLH.mjs');
|
|
7820
7852
|
const serveManager = new ServeManager(SVAMP_HOME, (msg) => logger.log(`[SERVE] ${msg}`), hyphaServerUrl);
|
|
7821
7853
|
ensureAutoInstalledSkills(logger).catch(() => {
|
|
7822
7854
|
});
|
|
@@ -8010,13 +8042,14 @@ async function startDaemon(options) {
|
|
|
8010
8042
|
const parentTracked = Array.from(pidToTrackedSession.values()).find((t) => t.svampSessionId === options2.parentSessionId);
|
|
8011
8043
|
return parentTracked?.directory ? { parentSessionPath: parentTracked.directory } : {};
|
|
8012
8044
|
})(),
|
|
8013
|
-
...options2.injectPlatformGuidance !== void 0 && { injectPlatformGuidance: options2.injectPlatformGuidance }
|
|
8045
|
+
...options2.injectPlatformGuidance !== void 0 && { injectPlatformGuidance: options2.injectPlatformGuidance },
|
|
8046
|
+
...options2.claudeChrome !== void 0 && { claudeChrome: options2.claudeChrome }
|
|
8014
8047
|
};
|
|
8015
8048
|
let claudeProcess = null;
|
|
8016
8049
|
const allPersisted = loadPersistedSessions();
|
|
8017
8050
|
const persisted = allPersisted.find((p) => p.sessionId === sessionId) || (resumeSessionId ? allPersisted.find((p) => p.claudeResumeId === resumeSessionId) : void 0);
|
|
8018
8051
|
let claudeResumeId = persisted?.claudeResumeId || (resumeSessionId || void 0);
|
|
8019
|
-
let currentPermissionMode = options2.permissionMode || persisted?.permissionMode || "
|
|
8052
|
+
let currentPermissionMode = options2.permissionMode || persisted?.permissionMode || "bypassPermissions";
|
|
8020
8053
|
const sessionCreatedAt = persisted?.createdAt || Date.now();
|
|
8021
8054
|
let lastSpawnMeta = persisted?.spawnMeta || {};
|
|
8022
8055
|
let sessionWasProcessing = !!options2.wasProcessing;
|
|
@@ -8172,6 +8205,13 @@ async function startDaemon(options) {
|
|
|
8172
8205
|
if (model) args.push("--model", model);
|
|
8173
8206
|
if (appendSystemPrompt) args.push("--append-system-prompt", appendSystemPrompt);
|
|
8174
8207
|
if (claudeResumeId) args.push("--resume", claudeResumeId);
|
|
8208
|
+
if (sessionMetadata.claudeChrome) {
|
|
8209
|
+
if (shouldIsolateSession()) {
|
|
8210
|
+
logger.log(`[Session ${sessionId}] claudeChrome=true but session is isolated; skipping --chrome (Chrome IPC not reachable from sandbox)`);
|
|
8211
|
+
} else {
|
|
8212
|
+
args.push("--chrome");
|
|
8213
|
+
}
|
|
8214
|
+
}
|
|
8175
8215
|
if (!hookSettings) {
|
|
8176
8216
|
try {
|
|
8177
8217
|
hookSettings = generateHookSettings({ id: sessionId });
|
|
@@ -8988,6 +9028,11 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
8988
9028
|
claudeResumeId,
|
|
8989
9029
|
"--fork-session",
|
|
8990
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",
|
|
8991
9036
|
"--output-format",
|
|
8992
9037
|
"stream-json",
|
|
8993
9038
|
"--verbose"
|
|
@@ -9122,6 +9167,9 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
9122
9167
|
},
|
|
9123
9168
|
onSwitchMode: async (mode) => {
|
|
9124
9169
|
const normalizedMode = toClaudePermissionMode(mode);
|
|
9170
|
+
if (currentPermissionMode === normalizedMode) {
|
|
9171
|
+
return;
|
|
9172
|
+
}
|
|
9125
9173
|
logger.log(`[Session ${sessionId}] Switch mode: ${mode}${mode !== normalizedMode ? ` \u2192 ${normalizedMode}` : ""}`);
|
|
9126
9174
|
if (isRestartingClaude || isSwitchingMode) {
|
|
9127
9175
|
logger.log(`[Session ${sessionId}] Switch mode deferred \u2014 restart/switch already in progress`);
|
|
@@ -9148,6 +9196,24 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
9148
9196
|
sessionMetadata = { ...sessionMetadata, securityContext: newSecurityContext };
|
|
9149
9197
|
return await restartClaudeHandler();
|
|
9150
9198
|
},
|
|
9199
|
+
onSetClaudeChrome: async (enabled) => {
|
|
9200
|
+
logger.log(`[Session ${sessionId}] Chrome integration ${enabled ? "enabled" : "disabled"} \u2014 restarting agent`);
|
|
9201
|
+
sessionMetadata = { ...sessionMetadata, claudeChrome: enabled };
|
|
9202
|
+
if (claudeResumeId && !trackedSession.stopped) {
|
|
9203
|
+
saveSession({
|
|
9204
|
+
sessionId,
|
|
9205
|
+
directory,
|
|
9206
|
+
claudeResumeId,
|
|
9207
|
+
permissionMode: currentPermissionMode,
|
|
9208
|
+
spawnMeta: lastSpawnMeta,
|
|
9209
|
+
metadata: sessionMetadata,
|
|
9210
|
+
createdAt: sessionCreatedAt,
|
|
9211
|
+
machineId,
|
|
9212
|
+
wasProcessing: sessionWasProcessing
|
|
9213
|
+
});
|
|
9214
|
+
}
|
|
9215
|
+
return await restartClaudeHandler();
|
|
9216
|
+
},
|
|
9151
9217
|
onSharingUpdate: (newSharing) => {
|
|
9152
9218
|
logger.log(`[Session ${sessionId}] Sharing config updated \u2014 persisting to disk`);
|
|
9153
9219
|
const oldSharing = sessionMetadata.sharing;
|
|
@@ -9190,7 +9256,6 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
9190
9256
|
if (trackedSession?.stopped) return;
|
|
9191
9257
|
logger.log(`[Session ${sessionId}] Inbox message received (urgency: ${message.urgency || "normal"}, from: ${message.from || "unknown"})`);
|
|
9192
9258
|
const formatted = formatInboxMessageXml(message);
|
|
9193
|
-
sessionService.markInboxRead(message.messageId);
|
|
9194
9259
|
if (message.urgency === "urgent") {
|
|
9195
9260
|
logger.log(`[Session ${sessionId}] Delivering urgent inbox message to agent`);
|
|
9196
9261
|
sessionService.pushMessage(formatted, "user");
|
|
@@ -9540,7 +9605,7 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
9540
9605
|
tags: options2.tags,
|
|
9541
9606
|
parentSessionId: options2.parentSessionId
|
|
9542
9607
|
};
|
|
9543
|
-
let currentPermissionMode = options2.permissionMode || "
|
|
9608
|
+
let currentPermissionMode = options2.permissionMode || "bypassPermissions";
|
|
9544
9609
|
const allowedTools = /* @__PURE__ */ new Set();
|
|
9545
9610
|
const allowedBashLiterals = /* @__PURE__ */ new Set();
|
|
9546
9611
|
const allowedBashPrefixes = /* @__PURE__ */ new Set();
|
|
@@ -9634,6 +9699,7 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
9634
9699
|
agentBackend.respondToPermission?.(requestId, params.approved);
|
|
9635
9700
|
},
|
|
9636
9701
|
onSwitchMode: (mode) => {
|
|
9702
|
+
if (currentPermissionMode === mode) return;
|
|
9637
9703
|
logger.log(`[${agentName} Session ${sessionId}] Switch mode: ${mode}`);
|
|
9638
9704
|
currentPermissionMode = mode;
|
|
9639
9705
|
},
|
|
@@ -9661,7 +9727,6 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
9661
9727
|
if (acpStopped) return;
|
|
9662
9728
|
logger.log(`[${agentName} Session ${sessionId}] Inbox message received (urgency: ${message.urgency || "normal"}, from: ${message.from || "unknown"})`);
|
|
9663
9729
|
const formatted = formatInboxMessageXml(message);
|
|
9664
|
-
sessionService.markInboxRead(message.messageId);
|
|
9665
9730
|
if (message.urgency === "urgent" && acpBackendReady) {
|
|
9666
9731
|
logger.log(`[${agentName} Session ${sessionId}] Delivering urgent inbox message to agent`);
|
|
9667
9732
|
sessionService.pushMessage(formatted, "user");
|
|
@@ -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';
|
|
@@ -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,12 +20,11 @@
|
|
|
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",
|
|
27
27
|
"test:e2e": "node --no-warnings test/e2e-session-tests.mjs",
|
|
28
|
-
"test:archive-resume": "node --no-warnings test/test-session-archive-resume.mjs",
|
|
29
28
|
"test:frpc": "npx tsx test/test-frpc-e2e.mjs"
|
|
30
29
|
},
|
|
31
30
|
"dependencies": {
|