@nomad-e/bluma-cli 0.1.30 → 0.1.31
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 +97 -27
- package/dist/config/native_tools.json +11 -7
- package/dist/main.js +1413 -640
- package/package.json +2 -1
package/dist/main.js
CHANGED
|
@@ -328,33 +328,71 @@ var init_async_command = __esm({
|
|
|
328
328
|
});
|
|
329
329
|
|
|
330
330
|
// src/main.ts
|
|
331
|
-
import
|
|
331
|
+
import React12 from "react";
|
|
332
332
|
import { render } from "ink";
|
|
333
|
-
import { EventEmitter as
|
|
333
|
+
import { EventEmitter as EventEmitter3 } from "events";
|
|
334
334
|
import fs15 from "fs";
|
|
335
335
|
import { v4 as uuidv46 } from "uuid";
|
|
336
336
|
|
|
337
337
|
// src/app/ui/App.tsx
|
|
338
|
-
import { useState as
|
|
339
|
-
import { Box as
|
|
338
|
+
import { useState as useState6, useEffect as useEffect7, useRef as useRef5, useCallback as useCallback2, memo as memo12 } from "react";
|
|
339
|
+
import { Box as Box20, Text as Text19, Static } from "ink";
|
|
340
340
|
|
|
341
341
|
// src/app/ui/layout.tsx
|
|
342
342
|
import { Box, Text } from "ink";
|
|
343
343
|
import { memo } from "react";
|
|
344
|
-
|
|
344
|
+
|
|
345
|
+
// src/app/ui/theme/blumaTerminal.ts
|
|
346
|
+
var BLUMA_TERMINAL = {
|
|
347
|
+
brandBlue: "blue",
|
|
348
|
+
brandMagenta: "magenta",
|
|
349
|
+
text: "white",
|
|
350
|
+
muted: "gray",
|
|
351
|
+
dim: "gray",
|
|
352
|
+
code: "gray",
|
|
353
|
+
codeLabel: "blue",
|
|
354
|
+
link: "blue",
|
|
355
|
+
linkUnderline: true,
|
|
356
|
+
success: "green",
|
|
357
|
+
warn: "yellow",
|
|
358
|
+
err: "red",
|
|
359
|
+
panelBorder: "blue",
|
|
360
|
+
toolLabel: "magenta",
|
|
361
|
+
toolMeta: "gray",
|
|
362
|
+
heading1: "blue",
|
|
363
|
+
heading2: "blue",
|
|
364
|
+
headingDeep: "magenta",
|
|
365
|
+
listBullet: "magenta",
|
|
366
|
+
listBulletSub: "blue",
|
|
367
|
+
rule: "gray",
|
|
368
|
+
/** M3 CLI — superfícies e hierarquia */
|
|
369
|
+
m3Outline: "blue",
|
|
370
|
+
m3TonalOutline: "magenta",
|
|
371
|
+
m3Rail: "blue",
|
|
372
|
+
m3Label: "gray",
|
|
373
|
+
m3OnSurface: "white"
|
|
374
|
+
};
|
|
375
|
+
|
|
376
|
+
// src/app/ui/layout.tsx
|
|
377
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
345
378
|
var HeaderComponent = ({
|
|
346
379
|
sessionId,
|
|
347
380
|
workdir
|
|
348
381
|
}) => {
|
|
349
382
|
const dirName = workdir.split("/").pop() || workdir;
|
|
350
383
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
351
|
-
/* @__PURE__ */
|
|
352
|
-
|
|
384
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", flexWrap: "wrap", children: [
|
|
385
|
+
/* @__PURE__ */ jsx(Text, { color: BLUMA_TERMINAL.brandBlue, bold: true, children: "BluMa" }),
|
|
386
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " \u2014 " }),
|
|
387
|
+
/* @__PURE__ */ jsx(Text, { children: "Base Language Unit" }),
|
|
388
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " \xB7 " }),
|
|
389
|
+
/* @__PURE__ */ jsx(Text, { color: BLUMA_TERMINAL.brandMagenta, bold: true, children: "Model Agent" })
|
|
390
|
+
] }),
|
|
391
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", flexWrap: "wrap", children: [
|
|
353
392
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "cwd " }),
|
|
354
|
-
/* @__PURE__ */ jsx(Text, { color:
|
|
355
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "
|
|
356
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children:
|
|
357
|
-
/* @__PURE__ */ jsx(Text, { color: "gray", children: sessionId.slice(0, 8) })
|
|
393
|
+
/* @__PURE__ */ jsx(Text, { color: BLUMA_TERMINAL.brandBlue, children: dirName }),
|
|
394
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " \u2502 session " }),
|
|
395
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: sessionId.slice(0, 8) })
|
|
358
396
|
] })
|
|
359
397
|
] });
|
|
360
398
|
};
|
|
@@ -366,12 +404,12 @@ var SessionInfoComponent = ({
|
|
|
366
404
|
mcpStatus
|
|
367
405
|
}) => /* @__PURE__ */ jsxs(Box, { paddingX: 1, children: [
|
|
368
406
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "mcp " }),
|
|
369
|
-
/* @__PURE__ */ jsx(Text, { color: mcpStatus === "connected" ?
|
|
370
|
-
toolsCount !== null
|
|
407
|
+
/* @__PURE__ */ jsx(Text, { color: mcpStatus === "connected" ? BLUMA_TERMINAL.success : BLUMA_TERMINAL.warn, children: mcpStatus === "connected" ? "on" : "\u2026" }),
|
|
408
|
+
toolsCount !== null ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
371
409
|
" ",
|
|
372
410
|
toolsCount,
|
|
373
411
|
" tools"
|
|
374
|
-
] })
|
|
412
|
+
] }) : null
|
|
375
413
|
] });
|
|
376
414
|
var SessionInfo = memo(SessionInfoComponent);
|
|
377
415
|
var TaskStatusBarComponent = ({
|
|
@@ -380,9 +418,9 @@ var TaskStatusBarComponent = ({
|
|
|
380
418
|
status
|
|
381
419
|
}) => {
|
|
382
420
|
const modeColors = {
|
|
383
|
-
PLANNING:
|
|
384
|
-
EXECUTION:
|
|
385
|
-
VERIFICATION:
|
|
421
|
+
PLANNING: BLUMA_TERMINAL.brandBlue,
|
|
422
|
+
EXECUTION: BLUMA_TERMINAL.brandBlue,
|
|
423
|
+
VERIFICATION: BLUMA_TERMINAL.brandMagenta
|
|
386
424
|
};
|
|
387
425
|
return /* @__PURE__ */ jsxs(Box, { paddingX: 1, children: [
|
|
388
426
|
/* @__PURE__ */ jsxs(Text, { color: modeColors[mode], bold: true, children: [
|
|
@@ -394,10 +432,10 @@ var TaskStatusBarComponent = ({
|
|
|
394
432
|
" ",
|
|
395
433
|
taskName
|
|
396
434
|
] }),
|
|
397
|
-
status
|
|
398
|
-
"
|
|
435
|
+
status ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
436
|
+
" \u2014 ",
|
|
399
437
|
status
|
|
400
|
-
] })
|
|
438
|
+
] }) : null
|
|
401
439
|
] });
|
|
402
440
|
};
|
|
403
441
|
var TaskStatusBar = memo(TaskStatusBarComponent);
|
|
@@ -408,6 +446,12 @@ import { Box as Box2, Text as Text2, useStdout, useInput as useInput2 } from "in
|
|
|
408
446
|
// src/app/ui/utils/useSimpleInputBuffer.ts
|
|
409
447
|
import { useReducer, useRef, useCallback, useEffect } from "react";
|
|
410
448
|
import { useInput } from "ink";
|
|
449
|
+
|
|
450
|
+
// src/app/ui/utils/expandPreviewHotkey.ts
|
|
451
|
+
import { EventEmitter } from "events";
|
|
452
|
+
var expandPreviewHotkeyBus = new EventEmitter();
|
|
453
|
+
|
|
454
|
+
// src/app/ui/utils/useSimpleInputBuffer.ts
|
|
411
455
|
function getLineStart(text, cursorPos) {
|
|
412
456
|
let pos = cursorPos - 1;
|
|
413
457
|
while (pos >= 0 && text[pos] !== "\n") {
|
|
@@ -546,7 +590,12 @@ function inputReducer(state, action, viewWidth) {
|
|
|
546
590
|
return state;
|
|
547
591
|
}
|
|
548
592
|
}
|
|
549
|
-
var useCustomInput = ({
|
|
593
|
+
var useCustomInput = ({
|
|
594
|
+
onSubmit,
|
|
595
|
+
viewWidth,
|
|
596
|
+
isReadOnly,
|
|
597
|
+
onInterrupt
|
|
598
|
+
}) => {
|
|
550
599
|
const [state, dispatch] = useReducer(
|
|
551
600
|
(s, a) => inputReducer(s, a, viewWidth),
|
|
552
601
|
{ text: "", cursorPosition: 0, viewStart: 0 }
|
|
@@ -597,6 +646,10 @@ var useCustomInput = ({ onSubmit, viewWidth, isReadOnly, onInterrupt }) => {
|
|
|
597
646
|
if (inputBuffer.current.length > 0 && (key.ctrl || key.meta || key.escape || key.return || key.leftArrow || key.rightArrow || key.upArrow || key.downArrow || key.tab || key.shift)) {
|
|
598
647
|
flushInputBuffer();
|
|
599
648
|
}
|
|
649
|
+
if (key.ctrl && input === "o") {
|
|
650
|
+
expandPreviewHotkeyBus.emit("expand");
|
|
651
|
+
return;
|
|
652
|
+
}
|
|
600
653
|
if (key.escape) {
|
|
601
654
|
onInterrupt();
|
|
602
655
|
return;
|
|
@@ -685,7 +738,7 @@ var useCustomInput = ({ onSubmit, viewWidth, isReadOnly, onInterrupt }) => {
|
|
|
685
738
|
|
|
686
739
|
// src/app/ui/components/InputPrompt.tsx
|
|
687
740
|
import { useEffect as useEffect3, useMemo, useState as useState2, memo as memo2 } from "react";
|
|
688
|
-
import { EventEmitter } from "events";
|
|
741
|
+
import { EventEmitter as EventEmitter2 } from "events";
|
|
689
742
|
|
|
690
743
|
// src/app/ui/utils/slashRegistry.ts
|
|
691
744
|
var getSlashCommands = () => [
|
|
@@ -884,9 +937,14 @@ function useAtCompletion({
|
|
|
884
937
|
return { open, suggestions, selected, setSelected, insertAtSelection, close, update };
|
|
885
938
|
}
|
|
886
939
|
|
|
940
|
+
// src/app/ui/constants/toolUiPreview.ts
|
|
941
|
+
var TOOL_PREVIEW_MAX_LINES = 8;
|
|
942
|
+
var EXPAND_OVERLAY_MAX_LINES = 60;
|
|
943
|
+
var TERMINAL_RULE_CHAR = "\u2500";
|
|
944
|
+
|
|
887
945
|
// src/app/ui/components/InputPrompt.tsx
|
|
888
|
-
import { Fragment
|
|
889
|
-
var uiEventBus = global.__bluma_ui_eventbus__ || new
|
|
946
|
+
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
947
|
+
var uiEventBus = global.__bluma_ui_eventbus__ || new EventEmitter2();
|
|
890
948
|
global.__bluma_ui_eventbus__ = uiEventBus;
|
|
891
949
|
var TextLine = memo2(({
|
|
892
950
|
line,
|
|
@@ -931,8 +989,8 @@ var PathSuggestions = memo2(({
|
|
|
931
989
|
const realIdx = start + idx;
|
|
932
990
|
const isSelected = realIdx === selected;
|
|
933
991
|
return /* @__PURE__ */ jsxs2(Box2, { paddingLeft: 1, paddingY: 0, children: [
|
|
934
|
-
/* @__PURE__ */ jsx2(Text2, { color: isSelected ?
|
|
935
|
-
/* @__PURE__ */ jsx2(Text2, { color: isSelected ?
|
|
992
|
+
/* @__PURE__ */ jsx2(Text2, { color: isSelected ? BLUMA_TERMINAL.brandMagenta : BLUMA_TERMINAL.muted, children: isSelected ? "> " : " " }),
|
|
993
|
+
/* @__PURE__ */ jsx2(Text2, { color: isSelected ? BLUMA_TERMINAL.brandBlue : void 0, bold: isSelected, dimColor: !isSelected, children: s.label })
|
|
936
994
|
] }, s.fullPath);
|
|
937
995
|
}) });
|
|
938
996
|
});
|
|
@@ -943,11 +1001,11 @@ var SlashSuggestions = memo2(({
|
|
|
943
1001
|
}) => /* @__PURE__ */ jsx2(Box2, { flexDirection: "column", marginTop: 1, children: suggestions.map((s, idx) => {
|
|
944
1002
|
const isSelected = idx === selectedIndex;
|
|
945
1003
|
return /* @__PURE__ */ jsxs2(Box2, { paddingLeft: 1, paddingY: 0, children: [
|
|
946
|
-
/* @__PURE__ */ jsx2(Text2, { color: isSelected ?
|
|
947
|
-
/* @__PURE__ */ jsxs2(Text2, { color: isSelected ?
|
|
1004
|
+
/* @__PURE__ */ jsx2(Text2, { color: isSelected ? BLUMA_TERMINAL.brandMagenta : BLUMA_TERMINAL.muted, children: isSelected ? "> " : " " }),
|
|
1005
|
+
/* @__PURE__ */ jsxs2(Text2, { color: isSelected ? BLUMA_TERMINAL.brandBlue : void 0, bold: isSelected, dimColor: !isSelected, children: [
|
|
948
1006
|
s.name,
|
|
949
1007
|
" ",
|
|
950
|
-
/* @__PURE__ */ jsxs2(Text2, {
|
|
1008
|
+
/* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
|
|
951
1009
|
"- ",
|
|
952
1010
|
s.description
|
|
953
1011
|
] })
|
|
@@ -955,7 +1013,14 @@ var SlashSuggestions = memo2(({
|
|
|
955
1013
|
] }, s.name);
|
|
956
1014
|
}) }));
|
|
957
1015
|
SlashSuggestions.displayName = "SlashSuggestions";
|
|
958
|
-
var
|
|
1016
|
+
var InputRuleLine = memo2(() => {
|
|
1017
|
+
const { stdout } = useStdout();
|
|
1018
|
+
const cols = stdout?.columns ?? 80;
|
|
1019
|
+
const n = Math.max(8, cols);
|
|
1020
|
+
return /* @__PURE__ */ jsx2(Text2, { color: "white", children: TERMINAL_RULE_CHAR.repeat(n) });
|
|
1021
|
+
});
|
|
1022
|
+
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 commands | esc interrupt | Ctrl+O expand last clip" }) }));
|
|
959
1024
|
Footer.displayName = "Footer";
|
|
960
1025
|
var TextLinesRenderer = memo2(({
|
|
961
1026
|
lines,
|
|
@@ -965,17 +1030,14 @@ var TextLinesRenderer = memo2(({
|
|
|
965
1030
|
showPlaceholder,
|
|
966
1031
|
placeholder
|
|
967
1032
|
}) => {
|
|
968
|
-
return /* @__PURE__ */ jsx2(
|
|
1033
|
+
return /* @__PURE__ */ jsx2(Fragment, { children: lines.map((line, idx) => {
|
|
969
1034
|
const isFirstLine = idx === 0;
|
|
970
|
-
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "row",
|
|
971
|
-
isFirstLine && /* @__PURE__ */ jsxs2(Text2, { color: "white", children: [
|
|
1035
|
+
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "row", children: [
|
|
1036
|
+
isFirstLine && /* @__PURE__ */ jsxs2(Text2, { color: "white", bold: true, children: [
|
|
972
1037
|
">",
|
|
973
1038
|
" "
|
|
974
1039
|
] }),
|
|
975
|
-
!isFirstLine && /* @__PURE__ */
|
|
976
|
-
"\u2502",
|
|
977
|
-
" "
|
|
978
|
-
] }),
|
|
1040
|
+
!isFirstLine && /* @__PURE__ */ jsx2(Text2, { color: BLUMA_TERMINAL.brandMagenta, children: "\u2502 " }),
|
|
979
1041
|
showPlaceholder && isFirstLine && line.length === 0 ? /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: placeholder }) : /* @__PURE__ */ jsx2(
|
|
980
1042
|
TextLine,
|
|
981
1043
|
{
|
|
@@ -1116,14 +1178,15 @@ var InputPrompt = memo2(({
|
|
|
1116
1178
|
return;
|
|
1117
1179
|
}
|
|
1118
1180
|
}, { isActive: true });
|
|
1119
|
-
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
|
|
1120
|
-
|
|
1121
|
-
|
|
1181
|
+
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", marginTop: 1, children: [
|
|
1182
|
+
/* @__PURE__ */ jsx2(InputRuleLine, {}),
|
|
1183
|
+
/* @__PURE__ */ jsx2(Box2, { flexDirection: "column", marginY: 0, children: disableWhileProcessing ? /* @__PURE__ */ jsxs2(Box2, { flexDirection: "row", flexWrap: "nowrap", children: [
|
|
1184
|
+
/* @__PURE__ */ jsxs2(Text2, { color: "white", bold: true, children: [
|
|
1122
1185
|
">",
|
|
1123
1186
|
" "
|
|
1124
1187
|
] }),
|
|
1125
1188
|
/* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "ctrl+c to exit" })
|
|
1126
|
-
] })
|
|
1189
|
+
] }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
1127
1190
|
/* @__PURE__ */ jsx2(Box2, { flexDirection: "column", children: /* @__PURE__ */ jsx2(
|
|
1128
1191
|
TextLinesRenderer,
|
|
1129
1192
|
{
|
|
@@ -1142,14 +1205,9 @@ var InputPrompt = memo2(({
|
|
|
1142
1205
|
selected: pathAutocomplete.selected
|
|
1143
1206
|
}
|
|
1144
1207
|
),
|
|
1145
|
-
slashOpen && slashSuggestions.length > 0 && /* @__PURE__ */ jsx2(
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
suggestions: slashSuggestions,
|
|
1149
|
-
selectedIndex: slashIndex
|
|
1150
|
-
}
|
|
1151
|
-
)
|
|
1152
|
-
] }),
|
|
1208
|
+
slashOpen && slashSuggestions.length > 0 && /* @__PURE__ */ jsx2(SlashSuggestions, { suggestions: slashSuggestions, selectedIndex: slashIndex })
|
|
1209
|
+
] }) }),
|
|
1210
|
+
/* @__PURE__ */ jsx2(InputRuleLine, {}),
|
|
1153
1211
|
/* @__PURE__ */ jsx2(Footer, { isReadOnly })
|
|
1154
1212
|
] });
|
|
1155
1213
|
});
|
|
@@ -1157,7 +1215,7 @@ InputPrompt.displayName = "InputPrompt";
|
|
|
1157
1215
|
|
|
1158
1216
|
// src/app/ui/ConfirmationPrompt.tsx
|
|
1159
1217
|
import { memo as memo4 } from "react";
|
|
1160
|
-
import { Box as
|
|
1218
|
+
import { Box as Box7, Text as Text7 } from "ink";
|
|
1161
1219
|
|
|
1162
1220
|
// src/app/ui/InteractiveMenu.tsx
|
|
1163
1221
|
import { useState as useState3, memo as memo3 } from "react";
|
|
@@ -1165,9 +1223,9 @@ import { Box as Box3, Text as Text3, useInput as useInput3 } from "ink";
|
|
|
1165
1223
|
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1166
1224
|
var InteractiveMenuComponent = ({ onDecision }) => {
|
|
1167
1225
|
const options = [
|
|
1168
|
-
{ key: "y", label: "yes", value: "accept"
|
|
1169
|
-
{ key: "n", label: "no", value: "decline"
|
|
1170
|
-
{ key: "a", label: "always", value: "accept_always"
|
|
1226
|
+
{ key: "y", label: "yes", value: "accept" },
|
|
1227
|
+
{ key: "n", label: "no", value: "decline" },
|
|
1228
|
+
{ key: "a", label: "always", value: "accept_always" }
|
|
1171
1229
|
];
|
|
1172
1230
|
const [selected, setSelected] = useState3(0);
|
|
1173
1231
|
useInput3((input, key) => {
|
|
@@ -1188,12 +1246,12 @@ var InteractiveMenuComponent = ({ onDecision }) => {
|
|
|
1188
1246
|
onDecision(opt.value);
|
|
1189
1247
|
}
|
|
1190
1248
|
});
|
|
1191
|
-
return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column",
|
|
1192
|
-
/* @__PURE__ */ jsxs3(Box3, { children: [
|
|
1193
|
-
/* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "approve
|
|
1249
|
+
return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", marginTop: 1, children: [
|
|
1250
|
+
/* @__PURE__ */ jsxs3(Box3, { flexDirection: "row", flexWrap: "wrap", children: [
|
|
1251
|
+
/* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "approve \xB7 " }),
|
|
1194
1252
|
options.map((opt, idx) => {
|
|
1195
1253
|
const isSelected = idx === selected;
|
|
1196
|
-
return /* @__PURE__ */ jsx3(Box3, { marginRight: 1, children: /* @__PURE__ */ jsxs3(Text3, { color: isSelected ?
|
|
1254
|
+
return /* @__PURE__ */ jsx3(Box3, { marginRight: 1, children: /* @__PURE__ */ jsxs3(Text3, { color: isSelected ? BLUMA_TERMINAL.brandMagenta : BLUMA_TERMINAL.muted, bold: isSelected, children: [
|
|
1197
1255
|
"[",
|
|
1198
1256
|
opt.key,
|
|
1199
1257
|
"]",
|
|
@@ -1201,7 +1259,7 @@ var InteractiveMenuComponent = ({ onDecision }) => {
|
|
|
1201
1259
|
] }) }, opt.value);
|
|
1202
1260
|
})
|
|
1203
1261
|
] }),
|
|
1204
|
-
/* @__PURE__ */ jsx3(Box3, { children: /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "arrows
|
|
1262
|
+
/* @__PURE__ */ jsx3(Box3, { marginTop: 0, children: /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "arrows \xB7 enter \xB7 esc cancel" }) })
|
|
1205
1263
|
] });
|
|
1206
1264
|
};
|
|
1207
1265
|
var InteractiveMenu = memo3(InteractiveMenuComponent);
|
|
@@ -1354,7 +1412,7 @@ var renderEditTool = ({ toolCall, preview }) => {
|
|
|
1354
1412
|
var renderGeneric = ({ toolCall }) => {
|
|
1355
1413
|
const toolName = toolCall.function.name;
|
|
1356
1414
|
const rawArguments = toolCall.function.arguments;
|
|
1357
|
-
const
|
|
1415
|
+
const MAX_LINES = 5;
|
|
1358
1416
|
let formattedArgsString;
|
|
1359
1417
|
if (!rawArguments) {
|
|
1360
1418
|
formattedArgsString = "";
|
|
@@ -1369,9 +1427,9 @@ var renderGeneric = ({ toolCall }) => {
|
|
|
1369
1427
|
formattedArgsString = JSON.stringify(rawArguments, null, 2);
|
|
1370
1428
|
}
|
|
1371
1429
|
const lines = formattedArgsString.split("\n");
|
|
1372
|
-
const isTruncated = lines.length >
|
|
1373
|
-
const visibleLines = isTruncated ? lines.slice(0,
|
|
1374
|
-
const remainingCount = lines.length -
|
|
1430
|
+
const isTruncated = lines.length > MAX_LINES;
|
|
1431
|
+
const visibleLines = isTruncated ? lines.slice(0, MAX_LINES) : lines;
|
|
1432
|
+
const remainingCount = lines.length - MAX_LINES;
|
|
1375
1433
|
return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [
|
|
1376
1434
|
/* @__PURE__ */ jsxs5(Box5, { children: [
|
|
1377
1435
|
/* @__PURE__ */ jsx5(Text5, { color: "blue", children: "\u25B8" }),
|
|
@@ -1411,12 +1469,12 @@ var renderTodoTool = ({ toolCall }) => {
|
|
|
1411
1469
|
/* @__PURE__ */ jsx5(Text5, { dimColor: true, children: " todo" })
|
|
1412
1470
|
] }),
|
|
1413
1471
|
/* @__PURE__ */ jsxs5(Box5, { paddingLeft: 2, flexDirection: "column", children: [
|
|
1414
|
-
/* @__PURE__ */ jsxs5(Text5, { color: "
|
|
1415
|
-
"
|
|
1472
|
+
/* @__PURE__ */ jsxs5(Text5, { color: "blue", children: [
|
|
1473
|
+
"todo ",
|
|
1416
1474
|
pending,
|
|
1417
|
-
"
|
|
1475
|
+
" open \xB7 ",
|
|
1418
1476
|
completed,
|
|
1419
|
-
"
|
|
1477
|
+
" done"
|
|
1420
1478
|
] }),
|
|
1421
1479
|
tasks.length > 0 && tasks.length <= 10 && /* @__PURE__ */ jsx5(Box5, { paddingLeft: 2, flexDirection: "column", marginTop: 1, children: tasks.map((task, idx) => {
|
|
1422
1480
|
const isComplete = task.isComplete === true;
|
|
@@ -1466,19 +1524,60 @@ var promptRenderers = {
|
|
|
1466
1524
|
// <--- ADICIONE ESTA LINHA
|
|
1467
1525
|
};
|
|
1468
1526
|
|
|
1469
|
-
// src/app/ui/
|
|
1527
|
+
// src/app/ui/theme/m3Layout.tsx
|
|
1528
|
+
import { Box as Box6, Text as Text6 } from "ink";
|
|
1470
1529
|
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1530
|
+
function ChatBlock({
|
|
1531
|
+
children,
|
|
1532
|
+
marginBottom = 1
|
|
1533
|
+
}) {
|
|
1534
|
+
return /* @__PURE__ */ jsx6(Box6, { flexDirection: "column", marginBottom, children });
|
|
1535
|
+
}
|
|
1536
|
+
function ChatUserMessage({ children }) {
|
|
1537
|
+
return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "row", marginBottom: 1, flexWrap: "wrap", alignItems: "flex-start", children: [
|
|
1538
|
+
/* @__PURE__ */ jsxs6(Text6, { color: "white", bold: true, children: [
|
|
1539
|
+
">",
|
|
1540
|
+
" "
|
|
1541
|
+
] }),
|
|
1542
|
+
/* @__PURE__ */ jsx6(Box6, { flexDirection: "column", flexGrow: 1, children })
|
|
1543
|
+
] });
|
|
1544
|
+
}
|
|
1545
|
+
function ChatMeta({ children }) {
|
|
1546
|
+
return /* @__PURE__ */ jsx6(Box6, { marginBottom: 1, children: /* @__PURE__ */ jsx6(Text6, { dimColor: true, children }) });
|
|
1547
|
+
}
|
|
1548
|
+
function ChatStatusRow({ children }) {
|
|
1549
|
+
return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "row", marginBottom: 1, flexWrap: "wrap", children: [
|
|
1550
|
+
/* @__PURE__ */ jsxs6(Text6, { color: BLUMA_TERMINAL.brandMagenta, bold: true, children: [
|
|
1551
|
+
"*",
|
|
1552
|
+
" "
|
|
1553
|
+
] }),
|
|
1554
|
+
children
|
|
1555
|
+
] });
|
|
1556
|
+
}
|
|
1557
|
+
function ChatTurnDuration({ secondsFormatted }) {
|
|
1558
|
+
return /* @__PURE__ */ jsx6(Box6, { marginBottom: 1, children: /* @__PURE__ */ jsxs6(Text6, { dimColor: true, children: [
|
|
1559
|
+
/* @__PURE__ */ jsx6(Text6, { color: BLUMA_TERMINAL.brandBlue, children: "\xB7 " }),
|
|
1560
|
+
/* @__PURE__ */ jsxs6(Text6, { color: BLUMA_TERMINAL.brandMagenta, children: [
|
|
1561
|
+
secondsFormatted,
|
|
1562
|
+
"s"
|
|
1563
|
+
] })
|
|
1564
|
+
] }) });
|
|
1565
|
+
}
|
|
1566
|
+
var M3StatusStrip = ChatStatusRow;
|
|
1567
|
+
|
|
1568
|
+
// src/app/ui/ConfirmationPrompt.tsx
|
|
1569
|
+
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1471
1570
|
var ConfirmationPromptComponent = ({ toolCalls, preview, onDecision }) => {
|
|
1472
|
-
const toolCall = toolCalls && toolCalls.length > 0 ? toolCalls[0] : null;
|
|
1473
|
-
if (!toolCall) {
|
|
1474
|
-
return /* @__PURE__ */
|
|
1571
|
+
const toolCall = toolCalls && Array.isArray(toolCalls) && toolCalls.length > 0 ? toolCalls[0] : null;
|
|
1572
|
+
if (!toolCall?.function) {
|
|
1573
|
+
return /* @__PURE__ */ jsx7(Box7, { paddingX: 1, children: /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "waiting\u2026" }) });
|
|
1475
1574
|
}
|
|
1476
|
-
const toolName = toolCall.function.name;
|
|
1575
|
+
const toolName = toolCall.function.name || "tool";
|
|
1477
1576
|
const renderFunction = promptRenderers[toolName] || renderGeneric;
|
|
1478
|
-
return /* @__PURE__ */
|
|
1577
|
+
return /* @__PURE__ */ jsx7(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", paddingLeft: 1, children: [
|
|
1479
1578
|
renderFunction({ toolCall, preview }),
|
|
1480
|
-
/* @__PURE__ */
|
|
1481
|
-
] });
|
|
1579
|
+
/* @__PURE__ */ jsx7(InteractiveMenu, { onDecision })
|
|
1580
|
+
] }) });
|
|
1482
1581
|
};
|
|
1483
1582
|
var ConfirmationPrompt = memo4(ConfirmationPromptComponent);
|
|
1484
1583
|
|
|
@@ -3605,14 +3704,84 @@ function searchNotes(args) {
|
|
|
3605
3704
|
matched: matches
|
|
3606
3705
|
};
|
|
3607
3706
|
}
|
|
3608
|
-
function
|
|
3707
|
+
function removeNote(args) {
|
|
3609
3708
|
loadMemoryFromFile();
|
|
3610
|
-
|
|
3611
|
-
|
|
3709
|
+
const id = args.id;
|
|
3710
|
+
if (id == null || typeof id !== "number" || !Number.isFinite(id)) {
|
|
3711
|
+
return {
|
|
3712
|
+
success: false,
|
|
3713
|
+
message: "id is required for action=remove (use list or search to get ids)",
|
|
3714
|
+
entries: memoryStore
|
|
3715
|
+
};
|
|
3716
|
+
}
|
|
3717
|
+
const idx = memoryStore.findIndex((e) => e.id === id);
|
|
3718
|
+
if (idx === -1) {
|
|
3719
|
+
return {
|
|
3720
|
+
success: false,
|
|
3721
|
+
message: `No coding memory entry with id=${id}`,
|
|
3722
|
+
entries: memoryStore
|
|
3723
|
+
};
|
|
3724
|
+
}
|
|
3725
|
+
memoryStore.splice(idx, 1);
|
|
3612
3726
|
saveMemoryToFile();
|
|
3613
3727
|
return {
|
|
3614
3728
|
success: true,
|
|
3615
|
-
message:
|
|
3729
|
+
message: `Removed coding memory entry id=${id}`,
|
|
3730
|
+
entries: memoryStore
|
|
3731
|
+
};
|
|
3732
|
+
}
|
|
3733
|
+
function updateNote(args) {
|
|
3734
|
+
loadMemoryFromFile();
|
|
3735
|
+
const id = args.id;
|
|
3736
|
+
if (id == null || typeof id !== "number" || !Number.isFinite(id)) {
|
|
3737
|
+
return {
|
|
3738
|
+
success: false,
|
|
3739
|
+
message: "id is required for action=update",
|
|
3740
|
+
entries: memoryStore
|
|
3741
|
+
};
|
|
3742
|
+
}
|
|
3743
|
+
const entry = memoryStore.find((e) => e.id === id);
|
|
3744
|
+
if (!entry) {
|
|
3745
|
+
return {
|
|
3746
|
+
success: false,
|
|
3747
|
+
message: `No coding memory entry with id=${id}`,
|
|
3748
|
+
entries: memoryStore
|
|
3749
|
+
};
|
|
3750
|
+
}
|
|
3751
|
+
const hasNote = typeof args.note === "string";
|
|
3752
|
+
const hasTags = args.tags !== void 0;
|
|
3753
|
+
if (!hasNote && !hasTags) {
|
|
3754
|
+
return {
|
|
3755
|
+
success: false,
|
|
3756
|
+
message: "update requires `note` and/or `tags` (omit fields you do not want to change)",
|
|
3757
|
+
entries: memoryStore
|
|
3758
|
+
};
|
|
3759
|
+
}
|
|
3760
|
+
if (hasNote) {
|
|
3761
|
+
const newNote = args.note.trim();
|
|
3762
|
+
if (!newNote) {
|
|
3763
|
+
return {
|
|
3764
|
+
success: false,
|
|
3765
|
+
message: "note cannot be empty; omit `note` to keep the existing text",
|
|
3766
|
+
entries: memoryStore
|
|
3767
|
+
};
|
|
3768
|
+
}
|
|
3769
|
+
if (newNote.length > 4e3) {
|
|
3770
|
+
return {
|
|
3771
|
+
success: false,
|
|
3772
|
+
message: "note too long (max 4000 chars)",
|
|
3773
|
+
entries: memoryStore
|
|
3774
|
+
};
|
|
3775
|
+
}
|
|
3776
|
+
entry.note = newNote;
|
|
3777
|
+
}
|
|
3778
|
+
if (hasTags) {
|
|
3779
|
+
entry.tags = normalizeTags(args.tags);
|
|
3780
|
+
}
|
|
3781
|
+
saveMemoryToFile();
|
|
3782
|
+
return {
|
|
3783
|
+
success: true,
|
|
3784
|
+
message: `Updated coding memory id=${id}`,
|
|
3616
3785
|
entries: memoryStore
|
|
3617
3786
|
};
|
|
3618
3787
|
}
|
|
@@ -3625,8 +3794,10 @@ async function coding_memory(args) {
|
|
|
3625
3794
|
return listNotes();
|
|
3626
3795
|
case "search":
|
|
3627
3796
|
return searchNotes(args);
|
|
3628
|
-
case "
|
|
3629
|
-
return
|
|
3797
|
+
case "remove":
|
|
3798
|
+
return removeNote(args);
|
|
3799
|
+
case "update":
|
|
3800
|
+
return updateNote(args);
|
|
3630
3801
|
default:
|
|
3631
3802
|
return {
|
|
3632
3803
|
success: false,
|
|
@@ -3939,20 +4110,21 @@ async function withFileLock(file, fn) {
|
|
|
3939
4110
|
}
|
|
3940
4111
|
var pendingSaves = /* @__PURE__ */ new Map();
|
|
3941
4112
|
var DEBOUNCE_DELAY_MS = 100;
|
|
3942
|
-
function debouncedSave(sessionFile, history) {
|
|
4113
|
+
function debouncedSave(sessionFile, history, memory) {
|
|
3943
4114
|
const existing = pendingSaves.get(sessionFile);
|
|
3944
4115
|
if (existing) {
|
|
3945
4116
|
clearTimeout(existing.timer);
|
|
3946
4117
|
}
|
|
4118
|
+
const resolvedMemory = memory !== void 0 ? memory : existing?.memory;
|
|
3947
4119
|
const timer = setTimeout(async () => {
|
|
3948
4120
|
pendingSaves.delete(sessionFile);
|
|
3949
4121
|
try {
|
|
3950
|
-
await doSaveSessionHistory(sessionFile, history);
|
|
4122
|
+
await doSaveSessionHistory(sessionFile, history, resolvedMemory);
|
|
3951
4123
|
} catch (e) {
|
|
3952
4124
|
console.warn(`Debounced save failed for ${sessionFile}: ${e.message}`);
|
|
3953
4125
|
}
|
|
3954
4126
|
}, DEBOUNCE_DELAY_MS);
|
|
3955
|
-
pendingSaves.set(sessionFile, { history: [...history], timer });
|
|
4127
|
+
pendingSaves.set(sessionFile, { history: [...history], memory: resolvedMemory, timer });
|
|
3956
4128
|
}
|
|
3957
4129
|
function expandHome(p) {
|
|
3958
4130
|
if (!p) return p;
|
|
@@ -4017,7 +4189,11 @@ async function loadOrcreateSession(sessionId) {
|
|
|
4017
4189
|
await fs11.access(sessionFile);
|
|
4018
4190
|
const fileContent = await fs11.readFile(sessionFile, "utf-8");
|
|
4019
4191
|
const sessionData = JSON.parse(fileContent);
|
|
4020
|
-
|
|
4192
|
+
const memory = {
|
|
4193
|
+
historyAnchor: sessionData.history_anchor ?? null,
|
|
4194
|
+
compressedTurnSliceCount: sessionData.compressed_turn_slice_count ?? 0
|
|
4195
|
+
};
|
|
4196
|
+
return [sessionFile, sessionData.conversation_history || [], memory];
|
|
4021
4197
|
} catch (error) {
|
|
4022
4198
|
const newSessionData = {
|
|
4023
4199
|
session_id: sessionId,
|
|
@@ -4025,10 +4201,14 @@ async function loadOrcreateSession(sessionId) {
|
|
|
4025
4201
|
conversation_history: []
|
|
4026
4202
|
};
|
|
4027
4203
|
await fs11.writeFile(sessionFile, JSON.stringify(newSessionData, null, 2), "utf-8");
|
|
4028
|
-
|
|
4204
|
+
const emptyMemory = {
|
|
4205
|
+
historyAnchor: null,
|
|
4206
|
+
compressedTurnSliceCount: 0
|
|
4207
|
+
};
|
|
4208
|
+
return [sessionFile, [], emptyMemory];
|
|
4029
4209
|
}
|
|
4030
4210
|
}
|
|
4031
|
-
async function doSaveSessionHistory(sessionFile, history) {
|
|
4211
|
+
async function doSaveSessionHistory(sessionFile, history, memory) {
|
|
4032
4212
|
await withFileLock(sessionFile, async () => {
|
|
4033
4213
|
let sessionData;
|
|
4034
4214
|
try {
|
|
@@ -4061,6 +4241,14 @@ async function doSaveSessionHistory(sessionFile, history) {
|
|
|
4061
4241
|
}
|
|
4062
4242
|
sessionData.conversation_history = history;
|
|
4063
4243
|
sessionData.last_updated = (/* @__PURE__ */ new Date()).toISOString();
|
|
4244
|
+
if (memory) {
|
|
4245
|
+
if (memory.historyAnchor) {
|
|
4246
|
+
sessionData.history_anchor = memory.historyAnchor;
|
|
4247
|
+
} else {
|
|
4248
|
+
delete sessionData.history_anchor;
|
|
4249
|
+
}
|
|
4250
|
+
sessionData.compressed_turn_slice_count = memory.compressedTurnSliceCount;
|
|
4251
|
+
}
|
|
4064
4252
|
const tempSessionFile = `${sessionFile}.${Date.now()}.tmp`;
|
|
4065
4253
|
try {
|
|
4066
4254
|
await fs11.writeFile(tempSessionFile, JSON.stringify(sessionData, null, 2), "utf-8");
|
|
@@ -4078,14 +4266,14 @@ async function doSaveSessionHistory(sessionFile, history) {
|
|
|
4078
4266
|
}
|
|
4079
4267
|
});
|
|
4080
4268
|
}
|
|
4081
|
-
async function saveSessionHistory(sessionFile, history) {
|
|
4269
|
+
async function saveSessionHistory(sessionFile, history, memory) {
|
|
4082
4270
|
const cleanHistory = history.filter((msg) => {
|
|
4083
4271
|
if (msg.role === "user" && typeof msg.content === "string") {
|
|
4084
4272
|
return !msg.content.startsWith("[SKILL:");
|
|
4085
4273
|
}
|
|
4086
4274
|
return true;
|
|
4087
4275
|
});
|
|
4088
|
-
debouncedSave(sessionFile, cleanHistory);
|
|
4276
|
+
debouncedSave(sessionFile, cleanHistory, memory);
|
|
4089
4277
|
}
|
|
4090
4278
|
|
|
4091
4279
|
// src/app/agent/core/prompt/prompt_builder.ts
|
|
@@ -4098,7 +4286,6 @@ import { execSync } from "child_process";
|
|
|
4098
4286
|
import fs12 from "fs";
|
|
4099
4287
|
import path14 from "path";
|
|
4100
4288
|
import os7 from "os";
|
|
4101
|
-
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
4102
4289
|
var SkillLoader = class _SkillLoader {
|
|
4103
4290
|
bundledSkillsDir;
|
|
4104
4291
|
projectSkillsDir;
|
|
@@ -4115,19 +4302,26 @@ var SkillLoader = class _SkillLoader {
|
|
|
4115
4302
|
* Funciona tanto em ESM como quando executado a partir de dist/.
|
|
4116
4303
|
*/
|
|
4117
4304
|
static resolveBundledDir() {
|
|
4118
|
-
if (process.env.
|
|
4119
|
-
if (typeof __dirname !== "undefined") {
|
|
4120
|
-
return path14.join(__dirname, "config", "skills");
|
|
4121
|
-
}
|
|
4305
|
+
if (process.env.JEST_WORKER_ID !== void 0 || process.env.NODE_ENV === "test") {
|
|
4122
4306
|
return path14.join(process.cwd(), "dist", "config", "skills");
|
|
4123
4307
|
}
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4308
|
+
const candidates = [
|
|
4309
|
+
path14.join(process.cwd(), "dist", "config", "skills"),
|
|
4310
|
+
path14.join(process.cwd(), "node_modules", "@nomad-e", "bluma-cli", "dist", "config", "skills")
|
|
4311
|
+
];
|
|
4312
|
+
if (typeof __dirname !== "undefined") {
|
|
4313
|
+
candidates.push(
|
|
4314
|
+
path14.join(__dirname, "config", "skills"),
|
|
4315
|
+
path14.join(__dirname, "..", "..", "..", "config", "skills")
|
|
4316
|
+
);
|
|
4130
4317
|
}
|
|
4318
|
+
for (const c of candidates) {
|
|
4319
|
+
const abs = path14.resolve(c);
|
|
4320
|
+
if (fs12.existsSync(abs)) {
|
|
4321
|
+
return abs;
|
|
4322
|
+
}
|
|
4323
|
+
}
|
|
4324
|
+
return path14.join(process.cwd(), "dist", "config", "skills");
|
|
4131
4325
|
}
|
|
4132
4326
|
/**
|
|
4133
4327
|
* Lista skills disponíveis de todas as fontes.
|
|
@@ -4553,19 +4747,35 @@ You MUST adapt all commands to this environment. Use the correct package manager
|
|
|
4553
4747
|
<coding_memory>
|
|
4554
4748
|
## Persistent coding memory (tool: \`coding_memory\`)
|
|
4555
4749
|
|
|
4556
|
-
|
|
4750
|
+
This is your **long-term scratchpad** (usually \`~/.bluma/coding_memory.json\`). It is **not** the chat log: it persists across sessions so you can behave like a coding agent that **actually recalls** stable project facts\u2014**but only if you use the tool**.
|
|
4751
|
+
|
|
4752
|
+
### Ground rules
|
|
4753
|
+
- **Never invent** what is stored: if you are not sure, run \`action: "search"\` (or \`list\`) before stating a remembered fact.
|
|
4754
|
+
- The **<coding_memory_snapshot>** below is a **one-time snapshot at session start**. After any \`add\`, \`remove\`, or \`update\` in this session, treat the snapshot as **possibly stale** and **search** or **list** before relying on it.
|
|
4755
|
+
- Do **not** ask the user for permission to search memory when it reduces risk (e.g. they mention a prior decision, branch name, or "as we agreed").
|
|
4756
|
+
- **There is no "clear all"**: you can only **remove** entries **one id at a time** (\`action: "remove"\`, \`id\`). To fix bad data, \`update\` or \`remove\` specific ids.
|
|
4557
4757
|
|
|
4558
|
-
###
|
|
4559
|
-
-
|
|
4560
|
-
-
|
|
4758
|
+
### When to search first
|
|
4759
|
+
- User: "lembra-te / remember / last time / o que combin\xE1mos / qual era o comando".
|
|
4760
|
+
- You are about to edit, run tests, or refactor using **assumptions** that came from earlier in this project (stack, scripts, env vars, URLs).
|
|
4761
|
+
- You return to a task after many unrelated turns\u2014the chat may have been compressed; **memory on disk still holds** the durable notes if you saved them.
|
|
4561
4762
|
|
|
4562
|
-
### When to
|
|
4563
|
-
-
|
|
4564
|
-
-
|
|
4763
|
+
### When to add
|
|
4764
|
+
- **Stable** facts: architecture, naming conventions, test commands, ports, API bases, repo layout, user preferences that repeat.
|
|
4765
|
+
- **Pointers**, not novels: one short \`note\` + \`tags\` (e.g. \`auth\`, \`deploy\`, \`bluma\`). Put long specs in the repo; here only **reminders**.
|
|
4766
|
+
|
|
4767
|
+
### CRUD (tool actions)
|
|
4768
|
+
- **Create:** \`add\` + \`note\` (+ optional \`tags\`).
|
|
4769
|
+
- **Read:** \`list\` (all ids) or \`search\` + \`query\`.
|
|
4770
|
+
- **Update:** \`update\` + \`id\` + new \`note\` and/or \`tags\` (omit fields you leave unchanged).
|
|
4771
|
+
- **Delete:** \`remove\` + \`id\` only \u2014 **never** bulk-wipe; the product intentionally forbids it.
|
|
4772
|
+
|
|
4773
|
+
### When something changes
|
|
4774
|
+
- Prefer \`update\` on the same \`id\` when correcting a note; add a **new** note if the old one should remain as history; \`remove\` obsolete ids.
|
|
4565
4775
|
|
|
4566
4776
|
### Habits (continuity)
|
|
4567
|
-
- Prefer **search** or **list** over guessing
|
|
4568
|
-
-
|
|
4777
|
+
- Prefer **search** or **list** over guessing whenever "memory" matters.
|
|
4778
|
+
- After important milestones (feature done, bug fixed, migration applied), consider a **brief add** so future-you in a new session is not blind.
|
|
4569
4779
|
</coding_memory>
|
|
4570
4780
|
|
|
4571
4781
|
---
|
|
@@ -4601,6 +4811,7 @@ Run tests when modifying code. If a testing skill is listed in available_skills,
|
|
|
4601
4811
|
- **ALWAYS read a file before editing** - Use read_file_lines or ls_tool first
|
|
4602
4812
|
- **Use absolute paths** when possible to avoid ambiguity
|
|
4603
4813
|
- **For edit_tool**: Provide exact content with correct whitespace (read first!)
|
|
4814
|
+
- **Truncated CLI preview** (user may press Ctrl+O for more lines): still not a substitute for \`read_file_lines\` \u2014 use the tool for authoritative content before editing
|
|
4604
4815
|
- **Check file exists** before attempting edits
|
|
4605
4816
|
|
|
4606
4817
|
### Safe Auto-Approved Tools (no confirmation needed):
|
|
@@ -5080,7 +5291,7 @@ User: "Publish the package"
|
|
|
5080
5291
|
<coding_memory_snapshot>
|
|
5081
5292
|
## Persistent notes (loaded at session start from disk)
|
|
5082
5293
|
|
|
5083
|
-
${memorySnapshot.trim().length > 0 ? memorySnapshot : "(No entries yet. Use coding_memory
|
|
5294
|
+
${memorySnapshot.trim().length > 0 ? memorySnapshot : "(No entries yet. Use coding_memory: add, list, search \u2014 remove/update by id when needed.)"}
|
|
5084
5295
|
</coding_memory_snapshot>
|
|
5085
5296
|
`;
|
|
5086
5297
|
return prompt;
|
|
@@ -5094,6 +5305,161 @@ function isGitRepo(dir) {
|
|
|
5094
5305
|
}
|
|
5095
5306
|
}
|
|
5096
5307
|
|
|
5308
|
+
// src/app/agent/core/context-api/token_counter.ts
|
|
5309
|
+
import { getEncoding } from "js-tiktoken";
|
|
5310
|
+
var MESSAGE_OVERHEAD_TOKENS = 4;
|
|
5311
|
+
var CONVERSATION_BASE_OVERHEAD = 3;
|
|
5312
|
+
var cachedEncoding = null;
|
|
5313
|
+
function getO200kEncoding() {
|
|
5314
|
+
if (!cachedEncoding) {
|
|
5315
|
+
cachedEncoding = getEncoding("o200k_base");
|
|
5316
|
+
}
|
|
5317
|
+
return cachedEncoding;
|
|
5318
|
+
}
|
|
5319
|
+
function messageBodyForTokens(msg) {
|
|
5320
|
+
const c = msg.content;
|
|
5321
|
+
if (c == null) {
|
|
5322
|
+
return "";
|
|
5323
|
+
}
|
|
5324
|
+
if (typeof c === "string") {
|
|
5325
|
+
return c;
|
|
5326
|
+
}
|
|
5327
|
+
return JSON.stringify(c);
|
|
5328
|
+
}
|
|
5329
|
+
function messageExtraForTokens(msg) {
|
|
5330
|
+
const m = msg;
|
|
5331
|
+
const parts = [String(m.role ?? "")];
|
|
5332
|
+
if (Array.isArray(m.tool_calls)) {
|
|
5333
|
+
parts.push(JSON.stringify(m.tool_calls));
|
|
5334
|
+
}
|
|
5335
|
+
if (typeof m.tool_call_id === "string") {
|
|
5336
|
+
parts.push(m.tool_call_id);
|
|
5337
|
+
}
|
|
5338
|
+
if (typeof m.name === "string") {
|
|
5339
|
+
parts.push(m.name);
|
|
5340
|
+
}
|
|
5341
|
+
return parts.join("\0");
|
|
5342
|
+
}
|
|
5343
|
+
function countTokens(messages) {
|
|
5344
|
+
if (messages.length === 0) {
|
|
5345
|
+
return CONVERSATION_BASE_OVERHEAD;
|
|
5346
|
+
}
|
|
5347
|
+
const enc = getO200kEncoding();
|
|
5348
|
+
let total = CONVERSATION_BASE_OVERHEAD;
|
|
5349
|
+
for (const msg of messages) {
|
|
5350
|
+
const body = messageBodyForTokens(msg);
|
|
5351
|
+
const extra = messageExtraForTokens(msg);
|
|
5352
|
+
const nBody = body ? enc.encode(body).length : 0;
|
|
5353
|
+
const nExtra = extra ? enc.encode(extra).length : 0;
|
|
5354
|
+
total += nBody + nExtra + MESSAGE_OVERHEAD_TOKENS;
|
|
5355
|
+
}
|
|
5356
|
+
return total;
|
|
5357
|
+
}
|
|
5358
|
+
|
|
5359
|
+
// src/app/agent/core/context-api/history_anchor.ts
|
|
5360
|
+
function stripJsonFence(text) {
|
|
5361
|
+
let s = text.trim();
|
|
5362
|
+
const fence = /^```(?:json)?\s*([\s\S]*?)```\s*$/im.exec(s);
|
|
5363
|
+
if (fence) {
|
|
5364
|
+
s = fence[1].trim();
|
|
5365
|
+
}
|
|
5366
|
+
return s;
|
|
5367
|
+
}
|
|
5368
|
+
function parseAnchorJson(raw) {
|
|
5369
|
+
const cleaned = stripJsonFence(raw);
|
|
5370
|
+
const start = cleaned.indexOf("{");
|
|
5371
|
+
const end = cleaned.lastIndexOf("}");
|
|
5372
|
+
if (start === -1 || end === -1 || end <= start) {
|
|
5373
|
+
throw new Error("compressToAnchor: resposta sem JSON object");
|
|
5374
|
+
}
|
|
5375
|
+
const parsed = JSON.parse(cleaned.slice(start, end + 1));
|
|
5376
|
+
return {
|
|
5377
|
+
intent: String(parsed.intent ?? ""),
|
|
5378
|
+
filesModified: Array.isArray(parsed.filesModified) ? parsed.filesModified.map(String) : [],
|
|
5379
|
+
decisionsMade: Array.isArray(parsed.decisionsMade) ? parsed.decisionsMade.map(String) : [],
|
|
5380
|
+
errorsEncountered: Array.isArray(parsed.errorsEncountered) ? parsed.errorsEncountered.map(String) : [],
|
|
5381
|
+
currentState: String(parsed.currentState ?? ""),
|
|
5382
|
+
nextSteps: String(parsed.nextSteps ?? ""),
|
|
5383
|
+
compressedAt: typeof parsed.compressedAt === "number" ? parsed.compressedAt : Date.now(),
|
|
5384
|
+
turnsCompressed: typeof parsed.turnsCompressed === "number" ? parsed.turnsCompressed : 0
|
|
5385
|
+
};
|
|
5386
|
+
}
|
|
5387
|
+
function formatMessagesForPrompt(msgs) {
|
|
5388
|
+
return msgs.map((m, i) => {
|
|
5389
|
+
const role = m.role ?? "?";
|
|
5390
|
+
const content = m.content;
|
|
5391
|
+
const text = typeof content === "string" ? content : content == null ? "" : JSON.stringify(content);
|
|
5392
|
+
const toolCalls = m.tool_calls;
|
|
5393
|
+
const tail = toolCalls ? `
|
|
5394
|
+
[tool_calls]: ${JSON.stringify(toolCalls)}` : "";
|
|
5395
|
+
return `--- msg ${i + 1} (${role}) ---
|
|
5396
|
+
${text.slice(0, 12e4)}${tail}`;
|
|
5397
|
+
}).join("\n\n");
|
|
5398
|
+
}
|
|
5399
|
+
async function compressToAnchor(spansToCompress, existingAnchor, llmService, userContext, turnSlicesInBatch) {
|
|
5400
|
+
const messagesBlock = formatMessagesForPrompt(spansToCompress);
|
|
5401
|
+
const existingBlock = existingAnchor ? `ANCHOR EXISTENTE (estende este, n\xE3o substitui \u2014 merge sem perder informa\xE7\xE3o):
|
|
5402
|
+
${JSON.stringify(existingAnchor, null, 2)}` : "N\xE3o existe anchor anterior.";
|
|
5403
|
+
const userPrompt = `Tu \xE9s um compressor de hist\xF3rico para um agente de c\xF3digo CLI.
|
|
5404
|
+
|
|
5405
|
+
${existingBlock}
|
|
5406
|
+
|
|
5407
|
+
MENSAGENS A COMPRIMIR (turnos antigos da conversa):
|
|
5408
|
+
${messagesBlock}
|
|
5409
|
+
|
|
5410
|
+
Produz um JSON com esta estrutura exata:
|
|
5411
|
+
{
|
|
5412
|
+
"intent": "objetivo principal da sess\xE3o",
|
|
5413
|
+
"filesModified": ["path1", "path2"],
|
|
5414
|
+
"decisionsMade": ["decis\xE3o 1", "decis\xE3o 2"],
|
|
5415
|
+
"errorsEncountered": ["erro X \u2192 resolvido com Y"],
|
|
5416
|
+
"currentState": "onde estamos agora em 2-3 frases",
|
|
5417
|
+
"nextSteps": "o que est\xE1 pendente",
|
|
5418
|
+
"compressedAt": ${Date.now()},
|
|
5419
|
+
"turnsCompressed": 0
|
|
5420
|
+
}
|
|
5421
|
+
|
|
5422
|
+
Regras:
|
|
5423
|
+
- Responde APENAS com JSON v\xE1lido, sem markdown, sem texto extra
|
|
5424
|
+
- filesModified: inclui TODOS os paths de ficheiros mencionados
|
|
5425
|
+
- decisionsMade: preserva decis\xF5es de arquitetura, abordagem, estrutura
|
|
5426
|
+
- errorsEncountered: formato "erro \u2192 solu\xE7\xE3o"
|
|
5427
|
+
- Se j\xE1 existe anchor, faz merge \u2014 n\xE3o percas informa\xE7\xE3o anterior
|
|
5428
|
+
- O campo turnsCompressed na resposta ser\xE1 ignorado; usa 0.`;
|
|
5429
|
+
const resp = await llmService.chatCompletion({
|
|
5430
|
+
messages: [
|
|
5431
|
+
{
|
|
5432
|
+
role: "system",
|
|
5433
|
+
content: "\xC9s um extrator factual. Sa\xEDda: apenas um objeto JSON v\xE1lido, sem markdown."
|
|
5434
|
+
},
|
|
5435
|
+
{ role: "user", content: userPrompt }
|
|
5436
|
+
],
|
|
5437
|
+
temperature: 0,
|
|
5438
|
+
max_tokens: 4096,
|
|
5439
|
+
userContext
|
|
5440
|
+
});
|
|
5441
|
+
const text = resp.choices[0]?.message?.content;
|
|
5442
|
+
if (typeof text !== "string" || !text.trim()) {
|
|
5443
|
+
throw new Error("compressToAnchor: modelo n\xE3o devolveu conte\xFAdo textual");
|
|
5444
|
+
}
|
|
5445
|
+
const anchor = parseAnchorJson(text);
|
|
5446
|
+
const prevTurns = existingAnchor?.turnsCompressed ?? 0;
|
|
5447
|
+
anchor.turnsCompressed = prevTurns + Math.max(0, turnSlicesInBatch);
|
|
5448
|
+
anchor.compressedAt = Date.now();
|
|
5449
|
+
return anchor;
|
|
5450
|
+
}
|
|
5451
|
+
function anchorToSystemMessage(anchor) {
|
|
5452
|
+
const date = new Date(anchor.compressedAt).toISOString();
|
|
5453
|
+
const content = `[MEM\xD3RIA DE SESS\xC3O \u2014 ${anchor.turnsCompressed} turnos comprimidos em ${date}]
|
|
5454
|
+
Objetivo: ${anchor.intent}
|
|
5455
|
+
Ficheiros modificados: ${anchor.filesModified.join(", ") || "(nenhum)"}
|
|
5456
|
+
Decis\xF5es tomadas: ${anchor.decisionsMade.join(" | ") || "(nenhuma)"}
|
|
5457
|
+
Erros resolvidos: ${anchor.errorsEncountered.join(" | ") || "(nenhum)"}
|
|
5458
|
+
Estado atual: ${anchor.currentState}
|
|
5459
|
+
Pr\xF3ximos passos: ${anchor.nextSteps}`;
|
|
5460
|
+
return { role: "system", content };
|
|
5461
|
+
}
|
|
5462
|
+
|
|
5097
5463
|
// src/app/agent/core/context-api/context_manager.ts
|
|
5098
5464
|
function isEndTurnToolCall(tc) {
|
|
5099
5465
|
if (tc.function.name === "agent_end_turn") {
|
|
@@ -5109,40 +5475,26 @@ function isEndTurnToolCall(tc) {
|
|
|
5109
5475
|
}
|
|
5110
5476
|
return false;
|
|
5111
5477
|
}
|
|
5112
|
-
function
|
|
5113
|
-
if (!fullHistory.length) {
|
|
5114
|
-
return [];
|
|
5115
|
-
}
|
|
5116
|
-
if (maxTurns === null || maxTurns === void 0) {
|
|
5117
|
-
return [...fullHistory];
|
|
5118
|
-
}
|
|
5119
|
-
const systemMessages = [];
|
|
5120
|
-
let historyStartIndex = 0;
|
|
5121
|
-
while (historyStartIndex < fullHistory.length && fullHistory[historyStartIndex].role === "system") {
|
|
5122
|
-
systemMessages.push(fullHistory[historyStartIndex]);
|
|
5123
|
-
historyStartIndex++;
|
|
5124
|
-
}
|
|
5125
|
-
const conversationHistory = fullHistory.slice(historyStartIndex);
|
|
5478
|
+
function partitionConversationIntoTurnSlices(conversationHistory) {
|
|
5126
5479
|
const turns = [];
|
|
5127
5480
|
let currentTurn = [];
|
|
5128
|
-
let turnsFound = 0;
|
|
5129
5481
|
const isDevOverlay = (m) => m?.role === "user" && m?.name === "user_overlay";
|
|
5130
5482
|
for (let i = conversationHistory.length - 1; i >= 0; i--) {
|
|
5131
5483
|
const msg = conversationHistory[i];
|
|
5132
5484
|
currentTurn.unshift(msg);
|
|
5133
|
-
const endsWithAgentEnd = msg.role === "assistant" && msg.tool_calls?.some(
|
|
5485
|
+
const endsWithAgentEnd = msg.role === "assistant" && msg.tool_calls?.some(
|
|
5486
|
+
(tc) => isEndTurnToolCall(tc)
|
|
5487
|
+
);
|
|
5134
5488
|
if (endsWithAgentEnd) {
|
|
5135
5489
|
turns.unshift([...currentTurn]);
|
|
5136
5490
|
currentTurn = [];
|
|
5137
|
-
turnsFound++;
|
|
5138
|
-
if (turnsFound >= maxTurns) {
|
|
5139
|
-
break;
|
|
5140
|
-
}
|
|
5141
5491
|
continue;
|
|
5142
5492
|
}
|
|
5143
5493
|
const prev = conversationHistory[i - 1];
|
|
5144
5494
|
if (msg.role === "user" && !isDevOverlay(msg)) {
|
|
5145
|
-
if (prev && prev.role === "assistant" && !prev.tool_calls?.some(
|
|
5495
|
+
if (prev && prev.role === "assistant" && !prev.tool_calls?.some(
|
|
5496
|
+
(tc) => isEndTurnToolCall(tc)
|
|
5497
|
+
)) {
|
|
5146
5498
|
const hasNonOverlay = currentTurn.some((m) => m.role !== "user" || !isDevOverlay(m));
|
|
5147
5499
|
if (hasNonOverlay) {
|
|
5148
5500
|
turns.unshift([...currentTurn]);
|
|
@@ -5154,8 +5506,76 @@ function createApiContextWindow(fullHistory, maxTurns) {
|
|
|
5154
5506
|
if (currentTurn.length > 0) {
|
|
5155
5507
|
turns.unshift(currentTurn);
|
|
5156
5508
|
}
|
|
5157
|
-
|
|
5158
|
-
|
|
5509
|
+
return turns;
|
|
5510
|
+
}
|
|
5511
|
+
var DEFAULT_TOKEN_BUDGET = 6e4;
|
|
5512
|
+
var DEFAULT_COMPRESS_THRESHOLD = 0.7;
|
|
5513
|
+
var DEFAULT_KEEP_RECENT_TURNS = 8;
|
|
5514
|
+
function readContextOptionInt(envKey, fallback) {
|
|
5515
|
+
const raw = (process.env[envKey] ?? "").trim();
|
|
5516
|
+
if (!raw) return fallback;
|
|
5517
|
+
const n = Number(raw);
|
|
5518
|
+
return Number.isFinite(n) && n > 0 ? Math.floor(n) : fallback;
|
|
5519
|
+
}
|
|
5520
|
+
function readContextOptionFloat(envKey, fallback) {
|
|
5521
|
+
const raw = (process.env[envKey] ?? "").trim();
|
|
5522
|
+
if (!raw) return fallback;
|
|
5523
|
+
const n = Number(raw);
|
|
5524
|
+
return Number.isFinite(n) && n > 0 && n <= 1 ? n : fallback;
|
|
5525
|
+
}
|
|
5526
|
+
function buildContextMessages(systemMessages, anchor, pendingRaw, recentFlat) {
|
|
5527
|
+
const anchorMsg = anchor ? [anchorToSystemMessage(anchor)] : [];
|
|
5528
|
+
return [...systemMessages, ...anchorMsg, ...pendingRaw, ...recentFlat];
|
|
5529
|
+
}
|
|
5530
|
+
async function createApiContextWindow(fullHistory, currentAnchor, compressedTurnSliceCount, llmService, userContext, options) {
|
|
5531
|
+
if (!fullHistory.length) {
|
|
5532
|
+
return {
|
|
5533
|
+
messages: [],
|
|
5534
|
+
newAnchor: currentAnchor,
|
|
5535
|
+
newCompressedTurnSliceCount: compressedTurnSliceCount
|
|
5536
|
+
};
|
|
5537
|
+
}
|
|
5538
|
+
const tokenBudget = options?.tokenBudget ?? readContextOptionInt("BLUMA_CONTEXT_TOKEN_BUDGET", DEFAULT_TOKEN_BUDGET);
|
|
5539
|
+
const compressThreshold = options?.compressThreshold ?? readContextOptionFloat("BLUMA_COMPRESS_THRESHOLD", DEFAULT_COMPRESS_THRESHOLD);
|
|
5540
|
+
const keepRecentTurns = options?.keepRecentTurns ?? readContextOptionInt("BLUMA_KEEP_RECENT_TURNS", DEFAULT_KEEP_RECENT_TURNS);
|
|
5541
|
+
const systemMessages = [];
|
|
5542
|
+
let historyStartIndex = 0;
|
|
5543
|
+
while (historyStartIndex < fullHistory.length && fullHistory[historyStartIndex].role === "system") {
|
|
5544
|
+
systemMessages.push(fullHistory[historyStartIndex]);
|
|
5545
|
+
historyStartIndex++;
|
|
5546
|
+
}
|
|
5547
|
+
const conversationHistory = fullHistory.slice(historyStartIndex);
|
|
5548
|
+
const turnSlices = partitionConversationIntoTurnSlices(conversationHistory);
|
|
5549
|
+
const n = turnSlices.length;
|
|
5550
|
+
const recentStart = Math.max(0, n - keepRecentTurns);
|
|
5551
|
+
let sliceCount = Math.min(Math.max(0, compressedTurnSliceCount), recentStart);
|
|
5552
|
+
let anchor = currentAnchor;
|
|
5553
|
+
const recentSlices = turnSlices.slice(recentStart);
|
|
5554
|
+
const recentFlat = recentSlices.flat();
|
|
5555
|
+
const thresholdTokens = tokenBudget * compressThreshold;
|
|
5556
|
+
let pendingSlices = turnSlices.slice(sliceCount, recentStart);
|
|
5557
|
+
let pendingFlat = pendingSlices.flat();
|
|
5558
|
+
let messages = buildContextMessages(systemMessages, anchor, pendingFlat, recentFlat);
|
|
5559
|
+
let tokens = countTokens(messages);
|
|
5560
|
+
while (tokens >= thresholdTokens && pendingSlices.length > 0) {
|
|
5561
|
+
anchor = await compressToAnchor(
|
|
5562
|
+
pendingFlat,
|
|
5563
|
+
anchor,
|
|
5564
|
+
llmService,
|
|
5565
|
+
userContext,
|
|
5566
|
+
pendingSlices.length
|
|
5567
|
+
);
|
|
5568
|
+
sliceCount = recentStart;
|
|
5569
|
+
pendingSlices = [];
|
|
5570
|
+
pendingFlat = [];
|
|
5571
|
+
messages = buildContextMessages(systemMessages, anchor, pendingFlat, recentFlat);
|
|
5572
|
+
tokens = countTokens(messages);
|
|
5573
|
+
}
|
|
5574
|
+
return {
|
|
5575
|
+
messages,
|
|
5576
|
+
newAnchor: anchor,
|
|
5577
|
+
newCompressedTurnSliceCount: sliceCount
|
|
5578
|
+
};
|
|
5159
5579
|
}
|
|
5160
5580
|
|
|
5161
5581
|
// src/app/agent/core/llm/llm.ts
|
|
@@ -5538,7 +5958,9 @@ var BluMaAgent = class {
|
|
|
5538
5958
|
mcpClient;
|
|
5539
5959
|
feedbackSystem;
|
|
5540
5960
|
skillLoader;
|
|
5541
|
-
|
|
5961
|
+
/** Memória comprimida persistida (turnos antigos) + cursor de fatias já absorvidas. */
|
|
5962
|
+
sessionAnchor = null;
|
|
5963
|
+
compressedTurnSliceCount = 0;
|
|
5542
5964
|
isInterrupted = false;
|
|
5543
5965
|
/** Mesmo turnId durante processTurn + todo o loop de tool_calls (FactorRouter). */
|
|
5544
5966
|
activeTurnContext = null;
|
|
@@ -5562,23 +5984,38 @@ var BluMaAgent = class {
|
|
|
5562
5984
|
this.eventBus.emit("backend_message", { type: "user_overlay", payload: clean, ts: data.ts || Date.now() });
|
|
5563
5985
|
try {
|
|
5564
5986
|
if (this.sessionFile) {
|
|
5565
|
-
|
|
5987
|
+
this.persistSession();
|
|
5566
5988
|
} else {
|
|
5567
|
-
const [sessionFile,
|
|
5989
|
+
const [sessionFile, , mem] = await loadOrcreateSession(this.sessionId);
|
|
5568
5990
|
this.sessionFile = sessionFile;
|
|
5569
|
-
|
|
5991
|
+
this.sessionAnchor = mem.historyAnchor;
|
|
5992
|
+
this.compressedTurnSliceCount = mem.compressedTurnSliceCount;
|
|
5993
|
+
this.persistSession();
|
|
5570
5994
|
}
|
|
5571
5995
|
} catch (e) {
|
|
5572
5996
|
this.eventBus.emit("backend_message", { type: "error", message: `Falha ao salvar hist\xF3rico ap\xF3s user_overlay: ${e.message}` });
|
|
5573
5997
|
}
|
|
5574
5998
|
});
|
|
5575
5999
|
}
|
|
6000
|
+
getMemorySnapshot() {
|
|
6001
|
+
return {
|
|
6002
|
+
historyAnchor: this.sessionAnchor,
|
|
6003
|
+
compressedTurnSliceCount: this.compressedTurnSliceCount
|
|
6004
|
+
};
|
|
6005
|
+
}
|
|
6006
|
+
/** Debounced: grava histórico + estado de compressão no mesmo ficheiro de sessão. */
|
|
6007
|
+
persistSession() {
|
|
6008
|
+
if (!this.sessionFile) return;
|
|
6009
|
+
void saveSessionHistory(this.sessionFile, this.history, this.getMemorySnapshot());
|
|
6010
|
+
}
|
|
5576
6011
|
async initialize() {
|
|
5577
6012
|
await this.mcpClient.nativeToolInvoker.initialize();
|
|
5578
6013
|
await this.mcpClient.initialize();
|
|
5579
|
-
const [sessionFile, history] = await loadOrcreateSession(this.sessionId);
|
|
6014
|
+
const [sessionFile, history, mem] = await loadOrcreateSession(this.sessionId);
|
|
5580
6015
|
this.sessionFile = sessionFile;
|
|
5581
6016
|
this.history = history;
|
|
6017
|
+
this.sessionAnchor = mem.historyAnchor;
|
|
6018
|
+
this.compressedTurnSliceCount = mem.compressedTurnSliceCount;
|
|
5582
6019
|
initializeSkillContext({
|
|
5583
6020
|
history: this.history,
|
|
5584
6021
|
skillLoader: this.skillLoader
|
|
@@ -5604,7 +6041,7 @@ var BluMaAgent = class {
|
|
|
5604
6041
|
}
|
|
5605
6042
|
const systemPrompt = getUnifiedSystemPrompt(availableSkills);
|
|
5606
6043
|
this.history.push({ role: "system", content: systemPrompt });
|
|
5607
|
-
|
|
6044
|
+
this.persistSession();
|
|
5608
6045
|
}
|
|
5609
6046
|
}
|
|
5610
6047
|
getAvailableTools() {
|
|
@@ -5634,11 +6071,13 @@ var BluMaAgent = class {
|
|
|
5634
6071
|
let toolResultContent;
|
|
5635
6072
|
let shouldContinueConversation = true;
|
|
5636
6073
|
if (!this.sessionFile) {
|
|
5637
|
-
const [sessionFile, history] = await loadOrcreateSession(this.sessionId);
|
|
6074
|
+
const [sessionFile, history, mem] = await loadOrcreateSession(this.sessionId);
|
|
5638
6075
|
this.sessionFile = sessionFile;
|
|
5639
6076
|
if (this.history.length === 0 && history.length > 0) {
|
|
5640
6077
|
this.history = history;
|
|
5641
6078
|
}
|
|
6079
|
+
this.sessionAnchor = mem.historyAnchor;
|
|
6080
|
+
this.compressedTurnSliceCount = mem.compressedTurnSliceCount;
|
|
5642
6081
|
}
|
|
5643
6082
|
if (decisionData.type === "user_decision_execute") {
|
|
5644
6083
|
const toolName = toolCall.function.name;
|
|
@@ -5660,7 +6099,7 @@ var BluMaAgent = class {
|
|
|
5660
6099
|
raw_arguments: toolCall.function.arguments
|
|
5661
6100
|
});
|
|
5662
6101
|
this.history.push({ role: "tool", tool_call_id: toolCall.id, content: toolResultContent });
|
|
5663
|
-
|
|
6102
|
+
this.persistSession();
|
|
5664
6103
|
await this._continueConversation();
|
|
5665
6104
|
return;
|
|
5666
6105
|
}
|
|
@@ -5672,7 +6111,7 @@ var BluMaAgent = class {
|
|
|
5672
6111
|
received: toolArgs
|
|
5673
6112
|
});
|
|
5674
6113
|
this.history.push({ role: "tool", tool_call_id: toolCall.id, content: toolResultContent });
|
|
5675
|
-
|
|
6114
|
+
this.persistSession();
|
|
5676
6115
|
await this._continueConversation();
|
|
5677
6116
|
return;
|
|
5678
6117
|
}
|
|
@@ -5683,7 +6122,7 @@ var BluMaAgent = class {
|
|
|
5683
6122
|
received: toolArgs
|
|
5684
6123
|
});
|
|
5685
6124
|
this.history.push({ role: "tool", tool_call_id: toolCall.id, content: toolResultContent });
|
|
5686
|
-
|
|
6125
|
+
this.persistSession();
|
|
5687
6126
|
await this._continueConversation();
|
|
5688
6127
|
return;
|
|
5689
6128
|
}
|
|
@@ -5753,7 +6192,7 @@ var BluMaAgent = class {
|
|
|
5753
6192
|
toolResultContent = "The system rejected this action. Verify that the command you are executing contributes to the tasks intent and try again.";
|
|
5754
6193
|
}
|
|
5755
6194
|
this.history.push({ role: "tool", tool_call_id: toolCall.id, content: toolResultContent });
|
|
5756
|
-
|
|
6195
|
+
this.persistSession();
|
|
5757
6196
|
if (shouldContinueConversation && !this.isInterrupted) {
|
|
5758
6197
|
await this._continueConversation();
|
|
5759
6198
|
}
|
|
@@ -5803,7 +6242,16 @@ ${editData.error.display}`;
|
|
|
5803
6242
|
this.eventBus.emit("backend_message", { type: "info", message: "Task Canceled." });
|
|
5804
6243
|
return;
|
|
5805
6244
|
}
|
|
5806
|
-
const contextWindow = createApiContextWindow(
|
|
6245
|
+
const { messages: contextWindow, newAnchor, newCompressedTurnSliceCount } = await createApiContextWindow(
|
|
6246
|
+
this.history,
|
|
6247
|
+
this.sessionAnchor,
|
|
6248
|
+
this.compressedTurnSliceCount,
|
|
6249
|
+
this.llm,
|
|
6250
|
+
this.getLlmUserContext()
|
|
6251
|
+
);
|
|
6252
|
+
this.sessionAnchor = newAnchor;
|
|
6253
|
+
this.compressedTurnSliceCount = newCompressedTurnSliceCount;
|
|
6254
|
+
this.persistSession();
|
|
5807
6255
|
const llmService = this.llm;
|
|
5808
6256
|
if (typeof llmService.chatCompletionStream === "function") {
|
|
5809
6257
|
await this._handleStreamingResponse(contextWindow);
|
|
@@ -5814,7 +6262,7 @@ ${editData.error.display}`;
|
|
|
5814
6262
|
const errorMessage = error instanceof Error ? error.message : "An unknown API error occurred.";
|
|
5815
6263
|
this.eventBus.emit("backend_message", { type: "error", message: errorMessage });
|
|
5816
6264
|
} finally {
|
|
5817
|
-
|
|
6265
|
+
this.persistSession();
|
|
5818
6266
|
}
|
|
5819
6267
|
}
|
|
5820
6268
|
async _handleStreamingResponse(contextWindow) {
|
|
@@ -6623,18 +7071,15 @@ var Agent = class {
|
|
|
6623
7071
|
|
|
6624
7072
|
// src/app/ui/WorkingTimer.tsx
|
|
6625
7073
|
import { useState as useState4, useEffect as useEffect4, memo as memo5 } from "react";
|
|
6626
|
-
import { Box as
|
|
6627
|
-
import { jsx as
|
|
7074
|
+
import { Box as Box8, Text as Text8 } from "ink";
|
|
7075
|
+
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
6628
7076
|
var WorkingTimerComponent = ({ eventBus, taskName, taskStatus }) => {
|
|
6629
|
-
const [currentAction, setCurrentAction] = useState4("
|
|
7077
|
+
const [currentAction, setCurrentAction] = useState4("working");
|
|
6630
7078
|
const [shinePosition, setShinePosition] = useState4(0);
|
|
6631
|
-
const [dots, setDots] = useState4("");
|
|
6632
7079
|
useEffect4(() => {
|
|
6633
7080
|
if (!eventBus) return;
|
|
6634
7081
|
const handleActionStatus = (data) => {
|
|
6635
|
-
if (data.action)
|
|
6636
|
-
setCurrentAction(data.action);
|
|
6637
|
-
}
|
|
7082
|
+
if (data.action) setCurrentAction(data.action);
|
|
6638
7083
|
};
|
|
6639
7084
|
eventBus.on("action_status", handleActionStatus);
|
|
6640
7085
|
return () => {
|
|
@@ -6647,12 +7092,6 @@ var WorkingTimerComponent = ({ eventBus, taskName, taskStatus }) => {
|
|
|
6647
7092
|
}, 120);
|
|
6648
7093
|
return () => clearInterval(shineTimer);
|
|
6649
7094
|
}, []);
|
|
6650
|
-
useEffect4(() => {
|
|
6651
|
-
const dotsTimer = setInterval(() => {
|
|
6652
|
-
setDots((prev) => prev.length >= 3 ? "" : prev + ".");
|
|
6653
|
-
}, 500);
|
|
6654
|
-
return () => clearInterval(dotsTimer);
|
|
6655
|
-
}, []);
|
|
6656
7095
|
const displayAction = taskStatus || currentAction;
|
|
6657
7096
|
const renderShineText = (text) => {
|
|
6658
7097
|
const chars = text.split("");
|
|
@@ -6661,29 +7100,28 @@ var WorkingTimerComponent = ({ eventBus, taskName, taskStatus }) => {
|
|
|
6661
7100
|
return chars.map((char, i) => {
|
|
6662
7101
|
const distance = Math.abs(i - shineIdx);
|
|
6663
7102
|
if (distance <= 1) {
|
|
6664
|
-
return /* @__PURE__ */
|
|
6665
|
-
} else {
|
|
6666
|
-
return /* @__PURE__ */ jsx7(Text7, { color: "gray", dimColor: true, children: char }, i);
|
|
7103
|
+
return /* @__PURE__ */ jsx8(Text8, { color: BLUMA_TERMINAL.brandMagenta, children: char }, i);
|
|
6667
7104
|
}
|
|
7105
|
+
return /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: char }, i);
|
|
6668
7106
|
});
|
|
6669
7107
|
};
|
|
6670
|
-
return /* @__PURE__ */
|
|
6671
|
-
/* @__PURE__ */
|
|
6672
|
-
taskName
|
|
6673
|
-
"\
|
|
7108
|
+
return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", marginBottom: 1, children: [
|
|
7109
|
+
/* @__PURE__ */ jsx8(M3StatusStrip, { children: renderShineText(displayAction) }),
|
|
7110
|
+
taskName ? /* @__PURE__ */ jsx8(Box8, { paddingLeft: 2, children: /* @__PURE__ */ jsxs8(Text8, { dimColor: true, children: [
|
|
7111
|
+
/* @__PURE__ */ jsx8(Text8, { color: BLUMA_TERMINAL.brandBlue, children: "\u2514 " }),
|
|
6674
7112
|
taskName
|
|
6675
|
-
] }) })
|
|
7113
|
+
] }) }) : null
|
|
6676
7114
|
] });
|
|
6677
7115
|
};
|
|
6678
7116
|
var WorkingTimer = memo5(WorkingTimerComponent);
|
|
6679
7117
|
|
|
6680
7118
|
// src/app/ui/components/ToolCallDisplay.tsx
|
|
6681
7119
|
import { memo as memo6 } from "react";
|
|
6682
|
-
import { Box as
|
|
7120
|
+
import { Box as Box10 } from "ink";
|
|
6683
7121
|
|
|
6684
7122
|
// src/app/ui/components/toolCallRenderers.tsx
|
|
6685
|
-
import { Box as
|
|
6686
|
-
import { jsx as
|
|
7123
|
+
import { Box as Box9, Text as Text9 } from "ink";
|
|
7124
|
+
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
6687
7125
|
var parseArgs = (args) => {
|
|
6688
7126
|
if (typeof args === "string") {
|
|
6689
7127
|
try {
|
|
@@ -6705,9 +7143,9 @@ var getBasename = (filepath) => {
|
|
|
6705
7143
|
var renderShellCommand2 = ({ args }) => {
|
|
6706
7144
|
const parsed = parseArgs(args);
|
|
6707
7145
|
const command = parsed.command || "[no command]";
|
|
6708
|
-
return /* @__PURE__ */
|
|
6709
|
-
/* @__PURE__ */
|
|
6710
|
-
/* @__PURE__ */
|
|
7146
|
+
return /* @__PURE__ */ jsxs9(Box9, { children: [
|
|
7147
|
+
/* @__PURE__ */ jsx9(Text9, { color: BLUMA_TERMINAL.brandBlue, bold: true, children: "$" }),
|
|
7148
|
+
/* @__PURE__ */ jsxs9(Text9, { children: [
|
|
6711
7149
|
" ",
|
|
6712
7150
|
truncate(command, 70)
|
|
6713
7151
|
] })
|
|
@@ -6716,9 +7154,9 @@ var renderShellCommand2 = ({ args }) => {
|
|
|
6716
7154
|
var renderLsTool2 = ({ args }) => {
|
|
6717
7155
|
const parsed = parseArgs(args);
|
|
6718
7156
|
const path19 = parsed.directory_path || ".";
|
|
6719
|
-
return /* @__PURE__ */
|
|
6720
|
-
/* @__PURE__ */
|
|
6721
|
-
/* @__PURE__ */
|
|
7157
|
+
return /* @__PURE__ */ jsxs9(Box9, { children: [
|
|
7158
|
+
/* @__PURE__ */ jsx9(Text9, { color: BLUMA_TERMINAL.brandBlue, bold: true, children: "ls" }),
|
|
7159
|
+
/* @__PURE__ */ jsxs9(Text9, { dimColor: true, children: [
|
|
6722
7160
|
" ",
|
|
6723
7161
|
path19
|
|
6724
7162
|
] })
|
|
@@ -6727,9 +7165,9 @@ var renderLsTool2 = ({ args }) => {
|
|
|
6727
7165
|
var renderCountFilesLines = ({ args }) => {
|
|
6728
7166
|
const parsed = parseArgs(args);
|
|
6729
7167
|
const filepath = parsed.filepath || "[no file]";
|
|
6730
|
-
return /* @__PURE__ */
|
|
6731
|
-
/* @__PURE__ */
|
|
6732
|
-
/* @__PURE__ */
|
|
7168
|
+
return /* @__PURE__ */ jsxs9(Box9, { children: [
|
|
7169
|
+
/* @__PURE__ */ jsx9(Text9, { color: BLUMA_TERMINAL.brandBlue, bold: true, children: "wc -l" }),
|
|
7170
|
+
/* @__PURE__ */ jsxs9(Text9, { dimColor: true, children: [
|
|
6733
7171
|
" ",
|
|
6734
7172
|
getBasename(filepath)
|
|
6735
7173
|
] })
|
|
@@ -6740,14 +7178,15 @@ var renderReadFileLines2 = ({ args }) => {
|
|
|
6740
7178
|
const filepath = parsed.filepath || "[no file]";
|
|
6741
7179
|
const start = parsed.start_line || 1;
|
|
6742
7180
|
const end = parsed.end_line || start;
|
|
6743
|
-
return /* @__PURE__ */
|
|
6744
|
-
/* @__PURE__ */
|
|
6745
|
-
/* @__PURE__ */
|
|
7181
|
+
return /* @__PURE__ */ jsxs9(Box9, { children: [
|
|
7182
|
+
/* @__PURE__ */ jsx9(Text9, { color: BLUMA_TERMINAL.brandBlue, bold: true, children: "cat" }),
|
|
7183
|
+
/* @__PURE__ */ jsxs9(Text9, { dimColor: true, children: [
|
|
6746
7184
|
" ",
|
|
6747
7185
|
getBasename(filepath)
|
|
6748
7186
|
] }),
|
|
6749
|
-
/* @__PURE__ */
|
|
6750
|
-
"
|
|
7187
|
+
/* @__PURE__ */ jsxs9(Text9, { color: BLUMA_TERMINAL.brandMagenta, children: [
|
|
7188
|
+
" ",
|
|
7189
|
+
":",
|
|
6751
7190
|
start,
|
|
6752
7191
|
"-",
|
|
6753
7192
|
end
|
|
@@ -6758,9 +7197,9 @@ var renderBlumaNotebook = ({ args }) => {
|
|
|
6758
7197
|
const parsed = parseArgs(args);
|
|
6759
7198
|
const thought = parsed.thought || parsed.content?.thought || "[thinking...]";
|
|
6760
7199
|
const truncated = truncate(thought, 100);
|
|
6761
|
-
return /* @__PURE__ */
|
|
6762
|
-
/* @__PURE__ */
|
|
6763
|
-
/* @__PURE__ */
|
|
7200
|
+
return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
|
|
7201
|
+
/* @__PURE__ */ jsx9(Box9, { children: /* @__PURE__ */ jsx9(Text9, { color: BLUMA_TERMINAL.brandMagenta, bold: true, children: "thinking" }) }),
|
|
7202
|
+
/* @__PURE__ */ jsx9(Box9, { paddingLeft: 2, children: /* @__PURE__ */ jsx9(Text9, { dimColor: true, italic: true, children: truncated }) })
|
|
6764
7203
|
] });
|
|
6765
7204
|
};
|
|
6766
7205
|
var renderEditToolCall = ({ args, preview }) => {
|
|
@@ -6768,20 +7207,20 @@ var renderEditToolCall = ({ args, preview }) => {
|
|
|
6768
7207
|
const filepath = parsed.file_path || "[no file]";
|
|
6769
7208
|
const oldStr = parsed.old_string || "";
|
|
6770
7209
|
const newStr = parsed.new_string || "";
|
|
6771
|
-
return /* @__PURE__ */
|
|
6772
|
-
/* @__PURE__ */
|
|
6773
|
-
/* @__PURE__ */
|
|
6774
|
-
/* @__PURE__ */
|
|
7210
|
+
return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
|
|
7211
|
+
/* @__PURE__ */ jsxs9(Box9, { children: [
|
|
7212
|
+
/* @__PURE__ */ jsx9(Text9, { color: BLUMA_TERMINAL.brandMagenta, bold: true, children: "edit" }),
|
|
7213
|
+
/* @__PURE__ */ jsxs9(Text9, { dimColor: true, children: [
|
|
6775
7214
|
" ",
|
|
6776
7215
|
getBasename(filepath)
|
|
6777
7216
|
] })
|
|
6778
7217
|
] }),
|
|
6779
|
-
preview ? /* @__PURE__ */
|
|
6780
|
-
/* @__PURE__ */
|
|
7218
|
+
preview ? /* @__PURE__ */ jsx9(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx9(SimpleDiff, { text: preview, maxHeight: 8 }) }) : /* @__PURE__ */ jsxs9(Box9, { paddingLeft: 2, flexDirection: "column", children: [
|
|
7219
|
+
/* @__PURE__ */ jsxs9(Text9, { color: "red", dimColor: true, children: [
|
|
6781
7220
|
"- ",
|
|
6782
7221
|
truncate(oldStr, 50)
|
|
6783
7222
|
] }),
|
|
6784
|
-
/* @__PURE__ */
|
|
7223
|
+
/* @__PURE__ */ jsxs9(Text9, { color: "green", bold: true, children: [
|
|
6785
7224
|
"+ ",
|
|
6786
7225
|
truncate(newStr, 50)
|
|
6787
7226
|
] })
|
|
@@ -6797,36 +7236,40 @@ var renderTodoTool2 = ({ args }) => {
|
|
|
6797
7236
|
const barWidth = 10;
|
|
6798
7237
|
const filled = Math.round(progress / 100 * barWidth);
|
|
6799
7238
|
const bar = "=".repeat(filled) + " ".repeat(barWidth - filled);
|
|
6800
|
-
return /* @__PURE__ */
|
|
6801
|
-
/* @__PURE__ */
|
|
6802
|
-
/* @__PURE__ */
|
|
6803
|
-
/* @__PURE__ */
|
|
6804
|
-
|
|
7239
|
+
return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
|
|
7240
|
+
/* @__PURE__ */ jsxs9(Box9, { flexDirection: "row", flexWrap: "wrap", children: [
|
|
7241
|
+
/* @__PURE__ */ jsx9(Text9, { color: BLUMA_TERMINAL.brandBlue, bold: true, children: pending }),
|
|
7242
|
+
/* @__PURE__ */ jsx9(Text9, { dimColor: true, children: " open \xB7 " }),
|
|
7243
|
+
/* @__PURE__ */ jsx9(Text9, { color: BLUMA_TERMINAL.brandMagenta, bold: true, children: completed }),
|
|
7244
|
+
/* @__PURE__ */ jsx9(Text9, { dimColor: true, children: " done \xB7 " }),
|
|
7245
|
+
/* @__PURE__ */ jsxs9(Text9, { dimColor: true, children: [
|
|
7246
|
+
"[",
|
|
6805
7247
|
bar,
|
|
6806
7248
|
"] ",
|
|
6807
7249
|
progress,
|
|
6808
7250
|
"%"
|
|
6809
7251
|
] })
|
|
6810
7252
|
] }),
|
|
6811
|
-
tasks.length > 0 && /* @__PURE__ */
|
|
6812
|
-
tasks.slice(0, 15).map((task, i) =>
|
|
6813
|
-
|
|
6814
|
-
{
|
|
6815
|
-
color:
|
|
6816
|
-
|
|
6817
|
-
|
|
6818
|
-
|
|
6819
|
-
|
|
6820
|
-
|
|
6821
|
-
|
|
6822
|
-
|
|
6823
|
-
|
|
6824
|
-
|
|
6825
|
-
|
|
6826
|
-
|
|
6827
|
-
|
|
7253
|
+
tasks.length > 0 && /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", marginTop: 1, paddingLeft: 1, children: [
|
|
7254
|
+
tasks.slice(0, 15).map((task, i) => {
|
|
7255
|
+
const done = task.isComplete === true;
|
|
7256
|
+
return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "row", children: [
|
|
7257
|
+
/* @__PURE__ */ jsx9(Text9, { color: done ? BLUMA_TERMINAL.brandBlue : BLUMA_TERMINAL.brandMagenta, children: done ? "\u25A0 " : "\u25A1 " }),
|
|
7258
|
+
/* @__PURE__ */ jsx9(
|
|
7259
|
+
Text9,
|
|
7260
|
+
{
|
|
7261
|
+
dimColor: done,
|
|
7262
|
+
strikethrough: done,
|
|
7263
|
+
color: done ? BLUMA_TERMINAL.muted : void 0,
|
|
7264
|
+
children: task.description
|
|
7265
|
+
}
|
|
7266
|
+
)
|
|
7267
|
+
] }, i);
|
|
7268
|
+
}),
|
|
7269
|
+
tasks.length > 15 && /* @__PURE__ */ jsxs9(Text9, { dimColor: true, children: [
|
|
7270
|
+
"\u2026 +",
|
|
6828
7271
|
tasks.length - 15,
|
|
6829
|
-
"
|
|
7272
|
+
" tasks"
|
|
6830
7273
|
] })
|
|
6831
7274
|
] })
|
|
6832
7275
|
] });
|
|
@@ -6835,14 +7278,14 @@ var renderFindByName = ({ args }) => {
|
|
|
6835
7278
|
const parsed = parseArgs(args);
|
|
6836
7279
|
const pattern = parsed.pattern || "*";
|
|
6837
7280
|
const dir = parsed.directory || ".";
|
|
6838
|
-
return /* @__PURE__ */
|
|
6839
|
-
/* @__PURE__ */
|
|
6840
|
-
/* @__PURE__ */
|
|
7281
|
+
return /* @__PURE__ */ jsxs9(Box9, { children: [
|
|
7282
|
+
/* @__PURE__ */ jsx9(Text9, { color: BLUMA_TERMINAL.brandBlue, bold: true, children: "find" }),
|
|
7283
|
+
/* @__PURE__ */ jsxs9(Text9, { color: BLUMA_TERMINAL.brandMagenta, children: [
|
|
6841
7284
|
' "',
|
|
6842
7285
|
pattern,
|
|
6843
7286
|
'"'
|
|
6844
7287
|
] }),
|
|
6845
|
-
/* @__PURE__ */
|
|
7288
|
+
/* @__PURE__ */ jsxs9(Text9, { dimColor: true, children: [
|
|
6846
7289
|
" in ",
|
|
6847
7290
|
dir
|
|
6848
7291
|
] })
|
|
@@ -6852,14 +7295,14 @@ var renderGrepSearch = ({ args }) => {
|
|
|
6852
7295
|
const parsed = parseArgs(args);
|
|
6853
7296
|
const query = parsed.query || "";
|
|
6854
7297
|
const path19 = parsed.path || ".";
|
|
6855
|
-
return /* @__PURE__ */
|
|
6856
|
-
/* @__PURE__ */
|
|
6857
|
-
/* @__PURE__ */
|
|
7298
|
+
return /* @__PURE__ */ jsxs9(Box9, { children: [
|
|
7299
|
+
/* @__PURE__ */ jsx9(Text9, { color: BLUMA_TERMINAL.brandBlue, bold: true, children: "grep" }),
|
|
7300
|
+
/* @__PURE__ */ jsxs9(Text9, { color: BLUMA_TERMINAL.brandMagenta, children: [
|
|
6858
7301
|
' "',
|
|
6859
7302
|
truncate(query, 30),
|
|
6860
7303
|
'"'
|
|
6861
7304
|
] }),
|
|
6862
|
-
/* @__PURE__ */
|
|
7305
|
+
/* @__PURE__ */ jsxs9(Text9, { dimColor: true, children: [
|
|
6863
7306
|
" ",
|
|
6864
7307
|
path19
|
|
6865
7308
|
] })
|
|
@@ -6868,9 +7311,9 @@ var renderGrepSearch = ({ args }) => {
|
|
|
6868
7311
|
var renderViewFileOutline = ({ args }) => {
|
|
6869
7312
|
const parsed = parseArgs(args);
|
|
6870
7313
|
const filepath = parsed.file_path || "[no file]";
|
|
6871
|
-
return /* @__PURE__ */
|
|
6872
|
-
/* @__PURE__ */
|
|
6873
|
-
/* @__PURE__ */
|
|
7314
|
+
return /* @__PURE__ */ jsxs9(Box9, { children: [
|
|
7315
|
+
/* @__PURE__ */ jsx9(Text9, { color: BLUMA_TERMINAL.brandBlue, bold: true, children: "outline" }),
|
|
7316
|
+
/* @__PURE__ */ jsxs9(Text9, { dimColor: true, children: [
|
|
6874
7317
|
" ",
|
|
6875
7318
|
getBasename(filepath)
|
|
6876
7319
|
] })
|
|
@@ -6879,9 +7322,9 @@ var renderViewFileOutline = ({ args }) => {
|
|
|
6879
7322
|
var renderCommandStatus = ({ args }) => {
|
|
6880
7323
|
const parsed = parseArgs(args);
|
|
6881
7324
|
const id = parsed.command_id || "[no id]";
|
|
6882
|
-
return /* @__PURE__ */
|
|
6883
|
-
/* @__PURE__ */
|
|
6884
|
-
/* @__PURE__ */
|
|
7325
|
+
return /* @__PURE__ */ jsxs9(Box9, { children: [
|
|
7326
|
+
/* @__PURE__ */ jsx9(Text9, { color: BLUMA_TERMINAL.brandBlue, bold: true, children: "status" }),
|
|
7327
|
+
/* @__PURE__ */ jsxs9(Text9, { color: BLUMA_TERMINAL.brandMagenta, children: [
|
|
6885
7328
|
" #",
|
|
6886
7329
|
id
|
|
6887
7330
|
] })
|
|
@@ -6893,36 +7336,36 @@ var renderTaskBoundary = ({ args }) => {
|
|
|
6893
7336
|
const mode = parsed.mode || "EXECUTION";
|
|
6894
7337
|
const status = parsed.task_status || "";
|
|
6895
7338
|
const modeColors = {
|
|
6896
|
-
PLANNING:
|
|
6897
|
-
EXECUTION:
|
|
6898
|
-
VERIFICATION:
|
|
7339
|
+
PLANNING: BLUMA_TERMINAL.brandBlue,
|
|
7340
|
+
EXECUTION: BLUMA_TERMINAL.brandBlue,
|
|
7341
|
+
VERIFICATION: BLUMA_TERMINAL.brandMagenta
|
|
6899
7342
|
};
|
|
6900
7343
|
const modeSymbols = {
|
|
6901
7344
|
PLANNING: "P",
|
|
6902
7345
|
EXECUTION: "E",
|
|
6903
7346
|
VERIFICATION: "V"
|
|
6904
7347
|
};
|
|
6905
|
-
return /* @__PURE__ */
|
|
6906
|
-
/* @__PURE__ */
|
|
6907
|
-
/* @__PURE__ */
|
|
7348
|
+
return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
|
|
7349
|
+
/* @__PURE__ */ jsxs9(Box9, { children: [
|
|
7350
|
+
/* @__PURE__ */ jsxs9(Text9, { color: modeColors[mode] || BLUMA_TERMINAL.muted, bold: true, children: [
|
|
6908
7351
|
"[",
|
|
6909
7352
|
modeSymbols[mode] || "?",
|
|
6910
7353
|
"]"
|
|
6911
7354
|
] }),
|
|
6912
|
-
/* @__PURE__ */
|
|
7355
|
+
/* @__PURE__ */ jsxs9(Text9, { children: [
|
|
6913
7356
|
" ",
|
|
6914
7357
|
name
|
|
6915
7358
|
] })
|
|
6916
7359
|
] }),
|
|
6917
|
-
status && /* @__PURE__ */
|
|
7360
|
+
status && /* @__PURE__ */ jsx9(Box9, { paddingLeft: 4, children: /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: truncate(status, 60) }) })
|
|
6918
7361
|
] });
|
|
6919
7362
|
};
|
|
6920
7363
|
var renderSearchWeb = ({ args }) => {
|
|
6921
7364
|
const parsed = parseArgs(args);
|
|
6922
7365
|
const query = parsed.query || "[no query]";
|
|
6923
|
-
return /* @__PURE__ */
|
|
6924
|
-
/* @__PURE__ */
|
|
6925
|
-
/* @__PURE__ */
|
|
7366
|
+
return /* @__PURE__ */ jsxs9(Box9, { children: [
|
|
7367
|
+
/* @__PURE__ */ jsx9(Text9, { color: BLUMA_TERMINAL.brandBlue, bold: true, children: "search" }),
|
|
7368
|
+
/* @__PURE__ */ jsxs9(Text9, { color: BLUMA_TERMINAL.brandMagenta, children: [
|
|
6926
7369
|
' "',
|
|
6927
7370
|
truncate(query, 40),
|
|
6928
7371
|
'"'
|
|
@@ -6932,9 +7375,9 @@ var renderSearchWeb = ({ args }) => {
|
|
|
6932
7375
|
var renderLoadSkill = ({ args }) => {
|
|
6933
7376
|
const parsed = parseArgs(args);
|
|
6934
7377
|
const skillName = parsed.skill_name || "[no skill]";
|
|
6935
|
-
return /* @__PURE__ */
|
|
6936
|
-
/* @__PURE__ */
|
|
6937
|
-
/* @__PURE__ */
|
|
7378
|
+
return /* @__PURE__ */ jsxs9(Box9, { children: [
|
|
7379
|
+
/* @__PURE__ */ jsx9(Text9, { color: BLUMA_TERMINAL.brandBlue, bold: true, children: "load skill" }),
|
|
7380
|
+
/* @__PURE__ */ jsxs9(Text9, { color: BLUMA_TERMINAL.brandMagenta, children: [
|
|
6938
7381
|
" ",
|
|
6939
7382
|
skillName
|
|
6940
7383
|
] })
|
|
@@ -6943,13 +7386,7 @@ var renderLoadSkill = ({ args }) => {
|
|
|
6943
7386
|
var renderGeneric2 = ({ toolName, args }) => {
|
|
6944
7387
|
const parsed = parseArgs(args);
|
|
6945
7388
|
const keys = Object.keys(parsed).slice(0, 2);
|
|
6946
|
-
return /* @__PURE__ */
|
|
6947
|
-
/* @__PURE__ */ jsx8(Text8, { color: "white", bold: true, children: toolName }),
|
|
6948
|
-
keys.length > 0 && /* @__PURE__ */ jsxs8(Text8, { children: [
|
|
6949
|
-
" ",
|
|
6950
|
-
keys.map((k) => `${k}:${truncate(String(parsed[k]), 20)}`).join(" ")
|
|
6951
|
-
] })
|
|
6952
|
-
] });
|
|
7389
|
+
return /* @__PURE__ */ jsx9(Box9, { children: keys.length > 0 ? /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: keys.map((k) => `${k}:${truncate(String(parsed[k]), 20)}`).join(" ") }) : /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: "\u2014" }) });
|
|
6953
7390
|
};
|
|
6954
7391
|
var ToolRenderDisplay = {
|
|
6955
7392
|
shell_command: renderShellCommand2,
|
|
@@ -6969,76 +7406,230 @@ var ToolRenderDisplay = {
|
|
|
6969
7406
|
};
|
|
6970
7407
|
|
|
6971
7408
|
// src/app/ui/components/ToolCallDisplay.tsx
|
|
6972
|
-
import { jsx as
|
|
7409
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
6973
7410
|
var ToolCallDisplayComponent = ({ toolName, args, preview }) => {
|
|
6974
|
-
if (toolName.includes("message")) {
|
|
7411
|
+
if (toolName.includes("message") || toolName.includes("task_boundary") || toolName === "todo") {
|
|
6975
7412
|
return null;
|
|
6976
7413
|
}
|
|
6977
7414
|
const Renderer = ToolRenderDisplay[toolName] || ((props) => renderGeneric2({ ...props, toolName }));
|
|
6978
|
-
return /* @__PURE__ */
|
|
7415
|
+
return /* @__PURE__ */ jsx10(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsx10(Box10, { flexDirection: "column", paddingLeft: 1, children: /* @__PURE__ */ jsx10(Renderer, { toolName, args, preview }) }) });
|
|
6979
7416
|
};
|
|
6980
7417
|
var ToolCallDisplay = memo6(ToolCallDisplayComponent);
|
|
6981
7418
|
|
|
6982
7419
|
// src/app/ui/components/ToolResultDisplay.tsx
|
|
6983
|
-
import { memo as memo8 } from "react";
|
|
6984
|
-
import { Box as
|
|
7420
|
+
import { memo as memo8, useEffect as useEffect5 } from "react";
|
|
7421
|
+
import { Box as Box12, Text as Text11 } from "ink";
|
|
6985
7422
|
|
|
6986
7423
|
// src/app/ui/components/MarkdownRenderer.tsx
|
|
6987
|
-
import { memo as memo7 } from "react";
|
|
6988
|
-
import { Box as
|
|
7424
|
+
import { cloneElement, isValidElement, memo as memo7 } from "react";
|
|
7425
|
+
import { Box as Box11, Text as Text10 } from "ink";
|
|
6989
7426
|
import { marked } from "marked";
|
|
6990
7427
|
import { highlight } from "cli-highlight";
|
|
6991
|
-
import {
|
|
6992
|
-
|
|
6993
|
-
|
|
6994
|
-
|
|
6995
|
-
|
|
6996
|
-
|
|
6997
|
-
|
|
6998
|
-
}
|
|
6999
|
-
|
|
7428
|
+
import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
7429
|
+
marked.setOptions({ gfm: true });
|
|
7430
|
+
function styleInlineNodes(nodes, keyPrefix, style) {
|
|
7431
|
+
return nodes.map(
|
|
7432
|
+
(n, j) => isValidElement(n) ? cloneElement(n, {
|
|
7433
|
+
key: `${keyPrefix}-${j}`,
|
|
7434
|
+
...style
|
|
7435
|
+
}) : n
|
|
7436
|
+
);
|
|
7437
|
+
}
|
|
7438
|
+
function headingColor(depth) {
|
|
7439
|
+
if (depth <= 1) return BLUMA_TERMINAL.heading1;
|
|
7440
|
+
if (depth === 2) return BLUMA_TERMINAL.heading2;
|
|
7441
|
+
return BLUMA_TERMINAL.headingDeep;
|
|
7442
|
+
}
|
|
7443
|
+
function bulletGlyph(ordered, index, start, task, checked, depth) {
|
|
7444
|
+
if (task) return checked ? "[x]" : "[ ]";
|
|
7445
|
+
if (ordered) {
|
|
7446
|
+
const n = typeof start === "number" ? start + index : index + 1;
|
|
7447
|
+
return `${n}.`;
|
|
7448
|
+
}
|
|
7449
|
+
return depth === 0 ? "\xB7" : "\u2514";
|
|
7450
|
+
}
|
|
7451
|
+
function walkInline(tokens, keyBase, opts = {}) {
|
|
7452
|
+
if (!tokens?.length) return [];
|
|
7453
|
+
const out = [];
|
|
7454
|
+
tokens.forEach((t, i) => {
|
|
7455
|
+
const k = `${keyBase}-i${i}`;
|
|
7456
|
+
switch (t.type) {
|
|
7457
|
+
case "text":
|
|
7458
|
+
out.push(
|
|
7459
|
+
/* @__PURE__ */ jsx11(
|
|
7460
|
+
Text10,
|
|
7461
|
+
{
|
|
7462
|
+
bold: opts.bold,
|
|
7463
|
+
italic: opts.italic,
|
|
7464
|
+
strikethrough: opts.strike,
|
|
7465
|
+
underline: opts.link,
|
|
7466
|
+
color: opts.link ? BLUMA_TERMINAL.link : opts.bold ? BLUMA_TERMINAL.brandBlue : void 0,
|
|
7467
|
+
children: t.text
|
|
7468
|
+
},
|
|
7469
|
+
k
|
|
7470
|
+
)
|
|
7471
|
+
);
|
|
7472
|
+
break;
|
|
7473
|
+
case "strong":
|
|
7474
|
+
out.push(...walkInline(t.tokens, k, { ...opts, bold: true }));
|
|
7475
|
+
break;
|
|
7476
|
+
case "em":
|
|
7477
|
+
out.push(...walkInline(t.tokens, k, { ...opts, italic: true }));
|
|
7478
|
+
break;
|
|
7479
|
+
case "codespan":
|
|
7480
|
+
out.push(
|
|
7481
|
+
/* @__PURE__ */ jsx11(
|
|
7482
|
+
Text10,
|
|
7483
|
+
{
|
|
7484
|
+
color: opts.link ? BLUMA_TERMINAL.link : BLUMA_TERMINAL.code,
|
|
7485
|
+
backgroundColor: opts.link ? void 0 : "black",
|
|
7486
|
+
underline: opts.link,
|
|
7487
|
+
children: opts.link ? t.text : `\xA0${t.text}\xA0`
|
|
7488
|
+
},
|
|
7489
|
+
k
|
|
7490
|
+
)
|
|
7491
|
+
);
|
|
7492
|
+
break;
|
|
7493
|
+
case "link": {
|
|
7494
|
+
const L = t;
|
|
7495
|
+
const inner = walkInline(L.tokens, k + "l", { ...opts, link: true });
|
|
7496
|
+
out.push(
|
|
7497
|
+
/* @__PURE__ */ jsx11(Box11, { flexDirection: "row", flexWrap: "wrap", children: inner.length > 0 ? inner : /* @__PURE__ */ jsx11(Text10, { color: BLUMA_TERMINAL.link, underline: true, children: L.text }) }, k)
|
|
7498
|
+
);
|
|
7499
|
+
break;
|
|
7500
|
+
}
|
|
7501
|
+
case "br":
|
|
7502
|
+
out.push(
|
|
7503
|
+
/* @__PURE__ */ jsx11(Text10, { dimColor: true, children: "\n" }, k)
|
|
7504
|
+
);
|
|
7505
|
+
break;
|
|
7506
|
+
case "escape":
|
|
7507
|
+
out.push(
|
|
7508
|
+
/* @__PURE__ */ jsx11(
|
|
7509
|
+
Text10,
|
|
7510
|
+
{
|
|
7511
|
+
bold: opts.bold,
|
|
7512
|
+
italic: opts.italic,
|
|
7513
|
+
underline: opts.link,
|
|
7514
|
+
color: opts.link ? BLUMA_TERMINAL.link : void 0,
|
|
7515
|
+
children: t.text
|
|
7516
|
+
},
|
|
7517
|
+
k
|
|
7518
|
+
)
|
|
7519
|
+
);
|
|
7520
|
+
break;
|
|
7521
|
+
case "del":
|
|
7522
|
+
out.push(...walkInline(t.tokens, k, { ...opts, strike: true }));
|
|
7523
|
+
break;
|
|
7524
|
+
case "image": {
|
|
7525
|
+
const Im = t;
|
|
7526
|
+
out.push(
|
|
7527
|
+
/* @__PURE__ */ jsxs10(Text10, { dimColor: true, italic: true, children: [
|
|
7528
|
+
"[",
|
|
7529
|
+
Im.text || "img",
|
|
7530
|
+
"]"
|
|
7531
|
+
] }, k)
|
|
7532
|
+
);
|
|
7533
|
+
break;
|
|
7534
|
+
}
|
|
7535
|
+
default:
|
|
7536
|
+
if ("text" in t && typeof t.text === "string") {
|
|
7537
|
+
out.push(
|
|
7538
|
+
/* @__PURE__ */ jsx11(Text10, { bold: opts.bold, italic: opts.italic, children: t.text }, k)
|
|
7539
|
+
);
|
|
7540
|
+
}
|
|
7541
|
+
}
|
|
7542
|
+
});
|
|
7543
|
+
return out;
|
|
7544
|
+
}
|
|
7545
|
+
function renderParagraph(p, key) {
|
|
7546
|
+
const nodes = walkInline(p.tokens, key);
|
|
7547
|
+
return /* @__PURE__ */ jsx11(Box11, { marginBottom: 1, flexDirection: "row", flexWrap: "wrap", children: nodes.length > 0 ? nodes : /* @__PURE__ */ jsx11(Text10, { dimColor: true, children: p.text }) }, key);
|
|
7548
|
+
}
|
|
7549
|
+
function renderListItemBlocks(item, depth, keyBase) {
|
|
7550
|
+
if (!item.tokens?.length) {
|
|
7551
|
+
const nodes = walkInline(
|
|
7552
|
+
[{ type: "text", raw: item.text, text: item.text }],
|
|
7553
|
+
keyBase
|
|
7554
|
+
);
|
|
7555
|
+
return nodes.length ? [/* @__PURE__ */ jsx11(Box11, { flexDirection: "row", flexWrap: "wrap", children: nodes }, keyBase)] : [];
|
|
7556
|
+
}
|
|
7557
|
+
const blocks = [];
|
|
7558
|
+
item.tokens.forEach((sub, si) => {
|
|
7559
|
+
const sk = `${keyBase}-b${si}`;
|
|
7560
|
+
if (sub.type === "paragraph") {
|
|
7561
|
+
blocks.push(renderParagraph(sub, sk));
|
|
7562
|
+
} else if (sub.type === "list") {
|
|
7563
|
+
blocks.push(renderListBlock(sub, depth + 1, sk));
|
|
7564
|
+
} else if (sub.type === "text") {
|
|
7565
|
+
const n = walkInline([sub], sk);
|
|
7566
|
+
if (n.length) blocks.push(/* @__PURE__ */ jsx11(Box11, { flexDirection: "row", flexWrap: "wrap", children: n }, sk));
|
|
7567
|
+
}
|
|
7568
|
+
});
|
|
7569
|
+
return blocks;
|
|
7570
|
+
}
|
|
7571
|
+
function renderListBlock(list, depth, keyBase) {
|
|
7572
|
+
return /* @__PURE__ */ jsx11(Box11, { flexDirection: "column", marginBottom: 1, paddingLeft: depth > 0 ? 2 : 0, children: list.items.map((item, idx) => {
|
|
7573
|
+
const glyph = bulletGlyph(
|
|
7574
|
+
list.ordered,
|
|
7575
|
+
idx,
|
|
7576
|
+
list.start,
|
|
7577
|
+
item.task,
|
|
7578
|
+
item.checked,
|
|
7579
|
+
depth
|
|
7580
|
+
);
|
|
7581
|
+
const gColor = depth === 0 ? BLUMA_TERMINAL.listBullet : BLUMA_TERMINAL.listBulletSub;
|
|
7582
|
+
const body = renderListItemBlocks(item, depth, `${keyBase}-it${idx}`);
|
|
7583
|
+
return /* @__PURE__ */ jsxs10(Box11, { flexDirection: "row", alignItems: "flex-start", marginBottom: 0, children: [
|
|
7584
|
+
/* @__PURE__ */ jsx11(Text10, { color: gColor, children: (item.task ? glyph : `${glyph} `).padEnd(item.task ? 4 : 3, " ") }),
|
|
7585
|
+
/* @__PURE__ */ jsx11(Box11, { flexDirection: "column", flexGrow: 1, children: body.length > 0 ? body : /* @__PURE__ */ jsx11(Text10, { dimColor: true, children: item.text }) })
|
|
7586
|
+
] }, `${keyBase}-row-${idx}`);
|
|
7587
|
+
}) }, keyBase);
|
|
7588
|
+
}
|
|
7589
|
+
function renderBlockquote(q, key) {
|
|
7590
|
+
const inner = q.tokens && q.tokens.length > 0 ? renderBlockTokens(q.tokens, `${key}-inner`) : /* @__PURE__ */ jsx11(Text10, { dimColor: true, italic: true, children: q.text });
|
|
7591
|
+
return /* @__PURE__ */ jsxs10(
|
|
7592
|
+
Box11,
|
|
7593
|
+
{
|
|
7594
|
+
flexDirection: "row",
|
|
7595
|
+
marginBottom: 1,
|
|
7596
|
+
borderStyle: "single",
|
|
7597
|
+
borderColor: BLUMA_TERMINAL.brandMagenta,
|
|
7598
|
+
paddingLeft: 1,
|
|
7599
|
+
paddingY: 0,
|
|
7600
|
+
children: [
|
|
7601
|
+
/* @__PURE__ */ jsx11(Text10, { color: BLUMA_TERMINAL.brandMagenta, children: "\u2502 " }),
|
|
7602
|
+
/* @__PURE__ */ jsx11(Box11, { flexDirection: "column", flexGrow: 1, children: inner })
|
|
7603
|
+
]
|
|
7604
|
+
},
|
|
7605
|
+
key
|
|
7606
|
+
);
|
|
7607
|
+
}
|
|
7608
|
+
function renderBlockTokens(tokens, keyRoot) {
|
|
7000
7609
|
const elements = [];
|
|
7001
7610
|
for (let i = 0; i < tokens.length; i++) {
|
|
7002
7611
|
const token = tokens[i];
|
|
7003
|
-
const key =
|
|
7612
|
+
const key = `${keyRoot}-${i}`;
|
|
7004
7613
|
switch (token.type) {
|
|
7005
7614
|
case "heading": {
|
|
7006
|
-
const
|
|
7007
|
-
const
|
|
7615
|
+
const h = token;
|
|
7616
|
+
const color = headingColor(h.depth);
|
|
7617
|
+
const prefix = h.depth <= 2 ? `${"#".repeat(h.depth)} ` : "";
|
|
7618
|
+
const inner = walkInline(h.tokens, `${key}-h`);
|
|
7008
7619
|
elements.push(
|
|
7009
|
-
/* @__PURE__ */
|
|
7010
|
-
prefix,
|
|
7011
|
-
|
|
7012
|
-
|
|
7013
|
-
] }) }, key)
|
|
7620
|
+
/* @__PURE__ */ jsxs10(Box11, { marginBottom: 1, flexDirection: "row", flexWrap: "wrap", alignItems: "flex-start", children: [
|
|
7621
|
+
/* @__PURE__ */ jsx11(Text10, { color, bold: true, children: prefix }),
|
|
7622
|
+
inner.length > 0 ? inner : /* @__PURE__ */ jsx11(Text10, { color, bold: true, children: h.text })
|
|
7623
|
+
] }, key)
|
|
7014
7624
|
);
|
|
7015
7625
|
break;
|
|
7016
7626
|
}
|
|
7017
|
-
case "paragraph":
|
|
7018
|
-
|
|
7019
|
-
elements.push(
|
|
7020
|
-
/* @__PURE__ */ jsx10(Box10, { marginBottom: 1, children: renderInline(para.text) }, key)
|
|
7021
|
-
);
|
|
7627
|
+
case "paragraph":
|
|
7628
|
+
elements.push(renderParagraph(token, key));
|
|
7022
7629
|
break;
|
|
7023
|
-
|
|
7024
|
-
|
|
7025
|
-
const list = token;
|
|
7026
|
-
list.items.forEach((item, idx) => {
|
|
7027
|
-
const bullet = list.ordered ? `${idx + 1}.` : "\u2022";
|
|
7028
|
-
const text = item.tokens?.filter((t) => t.type === "text").map((t) => t.text).join("") || item.text;
|
|
7029
|
-
elements.push(
|
|
7030
|
-
/* @__PURE__ */ jsxs9(Box10, { paddingLeft: 1, children: [
|
|
7031
|
-
/* @__PURE__ */ jsx10(Text9, { color: COLORS.listBullet, children: bullet }),
|
|
7032
|
-
/* @__PURE__ */ jsxs9(Text9, { children: [
|
|
7033
|
-
" ",
|
|
7034
|
-
renderInline(text)
|
|
7035
|
-
] })
|
|
7036
|
-
] }, `${key}-item-${idx}`)
|
|
7037
|
-
);
|
|
7038
|
-
});
|
|
7039
|
-
elements.push(/* @__PURE__ */ jsx10(Box10, { marginBottom: 1 }, `${key}-spacer`));
|
|
7630
|
+
case "list":
|
|
7631
|
+
elements.push(renderListBlock(token, 0, key));
|
|
7040
7632
|
break;
|
|
7041
|
-
}
|
|
7042
7633
|
case "code": {
|
|
7043
7634
|
const code = token;
|
|
7044
7635
|
let highlighted;
|
|
@@ -7051,110 +7642,144 @@ function renderTokens(tokens) {
|
|
|
7051
7642
|
highlighted = code.text;
|
|
7052
7643
|
}
|
|
7053
7644
|
elements.push(
|
|
7054
|
-
/* @__PURE__ */
|
|
7055
|
-
|
|
7056
|
-
|
|
7057
|
-
|
|
7645
|
+
/* @__PURE__ */ jsxs10(
|
|
7646
|
+
Box11,
|
|
7647
|
+
{
|
|
7648
|
+
flexDirection: "column",
|
|
7649
|
+
marginBottom: 1,
|
|
7650
|
+
borderStyle: "single",
|
|
7651
|
+
borderColor: BLUMA_TERMINAL.panelBorder,
|
|
7652
|
+
paddingX: 1,
|
|
7653
|
+
children: [
|
|
7654
|
+
code.lang ? /* @__PURE__ */ jsx11(Text10, { color: BLUMA_TERMINAL.codeLabel, dimColor: true, children: code.lang }) : null,
|
|
7655
|
+
/* @__PURE__ */ jsx11(Text10, { dimColor: true, children: highlighted })
|
|
7656
|
+
]
|
|
7657
|
+
},
|
|
7658
|
+
key
|
|
7659
|
+
)
|
|
7058
7660
|
);
|
|
7059
7661
|
break;
|
|
7060
7662
|
}
|
|
7061
|
-
case "blockquote":
|
|
7062
|
-
|
|
7063
|
-
elements.push(
|
|
7064
|
-
/* @__PURE__ */ jsxs9(Box10, { marginBottom: 1, children: [
|
|
7065
|
-
/* @__PURE__ */ jsx10(Text9, { color: COLORS.quote, children: "\u2502 " }),
|
|
7066
|
-
/* @__PURE__ */ jsx10(Text9, { dimColor: true, italic: true, children: quote.text })
|
|
7067
|
-
] }, key)
|
|
7068
|
-
);
|
|
7663
|
+
case "blockquote":
|
|
7664
|
+
elements.push(renderBlockquote(token, key));
|
|
7069
7665
|
break;
|
|
7070
|
-
}
|
|
7071
7666
|
case "table": {
|
|
7072
7667
|
const table = token;
|
|
7073
7668
|
elements.push(
|
|
7074
|
-
/* @__PURE__ */
|
|
7669
|
+
/* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", marginBottom: 1, children: [
|
|
7670
|
+
/* @__PURE__ */ jsx11(Box11, { flexDirection: "row", children: table.header.map((cell, idx) => {
|
|
7671
|
+
const headerNodes = walkInline(cell.tokens, `${key}-h${idx}`);
|
|
7672
|
+
const styled = headerNodes.length > 0 ? styleInlineNodes(headerNodes, `${key}-h${idx}`, { bold: true, color: BLUMA_TERMINAL.brandBlue }) : [/* @__PURE__ */ jsx11(Text10, { bold: true, color: BLUMA_TERMINAL.brandBlue, children: cell.text }, `${key}-h${idx}-t`)];
|
|
7673
|
+
return /* @__PURE__ */ jsx11(Box11, { paddingRight: 2, flexDirection: "row", flexWrap: "wrap", children: styled }, idx);
|
|
7674
|
+
}) }),
|
|
7675
|
+
table.rows.map((row, rowIdx) => /* @__PURE__ */ jsx11(Box11, { flexDirection: "row", children: row.map((cell, cellIdx) => {
|
|
7676
|
+
const cellNodes = walkInline(cell.tokens, `${key}-c${rowIdx}-${cellIdx}`);
|
|
7677
|
+
const styled = cellNodes.length > 0 ? styleInlineNodes(cellNodes, `${key}-c${rowIdx}-${cellIdx}`, { dimColor: true }) : [/* @__PURE__ */ jsx11(Text10, { dimColor: true, children: cell.text }, `${key}-c${rowIdx}-${cellIdx}-t`)];
|
|
7678
|
+
return /* @__PURE__ */ jsx11(Box11, { paddingRight: 2, flexDirection: "row", flexWrap: "wrap", children: styled }, cellIdx);
|
|
7679
|
+
}) }, `${key}-r${rowIdx}`))
|
|
7680
|
+
] }, key)
|
|
7075
7681
|
);
|
|
7076
|
-
table.rows.forEach((row, rowIdx) => {
|
|
7077
|
-
elements.push(
|
|
7078
|
-
/* @__PURE__ */ jsx10(Box10, { flexDirection: "row", children: row.map((cell, cellIdx) => /* @__PURE__ */ jsx10(Box10, { paddingRight: 2, children: /* @__PURE__ */ jsx10(Text9, { children: cell.text }) }, cellIdx)) }, `${key}-row-${rowIdx}`)
|
|
7079
|
-
);
|
|
7080
|
-
});
|
|
7081
|
-
elements.push(/* @__PURE__ */ jsx10(Box10, { marginBottom: 1 }, `${key}-spacer`));
|
|
7082
7682
|
break;
|
|
7083
7683
|
}
|
|
7084
|
-
case "hr":
|
|
7684
|
+
case "hr":
|
|
7085
7685
|
elements.push(
|
|
7086
|
-
/* @__PURE__ */
|
|
7686
|
+
/* @__PURE__ */ jsx11(Box11, { marginY: 1, children: /* @__PURE__ */ jsx11(Text10, { dimColor: true, children: "\u2500".repeat(42) }) }, key)
|
|
7087
7687
|
);
|
|
7088
7688
|
break;
|
|
7089
|
-
|
|
7090
|
-
case "space": {
|
|
7689
|
+
case "space":
|
|
7091
7690
|
break;
|
|
7092
|
-
|
|
7093
|
-
default: {
|
|
7691
|
+
default:
|
|
7094
7692
|
if ("text" in token && typeof token.text === "string") {
|
|
7095
|
-
elements.push(
|
|
7693
|
+
elements.push(
|
|
7694
|
+
/* @__PURE__ */ jsx11(Text10, { dimColor: true, children: token.text }, key)
|
|
7695
|
+
);
|
|
7096
7696
|
}
|
|
7097
|
-
}
|
|
7098
7697
|
}
|
|
7099
7698
|
}
|
|
7100
7699
|
return elements;
|
|
7101
7700
|
}
|
|
7102
|
-
function renderInline(text) {
|
|
7103
|
-
const parts = [];
|
|
7104
|
-
let remaining = text;
|
|
7105
|
-
let partIndex = 0;
|
|
7106
|
-
const inlineRegex = /(\*\*(.+?)\*\*|\*(.+?)\*|`(.+?)`|\[(.+?)\]\((.+?)\))/;
|
|
7107
|
-
while (remaining.length > 0) {
|
|
7108
|
-
const match = remaining.match(inlineRegex);
|
|
7109
|
-
if (!match) {
|
|
7110
|
-
parts.push(/* @__PURE__ */ jsx10(Text9, { children: remaining }, `inline-${partIndex++}`));
|
|
7111
|
-
break;
|
|
7112
|
-
}
|
|
7113
|
-
const matchIndex = match.index ?? 0;
|
|
7114
|
-
if (matchIndex > 0) {
|
|
7115
|
-
parts.push(
|
|
7116
|
-
/* @__PURE__ */ jsx10(Text9, { children: remaining.slice(0, matchIndex) }, `inline-${partIndex++}`)
|
|
7117
|
-
);
|
|
7118
|
-
}
|
|
7119
|
-
const fullMatch = match[0];
|
|
7120
|
-
if (fullMatch.startsWith("**")) {
|
|
7121
|
-
parts.push(
|
|
7122
|
-
/* @__PURE__ */ jsx10(Text9, { bold: true, children: match[2] }, `inline-${partIndex++}`)
|
|
7123
|
-
);
|
|
7124
|
-
} else if (fullMatch.startsWith("*")) {
|
|
7125
|
-
parts.push(
|
|
7126
|
-
/* @__PURE__ */ jsx10(Text9, { italic: true, children: match[3] }, `inline-${partIndex++}`)
|
|
7127
|
-
);
|
|
7128
|
-
} else if (fullMatch.startsWith("`")) {
|
|
7129
|
-
parts.push(
|
|
7130
|
-
/* @__PURE__ */ jsxs9(Text9, { color: COLORS.code, children: [
|
|
7131
|
-
"`",
|
|
7132
|
-
match[4],
|
|
7133
|
-
"`"
|
|
7134
|
-
] }, `inline-${partIndex++}`)
|
|
7135
|
-
);
|
|
7136
|
-
} else if (fullMatch.startsWith("[")) {
|
|
7137
|
-
parts.push(
|
|
7138
|
-
/* @__PURE__ */ jsx10(Text9, { color: COLORS.link, underline: true, children: match[5] }, `inline-${partIndex++}`)
|
|
7139
|
-
);
|
|
7140
|
-
}
|
|
7141
|
-
remaining = remaining.slice(matchIndex + fullMatch.length);
|
|
7142
|
-
}
|
|
7143
|
-
return parts.length === 1 ? parts[0] : /* @__PURE__ */ jsx10(Fragment3, { children: parts });
|
|
7144
|
-
}
|
|
7145
7701
|
var MarkdownRendererComponent = ({ markdown }) => {
|
|
7146
7702
|
if (!markdown || markdown.trim() === "") {
|
|
7147
7703
|
return null;
|
|
7148
7704
|
}
|
|
7149
7705
|
const tokens = marked.lexer(markdown);
|
|
7150
|
-
return /* @__PURE__ */
|
|
7706
|
+
return /* @__PURE__ */ jsx11(Box11, { flexDirection: "column", paddingRight: 1, children: renderBlockTokens(tokens, "md") });
|
|
7151
7707
|
};
|
|
7152
7708
|
var MarkdownRenderer = memo7(MarkdownRendererComponent);
|
|
7153
7709
|
|
|
7710
|
+
// src/app/ui/utils/expandablePreviewStore.ts
|
|
7711
|
+
var latest = null;
|
|
7712
|
+
function parseResult(result) {
|
|
7713
|
+
try {
|
|
7714
|
+
return JSON.parse(result);
|
|
7715
|
+
} catch {
|
|
7716
|
+
return null;
|
|
7717
|
+
}
|
|
7718
|
+
}
|
|
7719
|
+
function truncatedLineCount(text, maxVisible) {
|
|
7720
|
+
const allLines = text.split("\n").filter((l) => l.trim());
|
|
7721
|
+
if (allLines.length <= maxVisible) {
|
|
7722
|
+
return { truncated: 0, totalKept: allLines.length };
|
|
7723
|
+
}
|
|
7724
|
+
return { truncated: allLines.length - maxVisible, totalKept: maxVisible };
|
|
7725
|
+
}
|
|
7726
|
+
function refreshExpandableFromToolResult(toolName, result) {
|
|
7727
|
+
if (toolName.includes("task_boundary")) {
|
|
7728
|
+
return;
|
|
7729
|
+
}
|
|
7730
|
+
const parsed = parseResult(result);
|
|
7731
|
+
if (toolName.includes("read_file") && parsed && typeof parsed.content === "string") {
|
|
7732
|
+
const { truncated } = truncatedLineCount(parsed.content, TOOL_PREVIEW_MAX_LINES);
|
|
7733
|
+
if (truncated > 0) {
|
|
7734
|
+
const fp = typeof parsed.filepath === "string" ? parsed.filepath : "file";
|
|
7735
|
+
const sl = parsed.start_line;
|
|
7736
|
+
const el = parsed.end_line;
|
|
7737
|
+
const range = typeof sl === "number" && typeof el === "number" ? ` :${sl}-${el}` : "";
|
|
7738
|
+
latest = {
|
|
7739
|
+
fullText: parsed.content,
|
|
7740
|
+
title: `${fp}${range}`,
|
|
7741
|
+
toolName,
|
|
7742
|
+
linesHidden: truncated
|
|
7743
|
+
};
|
|
7744
|
+
} else {
|
|
7745
|
+
latest = null;
|
|
7746
|
+
}
|
|
7747
|
+
return;
|
|
7748
|
+
}
|
|
7749
|
+
if ((toolName.includes("shell_command") || toolName.includes("run_command") || toolName.includes("command_status")) && parsed) {
|
|
7750
|
+
const output = String(parsed.stdout || parsed.output || "");
|
|
7751
|
+
const stderr = String(parsed.stderr || "");
|
|
7752
|
+
const status = String(parsed.status || "");
|
|
7753
|
+
if (parsed.command_id && !output && !stderr && !status) {
|
|
7754
|
+
return;
|
|
7755
|
+
}
|
|
7756
|
+
if (status === "running") {
|
|
7757
|
+
return;
|
|
7758
|
+
}
|
|
7759
|
+
const blob = output || stderr;
|
|
7760
|
+
if (!blob) {
|
|
7761
|
+
return;
|
|
7762
|
+
}
|
|
7763
|
+
const { truncated } = truncatedLineCount(blob, TOOL_PREVIEW_MAX_LINES);
|
|
7764
|
+
if (truncated > 0) {
|
|
7765
|
+
latest = {
|
|
7766
|
+
fullText: blob,
|
|
7767
|
+
title: "shell output",
|
|
7768
|
+
toolName,
|
|
7769
|
+
linesHidden: truncated
|
|
7770
|
+
};
|
|
7771
|
+
} else {
|
|
7772
|
+
latest = null;
|
|
7773
|
+
}
|
|
7774
|
+
}
|
|
7775
|
+
}
|
|
7776
|
+
function peekLatestExpandable() {
|
|
7777
|
+
return latest;
|
|
7778
|
+
}
|
|
7779
|
+
|
|
7154
7780
|
// src/app/ui/components/ToolResultDisplay.tsx
|
|
7155
|
-
import { jsx as
|
|
7156
|
-
var
|
|
7157
|
-
var parseResult = (result) => {
|
|
7781
|
+
import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
7782
|
+
var parseResult2 = (result) => {
|
|
7158
7783
|
try {
|
|
7159
7784
|
return JSON.parse(result);
|
|
7160
7785
|
} catch {
|
|
@@ -7171,153 +7796,222 @@ var truncateLines = (text, max) => {
|
|
|
7171
7796
|
truncated: allLines.length - max
|
|
7172
7797
|
};
|
|
7173
7798
|
};
|
|
7799
|
+
function TodoTaskLine({
|
|
7800
|
+
done,
|
|
7801
|
+
label
|
|
7802
|
+
}) {
|
|
7803
|
+
return /* @__PURE__ */ jsxs11(Box12, { flexDirection: "row", children: [
|
|
7804
|
+
/* @__PURE__ */ jsx12(Text11, { color: done ? BLUMA_TERMINAL.brandBlue : BLUMA_TERMINAL.brandMagenta, children: done ? "\u25A0 " : "\u25A1 " }),
|
|
7805
|
+
/* @__PURE__ */ jsx12(Text11, { dimColor: done, strikethrough: done, color: done ? BLUMA_TERMINAL.muted : void 0, children: label })
|
|
7806
|
+
] });
|
|
7807
|
+
}
|
|
7174
7808
|
var ToolResultDisplayComponent = ({ toolName, result }) => {
|
|
7809
|
+
useEffect5(() => {
|
|
7810
|
+
refreshExpandableFromToolResult(toolName, result);
|
|
7811
|
+
}, [toolName, result]);
|
|
7175
7812
|
if (toolName.includes("task_boundary")) {
|
|
7176
7813
|
return null;
|
|
7177
7814
|
}
|
|
7178
|
-
const parsed =
|
|
7815
|
+
const parsed = parseResult2(result);
|
|
7179
7816
|
if (toolName.includes("message")) {
|
|
7180
|
-
const body = parsed?.content?.body
|
|
7817
|
+
const body = parsed?.content?.body ?? parsed?.body ?? parsed?.message;
|
|
7181
7818
|
if (!body) return null;
|
|
7182
|
-
return /* @__PURE__ */
|
|
7183
|
-
}
|
|
7184
|
-
if (toolName.includes("read_file") && parsed
|
|
7185
|
-
const { lines, truncated } = truncateLines(parsed.content,
|
|
7186
|
-
return /* @__PURE__ */
|
|
7187
|
-
lines.map((line, i) => /* @__PURE__ */
|
|
7188
|
-
truncated > 0
|
|
7189
|
-
"
|
|
7819
|
+
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsx12(Box12, { paddingLeft: 2, flexDirection: "column", children: /* @__PURE__ */ jsx12(MarkdownRenderer, { markdown: String(body) }) }) });
|
|
7820
|
+
}
|
|
7821
|
+
if (toolName.includes("read_file") && parsed && typeof parsed.content === "string") {
|
|
7822
|
+
const { lines, truncated } = truncateLines(parsed.content, TOOL_PREVIEW_MAX_LINES);
|
|
7823
|
+
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsxs11(Box12, { flexDirection: "column", paddingLeft: 2, children: [
|
|
7824
|
+
lines.map((line, i) => /* @__PURE__ */ jsx12(Text11, { dimColor: true, children: line.slice(0, 120) }, i)),
|
|
7825
|
+
truncated > 0 ? /* @__PURE__ */ jsxs11(Text11, { dimColor: true, children: [
|
|
7826
|
+
"\u2026 +",
|
|
7190
7827
|
truncated,
|
|
7191
|
-
" lines"
|
|
7192
|
-
] })
|
|
7193
|
-
] });
|
|
7828
|
+
" lines \xB7 Ctrl+O expand"
|
|
7829
|
+
] }) : null
|
|
7830
|
+
] }) });
|
|
7194
7831
|
}
|
|
7195
7832
|
if ((toolName.includes("shell_command") || toolName.includes("run_command") || toolName.includes("command_status")) && parsed) {
|
|
7196
|
-
const output = parsed.stdout || parsed.output || "";
|
|
7197
|
-
const stderr = parsed.stderr || "";
|
|
7833
|
+
const output = String(parsed.stdout || parsed.output || "");
|
|
7834
|
+
const stderr = String(parsed.stderr || "");
|
|
7198
7835
|
const exitCode = parsed.exit_code ?? parsed.exitCode ?? 0;
|
|
7199
|
-
const status = parsed.status || "";
|
|
7836
|
+
const status = String(parsed.status || "");
|
|
7200
7837
|
if (parsed.command_id && !output && !stderr && !status) {
|
|
7201
|
-
return /* @__PURE__ */
|
|
7838
|
+
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsx12(Box12, { paddingLeft: 2, children: /* @__PURE__ */ jsxs11(Text11, { dimColor: true, children: [
|
|
7202
7839
|
"started #",
|
|
7203
|
-
parsed.command_id.slice(0, 8)
|
|
7204
|
-
] }) });
|
|
7840
|
+
String(parsed.command_id).slice(0, 8)
|
|
7841
|
+
] }) }) });
|
|
7205
7842
|
}
|
|
7206
7843
|
if (status === "running") {
|
|
7207
|
-
return /* @__PURE__ */
|
|
7844
|
+
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsx12(Box12, { paddingLeft: 2, children: /* @__PURE__ */ jsx12(Text11, { color: BLUMA_TERMINAL.warn, dimColor: true, children: "still running\u2026" }) }) });
|
|
7208
7845
|
}
|
|
7209
7846
|
if (!output && !stderr) return null;
|
|
7210
|
-
const { lines, truncated } = truncateLines(output || stderr,
|
|
7847
|
+
const { lines, truncated } = truncateLines(output || stderr, TOOL_PREVIEW_MAX_LINES);
|
|
7211
7848
|
const isError = exitCode !== 0;
|
|
7212
7849
|
const isSuccess = exitCode === 0 && status !== "running";
|
|
7213
|
-
const
|
|
7214
|
-
return /* @__PURE__ */
|
|
7215
|
-
lines.map((line, i) => /* @__PURE__ */
|
|
7216
|
-
truncated > 0
|
|
7217
|
-
"
|
|
7850
|
+
const lineColor = isError ? BLUMA_TERMINAL.err : isSuccess ? BLUMA_TERMINAL.success : BLUMA_TERMINAL.muted;
|
|
7851
|
+
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsxs11(Box12, { flexDirection: "column", paddingLeft: 2, children: [
|
|
7852
|
+
lines.map((line, i) => /* @__PURE__ */ jsx12(Text11, { dimColor: true, color: lineColor, children: line.slice(0, 120) }, i)),
|
|
7853
|
+
truncated > 0 ? /* @__PURE__ */ jsxs11(Text11, { dimColor: true, children: [
|
|
7854
|
+
"\u2026 +",
|
|
7218
7855
|
truncated,
|
|
7219
|
-
" lines"
|
|
7220
|
-
] }),
|
|
7221
|
-
exitCode !== 0
|
|
7222
|
-
"exit
|
|
7856
|
+
" lines \xB7 Ctrl+O expand"
|
|
7857
|
+
] }) : null,
|
|
7858
|
+
exitCode !== 0 ? /* @__PURE__ */ jsxs11(Text11, { dimColor: true, color: BLUMA_TERMINAL.err, children: [
|
|
7859
|
+
"exit ",
|
|
7223
7860
|
exitCode
|
|
7224
|
-
] })
|
|
7225
|
-
] });
|
|
7861
|
+
] }) : null
|
|
7862
|
+
] }) });
|
|
7226
7863
|
}
|
|
7227
7864
|
if ((toolName.includes("grep") || toolName.includes("find_by_name")) && parsed) {
|
|
7228
7865
|
const matches = parsed.matches || parsed.results || parsed.files || [];
|
|
7229
7866
|
if (matches.length === 0) {
|
|
7230
|
-
return /* @__PURE__ */
|
|
7867
|
+
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsx12(Box12, { paddingLeft: 2, children: /* @__PURE__ */ jsx12(Text11, { dimColor: true, children: "no matches" }) }) });
|
|
7231
7868
|
}
|
|
7232
|
-
return /* @__PURE__ */
|
|
7233
|
-
/* @__PURE__ */
|
|
7869
|
+
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsxs11(Box12, { flexDirection: "column", paddingLeft: 2, children: [
|
|
7870
|
+
/* @__PURE__ */ jsxs11(Text11, { dimColor: true, children: [
|
|
7234
7871
|
matches.length,
|
|
7235
7872
|
" matches"
|
|
7236
7873
|
] }),
|
|
7237
|
-
matches.slice(0, 5).map((m, i) =>
|
|
7238
|
-
|
|
7239
|
-
|
|
7240
|
-
|
|
7241
|
-
|
|
7242
|
-
|
|
7243
|
-
|
|
7244
|
-
|
|
7245
|
-
|
|
7246
|
-
|
|
7874
|
+
matches.slice(0, 5).map((m, i) => {
|
|
7875
|
+
const row = m;
|
|
7876
|
+
const path19 = row.file || row.path || row.name || m;
|
|
7877
|
+
const line = row.line;
|
|
7878
|
+
return /* @__PURE__ */ jsxs11(Text11, { dimColor: true, children: [
|
|
7879
|
+
String(path19),
|
|
7880
|
+
line != null ? `:${line}` : ""
|
|
7881
|
+
] }, i);
|
|
7882
|
+
}),
|
|
7883
|
+
matches.length > 5 ? /* @__PURE__ */ jsxs11(Text11, { dimColor: true, children: [
|
|
7884
|
+
"\u2026 +",
|
|
7885
|
+
matches.length - 5
|
|
7886
|
+
] }) : null
|
|
7887
|
+
] }) });
|
|
7247
7888
|
}
|
|
7248
7889
|
if (toolName.includes("ls_tool") && parsed) {
|
|
7249
7890
|
const entries = parsed.entries || parsed.files || [];
|
|
7250
7891
|
if (entries.length === 0) return null;
|
|
7251
|
-
return /* @__PURE__ */
|
|
7252
|
-
entries.slice(0, 6).map((e, i) =>
|
|
7253
|
-
|
|
7254
|
-
|
|
7255
|
-
|
|
7256
|
-
|
|
7257
|
-
|
|
7258
|
-
|
|
7259
|
-
|
|
7260
|
-
|
|
7261
|
-
|
|
7262
|
-
|
|
7892
|
+
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsxs11(Box12, { flexDirection: "column", paddingLeft: 2, children: [
|
|
7893
|
+
entries.slice(0, 6).map((e, i) => {
|
|
7894
|
+
const row = e;
|
|
7895
|
+
const name = row.name ?? e;
|
|
7896
|
+
const isDir = Boolean(row.isDirectory);
|
|
7897
|
+
return /* @__PURE__ */ jsxs11(Text11, { dimColor: true, color: isDir ? BLUMA_TERMINAL.brandBlue : BLUMA_TERMINAL.muted, children: [
|
|
7898
|
+
isDir ? "d " : "f ",
|
|
7899
|
+
String(name)
|
|
7900
|
+
] }, i);
|
|
7901
|
+
}),
|
|
7902
|
+
entries.length > 6 ? /* @__PURE__ */ jsxs11(Text11, { dimColor: true, children: [
|
|
7903
|
+
"\u2026 +",
|
|
7904
|
+
entries.length - 6
|
|
7905
|
+
] }) : null
|
|
7906
|
+
] }) });
|
|
7263
7907
|
}
|
|
7264
7908
|
if (toolName.includes("load_skill") && parsed) {
|
|
7265
7909
|
if (!parsed.success) {
|
|
7266
|
-
return /* @__PURE__ */
|
|
7267
|
-
"
|
|
7268
|
-
parsed.message
|
|
7269
|
-
] }) });
|
|
7270
|
-
}
|
|
7271
|
-
|
|
7272
|
-
|
|
7273
|
-
/* @__PURE__ */
|
|
7274
|
-
/* @__PURE__ */
|
|
7275
|
-
"
|
|
7276
|
-
|
|
7277
|
-
|
|
7910
|
+
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsx12(Box12, { paddingLeft: 2, children: /* @__PURE__ */ jsxs11(Text11, { dimColor: true, color: BLUMA_TERMINAL.err, children: [
|
|
7911
|
+
"Not found: ",
|
|
7912
|
+
String(parsed.message || "")
|
|
7913
|
+
] }) }) });
|
|
7914
|
+
}
|
|
7915
|
+
const desc = parsed.description ? String(parsed.description) : "";
|
|
7916
|
+
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsxs11(Box12, { paddingLeft: 2, flexDirection: "row", flexWrap: "wrap", children: [
|
|
7917
|
+
/* @__PURE__ */ jsx12(Text11, { color: BLUMA_TERMINAL.brandMagenta, bold: true, children: String(parsed.skill_name || "") }),
|
|
7918
|
+
/* @__PURE__ */ jsxs11(Text11, { dimColor: true, children: [
|
|
7919
|
+
" ",
|
|
7920
|
+
"\u2014 ",
|
|
7921
|
+
desc.slice(0, 80),
|
|
7922
|
+
desc.length > 80 ? "\u2026" : ""
|
|
7278
7923
|
] })
|
|
7279
|
-
] });
|
|
7924
|
+
] }) });
|
|
7280
7925
|
}
|
|
7281
7926
|
if (toolName.includes("todo")) {
|
|
7282
|
-
|
|
7927
|
+
if (parsed && Array.isArray(parsed.tasks)) {
|
|
7928
|
+
const tasks = parsed.tasks;
|
|
7929
|
+
const stats = parsed.stats;
|
|
7930
|
+
const msg = typeof parsed.message === "string" ? parsed.message : "";
|
|
7931
|
+
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsxs11(Box12, { flexDirection: "column", paddingLeft: 2, children: [
|
|
7932
|
+
msg ? /* @__PURE__ */ jsx12(Box12, { marginBottom: 1, children: /* @__PURE__ */ jsx12(Text11, { dimColor: true, children: msg }) }) : null,
|
|
7933
|
+
stats && typeof stats.progress === "number" ? /* @__PURE__ */ jsxs11(Text11, { dimColor: true, children: [
|
|
7934
|
+
stats.completed ?? 0,
|
|
7935
|
+
"/",
|
|
7936
|
+
stats.total ?? tasks.length,
|
|
7937
|
+
" done \xB7 ",
|
|
7938
|
+
stats.progress,
|
|
7939
|
+
"%"
|
|
7940
|
+
] }) : null,
|
|
7941
|
+
/* @__PURE__ */ jsxs11(Box12, { flexDirection: "column", marginTop: 1, children: [
|
|
7942
|
+
tasks.slice(0, 12).map((t, i) => {
|
|
7943
|
+
const done = t.status === "completed" || t.isComplete === true;
|
|
7944
|
+
const line = `#${t.id ?? i + 1} ${t.description ?? ""}`;
|
|
7945
|
+
return /* @__PURE__ */ jsx12(TodoTaskLine, { done, label: line }, i);
|
|
7946
|
+
}),
|
|
7947
|
+
tasks.length > 12 ? /* @__PURE__ */ jsxs11(Text11, { dimColor: true, children: [
|
|
7948
|
+
"\u2026 +",
|
|
7949
|
+
tasks.length - 12,
|
|
7950
|
+
" tasks"
|
|
7951
|
+
] }) : null
|
|
7952
|
+
] })
|
|
7953
|
+
] }) });
|
|
7954
|
+
}
|
|
7955
|
+
const lines = result.split("\n").filter(Boolean);
|
|
7956
|
+
if (lines.length === 0) return null;
|
|
7957
|
+
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsx12(Box12, { flexDirection: "column", paddingLeft: 2, children: lines.slice(0, 14).map((line, i) => /* @__PURE__ */ jsx12(Text11, { dimColor: true, children: line.slice(0, 100) }, i)) }) });
|
|
7283
7958
|
}
|
|
7284
7959
|
if (toolName.includes("view_file_outline") && parsed) {
|
|
7285
7960
|
const symbols = parsed.symbols || parsed.outline || [];
|
|
7286
7961
|
if (symbols.length === 0) return null;
|
|
7287
|
-
return /* @__PURE__ */
|
|
7288
|
-
symbols.slice(0, 5).map((s, i) =>
|
|
7289
|
-
|
|
7290
|
-
|
|
7291
|
-
|
|
7292
|
-
|
|
7293
|
-
|
|
7294
|
-
|
|
7295
|
-
|
|
7296
|
-
|
|
7297
|
-
|
|
7298
|
-
|
|
7962
|
+
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsxs11(Box12, { flexDirection: "column", paddingLeft: 2, children: [
|
|
7963
|
+
symbols.slice(0, 5).map((s, i) => {
|
|
7964
|
+
const row = s;
|
|
7965
|
+
return /* @__PURE__ */ jsxs11(Text11, { dimColor: true, children: [
|
|
7966
|
+
String(row.kind || "sym"),
|
|
7967
|
+
" ",
|
|
7968
|
+
String(row.name || "")
|
|
7969
|
+
] }, i);
|
|
7970
|
+
}),
|
|
7971
|
+
symbols.length > 5 ? /* @__PURE__ */ jsxs11(Text11, { dimColor: true, children: [
|
|
7972
|
+
"\u2026 +",
|
|
7973
|
+
symbols.length - 5
|
|
7974
|
+
] }) : null
|
|
7975
|
+
] }) });
|
|
7299
7976
|
}
|
|
7300
7977
|
return null;
|
|
7301
7978
|
};
|
|
7302
7979
|
var ToolResultDisplay = memo8(ToolResultDisplayComponent);
|
|
7303
7980
|
|
|
7981
|
+
// src/app/ui/SessionInfoConnectingMCP.tsx
|
|
7982
|
+
import { Box as Box13, Text as Text12 } from "ink";
|
|
7983
|
+
import Spinner from "ink-spinner";
|
|
7984
|
+
import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
7985
|
+
var SessionInfoConnectingMCP = ({
|
|
7986
|
+
sessionId,
|
|
7987
|
+
workdir,
|
|
7988
|
+
statusMessage
|
|
7989
|
+
}) => /* @__PURE__ */ jsx13(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsxs12(Box13, { flexDirection: "column", paddingLeft: 1, children: [
|
|
7990
|
+
/* @__PURE__ */ jsxs12(Text12, { children: [
|
|
7991
|
+
/* @__PURE__ */ jsx13(Text12, { bold: true, color: BLUMA_TERMINAL.brandBlue, children: "session" }),
|
|
7992
|
+
/* @__PURE__ */ jsx13(Text12, { dimColor: true, children: " \xB7 " }),
|
|
7993
|
+
/* @__PURE__ */ jsx13(Text12, { color: BLUMA_TERMINAL.brandMagenta, children: sessionId.slice(0, 12) })
|
|
7994
|
+
] }),
|
|
7995
|
+
/* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
|
|
7996
|
+
/* @__PURE__ */ jsx13(Text12, { color: BLUMA_TERMINAL.brandMagenta, children: "\u2514 " }),
|
|
7997
|
+
workdir
|
|
7998
|
+
] }),
|
|
7999
|
+
/* @__PURE__ */ jsxs12(Box13, { marginTop: 1, flexDirection: "row", flexWrap: "wrap", children: [
|
|
8000
|
+
/* @__PURE__ */ jsxs12(Text12, { color: BLUMA_TERMINAL.warn, children: [
|
|
8001
|
+
/* @__PURE__ */ jsx13(Spinner, { type: "dots" }),
|
|
8002
|
+
" "
|
|
8003
|
+
] }),
|
|
8004
|
+
/* @__PURE__ */ jsx13(Text12, { dimColor: true, children: statusMessage || "Establishing MCP\u2026" })
|
|
8005
|
+
] })
|
|
8006
|
+
] }) });
|
|
8007
|
+
var SessionInfoConnectingMCP_default = SessionInfoConnectingMCP;
|
|
8008
|
+
|
|
7304
8009
|
// src/app/ui/components/SlashCommands.tsx
|
|
7305
|
-
import { Box as
|
|
7306
|
-
import { Fragment as
|
|
8010
|
+
import { Box as Box14, Text as Text13 } from "ink";
|
|
8011
|
+
import { Fragment as Fragment2, jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
7307
8012
|
var SlashCommands = ({ input, setHistory, agentRef }) => {
|
|
7308
8013
|
const [cmd, ...args] = input.slice(1).trim().split(/\s+/);
|
|
7309
|
-
const outBox = (children) => /* @__PURE__ */
|
|
7310
|
-
Box12,
|
|
7311
|
-
{
|
|
7312
|
-
borderStyle: "single",
|
|
7313
|
-
borderColor: "gray",
|
|
7314
|
-
paddingX: 2,
|
|
7315
|
-
paddingY: 0,
|
|
7316
|
-
marginBottom: 1,
|
|
7317
|
-
flexDirection: "column",
|
|
7318
|
-
children
|
|
7319
|
-
}
|
|
7320
|
-
);
|
|
8014
|
+
const outBox = (children) => /* @__PURE__ */ jsx14(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsx14(Box14, { paddingLeft: 1, flexDirection: "column", children }) });
|
|
7321
8015
|
const render2 = () => {
|
|
7322
8016
|
if (!cmd) {
|
|
7323
8017
|
return null;
|
|
@@ -7325,11 +8019,11 @@ var SlashCommands = ({ input, setHistory, agentRef }) => {
|
|
|
7325
8019
|
if (cmd === "help") {
|
|
7326
8020
|
const cmds = getSlashCommands();
|
|
7327
8021
|
return outBox(
|
|
7328
|
-
/* @__PURE__ */
|
|
7329
|
-
/* @__PURE__ */
|
|
7330
|
-
/* @__PURE__ */
|
|
7331
|
-
/* @__PURE__ */
|
|
7332
|
-
/* @__PURE__ */
|
|
8022
|
+
/* @__PURE__ */ jsxs13(Fragment2, { children: [
|
|
8023
|
+
/* @__PURE__ */ jsx14(Box14, { marginBottom: 1, children: /* @__PURE__ */ jsx14(Text13, { bold: true, color: BLUMA_TERMINAL.brandMagenta, children: "Available Commands" }) }),
|
|
8024
|
+
/* @__PURE__ */ jsx14(Box14, { flexDirection: "column", children: cmds.map((c, i) => /* @__PURE__ */ jsxs13(Box14, { children: [
|
|
8025
|
+
/* @__PURE__ */ jsx14(Text13, { color: BLUMA_TERMINAL.brandBlue, children: c.name.padEnd(12) }),
|
|
8026
|
+
/* @__PURE__ */ jsx14(Text13, { dimColor: true, children: c.description })
|
|
7333
8027
|
] }, i)) })
|
|
7334
8028
|
] })
|
|
7335
8029
|
);
|
|
@@ -7337,9 +8031,9 @@ var SlashCommands = ({ input, setHistory, agentRef }) => {
|
|
|
7337
8031
|
if (cmd === "clear") {
|
|
7338
8032
|
setHistory((prev) => prev.filter((item) => item.id === 0 || item.id === 1));
|
|
7339
8033
|
return outBox(
|
|
7340
|
-
/* @__PURE__ */
|
|
7341
|
-
/* @__PURE__ */
|
|
7342
|
-
/* @__PURE__ */
|
|
8034
|
+
/* @__PURE__ */ jsxs13(Box14, { children: [
|
|
8035
|
+
/* @__PURE__ */ jsx14(Text13, { color: "green", children: "[ok]" }),
|
|
8036
|
+
/* @__PURE__ */ jsx14(Text13, { dimColor: true, children: " History cleared" })
|
|
7343
8037
|
] })
|
|
7344
8038
|
);
|
|
7345
8039
|
}
|
|
@@ -7351,8 +8045,8 @@ var SlashCommands = ({ input, setHistory, agentRef }) => {
|
|
|
7351
8045
|
setHistory((prev) => prev.concat({
|
|
7352
8046
|
id: Date.now(),
|
|
7353
8047
|
component: outBox(
|
|
7354
|
-
/* @__PURE__ */
|
|
7355
|
-
"
|
|
8048
|
+
/* @__PURE__ */ jsx14(Box14, { children: /* @__PURE__ */ jsxs13(Text13, { color: "red", children: [
|
|
8049
|
+
"Failed to execute /init: ",
|
|
7356
8050
|
e?.message || String(e)
|
|
7357
8051
|
] }) })
|
|
7358
8052
|
)
|
|
@@ -7372,41 +8066,41 @@ var SlashCommands = ({ input, setHistory, agentRef }) => {
|
|
|
7372
8066
|
const colType = 10;
|
|
7373
8067
|
const colSource = 18;
|
|
7374
8068
|
return outBox(
|
|
7375
|
-
/* @__PURE__ */
|
|
7376
|
-
/* @__PURE__ */
|
|
7377
|
-
/* @__PURE__ */
|
|
7378
|
-
/* @__PURE__ */
|
|
7379
|
-
/* @__PURE__ */
|
|
8069
|
+
/* @__PURE__ */ jsxs13(Fragment2, { children: [
|
|
8070
|
+
/* @__PURE__ */ jsxs13(Box14, { marginBottom: 1, children: [
|
|
8071
|
+
/* @__PURE__ */ jsx14(Text13, { bold: true, color: BLUMA_TERMINAL.brandMagenta, children: "MCP Tools" }),
|
|
8072
|
+
/* @__PURE__ */ jsx14(Text13, { dimColor: true, children: " \u2022 " }),
|
|
8073
|
+
/* @__PURE__ */ jsxs13(Text13, { dimColor: true, children: [
|
|
7380
8074
|
tools.length,
|
|
7381
8075
|
" total"
|
|
7382
8076
|
] }),
|
|
7383
|
-
term && /* @__PURE__ */
|
|
7384
|
-
/* @__PURE__ */
|
|
7385
|
-
/* @__PURE__ */
|
|
8077
|
+
term && /* @__PURE__ */ jsxs13(Fragment2, { children: [
|
|
8078
|
+
/* @__PURE__ */ jsx14(Text13, { dimColor: true, children: " \u2022 filter: " }),
|
|
8079
|
+
/* @__PURE__ */ jsxs13(Text13, { color: BLUMA_TERMINAL.brandBlue, children: [
|
|
7386
8080
|
'"',
|
|
7387
8081
|
term,
|
|
7388
8082
|
'"'
|
|
7389
8083
|
] }),
|
|
7390
|
-
/* @__PURE__ */
|
|
8084
|
+
/* @__PURE__ */ jsxs13(Text13, { dimColor: true, children: [
|
|
7391
8085
|
" \u2022 showing: ",
|
|
7392
8086
|
filtered.length
|
|
7393
8087
|
] })
|
|
7394
8088
|
] })
|
|
7395
8089
|
] }),
|
|
7396
|
-
filtered.length === 0 ? /* @__PURE__ */
|
|
7397
|
-
/* @__PURE__ */
|
|
8090
|
+
filtered.length === 0 ? /* @__PURE__ */ jsx14(Text13, { color: "yellow", children: "No MCP tools found" }) : /* @__PURE__ */ jsxs13(Box14, { flexDirection: "column", children: [
|
|
8091
|
+
/* @__PURE__ */ jsx14(Box14, { children: /* @__PURE__ */ jsxs13(Text13, { color: "gray", children: [
|
|
7398
8092
|
pad("Name", colName),
|
|
7399
8093
|
" \u2502 ",
|
|
7400
8094
|
pad("Type", colType),
|
|
7401
8095
|
" \u2502 ",
|
|
7402
8096
|
pad("Source", colSource)
|
|
7403
8097
|
] }) }),
|
|
7404
|
-
/* @__PURE__ */
|
|
8098
|
+
/* @__PURE__ */ jsx14(Text13, { color: "gray", children: "\u2500".repeat(colName + colType + colSource + 6) }),
|
|
7405
8099
|
filtered.map((t, i) => {
|
|
7406
8100
|
const name = t.function?.name || t.name || "tool";
|
|
7407
8101
|
const type = t.function?.name ? "fn" : t.type || "tool";
|
|
7408
8102
|
const source = t.source || t.provider || "mcp";
|
|
7409
|
-
return /* @__PURE__ */
|
|
8103
|
+
return /* @__PURE__ */ jsxs13(Text13, { color: "white", children: [
|
|
7410
8104
|
pad(name, colName),
|
|
7411
8105
|
" \u2502 ",
|
|
7412
8106
|
pad(String(type), colType),
|
|
@@ -7429,22 +8123,22 @@ var SlashCommands = ({ input, setHistory, agentRef }) => {
|
|
|
7429
8123
|
const colType = 10;
|
|
7430
8124
|
const colSource = 18;
|
|
7431
8125
|
return outBox(
|
|
7432
|
-
/* @__PURE__ */
|
|
7433
|
-
/* @__PURE__ */
|
|
7434
|
-
/* @__PURE__ */
|
|
8126
|
+
/* @__PURE__ */ jsxs13(Fragment2, { children: [
|
|
8127
|
+
/* @__PURE__ */ jsx14(Text13, { color: BLUMA_TERMINAL.brandMagenta, bold: true, children: "Native Tools" }),
|
|
8128
|
+
/* @__PURE__ */ jsxs13(Text13, { color: "gray", children: [
|
|
7435
8129
|
"Total Native: ",
|
|
7436
8130
|
tools.length,
|
|
7437
8131
|
term ? ` | Filter: "${term}" | Showing: ${filtered.length}` : ""
|
|
7438
8132
|
] }),
|
|
7439
|
-
filtered.length === 0 ? /* @__PURE__ */
|
|
7440
|
-
/* @__PURE__ */
|
|
8133
|
+
filtered.length === 0 ? /* @__PURE__ */ jsx14(Text13, { color: "yellow", children: "No native tools to display." }) : /* @__PURE__ */ jsxs13(Box14, { flexDirection: "column", children: [
|
|
8134
|
+
/* @__PURE__ */ jsxs13(Text13, { color: "gray", children: [
|
|
7441
8135
|
pad("Name", colName),
|
|
7442
8136
|
" | ",
|
|
7443
8137
|
pad("Type", colType),
|
|
7444
8138
|
" | ",
|
|
7445
8139
|
pad("Source", colSource)
|
|
7446
8140
|
] }),
|
|
7447
|
-
/* @__PURE__ */
|
|
8141
|
+
/* @__PURE__ */ jsxs13(Text13, { color: "gray", children: [
|
|
7448
8142
|
"".padEnd(colName, "-"),
|
|
7449
8143
|
"---",
|
|
7450
8144
|
"".padEnd(colType, "-"),
|
|
@@ -7455,7 +8149,7 @@ var SlashCommands = ({ input, setHistory, agentRef }) => {
|
|
|
7455
8149
|
const name = t.function?.name || t.name || "tool";
|
|
7456
8150
|
const type = t.function?.name ? "fn" : t.type || "tool";
|
|
7457
8151
|
const source = t.source || "native";
|
|
7458
|
-
return /* @__PURE__ */
|
|
8152
|
+
return /* @__PURE__ */ jsxs13(Text13, { color: "white", children: [
|
|
7459
8153
|
pad(name, colName),
|
|
7460
8154
|
" | ",
|
|
7461
8155
|
pad(String(type), colType),
|
|
@@ -7467,18 +8161,18 @@ var SlashCommands = ({ input, setHistory, agentRef }) => {
|
|
|
7467
8161
|
] })
|
|
7468
8162
|
);
|
|
7469
8163
|
}
|
|
7470
|
-
return outBox(/* @__PURE__ */
|
|
8164
|
+
return outBox(/* @__PURE__ */ jsxs13(Text13, { color: "red", children: [
|
|
7471
8165
|
"Command not recognized: /",
|
|
7472
8166
|
cmd
|
|
7473
8167
|
] }));
|
|
7474
8168
|
};
|
|
7475
|
-
return /* @__PURE__ */
|
|
8169
|
+
return /* @__PURE__ */ jsx14(Fragment2, { children: render2() });
|
|
7476
8170
|
};
|
|
7477
8171
|
var SlashCommands_default = SlashCommands;
|
|
7478
8172
|
|
|
7479
8173
|
// src/app/agent/utils/update_check.ts
|
|
7480
8174
|
import updateNotifier from "update-notifier";
|
|
7481
|
-
import { fileURLToPath as
|
|
8175
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
7482
8176
|
import path18 from "path";
|
|
7483
8177
|
import fs14 from "fs";
|
|
7484
8178
|
var BLUMA_PACKAGE_NAME = "@nomad-e/bluma-cli";
|
|
@@ -7513,7 +8207,7 @@ async function checkForUpdates() {
|
|
|
7513
8207
|
pkg = findBlumaPackageJson(path18.dirname(binPath));
|
|
7514
8208
|
}
|
|
7515
8209
|
if (!pkg) {
|
|
7516
|
-
const __filename =
|
|
8210
|
+
const __filename = fileURLToPath3(import.meta.url);
|
|
7517
8211
|
const __dirname2 = path18.dirname(__filename);
|
|
7518
8212
|
pkg = findBlumaPackageJson(__dirname2);
|
|
7519
8213
|
}
|
|
@@ -7542,86 +8236,88 @@ Run: npm i -g ${BLUMA_PACKAGE_NAME} to update.`;
|
|
|
7542
8236
|
}
|
|
7543
8237
|
|
|
7544
8238
|
// src/app/ui/components/UpdateNotice.tsx
|
|
7545
|
-
import { Box as
|
|
7546
|
-
import { jsx as
|
|
8239
|
+
import { Box as Box15, Text as Text14 } from "ink";
|
|
8240
|
+
import { jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
7547
8241
|
function parseUpdateMessage(msg) {
|
|
7548
8242
|
const lines = msg.split(/\r?\n/).map((l) => l.trim());
|
|
7549
8243
|
const first = lines[0] || "";
|
|
7550
8244
|
const hintLine = lines.slice(1).join(" ") || "";
|
|
7551
8245
|
const nameMatch = first.match(/Update available for\s+([^!]+)!/i);
|
|
7552
8246
|
const versionMatch = first.match(/!\s*([^\s]+)\s*→\s*([^\s]+)/);
|
|
7553
|
-
const name = nameMatch?.[1]?.trim();
|
|
7554
|
-
const current = versionMatch?.[1]?.trim();
|
|
7555
|
-
const latest = versionMatch?.[2]?.trim();
|
|
7556
8247
|
return {
|
|
7557
|
-
name,
|
|
7558
|
-
current,
|
|
7559
|
-
latest,
|
|
8248
|
+
name: nameMatch?.[1]?.trim(),
|
|
8249
|
+
current: versionMatch?.[1]?.trim(),
|
|
8250
|
+
latest: versionMatch?.[2]?.trim(),
|
|
7560
8251
|
hint: hintLine || void 0
|
|
7561
8252
|
};
|
|
7562
8253
|
}
|
|
7563
8254
|
var UpdateNotice = ({ message: message2 }) => {
|
|
7564
|
-
const { name, current, latest, hint } = parseUpdateMessage(message2);
|
|
7565
|
-
return /* @__PURE__ */
|
|
7566
|
-
/* @__PURE__ */
|
|
7567
|
-
name && current &&
|
|
7568
|
-
|
|
7569
|
-
|
|
8255
|
+
const { name, current, latest: latest2, hint } = parseUpdateMessage(message2);
|
|
8256
|
+
return /* @__PURE__ */ jsx15(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsxs14(Box15, { flexDirection: "column", paddingLeft: 2, children: [
|
|
8257
|
+
name && current && latest2 ? /* @__PURE__ */ jsx15(Text14, { color: BLUMA_TERMINAL.brandMagenta, bold: true, children: name }) : null,
|
|
8258
|
+
name && current && latest2 ? /* @__PURE__ */ jsxs14(Text14, { dimColor: true, children: [
|
|
8259
|
+
current,
|
|
8260
|
+
" \u2192 ",
|
|
8261
|
+
latest2
|
|
8262
|
+
] }) : /* @__PURE__ */ jsx15(Text14, { dimColor: true, children: message2 }),
|
|
8263
|
+
hint ? /* @__PURE__ */ jsx15(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx15(Text14, { dimColor: true, children: hint }) }) : null
|
|
8264
|
+
] }) });
|
|
7570
8265
|
};
|
|
7571
8266
|
var UpdateNotice_default = UpdateNotice;
|
|
7572
8267
|
|
|
7573
8268
|
// src/app/ui/components/ErrorMessage.tsx
|
|
7574
|
-
import { Box as
|
|
7575
|
-
import { jsx as
|
|
7576
|
-
var ErrorMessage = ({ message: message2, details, hint }) => {
|
|
7577
|
-
|
|
7578
|
-
|
|
7579
|
-
|
|
7580
|
-
|
|
7581
|
-
|
|
7582
|
-
|
|
7583
|
-
|
|
7584
|
-
hint && /* @__PURE__ */ jsx14(Box14, { paddingLeft: 2, children: /* @__PURE__ */ jsxs13(Text13, { color: "gray", children: [
|
|
7585
|
-
"hint: ",
|
|
7586
|
-
hint
|
|
7587
|
-
] }) })
|
|
7588
|
-
] });
|
|
7589
|
-
};
|
|
8269
|
+
import { Box as Box16, Text as Text15 } from "ink";
|
|
8270
|
+
import { jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
8271
|
+
var ErrorMessage = ({ message: message2, details, hint }) => /* @__PURE__ */ jsx16(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsxs15(Box16, { flexDirection: "column", paddingLeft: 2, children: [
|
|
8272
|
+
/* @__PURE__ */ jsx16(Text15, { color: BLUMA_TERMINAL.err, children: message2 }),
|
|
8273
|
+
details ? /* @__PURE__ */ jsx16(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx16(Text15, { dimColor: true, children: details }) }) : null,
|
|
8274
|
+
hint ? /* @__PURE__ */ jsx16(Box16, { marginTop: 1, children: /* @__PURE__ */ jsxs15(Text15, { dimColor: true, children: [
|
|
8275
|
+
"hint: ",
|
|
8276
|
+
hint
|
|
8277
|
+
] }) }) : null
|
|
8278
|
+
] }) });
|
|
7590
8279
|
var ErrorMessage_default = ErrorMessage;
|
|
7591
8280
|
|
|
7592
8281
|
// src/app/ui/components/ReasoningDisplay.tsx
|
|
7593
|
-
import { memo as memo9
|
|
7594
|
-
import { Box as
|
|
7595
|
-
import { jsx as
|
|
8282
|
+
import { memo as memo9 } from "react";
|
|
8283
|
+
import { Box as Box17, Text as Text16 } from "ink";
|
|
8284
|
+
import { jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
7596
8285
|
var ReasoningDisplayComponent = ({
|
|
7597
8286
|
reasoning,
|
|
7598
8287
|
collapsed = false
|
|
7599
8288
|
}) => {
|
|
7600
|
-
const [isExpanded, setIsExpanded] = useState5(!collapsed);
|
|
7601
8289
|
if (!reasoning || reasoning.trim() === "") {
|
|
7602
8290
|
return null;
|
|
7603
8291
|
}
|
|
7604
|
-
const maxLines =
|
|
8292
|
+
const maxLines = collapsed ? 6 : 200;
|
|
7605
8293
|
const lines = reasoning.split("\n");
|
|
7606
|
-
const
|
|
7607
|
-
|
|
7608
|
-
|
|
7609
|
-
|
|
7610
|
-
|
|
8294
|
+
const displayLines = lines.slice(0, maxLines);
|
|
8295
|
+
const truncated = lines.length > maxLines;
|
|
8296
|
+
return /* @__PURE__ */ jsx17(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsxs16(Box17, { flexDirection: "column", paddingLeft: 2, children: [
|
|
8297
|
+
displayLines.map((line, i) => /* @__PURE__ */ jsx17(Text16, { dimColor: true, children: line }, i)),
|
|
8298
|
+
truncated ? /* @__PURE__ */ jsxs16(Text16, { dimColor: true, children: [
|
|
8299
|
+
"\u2026 +",
|
|
8300
|
+
lines.length - maxLines,
|
|
8301
|
+
" lines"
|
|
8302
|
+
] }) : null
|
|
8303
|
+
] }) });
|
|
7611
8304
|
};
|
|
7612
8305
|
var ReasoningDisplay = memo9(ReasoningDisplayComponent);
|
|
7613
8306
|
|
|
7614
8307
|
// src/app/ui/components/StreamingText.tsx
|
|
7615
|
-
import { useState as
|
|
7616
|
-
import { Box as
|
|
7617
|
-
import { jsx as
|
|
7618
|
-
var StreamingTextComponent = ({
|
|
7619
|
-
|
|
7620
|
-
|
|
8308
|
+
import { useState as useState5, useEffect as useEffect6, useRef as useRef4, memo as memo10 } from "react";
|
|
8309
|
+
import { Box as Box18, Text as Text17 } from "ink";
|
|
8310
|
+
import { jsx as jsx18, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
8311
|
+
var StreamingTextComponent = ({
|
|
8312
|
+
eventBus,
|
|
8313
|
+
onReasoningComplete
|
|
8314
|
+
}) => {
|
|
8315
|
+
const [reasoning, setReasoning] = useState5("");
|
|
8316
|
+
const [isStreaming, setIsStreaming] = useState5(false);
|
|
7621
8317
|
const reasoningRef = useRef4("");
|
|
7622
8318
|
const lastUpdateRef = useRef4(0);
|
|
7623
8319
|
const pendingUpdateRef = useRef4(null);
|
|
7624
|
-
|
|
8320
|
+
useEffect6(() => {
|
|
7625
8321
|
const handleStart = () => {
|
|
7626
8322
|
setReasoning("");
|
|
7627
8323
|
reasoningRef.current = "";
|
|
@@ -7677,19 +8373,56 @@ var StreamingTextComponent = ({ eventBus, onReasoningComplete }) => {
|
|
|
7677
8373
|
truncatedCount = lines.length - MAX_VISIBLE_LINES;
|
|
7678
8374
|
displayLines = lines.slice(-MAX_VISIBLE_LINES);
|
|
7679
8375
|
}
|
|
7680
|
-
return /* @__PURE__ */
|
|
7681
|
-
truncatedCount > 0
|
|
7682
|
-
"
|
|
8376
|
+
return /* @__PURE__ */ jsx18(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsxs17(Box18, { flexDirection: "column", paddingLeft: 2, children: [
|
|
8377
|
+
truncatedCount > 0 ? /* @__PURE__ */ jsxs17(Text17, { dimColor: true, children: [
|
|
8378
|
+
"\u2026 ",
|
|
7683
8379
|
truncatedCount,
|
|
7684
|
-
"
|
|
7685
|
-
] }),
|
|
7686
|
-
|
|
7687
|
-
] });
|
|
8380
|
+
" lines above hidden"
|
|
8381
|
+
] }) : null,
|
|
8382
|
+
displayLines.map((line, i) => /* @__PURE__ */ jsx18(Text17, { dimColor: true, children: line }, i))
|
|
8383
|
+
] }) });
|
|
7688
8384
|
};
|
|
7689
8385
|
var StreamingText = memo10(StreamingTextComponent);
|
|
7690
8386
|
|
|
8387
|
+
// src/app/ui/components/ExpandedPreviewBlock.tsx
|
|
8388
|
+
import { memo as memo11 } from "react";
|
|
8389
|
+
import { Box as Box19, Text as Text18 } from "ink";
|
|
8390
|
+
import { jsx as jsx19, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
8391
|
+
function ExpandedPreviewBlockComponent({ data }) {
|
|
8392
|
+
const cols = typeof process.stdout?.columns === "number" ? process.stdout.columns : 80;
|
|
8393
|
+
const rule = TERMINAL_RULE_CHAR.repeat(Math.max(8, cols));
|
|
8394
|
+
const lines = data.fullText.split("\n");
|
|
8395
|
+
const cap = EXPAND_OVERLAY_MAX_LINES;
|
|
8396
|
+
const shown = lines.slice(0, cap);
|
|
8397
|
+
const rest = lines.length - cap;
|
|
8398
|
+
return /* @__PURE__ */ jsxs18(ChatBlock, { marginBottom: 1, children: [
|
|
8399
|
+
/* @__PURE__ */ jsx19(Text18, { color: "white", children: rule }),
|
|
8400
|
+
/* @__PURE__ */ jsxs18(Box19, { flexDirection: "column", paddingLeft: 1, children: [
|
|
8401
|
+
/* @__PURE__ */ jsx19(Text18, { color: BLUMA_TERMINAL.brandMagenta, bold: true, children: "expand (Ctrl+O)" }),
|
|
8402
|
+
/* @__PURE__ */ jsx19(Text18, { dimColor: true, children: data.title }),
|
|
8403
|
+
/* @__PURE__ */ jsxs18(Text18, { dimColor: true, children: [
|
|
8404
|
+
"+",
|
|
8405
|
+
data.linesHidden,
|
|
8406
|
+
" lines were clipped in chat \xB7 below: up to ",
|
|
8407
|
+
cap,
|
|
8408
|
+
" lines \xB7 use read_file_lines before edit_tool"
|
|
8409
|
+
] }),
|
|
8410
|
+
/* @__PURE__ */ jsxs18(Box19, { flexDirection: "column", marginTop: 1, children: [
|
|
8411
|
+
shown.map((line, i) => /* @__PURE__ */ jsx19(Text18, { dimColor: true, children: line.slice(0, 200) }, i)),
|
|
8412
|
+
rest > 0 ? /* @__PURE__ */ jsxs18(Text18, { dimColor: true, children: [
|
|
8413
|
+
"\u2026 +",
|
|
8414
|
+
rest,
|
|
8415
|
+
" more lines in this chunk"
|
|
8416
|
+
] }) : null
|
|
8417
|
+
] })
|
|
8418
|
+
] }),
|
|
8419
|
+
/* @__PURE__ */ jsx19(Text18, { color: "white", children: rule })
|
|
8420
|
+
] });
|
|
8421
|
+
}
|
|
8422
|
+
var ExpandedPreviewBlock = memo11(ExpandedPreviewBlockComponent);
|
|
8423
|
+
|
|
7691
8424
|
// src/app/ui/App.tsx
|
|
7692
|
-
import { jsx as
|
|
8425
|
+
import { jsx as jsx20, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
7693
8426
|
var SAFE_AUTO_APPROVE_TOOLS = [
|
|
7694
8427
|
// Comunicação/UI
|
|
7695
8428
|
"message",
|
|
@@ -7707,36 +8440,64 @@ var SAFE_AUTO_APPROVE_TOOLS = [
|
|
|
7707
8440
|
];
|
|
7708
8441
|
var AppComponent = ({ eventBus, sessionId }) => {
|
|
7709
8442
|
const agentInstance = useRef5(null);
|
|
7710
|
-
const [history, setHistory] =
|
|
7711
|
-
const [statusMessage, setStatusMessage] =
|
|
8443
|
+
const [history, setHistory] = useState6([]);
|
|
8444
|
+
const [statusMessage, setStatusMessage] = useState6(
|
|
7712
8445
|
"Initializing agent..."
|
|
7713
8446
|
);
|
|
7714
|
-
const [toolsCount, setToolsCount] =
|
|
7715
|
-
const [mcpStatus, setMcpStatus] =
|
|
8447
|
+
const [toolsCount, setToolsCount] = useState6(null);
|
|
8448
|
+
const [mcpStatus, setMcpStatus] = useState6(
|
|
7716
8449
|
"connecting"
|
|
7717
8450
|
);
|
|
7718
|
-
const [isProcessing, setIsProcessing] =
|
|
7719
|
-
const [pendingConfirmation, setPendingConfirmation] =
|
|
8451
|
+
const [isProcessing, setIsProcessing] = useState6(true);
|
|
8452
|
+
const [pendingConfirmation, setPendingConfirmation] = useState6(
|
|
7720
8453
|
null
|
|
7721
8454
|
);
|
|
7722
|
-
const [confirmationPreview, setConfirmationPreview] =
|
|
8455
|
+
const [confirmationPreview, setConfirmationPreview] = useState6(
|
|
7723
8456
|
null
|
|
7724
8457
|
);
|
|
7725
|
-
const [isInitAgentActive, setIsInitAgentActive] =
|
|
8458
|
+
const [isInitAgentActive, setIsInitAgentActive] = useState6(false);
|
|
7726
8459
|
const alwaysAcceptList = useRef5([]);
|
|
7727
8460
|
const workdir = process.cwd();
|
|
7728
8461
|
const updateCheckRan = useRef5(false);
|
|
7729
|
-
const
|
|
7730
|
-
const
|
|
8462
|
+
const turnStartedAtRef = useRef5(null);
|
|
8463
|
+
const appendExpandPreviewToHistory = useCallback2(() => {
|
|
8464
|
+
const p = peekLatestExpandable();
|
|
8465
|
+
setHistory((prev) => {
|
|
8466
|
+
const id = prev.length;
|
|
8467
|
+
if (!p) {
|
|
8468
|
+
return [
|
|
8469
|
+
...prev,
|
|
8470
|
+
{
|
|
8471
|
+
id,
|
|
8472
|
+
component: /* @__PURE__ */ jsx20(ChatMeta, { children: "Ctrl+O: no truncated preview to expand" }, id)
|
|
8473
|
+
}
|
|
8474
|
+
];
|
|
8475
|
+
}
|
|
8476
|
+
return [
|
|
8477
|
+
...prev,
|
|
8478
|
+
{
|
|
8479
|
+
id,
|
|
8480
|
+
component: /* @__PURE__ */ jsx20(ExpandedPreviewBlock, { data: p }, id)
|
|
8481
|
+
}
|
|
8482
|
+
];
|
|
8483
|
+
});
|
|
8484
|
+
}, []);
|
|
8485
|
+
useEffect7(() => {
|
|
8486
|
+
expandPreviewHotkeyBus.on("expand", appendExpandPreviewToHistory);
|
|
8487
|
+
return () => {
|
|
8488
|
+
expandPreviewHotkeyBus.off("expand", appendExpandPreviewToHistory);
|
|
8489
|
+
};
|
|
8490
|
+
}, [appendExpandPreviewToHistory]);
|
|
7731
8491
|
const handleInterrupt = useCallback2(() => {
|
|
7732
8492
|
if (!isProcessing) return;
|
|
7733
8493
|
eventBus.emit("user_interrupt");
|
|
8494
|
+
turnStartedAtRef.current = null;
|
|
7734
8495
|
setIsProcessing(false);
|
|
7735
8496
|
setHistory((prev) => [
|
|
7736
8497
|
...prev,
|
|
7737
8498
|
{
|
|
7738
8499
|
id: prev.length,
|
|
7739
|
-
component: /* @__PURE__ */
|
|
8500
|
+
component: /* @__PURE__ */ jsx20(ChatMeta, { children: "cancelled (Esc)" })
|
|
7740
8501
|
}
|
|
7741
8502
|
]);
|
|
7742
8503
|
}, [isProcessing, eventBus]);
|
|
@@ -7752,6 +8513,7 @@ var AppComponent = ({ eventBus, sessionId }) => {
|
|
|
7752
8513
|
if (cmd === "init") {
|
|
7753
8514
|
setIsInitAgentActive(true);
|
|
7754
8515
|
setIsProcessing(true);
|
|
8516
|
+
turnStartedAtRef.current = Date.now();
|
|
7755
8517
|
} else {
|
|
7756
8518
|
setIsProcessing(false);
|
|
7757
8519
|
setIsInitAgentActive(false);
|
|
@@ -7760,11 +8522,11 @@ var AppComponent = ({ eventBus, sessionId }) => {
|
|
|
7760
8522
|
...prev,
|
|
7761
8523
|
{
|
|
7762
8524
|
id: prev.length,
|
|
7763
|
-
component: /* @__PURE__ */
|
|
8525
|
+
component: /* @__PURE__ */ jsx20(ChatUserMessage, { children: /* @__PURE__ */ jsx20(Text19, { dimColor: true, children: text }) })
|
|
7764
8526
|
},
|
|
7765
8527
|
{
|
|
7766
8528
|
id: prev.length + 1,
|
|
7767
|
-
component: /* @__PURE__ */
|
|
8529
|
+
component: /* @__PURE__ */ jsx20(
|
|
7768
8530
|
SlashCommands_default,
|
|
7769
8531
|
{
|
|
7770
8532
|
input: text,
|
|
@@ -7783,17 +8545,15 @@ var AppComponent = ({ eventBus, sessionId }) => {
|
|
|
7783
8545
|
return;
|
|
7784
8546
|
}
|
|
7785
8547
|
setIsProcessing(true);
|
|
8548
|
+
turnStartedAtRef.current = Date.now();
|
|
7786
8549
|
setHistory((prev) => [
|
|
7787
8550
|
...prev,
|
|
7788
8551
|
{
|
|
7789
8552
|
id: prev.length,
|
|
7790
|
-
component: /* @__PURE__ */
|
|
7791
|
-
|
|
7792
|
-
|
|
7793
|
-
|
|
7794
|
-
command
|
|
7795
|
-
] })
|
|
7796
|
-
] })
|
|
8553
|
+
component: /* @__PURE__ */ jsx20(ChatUserMessage, { children: /* @__PURE__ */ jsxs19(Text19, { bold: true, color: "white", children: [
|
|
8554
|
+
"$ !",
|
|
8555
|
+
command
|
|
8556
|
+
] }) })
|
|
7797
8557
|
}
|
|
7798
8558
|
]);
|
|
7799
8559
|
Promise.resolve().then(() => (init_async_command(), async_command_exports)).then(async ({ runCommandAsync: runCommandAsync2 }) => {
|
|
@@ -7807,11 +8567,12 @@ Command ID: ${result.command_id}
|
|
|
7807
8567
|
Please use command_status to check the result and report back to the user.`;
|
|
7808
8568
|
agentInstance.current?.processTurn({ content: contextMessage });
|
|
7809
8569
|
} else {
|
|
8570
|
+
turnStartedAtRef.current = null;
|
|
7810
8571
|
setHistory((prev) => [
|
|
7811
8572
|
...prev,
|
|
7812
8573
|
{
|
|
7813
8574
|
id: prev.length,
|
|
7814
|
-
component: /* @__PURE__ */
|
|
8575
|
+
component: /* @__PURE__ */ jsxs19(Text19, { color: "red", children: [
|
|
7815
8576
|
"Failed to execute: ",
|
|
7816
8577
|
result.error || result.message
|
|
7817
8578
|
] })
|
|
@@ -7820,11 +8581,12 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
7820
8581
|
setIsProcessing(false);
|
|
7821
8582
|
}
|
|
7822
8583
|
} catch (err) {
|
|
8584
|
+
turnStartedAtRef.current = null;
|
|
7823
8585
|
setHistory((prev) => [
|
|
7824
8586
|
...prev,
|
|
7825
8587
|
{
|
|
7826
8588
|
id: prev.length,
|
|
7827
|
-
component: /* @__PURE__ */
|
|
8589
|
+
component: /* @__PURE__ */ jsxs19(Text19, { color: "red", children: [
|
|
7828
8590
|
"Error: ",
|
|
7829
8591
|
err.message
|
|
7830
8592
|
] })
|
|
@@ -7836,21 +8598,13 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
7836
8598
|
return;
|
|
7837
8599
|
}
|
|
7838
8600
|
setIsProcessing(true);
|
|
8601
|
+
turnStartedAtRef.current = Date.now();
|
|
7839
8602
|
const displayText = text.length > 1e4 ? text.substring(0, 1e4) + "..." : text;
|
|
7840
8603
|
setHistory((prev) => [
|
|
7841
8604
|
...prev,
|
|
7842
8605
|
{
|
|
7843
8606
|
id: prev.length,
|
|
7844
|
-
component: (
|
|
7845
|
-
// Uma única Box para o espaçamento
|
|
7846
|
-
/* @__PURE__ */ jsx17(Box17, { marginBottom: 1, children: /* @__PURE__ */ jsxs16(Text16, { color: "white", dimColor: true, children: [
|
|
7847
|
-
/* @__PURE__ */ jsxs16(Text16, { color: "white", children: [
|
|
7848
|
-
">",
|
|
7849
|
-
" "
|
|
7850
|
-
] }),
|
|
7851
|
-
displayText
|
|
7852
|
-
] }) })
|
|
7853
|
-
)
|
|
8607
|
+
component: /* @__PURE__ */ jsx20(ChatUserMessage, { children: /* @__PURE__ */ jsx20(Text19, { children: displayText }) })
|
|
7854
8608
|
}
|
|
7855
8609
|
]);
|
|
7856
8610
|
agentInstance.current.processTurn({ content: text });
|
|
@@ -7878,8 +8632,8 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
7878
8632
|
},
|
|
7879
8633
|
[]
|
|
7880
8634
|
);
|
|
7881
|
-
|
|
7882
|
-
setHistory([{ id: 0, component: /* @__PURE__ */
|
|
8635
|
+
useEffect7(() => {
|
|
8636
|
+
setHistory([{ id: 0, component: /* @__PURE__ */ jsx20(Header, { sessionId, workdir }) }]);
|
|
7883
8637
|
const initializeAgent = async () => {
|
|
7884
8638
|
try {
|
|
7885
8639
|
agentInstance.current = new Agent(sessionId, eventBus);
|
|
@@ -7899,6 +8653,20 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
7899
8653
|
};
|
|
7900
8654
|
const handleBackendMessage = (parsed) => {
|
|
7901
8655
|
try {
|
|
8656
|
+
const appendTurnDurationIfAny = () => {
|
|
8657
|
+
const t = turnStartedAtRef.current;
|
|
8658
|
+
if (t == null) return;
|
|
8659
|
+
turnStartedAtRef.current = null;
|
|
8660
|
+
const ms = Date.now() - t;
|
|
8661
|
+
const sec = ms < 1e4 ? (ms / 1e3).toFixed(1) : String(Math.round(ms / 1e3));
|
|
8662
|
+
setHistory((prev) => [
|
|
8663
|
+
...prev,
|
|
8664
|
+
{
|
|
8665
|
+
id: prev.length,
|
|
8666
|
+
component: /* @__PURE__ */ jsx20(ChatTurnDuration, { secondsFormatted: sec })
|
|
8667
|
+
}
|
|
8668
|
+
]);
|
|
8669
|
+
};
|
|
7902
8670
|
if (parsed.type === "done" || parsed.type === "error") {
|
|
7903
8671
|
setIsInitAgentActive(false);
|
|
7904
8672
|
}
|
|
@@ -7924,6 +8692,7 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
7924
8692
|
if (parsed.type === "done") {
|
|
7925
8693
|
if (parsed.status !== "awaiting_confirmation") {
|
|
7926
8694
|
setStatusMessage(null);
|
|
8695
|
+
appendTurnDurationIfAny();
|
|
7927
8696
|
}
|
|
7928
8697
|
setIsProcessing(false);
|
|
7929
8698
|
return;
|
|
@@ -7945,7 +8714,7 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
7945
8714
|
...prev,
|
|
7946
8715
|
{
|
|
7947
8716
|
id: prev.length,
|
|
7948
|
-
component: /* @__PURE__ */
|
|
8717
|
+
component: /* @__PURE__ */ jsx20(UpdateNotice_default, { message: msg })
|
|
7949
8718
|
}
|
|
7950
8719
|
]);
|
|
7951
8720
|
}
|
|
@@ -7959,25 +8728,14 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
7959
8728
|
}
|
|
7960
8729
|
let newComponent = null;
|
|
7961
8730
|
if (parsed.type === "debug") {
|
|
7962
|
-
newComponent = /* @__PURE__ */
|
|
8731
|
+
newComponent = /* @__PURE__ */ jsx20(ChatMeta, { children: parsed.message });
|
|
7963
8732
|
} else if (parsed.type === "protocol_violation") {
|
|
7964
|
-
newComponent = /* @__PURE__ */
|
|
7965
|
-
|
|
7966
|
-
{
|
|
7967
|
-
|
|
7968
|
-
borderColor: "yellow",
|
|
7969
|
-
flexDirection: "column",
|
|
7970
|
-
marginBottom: 1,
|
|
7971
|
-
paddingX: 1,
|
|
7972
|
-
children: [
|
|
7973
|
-
/* @__PURE__ */ jsx17(Text16, { color: "yellow", bold: true, children: "Protocol Violation" }),
|
|
7974
|
-
/* @__PURE__ */ jsx17(Text16, { color: "gray", children: parsed.content }),
|
|
7975
|
-
/* @__PURE__ */ jsx17(Text16, { color: "yellow", children: parsed.message })
|
|
7976
|
-
]
|
|
7977
|
-
}
|
|
7978
|
-
);
|
|
8733
|
+
newComponent = /* @__PURE__ */ jsx20(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsxs19(Box20, { flexDirection: "column", paddingLeft: 2, children: [
|
|
8734
|
+
/* @__PURE__ */ jsx20(Text19, { dimColor: true, children: parsed.content }),
|
|
8735
|
+
/* @__PURE__ */ jsx20(Text19, { dimColor: true, children: parsed.message })
|
|
8736
|
+
] }) });
|
|
7979
8737
|
} else if (parsed.type === "error") {
|
|
7980
|
-
newComponent = /* @__PURE__ */
|
|
8738
|
+
newComponent = /* @__PURE__ */ jsx20(
|
|
7981
8739
|
ErrorMessage_default,
|
|
7982
8740
|
{
|
|
7983
8741
|
message: parsed.message,
|
|
@@ -7987,7 +8745,7 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
7987
8745
|
);
|
|
7988
8746
|
} else if (parsed.type === "tool_call") {
|
|
7989
8747
|
const nextId3 = history.length;
|
|
7990
|
-
newComponent = /* @__PURE__ */
|
|
8748
|
+
newComponent = /* @__PURE__ */ jsx20(
|
|
7991
8749
|
ToolCallDisplay,
|
|
7992
8750
|
{
|
|
7993
8751
|
toolName: parsed.tool_name,
|
|
@@ -7996,7 +8754,7 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
7996
8754
|
}
|
|
7997
8755
|
);
|
|
7998
8756
|
} else if (parsed.type === "tool_result") {
|
|
7999
|
-
newComponent = /* @__PURE__ */
|
|
8757
|
+
newComponent = /* @__PURE__ */ jsx20(
|
|
8000
8758
|
ToolResultDisplay,
|
|
8001
8759
|
{
|
|
8002
8760
|
toolName: parsed.tool_name,
|
|
@@ -8004,18 +8762,11 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
8004
8762
|
}
|
|
8005
8763
|
);
|
|
8006
8764
|
} else if (parsed.type === "user_overlay") {
|
|
8007
|
-
newComponent = /* @__PURE__ */
|
|
8008
|
-
/* @__PURE__ */ jsxs16(Text16, { color: "magenta", children: [
|
|
8009
|
-
">",
|
|
8010
|
-
" "
|
|
8011
|
-
] }),
|
|
8012
|
-
parsed.payload
|
|
8013
|
-
] }) });
|
|
8765
|
+
newComponent = /* @__PURE__ */ jsx20(ChatUserMessage, { children: /* @__PURE__ */ jsx20(Text19, { dimColor: true, children: parsed.payload }) });
|
|
8014
8766
|
} else if (parsed.type === "reasoning") {
|
|
8015
|
-
newComponent = /* @__PURE__ */
|
|
8767
|
+
newComponent = /* @__PURE__ */ jsx20(ReasoningDisplay, { reasoning: parsed.content });
|
|
8016
8768
|
} else if (parsed.type === "log") {
|
|
8017
|
-
newComponent = /* @__PURE__ */
|
|
8018
|
-
"\u2139\uFE0F ",
|
|
8769
|
+
newComponent = /* @__PURE__ */ jsxs19(ChatMeta, { children: [
|
|
8019
8770
|
parsed.message,
|
|
8020
8771
|
parsed.payload ? `: ${parsed.payload}` : ""
|
|
8021
8772
|
] });
|
|
@@ -8023,10 +8774,25 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
8023
8774
|
newComponent = null;
|
|
8024
8775
|
}
|
|
8025
8776
|
if (newComponent) {
|
|
8026
|
-
setHistory((prev) =>
|
|
8027
|
-
|
|
8028
|
-
|
|
8029
|
-
|
|
8777
|
+
setHistory((prev) => {
|
|
8778
|
+
const next = [
|
|
8779
|
+
...prev,
|
|
8780
|
+
{ id: prev.length, component: newComponent }
|
|
8781
|
+
];
|
|
8782
|
+
if (parsed.type === "error") {
|
|
8783
|
+
const t = turnStartedAtRef.current;
|
|
8784
|
+
if (t != null) {
|
|
8785
|
+
turnStartedAtRef.current = null;
|
|
8786
|
+
const ms = Date.now() - t;
|
|
8787
|
+
const sec = ms < 1e4 ? (ms / 1e3).toFixed(1) : String(Math.round(ms / 1e3));
|
|
8788
|
+
next.push({
|
|
8789
|
+
id: next.length,
|
|
8790
|
+
component: /* @__PURE__ */ jsx20(ChatTurnDuration, { secondsFormatted: sec })
|
|
8791
|
+
});
|
|
8792
|
+
}
|
|
8793
|
+
}
|
|
8794
|
+
return next;
|
|
8795
|
+
});
|
|
8030
8796
|
}
|
|
8031
8797
|
} catch (error) {
|
|
8032
8798
|
}
|
|
@@ -8044,10 +8810,17 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
8044
8810
|
}, [eventBus, sessionId, handleConfirmation]);
|
|
8045
8811
|
const renderInteractiveComponent = () => {
|
|
8046
8812
|
if (mcpStatus !== "connected") {
|
|
8047
|
-
return
|
|
8813
|
+
return /* @__PURE__ */ jsx20(
|
|
8814
|
+
SessionInfoConnectingMCP_default,
|
|
8815
|
+
{
|
|
8816
|
+
sessionId,
|
|
8817
|
+
workdir,
|
|
8818
|
+
statusMessage
|
|
8819
|
+
}
|
|
8820
|
+
);
|
|
8048
8821
|
}
|
|
8049
8822
|
if (pendingConfirmation) {
|
|
8050
|
-
return /* @__PURE__ */
|
|
8823
|
+
return /* @__PURE__ */ jsx20(
|
|
8051
8824
|
ConfirmationPrompt,
|
|
8052
8825
|
{
|
|
8053
8826
|
toolCalls: pendingConfirmation,
|
|
@@ -8059,9 +8832,9 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
8059
8832
|
}
|
|
8060
8833
|
);
|
|
8061
8834
|
}
|
|
8062
|
-
return /* @__PURE__ */
|
|
8063
|
-
isProcessing && !pendingConfirmation && /* @__PURE__ */
|
|
8064
|
-
/* @__PURE__ */
|
|
8835
|
+
return /* @__PURE__ */ jsxs19(Box20, { flexDirection: "column", children: [
|
|
8836
|
+
isProcessing && !pendingConfirmation && /* @__PURE__ */ jsx20(WorkingTimer, { eventBus }),
|
|
8837
|
+
/* @__PURE__ */ jsx20(
|
|
8065
8838
|
InputPrompt,
|
|
8066
8839
|
{
|
|
8067
8840
|
onSubmit: handleSubmit,
|
|
@@ -8072,9 +8845,9 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
8072
8845
|
)
|
|
8073
8846
|
] });
|
|
8074
8847
|
};
|
|
8075
|
-
return /* @__PURE__ */
|
|
8076
|
-
/* @__PURE__ */
|
|
8077
|
-
/* @__PURE__ */
|
|
8848
|
+
return /* @__PURE__ */ jsxs19(Box20, { flexDirection: "column", children: [
|
|
8849
|
+
/* @__PURE__ */ jsx20(Static, { items: history, children: (item) => /* @__PURE__ */ jsx20(Box20, { children: item.component }, item.id) }),
|
|
8850
|
+
/* @__PURE__ */ jsx20(
|
|
8078
8851
|
StreamingText,
|
|
8079
8852
|
{
|
|
8080
8853
|
eventBus,
|
|
@@ -8084,7 +8857,7 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
8084
8857
|
...prev,
|
|
8085
8858
|
{
|
|
8086
8859
|
id: prev.length,
|
|
8087
|
-
component: /* @__PURE__ */
|
|
8860
|
+
component: /* @__PURE__ */ jsx20(ReasoningDisplay, { reasoning })
|
|
8088
8861
|
}
|
|
8089
8862
|
]);
|
|
8090
8863
|
}
|
|
@@ -8094,7 +8867,7 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
8094
8867
|
renderInteractiveComponent()
|
|
8095
8868
|
] });
|
|
8096
8869
|
};
|
|
8097
|
-
var App =
|
|
8870
|
+
var App = memo12(AppComponent);
|
|
8098
8871
|
var App_default = App;
|
|
8099
8872
|
|
|
8100
8873
|
// src/app/ui/utils/terminalTitle.ts
|
|
@@ -8218,7 +8991,7 @@ async function runAgentMode() {
|
|
|
8218
8991
|
process.env.BLUMA_SANDBOX_NAME = String(envelope.metadata.sandbox_name);
|
|
8219
8992
|
}
|
|
8220
8993
|
}
|
|
8221
|
-
const eventBus = new
|
|
8994
|
+
const eventBus = new EventEmitter3();
|
|
8222
8995
|
const sessionId = envelope.session_id || envelope.message_id || uuidv46();
|
|
8223
8996
|
const uc = envelope.user_context;
|
|
8224
8997
|
const userContextInput = {
|
|
@@ -8350,13 +9123,13 @@ async function runAgentMode() {
|
|
|
8350
9123
|
function runCliMode() {
|
|
8351
9124
|
const BLUMA_TITLE = process.env.BLUMA_TITLE || "BluMa - NomadEngenuity";
|
|
8352
9125
|
startTitleKeeper(BLUMA_TITLE);
|
|
8353
|
-
const eventBus = new
|
|
9126
|
+
const eventBus = new EventEmitter3();
|
|
8354
9127
|
const sessionId = uuidv46();
|
|
8355
9128
|
const props = {
|
|
8356
9129
|
eventBus,
|
|
8357
9130
|
sessionId
|
|
8358
9131
|
};
|
|
8359
|
-
render(
|
|
9132
|
+
render(React12.createElement(App_default, props));
|
|
8360
9133
|
}
|
|
8361
9134
|
var argv = process.argv.slice(2);
|
|
8362
9135
|
if (argv[0] === "agent") {
|