svamp-cli 0.1.72 → 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-COX5-rj3.mjs → commands-ClMc3nSg.mjs} +174 -38
- package/dist/{commands-DMhuR7JE.mjs → commands-dKkUOvUb.mjs} +3 -3
- package/dist/index.mjs +1 -1
- package/dist/{package-BppQHKG7.mjs → package-CCjeil_X.mjs} +1 -1
- package/dist/{run-p-RshVII.mjs → run-6QgabuQN.mjs} +366 -65
- package/dist/{run-D9fkwRb3.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 && (() => {
|
|
@@ -5585,6 +5707,8 @@ async function startDaemon(options) {
|
|
|
5585
5707
|
let lastSpawnMeta = persisted?.spawnMeta || {};
|
|
5586
5708
|
let sessionWasProcessing = !!options2.wasProcessing;
|
|
5587
5709
|
let lastAssistantText = "";
|
|
5710
|
+
let consecutiveRalphErrors = 0;
|
|
5711
|
+
const MAX_RALPH_ERRORS = 3;
|
|
5588
5712
|
let spawnHasReceivedInit = false;
|
|
5589
5713
|
let startupFailureRetryPending = false;
|
|
5590
5714
|
let startupRetryMessage;
|
|
@@ -5642,7 +5766,8 @@ async function startDaemon(options) {
|
|
|
5642
5766
|
startupNonJsonLines = [];
|
|
5643
5767
|
startupRetryMessage = initialMessage;
|
|
5644
5768
|
let rawPermissionMode = effectiveMeta.permissionMode || agentConfig.default_permission_mode || currentPermissionMode;
|
|
5645
|
-
|
|
5769
|
+
const forceIsolation = sessionMetadata.forceIsolation ?? options2.forceIsolation;
|
|
5770
|
+
if (forceIsolation || sessionMetadata.sharing?.enabled) {
|
|
5646
5771
|
rawPermissionMode = rawPermissionMode === "default" ? "auto-approve-all" : rawPermissionMode;
|
|
5647
5772
|
}
|
|
5648
5773
|
if (sessionMetadata.ralphLoop?.active) {
|
|
@@ -5679,7 +5804,7 @@ async function startDaemon(options) {
|
|
|
5679
5804
|
if (wrapped.cleanupFiles) isolationCleanupFiles = wrapped.cleanupFiles;
|
|
5680
5805
|
sessionMetadata = { ...sessionMetadata, isolationMethod: isoConfig.method };
|
|
5681
5806
|
logger.log(`[Session ${sessionId}] Isolation: ${isoConfig.method} (binary: ${isoConfig.binaryPath})`);
|
|
5682
|
-
} else if (
|
|
5807
|
+
} else if (forceIsolation || sessionMetadata.sharing?.enabled) {
|
|
5683
5808
|
logger.log(`[Session ${sessionId}] WARNING: No isolation runtime (nono/docker/podman) available. Session is NOT sandboxed.`);
|
|
5684
5809
|
sessionMetadata = { ...sessionMetadata, isolationMethod: void 0 };
|
|
5685
5810
|
} else {
|
|
@@ -5904,7 +6029,34 @@ async function startDaemon(options) {
|
|
|
5904
6029
|
logger.log(`[Session ${sessionId}] ${taskInfo}`);
|
|
5905
6030
|
sessionService.pushMessage({ type: "session_event", message: taskInfo }, "session");
|
|
5906
6031
|
}
|
|
5907
|
-
const queueLen = sessionMetadata.
|
|
6032
|
+
const queueLen = sessionMetadata.inbox?.filter((m) => !m.read)?.length ?? 0;
|
|
6033
|
+
if (msg.is_error) {
|
|
6034
|
+
const rlStateForError = readRalphState(getRalphStateFilePath(directory, sessionId));
|
|
6035
|
+
if (rlStateForError) {
|
|
6036
|
+
consecutiveRalphErrors++;
|
|
6037
|
+
logger.log(`[Session ${sessionId}] Ralph loop: error result (consecutive=${consecutiveRalphErrors}/${MAX_RALPH_ERRORS})`);
|
|
6038
|
+
if (consecutiveRalphErrors >= MAX_RALPH_ERRORS) {
|
|
6039
|
+
logger.log(`[Session ${sessionId}] Ralph loop: ${MAX_RALPH_ERRORS} consecutive errors \u2014 stopping loop`);
|
|
6040
|
+
removeRalphState(getRalphStateFilePath(directory, sessionId));
|
|
6041
|
+
if (lastSpawnMeta.appendSystemPrompt) {
|
|
6042
|
+
const { appendSystemPrompt: _, ...rest } = lastSpawnMeta;
|
|
6043
|
+
lastSpawnMeta = rest;
|
|
6044
|
+
}
|
|
6045
|
+
sessionMetadata = { ...sessionMetadata, ralphLoop: { active: false }, lifecycleState: "idle" };
|
|
6046
|
+
sessionService.updateMetadata(sessionMetadata);
|
|
6047
|
+
sessionService.pushMessage(
|
|
6048
|
+
{ type: "message", message: `Ralph loop stopped \u2014 ${consecutiveRalphErrors} consecutive errors. Last error: ${msg.result || "unknown"}`, level: "error" },
|
|
6049
|
+
"event"
|
|
6050
|
+
);
|
|
6051
|
+
consecutiveRalphErrors = 0;
|
|
6052
|
+
signalProcessing(false);
|
|
6053
|
+
sessionService.sendSessionEnd();
|
|
6054
|
+
break;
|
|
6055
|
+
}
|
|
6056
|
+
}
|
|
6057
|
+
} else {
|
|
6058
|
+
consecutiveRalphErrors = 0;
|
|
6059
|
+
}
|
|
5908
6060
|
if (queueLen > 0 && claudeResumeId && !trackedSession.stopped) {
|
|
5909
6061
|
setTimeout(() => processMessageQueueRef?.(), 200);
|
|
5910
6062
|
} else if (claudeResumeId) {
|
|
@@ -6182,7 +6334,7 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
6182
6334
|
return;
|
|
6183
6335
|
}
|
|
6184
6336
|
}
|
|
6185
|
-
const queueLen = sessionMetadata.
|
|
6337
|
+
const queueLen = sessionMetadata.inbox?.filter((m) => !m.read)?.length ?? 0;
|
|
6186
6338
|
if (queueLen > 0 && claudeResumeId && !trackedSession.stopped) {
|
|
6187
6339
|
signalProcessing(false);
|
|
6188
6340
|
setTimeout(() => processMessageQueueRef?.(), 200);
|
|
@@ -6293,10 +6445,10 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
6293
6445
|
}
|
|
6294
6446
|
if (isKillingClaude || isRestartingClaude || isSwitchingMode) {
|
|
6295
6447
|
logger.log(`[Session ${sessionId}] Message received while restarting Claude, queuing to prevent loss`);
|
|
6296
|
-
const
|
|
6448
|
+
const existingInbox = sessionMetadata.inbox || [];
|
|
6297
6449
|
sessionMetadata = {
|
|
6298
6450
|
...sessionMetadata,
|
|
6299
|
-
|
|
6451
|
+
inbox: [...existingInbox, { messageId: randomUUID$1(), body: text, timestamp: Date.now(), read: false }]
|
|
6300
6452
|
};
|
|
6301
6453
|
sessionService.updateMetadata(sessionMetadata);
|
|
6302
6454
|
signalProcessing(false);
|
|
@@ -6331,7 +6483,7 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
6331
6483
|
}
|
|
6332
6484
|
signalProcessing(false);
|
|
6333
6485
|
sessionWasProcessing = false;
|
|
6334
|
-
const queueLen = sessionMetadata.
|
|
6486
|
+
const queueLen = sessionMetadata.inbox?.filter((m) => !m.read)?.length ?? 0;
|
|
6335
6487
|
const abortMsg = queueLen > 0 ? `Aborted by user. ${queueLen} queued message(s) will be processed next.` : "Aborted by user";
|
|
6336
6488
|
sessionService.pushMessage(
|
|
6337
6489
|
{ type: "message", message: abortMsg },
|
|
@@ -6413,6 +6565,24 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
6413
6565
|
sessionMetadata = { ...sessionMetadata, securityContext: newSecurityContext };
|
|
6414
6566
|
return await restartClaudeHandler();
|
|
6415
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
|
+
},
|
|
6416
6586
|
onSharingUpdate: (newSharing) => {
|
|
6417
6587
|
logger.log(`[Session ${sessionId}] Sharing config updated \u2014 persisting to disk`);
|
|
6418
6588
|
sessionMetadata = { ...sessionMetadata, sharing: newSharing };
|
|
@@ -6435,14 +6605,72 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
6435
6605
|
lastSpawnMeta = { ...lastSpawnMeta, appendSystemPrompt: prompt };
|
|
6436
6606
|
return await restartClaudeHandler();
|
|
6437
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
|
+
},
|
|
6438
6651
|
onKillSession: () => {
|
|
6439
6652
|
logger.log(`[Session ${sessionId}] Kill session requested`);
|
|
6440
6653
|
stopSession(sessionId);
|
|
6441
6654
|
},
|
|
6442
6655
|
onMetadataUpdate: (newMeta) => {
|
|
6443
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
|
+
}
|
|
6444
6669
|
sessionMetadata = {
|
|
6445
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 } : {},
|
|
6446
6674
|
// Daemon drives lifecycleState — don't let frontend overwrite with stale value
|
|
6447
6675
|
lifecycleState: sessionMetadata.lifecycleState,
|
|
6448
6676
|
// Preserve claudeSessionId set by 'system init' (frontend may not have it)
|
|
@@ -6458,8 +6686,11 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
6458
6686
|
if (prevRalphLoop && !newMeta.ralphLoop) {
|
|
6459
6687
|
sessionService.updateMetadata(sessionMetadata);
|
|
6460
6688
|
}
|
|
6461
|
-
|
|
6462
|
-
|
|
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) {
|
|
6463
6694
|
setTimeout(() => {
|
|
6464
6695
|
processMessageQueueRef?.();
|
|
6465
6696
|
}, 200);
|
|
@@ -6582,16 +6813,18 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
6582
6813
|
if (trackedSession?.stopped) return;
|
|
6583
6814
|
if (isKillingClaude) return;
|
|
6584
6815
|
if (isRestartingClaude || isSwitchingMode) return;
|
|
6585
|
-
const
|
|
6586
|
-
|
|
6587
|
-
|
|
6588
|
-
const
|
|
6589
|
-
|
|
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 };
|
|
6590
6822
|
sessionService.updateMetadata(sessionMetadata);
|
|
6591
|
-
|
|
6823
|
+
const deliverText = isStructuredMessage(next) ? formatInboxMessageXml(next) : next.body;
|
|
6824
|
+
logger.log(`[Session ${sessionId}] Processing inbox message: "${next.body.slice(0, 50)}..."`);
|
|
6592
6825
|
sessionWasProcessing = true;
|
|
6593
6826
|
signalProcessing(true);
|
|
6594
|
-
sessionService.pushMessage(next.displayText || next.
|
|
6827
|
+
sessionService.pushMessage(next.displayText || next.body, "user");
|
|
6595
6828
|
userMessagePending = true;
|
|
6596
6829
|
turnInitiatedByUser = true;
|
|
6597
6830
|
const queueMeta = next.ralphSystemPrompt ? { appendSystemPrompt: next.ralphSystemPrompt } : void 0;
|
|
@@ -6613,7 +6846,7 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
6613
6846
|
if (trackedSession?.stopped) return;
|
|
6614
6847
|
if (isRestartingClaude || isSwitchingMode) return;
|
|
6615
6848
|
claudeResumeId = void 0;
|
|
6616
|
-
spawnClaude(
|
|
6849
|
+
spawnClaude(deliverText, queueMeta);
|
|
6617
6850
|
} catch (err) {
|
|
6618
6851
|
logger.log(`[Session ${sessionId}] Error in fresh Ralph queue processing: ${err.message}`);
|
|
6619
6852
|
isKillingClaude = false;
|
|
@@ -6624,11 +6857,11 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
6624
6857
|
} else {
|
|
6625
6858
|
try {
|
|
6626
6859
|
if (!claudeProcess || claudeProcess.exitCode !== null) {
|
|
6627
|
-
spawnClaude(
|
|
6860
|
+
spawnClaude(deliverText, queueMeta);
|
|
6628
6861
|
} else {
|
|
6629
6862
|
const stdinMsg = JSON.stringify({
|
|
6630
6863
|
type: "user",
|
|
6631
|
-
message: { role: "user", content:
|
|
6864
|
+
message: { role: "user", content: deliverText }
|
|
6632
6865
|
});
|
|
6633
6866
|
claudeProcess.stdin?.write(stdinMsg + "\n");
|
|
6634
6867
|
}
|
|
@@ -6761,20 +6994,20 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
6761
6994
|
}
|
|
6762
6995
|
if (!acpBackendReady) {
|
|
6763
6996
|
logger.log(`[${agentName} Session ${sessionId}] Backend not ready \u2014 queuing message`);
|
|
6764
|
-
const
|
|
6997
|
+
const existingInbox = sessionMetadata.inbox || [];
|
|
6765
6998
|
sessionMetadata = {
|
|
6766
6999
|
...sessionMetadata,
|
|
6767
|
-
|
|
7000
|
+
inbox: [...existingInbox, { messageId: randomUUID$1(), body: text, timestamp: Date.now(), read: false }]
|
|
6768
7001
|
};
|
|
6769
7002
|
sessionService.updateMetadata(sessionMetadata);
|
|
6770
7003
|
return;
|
|
6771
7004
|
}
|
|
6772
7005
|
if (sessionMetadata.lifecycleState === "running") {
|
|
6773
7006
|
logger.log(`[${agentName} Session ${sessionId}] Agent busy \u2014 queuing message`);
|
|
6774
|
-
const
|
|
7007
|
+
const existingInbox = sessionMetadata.inbox || [];
|
|
6775
7008
|
sessionMetadata = {
|
|
6776
7009
|
...sessionMetadata,
|
|
6777
|
-
|
|
7010
|
+
inbox: [...existingInbox, { messageId: randomUUID$1(), body: text, timestamp: Date.now(), read: false }]
|
|
6778
7011
|
};
|
|
6779
7012
|
sessionService.updateMetadata(sessionMetadata);
|
|
6780
7013
|
return;
|
|
@@ -6831,6 +7064,10 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
6831
7064
|
sessionMetadata = { ...sessionMetadata, securityContext: newSecurityContext };
|
|
6832
7065
|
return { success: false, message: "Security context updates with restart are not yet supported for this agent type." };
|
|
6833
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
|
+
},
|
|
6834
7071
|
onSharingUpdate: (newSharing) => {
|
|
6835
7072
|
logger.log(`[${agentName} Session ${sessionId}] Sharing config updated \u2014 persisting in-memory`);
|
|
6836
7073
|
sessionMetadata = { ...sessionMetadata, sharing: newSharing };
|
|
@@ -6838,14 +7075,59 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
6838
7075
|
onApplySystemPrompt: async () => {
|
|
6839
7076
|
return { success: false, message: "System prompt updates with restart are not yet supported for this agent type." };
|
|
6840
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
|
+
},
|
|
6841
7108
|
onKillSession: () => {
|
|
6842
7109
|
logger.log(`[${agentName} Session ${sessionId}] Kill session requested`);
|
|
6843
7110
|
stopSession(sessionId);
|
|
6844
7111
|
},
|
|
6845
7112
|
onMetadataUpdate: (newMeta) => {
|
|
6846
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
|
+
}
|
|
6847
7126
|
sessionMetadata = {
|
|
6848
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 } : {},
|
|
6849
7131
|
// Daemon drives lifecycleState — don't let frontend overwrite with stale value
|
|
6850
7132
|
lifecycleState: sessionMetadata.lifecycleState,
|
|
6851
7133
|
...sessionMetadata.summary && !newMeta.summary ? { summary: sessionMetadata.summary } : {},
|
|
@@ -6859,17 +7141,24 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
6859
7141
|
if (prevRalphLoop && !newMeta.ralphLoop) {
|
|
6860
7142
|
sessionService.updateMetadata(sessionMetadata);
|
|
6861
7143
|
}
|
|
7144
|
+
if (legacyQueue && legacyQueue.length > 0) {
|
|
7145
|
+
sessionService.updateMetadata(sessionMetadata);
|
|
7146
|
+
}
|
|
6862
7147
|
if (acpStopped) return;
|
|
6863
|
-
const
|
|
6864
|
-
if (
|
|
6865
|
-
const next =
|
|
6866
|
-
|
|
6867
|
-
|
|
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
|
+
};
|
|
6868
7156
|
sessionService.updateMetadata(sessionMetadata);
|
|
6869
|
-
|
|
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)}..."`);
|
|
6870
7159
|
sessionService.sendKeepAlive(true);
|
|
6871
|
-
agentBackend.sendPrompt(sessionId,
|
|
6872
|
-
logger.error(`[Session ${sessionId}] Error processing
|
|
7160
|
+
agentBackend.sendPrompt(sessionId, deliverText).catch((err) => {
|
|
7161
|
+
logger.error(`[Session ${sessionId}] Error processing inbox message: ${err.message}`);
|
|
6873
7162
|
if (!acpStopped) {
|
|
6874
7163
|
sessionMetadata = { ...sessionMetadata, lifecycleState: "idle" };
|
|
6875
7164
|
sessionService.updateMetadata(sessionMetadata);
|
|
@@ -6986,16 +7275,20 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
6986
7275
|
() => {
|
|
6987
7276
|
if (acpStopped) return;
|
|
6988
7277
|
if (insideOnTurnEnd) return;
|
|
6989
|
-
const
|
|
6990
|
-
if (
|
|
6991
|
-
const next =
|
|
6992
|
-
|
|
6993
|
-
|
|
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
|
+
};
|
|
6994
7286
|
sessionService.updateMetadata(sessionMetadata);
|
|
6995
|
-
|
|
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)}..."`);
|
|
6996
7289
|
sessionService.sendKeepAlive(true);
|
|
6997
|
-
agentBackend.sendPrompt(sessionId,
|
|
6998
|
-
logger.error(`[Session ${sessionId}] Error processing
|
|
7290
|
+
agentBackend.sendPrompt(sessionId, deliverText).catch((err) => {
|
|
7291
|
+
logger.error(`[Session ${sessionId}] Error processing inbox message: ${err.message}`);
|
|
6999
7292
|
if (!acpStopped) {
|
|
7000
7293
|
sessionMetadata = { ...sessionMetadata, lifecycleState: "idle" };
|
|
7001
7294
|
sessionService.updateMetadata(sessionMetadata);
|
|
@@ -7009,7 +7302,7 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
7009
7302
|
const writeSvampConfigPatchAcp = svampConfigChecker.writeConfig;
|
|
7010
7303
|
const permissionHandler = new HyphaPermissionHandler(shouldAutoAllow2, logger.log);
|
|
7011
7304
|
let agentIsoConfig;
|
|
7012
|
-
if ((options2.forceIsolation || sessionMetadata.sharing?.enabled) && isolationCapabilities.preferred) {
|
|
7305
|
+
if (((sessionMetadata.forceIsolation ?? options2.forceIsolation) || sessionMetadata.sharing?.enabled) && isolationCapabilities.preferred) {
|
|
7013
7306
|
const method = isolationCapabilities.preferred;
|
|
7014
7307
|
const detail = isolationCapabilities.details[method];
|
|
7015
7308
|
if (detail.found && detail.verified !== false) {
|
|
@@ -7077,17 +7370,21 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
7077
7370
|
logger.log(`[${agentName} Session ${sessionId}] ${reason}`);
|
|
7078
7371
|
sessionService.pushMessage({ type: "message", message: reason }, "event");
|
|
7079
7372
|
} else {
|
|
7080
|
-
const
|
|
7081
|
-
if (
|
|
7082
|
-
const next =
|
|
7083
|
-
|
|
7084
|
-
|
|
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
|
+
};
|
|
7085
7381
|
sessionService.updateMetadata(sessionMetadata);
|
|
7086
7382
|
sessionService.sendKeepAlive(true);
|
|
7087
|
-
|
|
7088
|
-
|
|
7089
|
-
|
|
7090
|
-
|
|
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}`);
|
|
7091
7388
|
if (!acpStopped) {
|
|
7092
7389
|
sessionMetadata = { ...sessionMetadata, lifecycleState: "idle" };
|
|
7093
7390
|
sessionService.updateMetadata(sessionMetadata);
|
|
@@ -7154,17 +7451,21 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
7154
7451
|
return;
|
|
7155
7452
|
}
|
|
7156
7453
|
}
|
|
7157
|
-
const
|
|
7158
|
-
if (
|
|
7159
|
-
const next =
|
|
7160
|
-
|
|
7161
|
-
|
|
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
|
+
};
|
|
7162
7462
|
sessionService.updateMetadata(sessionMetadata);
|
|
7163
7463
|
sessionService.sendKeepAlive(true);
|
|
7164
|
-
|
|
7165
|
-
|
|
7166
|
-
|
|
7167
|
-
|
|
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}`);
|
|
7168
7469
|
if (!acpStopped) {
|
|
7169
7470
|
sessionMetadata = { ...sessionMetadata, lifecycleState: "idle" };
|
|
7170
7471
|
sessionService.updateMetadata(sessionMetadata);
|
|
@@ -7375,7 +7676,7 @@ The automated loop has finished. Review the progress above and let me know if yo
|
|
|
7375
7676
|
// Restore sharing & security context from persisted metadata
|
|
7376
7677
|
sharing: persisted.metadata?.sharing,
|
|
7377
7678
|
securityContext: persisted.metadata?.securityContext,
|
|
7378
|
-
forceIsolation: !!persisted.metadata?.isolationMethod,
|
|
7679
|
+
forceIsolation: persisted.metadata?.forceIsolation ?? !!persisted.metadata?.isolationMethod,
|
|
7379
7680
|
// Block queue processing until auto-continue completes
|
|
7380
7681
|
wasProcessing: persisted.wasProcessing && !!persisted.claudeResumeId && !isOrphaned
|
|
7381
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';
|