@nomad-e/bluma-cli 0.6.2 β†’ 0.6.5

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
@@ -13,6 +13,8 @@
13
13
 
14
14
  **BluMa** is an independent AI agent CLI for automation and advanced software engineering. It combines powerful tool orchestration, multi-agent coordination, and intelligent context management to help you build software faster and with higher quality.
15
15
 
16
+ **Latest Version:** v0.6.4 (2026-05-10) β€” Circular dependency resolution, enhanced native tool metadata, improved multi-agent coordination, and professional release engineering.
17
+
16
18
  ---
17
19
 
18
20
  ## πŸš€ Quick Start
@@ -75,18 +77,104 @@ Tools are now modularly structured in `src/app/agent/tools/` with separate UI co
75
77
  ### 🧠 **Multi-Agent Orchestration**
76
78
  - **Coordinator Mode**: Product Owner + Engineering Manager hybrid that delegates to specialist workers
77
79
  - **Parallel Execution**: Launch multiple workers concurrently for research, implementation, and verification
78
- - **Mailbox IPC**: Bidirectional communication between coordinator and workers via `send_message`, `list_mailbox_messages`, `poll_mailbox`, `signal_mailbox`
80
+ - **Mailbox IPC**: **Bidirectional file-based communication** between coordinator and workers
81
+ - **send_message**: Send follow-ups to running workers without re-spawning
82
+ - **list_mailbox_messages**: Read progress updates, permission requests, and results
83
+ - **poll_mailbox**: Poll for new messages from workers
84
+ - **signal_mailbox**: Send ack/nack/progress/heartbeat signals
85
+ - **File-based storage**: `~/.bluma/mailboxes/{session_id}.in/out/sig` (JSONL format)
79
86
  - **Worker Types**: Researchers, implementers, verifiers with specialized roles
80
87
  - **Session Registry**: Track and manage agent sessions with lifecycle events
88
+ - **Task Boundary Tracking**: Use `task_boundary` to track orchestration phases (PLANNING, EXECUTION, VERIFICATION)
81
89
 
82
90
  ### πŸ“ **Slash Commands** (80+ commands)
83
91
  Quick access to common operations across 5 categories:
84
92
 
85
- - **Session** (25+): `/clear`, `/sessions`, `/attach`, `/follow`, `/bridge`, `/status`, `/logs`, `/resume`, `/kill`, `/compact`, `/export`, `/summarize`, `/history`, `/share`, `/copy`, `/commit`, `/pr`, `/release`, `/snip`, `/collapse`, `/brief`, `/undo`, `/redo`, `/thread` (with subcommands: list/new/resume/fork/rename/archive/delete)
86
- - **Inspect** (30+): `/plugins`, `/plugin`, `/diagnostics`, `/permissions`, `/features`, `/hooks`, `/model`, `/effort`, `/style`, `/sandbox`, `/worktree`, `/statusline`, `/skills`, `/tools`, `/mcp`, `/debug-workers`, `/cost`, `/memory`, `/stats`, `/theme`, `/keybindings`, `/vim`, `/ctx`, `/dream`, `/diff`, `/editor`, `/config`, `/file`, `/search`, `/context`, `/token`, `/settings`, `/alias`, `/macro`, `/thread stats`
87
- - **Agent** (15+): `/agent`, `/agents`, `/img`, `/image`, `/init`, `/review`, `/explain`, `/fix`, `/debug`, `/bug`, `/test`, `/optimize`, `/refactor`, `/document`, `/chat`, `/code`, `/terminal`, `/template`
88
- - **Help**: `/help`
89
- - **Input**: `Ctrl+V`/`Cmd+V` (paste image/text/file), `Ctrl+Shift+I` (same as Ctrl+V)
93
+ **Session Commands** (25+):
94
+ - `/clear` - Clear current session
95
+ - `/sessions` - List all sessions
96
+ - `/attach` - Attach to existing session
97
+ - `/follow` - Follow session output
98
+ - `/bridge` - Bridge multiple sessions
99
+ - `/status` - Show session status
100
+ - `/logs` - View session logs
101
+ - `/resume` - Resume previous session
102
+ - `/kill` - Terminate session
103
+ - `/compact` - Compress context
104
+ - `/export` - Export session
105
+ - `/summarize` - Summarize conversation
106
+ - `/history` - Command history
107
+ - `/share` - Share session
108
+ - `/copy` - Copy output to clipboard
109
+ - `/commit` - Create git commit
110
+ - `/pr` - Create pull request
111
+ - `/release` - Professional release engineering
112
+ - `/snip` - Extract conversation snippets
113
+ - `/collapse` - Collapse context
114
+ - `/brief` - Generate brief
115
+ - `/undo` - Undo last action
116
+ - `/redo` - Redo undone action
117
+ - `/thread` - Thread management (list/new/resume/fork/rename/archive/delete)
118
+
119
+ **Inspect Commands** (30+):
120
+ - `/plugins` - List plugins
121
+ - `/plugin` - Plugin details
122
+ - `/diagnostics` - Run diagnostics
123
+ - `/permissions` - Show permissions
124
+ - `/features` - List features
125
+ - `/hooks` - Hook registry
126
+ - `/model` - Model info
127
+ - `/effort` - Effort estimation
128
+ - `/style` - Code style
129
+ - `/sandbox` - Sandbox status
130
+ - `/worktree` - Worktree info
131
+ - `/statusline` - Status line config
132
+ - `/skills` - List skills
133
+ - `/tools` - List tools
134
+ - `/mcp` - MCP resources
135
+ - `/debug-workers` - Worker debug
136
+ - `/cost` - Cost tracking
137
+ - `/memory` - Memory usage
138
+ - `/stats` - Session stats
139
+ - `/theme` - Theme config
140
+ - `/keybindings` - Key bindings
141
+ - `/vim` - Vim mode
142
+ - `/ctx` - Context inspector
143
+ - `/dream` - Dream engine status
144
+ - `/diff` - Show recent changes
145
+ - `/editor` - Open in editor
146
+ - `/config` - Runtime config
147
+ - `/file` - File operations
148
+ - `/search` - Search codebase
149
+ - `/context` - Context management
150
+ - `/token` - Token usage
151
+ - `/settings` - Runtime settings
152
+ - `/alias` - Manage aliases
153
+ - `/macro` - Execute macros
154
+ - `/thread stats` - Thread statistics
155
+
156
+ **Agent Commands** (15+):
157
+ - `/agent` - Agent info
158
+ - `/agents` - List agents
159
+ - `/img` / `/image` - Image handling
160
+ - `/init` - Initialize project
161
+ - `/review` - Code review
162
+ - `/explain` - Explain code
163
+ - `/fix` - Fix errors
164
+ - `/debug` - Debug issues
165
+ - `/bug` - Report bug
166
+ - `/test` - Run tests
167
+ - `/optimize` - Optimize code
168
+ - `/refactor` - Refactor code
169
+ - `/document` - Generate docs
170
+ - `/chat` - Chat mode
171
+ - `/code` - Code mode
172
+ - `/terminal` - Terminal placeholder
173
+ - `/template` - Create from template
174
+
175
+ **Input Methods**:
176
+ - `Ctrl+V` / `Cmd+V` - Paste image/text/file
177
+ - `Ctrl+Shift+I` - Same as Ctrl+V
90
178
 
