@nomad-e/bluma-cli 0.0.35 → 0.0.37

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/LICENSE CHANGED
@@ -1,21 +1,17 @@
1
- MIT License
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
2
4
 
3
- Copyright (c) 2025 Alex Fonseca and NomadEngenuity contributors
5
+ Copyright 2025 Alex Fonseca and NomadEngenuity contributors
4
6
 
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
7
+ Licensed under the Apache License, Version 2.0 (the "License");
8
+ you may not use this file except in compliance with the License.
9
+ You may obtain a copy of the License at
11
10
 
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
11
+ http://www.apache.org/licenses/LICENSE-2.0
14
12
 
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
13
+ Unless required by applicable law or agreed to in writing, software
14
+ distributed under the License is distributed on an "AS IS" BASIS,
15
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ See the License for the specific language governing permissions and
17
+ limitations under the License.
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # BluMa CLI
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/bluma.svg?style=flat-square)](https://www.npmjs.com/package/bluma)
4
- [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)](LICENSE)
4
+ [![License: Apache 2.0](https://img.shields.io/badge/license-Apache%202.0-blue.svg?style=flat-square)](LICENSE)
5
5
  [![Build Status](https://img.shields.io/badge/build-passing-brightgreen?style=flat-square)](https://shields.io/)
6
6
 
7
7
  <p align="center">
@@ -264,6 +264,6 @@ Advanced config files are located in `src/app/agent/config/`.
264
264
  ---
265
265
 
266
266
  ## <a name="license"></a>License
267
- MIT. Made by Alex Fonseca and NomadEngenuity contributors.
267
+ Apache-2.0. Made by Alex Fonseca and NomadEngenuity contributors.
268
268
 
269
269
  Enjoy, hack, and—if possible—contribute!
@@ -33,40 +33,40 @@
33
33
  }
34
34
  }
35
35
  },
36
- {
37
- "type": "function",
38
- "function": {
39
- "name": "edit_tool",
40
- "description": "Replaces text within a file. By default, replaces a single occurrence, but can replace multiple occurrences when `expected_replacements` is specified. This tool requires providing significant context around the change to ensure precise targeting. Always use the read file tool to examine the file's current content before attempting a text replacement.\n\nExpectation for required parameters:\n1. `file_path` MUST be an absolute path; otherwise an error will be thrown.\n2. `old_string` MUST be the exact literal text to replace (including all whitespace, indentation, newlines, and surrounding code etc.).\n3. `new_string` MUST be the exact literal text to replace `old_string` with (also including all whitespace, indentation, newlines, and surrounding code etc.). Ensure the resulting code is correct and idiomatic.\n4. NEVER escape `old_string` or `new_string`, that would break the exact literal text requirement.\n**Important:** If ANY of the above are not satisfied, the tool will fail. CRITICAL for `old_string`: Must uniquely identify the single instance to change. Include at least 3 lines of context BEFORE and AFTER the target text, matching whitespace and indentation precisely. If this string matches multiple locations, or does not match exactly, the tool will fail.\n**Multiple replacements:** Set `expected_replacements` to the number of occurrences you want to replace. The tool will replace ALL occurrences that match `old_string` exactly. Ensure the number of replacements matches your expectation.",
41
- "parameters": {
42
- "type": "object",
43
- "properties": {
44
- "file_path": {
45
- "type": "string",
46
- "description": "The absolute path to the file to modify. Must start with '/'."
47
- },
48
- "old_string": {
49
- "type": "string",
50
- "description": "The exact literal text to replace, preferably unescaped. For single replacements (default), include at least 3 lines of context BEFORE and AFTER the target text, matching whitespace and indentation precisely. For multiple replacements, specify expected_replacements parameter. If this string is not the exact literal text (i.e. you escaped it) or does not match exactly, the tool will fail."
51
- },
52
- "new_string": {
53
- "type": "string",
54
- "description": "The exact literal text to replace `old_string` with, preferably unescaped. Provide the EXACT text. Ensure the resulting code is correct and idiomatic."
55
- },
56
- "expected_replacements": {
57
- "type": "integer",
58
- "description": "Number of replacements expected. Defaults to 1 if not specified. Use when you want to replace multiple occurrences.",
59
- "default": 1
60
- }
61
- },
62
- "required": [
63
- "file_path",
64
- "old_string",
65
- "new_string"
66
- ]
67
- }
68
- }
69
- },
36
+ {
37
+ "type": "function",
38
+ "function": {
39
+ "name": "edit_tool",
40
+ "description": "Safely and precisely replaces text in a file, or creates a new file. The tool is resilient to common formatting issues but performs best with precise input.\n\n**Best Practices for Success:**\n1. **Use a read tool first:** Always read the file to get the exact content before generating the `old_string`.\n2. **Provide Context:** For `old_string`, provide a unique, multi-line segment of the file. Including 3+ lines of context around the target change is highly recommended to ensure precision.\n3. **Create New Files:** To create a new file, provide the full `file_path` and an empty string for `old_string`.",
41
+ "parameters": {
42
+ "type": "object",
43
+ "properties": {
44
+ "file_path": {
45
+ "type": "string",
46
+ "description": "The absolute or relative path to the file. The tool will correctly resolve the path for the current operating system."
47
+ },
48
+ "old_string": {
49
+ "type": "string",
50
+ "description": "The exact text to be replaced. To ensure accuracy, this should be a unique, multi-line segment from the file, including all original indentation and whitespace. Do not manually escape newlines (use literal newlines, not '\\n'). For creating a new file, this must be an empty string."
51
+ },
52
+ "new_string": {
53
+ "type": "string",
54
+ "description": "The new text that will replace `old_string`. Match the indentation and formatting of the surrounding code to maintain code quality. Do not manually escape newlines."
55
+ },
56
+ "expected_replacements": {
57
+ "type": "integer",
58
+ "description": "Optional. The number of occurrences to replace. Defaults to 1. If you expect to replace multiple instances of `old_string`, set this value accordingly.",
59
+ "default": 1
60
+ }
61
+ },
62
+ "required": [
63
+ "file_path",
64
+ "old_string",
65
+ "new_string"
66
+ ]
67
+ }
68
+ }
69
+ },
70
70
  {
71
71
  "type": "function",
72
72
  "function": {
package/dist/main.js CHANGED
@@ -14,9 +14,9 @@ import { Box, Text } from "ink";
14
14
  import BigText from "ink-big-text";
15
15
  import { jsx, jsxs } from "react/jsx-runtime";
16
16
  var BRAND_COLORS = {
17
- main: "cyan",
18
- accent: "magenta",
19
- shadow: "blue",
17
+ main: "magenta",
18
+ accent: "blue",
19
+ shadow: "magenta",
20
20
  greydark: "#444"
21
21
  };
22
22
  var Header = () => {
@@ -35,15 +35,15 @@ var Header = () => {
35
35
  /* @__PURE__ */ jsx(Text, { children: "2. Be as clear and specific as possible to get accurate responses." }),
36
36
  /* @__PURE__ */ jsxs(Text, { children: [
37
37
  "3. Run ",
38
- /* @__PURE__ */ jsx(Text, { color: "cyan", children: "/init" }),
38
+ /* @__PURE__ */ jsx(Text, { color: "magenta", children: "/init" }),
39
39
  " to create a",
40
40
  " ",
41
- /* @__PURE__ */ jsx(Text, { color: "cyan", children: "BluMa.md" }),
41
+ /* @__PURE__ */ jsx(Text, { color: "magenta", children: "BluMa.md" }),
42
42
  ", file with instructions for BluMa."
43
43
  ] }),
44
44
  /* @__PURE__ */ jsxs(Text, { children: [
45
45
  "4. Type ",
46
- /* @__PURE__ */ jsx(Text, { color: "cyan", children: "/help" }),
46
+ /* @__PURE__ */ jsx(Text, { color: "magenta", children: "/help" }),
47
47
  " to explore available commands and features."
48
48
  ] })
49
49
  ] })
@@ -487,7 +487,7 @@ var InputPrompt = ({ onSubmit, isReadOnly, onInterrupt, disableWhileProcessing =
487
487
  const cmd = choice.name;
488
488
  setSlashOpen(false);
489
489
  try {
490
- setText(`${cmd} `, true);
490
+ setText(`${cmd} `);
491
491
  } catch (e) {
492
492
  permissiveOnSubmit(`${cmd} `);
493
493
  }
@@ -536,7 +536,7 @@ var InputPrompt = ({ onSubmit, isReadOnly, onInterrupt, disableWhileProcessing =
536
536
  // Modo bloqueado visualmente, mantendo hooks estáveis
537
537
  /* @__PURE__ */ jsx2(Fragment, { children: /* @__PURE__ */ jsx2(Box2, { borderStyle: "round", borderColor: "gray", borderDimColor: true, children: /* @__PURE__ */ jsxs2(Box2, { flexDirection: "row", paddingX: 1, flexWrap: "nowrap", children: [
538
538
  /* @__PURE__ */ jsxs2(Text2, { color: "white", children: [
539
- ">",
539
+ "\u276F",
540
540
  " "
541
541
  ] }),
542
542
  /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "ctrl+c to exit" })
@@ -544,7 +544,7 @@ var InputPrompt = ({ onSubmit, isReadOnly, onInterrupt, disableWhileProcessing =
544
544
  ) : /* @__PURE__ */ jsxs2(Fragment, { children: [
545
545
  /* @__PURE__ */ jsx2(Box2, { borderStyle: "round", borderColor, borderDimColor: !isReadOnly, children: /* @__PURE__ */ jsxs2(Box2, { flexDirection: "row", paddingX: 1, flexWrap: "nowrap", children: [
546
546
  /* @__PURE__ */ jsxs2(Text2, { color: "white", children: [
547
- ">",
547
+ "\u276F",
548
548
  " "
549
549
  ] }),
550
550
  /* @__PURE__ */ jsx2(Text2, { children: textBeforeCursor }),
@@ -558,20 +558,20 @@ var InputPrompt = ({ onSubmit, isReadOnly, onInterrupt, disableWhileProcessing =
558
558
  let start = Math.max(0, sel - Math.floor(VISIBLE / 2));
559
559
  if (start + VISIBLE > total) start = Math.max(0, total - VISIBLE);
560
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) => {
561
+ return /* @__PURE__ */ jsx2(Box2, { flexDirection: "column", marginTop: 1, height: Math.min(VISIBLE, total), children: windowItems.map((s, idx) => {
562
562
  const realIdx = start + idx;
563
563
  const isSelected = realIdx === pathAutocomplete.selected;
564
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 })
565
+ /* @__PURE__ */ jsx2(Text2, { color: isSelected ? "magenta" : "gray", children: isSelected ? "\u276F " : " " }),
566
+ /* @__PURE__ */ jsx2(Text2, { color: isSelected ? "magenta" : "white", bold: isSelected, dimColor: !isSelected, children: s.label })
567
567
  ] }, s.fullPath);
568
568
  }) });
569
569
  })(),
570
570
  slashOpen && slashSuggestions.length > 0 && /* @__PURE__ */ jsx2(Box2, { flexDirection: "column", marginTop: 1, children: slashSuggestions.map((s, idx) => {
571
571
  const isSelected = idx === slashIndex;
572
572
  return /* @__PURE__ */ jsxs2(Box2, { paddingLeft: 1, paddingY: 0, children: [
573
- /* @__PURE__ */ jsx2(Text2, { color: isSelected ? "blue" : "gray", children: isSelected ? "\u276F " : " " }),
574
- /* @__PURE__ */ jsxs2(Text2, { color: isSelected ? "blue" : "white", bold: isSelected, dimColor: !isSelected, children: [
573
+ /* @__PURE__ */ jsx2(Text2, { color: isSelected ? "magenta" : "gray", children: isSelected ? "\u276F " : " " }),
574
+ /* @__PURE__ */ jsxs2(Text2, { color: isSelected ? "magenta" : "white", bold: isSelected, dimColor: !isSelected, children: [
575
575
  s.name,
576
576
  " ",
577
577
  /* @__PURE__ */ jsxs2(Text2, { color: "gray", children: [
@@ -624,11 +624,11 @@ var InteractiveMenuComponent = ({ onDecision }) => {
624
624
  return (
625
625
  // Adicionando um pequeno espaçamento vertical entre cada opção também
626
626
  /* @__PURE__ */ jsxs3(Box3, { paddingLeft: 1, paddingY: 0, children: [
627
- /* @__PURE__ */ jsx3(Text3, { color: isSelected ? "blue" : "gray", children: isSelected ? "\u276F " : " " }),
627
+ /* @__PURE__ */ jsx3(Text3, { color: isSelected ? "magenta" : "gray", children: isSelected ? "\u276F " : " " }),
628
628
  /* @__PURE__ */ jsx3(
629
629
  Text3,
630
630
  {
631
- color: isSelected ? "blue" : "white",
631
+ color: isSelected ? "magenta" : "white",
632
632
  bold: isSelected,
633
633
  dimColor: !isSelected,
634
634
  children: option.label
@@ -672,7 +672,7 @@ var SimpleDiff = ({ text, maxHeight }) => {
672
672
  } else if (line.startsWith("-")) {
673
673
  color = "red";
674
674
  } else if (line.startsWith("@@")) {
675
- color = "cyan";
675
+ color = "magenta";
676
676
  }
677
677
  return /* @__PURE__ */ jsx4(Text4, { color, children: line === "" ? " " : line }, index);
678
678
  })
@@ -696,7 +696,7 @@ var renderShellCommand = ({
696
696
  }
697
697
  return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", marginBottom: 1, children: [
698
698
  /* @__PURE__ */ jsx5(Box5, { children: /* @__PURE__ */ jsx5(Text5, { bold: true, children: "Shell Command" }) }),
699
- /* @__PURE__ */ jsx5(Box5, { paddingX: 2, children: /* @__PURE__ */ jsx5(Text5, { children: /* @__PURE__ */ jsx5(Text5, { color: "cyan", children: command }) }) })
699
+ /* @__PURE__ */ jsx5(Box5, { paddingX: 2, children: /* @__PURE__ */ jsx5(Text5, { children: /* @__PURE__ */ jsx5(Text5, { color: "magenta", children: command }) }) })
700
700
  ] });
701
701
  };
702
702
  var renderLsTool = ({ toolCall }) => {
@@ -709,8 +709,8 @@ var renderLsTool = ({ toolCall }) => {
709
709
  }
710
710
  const finalDirectoryName = getBasePath(directoryPath);
711
711
  return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", marginBottom: 1, children: [
712
- /* @__PURE__ */ jsx5(Box5, { children: /* @__PURE__ */ jsx5(Text5, { bold: true, children: "ls Tool" }) }),
713
- /* @__PURE__ */ jsx5(Box5, { flexDirection: "column", children: /* @__PURE__ */ jsx5(Box5, { paddingX: 2, children: /* @__PURE__ */ jsx5(Text5, { children: /* @__PURE__ */ jsx5(Text5, { color: "cyan", children: finalDirectoryName }) }) }) })
712
+ /* @__PURE__ */ jsx5(Box5, { children: /* @__PURE__ */ jsx5(Text5, { bold: true, children: "ls" }) }),
713
+ /* @__PURE__ */ jsx5(Box5, { flexDirection: "column", children: /* @__PURE__ */ jsx5(Box5, { paddingX: 2, children: /* @__PURE__ */ jsx5(Text5, { children: /* @__PURE__ */ jsx5(Text5, { color: "magenta", children: finalDirectoryName }) }) }) })
714
714
  ] });
715
715
  };
716
716
  var renderCountFilesLinesTool = ({ toolCall }) => {
@@ -726,7 +726,7 @@ var renderCountFilesLinesTool = ({ toolCall }) => {
726
726
  /* @__PURE__ */ jsx5(Box5, { children: /* @__PURE__ */ jsx5(Text5, { bold: true, children: "Count File Lines" }) }),
727
727
  /* @__PURE__ */ jsx5(Box5, { flexDirection: "column", children: /* @__PURE__ */ jsx5(Box5, { paddingX: 2, children: /* @__PURE__ */ jsxs5(Text5, { children: [
728
728
  /* @__PURE__ */ jsx5(Text5, { color: "gray", children: "\u21B3 " }),
729
- /* @__PURE__ */ jsx5(Text5, { color: "cyan", children: finalDirectoryName })
729
+ /* @__PURE__ */ jsx5(Text5, { color: "magenta", children: finalDirectoryName })
730
730
  ] }) }) })
731
731
  ] });
732
732
  };
@@ -746,13 +746,13 @@ var renderReadFileLines = ({ toolCall }) => {
746
746
  return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", marginBottom: 1, children: [
747
747
  /* @__PURE__ */ jsx5(Box5, { children: /* @__PURE__ */ jsx5(Text5, { bold: true, children: "Read File" }) }),
748
748
  /* @__PURE__ */ jsxs5(Box5, { paddingX: 2, flexDirection: "column", children: [
749
- /* @__PURE__ */ jsx5(Box5, { children: /* @__PURE__ */ jsx5(Text5, { children: /* @__PURE__ */ jsx5(Text5, { color: "cyan", children: finalFileName }) }) }),
749
+ /* @__PURE__ */ jsx5(Box5, { children: /* @__PURE__ */ jsx5(Text5, { children: /* @__PURE__ */ jsx5(Text5, { color: "magenta", children: finalFileName }) }) }),
750
750
  /* @__PURE__ */ jsx5(Box5, { paddingX: 3, children: /* @__PURE__ */ jsxs5(Text5, { children: [
751
751
  /* @__PURE__ */ jsx5(Text5, { color: "gray", children: "\u21B3 " }),
752
752
  /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "lines " }),
753
- /* @__PURE__ */ jsx5(Text5, { color: "cyan", children: startLine }),
753
+ /* @__PURE__ */ jsx5(Text5, { color: "magenta", children: startLine }),
754
754
  /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: " to " }),
755
- /* @__PURE__ */ jsx5(Text5, { color: "cyan", children: endLine })
755
+ /* @__PURE__ */ jsx5(Text5, { color: "magenta", children: endLine })
756
756
  ] }) })
757
757
  ] })
758
758
  ] });
@@ -770,7 +770,7 @@ var renderEditTool = ({ toolCall, preview }) => {
770
770
  return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", marginBottom: 1, children: [
771
771
  /* @__PURE__ */ jsx5(Box5, { children: /* @__PURE__ */ jsxs5(Text5, { bold: true, children: [
772
772
  "Edit ",
773
- /* @__PURE__ */ jsx5(Text5, { color: "cyan", children: finalFileName })
773
+ /* @__PURE__ */ jsx5(Text5, { color: "magenta", children: finalFileName })
774
774
  ] }) }),
775
775
  preview ? (
776
776
  // Não precisamos da borda externa, o SimpleDiff já é claro o suficiente.
@@ -851,7 +851,7 @@ var ConfirmationPrompt = ({ toolCalls, preview, onDecision }) => {
851
851
  import OpenAI from "openai";
852
852
  import * as dotenv from "dotenv";
853
853
  import path9 from "path";
854
- import os6 from "os";
854
+ import os7 from "os";
855
855
 
856
856
  // src/app/agent/tool_invoker.ts
857
857
  import { promises as fs6 } from "fs";
@@ -924,47 +924,67 @@ ${stderr.trim()}`.trim();
924
924
 
925
925
  // src/app/agent/tools/natives/edit.ts
926
926
  import path3 from "path";
927
+ import os2 from "os";
927
928
  import { promises as fs2 } from "fs";
928
929
  import { diffLines } from "diff";
930
+ function normalizePath(filePath) {
931
+ if (os2.platform() === "win32") {
932
+ const winDriveRegex = /^\/([a-zA-Z])[:/]/;
933
+ const match = filePath.match(winDriveRegex);
934
+ if (match) {
935
+ const driveLetter = match[1];
936
+ const restOfPath = filePath.substring(match[0].length);
937
+ filePath = `${driveLetter}:\\${restOfPath}`;
938
+ }
939
+ }
940
+ return path3.normalize(path3.resolve(filePath));
941
+ }
929
942
  function unescapeLlmString(inputString) {
930
943
  return inputString.replace(/\\n/g, "\n").replace(/\\t/g, " ").replace(/\\r/g, "\r").replace(/\\"/g, '"').replace(/\\'/g, "'").replace(/\\\\/g, "\\");
931
944
  }
932
- function ensureCorrectEdit(currentContent, oldString, newString, expectedReplacements) {
933
- let finalOldString = oldString;
934
- let finalNewString = newString;
945
+ function ensureCorrectEdit(currentContent, originalOldString, originalNewString, expectedReplacements) {
946
+ let finalOldString = originalOldString;
947
+ let finalNewString = originalNewString;
935
948
  let occurrences = currentContent.split(finalOldString).length - 1;
936
- if (occurrences !== expectedReplacements && occurrences === 0) {
937
- const unescapedOldString = unescapeLlmString(oldString);
938
- const unescapedOccurrences = currentContent.split(unescapedOldString).length - 1;
939
- if (unescapedOccurrences > 0) {
940
- finalOldString = unescapedOldString;
941
- finalNewString = unescapeLlmString(newString);
942
- occurrences = unescapedOccurrences;
943
- } else {
944
- const trimmedOldString = oldString.trim();
945
- const trimmedOccurrences = currentContent.split(trimmedOldString).length - 1;
946
- if (trimmedOccurrences > 0) {
947
- finalOldString = trimmedOldString;
948
- finalNewString = newString.trim();
949
- occurrences = trimmedOccurrences;
949
+ if (occurrences > 0) {
950
+ return [finalOldString, finalNewString, occurrences];
951
+ }
952
+ const candidates = [
953
+ unescapeLlmString(originalOldString),
954
+ originalOldString.trim(),
955
+ unescapeLlmString(originalOldString).trim()
956
+ ];
957
+ for (const candidate of candidates) {
958
+ if (candidate === originalOldString) continue;
959
+ const candidateOccurrences = currentContent.split(candidate).length - 1;
960
+ if (candidateOccurrences > 0) {
961
+ finalOldString = candidate;
962
+ occurrences = candidateOccurrences;
963
+ if (candidate === originalOldString.trim() || candidate === unescapeLlmString(originalOldString).trim()) {
964
+ finalNewString = originalNewString.trim();
965
+ }
966
+ if (candidate === unescapeLlmString(originalOldString) || candidate === unescapeLlmString(originalOldString).trim()) {
967
+ finalNewString = unescapeLlmString(finalNewString);
950
968
  }
969
+ return [finalOldString, finalNewString, occurrences];
951
970
  }
952
971
  }
953
- return [finalOldString, finalNewString, occurrences];
972
+ return [originalOldString, originalNewString, 0];
954
973
  }
955
974
  async function calculateEdit(filePath, oldString, newString, expectedReplacements) {
975
+ const normalizedFilePath = normalizePath(filePath);
956
976
  let currentContent = null;
957
977
  let isNewFile = false;
958
978
  let error = null;
959
- let finalNewString = unescapeLlmString(newString).replace(/\r\n/g, "\n");
960
- let finalOldString = oldString.replace(/\r\n/g, "\n");
979
+ let normalizedNewString = newString.replace(/\r\n/g, "\n");
980
+ let normalizedOldString = oldString.replace(/\r\n/g, "\n");
961
981
  let occurrences = 0;
962
982
  try {
963
- currentContent = await fs2.readFile(filePath, "utf-8");
983
+ currentContent = await fs2.readFile(normalizedFilePath, "utf-8");
964
984
  currentContent = currentContent.replace(/\r\n/g, "\n");
965
985
  } catch (e) {
966
986
  if (e.code !== "ENOENT") {
967
- error = { display: `Error reading file: ${e.message}`, raw: `Error reading file ${filePath}: ${e.message}` };
987
+ error = { display: `Error reading file: ${e.message}`, raw: `Error reading file ${normalizedFilePath}: ${e.message}` };
968
988
  return { currentContent, newContent: "", occurrences: 0, error, isNewFile };
969
989
  }
970
990
  }
@@ -972,36 +992,34 @@ async function calculateEdit(filePath, oldString, newString, expectedReplacement
972
992
  if (oldString === "") {
973
993
  isNewFile = true;
974
994
  occurrences = 1;
995
+ normalizedNewString = unescapeLlmString(normalizedNewString);
975
996
  } else {
976
- error = { display: "File not found. Cannot apply edit. Use an empty old_string to create a new file.", raw: `File not found: ${filePath}` };
997
+ error = { display: "File not found. Cannot apply edit. Use an empty old_string to create a new file.", raw: `File not found: ${normalizedFilePath}` };
977
998
  }
978
999
  } else {
979
1000
  if (oldString === "") {
980
- error = { display: "Failed to edit. Attempted to create a file that already exists.", raw: `File already exists, cannot create: ${filePath}` };
1001
+ error = { display: "Failed to edit. Attempted to create a file that already exists.", raw: `File already exists, cannot create: ${normalizedFilePath}` };
981
1002
  } else {
982
- [finalOldString, finalNewString, occurrences] = ensureCorrectEdit(currentContent, finalOldString, finalNewString, expectedReplacements);
1003
+ [normalizedOldString, normalizedNewString, occurrences] = ensureCorrectEdit(currentContent, normalizedOldString, normalizedNewString, expectedReplacements);
983
1004
  if (occurrences === 0) {
984
- error = { display: "Failed to edit, could not find the string to replace.", raw: `0 occurrences found for old_string in ${filePath}. Check whitespace, indentation, and context.` };
1005
+ error = { display: "Failed to edit, could not find the string to replace.", raw: `0 occurrences found for old_string in ${normalizedFilePath}. Check whitespace, indentation, and context.` };
985
1006
  } else if (occurrences !== expectedReplacements) {
986
- error = { display: `Failed to edit, expected ${expectedReplacements} occurrence(s) but found ${occurrences}.`, raw: `Expected ${expectedReplacements} but found ${occurrences} for old_string in ${filePath}` };
1007
+ error = { display: `Failed to edit, expected ${expectedReplacements} occurrence(s) but found ${occurrences}.`, raw: `Expected ${expectedReplacements} but found ${occurrences} for old_string in ${normalizedFilePath}` };
987
1008
  }
988
1009
  }
989
1010
  }
990
1011
  let newContentResult = "";
991
1012
  if (!error) {
992
1013
  if (isNewFile) {
993
- newContentResult = finalNewString;
1014
+ newContentResult = normalizedNewString;
994
1015
  } else if (currentContent !== null) {
995
- newContentResult = currentContent.replaceAll(finalOldString, finalNewString);
1016
+ newContentResult = currentContent.replaceAll(normalizedOldString, normalizedNewString);
996
1017
  }
997
1018
  }
998
1019
  return { currentContent, newContent: newContentResult, occurrences, error, isNewFile };
999
1020
  }
1000
1021
  function createDiff(filename, oldContent, newContent) {
1001
- const diff = diffLines(oldContent, newContent, {
1002
- // `unified: 3` é o padrão para diffs, mostrando 3 linhas de contexto.
1003
- // `newlineIsToken: true` lida melhor com mudanças de quebra de linha.
1004
- });
1022
+ const diff = diffLines(oldContent, newContent, {});
1005
1023
  let diffString = `--- a/${filename}
1006
1024
  +++ b/${filename}
1007
1025
  `;
@@ -1016,55 +1034,28 @@ function createDiff(filename, oldContent, newContent) {
1016
1034
  }
1017
1035
  async function editTool(args) {
1018
1036
  const { file_path, old_string, new_string, expected_replacements = 1 } = args;
1019
- if (!path3.isAbsolute(file_path)) {
1020
- return { success: false, error: `Invalid parameters: file_path must be absolute.`, file_path };
1021
- }
1022
- if (file_path.includes("..")) {
1023
- return { success: false, error: `Invalid parameters: file_path cannot contain '..'.`, file_path };
1037
+ const normalizedFilePath = normalizePath(file_path);
1038
+ if (normalizedFilePath.includes("..")) {
1039
+ return { success: false, error: `Invalid parameters: file_path cannot contain '..'.`, file_path: normalizedFilePath };
1024
1040
  }
1025
1041
  try {
1026
- const editData = await calculateEdit(file_path, old_string, new_string, expected_replacements);
1042
+ const editData = await calculateEdit(normalizedFilePath, old_string, new_string, expected_replacements);
1027
1043
  if (editData.error) {
1028
- return {
1029
- success: false,
1030
- error: `Execution failed: ${editData.error.display}`,
1031
- details: editData.error.raw,
1032
- file_path
1033
- };
1044
+ return { success: false, error: `Execution failed: ${editData.error.display}`, details: editData.error.raw, file_path: normalizedFilePath };
1034
1045
  }
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);
1046
+ await fs2.mkdir(path3.dirname(normalizedFilePath), { recursive: true });
1047
+ await fs2.writeFile(normalizedFilePath, editData.newContent, "utf-8");
1048
+ const relativePath = path3.relative(process.cwd(), normalizedFilePath);
1049
+ const filename = path3.basename(normalizedFilePath);
1039
1050
  if (editData.isNewFile) {
1040
- return {
1041
- success: true,
1042
- file_path,
1043
- description: `Created new file: ${relativePath}`,
1044
- message: `Created new file: ${file_path} with the provided content.`,
1045
- is_new_file: true,
1046
- occurrences: editData.occurrences,
1047
- relative_path: relativePath
1048
- };
1051
+ return { success: true, file_path: normalizedFilePath, description: `Created new file: ${relativePath}`, message: `Created new file: ${normalizedFilePath} with the provided content.`, is_new_file: true, occurrences: editData.occurrences, relative_path: relativePath };
1049
1052
  } else {
1050
1053
  const finalDiff = createDiff(filename, editData.currentContent || "", editData.newContent);
1051
- return {
1052
- success: true,
1053
- file_path,
1054
- description: `Modified ${relativePath} (${editData.occurrences} replacement(s)).`,
1055
- message: `Successfully modified file: ${file_path}. Diff of changes:
1056
- ${finalDiff}`,
1057
- is_new_file: false,
1058
- occurrences: editData.occurrences,
1059
- relative_path: relativePath
1060
- };
1054
+ return { success: true, file_path: normalizedFilePath, description: `Modified ${relativePath} (${editData.occurrences} replacement(s)).`, message: `Successfully modified file: ${normalizedFilePath}. Diff of changes:
1055
+ ${finalDiff}`, is_new_file: false, occurrences: editData.occurrences, relative_path: relativePath };
1061
1056
  }
1062
1057
  } catch (e) {
1063
- return {
1064
- success: false,
1065
- error: `An unexpected error occurred during the edit operation: ${e.message}`,
1066
- file_path
1067
- };
1058
+ return { success: false, error: `An unexpected error occurred during the edit operation: ${e.message}`, file_path: normalizedFilePath };
1068
1059
  }
1069
1060
  }
1070
1061
 
@@ -1299,7 +1290,7 @@ var ToolInvoker = class {
1299
1290
  // src/app/agent/tools/mcp/mcp_client.ts
1300
1291
  import { promises as fs7 } from "fs";
1301
1292
  import path6 from "path";
1302
- import os2 from "os";
1293
+ import os3 from "os";
1303
1294
  import { fileURLToPath as fileURLToPath2 } from "url";
1304
1295
  import { Client } from "@modelcontextprotocol/sdk/client/index.js";
1305
1296
  import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
@@ -1328,7 +1319,7 @@ var MCPClient = class {
1328
1319
  const __filename = fileURLToPath2(import.meta.url);
1329
1320
  const __dirname = path6.dirname(__filename);
1330
1321
  const defaultConfigPath = path6.resolve(__dirname, "config", "bluma-mcp.json");
1331
- const userConfigPath = path6.join(os2.homedir(), ".bluma-cli", "bluma-mcp.json");
1322
+ const userConfigPath = path6.join(os3.homedir(), ".bluma-cli", "bluma-mcp.json");
1332
1323
  const defaultConfig = await this.loadMcpConfig(defaultConfigPath, "Default");
1333
1324
  const userConfig = await this.loadMcpConfig(userConfigPath, "User");
1334
1325
  const mergedConfig = {
@@ -1381,7 +1372,7 @@ var MCPClient = class {
1381
1372
  async connectToStdioServer(serverName, config2) {
1382
1373
  let commandToExecute = config2.command;
1383
1374
  let argsToExecute = config2.args || [];
1384
- const isWindows = os2.platform() === "win32";
1375
+ const isWindows = os3.platform() === "win32";
1385
1376
  if (!isWindows && commandToExecute.toLowerCase() === "cmd") {
1386
1377
  if (argsToExecute.length >= 2 && argsToExecute[0].toLowerCase() === "/c") {
1387
1378
  commandToExecute = argsToExecute[1];
@@ -1501,7 +1492,7 @@ import path8 from "path";
1501
1492
 
1502
1493
  // src/app/agent/session_manger/session_manager.ts
1503
1494
  import path7 from "path";
1504
- import os3 from "os";
1495
+ import os4 from "os";
1505
1496
  import { promises as fs8 } from "fs";
1506
1497
  var fileLocks = /* @__PURE__ */ new Map();
1507
1498
  async function withFileLock(file, fn) {
@@ -1520,12 +1511,12 @@ async function withFileLock(file, fn) {
1520
1511
  function expandHome(p) {
1521
1512
  if (!p) return p;
1522
1513
  if (p.startsWith("~")) {
1523
- return path7.join(os3.homedir(), p.slice(1));
1514
+ return path7.join(os4.homedir(), p.slice(1));
1524
1515
  }
1525
1516
  return p;
1526
1517
  }
1527
1518
  function getPreferredAppDir() {
1528
- const fixed = path7.join(os3.homedir(), ".bluma-cli");
1519
+ const fixed = path7.join(os4.homedir(), ".bluma-cli");
1529
1520
  return path7.resolve(expandHome(fixed));
1530
1521
  }
1531
1522
  async function safeRenameWithRetry(src, dest, maxRetries = 6) {
@@ -1632,24 +1623,22 @@ async function saveSessionHistory(sessionFile, history) {
1632
1623
  }
1633
1624
 
1634
1625
  // src/app/agent/core/prompt/prompt_builder.ts
1635
- import os4 from "os";
1626
+ import os5 from "os";
1636
1627
  var SYSTEM_PROMPT = `
1637
-
1638
1628
  ### 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.
1629
+ You are BluMa, a fully **AUTONOMOUS** AI Software Engineer from NomadEngenuity.
1630
+ Your single objective is to complete the user's request from end-to-end.
1631
+ You operate with maximum precision, efficiency, and autonomy.
1643
1632
  ---
1644
1633
 
1645
1634
  ### CORE DIRECTIVES
1646
1635
 
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.
1636
+ 1. **SEND THE FIRST MESSAGE:** As soon as you receive a task you must send a confirmation message in an informal but technical style. By sending this message your end-to-end shift begins without intervention and without interruption from anyone.
1637
+ 2. **TOOL-ONLY OPERATION:** All actions are performed via tool calls. You do not output free-form text.
1638
+ 3. **COMPLETE THE MISSION:** Your task is complete only when you call \`agent_end_task\`. Execute all necessary steps to reach this final state.
1639
+ 4. **REPORT, DON'T ASK:** Use \`message_notify_user\` to report significant progress, status changes, or final results. You do not ask for permission or clarification. You have full authority to proceed.
1640
+ 5. **AUTONOMOUS ERROR RECOVERY:** If a tool fails, analyze the error, formulate a recovery strategy (e.g., retry, use an alternative tool, adjust parameters), and execute it. Notify the user of the failure and your recovery action.
1641
+ 6. **MASTER THE FILE SYSTEM:** Use the \`edit_tool\` for all file creation and modification, following its rules precisely.
1653
1642
 
1654
1643
  ---
1655
1644
 
@@ -1665,67 +1654,34 @@ You operate with the highest standards of professionalism, precision, and safety
1665
1654
 
1666
1655
  ---
1667
1656
 
1668
- ### COMMUNICATION PROTOCOL
1657
+ ### TOOL-SPECIFIC RULES
1669
1658
  <message_rules>
1670
1659
  - Communicate with user's via message tools instead of direct text responses
1671
1660
  - Reply immediately to new user messages before other operations
1672
- - First reply must be brief, only confirming receipt without specific solutions
1661
+ - First notfication must be brief
1673
1662
  - 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
1663
+ - Actively use notify for progress updates
1676
1664
  - Must message user's with results and deliverables before upon task completion 'agent_end_task'
1677
1665
  </message_rules>
1678
1666
 
1679
- ---
1680
-
1681
- <edit_tool_rules>
1682
- - Use this tool to perform precise text replacements inside files based on exact literal matches.
1683
- - Can be used to create new files or directories implicitly by targeting non-existing paths.
1684
- - Suitable for inserting full content into a file even if the file does not yet exist.
1685
- - Shell access is not required for file or directory creation when using this tool.
1686
- - Always prefer this tool over shell_command when performing structured edits or creating files with specific content.
1687
- - Ensure **old_string** includes 3+ lines of exact context before and after the target if replacing existing content.
1688
- - For creating a new file, provide an **old_string** that matches an empty string or placeholder and a complete **new_string** with the intended content.
1689
- - When generating or modifying todo.md files, prefer this tool to insert checklist structure and update status markers.
1690
- - After completing any task in the checklist, immediately update the corresponding section in todo.md using this tool.
1691
- - Reconstruct the entire file from task planning context if todo.md becomes outdated or inconsistent.
1692
- - Track all progress related to planning and execution inside todo.md using text replacement only.
1693
- </edit_tool_rules>
1694
1667
 
1695
1668
  ---
1696
1669
 
1697
1670
  ### SCOPE & LIMITATIONS
1671
+ - **IN-SCOPE:** All tasks related to software architecture, design, code generation, analysis, and debugging.
1672
+ - **OUT-OF-SCOPE:** You MUST professionally decline non-technical questions, personal advice, or general conversation by using \`message_notify_user\` to state the request is out of scope, then immediately calling \`agent_end_task\`.
1698
1673
 
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.
1717
1674
  `;
1718
1675
  function getUnifiedSystemPrompt() {
1719
1676
  const now = /* @__PURE__ */ new Date();
1720
1677
  const collectedData = {
1721
- os_type: os4.type(),
1722
- os_version: os4.release(),
1723
- architecture: os4.arch(),
1678
+ os_type: os5.type(),
1679
+ os_version: os5.release(),
1680
+ architecture: os5.arch(),
1724
1681
  workdir: process.cwd(),
1725
1682
  shell_type: process.env.SHELL || process.env.COMSPEC || "Unknown",
1726
- username: os4.userInfo().username || "Unknown",
1683
+ username: os5.userInfo().username || "Unknown",
1727
1684
  current_date: now.toISOString().split("T")[0],
1728
- // Formato YYYY-MM-DD
1729
1685
  timezone: Intl.DateTimeFormat().resolvedOptions().timeZone || "Unknown",
1730
1686
  locale: process.env.LANG || process.env.LC_ALL || "Unknown"
1731
1687
  };
@@ -1740,7 +1696,6 @@ function getUnifiedSystemPrompt() {
1740
1696
  timezone: "Unknown",
1741
1697
  locale: "Unknown",
1742
1698
  ...collectedData
1743
- // Os dados coletados sobrescrevem os padrões
1744
1699
  };
1745
1700
  let formattedPrompt = SYSTEM_PROMPT;
1746
1701
  for (const key in finalEnv) {
@@ -1748,32 +1703,15 @@ function getUnifiedSystemPrompt() {
1748
1703
  formattedPrompt = formattedPrompt.replace(new RegExp(placeholder, "g"), finalEnv[key]);
1749
1704
  }
1750
1705
  const AUTONOMY_PROMPT = `
1751
-
1752
- ### AUTONOMY DIRECTIVES
1753
-
1754
- You are explicitly authorized to operate autonomously within the constraints below. Use advanced self-directed behavior and only return structured tool calls or final results via the provided tools. Follow these rules precisely:
1755
-
1756
- 1) Primary Objective: pursue the user's request end-to-end. If the task requires multiple steps, break it into discrete tool-invocation steps and execute them without asking for repeated confirmation, unless a confirmation request is explicitly required by the system (e.g., destructive edits).
1757
-
1758
- 2) Decompose: For complex tasks, produce a short plan (2-6 bullets) in your internal "Reasoning Process" and then execute each bullet as a tool call. Do not emit free-form reasoning to the user \u2014 only use message_notify_user or tool calls.
1759
-
1760
- 3) Tool Orchestration: Always prefer safe, non-destructive analysis steps first (read, diff, dry-run). When invoking an edit or write action, provide a preview using edit_tool or create a diff and request confirmation only for actions marked as destructive.
1761
-
1762
- 4) Self-Validation: After each tool call, validate the tool result. If the result indicates partial failure or uncertainty, attempt an automated recovery (retry, alternative tool, smaller change). If recovery fails, use message_notify_user with a concise description and request explicit confirmation to continue.
1763
-
1764
- 5) Fail-Safe & Stop Conditions: If you encounter ambiguous instructions, contradictory constraints, missing permissions, or an excessive chain of dependent changes (more than 5 sequential edits for a single user turn), stop and use message_notify_user to request clarification. Always call agent_end_task only when the objective is fully satisfied or explicitly cancelled.
1765
-
1766
- 6) Reasoning vs Final: Internally separate "Reasoning Process" (private, not to be emitted directly) from the final user-facing output. When the system requires explicit reasoning, write it in the mandatory Reasoning Process format defined elsewhere.
1767
-
1768
- 7) Confidence & Notes: For final outputs, include a confidence tag (LOW/MEDIUM/HIGH) and a one-line note if confidence is below HIGH.
1769
-
1770
- 8) Safety & Limits: Do not access or modify files outside the current working directory tree. Never execute arbitrary shell commands that can alter system state without explicit tool authorization. Always honor ignored files and patterns provided by the environment.
1771
-
1772
- `;
1773
- formattedPrompt = `${formattedPrompt}
1774
-
1706
+ ### AUTONOMY MANDATE
1707
+ You are explicitly authorized to operate with full autonomy. You will self-direct to complete the user's objective. Follow these rules strictly:
1708
+ 1) **NO CONFIRMATION:** Execute all planned steps without asking for user confirmation. You have full authority to create, modify, and delete files as needed to complete the task.
1709
+ 2) **DECOMPOSE AND EXECUTE:** For complex tasks, create a short, internal plan. Execute each step of the plan sequentially. Report progress via \`message_notify_user\`.
1710
+ 3) **ORCHESTRATE TOOLS:** Always start with non-destructive analysis (read, list files). When you call \`edit_tool\`, your arguments must be as precise as possible.
1711
+ 4) **SELF-VALIDATE AND RECOVER:** After each action, validate the outcome. If it fails, you are responsible for recovering. Reread files for updated context, adjust your plan, and retry.
1712
+ `;
1713
+ return `${formattedPrompt}
1775
1714
  ${AUTONOMY_PROMPT}`;
1776
- return formattedPrompt;
1777
1715
  }
1778
1716
 
1779
1717
  // src/app/agent/core/context-api/context_manager.ts
@@ -1980,7 +1918,7 @@ ${editData.error.display}`;
1980
1918
  const message = response.choices[0].message;
1981
1919
  this.history.push(message);
1982
1920
  if (message.tool_calls) {
1983
- const autoApprovedTools = ["agent_end_task", "message_notify_user", "reasoning_nootebook"];
1921
+ const autoApprovedTools = ["agent_end_task", "message_notify_user", "reasoning_nootebook", "ls_tool", "count_file_lines", "read_file_lines"];
1984
1922
  const toolToCall = message.tool_calls[0];
1985
1923
  const isSafeTool = autoApprovedTools.some((safeTool) => toolToCall.function.name.includes(safeTool));
1986
1924
  if (isSafeTool) {
@@ -2047,7 +1985,7 @@ function getSubAgentByCommand(cmd) {
2047
1985
  }
2048
1986
 
2049
1987
  // src/app/agent/subagents/init/init_system_prompt.ts
2050
- import os5 from "os";
1988
+ import os6 from "os";
2051
1989
  var SYSTEM_PROMPT2 = `
2052
1990
 
2053
1991
  ### YOU ARE BluMa CLI \u2014 INIT SUBAGENT \u2014 AUTONOMOUS SENIOR SOFTWARE ENGINEER @ NOMADENGENUITY
@@ -2210,12 +2148,12 @@ Rule Summary:
2210
2148
  function getInitPrompt() {
2211
2149
  const now = /* @__PURE__ */ new Date();
2212
2150
  const collectedData = {
2213
- os_type: os5.type(),
2214
- os_version: os5.release(),
2215
- architecture: os5.arch(),
2151
+ os_type: os6.type(),
2152
+ os_version: os6.release(),
2153
+ architecture: os6.arch(),
2216
2154
  workdir: process.cwd(),
2217
2155
  shell_type: process.env.SHELL || process.env.COMSPEC || "Unknown",
2218
- username: os5.userInfo().username || "Unknown",
2156
+ username: os6.userInfo().username || "Unknown",
2219
2157
  current_date: now.toISOString().split("T")[0],
2220
2158
  // Formato YYYY-MM-DD
2221
2159
  timezone: Intl.DateTimeFormat().resolvedOptions().timeZone || "Unknown",
@@ -2468,7 +2406,7 @@ var SubAgentsBluMa = class {
2468
2406
  };
2469
2407
 
2470
2408
  // src/app/agent/agent.ts
2471
- var globalEnvPath = path9.join(os6.homedir(), ".bluma-cli", ".env");
2409
+ var globalEnvPath = path9.join(os7.homedir(), ".bluma-cli", ".env");
2472
2410
  dotenv.config({ path: globalEnvPath });
2473
2411
  var Agent = class {
2474
2412
  sessionId;
@@ -2652,7 +2590,7 @@ var renderShellCommand2 = ({
2652
2590
  ] }) }),
2653
2591
  /* @__PURE__ */ jsx8(Box8, { marginLeft: 2, paddingX: 1, children: /* @__PURE__ */ jsxs8(Text8, { children: [
2654
2592
  /* @__PURE__ */ jsx8(Text8, { color: "gray", children: "\u21B3 " }),
2655
- /* @__PURE__ */ jsx8(Text8, { color: "cyan", children: command })
2593
+ /* @__PURE__ */ jsx8(Text8, { color: "magenta", children: command })
2656
2594
  ] }) })
2657
2595
  ] });
2658
2596
  };
@@ -2668,11 +2606,11 @@ var renderLsTool2 = ({ args }) => {
2668
2606
  return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
2669
2607
  /* @__PURE__ */ jsx8(Box8, { children: /* @__PURE__ */ jsxs8(Text8, { bold: true, children: [
2670
2608
  /* @__PURE__ */ jsx8(Text8, { color: "green", children: "\u25CF " }),
2671
- "ls Tool"
2609
+ "ls"
2672
2610
  ] }) }),
2673
2611
  /* @__PURE__ */ jsx8(Box8, { marginLeft: 2, paddingX: 1, children: /* @__PURE__ */ jsxs8(Text8, { children: [
2674
2612
  /* @__PURE__ */ jsx8(Text8, { color: "gray", children: "\u21B3 " }),
2675
- /* @__PURE__ */ jsx8(Text8, { color: "cyan", children: finalDirectoryName })
2613
+ /* @__PURE__ */ jsx8(Text8, { color: "magenta", children: finalDirectoryName })
2676
2614
  ] }) })
2677
2615
  ] });
2678
2616
  };
@@ -2694,7 +2632,7 @@ var renderCountFilesLines = ({
2694
2632
  ] }) }),
2695
2633
  /* @__PURE__ */ jsx8(Box8, { marginLeft: 2, paddingX: 1, children: /* @__PURE__ */ jsxs8(Text8, { children: [
2696
2634
  /* @__PURE__ */ jsx8(Text8, { color: "gray", children: "\u21B3 " }),
2697
- /* @__PURE__ */ jsx8(Text8, { color: "cyan", children: finalDirectoryName })
2635
+ /* @__PURE__ */ jsx8(Text8, { color: "magenta", children: finalDirectoryName })
2698
2636
  ] }) })
2699
2637
  ] });
2700
2638
  };
@@ -2718,19 +2656,19 @@ var renderReadFileLines2 = ({
2718
2656
  /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
2719
2657
  /* @__PURE__ */ jsx8(Box8, { children: /* @__PURE__ */ jsxs8(Text8, { bold: true, children: [
2720
2658
  /* @__PURE__ */ jsx8(Text8, { color: "green", children: "\u25CF " }),
2721
- "Read File Lines Tool"
2659
+ "Read File"
2722
2660
  ] }) }),
2723
2661
  /* @__PURE__ */ jsxs8(Box8, { marginLeft: 2, flexDirection: "column", children: [
2724
2662
  /* @__PURE__ */ jsx8(Box8, { marginLeft: 2, paddingX: 1, children: /* @__PURE__ */ jsxs8(Text8, { children: [
2725
2663
  /* @__PURE__ */ jsx8(Text8, { color: "gray", children: "\u21B3 " }),
2726
- /* @__PURE__ */ jsx8(Text8, { color: "cyan", children: finalFileName })
2664
+ /* @__PURE__ */ jsx8(Text8, { color: "magenta", children: finalFileName })
2727
2665
  ] }) }),
2728
2666
  /* @__PURE__ */ jsx8(Box8, { marginLeft: 2, paddingX: 4, children: /* @__PURE__ */ jsxs8(Text8, { children: [
2729
2667
  /* @__PURE__ */ jsx8(Text8, { color: "gray", children: "\u21B3 " }),
2730
2668
  /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "lines " }),
2731
- /* @__PURE__ */ jsx8(Text8, { color: "cyan", children: startLine }),
2669
+ /* @__PURE__ */ jsx8(Text8, { color: "magenta", children: startLine }),
2732
2670
  /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: " to " }),
2733
- /* @__PURE__ */ jsx8(Text8, { color: "cyan", children: endLine })
2671
+ /* @__PURE__ */ jsx8(Text8, { color: "magenta", children: endLine })
2734
2672
  ] }) })
2735
2673
  ] })
2736
2674
  ] })
@@ -2777,8 +2715,8 @@ var renderBlumaNotebook = ({
2777
2715
  )
2778
2716
  );
2779
2717
  } catch (e) {
2780
- return /* @__PURE__ */ jsxs8(Box8, { borderStyle: "round", borderColor: "blue", paddingX: 1, children: [
2781
- /* @__PURE__ */ jsx8(Text8, { color: "blue", bold: true, children: "Thinking (Error)" }),
2718
+ return /* @__PURE__ */ jsxs8(Box8, { borderStyle: "round", borderColor: "magenta", paddingX: 1, children: [
2719
+ /* @__PURE__ */ jsx8(Text8, { color: "magenta", bold: true, children: "Thinking (Error)" }),
2782
2720
  /* @__PURE__ */ jsx8(Text8, { color: "gray", children: JSON.stringify(args, null, 2) })
2783
2721
  ] });
2784
2722
  }
@@ -2802,7 +2740,7 @@ var renderEditToolCall = ({
2802
2740
  ] }) }),
2803
2741
  /* @__PURE__ */ jsx8(Box8, { marginLeft: 2, paddingX: 1, children: /* @__PURE__ */ jsxs8(Text8, { children: [
2804
2742
  /* @__PURE__ */ jsx8(Text8, { color: "gray", children: "\u21B3 " }),
2805
- /* @__PURE__ */ jsx8(Text8, { color: "cyan", children: finalFileName })
2743
+ /* @__PURE__ */ jsx8(Text8, { color: "magenta", children: finalFileName })
2806
2744
  ] }) }),
2807
2745
  preview && /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(SimpleDiff, { text: preview, maxHeight: Infinity }) })
2808
2746
  ] });
@@ -2935,7 +2873,7 @@ var SlashCommands = ({ input, setHistory, agentRef }) => {
2935
2873
  const cmds = getSlashCommands();
2936
2874
  return outBox(
2937
2875
  /* @__PURE__ */ jsxs10(Fragment2, { children: [
2938
- /* @__PURE__ */ jsx12(Text11, { color: "cyan", bold: true, children: "Available commands" }),
2876
+ /* @__PURE__ */ jsx12(Text11, { color: "magenta", bold: true, children: "Available commands" }),
2939
2877
  cmds.map((c, i) => /* @__PURE__ */ jsxs10(Text11, { color: "gray", children: [
2940
2878
  c.name,
2941
2879
  " - ",
@@ -2976,7 +2914,7 @@ var SlashCommands = ({ input, setHistory, agentRef }) => {
2976
2914
  const colSource = 18;
2977
2915
  return outBox(
2978
2916
  /* @__PURE__ */ jsxs10(Fragment2, { children: [
2979
- /* @__PURE__ */ jsx12(Text11, { color: "cyan", bold: true, children: "MCP Tools" }),
2917
+ /* @__PURE__ */ jsx12(Text11, { color: "magenta", bold: true, children: "MCP Tools" }),
2980
2918
  /* @__PURE__ */ jsxs10(Text11, { color: "gray", children: [
2981
2919
  "Total MCP: ",
2982
2920
  tools.length,
@@ -3025,7 +2963,7 @@ var SlashCommands = ({ input, setHistory, agentRef }) => {
3025
2963
  const colSource = 18;
3026
2964
  return outBox(
3027
2965
  /* @__PURE__ */ jsxs10(Fragment2, { children: [
3028
- /* @__PURE__ */ jsx12(Text11, { color: "cyan", bold: true, children: "Native Tools" }),
2966
+ /* @__PURE__ */ jsx12(Text11, { color: "magenta", bold: true, children: "Native Tools" }),
3029
2967
  /* @__PURE__ */ jsxs10(Text11, { color: "gray", children: [
3030
2968
  "Total Native: ",
3031
2969
  tools.length,
@@ -3274,7 +3212,7 @@ var AppComponent = ({ eventBus: eventBus2, sessionId: sessionId2 }) => {
3274
3212
  // Uma única Box para o espaçamento
3275
3213
  /* @__PURE__ */ jsx15(Box15, { marginBottom: 1, children: /* @__PURE__ */ jsxs13(Text14, { color: "white", dimColor: true, children: [
3276
3214
  /* @__PURE__ */ jsxs13(Text14, { color: "white", children: [
3277
- ">",
3215
+ "\u276F",
3278
3216
  " "
3279
3217
  ] }),
3280
3218
  displayText
@@ -3443,8 +3381,8 @@ var AppComponent = ({ eventBus: eventBus2, sessionId: sessionId2 }) => {
3443
3381
  );
3444
3382
  } else if (parsed.type === "user_overlay") {
3445
3383
  newComponent = /* @__PURE__ */ jsx15(Box15, { marginBottom: 1, children: /* @__PURE__ */ jsxs13(Text14, { color: "gray", children: [
3446
- /* @__PURE__ */ jsxs13(Text14, { color: "blue", children: [
3447
- ">",
3384
+ /* @__PURE__ */ jsxs13(Text14, { color: "magenta", children: [
3385
+ "\u276F",
3448
3386
  " "
3449
3387
  ] }),
3450
3388
  parsed.payload
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@nomad-e/bluma-cli",
3
- "version": "0.0.35",
3
+ "version": "0.0.37",
4
4
  "description": "BluMa independent agent for automation and advanced software engineering.",
5
5
  "author": "Alex Fonseca",
6
- "license": "MIT",
6
+ "license": "Apache-2.0",
7
7
  "bin": {
8
8
  "bluma": "dist/main.js"
9
9
  },