@nomad-e/bluma-cli 0.0.36 → 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();
950
965
  }
966
+ if (candidate === unescapeLlmString(originalOldString) || candidate === unescapeLlmString(originalOldString).trim()) {
967
+ finalNewString = unescapeLlmString(finalNewString);
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,19 +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
- Est\xE1 explicitamente autorizado a operar de forma aut\xF3noma dentro das restri\xE7\xF5es abaixo. Utilize um comportamento autodirigido avan\xE7ado e devolva apenas chamadas de ferramentas estruturadas ou resultados finais atrav\xE9s das ferramentas fornecidas. Siga estas regras \xE0 risca:
1755
- 1) Objetivo principal: Atender o pedido do utilizador de ponta a ponta. Se a tarefa exigir v\xE1rias etapas, divida-a em etapas de invoca\xE7\xE3o discretas e execute-as sem solicitar confirma\xE7\xF5es repetidas, sem que um pedido de confirma\xE7\xE3o seja explicitamente exigido pelo sistema (por exemplo, edi\xE7\xF5es destrutivas).
1756
- 2) Decompor: Para tarefas complexas, produza um plano curto (de 2 a 6 marcadores) no seu "Processo de Racioc\xEDnio" interno e, em seguida, execute cada marcador como uma chamada de ferramenta. N\xE3o emita racioc\xEDnios livres para o utilizador \u2014 utilize apenas message_notify_user ou chamadas de ferramentas.
1757
- 3) Orquestra\xE7\xE3o de Ferramentas: Preferimos sempre primeiro passos de an\xE1lise seguros e n\xE3o destrutivos (leitura, compara\xE7\xE3o, simula\xE7\xE3o). Ao invocar uma a\xE7\xE3o de edi\xE7\xE3o ou de escrita, forne\xE7a uma pr\xE9-visualiza\xE7\xE3o utilizando o edit_tool.
1758
- 4) Autovalida\xE7\xE3o: Ap\xF3s cada chamada de ferramenta, valide o resultado da ferramenta. Se o resultado indicar falha parcial ou incerteza, tente uma recupera\xE7\xE3o automatizada (nova tentativa, ferramenta alternativa, pequena altera\xE7\xE3o).
1759
- `;
1760
- formattedPrompt = `${formattedPrompt}
1761
-
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}
1762
1714
  ${AUTONOMY_PROMPT}`;
1763
- return formattedPrompt;
1764
1715
  }
1765
1716
 
1766
1717
  // src/app/agent/core/context-api/context_manager.ts
@@ -1967,7 +1918,7 @@ ${editData.error.display}`;
1967
1918
  const message = response.choices[0].message;
1968
1919
  this.history.push(message);