91
179
  ### 🎯 **Intelligent Context Management**
92
180
  - **Auto Memory**: Persistent coding notes across sessions (`coding_memory`)
@@ -102,15 +190,29 @@ Structured problem-solving workflow with 3 phases:
102
190
  2. **EXECUTION**: Implementation
103
191
  3. **VERIFICATION**: Testing and validation
104
192
 
105
- ### πŸ”§ **Skills System**
106
- Extendable expertise modules with progressive disclosure:
193
+ ### πŸ”§ **Skills System** (6 skills)
194
+ Extendable expertise modules with **progressive disclosure** β€” load only when needed:
195
+
196
+ **Available Skills:**
107
197
  - **git-commit**: Conventional commits automation with BluMa watermark
108
- - **git-pr**: Pull request creation and management
109
- - **git-release**: Full release engineering workflow (version bumps, changelog, tags, npm publish)
198
+ - **git-pr**: Pull request creation and management (descriptions, reviewers, draft mode)
199
+ - **git-release**: Full release engineering (version bumps, changelog, tags, npm publish, GitHub releases)
110
200
  - **pdf**: PDF generation and manipulation (reports, merge, forms, OCR)
111
201
  - **xlsx**: Spreadsheet processing (create, edit, formulas, charting, cleaning)
112
202
  - **skill-creator**: Create custom skills
113
203
 
204
+ **How Skills Work:**
205
+ 1. **Discovery**: Skills loaded from `dist/config/skills/`, `{cwd}/.bluma/skills/`, `~/.bluma/skills/`
206
+ 2. **Progressive Disclosure**:
207
+ - Level 1: One-line description (always visible)
208
+ - Level 2: Full instructions (loaded on activation)
209
+ - Level 3: References and scripts (loaded on demand)
210
+ 3. **Triggering**: Agent auto-detects when to load skills based on task context
211
+ 4. **Priority**: Native > Project > Global (native skills cannot be overridden)
212
+
213
+ **Create Custom Skills:**
214
+ See [docs/SKILLS.md](docs/SKILLS.md) for complete guide on authoring skills.
215
+
114
216
  ### 🎨 **Modern UI**
115
217
  - Built with **Ink** (React for CLI)
116
218
  - **Shimmer effects** for working states (WorkingShimmerText, Spinner with ShimmerChar/FlashingChar)
@@ -132,6 +234,17 @@ Extendable expertise modules with progressive disclosure:
132
234
  - **ES Modules**: Modern module system with bundler resolution
