@nomad-e/bluma-cli 0.1.51 → 0.1.52

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.
Files changed (2) hide show
  1. package/dist/main.js +1688 -540
  2. package/package.json +3 -3
package/dist/main.js CHANGED
@@ -496,19 +496,701 @@ var init_async_command = __esm({
496
496
  }
497
497
  });
498
498
 
499
+ // src/app/agent/runtime/session_registry.ts
500
+ var session_registry_exports = {};
501
+ __export(session_registry_exports, {
502
+ appendSessionLog: () => appendSessionLog,
503
+ getSession: () => getSession,
504
+ getSessionLogPath: () => getSessionLogPath,
505
+ listSessions: () => listSessions,
506
+ readSessionLog: () => readSessionLog,
507
+ registerSession: () => registerSession,
508
+ updateSession: () => updateSession
509
+ });
510
+ import fs15 from "fs";
511
+ import os9 from "os";
512
+ import path17 from "path";
513
+ function getRegistryDir() {
514
+ return path17.join(process.env.HOME || os9.homedir(), ".bluma", "registry");
515
+ }
516
+ function getRegistryFile() {
517
+ return path17.join(getRegistryDir(), "sessions.json");
518
+ }
519
+ function ensureRegistryDir() {
520
+ fs15.mkdirSync(getRegistryDir(), { recursive: true });
521
+ }
522
+ function readRegistry() {
523
+ ensureRegistryDir();
524
+ const file = getRegistryFile();
525
+ if (!fs15.existsSync(file)) {
526
+ return { entries: [] };
527
+ }
528
+ try {
529
+ return JSON.parse(fs15.readFileSync(file, "utf-8"));
530
+ } catch {
531
+ return { entries: [] };
532
+ }
533
+ }
534
+ function writeRegistry(state) {
535
+ ensureRegistryDir();
536
+ fs15.writeFileSync(getRegistryFile(), JSON.stringify(state, null, 2), "utf-8");
537
+ }
538
+ function getSessionLogPath(sessionId) {
539
+ ensureRegistryDir();
540
+ return path17.join(getRegistryDir(), `${sessionId}.jsonl`);
541
+ }
542
+ function registerSession(entry) {
543
+ const state = readRegistry();
544
+ const nextEntry = {
545
+ ...entry,
546
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
547
+ logFile: getSessionLogPath(entry.sessionId)
548
+ };
549
+ state.entries = state.entries.filter((item) => item.sessionId !== entry.sessionId);
550
+ state.entries.unshift(nextEntry);
551
+ writeRegistry(state);
552
+ return nextEntry;
553
+ }
554
+ function updateSession(sessionId, patch) {
555
+ const state = readRegistry();
556
+ const index = state.entries.findIndex((entry) => entry.sessionId === sessionId);
557
+ if (index === -1) return null;
558
+ const nextEntry = {
559
+ ...state.entries[index],
560
+ ...patch,
561
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
562
+ };
563
+ state.entries[index] = nextEntry;
564
+ writeRegistry(state);
565
+ return nextEntry;
566
+ }
567
+ function listSessions() {
568
+ return readRegistry().entries;
569
+ }
570
+ function getSession(sessionId) {
571
+ return readRegistry().entries.find((entry) => entry.sessionId === sessionId) || null;
572
+ }
573
+ function appendSessionLog(sessionId, payload) {
574
+ const logFile = getSessionLogPath(sessionId);
575
+ fs15.appendFileSync(logFile, `${JSON.stringify(payload)}
576
+ `, "utf-8");
577
+ }
578
+ function readSessionLog(sessionId) {
579
+ const logFile = getSessionLogPath(sessionId);
580
+ if (!fs15.existsSync(logFile)) return [];
581
+ return fs15.readFileSync(logFile, "utf-8").split("\n").filter(Boolean);
582
+ }
583
+ var init_session_registry = __esm({
584
+ "src/app/agent/runtime/session_registry.ts"() {
585
+ "use strict";
586
+ }
587
+ });
588
+
589
+ // src/app/agent/tools/natives/agent_coordination.ts
590
+ var agent_coordination_exports = {};
591
+ __export(agent_coordination_exports, {
592
+ listAgents: () => listAgents,
593
+ spawnAgent: () => spawnAgent,
594
+ waitAgent: () => waitAgent
595
+ });
596
+ import fs16 from "fs";
597
+ import os10 from "os";
598
+ import path18 from "path";
599
+ import { spawn as spawn4 } from "child_process";
600
+ import { v4 as uuidv43 } from "uuid";
601
+ function readUserContextFromEnv() {
602
+ const raw = process.env.BLUMA_USER_CONTEXT_JSON;
603
+ if (!raw) return null;
604
+ try {
605
+ const parsed = JSON.parse(raw);
606
+ return {
607
+ conversationId: parsed.conversationId ?? null,
608
+ userId: parsed.userId ?? null,
609
+ userName: parsed.userName ?? null,
610
+ userEmail: parsed.userEmail ?? null,
611
+ companyId: parsed.companyId ?? null,
612
+ companyName: parsed.companyName ?? null
613
+ };
614
+ } catch {
615
+ return null;
616
+ }
617
+ }
618
+ function buildWorkerPayload(sessionId, args, parentSessionId, userContext) {
619
+ return {
620
+ message_id: sessionId,
621
+ session_id: sessionId,
622
+ from_agent: parentSessionId || "interactive",
623
+ to_agent: "bluma-worker",
624
+ action: "worker_task",
625
+ context: {
626
+ user_request: args.task,
627
+ coordinator_context: args.context || null,
628
+ worker_title: args.title || null,
629
+ worker_role: args.agent_type || "worker"
630
+ },
631
+ user_context: userContext || void 0,
632
+ metadata: {
633
+ sandbox: process.env.BLUMA_SANDBOX === "true",
634
+ sandbox_name: process.env.BLUMA_SANDBOX_NAME || void 0,
635
+ coordinator_worker: true,
636
+ parent_session_id: parentSessionId
637
+ }
638
+ };
639
+ }
640
+ function extractLatestResult(sessionId) {
641
+ const lines = readSessionLog(sessionId);
642
+ for (let index = lines.length - 1; index >= 0; index -= 1) {
643
+ try {
644
+ const parsed = JSON.parse(lines[index]);
645
+ if (parsed.event_type === "result") {
646
+ return parsed;
647
+ }
648
+ } catch {
649
+ }
650
+ }
651
+ return null;
652
+ }
653
+ function toAgentSummary(entry) {
654
+ return {
655
+ session_id: entry.sessionId,
656
+ title: entry.title,
657
+ kind: entry.kind,
658
+ status: entry.status,
659
+ started_at: entry.startedAt,
660
+ updated_at: entry.updatedAt,
661
+ pid: entry.pid || null,
662
+ metadata: entry.metadata || {}
663
+ };
664
+ }
665
+ async function spawnAgent(args) {
666
+ if (!args?.task || typeof args.task !== "string") {
667
+ return { success: false, error: "task is required" };
668
+ }
669
+ const entrypoint = process.argv[1];
670
+ if (!entrypoint) {
671
+ return { success: false, error: "Unable to resolve CLI entrypoint for worker spawn" };
672
+ }
673
+ const sessionId = uuidv43();
674
+ const parentSessionId = process.env.BLUMA_SESSION_ID || null;
675
+ const userContext = readUserContextFromEnv();
676
+ const title = args.title || `worker:${args.agent_type || "worker"}`;
677
+ const payload = buildWorkerPayload(sessionId, args, parentSessionId, userContext);
678
+ const payloadDir = fs16.mkdtempSync(path18.join(os10.tmpdir(), "bluma-worker-"));
679
+ const payloadPath = path18.join(payloadDir, `${sessionId}.json`);
680
+ fs16.writeFileSync(payloadPath, JSON.stringify(payload, null, 2), "utf-8");
681
+ registerSession({
682
+ sessionId,
683
+ kind: "agent",
684
+ status: "running",
685
+ startedAt: (/* @__PURE__ */ new Date()).toISOString(),
686
+ workdir: process.cwd(),
687
+ title,
688
+ metadata: {
689
+ action: "worker_task",
690
+ background: true,
691
+ coordinator_worker: true,
692
+ parent_session_id: parentSessionId,
693
+ agent_type: args.agent_type || "worker",
694
+ user_id: userContext?.userId ?? null,
695
+ company_id: userContext?.companyId ?? null
696
+ }
697
+ });
698
+ const child = spawn4(
699
+ process.execPath,
700
+ [entrypoint, "agent", "--input-file", payloadPath, "--background-worker", "--registry-session", sessionId],
701
+ {
702
+ detached: true,
703
+ stdio: "ignore",
704
+ cwd: process.cwd(),
705
+ env: {
706
+ ...process.env,
707
+ BLUMA_PARENT_SESSION_ID: parentSessionId || ""
708
+ }
709
+ }
710
+ );
711
+ child.unref();
712
+ updateSession(sessionId, { pid: child.pid });
713
+ return {
714
+ success: true,
715
+ session_id: sessionId,
716
+ pid: child.pid || null,
717
+ parent_session_id: parentSessionId,
718
+ title,
719
+ status: "running"
720
+ };
721
+ }
722
+ async function waitAgent(args) {
723
+ const sessionId = args?.session_id;
724
+ if (!sessionId || typeof sessionId !== "string") {
725
+ return { success: false, error: "session_id is required" };
726
+ }
727
+ const timeoutMs = Math.max(1e3, Number(args.timeout_ms || 3e4));
728
+ const pollIntervalMs = Math.max(200, Number(args.poll_interval_ms || 1e3));
729
+ const deadline = Date.now() + timeoutMs;
730
+ while (Date.now() < deadline) {
731
+ const session2 = getSession(sessionId);
732
+ if (!session2) {
733
+ return { success: false, error: `Unknown session: ${sessionId}` };
734
+ }
735
+ if (session2.status !== "running") {
736
+ return {
737
+ success: true,
738
+ completed: true,
739
+ session: toAgentSummary(session2),
740
+ result: extractLatestResult(sessionId)
741
+ };
742
+ }
743
+ await new Promise((resolve2) => setTimeout(resolve2, pollIntervalMs));
744
+ }
745
+ const session = getSession(sessionId);
746
+ if (!session) {
747
+ return { success: false, error: `Unknown session: ${sessionId}` };
748
+ }
749
+ return {
750
+ success: true,
751
+ completed: false,
752
+ session: toAgentSummary(session),
753
+ result: extractLatestResult(sessionId),
754
+ message: `Timed out after ${timeoutMs}ms while waiting for agent ${sessionId}.`
755
+ };
756
+ }
757
+ async function listAgents(args = {}) {
758
+ const entries = listSessions().filter((entry) => entry.kind === "agent").filter((entry) => {
759
+ if (args.parent_session_id) {
760
+ return entry.metadata?.parent_session_id === args.parent_session_id;
761
+ }
762
+ return true;
763
+ }).filter((entry) => {
764
+ if (args.status) {
765
+ return entry.status === args.status;
766
+ }
767
+ return true;
768
+ }).map(toAgentSummary);
769
+ return {
770
+ success: true,
771
+ count: entries.length,
772
+ agents: entries
773
+ };
774
+ }
775
+ var init_agent_coordination = __esm({
776
+ "src/app/agent/tools/natives/agent_coordination.ts"() {
777
+ "use strict";
778
+ init_session_registry();
779
+ }
780
+ });
781
+
782
+ // src/app/agent/runtime/mailbox_registry.ts
783
+ var mailbox_registry_exports = {};
784
+ __export(mailbox_registry_exports, {
785
+ ensureMailbox: () => ensureMailbox,
786
+ listActiveMailboxes: () => listActiveMailboxes,
787
+ pruneMailbox: () => pruneMailbox,
788
+ readFromMailbox: () => readFromMailbox,
789
+ readSignals: () => readSignals,
790
+ removeMailbox: () => removeMailbox,
791
+ sendFollowUp: () => sendFollowUp,
792
+ sendPermissionRequest: () => sendPermissionRequest,
793
+ sendPermissionResponse: () => sendPermissionResponse,
794
+ sendProgressUpdate: () => sendProgressUpdate,
795
+ sendSignal: () => sendSignal,
796
+ sendToMailbox: () => sendToMailbox
797
+ });
798
+ import fs17 from "fs";
799
+ import os11 from "os";
800
+ import path19 from "path";
801
+ import { v4 as uuidv44 } from "uuid";
802
+ function getMailboxesDir() {
803
+ if (mailboxesDir) {
804
+ return mailboxesDir;
805
+ }
806
+ mailboxesDir = path19.join(process.env.HOME || os11.homedir(), ".bluma", "mailboxes");
807
+ fs17.mkdirSync(mailboxesDir, { recursive: true });
808
+ return mailboxesDir;
809
+ }
810
+ function getMailboxPath(sessionId, type) {
811
+ const dir = getMailboxesDir();
812
+ return path19.join(dir, `${sessionId}.${type}`);
813
+ }
814
+ function ensureMailbox(sessionId) {
815
+ const dir = getMailboxesDir();
816
+ const types = ["in", "out", "sig"];
817
+ for (const type of types) {
818
+ const filePath = path19.join(dir, `${sessionId}.${type}`);
819
+ if (!fs17.existsSync(filePath)) {
820
+ fs17.writeFileSync(filePath, "", "utf-8");
821
+ }
822
+ }
823
+ }
824
+ function sendToMailbox(sessionId, type, message2) {
825
+ const filePath = getMailboxPath(sessionId, type);
826
+ const fullMessage = {
827
+ ...message2,
828
+ id: uuidv44(),
829
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
830
+ };
831
+ const line = JSON.stringify(fullMessage) + "\n";
832
+ fs17.appendFileSync(filePath, line, "utf-8");
833
+ return fullMessage.id;
834
+ }
835
+ function readFromMailbox(sessionId, type, lastReadId) {
836
+ const filePath = getMailboxPath(sessionId, type);
837
+ if (!fs17.existsSync(filePath)) {
838
+ return [];
839
+ }
840
+ const content = fs17.readFileSync(filePath, "utf-8");
841
+ if (!content.trim()) {
842
+ return [];
843
+ }
844
+ const lines = content.trim().split("\n");
845
+ const messages = [];
846
+ let shouldStartReading = !lastReadId;
847
+ for (const line of lines) {
848
+ if (!line.trim()) continue;
849
+ try {
850
+ const msg = JSON.parse(line);
851
+ if (lastReadId && !shouldStartReading) {
852
+ if (msg.id === lastReadId) {
853
+ shouldStartReading = true;
854
+ }
855
+ continue;
856
+ }
857
+ messages.push(msg);
858
+ } catch {
859
+ }
860
+ }
861
+ return messages;
862
+ }
863
+ function pruneMailbox(sessionId, type, keepLast = 100) {
864
+ const filePath = getMailboxPath(sessionId, type);
865
+ if (!fs17.existsSync(filePath)) {
866
+ return;
867
+ }
868
+ const content = fs17.readFileSync(filePath, "utf-8");
869
+ if (!content.trim()) {
870
+ return;
871
+ }
872
+ const lines = content.trim().split("\n").filter((l) => l.trim());
873
+ if (lines.length <= keepLast) {
874
+ return;
875
+ }
876
+ const pruned = lines.slice(-keepLast);
877
+ fs17.writeFileSync(filePath, pruned.join("\n") + "\n", "utf-8");
878
+ }
879
+ function sendSignal(sessionId, type, data, messageId) {
880
+ const filePath = getMailboxPath(sessionId, "sig");
881
+ const signal = {
882
+ id: uuidv44(),
883
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
884
+ type,
885
+ messageId,
886
+ data
887
+ };
888
+ const line = JSON.stringify(signal) + "\n";
889
+ fs17.appendFileSync(filePath, line, "utf-8");
890
+ return signal.id;
891
+ }
892
+ function readSignals(sessionId, lastReadId) {
893
+ const filePath = getMailboxPath(sessionId, "sig");
894
+ if (!fs17.existsSync(filePath)) {
895
+ return [];
896
+ }
897
+ const content = fs17.readFileSync(filePath, "utf-8");
898
+ if (!content.trim()) {
899
+ return [];
900
+ }
901
+ const lines = content.trim().split("\n");
902
+ const signals = [];
903
+ let shouldStartReading = !lastReadId;
904
+ for (const line of lines) {
905
+ if (!line.trim()) continue;
906
+ try {
907
+ const signal = JSON.parse(line);
908
+ if (lastReadId && !shouldStartReading) {
909
+ if (signal.id === lastReadId) {
910
+ shouldStartReading = true;
911
+ }
912
+ continue;
913
+ }
914
+ signals.push(signal);
915
+ } catch {
916
+ }
917
+ }
918
+ return signals;
919
+ }
920
+ function removeMailbox(sessionId) {
921
+ const dir = getMailboxesDir();
922
+ const types = ["in", "out", "sig"];
923
+ for (const type of types) {
924
+ const filePath = path19.join(dir, `${sessionId}.${type}`);
925
+ if (fs17.existsSync(filePath)) {
926
+ fs17.unlinkSync(filePath);
927
+ }
928
+ }
929
+ }
930
+ function listActiveMailboxes() {
931
+ const dir = getMailboxesDir();
932
+ if (!fs17.existsSync(dir)) {
933
+ return [];
934
+ }
935
+ const files = fs17.readdirSync(dir);
936
+ const mailboxes = /* @__PURE__ */ new Map();
937
+ for (const file of files) {
938
+ const match = file.match(/^([a-f0-9-]+)\.(in|out|sig)$/);
939
+ if (!match) continue;
940
+ const sessionId = match[1];
941
+ const type = match[2];
942
+ if (!mailboxes.has(sessionId)) {
943
+ mailboxes.set(sessionId, { in: 0, out: 0, sig: 0 });
944
+ }
945
+ const filePath = path19.join(dir, file);
946
+ const content = fs17.readFileSync(filePath, "utf-8");
947
+ const lines = content.trim().split("\n").filter((l) => l.trim()).length;
948
+ mailboxes.get(sessionId)[type] = lines;
949
+ }
950
+ return Array.from(mailboxes.entries()).map(([sessionId, counts]) => ({
951
+ sessionId,
952
+ hasMessages: counts.in > 0 || counts.out > 0 || counts.sig > 0
953
+ }));
954
+ }
955
+ function sendFollowUp(workerSessionId, coordinatorSessionId, message2, requiresAck = true) {
956
+ return sendToMailbox(workerSessionId, "in", {
957
+ type: "follow_up",
958
+ from: coordinatorSessionId,
959
+ to: workerSessionId,
960
+ content: message2,
961
+ metadata: {
962
+ priority: "normal",
963
+ requiresAck
964
+ }
965
+ });
966
+ }
967
+ function sendProgressUpdate(coordinatorSessionId, workerSessionId, percent, currentTask, toolCallsCount, tokensUsed) {
968
+ return sendToMailbox(coordinatorSessionId, "out", {
969
+ type: "progress_update",
970
+ from: workerSessionId,
971
+ to: coordinatorSessionId,
972
+ content: currentTask || `Progress: ${percent}%`,
973
+ metadata: {
974
+ priority: "low",
975
+ requiresAck: false,
976
+ progress: {
977
+ percent,
978
+ currentTask,
979
+ toolCallsCount,
980
+ tokensUsed
981
+ }
982
+ }
983
+ });
984
+ }
985
+ function sendPermissionRequest(coordinatorSessionId, workerSessionId, toolName, toolArgs, reason) {
986
+ return sendToMailbox(coordinatorSessionId, "out", {
987
+ type: "permission_request",
988
+ from: workerSessionId,
989
+ to: coordinatorSessionId,
990
+ content: `Permission request: ${toolName}`,
991
+ metadata: {
992
+ priority: "high",
993
+ requiresAck: true,
994
+ permission: {
995
+ toolName,
996
+ toolArgs,
997
+ reason
998
+ }
999
+ }
1000
+ });
1001
+ }
1002
+ function sendPermissionResponse(workerSessionId, coordinatorSessionId, approved, reason) {
1003
+ return sendToMailbox(workerSessionId, "in", {
1004
+ type: "permission_response",
1005
+ from: coordinatorSessionId,
1006
+ to: workerSessionId,
1007
+ content: approved ? "approved" : "denied",
1008
+ metadata: {
1009
+ priority: "urgent",
1010
+ requiresAck: true,
1011
+ permission: {
1012
+ toolName: "permission_response",
1013
+ toolArgs: { approved, reason },
1014
+ reason: reason || ""
1015
+ }
1016
+ }
1017
+ });
1018
+ }
1019
+ var mailboxesDir;
1020
+ var init_mailbox_registry = __esm({
1021
+ "src/app/agent/runtime/mailbox_registry.ts"() {
1022
+ "use strict";
1023
+ mailboxesDir = null;
1024
+ }
1025
+ });
1026
+
1027
+ // src/app/agent/tools/natives/list_mailbox_messages.ts
1028
+ var list_mailbox_messages_exports = {};
1029
+ __export(list_mailbox_messages_exports, {
1030
+ listMailboxMessages: () => listMailboxMessages
1031
+ });
1032
+ async function listMailboxMessages(args = {}) {
1033
+ const {
1034
+ from,
1035
+ type,
1036
+ unreadOnly = true,
1037
+ lastReadId,
1038
+ includeSignals = false,
1039
+ prune = false
1040
+ } = args;
1041
+ const coordinatorSessionId = process.env.BLUMA_SESSION_ID || "unknown";
1042
+ const allMessages = [];
1043
+ if (from) {
1044
+ const messages = readFromMailbox(from, "out", lastReadId);
1045
+ for (const msg of messages) {
1046
+ if (!type || msg.type === type) {
1047
+ allMessages.push({ ...msg, direction: "out" });
1048
+ }
1049
+ }
1050
+ } else {
1051
+ const { listActiveMailboxes: listActiveMailboxes2 } = await Promise.resolve().then(() => (init_mailbox_registry(), mailbox_registry_exports));
1052
+ const { getSession: getSession2 } = await Promise.resolve().then(() => (init_session_registry(), session_registry_exports));
1053
+ const activeMailboxes = listActiveMailboxes2();
1054
+ const workers = [];
1055
+ for (const { sessionId } of activeMailboxes) {
1056
+ const session = getSession2(sessionId);
1057
+ if (!session || session.kind !== "agent") continue;
1058
+ const messages = readFromMailbox(sessionId, "out", lastReadId);
1059
+ let messageCount = 0;
1060
+ for (const msg of messages) {
1061
+ if (!type || msg.type === type) {
1062
+ allMessages.push({ ...msg, direction: "out" });
1063
+ messageCount++;
1064
+ }
1065
+ }
1066
+ workers.push({
1067
+ sessionId,
1068
+ status: session.status,
1069
+ messageCount
1070
+ });
1071
+ }
1072
+ if (workers.length > 0) {
1073
+ return {
1074
+ success: true,
1075
+ messages: allMessages.sort(
1076
+ (a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()
1077
+ ),
1078
+ count: allMessages.length,
1079
+ lastMessageId: allMessages[allMessages.length - 1]?.id,
1080
+ workers
1081
+ };
1082
+ }
1083
+ }
1084
+ allMessages.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
1085
+ let signals;
1086
+ if (includeSignals && from) {
1087
+ signals = readSignals(from, lastReadId);
1088
+ }
1089
+ if (prune && from) {
1090
+ pruneMailbox(from, "out", 50);
1091
+ }
1092
+ return {
1093
+ success: true,
1094
+ messages: allMessages,
1095
+ signals,
1096
+ count: allMessages.length,
1097
+ lastMessageId: allMessages[allMessages.length - 1]?.id
1098
+ };
1099
+ }
1100
+ var init_list_mailbox_messages = __esm({
1101
+ "src/app/agent/tools/natives/list_mailbox_messages.ts"() {
1102
+ "use strict";
1103
+ init_mailbox_registry();
1104
+ }
1105
+ });
1106
+
1107
+ // src/app/agent/tools/natives/poll_mailbox.ts
1108
+ var poll_mailbox_exports = {};
1109
+ __export(poll_mailbox_exports, {
1110
+ pollMailbox: () => pollMailbox
1111
+ });
1112
+ async function pollMailbox(args = {}) {
1113
+ const {
1114
+ timeout = 0,
1115
+ pollInterval = 500,
1116
+ types,
1117
+ lastReadId,
1118
+ includeSignals = true
1119
+ } = args;
1120
+ const sessionId = process.env.BLUMA_SESSION_ID;
1121
+ if (!sessionId) {
1122
+ return {
1123
+ success: false,
1124
+ messages: [],
1125
+ count: 0,
1126
+ hasNewMessages: false,
1127
+ error: "BLUMA_SESSION_ID not set"
1128
+ };
1129
+ }
1130
+ ensureMailbox(sessionId);
1131
+ const deadline = Date.now() + timeout;
1132
+ let messages = [];
1133
+ let signals = [];
1134
+ do {
1135
+ messages = readFromMailbox(sessionId, "in", lastReadId);
1136
+ if (types && types.length > 0) {
1137
+ messages = messages.filter((msg) => types.includes(msg.type));
1138
+ }
1139
+ if (messages.length > 0) {
1140
+ break;
1141
+ }
1142
+ if (timeout > 0 && Date.now() < deadline) {
1143
+ await new Promise((resolve2) => setTimeout(resolve2, pollInterval));
1144
+ }
1145
+ } while (timeout > 0 && Date.now() < deadline);
1146
+ if (includeSignals) {
1147
+ signals = readSignals(sessionId, lastReadId);
1148
+ }
1149
+ const followUpMessage = messages.find((msg) => msg.type === "follow_up");
1150
+ const followUp = followUpMessage ? {
1151
+ message: followUpMessage.content,
1152
+ priority: followUpMessage.metadata?.priority || "normal",
1153
+ messageId: followUpMessage.id
1154
+ } : void 0;
1155
+ const cancelRequested = messages.some((msg) => msg.type === "cancel_request") || signals.some((sig) => sig.type === "progress" && sig.data?.event === "cancel");
1156
+ const permissionResponseMsg = messages.find((msg) => msg.type === "permission_response");
1157
+ const permissionResponse = permissionResponseMsg ? {
1158
+ approved: permissionResponseMsg.content === "approved",
1159
+ reason: permissionResponseMsg.metadata?.permission?.reason,
1160
+ messageId: permissionResponseMsg.id
1161
+ } : void 0;
1162
+ return {
1163
+ success: true,
1164
+ messages,
1165
+ signals,
1166
+ count: messages.length,
1167
+ hasNewMessages: messages.length > 0,
1168
+ lastMessageId: messages[messages.length - 1]?.id,
1169
+ followUp,
1170
+ cancelRequested,
1171
+ permissionResponse
1172
+ };
1173
+ }
1174
+ var init_poll_mailbox = __esm({
1175
+ "src/app/agent/tools/natives/poll_mailbox.ts"() {
1176
+ "use strict";
1177
+ init_mailbox_registry();
1178
+ }
1179
+ });
1180
+
499
1181
  // src/main.ts
500
- import React16 from "react";
1182
+ import React19 from "react";
501
1183
  import { render } from "ink";
502
1184
  import { EventEmitter as EventEmitter3 } from "events";
503
- import fs27 from "fs";
504
- import path32 from "path";
1185
+ import fs28 from "fs";
1186
+ import path33 from "path";
505
1187
  import { fileURLToPath as fileURLToPath6 } from "url";
506
1188
  import { spawn as spawn5 } from "child_process";
507
- import { v4 as uuidv47 } from "uuid";
1189
+ import { v4 as uuidv48 } from "uuid";
508
1190
 
509
1191
  // src/app/ui/App.tsx
510
- import { useState as useState8, useEffect as useEffect8, useRef as useRef6, useCallback as useCallback3, memo as memo15 } from "react";
511
- import { Box as Box23, Text as Text22, Static } from "ink";
1192
+ import { useState as useState11, useEffect as useEffect11, useRef as useRef6, useCallback as useCallback4, memo as memo15 } from "react";
1193
+ import { Box as Box26, Text as Text25, Static, useInput as useInput6 } from "ink";
512
1194
 
513
1195
  // src/app/ui/layout.tsx
514
1196
  import { Box, Text } from "ink";
@@ -2970,12 +3652,12 @@ function EditToolDiffPanel({
2970
3652
  maxHeight = EDIT_DIFF_PREVIEW_MAX_LINES,
2971
3653
  fallbackSnippet
2972
3654
  }) {
2973
- const path33 = filePath.trim() || "unknown file";
3655
+ const path34 = filePath.trim() || "unknown file";
2974
3656
  const diff = diffText?.trim() ?? "";
2975
3657
  return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
2976
3658
  /* @__PURE__ */ jsx5(Box5, { flexDirection: "row", flexWrap: "wrap", children: /* @__PURE__ */ jsxs5(Text5, { color: isNewFile ? BLUMA_TERMINAL.success : void 0, children: [
2977
3659
  isNewFile ? "Created " : "Wrote to ",
2978
- /* @__PURE__ */ jsx5(Text5, { bold: true, children: path33 })
3660
+ /* @__PURE__ */ jsx5(Text5, { bold: true, children: path34 })
2979
3661
  ] }) }),
2980
3662
  description ? /* @__PURE__ */ jsx5(Text5, { dimColor: true, wrap: "wrap", children: description }) : null,
2981
3663
  diff.length > 0 ? /* @__PURE__ */ jsx5(Box5, { marginTop: 0, children: /* @__PURE__ */ jsx5(SimpleDiff, { text: diff, maxHeight, frame: true }) }) : fallbackSnippet ? /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", marginTop: 0, children: [
@@ -3209,7 +3891,7 @@ var renderFindByName = ({ args }) => {
3209
3891
  var renderGrepSearch = ({ args }) => {
3210
3892
  const parsed = parseArgs(args);
3211
3893
  const query = parsed.query || "";
3212
- const path33 = parsed.path || ".";
3894
+ const path34 = parsed.path || ".";
3213
3895
  return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "row", flexWrap: "wrap", children: [
3214
3896
  /* @__PURE__ */ jsxs7(Text7, { color: BLUMA_TERMINAL.muted, children: [
3215
3897
  '"',
@@ -3218,7 +3900,7 @@ var renderGrepSearch = ({ args }) => {
3218
3900
  ] }),
3219
3901
  /* @__PURE__ */ jsxs7(Text7, { color: BLUMA_TERMINAL.m3OnSurface, bold: true, children: [
3220
3902
  " ",
3221
- path33
3903
+ path34
3222
3904
  ] })
3223
3905
  ] });
3224
3906
  };
@@ -3625,7 +4307,7 @@ var ConfirmationPromptComponent = ({ toolCalls, preview, onDecision }) => {
3625
4307
  const rule = TERMINAL_RULE_CHAR.repeat(Math.min(cols - 2, 64));
3626
4308
  return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", marginBottom: 1, paddingX: 0, children: [
3627
4309
  /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: rule }),
3628
- /* @__PURE__ */ jsxs8(Box8, { flexDirection: "row", marginTop: 0, marginBottom: 1, flexWrap: "wrap", alignItems: "baseline", children: [
4310
+ /* @__PURE__ */ jsxs8(Box8, { flexDirection: "row", marginTop: 0, marginBottom: 1, flexWrap: "wrap", alignItems: "flex-end", children: [
3629
4311
  /* @__PURE__ */ jsx8(Text8, { color: shellLike ? BLUMA_TERMINAL.m3OnSurface : BLUMA_TERMINAL.inactive, children: TOOL_INVOCATION_MARK }),
3630
4312
  /* @__PURE__ */ jsx8(Text8, { color: shellLike ? BLUMA_TERMINAL.m3OnSurface : BLUMA_TERMINAL.claude, bold: true, children: getToolInvocationTitle(toolName, toolCall.function.arguments) }),
3631
4313
  /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: " \xB7 permission required" }),
@@ -3648,12 +4330,12 @@ var ConfirmationPrompt = memo4(ConfirmationPromptComponent);
3648
4330
 
3649
4331
  // src/app/agent/agent.ts
3650
4332
  import * as dotenv from "dotenv";
3651
- import path30 from "path";
3652
- import os19 from "os";
4333
+ import path31 from "path";
4334
+ import os20 from "os";
3653
4335
 
3654
4336
  // src/app/agent/tool_invoker.ts
3655
- import { promises as fs17 } from "fs";
3656
- import path19 from "path";
4337
+ import { promises as fs18 } from "fs";
4338
+ import path20 from "path";
3657
4339
  import { fileURLToPath as fileURLToPath2 } from "url";
3658
4340
 
3659
4341
  // src/app/agent/tools/natives/edit.ts
@@ -6901,261 +7583,162 @@ async function webFetch(args) {
6901
7583
  }
6902
7584
  }
6903
7585
 
6904
- // src/app/agent/tools/natives/agent_coordination.ts
6905
- import fs16 from "fs";
6906
- import os10 from "os";
6907
- import path18 from "path";
6908
- import { spawn as spawn4 } from "child_process";
6909
- import { v4 as uuidv43 } from "uuid";
6910
-
6911
- // src/app/agent/runtime/session_registry.ts
6912
- import fs15 from "fs";
6913
- import os9 from "os";
6914
- import path17 from "path";
6915
- function getRegistryDir() {
6916
- return path17.join(process.env.HOME || os9.homedir(), ".bluma", "registry");
6917
- }
6918
- function getRegistryFile() {
6919
- return path17.join(getRegistryDir(), "sessions.json");
6920
- }
6921
- function ensureRegistryDir() {
6922
- fs15.mkdirSync(getRegistryDir(), { recursive: true });
6923
- }
6924
- function readRegistry() {
6925
- ensureRegistryDir();
6926
- const file = getRegistryFile();
6927
- if (!fs15.existsSync(file)) {
6928
- return { entries: [] };
6929
- }
6930
- try {
6931
- return JSON.parse(fs15.readFileSync(file, "utf-8"));
6932
- } catch {
6933
- return { entries: [] };
6934
- }
6935
- }
6936
- function writeRegistry(state) {
6937
- ensureRegistryDir();
6938
- fs15.writeFileSync(getRegistryFile(), JSON.stringify(state, null, 2), "utf-8");
6939
- }
6940
- function getSessionLogPath(sessionId) {
6941
- ensureRegistryDir();
6942
- return path17.join(getRegistryDir(), `${sessionId}.jsonl`);
6943
- }
6944
- function registerSession(entry) {
6945
- const state = readRegistry();
6946
- const nextEntry = {
6947
- ...entry,
6948
- updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
6949
- logFile: getSessionLogPath(entry.sessionId)
6950
- };
6951
- state.entries = state.entries.filter((item) => item.sessionId !== entry.sessionId);
6952
- state.entries.unshift(nextEntry);
6953
- writeRegistry(state);
6954
- return nextEntry;
6955
- }
6956
- function updateSession(sessionId, patch) {
6957
- const state = readRegistry();
6958
- const index = state.entries.findIndex((entry) => entry.sessionId === sessionId);
6959
- if (index === -1) return null;
6960
- const nextEntry = {
6961
- ...state.entries[index],
6962
- ...patch,
6963
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
6964
- };
6965
- state.entries[index] = nextEntry;
6966
- writeRegistry(state);
6967
- return nextEntry;
6968
- }
6969
- function listSessions() {
6970
- return readRegistry().entries;
6971
- }
6972
- function getSession(sessionId) {
6973
- return readRegistry().entries.find((entry) => entry.sessionId === sessionId) || null;
6974
- }
6975
- function appendSessionLog(sessionId, payload) {
6976
- const logFile = getSessionLogPath(sessionId);
6977
- fs15.appendFileSync(logFile, `${JSON.stringify(payload)}
6978
- `, "utf-8");
6979
- }
6980
- function readSessionLog(sessionId) {
6981
- const logFile = getSessionLogPath(sessionId);
6982
- if (!fs15.existsSync(logFile)) return [];
6983
- return fs15.readFileSync(logFile, "utf-8").split("\n").filter(Boolean);
6984
- }
6985
-
6986
- // src/app/agent/tools/natives/agent_coordination.ts
6987
- function readUserContextFromEnv() {
6988
- const raw = process.env.BLUMA_USER_CONTEXT_JSON;
6989
- if (!raw) return null;
6990
- try {
6991
- const parsed = JSON.parse(raw);
7586
+ // src/app/agent/runtime/native_tool_catalog.ts
7587
+ init_agent_coordination();
7588
+
7589
+ // src/app/agent/tools/natives/send_message.ts
7590
+ init_session_registry();
7591
+ init_mailbox_registry();
7592
+ async function sendMessage(args) {
7593
+ const { to, message: message2, priority = "normal", waitForAck = false, ackTimeout = 3e4 } = args;
7594
+ if (!to || typeof to !== "string") {
6992
7595
  return {
6993
- conversationId: parsed.conversationId ?? null,
6994
- userId: parsed.userId ?? null,
6995
- userName: parsed.userName ?? null,
6996
- userEmail: parsed.userEmail ?? null,
6997
- companyId: parsed.companyId ?? null,
6998
- companyName: parsed.companyName ?? null
7596
+ success: false,
7597
+ message_id: "",
7598
+ worker_session_id: to,
7599
+ status: "error",
7600
+ error: "to (worker session ID) is required"
6999
7601
  };
7000
- } catch {
7001
- return null;
7002
7602
  }
7003
- }
7004
- function buildWorkerPayload(sessionId, args, parentSessionId, userContext) {
7005
- return {
7006
- message_id: sessionId,
7007
- session_id: sessionId,
7008
- from_agent: parentSessionId || "interactive",
7009
- to_agent: "bluma-worker",
7010
- action: "worker_task",
7011
- context: {
7012
- user_request: args.task,
7013
- coordinator_context: args.context || null,
7014
- worker_title: args.title || null,
7015
- worker_role: args.agent_type || "worker"
7016
- },
7017
- user_context: userContext || void 0,
7018
- metadata: {
7019
- sandbox: process.env.BLUMA_SANDBOX === "true",
7020
- sandbox_name: process.env.BLUMA_SANDBOX_NAME || void 0,
7021
- coordinator_worker: true,
7022
- parent_session_id: parentSessionId
7023
- }
7024
- };
7025
- }
7026
- function extractLatestResult(sessionId) {
7027
- const lines = readSessionLog(sessionId);
7028
- for (let index = lines.length - 1; index >= 0; index -= 1) {
7029
- try {
7030
- const parsed = JSON.parse(lines[index]);
7031
- if (parsed.event_type === "result") {
7032
- return parsed;
7033
- }
7034
- } catch {
7035
- }
7603
+ if (!message2 || typeof message2 !== "string") {
7604
+ return {
7605
+ success: false,
7606
+ message_id: "",
7607
+ worker_session_id: to,
7608
+ status: "error",
7609
+ error: "message is required"
7610
+ };
7036
7611
  }
7037
- return null;
7038
- }
7039
- function toAgentSummary(entry) {
7040
- return {
7041
- session_id: entry.sessionId,
7042
- title: entry.title,
7043
- kind: entry.kind,
7044
- status: entry.status,
7045
- started_at: entry.startedAt,
7046
- updated_at: entry.updatedAt,
7047
- pid: entry.pid || null,
7048
- metadata: entry.metadata || {}
7049
- };
7050
- }
7051
- async function spawnAgent(args) {
7052
- if (!args?.task || typeof args.task !== "string") {
7053
- return { success: false, error: "task is required" };
7612
+ const workerSession = getSession(to);
7613
+ if (!workerSession) {
7614
+ return {
7615
+ success: false,
7616
+ message_id: "",
7617
+ worker_session_id: to,
7618
+ status: "error",
7619
+ error: `Worker session ${to} not found`
7620
+ };
7054
7621
  }
7055
- const entrypoint = process.argv[1];
7056
- if (!entrypoint) {
7057
- return { success: false, error: "Unable to resolve CLI entrypoint for worker spawn" };
7622
+ if (workerSession.status !== "running") {
7623
+ return {
7624
+ success: false,
7625
+ message_id: "",
7626
+ worker_session_id: to,
7627
+ status: "error",
7628
+ error: `Worker session ${to} is ${workerSession.status}, cannot send follow-up`
7629
+ };
7058
7630
  }
7059
- const sessionId = uuidv43();
7060
- const parentSessionId = process.env.BLUMA_SESSION_ID || null;
7061
- const userContext = readUserContextFromEnv();
7062
- const title = args.title || `worker:${args.agent_type || "worker"}`;
7063
- const payload = buildWorkerPayload(sessionId, args, parentSessionId, userContext);
7064
- const payloadDir = fs16.mkdtempSync(path18.join(os10.tmpdir(), "bluma-worker-"));
7065
- const payloadPath = path18.join(payloadDir, `${sessionId}.json`);
7066
- fs16.writeFileSync(payloadPath, JSON.stringify(payload, null, 2), "utf-8");
7067
- registerSession({
7068
- sessionId,
7069
- kind: "agent",
7070
- status: "running",
7071
- startedAt: (/* @__PURE__ */ new Date()).toISOString(),
7072
- workdir: process.cwd(),
7073
- title,
7074
- metadata: {
7075
- action: "worker_task",
7076
- background: true,
7077
- coordinator_worker: true,
7078
- parent_session_id: parentSessionId,
7079
- agent_type: args.agent_type || "worker",
7080
- user_id: userContext?.userId ?? null,
7081
- company_id: userContext?.companyId ?? null
7082
- }
7083
- });
7084
- const child = spawn4(
7085
- process.execPath,
7086
- [entrypoint, "agent", "--input-file", payloadPath, "--background-worker", "--registry-session", sessionId],
7087
- {
7088
- detached: true,
7089
- stdio: "ignore",
7090
- cwd: process.cwd(),
7091
- env: {
7092
- ...process.env,
7093
- BLUMA_PARENT_SESSION_ID: parentSessionId || ""
7094
- }
7631
+ const messageId = sendFollowUp(to, process.env.BLUMA_SESSION_ID || "unknown", message2, waitForAck);
7632
+ if (waitForAck) {
7633
+ const ackResult = await waitForAckSignal(to, messageId, ackTimeout);
7634
+ if (!ackResult.acknowledged) {
7635
+ return {
7636
+ success: false,
7637
+ message_id: messageId,
7638
+ worker_session_id: to,
7639
+ status: ackResult.timedOut ? "timeout" : "error",
7640
+ error: ackResult.error,
7641
+ ack_received: false,
7642
+ worker_status: workerSession.status
7643
+ };
7095
7644
  }
7096
- );
7097
- child.unref();
7098
- updateSession(sessionId, { pid: child.pid });
7645
+ }
7099
7646
  return {
7100
7647
  success: true,
7101
- session_id: sessionId,
7102
- pid: child.pid || null,
7103
- parent_session_id: parentSessionId,
7104
- title,
7105
- status: "running"
7648
+ message_id: messageId,
7649
+ worker_session_id: to,
7650
+ status: waitForAck ? "delivered" : "sent",
7651
+ ack_received: waitForAck,
7652
+ worker_status: workerSession.status
7106
7653
  };
7107
7654
  }
7108
- async function waitAgent(args) {
7109
- const sessionId = args?.session_id;
7110
- if (!sessionId || typeof sessionId !== "string") {
7111
- return { success: false, error: "session_id is required" };
7112
- }
7113
- const timeoutMs = Math.max(1e3, Number(args.timeout_ms || 3e4));
7114
- const pollIntervalMs = Math.max(200, Number(args.poll_interval_ms || 1e3));
7655
+ async function waitForAckSignal(sessionId, messageId, timeoutMs) {
7656
+ const { readSignals: readSignals2 } = await Promise.resolve().then(() => (init_mailbox_registry(), mailbox_registry_exports));
7115
7657
  const deadline = Date.now() + timeoutMs;
7658
+ const pollInterval = 500;
7116
7659
  while (Date.now() < deadline) {
7117
- const session2 = getSession(sessionId);
7118
- if (!session2) {
7119
- return { success: false, error: `Unknown session: ${sessionId}` };
7120
- }
7121
- if (session2.status !== "running") {
7122
- return {
7123
- success: true,
7124
- completed: true,
7125
- session: toAgentSummary(session2),
7126
- result: extractLatestResult(sessionId)
7127
- };
7660
+ const signals = readSignals2(sessionId);
7661
+ for (const signal of signals) {
7662
+ if (signal.messageId === messageId) {
7663
+ if (signal.type === "ack") {
7664
+ return { acknowledged: true };
7665
+ } else if (signal.type === "nack") {
7666
+ return {
7667
+ acknowledged: false,
7668
+ error: signal.data?.reason || "Worker rejected message"
7669
+ };
7670
+ }
7671
+ }
7128
7672
  }
7129
- await new Promise((resolve2) => setTimeout(resolve2, pollIntervalMs));
7673
+ await new Promise((resolve2) => setTimeout(resolve2, pollInterval));
7674
+ }
7675
+ return { acknowledged: false, timedOut: true, error: `Timeout waiting for ack after ${timeoutMs}ms` };
7676
+ }
7677
+
7678
+ // src/app/agent/runtime/native_tool_catalog.ts
7679
+ init_list_mailbox_messages();
7680
+ init_poll_mailbox();
7681
+
7682
+ // src/app/agent/tools/natives/signal_mailbox.ts
7683
+ init_mailbox_registry();
7684
+ async function signalMailbox(args) {
7685
+ const { to, type, messageId, data, progress, permissionResponse } = args;
7686
+ if (!to || typeof to !== "string") {
7687
+ return {
7688
+ success: false,
7689
+ signal_id: "",
7690
+ type,
7691
+ to,
7692
+ error: "to (session ID) is required"
7693
+ };
7694
+ }
7695
+ if (!type || !["ack", "nack", "progress", "heartbeat"].includes(type)) {
7696
+ return {
7697
+ success: false,
7698
+ signal_id: "",
7699
+ type,
7700
+ to,
7701
+ error: "type must be one of: ack, nack, progress, heartbeat"
7702
+ };
7703
+ }
7704
+ if (type === "progress" && progress) {
7705
+ const sessionId = process.env.BLUMA_SESSION_ID || "unknown";
7706
+ const signalId2 = sendProgressUpdate(
7707
+ to,
7708
+ sessionId,
7709
+ progress.percent,
7710
+ progress.currentTask,
7711
+ progress.toolCallsCount,
7712
+ progress.tokensUsed
7713
+ );
7714
+ return {
7715
+ success: true,
7716
+ signal_id: signalId2,
7717
+ type: "progress",
7718
+ to
7719
+ };
7130
7720
  }
7131
- const session = getSession(sessionId);
7132
- if (!session) {
7133
- return { success: false, error: `Unknown session: ${sessionId}` };
7721
+ if (type === "ack" && permissionResponse) {
7722
+ const sessionId = process.env.BLUMA_SESSION_ID || "unknown";
7723
+ const signalId2 = sendPermissionResponse(
7724
+ to,
7725
+ sessionId,
7726
+ permissionResponse.approved,
7727
+ permissionResponse.reason
7728
+ );
7729
+ return {
7730
+ success: true,
7731
+ signal_id: signalId2,
7732
+ type: permissionResponse.approved ? "ack" : "nack",
7733
+ to
7734
+ };
7134
7735
  }
7736
+ const signalId = sendSignal(to, type, data, messageId);
7135
7737
  return {
7136
7738
  success: true,
7137
- completed: false,
7138
- session: toAgentSummary(session),
7139
- result: extractLatestResult(sessionId),
7140
- message: `Timed out after ${timeoutMs}ms while waiting for agent ${sessionId}.`
7141
- };
7142
- }
7143
- async function listAgents(args = {}) {
7144
- const entries = listSessions().filter((entry) => entry.kind === "agent").filter((entry) => {
7145
- if (args.parent_session_id) {
7146
- return entry.metadata?.parent_session_id === args.parent_session_id;
7147
- }
7148
- return true;
7149
- }).filter((entry) => {
7150
- if (args.status) {
7151
- return entry.status === args.status;
7152
- }
7153
- return true;
7154
- }).map(toAgentSummary);
7155
- return {
7156
- success: true,
7157
- count: entries.length,
7158
- agents: entries
7739
+ signal_id: signalId,
7740
+ type,
7741
+ to
7159
7742
  };
7160
7743
  }
7161
7744
 
@@ -7589,6 +8172,50 @@ var NATIVE_TOOL_ENTRIES = [
7589
8172
  description: "LSP definition/references (TS/JS MVP)."
7590
8173
  },
7591
8174
  implementation: lsp_query
8175
+ },
8176
+ {
8177
+ metadata: {
8178
+ name: "send_message",
8179
+ category: "communication",
8180
+ riskLevel: "safe",
8181
+ autoApproveInLocal: true,
8182
+ autoApproveInSandbox: true,
8183
+ description: "Send a follow-up message to a running worker. Allows continuing a worker with new instructions without re-spawning (preserves loaded context)."
8184
+ },
8185
+ implementation: sendMessage
8186
+ },
8187
+ {
8188
+ metadata: {
8189
+ name: "list_mailbox_messages",
8190
+ category: "communication",
8191
+ riskLevel: "safe",
8192
+ autoApproveInLocal: true,
8193
+ autoApproveInSandbox: true,
8194
+ description: "List messages received from workers (progress updates, permission requests, etc.). Coordinator uses this to read worker responses."
8195
+ },
8196
+ implementation: listMailboxMessages
8197
+ },
8198
+ {
8199
+ metadata: {
8200
+ name: "poll_mailbox",
8201
+ category: "communication",
8202
+ riskLevel: "safe",
8203
+ autoApproveInLocal: true,
8204
+ autoApproveInSandbox: true,
8205
+ description: "Poll mailbox for new messages from coordinator. Worker uses this to check for follow-ups, cancel requests, or permission responses."
8206
+ },
8207
+ implementation: pollMailbox
8208
+ },
8209
+ {
8210
+ metadata: {
8211
+ name: "signal_mailbox",
8212
+ category: "communication",
8213
+ riskLevel: "safe",
8214
+ autoApproveInLocal: true,
8215
+ autoApproveInSandbox: true,
8216
+ description: "Send control signals (ack/nack/progress/heartbeat). Used by both coordinator and workers for flow control and status updates."
8217
+ },
8218
+ implementation: signalMailbox
7592
8219
  }
7593
8220
  ];
7594
8221
  var TOOL_METADATA_MAP = new Map(
@@ -7629,9 +8256,9 @@ var ToolInvoker = class {
7629
8256
  async initialize() {
7630
8257
  try {
7631
8258
  const __filename = fileURLToPath2(import.meta.url);
7632
- const __dirname = path19.dirname(__filename);
7633
- const configPath = path19.resolve(__dirname, "config", "native_tools.json");
7634
- const fileContent = await fs17.readFile(configPath, "utf-8");
8259
+ const __dirname = path20.dirname(__filename);
8260
+ const configPath = path20.resolve(__dirname, "config", "native_tools.json");
8261
+ const fileContent = await fs18.readFile(configPath, "utf-8");
7635
8262
  const config2 = JSON.parse(fileContent);
7636
8263
  this.toolDefinitions = applyMetadataToToolDefinitions(config2.nativeTools);
7637
8264
  } catch (error) {
@@ -7673,9 +8300,9 @@ var ToolInvoker = class {
7673
8300
  };
7674
8301
 
7675
8302
  // src/app/agent/tools/mcp/mcp_client.ts
7676
- import { promises as fs18 } from "fs";
7677
- import path20 from "path";
7678
- import os11 from "os";
8303
+ import { promises as fs19 } from "fs";
8304
+ import path21 from "path";
8305
+ import os12 from "os";
7679
8306
  import { fileURLToPath as fileURLToPath3 } from "url";
7680
8307
  import { Client } from "@modelcontextprotocol/sdk/client/index.js";
7681
8308
  import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
@@ -7702,9 +8329,9 @@ var MCPClient = class {
7702
8329
  });
7703
8330
  }
7704
8331
  const __filename = fileURLToPath3(import.meta.url);
7705
- const __dirname = path20.dirname(__filename);
7706
- const defaultConfigPath = path20.resolve(__dirname, "config", "bluma-mcp.json");
7707
- const userConfigPath = path20.join(os11.homedir(), ".bluma", "bluma-mcp.json");
8332
+ const __dirname = path21.dirname(__filename);
8333
+ const defaultConfigPath = path21.resolve(__dirname, "config", "bluma-mcp.json");
8334
+ const userConfigPath = path21.join(os12.homedir(), ".bluma", "bluma-mcp.json");
7708
8335
  const defaultConfig = await this.loadMcpConfig(defaultConfigPath, "Default");
7709
8336
  const userConfig = await this.loadMcpConfig(userConfigPath, "User");
7710
8337
  const mergedConfig = {
@@ -7738,7 +8365,7 @@ var MCPClient = class {
7738
8365
  }
7739
8366
  async loadMcpConfig(configPath, configType) {
7740
8367
  try {
7741
- const fileContent = await fs18.readFile(configPath, "utf-8");
8368
+ const fileContent = await fs19.readFile(configPath, "utf-8");
7742
8369
  const processedContent = this.replaceEnvPlaceholders(fileContent);
7743
8370
  return JSON.parse(processedContent);
7744
8371
  } catch (error) {
@@ -7757,7 +8384,7 @@ var MCPClient = class {
7757
8384
  async connectToStdioServer(serverName, config2) {
7758
8385
  let commandToExecute = config2.command;
7759
8386
  let argsToExecute = config2.args || [];
7760
- const isWindows = os11.platform() === "win32";
8387
+ const isWindows = os12.platform() === "win32";
7761
8388
  if (!isWindows && commandToExecute.toLowerCase() === "cmd") {
7762
8389
  if (argsToExecute.length >= 2 && argsToExecute[0].toLowerCase() === "/c") {
7763
8390
  commandToExecute = argsToExecute[1];
@@ -7909,13 +8536,13 @@ var AdvancedFeedbackSystem = class {
7909
8536
  };
7910
8537
 
7911
8538
  // src/app/agent/bluma/core/bluma.ts
7912
- import path28 from "path";
7913
- import { v4 as uuidv44 } from "uuid";
8539
+ import path29 from "path";
8540
+ import { v4 as uuidv45 } from "uuid";
7914
8541
 
7915
8542
  // src/app/agent/session_manager/session_manager.ts
7916
- import path21 from "path";
7917
- import os12 from "os";
7918
- import { promises as fs19 } from "fs";
8543
+ import path22 from "path";
8544
+ import os13 from "os";
8545
+ import { promises as fs20 } from "fs";
7919
8546
  var fileLocks = /* @__PURE__ */ new Map();
7920
8547
  async function withFileLock(file, fn) {
7921
8548
  const prev = fileLocks.get(file) || Promise.resolve();
@@ -7951,13 +8578,13 @@ function debouncedSave(sessionFile, history, memory) {
7951
8578
  function expandHome(p) {
7952
8579
  if (!p) return p;
7953
8580
  if (p.startsWith("~")) {
7954
- return path21.join(os12.homedir(), p.slice(1));
8581
+ return path22.join(os13.homedir(), p.slice(1));
7955
8582
  }
7956
8583
  return p;
7957
8584
  }
7958
8585
  function getPreferredAppDir() {
7959
- const fixed = path21.join(os12.homedir(), ".bluma");
7960
- return path21.resolve(expandHome(fixed));
8586
+ const fixed = path22.join(os13.homedir(), ".bluma");
8587
+ return path22.resolve(expandHome(fixed));
7961
8588
  }
7962
8589
  async function safeRenameWithRetry(src, dest, maxRetries = 6) {
7963
8590
  let attempt = 0;
@@ -7965,10 +8592,10 @@ async function safeRenameWithRetry(src, dest, maxRetries = 6) {
7965
8592
  const isWin = process.platform === "win32";
7966
8593
  while (attempt <= maxRetries) {
7967
8594
  try {
7968
- const dir = path21.dirname(dest);
7969
- await fs19.mkdir(dir, { recursive: true }).catch(() => {
8595
+ const dir = path22.dirname(dest);
8596
+ await fs20.mkdir(dir, { recursive: true }).catch(() => {
7970
8597
  });
7971
- await fs19.rename(src, dest);
8598
+ await fs20.rename(src, dest);
7972
8599
  return;
7973
8600
  } catch (e) {
7974
8601
  lastErr = e;
@@ -7981,13 +8608,13 @@ async function safeRenameWithRetry(src, dest, maxRetries = 6) {
7981
8608
  }
7982
8609
  }
7983
8610
  try {
7984
- await fs19.access(src);
7985
- const data = await fs19.readFile(src);
7986
- const dir = path21.dirname(dest);
7987
- await fs19.mkdir(dir, { recursive: true }).catch(() => {
8611
+ await fs20.access(src);
8612
+ const data = await fs20.readFile(src);
8613
+ const dir = path22.dirname(dest);
8614
+ await fs20.mkdir(dir, { recursive: true }).catch(() => {
7988
8615
  });
7989
- await fs19.writeFile(dest, data);
7990
- await fs19.unlink(src).catch(() => {
8616
+ await fs20.writeFile(dest, data);
8617
+ await fs20.unlink(src).catch(() => {
7991
8618
  });
7992
8619
  return;
7993
8620
  } catch (fallbackErr) {
@@ -8000,16 +8627,16 @@ async function safeRenameWithRetry(src, dest, maxRetries = 6) {
8000
8627
  }
8001
8628
  async function ensureSessionDir() {
8002
8629
  const appDir = getPreferredAppDir();
8003
- const sessionDir = path21.join(appDir, "sessions");
8004
- await fs19.mkdir(sessionDir, { recursive: true });
8630
+ const sessionDir = path22.join(appDir, "sessions");
8631
+ await fs20.mkdir(sessionDir, { recursive: true });
8005
8632
  return sessionDir;
8006
8633
  }
8007
8634
  async function loadOrcreateSession(sessionId) {
8008
8635
  const sessionDir = await ensureSessionDir();
8009
- const sessionFile = path21.join(sessionDir, `${sessionId}.json`);
8636
+ const sessionFile = path22.join(sessionDir, `${sessionId}.json`);
8010
8637
  try {
8011
- await fs19.access(sessionFile);
8012
- const fileContent = await fs19.readFile(sessionFile, "utf-8");
8638
+ await fs20.access(sessionFile);
8639
+ const fileContent = await fs20.readFile(sessionFile, "utf-8");
8013
8640
  const sessionData = JSON.parse(fileContent);
8014
8641
  const memory = {
8015
8642
  historyAnchor: sessionData.history_anchor ?? null,
@@ -8022,7 +8649,7 @@ async function loadOrcreateSession(sessionId) {
8022
8649
  created_at: (/* @__PURE__ */ new Date()).toISOString(),
8023
8650
  conversation_history: []
8024
8651
  };
8025
- await fs19.writeFile(sessionFile, JSON.stringify(newSessionData, null, 2), "utf-8");
8652
+ await fs20.writeFile(sessionFile, JSON.stringify(newSessionData, null, 2), "utf-8");
8026
8653
  const emptyMemory = {
8027
8654
  historyAnchor: null,
8028
8655
  compressedTurnSliceCount: 0
@@ -8034,12 +8661,12 @@ async function doSaveSessionHistory(sessionFile, history, memory) {
8034
8661
  await withFileLock(sessionFile, async () => {
8035
8662
  let sessionData;
8036
8663
  try {
8037
- const dir = path21.dirname(sessionFile);
8038
- await fs19.mkdir(dir, { recursive: true });
8664
+ const dir = path22.dirname(sessionFile);
8665
+ await fs20.mkdir(dir, { recursive: true });
8039
8666
  } catch {
8040
8667
  }
8041
8668
  try {
8042
- const fileContent = await fs19.readFile(sessionFile, "utf-8");
8669
+ const fileContent = await fs20.readFile(sessionFile, "utf-8");
8043
8670
  sessionData = JSON.parse(fileContent);
8044
8671
  } catch (error) {
8045
8672
  const code = error && error.code;
@@ -8050,14 +8677,14 @@ async function doSaveSessionHistory(sessionFile, history, memory) {
8050
8677
  console.warn(`An unknown error occurred while reading ${sessionFile}. Re-initializing.`, error);
8051
8678
  }
8052
8679
  }
8053
- const sessionId = path21.basename(sessionFile, ".json");
8680
+ const sessionId = path22.basename(sessionFile, ".json");
8054
8681
  sessionData = {
8055
8682
  session_id: sessionId,
8056
8683
  created_at: (/* @__PURE__ */ new Date()).toISOString(),
8057
8684
  conversation_history: []
8058
8685
  };
8059
8686
  try {
8060
- await fs19.writeFile(sessionFile, JSON.stringify(sessionData, null, 2), "utf-8");
8687
+ await fs20.writeFile(sessionFile, JSON.stringify(sessionData, null, 2), "utf-8");
8061
8688
  } catch {
8062
8689
  }
8063
8690
  }
@@ -8073,7 +8700,7 @@ async function doSaveSessionHistory(sessionFile, history, memory) {
8073
8700
  }
8074
8701
  const tempSessionFile = `${sessionFile}.${Date.now()}.tmp`;
8075
8702
  try {
8076
- await fs19.writeFile(tempSessionFile, JSON.stringify(sessionData, null, 2), "utf-8");
8703
+ await fs20.writeFile(tempSessionFile, JSON.stringify(sessionData, null, 2), "utf-8");
8077
8704
  await safeRenameWithRetry(tempSessionFile, sessionFile);
8078
8705
  } catch (writeError) {
8079
8706
  if (writeError instanceof Error) {
@@ -8082,7 +8709,7 @@ async function doSaveSessionHistory(sessionFile, history, memory) {
8082
8709
  console.error(`An unknown fatal error occurred while saving session to ${sessionFile}:`, writeError);
8083
8710
  }
8084
8711
  try {
8085
- await fs19.unlink(tempSessionFile);
8712
+ await fs20.unlink(tempSessionFile);
8086
8713
  } catch {
8087
8714
  }
8088
8715
  }
@@ -8099,15 +8726,15 @@ async function saveSessionHistory(sessionFile, history, memory) {
8099
8726
  }
8100
8727
 
8101
8728
  // src/app/agent/core/prompt/prompt_builder.ts
8102
- import os15 from "os";
8103
- import fs23 from "fs";
8104
- import path25 from "path";
8729
+ import os16 from "os";
8730
+ import fs24 from "fs";
8731
+ import path26 from "path";
8105
8732
  import { execSync as execSync3 } from "child_process";
8106
8733
 
8107
8734
  // src/app/agent/skills/skill_loader.ts
8108
- import fs20 from "fs";
8109
- import path22 from "path";
8110
- import os13 from "os";
8735
+ import fs21 from "fs";
8736
+ import path23 from "path";
8737
+ import os14 from "os";
8111
8738
  import { fileURLToPath as fileURLToPath4 } from "node:url";
8112
8739
  var SkillLoader = class _SkillLoader {
8113
8740
  bundledSkillsDir;
@@ -8116,8 +8743,8 @@ var SkillLoader = class _SkillLoader {
8116
8743
  cache = /* @__PURE__ */ new Map();
8117
8744
  conflicts = [];
8118
8745
  constructor(projectRoot, bundledDir) {
8119
- this.projectSkillsDir = path22.join(projectRoot, ".bluma", "skills");
8120
- this.globalSkillsDir = path22.join(os13.homedir(), ".bluma", "skills");
8746
+ this.projectSkillsDir = path23.join(projectRoot, ".bluma", "skills");
8747
+ this.globalSkillsDir = path23.join(os14.homedir(), ".bluma", "skills");
8121
8748
  this.bundledSkillsDir = bundledDir || _SkillLoader.resolveBundledDir();
8122
8749
  }
8123
8750
  /**
@@ -8126,48 +8753,48 @@ var SkillLoader = class _SkillLoader {
8126
8753
  */
8127
8754
  static resolveBundledDir() {
8128
8755
  if (process.env.JEST_WORKER_ID !== void 0 || process.env.NODE_ENV === "test") {
8129
- return path22.join(process.cwd(), "dist", "config", "skills");
8756
+ return path23.join(process.cwd(), "dist", "config", "skills");
8130
8757
  }
8131
8758
  const candidates = [];
8132
8759
  const push = (p) => {
8133
- const abs = path22.resolve(p);
8760
+ const abs = path23.resolve(p);
8134
8761
  if (!candidates.includes(abs)) {
8135
8762
  candidates.push(abs);
8136
8763
  }
8137
8764
  };
8138
8765
  let argvBundled = null;
8139
8766
  try {
8140
- const bundleDir = path22.dirname(fileURLToPath4(import.meta.url));
8141
- push(path22.join(bundleDir, "config", "skills"));
8767
+ const bundleDir = path23.dirname(fileURLToPath4(import.meta.url));
8768
+ push(path23.join(bundleDir, "config", "skills"));
8142
8769
  } catch {
8143
8770
  }
8144
8771
  const argv1 = process.argv[1];
8145
8772
  if (argv1 && !argv1.startsWith("-")) {
8146
8773
  try {
8147
8774
  let resolved = argv1;
8148
- if (path22.isAbsolute(argv1) && fs20.existsSync(argv1)) {
8149
- resolved = fs20.realpathSync(argv1);
8150
- } else if (!path22.isAbsolute(argv1)) {
8151
- resolved = path22.resolve(process.cwd(), argv1);
8775
+ if (path23.isAbsolute(argv1) && fs21.existsSync(argv1)) {
8776
+ resolved = fs21.realpathSync(argv1);
8777
+ } else if (!path23.isAbsolute(argv1)) {
8778
+ resolved = path23.resolve(process.cwd(), argv1);
8152
8779
  }
8153
- const scriptDir = path22.dirname(resolved);
8154
- argvBundled = path22.join(scriptDir, "config", "skills");
8780
+ const scriptDir = path23.dirname(resolved);
8781
+ argvBundled = path23.join(scriptDir, "config", "skills");
8155
8782
  push(argvBundled);
8156
8783
  } catch {
8157
8784
  }
8158
8785
  }
8159
8786
  for (const abs of candidates) {
8160
- if (fs20.existsSync(abs)) {
8787
+ if (fs21.existsSync(abs)) {
8161
8788
  return abs;
8162
8789
  }
8163
8790
  }
8164
8791
  try {
8165
- return path22.join(path22.dirname(fileURLToPath4(import.meta.url)), "config", "skills");
8792
+ return path23.join(path23.dirname(fileURLToPath4(import.meta.url)), "config", "skills");
8166
8793
  } catch {
8167
8794
  if (argvBundled) {
8168
8795
  return argvBundled;
8169
8796
  }
8170
- return path22.join(os13.homedir(), ".bluma", "__bundled_skills_unresolved__");
8797
+ return path23.join(os14.homedir(), ".bluma", "__bundled_skills_unresolved__");
8171
8798
  }
8172
8799
  }
8173
8800
  /**
@@ -8196,8 +8823,8 @@ var SkillLoader = class _SkillLoader {
8196
8823
  this.conflicts.push({
8197
8824
  name: skill.name,
8198
8825
  userSource: source,
8199
- userPath: path22.join(dir, skill.name, "SKILL.md"),
8200
- bundledPath: path22.join(this.bundledSkillsDir, skill.name, "SKILL.md")
8826
+ userPath: path23.join(dir, skill.name, "SKILL.md"),
8827
+ bundledPath: path23.join(this.bundledSkillsDir, skill.name, "SKILL.md")
8201
8828
  });
8202
8829
  continue;
8203
8830
  }
@@ -8205,20 +8832,20 @@ var SkillLoader = class _SkillLoader {
8205
8832
  }
8206
8833
  }
8207
8834
  listFromDir(dir, source) {
8208
- if (!fs20.existsSync(dir)) return [];
8835
+ if (!fs21.existsSync(dir)) return [];
8209
8836
  try {
8210
- return fs20.readdirSync(dir).filter((d) => {
8211
- const fullPath = path22.join(dir, d);
8212
- return fs20.statSync(fullPath).isDirectory() && fs20.existsSync(path22.join(fullPath, "SKILL.md"));
8213
- }).map((d) => this.loadMetadataFromPath(path22.join(dir, d, "SKILL.md"), d, source)).filter((m) => m !== null);
8837
+ return fs21.readdirSync(dir).filter((d) => {
8838
+ const fullPath = path23.join(dir, d);
8839
+ return fs21.statSync(fullPath).isDirectory() && fs21.existsSync(path23.join(fullPath, "SKILL.md"));
8840
+ }).map((d) => this.loadMetadataFromPath(path23.join(dir, d, "SKILL.md"), d, source)).filter((m) => m !== null);
8214
8841
  } catch {
8215
8842
  return [];
8216
8843
  }
8217
8844
  }
8218
8845
  loadMetadataFromPath(skillPath, skillName, source) {
8219
- if (!fs20.existsSync(skillPath)) return null;
8846
+ if (!fs21.existsSync(skillPath)) return null;
8220
8847
  try {
8221
- const raw = fs20.readFileSync(skillPath, "utf-8");
8848
+ const raw = fs21.readFileSync(skillPath, "utf-8");
8222
8849
  const parsed = this.parseFrontmatter(raw);
8223
8850
  return {
8224
8851
  name: parsed.name || skillName,
@@ -8240,12 +8867,12 @@ var SkillLoader = class _SkillLoader {
8240
8867
  */
8241
8868
  load(name) {
8242
8869
  if (this.cache.has(name)) return this.cache.get(name);
8243
- const bundledPath = path22.join(this.bundledSkillsDir, name, "SKILL.md");
8244
- const projectPath = path22.join(this.projectSkillsDir, name, "SKILL.md");
8245
- const globalPath = path22.join(this.globalSkillsDir, name, "SKILL.md");
8246
- const existsBundled = fs20.existsSync(bundledPath);
8247
- const existsProject = fs20.existsSync(projectPath);
8248
- const existsGlobal = fs20.existsSync(globalPath);
8870
+ const bundledPath = path23.join(this.bundledSkillsDir, name, "SKILL.md");
8871
+ const projectPath = path23.join(this.projectSkillsDir, name, "SKILL.md");
8872
+ const globalPath = path23.join(this.globalSkillsDir, name, "SKILL.md");
8873
+ const existsBundled = fs21.existsSync(bundledPath);
8874
+ const existsProject = fs21.existsSync(projectPath);
8875
+ const existsGlobal = fs21.existsSync(globalPath);
8249
8876
  if (existsBundled && (existsProject || existsGlobal)) {
8250
8877
  const conflictSource = existsProject ? "project" : "global";
8251
8878
  const conflictPath = existsProject ? projectPath : globalPath;
@@ -8284,9 +8911,9 @@ var SkillLoader = class _SkillLoader {
8284
8911
  }
8285
8912
  loadFromPath(skillPath, name, source) {
8286
8913
  try {
8287
- const raw = fs20.readFileSync(skillPath, "utf-8");
8914
+ const raw = fs21.readFileSync(skillPath, "utf-8");
8288
8915
  const parsed = this.parseFrontmatter(raw);
8289
- const skillDir = path22.dirname(skillPath);
8916
+ const skillDir = path23.dirname(skillPath);
8290
8917
  return {
8291
8918
  name: parsed.name || name,
8292
8919
  description: parsed.description || "",
@@ -8295,22 +8922,22 @@ var SkillLoader = class _SkillLoader {
8295
8922
  version: parsed.version,
8296
8923
  author: parsed.author,
8297
8924
  license: parsed.license,
8298
- references: this.scanAssets(path22.join(skillDir, "references")),
8299
- scripts: this.scanAssets(path22.join(skillDir, "scripts"))
8925
+ references: this.scanAssets(path23.join(skillDir, "references")),
8926
+ scripts: this.scanAssets(path23.join(skillDir, "scripts"))
8300
8927
  };
8301
8928
  } catch {
8302
8929
  return null;
8303
8930
  }
8304
8931
  }
8305
8932
  scanAssets(dir) {
8306
- if (!fs20.existsSync(dir)) return [];
8933
+ if (!fs21.existsSync(dir)) return [];
8307
8934
  try {
8308
- return fs20.readdirSync(dir).filter((f) => {
8309
- const fp = path22.join(dir, f);
8310
- return fs20.statSync(fp).isFile();
8935
+ return fs21.readdirSync(dir).filter((f) => {
8936
+ const fp = path23.join(dir, f);
8937
+ return fs21.statSync(fp).isFile();
8311
8938
  }).map((f) => ({
8312
8939
  name: f,
8313
- path: path22.resolve(dir, f)
8940
+ path: path23.resolve(dir, f)
8314
8941
  }));
8315
8942
  } catch {
8316
8943
  return [];
@@ -8367,10 +8994,10 @@ var SkillLoader = class _SkillLoader {
8367
8994
  this.cache.clear();
8368
8995
  }
8369
8996
  exists(name) {
8370
- const bundledPath = path22.join(this.bundledSkillsDir, name, "SKILL.md");
8371
- const projectPath = path22.join(this.projectSkillsDir, name, "SKILL.md");
8372
- const globalPath = path22.join(this.globalSkillsDir, name, "SKILL.md");
8373
- return fs20.existsSync(bundledPath) || fs20.existsSync(projectPath) || fs20.existsSync(globalPath);
8997
+ const bundledPath = path23.join(this.bundledSkillsDir, name, "SKILL.md");
8998
+ const projectPath = path23.join(this.projectSkillsDir, name, "SKILL.md");
8999
+ const globalPath = path23.join(this.globalSkillsDir, name, "SKILL.md");
9000
+ return fs21.existsSync(bundledPath) || fs21.existsSync(projectPath) || fs21.existsSync(globalPath);
8374
9001
  }
8375
9002
  /**
8376
9003
  * Retorna conflitos detetados (skills do utilizador com mesmo nome de nativas).
@@ -8402,8 +9029,8 @@ var SkillLoader = class _SkillLoader {
8402
9029
  };
8403
9030
 
8404
9031
  // src/app/agent/core/prompt/workspace_snapshot.ts
8405
- import fs21 from "fs";
8406
- import path23 from "path";
9032
+ import fs22 from "fs";
9033
+ import path24 from "path";
8407
9034
  import { execSync as execSync2 } from "child_process";
8408
9035
  var LIMITS = {
8409
9036
  readme: 1e4,
@@ -8418,10 +9045,10 @@ var LIMITS = {
8418
9045
  };
8419
9046
  function safeReadFile(filePath, maxChars) {
8420
9047
  try {
8421
- if (!fs21.existsSync(filePath)) return null;
8422
- const st = fs21.statSync(filePath);
9048
+ if (!fs22.existsSync(filePath)) return null;
9049
+ const st = fs22.statSync(filePath);
8423
9050
  if (!st.isFile()) return null;
8424
- const raw = fs21.readFileSync(filePath, "utf8");
9051
+ const raw = fs22.readFileSync(filePath, "utf8");
8425
9052
  if (raw.length <= maxChars) return raw;
8426
9053
  return `${raw.slice(0, maxChars)}
8427
9054
 
@@ -8432,7 +9059,7 @@ function safeReadFile(filePath, maxChars) {
8432
9059
  }
8433
9060
  function tryReadReadme(cwd) {
8434
9061
  for (const name of ["README.md", "README.MD", "readme.md", "Readme.md"]) {
8435
- const c = safeReadFile(path23.join(cwd, name), LIMITS.readme);
9062
+ const c = safeReadFile(path24.join(cwd, name), LIMITS.readme);
8436
9063
  if (c) return `(${name})
8437
9064
  ${c}`;
8438
9065
  }
@@ -8440,14 +9067,14 @@ ${c}`;
8440
9067
  }
8441
9068
  function tryReadBluMaMd(cwd) {
8442
9069
  const paths = [
8443
- path23.join(cwd, "BluMa.md"),
8444
- path23.join(cwd, "BLUMA.md"),
8445
- path23.join(cwd, ".bluma", "BluMa.md")
9070
+ path24.join(cwd, "BluMa.md"),
9071
+ path24.join(cwd, "BLUMA.md"),
9072
+ path24.join(cwd, ".bluma", "BluMa.md")
8446
9073
  ];
8447
9074
  for (const p of paths) {
8448
9075
  const c = safeReadFile(p, LIMITS.blumaMd);
8449
9076
  if (c) {
8450
- const rel = path23.relative(cwd, p) || p;
9077
+ const rel = path24.relative(cwd, p) || p;
8451
9078
  return `(${rel})
8452
9079
  ${c}`;
8453
9080
  }
@@ -8455,10 +9082,10 @@ ${c}`;
8455
9082
  return null;
8456
9083
  }
8457
9084
  function summarizePackageJson(cwd) {
8458
- const p = path23.join(cwd, "package.json");
9085
+ const p = path24.join(cwd, "package.json");
8459
9086
  try {
8460
- if (!fs21.existsSync(p)) return null;
8461
- const pkg = JSON.parse(fs21.readFileSync(p, "utf8"));
9087
+ if (!fs22.existsSync(p)) return null;
9088
+ const pkg = JSON.parse(fs22.readFileSync(p, "utf8"));
8462
9089
  const scripts = pkg.scripts;
8463
9090
  let scriptKeys = "";
8464
9091
  if (scripts && typeof scripts === "object" && !Array.isArray(scripts)) {
@@ -8491,7 +9118,7 @@ function summarizePackageJson(cwd) {
8491
9118
  }
8492
9119
  function topLevelListing(cwd) {
8493
9120
  try {
8494
- const names = fs21.readdirSync(cwd, { withFileTypes: true });
9121
+ const names = fs22.readdirSync(cwd, { withFileTypes: true });
8495
9122
  const sorted = [...names].sort((a, b) => a.name.localeCompare(b.name));
8496
9123
  const limited = sorted.slice(0, LIMITS.topDirEntries);
8497
9124
  const lines = limited.map((d) => `${d.name}${d.isDirectory() ? "/" : ""}`);
@@ -8549,7 +9176,7 @@ function buildWorkspaceSnapshot(cwd) {
8549
9176
  parts.push(pkg);
8550
9177
  parts.push("```\n");
8551
9178
  }
8552
- const py = safeReadFile(path23.join(cwd, "pyproject.toml"), LIMITS.pyproject);
9179
+ const py = safeReadFile(path24.join(cwd, "pyproject.toml"), LIMITS.pyproject);
8553
9180
  if (py) {
8554
9181
  parts.push("### pyproject.toml (excerpt)\n```toml");
8555
9182
  parts.push(py);
@@ -8567,15 +9194,15 @@ function buildWorkspaceSnapshot(cwd) {
8567
9194
  parts.push(bluma);
8568
9195
  parts.push("```\n");
8569
9196
  }
8570
- const contrib = safeReadFile(path23.join(cwd, "CONTRIBUTING.md"), LIMITS.contributing);
9197
+ const contrib = safeReadFile(path24.join(cwd, "CONTRIBUTING.md"), LIMITS.contributing);
8571
9198
  if (contrib) {
8572
9199
  parts.push("### CONTRIBUTING.md (excerpt)\n```markdown");
8573
9200
  parts.push(contrib);
8574
9201
  parts.push("```\n");
8575
9202
  }
8576
- const chlog = safeReadFile(path23.join(cwd, "CHANGELOG.md"), LIMITS.changelog);
9203
+ const chlog = safeReadFile(path24.join(cwd, "CHANGELOG.md"), LIMITS.changelog);
8577
9204
  if (!chlog) {
8578
- const alt = safeReadFile(path23.join(cwd, "CHANGES.md"), LIMITS.changelog);
9205
+ const alt = safeReadFile(path24.join(cwd, "CHANGES.md"), LIMITS.changelog);
8579
9206
  if (alt) {
8580
9207
  parts.push("### CHANGES.md (excerpt)\n```markdown");
8581
9208
  parts.push(alt);
@@ -8615,15 +9242,15 @@ init_runtime_config();
8615
9242
 
8616
9243
  // src/app/agent/runtime/plugin_registry.ts
8617
9244
  init_sandbox_policy();
8618
- import fs22 from "fs";
8619
- import os14 from "os";
8620
- import path24 from "path";
9245
+ import fs23 from "fs";
9246
+ import os15 from "os";
9247
+ import path25 from "path";
8621
9248
  function getProjectPluginsDir() {
8622
9249
  const policy = getSandboxPolicy();
8623
- return path24.join(policy.workspaceRoot, ".bluma", "plugins");
9250
+ return path25.join(policy.workspaceRoot, ".bluma", "plugins");
8624
9251
  }
8625
9252
  function getGlobalPluginsDir() {
8626
- return path24.join(process.env.HOME || os14.homedir(), ".bluma", "plugins");
9253
+ return path25.join(process.env.HOME || os15.homedir(), ".bluma", "plugins");
8627
9254
  }
8628
9255
  function getPluginDirs() {
8629
9256
  return {
@@ -8632,11 +9259,11 @@ function getPluginDirs() {
8632
9259
  };
8633
9260
  }
8634
9261
  function readManifest(manifestPath, fallbackName) {
8635
- if (!fs22.existsSync(manifestPath)) {
9262
+ if (!fs23.existsSync(manifestPath)) {
8636
9263
  return null;
8637
9264
  }
8638
9265
  try {
8639
- const parsed = JSON.parse(fs22.readFileSync(manifestPath, "utf-8"));
9266
+ const parsed = JSON.parse(fs23.readFileSync(manifestPath, "utf-8"));
8640
9267
  return {
8641
9268
  name: typeof parsed.name === "string" && parsed.name.trim() ? parsed.name.trim() : fallbackName,
8642
9269
  description: typeof parsed.description === "string" ? parsed.description.trim() : void 0,
@@ -8649,22 +9276,22 @@ function readManifest(manifestPath, fallbackName) {
8649
9276
  }
8650
9277
  function findManifestPath(pluginDir) {
8651
9278
  const candidates = [
8652
- path24.join(pluginDir, ".codex-plugin", "plugin.json"),
8653
- path24.join(pluginDir, "plugin.json")
9279
+ path25.join(pluginDir, ".codex-plugin", "plugin.json"),
9280
+ path25.join(pluginDir, "plugin.json")
8654
9281
  ];
8655
9282
  for (const candidate of candidates) {
8656
- if (fs22.existsSync(candidate)) {
9283
+ if (fs23.existsSync(candidate)) {
8657
9284
  return candidate;
8658
9285
  }
8659
9286
  }
8660
9287
  return null;
8661
9288
  }
8662
9289
  function listFromDir(baseDir, source) {
8663
- if (!fs22.existsSync(baseDir)) {
9290
+ if (!fs23.existsSync(baseDir)) {
8664
9291
  return [];
8665
9292
  }
8666
- return fs22.readdirSync(baseDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).flatMap((entry) => {
8667
- const pluginDir = path24.join(baseDir, entry.name);
9293
+ return fs23.readdirSync(baseDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).flatMap((entry) => {
9294
+ const pluginDir = path25.join(baseDir, entry.name);
8668
9295
  const manifestPath = findManifestPath(pluginDir);
8669
9296
  if (!manifestPath) {
8670
9297
  return [];
@@ -8725,6 +9352,9 @@ Every message you send is to the **user**. Worker results are internal notificat
8725
9352
  | \`spawn_agent\` | Create a new worker |
8726
9353
  | \`wait_agent\` | Wait for worker completion |
8727
9354
  | \`list_agents\` | List active/completed workers |
9355
+ | \`send_message\` | **NEW:** Send follow-up to running worker (continue without re-spawn) |
9356
+ | \`list_mailbox_messages\` | **NEW:** Read messages from workers (progress, permission requests) |
9357
+ | \`signal_mailbox\` | **NEW:** Send ack/nack/progress signals |
8728
9358
 
8729
9359
  ### Tool contract (BluMa)
8730
9360
 
@@ -8732,7 +9362,7 @@ Every message you send is to the **user**. Worker results are internal notificat
8732
9362
  - Call \`wait_agent\` with \`{ "session_id": "<id>" }\`. Default \`timeout_ms\` is short (~30s); for audits, refactors, or test runs use a **large** \`timeout_ms\` (e.g. \`600000\`) or poll with \`list_agents\` if appropriate.
8733
9363
  - \`list_agents\` accepts optional \`parent_session_id\` and \`status\` filters.
8734
9364
  - **Parallelism:** In a single turn you may issue **multiple** \`spawn_agent\` calls back-to-back so independent workers start together; then \`wait_agent\` on each \`session_id\` (order as needed).
8735
- - You do **not** receive XML or push notifications from workers \u2014 completion and payload come from \`wait_agent\` (and \`result\` inside that JSON when present).
9365
+ - **NEW: Bidirectional Communication** \u2014 Workers can now send messages to you via mailbox. Use \`list_mailbox_messages\` to read progress updates, permission requests, and results. Use \`send_message\` to continue a worker without re-spawning.
8736
9366
 
8737
9367
  ### When to call \`spawn_agent\`:
8738
9368
 
@@ -8940,10 +9570,10 @@ function getGitBranch(dir) {
8940
9570
  }
8941
9571
  function getPackageManager(dir) {
8942
9572
  try {
8943
- if (fs23.existsSync(path25.join(dir, "pnpm-lock.yaml"))) return "pnpm";
8944
- if (fs23.existsSync(path25.join(dir, "yarn.lock"))) return "yarn";
8945
- if (fs23.existsSync(path25.join(dir, "bun.lockb"))) return "bun";
8946
- if (fs23.existsSync(path25.join(dir, "package-lock.json"))) return "npm";
9573
+ if (fs24.existsSync(path26.join(dir, "pnpm-lock.yaml"))) return "pnpm";
9574
+ if (fs24.existsSync(path26.join(dir, "yarn.lock"))) return "yarn";
9575
+ if (fs24.existsSync(path26.join(dir, "bun.lockb"))) return "bun";
9576
+ if (fs24.existsSync(path26.join(dir, "package-lock.json"))) return "npm";
8947
9577
  return "unknown";
8948
9578
  } catch {
8949
9579
  return "unknown";
@@ -8951,9 +9581,9 @@ function getPackageManager(dir) {
8951
9581
  }
8952
9582
  function getProjectType(dir) {
8953
9583
  try {
8954
- const files = fs23.readdirSync(dir);
9584
+ const files = fs24.readdirSync(dir);
8955
9585
  if (files.includes("package.json")) {
8956
- const pkg = JSON.parse(fs23.readFileSync(path25.join(dir, "package.json"), "utf-8"));
9586
+ const pkg = JSON.parse(fs24.readFileSync(path26.join(dir, "package.json"), "utf-8"));
8957
9587
  if (pkg.dependencies?.next || pkg.devDependencies?.next) return "Next.js";
8958
9588
  if (pkg.dependencies?.react || pkg.devDependencies?.react) return "React";
8959
9589
  if (pkg.dependencies?.express || pkg.devDependencies?.express) return "Express";
@@ -8972,9 +9602,9 @@ function getProjectType(dir) {
8972
9602
  }
8973
9603
  function getTestFramework(dir) {
8974
9604
  try {
8975
- const pkgPath = path25.join(dir, "package.json");
8976
- if (fs23.existsSync(pkgPath)) {
8977
- const pkg = JSON.parse(fs23.readFileSync(pkgPath, "utf-8"));
9605
+ const pkgPath = path26.join(dir, "package.json");
9606
+ if (fs24.existsSync(pkgPath)) {
9607
+ const pkg = JSON.parse(fs24.readFileSync(pkgPath, "utf-8"));
8978
9608
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
8979
9609
  if (deps.jest) return "jest";
8980
9610
  if (deps.vitest) return "vitest";
@@ -8983,7 +9613,7 @@ function getTestFramework(dir) {
8983
9613
  if (deps["@playwright/test"]) return "playwright";
8984
9614
  if (deps.cypress) return "cypress";
8985
9615
  }
8986
- if (fs23.existsSync(path25.join(dir, "pytest.ini")) || fs23.existsSync(path25.join(dir, "conftest.py"))) return "pytest";
9616
+ if (fs24.existsSync(path26.join(dir, "pytest.ini")) || fs24.existsSync(path26.join(dir, "conftest.py"))) return "pytest";
8987
9617
  return "unknown";
8988
9618
  } catch {
8989
9619
  return "unknown";
@@ -8991,9 +9621,9 @@ function getTestFramework(dir) {
8991
9621
  }
8992
9622
  function getTestCommand(dir) {
8993
9623
  try {
8994
- const pkgPath = path25.join(dir, "package.json");
8995
- if (fs23.existsSync(pkgPath)) {
8996
- const pkg = JSON.parse(fs23.readFileSync(pkgPath, "utf-8"));
9624
+ const pkgPath = path26.join(dir, "package.json");
9625
+ if (fs24.existsSync(pkgPath)) {
9626
+ const pkg = JSON.parse(fs24.readFileSync(pkgPath, "utf-8"));
8997
9627
  if (pkg.scripts?.test) return `npm test`;
8998
9628
  if (pkg.scripts?.["test:unit"]) return `npm run test:unit`;
8999
9629
  }
@@ -9151,12 +9781,12 @@ function getUnifiedSystemPrompt(availableSkills) {
9151
9781
  const runtimeConfig = getRuntimeConfig();
9152
9782
  const availablePlugins = listPlugins();
9153
9783
  const env = {
9154
- os_type: os15.type(),
9155
- os_version: os15.release(),
9156
- architecture: os15.arch(),
9784
+ os_type: os16.type(),
9785
+ os_version: os16.release(),
9786
+ architecture: os16.arch(),
9157
9787
  workdir: cwd,
9158
9788
  shell_type: process.env.SHELL || process.env.COMSPEC || "unknown",
9159
- username: os15.userInfo().username,
9789
+ username: os16.userInfo().username,
9160
9790
  current_date: (/* @__PURE__ */ new Date()).toISOString().split("T")[0],
9161
9791
  timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
9162
9792
  is_git_repo: isGitRepo(cwd) ? "yes" : "no",
@@ -9214,8 +9844,8 @@ ${memorySnapshot.trim().length > 0 ? memorySnapshot : "(empty \u2014 use coding_
9214
9844
  }
9215
9845
  function isGitRepo(dir) {
9216
9846
  try {
9217
- const gitPath = path25.join(dir, ".git");
9218
- return fs23.existsSync(gitPath) && fs23.lstatSync(gitPath).isDirectory();
9847
+ const gitPath = path26.join(dir, ".git");
9848
+ return fs24.existsSync(gitPath) && fs24.lstatSync(gitPath).isDirectory();
9219
9849
  } catch {
9220
9850
  return false;
9221
9851
  }
@@ -9432,16 +10062,22 @@ async function createApiContextWindow(fullHistory, currentAnchor, compressedTurn
9432
10062
  let messages = buildContextMessages(systemMessages, anchor, pendingFlat, recentFlat);
9433
10063
  let tokens = countTokens(messages);
9434
10064
  while (tokens >= thresholdTokens && pendingSlices.length > 0) {
9435
- anchor = await compressToAnchor(
9436
- pendingFlat,
9437
- anchor,
9438
- llmService,
9439
- userContext,
9440
- pendingSlices.length
9441
- );
9442
- sliceCount = recentStart;
9443
- pendingSlices = [];
9444
- pendingFlat = [];
10065
+ try {
10066
+ anchor = await compressToAnchor(
10067
+ pendingFlat,
10068
+ anchor,
10069
+ llmService,
10070
+ userContext,
10071
+ pendingSlices.length
10072
+ );
10073
+ sliceCount = recentStart;
10074
+ pendingSlices = [];
10075
+ pendingFlat = [];
10076
+ } catch (compressError) {
10077
+ console.warn("[ContextManager] Compression failed, keeping uncompressed history:", compressError?.message || compressError);
10078
+ pendingSlices = [];
10079
+ pendingFlat = [];
10080
+ }
9445
10081
  messages = buildContextMessages(systemMessages, anchor, pendingFlat, recentFlat);
9446
10082
  tokens = countTokens(messages);
9447
10083
  }
@@ -9454,7 +10090,7 @@ async function createApiContextWindow(fullHistory, currentAnchor, compressedTurn
9454
10090
 
9455
10091
  // src/app/agent/core/llm/llm.ts
9456
10092
  init_runtime_config();
9457
- import os16 from "os";
10093
+ import os17 from "os";
9458
10094
  import OpenAI from "openai";
9459
10095
  function defaultBlumaUserContextInput(sessionId, userMessage) {
9460
10096
  const msg = String(userMessage || "").slice(0, 300);
@@ -9471,7 +10107,7 @@ function defaultBlumaUserContextInput(sessionId, userMessage) {
9471
10107
  }
9472
10108
  function getPreferredMacAddress() {
9473
10109
  try {
9474
- const ifaces = os16.networkInterfaces();
10110
+ const ifaces = os17.networkInterfaces();
9475
10111
  for (const name of Object.keys(ifaces)) {
9476
10112
  const addrs = ifaces[name];
9477
10113
  if (!addrs) continue;
@@ -9486,7 +10122,7 @@ function getPreferredMacAddress() {
9486
10122
  } catch {
9487
10123
  }
9488
10124
  try {
9489
- return `host:${os16.hostname()}`;
10125
+ return `host:${os17.hostname()}`;
9490
10126
  } catch {
9491
10127
  return "unknown";
9492
10128
  }
@@ -9496,7 +10132,7 @@ function defaultInteractiveCliUserContextInput(sessionId, userMessage) {
9496
10132
  const machineId = getPreferredMacAddress();
9497
10133
  let userName = null;
9498
10134
  try {
9499
- userName = os16.userInfo().username || null;
10135
+ userName = os17.userInfo().username || null;
9500
10136
  } catch {
9501
10137
  userName = null;
9502
10138
  }
@@ -9943,8 +10579,8 @@ function classifyToolInvocation(input) {
9943
10579
 
9944
10580
  // src/app/agent/runtime/hook_registry.ts
9945
10581
  init_sandbox_policy();
9946
- import fs24 from "fs";
9947
- import path26 from "path";
10582
+ import fs25 from "fs";
10583
+ import path27 from "path";
9948
10584
  var DEFAULT_STATE = {
9949
10585
  enabled: true,
9950
10586
  maxEvents: 120,
@@ -9955,7 +10591,7 @@ var cache2 = null;
9955
10591
  var cachePath2 = null;
9956
10592
  function getStatePath() {
9957
10593
  const policy = getSandboxPolicy();
9958
- return path26.join(policy.workspaceRoot, ".bluma", "hooks.json");
10594
+ return path27.join(policy.workspaceRoot, ".bluma", "hooks.json");
9959
10595
  }
9960
10596
  function getHookStatePath() {
9961
10597
  return getStatePath();
@@ -9974,8 +10610,8 @@ function ensureLoaded2() {
9974
10610
  return cache2;
9975
10611
  }
9976
10612
  try {
9977
- if (fs24.existsSync(statePath)) {
9978
- const parsed = JSON.parse(fs24.readFileSync(statePath, "utf-8"));
10613
+ if (fs25.existsSync(statePath)) {
10614
+ const parsed = JSON.parse(fs25.readFileSync(statePath, "utf-8"));
9979
10615
  cache2 = {
9980
10616
  enabled: typeof parsed.enabled === "boolean" ? parsed.enabled : DEFAULT_STATE.enabled,
9981
10617
  maxEvents: typeof parsed.maxEvents === "number" && Number.isFinite(parsed.maxEvents) && parsed.maxEvents > 0 ? Math.floor(parsed.maxEvents) : DEFAULT_STATE.maxEvents,
@@ -10001,9 +10637,9 @@ function ensureLoaded2() {
10001
10637
  }
10002
10638
  function persist2(state) {
10003
10639
  const statePath = getStatePath();
10004
- fs24.mkdirSync(path26.dirname(statePath), { recursive: true });
10640
+ fs25.mkdirSync(path27.dirname(statePath), { recursive: true });
10005
10641
  state.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
10006
- fs24.writeFileSync(statePath, JSON.stringify(state, null, 2), "utf-8");
10642
+ fs25.writeFileSync(statePath, JSON.stringify(state, null, 2), "utf-8");
10007
10643
  cache2 = state;
10008
10644
  cachePath2 = statePath;
10009
10645
  }
@@ -10100,11 +10736,11 @@ function effectiveToolAutoApprove(toolCall, sessionId, options) {
10100
10736
  }
10101
10737
 
10102
10738
  // src/app/agent/tools/natives/coding_memory_consolidate.ts
10103
- import * as fs25 from "fs";
10104
- import * as path27 from "path";
10105
- import os17 from "os";
10739
+ import * as fs26 from "fs";
10740
+ import * as path28 from "path";
10741
+ import os18 from "os";
10106
10742
  function memoryPath() {
10107
- return path27.join(process.env.HOME || os17.homedir(), ".bluma", "coding_memory.json");
10743
+ return path28.join(process.env.HOME || os18.homedir(), ".bluma", "coding_memory.json");
10108
10744
  }
10109
10745
  function normalizeNote(note) {
10110
10746
  return note.trim().toLowerCase().replace(/\s+/g, " ");
@@ -10114,18 +10750,18 @@ function uniqTags(a, b) {
10114
10750
  }
10115
10751
  function consolidateCodingMemoryFile() {
10116
10752
  const p = memoryPath();
10117
- if (!fs25.existsSync(p)) {
10753
+ if (!fs26.existsSync(p)) {
10118
10754
  return { success: true, removedDuplicates: 0, message: "no coding_memory.json" };
10119
10755
  }
10120
10756
  const bak = `${p}.bak`;
10121
10757
  try {
10122
- fs25.copyFileSync(p, bak);
10758
+ fs26.copyFileSync(p, bak);
10123
10759
  } catch (e) {
10124
10760
  return { success: false, removedDuplicates: 0, message: `backup failed: ${e.message}` };
10125
10761
  }
10126
10762
  let data;
10127
10763
  try {
10128
- data = JSON.parse(fs25.readFileSync(p, "utf-8"));
10764
+ data = JSON.parse(fs26.readFileSync(p, "utf-8"));
10129
10765
  } catch (e) {
10130
10766
  return { success: false, removedDuplicates: 0, message: `invalid json: ${e.message}` };
10131
10767
  }
@@ -10160,7 +10796,7 @@ function consolidateCodingMemoryFile() {
10160
10796
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
10161
10797
  };
10162
10798
  try {
10163
- fs25.writeFileSync(p, JSON.stringify(out, null, 2), "utf-8");
10799
+ fs26.writeFileSync(p, JSON.stringify(out, null, 2), "utf-8");
10164
10800
  } catch (e) {
10165
10801
  return { success: false, removedDuplicates: 0, message: `write failed: ${e.message}` };
10166
10802
  }
@@ -10353,7 +10989,7 @@ var BluMaAgent = class {
10353
10989
  this.isInterrupted = false;
10354
10990
  this.factorRouterTurnClosed = false;
10355
10991
  const inputText = String(userInput.content || "").trim();
10356
- const turnId = uuidv44();
10992
+ const turnId = uuidv45();
10357
10993
  this.activeTurnContext = {
10358
10994
  ...userContextInput,
10359
10995
  turnId,
@@ -10755,7 +11391,7 @@ var BluMaAgent = class {
10755
11391
 
10756
11392
  ${editData.error.display}`;
10757
11393
  }
10758
- const filename = path28.basename(toolArgs.file_path);
11394
+ const filename = path29.basename(toolArgs.file_path);
10759
11395
  return createDiff(filename, editData.currentContent || "", editData.newContent);
10760
11396
  } catch (e) {
10761
11397
  return `An unexpected error occurred while generating the edit preview: ${e.message}`;
@@ -10791,6 +11427,18 @@ ${editData.error.display}`;
10791
11427
  this.eventBus.emit("backend_message", { type: "info", message: "Task Canceled." });
10792
11428
  return;
10793
11429
  }
11430
+ const mailboxUpdate = await this._pollWorkerMailbox();
11431
+ if (mailboxUpdate && mailboxUpdate.followUp) {
11432
+ this.history.push({
11433
+ role: "user",
11434
+ content: mailboxUpdate.followUp.message
11435
+ });
11436
+ this.persistSession();
11437
+ this.eventBus.emit("backend_message", {
11438
+ type: "info",
11439
+ message: `Received follow-up from coordinator (priority: ${mailboxUpdate.followUp.priority})`
11440
+ });
11441
+ }
10794
11442
  const { messages: contextWindow, newAnchor, newCompressedTurnSliceCount } = await createApiContextWindow(
10795
11443
  this.history,
10796
11444
  this.sessionAnchor,
@@ -10855,7 +11503,6 @@ ${editData.error.display}`;
10855
11503
  }
10856
11504
  async _handleStreamingResponse(contextWindow) {
10857
11505
  const llmService = this.llm;
10858
- this.eventBus.emit("action_status", { action: "Thinking" });
10859
11506
  let accumulatedContent = "";
10860
11507
  let toolCalls;
10861
11508
  let hasEmittedStart = false;
@@ -10887,8 +11534,15 @@ ${editData.error.display}`;
10887
11534
  accumulatedContent += chunk.delta;
10888
11535
  this.eventBus.emit("stream_chunk", { delta: chunk.delta });
10889
11536
  }
10890
- if (chunk.tool_calls) {
11537
+ if (chunk.tool_calls && chunk.tool_calls.length > 0) {
10891
11538
  toolCalls = chunk.tool_calls;
11539
+ for (const tc of toolCalls || []) {
11540
+ const toolName = tc?.function?.name ?? "";
11541
+ const argsRaw = tc?.function?.arguments ?? "{}";
11542
+ if (toolName) {
11543
+ this.eventBus.emit("tool_stream_start", { toolName, argsRaw });
11544
+ }
11545
+ }
10892
11546
  }
10893
11547
  }
10894
11548
  const omitAssistantFlush = Array.isArray(toolCalls) && toolCalls.some((tc) => String(tc?.function?.name ?? "").includes("message"));
@@ -11048,6 +11702,37 @@ ${editData.error.display}`;
11048
11702
  } catch {
11049
11703
  }
11050
11704
  }
11705
+ /**
11706
+ * WORKER: Poll mailbox para checkar follow-ups do coordinator
11707
+ * Retorna null se não há novas mensagens ou se não é um worker
11708
+ */
11709
+ async _pollWorkerMailbox() {
11710
+ if (!process.env.BLUMA_PARENT_SESSION_ID) {
11711
+ return null;
11712
+ }
11713
+ try {
11714
+ const { pollMailbox: pollMailbox2 } = await Promise.resolve().then(() => (init_poll_mailbox(), poll_mailbox_exports));
11715
+ const result = await pollMailbox2({
11716
+ timeout: 0,
11717
+ // Non-blocking
11718
+ pollInterval: 500,
11719
+ types: ["follow_up", "cancel_request", "permission_response"],
11720
+ includeSignals: false
11721
+ });
11722
+ if (!result.success || !result.hasNewMessages) {
11723
+ return null;
11724
+ }
11725
+ return {
11726
+ followUp: result.followUp ? {
11727
+ message: result.followUp.message,
11728
+ priority: result.followUp.priority
11729
+ } : void 0,
11730
+ cancelRequested: result.cancelRequested
11731
+ };
11732
+ } catch (error) {
11733
+ return null;
11734
+ }
11735
+ }
11051
11736
  };
11052
11737
 
11053
11738
  // src/app/agent/subagents/registry.ts
@@ -11062,13 +11747,13 @@ function getSubAgentByCommand(cmd) {
11062
11747
  }
11063
11748
 
11064
11749
  // src/app/agent/subagents/init/init_subagent.ts
11065
- import { v4 as uuidv46 } from "uuid";
11750
+ import { v4 as uuidv47 } from "uuid";
11066
11751
 
11067
11752
  // src/app/agent/subagents/base_llm_subagent.ts
11068
- import { v4 as uuidv45 } from "uuid";
11753
+ import { v4 as uuidv46 } from "uuid";
11069
11754
 
11070
11755
  // src/app/agent/subagents/init/init_system_prompt.ts
11071
- import os18 from "os";
11756
+ import os19 from "os";
11072
11757
  var SYSTEM_PROMPT2 = `
11073
11758
 
11074
11759
  ### YOU ARE BluMa CLI \u2014 INIT SUBAGENT \u2014 AUTONOMOUS SENIOR SOFTWARE ENGINEER @ NOMADENGENUITY
@@ -11231,12 +11916,12 @@ Rule Summary:
11231
11916
  function getInitPrompt() {
11232
11917
  const now2 = /* @__PURE__ */ new Date();
11233
11918
  const collectedData = {
11234
- os_type: os18.type(),
11235
- os_version: os18.release(),
11236
- architecture: os18.arch(),
11919
+ os_type: os19.type(),
11920
+ os_version: os19.release(),
11921
+ architecture: os19.arch(),
11237
11922
  workdir: process.cwd(),
11238
11923
  shell_type: process.env.SHELL || process.env.COMSPEC || "Unknown",
11239
- username: os18.userInfo().username || "Unknown",
11924
+ username: os19.userInfo().username || "Unknown",
11240
11925
  current_date: now2.toISOString().split("T")[0],
11241
11926
  // Formato YYYY-MM-DD
11242
11927
  timezone: Intl.DateTimeFormat().resolvedOptions().timeZone || "Unknown",
@@ -11281,7 +11966,7 @@ var BaseLLMSubAgent = class {
11281
11966
  await this.initializeHistory();
11282
11967
  const rawUser = typeof input === "string" ? input : JSON.stringify(input);
11283
11968
  const base = ctx.blumaUserContextInput ?? defaultBlumaUserContextInput(`subagent:${this.id}`, rawUser.slice(0, 300));
11284
- const turnId = uuidv45();
11969
+ const turnId = uuidv46();
11285
11970
  this.subagentTurnContext = {
11286
11971
  ...base,
11287
11972
  turnId,
@@ -11449,7 +12134,7 @@ var InitAgentImpl = class extends BaseLLMSubAgent {
11449
12134
  const base = ctx.blumaUserContextInput ?? defaultBlumaUserContextInput(`subagent:${this.id}`, preview);
11450
12135
  this.subagentTurnContext = {
11451
12136
  ...base,
11452
- turnId: uuidv46(),
12137
+ turnId: uuidv47(),
11453
12138
  sessionId: base.sessionId || `subagent:${this.id}`
11454
12139
  };
11455
12140
  const seed = `
@@ -11543,14 +12228,14 @@ var RouteManager = class {
11543
12228
  this.subAgents = subAgents;
11544
12229
  this.core = core;
11545
12230
  }
11546
- registerRoute(path33, handler) {
11547
- this.routeHandlers.set(path33, handler);
12231
+ registerRoute(path34, handler) {
12232
+ this.routeHandlers.set(path34, handler);
11548
12233
  }
11549
12234
  async handleRoute(payload) {
11550
12235
  const inputText = String(payload.content || "").trim();
11551
12236
  const { userContext } = payload;
11552
- for (const [path33, handler] of this.routeHandlers) {
11553
- if (inputText === path33 || inputText.startsWith(`${path33} `)) {
12237
+ for (const [path34, handler] of this.routeHandlers) {
12238
+ if (inputText === path34 || inputText.startsWith(`${path34} `)) {
11554
12239
  return handler({ content: inputText, userContext });
11555
12240
  }
11556
12241
  }
@@ -11559,13 +12244,13 @@ var RouteManager = class {
11559
12244
  };
11560
12245
 
11561
12246
  // src/app/agent/runtime/plugin_runtime.ts
11562
- import path29 from "path";
12247
+ import path30 from "path";
11563
12248
  import { pathToFileURL as pathToFileURL2 } from "url";
11564
12249
  async function loadPluginsAtStartup() {
11565
12250
  for (const p of listPlugins()) {
11566
12251
  const entry = p.manifest.entry?.trim();
11567
12252
  if (!entry) continue;
11568
- const abs = path29.resolve(p.root, entry);
12253
+ const abs = path30.resolve(p.root, entry);
11569
12254
  try {
11570
12255
  const href = pathToFileURL2(abs).href;
11571
12256
  const mod = await import(href);
@@ -11586,7 +12271,7 @@ async function loadPluginsAtStartup() {
11586
12271
  }
11587
12272
 
11588
12273
  // src/app/agent/agent.ts
11589
- var globalEnvPath = path30.join(os19.homedir(), ".bluma", ".env");
12274
+ var globalEnvPath = path31.join(os20.homedir(), ".bluma", ".env");
11590
12275
  dotenv.config({ path: globalEnvPath });
11591
12276
  var Agent = class {
11592
12277
  sessionId;
@@ -11820,6 +12505,162 @@ function formatTurnDurationMs(ms) {
11820
12505
  return `${min}min \xB7 ${sec}s`;
11821
12506
  }
11822
12507
 
12508
+ // src/app/ui/utils/toolActionLabels.ts
12509
+ function parseArgsRecord2(args) {
12510
+ if (args == null) return {};
12511
+ if (typeof args === "string") {
12512
+ try {
12513
+ return JSON.parse(args);
12514
+ } catch {
12515
+ return {};
12516
+ }
12517
+ }
12518
+ if (typeof args === "object") {
12519
+ return args;
12520
+ }
12521
+ return {};
12522
+ }
12523
+ function getToolActionLabel(toolName, args) {
12524
+ const p = parseArgsRecord2(args);
12525
+ switch (toolName) {
12526
+ case "shell_command":
12527
+ case "run_command": {
12528
+ const cmd = typeof p.command === "string" ? p.command : "";
12529
+ const truncated = cmd.length > 40 ? `${cmd.slice(0, 40)}\u2026` : cmd;
12530
+ return truncated ? `Executing: ${truncated}` : "Executing command";
12531
+ }
12532
+ case "command_status":
12533
+ return "Checking command status";
12534
+ case "send_command_input":
12535
+ return "Sending input to command";
12536
+ case "kill_command":
12537
+ return "Terminating command";
12538
+ case "read_file_lines": {
12539
+ const filepath = typeof p.filepath === "string" ? p.filepath : "";
12540
+ const file = filepath.split("/").pop() || filepath;
12541
+ return file ? `Reading: ${file}` : "Reading file";
12542
+ }
12543
+ case "count_file_lines": {
12544
+ const filepath = typeof p.filepath === "string" ? p.filepath : "";
12545
+ const file = filepath.split("/").pop() || filepath;
12546
+ return file ? `Counting: ${file}` : "Counting lines";
12547
+ }
12548
+ case "edit_tool": {
12549
+ const edits = p.edits;
12550
+ const count = Array.isArray(edits) ? edits.length : 1;
12551
+ const filepath = typeof p.file_path === "string" ? p.file_path : Array.isArray(edits) && edits[0]?.file_path ? edits[0].file_path : "";
12552
+ const file = filepath ? filepath.split("/").pop() : "file";
12553
+ return count === 1 ? `Editing: ${file}` : `Editing ${count} changes`;
12554
+ }
12555
+ case "file_write": {
12556
+ const filepath = typeof p.filepath === "string" ? p.filepath : "";
12557
+ const file = filepath.split("/").pop() || filepath;
12558
+ return file ? `Writing: ${file}` : "Writing file";
12559
+ }
12560
+ case "grep_search": {
12561
+ const query = typeof p.query === "string" ? p.query : "";
12562
+ const truncated = query.length > 30 ? `${query.slice(0, 30)}\u2026` : query;
12563
+ return truncated ? `Searching: "${truncated}"` : "Searching";
12564
+ }
12565
+ case "find_by_name": {
12566
+ const pattern = typeof p.pattern === "string" ? p.pattern : "";
12567
+ return pattern ? `Finding: ${pattern}` : "Finding files";
12568
+ }
12569
+ case "view_file_outline": {
12570
+ const filepath = typeof p.file_path === "string" ? p.file_path : "";
12571
+ const file = filepath.split("/").pop() || filepath;
12572
+ return file ? `Outline: ${file}` : "Reading outline";
12573
+ }
12574
+ case "web_fetch": {
12575
+ const url = typeof p.url === "string" ? p.url : "";
12576
+ const truncated = url.length > 40 ? `${url.slice(0, 40)}\u2026` : url;
12577
+ return truncated ? `Fetching: ${truncated}` : "Fetching URL";
12578
+ }
12579
+ case "search_web": {
12580
+ const query = typeof p.query === "string" ? p.query : "";
12581
+ const truncated = query.length > 30 ? `${query.slice(0, 30)}\u2026` : query;
12582
+ return truncated ? `Web search: "${truncated}"` : "Searching web";
12583
+ }
12584
+ case "spawn_agent": {
12585
+ const title = typeof p.title === "string" ? p.title : "";
12586
+ const task = typeof p.task === "string" ? p.task : "";
12587
+ const label = title || (task ? task.slice(0, 40) : "task");
12588
+ return `Spawning agent: ${label}`;
12589
+ }
12590
+ case "wait_agent":
12591
+ return "Waiting for agent";
12592
+ case "list_agents":
12593
+ return "Listing agents";
12594
+ case "todo": {
12595
+ const action = typeof p.action === "string" ? p.action : "update";
12596
+ return `Updating todo: ${action}`;
12597
+ }
12598
+ case "task_boundary": {
12599
+ const mode = typeof p.mode === "string" ? p.mode : "";
12600
+ const taskName = typeof p.task_name === "string" ? p.task_name : "";
12601
+ return taskName ? `${mode}: ${taskName}` : `Task ${mode}`;
12602
+ }
12603
+ case "task_create":
12604
+ case "task_list":
12605
+ case "task_get":
12606
+ case "task_update":
12607
+ case "task_stop": {
12608
+ const title = typeof p.title === "string" ? p.title : "";
12609
+ return title ? `Task: ${title}` : "Managing task";
12610
+ }
12611
+ case "load_skill": {
12612
+ const skill = typeof p.skill_name === "string" ? p.skill_name : "";
12613
+ return skill ? `Loading skill: ${skill}` : "Loading skill";
12614
+ }
12615
+ case "coding_memory": {
12616
+ const action = typeof p.action === "string" ? p.action : "update";
12617
+ return `Coding memory: ${action}`;
12618
+ }
12619
+ case "create_artifact": {
12620
+ const filename = typeof p.filename === "string" ? p.filename : "";
12621
+ return filename ? `Creating: ${filename}` : "Creating artifact";
12622
+ }
12623
+ case "read_artifact": {
12624
+ const filename = typeof p.filename === "string" ? p.filename : "";
12625
+ return filename ? `Reading: ${filename}` : "Reading artifact";
12626
+ }
12627
+ case "message":
12628
+ return "Writing message";
12629
+ case "ask_user_question":
12630
+ return "Asking question";
12631
+ case "enter_plan_mode":
12632
+ return "Entering plan mode";
12633
+ case "exit_plan_mode":
12634
+ return "Exiting plan mode";
12635
+ case "list_mcp_resources":
12636
+ return "Listing MCP resources";
12637
+ case "read_mcp_resource": {
12638
+ const server = typeof p.server === "string" ? p.server : "";
12639
+ const uri = typeof p.uri === "string" ? p.uri : "";
12640
+ return `Reading MCP: ${server || uri || "resource"}`;
12641
+ }
12642
+ case "cron_create":
12643
+ return "Scheduling reminder";
12644
+ case "cron_list":
12645
+ return "Listing reminders";
12646
+ case "cron_delete":
12647
+ return "Canceling reminder";
12648
+ case "notebook_edit": {
12649
+ const filepath = typeof p.filepath === "string" ? p.filepath : "";
12650
+ const file = filepath.split("/").pop() || filepath;
12651
+ return file ? `Editing notebook: ${file}` : "Editing notebook";
12652
+ }
12653
+ case "lsp_query": {
12654
+ const operation = typeof p.operation === "string" ? p.operation : "";
12655
+ return `LSP: ${operation || "query"}`;
12656
+ }
12657
+ default: {
12658
+ const pretty = toolName.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
12659
+ return pretty || "Working";
12660
+ }
12661
+ }
12662
+ }
12663
+
11823
12664
  // src/app/ui/WorkingTimer.tsx
11824
12665
  import { Fragment as Fragment3, jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
11825
12666
  var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
@@ -11837,11 +12678,20 @@ function shimmerWorkingLine(text, phase) {
11837
12678
  }).join("");
11838
12679
  }
11839
12680
  var SHIMMER_RAMP_LEN = BLUMA_TERMINAL.workingShimmerRamp.length;
11840
- var WorkingTimerComponent = ({ eventBus, taskName, taskStatus, startedAtMs }) => {
11841
- const [currentAction, setCurrentAction] = useState4("Thinking");
12681
+ var WorkingTimerComponent = ({
12682
+ eventBus,
12683
+ taskName,
12684
+ taskStatus,
12685
+ liveToolName,
12686
+ liveToolArgs,
12687
+ isReasoning,
12688
+ startedAtMs
12689
+ }) => {
12690
+ const [currentAction, setCurrentAction] = useState4("working");
11842
12691
  const [frame, setFrame] = useState4(0);
11843
12692
  const [shimmerPhase, setShimmerPhase] = useState4(0);
11844
12693
  const [nowTick, setNowTick] = useState4(() => Date.now());
12694
+ const dynamicActionLabel = liveToolName ? getToolActionLabel(liveToolName, liveToolArgs) : null;
11845
12695
  useEffect4(() => {
11846
12696
  if (!eventBus) return;
11847
12697
  const handleActionStatus = (data) => {
@@ -11874,7 +12724,7 @@ var WorkingTimerComponent = ({ eventBus, taskName, taskStatus, startedAtMs }) =>
11874
12724
  const id = setInterval(() => setNowTick(Date.now()), 500);
11875
12725
  return () => clearInterval(id);
11876
12726
  }, [startedAtMs]);
11877
- const displayAction = (taskStatus || currentAction).trim() || "Thinking";
12727
+ const displayAction = dynamicActionLabel || (taskStatus || (isReasoning ? "thinking" : currentAction)).trim() || "working";
11878
12728
  const actionLine = `${displayAction}\u2026`;
11879
12729
  const shimmerLine = shimmerWorkingLine(actionLine, shimmerPhase);
11880
12730
  const elapsedMs = startedAtMs != null ? Math.max(0, nowTick - startedAtMs) : 0;
@@ -12127,12 +12977,12 @@ function renderBlockTokens(tokens, keyRoot) {
12127
12977
  /* @__PURE__ */ jsx10(Box10, { flexDirection: "row", flexWrap: "wrap", children: table.header.map((cell, idx) => {
12128
12978
  const headerNodes = walkInline(cell.tokens, `${key}-h${idx}`);
12129
12979
  const styled = headerNodes.length > 0 ? styleInlineNodes(headerNodes, `${key}-h${idx}`, { bold: true, color: BLUMA_TERMINAL.inactive }) : [/* @__PURE__ */ jsx10(Text10, { bold: true, color: BLUMA_TERMINAL.inactive, wrap: "wrap", children: cell.text }, `${key}-h${idx}-t`)];
12130
- return /* @__PURE__ */ jsx10(Box10, { paddingRight: 2, flexDirection: "row", flexWrap: "wrap", maxWidth: "100%", children: styled }, idx);
12980
+ return /* @__PURE__ */ jsx10(Box10, { paddingRight: 2, flexDirection: "row", flexWrap: "wrap", children: styled }, idx);
12131
12981
  }) }),
12132
12982
  table.rows.map((row, rowIdx) => /* @__PURE__ */ jsx10(Box10, { flexDirection: "row", flexWrap: "wrap", children: row.map((cell, cellIdx) => {
12133
12983
  const cellNodes = walkInline(cell.tokens, `${key}-c${rowIdx}-${cellIdx}`);
12134
12984
  const styled = cellNodes.length > 0 ? styleInlineNodes(cellNodes, `${key}-c${rowIdx}-${cellIdx}`, { dimColor: true }) : [/* @__PURE__ */ jsx10(Text10, { dimColor: true, wrap: "wrap", children: cell.text }, `${key}-c${rowIdx}-${cellIdx}-t`)];
12135
- return /* @__PURE__ */ jsx10(Box10, { paddingRight: 2, flexDirection: "row", flexWrap: "wrap", maxWidth: "100%", children: styled }, cellIdx);
12985
+ return /* @__PURE__ */ jsx10(Box10, { paddingRight: 2, flexDirection: "row", flexWrap: "wrap", children: styled }, cellIdx);
12136
12986
  }) }, `${key}-r${rowIdx}`))
12137
12987
  ] }, key)
12138
12988
  );
@@ -12728,7 +13578,7 @@ var ToolCallDisplayComponent = ({
12728
13578
  const Renderer = getToolRenderer(toolName);
12729
13579
  const shellLike = isShellLikeToolName(toolName);
12730
13580
  return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", marginBottom: 0, children: [
12731
- /* @__PURE__ */ jsxs13(Box13, { flexDirection: "row", flexWrap: "wrap", alignItems: "baseline", children: [
13581
+ /* @__PURE__ */ jsxs13(Box13, { flexDirection: "row", flexWrap: "wrap", alignItems: "flex-end", children: [
12732
13582
  /* @__PURE__ */ jsx13(Text13, { color: shellLike ? BLUMA_TERMINAL.m3OnSurface : BLUMA_TERMINAL.inactive, children: TOOL_INVOCATION_MARK }),
12733
13583
  /* @__PURE__ */ jsx13(Text13, { bold: true, color: shellLike ? BLUMA_TERMINAL.m3OnSurface : BLUMA_TERMINAL.claude, children: getToolInvocationTitle(toolName, args) })
12734
13584
  ] }),
@@ -12851,11 +13701,13 @@ function formatLogLine(line) {
12851
13701
  }
12852
13702
 
12853
13703
  // src/app/ui/components/SlashCommands.tsx
13704
+ init_session_registry();
12854
13705
  init_sandbox_policy();
12855
13706
 
12856
13707
  // src/app/agent/runtime/diagnostics.ts
12857
13708
  init_runtime_config();
12858
13709
  init_sandbox_policy();
13710
+ init_session_registry();
12859
13711
  function buildDiagnosticsSnapshot(feedbackScore) {
12860
13712
  const runtime = getRuntimeConfig();
12861
13713
  const policy = getSandboxPolicy();
@@ -14192,16 +15044,16 @@ import latestVersion from "latest-version";
14192
15044
  import semverGt from "semver/functions/gt.js";
14193
15045
  import semverValid from "semver/functions/valid.js";
14194
15046
  import { fileURLToPath as fileURLToPath5 } from "url";
14195
- import path31 from "path";
14196
- import fs26 from "fs";
15047
+ import path32 from "path";
15048
+ import fs27 from "fs";
14197
15049
  var BLUMA_PACKAGE_NAME = "@nomad-e/bluma-cli";
14198
15050
  function findBlumaPackageJson(startDir) {
14199
15051
  let dir = startDir;
14200
15052
  for (let i = 0; i < 12; i++) {
14201
- const candidate = path31.join(dir, "package.json");
14202
- if (fs26.existsSync(candidate)) {
15053
+ const candidate = path32.join(dir, "package.json");
15054
+ if (fs27.existsSync(candidate)) {
14203
15055
  try {
14204
- const raw = fs26.readFileSync(candidate, "utf8");
15056
+ const raw = fs27.readFileSync(candidate, "utf8");
14205
15057
  const parsed = JSON.parse(raw);
14206
15058
  if (parsed?.name === BLUMA_PACKAGE_NAME && parsed?.version) {
14207
15059
  return { name: parsed.name, version: String(parsed.version) };
@@ -14209,7 +15061,7 @@ function findBlumaPackageJson(startDir) {
14209
15061
  } catch {
14210
15062
  }
14211
15063
  }
14212
- const parent = path31.dirname(dir);
15064
+ const parent = path32.dirname(dir);
14213
15065
  if (parent === dir) break;
14214
15066
  dir = parent;
14215
15067
  }
@@ -14218,13 +15070,13 @@ function findBlumaPackageJson(startDir) {
14218
15070
  function resolveInstalledBlumaPackage() {
14219
15071
  const tried = /* @__PURE__ */ new Set();
14220
15072
  const tryFrom = (dir) => {
14221
- const abs = path31.resolve(dir);
15073
+ const abs = path32.resolve(dir);
14222
15074
  if (tried.has(abs)) return null;
14223
15075
  tried.add(abs);
14224
15076
  return findBlumaPackageJson(abs);
14225
15077
  };
14226
15078
  try {
14227
- const fromBundle = tryFrom(path31.dirname(fileURLToPath5(import.meta.url)));
15079
+ const fromBundle = tryFrom(path32.dirname(fileURLToPath5(import.meta.url)));
14228
15080
  if (fromBundle) return fromBundle;
14229
15081
  } catch {
14230
15082
  }
@@ -14232,12 +15084,12 @@ function resolveInstalledBlumaPackage() {
14232
15084
  if (argv1 && !argv1.startsWith("-")) {
14233
15085
  try {
14234
15086
  let resolved = argv1;
14235
- if (path31.isAbsolute(argv1) && fs26.existsSync(argv1)) {
14236
- resolved = fs26.realpathSync(argv1);
15087
+ if (path32.isAbsolute(argv1) && fs27.existsSync(argv1)) {
15088
+ resolved = fs27.realpathSync(argv1);
14237
15089
  } else {
14238
- resolved = path31.resolve(process.cwd(), argv1);
15090
+ resolved = path32.resolve(process.cwd(), argv1);
14239
15091
  }
14240
- const fromArgv = tryFrom(path31.dirname(resolved));
15092
+ const fromArgv = tryFrom(path32.dirname(resolved));
14241
15093
  if (fromArgv) return fromArgv;
14242
15094
  } catch {
14243
15095
  }
@@ -14610,8 +15462,240 @@ var AskUserQuestionPromptComponent = ({
14610
15462
  };
14611
15463
  var AskUserQuestionPrompt = memo14(AskUserQuestionPromptComponent);
14612
15464
 
14613
- // src/app/ui/App.tsx
15465
+ // src/app/ui/components/WorkerOverlay.tsx
15466
+ import { useState as useState10 } from "react";
15467
+ import { Box as Box25, useInput as useInput5 } from "ink";
15468
+
15469
+ // src/app/ui/components/WorkerStatusList.tsx
15470
+ import { useEffect as useEffect8, useState as useState8 } from "react";
15471
+ import { Box as Box23, Text as Text22 } from "ink";
15472
+ import Spinner2 from "ink-spinner";
14614
15473
  import { jsx as jsx24, jsxs as jsxs22 } from "react/jsx-runtime";
15474
+ var WorkerStatusList = ({
15475
+ parentSessionId,
15476
+ collapsed = false
15477
+ }) => {
15478
+ const [workers, setWorkers] = useState8([]);
15479
+ const [pollKey, setPollKey] = useState8(0);
15480
+ useEffect8(() => {
15481
+ const pollWorkers = async () => {
15482
+ try {
15483
+ const { listAgents: listAgents2 } = await Promise.resolve().then(() => (init_agent_coordination(), agent_coordination_exports));
15484
+ const { listMailboxMessages: listMailboxMessages2 } = await Promise.resolve().then(() => (init_list_mailbox_messages(), list_mailbox_messages_exports));
15485
+ const agentsResult = await listAgents2({ parent_session_id: parentSessionId });
15486
+ if (!agentsResult.success || !agentsResult.agents) {
15487
+ setWorkers([]);
15488
+ return;
15489
+ }
15490
+ const workersInfo = [];
15491
+ const agents = Array.isArray(agentsResult.agents) ? agentsResult.agents : [];
15492
+ for (const agent of agents) {
15493
+ const messagesResult = await listMailboxMessages2({
15494
+ from: agent.session_id,
15495
+ type: "progress_update",
15496
+ unreadOnly: false
15497
+ });
15498
+ let progress = void 0;
15499
+ if (messagesResult.messages && messagesResult.messages.length > 0) {
15500
+ const lastMsg = messagesResult.messages[0];
15501
+ if (lastMsg.metadata?.progress) {
15502
+ progress = {
15503
+ percent: lastMsg.metadata.progress.percent,
15504
+ currentTask: lastMsg.metadata.progress.currentTask,
15505
+ toolCallsCount: lastMsg.metadata.progress.toolCallsCount,
15506
+ tokensUsed: lastMsg.metadata.progress.tokensUsed
15507
+ };
15508
+ }
15509
+ }
15510
+ workersInfo.push({
15511
+ session_id: agent.session_id,
15512
+ title: agent.title || "worker",
15513
+ status: agent.status,
15514
+ started_at: agent.started_at,
15515
+ pid: agent.pid,
15516
+ metadata: agent.metadata,
15517
+ progress,
15518
+ isAlive: agent.status === "running"
15519
+ });
15520
+ }
15521
+ setWorkers(workersInfo);
15522
+ } catch (error) {
15523
+ }
15524
+ };
15525
+ pollWorkers();
15526
+ const interval = setInterval(() => setPollKey((k) => k + 1), 2e3);
15527
+ return () => clearInterval(interval);
15528
+ }, [pollKey, parentSessionId]);
15529
+ if (workers.length === 0) return null;
15530
+ if (collapsed) {
15531
+ return /* @__PURE__ */ jsx24(Box23, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", children: /* @__PURE__ */ jsxs22(Text22, { bold: true, color: "yellow", children: [
15532
+ "Workers: ",
15533
+ workers.length
15534
+ ] }) });
15535
+ }
15536
+ return /* @__PURE__ */ jsxs22(Box23, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", children: [
15537
+ /* @__PURE__ */ jsxs22(Text22, { bold: true, color: "yellow", children: [
15538
+ "Workers (",
15539
+ workers.length,
15540
+ ")"
15541
+ ] }),
15542
+ workers.map((w, idx) => /* @__PURE__ */ jsxs22(Box23, { flexDirection: "column", borderBottom: true, borderBottomColor: "gray", children: [
15543
+ /* @__PURE__ */ jsxs22(Box23, { children: [
15544
+ /* @__PURE__ */ jsx24(Text22, { color: "cyan", children: w.metadata?.agent_type === "researcher" ? "[R]" : w.metadata?.agent_type === "implementer" ? "[I]" : "[W]" }),
15545
+ /* @__PURE__ */ jsxs22(Text22, { bold: true, color: "cyan", children: [
15546
+ " ",
15547
+ w.title
15548
+ ] }),
15549
+ w.isAlive === true ? /* @__PURE__ */ jsxs22(Text22, { color: "green", children: [
15550
+ /* @__PURE__ */ jsx24(Spinner2, {}),
15551
+ " Running"
15552
+ ] }) : /* @__PURE__ */ jsx24(Text22, { color: "gray", children: w.status })
15553
+ ] }),
15554
+ w.progress && /* @__PURE__ */ jsxs22(Box23, { flexDirection: "column", children: [
15555
+ /* @__PURE__ */ jsxs22(Text22, { color: "magenta", children: [
15556
+ "Progress: ",
15557
+ w.progress.percent,
15558
+ "% ",
15559
+ w.progress.currentTask ? `- ${w.progress.currentTask}` : ""
15560
+ ] }),
15561
+ /* @__PURE__ */ jsx24(Box23, { children: /* @__PURE__ */ jsx24(Text22, { color: "gray", children: Array.from({ length: 20 }).map((_, i) => i / 20 * 100 <= (w.progress.percent || 0) ? "#" : "-").join("") }) }),
15562
+ /* @__PURE__ */ jsxs22(Box23, { children: [
15563
+ w.progress.toolCallsCount !== void 0 && /* @__PURE__ */ jsxs22(Text22, { color: "blue", children: [
15564
+ " Tools: ",
15565
+ w.progress.toolCallsCount
15566
+ ] }),
15567
+ w.progress.tokensUsed !== void 0 && /* @__PURE__ */ jsxs22(Text22, { color: "blue", children: [
15568
+ " Tokens: ",
15569
+ w.progress.tokensUsed.toLocaleString()
15570
+ ] })
15571
+ ] })
15572
+ ] }),
15573
+ /* @__PURE__ */ jsxs22(Text22, { dimColor: true, color: "gray", children: [
15574
+ "ID: ",
15575
+ w.session_id.slice(0, 8),
15576
+ "... PID: ",
15577
+ w.pid || "N/A",
15578
+ " Started: ",
15579
+ new Date(w.started_at).toLocaleTimeString()
15580
+ ] }),
15581
+ /* @__PURE__ */ jsxs22(Text22, { italic: true, dimColor: true, color: "gray", children: [
15582
+ "Ctrl+Shift+",
15583
+ idx + 1,
15584
+ " para transcript"
15585
+ ] })
15586
+ ] }, w.session_id))
15587
+ ] });
15588
+ };
15589
+
15590
+ // src/app/ui/components/WorkerTranscript.tsx
15591
+ import { useEffect as useEffect9, useState as useState9 } from "react";
15592
+ import { Box as Box24, Text as Text23 } from "ink";
15593
+ import { jsx as jsx25, jsxs as jsxs23 } from "react/jsx-runtime";
15594
+ var WorkerTranscript = ({ sessionId, title, onClose }) => {
15595
+ const [messages, setMessages] = useState9([]);
15596
+ useEffect9(() => {
15597
+ const loadTranscript = async () => {
15598
+ try {
15599
+ const { listMailboxMessages: listMailboxMessages2 } = await Promise.resolve().then(() => (init_list_mailbox_messages(), list_mailbox_messages_exports));
15600
+ const result = await listMailboxMessages2({ from: sessionId, unreadOnly: false, includeSignals: true });
15601
+ if (result.success && result.messages) {
15602
+ setMessages(result.messages);
15603
+ }
15604
+ } catch (error) {
15605
+ }
15606
+ };
15607
+ loadTranscript();
15608
+ const interval = setInterval(loadTranscript, 3e3);
15609
+ return () => clearInterval(interval);
15610
+ }, [sessionId]);
15611
+ return /* @__PURE__ */ jsxs23(Box24, { flexDirection: "column", borderStyle: "double", borderColor: "cyan", children: [
15612
+ /* @__PURE__ */ jsxs23(Box24, { children: [
15613
+ /* @__PURE__ */ jsxs23(Text23, { bold: true, color: "cyan", children: [
15614
+ "Transcript: ",
15615
+ title || sessionId.slice(0, 8),
15616
+ "..."
15617
+ ] }),
15618
+ /* @__PURE__ */ jsx25(Text23, { color: "gray", dimColor: true, children: " ESC: fechar" })
15619
+ ] }),
15620
+ /* @__PURE__ */ jsx25(Box24, { flexDirection: "column", height: 20, children: messages.length === 0 ? /* @__PURE__ */ jsx25(Text23, { dimColor: true, color: "gray", italic: true, children: "Nenhuma mensagem..." }) : messages.map((msg) => /* @__PURE__ */ jsxs23(Box24, { flexDirection: "column", children: [
15621
+ /* @__PURE__ */ jsxs23(Box24, { children: [
15622
+ /* @__PURE__ */ jsxs23(Text23, { dimColor: true, color: "gray", children: [
15623
+ "[",
15624
+ new Date(msg.timestamp).toLocaleTimeString(),
15625
+ "]"
15626
+ ] }),
15627
+ /* @__PURE__ */ jsxs23(Text23, { color: msg.type === "progress_update" ? "green" : msg.type === "permission_request" ? "yellow" : "cyan", bold: true, children: [
15628
+ " ",
15629
+ msg.type
15630
+ ] }),
15631
+ /* @__PURE__ */ jsxs23(Text23, { dimColor: true, color: "gray", children: [
15632
+ " ",
15633
+ msg.from.slice(0, 8),
15634
+ "... \u2192 ",
15635
+ msg.to.slice(0, 8),
15636
+ "..."
15637
+ ] })
15638
+ ] }),
15639
+ /* @__PURE__ */ jsxs23(Text23, { children: [
15640
+ " ",
15641
+ msg.content
15642
+ ] }),
15643
+ msg.metadata?.progress && /* @__PURE__ */ jsxs23(Text23, { color: "magenta", children: [
15644
+ " Progress: ",
15645
+ msg.metadata.progress.percent,
15646
+ "% ",
15647
+ msg.metadata.progress.currentTask || ""
15648
+ ] })
15649
+ ] }, msg.id)) }),
15650
+ /* @__PURE__ */ jsx25(Box24, { borderTop: true, borderTopColor: "gray", children: /* @__PURE__ */ jsxs23(Text23, { dimColor: true, color: "gray", children: [
15651
+ "Total: ",
15652
+ messages.length,
15653
+ " messages | Session: ",
15654
+ sessionId.slice(0, 8),
15655
+ "..."
15656
+ ] }) })
15657
+ ] });
15658
+ };
15659
+
15660
+ // src/app/ui/components/WorkerOverlay.tsx
15661
+ import { jsx as jsx26 } from "react/jsx-runtime";
15662
+ var WorkerOverlay = ({
15663
+ visible,
15664
+ sessionId,
15665
+ onClose,
15666
+ onZoomWorker
15667
+ }) => {
15668
+ const [zoomedWorker, setZoomedWorker] = useState10(null);
15669
+ useInput5((input, key) => {
15670
+ if (!visible) return;
15671
+ if (key.escape) {
15672
+ if (zoomedWorker) {
15673
+ setZoomedWorker(null);
15674
+ } else {
15675
+ onClose();
15676
+ }
15677
+ }
15678
+ });
15679
+ if (!visible) {
15680
+ return null;
15681
+ }
15682
+ return /* @__PURE__ */ jsx26(Box25, { flexDirection: "column", children: zoomedWorker ? /* @__PURE__ */ jsx26(
15683
+ WorkerTranscript,
15684
+ {
15685
+ sessionId: zoomedWorker,
15686
+ onClose: () => setZoomedWorker(null)
15687
+ }
15688
+ ) : /* @__PURE__ */ jsx26(
15689
+ WorkerStatusList,
15690
+ {
15691
+ parentSessionId: sessionId,
15692
+ collapsed: false
15693
+ }
15694
+ ) });
15695
+ };
15696
+
15697
+ // src/app/ui/App.tsx
15698
+ import { jsx as jsx27, jsxs as jsxs24 } from "react/jsx-runtime";
14615
15699
  var HISTORY_EMERGENCY_LIMIT = 3;
14616
15700
  var HISTORY_KEEP_AFTER_CLEANUP = 3;
14617
15701
  var blumaUpdateRegistryCheckStarted = false;
@@ -14641,51 +15725,67 @@ function UserMessageWithOptionalImages({
14641
15725
  const cap = stripped2.trim();
14642
15726
  const capDisp = cap.length > 800 ? `${cap.slice(0, 800)}\u2026` : cap;
14643
15727
  const fallbackDisp = raw.length > 800 ? `${raw.slice(0, 800)}\u2026` : raw;
14644
- return /* @__PURE__ */ jsx24(ChatUserMessage, { children: pathStrs.length > 0 ? /* @__PURE__ */ jsx24(
15728
+ return /* @__PURE__ */ jsx27(ChatUserMessage, { children: pathStrs.length > 0 ? /* @__PURE__ */ jsx27(
14645
15729
  ChatUserImageBlock,
14646
15730
  {
14647
15731
  imageCount: pathStrs.length,
14648
15732
  caption: cap.length > 0 ? capDisp : null,
14649
15733
  captionDim: true
14650
15734
  }
14651
- ) : /* @__PURE__ */ jsx24(Text22, { color: BLUMA_TERMINAL.m3OnSurface, bold: true, wrap: "wrap", children: fallbackDisp }) });
15735
+ ) : /* @__PURE__ */ jsx27(Text25, { color: BLUMA_TERMINAL.m3OnSurface, bold: true, wrap: "wrap", children: fallbackDisp }) });
14652
15736
  }
14653
15737
  const displayRaw = raw.length > 1e4 ? `${raw.substring(0, 1e4)}...` : raw;
14654
15738
  const paths = collectImagePathStrings(displayRaw);
14655
15739
  const stripped = paths.length > 0 ? stripImagePathStrings(displayRaw, paths) : displayRaw;
14656
- return /* @__PURE__ */ jsx24(ChatUserMessage, { children: paths.length > 0 ? /* @__PURE__ */ jsx24(
15740
+ return /* @__PURE__ */ jsx27(ChatUserMessage, { children: paths.length > 0 ? /* @__PURE__ */ jsx27(
14657
15741
  ChatUserImageBlock,
14658
15742
  {
14659
15743
  imageCount: paths.length,
14660
15744
  caption: stripped.trim().length > 0 ? stripped : null
14661
15745
  }
14662
- ) : /* @__PURE__ */ jsx24(Text22, { color: BLUMA_TERMINAL.m3OnSurface, bold: true, wrap: "wrap", children: displayRaw }) });
15746
+ ) : /* @__PURE__ */ jsx27(Text25, { color: BLUMA_TERMINAL.m3OnSurface, bold: true, wrap: "wrap", children: displayRaw }) });
14663
15747
  }
14664
15748
  var AppComponent = ({ eventBus, sessionId, cliVersion }) => {
14665
15749
  const agentInstance = useRef6(null);
14666
- const [history, setHistory] = useState8([]);
14667
- const [statusMessage, setStatusMessage] = useState8(
15750
+ const [history, setHistory] = useState11([]);
15751
+ const [statusMessage, setStatusMessage] = useState11(
14668
15752
  "Initializing agent..."
14669
15753
  );
14670
- const [toolsCount, setToolsCount] = useState8(null);
14671
- const [mcpStatus, setMcpStatus] = useState8(
15754
+ const [toolsCount, setToolsCount] = useState11(null);
15755
+ const [mcpStatus, setMcpStatus] = useState11(
14672
15756
  "connecting"
14673
15757
  );
14674
- const [isProcessing, setIsProcessing] = useState8(true);
14675
- const [pendingConfirmation, setPendingConfirmation] = useState8(
15758
+ const [isProcessing, setIsProcessing] = useState11(true);
15759
+ const [pendingConfirmation, setPendingConfirmation] = useState11(
14676
15760
  null
14677
15761
  );
14678
- const [confirmationPreview, setConfirmationPreview] = useState8(
15762
+ const [confirmationPreview, setConfirmationPreview] = useState11(
14679
15763
  null
14680
15764
  );
14681
- const [pendingAskUserQuestions, setPendingAskUserQuestions] = useState8(null);
14682
- const [isInitAgentActive, setIsInitAgentActive] = useState8(false);
14683
- const [liveToolName, setLiveToolName] = useState8(null);
15765
+ const [pendingAskUserQuestions, setPendingAskUserQuestions] = useState11(null);
15766
+ const [showWorkers, setShowWorkers] = useState11(false);
15767
+ const [zoomedWorkerSession, setZoomedWorkerSession] = useState11(null);
15768
+ useInput6((input, key) => {
15769
+ if (key.ctrl && key.shift && input.toLowerCase() === "w") {
15770
+ setShowWorkers((prev) => !prev);
15771
+ }
15772
+ if (key.escape && showWorkers) {
15773
+ if (zoomedWorkerSession) {
15774
+ setZoomedWorkerSession(null);
15775
+ } else {
15776
+ setShowWorkers(false);
15777
+ }
15778
+ }
15779
+ });
15780
+ const [isInitAgentActive, setIsInitAgentActive] = useState11(false);
15781
+ const [liveToolName, setLiveToolName] = useState11(null);
15782
+ const [liveToolArgs, setLiveToolArgs] = useState11(void 0);
15783
+ const [isReasoning, setIsReasoning] = useState11(false);
14684
15784
  const alwaysAcceptList = useRef6([]);
14685
15785
  const workdir = process.cwd();
14686
15786
  const turnStartedAtRef = useRef6(null);
14687
- const [processingStartMs, setProcessingStartMs] = useState8(null);
14688
- const markTurnStarted = useCallback3(() => {
15787
+ const [processingStartMs, setProcessingStartMs] = useState11(null);
15788
+ const markTurnStarted = useCallback4(() => {
14689
15789
  const t = Date.now();
14690
15790
  turnStartedAtRef.current = t;
14691
15791
  setProcessingStartMs(t);
@@ -14693,7 +15793,7 @@ var AppComponent = ({ eventBus, sessionId, cliVersion }) => {
14693
15793
  const lastReasoningTextRef = useRef6(null);
14694
15794
  const lastStreamAssistantKeyRef = useRef6(null);
14695
15795
  const pendingToolInvocationIdsRef = useRef6(/* @__PURE__ */ new Set());
14696
- const appendExpandPreviewToHistory = useCallback3(() => {
15796
+ const appendExpandPreviewToHistory = useCallback4(() => {
14697
15797
  const p = peekLatestExpandable();
14698
15798
  setHistory((prev) => {
14699
15799
  const id = prev.length;
@@ -14702,7 +15802,7 @@ var AppComponent = ({ eventBus, sessionId, cliVersion }) => {
14702
15802
  ...prev,
14703
15803
  {
14704
15804
  id,
14705
- component: /* @__PURE__ */ jsx24(ChatMeta, { children: "Ctrl+O: no truncated preview to expand" }, id)
15805
+ component: /* @__PURE__ */ jsx27(ChatMeta, { children: "Ctrl+O: no truncated preview to expand" }, id)
14706
15806
  }
14707
15807
  ];
14708
15808
  }
@@ -14710,18 +15810,18 @@ var AppComponent = ({ eventBus, sessionId, cliVersion }) => {
14710
15810
  ...prev,
14711
15811
  {
14712
15812
  id,
14713
- component: /* @__PURE__ */ jsx24(ExpandedPreviewBlock, { data: p }, id)
15813
+ component: /* @__PURE__ */ jsx27(ExpandedPreviewBlock, { data: p }, id)
14714
15814
  }
14715
15815
  ];
14716
15816
  });
14717
15817
  }, []);
14718
- useEffect8(() => {
15818
+ useEffect11(() => {
14719
15819
  expandPreviewHotkeyBus.on("expand", appendExpandPreviewToHistory);
14720
15820
  return () => {
14721
15821
  expandPreviewHotkeyBus.off("expand", appendExpandPreviewToHistory);
14722
15822
  };
14723
15823
  }, [appendExpandPreviewToHistory]);
14724
- useEffect8(() => {
15824
+ useEffect11(() => {
14725
15825
  if (process.env.CI || blumaUpdateRegistryCheckStarted) return;
14726
15826
  blumaUpdateRegistryCheckStarted = true;
14727
15827
  void checkForUpdates().then((msg) => {
@@ -14732,25 +15832,25 @@ var AppComponent = ({ eventBus, sessionId, cliVersion }) => {
14732
15832
  ...prev,
14733
15833
  {
14734
15834
  id: nextId2,
14735
- component: /* @__PURE__ */ jsx24(UpdateNotice_default, { message: msg })
15835
+ component: /* @__PURE__ */ jsx27(UpdateNotice_default, { message: msg })
14736
15836
  }
14737
15837
  ];
14738
15838
  });
14739
15839
  });
14740
15840
  }, []);
14741
- useEffect8(() => {
15841
+ useEffect11(() => {
14742
15842
  setHistory((prev) => {
14743
15843
  const tail = prev.filter((h) => h.id !== HEADER_PANEL_HISTORY_ID);
14744
15844
  return [
14745
15845
  {
14746
15846
  id: HEADER_PANEL_HISTORY_ID,
14747
- component: /* @__PURE__ */ jsx24(Header, { sessionId, workdir, cliVersion })
15847
+ component: /* @__PURE__ */ jsx27(Header, { sessionId, workdir, cliVersion })
14748
15848
  },
14749
15849
  ...tail
14750
15850
  ];
14751
15851
  });
14752
15852
  }, [sessionId, workdir, cliVersion]);
14753
- const handleInterrupt = useCallback3(() => {
15853
+ const handleInterrupt = useCallback4(() => {
14754
15854
  if (!isProcessing) return;
14755
15855
  eventBus.emit("user_interrupt");
14756
15856
  turnStartedAtRef.current = null;
@@ -14762,12 +15862,12 @@ var AppComponent = ({ eventBus, sessionId, cliVersion }) => {
14762
15862
  ...prev,
14763
15863
  {
14764
15864
  id,
14765
- component: /* @__PURE__ */ jsx24(ChatMeta, { children: "cancelled (Esc)" })
15865
+ component: /* @__PURE__ */ jsx27(ChatMeta, { children: "cancelled (Esc)" })
14766
15866
  }
14767
15867
  ];
14768
15868
  });
14769
15869
  }, [isProcessing, eventBus]);
14770
- const handleSubmit = useCallback3(
15870
+ const handleSubmit = useCallback4(
14771
15871
  (text) => {
14772
15872
  if (!text || !agentInstance.current) return;
14773
15873
  const trimmedForSlash = text.trim();
@@ -14779,7 +15879,7 @@ var AppComponent = ({ eventBus, sessionId, cliVersion }) => {
14779
15879
  ...prev,
14780
15880
  {
14781
15881
  id,
14782
- component: /* @__PURE__ */ jsx24(ChatMeta, { children: "Slash command not recognized or incomplete. Type /help for the list." })
15882
+ component: /* @__PURE__ */ jsx27(ChatMeta, { children: "Slash command not recognized or incomplete. Type /help for the list." })
14783
15883
  }
14784
15884
  ];
14785
15885
  });
@@ -14797,7 +15897,7 @@ var AppComponent = ({ eventBus, sessionId, cliVersion }) => {
14797
15897
  ...prev,
14798
15898
  {
14799
15899
  id,
14800
- component: /* @__PURE__ */ jsx24(ChatMeta, { children: "Usage: /img ./screenshot.png \u2014 optional text after the path is sent too" })
15900
+ component: /* @__PURE__ */ jsx27(ChatMeta, { children: "Usage: /img ./screenshot.png \u2014 optional text after the path is sent too" })
14801
15901
  }
14802
15902
  ];
14803
15903
  });
@@ -14816,7 +15916,7 @@ var AppComponent = ({ eventBus, sessionId, cliVersion }) => {
14816
15916
  ...prev,
14817
15917
  {
14818
15918
  id,
14819
- component: /* @__PURE__ */ jsx24(UserMessageWithOptionalImages, { raw: payload, variant: "slash-img" })
15919
+ component: /* @__PURE__ */ jsx27(UserMessageWithOptionalImages, { raw: payload, variant: "slash-img" })
14820
15920
  }
14821
15921
  ];
14822
15922
  });
@@ -14849,11 +15949,11 @@ var AppComponent = ({ eventBus, sessionId, cliVersion }) => {
14849
15949
  ...prev,
14850
15950
  {
14851
15951
  id: firstId,
14852
- component: /* @__PURE__ */ jsx24(ChatUserMessage, { children: /* @__PURE__ */ jsx24(Text22, { color: BLUMA_TERMINAL.m3OnSurface, bold: true, wrap: "wrap", children: text }) })
15952
+ component: /* @__PURE__ */ jsx27(ChatUserMessage, { children: /* @__PURE__ */ jsx27(Text25, { color: BLUMA_TERMINAL.m3OnSurface, bold: true, wrap: "wrap", children: text }) })
14853
15953
  },
14854
15954
  {
14855
15955
  id: secondId,
14856
- component: /* @__PURE__ */ jsx24(
15956
+ component: /* @__PURE__ */ jsx27(
14857
15957
  SlashCommands_default,
14858
15958
  {
14859
15959
  input: text,
@@ -14885,7 +15985,7 @@ var AppComponent = ({ eventBus, sessionId, cliVersion }) => {
14885
15985
  ...prev,
14886
15986
  {
14887
15987
  id,
14888
- component: /* @__PURE__ */ jsx24(ChatUserMessage, { children: /* @__PURE__ */ jsxs22(Text22, { bold: true, color: "white", children: [
15988
+ component: /* @__PURE__ */ jsx27(ChatUserMessage, { children: /* @__PURE__ */ jsxs24(Text25, { bold: true, color: "white", children: [
14889
15989
  "$ !",
14890
15990
  command
14891
15991
  ] }) })
@@ -14911,7 +16011,7 @@ Please use command_status to check the result and report back to the user.`;
14911
16011
  ...prev,
14912
16012
  {
14913
16013
  id,
14914
- component: /* @__PURE__ */ jsxs22(Text22, { color: "red", children: [
16014
+ component: /* @__PURE__ */ jsxs24(Text25, { color: "red", children: [
14915
16015
  "Failed to execute: ",
14916
16016
  result.error || result.message
14917
16017
  ] })
@@ -14929,7 +16029,7 @@ Please use command_status to check the result and report back to the user.`;
14929
16029
  ...prev,
14930
16030
  {
14931
16031
  id,
14932
- component: /* @__PURE__ */ jsxs22(Text22, { color: "red", children: [
16032
+ component: /* @__PURE__ */ jsxs24(Text25, { color: "red", children: [
14933
16033
  "Error: ",
14934
16034
  err.message
14935
16035
  ] })
@@ -14949,7 +16049,7 @@ Please use command_status to check the result and report back to the user.`;
14949
16049
  ...prev,
14950
16050
  {
14951
16051
  id,
14952
- component: /* @__PURE__ */ jsx24(UserMessageWithOptionalImages, { raw: text, variant: "plain" })
16052
+ component: /* @__PURE__ */ jsx27(UserMessageWithOptionalImages, { raw: text, variant: "plain" })
14953
16053
  }
14954
16054
  ];
14955
16055
  });
@@ -14957,7 +16057,7 @@ Please use command_status to check the result and report back to the user.`;
14957
16057
  },
14958
16058
  [isProcessing, markTurnStarted]
14959
16059
  );
14960
- const handleConfirmation = useCallback3(
16060
+ const handleConfirmation = useCallback4(
14961
16061
  (decision, toolCalls, opts) => {
14962
16062
  if (!agentInstance.current) return;
14963
16063
  setPendingConfirmation(null);
@@ -14979,7 +16079,7 @@ Please use command_status to check the result and report back to the user.`;
14979
16079
  },
14980
16080
  []
14981
16081
  );
14982
- const appendStreamedReasoning = useCallback3((reasoning) => {
16082
+ const appendStreamedReasoning = useCallback4((reasoning) => {
14983
16083
  const r = String(reasoning ?? "").trim();
14984
16084
  const key = reasoningDedupeKey(r);
14985
16085
  if (!r || key === lastReasoningTextRef.current) return;
@@ -14990,12 +16090,12 @@ Please use command_status to check the result and report back to the user.`;
14990
16090
  ...prev,
14991
16091
  {
14992
16092
  id,
14993
- component: /* @__PURE__ */ jsx24(ReasoningDisplay, { reasoning })
16093
+ component: /* @__PURE__ */ jsx27(ReasoningDisplay, { reasoning })
14994
16094
  }
14995
16095
  ];
14996
16096
  });
14997
16097
  }, []);
14998
- const appendStreamedAssistant = useCallback3((content) => {
16098
+ const appendStreamedAssistant = useCallback4((content) => {
14999
16099
  const t = String(content ?? "").trim();
15000
16100
  if (!t) return;
15001
16101
  const key = reasoningDedupeKey(t);
@@ -15006,12 +16106,12 @@ Please use command_status to check the result and report back to the user.`;
15006
16106
  ...prev,
15007
16107
  {
15008
16108
  id,
15009
- component: /* @__PURE__ */ jsx24(AssistantMessageDisplay, { content })
16109
+ component: /* @__PURE__ */ jsx27(AssistantMessageDisplay, { content })
15010
16110
  }
15011
16111
  ];
15012
16112
  });
15013
16113
  }, []);
15014
- useEffect8(() => {
16114
+ useEffect11(() => {
15015
16115
  if (history.length >= HISTORY_EMERGENCY_LIMIT) {
15016
16116
  setHistory((prev) => {
15017
16117
  const header = prev.find((h) => h.id === HEADER_PANEL_HISTORY_ID);
@@ -15021,7 +16121,7 @@ Please use command_status to check the result and report back to the user.`;
15021
16121
  });
15022
16122
  }
15023
16123
  }, [history.length]);
15024
- useEffect8(() => {
16124
+ useEffect11(() => {
15025
16125
  const initializeAgent = async () => {
15026
16126
  try {
15027
16127
  agentInstance.current = new Agent(sessionId, eventBus);
@@ -15058,7 +16158,7 @@ Please use command_status to check the result and report back to the user.`;
15058
16158
  ...prev,
15059
16159
  {
15060
16160
  id,
15061
- component: /* @__PURE__ */ jsx24(ChatTurnDuration, { durationMs: ms })
16161
+ component: /* @__PURE__ */ jsx27(ChatTurnDuration, { durationMs: ms })
15062
16162
  }
15063
16163
  ];
15064
16164
  });
@@ -15080,6 +16180,31 @@ Please use command_status to check the result and report back to the user.`;
15080
16180
  });
15081
16181
  return;
15082
16182
  }
16183
+ if (parsed.type === "tool_stream_start") {
16184
+ const toolName = String(parsed.toolName || "");
16185
+ const argsRaw = parsed.argsRaw;
16186
+ let args = void 0;
16187
+ if (typeof argsRaw === "string") {
16188
+ try {
16189
+ args = JSON.parse(argsRaw);
16190
+ } catch {
16191
+ args = argsRaw;
16192
+ }
16193
+ } else {
16194
+ args = argsRaw;
16195
+ }
16196
+ if (toolName) {
16197
+ setLiveToolName(toolName);
16198
+ setLiveToolArgs(args);
16199
+ }
16200
+ return;
16201
+ }
16202
+ if (parsed.type === "reasoning") {
16203
+ setIsReasoning(true);
16204
+ }
16205
+ if (parsed.type === "stream_end") {
16206
+ setIsReasoning(false);
16207
+ }
15083
16208
  if (parsed.type === "ask_user_question") {
15084
16209
  const qs = parsed.questions;
15085
16210
  if (Array.isArray(qs) && qs.length > 0) {
@@ -15143,14 +16268,14 @@ Please use command_status to check the result and report back to the user.`;
15143
16268
  }
15144
16269
  let newComponent = null;
15145
16270
  if (parsed.type === "debug") {
15146
- newComponent = /* @__PURE__ */ jsx24(ChatMeta, { children: parsed.message });
16271
+ newComponent = /* @__PURE__ */ jsx27(ChatMeta, { children: parsed.message });
15147
16272
  } else if (parsed.type === "protocol_violation") {
15148
- newComponent = /* @__PURE__ */ jsx24(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsxs22(Box23, { flexDirection: "column", paddingLeft: 2, children: [
15149
- /* @__PURE__ */ jsx24(Text22, { dimColor: true, children: parsed.content }),
15150
- /* @__PURE__ */ jsx24(Text22, { dimColor: true, children: parsed.message })
16273
+ newComponent = /* @__PURE__ */ jsx27(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsxs24(Box26, { flexDirection: "column", paddingLeft: 2, children: [
16274
+ /* @__PURE__ */ jsx27(Text25, { dimColor: true, children: parsed.content }),
16275
+ /* @__PURE__ */ jsx27(Text25, { dimColor: true, children: parsed.message })
15151
16276
  ] }) });
15152
16277
  } else if (parsed.type === "error") {
15153
- newComponent = /* @__PURE__ */ jsx24(
16278
+ newComponent = /* @__PURE__ */ jsx27(
15154
16279
  ErrorMessage_default,
15155
16280
  {
15156
16281
  message: parsed.message,
@@ -15168,6 +16293,7 @@ Please use command_status to check the result and report back to the user.`;
15168
16293
  });
15169
16294
  if (parsed.tool_name) {
15170
16295
  setLiveToolName(String(parsed.tool_name));
16296
+ setLiveToolArgs(parsed.arguments);
15171
16297
  }
15172
16298
  const tn = String(parsed.tool_name || "");
15173
16299
  if (isToolInvocationRowVisible(tn)) {
@@ -15176,7 +16302,7 @@ Please use command_status to check the result and report back to the user.`;
15176
16302
  parsed.tool_call_id
15177
16303
  );
15178
16304
  }
15179
- newComponent = isToolInvocationRowVisible(tn) ? /* @__PURE__ */ jsx24(
16305
+ newComponent = isToolInvocationRowVisible(tn) ? /* @__PURE__ */ jsx27(
15180
16306
  ToolInvocationBlock,
15181
16307
  {
15182
16308
  toolName: tn,
@@ -15197,7 +16323,7 @@ Please use command_status to check the result and report back to the user.`;
15197
16323
  pendingToolInvocationIdsRef.current,
15198
16324
  parsed.tool_call_id
15199
16325
  );
15200
- newComponent = /* @__PURE__ */ jsx24(
16326
+ newComponent = /* @__PURE__ */ jsx27(
15201
16327
  ToolResultDisplay,
15202
16328
  {
15203
16329
  toolName: parsed.tool_name,
@@ -15208,7 +16334,7 @@ Please use command_status to check the result and report back to the user.`;
15208
16334
  }
15209
16335
  );
15210
16336
  } else if (parsed.type === "user_overlay") {
15211
- newComponent = /* @__PURE__ */ jsx24(ChatUserMessage, { children: /* @__PURE__ */ jsx24(Text22, { color: BLUMA_TERMINAL.m3OnSurface, bold: true, wrap: "wrap", children: parsed.payload }) });
16337
+ newComponent = /* @__PURE__ */ jsx27(ChatUserMessage, { children: /* @__PURE__ */ jsx27(Text25, { color: BLUMA_TERMINAL.m3OnSurface, bold: true, wrap: "wrap", children: parsed.payload }) });
15212
16338
  } else if (parsed.type === "reasoning") {
15213
16339
  const r = String(parsed.content ?? "").trim();
15214
16340
  const key = reasoningDedupeKey(r);
@@ -15216,10 +16342,10 @@ Please use command_status to check the result and report back to the user.`;
15216
16342
  newComponent = null;
15217
16343
  } else {
15218
16344
  if (r) lastReasoningTextRef.current = key;
15219
- newComponent = /* @__PURE__ */ jsx24(ReasoningDisplay, { reasoning: String(parsed.content ?? "") });
16345
+ newComponent = /* @__PURE__ */ jsx27(ReasoningDisplay, { reasoning: String(parsed.content ?? "") });
15220
16346
  }
15221
16347
  } else if (parsed.type === "log") {
15222
- newComponent = /* @__PURE__ */ jsxs22(ChatMeta, { children: [
16348
+ newComponent = /* @__PURE__ */ jsxs24(ChatMeta, { children: [
15223
16349
  parsed.message,
15224
16350
  parsed.payload ? `: ${parsed.payload}` : ""
15225
16351
  ] });
@@ -15230,7 +16356,7 @@ Please use command_status to check the result and report back to the user.`;
15230
16356
  newComponent = null;
15231
16357
  } else {
15232
16358
  lastStreamAssistantKeyRef.current = key || null;
15233
- newComponent = /* @__PURE__ */ jsx24(AssistantMessageDisplay, { content: body });
16359
+ newComponent = /* @__PURE__ */ jsx27(AssistantMessageDisplay, { content: body });
15234
16360
  }
15235
16361
  }
15236
16362
  if (newComponent) {
@@ -15248,7 +16374,7 @@ Please use command_status to check the result and report back to the user.`;
15248
16374
  const ms = Date.now() - t;
15249
16375
  next.push({
15250
16376
  id: nextHistoryId(next),
15251
- component: /* @__PURE__ */ jsx24(ChatTurnDuration, { durationMs: ms })
16377
+ component: /* @__PURE__ */ jsx27(ChatTurnDuration, { durationMs: ms })
15252
16378
  });
15253
16379
  }
15254
16380
  }
@@ -15266,7 +16392,7 @@ Please use command_status to check the result and report back to the user.`;
15266
16392
  if (!msg) return;
15267
16393
  setHistory((prev) => {
15268
16394
  const id = nextHistoryId(prev);
15269
- return [...prev, { id, component: /* @__PURE__ */ jsx24(ChatMeta, { children: msg }) }];
16395
+ return [...prev, { id, component: /* @__PURE__ */ jsx27(ChatMeta, { children: msg }) }];
15270
16396
  });
15271
16397
  };
15272
16398
  uiEventBus.on("user_overlay", handleUiOverlay);
@@ -15281,7 +16407,7 @@ Please use command_status to check the result and report back to the user.`;
15281
16407
  }, [eventBus, sessionId, handleConfirmation]);
15282
16408
  const renderInteractiveComponent = () => {
15283
16409
  if (mcpStatus !== "connected") {
15284
- return /* @__PURE__ */ jsx24(
16410
+ return /* @__PURE__ */ jsx27(
15285
16411
  SessionInfoConnectingMCP_default,
15286
16412
  {
15287
16413
  workdir,
@@ -15289,8 +16415,8 @@ Please use command_status to check the result and report back to the user.`;
15289
16415
  }
15290
16416
  );
15291
16417
  }
15292
- return /* @__PURE__ */ jsxs22(Box23, { flexDirection: "column", children: [
15293
- pendingAskUserQuestions && pendingAskUserQuestions.length > 0 ? /* @__PURE__ */ jsx24(
16418
+ return /* @__PURE__ */ jsxs24(Box26, { flexDirection: "column", children: [
16419
+ pendingAskUserQuestions && pendingAskUserQuestions.length > 0 ? /* @__PURE__ */ jsx27(
15294
16420
  AskUserQuestionPrompt,
15295
16421
  {
15296
16422
  questions: pendingAskUserQuestions,
@@ -15306,7 +16432,7 @@ Please use command_status to check the result and report back to the user.`;
15306
16432
  }
15307
16433
  }
15308
16434
  ) : null,
15309
- pendingConfirmation ? /* @__PURE__ */ jsx24(
16435
+ pendingConfirmation ? /* @__PURE__ */ jsx27(
15310
16436
  ConfirmationPrompt,
15311
16437
  {
15312
16438
  toolCalls: pendingConfirmation,
@@ -15319,8 +16445,17 @@ Please use command_status to check the result and report back to the user.`;
15319
16445
  }
15320
16446
  }
15321
16447
  ) : null,
15322
- isProcessing && !pendingConfirmation && !pendingAskUserQuestions && /* @__PURE__ */ jsx24(WorkingTimer, { eventBus, startedAtMs: processingStartMs }),
15323
- /* @__PURE__ */ jsx24(
16448
+ isProcessing && !pendingConfirmation && !pendingAskUserQuestions && /* @__PURE__ */ jsx27(
16449
+ WorkingTimer,
16450
+ {
16451
+ eventBus,
16452
+ startedAtMs: processingStartMs,
16453
+ liveToolName,
16454
+ liveToolArgs,
16455
+ isReasoning
16456
+ }
16457
+ ),
16458
+ /* @__PURE__ */ jsx27(
15324
16459
  InputPrompt,
15325
16460
  {
15326
16461
  onSubmit: handleSubmit,
@@ -15332,10 +16467,10 @@ Please use command_status to check the result and report back to the user.`;
15332
16467
  )
15333
16468
  ] });
15334
16469
  };
15335
- return /* @__PURE__ */ jsxs22(Box23, { flexDirection: "column", children: [
15336
- /* @__PURE__ */ jsx24(Static, { items: history, children: (item) => /* @__PURE__ */ jsx24(Box23, { children: item.component }, item.id) }),
15337
- liveToolName ? /* @__PURE__ */ jsx24(Box23, { paddingLeft: 2, marginBottom: 0, children: /* @__PURE__ */ jsxs22(Text22, { dimColor: true, children: [
15338
- /* @__PURE__ */ jsxs22(Text22, { color: BLUMA_TERMINAL.brandMagenta, bold: true, children: [
16470
+ return /* @__PURE__ */ jsxs24(Box26, { flexDirection: "column", children: [
16471
+ /* @__PURE__ */ jsx27(Static, { items: history, children: (item) => /* @__PURE__ */ jsx27(Box26, { children: item.component }, item.id) }),
16472
+ liveToolName ? /* @__PURE__ */ jsx27(Box26, { paddingLeft: 2, marginBottom: 0, children: /* @__PURE__ */ jsxs24(Text25, { dimColor: true, children: [
16473
+ /* @__PURE__ */ jsxs24(Text25, { color: BLUMA_TERMINAL.brandMagenta, bold: true, children: [
15339
16474
  "*",
15340
16475
  " "
15341
16476
  ] }),
@@ -15343,7 +16478,7 @@ Please use command_status to check the result and report back to the user.`;
15343
16478
  liveToolName,
15344
16479
  "\u2026"
15345
16480
  ] }) }) : null,
15346
- /* @__PURE__ */ jsx24(
16481
+ /* @__PURE__ */ jsx27(
15347
16482
  StreamingText,
15348
16483
  {
15349
16484
  eventBus,
@@ -15351,7 +16486,19 @@ Please use command_status to check the result and report back to the user.`;
15351
16486
  onAssistantContentComplete: appendStreamedAssistant
15352
16487
  }
15353
16488
  ),
15354
- renderInteractiveComponent()
16489
+ renderInteractiveComponent(),
16490
+ showWorkers && /* @__PURE__ */ jsx27(
16491
+ WorkerOverlay,
16492
+ {
16493
+ visible: showWorkers,
16494
+ sessionId,
16495
+ onClose: () => {
16496
+ setShowWorkers(false);
16497
+ setZoomedWorkerSession(null);
16498
+ },
16499
+ onZoomWorker: setZoomedWorkerSession
16500
+ }
16501
+ )
15355
16502
  ] });
15356
16503
  };
15357
16504
  var App = memo15(AppComponent);
@@ -15413,6 +16560,7 @@ function stopTitleKeeper() {
15413
16560
  }
15414
16561
 
15415
16562
  // src/main.ts
16563
+ init_session_registry();
15416
16564
  function extractUserMessage(envelope) {
15417
16565
  const c = envelope.context;
15418
16566
  if (c && typeof c === "object" && typeof c.user_request === "string") {
@@ -15477,9 +16625,9 @@ async function runAgentMode() {
15477
16625
  try {
15478
16626
  if (inputFileIndex !== -1 && args[inputFileIndex + 1]) {
15479
16627
  const filePath = args[inputFileIndex + 1];
15480
- rawPayload = fs27.readFileSync(filePath, "utf-8");
16628
+ rawPayload = fs28.readFileSync(filePath, "utf-8");
15481
16629
  } else {
15482
- rawPayload = fs27.readFileSync(0, "utf-8");
16630
+ rawPayload = fs28.readFileSync(0, "utf-8");
15483
16631
  }
15484
16632
  } catch (err) {
15485
16633
  writeAgentEvent(registrySessionId, {
@@ -15517,7 +16665,7 @@ async function runAgentMode() {
15517
16665
  }
15518
16666
  }
15519
16667
  const eventBus = new EventEmitter3();
15520
- const sessionId = registrySessionId || envelope.session_id || envelope.message_id || uuidv47();
16668
+ const sessionId = registrySessionId || envelope.session_id || envelope.message_id || uuidv48();
15521
16669
  process.env.BLUMA_SESSION_ID = sessionId;
15522
16670
  installSessionLifecycle(sessionId);
15523
16671
  const uc = envelope.user_context;
@@ -15675,9 +16823,9 @@ async function runAgentMode() {
15675
16823
  }
15676
16824
  function readCliPackageVersion() {
15677
16825
  try {
15678
- const base = path32.dirname(fileURLToPath6(import.meta.url));
15679
- const pkgPath = path32.join(base, "..", "package.json");
15680
- const j = JSON.parse(fs27.readFileSync(pkgPath, "utf8"));
16826
+ const base = path33.dirname(fileURLToPath6(import.meta.url));
16827
+ const pkgPath = path33.join(base, "..", "package.json");
16828
+ const j = JSON.parse(fs28.readFileSync(pkgPath, "utf8"));
15681
16829
  return String(j.version || "0.0.0");
15682
16830
  } catch {
15683
16831
  return "0.0.0";
@@ -15687,7 +16835,7 @@ function runCliMode(sessionId) {
15687
16835
  const BLUMA_TITLE = "bluma";
15688
16836
  startTitleKeeper(BLUMA_TITLE);
15689
16837
  const eventBus = new EventEmitter3();
15690
- const resolvedSessionId = sessionId || uuidv47();
16838
+ const resolvedSessionId = sessionId || uuidv48();
15691
16839
  process.env.BLUMA_SESSION_ID = resolvedSessionId;
15692
16840
  registerSession({
15693
16841
  sessionId: resolvedSessionId,
@@ -15705,7 +16853,7 @@ function runCliMode(sessionId) {
15705
16853
  sessionId: resolvedSessionId,
15706
16854
  cliVersion: readCliPackageVersion()
15707
16855
  };
15708
- const instance = render(React16.createElement(App_default, props));
16856
+ const instance = render(React19.createElement(App_default, props));
15709
16857
  void instance.waitUntilExit().then(() => {
15710
16858
  finalizeSession(resolvedSessionId, "completed", { finishedBy: "interactive-exit" });
15711
16859
  });
@@ -15800,9 +16948,9 @@ function startBackgroundAgent() {
15800
16948
  process.exit(1);
15801
16949
  }
15802
16950
  const filePath = args[inputFileIndex + 1];
15803
- const rawPayload = fs27.readFileSync(filePath, "utf-8");
16951
+ const rawPayload = fs28.readFileSync(filePath, "utf-8");
15804
16952
  const envelope = JSON.parse(rawPayload);
15805
- const sessionId = envelope.session_id || envelope.message_id || uuidv47();
16953
+ const sessionId = envelope.session_id || envelope.message_id || uuidv48();
15806
16954
  registerSession({
15807
16955
  sessionId,
15808
16956
  kind: "agent",