@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 +216 -11
- package/dist/config/native_tools.json +8 -5
- package/dist/main.js +46 -139
- package/package.json +1 -1
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
|
|
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
|
-
|
|
86
|
-
-
|
|
87
|
-
-
|
|
88
|
-
-
|
|
89
|
-
-
|
|
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
|
|
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
|
-
|
|
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
|
-
"
|
|
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
|
-
"
|
|
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
|
-
"
|
|
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
|
|
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 >
|
|
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
|
-
|
|
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
|
-
|
|
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: "
|
|
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, "
|
|
36394
|
+
setSessionPermissionMode(sessionId, "full");
|
|
36488
36395
|
return usageBox("Permission", "Set to full");
|
|
36489
36396
|
} else {
|
|
36490
|
-
setRuntimeConfig({ permissionMode: "
|
|
36397
|
+
setRuntimeConfig({ permissionMode: "full", sandboxEnabled: false });
|
|
36491
36398
|
return usageBox("Permission", "Set to full (global)");
|
|
36492
36399
|
}
|
|
36493
36400
|
}
|