@nomad-e/bluma-cli 0.1.28 → 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 +1429 -647
- 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.
|
|
4757
|
+
|
|
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.
|
|
4557
4762
|
|
|
4558
|
-
###
|
|
4559
|
-
-
|
|
4560
|
-
-
|
|
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**.
|
|
4561
4766
|
|
|
4562
|
-
###
|
|
4563
|
-
-
|
|
4564
|
-
-
|
|
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,10 +5958,14 @@ 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;
|
|
5967
|
+
/** Evita POST /turns/.../end duplicado no mesmo turno (ex.: Esc após message_result). */
|
|
5968
|
+
factorRouterTurnClosed = false;
|
|
5545
5969
|
constructor(sessionId, eventBus, llm, mcpClient, feedbackSystem) {
|
|
5546
5970
|
this.sessionId = sessionId;
|
|
5547
5971
|
this.eventBus = eventBus;
|
|
@@ -5551,6 +5975,7 @@ var BluMaAgent = class {
|
|
|
5551
5975
|
this.skillLoader = new SkillLoader(process.cwd());
|
|
5552
5976
|
this.eventBus.on("user_interrupt", () => {
|
|
5553
5977
|
this.isInterrupted = true;
|
|
5978
|
+
void this.notifyFactorTurnEndIfNeeded("user_interrupt");
|
|
5554
5979
|
this.eventBus.emit("backend_message", { type: "done", status: "interrupted" });
|
|
5555
5980
|
});
|
|
5556
5981
|
this.eventBus.on("user_overlay", async (data) => {
|
|
@@ -5559,23 +5984,38 @@ var BluMaAgent = class {
|
|
|
5559
5984
|
this.eventBus.emit("backend_message", { type: "user_overlay", payload: clean, ts: data.ts || Date.now() });
|
|
5560
5985
|
try {
|
|
5561
5986
|
if (this.sessionFile) {
|
|
5562
|
-
|
|
5987
|
+
this.persistSession();
|
|
5563
5988
|
} else {
|
|
5564
|
-
const [sessionFile,
|
|
5989
|
+
const [sessionFile, , mem] = await loadOrcreateSession(this.sessionId);
|
|
5565
5990
|
this.sessionFile = sessionFile;
|
|
5566
|
-
|
|
5991
|
+
this.sessionAnchor = mem.historyAnchor;
|
|
5992
|
+
this.compressedTurnSliceCount = mem.compressedTurnSliceCount;
|
|
5993
|
+
this.persistSession();
|
|
5567
5994
|
}
|
|
5568
5995
|
} catch (e) {
|
|
5569
5996
|
this.eventBus.emit("backend_message", { type: "error", message: `Falha ao salvar hist\xF3rico ap\xF3s user_overlay: ${e.message}` });
|
|
5570
5997
|
}
|
|
5571
5998
|
});
|
|
5572
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
|
+
}
|
|
5573
6011
|
async initialize() {
|
|
5574
6012
|
await this.mcpClient.nativeToolInvoker.initialize();
|
|
5575
6013
|
await this.mcpClient.initialize();
|
|
5576
|
-
const [sessionFile, history] = await loadOrcreateSession(this.sessionId);
|
|
6014
|
+
const [sessionFile, history, mem] = await loadOrcreateSession(this.sessionId);
|
|
5577
6015
|
this.sessionFile = sessionFile;
|
|
5578
6016
|
this.history = history;
|
|
6017
|
+
this.sessionAnchor = mem.historyAnchor;
|
|
6018
|
+
this.compressedTurnSliceCount = mem.compressedTurnSliceCount;
|
|
5579
6019
|
initializeSkillContext({
|
|
5580
6020
|
history: this.history,
|
|
5581
6021
|
skillLoader: this.skillLoader
|
|
@@ -5601,7 +6041,7 @@ var BluMaAgent = class {
|
|
|
5601
6041
|
}
|
|
5602
6042
|
const systemPrompt = getUnifiedSystemPrompt(availableSkills);
|
|
5603
6043
|
this.history.push({ role: "system", content: systemPrompt });
|
|
5604
|
-
|
|
6044
|
+
this.persistSession();
|
|
5605
6045
|
}
|
|
5606
6046
|
}
|
|
5607
6047
|
getAvailableTools() {
|
|
@@ -5612,6 +6052,7 @@ var BluMaAgent = class {
|
|
|
5612
6052
|
}
|
|
5613
6053
|
async processTurn(userInput, userContextInput) {
|
|
5614
6054
|
this.isInterrupted = false;
|
|
6055
|
+
this.factorRouterTurnClosed = false;
|
|
5615
6056
|
const inputText = String(userInput.content || "").trim();
|
|
5616
6057
|
const turnId = uuidv43();
|
|
5617
6058
|
this.activeTurnContext = {
|
|
@@ -5630,11 +6071,13 @@ var BluMaAgent = class {
|
|
|
5630
6071
|
let toolResultContent;
|
|
5631
6072
|
let shouldContinueConversation = true;
|
|
5632
6073
|
if (!this.sessionFile) {
|
|
5633
|
-
const [sessionFile, history] = await loadOrcreateSession(this.sessionId);
|
|
6074
|
+
const [sessionFile, history, mem] = await loadOrcreateSession(this.sessionId);
|
|
5634
6075
|
this.sessionFile = sessionFile;
|
|
5635
6076
|
if (this.history.length === 0 && history.length > 0) {
|
|
5636
6077
|
this.history = history;
|
|
5637
6078
|
}
|
|
6079
|
+
this.sessionAnchor = mem.historyAnchor;
|
|
6080
|
+
this.compressedTurnSliceCount = mem.compressedTurnSliceCount;
|
|
5638
6081
|
}
|
|
5639
6082
|
if (decisionData.type === "user_decision_execute") {
|
|
5640
6083
|
const toolName = toolCall.function.name;
|
|
@@ -5656,7 +6099,7 @@ var BluMaAgent = class {
|
|
|
5656
6099
|
raw_arguments: toolCall.function.arguments
|
|
5657
6100
|
});
|
|
5658
6101
|
this.history.push({ role: "tool", tool_call_id: toolCall.id, content: toolResultContent });
|
|
5659
|
-
|
|
6102
|
+
this.persistSession();
|
|
5660
6103
|
await this._continueConversation();
|
|
5661
6104
|
return;
|
|
5662
6105
|
}
|
|
@@ -5668,7 +6111,7 @@ var BluMaAgent = class {
|
|
|
5668
6111
|
received: toolArgs
|
|
5669
6112
|
});
|
|
5670
6113
|
this.history.push({ role: "tool", tool_call_id: toolCall.id, content: toolResultContent });
|
|
5671
|
-
|
|
6114
|
+
this.persistSession();
|
|
5672
6115
|
await this._continueConversation();
|
|
5673
6116
|
return;
|
|
5674
6117
|
}
|
|
@@ -5679,7 +6122,7 @@ var BluMaAgent = class {
|
|
|
5679
6122
|
received: toolArgs
|
|
5680
6123
|
});
|
|
5681
6124
|
this.history.push({ role: "tool", tool_call_id: toolCall.id, content: toolResultContent });
|
|
5682
|
-
|
|
6125
|
+
this.persistSession();
|
|
5683
6126
|
await this._continueConversation();
|
|
5684
6127
|
return;
|
|
5685
6128
|
}
|
|
@@ -5738,13 +6181,7 @@ var BluMaAgent = class {
|
|
|
5738
6181
|
try {
|
|
5739
6182
|
const resultObj = typeof toolResultContent === "string" ? JSON.parse(toolResultContent) : toolResultContent;
|
|
5740
6183
|
if (resultObj.message_type === "result") {
|
|
5741
|
-
|
|
5742
|
-
await notifyFactorRouterTurnEnd({
|
|
5743
|
-
turnId: this.activeTurnContext.turnId,
|
|
5744
|
-
userContext: this.activeTurnContext,
|
|
5745
|
-
reason: "message_result"
|
|
5746
|
-
});
|
|
5747
|
-
}
|
|
6184
|
+
await this.notifyFactorTurnEndIfNeeded("message_result");
|
|
5748
6185
|
shouldContinueConversation = false;
|
|
5749
6186
|
this.eventBus.emit("backend_message", { type: "done", status: "completed" });
|
|
5750
6187
|
}
|
|
@@ -5755,7 +6192,7 @@ var BluMaAgent = class {
|
|
|
5755
6192
|
toolResultContent = "The system rejected this action. Verify that the command you are executing contributes to the tasks intent and try again.";
|
|
5756
6193
|
}
|
|
5757
6194
|
this.history.push({ role: "tool", tool_call_id: toolCall.id, content: toolResultContent });
|
|
5758
|
-
|
|
6195
|
+
this.persistSession();
|
|
5759
6196
|
if (shouldContinueConversation && !this.isInterrupted) {
|
|
5760
6197
|
await this._continueConversation();
|
|
5761
6198
|
}
|
|
@@ -5788,13 +6225,33 @@ ${editData.error.display}`;
|
|
|
5788
6225
|
}
|
|
5789
6226
|
return this.activeTurnContext;
|
|
5790
6227
|
}
|
|
6228
|
+
/** Um único aviso ao Factor Router por turno (fim normal ou interrupção). */
|
|
6229
|
+
async notifyFactorTurnEndIfNeeded(reason) {
|
|
6230
|
+
if (this.factorRouterTurnClosed || !this.activeTurnContext) return;
|
|
6231
|
+
this.factorRouterTurnClosed = true;
|
|
6232
|
+
const ctx = this.activeTurnContext;
|
|
6233
|
+
await notifyFactorRouterTurnEnd({
|
|
6234
|
+
turnId: ctx.turnId,
|
|
6235
|
+
userContext: ctx,
|
|
6236
|
+
reason
|
|
6237
|
+
});
|
|
6238
|
+
}
|
|
5791
6239
|
async _continueConversation() {
|
|
5792
6240
|
try {
|
|
5793
6241
|
if (this.isInterrupted) {
|
|
5794
6242
|
this.eventBus.emit("backend_message", { type: "info", message: "Task Canceled." });
|
|
5795
6243
|
return;
|
|
5796
6244
|
}
|
|
5797
|
-
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();
|
|
5798
6255
|
const llmService = this.llm;
|
|
5799
6256
|
if (typeof llmService.chatCompletionStream === "function") {
|
|
5800
6257
|
await this._handleStreamingResponse(contextWindow);
|
|
@@ -5805,7 +6262,7 @@ ${editData.error.display}`;
|
|
|
5805
6262
|
const errorMessage = error instanceof Error ? error.message : "An unknown API error occurred.";
|
|
5806
6263
|
this.eventBus.emit("backend_message", { type: "error", message: errorMessage });
|
|
5807
6264
|
} finally {
|
|
5808
|
-
|
|
6265
|
+
this.persistSession();
|
|
5809
6266
|
}
|
|
5810
6267
|
}
|
|
5811
6268
|
async _handleStreamingResponse(contextWindow) {
|
|
@@ -6614,18 +7071,15 @@ var Agent = class {
|
|
|
6614
7071
|
|
|
6615
7072
|
// src/app/ui/WorkingTimer.tsx
|
|
6616
7073
|
import { useState as useState4, useEffect as useEffect4, memo as memo5 } from "react";
|
|
6617
|
-
import { Box as
|
|
6618
|
-
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";
|
|
6619
7076
|
var WorkingTimerComponent = ({ eventBus, taskName, taskStatus }) => {
|
|
6620
|
-
const [currentAction, setCurrentAction] = useState4("
|
|
7077
|
+
const [currentAction, setCurrentAction] = useState4("working");
|
|
6621
7078
|
const [shinePosition, setShinePosition] = useState4(0);
|
|
6622
|
-
const [dots, setDots] = useState4("");
|
|
6623
7079
|
useEffect4(() => {
|
|
6624
7080
|
if (!eventBus) return;
|
|
6625
7081
|
const handleActionStatus = (data) => {
|
|
6626
|
-
if (data.action)
|
|
6627
|
-
setCurrentAction(data.action);
|
|
6628
|
-
}
|
|
7082
|
+
if (data.action) setCurrentAction(data.action);
|
|
6629
7083
|
};
|
|
6630
7084
|
eventBus.on("action_status", handleActionStatus);
|
|
6631
7085
|
return () => {
|
|
@@ -6638,12 +7092,6 @@ var WorkingTimerComponent = ({ eventBus, taskName, taskStatus }) => {
|
|
|
6638
7092
|
}, 120);
|
|
6639
7093
|
return () => clearInterval(shineTimer);
|
|
6640
7094
|
}, []);
|
|
6641
|
-
useEffect4(() => {
|
|
6642
|
-
const dotsTimer = setInterval(() => {
|
|
6643
|
-
setDots((prev) => prev.length >= 3 ? "" : prev + ".");
|
|
6644
|
-
}, 500);
|
|
6645
|
-
return () => clearInterval(dotsTimer);
|
|
6646
|
-
}, []);
|
|
6647
7095
|
const displayAction = taskStatus || currentAction;
|
|
6648
7096
|
const renderShineText = (text) => {
|
|
6649
7097
|
const chars = text.split("");
|
|
@@ -6652,29 +7100,28 @@ var WorkingTimerComponent = ({ eventBus, taskName, taskStatus }) => {
|
|
|
6652
7100
|
return chars.map((char, i) => {
|
|
6653
7101
|
const distance = Math.abs(i - shineIdx);
|
|
6654
7102
|
if (distance <= 1) {
|
|
6655
|
-
return /* @__PURE__ */
|
|
6656
|
-
} else {
|
|
6657
|
-
return /* @__PURE__ */ jsx7(Text7, { color: "gray", dimColor: true, children: char }, i);
|
|
7103
|
+
return /* @__PURE__ */ jsx8(Text8, { color: BLUMA_TERMINAL.brandMagenta, children: char }, i);
|
|
6658
7104
|
}
|
|
7105
|
+
return /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: char }, i);
|
|
6659
7106
|
});
|
|
6660
7107
|
};
|
|
6661
|
-
return /* @__PURE__ */
|
|
6662
|
-
/* @__PURE__ */
|
|
6663
|
-
taskName
|
|
6664
|
-
"\
|
|
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 " }),
|
|
6665
7112
|
taskName
|
|
6666
|
-
] }) })
|
|
7113
|
+
] }) }) : null
|
|
6667
7114
|
] });
|
|
6668
7115
|
};
|
|
6669
7116
|
var WorkingTimer = memo5(WorkingTimerComponent);
|
|
6670
7117
|
|
|
6671
7118
|
// src/app/ui/components/ToolCallDisplay.tsx
|
|
6672
7119
|
import { memo as memo6 } from "react";
|
|
6673
|
-
import { Box as
|
|
7120
|
+
import { Box as Box10 } from "ink";
|
|
6674
7121
|
|
|
6675
7122
|
// src/app/ui/components/toolCallRenderers.tsx
|
|
6676
|
-
import { Box as
|
|
6677
|
-
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";
|
|
6678
7125
|
var parseArgs = (args) => {
|
|
6679
7126
|
if (typeof args === "string") {
|
|
6680
7127
|
try {
|
|
@@ -6696,9 +7143,9 @@ var getBasename = (filepath) => {
|
|
|
6696
7143
|
var renderShellCommand2 = ({ args }) => {
|
|
6697
7144
|
const parsed = parseArgs(args);
|
|
6698
7145
|
const command = parsed.command || "[no command]";
|
|
6699
|
-
return /* @__PURE__ */
|
|
6700
|
-
/* @__PURE__ */
|
|
6701
|
-
/* @__PURE__ */
|
|
7146
|
+
return /* @__PURE__ */ jsxs9(Box9, { children: [
|
|
7147
|
+
/* @__PURE__ */ jsx9(Text9, { color: BLUMA_TERMINAL.brandBlue, bold: true, children: "$" }),
|
|
7148
|
+
/* @__PURE__ */ jsxs9(Text9, { children: [
|
|
6702
7149
|
" ",
|
|
6703
7150
|
truncate(command, 70)
|
|
6704
7151
|
] })
|
|
@@ -6707,9 +7154,9 @@ var renderShellCommand2 = ({ args }) => {
|
|
|
6707
7154
|
var renderLsTool2 = ({ args }) => {
|
|
6708
7155
|
const parsed = parseArgs(args);
|
|
6709
7156
|
const path19 = parsed.directory_path || ".";
|
|
6710
|
-
return /* @__PURE__ */
|
|
6711
|
-
/* @__PURE__ */
|
|
6712
|
-
/* @__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: [
|
|
6713
7160
|
" ",
|
|
6714
7161
|
path19
|
|
6715
7162
|
] })
|
|
@@ -6718,9 +7165,9 @@ var renderLsTool2 = ({ args }) => {
|
|
|
6718
7165
|
var renderCountFilesLines = ({ args }) => {
|
|
6719
7166
|
const parsed = parseArgs(args);
|
|
6720
7167
|
const filepath = parsed.filepath || "[no file]";
|
|
6721
|
-
return /* @__PURE__ */
|
|
6722
|
-
/* @__PURE__ */
|
|
6723
|
-
/* @__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: [
|
|
6724
7171
|
" ",
|
|
6725
7172
|
getBasename(filepath)
|
|
6726
7173
|
] })
|
|
@@ -6731,14 +7178,15 @@ var renderReadFileLines2 = ({ args }) => {
|
|
|
6731
7178
|
const filepath = parsed.filepath || "[no file]";
|
|
6732
7179
|
const start = parsed.start_line || 1;
|
|
6733
7180
|
const end = parsed.end_line || start;
|
|
6734
|
-
return /* @__PURE__ */
|
|
6735
|
-
/* @__PURE__ */
|
|
6736
|
-
/* @__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: [
|
|
6737
7184
|
" ",
|
|
6738
7185
|
getBasename(filepath)
|
|
6739
7186
|
] }),
|
|
6740
|
-
/* @__PURE__ */
|
|
6741
|
-
"
|
|
7187
|
+
/* @__PURE__ */ jsxs9(Text9, { color: BLUMA_TERMINAL.brandMagenta, children: [
|
|
7188
|
+
" ",
|
|
7189
|
+
":",
|
|
6742
7190
|
start,
|
|
6743
7191
|
"-",
|
|
6744
7192
|
end
|
|
@@ -6749,9 +7197,9 @@ var renderBlumaNotebook = ({ args }) => {
|
|
|
6749
7197
|
const parsed = parseArgs(args);
|
|
6750
7198
|
const thought = parsed.thought || parsed.content?.thought || "[thinking...]";
|
|
6751
7199
|
const truncated = truncate(thought, 100);
|
|
6752
|
-
return /* @__PURE__ */
|
|
6753
|
-
/* @__PURE__ */
|
|
6754
|
-
/* @__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 }) })
|
|
6755
7203
|
] });
|
|
6756
7204
|
};
|
|
6757
7205
|
var renderEditToolCall = ({ args, preview }) => {
|
|
@@ -6759,20 +7207,20 @@ var renderEditToolCall = ({ args, preview }) => {
|
|
|
6759
7207
|
const filepath = parsed.file_path || "[no file]";
|
|
6760
7208
|
const oldStr = parsed.old_string || "";
|
|
6761
7209
|
const newStr = parsed.new_string || "";
|
|
6762
|
-
return /* @__PURE__ */
|
|
6763
|
-
/* @__PURE__ */
|
|
6764
|
-
/* @__PURE__ */
|
|
6765
|
-
/* @__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: [
|
|
6766
7214
|
" ",
|
|
6767
7215
|
getBasename(filepath)
|
|
6768
7216
|
] })
|
|
6769
7217
|
] }),
|
|
6770
|
-
preview ? /* @__PURE__ */
|
|
6771
|
-
/* @__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: [
|
|
6772
7220
|
"- ",
|
|
6773
7221
|
truncate(oldStr, 50)
|
|
6774
7222
|
] }),
|
|
6775
|
-
/* @__PURE__ */
|
|
7223
|
+
/* @__PURE__ */ jsxs9(Text9, { color: "green", bold: true, children: [
|
|
6776
7224
|
"+ ",
|
|
6777
7225
|
truncate(newStr, 50)
|
|
6778
7226
|
] })
|
|
@@ -6788,36 +7236,40 @@ var renderTodoTool2 = ({ args }) => {
|
|
|
6788
7236
|
const barWidth = 10;
|
|
6789
7237
|
const filled = Math.round(progress / 100 * barWidth);
|
|
6790
7238
|
const bar = "=".repeat(filled) + " ".repeat(barWidth - filled);
|
|
6791
|
-
return /* @__PURE__ */
|
|
6792
|
-
/* @__PURE__ */
|
|
6793
|
-
/* @__PURE__ */
|
|
6794
|
-
/* @__PURE__ */
|
|
6795
|
-
|
|
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
|
+
"[",
|
|
6796
7247
|
bar,
|
|
6797
7248
|
"] ",
|
|
6798
7249
|
progress,
|
|
6799
7250
|
"%"
|
|
6800
7251
|
] })
|
|
6801
7252
|
] }),
|
|
6802
|
-
tasks.length > 0 && /* @__PURE__ */
|
|
6803
|
-
tasks.slice(0, 15).map((task, i) =>
|
|
6804
|
-
|
|
6805
|
-
{
|
|
6806
|
-
color:
|
|
6807
|
-
|
|
6808
|
-
|
|
6809
|
-
|
|
6810
|
-
|
|
6811
|
-
|
|
6812
|
-
|
|
6813
|
-
|
|
6814
|
-
|
|
6815
|
-
|
|
6816
|
-
|
|
6817
|
-
|
|
6818
|
-
|
|
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 +",
|
|
6819
7271
|
tasks.length - 15,
|
|
6820
|
-
"
|
|
7272
|
+
" tasks"
|
|
6821
7273
|
] })
|
|
6822
7274
|
] })
|
|
6823
7275
|
] });
|
|
@@ -6826,14 +7278,14 @@ var renderFindByName = ({ args }) => {
|
|
|
6826
7278
|
const parsed = parseArgs(args);
|
|
6827
7279
|
const pattern = parsed.pattern || "*";
|
|
6828
7280
|
const dir = parsed.directory || ".";
|
|
6829
|
-
return /* @__PURE__ */
|
|
6830
|
-
/* @__PURE__ */
|
|
6831
|
-
/* @__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: [
|
|
6832
7284
|
' "',
|
|
6833
7285
|
pattern,
|
|
6834
7286
|
'"'
|
|
6835
7287
|
] }),
|
|
6836
|
-
/* @__PURE__ */
|
|
7288
|
+
/* @__PURE__ */ jsxs9(Text9, { dimColor: true, children: [
|
|
6837
7289
|
" in ",
|
|
6838
7290
|
dir
|
|
6839
7291
|
] })
|
|
@@ -6843,14 +7295,14 @@ var renderGrepSearch = ({ args }) => {
|
|
|
6843
7295
|
const parsed = parseArgs(args);
|
|
6844
7296
|
const query = parsed.query || "";
|
|
6845
7297
|
const path19 = parsed.path || ".";
|
|
6846
|
-
return /* @__PURE__ */
|
|
6847
|
-
/* @__PURE__ */
|
|
6848
|
-
/* @__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: [
|
|
6849
7301
|
' "',
|
|
6850
7302
|
truncate(query, 30),
|
|
6851
7303
|
'"'
|
|
6852
7304
|
] }),
|
|
6853
|
-
/* @__PURE__ */
|
|
7305
|
+
/* @__PURE__ */ jsxs9(Text9, { dimColor: true, children: [
|
|
6854
7306
|
" ",
|
|
6855
7307
|
path19
|
|
6856
7308
|
] })
|
|
@@ -6859,9 +7311,9 @@ var renderGrepSearch = ({ args }) => {
|
|
|
6859
7311
|
var renderViewFileOutline = ({ args }) => {
|
|
6860
7312
|
const parsed = parseArgs(args);
|
|
6861
7313
|
const filepath = parsed.file_path || "[no file]";
|
|
6862
|
-
return /* @__PURE__ */
|
|
6863
|
-
/* @__PURE__ */
|
|
6864
|
-
/* @__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: [
|
|
6865
7317
|
" ",
|
|
6866
7318
|
getBasename(filepath)
|
|
6867
7319
|
] })
|
|
@@ -6870,9 +7322,9 @@ var renderViewFileOutline = ({ args }) => {
|
|
|
6870
7322
|
var renderCommandStatus = ({ args }) => {
|
|
6871
7323
|
const parsed = parseArgs(args);
|
|
6872
7324
|
const id = parsed.command_id || "[no id]";
|
|
6873
|
-
return /* @__PURE__ */
|
|
6874
|
-
/* @__PURE__ */
|
|
6875
|
-
/* @__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: [
|
|
6876
7328
|
" #",
|
|
6877
7329
|
id
|
|
6878
7330
|
] })
|
|
@@ -6884,36 +7336,36 @@ var renderTaskBoundary = ({ args }) => {
|
|
|
6884
7336
|
const mode = parsed.mode || "EXECUTION";
|
|
6885
7337
|
const status = parsed.task_status || "";
|
|
6886
7338
|
const modeColors = {
|
|
6887
|
-
PLANNING:
|
|
6888
|
-
EXECUTION:
|
|
6889
|
-
VERIFICATION:
|
|
7339
|
+
PLANNING: BLUMA_TERMINAL.brandBlue,
|
|
7340
|
+
EXECUTION: BLUMA_TERMINAL.brandBlue,
|
|
7341
|
+
VERIFICATION: BLUMA_TERMINAL.brandMagenta
|
|
6890
7342
|
};
|
|
6891
7343
|
const modeSymbols = {
|
|
6892
7344
|
PLANNING: "P",
|
|
6893
7345
|
EXECUTION: "E",
|
|
6894
7346
|
VERIFICATION: "V"
|
|
6895
7347
|
};
|
|
6896
|
-
return /* @__PURE__ */
|
|
6897
|
-
/* @__PURE__ */
|
|
6898
|
-
/* @__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: [
|
|
6899
7351
|
"[",
|
|
6900
7352
|
modeSymbols[mode] || "?",
|
|
6901
7353
|
"]"
|
|
6902
7354
|
] }),
|
|
6903
|
-
/* @__PURE__ */
|
|
7355
|
+
/* @__PURE__ */ jsxs9(Text9, { children: [
|
|
6904
7356
|
" ",
|
|
6905
7357
|
name
|
|
6906
7358
|
] })
|
|
6907
7359
|
] }),
|
|
6908
|
-
status && /* @__PURE__ */
|
|
7360
|
+
status && /* @__PURE__ */ jsx9(Box9, { paddingLeft: 4, children: /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: truncate(status, 60) }) })
|
|
6909
7361
|
] });
|
|
6910
7362
|
};
|
|
6911
7363
|
var renderSearchWeb = ({ args }) => {
|
|
6912
7364
|
const parsed = parseArgs(args);
|
|
6913
7365
|
const query = parsed.query || "[no query]";
|
|
6914
|
-
return /* @__PURE__ */
|
|
6915
|
-
/* @__PURE__ */
|
|
6916
|
-
/* @__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: [
|
|
6917
7369
|
' "',
|
|
6918
7370
|
truncate(query, 40),
|
|
6919
7371
|
'"'
|
|
@@ -6923,9 +7375,9 @@ var renderSearchWeb = ({ args }) => {
|
|
|
6923
7375
|
var renderLoadSkill = ({ args }) => {
|
|
6924
7376
|
const parsed = parseArgs(args);
|
|
6925
7377
|
const skillName = parsed.skill_name || "[no skill]";
|
|
6926
|
-
return /* @__PURE__ */
|
|
6927
|
-
/* @__PURE__ */
|
|
6928
|
-
/* @__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: [
|
|
6929
7381
|
" ",
|
|
6930
7382
|
skillName
|
|
6931
7383
|
] })
|
|
@@ -6934,13 +7386,7 @@ var renderLoadSkill = ({ args }) => {
|
|
|
6934
7386
|
var renderGeneric2 = ({ toolName, args }) => {
|
|
6935
7387
|
const parsed = parseArgs(args);
|
|
6936
7388
|
const keys = Object.keys(parsed).slice(0, 2);
|
|
6937
|
-
return /* @__PURE__ */
|
|
6938
|
-
/* @__PURE__ */ jsx8(Text8, { color: "white", bold: true, children: toolName }),
|
|
6939
|
-
keys.length > 0 && /* @__PURE__ */ jsxs8(Text8, { children: [
|
|
6940
|
-
" ",
|
|
6941
|
-
keys.map((k) => `${k}:${truncate(String(parsed[k]), 20)}`).join(" ")
|
|
6942
|
-
] })
|
|
6943
|
-
] });
|
|
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" }) });
|
|
6944
7390
|
};
|
|
6945
7391
|
var ToolRenderDisplay = {
|
|
6946
7392
|
shell_command: renderShellCommand2,
|
|
@@ -6960,76 +7406,230 @@ var ToolRenderDisplay = {
|
|
|
6960
7406
|
};
|
|
6961
7407
|
|
|
6962
7408
|
// src/app/ui/components/ToolCallDisplay.tsx
|
|
6963
|
-
import { jsx as
|
|
7409
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
6964
7410
|
var ToolCallDisplayComponent = ({ toolName, args, preview }) => {
|
|
6965
|
-
if (toolName.includes("message")) {
|
|
7411
|
+
if (toolName.includes("message") || toolName.includes("task_boundary") || toolName === "todo") {
|
|
6966
7412
|
return null;
|
|
6967
7413
|
}
|
|
6968
7414
|
const Renderer = ToolRenderDisplay[toolName] || ((props) => renderGeneric2({ ...props, toolName }));
|
|
6969
|
-
return /* @__PURE__ */
|
|
7415
|
+
return /* @__PURE__ */ jsx10(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsx10(Box10, { flexDirection: "column", paddingLeft: 1, children: /* @__PURE__ */ jsx10(Renderer, { toolName, args, preview }) }) });
|
|
6970
7416
|
};
|
|
6971
7417
|
var ToolCallDisplay = memo6(ToolCallDisplayComponent);
|
|
6972
7418
|
|
|
6973
7419
|
// src/app/ui/components/ToolResultDisplay.tsx
|
|
6974
|
-
import { memo as memo8 } from "react";
|
|
6975
|
-
import { Box as
|
|
7420
|
+
import { memo as memo8, useEffect as useEffect5 } from "react";
|
|
7421
|
+
import { Box as Box12, Text as Text11 } from "ink";
|
|
6976
7422
|
|
|
6977
7423
|
// src/app/ui/components/MarkdownRenderer.tsx
|
|
6978
|
-
import { memo as memo7 } from "react";
|
|
6979
|
-
import { Box as
|
|
7424
|
+
import { cloneElement, isValidElement, memo as memo7 } from "react";
|
|
7425
|
+
import { Box as Box11, Text as Text10 } from "ink";
|
|
6980
7426
|
import { marked } from "marked";
|
|
6981
7427
|
import { highlight } from "cli-highlight";
|
|
6982
|
-
import {
|
|
6983
|
-
|
|
6984
|
-
|
|
6985
|
-
|
|
6986
|
-
|
|
6987
|
-
|
|
6988
|
-
|
|
6989
|
-
}
|
|
6990
|
-
|
|
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) {
|
|
6991
7609
|
const elements = [];
|
|
6992
7610
|
for (let i = 0; i < tokens.length; i++) {
|
|
6993
7611
|
const token = tokens[i];
|
|
6994
|
-
const key =
|
|
7612
|
+
const key = `${keyRoot}-${i}`;
|
|
6995
7613
|
switch (token.type) {
|
|
6996
7614
|
case "heading": {
|
|
6997
|
-
const
|
|
6998
|
-
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`);
|
|
6999
7619
|
elements.push(
|
|
7000
|
-
/* @__PURE__ */
|
|
7001
|
-
prefix,
|
|
7002
|
-
|
|
7003
|
-
|
|
7004
|
-
] }) }, 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)
|
|
7005
7624
|
);
|
|
7006
7625
|
break;
|
|
7007
7626
|
}
|
|
7008
|
-
case "paragraph":
|
|
7009
|
-
|
|
7010
|
-
elements.push(
|
|
7011
|
-
/* @__PURE__ */ jsx10(Box10, { marginBottom: 1, children: renderInline(para.text) }, key)
|
|
7012
|
-
);
|
|
7627
|
+
case "paragraph":
|
|
7628
|
+
elements.push(renderParagraph(token, key));
|
|
7013
7629
|
break;
|
|
7014
|
-
|
|
7015
|
-
|
|
7016
|
-
const list = token;
|
|
7017
|
-
list.items.forEach((item, idx) => {
|
|
7018
|
-
const bullet = list.ordered ? `${idx + 1}.` : "\u2022";
|
|
7019
|
-
const text = item.tokens?.filter((t) => t.type === "text").map((t) => t.text).join("") || item.text;
|
|
7020
|
-
elements.push(
|
|
7021
|
-
/* @__PURE__ */ jsxs9(Box10, { paddingLeft: 1, children: [
|
|
7022
|
-
/* @__PURE__ */ jsx10(Text9, { color: COLORS.listBullet, children: bullet }),
|
|
7023
|
-
/* @__PURE__ */ jsxs9(Text9, { children: [
|
|
7024
|
-
" ",
|
|
7025
|
-
renderInline(text)
|
|
7026
|
-
] })
|
|
7027
|
-
] }, `${key}-item-${idx}`)
|
|
7028
|
-
);
|
|
7029
|
-
});
|
|
7030
|
-
elements.push(/* @__PURE__ */ jsx10(Box10, { marginBottom: 1 }, `${key}-spacer`));
|
|
7630
|
+
case "list":
|
|
7631
|
+
elements.push(renderListBlock(token, 0, key));
|
|
7031
7632
|
break;
|
|
7032
|
-
}
|
|
7033
7633
|
case "code": {
|
|
7034
7634
|
const code = token;
|
|
7035
7635
|
let highlighted;
|
|
@@ -7042,110 +7642,144 @@ function renderTokens(tokens) {
|
|
|
7042
7642
|
highlighted = code.text;
|
|
7043
7643
|
}
|
|
7044
7644
|
elements.push(
|
|
7045
|
-
/* @__PURE__ */
|
|
7046
|
-
|
|
7047
|
-
|
|
7048
|
-
|
|
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
|
+
)
|
|
7049
7660
|
);
|
|
7050
7661
|
break;
|
|
7051
7662
|
}
|
|
7052
|
-
case "blockquote":
|
|
7053
|
-
|
|
7054
|
-
elements.push(
|
|
7055
|
-
/* @__PURE__ */ jsxs9(Box10, { marginBottom: 1, children: [
|
|
7056
|
-
/* @__PURE__ */ jsx10(Text9, { color: COLORS.quote, children: "\u2502 " }),
|
|
7057
|
-
/* @__PURE__ */ jsx10(Text9, { dimColor: true, italic: true, children: quote.text })
|
|
7058
|
-
] }, key)
|
|
7059
|
-
);
|
|
7663
|
+
case "blockquote":
|
|
7664
|
+
elements.push(renderBlockquote(token, key));
|
|
7060
7665
|
break;
|
|
7061
|
-
}
|
|
7062
7666
|
case "table": {
|
|
7063
7667
|
const table = token;
|
|
7064
7668
|
elements.push(
|
|
7065
|
-
/* @__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)
|
|
7066
7681
|
);
|
|
7067
|
-
table.rows.forEach((row, rowIdx) => {
|
|
7068
|
-
elements.push(
|
|
7069
|
-
/* @__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}`)
|
|
7070
|
-
);
|
|
7071
|
-
});
|
|
7072
|
-
elements.push(/* @__PURE__ */ jsx10(Box10, { marginBottom: 1 }, `${key}-spacer`));
|
|
7073
7682
|
break;
|
|
7074
7683
|
}
|
|
7075
|
-
case "hr":
|
|
7684
|
+
case "hr":
|
|
7076
7685
|
elements.push(
|
|
7077
|
-
/* @__PURE__ */
|
|
7686
|
+
/* @__PURE__ */ jsx11(Box11, { marginY: 1, children: /* @__PURE__ */ jsx11(Text10, { dimColor: true, children: "\u2500".repeat(42) }) }, key)
|
|
7078
7687
|
);
|
|
7079
7688
|
break;
|
|
7080
|
-
|
|
7081
|
-
case "space": {
|
|
7689
|
+
case "space":
|
|
7082
7690
|
break;
|
|
7083
|
-
|
|
7084
|
-
default: {
|
|
7691
|
+
default:
|
|
7085
7692
|
if ("text" in token && typeof token.text === "string") {
|
|
7086
|
-
elements.push(
|
|
7693
|
+
elements.push(
|
|
7694
|
+
/* @__PURE__ */ jsx11(Text10, { dimColor: true, children: token.text }, key)
|
|
7695
|
+
);
|
|
7087
7696
|
}
|
|
7088
|
-
}
|
|
7089
7697
|
}
|
|
7090
7698
|
}
|
|
7091
7699
|
return elements;
|
|
7092
7700
|
}
|
|
7093
|
-
function renderInline(text) {
|
|
7094
|
-
const parts = [];
|
|
7095
|
-
let remaining = text;
|
|
7096
|
-
let partIndex = 0;
|
|
7097
|
-
const inlineRegex = /(\*\*(.+?)\*\*|\*(.+?)\*|`(.+?)`|\[(.+?)\]\((.+?)\))/;
|
|
7098
|
-
while (remaining.length > 0) {
|
|
7099
|
-
const match = remaining.match(inlineRegex);
|
|
7100
|
-
if (!match) {
|
|
7101
|
-
parts.push(/* @__PURE__ */ jsx10(Text9, { children: remaining }, `inline-${partIndex++}`));
|
|
7102
|
-
break;
|
|
7103
|
-
}
|
|
7104
|
-
const matchIndex = match.index ?? 0;
|
|
7105
|
-
if (matchIndex > 0) {
|
|
7106
|
-
parts.push(
|
|
7107
|
-
/* @__PURE__ */ jsx10(Text9, { children: remaining.slice(0, matchIndex) }, `inline-${partIndex++}`)
|
|
7108
|
-
);
|
|
7109
|
-
}
|
|
7110
|
-
const fullMatch = match[0];
|
|
7111
|
-
if (fullMatch.startsWith("**")) {
|
|
7112
|
-
parts.push(
|
|
7113
|
-
/* @__PURE__ */ jsx10(Text9, { bold: true, children: match[2] }, `inline-${partIndex++}`)
|
|
7114
|
-
);
|
|
7115
|
-
} else if (fullMatch.startsWith("*")) {
|
|
7116
|
-
parts.push(
|
|
7117
|
-
/* @__PURE__ */ jsx10(Text9, { italic: true, children: match[3] }, `inline-${partIndex++}`)
|
|
7118
|
-
);
|
|
7119
|
-
} else if (fullMatch.startsWith("`")) {
|
|
7120
|
-
parts.push(
|
|
7121
|
-
/* @__PURE__ */ jsxs9(Text9, { color: COLORS.code, children: [
|
|
7122
|
-
"`",
|
|
7123
|
-
match[4],
|
|
7124
|
-
"`"
|
|
7125
|
-
] }, `inline-${partIndex++}`)
|
|
7126
|
-
);
|
|
7127
|
-
} else if (fullMatch.startsWith("[")) {
|
|
7128
|
-
parts.push(
|
|
7129
|
-
/* @__PURE__ */ jsx10(Text9, { color: COLORS.link, underline: true, children: match[5] }, `inline-${partIndex++}`)
|
|
7130
|
-
);
|
|
7131
|
-
}
|
|
7132
|
-
remaining = remaining.slice(matchIndex + fullMatch.length);
|
|
7133
|
-
}
|
|
7134
|
-
return parts.length === 1 ? parts[0] : /* @__PURE__ */ jsx10(Fragment3, { children: parts });
|
|
7135
|
-
}
|
|
7136
7701
|
var MarkdownRendererComponent = ({ markdown }) => {
|
|
7137
7702
|
if (!markdown || markdown.trim() === "") {
|
|
7138
7703
|
return null;
|
|
7139
7704
|
}
|
|
7140
7705
|
const tokens = marked.lexer(markdown);
|
|
7141
|
-
return /* @__PURE__ */
|
|
7706
|
+
return /* @__PURE__ */ jsx11(Box11, { flexDirection: "column", paddingRight: 1, children: renderBlockTokens(tokens, "md") });
|
|
7142
7707
|
};
|
|
7143
7708
|
var MarkdownRenderer = memo7(MarkdownRendererComponent);
|
|
7144
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
|
+
|
|
7145
7780
|
// src/app/ui/components/ToolResultDisplay.tsx
|
|
7146
|
-
import { jsx as
|
|
7147
|
-
var
|
|
7148
|
-
var parseResult = (result) => {
|
|
7781
|
+
import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
7782
|
+
var parseResult2 = (result) => {
|
|
7149
7783
|
try {
|
|
7150
7784
|
return JSON.parse(result);
|
|
7151
7785
|
} catch {
|
|
@@ -7162,153 +7796,222 @@ var truncateLines = (text, max) => {
|
|
|
7162
7796
|
truncated: allLines.length - max
|
|
7163
7797
|
};
|
|
7164
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
|
+
}
|
|
7165
7808
|
var ToolResultDisplayComponent = ({ toolName, result }) => {
|
|
7809
|
+
useEffect5(() => {
|
|
7810
|
+
refreshExpandableFromToolResult(toolName, result);
|
|
7811
|
+
}, [toolName, result]);
|
|
7166
7812
|
if (toolName.includes("task_boundary")) {
|
|
7167
7813
|
return null;
|
|
7168
7814
|
}
|
|
7169
|
-
const parsed =
|
|
7815
|
+
const parsed = parseResult2(result);
|
|
7170
7816
|
if (toolName.includes("message")) {
|
|
7171
|
-
const body = parsed?.content?.body
|
|
7817
|
+
const body = parsed?.content?.body ?? parsed?.body ?? parsed?.message;
|
|
7172
7818
|
if (!body) return null;
|
|
7173
|
-
return /* @__PURE__ */
|
|
7174
|
-
}
|
|
7175
|
-
if (toolName.includes("read_file") && parsed
|
|
7176
|
-
const { lines, truncated } = truncateLines(parsed.content,
|
|
7177
|
-
return /* @__PURE__ */
|
|
7178
|
-
lines.map((line, i) => /* @__PURE__ */
|
|
7179
|
-
truncated > 0
|
|
7180
|
-
"
|
|
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 +",
|
|
7181
7827
|
truncated,
|
|
7182
|
-
" lines"
|
|
7183
|
-
] })
|
|
7184
|
-
] });
|
|
7828
|
+
" lines \xB7 Ctrl+O expand"
|
|
7829
|
+
] }) : null
|
|
7830
|
+
] }) });
|
|
7185
7831
|
}
|
|
7186
7832
|
if ((toolName.includes("shell_command") || toolName.includes("run_command") || toolName.includes("command_status")) && parsed) {
|
|
7187
|
-
const output = parsed.stdout || parsed.output || "";
|
|
7188
|
-
const stderr = parsed.stderr || "";
|
|
7833
|
+
const output = String(parsed.stdout || parsed.output || "");
|
|
7834
|
+
const stderr = String(parsed.stderr || "");
|
|
7189
7835
|
const exitCode = parsed.exit_code ?? parsed.exitCode ?? 0;
|
|
7190
|
-
const status = parsed.status || "";
|
|
7836
|
+
const status = String(parsed.status || "");
|
|
7191
7837
|
if (parsed.command_id && !output && !stderr && !status) {
|
|
7192
|
-
return /* @__PURE__ */
|
|
7838
|
+
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsx12(Box12, { paddingLeft: 2, children: /* @__PURE__ */ jsxs11(Text11, { dimColor: true, children: [
|
|
7193
7839
|
"started #",
|
|
7194
|
-
parsed.command_id.slice(0, 8)
|
|
7195
|
-
] }) });
|
|
7840
|
+
String(parsed.command_id).slice(0, 8)
|
|
7841
|
+
] }) }) });
|
|
7196
7842
|
}
|
|
7197
7843
|
if (status === "running") {
|
|
7198
|
-
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" }) }) });
|
|
7199
7845
|
}
|
|
7200
7846
|
if (!output && !stderr) return null;
|
|
7201
|
-
const { lines, truncated } = truncateLines(output || stderr,
|
|
7847
|
+
const { lines, truncated } = truncateLines(output || stderr, TOOL_PREVIEW_MAX_LINES);
|
|
7202
7848
|
const isError = exitCode !== 0;
|
|
7203
7849
|
const isSuccess = exitCode === 0 && status !== "running";
|
|
7204
|
-
const
|
|
7205
|
-
return /* @__PURE__ */
|
|
7206
|
-
lines.map((line, i) => /* @__PURE__ */
|
|
7207
|
-
truncated > 0
|
|
7208
|
-
"
|
|
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 +",
|
|
7209
7855
|
truncated,
|
|
7210
|
-
" lines"
|
|
7211
|
-
] }),
|
|
7212
|
-
exitCode !== 0
|
|
7213
|
-
"exit
|
|
7856
|
+
" lines \xB7 Ctrl+O expand"
|
|
7857
|
+
] }) : null,
|
|
7858
|
+
exitCode !== 0 ? /* @__PURE__ */ jsxs11(Text11, { dimColor: true, color: BLUMA_TERMINAL.err, children: [
|
|
7859
|
+
"exit ",
|
|
7214
7860
|
exitCode
|
|
7215
|
-
] })
|
|
7216
|
-
] });
|
|
7861
|
+
] }) : null
|
|
7862
|
+
] }) });
|
|
7217
7863
|
}
|
|
7218
7864
|
if ((toolName.includes("grep") || toolName.includes("find_by_name")) && parsed) {
|
|
7219
7865
|
const matches = parsed.matches || parsed.results || parsed.files || [];
|
|
7220
7866
|
if (matches.length === 0) {
|
|
7221
|
-
return /* @__PURE__ */
|
|
7867
|
+
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsx12(Box12, { paddingLeft: 2, children: /* @__PURE__ */ jsx12(Text11, { dimColor: true, children: "no matches" }) }) });
|
|
7222
7868
|
}
|
|
7223
|
-
return /* @__PURE__ */
|
|
7224
|
-
/* @__PURE__ */
|
|
7869
|
+
return /* @__PURE__ */ jsx12(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsxs11(Box12, { flexDirection: "column", paddingLeft: 2, children: [
|
|
7870
|
+
/* @__PURE__ */ jsxs11(Text11, { dimColor: true, children: [
|
|
7225
7871
|
matches.length,
|
|
7226
7872
|
" matches"
|
|
7227
7873
|
] }),
|
|
7228
|
-
matches.slice(0, 5).map((m, i) =>
|
|
7229
|
-
|
|
7230
|
-
|
|
7231
|
-
|
|
7232
|
-
|
|
7233
|
-
|
|
7234
|
-
|
|
7235
|
-
|
|
7236
|
-
|
|
7237
|
-
|
|
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
|
+
] }) });
|
|
7238
7888
|
}
|
|
7239
7889
|
if (toolName.includes("ls_tool") && parsed) {
|
|
7240
7890
|
const entries = parsed.entries || parsed.files || [];
|
|
7241
7891
|
if (entries.length === 0) return null;
|
|
7242
|
-
return /* @__PURE__ */
|
|
7243
|
-
entries.slice(0, 6).map((e, i) =>
|
|
7244
|
-
|
|
7245
|
-
|
|
7246
|
-
|
|
7247
|
-
|
|
7248
|
-
|
|
7249
|
-
|
|
7250
|
-
|
|
7251
|
-
|
|
7252
|
-
|
|
7253
|
-
|
|
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
|
+
] }) });
|
|
7254
7907
|
}
|
|
7255
7908
|
if (toolName.includes("load_skill") && parsed) {
|
|
7256
7909
|
if (!parsed.success) {
|
|
7257
|
-
return /* @__PURE__ */
|
|
7258
|
-
"
|
|
7259
|
-
parsed.message
|
|
7260
|
-
] }) });
|
|
7261
|
-
}
|
|
7262
|
-
|
|
7263
|
-
|
|
7264
|
-
/* @__PURE__ */
|
|
7265
|
-
/* @__PURE__ */
|
|
7266
|
-
"
|
|
7267
|
-
|
|
7268
|
-
|
|
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" : ""
|
|
7269
7923
|
] })
|
|
7270
|
-
] });
|
|
7924
|
+
] }) });
|
|
7271
7925
|
}
|
|
7272
7926
|
if (toolName.includes("todo")) {
|
|
7273
|
-
|
|
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)) }) });
|
|
7274
7958
|
}
|
|
7275
7959
|
if (toolName.includes("view_file_outline") && parsed) {
|
|
7276
7960
|
const symbols = parsed.symbols || parsed.outline || [];
|
|
7277
7961
|
if (symbols.length === 0) return null;
|
|
7278
|
-
return /* @__PURE__ */
|
|
7279
|
-
symbols.slice(0, 5).map((s, i) =>
|
|
7280
|
-
|
|
7281
|
-
|
|
7282
|
-
|
|
7283
|
-
|
|
7284
|
-
|
|
7285
|
-
|
|
7286
|
-
|
|
7287
|
-
|
|
7288
|
-
|
|
7289
|
-
|
|
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
|
+
] }) });
|
|
7290
7976
|
}
|
|
7291
7977
|
return null;
|
|
7292
7978
|
};
|
|
7293
7979
|
var ToolResultDisplay = memo8(ToolResultDisplayComponent);
|
|
7294
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
|
+
|
|
7295
8009
|
// src/app/ui/components/SlashCommands.tsx
|
|
7296
|
-
import { Box as
|
|
7297
|
-
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";
|
|
7298
8012
|
var SlashCommands = ({ input, setHistory, agentRef }) => {
|
|
7299
8013
|
const [cmd, ...args] = input.slice(1).trim().split(/\s+/);
|
|
7300
|
-
const outBox = (children) => /* @__PURE__ */
|
|
7301
|
-
Box12,
|
|
7302
|
-
{
|
|
7303
|
-
borderStyle: "single",
|
|
7304
|
-
borderColor: "gray",
|
|
7305
|
-
paddingX: 2,
|
|
7306
|
-
paddingY: 0,
|
|
7307
|
-
marginBottom: 1,
|
|
7308
|
-
flexDirection: "column",
|
|
7309
|
-
children
|
|
7310
|
-
}
|
|
7311
|
-
);
|
|
8014
|
+
const outBox = (children) => /* @__PURE__ */ jsx14(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsx14(Box14, { paddingLeft: 1, flexDirection: "column", children }) });
|
|
7312
8015
|
const render2 = () => {
|
|
7313
8016
|
if (!cmd) {
|
|
7314
8017
|
return null;
|
|
@@ -7316,11 +8019,11 @@ var SlashCommands = ({ input, setHistory, agentRef }) => {
|
|
|
7316
8019
|
if (cmd === "help") {
|
|
7317
8020
|
const cmds = getSlashCommands();
|
|
7318
8021
|
return outBox(
|
|
7319
|
-
/* @__PURE__ */
|
|
7320
|
-
/* @__PURE__ */
|
|
7321
|
-
/* @__PURE__ */
|
|
7322
|
-
/* @__PURE__ */
|
|
7323
|
-
/* @__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 })
|
|
7324
8027
|
] }, i)) })
|
|
7325
8028
|
] })
|
|
7326
8029
|
);
|
|
@@ -7328,9 +8031,9 @@ var SlashCommands = ({ input, setHistory, agentRef }) => {
|
|
|
7328
8031
|
if (cmd === "clear") {
|
|
7329
8032
|
setHistory((prev) => prev.filter((item) => item.id === 0 || item.id === 1));
|
|
7330
8033
|
return outBox(
|
|
7331
|
-
/* @__PURE__ */
|
|
7332
|
-
/* @__PURE__ */
|
|
7333
|
-
/* @__PURE__ */
|
|
8034
|
+
/* @__PURE__ */ jsxs13(Box14, { children: [
|
|
8035
|
+
/* @__PURE__ */ jsx14(Text13, { color: "green", children: "[ok]" }),
|
|
8036
|
+
/* @__PURE__ */ jsx14(Text13, { dimColor: true, children: " History cleared" })
|
|
7334
8037
|
] })
|
|
7335
8038
|
);
|
|
7336
8039
|
}
|
|
@@ -7342,8 +8045,8 @@ var SlashCommands = ({ input, setHistory, agentRef }) => {
|
|
|
7342
8045
|
setHistory((prev) => prev.concat({
|
|
7343
8046
|
id: Date.now(),
|
|
7344
8047
|
component: outBox(
|
|
7345
|
-
/* @__PURE__ */
|
|
7346
|
-
"
|
|
8048
|
+
/* @__PURE__ */ jsx14(Box14, { children: /* @__PURE__ */ jsxs13(Text13, { color: "red", children: [
|
|
8049
|
+
"Failed to execute /init: ",
|
|
7347
8050
|
e?.message || String(e)
|
|
7348
8051
|
] }) })
|
|
7349
8052
|
)
|
|
@@ -7363,41 +8066,41 @@ var SlashCommands = ({ input, setHistory, agentRef }) => {
|
|
|
7363
8066
|
const colType = 10;
|
|
7364
8067
|
const colSource = 18;
|
|
7365
8068
|
return outBox(
|
|
7366
|
-
/* @__PURE__ */
|
|
7367
|
-
/* @__PURE__ */
|
|
7368
|
-
/* @__PURE__ */
|
|
7369
|
-
/* @__PURE__ */
|
|
7370
|
-
/* @__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: [
|
|
7371
8074
|
tools.length,
|
|
7372
8075
|
" total"
|
|
7373
8076
|
] }),
|
|
7374
|
-
term && /* @__PURE__ */
|
|
7375
|
-
/* @__PURE__ */
|
|
7376
|
-
/* @__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: [
|
|
7377
8080
|
'"',
|
|
7378
8081
|
term,
|
|
7379
8082
|
'"'
|
|
7380
8083
|
] }),
|
|
7381
|
-
/* @__PURE__ */
|
|
8084
|
+
/* @__PURE__ */ jsxs13(Text13, { dimColor: true, children: [
|
|
7382
8085
|
" \u2022 showing: ",
|
|
7383
8086
|
filtered.length
|
|
7384
8087
|
] })
|
|
7385
8088
|
] })
|
|
7386
8089
|
] }),
|
|
7387
|
-
filtered.length === 0 ? /* @__PURE__ */
|
|
7388
|
-
/* @__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: [
|
|
7389
8092
|
pad("Name", colName),
|
|
7390
8093
|
" \u2502 ",
|
|
7391
8094
|
pad("Type", colType),
|
|
7392
8095
|
" \u2502 ",
|
|
7393
8096
|
pad("Source", colSource)
|
|
7394
8097
|
] }) }),
|
|
7395
|
-
/* @__PURE__ */
|
|
8098
|
+
/* @__PURE__ */ jsx14(Text13, { color: "gray", children: "\u2500".repeat(colName + colType + colSource + 6) }),
|
|
7396
8099
|
filtered.map((t, i) => {
|
|
7397
8100
|
const name = t.function?.name || t.name || "tool";
|
|
7398
8101
|
const type = t.function?.name ? "fn" : t.type || "tool";
|
|
7399
8102
|
const source = t.source || t.provider || "mcp";
|
|
7400
|
-
return /* @__PURE__ */
|
|
8103
|
+
return /* @__PURE__ */ jsxs13(Text13, { color: "white", children: [
|
|
7401
8104
|
pad(name, colName),
|
|
7402
8105
|
" \u2502 ",
|
|
7403
8106
|
pad(String(type), colType),
|
|
@@ -7420,22 +8123,22 @@ var SlashCommands = ({ input, setHistory, agentRef }) => {
|
|
|
7420
8123
|
const colType = 10;
|
|
7421
8124
|
const colSource = 18;
|
|
7422
8125
|
return outBox(
|
|
7423
|
-
/* @__PURE__ */
|
|
7424
|
-
/* @__PURE__ */
|
|
7425
|
-
/* @__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: [
|
|
7426
8129
|
"Total Native: ",
|
|
7427
8130
|
tools.length,
|
|
7428
8131
|
term ? ` | Filter: "${term}" | Showing: ${filtered.length}` : ""
|
|
7429
8132
|
] }),
|
|
7430
|
-
filtered.length === 0 ? /* @__PURE__ */
|
|
7431
|
-
/* @__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: [
|
|
7432
8135
|
pad("Name", colName),
|
|
7433
8136
|
" | ",
|
|
7434
8137
|
pad("Type", colType),
|
|
7435
8138
|
" | ",
|
|
7436
8139
|
pad("Source", colSource)
|
|
7437
8140
|
] }),
|
|
7438
|
-
/* @__PURE__ */
|
|
8141
|
+
/* @__PURE__ */ jsxs13(Text13, { color: "gray", children: [
|
|
7439
8142
|
"".padEnd(colName, "-"),
|
|
7440
8143
|
"---",
|
|
7441
8144
|
"".padEnd(colType, "-"),
|
|
@@ -7446,7 +8149,7 @@ var SlashCommands = ({ input, setHistory, agentRef }) => {
|
|
|
7446
8149
|
const name = t.function?.name || t.name || "tool";
|
|
7447
8150
|
const type = t.function?.name ? "fn" : t.type || "tool";
|
|
7448
8151
|
const source = t.source || "native";
|
|
7449
|
-
return /* @__PURE__ */
|
|
8152
|
+
return /* @__PURE__ */ jsxs13(Text13, { color: "white", children: [
|
|
7450
8153
|
pad(name, colName),
|
|
7451
8154
|
" | ",
|
|
7452
8155
|
pad(String(type), colType),
|
|
@@ -7458,18 +8161,18 @@ var SlashCommands = ({ input, setHistory, agentRef }) => {
|
|
|
7458
8161
|
] })
|
|
7459
8162
|
);
|
|
7460
8163
|
}
|
|
7461
|
-
return outBox(/* @__PURE__ */
|
|
8164
|
+
return outBox(/* @__PURE__ */ jsxs13(Text13, { color: "red", children: [
|
|
7462
8165
|
"Command not recognized: /",
|
|
7463
8166
|
cmd
|
|
7464
8167
|
] }));
|
|
7465
8168
|
};
|
|
7466
|
-
return /* @__PURE__ */
|
|
8169
|
+
return /* @__PURE__ */ jsx14(Fragment2, { children: render2() });
|
|
7467
8170
|
};
|
|
7468
8171
|
var SlashCommands_default = SlashCommands;
|
|
7469
8172
|
|
|
7470
8173
|
// src/app/agent/utils/update_check.ts
|
|
7471
8174
|
import updateNotifier from "update-notifier";
|
|
7472
|
-
import { fileURLToPath as
|
|
8175
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
7473
8176
|
import path18 from "path";
|
|
7474
8177
|
import fs14 from "fs";
|
|
7475
8178
|
var BLUMA_PACKAGE_NAME = "@nomad-e/bluma-cli";
|
|
@@ -7504,7 +8207,7 @@ async function checkForUpdates() {
|
|
|
7504
8207
|
pkg = findBlumaPackageJson(path18.dirname(binPath));
|
|
7505
8208
|
}
|
|
7506
8209
|
if (!pkg) {
|
|
7507
|
-
const __filename =
|
|
8210
|
+
const __filename = fileURLToPath3(import.meta.url);
|
|
7508
8211
|
const __dirname2 = path18.dirname(__filename);
|
|
7509
8212
|
pkg = findBlumaPackageJson(__dirname2);
|
|
7510
8213
|
}
|
|
@@ -7533,86 +8236,88 @@ Run: npm i -g ${BLUMA_PACKAGE_NAME} to update.`;
|
|
|
7533
8236
|
}
|
|
7534
8237
|
|
|
7535
8238
|
// src/app/ui/components/UpdateNotice.tsx
|
|
7536
|
-
import { Box as
|
|
7537
|
-
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";
|
|
7538
8241
|
function parseUpdateMessage(msg) {
|
|
7539
8242
|
const lines = msg.split(/\r?\n/).map((l) => l.trim());
|
|
7540
8243
|
const first = lines[0] || "";
|
|
7541
8244
|
const hintLine = lines.slice(1).join(" ") || "";
|
|
7542
8245
|
const nameMatch = first.match(/Update available for\s+([^!]+)!/i);
|
|
7543
8246
|
const versionMatch = first.match(/!\s*([^\s]+)\s*→\s*([^\s]+)/);
|
|
7544
|
-
const name = nameMatch?.[1]?.trim();
|
|
7545
|
-
const current = versionMatch?.[1]?.trim();
|
|
7546
|
-
const latest = versionMatch?.[2]?.trim();
|
|
7547
8247
|
return {
|
|
7548
|
-
name,
|
|
7549
|
-
current,
|
|
7550
|
-
latest,
|
|
8248
|
+
name: nameMatch?.[1]?.trim(),
|
|
8249
|
+
current: versionMatch?.[1]?.trim(),
|
|
8250
|
+
latest: versionMatch?.[2]?.trim(),
|
|
7551
8251
|
hint: hintLine || void 0
|
|
7552
8252
|
};
|
|
7553
8253
|
}
|
|
7554
8254
|
var UpdateNotice = ({ message: message2 }) => {
|
|
7555
|
-
const { name, current, latest, hint } = parseUpdateMessage(message2);
|
|
7556
|
-
return /* @__PURE__ */
|
|
7557
|
-
/* @__PURE__ */
|
|
7558
|
-
name && current &&
|
|
7559
|
-
|
|
7560
|
-
|
|
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
|
+
] }) });
|
|
7561
8265
|
};
|
|
7562
8266
|
var UpdateNotice_default = UpdateNotice;
|
|
7563
8267
|
|
|
7564
8268
|
// src/app/ui/components/ErrorMessage.tsx
|
|
7565
|
-
import { Box as
|
|
7566
|
-
import { jsx as
|
|
7567
|
-
var ErrorMessage = ({ message: message2, details, hint }) => {
|
|
7568
|
-
|
|
7569
|
-
|
|
7570
|
-
|
|
7571
|
-
|
|
7572
|
-
|
|
7573
|
-
|
|
7574
|
-
|
|
7575
|
-
hint && /* @__PURE__ */ jsx14(Box14, { paddingLeft: 2, children: /* @__PURE__ */ jsxs13(Text13, { color: "gray", children: [
|
|
7576
|
-
"hint: ",
|
|
7577
|
-
hint
|
|
7578
|
-
] }) })
|
|
7579
|
-
] });
|
|
7580
|
-
};
|
|
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
|
+
] }) });
|
|
7581
8279
|
var ErrorMessage_default = ErrorMessage;
|
|
7582
8280
|
|
|
7583
8281
|
// src/app/ui/components/ReasoningDisplay.tsx
|
|
7584
|
-
import { memo as memo9
|
|
7585
|
-
import { Box as
|
|
7586
|
-
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";
|
|
7587
8285
|
var ReasoningDisplayComponent = ({
|
|
7588
8286
|
reasoning,
|
|
7589
8287
|
collapsed = false
|
|
7590
8288
|
}) => {
|
|
7591
|
-
const [isExpanded, setIsExpanded] = useState5(!collapsed);
|
|
7592
8289
|
if (!reasoning || reasoning.trim() === "") {
|
|
7593
8290
|
return null;
|
|
7594
8291
|
}
|
|
7595
|
-
const maxLines =
|
|
8292
|
+
const maxLines = collapsed ? 6 : 200;
|
|
7596
8293
|
const lines = reasoning.split("\n");
|
|
7597
|
-
const
|
|
7598
|
-
|
|
7599
|
-
|
|
7600
|
-
|
|
7601
|
-
|
|
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
|
+
] }) });
|
|
7602
8304
|
};
|
|
7603
8305
|
var ReasoningDisplay = memo9(ReasoningDisplayComponent);
|
|
7604
8306
|
|
|
7605
8307
|
// src/app/ui/components/StreamingText.tsx
|
|
7606
|
-
import { useState as
|
|
7607
|
-
import { Box as
|
|
7608
|
-
import { jsx as
|
|
7609
|
-
var StreamingTextComponent = ({
|
|
7610
|
-
|
|
7611
|
-
|
|
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);
|
|
7612
8317
|
const reasoningRef = useRef4("");
|
|
7613
8318
|
const lastUpdateRef = useRef4(0);
|
|
7614
8319
|
const pendingUpdateRef = useRef4(null);
|
|
7615
|
-
|
|
8320
|
+
useEffect6(() => {
|
|
7616
8321
|
const handleStart = () => {
|
|
7617
8322
|
setReasoning("");
|
|
7618
8323
|
reasoningRef.current = "";
|
|
@@ -7668,19 +8373,56 @@ var StreamingTextComponent = ({ eventBus, onReasoningComplete }) => {
|
|
|
7668
8373
|
truncatedCount = lines.length - MAX_VISIBLE_LINES;
|
|
7669
8374
|
displayLines = lines.slice(-MAX_VISIBLE_LINES);
|
|
7670
8375
|
}
|
|
7671
|
-
return /* @__PURE__ */
|
|
7672
|
-
truncatedCount > 0
|
|
7673
|
-
"
|
|
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 ",
|
|
7674
8379
|
truncatedCount,
|
|
7675
|
-
"
|
|
7676
|
-
] }),
|
|
7677
|
-
|
|
7678
|
-
] });
|
|
8380
|
+
" lines above hidden"
|
|
8381
|
+
] }) : null,
|
|
8382
|
+
displayLines.map((line, i) => /* @__PURE__ */ jsx18(Text17, { dimColor: true, children: line }, i))
|
|
8383
|
+
] }) });
|
|
7679
8384
|
};
|
|
7680
8385
|
var StreamingText = memo10(StreamingTextComponent);
|
|
7681
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
|
+
|
|
7682
8424
|
// src/app/ui/App.tsx
|
|
7683
|
-
import { jsx as
|
|
8425
|
+
import { jsx as jsx20, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
7684
8426
|
var SAFE_AUTO_APPROVE_TOOLS = [
|
|
7685
8427
|
// Comunicação/UI
|
|
7686
8428
|
"message",
|
|
@@ -7698,36 +8440,64 @@ var SAFE_AUTO_APPROVE_TOOLS = [
|
|
|
7698
8440
|
];
|
|
7699
8441
|
var AppComponent = ({ eventBus, sessionId }) => {
|
|
7700
8442
|
const agentInstance = useRef5(null);
|
|
7701
|
-
const [history, setHistory] =
|
|
7702
|
-
const [statusMessage, setStatusMessage] =
|
|
8443
|
+
const [history, setHistory] = useState6([]);
|
|
8444
|
+
const [statusMessage, setStatusMessage] = useState6(
|
|
7703
8445
|
"Initializing agent..."
|
|
7704
8446
|
);
|
|
7705
|
-
const [toolsCount, setToolsCount] =
|
|
7706
|
-
const [mcpStatus, setMcpStatus] =
|
|
8447
|
+
const [toolsCount, setToolsCount] = useState6(null);
|
|
8448
|
+
const [mcpStatus, setMcpStatus] = useState6(
|
|
7707
8449
|
"connecting"
|
|
7708
8450
|
);
|
|
7709
|
-
const [isProcessing, setIsProcessing] =
|
|
7710
|
-
const [pendingConfirmation, setPendingConfirmation] =
|
|
8451
|
+
const [isProcessing, setIsProcessing] = useState6(true);
|
|
8452
|
+
const [pendingConfirmation, setPendingConfirmation] = useState6(
|
|
7711
8453
|
null
|
|
7712
8454
|
);
|
|
7713
|
-
const [confirmationPreview, setConfirmationPreview] =
|
|
8455
|
+
const [confirmationPreview, setConfirmationPreview] = useState6(
|
|
7714
8456
|
null
|
|
7715
8457
|
);
|
|
7716
|
-
const [isInitAgentActive, setIsInitAgentActive] =
|
|
8458
|
+
const [isInitAgentActive, setIsInitAgentActive] = useState6(false);
|
|
7717
8459
|
const alwaysAcceptList = useRef5([]);
|
|
7718
8460
|
const workdir = process.cwd();
|
|
7719
8461
|
const updateCheckRan = useRef5(false);
|
|
7720
|
-
const
|
|
7721
|
-
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]);
|
|
7722
8491
|
const handleInterrupt = useCallback2(() => {
|
|
7723
8492
|
if (!isProcessing) return;
|
|
7724
8493
|
eventBus.emit("user_interrupt");
|
|
8494
|
+
turnStartedAtRef.current = null;
|
|
7725
8495
|
setIsProcessing(false);
|
|
7726
8496
|
setHistory((prev) => [
|
|
7727
8497
|
...prev,
|
|
7728
8498
|
{
|
|
7729
8499
|
id: prev.length,
|
|
7730
|
-
component: /* @__PURE__ */
|
|
8500
|
+
component: /* @__PURE__ */ jsx20(ChatMeta, { children: "cancelled (Esc)" })
|
|
7731
8501
|
}
|
|
7732
8502
|
]);
|
|
7733
8503
|
}, [isProcessing, eventBus]);
|
|
@@ -7743,6 +8513,7 @@ var AppComponent = ({ eventBus, sessionId }) => {
|
|
|
7743
8513
|
if (cmd === "init") {
|
|
7744
8514
|
setIsInitAgentActive(true);
|
|
7745
8515
|
setIsProcessing(true);
|
|
8516
|
+
turnStartedAtRef.current = Date.now();
|
|
7746
8517
|
} else {
|
|
7747
8518
|
setIsProcessing(false);
|
|
7748
8519
|
setIsInitAgentActive(false);
|
|
@@ -7751,11 +8522,11 @@ var AppComponent = ({ eventBus, sessionId }) => {
|
|
|
7751
8522
|
...prev,
|
|
7752
8523
|
{
|
|
7753
8524
|
id: prev.length,
|
|
7754
|
-
component: /* @__PURE__ */
|
|
8525
|
+
component: /* @__PURE__ */ jsx20(ChatUserMessage, { children: /* @__PURE__ */ jsx20(Text19, { dimColor: true, children: text }) })
|
|
7755
8526
|
},
|
|
7756
8527
|
{
|
|
7757
8528
|
id: prev.length + 1,
|
|
7758
|
-
component: /* @__PURE__ */
|
|
8529
|
+
component: /* @__PURE__ */ jsx20(
|
|
7759
8530
|
SlashCommands_default,
|
|
7760
8531
|
{
|
|
7761
8532
|
input: text,
|
|
@@ -7774,17 +8545,15 @@ var AppComponent = ({ eventBus, sessionId }) => {
|
|
|
7774
8545
|
return;
|
|
7775
8546
|
}
|
|
7776
8547
|
setIsProcessing(true);
|
|
8548
|
+
turnStartedAtRef.current = Date.now();
|
|
7777
8549
|
setHistory((prev) => [
|
|
7778
8550
|
...prev,
|
|
7779
8551
|
{
|
|
7780
8552
|
id: prev.length,
|
|
7781
|
-
component: /* @__PURE__ */
|
|
7782
|
-
|
|
7783
|
-
|
|
7784
|
-
|
|
7785
|
-
command
|
|
7786
|
-
] })
|
|
7787
|
-
] })
|
|
8553
|
+
component: /* @__PURE__ */ jsx20(ChatUserMessage, { children: /* @__PURE__ */ jsxs19(Text19, { bold: true, color: "white", children: [
|
|
8554
|
+
"$ !",
|
|
8555
|
+
command
|
|
8556
|
+
] }) })
|
|
7788
8557
|
}
|
|
7789
8558
|
]);
|
|
7790
8559
|
Promise.resolve().then(() => (init_async_command(), async_command_exports)).then(async ({ runCommandAsync: runCommandAsync2 }) => {
|
|
@@ -7798,11 +8567,12 @@ Command ID: ${result.command_id}
|
|
|
7798
8567
|
Please use command_status to check the result and report back to the user.`;
|
|
7799
8568
|
agentInstance.current?.processTurn({ content: contextMessage });
|
|
7800
8569
|
} else {
|
|
8570
|
+
turnStartedAtRef.current = null;
|
|
7801
8571
|
setHistory((prev) => [
|
|
7802
8572
|
...prev,
|
|
7803
8573
|
{
|
|
7804
8574
|
id: prev.length,
|
|
7805
|
-
component: /* @__PURE__ */
|
|
8575
|
+
component: /* @__PURE__ */ jsxs19(Text19, { color: "red", children: [
|
|
7806
8576
|
"Failed to execute: ",
|
|
7807
8577
|
result.error || result.message
|
|
7808
8578
|
] })
|
|
@@ -7811,11 +8581,12 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
7811
8581
|
setIsProcessing(false);
|
|
7812
8582
|
}
|
|
7813
8583
|
} catch (err) {
|
|
8584
|
+
turnStartedAtRef.current = null;
|
|
7814
8585
|
setHistory((prev) => [
|
|
7815
8586
|
...prev,
|
|
7816
8587
|
{
|
|
7817
8588
|
id: prev.length,
|
|
7818
|
-
component: /* @__PURE__ */
|
|
8589
|
+
component: /* @__PURE__ */ jsxs19(Text19, { color: "red", children: [
|
|
7819
8590
|
"Error: ",
|
|
7820
8591
|
err.message
|
|
7821
8592
|
] })
|
|
@@ -7827,21 +8598,13 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
7827
8598
|
return;
|
|
7828
8599
|
}
|
|
7829
8600
|
setIsProcessing(true);
|
|
8601
|
+
turnStartedAtRef.current = Date.now();
|
|
7830
8602
|
const displayText = text.length > 1e4 ? text.substring(0, 1e4) + "..." : text;
|
|
7831
8603
|
setHistory((prev) => [
|
|
7832
8604
|
...prev,
|
|
7833
8605
|
{
|
|
7834
8606
|
id: prev.length,
|
|
7835
|
-
component: (
|
|
7836
|
-
// Uma única Box para o espaçamento
|
|
7837
|
-
/* @__PURE__ */ jsx17(Box17, { marginBottom: 1, children: /* @__PURE__ */ jsxs16(Text16, { color: "white", dimColor: true, children: [
|
|
7838
|
-
/* @__PURE__ */ jsxs16(Text16, { color: "white", children: [
|
|
7839
|
-
">",
|
|
7840
|
-
" "
|
|
7841
|
-
] }),
|
|
7842
|
-
displayText
|
|
7843
|
-
] }) })
|
|
7844
|
-
)
|
|
8607
|
+
component: /* @__PURE__ */ jsx20(ChatUserMessage, { children: /* @__PURE__ */ jsx20(Text19, { children: displayText }) })
|
|
7845
8608
|
}
|
|
7846
8609
|
]);
|
|
7847
8610
|
agentInstance.current.processTurn({ content: text });
|
|
@@ -7869,8 +8632,8 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
7869
8632
|
},
|
|
7870
8633
|
[]
|
|
7871
8634
|
);
|
|
7872
|
-
|
|
7873
|
-
setHistory([{ id: 0, component: /* @__PURE__ */
|
|
8635
|
+
useEffect7(() => {
|
|
8636
|
+
setHistory([{ id: 0, component: /* @__PURE__ */ jsx20(Header, { sessionId, workdir }) }]);
|
|
7874
8637
|
const initializeAgent = async () => {
|
|
7875
8638
|
try {
|
|
7876
8639
|
agentInstance.current = new Agent(sessionId, eventBus);
|
|
@@ -7890,6 +8653,20 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
7890
8653
|
};
|
|
7891
8654
|
const handleBackendMessage = (parsed) => {
|
|
7892
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
|
+
};
|
|
7893
8670
|
if (parsed.type === "done" || parsed.type === "error") {
|
|
7894
8671
|
setIsInitAgentActive(false);
|
|
7895
8672
|
}
|
|
@@ -7915,6 +8692,7 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
7915
8692
|
if (parsed.type === "done") {
|
|
7916
8693
|
if (parsed.status !== "awaiting_confirmation") {
|
|
7917
8694
|
setStatusMessage(null);
|
|
8695
|
+
appendTurnDurationIfAny();
|
|
7918
8696
|
}
|
|
7919
8697
|
setIsProcessing(false);
|
|
7920
8698
|
return;
|
|
@@ -7936,7 +8714,7 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
7936
8714
|
...prev,
|
|
7937
8715
|
{
|
|
7938
8716
|
id: prev.length,
|
|
7939
|
-
component: /* @__PURE__ */
|
|
8717
|
+
component: /* @__PURE__ */ jsx20(UpdateNotice_default, { message: msg })
|
|
7940
8718
|
}
|
|
7941
8719
|
]);
|
|
7942
8720
|
}
|
|
@@ -7950,25 +8728,14 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
7950
8728
|
}
|
|
7951
8729
|
let newComponent = null;
|
|
7952
8730
|
if (parsed.type === "debug") {
|
|
7953
|
-
newComponent = /* @__PURE__ */
|
|
8731
|
+
newComponent = /* @__PURE__ */ jsx20(ChatMeta, { children: parsed.message });
|
|
7954
8732
|
} else if (parsed.type === "protocol_violation") {
|
|
7955
|
-
newComponent = /* @__PURE__ */
|
|
7956
|
-
|
|
7957
|
-
{
|
|
7958
|
-
|
|
7959
|
-
borderColor: "yellow",
|
|
7960
|
-
flexDirection: "column",
|
|
7961
|
-
marginBottom: 1,
|
|
7962
|
-
paddingX: 1,
|
|
7963
|
-
children: [
|
|
7964
|
-
/* @__PURE__ */ jsx17(Text16, { color: "yellow", bold: true, children: "Protocol Violation" }),
|
|
7965
|
-
/* @__PURE__ */ jsx17(Text16, { color: "gray", children: parsed.content }),
|
|
7966
|
-
/* @__PURE__ */ jsx17(Text16, { color: "yellow", children: parsed.message })
|
|
7967
|
-
]
|
|
7968
|
-
}
|
|
7969
|
-
);
|
|
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
|
+
] }) });
|
|
7970
8737
|
} else if (parsed.type === "error") {
|
|
7971
|
-
newComponent = /* @__PURE__ */
|
|
8738
|
+
newComponent = /* @__PURE__ */ jsx20(
|
|
7972
8739
|
ErrorMessage_default,
|
|
7973
8740
|
{
|
|
7974
8741
|
message: parsed.message,
|
|
@@ -7978,7 +8745,7 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
7978
8745
|
);
|
|
7979
8746
|
} else if (parsed.type === "tool_call") {
|
|
7980
8747
|
const nextId3 = history.length;
|
|
7981
|
-
newComponent = /* @__PURE__ */
|
|
8748
|
+
newComponent = /* @__PURE__ */ jsx20(
|
|
7982
8749
|
ToolCallDisplay,
|
|
7983
8750
|
{
|
|
7984
8751
|
toolName: parsed.tool_name,
|
|
@@ -7987,7 +8754,7 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
7987
8754
|
}
|
|
7988
8755
|
);
|
|
7989
8756
|
} else if (parsed.type === "tool_result") {
|
|
7990
|
-
newComponent = /* @__PURE__ */
|
|
8757
|
+
newComponent = /* @__PURE__ */ jsx20(
|
|
7991
8758
|
ToolResultDisplay,
|
|
7992
8759
|
{
|
|
7993
8760
|
toolName: parsed.tool_name,
|
|
@@ -7995,18 +8762,11 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
7995
8762
|
}
|
|
7996
8763
|
);
|
|
7997
8764
|
} else if (parsed.type === "user_overlay") {
|
|
7998
|
-
newComponent = /* @__PURE__ */
|
|
7999
|
-
/* @__PURE__ */ jsxs16(Text16, { color: "magenta", children: [
|
|
8000
|
-
">",
|
|
8001
|
-
" "
|
|
8002
|
-
] }),
|
|
8003
|
-
parsed.payload
|
|
8004
|
-
] }) });
|
|
8765
|
+
newComponent = /* @__PURE__ */ jsx20(ChatUserMessage, { children: /* @__PURE__ */ jsx20(Text19, { dimColor: true, children: parsed.payload }) });
|
|
8005
8766
|
} else if (parsed.type === "reasoning") {
|
|
8006
|
-
newComponent = /* @__PURE__ */
|
|
8767
|
+
newComponent = /* @__PURE__ */ jsx20(ReasoningDisplay, { reasoning: parsed.content });
|
|
8007
8768
|
} else if (parsed.type === "log") {
|
|
8008
|
-
newComponent = /* @__PURE__ */
|
|
8009
|
-
"\u2139\uFE0F ",
|
|
8769
|
+
newComponent = /* @__PURE__ */ jsxs19(ChatMeta, { children: [
|
|
8010
8770
|
parsed.message,
|
|
8011
8771
|
parsed.payload ? `: ${parsed.payload}` : ""
|
|
8012
8772
|
] });
|
|
@@ -8014,10 +8774,25 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
8014
8774
|
newComponent = null;
|
|
8015
8775
|
}
|
|
8016
8776
|
if (newComponent) {
|
|
8017
|
-
setHistory((prev) =>
|
|
8018
|
-
|
|
8019
|
-
|
|
8020
|
-
|
|
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
|
+
});
|
|
8021
8796
|
}
|
|
8022
8797
|
} catch (error) {
|
|
8023
8798
|
}
|
|
@@ -8035,10 +8810,17 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
8035
8810
|
}, [eventBus, sessionId, handleConfirmation]);
|
|
8036
8811
|
const renderInteractiveComponent = () => {
|
|
8037
8812
|
if (mcpStatus !== "connected") {
|
|
8038
|
-
return
|
|
8813
|
+
return /* @__PURE__ */ jsx20(
|
|
8814
|
+
SessionInfoConnectingMCP_default,
|
|
8815
|
+
{
|
|
8816
|
+
sessionId,
|
|
8817
|
+
workdir,
|
|
8818
|
+
statusMessage
|
|
8819
|
+
}
|
|
8820
|
+
);
|
|
8039
8821
|
}
|
|
8040
8822
|
if (pendingConfirmation) {
|
|
8041
|
-
return /* @__PURE__ */
|
|
8823
|
+
return /* @__PURE__ */ jsx20(
|
|
8042
8824
|
ConfirmationPrompt,
|
|
8043
8825
|
{
|
|
8044
8826
|
toolCalls: pendingConfirmation,
|
|
@@ -8050,9 +8832,9 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
8050
8832
|
}
|
|
8051
8833
|
);
|
|
8052
8834
|
}
|
|
8053
|
-
return /* @__PURE__ */
|
|
8054
|
-
isProcessing && !pendingConfirmation && /* @__PURE__ */
|
|
8055
|
-
/* @__PURE__ */
|
|
8835
|
+
return /* @__PURE__ */ jsxs19(Box20, { flexDirection: "column", children: [
|
|
8836
|
+
isProcessing && !pendingConfirmation && /* @__PURE__ */ jsx20(WorkingTimer, { eventBus }),
|
|
8837
|
+
/* @__PURE__ */ jsx20(
|
|
8056
8838
|
InputPrompt,
|
|
8057
8839
|
{
|
|
8058
8840
|
onSubmit: handleSubmit,
|
|
@@ -8063,9 +8845,9 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
8063
8845
|
)
|
|
8064
8846
|
] });
|
|
8065
8847
|
};
|
|
8066
|
-
return /* @__PURE__ */
|
|
8067
|
-
/* @__PURE__ */
|
|
8068
|
-
/* @__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(
|
|
8069
8851
|
StreamingText,
|
|
8070
8852
|
{
|
|
8071
8853
|
eventBus,
|
|
@@ -8075,7 +8857,7 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
8075
8857
|
...prev,
|
|
8076
8858
|
{
|
|
8077
8859
|
id: prev.length,
|
|
8078
|
-
component: /* @__PURE__ */
|
|
8860
|
+
component: /* @__PURE__ */ jsx20(ReasoningDisplay, { reasoning })
|
|
8079
8861
|
}
|
|
8080
8862
|
]);
|
|
8081
8863
|
}
|
|
@@ -8085,7 +8867,7 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
8085
8867
|
renderInteractiveComponent()
|
|
8086
8868
|
] });
|
|
8087
8869
|
};
|
|
8088
|
-
var App =
|
|
8870
|
+
var App = memo12(AppComponent);
|
|
8089
8871
|
var App_default = App;
|
|
8090
8872
|
|
|
8091
8873
|
// src/app/ui/utils/terminalTitle.ts
|
|
@@ -8209,7 +8991,7 @@ async function runAgentMode() {
|
|
|
8209
8991
|
process.env.BLUMA_SANDBOX_NAME = String(envelope.metadata.sandbox_name);
|
|
8210
8992
|
}
|
|
8211
8993
|
}
|
|
8212
|
-
const eventBus = new
|
|
8994
|
+
const eventBus = new EventEmitter3();
|
|
8213
8995
|
const sessionId = envelope.session_id || envelope.message_id || uuidv46();
|
|
8214
8996
|
const uc = envelope.user_context;
|
|
8215
8997
|
const userContextInput = {
|
|
@@ -8341,13 +9123,13 @@ async function runAgentMode() {
|
|
|
8341
9123
|
function runCliMode() {
|
|
8342
9124
|
const BLUMA_TITLE = process.env.BLUMA_TITLE || "BluMa - NomadEngenuity";
|
|
8343
9125
|
startTitleKeeper(BLUMA_TITLE);
|
|
8344
|
-
const eventBus = new
|
|
9126
|
+
const eventBus = new EventEmitter3();
|
|
8345
9127
|
const sessionId = uuidv46();
|
|
8346
9128
|
const props = {
|
|
8347
9129
|
eventBus,
|
|
8348
9130
|
sessionId
|
|
8349
9131
|
};
|
|
8350
|
-
render(
|
|
9132
|
+
render(React12.createElement(App_default, props));
|
|
8351
9133
|
}
|
|
8352
9134
|
var argv = process.argv.slice(2);
|
|
8353
9135
|
if (argv[0] === "agent") {
|