133
235
  - **React 19**: Latest React with concurrent features
134
236
  - **Optimized rendering**: Memoized message blocks, offscreen freeze, expandable previews
237
+ - **Parallel tests**: Up to 8 workers for faster test execution
238
+ - **Native modules**: Rust-based clipboard and layout engine for critical paths
239
+
240
+ ### πŸ”Œ **Hooks & Plugins**
241
+ Extensible architecture with hook registry and plugin system:
242
+
243
+ - **Hook Registry**: Execute custom scripts on events (pre-commit, post-build, etc.)
244
+ - **Plugin System**: Extend BluMa with custom plugins
245
+ - **Event-driven**: Hooks triggered by tool execution, session events, and lifecycle hooks
246
+
247
+ See [docs/BLUMA_DEVELOPER_GUIDE.md](docs/BLUMA_DEVELOPER_GUIDE.md) for plugin development.
135
248
 
136
249
  ### πŸ”Œ **MCP Support**
137
250
  - **Model Context Protocol**: Connect to external MCP servers
@@ -143,6 +256,28 @@ Extendable expertise modules with progressive disclosure:
143
256
  - **Thread stats**: View thread metadata and statistics
144
257
  - **Codex-style interface**: Familiar thread management commands
145
258
 
259
+ ### πŸ¦€ **Native Modules** (Rust)
260
+ High-performance native extensions for critical operations:
261
+
262
+ - **bluma-clipboard**: Cross-platform clipboard with image support
263
+ - Built with Rust (arboard crate)
264
+ - No dependencies on wl-paste/xclip
265
+ - Native image reading for terminal paste
266
+ - **yoga-layout**: High-performance layout engine for Ink
267
+ - Facebook's Yoga layout library
268
+ - Optimized for terminal UI rendering
269
+
270
+ ### πŸ“¦ **VS Code Extension**
271
+ Full BluMa capabilities integrated into VS Code:
272
+
273
+ - **Chat Panel**: Interactive chat interface with full BluMa capabilities
274
+ - **Session Sync**: Real-time synchronization with terminal sessions
275
+ - **Image Support**: Paste and view images directly in VS Code
276
+ - **File Integration**: Open and edit files from within the chat
277
+ - **Streaming**: Real-time response streaming with markdown rendering
278
+
279
+ See [vscode-extension/README.md](vscode-extension/README.md) for setup instructions.
280
+
146
281
  ---
147
282
 
148
283
  ## πŸ—οΈ Architecture
@@ -207,7 +342,12 @@ This modular design enables:
207
342
  - **`src/ink/`**: Ink renderer shims and compatibility layer
208
343
  - **`src/shims/`**: Build-time shims for react-compiler-runtime and bidi-js
209
344
  - **`native/`**: Rust-based native modules (clipboard, yoga-layout)
345
+ - **bluma-clipboard**: Cross-platform clipboard with image support
346
+ - **yoga-layout**: High-performance layout engine for Ink
210
347
  - **`vscode-extension/`**: VS Code extension for chat integration
348
+ - Chat panel with full BluMa capabilities
349
+ - Real-time session sync
350
+ - Image and file support
211
351
 
212
352
  ---
213
353
 
@@ -352,6 +492,24 @@ bluma
352
492
  /pr "feat: add new authentication" # Create PR with conventional commit
