@nomad-e/bluma-cli 0.1.31 → 0.1.33
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/README.md +370 -54
- package/dist/config/native_tools.json +1 -1
- package/dist/main.js +559 -127
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -17,7 +17,7 @@ __export(async_command_exports, {
|
|
|
17
17
|
runCommandAsync: () => runCommandAsync,
|
|
18
18
|
sendCommandInput: () => sendCommandInput
|
|
19
19
|
});
|
|
20
|
-
import
|
|
20
|
+
import os3 from "os";
|
|
21
21
|
import { spawn } from "child_process";
|
|
22
22
|
import { v4 as uuidv42 } from "uuid";
|
|
23
23
|
function cleanupOldCommands() {
|
|
@@ -63,7 +63,7 @@ async function runCommandAsync(args) {
|
|
|
63
63
|
};
|
|
64
64
|
}
|
|
65
65
|
const commandId = uuidv42().substring(0, 8);
|
|
66
|
-
const platform =
|
|
66
|
+
const platform = os3.platform();
|
|
67
67
|
let shellCmd;
|
|
68
68
|
let shellArgs;
|
|
69
69
|
if (platform === "win32") {
|
|
@@ -331,7 +331,9 @@ var init_async_command = __esm({
|
|
|
331
331
|
import React12 from "react";
|
|
332
332
|
import { render } from "ink";
|
|
333
333
|
import { EventEmitter as EventEmitter3 } from "events";
|
|
334
|
-
import
|
|
334
|
+
import fs16 from "fs";
|
|
335
|
+
import path20 from "path";
|
|
336
|
+
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
335
337
|
import { v4 as uuidv46 } from "uuid";
|
|
336
338
|
|
|
337
339
|
// src/app/ui/App.tsx
|
|
@@ -339,8 +341,9 @@ import { useState as useState6, useEffect as useEffect7, useRef as useRef5, useC
|
|
|
339
341
|
import { Box as Box20, Text as Text19, Static } from "ink";
|
|
340
342
|
|
|
341
343
|
// src/app/ui/layout.tsx
|
|
342
|
-
import { Box, Text } from "ink";
|
|
344
|
+
import { Box, Text, useStdout } from "ink";
|
|
343
345
|
import { memo } from "react";
|
|
346
|
+
import os from "os";
|
|
344
347
|
|
|
345
348
|
// src/app/ui/theme/blumaTerminal.ts
|
|
346
349
|
var BLUMA_TERMINAL = {
|
|
@@ -375,24 +378,106 @@ var BLUMA_TERMINAL = {
|
|
|
375
378
|
|
|
376
379
|
// src/app/ui/layout.tsx
|
|
377
380
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
381
|
+
function buildTopBorder(cols, leftW, rightW, titleInLeft) {
|
|
382
|
+
const t = titleInLeft.length <= leftW ? titleInLeft : titleInLeft.slice(0, leftW);
|
|
383
|
+
const leftFill = t + "\u2500".repeat(Math.max(0, leftW - t.length));
|
|
384
|
+
const rightFill = "\u2500".repeat(rightW);
|
|
385
|
+
return "\u250C" + leftFill + "\u252C" + rightFill + "\u2510";
|
|
386
|
+
}
|
|
387
|
+
function buildBottomBorder(leftW, rightW) {
|
|
388
|
+
return "\u2514" + "\u2500".repeat(leftW) + "\u2534" + "\u2500".repeat(rightW) + "\u2518";
|
|
389
|
+
}
|
|
378
390
|
var HeaderComponent = ({
|
|
379
391
|
sessionId,
|
|
380
|
-
workdir
|
|
392
|
+
workdir,
|
|
393
|
+
cliVersion = "?",
|
|
394
|
+
recentActivitySummary
|
|
381
395
|
}) => {
|
|
382
|
-
const
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
396
|
+
const { stdout } = useStdout();
|
|
397
|
+
const cols = Math.max(52, stdout?.columns ?? 80);
|
|
398
|
+
let username = "there";
|
|
399
|
+
try {
|
|
400
|
+
username = os.userInfo().username || username;
|
|
401
|
+
} catch {
|
|
402
|
+
}
|
|
403
|
+
const inner = cols - 3;
|
|
404
|
+
const leftW = Math.max(24, Math.floor(inner * 0.48));
|
|
405
|
+
const rightW = Math.max(22, inner - leftW);
|
|
406
|
+
const borderTitle = ` BluMa v${cliVersion} `;
|
|
407
|
+
const topLine = buildTopBorder(cols, leftW, rightW, borderTitle);
|
|
408
|
+
const bottomLine = buildBottomBorder(leftW, rightW);
|
|
409
|
+
const M = BLUMA_TERMINAL.brandMagenta;
|
|
410
|
+
const B = BLUMA_TERMINAL.panelBorder;
|
|
411
|
+
const ruleW = Math.max(6, rightW - 2);
|
|
412
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, width: cols, children: [
|
|
413
|
+
/* @__PURE__ */ jsx(Text, { color: B, children: topLine }),
|
|
414
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", width: cols, children: [
|
|
415
|
+
/* @__PURE__ */ jsx(Text, { color: B, children: "\u2502" }),
|
|
416
|
+
/* @__PURE__ */ jsxs(
|
|
417
|
+
Box,
|
|
418
|
+
{
|
|
419
|
+
width: leftW,
|
|
420
|
+
flexDirection: "column",
|
|
421
|
+
alignItems: "center",
|
|
422
|
+
paddingX: 1,
|
|
423
|
+
children: [
|
|
424
|
+
/* @__PURE__ */ jsxs(Text, { wrap: "wrap", children: [
|
|
425
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: M, children: "BluMa" }),
|
|
426
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " \u2014 " }),
|
|
427
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: B, children: "Base Language Unit" }),
|
|
428
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " \xB7 " }),
|
|
429
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: M, children: "Model Agent" })
|
|
430
|
+
] }),
|
|
431
|
+
/* @__PURE__ */ jsx(Box, { marginTop: 1, flexDirection: "column", alignItems: "center", children: /* @__PURE__ */ jsxs(Text, { children: [
|
|
432
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Welcome back " }),
|
|
433
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "white", children: username }),
|
|
434
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "!" })
|
|
435
|
+
] }) }),
|
|
436
|
+
/* @__PURE__ */ jsxs(Box, { marginY: 1, flexDirection: "column", alignItems: "center", children: [
|
|
437
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2500".repeat(Math.min(13, Math.max(7, leftW - 6))) }),
|
|
438
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: M, children: " \u27E8 \u03BB \u27E9 " }),
|
|
439
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2500".repeat(Math.min(13, Math.max(7, leftW - 6))) })
|
|
440
|
+
] }),
|
|
441
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", alignSelf: "flex-start", width: leftW - 2, children: [
|
|
442
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, wrap: "wrap", children: [
|
|
443
|
+
/* @__PURE__ */ jsx(Text, { color: "white", children: "auto" }),
|
|
444
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " \xB7 FactorRouter \xB7 session " }),
|
|
445
|
+
/* @__PURE__ */ jsx(Text, { color: B, children: sessionId.slice(0, 8) })
|
|
446
|
+
] }),
|
|
447
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, wrap: "wrap", children: workdir })
|
|
448
|
+
] })
|
|
449
|
+
]
|
|
450
|
+
}
|
|
451
|
+
),
|
|
452
|
+
/* @__PURE__ */ jsx(Text, { color: B, children: "\u2502" }),
|
|
453
|
+
/* @__PURE__ */ jsxs(Box, { width: rightW, flexDirection: "column", paddingX: 1, children: [
|
|
454
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: M, children: "Tips for getting started" }),
|
|
455
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, wrap: "wrap", children: [
|
|
456
|
+
"Run ",
|
|
457
|
+
/* @__PURE__ */ jsx(Text, { color: "white", children: "/init" }),
|
|
458
|
+
" to scaffold project context (BluMa.md). Use",
|
|
459
|
+
" ",
|
|
460
|
+
/* @__PURE__ */ jsx(Text, { color: "white", children: "/help" }),
|
|
461
|
+
", ",
|
|
462
|
+
/* @__PURE__ */ jsx(Text, { color: "white", children: "/img" }),
|
|
463
|
+
", ",
|
|
464
|
+
/* @__PURE__ */ jsx(Text, { color: "white", children: "!" }),
|
|
465
|
+
" ",
|
|
466
|
+
"as needed."
|
|
467
|
+
] }),
|
|
468
|
+
/* @__PURE__ */ jsx(Box, { marginY: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2500".repeat(ruleW) }) }),
|
|
469
|
+
/* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { bold: true, color: M, children: "Recent activity" }) }),
|
|
470
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, wrap: "wrap", children: recentActivitySummary?.trim() ? recentActivitySummary.trim() : "No recent activity." })
|
|
471
|
+
] }),
|
|
472
|
+
/* @__PURE__ */ jsx(Text, { color: B, children: "\u2502" })
|
|
390
473
|
] }),
|
|
391
|
-
/* @__PURE__ */
|
|
392
|
-
|
|
393
|
-
/* @__PURE__ */ jsx(Text, {
|
|
394
|
-
/* @__PURE__ */ jsx(Text, {
|
|
395
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children:
|
|
474
|
+
/* @__PURE__ */ jsx(Text, { color: B, children: bottomLine }),
|
|
475
|
+
/* @__PURE__ */ jsxs(Box, { marginTop: 1, children: [
|
|
476
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7 " }),
|
|
477
|
+
/* @__PURE__ */ jsx(Text, { color: B, bold: true, children: "NomadEngenuity" }),
|
|
478
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " \xB7 Factor stack \xB7 " }),
|
|
479
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: M, children: "/help" }),
|
|
480
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " for shortcuts" })
|
|
396
481
|
] })
|
|
397
482
|
] });
|
|
398
483
|
};
|
|
@@ -441,7 +526,7 @@ var TaskStatusBarComponent = ({
|
|
|
441
526
|
var TaskStatusBar = memo(TaskStatusBarComponent);
|
|
442
527
|
|
|
443
528
|
// src/app/ui/components/InputPrompt.tsx
|
|
444
|
-
import { Box as Box2, Text as Text2, useStdout, useInput as useInput2 } from "ink";
|
|
529
|
+
import { Box as Box2, Text as Text2, useStdout as useStdout2, useInput as useInput2 } from "ink";
|
|
445
530
|
|
|
446
531
|
// src/app/ui/utils/useSimpleInputBuffer.ts
|
|
447
532
|
import { useReducer, useRef, useCallback, useEffect } from "react";
|
|
@@ -742,12 +827,68 @@ import { EventEmitter as EventEmitter2 } from "events";
|
|
|
742
827
|
|
|
743
828
|
// src/app/ui/utils/slashRegistry.ts
|
|
744
829
|
var getSlashCommands = () => [
|
|
745
|
-
{
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
830
|
+
{
|
|
831
|
+
name: "/help",
|
|
832
|
+
description: "list all slash commands (grouped)",
|
|
833
|
+
category: "help"
|
|
834
|
+
},
|
|
835
|
+
{
|
|
836
|
+
name: "/clear",
|
|
837
|
+
description: "clear chat below the welcome panel (welcome + session file unchanged)",
|
|
838
|
+
category: "session"
|
|
839
|
+
},
|
|
840
|
+
{
|
|
841
|
+
name: "/img",
|
|
842
|
+
description: "send local image(s) to the model: /img ./shot.png [your question]",
|
|
843
|
+
category: "agent"
|
|
844
|
+
},
|
|
845
|
+
{
|
|
846
|
+
name: "/image",
|
|
847
|
+
description: "alias of /img",
|
|
848
|
+
category: "agent"
|
|
849
|
+
},
|
|
850
|
+
{
|
|
851
|
+
name: "/skills",
|
|
852
|
+
description: "list load_skill modules (bundled + project + ~/.bluma)",
|
|
853
|
+
category: "inspect"
|
|
854
|
+
},
|
|
855
|
+
{
|
|
856
|
+
name: "/tools",
|
|
857
|
+
description: "list native tools (optional filter: /tools grep)",
|
|
858
|
+
category: "inspect"
|
|
859
|
+
},
|
|
860
|
+
{
|
|
861
|
+
name: "/mcp",
|
|
862
|
+
description: "list MCP tools (optional filter: /mcp fs)",
|
|
863
|
+
category: "inspect"
|
|
864
|
+
},
|
|
865
|
+
{
|
|
866
|
+
name: "/init",
|
|
867
|
+
description: "run init subagent \u2014 BluMa.md codebase documentation",
|
|
868
|
+
category: "agent"
|
|
869
|
+
}
|
|
750
870
|
];
|
|
871
|
+
var CATEGORY_LABEL = {
|
|
872
|
+
session: "Session & UI",
|
|
873
|
+
inspect: "Inspect",
|
|
874
|
+
agent: "Agent",
|
|
875
|
+
help: "Help"
|
|
876
|
+
};
|
|
877
|
+
function formatSlashHelpLines() {
|
|
878
|
+
const cmds = getSlashCommands();
|
|
879
|
+
const byCat = (cat) => cmds.filter((c) => c.category === cat);
|
|
880
|
+
const lines = [];
|
|
881
|
+
for (const cat of ["help", "session", "agent", "inspect"]) {
|
|
882
|
+
const group = byCat(cat);
|
|
883
|
+
if (group.length === 0) continue;
|
|
884
|
+
lines.push(`${CATEGORY_LABEL[cat]}:`);
|
|
885
|
+
for (const c of group) {
|
|
886
|
+
lines.push(` ${c.name.padEnd(14)} ${c.description}`);
|
|
887
|
+
}
|
|
888
|
+
lines.push("");
|
|
889
|
+
}
|
|
890
|
+
return lines;
|
|
891
|
+
}
|
|
751
892
|
var filterSlashCommands = (query) => {
|
|
752
893
|
const list = getSlashCommands();
|
|
753
894
|
const q = (query || "").toLowerCase();
|
|
@@ -1006,7 +1147,9 @@ var SlashSuggestions = memo2(({
|
|
|
1006
1147
|
s.name,
|
|
1007
1148
|
" ",
|
|
1008
1149
|
/* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
|
|
1009
|
-
"
|
|
1150
|
+
"[",
|
|
1151
|
+
s.category,
|
|
1152
|
+
"] ",
|
|
1010
1153
|
s.description
|
|
1011
1154
|
] })
|
|
1012
1155
|
] })
|
|
@@ -1014,13 +1157,13 @@ var SlashSuggestions = memo2(({
|
|
|
1014
1157
|
}) }));
|
|
1015
1158
|
SlashSuggestions.displayName = "SlashSuggestions";
|
|
1016
1159
|
var InputRuleLine = memo2(() => {
|
|
1017
|
-
const { stdout } =
|
|
1160
|
+
const { stdout } = useStdout2();
|
|
1018
1161
|
const cols = stdout?.columns ?? 80;
|
|
1019
1162
|
const n = Math.max(8, cols);
|
|
1020
1163
|
return /* @__PURE__ */ jsx2(Text2, { color: "white", children: TERMINAL_RULE_CHAR.repeat(n) });
|
|
1021
1164
|
});
|
|
1022
1165
|
InputRuleLine.displayName = "InputRuleLine";
|
|
1023
|
-
var Footer = memo2(({ isReadOnly }) => /* @__PURE__ */ jsx2(Box2, { justifyContent: "center", children: /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: isReadOnly ? "ctrl+c to exit | Enter to send message | Shift+Enter for new line | esc interrupt | Ctrl+O expand last clip" : "ctrl+c to exit | Enter to submit | Shift+Enter for new line | /help
|
|
1166
|
+
var Footer = memo2(({ isReadOnly }) => /* @__PURE__ */ jsx2(Box2, { justifyContent: "center", children: /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: isReadOnly ? "ctrl+c to exit | Enter to send message | Shift+Enter for new line | esc interrupt | Ctrl+O expand last clip" : "ctrl+c to exit | Enter to submit | Shift+Enter for new line | ? /help \xB7 /img \xB7 esc \xB7 Ctrl+O expand" }) }));
|
|
1024
1167
|
Footer.displayName = "Footer";
|
|
1025
1168
|
var TextLinesRenderer = memo2(({
|
|
1026
1169
|
lines,
|
|
@@ -1058,7 +1201,7 @@ var InputPrompt = memo2(({
|
|
|
1058
1201
|
onInterrupt,
|
|
1059
1202
|
disableWhileProcessing = false
|
|
1060
1203
|
}) => {
|
|
1061
|
-
const { stdout } =
|
|
1204
|
+
const { stdout } = useStdout2();
|
|
1062
1205
|
const [viewWidth] = useState2(() => stdout.columns - 6);
|
|
1063
1206
|
const [slashOpen, setSlashOpen] = useState2(false);
|
|
1064
1207
|
const [slashIndex, setSlashIndex] = useState2(0);
|
|
@@ -1583,8 +1726,8 @@ var ConfirmationPrompt = memo4(ConfirmationPromptComponent);
|
|
|
1583
1726
|
|
|
1584
1727
|
// src/app/agent/agent.ts
|
|
1585
1728
|
import * as dotenv from "dotenv";
|
|
1586
|
-
import
|
|
1587
|
-
import
|
|
1729
|
+
import path18 from "path";
|
|
1730
|
+
import os13 from "os";
|
|
1588
1731
|
|
|
1589
1732
|
// src/app/agent/tool_invoker.ts
|
|
1590
1733
|
import { promises as fs9 } from "fs";
|
|
@@ -1593,7 +1736,7 @@ import { fileURLToPath } from "url";
|
|
|
1593
1736
|
|
|
1594
1737
|
// src/app/agent/tools/natives/edit.ts
|
|
1595
1738
|
import path3 from "path";
|
|
1596
|
-
import
|
|
1739
|
+
import os2 from "os";
|
|
1597
1740
|
import { promises as fs2 } from "fs";
|
|
1598
1741
|
import { diffLines } from "diff";
|
|
1599
1742
|
var MAX_DIFF_SIZE = 5e4;
|
|
@@ -1601,7 +1744,7 @@ var MAX_FILE_SIZE = 10 * 1024 * 1024;
|
|
|
1601
1744
|
function normalizePath(filePath) {
|
|
1602
1745
|
try {
|
|
1603
1746
|
filePath = filePath.trim();
|
|
1604
|
-
if (
|
|
1747
|
+
if (os2.platform() === "win32") {
|
|
1605
1748
|
const winDriveRegex = /^\/([a-zA-Z])[:/]/;
|
|
1606
1749
|
const match = filePath.match(winDriveRegex);
|
|
1607
1750
|
if (match) {
|
|
@@ -3028,12 +3171,12 @@ init_async_command();
|
|
|
3028
3171
|
// src/app/agent/tools/natives/task_boundary.ts
|
|
3029
3172
|
import path9 from "path";
|
|
3030
3173
|
import { promises as fs7 } from "fs";
|
|
3031
|
-
import
|
|
3174
|
+
import os4 from "os";
|
|
3032
3175
|
var currentTask = null;
|
|
3033
3176
|
var artifactsDir = null;
|
|
3034
3177
|
async function getArtifactsDir() {
|
|
3035
3178
|
if (artifactsDir) return artifactsDir;
|
|
3036
|
-
const homeDir =
|
|
3179
|
+
const homeDir = os4.homedir();
|
|
3037
3180
|
const baseDir = path9.join(homeDir, ".bluma", "artifacts");
|
|
3038
3181
|
const sessionId = Date.now().toString(36) + Math.random().toString(36).substr(2, 5);
|
|
3039
3182
|
artifactsDir = path9.join(baseDir, sessionId);
|
|
@@ -3526,7 +3669,7 @@ ${skill.content}`;
|
|
|
3526
3669
|
// src/app/agent/tools/natives/coding_memory.ts
|
|
3527
3670
|
import * as fs8 from "fs";
|
|
3528
3671
|
import * as path10 from "path";
|
|
3529
|
-
import
|
|
3672
|
+
import os5 from "os";
|
|
3530
3673
|
var PROMPT_DEFAULT_MAX_TOTAL = 1e4;
|
|
3531
3674
|
var PROMPT_DEFAULT_MAX_NOTES = 25;
|
|
3532
3675
|
var PROMPT_DEFAULT_PREVIEW = 500;
|
|
@@ -3534,7 +3677,7 @@ function readCodingMemoryForPrompt(options) {
|
|
|
3534
3677
|
const maxTotal = options?.maxTotalChars ?? PROMPT_DEFAULT_MAX_TOTAL;
|
|
3535
3678
|
const maxNotes = options?.maxNotes ?? PROMPT_DEFAULT_MAX_NOTES;
|
|
3536
3679
|
const preview = options?.previewCharsPerNote ?? PROMPT_DEFAULT_PREVIEW;
|
|
3537
|
-
const globalPath = path10.join(
|
|
3680
|
+
const globalPath = path10.join(os5.homedir(), ".bluma", "coding_memory.json");
|
|
3538
3681
|
const legacyPath = path10.join(process.cwd(), ".bluma", "coding_memory.json");
|
|
3539
3682
|
let raw = null;
|
|
3540
3683
|
try {
|
|
@@ -3579,7 +3722,7 @@ var memoryStore = [];
|
|
|
3579
3722
|
var nextId2 = 1;
|
|
3580
3723
|
var loaded = false;
|
|
3581
3724
|
function getMemoryFilePath() {
|
|
3582
|
-
return path10.join(
|
|
3725
|
+
return path10.join(os5.homedir(), ".bluma", "coding_memory.json");
|
|
3583
3726
|
}
|
|
3584
3727
|
function getLegacyMemoryFilePath() {
|
|
3585
3728
|
return path10.join(process.cwd(), ".bluma", "coding_memory.json");
|
|
@@ -3889,7 +4032,7 @@ var ToolInvoker = class {
|
|
|
3889
4032
|
// src/app/agent/tools/mcp/mcp_client.ts
|
|
3890
4033
|
import { promises as fs10 } from "fs";
|
|
3891
4034
|
import path12 from "path";
|
|
3892
|
-
import
|
|
4035
|
+
import os6 from "os";
|
|
3893
4036
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
3894
4037
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
3895
4038
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
@@ -3918,7 +4061,7 @@ var MCPClient = class {
|
|
|
3918
4061
|
const __filename = fileURLToPath2(import.meta.url);
|
|
3919
4062
|
const __dirname2 = path12.dirname(__filename);
|
|
3920
4063
|
const defaultConfigPath = path12.resolve(__dirname2, "config", "bluma-mcp.json");
|
|
3921
|
-
const userConfigPath = path12.join(
|
|
4064
|
+
const userConfigPath = path12.join(os6.homedir(), ".bluma", "bluma-mcp.json");
|
|
3922
4065
|
const defaultConfig = await this.loadMcpConfig(defaultConfigPath, "Default");
|
|
3923
4066
|
const userConfig = await this.loadMcpConfig(userConfigPath, "User");
|
|
3924
4067
|
const mergedConfig = {
|
|
@@ -3971,7 +4114,7 @@ var MCPClient = class {
|
|
|
3971
4114
|
async connectToStdioServer(serverName, config2) {
|
|
3972
4115
|
let commandToExecute = config2.command;
|
|
3973
4116
|
let argsToExecute = config2.args || [];
|
|
3974
|
-
const isWindows =
|
|
4117
|
+
const isWindows = os6.platform() === "win32";
|
|
3975
4118
|
if (!isWindows && commandToExecute.toLowerCase() === "cmd") {
|
|
3976
4119
|
if (argsToExecute.length >= 2 && argsToExecute[0].toLowerCase() === "/c") {
|
|
3977
4120
|
commandToExecute = argsToExecute[1];
|
|
@@ -4087,12 +4230,12 @@ var AdvancedFeedbackSystem = class {
|
|
|
4087
4230
|
};
|
|
4088
4231
|
|
|
4089
4232
|
// src/app/agent/bluma/core/bluma.ts
|
|
4090
|
-
import
|
|
4233
|
+
import path17 from "path";
|
|
4091
4234
|
import { v4 as uuidv43 } from "uuid";
|
|
4092
4235
|
|
|
4093
4236
|
// src/app/agent/session_manager/session_manager.ts
|
|
4094
4237
|
import path13 from "path";
|
|
4095
|
-
import
|
|
4238
|
+
import os7 from "os";
|
|
4096
4239
|
import { promises as fs11 } from "fs";
|
|
4097
4240
|
var fileLocks = /* @__PURE__ */ new Map();
|
|
4098
4241
|
async function withFileLock(file, fn) {
|
|
@@ -4129,12 +4272,12 @@ function debouncedSave(sessionFile, history, memory) {
|
|
|
4129
4272
|
function expandHome(p) {
|
|
4130
4273
|
if (!p) return p;
|
|
4131
4274
|
if (p.startsWith("~")) {
|
|
4132
|
-
return path13.join(
|
|
4275
|
+
return path13.join(os7.homedir(), p.slice(1));
|
|
4133
4276
|
}
|
|
4134
4277
|
return p;
|
|
4135
4278
|
}
|
|
4136
4279
|
function getPreferredAppDir() {
|
|
4137
|
-
const fixed = path13.join(
|
|
4280
|
+
const fixed = path13.join(os7.homedir(), ".bluma");
|
|
4138
4281
|
return path13.resolve(expandHome(fixed));
|
|
4139
4282
|
}
|
|
4140
4283
|
async function safeRenameWithRetry(src, dest, maxRetries = 6) {
|
|
@@ -4277,7 +4420,7 @@ async function saveSessionHistory(sessionFile, history, memory) {
|
|
|
4277
4420
|
}
|
|
4278
4421
|
|
|
4279
4422
|
// src/app/agent/core/prompt/prompt_builder.ts
|
|
4280
|
-
import
|
|
4423
|
+
import os9 from "os";
|
|
4281
4424
|
import fs13 from "fs";
|
|
4282
4425
|
import path15 from "path";
|
|
4283
4426
|
import { execSync } from "child_process";
|
|
@@ -4285,7 +4428,7 @@ import { execSync } from "child_process";
|
|
|
4285
4428
|
// src/app/agent/skills/skill_loader.ts
|
|
4286
4429
|
import fs12 from "fs";
|
|
4287
4430
|
import path14 from "path";
|
|
4288
|
-
import
|
|
4431
|
+
import os8 from "os";
|
|
4289
4432
|
var SkillLoader = class _SkillLoader {
|
|
4290
4433
|
bundledSkillsDir;
|
|
4291
4434
|
projectSkillsDir;
|
|
@@ -4294,7 +4437,7 @@ var SkillLoader = class _SkillLoader {
|
|
|
4294
4437
|
conflicts = [];
|
|
4295
4438
|
constructor(projectRoot, bundledDir) {
|
|
4296
4439
|
this.projectSkillsDir = path14.join(projectRoot, ".bluma", "skills");
|
|
4297
|
-
this.globalSkillsDir = path14.join(
|
|
4440
|
+
this.globalSkillsDir = path14.join(os8.homedir(), ".bluma", "skills");
|
|
4298
4441
|
this.bundledSkillsDir = bundledDir || _SkillLoader.resolveBundledDir();
|
|
4299
4442
|
}
|
|
4300
4443
|
/**
|
|
@@ -4305,10 +4448,19 @@ var SkillLoader = class _SkillLoader {
|
|
|
4305
4448
|
if (process.env.JEST_WORKER_ID !== void 0 || process.env.NODE_ENV === "test") {
|
|
4306
4449
|
return path14.join(process.cwd(), "dist", "config", "skills");
|
|
4307
4450
|
}
|
|
4308
|
-
const candidates = [
|
|
4451
|
+
const candidates = [];
|
|
4452
|
+
const argv1 = process.argv[1];
|
|
4453
|
+
if (argv1 && !argv1.startsWith("-")) {
|
|
4454
|
+
try {
|
|
4455
|
+
const scriptDir = path14.dirname(path14.resolve(argv1));
|
|
4456
|
+
candidates.push(path14.join(scriptDir, "config", "skills"));
|
|
4457
|
+
} catch {
|
|
4458
|
+
}
|
|
4459
|
+
}
|
|
4460
|
+
candidates.push(
|
|
4309
4461
|
path14.join(process.cwd(), "dist", "config", "skills"),
|
|
4310
4462
|
path14.join(process.cwd(), "node_modules", "@nomad-e", "bluma-cli", "dist", "config", "skills")
|
|
4311
|
-
|
|
4463
|
+
);
|
|
4312
4464
|
if (typeof __dirname !== "undefined") {
|
|
4313
4465
|
candidates.push(
|
|
4314
4466
|
path14.join(__dirname, "config", "skills"),
|
|
@@ -4695,6 +4847,10 @@ var SYSTEM_PROMPT = `
|
|
|
4695
4847
|
- NEVER try to \`load_skill\` with a name that isn't in \`<available_skills>\`
|
|
4696
4848
|
- Your base knowledge (testing, git, docker...) is NOT a skill - it's just knowledge you have
|
|
4697
4849
|
|
|
4850
|
+
**Git / commits (when \`git-commit\` is listed in \`<available_skills>\`):**
|
|
4851
|
+
- For "commit", "push", "commit message", or "conventional commit": call \`load_skill({ skill_name: "git-commit" })\` **before** \`git commit\`, then follow the skill body (scopes, types, optional validator script).
|
|
4852
|
+
- The bundled skill name is exactly \`git-commit\`. Do **not** use \`git-conventional\` or other invented names.
|
|
4853
|
+
|
|
4698
4854
|
**Progressive Disclosure (Skills with references and scripts):**
|
|
4699
4855
|
|
|
4700
4856
|
Skills may include additional assets beyond the SKILL.md body:
|
|
@@ -5108,12 +5264,12 @@ In sandbox mode you are a Python-focused, non-interactive, deterministic agent t
|
|
|
5108
5264
|
function getUnifiedSystemPrompt(availableSkills) {
|
|
5109
5265
|
const cwd = process.cwd();
|
|
5110
5266
|
const env = {
|
|
5111
|
-
os_type:
|
|
5112
|
-
os_version:
|
|
5113
|
-
architecture:
|
|
5267
|
+
os_type: os9.type(),
|
|
5268
|
+
os_version: os9.release(),
|
|
5269
|
+
architecture: os9.arch(),
|
|
5114
5270
|
workdir: cwd,
|
|
5115
5271
|
shell_type: process.env.SHELL || process.env.COMSPEC || "unknown",
|
|
5116
|
-
username:
|
|
5272
|
+
username: os9.userInfo().username,
|
|
5117
5273
|
current_date: (/* @__PURE__ */ new Date()).toISOString().split("T")[0],
|
|
5118
5274
|
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
5119
5275
|
is_git_repo: isGitRepo(cwd) ? "yes" : "no",
|
|
@@ -5218,7 +5374,7 @@ tools:
|
|
|
5218
5374
|
|
|
5219
5375
|
2. READ FRONTMATTER FIRST
|
|
5220
5376
|
- name: npm-publish
|
|
5221
|
-
- depends_on: [git-
|
|
5377
|
+
- depends_on: [git-commit]
|
|
5222
5378
|
- tools.required: [shell_command, command_status]
|
|
5223
5379
|
- tools.recommended: [read_file_lines, message]
|
|
5224
5380
|
|
|
@@ -5255,17 +5411,17 @@ User: "Publish the package"
|
|
|
5255
5411
|
2. load_skill({ skill_name: "npm-publish" })
|
|
5256
5412
|
|
|
5257
5413
|
3. Read frontmatter:
|
|
5258
|
-
- depends_on: [git-
|
|
5414
|
+
- depends_on: [git-commit]
|
|
5259
5415
|
- tools.required: [shell_command, command_status]
|
|
5260
5416
|
|
|
5261
5417
|
4. Read body -> Workflow says:
|
|
5262
|
-
"Step 1: If uncommitted changes, delegate to git-
|
|
5418
|
+
"Step 1: If uncommitted changes, delegate to git-commit"
|
|
5263
5419
|
|
|
5264
5420
|
5. Check git status with shell_command (required tool)
|
|
5265
5421
|
Found changes
|
|
5266
5422
|
|
|
5267
|
-
6. Delegate: load_skill({ skill_name: "git-
|
|
5268
|
-
- Read git-
|
|
5423
|
+
6. Delegate: load_skill({ skill_name: "git-commit" })
|
|
5424
|
+
- Read git-commit frontmatter
|
|
5269
5425
|
- Follow its workflow for commit
|
|
5270
5426
|
- Commit done
|
|
5271
5427
|
|
|
@@ -5579,7 +5735,7 @@ async function createApiContextWindow(fullHistory, currentAnchor, compressedTurn
|
|
|
5579
5735
|
}
|
|
5580
5736
|
|
|
5581
5737
|
// src/app/agent/core/llm/llm.ts
|
|
5582
|
-
import
|
|
5738
|
+
import os10 from "os";
|
|
5583
5739
|
import OpenAI from "openai";
|
|
5584
5740
|
function defaultBlumaUserContextInput(sessionId, userMessage) {
|
|
5585
5741
|
const msg = String(userMessage || "").slice(0, 300);
|
|
@@ -5596,7 +5752,7 @@ function defaultBlumaUserContextInput(sessionId, userMessage) {
|
|
|
5596
5752
|
}
|
|
5597
5753
|
function getPreferredMacAddress() {
|
|
5598
5754
|
try {
|
|
5599
|
-
const ifaces =
|
|
5755
|
+
const ifaces = os10.networkInterfaces();
|
|
5600
5756
|
for (const name of Object.keys(ifaces)) {
|
|
5601
5757
|
const addrs = ifaces[name];
|
|
5602
5758
|
if (!addrs) continue;
|
|
@@ -5611,7 +5767,7 @@ function getPreferredMacAddress() {
|
|
|
5611
5767
|
} catch {
|
|
5612
5768
|
}
|
|
5613
5769
|
try {
|
|
5614
|
-
return `host:${
|
|
5770
|
+
return `host:${os10.hostname()}`;
|
|
5615
5771
|
} catch {
|
|
5616
5772
|
return "unknown";
|
|
5617
5773
|
}
|
|
@@ -5621,7 +5777,7 @@ function defaultInteractiveCliUserContextInput(sessionId, userMessage) {
|
|
|
5621
5777
|
const machineId = getPreferredMacAddress();
|
|
5622
5778
|
let userName = null;
|
|
5623
5779
|
try {
|
|
5624
|
-
userName =
|
|
5780
|
+
userName = os10.userInfo().username || null;
|
|
5625
5781
|
} catch {
|
|
5626
5782
|
userName = null;
|
|
5627
5783
|
}
|
|
@@ -5948,6 +6104,134 @@ var ToolCallNormalizer = class {
|
|
|
5948
6104
|
}
|
|
5949
6105
|
};
|
|
5950
6106
|
|
|
6107
|
+
// src/app/agent/utils/user_message_images.ts
|
|
6108
|
+
import fs14 from "fs";
|
|
6109
|
+
import os11 from "os";
|
|
6110
|
+
import path16 from "path";
|
|
6111
|
+
var IMAGE_EXT = /\.(png|jpe?g|gif|webp|bmp)$/i;
|
|
6112
|
+
var MAX_IMAGE_BYTES = 4 * 1024 * 1024;
|
|
6113
|
+
var MAX_IMAGES = 6;
|
|
6114
|
+
var MIME = {
|
|
6115
|
+
".png": "image/png",
|
|
6116
|
+
".jpg": "image/jpeg",
|
|
6117
|
+
".jpeg": "image/jpeg",
|
|
6118
|
+
".gif": "image/gif",
|
|
6119
|
+
".webp": "image/webp",
|
|
6120
|
+
".bmp": "image/bmp"
|
|
6121
|
+
};
|
|
6122
|
+
function expandUserPath(p) {
|
|
6123
|
+
const t = p.trim();
|
|
6124
|
+
if (t.startsWith("~")) {
|
|
6125
|
+
return path16.join(os11.homedir(), t.slice(1).replace(/^\//, ""));
|
|
6126
|
+
}
|
|
6127
|
+
return t;
|
|
6128
|
+
}
|
|
6129
|
+
function isPathAllowed(absResolved, cwd) {
|
|
6130
|
+
const resolved = path16.normalize(path16.resolve(absResolved));
|
|
6131
|
+
const cwdR = path16.normalize(path16.resolve(cwd));
|
|
6132
|
+
const homeR = path16.normalize(path16.resolve(os11.homedir()));
|
|
6133
|
+
const underCwd = resolved === cwdR || resolved.startsWith(cwdR + path16.sep);
|
|
6134
|
+
const underHome = resolved === homeR || resolved.startsWith(homeR + path16.sep);
|
|
6135
|
+
return underCwd || underHome;
|
|
6136
|
+
}
|
|
6137
|
+
function mimeFor(abs) {
|
|
6138
|
+
const ext = path16.extname(abs).toLowerCase();
|
|
6139
|
+
return MIME[ext] || "application/octet-stream";
|
|
6140
|
+
}
|
|
6141
|
+
function collectImagePathStrings(raw) {
|
|
6142
|
+
const found = [];
|
|
6143
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6144
|
+
const quoted = /(["'])((?:(?!\1).)*?\.(?:png|jpe?g|gif|webp|bmp))\1/gi;
|
|
6145
|
+
for (const m of raw.matchAll(quoted)) {
|
|
6146
|
+
const p = m[2].trim();
|
|
6147
|
+
if (p && !seen.has(p)) {
|
|
6148
|
+
seen.add(p);
|
|
6149
|
+
found.push(p);
|
|
6150
|
+
}
|
|
6151
|
+
}
|
|
6152
|
+
const withoutQuoted = raw.replace(quoted, " ");
|
|
6153
|
+
const tokens = withoutQuoted.split(/\s+/);
|
|
6154
|
+
for (let tok of tokens) {
|
|
6155
|
+
tok = tok.replace(/^[([{]+/, "").replace(/[)\]},;:]+$/, "");
|
|
6156
|
+
if (!tok || !IMAGE_EXT.test(tok)) continue;
|
|
6157
|
+
if (!seen.has(tok)) {
|
|
6158
|
+
seen.add(tok);
|
|
6159
|
+
found.push(tok);
|
|
6160
|
+
}
|
|
6161
|
+
}
|
|
6162
|
+
return found;
|
|
6163
|
+
}
|
|
6164
|
+
function resolveImagePath(candidate, cwd) {
|
|
6165
|
+
const expanded = expandUserPath(candidate);
|
|
6166
|
+
const abs = path16.isAbsolute(expanded) ? path16.normalize(expanded) : path16.normalize(path16.resolve(cwd, expanded));
|
|
6167
|
+
if (!isPathAllowed(abs, cwd)) return null;
|
|
6168
|
+
try {
|
|
6169
|
+
if (!fs14.existsSync(abs) || !fs14.statSync(abs).isFile()) return null;
|
|
6170
|
+
} catch {
|
|
6171
|
+
return null;
|
|
6172
|
+
}
|
|
6173
|
+
if (!IMAGE_EXT.test(abs)) return null;
|
|
6174
|
+
return abs;
|
|
6175
|
+
}
|
|
6176
|
+
function stripImagePathStrings(text, paths) {
|
|
6177
|
+
let out = text;
|
|
6178
|
+
for (const p of paths) {
|
|
6179
|
+
const q = p.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
6180
|
+
out = out.replace(new RegExp(`["']${q}["']`, "gi"), " ");
|
|
6181
|
+
out = out.replace(new RegExp(`(?<=^|\\s)${q}(?=\\s|$)`, "gi"), " ");
|
|
6182
|
+
}
|
|
6183
|
+
return out.replace(/\s{2,}/g, " ").trim();
|
|
6184
|
+
}
|
|
6185
|
+
function buildUserMessageContent(raw, cwd) {
|
|
6186
|
+
const trimmed = raw.trim();
|
|
6187
|
+
if (!trimmed) return trimmed;
|
|
6188
|
+
const candidates = collectImagePathStrings(trimmed);
|
|
6189
|
+
const resolvedAbs = [];
|
|
6190
|
+
const usedStrings = [];
|
|
6191
|
+
for (const c of candidates) {
|
|
6192
|
+
if (resolvedAbs.length >= MAX_IMAGES) break;
|
|
6193
|
+
const abs = resolveImagePath(c, cwd);
|
|
6194
|
+
if (!abs) continue;
|
|
6195
|
+
try {
|
|
6196
|
+
const st = fs14.statSync(abs);
|
|
6197
|
+
if (st.size > MAX_IMAGE_BYTES) continue;
|
|
6198
|
+
} catch {
|
|
6199
|
+
continue;
|
|
6200
|
+
}
|
|
6201
|
+
resolvedAbs.push(abs);
|
|
6202
|
+
usedStrings.push(c);
|
|
6203
|
+
}
|
|
6204
|
+
if (resolvedAbs.length === 0) {
|
|
6205
|
+
return trimmed;
|
|
6206
|
+
}
|
|
6207
|
+
let textPart = stripImagePathStrings(trimmed, usedStrings);
|
|
6208
|
+
if (!textPart) {
|
|
6209
|
+
textPart = "(User attached image(s) only \u2014 describe, compare, or answer using the image(s).)";
|
|
6210
|
+
}
|
|
6211
|
+
const note = resolvedAbs.map((p) => path16.basename(p)).join(", ");
|
|
6212
|
+
const parts = [
|
|
6213
|
+
{
|
|
6214
|
+
type: "text",
|
|
6215
|
+
text: `${textPart}
|
|
6216
|
+
|
|
6217
|
+
[Attached local image file(s): ${note}]`
|
|
6218
|
+
}
|
|
6219
|
+
];
|
|
6220
|
+
for (const abs of resolvedAbs) {
|
|
6221
|
+
const buf = fs14.readFileSync(abs);
|
|
6222
|
+
const b64 = buf.toString("base64");
|
|
6223
|
+
const mime = mimeFor(abs);
|
|
6224
|
+
parts.push({
|
|
6225
|
+
type: "image_url",
|
|
6226
|
+
image_url: {
|
|
6227
|
+
url: `data:${mime};base64,${b64}`,
|
|
6228
|
+
detail: "auto"
|
|
6229
|
+
}
|
|
6230
|
+
});
|
|
6231
|
+
}
|
|
6232
|
+
return parts;
|
|
6233
|
+
}
|
|
6234
|
+
|
|
5951
6235
|
// src/app/agent/bluma/core/bluma.ts
|
|
5952
6236
|
var BluMaAgent = class {
|
|
5953
6237
|
llm;
|
|
@@ -6020,29 +6304,38 @@ var BluMaAgent = class {
|
|
|
6020
6304
|
history: this.history,
|
|
6021
6305
|
skillLoader: this.skillLoader
|
|
6022
6306
|
});
|
|
6023
|
-
|
|
6024
|
-
|
|
6025
|
-
|
|
6026
|
-
|
|
6027
|
-
|
|
6028
|
-
|
|
6029
|
-
|
|
6030
|
-
|
|
6031
|
-
|
|
6032
|
-
|
|
6033
|
-
|
|
6034
|
-
|
|
6035
|
-
|
|
6036
|
-
|
|
6037
|
-
|
|
6038
|
-
|
|
6039
|
-
});
|
|
6040
|
-
}
|
|
6307
|
+
const dirs = this.skillLoader.getSkillsDirs();
|
|
6308
|
+
this.eventBus.emit("backend_message", {
|
|
6309
|
+
type: "info",
|
|
6310
|
+
message: `Skills dirs \u2014 bundled: ${dirs.bundled} | project: ${dirs.project} | global: ${dirs.global}`
|
|
6311
|
+
});
|
|
6312
|
+
const availableSkills = this.skillLoader.listAvailable();
|
|
6313
|
+
this.eventBus.emit("backend_message", {
|
|
6314
|
+
type: "info",
|
|
6315
|
+
message: `Skills loaded: ${availableSkills.length} \u2014 ${availableSkills.map((s) => `${s.name} (${s.source})`).join(", ") || "none"}`
|
|
6316
|
+
});
|
|
6317
|
+
if (this.skillLoader.hasConflicts()) {
|
|
6318
|
+
for (const warning of this.skillLoader.formatConflictWarnings()) {
|
|
6319
|
+
this.eventBus.emit("backend_message", {
|
|
6320
|
+
type: "warning",
|
|
6321
|
+
message: warning
|
|
6322
|
+
});
|
|
6041
6323
|
}
|
|
6042
|
-
|
|
6324
|
+
}
|
|
6325
|
+
const systemPrompt = getUnifiedSystemPrompt(availableSkills);
|
|
6326
|
+
if (this.history.length === 0) {
|
|
6043
6327
|
this.history.push({ role: "system", content: systemPrompt });
|
|
6044
|
-
|
|
6328
|
+
} else {
|
|
6329
|
+
const sysIdx = this.history.findIndex(
|
|
6330
|
+
(m) => m.role === "system" && typeof m.content === "string" && String(m.content).includes("<identity>")
|
|
6331
|
+
);
|
|
6332
|
+
if (sysIdx >= 0) {
|
|
6333
|
+
this.history[sysIdx] = { ...this.history[sysIdx], content: systemPrompt };
|
|
6334
|
+
} else {
|
|
6335
|
+
this.history.unshift({ role: "system", content: systemPrompt });
|
|
6336
|
+
}
|
|
6045
6337
|
}
|
|
6338
|
+
this.persistSession();
|
|
6046
6339
|
}
|
|
6047
6340
|
getAvailableTools() {
|
|
6048
6341
|
return this.mcpClient.getAvailableTools();
|
|
@@ -6050,6 +6343,12 @@ var BluMaAgent = class {
|
|
|
6050
6343
|
getUiToolsDetailed() {
|
|
6051
6344
|
return this.mcpClient.getAvailableToolsDetailed();
|
|
6052
6345
|
}
|
|
6346
|
+
listAvailableSkills() {
|
|
6347
|
+
return this.skillLoader.listAvailable();
|
|
6348
|
+
}
|
|
6349
|
+
getSkillsDirs() {
|
|
6350
|
+
return this.skillLoader.getSkillsDirs();
|
|
6351
|
+
}
|
|
6053
6352
|
async processTurn(userInput, userContextInput) {
|
|
6054
6353
|
this.isInterrupted = false;
|
|
6055
6354
|
this.factorRouterTurnClosed = false;
|
|
@@ -6060,7 +6359,8 @@ var BluMaAgent = class {
|
|
|
6060
6359
|
turnId,
|
|
6061
6360
|
sessionId: userContextInput.sessionId || this.sessionId
|
|
6062
6361
|
};
|
|
6063
|
-
|
|
6362
|
+
const userContent = buildUserMessageContent(inputText, process.cwd());
|
|
6363
|
+
this.history.push({ role: "user", content: userContent });
|
|
6064
6364
|
if (inputText === "/init") {
|
|
6065
6365
|
this.eventBus.emit("dispatch", inputText);
|
|
6066
6366
|
}
|
|
@@ -6213,7 +6513,7 @@ var BluMaAgent = class {
|
|
|
6213
6513
|
|
|
6214
6514
|
${editData.error.display}`;
|
|
6215
6515
|
}
|
|
6216
|
-
const filename =
|
|
6516
|
+
const filename = path17.basename(toolArgs.file_path);
|
|
6217
6517
|
return createDiff(filename, editData.currentContent || "", editData.newContent);
|
|
6218
6518
|
} catch (e) {
|
|
6219
6519
|
return `An unexpected error occurred while generating the edit preview: ${e.message}`;
|
|
@@ -6471,7 +6771,7 @@ import { v4 as uuidv45 } from "uuid";
|
|
|
6471
6771
|
import { v4 as uuidv44 } from "uuid";
|
|
6472
6772
|
|
|
6473
6773
|
// src/app/agent/subagents/init/init_system_prompt.ts
|
|
6474
|
-
import
|
|
6774
|
+
import os12 from "os";
|
|
6475
6775
|
var SYSTEM_PROMPT2 = `
|
|
6476
6776
|
|
|
6477
6777
|
### YOU ARE BluMa CLI \u2014 INIT SUBAGENT \u2014 AUTONOMOUS SENIOR SOFTWARE ENGINEER @ NOMADENGENUITY
|
|
@@ -6634,12 +6934,12 @@ Rule Summary:
|
|
|
6634
6934
|
function getInitPrompt() {
|
|
6635
6935
|
const now = /* @__PURE__ */ new Date();
|
|
6636
6936
|
const collectedData = {
|
|
6637
|
-
os_type:
|
|
6638
|
-
os_version:
|
|
6639
|
-
architecture:
|
|
6937
|
+
os_type: os12.type(),
|
|
6938
|
+
os_version: os12.release(),
|
|
6939
|
+
architecture: os12.arch(),
|
|
6640
6940
|
workdir: process.cwd(),
|
|
6641
6941
|
shell_type: process.env.SHELL || process.env.COMSPEC || "Unknown",
|
|
6642
|
-
username:
|
|
6942
|
+
username: os12.userInfo().username || "Unknown",
|
|
6643
6943
|
current_date: now.toISOString().split("T")[0],
|
|
6644
6944
|
// Formato YYYY-MM-DD
|
|
6645
6945
|
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone || "Unknown",
|
|
@@ -6920,14 +7220,14 @@ var RouteManager = class {
|
|
|
6920
7220
|
this.subAgents = subAgents;
|
|
6921
7221
|
this.core = core;
|
|
6922
7222
|
}
|
|
6923
|
-
registerRoute(
|
|
6924
|
-
this.routeHandlers.set(
|
|
7223
|
+
registerRoute(path21, handler) {
|
|
7224
|
+
this.routeHandlers.set(path21, handler);
|
|
6925
7225
|
}
|
|
6926
7226
|
async handleRoute(payload) {
|
|
6927
7227
|
const inputText = String(payload.content || "").trim();
|
|
6928
7228
|
const { userContext } = payload;
|
|
6929
|
-
for (const [
|
|
6930
|
-
if (inputText ===
|
|
7229
|
+
for (const [path21, handler] of this.routeHandlers) {
|
|
7230
|
+
if (inputText === path21 || inputText.startsWith(`${path21} `)) {
|
|
6931
7231
|
return handler({ content: inputText, userContext });
|
|
6932
7232
|
}
|
|
6933
7233
|
}
|
|
@@ -6936,7 +7236,7 @@ var RouteManager = class {
|
|
|
6936
7236
|
};
|
|
6937
7237
|
|
|
6938
7238
|
// src/app/agent/agent.ts
|
|
6939
|
-
var globalEnvPath =
|
|
7239
|
+
var globalEnvPath = path18.join(os13.homedir(), ".bluma", ".env");
|
|
6940
7240
|
dotenv.config({ path: globalEnvPath });
|
|
6941
7241
|
var Agent = class {
|
|
6942
7242
|
sessionId;
|
|
@@ -7047,6 +7347,13 @@ var Agent = class {
|
|
|
7047
7347
|
getUiToolsDetailed() {
|
|
7048
7348
|
return this.core.getUiToolsDetailed();
|
|
7049
7349
|
}
|
|
7350
|
+
/** Skills list for UI (/skills) — same source as system prompt & load_skill. */
|
|
7351
|
+
listAvailableSkills() {
|
|
7352
|
+
return this.core.listAvailableSkills();
|
|
7353
|
+
}
|
|
7354
|
+
getSkillsDirs() {
|
|
7355
|
+
return this.core.getSkillsDirs();
|
|
7356
|
+
}
|
|
7050
7357
|
async processTurn(userInput, userContextInput) {
|
|
7051
7358
|
const inputText = String(userInput.content || "").trim();
|
|
7052
7359
|
const resolvedUserContext = userContextInput ?? defaultInteractiveCliUserContextInput(this.sessionId, inputText.slice(0, 300));
|
|
@@ -7153,12 +7460,12 @@ var renderShellCommand2 = ({ args }) => {
|
|
|
7153
7460
|
};
|
|
7154
7461
|
var renderLsTool2 = ({ args }) => {
|
|
7155
7462
|
const parsed = parseArgs(args);
|
|
7156
|
-
const
|
|
7463
|
+
const path21 = parsed.directory_path || ".";
|
|
7157
7464
|
return /* @__PURE__ */ jsxs9(Box9, { children: [
|
|
7158
7465
|
/* @__PURE__ */ jsx9(Text9, { color: BLUMA_TERMINAL.brandBlue, bold: true, children: "ls" }),
|
|
7159
7466
|
/* @__PURE__ */ jsxs9(Text9, { dimColor: true, children: [
|
|
7160
7467
|
" ",
|
|
7161
|
-
|
|
7468
|
+
path21
|
|
7162
7469
|
] })
|
|
7163
7470
|
] });
|
|
7164
7471
|
};
|
|
@@ -7294,7 +7601,7 @@ var renderFindByName = ({ args }) => {
|
|
|
7294
7601
|
var renderGrepSearch = ({ args }) => {
|
|
7295
7602
|
const parsed = parseArgs(args);
|
|
7296
7603
|
const query = parsed.query || "";
|
|
7297
|
-
const
|
|
7604
|
+
const path21 = parsed.path || ".";
|
|
7298
7605
|
return /* @__PURE__ */ jsxs9(Box9, { children: [
|
|
7299
7606
|
/* @__PURE__ */ jsx9(Text9, { color: BLUMA_TERMINAL.brandBlue, bold: true, children: "grep" }),
|
|
7300
7607
|
/* @__PURE__ */ jsxs9(Text9, { color: BLUMA_TERMINAL.brandMagenta, children: [
|
|
@@ -7304,7 +7611,7 @@ var renderGrepSearch = ({ args }) => {
|
|
|
7304
7611
|
] }),
|
|
7305
7612
|
/* @__PURE__ */ jsxs9(Text9, { dimColor: true, children: [
|
|
7306
7613
|
" ",
|
|
7307
|
-
|
|
7614
|
+
path21
|
|
7308
7615
|
] })
|
|
7309
7616
|
] });
|
|
7310
7617
|
};
|
|
@@ -7873,10 +8180,10 @@ var ToolResultDisplayComponent = ({ toolName, result }) => {
|
|
|
7873
8180
|
] }),
|
|
7874
8181
|
matches.slice(0, 5).map((m, i) => {
|
|
7875
8182
|
const row = m;
|
|
7876
|
-
const
|
|
8183
|
+
const path21 = row.file || row.path || row.name || m;
|
|
7877
8184
|
const line = row.line;
|
|
7878
8185
|
return /* @__PURE__ */ jsxs11(Text11, { dimColor: true, children: [
|
|
7879
|
-
String(
|
|
8186
|
+
String(path21),
|
|
7880
8187
|
line != null ? `:${line}` : ""
|
|
7881
8188
|
] }, i);
|
|
7882
8189
|
}),
|
|
@@ -8008,8 +8315,18 @@ var SessionInfoConnectingMCP_default = SessionInfoConnectingMCP;
|
|
|
8008
8315
|
|
|
8009
8316
|
// src/app/ui/components/SlashCommands.tsx
|
|
8010
8317
|
import { Box as Box14, Text as Text13 } from "ink";
|
|
8318
|
+
|
|
8319
|
+
// src/app/ui/constants/historyLayout.ts
|
|
8320
|
+
var HEADER_PANEL_HISTORY_ID = 0;
|
|
8321
|
+
|
|
8322
|
+
// src/app/ui/components/SlashCommands.tsx
|
|
8011
8323
|
import { Fragment as Fragment2, jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
8012
|
-
var SlashCommands = ({
|
|
8324
|
+
var SlashCommands = ({
|
|
8325
|
+
input,
|
|
8326
|
+
setHistory,
|
|
8327
|
+
agentRef,
|
|
8328
|
+
onClearRecent
|
|
8329
|
+
}) => {
|
|
8013
8330
|
const [cmd, ...args] = input.slice(1).trim().split(/\s+/);
|
|
8014
8331
|
const outBox = (children) => /* @__PURE__ */ jsx14(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsx14(Box14, { paddingLeft: 1, flexDirection: "column", children }) });
|
|
8015
8332
|
const render2 = () => {
|
|
@@ -8017,19 +8334,59 @@ var SlashCommands = ({ input, setHistory, agentRef }) => {
|
|
|
8017
8334
|
return null;
|
|
8018
8335
|
}
|
|
8019
8336
|
if (cmd === "help") {
|
|
8020
|
-
const
|
|
8337
|
+
const lines = formatSlashHelpLines();
|
|
8338
|
+
return outBox(
|
|
8339
|
+
/* @__PURE__ */ jsxs13(Fragment2, { children: [
|
|
8340
|
+
/* @__PURE__ */ jsxs13(Box14, { marginBottom: 1, children: [
|
|
8341
|
+
/* @__PURE__ */ jsx14(Text13, { bold: true, color: BLUMA_TERMINAL.brandMagenta, children: "Slash commands" }),
|
|
8342
|
+
/* @__PURE__ */ jsx14(Text13, { dimColor: true, children: " \xB7 " }),
|
|
8343
|
+
/* @__PURE__ */ jsx14(Text13, { dimColor: true, children: "put .png/.jpg/.webp paths in a normal message to attach images (project dir or ~)" })
|
|
8344
|
+
] }),
|
|
8345
|
+
/* @__PURE__ */ jsx14(Box14, { flexDirection: "column", children: lines.map((line, i) => /* @__PURE__ */ jsx14(Text13, { dimColor: line.trim().length > 0, children: line || " " }, i)) })
|
|
8346
|
+
] })
|
|
8347
|
+
);
|
|
8348
|
+
}
|
|
8349
|
+
if (cmd === "skills") {
|
|
8350
|
+
const list = agentRef.current?.listAvailableSkills?.() || [];
|
|
8351
|
+
const dirs = agentRef.current?.getSkillsDirs?.();
|
|
8021
8352
|
return outBox(
|
|
8022
8353
|
/* @__PURE__ */ jsxs13(Fragment2, { children: [
|
|
8023
|
-
/* @__PURE__ */
|
|
8024
|
-
|
|
8025
|
-
/* @__PURE__ */
|
|
8026
|
-
|
|
8354
|
+
/* @__PURE__ */ jsxs13(Box14, { marginBottom: 1, children: [
|
|
8355
|
+
/* @__PURE__ */ jsx14(Text13, { bold: true, color: BLUMA_TERMINAL.brandMagenta, children: "Skills (load_skill)" }),
|
|
8356
|
+
/* @__PURE__ */ jsxs13(Text13, { dimColor: true, children: [
|
|
8357
|
+
" \xB7 ",
|
|
8358
|
+
list.length,
|
|
8359
|
+
" available"
|
|
8360
|
+
] })
|
|
8361
|
+
] }),
|
|
8362
|
+
dirs ? /* @__PURE__ */ jsxs13(Box14, { marginBottom: 1, flexDirection: "column", children: [
|
|
8363
|
+
/* @__PURE__ */ jsxs13(Text13, { dimColor: true, children: [
|
|
8364
|
+
"bundled: ",
|
|
8365
|
+
String(dirs.bundled || "")
|
|
8366
|
+
] }),
|
|
8367
|
+
/* @__PURE__ */ jsxs13(Text13, { dimColor: true, children: [
|
|
8368
|
+
"project: ",
|
|
8369
|
+
String(dirs.project || "")
|
|
8370
|
+
] }),
|
|
8371
|
+
/* @__PURE__ */ jsxs13(Text13, { dimColor: true, children: [
|
|
8372
|
+
"global: ",
|
|
8373
|
+
String(dirs.global || "")
|
|
8374
|
+
] })
|
|
8375
|
+
] }) : null,
|
|
8376
|
+
list.length === 0 ? /* @__PURE__ */ jsx14(Text13, { color: "yellow", children: "No skills found (check bundled dist/config/skills)." }) : /* @__PURE__ */ jsx14(Box14, { flexDirection: "column", children: list.map((s, i) => /* @__PURE__ */ jsxs13(Box14, { flexDirection: "column", marginBottom: 1, children: [
|
|
8377
|
+
/* @__PURE__ */ jsx14(Text13, { color: BLUMA_TERMINAL.brandBlue, bold: true, children: s.name }),
|
|
8378
|
+
/* @__PURE__ */ jsxs13(Text13, { dimColor: true, children: [
|
|
8379
|
+
s.source,
|
|
8380
|
+
" \u2014 ",
|
|
8381
|
+
s.description || "\u2014"
|
|
8382
|
+
] })
|
|
8027
8383
|
] }, i)) })
|
|
8028
8384
|
] })
|
|
8029
8385
|
);
|
|
8030
8386
|
}
|
|
8031
8387
|
if (cmd === "clear") {
|
|
8032
|
-
|
|
8388
|
+
onClearRecent?.();
|
|
8389
|
+
setHistory((prev) => prev.filter((item) => item.id === HEADER_PANEL_HISTORY_ID));
|
|
8033
8390
|
return outBox(
|
|
8034
8391
|
/* @__PURE__ */ jsxs13(Box14, { children: [
|
|
8035
8392
|
/* @__PURE__ */ jsx14(Text13, { color: "green", children: "[ok]" }),
|
|
@@ -8173,16 +8530,16 @@ var SlashCommands_default = SlashCommands;
|
|
|
8173
8530
|
// src/app/agent/utils/update_check.ts
|
|
8174
8531
|
import updateNotifier from "update-notifier";
|
|
8175
8532
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
8176
|
-
import
|
|
8177
|
-
import
|
|
8533
|
+
import path19 from "path";
|
|
8534
|
+
import fs15 from "fs";
|
|
8178
8535
|
var BLUMA_PACKAGE_NAME = "@nomad-e/bluma-cli";
|
|
8179
8536
|
function findBlumaPackageJson(startDir) {
|
|
8180
8537
|
let dir = startDir;
|
|
8181
8538
|
for (let i = 0; i < 10; i++) {
|
|
8182
|
-
const candidate =
|
|
8183
|
-
if (
|
|
8539
|
+
const candidate = path19.join(dir, "package.json");
|
|
8540
|
+
if (fs15.existsSync(candidate)) {
|
|
8184
8541
|
try {
|
|
8185
|
-
const raw =
|
|
8542
|
+
const raw = fs15.readFileSync(candidate, "utf8");
|
|
8186
8543
|
const parsed = JSON.parse(raw);
|
|
8187
8544
|
if (parsed?.name === BLUMA_PACKAGE_NAME && parsed?.version) {
|
|
8188
8545
|
return { name: parsed.name, version: parsed.version };
|
|
@@ -8190,7 +8547,7 @@ function findBlumaPackageJson(startDir) {
|
|
|
8190
8547
|
} catch {
|
|
8191
8548
|
}
|
|
8192
8549
|
}
|
|
8193
|
-
const parent =
|
|
8550
|
+
const parent = path19.dirname(dir);
|
|
8194
8551
|
if (parent === dir) break;
|
|
8195
8552
|
dir = parent;
|
|
8196
8553
|
}
|
|
@@ -8203,12 +8560,12 @@ async function checkForUpdates() {
|
|
|
8203
8560
|
}
|
|
8204
8561
|
const binPath = process.argv?.[1];
|
|
8205
8562
|
let pkg = null;
|
|
8206
|
-
if (binPath &&
|
|
8207
|
-
pkg = findBlumaPackageJson(
|
|
8563
|
+
if (binPath && fs15.existsSync(binPath)) {
|
|
8564
|
+
pkg = findBlumaPackageJson(path19.dirname(binPath));
|
|
8208
8565
|
}
|
|
8209
8566
|
if (!pkg) {
|
|
8210
8567
|
const __filename = fileURLToPath3(import.meta.url);
|
|
8211
|
-
const __dirname2 =
|
|
8568
|
+
const __dirname2 = path19.dirname(__filename);
|
|
8212
8569
|
pkg = findBlumaPackageJson(__dirname2);
|
|
8213
8570
|
}
|
|
8214
8571
|
if (!pkg) {
|
|
@@ -8438,7 +8795,12 @@ var SAFE_AUTO_APPROVE_TOOLS = [
|
|
|
8438
8795
|
// Status de comandos (read-only)
|
|
8439
8796
|
"command_status"
|
|
8440
8797
|
];
|
|
8441
|
-
|
|
8798
|
+
function trimRecentActivity(s, max = 72) {
|
|
8799
|
+
const t = String(s ?? "").replace(/\s+/g, " ").trim();
|
|
8800
|
+
if (!t) return "";
|
|
8801
|
+
return t.length <= max ? t : `${t.slice(0, max - 1)}\u2026`;
|
|
8802
|
+
}
|
|
8803
|
+
var AppComponent = ({ eventBus, sessionId, cliVersion }) => {
|
|
8442
8804
|
const agentInstance = useRef5(null);
|
|
8443
8805
|
const [history, setHistory] = useState6([]);
|
|
8444
8806
|
const [statusMessage, setStatusMessage] = useState6(
|
|
@@ -8456,6 +8818,7 @@ var AppComponent = ({ eventBus, sessionId }) => {
|
|
|
8456
8818
|
null
|
|
8457
8819
|
);
|
|
8458
8820
|
const [isInitAgentActive, setIsInitAgentActive] = useState6(false);
|
|
8821
|
+
const [recentActivityLine, setRecentActivityLine] = useState6(null);
|
|
8459
8822
|
const alwaysAcceptList = useRef5([]);
|
|
8460
8823
|
const workdir = process.cwd();
|
|
8461
8824
|
const updateCheckRan = useRef5(false);
|
|
@@ -8488,6 +8851,26 @@ var AppComponent = ({ eventBus, sessionId }) => {
|
|
|
8488
8851
|
expandPreviewHotkeyBus.off("expand", appendExpandPreviewToHistory);
|
|
8489
8852
|
};
|
|
8490
8853
|
}, [appendExpandPreviewToHistory]);
|
|
8854
|
+
useEffect7(() => {
|
|
8855
|
+
setHistory((prev) => {
|
|
8856
|
+
const tail = prev.filter((h) => h.id !== HEADER_PANEL_HISTORY_ID);
|
|
8857
|
+
return [
|
|
8858
|
+
{
|
|
8859
|
+
id: HEADER_PANEL_HISTORY_ID,
|
|
8860
|
+
component: /* @__PURE__ */ jsx20(
|
|
8861
|
+
Header,
|
|
8862
|
+
{
|
|
8863
|
+
sessionId,
|
|
8864
|
+
workdir,
|
|
8865
|
+
cliVersion,
|
|
8866
|
+
recentActivitySummary: recentActivityLine
|
|
8867
|
+
}
|
|
8868
|
+
)
|
|
8869
|
+
},
|
|
8870
|
+
...tail
|
|
8871
|
+
];
|
|
8872
|
+
});
|
|
8873
|
+
}, [sessionId, workdir, cliVersion, recentActivityLine]);
|
|
8491
8874
|
const handleInterrupt = useCallback2(() => {
|
|
8492
8875
|
if (!isProcessing) return;
|
|
8493
8876
|
eventBus.emit("user_interrupt");
|
|
@@ -8504,12 +8887,45 @@ var AppComponent = ({ eventBus, sessionId }) => {
|
|
|
8504
8887
|
const handleSubmit = useCallback2(
|
|
8505
8888
|
(text) => {
|
|
8506
8889
|
if (!text || isProcessing || !agentInstance.current) return;
|
|
8890
|
+
if (/^\/img\s+/i.test(text) || /^\/image\s+/i.test(text)) {
|
|
8891
|
+
const payload = text.replace(/^\/img\s+/i, "").replace(/^\/image\s+/i, "").trim();
|
|
8892
|
+
if (!payload) {
|
|
8893
|
+
setHistory((prev) => [
|
|
8894
|
+
...prev,
|
|
8895
|
+
{
|
|
8896
|
+
id: prev.length,
|
|
8897
|
+
component: /* @__PURE__ */ jsx20(ChatMeta, { children: "Usage: /img ./screenshot.png \u2014 optional text after the path is sent too" })
|
|
8898
|
+
}
|
|
8899
|
+
]);
|
|
8900
|
+
return;
|
|
8901
|
+
}
|
|
8902
|
+
setIsProcessing(true);
|
|
8903
|
+
turnStartedAtRef.current = Date.now();
|
|
8904
|
+
const shown = payload.length > 800 ? `${payload.slice(0, 800)}\u2026` : payload;
|
|
8905
|
+
setHistory((prev) => [
|
|
8906
|
+
...prev,
|
|
8907
|
+
{
|
|
8908
|
+
id: prev.length,
|
|
8909
|
+
component: /* @__PURE__ */ jsxs19(ChatUserMessage, { children: [
|
|
8910
|
+
/* @__PURE__ */ jsxs19(Text19, { bold: true, color: "white", children: [
|
|
8911
|
+
"/img",
|
|
8912
|
+
" "
|
|
8913
|
+
] }),
|
|
8914
|
+
/* @__PURE__ */ jsx20(Text19, { dimColor: true, children: shown })
|
|
8915
|
+
] })
|
|
8916
|
+
}
|
|
8917
|
+
]);
|
|
8918
|
+
setRecentActivityLine(`Prompt: ${trimRecentActivity(payload)}`);
|
|
8919
|
+
agentInstance.current.processTurn({ content: payload });
|
|
8920
|
+
return;
|
|
8921
|
+
}
|
|
8507
8922
|
if (text.startsWith("/")) {
|
|
8508
8923
|
const [cmd] = text.slice(1).trim().split(/\s+/);
|
|
8509
8924
|
if (!cmd) {
|
|
8510
8925
|
setIsProcessing(false);
|
|
8511
8926
|
return;
|
|
8512
8927
|
}
|
|
8928
|
+
setRecentActivityLine(`You: ${trimRecentActivity(text)}`);
|
|
8513
8929
|
if (cmd === "init") {
|
|
8514
8930
|
setIsInitAgentActive(true);
|
|
8515
8931
|
setIsProcessing(true);
|
|
@@ -8531,7 +8947,8 @@ var AppComponent = ({ eventBus, sessionId }) => {
|
|
|
8531
8947
|
{
|
|
8532
8948
|
input: text,
|
|
8533
8949
|
setHistory,
|
|
8534
|
-
agentRef: agentInstance
|
|
8950
|
+
agentRef: agentInstance,
|
|
8951
|
+
onClearRecent: () => setRecentActivityLine(null)
|
|
8535
8952
|
}
|
|
8536
8953
|
)
|
|
8537
8954
|
}
|
|
@@ -8556,6 +8973,7 @@ var AppComponent = ({ eventBus, sessionId }) => {
|
|
|
8556
8973
|
] }) })
|
|
8557
8974
|
}
|
|
8558
8975
|
]);
|
|
8976
|
+
setRecentActivityLine(`Shell: ${trimRecentActivity(command)}`);
|
|
8559
8977
|
Promise.resolve().then(() => (init_async_command(), async_command_exports)).then(async ({ runCommandAsync: runCommandAsync2 }) => {
|
|
8560
8978
|
try {
|
|
8561
8979
|
const result = await runCommandAsync2({ command, cwd: workdir });
|
|
@@ -8607,6 +9025,7 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
8607
9025
|
component: /* @__PURE__ */ jsx20(ChatUserMessage, { children: /* @__PURE__ */ jsx20(Text19, { children: displayText }) })
|
|
8608
9026
|
}
|
|
8609
9027
|
]);
|
|
9028
|
+
setRecentActivityLine(`You: ${trimRecentActivity(text)}`);
|
|
8610
9029
|
agentInstance.current.processTurn({ content: text });
|
|
8611
9030
|
},
|
|
8612
9031
|
[isProcessing]
|
|
@@ -8633,7 +9052,6 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
8633
9052
|
[]
|
|
8634
9053
|
);
|
|
8635
9054
|
useEffect7(() => {
|
|
8636
|
-
setHistory([{ id: 0, component: /* @__PURE__ */ jsx20(Header, { sessionId, workdir }) }]);
|
|
8637
9055
|
const initializeAgent = async () => {
|
|
8638
9056
|
try {
|
|
8639
9057
|
agentInstance.current = new Agent(sessionId, eventBus);
|
|
@@ -8702,10 +9120,6 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
8702
9120
|
setToolsCount(parsed.tools);
|
|
8703
9121
|
setMcpStatus("connected");
|
|
8704
9122
|
setIsProcessing(false);
|
|
8705
|
-
setHistory((prev) => {
|
|
8706
|
-
const newHistory = [...prev];
|
|
8707
|
-
return newHistory;
|
|
8708
|
-
});
|
|
8709
9123
|
if (!updateCheckRan.current) {
|
|
8710
9124
|
updateCheckRan.current = true;
|
|
8711
9125
|
Promise.resolve().then(() => checkForUpdates()).then((msg) => {
|
|
@@ -8744,7 +9158,9 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
8744
9158
|
}
|
|
8745
9159
|
);
|
|
8746
9160
|
} else if (parsed.type === "tool_call") {
|
|
8747
|
-
|
|
9161
|
+
if (parsed.tool_name) {
|
|
9162
|
+
setRecentActivityLine(`Tool: ${String(parsed.tool_name)}`);
|
|
9163
|
+
}
|
|
8748
9164
|
newComponent = /* @__PURE__ */ jsx20(
|
|
8749
9165
|
ToolCallDisplay,
|
|
8750
9166
|
{
|
|
@@ -8762,6 +9178,11 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
8762
9178
|
}
|
|
8763
9179
|
);
|
|
8764
9180
|
} else if (parsed.type === "user_overlay") {
|
|
9181
|
+
if (parsed.payload != null && String(parsed.payload).trim()) {
|
|
9182
|
+
setRecentActivityLine(
|
|
9183
|
+
`Context: ${trimRecentActivity(String(parsed.payload))}`
|
|
9184
|
+
);
|
|
9185
|
+
}
|
|
8765
9186
|
newComponent = /* @__PURE__ */ jsx20(ChatUserMessage, { children: /* @__PURE__ */ jsx20(Text19, { dimColor: true, children: parsed.payload }) });
|
|
8766
9187
|
} else if (parsed.type === "reasoning") {
|
|
8767
9188
|
newComponent = /* @__PURE__ */ jsx20(ReasoningDisplay, { reasoning: parsed.content });
|
|
@@ -8952,9 +9373,9 @@ async function runAgentMode() {
|
|
|
8952
9373
|
try {
|
|
8953
9374
|
if (inputFileIndex !== -1 && args[inputFileIndex + 1]) {
|
|
8954
9375
|
const filePath = args[inputFileIndex + 1];
|
|
8955
|
-
rawPayload =
|
|
9376
|
+
rawPayload = fs16.readFileSync(filePath, "utf-8");
|
|
8956
9377
|
} else {
|
|
8957
|
-
rawPayload =
|
|
9378
|
+
rawPayload = fs16.readFileSync(0, "utf-8");
|
|
8958
9379
|
}
|
|
8959
9380
|
} catch (err) {
|
|
8960
9381
|
writeJsonl({
|
|
@@ -9120,6 +9541,16 @@ async function runAgentMode() {
|
|
|
9120
9541
|
process.exit(1);
|
|
9121
9542
|
}
|
|
9122
9543
|
}
|
|
9544
|
+
function readCliPackageVersion() {
|
|
9545
|
+
try {
|
|
9546
|
+
const base = path20.dirname(fileURLToPath4(import.meta.url));
|
|
9547
|
+
const pkgPath = path20.join(base, "..", "package.json");
|
|
9548
|
+
const j = JSON.parse(fs16.readFileSync(pkgPath, "utf8"));
|
|
9549
|
+
return String(j.version || "0.0.0");
|
|
9550
|
+
} catch {
|
|
9551
|
+
return "0.0.0";
|
|
9552
|
+
}
|
|
9553
|
+
}
|
|
9123
9554
|
function runCliMode() {
|
|
9124
9555
|
const BLUMA_TITLE = process.env.BLUMA_TITLE || "BluMa - NomadEngenuity";
|
|
9125
9556
|
startTitleKeeper(BLUMA_TITLE);
|
|
@@ -9127,7 +9558,8 @@ function runCliMode() {
|
|
|
9127
9558
|
const sessionId = uuidv46();
|
|
9128
9559
|
const props = {
|
|
9129
9560
|
eventBus,
|
|
9130
|
-
sessionId
|
|
9561
|
+
sessionId,
|
|
9562
|
+
cliVersion: readCliPackageVersion()
|
|
9131
9563
|
};
|
|
9132
9564
|
render(React12.createElement(App_default, props));
|
|
9133
9565
|
}
|