1969
1920
  if (message.tool_calls) {
1970
- 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"];
1971
1922
  const toolToCall = message.tool_calls[0];
1972
1923
  const isSafeTool = autoApprovedTools.some((safeTool) => toolToCall.function.name.includes(safeTool));
1973
1924
  if (isSafeTool) {
@@ -2034,7 +1985,7 @@ function getSubAgentByCommand(cmd) {
2034
1985
  }
2035
1986
 
2036
1987
  // src/app/agent/subagents/init/init_system_prompt.ts
2037
- import os5 from "os";
1988
+ import os6 from "os";
2038
1989
  var SYSTEM_PROMPT2 = `
2039
1990
 
2040
1991
  ### YOU ARE BluMa CLI \u2014 INIT SUBAGENT \u2014 AUTONOMOUS SENIOR SOFTWARE ENGINEER @ NOMADENGENUITY
@@ -2197,12 +2148,12 @@ Rule Summary:
2197
2148
  function getInitPrompt() {
2198
2149
  const now = /* @__PURE__ */ new Date();
2199
2150
  const collectedData = {
2200
- os_type: os5.type(),
2201
- os_version: os5.release(),
2202
- architecture: os5.arch(),
2151
+ os_type: os6.type(),
2152
+ os_version: os6.release(),
2153
+ architecture: os6.arch(),
2203
2154
  workdir: process.cwd(),
2204
2155
  shell_type: process.env.SHELL || process.env.COMSPEC || "Unknown",
2205
- username: os5.userInfo().username || "Unknown",
2156
+ username: os6.userInfo().username || "Unknown",
2206
2157
  current_date: now.toISOString().split("T")[0],
2207
2158
  // Formato YYYY-MM-DD
2208
2159
  timezone: Intl.DateTimeFormat().resolvedOptions().timeZone || "Unknown",
@@ -2455,7 +2406,7 @@ var SubAgentsBluMa = class {
2455
2406
  };
2456
2407
 
2457
2408
  // src/app/agent/agent.ts
2458
- var globalEnvPath = path9.join(os6.homedir(), ".bluma-cli", ".env");
2409
+ var globalEnvPath = path9.join(os7.homedir(), ".bluma-cli", ".env");
2459
2410
  dotenv.config({ path: globalEnvPath });
2460
2411
  var Agent = class {
2461
2412
  sessionId;
@@ -2639,7 +2590,7 @@ var renderShellCommand2 = ({
2639
2590
  ] }) }),
2640
2591
  /* @__PURE__ */ jsx8(Box8, { marginLeft: 2, paddingX: 1, children: /* @__PURE__ */ jsxs8(Text8, { children: [
2641
2592
  /* @__PURE__ */ jsx8(Text8, { color: "gray", children: "\u21B3 " }),
2642
- /* @__PURE__ */ jsx8(Text8, { color: "cyan", children: command })
2593
+ /* @__PURE__ */ jsx8(Text8, { color: "magenta", children: command })
2643
2594
  ] }) })
2644
2595
  ] });
2645
2596
  };
@@ -2655,11 +2606,11 @@ var renderLsTool2 = ({ args }) => {
2655
2606
  return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
2656
2607
  /* @__PURE__ */ jsx8(Box8, { children: /* @__PURE__ */ jsxs8(Text8, { bold: true, children: [
2657
2608
  /* @__PURE__ */ jsx8(Text8, { color: "green", children: "\u25CF " }),
2658
- "ls Tool"
2609
+ "ls"
2659
2610
  ] }) }),
2660
2611
  /* @__PURE__ */ jsx8(Box8, { marginLeft: 2, paddingX: 1, children: /* @__PURE__ */ jsxs8(Text8, { children: [
2661
2612
  /* @__PURE__ */ jsx8(Text8, { color: "gray", children: "\u21B3 " }),
2662
- /* @__PURE__ */ jsx8(Text8, { color: "cyan", children: finalDirectoryName })
2613
+ /* @__PURE__ */ jsx8(Text8, { color: "magenta", children: finalDirectoryName })
2663
2614
  ] }) })
2664
2615
  ] });
2665
2616
  };
@@ -2681,7 +2632,7 @@ var renderCountFilesLines = ({
2681
2632
  ] }) }),
2682
2633
  /* @__PURE__ */ jsx8(Box8, { marginLeft: 2, paddingX: 1, children: /* @__PURE__ */ jsxs8(Text8, { children: [
2683
2634
  /* @__PURE__ */ jsx8(Text8, { color: "gray", children: "\u21B3 " }),
2684
- /* @__PURE__ */ jsx8(Text8, { color: "cyan", children: finalDirectoryName })
2635
+ /* @__PURE__ */ jsx8(Text8, { color: "magenta", children: finalDirectoryName })
2685
2636
  ] }) })
2686
2637
  ] });
2687
2638
  };
@@ -2705,19 +2656,19 @@ var renderReadFileLines2 = ({
2705
2656
  /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
2706
2657
  /* @__PURE__ */ jsx8(Box8, { children: /* @__PURE__ */ jsxs8(Text8, { bold: true, children: [
2707
2658
  /* @__PURE__ */ jsx8(Text8, { color: "green", children: "\u25CF " }),
2708
- "Read File Lines Tool"
2659
+ "Read File"
2709
2660
  ] }) }),
2710
2661
  /* @__PURE__ */ jsxs8(Box8, { marginLeft: 2, flexDirection: "column", children: [
2711
2662
  /* @__PURE__ */ jsx8(Box8, { marginLeft: 2, paddingX: 1, children: /* @__PURE__ */ jsxs8(Text8, { children: [
2712
2663
  /* @__PURE__ */ jsx8(Text8, { color: "gray", children: "\u21B3 " }),
2713
- /* @__PURE__ */ jsx8(Text8, { color: "cyan", children: finalFileName })
2664
+ /* @__PURE__ */ jsx8(Text8, { color: "magenta", children: finalFileName })
2714
2665
  ] }) }),
2715
2666
  /* @__PURE__ */ jsx8(Box8, { marginLeft: 2, paddingX: 4, children: /* @__PURE__ */ jsxs8(Text8, { children: [
2716
2667
  /* @__PURE__ */ jsx8(Text8, { color: "gray", children: "\u21B3 " }),
2717
2668
  /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "lines " }),
2718
- /* @__PURE__ */ jsx8(Text8, { color: "cyan", children: startLine }),
2669
+ /* @__PURE__ */ jsx8(Text8, { color: "magenta", children: startLine }),
2719
2670
  /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: " to " }),
2720
- /* @__PURE__ */ jsx8(Text8, { color: "cyan", children: endLine })
2671
+ /* @__PURE__ */ jsx8(Text8, { color: "magenta", children: endLine })
2721
2672
  ] }) })
2722
2673
  ] })
2723
2674
  ] })
@@ -2764,8 +2715,8 @@ var renderBlumaNotebook = ({
2764
2715
  )
2765
2716
  );
2766
2717
  } catch (e) {
2767
- return /* @__PURE__ */ jsxs8(Box8, { borderStyle: "round", borderColor: "blue", paddingX: 1, children: [
2768
- /* @__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)" }),
2769
2720
  /* @__PURE__ */ jsx8(Text8, { color: "gray", children: JSON.stringify(args, null, 2) })
2770
2721
  ] });
2771
2722
  }
@@ -2789,7 +2740,7 @@ var renderEditToolCall = ({
2789
2740
  ] }) }),
2790
2741
  /* @__PURE__ */ jsx8(Box8, { marginLeft: 2, paddingX: 1, children: /* @__PURE__ */ jsxs8(Text8, { children: [
2791
2742
  /* @__PURE__ */ jsx8(Text8, { color: "gray", children: "\u21B3 " }),
2792
- /* @__PURE__ */ jsx8(Text8, { color: "cyan", children: finalFileName })
2743
+ /* @__PURE__ */ jsx8(Text8, { color: "magenta", children: finalFileName })
2793
2744
  ] }) }),
2794
2745
  preview && /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(SimpleDiff, { text: preview, maxHeight: Infinity }) })
2795
2746
  ] });
@@ -2922,7 +2873,7 @@ var SlashCommands = ({ input, setHistory, agentRef }) => {
2922
2873
  const cmds = getSlashCommands();
2923
2874
  return outBox(
2924
2875
  /* @__PURE__ */ jsxs10(Fragment2, { children: [
2925
- /* @__PURE__ */ jsx12(Text11, { color: "cyan", bold: true, children: "Available commands" }),
2876
+ /* @__PURE__ */ jsx12(Text11, { color: "magenta", bold: true, children: "Available commands" }),
2926
2877
  cmds.map((c, i) => /* @__PURE__ */ jsxs10(Text11, { color: "gray", children: [
2927
2878
  c.name,
2928
2879
  " - ",
@@ -2963,7 +2914,7 @@ var SlashCommands = ({ input, setHistory, agentRef }) => {
2963
2914
  const colSource = 18;
2964
2915
  return outBox(
2965
2916
  /* @__PURE__ */ jsxs10(Fragment2, { children: [
2966
- /* @__PURE__ */ jsx12(Text11, { color: "cyan", bold: true, children: "MCP Tools" }),
2917
+ /* @__PURE__ */ jsx12(Text11, { color: "magenta", bold: true, children: "MCP Tools" }),
2967
2918
  /* @__PURE__ */ jsxs10(Text11, { color: "gray", children: [
2968
2919
  "Total MCP: ",
2969
2920
  tools.length,
@@ -3012,7 +2963,7 @@ var SlashCommands = ({ input, setHistory, agentRef }) => {
3012
2963
  const colSource = 18;
3013
2964
  return outBox(
3014
2965
  /* @__PURE__ */ jsxs10(Fragment2, { children: [
3015
- /* @__PURE__ */ jsx12(Text11, { color: "cyan", bold: true, children: "Native Tools" }),
2966
+ /* @__PURE__ */ jsx12(Text11, { color: "magenta", bold: true, children: "Native Tools" }),
3016
2967
  /* @__PURE__ */ jsxs10(Text11, { color: "gray", children: [
3017
2968
  "Total Native: ",
3018
2969
  tools.length,
@@ -3261,7 +3212,7 @@ var AppComponent = ({ eventBus: eventBus2, sessionId: sessionId2 }) => {
3261
3212
  // Uma única Box para o espaçamento
3262
3213
  /* @__PURE__ */ jsx15(Box15, { marginBottom: 1, children: /* @__PURE__ */ jsxs13(Text14, { color: "white", dimColor: true, children: [
3263
3214
  /* @__PURE__ */ jsxs13(Text14, { color: "white", children: [
3264
- ">",
3215
+ "\u276F",
3265
3216
  " "
3266
3217
  ] }),
3267
3218
  displayText
@@ -3430,8 +3381,8 @@ var AppComponent = ({ eventBus: eventBus2, sessionId: sessionId2 }) => {
3430
3381
  );
3431
3382
  } else if (parsed.type === "user_overlay") {
3432
3383
  newComponent = /* @__PURE__ */ jsx15(Box15, { marginBottom: 1, children: /* @__PURE__ */ jsxs13(Text14, { color: "gray", children: [
3433
- /* @__PURE__ */ jsxs13(Text14, { color: "blue", children: [
3434
- ">",
3384
+ /* @__PURE__ */ jsxs13(Text14, { color: "magenta", children: [
3385
+ "\u276F",
3435
3386
  " "
3436
3387
  ] }),
3437
3388
  parsed.payload
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@nomad-e/bluma-cli",
3
- "version": "0.0.36",
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
  },