353
493
  ```
354
494
 
495
+ ### 5. **Web Integration**
496
+ ```bash
497
+ # Use the embeddable React chat widget
498
+ import { useChatWidget } from '@nomad-e/bluma-cli/chat-widget';
499
+
500
+ // Embed BluMa capabilities in your web app
501
+ const { messages, streamResponse } = useChatWidget();
502
+ ```
503
+
504
+ ### 6. **VS Code Integration**
505
+ ```bash
506
+ # Install the VS Code extension
507
+ # Access full BluMa capabilities from within VS Code
508
+ - Chat panel with session sync
509
+ - Image and file support
510
+ - Real-time streaming
511
+ ```
512
+
355
513
  ---
356
514
 
357
515
  ## πŸ“„ License
@@ -366,4 +524,51 @@ Apache 2.0 β€” see [LICENSE](LICENSE) for details.
366
524
 
367
525
  ---
368
526
 
369
- *BluMa CLI v0.3.1 β€” Built with TypeScript, React/Ink, and ES modules.*
527
+ ## πŸ“° Changelog
528
+
529
+ See [CHANGELOG.md](CHANGELOG.md) for detailed release notes.
530
+
531
+ ### What's New in v0.6.4 (2026-05-10)
532
+
533
+ **Major Changes:**
534
+ - **Circular Dependency Resolution**: Fixed 'getNativeToolMetadata is not defined' error in tool metadata
535
+ - **Enhanced Native Tool Metadata**: Improved tool descriptions and metadata clarity across all 45+ tools
536
+ - **Improved Multi-Agent Coordination**: Better coordinator-worker communication and task tracking
537
+ - **Permission Mode Enhancement**: Full mode enabled for auto-approve of all tools
538
+
539
+ **Improvements:**
540
+ - Streamlined tool guidance in prompts
541
+ - Better error handling and user-friendly error messages
542
+ - Enhanced session persistence on LLM errors
543
+ - Improved worker registration for UI visibility
544
+
545
+ **Fixes:**
546
+ - Resolved circular dependency in tool metadata (prompt β†’ tools β†’ prompt cycle)
547
+ - Fixed worker registration for UI visibility in task_boundary tracking
548
+ - Improved session persistence on LLM errors
549
+
550
+ ---
551
+
552
+ ### What's New in v0.6.2 (2026-05-09)
553
+
554
+ **Major Features:**
555
+ - **Modular Tool Architecture**: All 45+ tools now have dedicated directories with separate logic, UI, and types
556
+ - **Native Clipboard Support**: Rust-based clipboard implementation for cross-platform image handling
557
+ - **Thread Management**: Full thread lifecycle with create, resume, fork, rename, archive, delete operations
558
+ - **Enhanced Multi-Agent Orchestration**: Improved coordinator-worker communication with bidirectional mailbox IPC
559
+ - **Chat Widget**: Embeddable React chat component for web integration
560
+
561
+ **Improvements:**
562
+ - 27 new slash commands for session management, inspection, and agent control
563
+ - Performance optimizations in UI rendering and context management
564
+ - Enhanced sandbox security with improved policy enforcement
565
+ - Better error handling and user-friendly error messages
566
+
567
+ **Fixes:**
568
+ - Resolved circular dependency in tool metadata
569
+ - Fixed worker registration for UI visibility
570
+ - Improved session persistence on LLM errors
571
+
572
+ ---
573
+
574
+ *BluMa CLI v0.6.4 β€” Built with TypeScript, React 19, Ink, and ES modules.*
@@ -570,13 +570,14 @@
570
570
  "type": "function",
571
571
  "function": {
572
572
  "name": "task_boundary",
573
- "description": "Indicate the start of a task or make an update to the current task. Use this to organize complex work into phases (PLANNING, EXECUTION, VERIFICATION). The UI will show this as a structured task view with progress tracking.",
573
+ "description": "Indicate the start of a task or make an update to the current task. Use this to organize complex work into phases (PLANNING, EXECUTION, VERIFICATION). The UI will show this as a structured task view with progress tracking. **IMPORTANT: All 4 fields are required and must not be empty.**",
574
574
  "parameters": {
575
575
  "type": "object",
576
576
  "properties": {
577
577
  "task_name": {
578
578
  "type": "string",
579
- "description": "Name of the task, e.g. 'Implementing Authentication'. Use the same name to update an existing task."
579
+ "minLength": 1,
580
+ "description": "Name of the task, e.g. 'Implementing Authentication'. Use the same name to update an existing task. **REQUIRED: Must not be empty.**"
580
581
  },
581
582
  "mode": {
582
583
  "type": "string",
@@ -585,15 +586,17 @@
585
586
  "EXECUTION",
586
587
  "VERIFICATION"
587
588
  ],
588
- "description": "Current mode: PLANNING (research/design), EXECUTION (implementing), VERIFICATION (testing)."
589
+ "description": "Current mode: PLANNING (research/design), EXECUTION (implementing), VERIFICATION (testing). **REQUIRED.**"
589
590
  },
590
591
  "task_status": {
591
592
  "type": "string",
592
- "description": "Current activity, e.g. 'Creating authentication middleware'. Describes what you are about to do."
593
+ "minLength": 1,
594
+ "description": "Current activity, e.g. 'Creating authentication middleware'. Describes what you are about to do. **REQUIRED: Must not be empty.**"
593
595
  },
594
596
  "task_summary": {
595
597
  "type": "string",
596
- "description": "Summary of what has been accomplished so far. Should be concise but comprehensive."
598
+ "minLength": 1,
599
+ "description": "Summary of what has been accomplished so far. Should be concise but comprehensive. **REQUIRED: Must not be empty.**"
597
600
  }
598
601
  },
599
602
  "required": [
package/dist/main.js CHANGED
@@ -14933,8 +14933,6 @@ import path7 from "path";
14933
14933
  import os6 from "os";
14934
14934
  import { promises as fs8 } from "fs";
14935
14935
  import { diffLines } from "diff";
14936
- var MAX_DIFF_SIZE = 5e4;
14937
- var MAX_FILE_SIZE = 10 * 1024 * 1024;
14938
14936
  function normalizePath(filePath) {
14939
14937
  try {
14940
14938
  filePath = filePath.trim();
@@ -15138,18 +15136,6 @@ async function calculateEdit(filePath, oldString, newString, expectedReplacement
15138
15136
  let currentContent = null;
15139
15137
  try {
15140
15138
  const stats = await fs8.stat(normalizedFilePath);
15141
- if (stats.size > MAX_FILE_SIZE) {
15142
- return {
15143
- currentContent,
15144
- newContent: "",
15145
- occurrences: 0,
15146
- error: {
15147
- display: `File too large (${(stats.size / 1024 / 1024).toFixed(2)}MB). Maximum allowed: ${MAX_FILE_SIZE / 1024 / 1024}MB`,
15148
- raw: `File size exceeds limit: ${normalizedFilePath}`
15149
- },
15150
- isNewFile: false
15151
- };
15152
- }
15153
15139
  const buf = await fs8.readFile(normalizedFilePath, "utf-8");
15154
15140
  currentContent = buf.replace(/\r\n/g, "\n");
15155
15141
  } catch (e) {
@@ -15170,12 +15156,6 @@ async function calculateEdit(filePath, oldString, newString, expectedReplacement
15170
15156
  }
15171
15157
  function createDiff(filename, oldContent, newContent) {
15172
15158
  try {
15173
- if (oldContent.length > MAX_DIFF_SIZE || newContent.length > MAX_DIFF_SIZE) {
15174
- return `--- a/${filename}
15175
- +++ b/${filename}
15176
- [Diff too large to display. File size: ${oldContent.length} -> ${newContent.length} bytes]
15177
- `;
15178
- }
15179
15159
  const diff2 = diffLines(oldContent, newContent, {});
15180
15160
  let diffString = `--- a/${filename}
