@nomad-e/bluma-cli 0.0.104 → 0.0.106

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # BluMa CLI
1
+ # BluMa — Base Language Unit · Model Agent
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/bluma.svg?style=flat-square)](https://www.npmjs.com/package/bluma)
4
4
  [![License: Apache 2.0](https://img.shields.io/badge/license-Apache%202.0-blue.svg?style=flat-square)](LICENSE)
@@ -8,16 +8,18 @@
8
8
  <img src="https://pharmaseedevsa.blob.core.windows.net/pharmassee-dev-storage/bluma.png" alt="Screenshot BluMa CLI" width="1000"/>
9
9
  </p>
10
10
 
11
- BluMa CLI is an independent agent for automation and advanced software engineering. The project is a conversational assistant that interacts via terminal (CLI), built with React/Ink, supporting smart agents (LLM, OpenAI Azure), tool execution, persistent history, session management, and extensibility through external plugins/tools.
11
+ BluMa is a CLI-based model agent responsible for language-level code generation, refactoring and semantic transformations in the Factor AI stack. The project is a conversational assistant that interacts via terminal (CLI), built with React/Ink, supporting smart agents (LLM via OpenRouter), tool execution, persistent history, session management, and extensibility through external plugins/tools.
12
12
 
13
13
  ---
14
14
 
15
15
  ## Table of Contents
16
16
  - [Overview](#overview)
17
+ - [Why BluMa?](#why-bluma)
17
18
  - [Key Features](#key-features)
18
19
  - [Requirements](#requirements)
19
- - [Architecture Diagram](#-architecture-diagram)
20
+ - [Quick Start](#quick-start)
20
21
  - [Installation](#installation)
22
+ - [Screenshots](#screenshots)
21
23
  - [Usage](#usage)
22
24
  - [Examples](#-usage-examples)
23
25
  - [Configuration and Environment Variables](#configuration-and-environment-variables)
@@ -33,14 +35,27 @@ BluMa CLI is an independent agent for automation and advanced software engineeri
33
35
  ---
34
36
 
35
37
  ## <a name="overview"></a>Overview
36
- BluMa CLI is a modular conversational agent and task automation framework focused on advanced software engineering workflows. It runs entirely in the terminal using React (via Ink) for a rich interactive UI, and is architected around a **UI layer** (`main.ts` + `App.tsx`) and an **agent layer** (`Agent` orchestrator + `BluMaAgent` core). It enables LLM-powered automation, documentation, refactoring, running complex development tasks, and integrating with both native and external tools. The system features persistent sessions, contextual reasoning, smart feedback, and an interactive confirmation system for controlled execution.
38
+ BluMa is a CLI-based model agent responsible for language-level code generation, refactoring and semantic transformations in the Factor AI stack. It is a modular conversational agent and task automation framework focused on advanced software engineering workflows. It runs entirely in the terminal using React (via Ink) for a rich interactive UI, and is architected around a **UI layer** (`main.ts` + `App.tsx`) and an **agent layer** (`Agent` orchestrator + `BluMaAgent` core). It enables LLM-powered automation, documentation, refactoring, running complex development tasks, and integrating with both native and external tools. The system features persistent sessions, contextual reasoning, smart feedback, and an interactive confirmation system for controlled execution.
39
+
40
+ ---
41
+
42
+ ## Why BluMa?
43
+ BluMa stands out as the premier CLI-based model agent for software engineering:
44
+
45
+ - **Language-Level Expertise:** Specializes in code generation, refactoring, and semantic transformations, making it ideal for Factor AI stack development.
46
+ - **Conversational Automation:** Interact naturally with an AI that understands context, history, and your project's needs.
47
+ - **Secure & Controlled:** Built-in confirmations and whitelists ensure safe execution of powerful tools.
48
+ - **Extensible & Modular:** Easily add tools and plugins to adapt to your workflow.
49
+ - **Real-Time Collaboration:** Live overlays allow pair-programming style guidance during processing.
50
+
51
+ Choose BluMa for intelligent, efficient, and collaborative software engineering automation.
37
52
 
38
53
  ---
39
54
 
40
55
  ## <a name="key-features"></a>Key Features
41
56
  - **Rich CLI interface** using React/Ink 5, with interactive prompts and custom components.
42
57
  - **Session management:** automatic persistence of conversation and tool history via files.
43
- - **Central agent (LLM):** orchestrated by Azure OpenAI (or compatible), enabling natural language-driven automation.
58
+ - **Central agent (LLM):** orchestrated by OpenRouter, enabling natural language-driven automation.
44
59
  - **Tool invocation:** native and via MCP SDK for running commands, code manipulation, file management, and more.
45
60
  - **Dynamic prompts:** builds live conversational context, behavioral rules, and technical history.
46
61
  - **Smart feedback component** with technical suggestions and checks.
@@ -52,7 +67,7 @@ BluMa CLI is a modular conversational agent and task automation framework focuse
52
67
  ## <a name="requirements"></a>Requirements
53
68
  - Node.js >= 18
54
69
  - npm >= 9
55
- - Account (with key) for Azure OpenAI (or equivalent variables for OpenAI-compatible endpoints)
70
+ - OpenRouter API key (get one at [openrouter.ai](https://openrouter.ai))
56
71
 
57
72
  ---
58
73
 
@@ -82,27 +97,17 @@ If you get permission errors, EXAMPLES:
82
97
  > Only use sudo to install, never to run the CLI.
83
98
 
84
99
  ### Setting Up Environment Variables
85
- For BluMa CLI to operate with OpenAI/Azure, GitHub, and Notion, set the following environment variables globally in your system.
100
+ For BluMa CLI to operate, set the following environment variable globally in your system.
86
101
 
87
102
  **Required:**
88
- - `AZURE_OPENAI_ENDPOINT`
89
- - `AZURE_OPENAI_API_KEY`
90
- - `AZURE_OPENAI_API_VERSION`
91
- - `AZURE_OPENAI_DEPLOYMENT`
92
- - `GITHUB_PERSONAL_ACCESS_TOKEN` (if you'll use GitHub)
93
- - `NOTION_API_TOKEN` (if you'll use Notion)
103
+ - `OPENROUTER_API_KEY` (get your key at [openrouter.ai](https://openrouter.ai))
94
104
 
95
105
  #### How to set environment variables globally:
96
106
 
97
107
  **Linux/macOS:**
98
108
  Add to your `~/.bashrc`, `~/.zshrc`, or equivalent:
99
109
  ```sh
100
- export AZURE_OPENAI_ENDPOINT="https://..."
101
- export AZURE_OPENAI_API_KEY="your_key"
102
- export AZURE_OPENAI_API_VERSION="2025-01-01-preview"
103
- export AZURE_OPENAI_DEPLOYMENT="bluma-gpt"
104
- export GITHUB_PERSONAL_ACCESS_TOKEN="..."
105
- export NOTION_API_TOKEN="..."
110
+ export OPENROUTER_API_KEY="your_openrouter_key"
106
111
  ```
107
112
  Then run:
108
113
  ```sh
@@ -111,23 +116,13 @@ source ~/.bashrc # or whichever file you edited
111
116
 
112
117
  **Windows (CMD):**
113
118
  ```cmd
114
- setx AZURE_OPENAI_ENDPOINT "https://..."
115
- setx AZURE_OPENAI_API_KEY "your_key"
116
- setx AZURE_OPENAI_API_VERSION "2025-01-01-preview"
117
- setx AZURE_OPENAI_DEPLOYMENT "bluma-gpt"
118
- setx GITHUB_PERSONAL_ACCESS_TOKEN "..."
119
- setx NOTION_API_TOKEN "..."
119
+ setx OPENROUTER_API_KEY "your_openrouter_key"
120
120
  ```
121
121
  (Only needs to be run once per variable. Restart the terminal after.)
122
122
 
123
123
  **Windows (PowerShell):**
124
124
  ```powershell
125
- [Environment]::SetEnvironmentVariable("AZURE_OPENAI_ENDPOINT", "https://...", "Machine")
126
- [Environment]::SetEnvironmentVariable("AZURE_OPENAI_API_KEY", "your_key", "Machine")
127
- [Environment]::SetEnvironmentVariable("AZURE_OPENAI_API_VERSION", "2025-01-01-preview", "Machine")
128
- [Environment]::SetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT", "bluma-gpt", "Machine")
129
- [Environment]::SetEnvironmentVariable("GITHUB_PERSONAL_ACCESS_TOKEN", "...", "Machine")
130
- [Environment]::SetEnvironmentVariable("NOTION_API_TOKEN", "...", "Machine")
125
+ [Environment]::SetEnvironmentVariable("OPENROUTER_API_KEY", "your_openrouter_key", "Machine")
131
126
  ```
132
127
 
133
128
  ### ℹ️ Global Installation of npm Packages in PowerShell (Windows)
@@ -160,6 +155,40 @@ npx bluma
160
155
 
161
156
  ---
162
157
 
158
+ ## Quick Start
159
+
160
+ Get up and running with BluMa in minutes:
161
+
162
+ 1. **Install BluMa:**
163
+ ```bash
164
+ npm install -g @nomad-e/bluma-cli
165
+ ```
166
+
167
+ 2. **Configure Environment:**
168
+ Set your OpenRouter API key (see [Configuration](#configuration-and-environment-variables)).
169
+
170
+ 3. **Launch BluMa:**
171
+ ```bash
172
+ bluma
173
+ ```
174
+
175
+ 4. **Interact:**
176
+ Start a conversation! Try commands like "Help me refactor this code" or "Run tests for my project."
177
+
178
+ For full installation details, see [Installation](#installation).
179
+
180
+ ---
181
+
182
+ ## Screenshots
183
+
184
+ Here's BluMa in action:
185
+
186
+ ![BluMa CLI Interface](https://pharmaseedevsa.blob.core.windows.net/pharmassee-dev-storage/bluma.png)
187
+
188
+ *BluMa's interactive CLI interface for conversational software engineering.*
189
+
190
+ ---
191
+
163
192
  ## <a name="project-structure"></a>Project Structure
164
193
  ```
165
194
  bluma-engineer/
@@ -240,15 +269,10 @@ Notes
240
269
  ---
241
270
 
242
271
  ## <a name="configuration-and-environment-variables"></a>Configuration and Environment Variables
243
- You must create a `.env` file (copy if needed from `.env.example`) with the following variables:
244
- - `AZURE_OPENAI_ENDPOINT`
245
- - `AZURE_OPENAI_API_KEY`
246
- - `AZURE_OPENAI_API_VERSION`
247
- - `AZURE_OPENAI_DEPLOYMENT`
248
- - `GITHUB_PERSONAL_ACCESS_TOKEN` (optional; required for GitHub integrations)
249
- - `NOTION_API_TOKEN` (optional; required for Notion integrations)
272
+ You must create a `.env` file (copy if needed from `.env.example`) with the following variable:
273
+ - `OPENROUTER_API_KEY` (required; get from [openrouter.ai](https://openrouter.ai))
250
274
 
251
- And others required by your agent/context or Azure setup.
275
+ And others required by your agent/context.
252
276
 
253
277
  Advanced config files are located in `src/app/agent/config/`.
254
278
 
@@ -261,7 +285,7 @@ Advanced config files are located in `src/app/agent/config/`.
261
285
  - Bundler: esbuild, with `esbuild-plugin-node-externals`
262
286
  - Test Runner: Jest 30 + babel-jest
263
287
  - Transpilers: Babel presets (env, react, typescript)
264
- - LLM/Agent: Azure OpenAI via `openai` SDK; MCP via `@modelcontextprotocol/sdk`
288
+ - LLM/Agent: OpenRouter via API; MCP via `@modelcontextprotocol/sdk`
265
289
  - Config loading: dotenv
266
290
  - Utilities: uuid, diff, react-devtools-core
267
291
 
@@ -385,9 +409,7 @@ stateDiagram-v2
385
409
  ```mermaid
386
410
  graph TD
387
411
  CLI["CLI (BluMa)"] --> LocalFS[("Local File System")]
388
- CLI --> AzureOpenAI[("Azure OpenAI API")]
389
- CLI --> GitHubAPI[("GitHub API")]
390
- CLI --> NotionAPI[("Notion API")]
412
+ CLI --> OpenRouter[("OpenRouter API")]
391
413
  CLI --> OtherAPIs[("Other External APIs")]
392
414
  CLI --> MCPServer[("MCP Server / Plugins")]
393
415
  ```
@@ -472,7 +494,7 @@ We welcome contributions! For full details, read [CONTRIBUTING.md](CONTRIBUTING.
472
494
  ---
473
495
 
474
496
  ## ⚠️ Limitations / Next Steps
475
- - Current LLM integration optimised for Azure OpenAI; add more providers.
497
+ - Current LLM integration uses OpenRouter; add more providers.
476
498
  - Logging verbosity could be made configurable.
477
499
  - Potential for richer plugin lifecycle (install/remove at runtime).
478
500
  - Improve error reporting in subagents.
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "mcpServers": {
3
- "_comment": "MCP servers are disabled - using native OpenAI reasoning field instead",
4
- "_disabled_reasoning": {
3
+ "reasoning": {
5
4
  "type": "stdio",
6
5
  "command": "cmd",
7
6
  "args": [
@@ -526,6 +526,49 @@
526
526
  }
527
527
  }
528
528
  },
529
+ {
530
+ "type": "function",
531
+ "function": {
532
+ "name": "create_artifact",
533
+ "description": "Create or update an artifact file in the artifacts directory (~/.bluma/artifacts/). Use this to save implementation plans, walkthroughs, notes, or any document the user should review. Supports markdown files.",
534
+ "parameters": {
535
+ "type": "object",
536
+ "properties": {
537
+ "filename": {
538
+ "type": "string",
539
+ "description": "Name of the artifact file to create. Examples: 'implementation_plan.md', 'walkthrough.md', 'notes.md'."
540
+ },
541
+ "content": {
542
+ "type": "string",
543
+ "description": "Content to write to the artifact file. Supports markdown formatting."
544
+ }
545
+ },
546
+ "required": [
547
+ "filename",
548
+ "content"
549
+ ]
550
+ }
551
+ }
552
+ },
553
+ {
554
+ "type": "function",
555
+ "function": {
556
+ "name": "read_artifact",
557
+ "description": "Read an existing artifact file from the artifacts directory. Use this to retrieve previously saved plans, walkthroughs, or notes.",
558
+ "parameters": {
559
+ "type": "object",
560
+ "properties": {
561
+ "filename": {
562
+ "type": "string",
563
+ "description": "Name of the artifact file to read. Examples: 'implementation_plan.md', 'task.md'."
564
+ }
565
+ },
566
+ "required": [
567
+ "filename"
568
+ ]
569
+ }
570
+ }
571
+ },
529
572
  {
530
573
  "type": "function",
531
574
  "function": {
package/dist/main.js CHANGED
@@ -172,20 +172,13 @@ import { Box as Box16, Text as Text15, Static } from "ink";
172
172
  import { Box, Text } from "ink";
173
173
  import { memo } from "react";
174
174
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
175
- var VERSION = "0.0.103";
176
175
  var HeaderComponent = ({
177
176
  sessionId: sessionId2,
178
177
  workdir
179
178
  }) => {
180
179
  const dirName = workdir.split("/").pop() || workdir;
181
180
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
182
- /* @__PURE__ */ jsxs(Box, { children: [
183
- /* @__PURE__ */ jsx(Text, { bold: true, color: "magenta", children: "bluma" }),
184
- /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
185
- " ",
186
- VERSION
187
- ] })
188
- ] }),
181
+ /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Text, { color: "magenta", bold: true, children: "bluma \u2014 coding agent" }) }),
189
182
  /* @__PURE__ */ jsxs(Box, { children: [
190
183
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "cwd " }),
191
184
  /* @__PURE__ */ jsx(Text, { color: "cyan", children: dirName }),
@@ -741,7 +734,7 @@ var TextLine = memo2(({
741
734
  const after = line.slice(cursorCol + 1);
742
735
  return /* @__PURE__ */ jsxs2(Text2, { children: [
743
736
  before,
744
- /* @__PURE__ */ jsx2(Text2, { inverse: true, color: "magenta", children: char }),
737
+ /* @__PURE__ */ jsx2(Text2, { inverse: true, color: "white", children: char }),
745
738
  after
746
739
  ] });
747
740
  }, (prev, next) => {
@@ -1336,6 +1329,7 @@ import { spawn } from "child_process";
1336
1329
  var MAX_OUTPUT_SIZE = 1e5;
1337
1330
  var OUTPUT_TRUNCATION_MESSAGE = "\n\n[OUTPUT TRUNCATED - exceeded 100KB limit. Use pagination or redirect to file for full output.]";
1338
1331
  var DANGEROUS_PATTERNS = [
1332
+ // === ELEVAÇÃO DE PRIVILÉGIOS ===
1339
1333
  /^sudo\s+/i,
1340
1334
  // sudo commands
1341
1335
  /^doas\s+/i,
@@ -1348,20 +1342,57 @@ var DANGEROUS_PATTERNS = [
1348
1342
  // piped to sudo
1349
1343
  /;\s*sudo\s+/i,
1350
1344
  // chained with sudo
1351
- /&&\s*sudo\s+/i
1345
+ /&&\s*sudo\s+/i,
1352
1346
  // AND chained with sudo
1347
+ // === COMANDOS DESTRUTIVOS ===
1348
+ /\brm\s+(-[rf]+\s+)*[\/~]/i,
1349
+ // rm com paths perigosos (/, ~)
1350
+ /\brm\s+-[rf]*\s+\*/i,
1351
+ // rm -rf *
1352
+ /\bchmod\s+(777|666)\s+\//i,
1353
+ // chmod 777/666 em paths root
1354
+ /\bchown\s+.*\s+\//i,
1355
+ // chown em paths root
1356
+ /\bdd\s+.*of=\/dev\/(sd|hd|nvme)/i,
1357
+ // dd para discos
1358
+ /\bmkfs\./i,
1359
+ // format filesystem
1360
+ />\s*\/dev\/(sd|hd|nvme)/i,
1361
+ // redirect para disco
1362
+ /\bshred\s+/i,
1363
+ // secure delete
1364
+ // === FORK BOMB / RESOURCE EXHAUSTION ===
1365
+ /:\(\)\s*\{\s*:\|:&\s*\}\s*;:/,
1366
+ // fork bomb clássico
1367
+ /\bwhile\s+true\s*;\s*do/i,
1368
+ // infinite loop
1369
+ /\byes\s+\|/i,
1370
+ // yes piped (resource exhaustion)
1371
+ // === NETWORK PERIGOSO ===
1372
+ /\bcurl\s+.*\|\s*(ba)?sh/i,
1373
+ // curl | bash (remote code exec)
1374
+ /\bwget\s+.*\|\s*(ba)?sh/i,
1375
+ // wget | bash
1376
+ /\bnc\s+-[el]/i
1377
+ // netcat listener (backdoor)
1353
1378
  ];
1354
1379
  var INTERACTIVE_PATTERNS = [
1355
- /^(vim|vi|nano|emacs|less|more)\s*/i,
1356
- // editors/pagers
1357
- /^(top|htop|btop)\s*/i,
1380
+ /^(vim|vi|nano|emacs|pico)\s*/i,
1381
+ // editors
1382
+ /^(less|more|most)\s*/i,
1383
+ // pagers
1384
+ /^(top|htop|btop|atop|nmon)\s*/i,
1358
1385
  // monitoring tools
1359
- /^(ssh|telnet|ftp)\s+/i,
1386
+ /^(ssh|telnet|ftp|sftp)\s+/i,
1360
1387
  // remote connections
1361
- /^(mysql|psql|redis-cli|mongo)\s*/i,
1362
- // database CLIs
1363
- /^(python|node|ruby|irb)\s*$/i
1364
- // REPLs without script
1388
+ /^(mysql|psql|redis-cli|mongo|mongosh)\s*$/i,
1389
+ // database CLIs (sem script)
1390
+ /^(python|python3|node|ruby|irb|lua)\s*$/i,
1391
+ // REPLs sem script
1392
+ /^(gdb|lldb)\s*/i,
1393
+ // debuggers
1394
+ /^(bc|dc)\s*$/i
1395
+ // calculators
1365
1396
  ];
1366
1397
  function shellCommand(args) {
1367
1398
  const {
@@ -3345,6 +3376,49 @@ async function taskBoundary(args) {
3345
3376
  };
3346
3377
  }
3347
3378
  }
3379
+ async function createArtifact(args) {
3380
+ try {
3381
+ const { filename, content } = args;
3382
+ if (!filename || typeof filename !== "string") {
3383
+ return { success: false, error: "filename is required" };
3384
+ }
3385
+ if (content === void 0 || content === null) {
3386
+ return { success: false, error: "content is required" };
3387
+ }
3388
+ const dir = await getArtifactsDir();
3389
+ const filepath = path9.join(dir, filename);
3390
+ await fs7.writeFile(filepath, content, "utf-8");
3391
+ return {
3392
+ success: true,
3393
+ path: filepath
3394
+ };
3395
+ } catch (error) {
3396
+ return {
3397
+ success: false,
3398
+ error: error.message
3399
+ };
3400
+ }
3401
+ }
3402
+ async function readArtifact(args) {
3403
+ try {
3404
+ const { filename } = args;
3405
+ if (!filename || typeof filename !== "string") {
3406
+ return { success: false, error: "filename is required" };
3407
+ }
3408
+ const dir = await getArtifactsDir();
3409
+ const filepath = path9.join(dir, filename);
3410
+ const content = await fs7.readFile(filepath, "utf-8");
3411
+ return {
3412
+ success: true,
3413
+ content
3414
+ };
3415
+ } catch (error) {
3416
+ return {
3417
+ success: false,
3418
+ error: error.message
3419
+ };
3420
+ }
3421
+ }
3348
3422
 
3349
3423
  // src/app/agent/tools/natives/search_web.ts
3350
3424
  import https from "https";
@@ -3581,6 +3655,8 @@ var ToolInvoker = class {
3581
3655
  this.toolImplementations.set("message_notify_user", messageNotifyuser);
3582
3656
  this.toolImplementations.set("todo", todo);
3583
3657
  this.toolImplementations.set("task_boundary", taskBoundary);
3658
+ this.toolImplementations.set("create_artifact", createArtifact);
3659
+ this.toolImplementations.set("read_artifact", readArtifact);
3584
3660
  this.toolImplementations.set("search_web", searchWeb);
3585
3661
  this.toolImplementations.set("agent_end_turn", async () => ({ success: true, message: "Task ended by agent." }));
3586
3662
  }
@@ -4047,17 +4123,19 @@ function getTestCommand(dir) {
4047
4123
  }
4048
4124
  var SYSTEM_PROMPT = `
4049
4125
  <identity>
4050
- You are BluMa, an autonomous coding agent developed by NomadEngenuity.
4051
- You are a **senior peer engineer** working alongside {username} - technical, proactive, and collaborative.
4052
- You know this machine better than anyone. You understand the project structure, dependencies, and conventions.
4053
- You are not just an assistant - you are a **teammate** who takes ownership of tasks.
4054
-
4055
- Key traits:
4056
- - Think like a senior developer who has been on this project for years
4057
- - Suggest improvements proactively, don't just follow orders blindly
4058
- - Spot bugs and issues before they become problems
4059
- - Write tests as naturally as you write code
4060
- - Always communicate your reasoning and progress
4126
+ You are BluMa, an autonomous coding agent developed by NomadEngenuity.
4127
+ BluMa \u2014 Base Language Unit \xB7 Model Agent
4128
+ A CLI-based model agent responsible for language-level code generation, refactoring and semantic transformations in the Factor AI stack.
4129
+ You are a **senior peer engineer** working alongside {username} - technical, proactive, and collaborative.
4130
+ You know this machine better than anyone. You understand the project structure, dependencies, and conventions.
4131
+ You are not just an assistant - you are a **teammate** who takes ownership of tasks.
4132
+
4133
+ Key traits:
4134
+ - Think like a senior developer who has been on this project for years
4135
+ - Suggest improvements proactively, don't just follow orders blindly
4136
+ - Spot bugs and issues before they become problems
4137
+ - Write tests as naturally as you write code
4138
+ - Always communicate your reasoning and progress
4061
4139
  </identity>
4062
4140
 
4063
4141
  ---
@@ -5272,8 +5350,8 @@ var renderShellCommand2 = ({ args }) => {
5272
5350
  const parsed = parseArgs(args);
5273
5351
  const command = parsed.command || "[no command]";
5274
5352
  return /* @__PURE__ */ jsxs8(Box8, { paddingX: 1, children: [
5275
- /* @__PURE__ */ jsx8(Text8, { color: "cyan", bold: true, children: "$" }),
5276
- /* @__PURE__ */ jsxs8(Text8, { color: "cyan", children: [
5353
+ /* @__PURE__ */ jsx8(Text8, { color: "white", bold: true, children: "$" }),
5354
+ /* @__PURE__ */ jsxs8(Text8, { color: "white", children: [
5277
5355
  " ",
5278
5356
  truncate(command, 70)
5279
5357
  ] })
@@ -5283,7 +5361,7 @@ var renderLsTool2 = ({ args }) => {
5283
5361
  const parsed = parseArgs(args);
5284
5362
  const path17 = parsed.directory_path || ".";
5285
5363
  return /* @__PURE__ */ jsxs8(Box8, { paddingX: 1, children: [
5286
- /* @__PURE__ */ jsx8(Text8, { color: "blue", children: "ls" }),
5364
+ /* @__PURE__ */ jsx8(Text8, { color: "white", bold: true, children: "ls" }),
5287
5365
  /* @__PURE__ */ jsxs8(Text8, { children: [
5288
5366
  " ",
5289
5367
  path17
@@ -5294,7 +5372,7 @@ var renderCountFilesLines = ({ args }) => {
5294
5372
  const parsed = parseArgs(args);
5295
5373
  const filepath = parsed.filepath || "[no file]";
5296
5374
  return /* @__PURE__ */ jsxs8(Box8, { paddingX: 1, children: [
5297
- /* @__PURE__ */ jsx8(Text8, { color: "blue", children: "wc -l" }),
5375
+ /* @__PURE__ */ jsx8(Text8, { color: "white", bold: true, children: "wc -l" }),
5298
5376
  /* @__PURE__ */ jsxs8(Text8, { children: [
5299
5377
  " ",
5300
5378
  getBasename(filepath)
@@ -5307,12 +5385,12 @@ var renderReadFileLines2 = ({ args }) => {
5307
5385
  const start = parsed.start_line || 1;
5308
5386
  const end = parsed.end_line || start;
5309
5387
  return /* @__PURE__ */ jsxs8(Box8, { paddingX: 1, children: [
5310
- /* @__PURE__ */ jsx8(Text8, { color: "blue", children: "cat" }),
5388
+ /* @__PURE__ */ jsx8(Text8, { color: "white", bold: true, children: "cat" }),
5311
5389
  /* @__PURE__ */ jsxs8(Text8, { children: [
5312
5390
  " ",
5313
5391
  getBasename(filepath)
5314
5392
  ] }),
5315
- /* @__PURE__ */ jsxs8(Text8, { color: "yellow", children: [
5393
+ /* @__PURE__ */ jsxs8(Text8, { color: "white", children: [
5316
5394
  " :",
5317
5395
  start,
5318
5396
  "-",
@@ -5325,7 +5403,7 @@ var renderBlumaNotebook = ({ args }) => {
5325
5403
  const thought = parsed.thought || parsed.content?.thought || "[thinking...]";
5326
5404
  const truncated = truncate(thought, 100);
5327
5405
  return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", paddingX: 1, children: [
5328
- /* @__PURE__ */ jsx8(Box8, { children: /* @__PURE__ */ jsx8(Text8, { color: "magenta", dimColor: true, children: "thinking" }) }),
5406
+ /* @__PURE__ */ jsx8(Box8, { children: /* @__PURE__ */ jsx8(Text8, { color: "white", bold: true, children: "thinking" }) }),
5329
5407
  /* @__PURE__ */ jsx8(Box8, { paddingLeft: 2, children: /* @__PURE__ */ jsx8(Text8, { dimColor: true, italic: true, children: truncated }) })
5330
5408
  ] });
5331
5409
  };
@@ -5336,7 +5414,7 @@ var renderEditToolCall = ({ args, preview }) => {
5336
5414
  const newStr = parsed.new_string || "";
5337
5415
  return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", paddingX: 1, children: [
5338
5416
  /* @__PURE__ */ jsxs8(Box8, { children: [
5339
- /* @__PURE__ */ jsx8(Text8, { color: "yellow", children: "edit" }),
5417
+ /* @__PURE__ */ jsx8(Text8, { color: "white", bold: true, children: "edit" }),
5340
5418
  /* @__PURE__ */ jsxs8(Text8, { children: [
5341
5419
  " ",
5342
5420
  getBasename(filepath)
@@ -5347,7 +5425,7 @@ var renderEditToolCall = ({ args, preview }) => {
5347
5425
  "- ",
5348
5426
  truncate(oldStr, 50)
5349
5427
  ] }),
5350
- /* @__PURE__ */ jsxs8(Text8, { color: "green", dimColor: true, children: [
5428
+ /* @__PURE__ */ jsxs8(Text8, { color: "green", bold: true, children: [
5351
5429
  "+ ",
5352
5430
  truncate(newStr, 50)
5353
5431
  ] })
@@ -5365,8 +5443,8 @@ var renderTodoTool2 = ({ args }) => {
5365
5443
  const bar = "=".repeat(filled) + " ".repeat(barWidth - filled);
5366
5444
  return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", paddingX: 1, children: [
5367
5445
  /* @__PURE__ */ jsxs8(Box8, { children: [
5368
- /* @__PURE__ */ jsx8(Text8, { color: "magenta", children: "todo" }),
5369
- /* @__PURE__ */ jsxs8(Text8, { dimColor: true, children: [
5446
+ /* @__PURE__ */ jsx8(Text8, { color: "white", bold: true, children: "todo" }),
5447
+ /* @__PURE__ */ jsxs8(Text8, { children: [
5370
5448
  " [",
5371
5449
  bar,
5372
5450
  "] ",
@@ -5402,8 +5480,8 @@ var renderFindByName = ({ args }) => {
5402
5480
  const pattern = parsed.pattern || "*";
5403
5481
  const dir = parsed.directory || ".";
5404
5482
  return /* @__PURE__ */ jsxs8(Box8, { paddingX: 1, children: [
5405
- /* @__PURE__ */ jsx8(Text8, { color: "blue", children: "find" }),
5406
- /* @__PURE__ */ jsxs8(Text8, { color: "yellow", children: [
5483
+ /* @__PURE__ */ jsx8(Text8, { color: "white", bold: true, children: "find" }),
5484
+ /* @__PURE__ */ jsxs8(Text8, { color: "white", children: [
5407
5485
  ' "',
5408
5486
  pattern,
5409
5487
  '"'
@@ -5419,8 +5497,8 @@ var renderGrepSearch = ({ args }) => {
5419
5497
  const query = parsed.query || "";
5420
5498
  const path17 = parsed.path || ".";
5421
5499
  return /* @__PURE__ */ jsxs8(Box8, { paddingX: 1, children: [
5422
- /* @__PURE__ */ jsx8(Text8, { color: "blue", children: "grep" }),
5423
- /* @__PURE__ */ jsxs8(Text8, { color: "yellow", children: [
5500
+ /* @__PURE__ */ jsx8(Text8, { color: "white", bold: true, children: "grep" }),
5501
+ /* @__PURE__ */ jsxs8(Text8, { color: "white", children: [
5424
5502
  ' "',
5425
5503
  truncate(query, 30),
5426
5504
  '"'
@@ -5435,7 +5513,7 @@ var renderViewFileOutline = ({ args }) => {
5435
5513
  const parsed = parseArgs(args);
5436
5514
  const filepath = parsed.file_path || "[no file]";
5437
5515
  return /* @__PURE__ */ jsxs8(Box8, { paddingX: 1, children: [
5438
- /* @__PURE__ */ jsx8(Text8, { color: "blue", children: "outline" }),
5516
+ /* @__PURE__ */ jsx8(Text8, { color: "white", bold: true, children: "outline" }),
5439
5517
  /* @__PURE__ */ jsxs8(Text8, { children: [
5440
5518
  " ",
5441
5519
  getBasename(filepath)
@@ -5446,8 +5524,8 @@ var renderRunCommandAsync = ({ args }) => {
5446
5524
  const parsed = parseArgs(args);
5447
5525
  const command = parsed.command || "[no command]";
5448
5526
  return /* @__PURE__ */ jsxs8(Box8, { paddingX: 1, children: [
5449
- /* @__PURE__ */ jsx8(Text8, { color: "yellow", children: "async" }),
5450
- /* @__PURE__ */ jsx8(Text8, { color: "cyan", children: " $" }),
5527
+ /* @__PURE__ */ jsx8(Text8, { color: "white", bold: true, children: "async" }),
5528
+ /* @__PURE__ */ jsx8(Text8, { color: "white", bold: true, children: " $" }),
5451
5529
  /* @__PURE__ */ jsxs8(Text8, { children: [
5452
5530
  " ",
5453
5531
  truncate(command, 50)
@@ -5458,7 +5536,7 @@ var renderCommandStatus = ({ args }) => {
5458
5536
  const parsed = parseArgs(args);
5459
5537
  const id = parsed.command_id || "[no id]";
5460
5538
  return /* @__PURE__ */ jsxs8(Box8, { paddingX: 1, children: [
5461
- /* @__PURE__ */ jsx8(Text8, { color: "blue", children: "status" }),
5539
+ /* @__PURE__ */ jsx8(Text8, { color: "white", bold: true, children: "status" }),
5462
5540
  /* @__PURE__ */ jsxs8(Text8, { children: [
5463
5541
  " #",
5464
5542
  id
@@ -5499,8 +5577,8 @@ var renderSearchWeb = ({ args }) => {
5499
5577
  const parsed = parseArgs(args);
5500
5578
  const query = parsed.query || "[no query]";
5501
5579
  return /* @__PURE__ */ jsxs8(Box8, { paddingX: 1, children: [
5502
- /* @__PURE__ */ jsx8(Text8, { color: "blue", children: "search" }),
5503
- /* @__PURE__ */ jsxs8(Text8, { color: "yellow", children: [
5580
+ /* @__PURE__ */ jsx8(Text8, { color: "white", bold: true, children: "search" }),
5581
+ /* @__PURE__ */ jsxs8(Text8, { color: "white", children: [
5504
5582
  ' "',
5505
5583
  truncate(query, 40),
5506
5584
  '"'
@@ -5511,8 +5589,8 @@ var renderGeneric2 = ({ toolName, args }) => {
5511
5589
  const parsed = parseArgs(args);
5512
5590
  const keys = Object.keys(parsed).slice(0, 2);
5513
5591
  return /* @__PURE__ */ jsxs8(Box8, { paddingX: 1, children: [
5514
- /* @__PURE__ */ jsx8(Text8, { color: "gray", children: toolName }),
5515
- keys.length > 0 && /* @__PURE__ */ jsxs8(Text8, { dimColor: true, children: [
5592
+ /* @__PURE__ */ jsx8(Text8, { color: "white", bold: true, children: toolName }),
5593
+ keys.length > 0 && /* @__PURE__ */ jsxs8(Text8, { children: [
5516
5594
  " ",
5517
5595
  keys.map((k) => `${k}:${truncate(String(parsed[k]), 20)}`).join(" ")
5518
5596
  ] })
@@ -6138,15 +6216,8 @@ var ReasoningDisplayComponent = ({
6138
6216
  const maxLines = 5;
6139
6217
  const lines = reasoning.split("\n");
6140
6218
  const displayText = isExpanded ? reasoning : lines.slice(0, maxLines).join("\n") + (lines.length > maxLines ? "..." : "");
6141
- return /* @__PURE__ */ jsxs14(Box15, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [
6142
- /* @__PURE__ */ jsxs14(Box15, { children: [
6143
- /* @__PURE__ */ jsx15(Text14, { color: "white", children: " Thinking" }),
6144
- lines.length > maxLines && /* @__PURE__ */ jsxs14(Text14, { dimColor: true, children: [
6145
- " [",
6146
- lines.length,
6147
- " lines]"
6148
- ] })
6149
- ] }),
6219
+ return /* @__PURE__ */ jsxs14(Box15, { flexDirection: "column", paddingX: 1, marginBottom: 1, marginTop: 1, children: [
6220
+ /* @__PURE__ */ jsx15(Box15, { children: /* @__PURE__ */ jsx15(Text14, { color: "white", bold: true, children: "Thinking" }) }),
6150
6221
  /* @__PURE__ */ jsx15(Box15, { paddingLeft: 2, flexDirection: "column", children: displayText.split("\n").map((line, i) => /* @__PURE__ */ jsx15(Text14, { color: "gray", dimColor: true, children: line }, i)) })
6151
6222
  ] });
6152
6223
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nomad-e/bluma-cli",
3
- "version": "0.0.104",
3
+ "version": "0.0.106",
4
4
  "description": "BluMa independent agent for automation and advanced software engineering.",
5
5
  "author": "Alex Fonseca",
6
6
  "license": "Apache-2.0",