@nomad-e/bluma-cli 0.0.32 → 0.0.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.js CHANGED
@@ -6,7 +6,7 @@ import { EventEmitter as EventEmitter2 } from "events";
6
6
  import { v4 as uuidv42 } from "uuid";
7
7
 
8
8
  // src/app/ui/App.tsx
9
- import { useState as useState4, useEffect as useEffect3, useRef, useCallback, memo as memo4 } from "react";
9
+ import { useState as useState5, useEffect as useEffect4, useRef as useRef2, useCallback, memo as memo4 } from "react";
10
10
  import { Box as Box15, Text as Text14, Static } from "ink";
11
11
 
12
12
  // src/app/ui/layout.tsx
@@ -115,7 +115,7 @@ function inputReducer(state, action, viewWidth) {
115
115
  };
116
116
  switch (action.type) {
117
117
  case "INPUT": {
118
- const cleanInput = action.payload.replace(/(\r\n|\n|\r)/gm, "");
118
+ const cleanInput = action.payload.replace(/(||)/gm, "");
119
119
  const newText = state.text.slice(0, state.cursorPosition) + cleanInput + state.text.slice(state.cursorPosition);
120
120
  const newCursorPosition = state.cursorPosition + cleanInput.length;
121
121
  const newViewStart = adjustView(newCursorPosition, state.viewStart);
@@ -140,6 +140,14 @@ function inputReducer(state, action, viewWidth) {
140
140
  case "SUBMIT": {
141
141
  return { text: "", cursorPosition: 0, viewStart: 0 };
142
142
  }
143
+ case "SET": {
144
+ const t = action.payload.text.replace(/(||)/gm, "");
145
+ const moveToEnd = action.payload.moveCursorToEnd ?? true;
146
+ const newText = t;
147
+ const newCursorPosition = moveToEnd ? newText.length : Math.min(state.cursorPosition, newText.length);
148
+ const newViewStart = adjustView(newCursorPosition, 0);
149
+ return { text: newText, cursorPosition: newCursorPosition, viewStart: newViewStart };
150
+ }
143
151
  default:
144
152
  return state;
145
153
  }
@@ -170,6 +178,13 @@ var useCustomInput = ({ onSubmit, viewWidth, isReadOnly, onInterrupt }) => {
170
178
  return dispatch({ type: "INPUT", payload: input });
171
179
  }
172
180
  if (key.return) {
181
+ if (globalThis.__BLUMA_AT_OPEN__) {
182
+ return;
183
+ }
184
+ if (globalThis.__BLUMA_SUPPRESS_SUBMIT__) {
185
+ globalThis.__BLUMA_SUPPRESS_SUBMIT__ = false;
186
+ return;
187
+ }
173
188
  if (state.text.trim().length > 0) {
174
189
  onSubmit(state.text);
175
190
  dispatch({ type: "SUBMIT" });
@@ -188,12 +203,20 @@ var useCustomInput = ({ onSubmit, viewWidth, isReadOnly, onInterrupt }) => {
188
203
  return {
189
204
  text: state.text,
190
205
  cursorPosition: state.cursorPosition,
191
- viewStart: state.viewStart
206
+ viewStart: state.viewStart,
207
+ setText: (t, pos) => {
208
+ if (typeof pos === "number") {
209
+ dispatch({ type: "SET", payload: { text: t, moveCursorToEnd: false, cursorPosition: pos } });
210
+ } else {
211
+ dispatch({ type: "SET", payload: { text: t, moveCursorToEnd: true } });
212
+ }
213
+ },
214
+ setCursor: (pos) => dispatch({ type: "SET_CURSOR", payload: pos })
192
215
  };
193
216
  };
194
217
 
195
218
  // src/app/ui/components/InputPrompt.tsx
196
- import { useEffect, useMemo, useState } from "react";
219
+ import { useEffect as useEffect2, useMemo, useState as useState2 } from "react";
197
220
  import { EventEmitter } from "events";
198
221
 
199
222
  // src/app/ui/utils/slashRegistry.ts
@@ -242,16 +265,160 @@ var filterSlashCommands = (query) => {
242
265
  return scored.map((s) => s.cmd);
243
266
  };
244
267
 
268
+ // src/app/ui/hooks/useAtCompletion.ts
269
+ import { useEffect, useRef, useState } from "react";
270
+ import fs from "fs";
271
+ import path from "path";
272
+ var MAX_RESULTS = 50;
273
+ var DEFAULT_RECURSIVE_DEPTH = 2;
274
+ function listPathSuggestions(baseDir, pattern) {
275
+ const raw = pattern || "";
276
+ const patternEndsWithSlash = raw.endsWith("/");
277
+ const relDir = raw.replace(/^\/+|\/+$/g, "");
278
+ const filterPrefix = patternEndsWithSlash ? "" : relDir.split("/").slice(-1)[0] || "";
279
+ const listDir = path.resolve(baseDir, relDir || ".");
280
+ const results = [];
281
+ const IGNORED_DIRS = ["node_modules", ".git", ".venv", "dist", "build"];
282
+ const IGNORED_EXTS = [".pyc", ".class", ".o", ".map", ".log", ".tmp"];
283
+ function isIgnoredName(name) {
284
+ if (!name) return false;
285
+ if (IGNORED_DIRS.includes(name)) return true;
286
+ if (name.startsWith(".")) return true;
287
+ return false;
288
+ }
289
+ function isIgnoredFile(name) {
290
+ if (!name) return false;
291
+ for (const e of IGNORED_EXTS) if (name.endsWith(e)) return true;
292
+ return false;
293
+ }
294
+ function pushEntry(entryPath, label, isDir) {
295
+ if (results.length >= MAX_RESULTS) return;
296
+ const clean = label.split(path.sep).join("/").replace(/[]+/g, "");
297
+ results.push({ label: clean + (isDir ? "/" : ""), fullPath: entryPath, isDir });
298
+ }
299
+ try {
300
+ if (raw.length === 0 || patternEndsWithSlash) {
301
+ const queue = [{ dir: listDir, depth: 0, rel: relDir }];
302
+ while (queue.length && results.length < MAX_RESULTS) {
303
+ const node = queue.shift();
304
+ try {
305
+ const entries = fs.readdirSync(node.dir, { withFileTypes: true });
306
+ for (const entry of entries) {
307
+ if (isIgnoredName(entry.name)) continue;
308
+ const entryAbs = path.join(node.dir, entry.name);
309
+ const entryRel = node.rel ? path.posix.join(node.rel, entry.name) : entry.name;
310
+ if (entryRel.split("/").includes("node_modules")) continue;
311
+ if (!entry.isDirectory() && isIgnoredFile(entry.name)) continue;
312
+ pushEntry(entryAbs, entryRel, entry.isDirectory());
313
+ if (entry.isDirectory() && node.depth < DEFAULT_RECURSIVE_DEPTH) {
314
+ queue.push({ dir: entryAbs, depth: node.depth + 1, rel: node.rel ? node.rel + "/" + entry.name : entry.name + "/" });
315
+ }
316
+ if (results.length >= MAX_RESULTS) break;
317
+ }
318
+ } catch (e) {
319
+ }
320
+ }
321
+ } else {
322
+ const entries = fs.readdirSync(listDir, { withFileTypes: true });
323
+ for (const entry of entries) {
324
+ if (filterPrefix && !entry.name.startsWith(filterPrefix)) continue;
325
+ if (isIgnoredName(entry.name)) continue;
326
+ if (!entry.isDirectory() && isIgnoredFile(entry.name)) continue;
327
+ const entryAbs = path.join(listDir, entry.name);
328
+ const label = relDir ? path.posix.join(relDir, entry.name) : entry.name;
329
+ pushEntry(entryAbs, label, entry.isDirectory());
330
+ if (results.length >= MAX_RESULTS) break;
331
+ }
332
+ }
333
+ } catch (e) {
334
+ }
335
+ return results.slice(0, MAX_RESULTS);
336
+ }
337
+ function useAtCompletion({
338
+ cwd,
339
+ text,
340
+ cursorPosition,
341
+ setText
342
+ }) {
343
+ const [open, setOpen] = useState(false);
344
+ const [selected, setSelected] = useState(0);
345
+ const [suggestions, setSuggestions] = useState([]);
346
+ const lastQuery = useRef("");
347
+ function scanForAt(text2, pos) {
348
+ const before = text2.slice(0, pos);
349
+ const m = before.match(/@([\w\/.\-_]*)$/);
350
+ if (!m) return { pattern: null, insertStart: -1 };
351
+ return { pattern: m[1] || "", insertStart: m.index + 1 };
352
+ }
353
+ function update(newText, newCursor) {
354
+ const res = scanForAt(newText, newCursor);
355
+ if (res.pattern !== null && res.pattern.length >= 0) {
356
+ setOpen(true);
357
+ globalThis.__BLUMA_AT_OPEN__ = true;
358
+ const suggs = listPathSuggestions(cwd, res.pattern);
359
+ setSuggestions(suggs);
360
+ setSelected(0);
361
+ lastQuery.current = res.pattern;
362
+ } else {
363
+ setOpen(false);
364
+ globalThis.__BLUMA_AT_OPEN__ = false;
365
+ setSuggestions([]);
366
+ }
367
+ }
368
+ useEffect(() => {
369
+ update(text, cursorPosition);
370
+ }, [text, cursorPosition, cwd]);
371
+ function insertAtSelection() {
372
+ if (!open || !suggestions[selected]) return;
373
+ const res = scanForAt(text, cursorPosition);
374
+ if (!res || res.insertStart < 0) return;
375
+ let chosen = suggestions[selected].label;
376
+ const isDir = suggestions[selected].isDir;
377
+ chosen = chosen.replace(/\\/g, "/").replace(/\|/g, "");
378
+ let insertVal = chosen;
379
+ if (insertVal.includes("/")) {
380
+ insertVal = insertVal.replace(/\/+$/g, "");
381
+ const parts = insertVal.split("/");
382
+ insertVal = parts[parts.length - 1];
383
+ }
384
+ if (isDir && !insertVal.endsWith("/")) insertVal = insertVal + "/";
385
+ const pattern = res.pattern || "";
386
+ const lastSlash = pattern.lastIndexOf("/");
387
+ const segmentOffset = lastSlash >= 0 ? lastSlash + 1 : 0;
388
+ const segmentStart = res.insertStart + segmentOffset;
389
+ const before = text.slice(0, segmentStart);
390
+ const after = text.slice(cursorPosition);
391
+ const newText = before + insertVal + after;
392
+ setText(newText + (isDir ? "" : " "), true);
393
+ if (isDir) {
394
+ setOpen(false);
395
+ setSuggestions([]);
396
+ setTimeout(() => {
397
+ setOpen(true);
398
+ update(newText, newText.length);
399
+ }, 0);
400
+ } else {
401
+ setOpen(false);
402
+ setSuggestions([]);
403
+ }
404
+ }
405
+ function close() {
406
+ setOpen(false);
407
+ setSuggestions([]);
408
+ }
409
+ return { open, suggestions, selected, setSelected, insertAtSelection, close, update };
410
+ }
411
+
245
412
  // src/app/ui/components/InputPrompt.tsx
246
413
  import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
247
414
  var uiEventBus = global.__bluma_ui_eventbus__ || new EventEmitter();
248
415
  global.__bluma_ui_eventbus__ = uiEventBus;
249
416
  var InputPrompt = ({ onSubmit, isReadOnly, onInterrupt, disableWhileProcessing = false }) => {
250
417
  const { stdout } = useStdout();
251
- const [viewWidth, setViewWidth] = useState(() => stdout.columns - 6);
252
- const [slashOpen, setSlashOpen] = useState(false);
253
- const [slashIndex, setSlashIndex] = useState(0);
254
- useEffect(() => {
418
+ const [viewWidth, setViewWidth] = useState2(() => stdout.columns - 6);
419
+ const [slashOpen, setSlashOpen] = useState2(false);
420
+ const [slashIndex, setSlashIndex] = useState2(0);
421
+ useEffect2(() => {
255
422
  const onResize = () => setViewWidth(stdout.columns - 6);
256
423
  stdout.on("resize", onResize);
257
424
  return () => {
@@ -263,7 +430,7 @@ var InputPrompt = ({ onSubmit, isReadOnly, onInterrupt, disableWhileProcessing =
263
430
  if (isReadOnly) {
264
431
  if (trimmed.length > 0) {
265
432
  const payload = trimmed;
266
- uiEventBus.emit("dev_overlay", { kind: "message", payload, ts: Date.now() });
433
+ uiEventBus.emit("user_overlay", { kind: "message", payload, ts: Date.now() });
267
434
  return;
268
435
  }
269
436
  return;
@@ -271,9 +438,11 @@ var InputPrompt = ({ onSubmit, isReadOnly, onInterrupt, disableWhileProcessing =
271
438
  onSubmit(value);
272
439
  };
273
440
  const effectiveReadOnly = isReadOnly;
274
- const { text, cursorPosition, viewStart } = useCustomInput({
441
+ const { text, cursorPosition, viewStart, setText } = useCustomInput({
442
+ // Sobrepõe a lógica padrão: nunca submete se autocomplete aberto
275
443
  onSubmit: (value) => {
276
444
  if (disableWhileProcessing && isReadOnly) return;
445
+ if (pathAutocomplete.open) return;
277
446
  permissiveOnSubmit(value);
278
447
  },
279
448
  viewWidth,
@@ -294,7 +463,7 @@ var InputPrompt = ({ onSubmit, isReadOnly, onInterrupt, disableWhileProcessing =
294
463
  if (!slashQuery) return [];
295
464
  return filterSlashCommands(slashQuery);
296
465
  }, [slashQuery]);
297
- useEffect(() => {
466
+ useEffect2(() => {
298
467
  if (isReadOnly) {
299
468
  setSlashOpen(false);
300
469
  return;
@@ -317,12 +486,51 @@ var InputPrompt = ({ onSubmit, isReadOnly, onInterrupt, disableWhileProcessing =
317
486
  if (choice) {
318
487
  const cmd = choice.name;
319
488
  setSlashOpen(false);
320
- permissiveOnSubmit(cmd);
489
+ try {
490
+ setText(`${cmd} `, true);
491
+ } catch (e) {
492
+ permissiveOnSubmit(`${cmd} `);
493
+ }
321
494
  }
322
495
  } else if (key.escape) {
323
496
  setSlashOpen(false);
324
497
  }
325
498
  }, { isActive: slashOpen });
499
+ const cwd = process.cwd();
500
+ const pathAutocomplete = useAtCompletion({ cwd, text, cursorPosition, setText });
501
+ useInput2((input, key) => {
502
+ if (pathAutocomplete.open) {
503
+ if (key.downArrow) {
504
+ pathAutocomplete.setSelected((i) => Math.min(i + 1, Math.max(0, pathAutocomplete.suggestions.length - 1)));
505
+ return;
506
+ } else if (key.upArrow) {
507
+ pathAutocomplete.setSelected((i) => Math.max(i - 1, 0));
508
+ return;
509
+ } else if (key.return || key.tab) {
510
+ const selected = pathAutocomplete.suggestions[pathAutocomplete.selected];
511
+ if (selected) {
512
+ const before = text.slice(0, cursorPosition);
513
+ const m = before.match(/@([\w\/.\-_]*)$/);
514
+ if (m) {
515
+ globalThis.__BLUMA_SUPPRESS_SUBMIT__ = true;
516
+ pathAutocomplete.insertAtSelection();
517
+ }
518
+ }
519
+ return;
520
+ } else if (key.escape) {
521
+ pathAutocomplete.close();
522
+ return;
523
+ }
524
+ return;
525
+ }
526
+ }, { isActive: true });
527
+ function canSubmitGivenCursor() {
528
+ if (visibleCursorPosition < visibleText.length) {
529
+ return visibleText[visibleCursorPosition] === " ";
530
+ } else {
531
+ return false;
532
+ }
533
+ }
326
534
  return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
327
535
  disableWhileProcessing ? (
328
536
  // Modo bloqueado visualmente, mantendo hooks estáveis
@@ -343,6 +551,22 @@ var InputPrompt = ({ onSubmit, isReadOnly, onInterrupt, disableWhileProcessing =
343
551
  /* @__PURE__ */ jsx2(Text2, { inverse: true, children: cursorGlyph }),
344
552
  showPlaceholder ? /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: placeholder }) : /* @__PURE__ */ jsx2(Text2, { children: textAfterCursor })
345
553
  ] }) }),
554
+ pathAutocomplete.open && pathAutocomplete.suggestions.length > 0 && (() => {
555
+ const VISIBLE = 7;
556
+ const total = pathAutocomplete.suggestions.length;
557
+ const sel = Math.max(0, Math.min(pathAutocomplete.selected, total - 1));
558
+ let start = Math.max(0, sel - Math.floor(VISIBLE / 2));
559
+ if (start + VISIBLE > total) start = Math.max(0, total - VISIBLE);
560
+ const windowItems = pathAutocomplete.suggestions.slice(start, start + VISIBLE);
561
+ return /* @__PURE__ */ jsx2(Box2, { flexDirection: "column", marginTop: 1, height: Math.min(VISIBLE, total), overflowY: "auto", children: windowItems.map((s, idx) => {
562
+ const realIdx = start + idx;
563
+ const isSelected = realIdx === pathAutocomplete.selected;
564
+ return /* @__PURE__ */ jsxs2(Box2, { paddingLeft: 1, paddingY: 0, children: [
565
+ /* @__PURE__ */ jsx2(Text2, { color: isSelected ? "cyan" : "gray", children: isSelected ? "\u276F " : " " }),
566
+ /* @__PURE__ */ jsx2(Text2, { color: isSelected ? "cyan" : "white", bold: isSelected, dimColor: !isSelected, children: s.label })
567
+ ] }, s.fullPath);
568
+ }) });
569
+ })(),
346
570
  slashOpen && slashSuggestions.length > 0 && /* @__PURE__ */ jsx2(Box2, { flexDirection: "column", marginTop: 1, children: slashSuggestions.map((s, idx) => {
347
571
  const isSelected = idx === slashIndex;
348
572
  return /* @__PURE__ */ jsxs2(Box2, { paddingLeft: 1, paddingY: 0, children: [
@@ -369,7 +593,7 @@ var InputPrompt = ({ onSubmit, isReadOnly, onInterrupt, disableWhileProcessing =
369
593
  import { Box as Box6, Text as Text6 } from "ink";
370
594
 
371
595
  // src/app/ui/InteractiveMenu.tsx
372
- import { useState as useState2, memo } from "react";
596
+ import { useState as useState3, memo } from "react";
373
597
  import { Box as Box3, Text as Text3, useInput as useInput3 } from "ink";
374
598
  import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
375
599
  var InteractiveMenuComponent = ({ onDecision }) => {
@@ -378,7 +602,7 @@ var InteractiveMenuComponent = ({ onDecision }) => {
378
602
  { label: "2. No, cancel this command", value: "decline" },
379
603
  { label: "3. Always allow this type of command", value: "accept_always" }
380
604
  ];
381
- const [selectedOption, setSelectedOption] = useState2(0);
605
+ const [selectedOption, setSelectedOption] = useState3(0);
382
606
  useInput3((input, key) => {
383
607
  if (key.upArrow) {
384
608
  setSelectedOption((prev) => prev > 0 ? prev - 1 : options.length - 1);
@@ -419,7 +643,7 @@ var InteractiveMenu = memo(InteractiveMenuComponent);
419
643
 
420
644
  // src/app/ui/components/promptRenderers.tsx
421
645
  import { Box as Box5, Text as Text5 } from "ink";
422
- import path from "path";
646
+ import path2 from "path";
423
647
 
424
648
  // src/app/ui/components/SimpleDiff.tsx
425
649
  import { Box as Box4, Text as Text4 } from "ink";
@@ -458,7 +682,7 @@ var SimpleDiff = ({ text, maxHeight }) => {
458
682
  // src/app/ui/components/promptRenderers.tsx
459
683
  import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
460
684
  var getBasePath = (filePath) => {
461
- return path.basename(filePath);
685
+ return path2.basename(filePath);
462
686
  };
463
687
  var renderShellCommand = ({
464
688
  toolCall
@@ -626,12 +850,12 @@ var ConfirmationPrompt = ({ toolCalls, preview, onDecision }) => {
626
850
  // src/app/agent/agent.ts
627
851
  import OpenAI from "openai";
628
852
  import * as dotenv from "dotenv";
629
- import path8 from "path";
853
+ import path9 from "path";
630
854
  import os6 from "os";
631
855
 
632
856
  // src/app/agent/tool_invoker.ts
633
- import { promises as fs5 } from "fs";
634
- import path4 from "path";
857
+ import { promises as fs6 } from "fs";
858
+ import path5 from "path";
635
859
  import { fileURLToPath } from "url";
636
860
 
637
861
  // src/app/agent/tools/natives/shell_command.ts
@@ -699,8 +923,8 @@ ${stderr.trim()}`.trim();
699
923
  }
700
924
 
701
925
  // src/app/agent/tools/natives/edit.ts
702
- import path2 from "path";
703
- import { promises as fs } from "fs";
926
+ import path3 from "path";
927
+ import { promises as fs2 } from "fs";
704
928
  import { diffLines } from "diff";
705
929
  function unescapeLlmString(inputString) {
706
930
  return inputString.replace(/\\n/g, "\n").replace(/\\t/g, " ").replace(/\\r/g, "\r").replace(/\\"/g, '"').replace(/\\'/g, "'").replace(/\\\\/g, "\\");
@@ -736,7 +960,7 @@ async function calculateEdit(filePath, oldString, newString, expectedReplacement
736
960
  let finalOldString = oldString.replace(/\r\n/g, "\n");
737
961
  let occurrences = 0;
738
962
  try {
739
- currentContent = await fs.readFile(filePath, "utf-8");
963
+ currentContent = await fs2.readFile(filePath, "utf-8");
740
964
  currentContent = currentContent.replace(/\r\n/g, "\n");
741
965
  } catch (e) {
742
966
  if (e.code !== "ENOENT") {
@@ -792,7 +1016,7 @@ function createDiff(filename, oldContent, newContent) {
792
1016
  }
793
1017
  async function editTool(args) {
794
1018
  const { file_path, old_string, new_string, expected_replacements = 1 } = args;
795
- if (!path2.isAbsolute(file_path)) {
1019
+ if (!path3.isAbsolute(file_path)) {
796
1020
  return { success: false, error: `Invalid parameters: file_path must be absolute.`, file_path };
797
1021
  }
798
1022
  if (file_path.includes("..")) {
@@ -808,10 +1032,10 @@ async function editTool(args) {
808
1032
  file_path
809
1033
  };
810
1034
  }
811
- await fs.mkdir(path2.dirname(file_path), { recursive: true });
812
- await fs.writeFile(file_path, editData.newContent, "utf-8");
813
- const relativePath = path2.relative(process.cwd(), file_path);
814
- const filename = path2.basename(file_path);
1035
+ await fs2.mkdir(path3.dirname(file_path), { recursive: true });
1036
+ await fs2.writeFile(file_path, editData.newContent, "utf-8");
1037
+ const relativePath = path3.relative(process.cwd(), file_path);
1038
+ const filename = path3.basename(file_path);
815
1039
  if (editData.isNewFile) {
816
1040
  return {
817
1041
  success: true,
@@ -846,10 +1070,10 @@ ${finalDiff}`,
846
1070
 
847
1071
  // src/app/agent/tools/natives/message.ts
848
1072
  import { v4 as uuidv4 } from "uuid";
849
- function messageNotifyDev(args) {
1073
+ function messageNotifyuser(args) {
850
1074
  const { text_markdown } = args;
851
1075
  const notification = {
852
- type: "message_notify_dev",
1076
+ type: "message_notify_user",
853
1077
  id: `notify_${uuidv4()}`,
854
1078
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
855
1079
  content: {
@@ -863,8 +1087,8 @@ function messageNotifyDev(args) {
863
1087
  }
864
1088
 
865
1089
  // src/app/agent/tools/natives/ls.ts
866
- import { promises as fs2 } from "fs";
867
- import path3 from "path";
1090
+ import { promises as fs3 } from "fs";
1091
+ import path4 from "path";
868
1092
  var DEFAULT_IGNORE = /* @__PURE__ */ new Set([
869
1093
  ".git",
870
1094
  ".gitignore",
@@ -892,8 +1116,8 @@ async function ls(args) {
892
1116
  max_depth
893
1117
  } = args;
894
1118
  try {
895
- const basePath = path3.resolve(directory_path);
896
- if (!(await fs2.stat(basePath)).isDirectory()) {
1119
+ const basePath = path4.resolve(directory_path);
1120
+ if (!(await fs3.stat(basePath)).isDirectory()) {
897
1121
  throw new Error(`Directory '${directory_path}' not found.`);
898
1122
  }
899
1123
  const allIgnorePatterns = /* @__PURE__ */ new Set([...DEFAULT_IGNORE, ...ignore_patterns]);
@@ -902,11 +1126,11 @@ async function ls(args) {
902
1126
  const allDirs = [];
903
1127
  const walk = async (currentDir, currentDepth) => {
904
1128
  if (max_depth !== void 0 && currentDepth > max_depth) return;
905
- const entries = await fs2.readdir(currentDir, { withFileTypes: true });
1129
+ const entries = await fs3.readdir(currentDir, { withFileTypes: true });
906
1130
  for (const entry of entries) {
907
1131
  const entryName = entry.name;
908
- const fullPath = path3.join(currentDir, entryName);
909
- const posixPath = fullPath.split(path3.sep).join("/");
1132
+ const fullPath = path4.join(currentDir, entryName);
1133
+ const posixPath = fullPath.split(path4.sep).join("/");
910
1134
  const isHidden = entryName.startsWith(".");
911
1135
  if (allIgnorePatterns.has(entryName) || isHidden && !show_hidden) {
912
1136
  continue;
@@ -917,7 +1141,7 @@ async function ls(args) {
917
1141
  await walk(fullPath, currentDepth + 1);
918
1142
  }
919
1143
  } else if (entry.isFile()) {
920
- if (!normalizedExtensions || normalizedExtensions.includes(path3.extname(entryName).toLowerCase())) {
1144
+ if (!normalizedExtensions || normalizedExtensions.includes(path4.extname(entryName).toLowerCase())) {
921
1145
  allFiles.push(posixPath);
922
1146
  }
923
1147
  }
@@ -928,7 +1152,7 @@ async function ls(args) {
928
1152
  allDirs.sort();
929
1153
  return {
930
1154
  success: true,
931
- path: basePath.split(path3.sep).join("/"),
1155
+ path: basePath.split(path4.sep).join("/"),
932
1156
  recursive,
933
1157
  total_files: allFiles.length,
934
1158
  total_directories: allDirs.length,
@@ -944,17 +1168,17 @@ async function ls(args) {
944
1168
  }
945
1169
 
946
1170
  // src/app/agent/tools/natives/readLines.ts
947
- import { promises as fs3 } from "fs";
1171
+ import { promises as fs4 } from "fs";
948
1172
  async function readLines(args) {
949
1173
  const { filepath, start_line, end_line } = args;
950
1174
  try {
951
- if (!(await fs3.stat(filepath)).isFile()) {
1175
+ if (!(await fs4.stat(filepath)).isFile()) {
952
1176
  throw new Error(`File '${filepath}' not found or is not a file.`);
953
1177
  }
954
1178
  if (start_line < 1 || end_line < start_line) {
955
1179
  throw new Error("Invalid line range. start_line must be >= 1 and end_line must be >= start_line.");
956
1180
  }
957
- const fileContent = await fs3.readFile(filepath, "utf-8");
1181
+ const fileContent = await fs4.readFile(filepath, "utf-8");
958
1182
  const lines = fileContent.split("\n");
959
1183
  const total_lines = lines.length;
960
1184
  const startIndex = start_line - 1;
@@ -982,12 +1206,12 @@ async function readLines(args) {
982
1206
 
983
1207
  // src/app/agent/tools/natives/count_lines.ts
984
1208
  import { createReadStream } from "fs";
985
- import { promises as fs4 } from "fs";
1209
+ import { promises as fs5 } from "fs";
986
1210
  import readline from "readline";
987
1211
  async function countLines(args) {
988
1212
  const { filepath } = args;
989
1213
  try {
990
- if (!(await fs4.stat(filepath)).isFile()) {
1214
+ if (!(await fs5.stat(filepath)).isFile()) {
991
1215
  throw new Error(`File '${filepath}' not found or is not a file.`);
992
1216
  }
993
1217
  const fileStream = createReadStream(filepath);
@@ -1022,9 +1246,9 @@ var ToolInvoker = class {
1022
1246
  async initialize() {
1023
1247
  try {
1024
1248
  const __filename = fileURLToPath(import.meta.url);
1025
- const __dirname = path4.dirname(__filename);
1026
- const configPath = path4.resolve(__dirname, "config", "native_tools.json");
1027
- const fileContent = await fs5.readFile(configPath, "utf-8");
1249
+ const __dirname = path5.dirname(__filename);
1250
+ const configPath = path5.resolve(__dirname, "config", "native_tools.json");
1251
+ const fileContent = await fs6.readFile(configPath, "utf-8");
1028
1252
  const config2 = JSON.parse(fileContent);
1029
1253
  this.toolDefinitions = config2.nativeTools;
1030
1254
  } catch (error) {
@@ -1039,7 +1263,7 @@ var ToolInvoker = class {
1039
1263
  registerTools() {
1040
1264
  this.toolImplementations.set("shell_command", shellCommand);
1041
1265
  this.toolImplementations.set("edit_tool", editTool);
1042
- this.toolImplementations.set("message_notify_dev", messageNotifyDev);
1266
+ this.toolImplementations.set("message_notify_user", messageNotifyuser);
1043
1267
  this.toolImplementations.set("ls_tool", ls);
1044
1268
  this.toolImplementations.set("count_file_lines", countLines);
1045
1269
  this.toolImplementations.set("read_file_lines", readLines);
@@ -1073,8 +1297,8 @@ var ToolInvoker = class {
1073
1297
  };
1074
1298
 
1075
1299
  // src/app/agent/tools/mcp/mcp_client.ts
1076
- import { promises as fs6 } from "fs";
1077
- import path5 from "path";
1300
+ import { promises as fs7 } from "fs";
1301
+ import path6 from "path";
1078
1302
  import os2 from "os";
1079
1303
  import { fileURLToPath as fileURLToPath2 } from "url";
1080
1304
  import { Client } from "@modelcontextprotocol/sdk/client/index.js";
@@ -1102,9 +1326,9 @@ var MCPClient = class {
1102
1326
  });
1103
1327
  }
1104
1328
  const __filename = fileURLToPath2(import.meta.url);
1105
- const __dirname = path5.dirname(__filename);
1106
- const defaultConfigPath = path5.resolve(__dirname, "config", "bluma-mcp.json");
1107
- const userConfigPath = path5.join(os2.homedir(), ".bluma-cli", "bluma-mcp.json");
1329
+ const __dirname = path6.dirname(__filename);
1330
+ const defaultConfigPath = path6.resolve(__dirname, "config", "bluma-mcp.json");
1331
+ const userConfigPath = path6.join(os2.homedir(), ".bluma-cli", "bluma-mcp.json");
1108
1332
  const defaultConfig = await this.loadMcpConfig(defaultConfigPath, "Default");
1109
1333
  const userConfig = await this.loadMcpConfig(userConfigPath, "User");
1110
1334
  const mergedConfig = {
@@ -1138,7 +1362,7 @@ var MCPClient = class {
1138
1362
  }
1139
1363
  async loadMcpConfig(configPath, configType) {
1140
1364
  try {
1141
- const fileContent = await fs6.readFile(configPath, "utf-8");
1365
+ const fileContent = await fs7.readFile(configPath, "utf-8");
1142
1366
  const processedContent = this.replaceEnvPlaceholders(fileContent);
1143
1367
  return JSON.parse(processedContent);
1144
1368
  } catch (error) {
@@ -1273,12 +1497,12 @@ var AdvancedFeedbackSystem = class {
1273
1497
  };
1274
1498
 
1275
1499
  // src/app/agent/bluma/core/bluma.ts
1276
- import path7 from "path";
1500
+ import path8 from "path";
1277
1501
 
1278
1502
  // src/app/agent/session_manger/session_manager.ts
1279
- import path6 from "path";
1503
+ import path7 from "path";
1280
1504
  import os3 from "os";
1281
- import { promises as fs7 } from "fs";
1505
+ import { promises as fs8 } from "fs";
1282
1506
  var fileLocks = /* @__PURE__ */ new Map();
1283
1507
  async function withFileLock(file, fn) {
1284
1508
  const prev = fileLocks.get(file) || Promise.resolve();
@@ -1296,13 +1520,13 @@ async function withFileLock(file, fn) {
1296
1520
  function expandHome(p) {
1297
1521
  if (!p) return p;
1298
1522
  if (p.startsWith("~")) {
1299
- return path6.join(os3.homedir(), p.slice(1));
1523
+ return path7.join(os3.homedir(), p.slice(1));
1300
1524
  }
1301
1525
  return p;
1302
1526
  }
1303
1527
  function getPreferredAppDir() {
1304
- const fixed = path6.join(os3.homedir(), ".bluma-cli");
1305
- return path6.resolve(expandHome(fixed));
1528
+ const fixed = path7.join(os3.homedir(), ".bluma-cli");
1529
+ return path7.resolve(expandHome(fixed));
1306
1530
  }
1307
1531
  async function safeRenameWithRetry(src, dest, maxRetries = 6) {
1308
1532
  let attempt = 0;
@@ -1310,7 +1534,7 @@ async function safeRenameWithRetry(src, dest, maxRetries = 6) {
1310
1534
  const isWin = process.platform === "win32";
1311
1535
  while (attempt <= maxRetries) {
1312
1536
  try {
1313
- await fs7.rename(src, dest);
1537
+ await fs8.rename(src, dest);
1314
1538
  return;
1315
1539
  } catch (e) {
1316
1540
  lastErr = e;
@@ -1323,9 +1547,9 @@ async function safeRenameWithRetry(src, dest, maxRetries = 6) {
1323
1547
  }
1324
1548
  }
1325
1549
  try {
1326
- const data = await fs7.readFile(src);
1327
- await fs7.writeFile(dest, data);
1328
- await fs7.unlink(src).catch(() => {
1550
+ const data = await fs8.readFile(src);
1551
+ await fs8.writeFile(dest, data);
1552
+ await fs8.unlink(src).catch(() => {
1329
1553
  });
1330
1554
  return;
1331
1555
  } catch (fallbackErr) {
@@ -1334,16 +1558,16 @@ async function safeRenameWithRetry(src, dest, maxRetries = 6) {
1334
1558
  }
1335
1559
  async function ensureSessionDir() {
1336
1560
  const appDir = getPreferredAppDir();
1337
- const sessionDir = path6.join(appDir, "sessions");
1338
- await fs7.mkdir(sessionDir, { recursive: true });
1561
+ const sessionDir = path7.join(appDir, "sessions");
1562
+ await fs8.mkdir(sessionDir, { recursive: true });
1339
1563
  return sessionDir;
1340
1564
  }
1341
1565
  async function loadOrcreateSession(sessionId2) {
1342
1566
  const sessionDir = await ensureSessionDir();
1343
- const sessionFile = path6.join(sessionDir, `${sessionId2}.json`);
1567
+ const sessionFile = path7.join(sessionDir, `${sessionId2}.json`);
1344
1568
  try {
1345
- await fs7.access(sessionFile);
1346
- const fileContent = await fs7.readFile(sessionFile, "utf-8");
1569
+ await fs8.access(sessionFile);
1570
+ const fileContent = await fs8.readFile(sessionFile, "utf-8");
1347
1571
  const sessionData = JSON.parse(fileContent);
1348
1572
  return [sessionFile, sessionData.conversation_history || []];
1349
1573
  } catch (error) {
@@ -1352,7 +1576,7 @@ async function loadOrcreateSession(sessionId2) {
1352
1576
  created_at: (/* @__PURE__ */ new Date()).toISOString(),
1353
1577
  conversation_history: []
1354
1578
  };
1355
- await fs7.writeFile(sessionFile, JSON.stringify(newSessionData, null, 2), "utf-8");
1579
+ await fs8.writeFile(sessionFile, JSON.stringify(newSessionData, null, 2), "utf-8");
1356
1580
  return [sessionFile, []];
1357
1581
  }
1358
1582
  }
@@ -1360,12 +1584,12 @@ async function saveSessionHistory(sessionFile, history) {
1360
1584
  await withFileLock(sessionFile, async () => {
1361
1585
  let sessionData;
1362
1586
  try {
1363
- const dir = path6.dirname(sessionFile);
1364
- await fs7.mkdir(dir, { recursive: true });
1587
+ const dir = path7.dirname(sessionFile);
1588
+ await fs8.mkdir(dir, { recursive: true });
1365
1589
  } catch {
1366
1590
  }
1367
1591
  try {
1368
- const fileContent = await fs7.readFile(sessionFile, "utf-8");
1592
+ const fileContent = await fs8.readFile(sessionFile, "utf-8");
1369
1593
  sessionData = JSON.parse(fileContent);
1370
1594
  } catch (error) {
1371
1595
  const code = error && error.code;
@@ -1376,14 +1600,14 @@ async function saveSessionHistory(sessionFile, history) {
1376
1600
  console.warn(`An unknown error occurred while reading ${sessionFile}. Re-initializing.`, error);
1377
1601
  }
1378
1602
  }
1379
- const sessionId2 = path6.basename(sessionFile, ".json");
1603
+ const sessionId2 = path7.basename(sessionFile, ".json");
1380
1604
  sessionData = {
1381
1605
  session_id: sessionId2,
1382
1606
  created_at: (/* @__PURE__ */ new Date()).toISOString(),
1383
1607
  conversation_history: []
1384
1608
  };
1385
1609
  try {
1386
- await fs7.writeFile(sessionFile, JSON.stringify(sessionData, null, 2), "utf-8");
1610
+ await fs8.writeFile(sessionFile, JSON.stringify(sessionData, null, 2), "utf-8");
1387
1611
  } catch {
1388
1612
  }
1389
1613
  }
@@ -1391,7 +1615,7 @@ async function saveSessionHistory(sessionFile, history) {
1391
1615
  sessionData.last_updated = (/* @__PURE__ */ new Date()).toISOString();
1392
1616
  const tempSessionFile = `${sessionFile}.${Date.now()}.tmp`;
1393
1617
  try {
1394
- await fs7.writeFile(tempSessionFile, JSON.stringify(sessionData, null, 2), "utf-8");
1618
+ await fs8.writeFile(tempSessionFile, JSON.stringify(sessionData, null, 2), "utf-8");
1395
1619
  await safeRenameWithRetry(tempSessionFile, sessionFile);
1396
1620
  } catch (writeError) {
1397
1621
  if (writeError instanceof Error) {
@@ -1400,7 +1624,7 @@ async function saveSessionHistory(sessionFile, history) {
1400
1624
  console.error(`An unknown fatal error occurred while saving session to ${sessionFile}:`, writeError);
1401
1625
  }
1402
1626
  try {
1403
- await fs7.unlink(tempSessionFile);
1627
+ await fs8.unlink(tempSessionFile);
1404
1628
  } catch {
1405
1629
  }
1406
1630
  }
@@ -1411,271 +1635,49 @@ async function saveSessionHistory(sessionFile, history) {
1411
1635
  import os4 from "os";
1412
1636
  var SYSTEM_PROMPT = `
1413
1637
 
1414
- ### YOU ARE BluMa CLI \u2014 AUTONOMOUS SENIOR SOFTWARE ENGINEER @ NOMADENGENUITY
1415
- You use a proprietary Large Language Model (LLM) fine-tuned by the NomadEngenuity team.
1416
-
1638
+ ### IDENTITY AND OBJECTIVE
1639
+ You are BluMa, an autonomous AI Software Engineer developed by the specialists at NomadEngenuity.
1640
+ You leverage a proprietary Large Language Model, fine-tuned specifically for complex software engineering and code generation tasks.
1641
+ Your objective is to analyze user requests, formulate a precise plan, and execute that plan flawlessly using your available tools.
1642
+ You operate with the highest standards of professionalism, precision, and safety.
1417
1643
  ---
1418
1644
 
1419
- ## BEHAVIORAL RULES
1420
-
1421
- - **Identity:**
1422
- You are BluMa (NomadEngenuity). Maintain professionalism and technical language.
1645
+ ### CORE DIRECTIVES
1423
1646
 
1424
- - **Communication:**
1425
- ALL messages must be sent via 'message_notify_dev'.
1426
- **No direct text replies to the developer.**
1647
+ 1. **THINK FIRST, ACT SECOND:** Your first action in any turn is to formulate an internal plan. Use the mandatory **"Reasoning Process"** format detailed below.
1648
+ 2. **TOOL-BASED OPERATION:** All actions and communications MUST be performed through a tool call. NEVER respond with free-form text.
1649
+ 3. **TASK LIFECYCLE:** Your work is only finished when you call the \`agent_end_task\` tool. Each tool call is a step within your current turn. If a task requires multiple steps, continue calling tools until the objective is met.
1650
+ 4. **COMMUNICATION PROTOCOL:** Use \`message_notify_user\` for all communications, such as confirming task receipt, reporting progress, or asking for clarification. Be concise.
1651
+ 5. **ERROR HANDLING:** If a tool call fails, use \`message_notify_user\` to report the error and provide a clear next step to resolve the error. Always try to recover from errors.
1652
+ 6. **CREATE AND MODIFY FILES:** Use the \`edit_tool\` tool to create or modify files. Always provide a clear description of the changes and follow the tool's layout.
1427
1653
 
1428
- - **Task Completion:**
1429
- When a task is completed, immediately invoke 'agent_end_task' without dev permissions.
1430
-
1431
- - **Tool Rules:**
1432
- Never make parallel tool calls.
1433
- Always use only the defined tools with their exact names.
1434
-
1435
- - **Autonomy:**
1436
- Act 100% autonomously.
1437
- Do not ask for formatting preferences.
1438
- Use the notebook for internal reasoning.
1439
-
1440
-
1441
- ### CRITICAL COMMUNICATION PROTOCOL
1442
- - Only tool_calls are allowed for assistant replies. Never include a "content" field.
1443
- - Always use tools to respond, retrieve data, compute or transform. Await a valid tool response before any final message.
1444
- - Zero tolerance for protocol violations.
1654
+ ---
1445
1655
 
1656
+ ### CURRENT ENVIRONMENT CONTEXT
1446
1657
  <current_system_environment>
1447
1658
  - Operating System: {os_type} ({os_version})
1448
1659
  - Architecture: {architecture}
1449
- - Current Working Directory: {workdir}
1660
+ - Current Directory: {workdir}
1450
1661
  - Shell: {shell_type}
1451
- - Username: {username}
1662
+ - User: {username}
1452
1663
  - Current Date: {current_date}
1453
- - Timezone: {timezone}
1454
- - Locale: {locale}
1455
1664
  </current_system_environment>
1456
1665
 
1666
+ ---
1457
1667
 
1458
- <mermaid_diagrams>
1459
- # MERMAID DIAGRAM CREATION - PERFECT SYNTAX REQUIRED!
1460
- ## CRITICAL: ALL DIAGRAMS MUST RENDER WITHOUT ERRORS
1461
-
1462
- ### MANDATORY MERMAID SYNTAX RULES
1463
- 1. **ALWAYS wrap ALL labels in double quotes**: "label text"
1464
- 2. **NEVER use unescaped special characters**: /, (), [], {}, +, *, ?, ^, $, |, 3. **Use line breaks (<br/>) for multi-line labels**: "Line 1<br/>Line 2"
1465
- 4. **NO custom colors or ::: syntax**: Stick to standard themes
1466
- 5. **NO beta features**: Use only stable Mermaid syntax
1467
- 6. **NO remote images**: Never embed external images
1468
-
1469
- ### SAFE LABEL FORMATTING
1470
-
1471
- CORRECT:
1472
- - "dev Authentication"
1473
- - "API Gateway (REST)"
1474
- - "Database Connection<br/>MySQL 8.0"
1475
- - "Process Data<br/>Transform & Validate"
1476
-
1477
- INCORRECT:
1478
- - dev Authentication (missing quotes)
1479
- - API Gateway (REST) (parentheses without quotes)
1480
- - Database/MySQL (slash without quotes)
1481
- - Process & Transform (ampersand without quotes)
1482
-
1483
-
1484
- ### DIAGRAM TYPE BEST PRACTICES
1485
-
1486
- IMPORTANT
1487
- The Notion API rejects rich text of type "code" and only accepts "text" for code blocks \u2013
1488
- a limitation of their own JSON (even for the language: "mermaid"). Therefore, only the code/text block
1489
- type is viable.
1490
-
1491
- You should insert the pretty diagram without any delimiters or headers, in the code block with
1492
- proper indentation and double quotes, only in the text field, to facilitate as little manual rework as possible.
1493
- It's ready to copy into the native Mermaid block.
1494
-
1495
- #### FLOWCHART
1496
-
1497
- flowchart TD
1498
- A["Start Process"] --> B["Validate Input"]
1499
- B --> C{"Is Valid?"}
1500
- C -->|"Yes"| D["Process Data"]
1501
- C -->|"No"| E["Return Error"]
1502
- D --> F["Save to Database"]
1503
- F --> G["Send Response"]
1504
-
1505
-
1506
- #### SEQUENCE DIAGRAM
1507
-
1508
- sequenceDiagram
1509
- participant U as "dev"
1510
- participant A as "API Gateway"
1511
- participant D as "Database"
1512
-
1513
- U->>A: "Submit Request"
1514
- A->>D: "Query Data"
1515
- D-->>A: "Return Results"
1516
- A-->>U: "Response Data"
1517
-
1518
- #### CLASS DIAGRAM
1519
-
1520
- classDiagram
1521
- class dev {
1522
- +String name
1523
- +String email
1524
- +authenticate()
1525
- +updateProfile()
1526
- }
1527
-
1528
- class Database {
1529
- +connect()
1530
- +query()
1531
- +close()
1532
- }
1533
-
1534
- dev --> Database : "uses"
1535
-
1536
-
1537
- ### VALIDATION CHECKLIST
1538
- Before creating any diagram, ensure:
1539
- - [ ] All labels are wrapped in double quotes
1540
- - [ ] No unescaped special characters (/, (), etc.)
1541
- - [ ] Line breaks use <br/> syntax
1542
- - [ ] No custom colors or styling
1543
- - [ ] No beta features or experimental syntax
1544
- - [ ] All connections use proper arrow syntax
1545
- - [ ] Node IDs are simple alphanumeric
1546
-
1547
- ### ERROR PREVENTION
1548
- - Always test diagram syntax mentally before generating
1549
- - Use simple, descriptive labels without special formatting
1550
- - Prefer clarity over visual complexity
1551
- - Keep diagrams focused and readable
1552
- - Use standard Mermaid themes only
1553
-
1554
- ## ZERO TOLERANCE FOR SYNTAX ERRORS
1555
- Every diagram MUST render perfectly on first try. No exceptions.
1556
- </mermaid_diagrams>
1557
-
1668
+ ### COMMUNICATION PROTOCOL
1558
1669
  <message_rules>
1559
- - Communicate with dev's via message tools instead of direct text responses
1670
+ - Communicate with user's via message tools instead of direct text responses
1560
1671
  - Reply immediately to new user messages before other operations
1561
1672
  - First reply must be brief, only confirming receipt without specific solutions
1562
- - Notify dev's with brief explanation when changing methods or strategies
1563
- - Message tools are divided into notify (non-blocking, no reply needed from dev's) and ask (blocking, reply required)
1564
- - Actively use notify for progress updates, but reserve ask for only essential needs to minimize dev's disruption and avoid blocking progress
1565
- - Must message dev's with results and deliverables before upon task completion 'agent_end_task'
1673
+ - Notify user's with brief explanation when changing methods or strategies
1674
+ - Message tools are divided into notify (non-blocking, no reply needed from user's) and ask (blocking, reply required)
1675
+ - Actively use notify for progress updates, but reserve ask for only essential needs to minimize user's disruption and avoid blocking progress
1676
+ - Must message user's with results and deliverables before upon task completion 'agent_end_task'
1566
1677
  </message_rules>
1567
1678
 
1568
-
1569
- ### Live Development Overlaps
1570
-
1571
- During your workflow, the programmer {username} may send messages at any time.
1572
- These messages **must be immediately incorporated** into your execution flow.
1573
- **Always confirm receipt using {message_notify_dev}** and proceed with your work.
1574
-
1575
- ### Instructions for Handling Messages from the Programmer
1576
-
1577
- 1. **Upon receiving a message from {username}:**
1578
- - Immediately confirm using {message_notify_dev}.
1579
- - Integrate the instruction into your reasoning and execution flow.
1580
-
1581
- 2. **Regarding your reasoning:**
1582
- - Be direct, minimalist, and clear.
1583
- - Avoid unnecessary or verbose thoughts.
1584
-
1585
- 3. **Avoid polluting the history:**
1586
- - **Do not repeat or reply to existing messages.**
1587
- - Only act if the new message introduces a **new instruction or shifts the current task\u2019s focus**.
1588
-
1589
- <reasoning_rules>
1590
- # YOUR THINKING ON A NOTEBOOK - MANDATORY USE
1591
- CRITICAL: Your laptop (**reasoning_nootebook**) is your ORGANIZED MIND
1592
- ## IMPORTANT
1593
- ## NEVER PUT CHECKLISTS OR STEPS IN THE THOUGHT TEXT
1594
- ## ALWAYS USE A NOTEBOOK (Always for):
1595
- - ANY task
1596
- - Before starting development (plan first!)
1597
- - Projects with multiple files (organize the structure)
1598
- - Debugging sessions (monitor discoveries)
1599
- - Extensive refactoring (map the changes)
1600
- - Architectural decisions (think through the options)
1601
-
1602
- ## HOW TO USE A NOTEBOOK:
1603
- 1. Start with **reasoning_nootebook**
1604
- 2. Break the task down into logical steps
1605
- 3. Plan the approach - Which files? What changes? What order? 4. Track progress - Check off completed steps
1606
- 5. Write down decisions - Why did you choose this approach?
1607
- 6. Update continuously - Keep the notebook up to date
1608
-
1609
- ## THE NOTEBOOK PREVENTS:
1610
- - Acting "outside the box"
1611
- - Forgetting task requirements
1612
- - Losing control of complex workflows
1613
- - Making unplanned changes
1614
- - Ineffective approaches
1615
- - Working without a clear roadmap
1616
- - Jumping between unrelated subtasks
1617
-
1618
- ##Important rule:
1619
- Do **not** include any future steps, to-do items, or pending tasks here.
1620
- Those belong strictly in the **remaining_tasks** field.
1621
-
1622
- Never write phrases like:
1623
- - "Next I will..."
1624
- - "I still need to..."
1625
- - "Pending: ..."
1626
- Such content must go in **remaining_tasks**, not **thought**.
1627
-
1628
- - remaining_tasks: Checklist-style list of high-level upcoming tasks.
1629
- This format is **mandatory**:
1630
- - Each task **must start** with either:
1631
- - "\u{1F5F8}" \u2192 for tasks not yet done (pending)
1632
- - "[ ]" \u2192 for tasks that have already been completed
1633
-
1634
- Whenever a task is already done, it **must** be marked with "\u{1F5F8}". Do not leave completed tasks without the checkmark.
1635
-
1636
- Do not use other formats like "-", "*", or plain text without the prefix.
1637
-
1638
- Examples:
1639
- \u{1F5F8} Test integration flow
1640
- \u{1F5F8} Set up environment
1641
- [ ] Configure database
1642
-
1643
- </reasoning_rules>
1644
-
1645
- ### Tool Naming Policy
1646
-
1647
- Tool names must strictly follow the standard naming format:
1648
-
1649
- - Use: plain, unmodified, lowercase names
1650
- - Do NOT use: special characters, extra spaces, version suffixes, or dynamic IDs
1651
-
1652
1679
  ---
1653
1680
 
1654
- Correct Examples:
1655
- - bluma_notebook
1656
- - getDataTool
1657
- - convertImage
1658
- - userAuth
1659
-
1660
- ---
1661
-
1662
- Incorrect Examples:
1663
- - reasoning_nootebook:0 \u2190 contains colon and dynamic suffix
1664
- - reasoning_nootebook 1 \u2190 contains space and number
1665
- - reasoning_nootebook#v2 \u2190 contains special character #
1666
- - bluma__nootebook \u2190 double underscore
1667
- - reasoning_nootebook \u2190 capital letters and underscore
1668
- - bluma nootebook \u2190 contains space
1669
-
1670
- ---
1671
-
1672
- Rule Summary:
1673
- - Use only a\u2013z, 0\u20139, and underscores (_)
1674
- - Do not append suffixes like :0, :v2, etc.
1675
- - Tool names must be static and predictable
1676
- - No whitespace, no dynamic elements, no special characters
1677
-
1678
-
1679
1681
  <edit_tool_rules>
1680
1682
  - Use this tool to perform precise text replacements inside files based on exact literal matches.
1681
1683
  - Can be used to create new files or directories implicitly by targeting non-existing paths.
@@ -1690,41 +1692,28 @@ Rule Summary:
1690
1692
  - Track all progress related to planning and execution inside todo.md using text replacement only.
1691
1693
  </edit_tool_rules>
1692
1694
 
1693
- Real-Time Developer Messages
1694
- - During processing, the developer will send you messages.
1695
- - You MUST respond immediately via message_notify_dev, and be brief. You should use it in your next thoughts/actions.
1696
-
1697
-
1698
- <agent_end_task_rules>
1699
- This tool is mandatory.
1700
- You must use it to inform developer {username} that the task has been completed and that there are no further pending actions, in accordance with the objectives defined for the task.
1701
- </agent_end_task_rules>
1702
-
1703
- ### QUALITY STANDARDS
1704
- - Document every major decision in Notion(
1705
- ##Important: When writing to Notion, you must strictly follow its content structure, including the correct use of headings (heading_1, heading_2, etc.) and other formatting standards. No deviations are allowed.
1706
- You should always standardize everything using Notion's actual headers (heading_1, heading_2, etc.), making the structure
1707
- semantically better for reading and navigation.
1708
- )
1709
- - Communicate transparently at each step
1710
- - Write clean, well-documented code
1711
- - Follow existing project conventions
1712
- - Test implementations when possible
1713
- - Ensure security and performance
1714
-
1715
- <scope_and_limitations>
1716
- # WHAT YOU DON'T HANDLE
1717
- - Non-technical questions
1718
- - Personal advice
1719
- - General conversation
1720
- - Tasks outside software development
1721
-
1722
- # IF ASKED NON-TECHNICAL QUESTIONS
1723
- - Use message_notify_dev to politely decline
1724
- - Explain you only handle technical/coding tasks
1725
- - Suggest they ask a development-related question instead
1726
- </scope_and_limitations>
1695
+ ---
1727
1696
 
1697
+ ### SCOPE & LIMITATIONS
1698
+
1699
+ **1. IN-SCOPE TASKS:**
1700
+ - Software architecture and design.
1701
+ - Code generation, analysis, and debugging.
1702
+ - Using provided tools to complete development objectives.
1703
+ - Creating technical documentation and diagrams.
1704
+
1705
+ **2. OUT-OF-SCOPE TASKS:**
1706
+ You MUST professionally decline to engage with any of the following:
1707
+ - Non-technical questions (e.g., weather, news, general facts).
1708
+ - Personal, financial, or legal advice.
1709
+ - General conversation, opinions, or jokes.
1710
+ - Any task not directly related to software development.
1711
+
1712
+ **3. PROTOCOL FOR OUT-OF-SCOPE REQUESTS:**
1713
+ If a user asks for something that is out-of-scope, follow this exact procedure:
1714
+ 1. Do NOT attempt to answer the question.
1715
+ 2. Use the \`message_notify_user\` tool.
1716
+ 3. Use the \`agent_end_task\` tool.
1728
1717
  `;
1729
1718
  function getUnifiedSystemPrompt() {
1730
1719
  const now = /* @__PURE__ */ new Date();
@@ -1779,7 +1768,7 @@ function createApiContextWindow(fullHistory, maxTurns) {
1779
1768
  const turns = [];
1780
1769
  let currentTurn = [];
1781
1770
  let turnsFound = 0;
1782
- const isDevOverlay = (m) => m?.role === "user" && m?.name === "dev_overlay";
1771
+ const isDevOverlay = (m) => m?.role === "user" && m?.name === "user_overlay";
1783
1772
  for (let i = conversationHistory.length - 1; i >= 0; i--) {
1784
1773
  const msg = conversationHistory[i];
1785
1774
  currentTurn.unshift(msg);
@@ -1834,16 +1823,16 @@ var BluMaAgent = class {
1834
1823
  this.isInterrupted = true;
1835
1824
  this.eventBus.emit("backend_message", { type: "done", status: "interrupted" });
1836
1825
  });
1837
- this.eventBus.on("dev_overlay", async (data) => {
1826
+ this.eventBus.on("user_overlay", async (data) => {
1838
1827
  const clean = String(data.payload ?? "").trim();
1839
- this.history.push({ role: "user", name: "dev_overlay", content: clean });
1840
- this.eventBus.emit("backend_message", { type: "dev_overlay", payload: clean, ts: data.ts || Date.now() });
1828
+ this.history.push({ role: "user", name: "user_overlay", content: clean });
1829
+ this.eventBus.emit("backend_message", { type: "user_overlay", payload: clean, ts: data.ts || Date.now() });
1841
1830
  try {
1842
1831
  if (this.sessionFile) {
1843
1832
  await saveSessionHistory(this.sessionFile, this.history);
1844
1833
  }
1845
1834
  } catch (e) {
1846
- this.eventBus.emit("backend_message", { type: "error", message: `Falha ao salvar hist\xF3rico ap\xF3s dev_overlay: ${e.message}` });
1835
+ this.eventBus.emit("backend_message", { type: "error", message: `Falha ao salvar hist\xF3rico ap\xF3s user_overlay: ${e.message}` });
1847
1836
  }
1848
1837
  });
1849
1838
  }
@@ -1934,7 +1923,7 @@ var BluMaAgent = class {
1934
1923
 
1935
1924
  ${editData.error.display}`;
1936
1925
  }
1937
- const filename = path7.basename(toolArgs.file_path);
1926
+ const filename = path8.basename(toolArgs.file_path);
1938
1927
  return createDiff(filename, editData.currentContent || "", editData.newContent);
1939
1928
  } catch (e) {
1940
1929
  return `An unexpected error occurred while generating the edit preview: ${e.message}`;
@@ -1943,16 +1932,20 @@ ${editData.error.display}`;
1943
1932
  async _continueConversation() {
1944
1933
  try {
1945
1934
  if (this.isInterrupted) {
1946
- this.eventBus.emit("backend_message", { type: "info", message: "Agent task cancelled by user." });
1935
+ this.eventBus.emit("backend_message", { type: "info", message: "Task Canceled." });
1947
1936
  return;
1948
1937
  }
1949
1938
  const contextWindow = createApiContextWindow(this.history, this.maxContextTurns);
1950
1939
  const response = await this.llm.chatCompletion({
1951
1940
  model: this.deploymentName,
1952
1941
  messages: contextWindow,
1942
+ temperature: 0.2,
1953
1943
  tools: this.mcpClient.getAvailableTools(),
1954
1944
  tool_choice: "required",
1955
- parallel_tool_calls: false
1945
+ reasoning_effort: "high",
1946
+ parallel_tool_calls: false,
1947
+ max_tokens: 512
1948
+ // Limite de tokens para evitar respostas muito longas
1956
1949
  });
1957
1950
  if (this.isInterrupted) {
1958
1951
  this.eventBus.emit("backend_message", { type: "info", message: "Agent task cancelled by user." });
@@ -1961,7 +1954,7 @@ ${editData.error.display}`;
1961
1954
  const message = response.choices[0].message;
1962
1955
  this.history.push(message);
1963
1956
  if (message.tool_calls) {
1964
- const autoApprovedTools = ["agent_end_task", "message_notify_dev", "reasoning_nootebook"];
1957
+ const autoApprovedTools = ["agent_end_task", "message_notify_user", "reasoning_nootebook"];
1965
1958
  const toolToCall = message.tool_calls[0];
1966
1959
  const isSafeTool = autoApprovedTools.some((safeTool) => toolToCall.function.name.includes(safeTool));
1967
1960
  if (isSafeTool) {
@@ -2042,11 +2035,11 @@ You extend the BluMa multi-agent architecture and handle the project bootstrappi
2042
2035
  You are BluMa InitSubAgent. Maintain professionalism and technical language.
2043
2036
 
2044
2037
  - Communication:
2045
- ALL messages must be sent via 'message_notify_dev'.
2046
- No direct text replies to the developer.
2038
+ ALL messages must be sent via 'message_notify_user'.
2039
+ No direct text replies to the user.
2047
2040
 
2048
2041
  - Task Completion:
2049
- When the init task is completed, immediately invoke 'agent_end_task' without dev permissions.
2042
+ When the init task is completed, immediately invoke 'agent_end_task' without user permissions.
2050
2043
 
2051
2044
  - Tool Rules:
2052
2045
  Never make parallel tool calls.
@@ -2068,20 +2061,20 @@ You extend the BluMa multi-agent architecture and handle the project bootstrappi
2068
2061
  - Architecture: {architecture}
2069
2062
  - Current Working Directory: {workdir}
2070
2063
  - Shell: {shell_type}
2071
- - Username: {username}
2064
+ - User: {username}
2072
2065
  - Current Date: {current_date}
2073
2066
  - Timezone: {timezone}
2074
2067
  - Locale: {locale}
2075
2068
  </current_system_environment>
2076
2069
 
2077
2070
  <message_rules>
2078
- - Communicate with dev's via message tools instead of direct text responses
2071
+ - Communicate with user's via message tools instead of direct text responses
2079
2072
  - Reply immediately to new user messages before other operations
2080
2073
  - First reply must be brief, only confirming receipt without specific solutions
2081
- - Notify dev's with brief explanation when changing methods or strategies
2074
+ - Notify user's with brief explanation when changing methods or strategies
2082
2075
  - Message tools are divided into notify (non-blocking, no reply needed) and ask (blocking)
2083
2076
  - Actively use notify for progress updates, reserve ask for essential needs to avoid blocking
2084
- - Must message dev's with results and deliverables before upon task completion 'agent_end_task'
2077
+ - Must message user's with results and deliverables before upon task completion 'agent_end_task'
2085
2078
  </message_rules>
2086
2079
 
2087
2080
  <reasoning_rules>
@@ -2091,7 +2084,7 @@ CRITICAL: Your laptop (reasoning_nootebook) is your ORGANIZED MIND
2091
2084
  ## NEVER PUT CHECKLISTS OR STEPS IN THE THOUGHT TEXT
2092
2085
  ## ALWAYS USE A NOTEBOOK (Always for):
2093
2086
  - ANY task
2094
- - Before starting development (plan first!)
2087
+ - Before starting userelopment (plan first!)
2095
2088
  - Projects with multiple files (organize the structure)
2096
2089
  - Debugging sessions (monitor discoveries)
2097
2090
  - Extensive refactoring (map the changes)
@@ -2140,7 +2133,7 @@ Do not include future steps/to-dos in thought; put them strictly in remaining_ta
2140
2133
 
2141
2134
  <agent_end_task_rules>
2142
2135
  This tool is mandatory.
2143
- You must use it to inform developer {username} that the task has been completed and that there are no further pending actions, in accordance with the objectives defined for the task.
2136
+ You must use it to inform usereloper {username} that the task has been completed and that there are no further pending actions, in accordance with the objectives defined for the task.
2144
2137
  </agent_end_task_rules>
2145
2138
 
2146
2139
  ### Tool Naming Policy
@@ -2167,9 +2160,9 @@ Rule Summary:
2167
2160
  - Never invent file content. Read files via tools to confirm.
2168
2161
 
2169
2162
  ## OUTPUT & PROTOCOLS
2170
- - Emit 'backend_message' events through tools only (message_notify_dev) for progress updates.
2171
- - Before writing BluMa.md, propose structure via message_notify_dev and proceed using edit_tool.
2172
- - If an irreversible operation is needed (e.g., overwriting an existing BluMa.md), issue 'confirmation_request' unless dev policy indicates auto-approval.
2163
+ - Emit 'backend_message' events through tools only (message_notify_user) for progress updates.
2164
+ - Before writing BluMa.md, propose structure via message_notify_user and proceed using edit_tool.
2165
+ - If an irreversible operation is needed (e.g., overwriting an existing BluMa.md), issue 'confirmation_request' unless user policy indicates auto-approval.
2173
2166
  - Never send or present draft versions of BluMa.md. Only produce and deliver the final, validated BluMa.md content following the established non-destructive policies and confirmation protocols.
2174
2167
  - On successful generation of BluMa.md, emit 'done' with status 'completed' and call agent_end_task.
2175
2168
 
@@ -2182,7 +2175,7 @@ Rule Summary:
2182
2175
  ## EXEMPLAR FLOW (GUIDELINE)
2183
2176
  1) Explore repo: ls + targeted readLines for key files (package.json, tsconfig.json, README, etc.)
2184
2177
  2) Synthesize stack and structure with citations of evidence (file paths) in the notebook
2185
- 3) Draft BluMa.md structure (message_notify_dev)
2178
+ 3) Draft BluMa.md structure (message_notify_user)
2186
2179
  4) Write BluMa.md via edit_tool
2187
2180
  5) Announce completion and agent_end_task
2188
2181
 
@@ -2272,7 +2265,7 @@ ${editData.error.display}`;
2272
2265
  async _continueConversation() {
2273
2266
  try {
2274
2267
  if (this.isInterrupted) {
2275
- this.emitEvent("info", { message: "SubAgent task cancelled by user." });
2268
+ this.emitEvent("info", { message: "SubAgent task cancelled byuserr." });
2276
2269
  return;
2277
2270
  }
2278
2271
  const contextWindow = this.history.slice(-this.maxContextTurns);
@@ -2284,7 +2277,7 @@ ${editData.error.display}`;
2284
2277
  parallel_tool_calls: false
2285
2278
  });
2286
2279
  if (this.isInterrupted) {
2287
- this.emitEvent("info", { message: "SubAgent task cancelled by user." });
2280
+ this.emitEvent("info", { message: "SubAgent task cancelled byuserr." });
2288
2281
  return;
2289
2282
  }
2290
2283
  const message = response.choices[0].message;
@@ -2333,7 +2326,7 @@ ${editData.error.display}`;
2333
2326
  try {
2334
2327
  if (this.isInterrupted) {
2335
2328
  this.emitEvent("info", { message: "SubAgent task cancelled before tool execution." });
2336
- toolResultContent = JSON.stringify({ error: "Task cancelled by user before execution." });
2329
+ toolResultContent = JSON.stringify({ error: "Task cancelled byuserr before execution." });
2337
2330
  } else {
2338
2331
  const result = await this.ctx.mcpClient.invoke(toolName, toolArgs);
2339
2332
  let finalResult = result;
@@ -2449,7 +2442,7 @@ var SubAgentsBluMa = class {
2449
2442
  };
2450
2443
 
2451
2444
  // src/app/agent/agent.ts
2452
- var globalEnvPath = path8.join(os6.homedir(), ".bluma-cli", ".env");
2445
+ var globalEnvPath = path9.join(os6.homedir(), ".bluma-cli", ".env");
2453
2446
  dotenv.config({ path: globalEnvPath });
2454
2447
  var Agent = class {
2455
2448
  sessionId;
@@ -2579,19 +2572,19 @@ var Agent = class {
2579
2572
  };
2580
2573
 
2581
2574
  // src/app/ui/WorkingTimer.tsx
2582
- import { useState as useState3, useEffect as useEffect2 } from "react";
2575
+ import { useState as useState4, useEffect as useEffect3 } from "react";
2583
2576
  import { Box as Box7, Text as Text7 } from "ink";
2584
2577
  import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
2585
2578
  var WorkingTimer = () => {
2586
- const [seconds, setSeconds] = useState3(0);
2587
- const [dotIndex, setDotIndex] = useState3(1);
2588
- useEffect2(() => {
2579
+ const [seconds, setSeconds] = useState4(0);
2580
+ const [dotIndex, setDotIndex] = useState4(1);
2581
+ useEffect3(() => {
2589
2582
  const secondsTimer = setInterval(() => {
2590
2583
  setSeconds((prev) => prev + 1);
2591
2584
  }, 1e3);
2592
2585
  return () => clearInterval(secondsTimer);
2593
2586
  }, []);
2594
- useEffect2(() => {
2587
+ useEffect3(() => {
2595
2588
  const dotsTimer = setInterval(() => {
2596
2589
  setDotIndex((prev) => prev % 3 + 1);
2597
2590
  }, 100);
@@ -2610,7 +2603,7 @@ import { Box as Box9 } from "ink";
2610
2603
 
2611
2604
  // src/app/ui/components/toolCallRenderers.tsx
2612
2605
  import { Box as Box8, Text as Text8 } from "ink";
2613
- import path9 from "path";
2606
+ import path10 from "path";
2614
2607
  import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
2615
2608
  var formatArgumentsForDisplay = (args) => {
2616
2609
  if (typeof args === "string") {
@@ -2622,7 +2615,9 @@ var formatArgumentsForDisplay = (args) => {
2622
2615
  }
2623
2616
  return JSON.stringify(args, null, 2);
2624
2617
  };
2625
- var renderShellCommand2 = ({ args }) => {
2618
+ var renderShellCommand2 = ({
2619
+ args
2620
+ }) => {
2626
2621
  const command = args.command || "[command not found]";
2627
2622
  return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
2628
2623
  /* @__PURE__ */ jsx8(Box8, { children: /* @__PURE__ */ jsxs8(Text8, { bold: true, children: [
@@ -2643,7 +2638,7 @@ var renderLsTool2 = ({ args }) => {
2643
2638
  } catch (e) {
2644
2639
  directoryPath = "Error parsing arguments";
2645
2640
  }
2646
- const finalDirectoryName = path9.basename(directoryPath);
2641
+ const finalDirectoryName = path10.basename(directoryPath);
2647
2642
  return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
2648
2643
  /* @__PURE__ */ jsx8(Box8, { children: /* @__PURE__ */ jsxs8(Text8, { bold: true, children: [
2649
2644
  /* @__PURE__ */ jsx8(Text8, { color: "green", children: "\u25CF " }),
@@ -2655,7 +2650,9 @@ var renderLsTool2 = ({ args }) => {
2655
2650
  ] }) })
2656
2651
  ] });
2657
2652
  };
2658
- var renderCountFilesLines = ({ args }) => {
2653
+ var renderCountFilesLines = ({
2654
+ args
2655
+ }) => {
2659
2656
  let directoryPath = "[path not found]";
2660
2657
  try {
2661
2658
  const parsedArgs = typeof args === "string" ? JSON.parse(args) : args;
@@ -2663,7 +2660,7 @@ var renderCountFilesLines = ({ args }) => {
2663
2660
  } catch (e) {
2664
2661
  directoryPath = "Error parsing arguments";
2665
2662
  }
2666
- const finalDirectoryName = path9.basename(directoryPath);
2663
+ const finalDirectoryName = path10.basename(directoryPath);
2667
2664
  return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
2668
2665
  /* @__PURE__ */ jsx8(Box8, { children: /* @__PURE__ */ jsxs8(Text8, { bold: true, children: [
2669
2666
  /* @__PURE__ */ jsx8(Text8, { color: "green", children: "\u25CF " }),
@@ -2675,7 +2672,9 @@ var renderCountFilesLines = ({ args }) => {
2675
2672
  ] }) })
2676
2673
  ] });
2677
2674
  };
2678
- var renderReadFileLines2 = ({ args }) => {
2675
+ var renderReadFileLines2 = ({
2676
+ args
2677
+ }) => {
2679
2678
  let filepath = "[path not found]";
2680
2679
  let startLine = 0;
2681
2680
  let endLine = 0;
@@ -2687,7 +2686,7 @@ var renderReadFileLines2 = ({ args }) => {
2687
2686
  } catch (e) {
2688
2687
  filepath = "Error parsing arguments";
2689
2688
  }
2690
- const finalFileName = path9.basename(filepath);
2689
+ const finalFileName = path10.basename(filepath);
2691
2690
  return (
2692
2691
  // A caixa externa com a borda, seguindo o template
2693
2692
  /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
@@ -2711,7 +2710,9 @@ var renderReadFileLines2 = ({ args }) => {
2711
2710
  ] })
2712
2711
  );
2713
2712
  };
2714
- var renderBlumaNotebook = ({ args }) => {
2713
+ var renderBlumaNotebook = ({
2714
+ args
2715
+ }) => {
2715
2716
  try {
2716
2717
  let dataToParse = args;
2717
2718
  if (args && typeof args === "object") {
@@ -2724,16 +2725,30 @@ var renderBlumaNotebook = ({ args }) => {
2724
2725
  }
2725
2726
  return (
2726
2727
  // Usamos a mesma estrutura de caixa com borda
2727
- /* @__PURE__ */ jsxs8(Box8, { borderStyle: "round", borderColor: "green", flexDirection: "column", paddingX: 1, children: [
2728
- /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
2729
- /* @__PURE__ */ jsx8(Text8, { bold: true, children: "Thought:" }),
2730
- /* @__PURE__ */ jsx8(Box8, { marginLeft: 2, children: /* @__PURE__ */ jsx8(Text8, { color: "gray", children: thinkingData.thought }) })
2731
- ] }),
2732
- thinkingData.remaining_tasks && thinkingData.remaining_tasks.length > 0 && /* @__PURE__ */ jsxs8(Box8, { marginTop: 1, flexDirection: "column", children: [
2733
- /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "Remaining Tasks:" }),
2734
- thinkingData.remaining_tasks.map((task, index) => /* @__PURE__ */ jsx8(Box8, { marginLeft: 2, children: /* @__PURE__ */ jsx8(Text8, { children: /* @__PURE__ */ jsx8(Text8, { color: task.startsWith("\u{1F5F8}") ? "green" : "yellow", children: task }) }) }, index))
2735
- ] })
2736
- ] })
2728
+ /* @__PURE__ */ jsxs8(
2729
+ Box8,
2730
+ {
2731
+ flexDirection: "column",
2732
+ paddingX: 1,
2733
+ children: [
2734
+ /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
2735
+ /* @__PURE__ */ jsx8(Text8, { bold: true, children: "Thought:" }),
2736
+ /* @__PURE__ */ jsx8(Box8, { marginLeft: 2, children: /* @__PURE__ */ jsx8(Text8, { color: "gray", children: thinkingData.thought }) })
2737
+ ] }),
2738
+ thinkingData.remaining_tasks && thinkingData.remaining_tasks.length > 0 && /* @__PURE__ */ jsxs8(Box8, { marginTop: 1, flexDirection: "column", children: [
2739
+ /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "Remaining Tasks:" }),
2740
+ thinkingData.remaining_tasks.map((task, index) => /* @__PURE__ */ jsx8(Box8, { marginLeft: 2, children: /* @__PURE__ */ jsx8(Text8, { children: /* @__PURE__ */ jsx8(
2741
+ Text8,
2742
+ {
2743
+ color: task.startsWith("\u{1F5F9}") ? "green" : "yellow",
2744
+ strikethrough: task.startsWith("\u{1F5F9}"),
2745
+ children: task
2746
+ }
2747
+ ) }) }, index))
2748
+ ] })
2749
+ ]
2750
+ }
2751
+ )
2737
2752
  );
2738
2753
  } catch (e) {
2739
2754
  return /* @__PURE__ */ jsxs8(Box8, { borderStyle: "round", borderColor: "blue", paddingX: 1, children: [
@@ -2742,7 +2757,10 @@ var renderBlumaNotebook = ({ args }) => {
2742
2757
  ] });
2743
2758
  }
2744
2759
  };
2745
- var renderEditToolCall = ({ args, preview }) => {
2760
+ var renderEditToolCall = ({
2761
+ args,
2762
+ preview
2763
+ }) => {
2746
2764
  let filepath = "[path not specified]";
2747
2765
  try {
2748
2766
  const parsedArgs = typeof args === "string" ? JSON.parse(args) : args;
@@ -2750,7 +2768,7 @@ var renderEditToolCall = ({ args, preview }) => {
2750
2768
  } catch (e) {
2751
2769
  filepath = "Error parsing arguments";
2752
2770
  }
2753
- const finalFileName = path9.basename(filepath);
2771
+ const finalFileName = path10.basename(filepath);
2754
2772
  return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", paddingX: 1, children: [
2755
2773
  /* @__PURE__ */ jsx8(Box8, { children: /* @__PURE__ */ jsxs8(Text8, { bold: true, children: [
2756
2774
  /* @__PURE__ */ jsx8(Text8, { color: "green", children: "\u25CF " }),
@@ -2763,7 +2781,10 @@ var renderEditToolCall = ({ args, preview }) => {
2763
2781
  preview && /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(SimpleDiff, { text: preview, maxHeight: Infinity }) })
2764
2782
  ] });
2765
2783
  };
2766
- var renderGenericToolCall = ({ toolName, args }) => {
2784
+ var renderGenericToolCall = ({
2785
+ toolName,
2786
+ args
2787
+ }) => {
2767
2788
  const formattedArgs = formatArgumentsForDisplay(args);
2768
2789
  return (
2769
2790
  // A "moldura" padrão de sucesso com a borda cinza
@@ -2780,18 +2801,18 @@ var renderGenericToolCall = ({ toolName, args }) => {
2780
2801
  );
2781
2802
  };
2782
2803
  var ToolRenderDisplay = {
2783
- "shell_command": renderShellCommand2,
2784
- "ls_tool": renderLsTool2,
2785
- "reasoning_nootebook": renderBlumaNotebook,
2786
- "count_file_lines": renderCountFilesLines,
2787
- "read_file_lines": renderReadFileLines2,
2788
- "edit_tool": renderEditToolCall
2804
+ shell_command: renderShellCommand2,
2805
+ ls_tool: renderLsTool2,
2806
+ reasoning_nootebook: renderBlumaNotebook,
2807
+ count_file_lines: renderCountFilesLines,
2808
+ read_file_lines: renderReadFileLines2,
2809
+ edit_tool: renderEditToolCall
2789
2810
  };
2790
2811
 
2791
2812
  // src/app/ui/components/ToolCallDisplay.tsx
2792
2813
  import { jsx as jsx9 } from "react/jsx-runtime";
2793
2814
  var ToolCallDisplayComponent = ({ toolName, args, preview }) => {
2794
- if (toolName.includes("message_notify_dev") || toolName.includes("agent_end_task")) {
2815
+ if (toolName.includes("message_notify_user") || toolName.includes("agent_end_task")) {
2795
2816
  return null;
2796
2817
  }
2797
2818
  const Renderer = ToolRenderDisplay[toolName] || renderGenericToolCall;
@@ -2804,7 +2825,7 @@ import { memo as memo3 } from "react";
2804
2825
  import { Box as Box10, Text as Text9 } from "ink";
2805
2826
  import { jsx as jsx10 } from "react/jsx-runtime";
2806
2827
  var ToolResultDisplayComponent = ({ toolName, result }) => {
2807
- if (!toolName.includes("message_notify_dev")) {
2828
+ if (!toolName.includes("message_notify_user")) {
2808
2829
  return null;
2809
2830
  }
2810
2831
  try {
@@ -3028,21 +3049,21 @@ var SlashCommands_default = SlashCommands;
3028
3049
  import updateNotifier from "update-notifier";
3029
3050
  import { readPackageUp } from "read-package-up";
3030
3051
  import { fileURLToPath as fileURLToPath3 } from "url";
3031
- import path10 from "path";
3032
- import fs8 from "fs";
3052
+ import path11 from "path";
3053
+ import fs9 from "fs";
3033
3054
  function findPackageJsonNearest(startDir) {
3034
3055
  let dir = startDir;
3035
3056
  for (let i = 0; i < 6; i++) {
3036
- const candidate = path10.join(dir, "package.json");
3037
- if (fs8.existsSync(candidate)) {
3057
+ const candidate = path11.join(dir, "package.json");
3058
+ if (fs9.existsSync(candidate)) {
3038
3059
  try {
3039
- const raw = fs8.readFileSync(candidate, "utf8");
3060
+ const raw = fs9.readFileSync(candidate, "utf8");
3040
3061
  const parsed = JSON.parse(raw);
3041
3062
  if (parsed?.name && parsed?.version) return parsed;
3042
3063
  } catch {
3043
3064
  }
3044
3065
  }
3045
- const parent = path10.dirname(dir);
3066
+ const parent = path11.dirname(dir);
3046
3067
  if (parent === dir) break;
3047
3068
  dir = parent;
3048
3069
  }
@@ -3055,15 +3076,15 @@ async function checkForUpdates() {
3055
3076
  }
3056
3077
  const binPath = process.argv?.[1];
3057
3078
  let pkg;
3058
- if (binPath && fs8.existsSync(binPath)) {
3059
- const candidatePkg = findPackageJsonNearest(path10.dirname(binPath));
3079
+ if (binPath && fs9.existsSync(binPath)) {
3080
+ const candidatePkg = findPackageJsonNearest(path11.dirname(binPath));
3060
3081
  if (candidatePkg?.name && candidatePkg?.version) {
3061
3082
  pkg = candidatePkg;
3062
3083
  }
3063
3084
  }
3064
3085
  if (!pkg) {
3065
3086
  const __filename = fileURLToPath3(import.meta.url);
3066
- const __dirname = path10.dirname(__filename);
3087
+ const __dirname = path11.dirname(__filename);
3067
3088
  const result = await readPackageUp({ cwd: __dirname });
3068
3089
  pkg = result?.packageJson;
3069
3090
  }
@@ -3149,26 +3170,26 @@ var ErrorMessage_default = ErrorMessage;
3149
3170
  // src/app/ui/App.tsx
3150
3171
  import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
3151
3172
  var AppComponent = ({ eventBus: eventBus2, sessionId: sessionId2 }) => {
3152
- const agentInstance = useRef(null);
3153
- const [history, setHistory] = useState4([]);
3154
- const [statusMessage, setStatusMessage] = useState4(
3173
+ const agentInstance = useRef2(null);
3174
+ const [history, setHistory] = useState5([]);
3175
+ const [statusMessage, setStatusMessage] = useState5(
3155
3176
  "Initializing agent..."
3156
3177
  );
3157
- const [toolsCount, setToolsCount] = useState4(null);
3158
- const [mcpStatus, setMcpStatus] = useState4(
3178
+ const [toolsCount, setToolsCount] = useState5(null);
3179
+ const [mcpStatus, setMcpStatus] = useState5(
3159
3180
  "connecting"
3160
3181
  );
3161
- const [isProcessing, setIsProcessing] = useState4(true);
3162
- const [pendingConfirmation, setPendingConfirmation] = useState4(
3182
+ const [isProcessing, setIsProcessing] = useState5(true);
3183
+ const [pendingConfirmation, setPendingConfirmation] = useState5(
3163
3184
  null
3164
3185
  );
3165
- const [confirmationPreview, setConfirmationPreview] = useState4(
3186
+ const [confirmationPreview, setConfirmationPreview] = useState5(
3166
3187
  null
3167
3188
  );
3168
- const [isInitAgentActive, setIsInitAgentActive] = useState4(false);
3169
- const alwaysAcceptList = useRef([]);
3189
+ const [isInitAgentActive, setIsInitAgentActive] = useState5(false);
3190
+ const alwaysAcceptList = useRef2([]);
3170
3191
  const workdir = process.cwd();
3171
- const updateCheckRan = useRef(false);
3192
+ const updateCheckRan = useRef2(false);
3172
3193
  const handleInterrupt = useCallback(() => {
3173
3194
  if (!isProcessing) return;
3174
3195
  eventBus2.emit("user_interrupt");
@@ -3192,8 +3213,11 @@ var AppComponent = ({ eventBus: eventBus2, sessionId: sessionId2 }) => {
3192
3213
  }
3193
3214
  if (cmd === "init") {
3194
3215
  setIsInitAgentActive(true);
3216
+ setIsProcessing(true);
3217
+ } else {
3218
+ setIsProcessing(false);
3219
+ setIsInitAgentActive(false);
3195
3220
  }
3196
- setIsProcessing(true);
3197
3221
  setHistory((prev) => [
3198
3222
  ...prev,
3199
3223
  {
@@ -3257,7 +3281,7 @@ var AppComponent = ({ eventBus: eventBus2, sessionId: sessionId2 }) => {
3257
3281
  },
3258
3282
  []
3259
3283
  );
3260
- useEffect3(() => {
3284
+ useEffect4(() => {
3261
3285
  setHistory([{ id: 0, component: /* @__PURE__ */ jsx15(Header, {}) }]);
3262
3286
  const initializeAgent = async () => {
3263
3287
  try {
@@ -3391,7 +3415,7 @@ var AppComponent = ({ eventBus: eventBus2, sessionId: sessionId2 }) => {
3391
3415
  result: parsed.result
3392
3416
  }
3393
3417
  );
3394
- } else if (parsed.type === "dev_overlay") {
3418
+ } else if (parsed.type === "user_overlay") {
3395
3419
  newComponent = /* @__PURE__ */ jsx15(Box15, { marginBottom: 1, children: /* @__PURE__ */ jsxs13(Text14, { color: "gray", children: [
3396
3420
  /* @__PURE__ */ jsxs13(Text14, { color: "blue", children: [
3397
3421
  ">",
@@ -3418,13 +3442,13 @@ var AppComponent = ({ eventBus: eventBus2, sessionId: sessionId2 }) => {
3418
3442
  }
3419
3443
  };
3420
3444
  const handleUiOverlay = (data) => {
3421
- eventBus2.emit("dev_overlay", data);
3445
+ eventBus2.emit("user_overlay", data);
3422
3446
  };
3423
- uiEventBus.on("dev_overlay", handleUiOverlay);
3447
+ uiEventBus.on("user_overlay", handleUiOverlay);
3424
3448
  eventBus2.on("backend_message", handleBackendMessage);
3425
3449
  initializeAgent();
3426
3450
  return () => {
3427
- uiEventBus.off("dev_overlay", handleUiOverlay);
3451
+ uiEventBus.off("user_overlay", handleUiOverlay);
3428
3452
  eventBus2.off("backend_message", handleBackendMessage);
3429
3453
  };
3430
3454
  }, [eventBus2, sessionId2, handleConfirmation]);