15181
15161
  +++ b/${filename}
@@ -15280,17 +15260,6 @@ async function applyBatchEditsInMemory(edits, readFileState) {
15280
15260
  if (!slots.has(norm)) {
15281
15261
  let content = null;
15282
15262
  try {
15283
- const stats = await fs8.stat(norm);
15284
- if (stats.size > MAX_FILE_SIZE) {
15285
- return {
15286
- ok: false,
15287
- failed: {
15288
- success: false,
15289
- error: `File too large (${(stats.size / 1024 / 1024).toFixed(2)}MB). Maximum allowed: ${MAX_FILE_SIZE / 1024 / 1024}MB`,
15290
- file_path: norm
15291
- }
15292
- };
15293
- }
15294
15263
  const buf = await fs8.readFile(norm, "utf-8");
15295
15264
  content = buf.replace(/\r\n/g, "\n");
15296
15265
  } catch (err) {
@@ -16089,7 +16058,7 @@ import { promises as fsPromises2 } from "fs";
16089
16058
  import os10 from "os";
16090
16059
  var MAX_RESULTS3 = 200;
16091
16060
  var MAX_MATCHES_PER_FILE = 10;
16092
- var MAX_FILE_SIZE2 = 1024 * 1024;
16061
+ var MAX_FILE_SIZE = 1024 * 1024;
16093
16062
  var MAX_LINE_LENGTH = 300;
16094
16063
  var DEFAULT_IGNORE3 = /* @__PURE__ */ new Set([
16095
16064
  "node_modules",
@@ -16213,7 +16182,7 @@ function createSearchPattern(query, isRegex, caseInsensitive) {
16213
16182
  async function searchFile(filepath, baseDir, pattern, contextLines, maxMatchesPerFile) {
16214
16183
  try {
16215
16184
  const stat = await fsPromises2.stat(filepath);
16216
- if (stat.size > MAX_FILE_SIZE2) return null;
16185
+ if (stat.size > MAX_FILE_SIZE) return null;
16217
16186
  const content = await fsPromises2.readFile(filepath, "utf-8");
16218
16187
  const lines = content.split("\n");
16219
16188
  const relativePath = path12.relative(baseDir, filepath).split(path12.sep).join("/");
@@ -16617,31 +16586,26 @@ async function updateTaskFile(task) {
16617
16586
  async function taskBoundary(args) {
16618
16587
  try {
16619
16588
  const { task_name, mode, task_status, task_summary } = args;
16589
+ const missingFields = [];
16620
16590
  if (!task_name || typeof task_name !== "string") {
16621
- return {
16622
- success: false,
16623
- task_name: "",
16624
- mode: "EXECUTION",
16625
- status: "",
16626
- message: "task_name is required"
16627
- };
16591
+ missingFields.push("task_name");
16628
16592
  }
16629
- if (!["PLANNING", "EXECUTION", "VERIFICATION"].includes(mode)) {
16630
- return {
16631
- success: false,
16632
- task_name,
16633
- mode: "EXECUTION",
16634
- status: "",
16635
- message: `Invalid mode: ${mode}. Must be PLANNING, EXECUTION, or VERIFICATION`
16636
- };
16593
+ if (!mode || !["PLANNING", "EXECUTION", "VERIFICATION"].includes(mode)) {
16594
+ missingFields.push("mode");
16637
16595
  }
16638
16596
  if (!task_status || typeof task_status !== "string") {
16597
+ missingFields.push("task_status");
16598
+ }
16599
+ if (!task_summary || typeof task_summary !== "string") {
16600
+ missingFields.push("task_summary");
16601
+ }
16602
+ if (missingFields.length > 0) {
16639
16603
  return {
16640
16604
  success: false,
16641
- task_name,
16642
- mode,
16643
- status: "",
16644
- message: "task_status is required"
16605
+ task_name: task_name || "",
16606
+ mode: mode || "EXECUTION",
16607
+ status: task_status || "",
16608
+ message: `Missing required fields: ${missingFields.join(", ")}. All 4 fields are required: task_name, mode, task_status, task_summary`
16645
16609
  };
16646
16610
  }
16647
16611
  const now2 = Date.now();
@@ -23542,53 +23506,6 @@ function disableCoordinatorMode() {
23542
23506
  delete process.env.BLUMA_COORDINATOR_MODE;
23543
23507
  }
23544
23508
 
23545
- // src/app/agent/core/prompt/tool_guidance.ts
23546
- var TOOL_GUIDANCE_RULES = [
23547
- {
23548
- toolName: "read_file_lines",
23549
- guidance: "To read files use `read_file_lines` instead of cat, head, tail, or sed"
23550
- },
23551
- {
23552
- toolName: "edit_tool",
23553
- guidance: "To edit files use `edit_tool` instead of sed or awk"
23554
- },
23555
- {
23556
- toolName: "file_write",
23557
- guidance: "To create files use `file_write` instead of cat with heredoc or echo redirection"
23558
- },
23559
- {
23560
- toolName: "grep_search",
23561
- guidance: "To search file content use `grep_search` instead of grep or rg"
23562
- },
23563
- {
23564
- toolName: "find_by_name",
23565
- guidance: "To search for files use `find_by_name` instead of find or ls"
23566
- },
23567
- {
23568
- toolName: "view_file_outline",
23569
- guidance: "To understand file structure use `view_file_outline` instead of opening the whole file"
23570
- }
23571
- ];
23572
- var ALWAYS_INCLUDED = [
23573
- "Reserve using `shell_command` exclusively for system commands and terminal operations that require shell execution. If you are unsure and there is a relevant dedicated tool, default to using the dedicated tool.",
23574
- "You can call multiple tools in a single response. If you intend to call multiple tools and there are no dependencies between them, make all independent tool calls in parallel. Maximize use of parallel tool calls where possible to increase efficiency.",
23575
- "Do NOT use `shell_command` to run commands when a relevant dedicated tool is provided. Using dedicated tools allows the user to better understand and review your work."
23576
- ];
23577
- function buildToolGuidanceSection(availableTools) {
23578
- const toolSet = new Set(availableTools);
23579
- const activeRules = TOOL_GUIDANCE_RULES.filter((rule) => toolSet.has(rule.toolName)).map((rule) => rule.guidance);
23580
- if (activeRules.length === 0) {
23581
- return "";
23582
- }
23583
- const lines = [
23584
- "# Using your tools",
23585
- "",
23586
- ...activeRules.map((r) => `- ${r}`),
23587
- ...ALWAYS_INCLUDED.map((r) => `- ${r}`)
23588
- ];
23589
- return lines.join("\n");
23590
- }
23591
-
23592
23509
  // src/app/agent/core/prompt/model_info.ts
23593
23510
  var KNOWLEDGE_CUTOFFS = [
23594
23511
  { match: "claude-sonnet-4-6", cutoff: "August 2025" },
@@ -23811,16 +23728,6 @@ function isAutoMemoryEnabled() {
23811
23728
  }
23812
23729
 
23813
23730
  // src/app/agent/core/prompt/prompt_builder.ts
23814
- var INTERNAL_TOOLS = /* @__PURE__ */ new Set([
23815
- "spawn_agent",
23816
- "wait_agent",
23817
- "list_agents",
23818
- "send_message",
23819
- "list_mailbox_messages",
23820
- "poll_mailbox",
23821
- "signal_mailbox",
23822
- "kill_agent"
23823
- ]);
23824
23731
  function getNodeVersion() {
23825
23732
  return process.version;
23826
23733
  }
@@ -24167,14 +24074,6 @@ ${formatFactorAiAppContextSummary(appContext)}
24167
24074
  if (modelInfo) prompt += `
24168
24075
 
24169
24076
  ${modelInfo}`;
24170
- const allToolNames = options?.availableToolNames ?? [];
24171
- if (allToolNames.length > 0) {
24172
- const visibleTools = isSandbox ? allToolNames : allToolNames.filter((n) => !INTERNAL_TOOLS.has(n));
24173
- const guidance = buildToolGuidanceSection(visibleTools);
24174
- if (guidance) prompt += `
24175
-
24176
- ${guidance}`;
24177
- }
24178
24077
  prompt += `
24179
24078
 
24180
24079
  ${buildSystemRemindersSection()}`;
@@ -25279,6 +25178,9 @@ var ToolCallNormalizer = class {
25279
25178
  }
25280
25179
  /**
25281
25180
  * Valida se um tool call normalizado Γ© vΓ‘lido
25181
+ * ValidaΓ§Γ£o dupla:
25182
+ * 1. JSON dos argumentos Γ© vΓ‘lido
25183
+ * 2. A ferramenta existe no catΓ‘logo de ferramentas nativas
25282
25184
  */
25283
25185
  static isValidToolCall(call) {
25284
25186
  if (!(call.id && call.type === "function" && call.function?.name && typeof call.function.arguments === "string")) {
@@ -25286,10 +25188,14 @@ var ToolCallNormalizer = class {
25286
25188
  }
25287
25189
  try {
25288
25190
  JSON.parse(call.function.arguments);
25289
- return true;
25290
25191
  } catch {
25291
25192
  return false;
25292
25193
  }
25194
+ const toolMetadata = getNativeToolMetadata(call.function.name);
25195
+ if (!toolMetadata) {
25196
+ return false;
25197
+ }
25198
+ return true;
25293
25199
  }
25294
25200
  };
25295
25201
 
@@ -25336,7 +25242,7 @@ function checkFilePermissionRules(toolName, filePath, policy) {
25336
25242
  }
25337
25243
  return { allowed: false, reason: `No permission rule found for file "${filePath}".` };
25338
25244
  }
25339
- function decideToolExecution(toolName, args) {
25245
+ function decideToolExecution(toolName, args, sessionId) {
25340
25246
  const policy = getSandboxPolicy();
25341
25247
  const metadata = getNativeToolMetadata(toolName);
25342
25248
  if (!metadata) {
@@ -25347,6 +25253,15 @@ function decideToolExecution(toolName, args) {
25347
25253
  reason: "Unknown tool metadata; require confirmation by default."
25348
25254
  };
25349
25255
  }
25256
+ if (sessionId && getEffectivePermissionMode(sessionId) === "full") {
25257
+ return {
25258
+ toolName,
25259
+ metadata,
25260
+ autoApprove: true,
25261
+ requiresConfirmation: false,
25262
+ reason: "Full permission mode: ALL tools auto-approved. User explicitly enabled unrestricted mode."
25263
+ };
25264
+ }
25350
25265
  const ruleDecision = permissionRulesEngine.checkPermission(toolName, args);
25351
25266
  if (ruleDecision === "deny") {
25352
25267
  return {
@@ -25619,10 +25534,10 @@ var PARALLEL_SAFE_TOOL_NAMES = /* @__PURE__ */ new Set([
25619
25534
  "read_mcp_resource",
25620
25535
  "todo"
25621
25536
  ]);
25622
- function toolEligibleForParallelRead(toolName) {
25537
+ function toolEligibleForParallelRead(toolName, sessionId) {
25623
25538
  const name = String(toolName || "").trim();
25624
25539
  if (!name || !PARALLEL_SAFE_TOOL_NAMES.has(name)) return false;
25625
- if (!decideToolExecution(name).autoApprove) return false;
25540
+ if (!decideToolExecution(name, void 0, sessionId).autoApprove) return false;
25626
25541
  const meta = getNativeToolMetadata(name);
25627
25542
  return meta?.riskLevel === "safe";
25628
25543
  }
@@ -25928,7 +25843,7 @@ var BluMaAgent = class _BluMaAgent {
25928
25843
  }
25929
25844
  /** PolΓ­tica mostrada na UI: combina metadata base com auto-approve efectivo (incl. permission_ml). */
25930
25845
  buildToolPolicyForUi(toolName, toolArgs) {
25931
- const base = decideToolExecution(toolName);
25846
+ const base = decideToolExecution(toolName, void 0, this.sessionId);
25932
25847
  const argsStr = typeof toolArgs === "string" ? toolArgs : JSON.stringify(toolArgs ?? {});
25933
25848
  const synthetic = { function: { name: toolName, arguments: argsStr } };
25934
25849
  const auto = effectiveToolAutoApprove(synthetic, this.sessionId, { logClassifier: false });
@@ -25988,10 +25903,6 @@ var BluMaAgent = class _BluMaAgent {
25988
25903
  role: "system",
25989
25904
  content: `[SYSTEM] Tool "${toolName}" is not found in the agent's available tools. Please use only tools that are listed in your tool catalog.`
25990
25905
  });
25991
- this.eventBus.emit("backend_message", {
25992
- type: "error",
25993
- message: `Tool "${toolName}" does not exist in the agent catalog.`
25994
- });
25995
25906
  this.persistSession();
25996
25907
  return true;
25997
25908
  }
@@ -26178,10 +26089,6 @@ var BluMaAgent = class _BluMaAgent {
26178
26089
  role: "system",
26179
26090
  content: `[SYSTEM] Tool "${toolName}" is not found in the agent's available tools. Please use only tools that are listed in your tool catalog.`
26180
26091
  });
26181
- this.eventBus.emit("backend_message", {
26182
- type: "error",
26183
- message: `Tool "${toolName}" does not exist in the agent catalog.`
26184
- });
26185
26092
  this.persistSession();
26186
26093
  return true;
26187
26094
  }
@@ -26330,13 +26237,13 @@ var BluMaAgent = class _BluMaAgent {
26330
26237
  let i = 0;
26331
26238
  while (i < calls.length && shouldContinue && !this.isInterrupted) {
26332
26239
  const name = calls[i].function.name;
26333
- if (!toolEligibleForParallelRead(name)) {
26240
+ if (!toolEligibleForParallelRead(name, this.sessionId)) {
26334
26241
  shouldContinue = await this.executeApprovedToolInvocation(calls[i], decisionData);
26335
26242
  i += 1;
26336
26243
  continue;
26337
26244
  }
26338
26245
  let j = i;
26339
- while (j < calls.length && toolEligibleForParallelRead(calls[j].function.name)) {
26246
+ while (j < calls.length && toolEligibleForParallelRead(calls[j].function.name, this.sessionId)) {
26340
26247
  j += 1;
26341
26248
  }
26342
26249
  const slice = calls.slice(i, j);
@@ -26624,7 +26531,7 @@ ${editData.error.display}`;
26624
26531
  }
26625
26532
  if (confirmationToolCalls.length > 0) {
26626
26533
  const toolToCall = confirmationToolCalls[0];
26627
- const decision = decideToolExecution(toolToCall.function.name);
26534
+ const decision = decideToolExecution(toolToCall.function.name, void 0, this.sessionId);
26628
26535
  const toolName = toolToCall.function.name;
26629
26536
  let previewContent;
26630
26537
  if (toolName === "edit_tool") {
@@ -26699,7 +26606,7 @@ ${editData.error.display}`;
26699
26606
  }
26700
26607
  if (confirmationToolCalls.length > 0) {
26701
26608
  const toolToCall = confirmationToolCalls[0];
26702
- const decision = decideToolExecution(toolToCall.function.name);
26609
+ const decision = decideToolExecution(toolToCall.function.name, void 0, this.sessionId);
26703
26610
  const toolName = toolToCall.function.name;
26704
26611
  let previewContent;
26705
26612
  if (toolName === "edit_tool") {
@@ -27647,7 +27554,7 @@ var BaseLLMSubAgent = class {
27647
27554
  break;
27648
27555
  }
27649
27556
  if (message2.tool_calls) {
27650
- const decision = decideToolExecution(message2.tool_calls[0].function.name);
27557
+ const decision = decideToolExecution(message2.tool_calls[0].function.name, void 0, `${this.id}`);
27651
27558
  if (!decision.autoApprove) {
27652
27559
  this.emitEvent("error", {
27653
27560
  message: `Subagent tool "${message2.tool_calls[0].function.name}" requires confirmation outside sandbox mode.`
@@ -27771,7 +27678,7 @@ ${editData.error.display}`;
27771
27678
  }
27772
27679
  }
27773
27680
  if (message2.tool_calls) {
27774
- const decision = decideToolExecution(message2.tool_calls[0].function.name);
27681
+ const decision = decideToolExecution(message2.tool_calls[0].function.name, void 0, `${this.id}`);
27775
27682
  if (!decision.autoApprove) {
27776
27683
  this.emitEvent("error", {
27777
27684
  message: `Subagent tool "${message2.tool_calls[0].function.name}" requires confirmation outside sandbox mode.`
@@ -27821,7 +27728,7 @@ ${editData.error.display}`;
27821
27728
  tool_name: toolName,
27822
27729
  arguments: toolArgs,
27823
27730
  preview: previewContent,
27824
- tool_policy: decideToolExecution(toolName)
27731
+ tool_policy: decideToolExecution(toolName, void 0, `${this.id}`)
27825
27732
  });
27826
27733
  try {
27827
27734
  if (this.isInterrupted) {
@@ -36484,10 +36391,10 @@ var runWorktreeSet = (_agentRef, _path, _setIsProcessing, _markTurnStarted) => {
36484
36391
  var runPermissionSet = (_agentRef, mode, _setIsProcessing, _markTurnStarted, sessionId) => {
36485
36392
  if (mode === "full") {
36486
36393
  if (sessionId) {
36487
- setSessionPermissionMode(sessionId, "accept_edits");
36394
+ setSessionPermissionMode(sessionId, "full");
36488
36395
  return usageBox("Permission", "Set to full");
36489
36396
  } else {
36490
- setRuntimeConfig({ permissionMode: "accept_edits", sandboxEnabled: false });
36397
+ setRuntimeConfig({ permissionMode: "full", sandboxEnabled: false });
36491
36398
  return usageBox("Permission", "Set to full (global)");
36492
36399
  }
36493
36400
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nomad-e/bluma-cli",
3
- "version": "0.6.2",
3
+ "version": "0.6.5",
4
4
  "description": "BluMa independent agent for automation and advanced software engineering.",
5
5
  "author": "Alex Fonseca",
6
6
  "license": "Apache-2.0",