@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.
- package/dist/main.js +1688 -540
- 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
|
|
1182
|
+
import React19 from "react";
|
|
501
1183
|
import { render } from "ink";
|
|
502
1184
|
import { EventEmitter as EventEmitter3 } from "events";
|
|
503
|
-
import
|
|
504
|
-
import
|
|
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
|
|
1189
|
+
import { v4 as uuidv48 } from "uuid";
|
|
508
1190
|
|
|
509
1191
|
// src/app/ui/App.tsx
|
|
510
|
-
import { useState as
|
|
511
|
-
import { Box as
|
|
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
|
|
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:
|
|
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
|
|
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
|
-
|
|
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: "
|
|
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
|
|
3652
|
-
import
|
|
4333
|
+
import path31 from "path";
|
|
4334
|
+
import os20 from "os";
|
|
3653
4335
|
|
|
3654
4336
|
// src/app/agent/tool_invoker.ts
|
|
3655
|
-
import { promises as
|
|
3656
|
-
import
|
|
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/
|
|
6905
|
-
|
|
6906
|
-
|
|
6907
|
-
|
|
6908
|
-
|
|
6909
|
-
|
|
6910
|
-
|
|
6911
|
-
|
|
6912
|
-
|
|
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
|
-
|
|
6994
|
-
|
|
6995
|
-
|
|
6996
|
-
|
|
6997
|
-
|
|
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
|
-
|
|
7005
|
-
|
|
7006
|
-
|
|
7007
|
-
|
|
7008
|
-
|
|
7009
|
-
|
|
7010
|
-
|
|
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
|
-
|
|
7038
|
-
|
|
7039
|
-
|
|
7040
|
-
|
|
7041
|
-
|
|
7042
|
-
|
|
7043
|
-
|
|
7044
|
-
|
|
7045
|
-
|
|
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
|
-
|
|
7056
|
-
|
|
7057
|
-
|
|
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
|
|
7060
|
-
|
|
7061
|
-
|
|
7062
|
-
|
|
7063
|
-
|
|
7064
|
-
|
|
7065
|
-
|
|
7066
|
-
|
|
7067
|
-
|
|
7068
|
-
|
|
7069
|
-
|
|
7070
|
-
|
|
7071
|
-
|
|
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
|
-
|
|
7102
|
-
|
|
7103
|
-
|
|
7104
|
-
|
|
7105
|
-
|
|
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
|
|
7109
|
-
const
|
|
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
|
|
7118
|
-
|
|
7119
|
-
|
|
7120
|
-
|
|
7121
|
-
|
|
7122
|
-
|
|
7123
|
-
|
|
7124
|
-
|
|
7125
|
-
|
|
7126
|
-
|
|
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,
|
|
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
|
-
|
|
7132
|
-
|
|
7133
|
-
|
|
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
|
-
|
|
7138
|
-
|
|
7139
|
-
|
|
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 =
|
|
7633
|
-
const configPath =
|
|
7634
|
-
const fileContent = await
|
|
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
|
|
7677
|
-
import
|
|
7678
|
-
import
|
|
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 =
|
|
7706
|
-
const defaultConfigPath =
|
|
7707
|
-
const userConfigPath =
|
|
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
|
|
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 =
|
|
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
|
|
7913
|
-
import { v4 as
|
|
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
|
|
7917
|
-
import
|
|
7918
|
-
import { promises as
|
|
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
|
|
8581
|
+
return path22.join(os13.homedir(), p.slice(1));
|
|
7955
8582
|
}
|
|
7956
8583
|
return p;
|
|
7957
8584
|
}
|
|
7958
8585
|
function getPreferredAppDir() {
|
|
7959
|
-
const fixed =
|
|
7960
|
-
return
|
|
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 =
|
|
7969
|
-
await
|
|
8595
|
+
const dir = path22.dirname(dest);
|
|
8596
|
+
await fs20.mkdir(dir, { recursive: true }).catch(() => {
|
|
7970
8597
|
});
|
|
7971
|
-
await
|
|
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
|
|
7985
|
-
const data = await
|
|
7986
|
-
const dir =
|
|
7987
|
-
await
|
|
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
|
|
7990
|
-
await
|
|
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 =
|
|
8004
|
-
await
|
|
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 =
|
|
8636
|
+
const sessionFile = path22.join(sessionDir, `${sessionId}.json`);
|
|
8010
8637
|
try {
|
|
8011
|
-
await
|
|
8012
|
-
const fileContent = await
|
|
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
|
|
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 =
|
|
8038
|
-
await
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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
|
|
8103
|
-
import
|
|
8104
|
-
import
|
|
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
|
|
8109
|
-
import
|
|
8110
|
-
import
|
|
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 =
|
|
8120
|
-
this.globalSkillsDir =
|
|
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
|
|
8756
|
+
return path23.join(process.cwd(), "dist", "config", "skills");
|
|
8130
8757
|
}
|
|
8131
8758
|
const candidates = [];
|
|
8132
8759
|
const push = (p) => {
|
|
8133
|
-
const abs =
|
|
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 =
|
|
8141
|
-
push(
|
|
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 (
|
|
8149
|
-
resolved =
|
|
8150
|
-
} else if (!
|
|
8151
|
-
resolved =
|
|
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 =
|
|
8154
|
-
argvBundled =
|
|
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 (
|
|
8787
|
+
if (fs21.existsSync(abs)) {
|
|
8161
8788
|
return abs;
|
|
8162
8789
|
}
|
|
8163
8790
|
}
|
|
8164
8791
|
try {
|
|
8165
|
-
return
|
|
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
|
|
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:
|
|
8200
|
-
bundledPath:
|
|
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 (!
|
|
8835
|
+
if (!fs21.existsSync(dir)) return [];
|
|
8209
8836
|
try {
|
|
8210
|
-
return
|
|
8211
|
-
const fullPath =
|
|
8212
|
-
return
|
|
8213
|
-
}).map((d) => this.loadMetadataFromPath(
|
|
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 (!
|
|
8846
|
+
if (!fs21.existsSync(skillPath)) return null;
|
|
8220
8847
|
try {
|
|
8221
|
-
const raw =
|
|
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 =
|
|
8244
|
-
const projectPath =
|
|
8245
|
-
const globalPath =
|
|
8246
|
-
const existsBundled =
|
|
8247
|
-
const existsProject =
|
|
8248
|
-
const existsGlobal =
|
|
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 =
|
|
8914
|
+
const raw = fs21.readFileSync(skillPath, "utf-8");
|
|
8288
8915
|
const parsed = this.parseFrontmatter(raw);
|
|
8289
|
-
const skillDir =
|
|
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(
|
|
8299
|
-
scripts: this.scanAssets(
|
|
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 (!
|
|
8933
|
+
if (!fs21.existsSync(dir)) return [];
|
|
8307
8934
|
try {
|
|
8308
|
-
return
|
|
8309
|
-
const fp =
|
|
8310
|
-
return
|
|
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:
|
|
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 =
|
|
8371
|
-
const projectPath =
|
|
8372
|
-
const globalPath =
|
|
8373
|
-
return
|
|
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
|
|
8406
|
-
import
|
|
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 (!
|
|
8422
|
-
const st =
|
|
9048
|
+
if (!fs22.existsSync(filePath)) return null;
|
|
9049
|
+
const st = fs22.statSync(filePath);
|
|
8423
9050
|
if (!st.isFile()) return null;
|
|
8424
|
-
const raw =
|
|
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(
|
|
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
|
-
|
|
8444
|
-
|
|
8445
|
-
|
|
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 =
|
|
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 =
|
|
9085
|
+
const p = path24.join(cwd, "package.json");
|
|
8459
9086
|
try {
|
|
8460
|
-
if (!
|
|
8461
|
-
const pkg = JSON.parse(
|
|
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 =
|
|
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(
|
|
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(
|
|
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(
|
|
9203
|
+
const chlog = safeReadFile(path24.join(cwd, "CHANGELOG.md"), LIMITS.changelog);
|
|
8577
9204
|
if (!chlog) {
|
|
8578
|
-
const alt = safeReadFile(
|
|
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
|
|
8619
|
-
import
|
|
8620
|
-
import
|
|
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
|
|
9250
|
+
return path25.join(policy.workspaceRoot, ".bluma", "plugins");
|
|
8624
9251
|
}
|
|
8625
9252
|
function getGlobalPluginsDir() {
|
|
8626
|
-
return
|
|
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 (!
|
|
9262
|
+
if (!fs23.existsSync(manifestPath)) {
|
|
8636
9263
|
return null;
|
|
8637
9264
|
}
|
|
8638
9265
|
try {
|
|
8639
|
-
const parsed = JSON.parse(
|
|
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
|
-
|
|
8653
|
-
|
|
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 (
|
|
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 (!
|
|
9290
|
+
if (!fs23.existsSync(baseDir)) {
|
|
8664
9291
|
return [];
|
|
8665
9292
|
}
|
|
8666
|
-
return
|
|
8667
|
-
const pluginDir =
|
|
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
|
-
-
|
|
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 (
|
|
8944
|
-
if (
|
|
8945
|
-
if (
|
|
8946
|
-
if (
|
|
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 =
|
|
9584
|
+
const files = fs24.readdirSync(dir);
|
|
8955
9585
|
if (files.includes("package.json")) {
|
|
8956
|
-
const pkg = JSON.parse(
|
|
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 =
|
|
8976
|
-
if (
|
|
8977
|
-
const pkg = JSON.parse(
|
|
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 (
|
|
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 =
|
|
8995
|
-
if (
|
|
8996
|
-
const pkg = JSON.parse(
|
|
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:
|
|
9155
|
-
os_version:
|
|
9156
|
-
architecture:
|
|
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:
|
|
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 =
|
|
9218
|
-
return
|
|
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
|
-
|
|
9436
|
-
|
|
9437
|
-
|
|
9438
|
-
|
|
9439
|
-
|
|
9440
|
-
|
|
9441
|
-
|
|
9442
|
-
|
|
9443
|
-
|
|
9444
|
-
|
|
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
|
|
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 =
|
|
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:${
|
|
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 =
|
|
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
|
|
9947
|
-
import
|
|
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
|
|
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 (
|
|
9978
|
-
const parsed = JSON.parse(
|
|
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
|
-
|
|
10640
|
+
fs25.mkdirSync(path27.dirname(statePath), { recursive: true });
|
|
10005
10641
|
state.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
10006
|
-
|
|
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
|
|
10104
|
-
import * as
|
|
10105
|
-
import
|
|
10739
|
+
import * as fs26 from "fs";
|
|
10740
|
+
import * as path28 from "path";
|
|
10741
|
+
import os18 from "os";
|
|
10106
10742
|
function memoryPath() {
|
|
10107
|
-
return
|
|
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 (!
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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
|
|
11750
|
+
import { v4 as uuidv47 } from "uuid";
|
|
11066
11751
|
|
|
11067
11752
|
// src/app/agent/subagents/base_llm_subagent.ts
|
|
11068
|
-
import { v4 as
|
|
11753
|
+
import { v4 as uuidv46 } from "uuid";
|
|
11069
11754
|
|
|
11070
11755
|
// src/app/agent/subagents/init/init_system_prompt.ts
|
|
11071
|
-
import
|
|
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:
|
|
11235
|
-
os_version:
|
|
11236
|
-
architecture:
|
|
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:
|
|
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 =
|
|
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:
|
|
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(
|
|
11547
|
-
this.routeHandlers.set(
|
|
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 [
|
|
11553
|
-
if (inputText ===
|
|
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
|
|
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 =
|
|
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 =
|
|
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 = ({
|
|
11841
|
-
|
|
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() || "
|
|
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",
|
|
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",
|
|
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: "
|
|
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
|
|
14196
|
-
import
|
|
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 =
|
|
14202
|
-
if (
|
|
15053
|
+
const candidate = path32.join(dir, "package.json");
|
|
15054
|
+
if (fs27.existsSync(candidate)) {
|
|
14203
15055
|
try {
|
|
14204
|
-
const raw =
|
|
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 =
|
|
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 =
|
|
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(
|
|
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 (
|
|
14236
|
-
resolved =
|
|
15087
|
+
if (path32.isAbsolute(argv1) && fs27.existsSync(argv1)) {
|
|
15088
|
+
resolved = fs27.realpathSync(argv1);
|
|
14237
15089
|
} else {
|
|
14238
|
-
resolved =
|
|
15090
|
+
resolved = path32.resolve(process.cwd(), argv1);
|
|
14239
15091
|
}
|
|
14240
|
-
const fromArgv = tryFrom(
|
|
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/
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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] =
|
|
14667
|
-
const [statusMessage, setStatusMessage] =
|
|
15750
|
+
const [history, setHistory] = useState11([]);
|
|
15751
|
+
const [statusMessage, setStatusMessage] = useState11(
|
|
14668
15752
|
"Initializing agent..."
|
|
14669
15753
|
);
|
|
14670
|
-
const [toolsCount, setToolsCount] =
|
|
14671
|
-
const [mcpStatus, setMcpStatus] =
|
|
15754
|
+
const [toolsCount, setToolsCount] = useState11(null);
|
|
15755
|
+
const [mcpStatus, setMcpStatus] = useState11(
|
|
14672
15756
|
"connecting"
|
|
14673
15757
|
);
|
|
14674
|
-
const [isProcessing, setIsProcessing] =
|
|
14675
|
-
const [pendingConfirmation, setPendingConfirmation] =
|
|
15758
|
+
const [isProcessing, setIsProcessing] = useState11(true);
|
|
15759
|
+
const [pendingConfirmation, setPendingConfirmation] = useState11(
|
|
14676
15760
|
null
|
|
14677
15761
|
);
|
|
14678
|
-
const [confirmationPreview, setConfirmationPreview] =
|
|
15762
|
+
const [confirmationPreview, setConfirmationPreview] = useState11(
|
|
14679
15763
|
null
|
|
14680
15764
|
);
|
|
14681
|
-
const [pendingAskUserQuestions, setPendingAskUserQuestions] =
|
|
14682
|
-
const [
|
|
14683
|
-
const [
|
|
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] =
|
|
14688
|
-
const markTurnStarted =
|
|
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 =
|
|
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__ */
|
|
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__ */
|
|
15813
|
+
component: /* @__PURE__ */ jsx27(ExpandedPreviewBlock, { data: p }, id)
|
|
14714
15814
|
}
|
|
14715
15815
|
];
|
|
14716
15816
|
});
|
|
14717
15817
|
}, []);
|
|
14718
|
-
|
|
15818
|
+
useEffect11(() => {
|
|
14719
15819
|
expandPreviewHotkeyBus.on("expand", appendExpandPreviewToHistory);
|
|
14720
15820
|
return () => {
|
|
14721
15821
|
expandPreviewHotkeyBus.off("expand", appendExpandPreviewToHistory);
|
|
14722
15822
|
};
|
|
14723
15823
|
}, [appendExpandPreviewToHistory]);
|
|
14724
|
-
|
|
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__ */
|
|
15835
|
+
component: /* @__PURE__ */ jsx27(UpdateNotice_default, { message: msg })
|
|
14736
15836
|
}
|
|
14737
15837
|
];
|
|
14738
15838
|
});
|
|
14739
15839
|
});
|
|
14740
15840
|
}, []);
|
|
14741
|
-
|
|
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__ */
|
|
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 =
|
|
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__ */
|
|
15865
|
+
component: /* @__PURE__ */ jsx27(ChatMeta, { children: "cancelled (Esc)" })
|
|
14766
15866
|
}
|
|
14767
15867
|
];
|
|
14768
15868
|
});
|
|
14769
15869
|
}, [isProcessing, eventBus]);
|
|
14770
|
-
const handleSubmit =
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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 =
|
|
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 =
|
|
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__ */
|
|
16093
|
+
component: /* @__PURE__ */ jsx27(ReasoningDisplay, { reasoning })
|
|
14994
16094
|
}
|
|
14995
16095
|
];
|
|
14996
16096
|
});
|
|
14997
16097
|
}, []);
|
|
14998
|
-
const appendStreamedAssistant =
|
|
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__ */
|
|
16109
|
+
component: /* @__PURE__ */ jsx27(AssistantMessageDisplay, { content })
|
|
15010
16110
|
}
|
|
15011
16111
|
];
|
|
15012
16112
|
});
|
|
15013
16113
|
}, []);
|
|
15014
|
-
|
|
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
|
-
|
|
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__ */
|
|
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__ */
|
|
16271
|
+
newComponent = /* @__PURE__ */ jsx27(ChatMeta, { children: parsed.message });
|
|
15147
16272
|
} else if (parsed.type === "protocol_violation") {
|
|
15148
|
-
newComponent = /* @__PURE__ */
|
|
15149
|
-
/* @__PURE__ */
|
|
15150
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
16345
|
+
newComponent = /* @__PURE__ */ jsx27(ReasoningDisplay, { reasoning: String(parsed.content ?? "") });
|
|
15220
16346
|
}
|
|
15221
16347
|
} else if (parsed.type === "log") {
|
|
15222
|
-
newComponent = /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
15293
|
-
pendingAskUserQuestions && pendingAskUserQuestions.length > 0 ? /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
15323
|
-
|
|
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__ */
|
|
15336
|
-
/* @__PURE__ */
|
|
15337
|
-
liveToolName ? /* @__PURE__ */
|
|
15338
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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 =
|
|
16628
|
+
rawPayload = fs28.readFileSync(filePath, "utf-8");
|
|
15481
16629
|
} else {
|
|
15482
|
-
rawPayload =
|
|
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 ||
|
|
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 =
|
|
15679
|
-
const pkgPath =
|
|
15680
|
-
const j = JSON.parse(
|
|
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 ||
|
|
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(
|
|
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 =
|
|
16951
|
+
const rawPayload = fs28.readFileSync(filePath, "utf-8");
|
|
15804
16952
|
const envelope = JSON.parse(rawPayload);
|
|
15805
|
-
const sessionId = envelope.session_id || envelope.message_id ||
|
|
16953
|
+
const sessionId = envelope.session_id || envelope.message_id || uuidv48();
|
|
15806
16954
|
registerSession({
|
|
15807
16955
|
sessionId,
|
|
15808
16956
|
kind: "agent",
|