@nomad-e/bluma-cli 0.1.48 → 0.1.49
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 +148 -25
- package/dist/main.js +177 -114
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -36,8 +36,8 @@ BluMa operates as a **conversational agent** in the terminal, combining:
|
|
|
36
36
|
|
|
37
37
|
- **Rich UI Layer**: React/Ink 5 components for interactive prompts, live overlays, and real-time feedback
|
|
38
38
|
- **Agent Layer**: LLM orchestration via FactorRouter with tool invocation and context management
|
|
39
|
-
- **Runtime Layer**: Task tracking, plugin system, hooks, diagnostics, and
|
|
40
|
-
- **Tool Layer**:
|
|
39
|
+
- **Runtime Layer**: Task tracking, plugin system, hooks, diagnostics, session management, and coordinator mode
|
|
40
|
+
- **Tool Layer**: 40+ native tools + MCP SDK integration for external tools
|
|
41
41
|
|
|
42
42
|
The agent maintains persistent conversation history, workspace snapshots, and coding memory across sessions.
|
|
43
43
|
|
|
@@ -223,15 +223,26 @@ npm start
|
|
|
223
223
|
│ │Sandbox │ │ToolExec │ │Diagnostics│ │SessionView │ │
|
|
224
224
|
│ │Policy │ │Policy │ │ │ │ │ │
|
|
225
225
|
│ └──────────┘ └──────────┘ └──────────┘ └──────────────┘ │
|
|
226
|
+
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │
|
|
227
|
+
│ │Feature │ │Plan Mode │ │Tool Auto │ │Tool Permission│ │
|
|
228
|
+
│ │Flags │ │Session │ │Approve │ │Classifier │ │
|
|
229
|
+
│ └──────────┘ └──────────┘ └──────────┘ └──────────────┘ │
|
|
226
230
|
└─────────────────────────────────────────────────────────────┘
|
|
227
231
|
│
|
|
228
232
|
┌────────────────────────┼────────────────────────────────────┐
|
|
229
233
|
│ Tools Layer │
|
|
230
234
|
│ ┌──────────────────────────────────────────────────────┐ │
|
|
231
|
-
│ │ Native Tools (
|
|
235
|
+
│ │ Native Tools (40+) │ │
|
|
232
236
|
│ │ edit_tool, file_write, shell_command, grep_search, │ │
|
|
233
|
-
│ │ spawn_agent,
|
|
234
|
-
│ │
|
|
237
|
+
│ │ spawn_agent, wait_agent, list_agents, │ │
|
|
238
|
+
│ │ todo, task_boundary, task_create, task_list, │ │
|
|
239
|
+
│ │ task_get, task_update, task_stop, │ │
|
|
240
|
+
│ │ coding_memory, search_web, web_fetch, load_skill, │ │
|
|
241
|
+
│ │ message, ask_user_question, │ │
|
|
242
|
+
│ │ list_mcp_resources, read_mcp_resource, │ │
|
|
243
|
+
│ │ cron_create, cron_list, cron_delete, │ │
|
|
244
|
+
│ │ lsp_query, notebook_edit, │ │
|
|
245
|
+
│ │ enter_plan_mode, exit_plan_mode, ... │ │
|
|
235
246
|
│ └──────────────────────────────────────────────────────┘ │
|
|
236
247
|
│ ┌──────────────────────────────────────────────────────┐ │
|
|
237
248
|
│ │ MCP SDK Integration │ │
|
|
@@ -244,26 +255,27 @@ npm start
|
|
|
244
255
|
|
|
245
256
|
## Native Tools
|
|
246
257
|
|
|
247
|
-
BluMa includes
|
|
258
|
+
BluMa includes **40+ built-in tools** organized by category:
|
|
248
259
|
|
|
249
260
|
### File Operations
|
|
250
261
|
| Tool | Description |
|
|
251
262
|
|------|-------------|
|
|
252
|
-
| `edit_tool` | Replace text in files (precise, multi-line) |
|
|
263
|
+
| `edit_tool` | Replace text in files (precise, multi-line, batch edits) |
|
|
253
264
|
| `file_write` | Create/overwrite entire files |
|
|
254
|
-
| `read_file_lines` | Read specific line ranges |
|
|
265
|
+
| `read_file_lines` | Read specific line ranges (up to 2000 lines) |
|
|
255
266
|
| `count_file_lines` | Get file line count |
|
|
256
|
-
| `ls_tool` | List directories with filtering |
|
|
267
|
+
| `ls_tool` | List directories with filtering and pagination |
|
|
257
268
|
| `find_by_name` | Glob-based file search |
|
|
258
269
|
| `grep_search` | Text/regex search across files |
|
|
259
|
-
| `view_file_outline` | Show code structure (classes, functions) |
|
|
270
|
+
| `view_file_outline` | Show code structure (classes, functions, interfaces) |
|
|
271
|
+
| `notebook_edit` | Edit Jupyter `.ipynb` files (cells operations) |
|
|
260
272
|
|
|
261
273
|
### Shell & Commands
|
|
262
274
|
| Tool | Description |
|
|
263
275
|
|------|-------------|
|
|
264
276
|
| `shell_command` | Execute background commands |
|
|
265
277
|
| `command_status` | Check command progress/output |
|
|
266
|
-
| `send_command_input` | Send input to running commands |
|
|
278
|
+
| `send_command_input` | Send input to running commands' stdin |
|
|
267
279
|
| `kill_command` | Terminate running commands |
|
|
268
280
|
|
|
269
281
|
### Agent Coordination
|
|
@@ -278,6 +290,11 @@ BluMa includes 25+ built-in tools organized by category:
|
|
|
278
290
|
|------|-------------|
|
|
279
291
|
| `todo` | Manage task lists |
|
|
280
292
|
| `task_boundary` | Track task phases (PLANNING/EXECUTION/VERIFICATION) |
|
|
293
|
+
| `task_create` | Create session-scoped tasks |
|
|
294
|
+
| `task_list` | List all session tasks |
|
|
295
|
+
| `task_get` | Get one task by id |
|
|
296
|
+
| `task_update` | Update task fields |
|
|
297
|
+
| `task_stop` | Cancel a task |
|
|
281
298
|
| `create_artifact` | Save documents to `~/.bluma/artifacts/` |
|
|
282
299
|
| `read_artifact` | Retrieve saved artifacts |
|
|
283
300
|
|
|
@@ -287,12 +304,37 @@ BluMa includes 25+ built-in tools organized by category:
|
|
|
287
304
|
| `search_web` | Search programming solutions (Reddit, GitHub, StackOverflow) |
|
|
288
305
|
| `web_fetch` | Fetch and analyze remote URLs |
|
|
289
306
|
| `load_skill` | Activate domain-specific skills |
|
|
290
|
-
| `coding_memory` |
|
|
307
|
+
| `coding_memory` | CRUD for persistent coding notes |
|
|
291
308
|
|
|
292
|
-
### Communication
|
|
309
|
+
### Communication & Interaction
|
|
293
310
|
| Tool | Description |
|
|
294
311
|
|------|-------------|
|
|
295
312
|
| `message` | Post user-visible chat (info/result types) |
|
|
313
|
+
| `ask_user_question` | Ask multiple-choice questions in terminal |
|
|
314
|
+
|
|
315
|
+
### MCP & Resources
|
|
316
|
+
| Tool | Description |
|
|
317
|
+
|------|-------------|
|
|
318
|
+
| `list_mcp_resources` | List resources from MCP servers |
|
|
319
|
+
| `read_mcp_resource` | Read a resource URI from MCP server |
|
|
320
|
+
|
|
321
|
+
### Scheduling
|
|
322
|
+
| Tool | Description |
|
|
323
|
+
|------|-------------|
|
|
324
|
+
| `cron_create` | Schedule one-shot or repeating reminders |
|
|
325
|
+
| `cron_list` | List scheduled cron jobs |
|
|
326
|
+
| `cron_delete` | Cancel scheduled job |
|
|
327
|
+
|
|
328
|
+
### Development Tools
|
|
329
|
+
| Tool | Description |
|
|
330
|
+
|------|-------------|
|
|
331
|
+
| `lsp_query` | LSP go-to-definition or references (TS/JS) |
|
|
332
|
+
|
|
333
|
+
### Plan Mode
|
|
334
|
+
| Tool | Description |
|
|
335
|
+
|------|-------------|
|
|
336
|
+
| `enter_plan_mode` | Enter plan-only mode (edits require confirmation) |
|
|
337
|
+
| `exit_plan_mode` | Leave plan mode |
|
|
296
338
|
|
|
297
339
|
---
|
|
298
340
|
|
|
@@ -464,6 +506,8 @@ Built-in terminal commands (type `/` to see all):
|
|
|
464
506
|
| `/img ./shot.png [question]` | Send local image(s) to the model |
|
|
465
507
|
| `/image` | Alias of /img |
|
|
466
508
|
| `/init` | Run init subagent — BluMa.md codebase documentation |
|
|
509
|
+
| `/agent [default\|coordinator]` | Set prompt profile (coordinator playbook for worker orchestration) |
|
|
510
|
+
| `/agents` | List worker/agent sessions (spawn_agent children) |
|
|
467
511
|
|
|
468
512
|
### Inspect
|
|
469
513
|
| Command | Description |
|
|
@@ -471,7 +515,7 @@ Built-in terminal commands (type `/` to see all):
|
|
|
471
515
|
| `/plugins` | List installed plugins and plugin paths |
|
|
472
516
|
| `/plugin <name>` | Inspect one plugin |
|
|
473
517
|
| `/diagnostics` | Show a consolidated health snapshot |
|
|
474
|
-
| `/permissions` | Inspect sandbox and tool
|
|
518
|
+
| `/permissions` | Inspect sandbox and tool rules; set mode |
|
|
475
519
|
| `/hooks` | Inspect, enable, disable, or clear lifecycle hooks |
|
|
476
520
|
| `/model [list\|name\|auto]` | Show, list, or set the active model |
|
|
477
521
|
| `/effort [low\|medium\|high]` | Show or set reasoning effort |
|
|
@@ -482,6 +526,7 @@ Built-in terminal commands (type `/` to see all):
|
|
|
482
526
|
| `/skills` | List load_skill modules, dirs, and conflicts |
|
|
483
527
|
| `/tools [grep]` | List native tools (optional filter) |
|
|
484
528
|
| `/mcp [fs]` | List MCP tools (optional filter) |
|
|
529
|
+
| `/features` | Feature flags: `/features` or `/features <key> on\|off` |
|
|
485
530
|
|
|
486
531
|
### Help
|
|
487
532
|
| Command | Description |
|
|
@@ -491,8 +536,8 @@ Built-in terminal commands (type `/` to see all):
|
|
|
491
536
|
### Input (Keyboard Shortcuts)
|
|
492
537
|
| Shortcut | Description |
|
|
493
538
|
|----------|-------------|
|
|
494
|
-
| `Ctrl+V / Cmd+V` | Paste from clipboard: image →
|
|
495
|
-
| `Ctrl+Shift+I` | Same as Ctrl+V
|
|
539
|
+
| `Ctrl+V / Cmd+V` | Paste from clipboard: image → cache `~/.cache/bluma/clipboard`; text; or file path as image |
|
|
540
|
+
| `Ctrl+Shift+I` | Same as Ctrl+V (paste image, text, or file path) |
|
|
496
541
|
|
|
497
542
|
---
|
|
498
543
|
|
|
@@ -520,6 +565,12 @@ src/
|
|
|
520
565
|
│ ├── agent/
|
|
521
566
|
│ │ ├── agent.ts # Main orchestrator
|
|
522
567
|
│ │ ├── bluma/ # Core agent logic
|
|
568
|
+
│ │ │ ├── core/
|
|
569
|
+
│ │ │ │ └── bluma.ts # BluMaAgent class
|
|
570
|
+
│ │ │ └── turn_start_payload.ts # Backend turn payload
|
|
571
|
+
│ │ ├── config/
|
|
572
|
+
│ │ │ ├── native_tools.json # Tool definitions (40+)
|
|
573
|
+
│ │ │ └── skills/ # Bundled skills (git-commit, git-pr, pdf, xlsx, skill-creator)
|
|
523
574
|
│ │ ├── core/ # LLM, context, prompts
|
|
524
575
|
│ │ │ ├── context-api/ # Context management
|
|
525
576
|
│ │ │ │ ├── context_manager.ts # Token-aware context
|
|
@@ -531,41 +582,80 @@ src/
|
|
|
531
582
|
│ │ │ └── prompt/ # Prompt engineering
|
|
532
583
|
│ │ │ ├── prompt_builder.ts # Dynamic prompts
|
|
533
584
|
│ │ │ └── workspace_snapshot.ts
|
|
585
|
+
│ │ ├── feedback/
|
|
586
|
+
│ │ │ └── feedback_system.ts # Smart feedback system
|
|
534
587
|
│ │ ├── runtime/ # Orchestration layer (v0.1.41+)
|
|
535
588
|
│ │ │ ├── diagnostics.ts # System snapshots
|
|
589
|
+
│ │ │ ├── feature_flags.ts # Feature gates
|
|
536
590
|
│ │ │ ├── hook_registry.ts # Event-driven hooks
|
|
537
591
|
│ │ │ ├── native_tool_catalog.ts # Tool registry
|
|
592
|
+
│ │ │ ├── plan_mode_session.ts # Plan mode state
|
|
538
593
|
│ │ │ ├── plugin_registry.ts # Plugin system
|
|
594
|
+
│ │ │ ├── plugin_runtime.ts # Plugin execution
|
|
539
595
|
│ │ │ ├── runtime_config.ts # Runtime settings
|
|
540
596
|
│ │ │ ├── sandbox_policy.ts # Safety policies
|
|
541
597
|
│ │ │ ├── session_registry.ts # Multi-session mgmt
|
|
542
598
|
│ │ │ ├── session_view.ts # Session monitoring
|
|
543
599
|
│ │ │ ├── task_store.ts # Task lifecycle
|
|
544
|
-
│ │ │
|
|
545
|
-
│ │ ├──
|
|
546
|
-
│ │ │
|
|
600
|
+
│ │ │ ├── tool_auto_approve.ts # Auto-approve rules
|
|
601
|
+
│ │ │ ├── tool_execution_policy.ts
|
|
602
|
+
│ │ │ ├── tool_orchestration.ts # Parallel read eligibility
|
|
603
|
+
│ │ │ └── tool_permission_classifier.ts
|
|
604
|
+
│ │ ├── session_manager/
|
|
605
|
+
│ │ │ └── session_manager.ts # Session persistence
|
|
606
|
+
│ │ ├── skills/
|
|
607
|
+
│ │ │ └── skill_loader.ts # Skill loading
|
|
608
|
+
│ │ ├── subagents/ # Subagent system
|
|
609
|
+
│ │ │ ├── base_llm_subagent.ts
|
|
610
|
+
│ │ │ ├── init/ # Init subagent (BluMa.md)
|
|
611
|
+
│ │ │ ├── registry.ts
|
|
612
|
+
│ │ │ ├── subagents_bluma.ts
|
|
613
|
+
│ │ │ └── types.ts
|
|
614
|
+
│ │ ├── tools/
|
|
615
|
+
│ │ │ ├── mcp/
|
|
616
|
+
│ │ │ │ └── mcp_client.ts # MCP SDK client
|
|
617
|
+
│ │ │ └── natives/ # 27 native tool implementations
|
|
547
618
|
│ │ │ ├── agent_coordination.ts
|
|
619
|
+
│ │ │ ├── ask_user_question.ts
|
|
548
620
|
│ │ │ ├── async_command.ts
|
|
549
621
|
│ │ │ ├── coding_memory.ts
|
|
622
|
+
│ │ │ ├── coding_memory_consolidate.ts
|
|
623
|
+
│ │ │ ├── coordinator_tools.ts
|
|
624
|
+
│ │ │ ├── count_lines.ts
|
|
550
625
|
│ │ │ ├── edit.ts
|
|
551
626
|
│ │ │ ├── file_write.ts
|
|
552
627
|
│ │ │ ├── find_by_name.ts
|
|
553
628
|
│ │ │ ├── grep_search.ts
|
|
554
629
|
│ │ │ ├── load_skill.ts
|
|
555
630
|
│ │ │ ├── ls.ts
|
|
631
|
+
│ │ │ ├── lsp_query.ts
|
|
632
|
+
│ │ │ ├── mcp_resources.ts
|
|
556
633
|
│ │ │ ├── message.ts
|
|
634
|
+
│ │ │ ├── notebook_edit.ts
|
|
635
|
+
│ │ │ ├── plan_mode_tools.ts
|
|
557
636
|
│ │ │ ├── readLines.ts
|
|
558
637
|
│ │ │ ├── search_web.ts
|
|
638
|
+
│ │ │ ├── session_cron.ts
|
|
559
639
|
│ │ │ ├── shell_command.ts
|
|
560
640
|
│ │ │ ├── task_boundary.ts
|
|
641
|
+
│ │ │ ├── task_tools.ts
|
|
561
642
|
│ │ │ ├── todo.ts
|
|
562
643
|
│ │ │ ├── view_file_outline.ts
|
|
563
644
|
│ │ │ └── web_fetch.ts
|
|
564
|
-
│ │
|
|
645
|
+
│ │ ├── types/
|
|
646
|
+
│ │ │ └── index.ts
|
|
647
|
+
│ │ └── utils/
|
|
648
|
+
│ │ ├── coordinator_prompt.ts # Coordinator mode playbook
|
|
649
|
+
│ │ ├── update_check.ts
|
|
650
|
+
│ │ └── user_message_images.ts
|
|
565
651
|
│ └── ui/
|
|
566
652
|
│ ├── App.tsx # Main UI component
|
|
567
|
-
│ ├──
|
|
653
|
+
│ ├── Asci/
|
|
654
|
+
│ │ └── AsciiArt.ts
|
|
655
|
+
│ ├── components/ # 24+ UI components
|
|
568
656
|
│ │ ├── AnimatedBorder.tsx
|
|
657
|
+
│ │ ├── AskUserQuestionPrompt.tsx
|
|
658
|
+
│ │ ├── AssistantMessageDisplay.tsx
|
|
569
659
|
│ │ ├── CollapsibleResult.tsx
|
|
570
660
|
│ │ ├── EditToolDiffPanel.tsx # Diff preview for edits
|
|
571
661
|
│ │ ├── ErrorMessage.tsx
|
|
@@ -576,20 +666,44 @@ src/
|
|
|
576
666
|
│ │ ├── ReasoningDisplay.tsx # LLM reasoning
|
|
577
667
|
│ │ ├── SessionStats.tsx
|
|
578
668
|
│ │ ├── SimpleDiff.tsx
|
|
579
|
-
│ │ ├── SlashCommands.tsx #
|
|
669
|
+
│ │ ├── SlashCommands.tsx # 30+ commands
|
|
580
670
|
│ │ ├── StatusNotification.tsx
|
|
581
671
|
│ │ ├── StreamingText.tsx # Live text output
|
|
582
672
|
│ │ ├── TodoPlanDisplay.tsx # Task visualization
|
|
583
673
|
│ │ ├── ToolCallDisplay.tsx
|
|
674
|
+
│ │ ├── ToolInvocationBlock.tsx
|
|
584
675
|
│ │ ├── ToolResultCard.tsx # Structured results
|
|
585
676
|
│ │ ├── ToolResultDisplay.tsx
|
|
586
677
|
│ │ ├── TypewriterText.tsx
|
|
587
678
|
│ │ ├── UpdateNotice.tsx
|
|
679
|
+
│ │ ├── streamingTextFlush.ts
|
|
588
680
|
│ │ └── toolCallRenderers.tsx
|
|
589
|
-
│ ├──
|
|
590
|
-
│
|
|
681
|
+
│ ├── constants/
|
|
682
|
+
│ │ ├── historyLayout.ts
|
|
683
|
+
│ │ ├── inputPaste.ts
|
|
684
|
+
│ │ └── toolUiPreview.ts
|
|
685
|
+
│ ├── hooks/
|
|
686
|
+
│ │ └── useAtCompletion.ts
|
|
687
|
+
│ ├── theme/
|
|
688
|
+
│ │ ├── blumaTerminal.ts
|
|
689
|
+
│ │ └── m3Layout.tsx
|
|
690
|
+
│ └── utils/
|
|
691
|
+
│ ├── clipboardImage.ts
|
|
692
|
+
│ ├── editToolDiffUtils.ts
|
|
693
|
+
│ ├── expandPreviewHotkey.ts
|
|
694
|
+
│ ├── expandablePreviewStore.ts
|
|
695
|
+
│ ├── formatTurnDurationMs.ts
|
|
696
|
+
│ ├── inlineImageInputLabels.ts
|
|
697
|
+
│ ├── pathDisplay.ts
|
|
698
|
+
│ ├── shellToolNames.ts
|
|
699
|
+
│ ├── slashRegistry.ts
|
|
700
|
+
│ ├── terminalTitle.ts
|
|
701
|
+
│ ├── toolDisplayLabels.ts
|
|
702
|
+
│ ├── toolInvocationPairing.ts
|
|
703
|
+
│ └── useSimpleInputBuffer.ts
|
|
591
704
|
├── main.ts # Entry point
|
|
592
|
-
└── types/
|
|
705
|
+
└── types/
|
|
706
|
+
└── semver-functions.d.ts
|
|
593
707
|
```
|
|
594
708
|
|
|
595
709
|
---
|
|
@@ -682,6 +796,12 @@ BluMa's runtime layer provides enterprise-grade orchestration:
|
|
|
682
796
|
| `session_view.ts` | Session monitoring | Log streaming, status display |
|
|
683
797
|
| `native_tool_catalog.ts` | Tool registry | Discovery and metadata |
|
|
684
798
|
| `runtime_config.ts` | Settings | Runtime configuration management |
|
|
799
|
+
| `feature_flags.ts` | Feature gates | Opt-in features via env or settings |
|
|
800
|
+
| `plan_mode_session.ts` | Plan mode | Forces confirmation for edits/writes |
|
|
801
|
+
| `tool_auto_approve.ts` | Auto-approve | Effective approve rules |
|
|
802
|
+
| `tool_orchestration.ts` | Parallel reads | Eligibility for parallel execution |
|
|
803
|
+
| `tool_permission_classifier` | Tool classification | Classify tool invocations |
|
|
804
|
+
| `plugin_runtime.ts` | Plugin execution | Plugin runtime context |
|
|
685
805
|
|
|
686
806
|
### UI Components
|
|
687
807
|
|
|
@@ -699,6 +819,9 @@ Key UI components that power the rich terminal experience:
|
|
|
699
819
|
| `AnimatedBorder.tsx` | Visual feedback for active elements |
|
|
700
820
|
| `CollapsibleResult.tsx` | Expandable result sections |
|
|
701
821
|
| `ProgressBar.tsx` | Progress indicators |
|
|
822
|
+
| `AskUserQuestionPrompt.tsx` | Multiple-choice question UI |
|
|
823
|
+
| `ToolInvocationBlock.tsx` | Tool call visualization |
|
|
824
|
+
| `AssistantMessageDisplay.tsx` | Assistant message formatting |
|
|
702
825
|
|
|
703
826
|
---
|
|
704
827
|
|
package/dist/main.js
CHANGED
|
@@ -10234,9 +10234,9 @@ var BluMaAgent = class {
|
|
|
10234
10234
|
this.mcpClient = mcpClient;
|
|
10235
10235
|
this.feedbackSystem = feedbackSystem;
|
|
10236
10236
|
this.skillLoader = new SkillLoader(process.cwd());
|
|
10237
|
-
this.eventBus.on("user_interrupt", () => {
|
|
10237
|
+
this.eventBus.on("user_interrupt", async () => {
|
|
10238
10238
|
this.isInterrupted = true;
|
|
10239
|
-
|
|
10239
|
+
await this.notifyFactorTurnEndIfNeeded("user_interrupt");
|
|
10240
10240
|
this.eventBus.emit("backend_message", { type: "done", status: "interrupted" });
|
|
10241
10241
|
});
|
|
10242
10242
|
this.eventBus.on("user_overlay", async (data) => {
|
|
@@ -10781,6 +10781,10 @@ ${editData.error.display}`;
|
|
|
10781
10781
|
reason
|
|
10782
10782
|
});
|
|
10783
10783
|
}
|
|
10784
|
+
/** Fecho explícito de turno (útil para workers antes de process.exit). */
|
|
10785
|
+
async closeActiveTurn(reason = "worker_exit") {
|
|
10786
|
+
await this.notifyFactorTurnEndIfNeeded(reason);
|
|
10787
|
+
}
|
|
10784
10788
|
async _continueConversation() {
|
|
10785
10789
|
try {
|
|
10786
10790
|
if (this.isInterrupted) {
|
|
@@ -10806,7 +10810,7 @@ ${editData.error.display}`;
|
|
|
10806
10810
|
} catch (error) {
|
|
10807
10811
|
const errorMessage = error instanceof Error ? error.message : "An unknown API error occurred.";
|
|
10808
10812
|
this.eventBus.emit("backend_message", { type: "error", message: errorMessage });
|
|
10809
|
-
|
|
10813
|
+
await this.notifyFactorTurnEndIfNeeded("llm_error");
|
|
10810
10814
|
this.eventBus.emit("backend_message", { type: "done", status: "failed" });
|
|
10811
10815
|
} finally {
|
|
10812
10816
|
this.persistSession();
|
|
@@ -11720,6 +11724,10 @@ var Agent = class {
|
|
|
11720
11724
|
}
|
|
11721
11725
|
await this.routeManager.handleRoute({ content: inputText, userContext: resolvedUserContext });
|
|
11722
11726
|
}
|
|
11727
|
+
/** Fecha o turno ativo no FactorRouter (idempotente). */
|
|
11728
|
+
async closeActiveTurn(reason = "worker_exit") {
|
|
11729
|
+
await this.core.closeActiveTurn(reason);
|
|
11730
|
+
}
|
|
11723
11731
|
/**
|
|
11724
11732
|
* Handler para o comando /coordinator
|
|
11725
11733
|
* /coordinator enable - Ativa o Coordinator Mode
|
|
@@ -14606,6 +14614,14 @@ var AskUserQuestionPrompt = memo14(AskUserQuestionPromptComponent);
|
|
|
14606
14614
|
import { jsx as jsx24, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
14607
14615
|
var MAX_STATIC_HISTORY_ITEMS = 220;
|
|
14608
14616
|
var blumaUpdateRegistryCheckStarted = false;
|
|
14617
|
+
function nextHistoryId(items) {
|
|
14618
|
+
if (items.length === 0) return HEADER_PANEL_HISTORY_ID + 1;
|
|
14619
|
+
let maxId = HEADER_PANEL_HISTORY_ID;
|
|
14620
|
+
for (const it of items) {
|
|
14621
|
+
if (typeof it.id === "number" && it.id > maxId) maxId = it.id;
|
|
14622
|
+
}
|
|
14623
|
+
return maxId + 1;
|
|
14624
|
+
}
|
|
14609
14625
|
function trimRecentActivity(s, max = 72) {
|
|
14610
14626
|
const t = String(s ?? "").replace(/\s+/g, " ").trim();
|
|
14611
14627
|
if (!t) return "";
|
|
@@ -14739,13 +14755,16 @@ var AppComponent = ({ eventBus, sessionId, cliVersion }) => {
|
|
|
14739
14755
|
turnStartedAtRef.current = null;
|
|
14740
14756
|
setProcessingStartMs(null);
|
|
14741
14757
|
setIsProcessing(false);
|
|
14742
|
-
setHistory((prev) =>
|
|
14743
|
-
|
|
14744
|
-
|
|
14745
|
-
|
|
14746
|
-
|
|
14747
|
-
|
|
14748
|
-
|
|
14758
|
+
setHistory((prev) => {
|
|
14759
|
+
const id = nextHistoryId(prev);
|
|
14760
|
+
return [
|
|
14761
|
+
...prev,
|
|
14762
|
+
{
|
|
14763
|
+
id,
|
|
14764
|
+
component: /* @__PURE__ */ jsx24(ChatMeta, { children: "cancelled (Esc)" })
|
|
14765
|
+
}
|
|
14766
|
+
];
|
|
14767
|
+
});
|
|
14749
14768
|
}, [isProcessing, eventBus]);
|
|
14750
14769
|
const handleSubmit = useCallback3(
|
|
14751
14770
|
(text) => {
|
|
@@ -14753,13 +14772,16 @@ var AppComponent = ({ eventBus, sessionId, cliVersion }) => {
|
|
|
14753
14772
|
const trimmedForSlash = text.trim();
|
|
14754
14773
|
if (isProcessing && !isSlashRoutingLine(trimmedForSlash)) {
|
|
14755
14774
|
if (trimmedForSlash.startsWith("/")) {
|
|
14756
|
-
setHistory((prev) =>
|
|
14757
|
-
|
|
14758
|
-
|
|
14759
|
-
|
|
14760
|
-
|
|
14761
|
-
|
|
14762
|
-
|
|
14775
|
+
setHistory((prev) => {
|
|
14776
|
+
const id = nextHistoryId(prev);
|
|
14777
|
+
return [
|
|
14778
|
+
...prev,
|
|
14779
|
+
{
|
|
14780
|
+
id,
|
|
14781
|
+
component: /* @__PURE__ */ jsx24(ChatMeta, { children: "Slash command not recognized or incomplete. Type /help for the list." })
|
|
14782
|
+
}
|
|
14783
|
+
];
|
|
14784
|
+
});
|
|
14763
14785
|
}
|
|
14764
14786
|
return;
|
|
14765
14787
|
}
|
|
@@ -14768,13 +14790,16 @@ var AppComponent = ({ eventBus, sessionId, cliVersion }) => {
|
|
|
14768
14790
|
if (/^\/img\s+/i.test(text) || /^\/image\s+/i.test(text)) {
|
|
14769
14791
|
const payload = text.replace(/^\/img\s+/i, "").replace(/^\/image\s+/i, "").trim();
|
|
14770
14792
|
if (!payload) {
|
|
14771
|
-
setHistory((prev) =>
|
|
14772
|
-
|
|
14773
|
-
|
|
14774
|
-
|
|
14775
|
-
|
|
14776
|
-
|
|
14777
|
-
|
|
14793
|
+
setHistory((prev) => {
|
|
14794
|
+
const id = nextHistoryId(prev);
|
|
14795
|
+
return [
|
|
14796
|
+
...prev,
|
|
14797
|
+
{
|
|
14798
|
+
id,
|
|
14799
|
+
component: /* @__PURE__ */ jsx24(ChatMeta, { children: "Usage: /img ./screenshot.png \u2014 optional text after the path is sent too" })
|
|
14800
|
+
}
|
|
14801
|
+
];
|
|
14802
|
+
});
|
|
14778
14803
|
return;
|
|
14779
14804
|
}
|
|
14780
14805
|
setIsProcessing(true);
|
|
@@ -14784,13 +14809,16 @@ var AppComponent = ({ eventBus, sessionId, cliVersion }) => {
|
|
|
14784
14809
|
sessionId,
|
|
14785
14810
|
summary: trimRecentActivity(payload, 120)
|
|
14786
14811
|
});
|
|
14787
|
-
setHistory((prev) =>
|
|
14788
|
-
|
|
14789
|
-
|
|
14790
|
-
|
|
14791
|
-
|
|
14792
|
-
|
|
14793
|
-
|
|
14812
|
+
setHistory((prev) => {
|
|
14813
|
+
const id = nextHistoryId(prev);
|
|
14814
|
+
return [
|
|
14815
|
+
...prev,
|
|
14816
|
+
{
|
|
14817
|
+
id,
|
|
14818
|
+
component: /* @__PURE__ */ jsx24(UserMessageWithOptionalImages, { raw: payload, variant: "slash-img" })
|
|
14819
|
+
}
|
|
14820
|
+
];
|
|
14821
|
+
});
|
|
14794
14822
|
agentInstance.current.processTurn({ content: payload });
|
|
14795
14823
|
return;
|
|
14796
14824
|
}
|
|
@@ -14813,24 +14841,28 @@ var AppComponent = ({ eventBus, sessionId, cliVersion }) => {
|
|
|
14813
14841
|
setIsProcessing(false);
|
|
14814
14842
|
setIsInitAgentActive(false);
|
|
14815
14843
|
}
|
|
14816
|
-
setHistory((prev) =>
|
|
14817
|
-
|
|
14818
|
-
|
|
14819
|
-
|
|
14820
|
-
|
|
14821
|
-
|
|
14822
|
-
|
|
14823
|
-
|
|
14824
|
-
|
|
14825
|
-
|
|
14826
|
-
|
|
14827
|
-
|
|
14828
|
-
|
|
14829
|
-
|
|
14830
|
-
|
|
14831
|
-
|
|
14832
|
-
|
|
14833
|
-
|
|
14844
|
+
setHistory((prev) => {
|
|
14845
|
+
const firstId = nextHistoryId(prev);
|
|
14846
|
+
const secondId = firstId + 1;
|
|
14847
|
+
return [
|
|
14848
|
+
...prev,
|
|
14849
|
+
{
|
|
14850
|
+
id: firstId,
|
|
14851
|
+
component: /* @__PURE__ */ jsx24(ChatUserMessage, { children: /* @__PURE__ */ jsx24(Text22, { color: BLUMA_TERMINAL.m3OnSurface, bold: true, wrap: "wrap", children: text }) })
|
|
14852
|
+
},
|
|
14853
|
+
{
|
|
14854
|
+
id: secondId,
|
|
14855
|
+
component: /* @__PURE__ */ jsx24(
|
|
14856
|
+
SlashCommands_default,
|
|
14857
|
+
{
|
|
14858
|
+
input: text,
|
|
14859
|
+
setHistory,
|
|
14860
|
+
agentRef: agentInstance
|
|
14861
|
+
}
|
|
14862
|
+
)
|
|
14863
|
+
}
|
|
14864
|
+
];
|
|
14865
|
+
});
|
|
14834
14866
|
return;
|
|
14835
14867
|
}
|
|
14836
14868
|
if (text.startsWith("!")) {
|
|
@@ -14846,16 +14878,19 @@ var AppComponent = ({ eventBus, sessionId, cliVersion }) => {
|
|
|
14846
14878
|
sessionId,
|
|
14847
14879
|
summary: trimRecentActivity(command, 120)
|
|
14848
14880
|
});
|
|
14849
|
-
setHistory((prev) =>
|
|
14850
|
-
|
|
14851
|
-
|
|
14852
|
-
|
|
14853
|
-
|
|
14854
|
-
|
|
14855
|
-
|
|
14856
|
-
|
|
14857
|
-
|
|
14858
|
-
|
|
14881
|
+
setHistory((prev) => {
|
|
14882
|
+
const id = nextHistoryId(prev);
|
|
14883
|
+
return [
|
|
14884
|
+
...prev,
|
|
14885
|
+
{
|
|
14886
|
+
id,
|
|
14887
|
+
component: /* @__PURE__ */ jsx24(ChatUserMessage, { children: /* @__PURE__ */ jsxs22(Text22, { bold: true, color: "white", children: [
|
|
14888
|
+
"$ !",
|
|
14889
|
+
command
|
|
14890
|
+
] }) })
|
|
14891
|
+
}
|
|
14892
|
+
];
|
|
14893
|
+
});
|
|
14859
14894
|
Promise.resolve().then(() => (init_async_command(), async_command_exports)).then(async ({ runCommandAsync: runCommandAsync2 }) => {
|
|
14860
14895
|
try {
|
|
14861
14896
|
const result = await runCommandAsync2({ command, cwd: workdir });
|
|
@@ -14869,31 +14904,37 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
14869
14904
|
} else {
|
|
14870
14905
|
turnStartedAtRef.current = null;
|
|
14871
14906
|
setProcessingStartMs(null);
|
|
14872
|
-
setHistory((prev) =>
|
|
14873
|
-
|
|
14874
|
-
|
|
14875
|
-
|
|
14876
|
-
|
|
14877
|
-
|
|
14878
|
-
|
|
14879
|
-
|
|
14880
|
-
|
|
14881
|
-
|
|
14907
|
+
setHistory((prev) => {
|
|
14908
|
+
const id = nextHistoryId(prev);
|
|
14909
|
+
return [
|
|
14910
|
+
...prev,
|
|
14911
|
+
{
|
|
14912
|
+
id,
|
|
14913
|
+
component: /* @__PURE__ */ jsxs22(Text22, { color: "red", children: [
|
|
14914
|
+
"Failed to execute: ",
|
|
14915
|
+
result.error || result.message
|
|
14916
|
+
] })
|
|
14917
|
+
}
|
|
14918
|
+
];
|
|
14919
|
+
});
|
|
14882
14920
|
setIsProcessing(false);
|
|
14883
14921
|
}
|
|
14884
14922
|
} catch (err) {
|
|
14885
14923
|
turnStartedAtRef.current = null;
|
|
14886
14924
|
setProcessingStartMs(null);
|
|
14887
|
-
setHistory((prev) =>
|
|
14888
|
-
|
|
14889
|
-
|
|
14890
|
-
|
|
14891
|
-
|
|
14892
|
-
|
|
14893
|
-
|
|
14894
|
-
|
|
14895
|
-
|
|
14896
|
-
|
|
14925
|
+
setHistory((prev) => {
|
|
14926
|
+
const id = nextHistoryId(prev);
|
|
14927
|
+
return [
|
|
14928
|
+
...prev,
|
|
14929
|
+
{
|
|
14930
|
+
id,
|
|
14931
|
+
component: /* @__PURE__ */ jsxs22(Text22, { color: "red", children: [
|
|
14932
|
+
"Error: ",
|
|
14933
|
+
err.message
|
|
14934
|
+
] })
|
|
14935
|
+
}
|
|
14936
|
+
];
|
|
14937
|
+
});
|
|
14897
14938
|
setIsProcessing(false);
|
|
14898
14939
|
}
|
|
14899
14940
|
});
|
|
@@ -14901,13 +14942,16 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
14901
14942
|
}
|
|
14902
14943
|
setIsProcessing(true);
|
|
14903
14944
|
markTurnStarted();
|
|
14904
|
-
setHistory((prev) =>
|
|
14905
|
-
|
|
14906
|
-
|
|
14907
|
-
|
|
14908
|
-
|
|
14909
|
-
|
|
14910
|
-
|
|
14945
|
+
setHistory((prev) => {
|
|
14946
|
+
const id = nextHistoryId(prev);
|
|
14947
|
+
return [
|
|
14948
|
+
...prev,
|
|
14949
|
+
{
|
|
14950
|
+
id,
|
|
14951
|
+
component: /* @__PURE__ */ jsx24(UserMessageWithOptionalImages, { raw: text, variant: "plain" })
|
|
14952
|
+
}
|
|
14953
|
+
];
|
|
14954
|
+
});
|
|
14911
14955
|
agentInstance.current.processTurn({ content: text });
|
|
14912
14956
|
},
|
|
14913
14957
|
[isProcessing, markTurnStarted]
|
|
@@ -14939,26 +14983,32 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
14939
14983
|
const key = reasoningDedupeKey(r);
|
|
14940
14984
|
if (!r || key === lastReasoningTextRef.current) return;
|
|
14941
14985
|
lastReasoningTextRef.current = key;
|
|
14942
|
-
setHistory((prev) =>
|
|
14943
|
-
|
|
14944
|
-
|
|
14945
|
-
|
|
14946
|
-
|
|
14947
|
-
|
|
14948
|
-
|
|
14986
|
+
setHistory((prev) => {
|
|
14987
|
+
const id = nextHistoryId(prev);
|
|
14988
|
+
return [
|
|
14989
|
+
...prev,
|
|
14990
|
+
{
|
|
14991
|
+
id,
|
|
14992
|
+
component: /* @__PURE__ */ jsx24(ReasoningDisplay, { reasoning })
|
|
14993
|
+
}
|
|
14994
|
+
];
|
|
14995
|
+
});
|
|
14949
14996
|
}, []);
|
|
14950
14997
|
const appendStreamedAssistant = useCallback3((content) => {
|
|
14951
14998
|
const t = String(content ?? "").trim();
|
|
14952
14999
|
if (!t) return;
|
|
14953
15000
|
const key = reasoningDedupeKey(t);
|
|
14954
15001
|
lastStreamAssistantKeyRef.current = key;
|
|
14955
|
-
setHistory((prev) =>
|
|
14956
|
-
|
|
14957
|
-
|
|
14958
|
-
|
|
14959
|
-
|
|
14960
|
-
|
|
14961
|
-
|
|
15002
|
+
setHistory((prev) => {
|
|
15003
|
+
const id = nextHistoryId(prev);
|
|
15004
|
+
return [
|
|
15005
|
+
...prev,
|
|
15006
|
+
{
|
|
15007
|
+
id,
|
|
15008
|
+
component: /* @__PURE__ */ jsx24(AssistantMessageDisplay, { content })
|
|
15009
|
+
}
|
|
15010
|
+
];
|
|
15011
|
+
});
|
|
14962
15012
|
}, []);
|
|
14963
15013
|
const cappedHistory = useMemo2(() => {
|
|
14964
15014
|
if (history.length <= MAX_STATIC_HISTORY_ITEMS) return history;
|
|
@@ -14998,13 +15048,16 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
14998
15048
|
turnStartedAtRef.current = null;
|
|
14999
15049
|
setProcessingStartMs(null);
|
|
15000
15050
|
const ms = Date.now() - t;
|
|
15001
|
-
setHistory((prev) =>
|
|
15002
|
-
|
|
15003
|
-
|
|
15004
|
-
|
|
15005
|
-
|
|
15006
|
-
|
|
15007
|
-
|
|
15051
|
+
setHistory((prev) => {
|
|
15052
|
+
const id = nextHistoryId(prev);
|
|
15053
|
+
return [
|
|
15054
|
+
...prev,
|
|
15055
|
+
{
|
|
15056
|
+
id,
|
|
15057
|
+
component: /* @__PURE__ */ jsx24(ChatTurnDuration, { durationMs: ms })
|
|
15058
|
+
}
|
|
15059
|
+
];
|
|
15060
|
+
});
|
|
15008
15061
|
};
|
|
15009
15062
|
if (parsed.type === "done" || parsed.type === "error") {
|
|
15010
15063
|
setIsInitAgentActive(false);
|
|
@@ -15178,9 +15231,10 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
15178
15231
|
}
|
|
15179
15232
|
if (newComponent) {
|
|
15180
15233
|
setHistory((prev) => {
|
|
15234
|
+
const id = nextHistoryId(prev);
|
|
15181
15235
|
const next = [
|
|
15182
15236
|
...prev,
|
|
15183
|
-
{ id
|
|
15237
|
+
{ id, component: newComponent }
|
|
15184
15238
|
];
|
|
15185
15239
|
if (parsed.type === "error") {
|
|
15186
15240
|
const t = turnStartedAtRef.current;
|
|
@@ -15189,7 +15243,7 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
15189
15243
|
setProcessingStartMs(null);
|
|
15190
15244
|
const ms = Date.now() - t;
|
|
15191
15245
|
next.push({
|
|
15192
|
-
id: next
|
|
15246
|
+
id: nextHistoryId(next),
|
|
15193
15247
|
component: /* @__PURE__ */ jsx24(ChatTurnDuration, { durationMs: ms })
|
|
15194
15248
|
});
|
|
15195
15249
|
}
|
|
@@ -15206,10 +15260,10 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
15206
15260
|
const handleInputNotice = (data) => {
|
|
15207
15261
|
const msg = String(data.message || "").trim();
|
|
15208
15262
|
if (!msg) return;
|
|
15209
|
-
setHistory((prev) =>
|
|
15210
|
-
|
|
15211
|
-
{ id
|
|
15212
|
-
|
|
15263
|
+
setHistory((prev) => {
|
|
15264
|
+
const id = nextHistoryId(prev);
|
|
15265
|
+
return [...prev, { id, component: /* @__PURE__ */ jsx24(ChatMeta, { children: msg }) }];
|
|
15266
|
+
});
|
|
15213
15267
|
};
|
|
15214
15268
|
uiEventBus.on("user_overlay", handleUiOverlay);
|
|
15215
15269
|
uiEventBus.on("input_notice", handleInputNotice);
|
|
@@ -15491,7 +15545,8 @@ async function runAgentMode() {
|
|
|
15491
15545
|
let reasoningBuffer = null;
|
|
15492
15546
|
let lastAttachments = null;
|
|
15493
15547
|
let resultEmitted = false;
|
|
15494
|
-
|
|
15548
|
+
let agentRef = null;
|
|
15549
|
+
eventBus.on("backend_message", async (payload) => {
|
|
15495
15550
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
15496
15551
|
writeAgentEvent(sessionId, {
|
|
15497
15552
|
event_type: "backend_message",
|
|
@@ -15524,6 +15579,9 @@ async function runAgentMode() {
|
|
|
15524
15579
|
}
|
|
15525
15580
|
if (!resultEmitted && payload?.type === "done") {
|
|
15526
15581
|
resultEmitted = true;
|
|
15582
|
+
if (agentRef) {
|
|
15583
|
+
await agentRef.closeActiveTurn("worker_done_exit");
|
|
15584
|
+
}
|
|
15527
15585
|
finalizeSession(sessionId, "completed", { finishedBy: "done-event" });
|
|
15528
15586
|
writeAgentEvent(sessionId, {
|
|
15529
15587
|
event_type: "result",
|
|
@@ -15564,6 +15622,7 @@ async function runAgentMode() {
|
|
|
15564
15622
|
});
|
|
15565
15623
|
try {
|
|
15566
15624
|
const agent = new Agent(sessionId, eventBus);
|
|
15625
|
+
agentRef = agent;
|
|
15567
15626
|
await agent.initialize();
|
|
15568
15627
|
const userContent = JSON.stringify({
|
|
15569
15628
|
message_id: envelope.message_id || sessionId,
|
|
@@ -15575,6 +15634,7 @@ async function runAgentMode() {
|
|
|
15575
15634
|
await agent.processTurn({ content: userContent }, userContextInput);
|
|
15576
15635
|
if (!resultEmitted) {
|
|
15577
15636
|
resultEmitted = true;
|
|
15637
|
+
await agent.closeActiveTurn("worker_post_turn_fallback");
|
|
15578
15638
|
finalizeSession(sessionId, "completed", { finishedBy: "post-turn-fallback" });
|
|
15579
15639
|
writeAgentEvent(sessionId, {
|
|
15580
15640
|
event_type: "result",
|
|
@@ -15592,6 +15652,9 @@ async function runAgentMode() {
|
|
|
15592
15652
|
}
|
|
15593
15653
|
} catch (err) {
|
|
15594
15654
|
if (!resultEmitted) {
|
|
15655
|
+
if (agentRef) {
|
|
15656
|
+
await agentRef.closeActiveTurn("worker_exception");
|
|
15657
|
+
}
|
|
15595
15658
|
finalizeSession(sessionId, "error", { finishedBy: "exception" });
|
|
15596
15659
|
writeAgentEvent(sessionId, {
|
|
15597
15660
|
event_type: "result",
|