svamp-cli 0.1.73 → 0.1.74
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-C6iGblcL.mjs → agentCommands-7GGmL2zY.mjs} +1 -0
- package/dist/cli.mjs +110 -27
- package/dist/{commands-gghG16ZB.mjs → commands-ClMc3nSg.mjs} +174 -38
- package/dist/{commands-CPy4F-7w.mjs → commands-dKkUOvUb.mjs} +3 -3
- package/dist/index.mjs +1 -1
- package/dist/{package-BAXhI1Iz.mjs → package-CCjeil_X.mjs} +1 -1
- package/dist/{run-DWTcdCOS.mjs → run-6QgabuQN.mjs} +337 -65
- package/dist/{run-C2UwUIgR.mjs → run-BgwhZgkT.mjs} +1 -1
- package/package.json +1 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { existsSync, readFileSync, mkdirSync, writeFileSync, renameSync } from 'node:fs';
|
|
2
2
|
import { join, dirname } from 'node:path';
|
|
3
3
|
import os from 'node:os';
|
|
4
|
+
import 'node:crypto';
|
|
4
5
|
|
|
5
6
|
const SVAMP_HOME = process.env.SVAMP_HOME || join(os.homedir(), ".svamp");
|
|
6
7
|
function getConfigPath(sessionId) {
|
package/dist/cli.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { b as stopDaemon, s as startDaemon, d as daemonStatus } from './run-
|
|
1
|
+
import { b as stopDaemon, s as startDaemon, d as daemonStatus } from './run-6QgabuQN.mjs';
|
|
2
2
|
import 'os';
|
|
3
3
|
import 'fs/promises';
|
|
4
4
|
import 'fs';
|
|
@@ -109,7 +109,7 @@ async function main() {
|
|
|
109
109
|
const { handleServiceCommand } = await import('./commands-BLjcT1Vl.mjs');
|
|
110
110
|
await handleServiceCommand();
|
|
111
111
|
} else if (subcommand === "process" || subcommand === "proc") {
|
|
112
|
-
const { processCommand } = await import('./commands-
|
|
112
|
+
const { processCommand } = await import('./commands-dKkUOvUb.mjs');
|
|
113
113
|
let machineId;
|
|
114
114
|
const processArgs = args.slice(1);
|
|
115
115
|
const mIdx = processArgs.findIndex((a) => a === "--machine" || a === "-m");
|
|
@@ -127,7 +127,7 @@ async function main() {
|
|
|
127
127
|
} else if (!subcommand || subcommand === "start") {
|
|
128
128
|
await handleInteractiveCommand();
|
|
129
129
|
} else if (subcommand === "--version" || subcommand === "-v") {
|
|
130
|
-
const pkg = await import('./package-
|
|
130
|
+
const pkg = await import('./package-CCjeil_X.mjs').catch(() => ({ default: { version: "unknown" } }));
|
|
131
131
|
console.log(`svamp version: ${pkg.default.version}`);
|
|
132
132
|
} else {
|
|
133
133
|
console.error(`Unknown command: ${subcommand}`);
|
|
@@ -136,7 +136,7 @@ async function main() {
|
|
|
136
136
|
}
|
|
137
137
|
}
|
|
138
138
|
async function handleInteractiveCommand() {
|
|
139
|
-
const { runInteractive } = await import('./run-
|
|
139
|
+
const { runInteractive } = await import('./run-BgwhZgkT.mjs');
|
|
140
140
|
const interactiveArgs = subcommand === "start" ? args.slice(1) : args;
|
|
141
141
|
let directory = process.cwd();
|
|
142
142
|
let resumeSessionId;
|
|
@@ -181,7 +181,7 @@ async function handleAgentCommand() {
|
|
|
181
181
|
return;
|
|
182
182
|
}
|
|
183
183
|
if (agentArgs[0] === "list") {
|
|
184
|
-
const { KNOWN_ACP_AGENTS, KNOWN_MCP_AGENTS: KNOWN_MCP_AGENTS2 } = await import('./run-
|
|
184
|
+
const { KNOWN_ACP_AGENTS, KNOWN_MCP_AGENTS: KNOWN_MCP_AGENTS2 } = await import('./run-6QgabuQN.mjs').then(function (n) { return n.i; });
|
|
185
185
|
console.log("Known agents:");
|
|
186
186
|
for (const [name, config2] of Object.entries(KNOWN_ACP_AGENTS)) {
|
|
187
187
|
console.log(` ${name.padEnd(12)} ${config2.command} ${config2.args.join(" ")} (ACP)`);
|
|
@@ -193,7 +193,7 @@ async function handleAgentCommand() {
|
|
|
193
193
|
console.log('Use "svamp agent -- <command> [args]" for a custom ACP agent.');
|
|
194
194
|
return;
|
|
195
195
|
}
|
|
196
|
-
const { resolveAcpAgentConfig, KNOWN_MCP_AGENTS } = await import('./run-
|
|
196
|
+
const { resolveAcpAgentConfig, KNOWN_MCP_AGENTS } = await import('./run-6QgabuQN.mjs').then(function (n) { return n.i; });
|
|
197
197
|
let cwd = process.cwd();
|
|
198
198
|
const filteredArgs = [];
|
|
199
199
|
for (let i = 0; i < agentArgs.length; i++) {
|
|
@@ -217,12 +217,12 @@ async function handleAgentCommand() {
|
|
|
217
217
|
console.log(`Starting ${config.agentName} agent in ${cwd}...`);
|
|
218
218
|
let backend;
|
|
219
219
|
if (KNOWN_MCP_AGENTS[config.agentName]) {
|
|
220
|
-
const { CodexMcpBackend } = await import('./run-
|
|
220
|
+
const { CodexMcpBackend } = await import('./run-6QgabuQN.mjs').then(function (n) { return n.j; });
|
|
221
221
|
backend = new CodexMcpBackend({ cwd, log: logFn });
|
|
222
222
|
} else {
|
|
223
|
-
const { AcpBackend } = await import('./run-
|
|
224
|
-
const { GeminiTransport } = await import('./run-
|
|
225
|
-
const { DefaultTransport } = await import('./run-
|
|
223
|
+
const { AcpBackend } = await import('./run-6QgabuQN.mjs').then(function (n) { return n.h; });
|
|
224
|
+
const { GeminiTransport } = await import('./run-6QgabuQN.mjs').then(function (n) { return n.G; });
|
|
225
|
+
const { DefaultTransport } = await import('./run-6QgabuQN.mjs').then(function (n) { return n.D; });
|
|
226
226
|
const transportHandler = config.agentName === "gemini" ? new GeminiTransport() : new DefaultTransport(config.agentName);
|
|
227
227
|
backend = new AcpBackend({
|
|
228
228
|
agentName: config.agentName,
|
|
@@ -340,7 +340,7 @@ async function handleSessionCommand() {
|
|
|
340
340
|
printSessionHelp();
|
|
341
341
|
return;
|
|
342
342
|
}
|
|
343
|
-
const { sessionList, sessionSpawn, sessionStop, sessionInfo, sessionMessages, sessionAttach, sessionMachines, sessionSend, sessionWait, sessionShare, sessionRalphStart, sessionRalphCancel, sessionRalphStatus, sessionQueueAdd, sessionQueueList, sessionQueueClear } = await import('./commands-
|
|
343
|
+
const { sessionList, sessionSpawn, sessionStop, sessionInfo, sessionMessages, sessionAttach, sessionMachines, sessionSend, sessionWait, sessionShare, sessionRalphStart, sessionRalphCancel, sessionRalphStatus, sessionQueueAdd, sessionQueueList, sessionQueueClear, sessionInboxSend, sessionInboxList, sessionInboxRead, sessionInboxReply, sessionInboxClear } = await import('./commands-ClMc3nSg.mjs');
|
|
344
344
|
const parseFlagStr = (flag, shortFlag) => {
|
|
345
345
|
for (let i = 1; i < sessionArgs.length; i++) {
|
|
346
346
|
if ((sessionArgs[i] === flag || shortFlag) && i + 1 < sessionArgs.length) {
|
|
@@ -400,7 +400,7 @@ async function handleSessionCommand() {
|
|
|
400
400
|
allowDomain.push(sessionArgs[++i]);
|
|
401
401
|
}
|
|
402
402
|
}
|
|
403
|
-
const { parseShareArg } = await import('./commands-
|
|
403
|
+
const { parseShareArg } = await import('./commands-ClMc3nSg.mjs');
|
|
404
404
|
const shareEntries = share.map((s) => parseShareArg(s));
|
|
405
405
|
await sessionSpawn(agent, dir, targetMachineId, {
|
|
406
406
|
message,
|
|
@@ -484,7 +484,7 @@ async function handleSessionCommand() {
|
|
|
484
484
|
console.error("Usage: svamp session approve <session-id> [request-id] [--json]");
|
|
485
485
|
process.exit(1);
|
|
486
486
|
}
|
|
487
|
-
const { sessionApprove } = await import('./commands-
|
|
487
|
+
const { sessionApprove } = await import('./commands-ClMc3nSg.mjs');
|
|
488
488
|
const approveReqId = sessionArgs[2] && !sessionArgs[2].startsWith("--") ? sessionArgs[2] : void 0;
|
|
489
489
|
await sessionApprove(sessionArgs[1], approveReqId, targetMachineId, {
|
|
490
490
|
json: hasFlag("--json")
|
|
@@ -494,7 +494,7 @@ async function handleSessionCommand() {
|
|
|
494
494
|
console.error("Usage: svamp session deny <session-id> [request-id] [--json]");
|
|
495
495
|
process.exit(1);
|
|
496
496
|
}
|
|
497
|
-
const { sessionDeny } = await import('./commands-
|
|
497
|
+
const { sessionDeny } = await import('./commands-ClMc3nSg.mjs');
|
|
498
498
|
const denyReqId = sessionArgs[2] && !sessionArgs[2].startsWith("--") ? sessionArgs[2] : void 0;
|
|
499
499
|
await sessionDeny(sessionArgs[1], denyReqId, targetMachineId, {
|
|
500
500
|
json: hasFlag("--json")
|
|
@@ -530,7 +530,7 @@ async function handleSessionCommand() {
|
|
|
530
530
|
console.error("Usage: svamp session set-title <title>");
|
|
531
531
|
process.exit(1);
|
|
532
532
|
}
|
|
533
|
-
const { sessionSetTitle } = await import('./agentCommands-
|
|
533
|
+
const { sessionSetTitle } = await import('./agentCommands-7GGmL2zY.mjs');
|
|
534
534
|
await sessionSetTitle(title);
|
|
535
535
|
} else if (sessionSubcommand === "set-link") {
|
|
536
536
|
const url = sessionArgs[1];
|
|
@@ -539,7 +539,7 @@ async function handleSessionCommand() {
|
|
|
539
539
|
process.exit(1);
|
|
540
540
|
}
|
|
541
541
|
const label = sessionArgs[2] && !sessionArgs[2].startsWith("--") ? sessionArgs[2] : void 0;
|
|
542
|
-
const { sessionSetLink } = await import('./agentCommands-
|
|
542
|
+
const { sessionSetLink } = await import('./agentCommands-7GGmL2zY.mjs');
|
|
543
543
|
await sessionSetLink(url, label);
|
|
544
544
|
} else if (sessionSubcommand === "notify") {
|
|
545
545
|
const message = sessionArgs[1];
|
|
@@ -548,7 +548,7 @@ async function handleSessionCommand() {
|
|
|
548
548
|
process.exit(1);
|
|
549
549
|
}
|
|
550
550
|
const level = parseFlagStr("--level") || "info";
|
|
551
|
-
const { sessionNotify } = await import('./agentCommands-
|
|
551
|
+
const { sessionNotify } = await import('./agentCommands-7GGmL2zY.mjs');
|
|
552
552
|
await sessionNotify(message, level);
|
|
553
553
|
} else if (sessionSubcommand === "broadcast") {
|
|
554
554
|
const action = sessionArgs[1];
|
|
@@ -556,7 +556,7 @@ async function handleSessionCommand() {
|
|
|
556
556
|
console.error("Usage: svamp session broadcast <action> [args...]\nActions: open-canvas <url> [label], close-canvas, toast <message>");
|
|
557
557
|
process.exit(1);
|
|
558
558
|
}
|
|
559
|
-
const { sessionBroadcast } = await import('./agentCommands-
|
|
559
|
+
const { sessionBroadcast } = await import('./agentCommands-7GGmL2zY.mjs');
|
|
560
560
|
await sessionBroadcast(action, sessionArgs.slice(2).filter((a) => !a.startsWith("--")));
|
|
561
561
|
} else if (sessionSubcommand === "queue") {
|
|
562
562
|
const queueSubcmd = sessionArgs[1];
|
|
@@ -582,6 +582,82 @@ async function handleSessionCommand() {
|
|
|
582
582
|
console.error("Usage: svamp session queue <add|list|clear> <session-id> [args]");
|
|
583
583
|
process.exit(1);
|
|
584
584
|
}
|
|
585
|
+
} else if (sessionSubcommand === "inbox") {
|
|
586
|
+
const inboxSubcmd = sessionArgs[1];
|
|
587
|
+
if (inboxSubcmd === "send") {
|
|
588
|
+
const targetId = sessionArgs[2];
|
|
589
|
+
if (!targetId) {
|
|
590
|
+
console.error('Usage: svamp session inbox send <target-session-id> --subject "..." --body "..."');
|
|
591
|
+
process.exit(1);
|
|
592
|
+
}
|
|
593
|
+
const ccStr = parseFlagStr("--cc");
|
|
594
|
+
await sessionInboxSend(targetId, targetMachineId, {
|
|
595
|
+
subject: parseFlagStr("--subject") || "",
|
|
596
|
+
body: parseFlagStr("--body") || "",
|
|
597
|
+
urgency: parseFlagStr("--urgency") || "normal",
|
|
598
|
+
replyTo: parseFlagStr("--reply-to"),
|
|
599
|
+
cc: ccStr ? ccStr.split(",").map((s) => s.trim()).filter(Boolean) : void 0,
|
|
600
|
+
wait: hasFlag("--wait"),
|
|
601
|
+
timeout: parseFlagInt("--timeout"),
|
|
602
|
+
json: hasFlag("--json")
|
|
603
|
+
});
|
|
604
|
+
} else if (inboxSubcmd === "list" || inboxSubcmd === "ls") {
|
|
605
|
+
const targetId = sessionArgs[2] && !sessionArgs[2].startsWith("--") ? sessionArgs[2] : process.env.SVAMP_SESSION_ID;
|
|
606
|
+
if (!targetId) {
|
|
607
|
+
console.error("Usage: svamp session inbox list [session-id] [--unread] [--limit N] [--json]");
|
|
608
|
+
process.exit(1);
|
|
609
|
+
}
|
|
610
|
+
await sessionInboxList(targetId, targetMachineId, {
|
|
611
|
+
unread: hasFlag("--unread"),
|
|
612
|
+
limit: parseFlagInt("--limit"),
|
|
613
|
+
json: hasFlag("--json")
|
|
614
|
+
});
|
|
615
|
+
} else if (inboxSubcmd === "read") {
|
|
616
|
+
const targetId = sessionArgs[2];
|
|
617
|
+
const msgId = sessionArgs[3];
|
|
618
|
+
if (!targetId || !msgId) {
|
|
619
|
+
console.error("Usage: svamp session inbox read <session-id> <message-id>");
|
|
620
|
+
process.exit(1);
|
|
621
|
+
}
|
|
622
|
+
await sessionInboxRead(targetId, msgId, targetMachineId, {
|
|
623
|
+
json: hasFlag("--json")
|
|
624
|
+
});
|
|
625
|
+
} else if (inboxSubcmd === "reply") {
|
|
626
|
+
let targetId;
|
|
627
|
+
let msgId;
|
|
628
|
+
if (sessionArgs[3] && !sessionArgs[3].startsWith("--")) {
|
|
629
|
+
targetId = sessionArgs[2];
|
|
630
|
+
msgId = sessionArgs[3];
|
|
631
|
+
} else if (sessionArgs[2] && !sessionArgs[2].startsWith("--")) {
|
|
632
|
+
targetId = process.env.SVAMP_SESSION_ID;
|
|
633
|
+
msgId = sessionArgs[2];
|
|
634
|
+
}
|
|
635
|
+
if (!targetId || !msgId) {
|
|
636
|
+
console.error('Usage: svamp session inbox reply [session-id] <message-id> --body "..."');
|
|
637
|
+
process.exit(1);
|
|
638
|
+
}
|
|
639
|
+
await sessionInboxReply(targetId, msgId, targetMachineId, {
|
|
640
|
+
body: parseFlagStr("--body") || "",
|
|
641
|
+
urgency: parseFlagStr("--urgency") || "normal",
|
|
642
|
+
wait: hasFlag("--wait"),
|
|
643
|
+
json: hasFlag("--json")
|
|
644
|
+
});
|
|
645
|
+
} else if (inboxSubcmd === "clear") {
|
|
646
|
+
const targetId = sessionArgs[2];
|
|
647
|
+
if (!targetId) {
|
|
648
|
+
console.error("Usage: svamp session inbox clear <session-id> [--all]");
|
|
649
|
+
process.exit(1);
|
|
650
|
+
}
|
|
651
|
+
const msgId = sessionArgs[3] && !sessionArgs[3].startsWith("--") ? sessionArgs[3] : void 0;
|
|
652
|
+
await sessionInboxClear(targetId, targetMachineId, {
|
|
653
|
+
messageId: msgId,
|
|
654
|
+
all: hasFlag("--all"),
|
|
655
|
+
json: hasFlag("--json")
|
|
656
|
+
});
|
|
657
|
+
} else {
|
|
658
|
+
console.error("Usage: svamp session inbox <send|list|read|reply|clear> [args]");
|
|
659
|
+
process.exit(1);
|
|
660
|
+
}
|
|
585
661
|
} else {
|
|
586
662
|
console.error(`Unknown session command: ${sessionSubcommand}`);
|
|
587
663
|
printSessionHelp();
|
|
@@ -597,7 +673,7 @@ async function handleMachineCommand() {
|
|
|
597
673
|
return;
|
|
598
674
|
}
|
|
599
675
|
if (machineSubcommand === "share") {
|
|
600
|
-
const { machineShare } = await import('./commands-
|
|
676
|
+
const { machineShare } = await import('./commands-ClMc3nSg.mjs');
|
|
601
677
|
let machineId;
|
|
602
678
|
const shareArgs = [];
|
|
603
679
|
for (let i = 1; i < machineArgs.length; i++) {
|
|
@@ -627,7 +703,7 @@ async function handleMachineCommand() {
|
|
|
627
703
|
}
|
|
628
704
|
await machineShare(machineId, { add, remove, list, configPath, showConfig });
|
|
629
705
|
} else if (machineSubcommand === "exec") {
|
|
630
|
-
const { machineExec } = await import('./commands-
|
|
706
|
+
const { machineExec } = await import('./commands-ClMc3nSg.mjs');
|
|
631
707
|
let machineId;
|
|
632
708
|
let cwd;
|
|
633
709
|
const cmdParts = [];
|
|
@@ -647,7 +723,7 @@ async function handleMachineCommand() {
|
|
|
647
723
|
}
|
|
648
724
|
await machineExec(machineId, command, cwd);
|
|
649
725
|
} else if (machineSubcommand === "info") {
|
|
650
|
-
const { machineInfo } = await import('./commands-
|
|
726
|
+
const { machineInfo } = await import('./commands-ClMc3nSg.mjs');
|
|
651
727
|
let machineId;
|
|
652
728
|
for (let i = 1; i < machineArgs.length; i++) {
|
|
653
729
|
if ((machineArgs[i] === "--machine" || machineArgs[i] === "-m") && i + 1 < machineArgs.length) {
|
|
@@ -667,10 +743,10 @@ async function handleMachineCommand() {
|
|
|
667
743
|
level = machineArgs[++i];
|
|
668
744
|
}
|
|
669
745
|
}
|
|
670
|
-
const { machineNotify } = await import('./agentCommands-
|
|
746
|
+
const { machineNotify } = await import('./agentCommands-7GGmL2zY.mjs');
|
|
671
747
|
await machineNotify(message, level);
|
|
672
748
|
} else if (machineSubcommand === "ls") {
|
|
673
|
-
const { machineLs } = await import('./commands-
|
|
749
|
+
const { machineLs } = await import('./commands-ClMc3nSg.mjs');
|
|
674
750
|
let machineId;
|
|
675
751
|
let showHidden = false;
|
|
676
752
|
let path;
|
|
@@ -1160,10 +1236,17 @@ COMMANDS:
|
|
|
1160
1236
|
ralph-cancel <id> Cancel loop
|
|
1161
1237
|
ralph-status <id> Show loop status
|
|
1162
1238
|
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1239
|
+
Inbox:
|
|
1240
|
+
inbox send <target> --subject "..." --body "..." Send inbox message
|
|
1241
|
+
inbox list [session-id] [--unread] [--json] List inbox messages
|
|
1242
|
+
inbox read <session-id> <message-id> Read a message
|
|
1243
|
+
inbox reply [session-id] <message-id> --body "..." Reply to a message
|
|
1244
|
+
inbox clear <session-id> [--all] Clear inbox
|
|
1245
|
+
|
|
1246
|
+
Queue (deprecated, use inbox):
|
|
1247
|
+
queue add <id> "<message>" Queue a message (alias for inbox send)
|
|
1248
|
+
queue list <id> List messages (alias for inbox list)
|
|
1249
|
+
queue clear <id> Clear messages (alias for inbox clear)
|
|
1167
1250
|
|
|
1168
1251
|
SPAWN OPTIONS:
|
|
1169
1252
|
-d, --directory <path> Working directory (REQUIRED for meaningful work)
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from 'node:fs';
|
|
2
2
|
import { execSync } from 'node:child_process';
|
|
3
|
+
import { randomUUID } from 'node:crypto';
|
|
3
4
|
import { resolve, join } from 'node:path';
|
|
4
5
|
import os from 'node:os';
|
|
5
|
-
import { l as loadSecurityContextConfig, e as resolveSecurityContext, f as buildSecurityContextFromFlags, m as mergeSecurityContexts, c as connectToHypha } from './run-
|
|
6
|
+
import { l as loadSecurityContextConfig, e as resolveSecurityContext, f as buildSecurityContextFromFlags, m as mergeSecurityContexts, c as connectToHypha } from './run-6QgabuQN.mjs';
|
|
6
7
|
import 'os';
|
|
7
8
|
import 'fs/promises';
|
|
8
9
|
import 'fs';
|
|
@@ -10,7 +11,6 @@ import 'path';
|
|
|
10
11
|
import 'url';
|
|
11
12
|
import 'child_process';
|
|
12
13
|
import 'crypto';
|
|
13
|
-
import 'node:crypto';
|
|
14
14
|
import '@agentclientprotocol/sdk';
|
|
15
15
|
import '@modelcontextprotocol/sdk/client/index.js';
|
|
16
16
|
import '@modelcontextprotocol/sdk/client/stdio.js';
|
|
@@ -1713,71 +1713,207 @@ async function sessionQueueAdd(sessionIdPartial, message, machineId) {
|
|
|
1713
1713
|
const match = resolveSessionId(sessions, sessionIdPartial);
|
|
1714
1714
|
const fullId = match.sessionId;
|
|
1715
1715
|
const svc = await server.getService(`svamp-session-${fullId}`);
|
|
1716
|
-
const { metadata, version } = await svc.getMetadata();
|
|
1717
|
-
const existingQueue = metadata?.messageQueue || [];
|
|
1718
1716
|
const newMsg = {
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1717
|
+
messageId: `msg-${randomUUID()}`,
|
|
1718
|
+
body: message,
|
|
1719
|
+
timestamp: Date.now(),
|
|
1720
|
+
read: false
|
|
1722
1721
|
};
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
const result = await svc.updateMetadata(updatedMetadata, version);
|
|
1726
|
-
if (result.result !== "success") {
|
|
1727
|
-
console.error(`Failed to add to queue: ${result.result}`);
|
|
1728
|
-
process.exit(1);
|
|
1729
|
-
}
|
|
1730
|
-
console.log(`Message queued on session ${fullId.slice(0, 8)} (${updatedQueue.length} total)`);
|
|
1722
|
+
await svc.sendInboxMessage(newMsg);
|
|
1723
|
+
console.log(`Message queued on session ${fullId.slice(0, 8)}`);
|
|
1731
1724
|
} finally {
|
|
1732
1725
|
await server.disconnect();
|
|
1733
1726
|
}
|
|
1734
1727
|
}
|
|
1735
1728
|
async function sessionQueueList(sessionIdPartial, machineId) {
|
|
1729
|
+
return sessionInboxList(sessionIdPartial, machineId);
|
|
1730
|
+
}
|
|
1731
|
+
async function sessionQueueClear(sessionIdPartial, machineId) {
|
|
1732
|
+
return sessionInboxClear(sessionIdPartial, machineId);
|
|
1733
|
+
}
|
|
1734
|
+
async function sessionInboxSend(targetSessionId, machineId, opts) {
|
|
1735
|
+
if (!opts?.subject || !opts?.body) {
|
|
1736
|
+
console.error('Usage: svamp session inbox send <target-session-id> --subject "..." --body "..."');
|
|
1737
|
+
process.exit(1);
|
|
1738
|
+
}
|
|
1739
|
+
const { server, machine } = await connectAndGetMachine(machineId);
|
|
1740
|
+
try {
|
|
1741
|
+
const sessions = await machine.listSessions();
|
|
1742
|
+
const match = resolveSessionId(sessions, targetSessionId);
|
|
1743
|
+
const fullTargetId = match.sessionId;
|
|
1744
|
+
const senderSessionId = process.env.SVAMP_SESSION_ID || "cli";
|
|
1745
|
+
const senderEmail = process.env.USER_EMAIL || process.env.USER || os.userInfo().username;
|
|
1746
|
+
const from = senderSessionId === "cli" ? `user:${senderEmail}` : `agent:${senderSessionId}`;
|
|
1747
|
+
const message = {
|
|
1748
|
+
messageId: `msg-${randomUUID()}`,
|
|
1749
|
+
from,
|
|
1750
|
+
fromSession: senderSessionId,
|
|
1751
|
+
to: fullTargetId,
|
|
1752
|
+
subject: opts.subject,
|
|
1753
|
+
body: opts.body,
|
|
1754
|
+
urgency: opts.urgency || "normal",
|
|
1755
|
+
replyTo: opts.replyTo,
|
|
1756
|
+
cc: opts.cc,
|
|
1757
|
+
timestamp: Date.now(),
|
|
1758
|
+
read: false,
|
|
1759
|
+
threadId: opts.replyTo ? void 0 : void 0
|
|
1760
|
+
// will be set by reply logic
|
|
1761
|
+
};
|
|
1762
|
+
const svc = await server.getService(`svamp-session-${fullTargetId}`);
|
|
1763
|
+
const result = await svc.sendInboxMessage(message);
|
|
1764
|
+
if (opts.wait) {
|
|
1765
|
+
const timeoutMs = (opts.timeout || 300) * 1e3;
|
|
1766
|
+
await waitForBusyThenIdle(server, fullTargetId, timeoutMs);
|
|
1767
|
+
}
|
|
1768
|
+
if (opts.json) {
|
|
1769
|
+
console.log(formatJson({
|
|
1770
|
+
messageId: message.messageId,
|
|
1771
|
+
targetSessionId: fullTargetId,
|
|
1772
|
+
subject: opts.subject,
|
|
1773
|
+
urgency: message.urgency,
|
|
1774
|
+
delivered: result.delivered
|
|
1775
|
+
}));
|
|
1776
|
+
} else {
|
|
1777
|
+
console.log(`Inbox message sent to session ${fullTargetId.slice(0, 8)} [${message.urgency}]: "${opts.subject}"`);
|
|
1778
|
+
}
|
|
1779
|
+
} finally {
|
|
1780
|
+
await server.disconnect();
|
|
1781
|
+
}
|
|
1782
|
+
}
|
|
1783
|
+
async function sessionInboxList(sessionIdPartial, machineId, opts) {
|
|
1736
1784
|
const { server, machine } = await connectAndGetMachine(machineId);
|
|
1737
1785
|
try {
|
|
1738
1786
|
const sessions = await machine.listSessions();
|
|
1739
1787
|
const match = resolveSessionId(sessions, sessionIdPartial);
|
|
1740
1788
|
const fullId = match.sessionId;
|
|
1741
1789
|
const svc = await server.getService(`svamp-session-${fullId}`);
|
|
1742
|
-
const
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
console.log(`
|
|
1790
|
+
const result = await svc.getInbox({
|
|
1791
|
+
unreadOnly: opts?.unread || false,
|
|
1792
|
+
limit: opts?.limit || 50
|
|
1793
|
+
});
|
|
1794
|
+
if (opts?.json) ; else {
|
|
1795
|
+
const msgs = result.messages || [];
|
|
1796
|
+
if (msgs.length === 0) {
|
|
1797
|
+
console.log("Inbox is empty.");
|
|
1798
|
+
return;
|
|
1799
|
+
}
|
|
1800
|
+
console.log(`Inbox for session ${fullId.slice(0, 8)} (${msgs.length} message(s), ${result.total} total):
|
|
1801
|
+
`);
|
|
1802
|
+
for (const msg of msgs) {
|
|
1803
|
+
const readMark = msg.read ? " " : "*";
|
|
1804
|
+
const date = new Date(msg.timestamp).toLocaleString();
|
|
1805
|
+
console.log(`${readMark} [${msg.messageId.slice(0, 12)}] ${date}`);
|
|
1806
|
+
console.log(` From: ${msg.from} | Subject: ${msg.subject} | Urgency: ${msg.urgency}`);
|
|
1807
|
+
if (msg.replyTo) console.log(` Reply-To: ${msg.replyTo.slice(0, 12)}`);
|
|
1808
|
+
console.log(` ${msg.body.slice(0, 120)}${msg.body.length > 120 ? "..." : ""}`);
|
|
1809
|
+
console.log();
|
|
1810
|
+
}
|
|
1753
1811
|
}
|
|
1754
1812
|
} finally {
|
|
1755
1813
|
await server.disconnect();
|
|
1756
1814
|
}
|
|
1757
1815
|
}
|
|
1758
|
-
async function
|
|
1816
|
+
async function sessionInboxRead(sessionIdPartial, messageId, machineId, opts) {
|
|
1759
1817
|
const { server, machine } = await connectAndGetMachine(machineId);
|
|
1760
1818
|
try {
|
|
1761
1819
|
const sessions = await machine.listSessions();
|
|
1762
1820
|
const match = resolveSessionId(sessions, sessionIdPartial);
|
|
1763
1821
|
const fullId = match.sessionId;
|
|
1764
1822
|
const svc = await server.getService(`svamp-session-${fullId}`);
|
|
1765
|
-
const
|
|
1766
|
-
const
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1823
|
+
const result = await svc.getInbox({});
|
|
1824
|
+
const msg = (result.messages || []).find(
|
|
1825
|
+
(m) => m.messageId === messageId || m.messageId.startsWith(messageId)
|
|
1826
|
+
);
|
|
1827
|
+
if (!msg) {
|
|
1828
|
+
console.error(`Message ${messageId} not found in inbox.`);
|
|
1829
|
+
process.exit(1);
|
|
1770
1830
|
}
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1831
|
+
await svc.markInboxRead([msg.messageId]);
|
|
1832
|
+
if (opts?.json) {
|
|
1833
|
+
console.log(formatJson(msg));
|
|
1834
|
+
} else {
|
|
1835
|
+
console.log(`Message-ID: ${msg.messageId}`);
|
|
1836
|
+
console.log(`From: ${msg.from}`);
|
|
1837
|
+
console.log(`From-Session: ${msg.fromSession}`);
|
|
1838
|
+
console.log(`Subject: ${msg.subject}`);
|
|
1839
|
+
console.log(`Urgency: ${msg.urgency}`);
|
|
1840
|
+
console.log(`Date: ${new Date(msg.timestamp).toLocaleString()}`);
|
|
1841
|
+
if (msg.replyTo) console.log(`Reply-To: ${msg.replyTo}`);
|
|
1842
|
+
if (msg.cc?.length) console.log(`CC: ${msg.cc.join(", ")}`);
|
|
1843
|
+
console.log(`---`);
|
|
1844
|
+
console.log(msg.body);
|
|
1845
|
+
}
|
|
1846
|
+
} finally {
|
|
1847
|
+
await server.disconnect();
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
async function sessionInboxReply(sessionIdPartial, messageId, machineId, opts) {
|
|
1851
|
+
if (!opts?.body) {
|
|
1852
|
+
console.error('Usage: svamp session inbox reply <session-id> <message-id> --body "..."');
|
|
1853
|
+
process.exit(1);
|
|
1854
|
+
}
|
|
1855
|
+
const { server, machine } = await connectAndGetMachine(machineId);
|
|
1856
|
+
try {
|
|
1857
|
+
const sessions = await machine.listSessions();
|
|
1858
|
+
const match = resolveSessionId(sessions, sessionIdPartial);
|
|
1859
|
+
const fullId = match.sessionId;
|
|
1860
|
+
const svc = await server.getService(`svamp-session-${fullId}`);
|
|
1861
|
+
const inboxResult = await svc.getInbox({});
|
|
1862
|
+
const originalMsg = (inboxResult.messages || []).find(
|
|
1863
|
+
(m) => m.messageId === messageId || m.messageId.startsWith(messageId)
|
|
1864
|
+
);
|
|
1865
|
+
if (!originalMsg) {
|
|
1866
|
+
console.error(`Message ${messageId} not found in inbox. Cannot reply.`);
|
|
1775
1867
|
process.exit(1);
|
|
1776
1868
|
}
|
|
1777
|
-
|
|
1869
|
+
const senderSessionId = process.env.SVAMP_SESSION_ID || fullId;
|
|
1870
|
+
const senderEmail = process.env.USER_EMAIL || process.env.USER || os.userInfo().username;
|
|
1871
|
+
const from = senderSessionId === "cli" ? `user:${senderEmail}` : `agent:${senderSessionId}`;
|
|
1872
|
+
const reply = {
|
|
1873
|
+
messageId: `msg-${randomUUID()}`,
|
|
1874
|
+
from,
|
|
1875
|
+
fromSession: senderSessionId,
|
|
1876
|
+
to: originalMsg.fromSession,
|
|
1877
|
+
subject: `Re: ${originalMsg.subject}`,
|
|
1878
|
+
body: opts.body,
|
|
1879
|
+
urgency: opts.urgency || "normal",
|
|
1880
|
+
replyTo: originalMsg.messageId,
|
|
1881
|
+
threadId: originalMsg.threadId || originalMsg.messageId,
|
|
1882
|
+
timestamp: Date.now(),
|
|
1883
|
+
read: false
|
|
1884
|
+
};
|
|
1885
|
+
const targetSvc = await server.getService(`svamp-session-${originalMsg.fromSession}`);
|
|
1886
|
+
const result = await targetSvc.sendInboxMessage(reply);
|
|
1887
|
+
if (opts.json) {
|
|
1888
|
+
console.log(formatJson({
|
|
1889
|
+
messageId: reply.messageId,
|
|
1890
|
+
targetSessionId: originalMsg.fromSession,
|
|
1891
|
+
subject: reply.subject,
|
|
1892
|
+
urgency: reply.urgency,
|
|
1893
|
+
delivered: result.delivered
|
|
1894
|
+
}));
|
|
1895
|
+
} else {
|
|
1896
|
+
console.log(`Reply sent to session ${originalMsg.fromSession.slice(0, 8)}: "${reply.subject}"`);
|
|
1897
|
+
}
|
|
1898
|
+
} finally {
|
|
1899
|
+
await server.disconnect();
|
|
1900
|
+
}
|
|
1901
|
+
}
|
|
1902
|
+
async function sessionInboxClear(sessionIdPartial, machineId, opts) {
|
|
1903
|
+
const { server, machine } = await connectAndGetMachine(machineId);
|
|
1904
|
+
try {
|
|
1905
|
+
const sessions = await machine.listSessions();
|
|
1906
|
+
const match = resolveSessionId(sessions, sessionIdPartial);
|
|
1907
|
+
const fullId = match.sessionId;
|
|
1908
|
+
const svc = await server.getService(`svamp-session-${fullId}`);
|
|
1909
|
+
const messageIds = opts?.messageId ? [opts.messageId] : void 0;
|
|
1910
|
+
const result = await svc.clearInbox(messageIds);
|
|
1911
|
+
if (opts?.json) ; else {
|
|
1912
|
+
console.log(`Cleared ${result.removed} message(s) from inbox on session ${fullId.slice(0, 8)}`);
|
|
1913
|
+
}
|
|
1778
1914
|
} finally {
|
|
1779
1915
|
await server.disconnect();
|
|
1780
1916
|
}
|
|
1781
1917
|
}
|
|
1782
1918
|
|
|
1783
|
-
export { connectAndGetMachine, createWorktree, generateWorktreeName, machineExec, machineInfo, machineLs, machineShare, parseShareArg, renderMessage, resolveSessionId, sessionApprove, sessionAttach, sessionDeny, sessionInfo, sessionList, sessionMachines, sessionMessages, sessionQueueAdd, sessionQueueClear, sessionQueueList, sessionRalphCancel, sessionRalphStart, sessionRalphStatus, sessionSend, sessionShare, sessionSpawn, sessionStop, sessionWait };
|
|
1919
|
+
export { connectAndGetMachine, createWorktree, generateWorktreeName, machineExec, machineInfo, machineLs, machineShare, parseShareArg, renderMessage, resolveSessionId, sessionApprove, sessionAttach, sessionDeny, sessionInboxClear, sessionInboxList, sessionInboxRead, sessionInboxReply, sessionInboxSend, sessionInfo, sessionList, sessionMachines, sessionMessages, sessionQueueAdd, sessionQueueClear, sessionQueueList, sessionRalphCancel, sessionRalphStart, sessionRalphStatus, sessionSend, sessionShare, sessionSpawn, sessionStop, sessionWait };
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { writeFileSync, readFileSync } from 'fs';
|
|
2
2
|
import { resolve } from 'path';
|
|
3
|
-
import { connectAndGetMachine } from './commands-
|
|
3
|
+
import { connectAndGetMachine } from './commands-ClMc3nSg.mjs';
|
|
4
4
|
import 'node:fs';
|
|
5
5
|
import 'node:child_process';
|
|
6
|
+
import 'node:crypto';
|
|
6
7
|
import 'node:path';
|
|
7
8
|
import 'node:os';
|
|
8
|
-
import './run-
|
|
9
|
+
import './run-6QgabuQN.mjs';
|
|
9
10
|
import 'os';
|
|
10
11
|
import 'fs/promises';
|
|
11
12
|
import 'url';
|
|
12
13
|
import 'child_process';
|
|
13
14
|
import 'crypto';
|
|
14
|
-
import 'node:crypto';
|
|
15
15
|
import '@agentclientprotocol/sdk';
|
|
16
16
|
import '@modelcontextprotocol/sdk/client/index.js';
|
|
17
17
|
import '@modelcontextprotocol/sdk/client/stdio.js';
|
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-6QgabuQN.mjs';
|
|
2
2
|
import 'os';
|
|
3
3
|
import 'fs/promises';
|
|
4
4
|
import 'fs';
|
|
@@ -871,6 +871,27 @@ async function registerMachineService(server, machineId, metadata, daemonState,
|
|
|
871
871
|
};
|
|
872
872
|
}
|
|
873
873
|
|
|
874
|
+
function isStructuredMessage(msg) {
|
|
875
|
+
return !!(msg.from && msg.subject);
|
|
876
|
+
}
|
|
877
|
+
function formatInboxMessageXml(msg) {
|
|
878
|
+
if (!isStructuredMessage(msg)) return msg.body;
|
|
879
|
+
const attrs = [
|
|
880
|
+
`message-id="${msg.messageId}"`,
|
|
881
|
+
`from="${msg.from}"`,
|
|
882
|
+
`from-session="${msg.fromSession || ""}"`,
|
|
883
|
+
`to="${msg.to || ""}"`,
|
|
884
|
+
`subject="${msg.subject}"`,
|
|
885
|
+
`urgency="${msg.urgency || "normal"}"`,
|
|
886
|
+
`timestamp="${msg.timestamp}"`
|
|
887
|
+
];
|
|
888
|
+
if (msg.replyTo) attrs.push(`reply-to="${msg.replyTo}"`);
|
|
889
|
+
if (msg.cc && msg.cc.length > 0) attrs.push(`cc="${msg.cc.join(",")}"`);
|
|
890
|
+
if (msg.threadId) attrs.push(`thread-id="${msg.threadId}"`);
|
|
891
|
+
return `<svamp-message ${attrs.join(" ")}>
|
|
892
|
+
${msg.body}
|
|
893
|
+
</svamp-message>`;
|
|
894
|
+
}
|
|
874
895
|
function loadMessages(messagesDir, sessionId) {
|
|
875
896
|
const filePath = join$1(messagesDir, "messages.jsonl");
|
|
876
897
|
if (!existsSync(filePath)) return [];
|
|
@@ -1247,6 +1268,24 @@ function createSessionStore(server, sessionId, initialMetadata, initialAgentStat
|
|
|
1247
1268
|
});
|
|
1248
1269
|
return await callbacks.onUpdateSecurityContext(newSecurityContext);
|
|
1249
1270
|
},
|
|
1271
|
+
/** Toggle isolation (nono/docker/podman) on or off — triggers agent restart */
|
|
1272
|
+
updateIsolation: async (enabled, context) => {
|
|
1273
|
+
authorizeRequest(context, metadata.sharing, "admin");
|
|
1274
|
+
if (metadata.sharing && context?.user?.email && metadata.sharing.owner && context.user.email.toLowerCase() !== metadata.sharing.owner.toLowerCase()) {
|
|
1275
|
+
throw new Error("Only the session owner can change isolation settings");
|
|
1276
|
+
}
|
|
1277
|
+
if (!callbacks.onUpdateIsolation) {
|
|
1278
|
+
throw new Error("Isolation updates are not supported for this session");
|
|
1279
|
+
}
|
|
1280
|
+
metadata = { ...metadata, forceIsolation: enabled };
|
|
1281
|
+
metadataVersion++;
|
|
1282
|
+
notifyListeners({
|
|
1283
|
+
type: "update-session",
|
|
1284
|
+
sessionId,
|
|
1285
|
+
metadata: { value: metadata, version: metadataVersion }
|
|
1286
|
+
});
|
|
1287
|
+
return await callbacks.onUpdateIsolation(enabled);
|
|
1288
|
+
},
|
|
1250
1289
|
/** Apply a new system prompt and restart the agent process */
|
|
1251
1290
|
applySystemPrompt: async (prompt, context) => {
|
|
1252
1291
|
authorizeRequest(context, metadata.sharing, "admin");
|
|
@@ -1255,6 +1294,86 @@ function createSessionStore(server, sessionId, initialMetadata, initialAgentStat
|
|
|
1255
1294
|
}
|
|
1256
1295
|
return await callbacks.onApplySystemPrompt(prompt);
|
|
1257
1296
|
},
|
|
1297
|
+
// ── Inbox Messaging ──
|
|
1298
|
+
sendInboxMessage: async (message, context) => {
|
|
1299
|
+
authorizeRequest(context, metadata.sharing, "interact");
|
|
1300
|
+
if (!message.messageId || !message.body) {
|
|
1301
|
+
throw new Error("Inbox message requires messageId and body");
|
|
1302
|
+
}
|
|
1303
|
+
const inbox = (metadata.inbox || []).slice();
|
|
1304
|
+
inbox.push({ ...message, read: false });
|
|
1305
|
+
if (inbox.length > 100) {
|
|
1306
|
+
const readIdx = inbox.findIndex((m) => m.read);
|
|
1307
|
+
if (readIdx >= 0) {
|
|
1308
|
+
inbox.splice(readIdx, 1);
|
|
1309
|
+
} else {
|
|
1310
|
+
inbox.shift();
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
metadata = { ...metadata, inbox };
|
|
1314
|
+
metadataVersion++;
|
|
1315
|
+
notifyListeners({
|
|
1316
|
+
type: "update-session",
|
|
1317
|
+
sessionId,
|
|
1318
|
+
metadata: { value: metadata, version: metadataVersion }
|
|
1319
|
+
});
|
|
1320
|
+
callbacks.onInboxMessage?.(message);
|
|
1321
|
+
return { messageId: message.messageId, delivered: true };
|
|
1322
|
+
},
|
|
1323
|
+
getInbox: async (opts, context) => {
|
|
1324
|
+
authorizeRequest(context, metadata.sharing, "view");
|
|
1325
|
+
let inbox = metadata.inbox || [];
|
|
1326
|
+
if (opts?.unreadOnly) {
|
|
1327
|
+
inbox = inbox.filter((m) => !m.read);
|
|
1328
|
+
}
|
|
1329
|
+
if (opts?.limit && opts.limit > 0) {
|
|
1330
|
+
inbox = inbox.slice(-opts.limit);
|
|
1331
|
+
}
|
|
1332
|
+
return { messages: inbox, total: (metadata.inbox || []).length };
|
|
1333
|
+
},
|
|
1334
|
+
markInboxRead: async (messageIds, context) => {
|
|
1335
|
+
authorizeRequest(context, metadata.sharing, "interact");
|
|
1336
|
+
let updated = 0;
|
|
1337
|
+
const inbox = (metadata.inbox || []).map((m) => {
|
|
1338
|
+
if (messageIds.includes(m.messageId) && !m.read) {
|
|
1339
|
+
updated++;
|
|
1340
|
+
return { ...m, read: true };
|
|
1341
|
+
}
|
|
1342
|
+
return m;
|
|
1343
|
+
});
|
|
1344
|
+
if (updated > 0) {
|
|
1345
|
+
metadata = { ...metadata, inbox };
|
|
1346
|
+
metadataVersion++;
|
|
1347
|
+
notifyListeners({
|
|
1348
|
+
type: "update-session",
|
|
1349
|
+
sessionId,
|
|
1350
|
+
metadata: { value: metadata, version: metadataVersion }
|
|
1351
|
+
});
|
|
1352
|
+
}
|
|
1353
|
+
return { updated };
|
|
1354
|
+
},
|
|
1355
|
+
clearInbox: async (messageIds, context) => {
|
|
1356
|
+
authorizeRequest(context, metadata.sharing, "interact");
|
|
1357
|
+
const currentInbox = metadata.inbox || [];
|
|
1358
|
+
let removed;
|
|
1359
|
+
if (messageIds && messageIds.length > 0) {
|
|
1360
|
+
const newInbox = currentInbox.filter((m) => !messageIds.includes(m.messageId));
|
|
1361
|
+
removed = currentInbox.length - newInbox.length;
|
|
1362
|
+
metadata = { ...metadata, inbox: newInbox.length > 0 ? newInbox : void 0 };
|
|
1363
|
+
} else {
|
|
1364
|
+
removed = currentInbox.length;
|
|
1365
|
+
metadata = { ...metadata, inbox: void 0 };
|
|
1366
|
+
}
|
|
1367
|
+
if (removed > 0) {
|
|
1368
|
+
metadataVersion++;
|
|
1369
|
+
notifyListeners({
|
|
1370
|
+
type: "update-session",
|
|
1371
|
+
sessionId,
|
|
1372
|
+
metadata: { value: metadata, version: metadataVersion }
|
|
1373
|
+
});
|
|
1374
|
+
}
|
|
1375
|
+
return { removed };
|
|
1376
|
+
},
|
|
1258
1377
|
// ── Listener Registration ──
|
|
1259
1378
|
registerListener: async (callback, context) => {
|
|
1260
1379
|
authorizeRequest(context, metadata.sharing, "view");
|
|
@@ -4852,15 +4971,16 @@ function createSvampConfigChecker(directory, sessionId, getMetadata, setMetadata
|
|
|
4852
4971
|
const progressRelPath = `.svamp/${sessionId}/ralph-progress.md`;
|
|
4853
4972
|
const prompt = buildRalphPrompt(state.task, state);
|
|
4854
4973
|
const ralphSysPrompt = buildRalphSystemPrompt(state, progressRelPath);
|
|
4855
|
-
const
|
|
4974
|
+
const existingInbox = getMetadata().inbox || [];
|
|
4856
4975
|
setMetadata((m) => ({
|
|
4857
4976
|
...m,
|
|
4858
4977
|
ralphLoop,
|
|
4859
|
-
|
|
4860
|
-
|
|
4861
|
-
|
|
4978
|
+
inbox: [...existingInbox, {
|
|
4979
|
+
messageId: randomUUID$1(),
|
|
4980
|
+
body: prompt,
|
|
4862
4981
|
displayText: state.task,
|
|
4863
|
-
|
|
4982
|
+
timestamp: Date.now(),
|
|
4983
|
+
read: false,
|
|
4864
4984
|
ralphSystemPrompt: ralphSysPrompt
|
|
4865
4985
|
}]
|
|
4866
4986
|
}));
|
|
@@ -5528,7 +5648,8 @@ async function startDaemon(options) {
|
|
|
5528
5648
|
}
|
|
5529
5649
|
});
|
|
5530
5650
|
}, buildIsolationConfig2 = function(dir) {
|
|
5531
|
-
|
|
5651
|
+
const forceIsolation = sessionMetadata.forceIsolation ?? options2.forceIsolation;
|
|
5652
|
+
if (!forceIsolation && !sessionMetadata.sharing?.enabled) return null;
|
|
5532
5653
|
const method = isolationCapabilities.preferred;
|
|
5533
5654
|
if (!method) return null;
|
|
5534
5655
|
const detail = isolationCapabilities.details[method];
|
|
@@ -5569,6 +5690,7 @@ async function startDaemon(options) {
|
|
|
5569
5690
|
lifecycleState: resumeSessionId ? "idle" : "starting",
|
|
5570
5691
|
sharing: options2.sharing,
|
|
5571
5692
|
securityContext: options2.securityContext,
|
|
5693
|
+
forceIsolation: options2.forceIsolation || void 0,
|
|
5572
5694
|
tags: options2.tags,
|
|
5573
5695
|
parentSessionId: options2.parentSessionId,
|
|
5574
5696
|
...options2.parentSessionId && (() => {
|
|
@@ -5644,7 +5766,8 @@ async function startDaemon(options) {
|
|
|
5644
5766
|
startupNonJsonLines = [];
|
|
5645
5767
|
startupRetryMessage = initialMessage;
|
|
5646
5768
|
let rawPermissionMode = effectiveMeta.permissionMode || agentConfig.default_permission_mode || currentPermissionMode;
|
|
5647
|
-
|
|
5769
|
+
const forceIsolation = sessionMetadata.forceIsolation ?? options2.forceIsolation;
|
|
5770
|
+
if (forceIsolation || sessionMetadata.sharing?.enabled) {
|
|
5648
5771
|
rawPermissionMode = rawPermissionMode === "default" ? "auto-approve-all" : rawPermissionMode;
|
|
5649
5772
|
}
|
|
5650
5773
|
if (sessionMetadata.ralphLoop?.active) {
|
|
@@ -5681,7 +5804,7 @@ async function startDaemon(options) {
|
|
|
5681
5804
|
if (wrapped.cleanupFiles) isolationCleanupFiles = wrapped.cleanupFiles;
|
|
5682
5805
|
sessionMetadata = { ...sessionMetadata, isolationMethod: isoConfig.method };
|
|
5683
5806
|
logger.log(`[Session ${sessionId}] Isolation: ${isoConfig.method} (binary: ${isoConfig.binaryPath})`);
|
|
5684
|
-
} else if (
|
|
5807
|
+
} else if (forceIsolation || sessionMetadata.sharing?.enabled) {
|
|
5685
5808
|
logger.log(`[Session ${sessionId}] WARNING: No isolation runtime (nono/docker/podman) available. Session is NOT sandboxed.`);
|
|
5686
5809
|
sessionMetadata = { ...sessionMetadata, isolationMethod: void 0 };
|
|
5687
5810
|
} else {
|
|
@@ -5906,7 +6029,7 @@ async function startDaemon(options) {
|
|
|
5906
6029
|
logger.log(`[Session ${sessionId}] ${taskInfo}`);
|
|
5907
6030
|
sessionService.pushMessage({ type: "session_event", message: taskInfo }, "session");
|
|
5908
6031
|
}
|
|
5909
|
-
const queueLen = sessionMetadata.
|
|
6032
|
+
const queueLen = sessionMetadata.inbox?.filter((m) => !m.read)?.length ?? 0;
|
|
5910
6033
|
if (msg.is_error) {
|
|
5911
6034
|
const rlStateForError = readRalphState(getRalphStateFilePath(directory, sessionId));
|
|
5912
6035
|
if (rlStateForError) {
|
|
@@ -6211,7 +6334,7 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
6211
6334
|
return;
|
|
6212
6335
|
}
|
|
6213
6336
|
}
|
|
6214
|
-
const queueLen = sessionMetadata.
|
|
6337
|
+
const queueLen = sessionMetadata.inbox?.filter((m) => !m.read)?.length ?? 0;
|
|
6215
6338
|
if (queueLen > 0 && claudeResumeId && !trackedSession.stopped) {
|
|
6216
6339
|
signalProcessing(false);
|
|
6217
6340
|
setTimeout(() => processMessageQueueRef?.(), 200);
|
|
@@ -6322,10 +6445,10 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
6322
6445
|
}
|
|
6323
6446
|
if (isKillingClaude || isRestartingClaude || isSwitchingMode) {
|
|
6324
6447
|
logger.log(`[Session ${sessionId}] Message received while restarting Claude, queuing to prevent loss`);
|
|
6325
|
-
const
|
|
6448
|
+
const existingInbox = sessionMetadata.inbox || [];
|
|
6326
6449
|
sessionMetadata = {
|
|
6327
6450
|
...sessionMetadata,
|
|
6328
|
-
|
|
6451
|
+
inbox: [...existingInbox, { messageId: randomUUID$1(), body: text, timestamp: Date.now(), read: false }]
|
|
6329
6452
|
};
|
|
6330
6453
|
sessionService.updateMetadata(sessionMetadata);
|
|
6331
6454
|
signalProcessing(false);
|
|
@@ -6360,7 +6483,7 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
6360
6483
|
}
|
|
6361
6484
|
signalProcessing(false);
|
|
6362
6485
|
sessionWasProcessing = false;
|
|
6363
|
-
const queueLen = sessionMetadata.
|
|
6486
|
+
const queueLen = sessionMetadata.inbox?.filter((m) => !m.read)?.length ?? 0;
|
|
6364
6487
|
const abortMsg = queueLen > 0 ? `Aborted by user. ${queueLen} queued message(s) will be processed next.` : "Aborted by user";
|
|
6365
6488
|
sessionService.pushMessage(
|
|
6366
6489
|
{ type: "message", message: abortMsg },
|
|
@@ -6442,6 +6565,24 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
6442
6565
|
sessionMetadata = { ...sessionMetadata, securityContext: newSecurityContext };
|
|
6443
6566
|
return await restartClaudeHandler();
|
|
6444
6567
|
},
|
|
6568
|
+
onUpdateIsolation: async (enabled) => {
|
|
6569
|
+
logger.log(`[Session ${sessionId}] Isolation ${enabled ? "enabled" : "disabled"} \u2014 restarting agent`);
|
|
6570
|
+
sessionMetadata = { ...sessionMetadata, forceIsolation: enabled };
|
|
6571
|
+
if (!trackedSession.stopped) {
|
|
6572
|
+
saveSession({
|
|
6573
|
+
sessionId,
|
|
6574
|
+
directory,
|
|
6575
|
+
claudeResumeId,
|
|
6576
|
+
permissionMode: currentPermissionMode,
|
|
6577
|
+
spawnMeta: lastSpawnMeta,
|
|
6578
|
+
metadata: sessionMetadata,
|
|
6579
|
+
createdAt: Date.now(),
|
|
6580
|
+
machineId,
|
|
6581
|
+
wasProcessing: sessionWasProcessing
|
|
6582
|
+
});
|
|
6583
|
+
}
|
|
6584
|
+
return await restartClaudeHandler();
|
|
6585
|
+
},
|
|
6445
6586
|
onSharingUpdate: (newSharing) => {
|
|
6446
6587
|
logger.log(`[Session ${sessionId}] Sharing config updated \u2014 persisting to disk`);
|
|
6447
6588
|
sessionMetadata = { ...sessionMetadata, sharing: newSharing };
|
|
@@ -6464,14 +6605,72 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
6464
6605
|
lastSpawnMeta = { ...lastSpawnMeta, appendSystemPrompt: prompt };
|
|
6465
6606
|
return await restartClaudeHandler();
|
|
6466
6607
|
},
|
|
6608
|
+
onInboxMessage: (message) => {
|
|
6609
|
+
const xmlText = formatInboxMessageXml(message);
|
|
6610
|
+
if (message.urgency === "urgent") {
|
|
6611
|
+
logger.log(`[Session ${sessionId}] Urgent inbox message from ${message.from}: ${message.subject}`);
|
|
6612
|
+
const text = xmlText;
|
|
6613
|
+
if (sessionWasProcessing) {
|
|
6614
|
+
const existingInbox = sessionMetadata.inbox || [];
|
|
6615
|
+
sessionMetadata = { ...sessionMetadata, inbox: [{ messageId: message.messageId, body: text, displayText: `[Inbox] ${message.subject}`, timestamp: Date.now(), read: false, from: message.from, fromSession: message.fromSession, subject: message.subject, urgency: "urgent" }, ...existingInbox] };
|
|
6616
|
+
sessionService.updateMetadata(sessionMetadata);
|
|
6617
|
+
} else {
|
|
6618
|
+
sessionWasProcessing = true;
|
|
6619
|
+
signalProcessing(true);
|
|
6620
|
+
sessionService.pushMessage(`[Inbox] ${message.subject}`, "user");
|
|
6621
|
+
userMessagePending = true;
|
|
6622
|
+
turnInitiatedByUser = true;
|
|
6623
|
+
try {
|
|
6624
|
+
if (!claudeProcess || claudeProcess.exitCode !== null) {
|
|
6625
|
+
spawnClaude(text);
|
|
6626
|
+
} else {
|
|
6627
|
+
const stdinMsg = JSON.stringify({
|
|
6628
|
+
type: "user",
|
|
6629
|
+
message: { role: "user", content: text }
|
|
6630
|
+
});
|
|
6631
|
+
claudeProcess.stdin?.write(stdinMsg + "\n");
|
|
6632
|
+
}
|
|
6633
|
+
} catch (err) {
|
|
6634
|
+
logger.log(`[Session ${sessionId}] Error injecting urgent inbox message: ${err.message}`);
|
|
6635
|
+
sessionWasProcessing = false;
|
|
6636
|
+
signalProcessing(false);
|
|
6637
|
+
}
|
|
6638
|
+
}
|
|
6639
|
+
const inbox = (sessionMetadata.inbox || []).map(
|
|
6640
|
+
(m) => m.messageId === message.messageId ? { ...m, read: true } : m
|
|
6641
|
+
);
|
|
6642
|
+
sessionMetadata = { ...sessionMetadata, inbox };
|
|
6643
|
+
sessionService.updateMetadata(sessionMetadata);
|
|
6644
|
+
} else {
|
|
6645
|
+
logger.log(`[Session ${sessionId}] Normal inbox message from ${message.from}: ${message.subject}`);
|
|
6646
|
+
if (!sessionWasProcessing && !trackedSession.stopped) {
|
|
6647
|
+
setTimeout(() => processMessageQueueRef?.(), 200);
|
|
6648
|
+
}
|
|
6649
|
+
}
|
|
6650
|
+
},
|
|
6467
6651
|
onKillSession: () => {
|
|
6468
6652
|
logger.log(`[Session ${sessionId}] Kill session requested`);
|
|
6469
6653
|
stopSession(sessionId);
|
|
6470
6654
|
},
|
|
6471
6655
|
onMetadataUpdate: (newMeta) => {
|
|
6472
6656
|
const prevRalphLoop = sessionMetadata.ralphLoop;
|
|
6657
|
+
const legacyQueue = newMeta.messageQueue;
|
|
6658
|
+
let migratedInbox = newMeta.inbox || [];
|
|
6659
|
+
if (legacyQueue && legacyQueue.length > 0) {
|
|
6660
|
+
const converted = legacyQueue.map((q) => ({
|
|
6661
|
+
messageId: q.id,
|
|
6662
|
+
body: q.text,
|
|
6663
|
+
displayText: q.displayText,
|
|
6664
|
+
timestamp: q.createdAt,
|
|
6665
|
+
read: false
|
|
6666
|
+
}));
|
|
6667
|
+
migratedInbox = [...migratedInbox || [], ...converted];
|
|
6668
|
+
}
|
|
6473
6669
|
sessionMetadata = {
|
|
6474
6670
|
...newMeta,
|
|
6671
|
+
inbox: migratedInbox.length > 0 ? migratedInbox : newMeta.inbox,
|
|
6672
|
+
// Clear legacy messageQueue — daemon uses inbox only
|
|
6673
|
+
...legacyQueue && legacyQueue.length > 0 ? { messageQueue: void 0 } : {},
|
|
6475
6674
|
// Daemon drives lifecycleState — don't let frontend overwrite with stale value
|
|
6476
6675
|
lifecycleState: sessionMetadata.lifecycleState,
|
|
6477
6676
|
// Preserve claudeSessionId set by 'system init' (frontend may not have it)
|
|
@@ -6487,8 +6686,11 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
6487
6686
|
if (prevRalphLoop && !newMeta.ralphLoop) {
|
|
6488
6687
|
sessionService.updateMetadata(sessionMetadata);
|
|
6489
6688
|
}
|
|
6490
|
-
|
|
6491
|
-
|
|
6689
|
+
if (legacyQueue && legacyQueue.length > 0) {
|
|
6690
|
+
sessionService.updateMetadata(sessionMetadata);
|
|
6691
|
+
}
|
|
6692
|
+
const unreadInbox = sessionMetadata.inbox?.filter((m) => !m.read);
|
|
6693
|
+
if (unreadInbox && unreadInbox.length > 0 && !sessionWasProcessing && !trackedSession.stopped) {
|
|
6492
6694
|
setTimeout(() => {
|
|
6493
6695
|
processMessageQueueRef?.();
|
|
6494
6696
|
}, 200);
|
|
@@ -6611,16 +6813,18 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
6611
6813
|
if (trackedSession?.stopped) return;
|
|
6612
6814
|
if (isKillingClaude) return;
|
|
6613
6815
|
if (isRestartingClaude || isSwitchingMode) return;
|
|
6614
|
-
const
|
|
6615
|
-
|
|
6616
|
-
|
|
6617
|
-
const
|
|
6618
|
-
|
|
6816
|
+
const inbox = sessionMetadata.inbox;
|
|
6817
|
+
const unreadIdx = inbox?.findIndex((m) => !m.read) ?? -1;
|
|
6818
|
+
if (inbox && unreadIdx >= 0) {
|
|
6819
|
+
const next = inbox[unreadIdx];
|
|
6820
|
+
const updatedInbox = inbox.map((m, i) => i === unreadIdx ? { ...m, read: true } : m);
|
|
6821
|
+
sessionMetadata = { ...sessionMetadata, inbox: updatedInbox };
|
|
6619
6822
|
sessionService.updateMetadata(sessionMetadata);
|
|
6620
|
-
|
|
6823
|
+
const deliverText = isStructuredMessage(next) ? formatInboxMessageXml(next) : next.body;
|
|
6824
|
+
logger.log(`[Session ${sessionId}] Processing inbox message: "${next.body.slice(0, 50)}..."`);
|
|
6621
6825
|
sessionWasProcessing = true;
|
|
6622
6826
|
signalProcessing(true);
|
|
6623
|
-
sessionService.pushMessage(next.displayText || next.
|
|
6827
|
+
sessionService.pushMessage(next.displayText || next.body, "user");
|
|
6624
6828
|
userMessagePending = true;
|
|
6625
6829
|
turnInitiatedByUser = true;
|
|
6626
6830
|
const queueMeta = next.ralphSystemPrompt ? { appendSystemPrompt: next.ralphSystemPrompt } : void 0;
|
|
@@ -6642,7 +6846,7 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
6642
6846
|
if (trackedSession?.stopped) return;
|
|
6643
6847
|
if (isRestartingClaude || isSwitchingMode) return;
|
|
6644
6848
|
claudeResumeId = void 0;
|
|
6645
|
-
spawnClaude(
|
|
6849
|
+
spawnClaude(deliverText, queueMeta);
|
|
6646
6850
|
} catch (err) {
|
|
6647
6851
|
logger.log(`[Session ${sessionId}] Error in fresh Ralph queue processing: ${err.message}`);
|
|
6648
6852
|
isKillingClaude = false;
|
|
@@ -6653,11 +6857,11 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
6653
6857
|
} else {
|
|
6654
6858
|
try {
|
|
6655
6859
|
if (!claudeProcess || claudeProcess.exitCode !== null) {
|
|
6656
|
-
spawnClaude(
|
|
6860
|
+
spawnClaude(deliverText, queueMeta);
|
|
6657
6861
|
} else {
|
|
6658
6862
|
const stdinMsg = JSON.stringify({
|
|
6659
6863
|
type: "user",
|
|
6660
|
-
message: { role: "user", content:
|
|
6864
|
+
message: { role: "user", content: deliverText }
|
|
6661
6865
|
});
|
|
6662
6866
|
claudeProcess.stdin?.write(stdinMsg + "\n");
|
|
6663
6867
|
}
|
|
@@ -6790,20 +6994,20 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
6790
6994
|
}
|
|
6791
6995
|
if (!acpBackendReady) {
|
|
6792
6996
|
logger.log(`[${agentName} Session ${sessionId}] Backend not ready \u2014 queuing message`);
|
|
6793
|
-
const
|
|
6997
|
+
const existingInbox = sessionMetadata.inbox || [];
|
|
6794
6998
|
sessionMetadata = {
|
|
6795
6999
|
...sessionMetadata,
|
|
6796
|
-
|
|
7000
|
+
inbox: [...existingInbox, { messageId: randomUUID$1(), body: text, timestamp: Date.now(), read: false }]
|
|
6797
7001
|
};
|
|
6798
7002
|
sessionService.updateMetadata(sessionMetadata);
|
|
6799
7003
|
return;
|
|
6800
7004
|
}
|
|
6801
7005
|
if (sessionMetadata.lifecycleState === "running") {
|
|
6802
7006
|
logger.log(`[${agentName} Session ${sessionId}] Agent busy \u2014 queuing message`);
|
|
6803
|
-
const
|
|
7007
|
+
const existingInbox = sessionMetadata.inbox || [];
|
|
6804
7008
|
sessionMetadata = {
|
|
6805
7009
|
...sessionMetadata,
|
|
6806
|
-
|
|
7010
|
+
inbox: [...existingInbox, { messageId: randomUUID$1(), body: text, timestamp: Date.now(), read: false }]
|
|
6807
7011
|
};
|
|
6808
7012
|
sessionService.updateMetadata(sessionMetadata);
|
|
6809
7013
|
return;
|
|
@@ -6860,6 +7064,10 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
6860
7064
|
sessionMetadata = { ...sessionMetadata, securityContext: newSecurityContext };
|
|
6861
7065
|
return { success: false, message: "Security context updates with restart are not yet supported for this agent type." };
|
|
6862
7066
|
},
|
|
7067
|
+
onUpdateIsolation: async (enabled) => {
|
|
7068
|
+
sessionMetadata = { ...sessionMetadata, forceIsolation: enabled };
|
|
7069
|
+
return { success: false, message: "Isolation changes with restart are not yet supported for this agent type." };
|
|
7070
|
+
},
|
|
6863
7071
|
onSharingUpdate: (newSharing) => {
|
|
6864
7072
|
logger.log(`[${agentName} Session ${sessionId}] Sharing config updated \u2014 persisting in-memory`);
|
|
6865
7073
|
sessionMetadata = { ...sessionMetadata, sharing: newSharing };
|
|
@@ -6867,14 +7075,59 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
6867
7075
|
onApplySystemPrompt: async () => {
|
|
6868
7076
|
return { success: false, message: "System prompt updates with restart are not yet supported for this agent type." };
|
|
6869
7077
|
},
|
|
7078
|
+
onInboxMessage: (message) => {
|
|
7079
|
+
const xmlText = formatInboxMessageXml(message);
|
|
7080
|
+
if (message.urgency === "urgent") {
|
|
7081
|
+
logger.log(`[${agentName} Session ${sessionId}] Urgent inbox message from ${message.from}: ${message.subject}`);
|
|
7082
|
+
if (sessionMetadata.lifecycleState === "running" || !acpBackendReady) {
|
|
7083
|
+
const existingInbox = sessionMetadata.inbox || [];
|
|
7084
|
+
sessionMetadata = { ...sessionMetadata, inbox: [{ messageId: message.messageId, body: xmlText, displayText: `[Inbox] ${message.subject}`, timestamp: Date.now(), read: false, from: message.from, fromSession: message.fromSession, subject: message.subject, urgency: "urgent" }, ...existingInbox] };
|
|
7085
|
+
sessionService.updateMetadata(sessionMetadata);
|
|
7086
|
+
} else {
|
|
7087
|
+
sessionMetadata = { ...sessionMetadata, lifecycleState: "running" };
|
|
7088
|
+
sessionService.updateMetadata(sessionMetadata);
|
|
7089
|
+
sessionService.pushMessage(`[Inbox] ${message.subject}`, "user");
|
|
7090
|
+
agentBackend.sendPrompt(sessionId, xmlText).catch((err) => {
|
|
7091
|
+
logger.error(`[${agentName} Session ${sessionId}] Error sending urgent inbox: ${err.message}`);
|
|
7092
|
+
if (!acpStopped) {
|
|
7093
|
+
sessionMetadata = { ...sessionMetadata, lifecycleState: "idle" };
|
|
7094
|
+
sessionService.updateMetadata(sessionMetadata);
|
|
7095
|
+
sessionService.sendSessionEnd();
|
|
7096
|
+
}
|
|
7097
|
+
});
|
|
7098
|
+
}
|
|
7099
|
+
const inbox = (sessionMetadata.inbox || []).map(
|
|
7100
|
+
(m) => m.messageId === message.messageId ? { ...m, read: true } : m
|
|
7101
|
+
);
|
|
7102
|
+
sessionMetadata = { ...sessionMetadata, inbox };
|
|
7103
|
+
sessionService.updateMetadata(sessionMetadata);
|
|
7104
|
+
} else {
|
|
7105
|
+
logger.log(`[${agentName} Session ${sessionId}] Normal inbox message from ${message.from}: ${message.subject}`);
|
|
7106
|
+
}
|
|
7107
|
+
},
|
|
6870
7108
|
onKillSession: () => {
|
|
6871
7109
|
logger.log(`[${agentName} Session ${sessionId}] Kill session requested`);
|
|
6872
7110
|
stopSession(sessionId);
|
|
6873
7111
|
},
|
|
6874
7112
|
onMetadataUpdate: (newMeta) => {
|
|
6875
7113
|
const prevRalphLoop = sessionMetadata.ralphLoop;
|
|
7114
|
+
const legacyQueue = newMeta.messageQueue;
|
|
7115
|
+
let migratedInbox = newMeta.inbox || [];
|
|
7116
|
+
if (legacyQueue && legacyQueue.length > 0) {
|
|
7117
|
+
const converted = legacyQueue.map((q) => ({
|
|
7118
|
+
messageId: q.id,
|
|
7119
|
+
body: q.text,
|
|
7120
|
+
displayText: q.displayText,
|
|
7121
|
+
timestamp: q.createdAt,
|
|
7122
|
+
read: false
|
|
7123
|
+
}));
|
|
7124
|
+
migratedInbox = [...migratedInbox || [], ...converted];
|
|
7125
|
+
}
|
|
6876
7126
|
sessionMetadata = {
|
|
6877
7127
|
...newMeta,
|
|
7128
|
+
inbox: migratedInbox.length > 0 ? migratedInbox : newMeta.inbox,
|
|
7129
|
+
// Clear legacy messageQueue — daemon uses inbox only
|
|
7130
|
+
...legacyQueue && legacyQueue.length > 0 ? { messageQueue: void 0 } : {},
|
|
6878
7131
|
// Daemon drives lifecycleState — don't let frontend overwrite with stale value
|
|
6879
7132
|
lifecycleState: sessionMetadata.lifecycleState,
|
|
6880
7133
|
...sessionMetadata.summary && !newMeta.summary ? { summary: sessionMetadata.summary } : {},
|
|
@@ -6888,17 +7141,24 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
6888
7141
|
if (prevRalphLoop && !newMeta.ralphLoop) {
|
|
6889
7142
|
sessionService.updateMetadata(sessionMetadata);
|
|
6890
7143
|
}
|
|
7144
|
+
if (legacyQueue && legacyQueue.length > 0) {
|
|
7145
|
+
sessionService.updateMetadata(sessionMetadata);
|
|
7146
|
+
}
|
|
6891
7147
|
if (acpStopped) return;
|
|
6892
|
-
const
|
|
6893
|
-
if (
|
|
6894
|
-
const next =
|
|
6895
|
-
|
|
6896
|
-
|
|
7148
|
+
const unreadInbox = sessionMetadata.inbox?.filter((m) => !m.read);
|
|
7149
|
+
if (unreadInbox && unreadInbox.length > 0 && sessionMetadata.lifecycleState === "idle") {
|
|
7150
|
+
const next = unreadInbox[0];
|
|
7151
|
+
sessionMetadata = {
|
|
7152
|
+
...sessionMetadata,
|
|
7153
|
+
inbox: (sessionMetadata.inbox || []).map((m) => m.messageId === next.messageId ? { ...m, read: true } : m),
|
|
7154
|
+
lifecycleState: "running"
|
|
7155
|
+
};
|
|
6897
7156
|
sessionService.updateMetadata(sessionMetadata);
|
|
6898
|
-
|
|
7157
|
+
const deliverText = isStructuredMessage(next) ? formatInboxMessageXml(next) : next.body;
|
|
7158
|
+
logger.log(`[Session ${sessionId}] Processing inbox message from metadata update: "${next.body.slice(0, 50)}..."`);
|
|
6899
7159
|
sessionService.sendKeepAlive(true);
|
|
6900
|
-
agentBackend.sendPrompt(sessionId,
|
|
6901
|
-
logger.error(`[Session ${sessionId}] Error processing
|
|
7160
|
+
agentBackend.sendPrompt(sessionId, deliverText).catch((err) => {
|
|
7161
|
+
logger.error(`[Session ${sessionId}] Error processing inbox message: ${err.message}`);
|
|
6902
7162
|
if (!acpStopped) {
|
|
6903
7163
|
sessionMetadata = { ...sessionMetadata, lifecycleState: "idle" };
|
|
6904
7164
|
sessionService.updateMetadata(sessionMetadata);
|
|
@@ -7015,16 +7275,20 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
7015
7275
|
() => {
|
|
7016
7276
|
if (acpStopped) return;
|
|
7017
7277
|
if (insideOnTurnEnd) return;
|
|
7018
|
-
const
|
|
7019
|
-
if (
|
|
7020
|
-
const next =
|
|
7021
|
-
|
|
7022
|
-
|
|
7278
|
+
const unreadInbox = sessionMetadata.inbox?.filter((m) => !m.read);
|
|
7279
|
+
if (unreadInbox && unreadInbox.length > 0 && sessionMetadata.lifecycleState === "idle") {
|
|
7280
|
+
const next = unreadInbox[0];
|
|
7281
|
+
sessionMetadata = {
|
|
7282
|
+
...sessionMetadata,
|
|
7283
|
+
inbox: (sessionMetadata.inbox || []).map((m) => m.messageId === next.messageId ? { ...m, read: true } : m),
|
|
7284
|
+
lifecycleState: "running"
|
|
7285
|
+
};
|
|
7023
7286
|
sessionService.updateMetadata(sessionMetadata);
|
|
7024
|
-
|
|
7287
|
+
const deliverText = isStructuredMessage(next) ? formatInboxMessageXml(next) : next.body;
|
|
7288
|
+
logger.log(`[Session ${sessionId}] Processing inbox message (ACP ralph activation): "${next.body.slice(0, 50)}..."`);
|
|
7025
7289
|
sessionService.sendKeepAlive(true);
|
|
7026
|
-
agentBackend.sendPrompt(sessionId,
|
|
7027
|
-
logger.error(`[Session ${sessionId}] Error processing
|
|
7290
|
+
agentBackend.sendPrompt(sessionId, deliverText).catch((err) => {
|
|
7291
|
+
logger.error(`[Session ${sessionId}] Error processing inbox message: ${err.message}`);
|
|
7028
7292
|
if (!acpStopped) {
|
|
7029
7293
|
sessionMetadata = { ...sessionMetadata, lifecycleState: "idle" };
|
|
7030
7294
|
sessionService.updateMetadata(sessionMetadata);
|
|
@@ -7038,7 +7302,7 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
7038
7302
|
const writeSvampConfigPatchAcp = svampConfigChecker.writeConfig;
|
|
7039
7303
|
const permissionHandler = new HyphaPermissionHandler(shouldAutoAllow2, logger.log);
|
|
7040
7304
|
let agentIsoConfig;
|
|
7041
|
-
if ((options2.forceIsolation || sessionMetadata.sharing?.enabled) && isolationCapabilities.preferred) {
|
|
7305
|
+
if (((sessionMetadata.forceIsolation ?? options2.forceIsolation) || sessionMetadata.sharing?.enabled) && isolationCapabilities.preferred) {
|
|
7042
7306
|
const method = isolationCapabilities.preferred;
|
|
7043
7307
|
const detail = isolationCapabilities.details[method];
|
|
7044
7308
|
if (detail.found && detail.verified !== false) {
|
|
@@ -7106,17 +7370,21 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
7106
7370
|
logger.log(`[${agentName} Session ${sessionId}] ${reason}`);
|
|
7107
7371
|
sessionService.pushMessage({ type: "message", message: reason }, "event");
|
|
7108
7372
|
} else {
|
|
7109
|
-
const
|
|
7110
|
-
if (
|
|
7111
|
-
const next =
|
|
7112
|
-
|
|
7113
|
-
|
|
7373
|
+
const pendingInbox = sessionMetadata.inbox?.filter((m) => !m.read);
|
|
7374
|
+
if (pendingInbox && pendingInbox.length > 0) {
|
|
7375
|
+
const next = pendingInbox[0];
|
|
7376
|
+
sessionMetadata = {
|
|
7377
|
+
...sessionMetadata,
|
|
7378
|
+
inbox: (sessionMetadata.inbox || []).map((m) => m.messageId === next.messageId ? { ...m, read: true } : m),
|
|
7379
|
+
lifecycleState: "running"
|
|
7380
|
+
};
|
|
7114
7381
|
sessionService.updateMetadata(sessionMetadata);
|
|
7115
7382
|
sessionService.sendKeepAlive(true);
|
|
7116
|
-
|
|
7117
|
-
|
|
7118
|
-
|
|
7119
|
-
|
|
7383
|
+
const deliverText = isStructuredMessage(next) ? formatInboxMessageXml(next) : next.body;
|
|
7384
|
+
sessionService.pushMessage(next.displayText || next.body, "user");
|
|
7385
|
+
logger.log(`[${agentName} Session ${sessionId}] Processing inbox message (priority over Ralph advance): "${next.body.slice(0, 50)}..."`);
|
|
7386
|
+
agentBackend.sendPrompt(sessionId, deliverText).catch((err) => {
|
|
7387
|
+
logger.error(`[${agentName} Session ${sessionId}] Error processing inbox message (Ralph): ${err.message}`);
|
|
7120
7388
|
if (!acpStopped) {
|
|
7121
7389
|
sessionMetadata = { ...sessionMetadata, lifecycleState: "idle" };
|
|
7122
7390
|
sessionService.updateMetadata(sessionMetadata);
|
|
@@ -7183,17 +7451,21 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
7183
7451
|
return;
|
|
7184
7452
|
}
|
|
7185
7453
|
}
|
|
7186
|
-
const
|
|
7187
|
-
if (
|
|
7188
|
-
const next =
|
|
7189
|
-
|
|
7190
|
-
|
|
7454
|
+
const unreadInboxItems = sessionMetadata.inbox?.filter((m) => !m.read);
|
|
7455
|
+
if (unreadInboxItems && unreadInboxItems.length > 0) {
|
|
7456
|
+
const next = unreadInboxItems[0];
|
|
7457
|
+
sessionMetadata = {
|
|
7458
|
+
...sessionMetadata,
|
|
7459
|
+
inbox: (sessionMetadata.inbox || []).map((m) => m.messageId === next.messageId ? { ...m, read: true } : m),
|
|
7460
|
+
lifecycleState: "running"
|
|
7461
|
+
};
|
|
7191
7462
|
sessionService.updateMetadata(sessionMetadata);
|
|
7192
7463
|
sessionService.sendKeepAlive(true);
|
|
7193
|
-
|
|
7194
|
-
|
|
7195
|
-
|
|
7196
|
-
|
|
7464
|
+
const deliverText = isStructuredMessage(next) ? formatInboxMessageXml(next) : next.body;
|
|
7465
|
+
logger.log(`[Session ${sessionId}] Processing inbox message: "${next.body.slice(0, 50)}..."`);
|
|
7466
|
+
sessionService.pushMessage(next.displayText || next.body, "user");
|
|
7467
|
+
agentBackend.sendPrompt(sessionId, deliverText).catch((err) => {
|
|
7468
|
+
logger.error(`[Session ${sessionId}] Error processing inbox message: ${err.message}`);
|
|
7197
7469
|
if (!acpStopped) {
|
|
7198
7470
|
sessionMetadata = { ...sessionMetadata, lifecycleState: "idle" };
|
|
7199
7471
|
sessionService.updateMetadata(sessionMetadata);
|
|
@@ -7404,7 +7676,7 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
7404
7676
|
// Restore sharing & security context from persisted metadata
|
|
7405
7677
|
sharing: persisted.metadata?.sharing,
|
|
7406
7678
|
securityContext: persisted.metadata?.securityContext,
|
|
7407
|
-
forceIsolation: !!persisted.metadata?.isolationMethod,
|
|
7679
|
+
forceIsolation: persisted.metadata?.forceIsolation ?? !!persisted.metadata?.isolationMethod,
|
|
7408
7680
|
// Block queue processing until auto-continue completes
|
|
7409
7681
|
wasProcessing: persisted.wasProcessing && !!persisted.claudeResumeId && !isOrphaned
|
|
7410
7682
|
});
|
|
@@ -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-6QgabuQN.mjs';
|
|
6
6
|
import { createServer } from 'node:http';
|
|
7
7
|
import { spawn } from 'node:child_process';
|
|
8
8
|
import { createInterface } from 'node:readline';
|