@nomad-e/bluma-cli 0.1.48 → 0.1.50
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 +189 -115
- 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
|
|
@@ -14604,8 +14612,17 @@ var AskUserQuestionPrompt = memo14(AskUserQuestionPromptComponent);
|
|
|
14604
14612
|
|
|
14605
14613
|
// src/app/ui/App.tsx
|
|
14606
14614
|
import { jsx as jsx24, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
14607
|
-
var MAX_STATIC_HISTORY_ITEMS =
|
|
14615
|
+
var MAX_STATIC_HISTORY_ITEMS = 100;
|
|
14616
|
+
var HISTORY_CLEANUP_THRESHOLD = 120;
|
|
14608
14617
|
var blumaUpdateRegistryCheckStarted = false;
|
|
14618
|
+
function nextHistoryId(items) {
|
|
14619
|
+
if (items.length === 0) return HEADER_PANEL_HISTORY_ID + 1;
|
|
14620
|
+
let maxId = HEADER_PANEL_HISTORY_ID;
|
|
14621
|
+
for (const it of items) {
|
|
14622
|
+
if (typeof it.id === "number" && it.id > maxId) maxId = it.id;
|
|
14623
|
+
}
|
|
14624
|
+
return maxId + 1;
|
|
14625
|
+
}
|
|
14609
14626
|
function trimRecentActivity(s, max = 72) {
|
|
14610
14627
|
const t = String(s ?? "").replace(/\s+/g, " ").trim();
|
|
14611
14628
|
if (!t) return "";
|
|
@@ -14739,13 +14756,16 @@ var AppComponent = ({ eventBus, sessionId, cliVersion }) => {
|
|
|
14739
14756
|
turnStartedAtRef.current = null;
|
|
14740
14757
|
setProcessingStartMs(null);
|
|
14741
14758
|
setIsProcessing(false);
|
|
14742
|
-
setHistory((prev) =>
|
|
14743
|
-
|
|
14744
|
-
|
|
14745
|
-
|
|
14746
|
-
|
|
14747
|
-
|
|
14748
|
-
|
|
14759
|
+
setHistory((prev) => {
|
|
14760
|
+
const id = nextHistoryId(prev);
|
|
14761
|
+
return [
|
|
14762
|
+
...prev,
|
|
14763
|
+
{
|
|
14764
|
+
id,
|
|
14765
|
+
component: /* @__PURE__ */ jsx24(ChatMeta, { children: "cancelled (Esc)" })
|
|
14766
|
+
}
|
|
14767
|
+
];
|
|
14768
|
+
});
|
|
14749
14769
|
}, [isProcessing, eventBus]);
|
|
14750
14770
|
const handleSubmit = useCallback3(
|
|
14751
14771
|
(text) => {
|
|
@@ -14753,13 +14773,16 @@ var AppComponent = ({ eventBus, sessionId, cliVersion }) => {
|
|
|
14753
14773
|
const trimmedForSlash = text.trim();
|
|
14754
14774
|
if (isProcessing && !isSlashRoutingLine(trimmedForSlash)) {
|
|
14755
14775
|
if (trimmedForSlash.startsWith("/")) {
|
|
14756
|
-
setHistory((prev) =>
|
|
14757
|
-
|
|
14758
|
-
|
|
14759
|
-
|
|
14760
|
-
|
|
14761
|
-
|
|
14762
|
-
|
|
14776
|
+
setHistory((prev) => {
|
|
14777
|
+
const id = nextHistoryId(prev);
|
|
14778
|
+
return [
|
|
14779
|
+
...prev,
|
|
14780
|
+
{
|
|
14781
|
+
id,
|
|
14782
|
+
component: /* @__PURE__ */ jsx24(ChatMeta, { children: "Slash command not recognized or incomplete. Type /help for the list." })
|
|
14783
|
+
}
|
|
14784
|
+
];
|
|
14785
|
+
});
|
|
14763
14786
|
}
|
|
14764
14787
|
return;
|
|
14765
14788
|
}
|
|
@@ -14768,13 +14791,16 @@ var AppComponent = ({ eventBus, sessionId, cliVersion }) => {
|
|
|
14768
14791
|
if (/^\/img\s+/i.test(text) || /^\/image\s+/i.test(text)) {
|
|
14769
14792
|
const payload = text.replace(/^\/img\s+/i, "").replace(/^\/image\s+/i, "").trim();
|
|
14770
14793
|
if (!payload) {
|
|
14771
|
-
setHistory((prev) =>
|
|
14772
|
-
|
|
14773
|
-
|
|
14774
|
-
|
|
14775
|
-
|
|
14776
|
-
|
|
14777
|
-
|
|
14794
|
+
setHistory((prev) => {
|
|
14795
|
+
const id = nextHistoryId(prev);
|
|
14796
|
+
return [
|
|
14797
|
+
...prev,
|
|
14798
|
+
{
|
|
14799
|
+
id,
|
|
14800
|
+
component: /* @__PURE__ */ jsx24(ChatMeta, { children: "Usage: /img ./screenshot.png \u2014 optional text after the path is sent too" })
|
|
14801
|
+
}
|
|
14802
|
+
];
|
|
14803
|
+
});
|
|
14778
14804
|
return;
|
|
14779
14805
|
}
|
|
14780
14806
|
setIsProcessing(true);
|
|
@@ -14784,13 +14810,16 @@ var AppComponent = ({ eventBus, sessionId, cliVersion }) => {
|
|
|
14784
14810
|
sessionId,
|
|
14785
14811
|
summary: trimRecentActivity(payload, 120)
|
|
14786
14812
|
});
|
|
14787
|
-
setHistory((prev) =>
|
|
14788
|
-
|
|
14789
|
-
|
|
14790
|
-
|
|
14791
|
-
|
|
14792
|
-
|
|
14793
|
-
|
|
14813
|
+
setHistory((prev) => {
|
|
14814
|
+
const id = nextHistoryId(prev);
|
|
14815
|
+
return [
|
|
14816
|
+
...prev,
|
|
14817
|
+
{
|
|
14818
|
+
id,
|
|
14819
|
+
component: /* @__PURE__ */ jsx24(UserMessageWithOptionalImages, { raw: payload, variant: "slash-img" })
|
|
14820
|
+
}
|
|
14821
|
+
];
|
|
14822
|
+
});
|
|
14794
14823
|
agentInstance.current.processTurn({ content: payload });
|
|
14795
14824
|
return;
|
|
14796
14825
|
}
|
|
@@ -14813,24 +14842,28 @@ var AppComponent = ({ eventBus, sessionId, cliVersion }) => {
|
|
|
14813
14842
|
setIsProcessing(false);
|
|
14814
14843
|
setIsInitAgentActive(false);
|
|
14815
14844
|
}
|
|
14816
|
-
setHistory((prev) =>
|
|
14817
|
-
|
|
14818
|
-
|
|
14819
|
-
|
|
14820
|
-
|
|
14821
|
-
|
|
14822
|
-
|
|
14823
|
-
|
|
14824
|
-
|
|
14825
|
-
|
|
14826
|
-
|
|
14827
|
-
|
|
14828
|
-
|
|
14829
|
-
|
|
14830
|
-
|
|
14831
|
-
|
|
14832
|
-
|
|
14833
|
-
|
|
14845
|
+
setHistory((prev) => {
|
|
14846
|
+
const firstId = nextHistoryId(prev);
|
|
14847
|
+
const secondId = firstId + 1;
|
|
14848
|
+
return [
|
|
14849
|
+
...prev,
|
|
14850
|
+
{
|
|
14851
|
+
id: firstId,
|
|
14852
|
+
component: /* @__PURE__ */ jsx24(ChatUserMessage, { children: /* @__PURE__ */ jsx24(Text22, { color: BLUMA_TERMINAL.m3OnSurface, bold: true, wrap: "wrap", children: text }) })
|
|
14853
|
+
},
|
|
14854
|
+
{
|
|
14855
|
+
id: secondId,
|
|
14856
|
+
component: /* @__PURE__ */ jsx24(
|
|
14857
|
+
SlashCommands_default,
|
|
14858
|
+
{
|
|
14859
|
+
input: text,
|
|
14860
|
+
setHistory,
|
|
14861
|
+
agentRef: agentInstance
|
|
14862
|
+
}
|
|
14863
|
+
)
|
|
14864
|
+
}
|
|
14865
|
+
];
|
|
14866
|
+
});
|
|
14834
14867
|
return;
|
|
14835
14868
|
}
|
|
14836
14869
|
if (text.startsWith("!")) {
|
|
@@ -14846,16 +14879,19 @@ var AppComponent = ({ eventBus, sessionId, cliVersion }) => {
|
|
|
14846
14879
|
sessionId,
|
|
14847
14880
|
summary: trimRecentActivity(command, 120)
|
|
14848
14881
|
});
|
|
14849
|
-
setHistory((prev) =>
|
|
14850
|
-
|
|
14851
|
-
|
|
14852
|
-
|
|
14853
|
-
|
|
14854
|
-
|
|
14855
|
-
|
|
14856
|
-
|
|
14857
|
-
|
|
14858
|
-
|
|
14882
|
+
setHistory((prev) => {
|
|
14883
|
+
const id = nextHistoryId(prev);
|
|
14884
|
+
return [
|
|
14885
|
+
...prev,
|
|
14886
|
+
{
|
|
14887
|
+
id,
|
|
14888
|
+
component: /* @__PURE__ */ jsx24(ChatUserMessage, { children: /* @__PURE__ */ jsxs22(Text22, { bold: true, color: "white", children: [
|
|
14889
|
+
"$ !",
|
|
14890
|
+
command
|
|
14891
|
+
] }) })
|
|
14892
|
+
}
|
|
14893
|
+
];
|
|
14894
|
+
});
|
|
14859
14895
|
Promise.resolve().then(() => (init_async_command(), async_command_exports)).then(async ({ runCommandAsync: runCommandAsync2 }) => {
|
|
14860
14896
|
try {
|
|
14861
14897
|
const result = await runCommandAsync2({ command, cwd: workdir });
|
|
@@ -14869,31 +14905,37 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
14869
14905
|
} else {
|
|
14870
14906
|
turnStartedAtRef.current = null;
|
|
14871
14907
|
setProcessingStartMs(null);
|
|
14872
|
-
setHistory((prev) =>
|
|
14873
|
-
|
|
14874
|
-
|
|
14875
|
-
|
|
14876
|
-
|
|
14877
|
-
|
|
14878
|
-
|
|
14879
|
-
|
|
14880
|
-
|
|
14881
|
-
|
|
14908
|
+
setHistory((prev) => {
|
|
14909
|
+
const id = nextHistoryId(prev);
|
|
14910
|
+
return [
|
|
14911
|
+
...prev,
|
|
14912
|
+
{
|
|
14913
|
+
id,
|
|
14914
|
+
component: /* @__PURE__ */ jsxs22(Text22, { color: "red", children: [
|
|
14915
|
+
"Failed to execute: ",
|
|
14916
|
+
result.error || result.message
|
|
14917
|
+
] })
|
|
14918
|
+
}
|
|
14919
|
+
];
|
|
14920
|
+
});
|
|
14882
14921
|
setIsProcessing(false);
|
|
14883
14922
|
}
|
|
14884
14923
|
} catch (err) {
|
|
14885
14924
|
turnStartedAtRef.current = null;
|
|
14886
14925
|
setProcessingStartMs(null);
|
|
14887
|
-
setHistory((prev) =>
|
|
14888
|
-
|
|
14889
|
-
|
|
14890
|
-
|
|
14891
|
-
|
|
14892
|
-
|
|
14893
|
-
|
|
14894
|
-
|
|
14895
|
-
|
|
14896
|
-
|
|
14926
|
+
setHistory((prev) => {
|
|
14927
|
+
const id = nextHistoryId(prev);
|
|
14928
|
+
return [
|
|
14929
|
+
...prev,
|
|
14930
|
+
{
|
|
14931
|
+
id,
|
|
14932
|
+
component: /* @__PURE__ */ jsxs22(Text22, { color: "red", children: [
|
|
14933
|
+
"Error: ",
|
|
14934
|
+
err.message
|
|
14935
|
+
] })
|
|
14936
|
+
}
|
|
14937
|
+
];
|
|
14938
|
+
});
|
|
14897
14939
|
setIsProcessing(false);
|
|
14898
14940
|
}
|
|
14899
14941
|
});
|
|
@@ -14901,13 +14943,16 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
14901
14943
|
}
|
|
14902
14944
|
setIsProcessing(true);
|
|
14903
14945
|
markTurnStarted();
|
|
14904
|
-
setHistory((prev) =>
|
|
14905
|
-
|
|
14906
|
-
|
|
14907
|
-
|
|
14908
|
-
|
|
14909
|
-
|
|
14910
|
-
|
|
14946
|
+
setHistory((prev) => {
|
|
14947
|
+
const id = nextHistoryId(prev);
|
|
14948
|
+
return [
|
|
14949
|
+
...prev,
|
|
14950
|
+
{
|
|
14951
|
+
id,
|
|
14952
|
+
component: /* @__PURE__ */ jsx24(UserMessageWithOptionalImages, { raw: text, variant: "plain" })
|
|
14953
|
+
}
|
|
14954
|
+
];
|
|
14955
|
+
});
|
|
14911
14956
|
agentInstance.current.processTurn({ content: text });
|
|
14912
14957
|
},
|
|
14913
14958
|
[isProcessing, markTurnStarted]
|
|
@@ -14939,27 +14984,43 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
14939
14984
|
const key = reasoningDedupeKey(r);
|
|
14940
14985
|
if (!r || key === lastReasoningTextRef.current) return;
|
|
14941
14986
|
lastReasoningTextRef.current = key;
|
|
14942
|
-
setHistory((prev) =>
|
|
14943
|
-
|
|
14944
|
-
|
|
14945
|
-
|
|
14946
|
-
|
|
14947
|
-
|
|
14948
|
-
|
|
14987
|
+
setHistory((prev) => {
|
|
14988
|
+
const id = nextHistoryId(prev);
|
|
14989
|
+
return [
|
|
14990
|
+
...prev,
|
|
14991
|
+
{
|
|
14992
|
+
id,
|
|
14993
|
+
component: /* @__PURE__ */ jsx24(ReasoningDisplay, { reasoning })
|
|
14994
|
+
}
|
|
14995
|
+
];
|
|
14996
|
+
});
|
|
14949
14997
|
}, []);
|
|
14950
14998
|
const appendStreamedAssistant = useCallback3((content) => {
|
|
14951
14999
|
const t = String(content ?? "").trim();
|
|
14952
15000
|
if (!t) return;
|
|
14953
15001
|
const key = reasoningDedupeKey(t);
|
|
14954
15002
|
lastStreamAssistantKeyRef.current = key;
|
|
14955
|
-
setHistory((prev) =>
|
|
14956
|
-
|
|
14957
|
-
|
|
14958
|
-
|
|
14959
|
-
|
|
14960
|
-
|
|
14961
|
-
|
|
15003
|
+
setHistory((prev) => {
|
|
15004
|
+
const id = nextHistoryId(prev);
|
|
15005
|
+
return [
|
|
15006
|
+
...prev,
|
|
15007
|
+
{
|
|
15008
|
+
id,
|
|
15009
|
+
component: /* @__PURE__ */ jsx24(AssistantMessageDisplay, { content })
|
|
15010
|
+
}
|
|
15011
|
+
];
|
|
15012
|
+
});
|
|
14962
15013
|
}, []);
|
|
15014
|
+
useEffect8(() => {
|
|
15015
|
+
if (history.length >= HISTORY_CLEANUP_THRESHOLD) {
|
|
15016
|
+
setHistory((prev) => {
|
|
15017
|
+
const header = prev.find((h) => h.id === HEADER_PANEL_HISTORY_ID);
|
|
15018
|
+
const rest = prev.filter((h) => h.id !== HEADER_PANEL_HISTORY_ID);
|
|
15019
|
+
const tail = rest.slice(-(MAX_STATIC_HISTORY_ITEMS - 1));
|
|
15020
|
+
return header ? [header, ...tail] : tail;
|
|
15021
|
+
});
|
|
15022
|
+
}
|
|
15023
|
+
}, [history.length]);
|
|
14963
15024
|
const cappedHistory = useMemo2(() => {
|
|
14964
15025
|
if (history.length <= MAX_STATIC_HISTORY_ITEMS) return history;
|
|
14965
15026
|
const header = history.find((h) => h.id === HEADER_PANEL_HISTORY_ID);
|
|
@@ -14998,13 +15059,16 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
14998
15059
|
turnStartedAtRef.current = null;
|
|
14999
15060
|
setProcessingStartMs(null);
|
|
15000
15061
|
const ms = Date.now() - t;
|
|
15001
|
-
setHistory((prev) =>
|
|
15002
|
-
|
|
15003
|
-
|
|
15004
|
-
|
|
15005
|
-
|
|
15006
|
-
|
|
15007
|
-
|
|
15062
|
+
setHistory((prev) => {
|
|
15063
|
+
const id = nextHistoryId(prev);
|
|
15064
|
+
return [
|
|
15065
|
+
...prev,
|
|
15066
|
+
{
|
|
15067
|
+
id,
|
|
15068
|
+
component: /* @__PURE__ */ jsx24(ChatTurnDuration, { durationMs: ms })
|
|
15069
|
+
}
|
|
15070
|
+
];
|
|
15071
|
+
});
|
|
15008
15072
|
};
|
|
15009
15073
|
if (parsed.type === "done" || parsed.type === "error") {
|
|
15010
15074
|
setIsInitAgentActive(false);
|
|
@@ -15178,9 +15242,10 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
15178
15242
|
}
|
|
15179
15243
|
if (newComponent) {
|
|
15180
15244
|
setHistory((prev) => {
|
|
15245
|
+
const id = nextHistoryId(prev);
|
|
15181
15246
|
const next = [
|
|
15182
15247
|
...prev,
|
|
15183
|
-
{ id
|
|
15248
|
+
{ id, component: newComponent }
|
|
15184
15249
|
];
|
|
15185
15250
|
if (parsed.type === "error") {
|
|
15186
15251
|
const t = turnStartedAtRef.current;
|
|
@@ -15189,7 +15254,7 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
15189
15254
|
setProcessingStartMs(null);
|
|
15190
15255
|
const ms = Date.now() - t;
|
|
15191
15256
|
next.push({
|
|
15192
|
-
id: next
|
|
15257
|
+
id: nextHistoryId(next),
|
|
15193
15258
|
component: /* @__PURE__ */ jsx24(ChatTurnDuration, { durationMs: ms })
|
|
15194
15259
|
});
|
|
15195
15260
|
}
|
|
@@ -15206,10 +15271,10 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
15206
15271
|
const handleInputNotice = (data) => {
|
|
15207
15272
|
const msg = String(data.message || "").trim();
|
|
15208
15273
|
if (!msg) return;
|
|
15209
|
-
setHistory((prev) =>
|
|
15210
|
-
|
|
15211
|
-
{ id
|
|
15212
|
-
|
|
15274
|
+
setHistory((prev) => {
|
|
15275
|
+
const id = nextHistoryId(prev);
|
|
15276
|
+
return [...prev, { id, component: /* @__PURE__ */ jsx24(ChatMeta, { children: msg }) }];
|
|
15277
|
+
});
|
|
15213
15278
|
};
|
|
15214
15279
|
uiEventBus.on("user_overlay", handleUiOverlay);
|
|
15215
15280
|
uiEventBus.on("input_notice", handleInputNotice);
|
|
@@ -15491,7 +15556,8 @@ async function runAgentMode() {
|
|
|
15491
15556
|
let reasoningBuffer = null;
|
|
15492
15557
|
let lastAttachments = null;
|
|
15493
15558
|
let resultEmitted = false;
|
|
15494
|
-
|
|
15559
|
+
let agentRef = null;
|
|
15560
|
+
eventBus.on("backend_message", async (payload) => {
|
|
15495
15561
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
15496
15562
|
writeAgentEvent(sessionId, {
|
|
15497
15563
|
event_type: "backend_message",
|
|
@@ -15524,6 +15590,9 @@ async function runAgentMode() {
|
|
|
15524
15590
|
}
|
|
15525
15591
|
if (!resultEmitted && payload?.type === "done") {
|
|
15526
15592
|
resultEmitted = true;
|
|
15593
|
+
if (agentRef) {
|
|
15594
|
+
await agentRef.closeActiveTurn("worker_done_exit");
|
|
15595
|
+
}
|
|
15527
15596
|
finalizeSession(sessionId, "completed", { finishedBy: "done-event" });
|
|
15528
15597
|
writeAgentEvent(sessionId, {
|
|
15529
15598
|
event_type: "result",
|
|
@@ -15564,6 +15633,7 @@ async function runAgentMode() {
|
|
|
15564
15633
|
});
|
|
15565
15634
|
try {
|
|
15566
15635
|
const agent = new Agent(sessionId, eventBus);
|
|
15636
|
+
agentRef = agent;
|
|
15567
15637
|
await agent.initialize();
|
|
15568
15638
|
const userContent = JSON.stringify({
|
|
15569
15639
|
message_id: envelope.message_id || sessionId,
|
|
@@ -15575,6 +15645,7 @@ async function runAgentMode() {
|
|
|
15575
15645
|
await agent.processTurn({ content: userContent }, userContextInput);
|
|
15576
15646
|
if (!resultEmitted) {
|
|
15577
15647
|
resultEmitted = true;
|
|
15648
|
+
await agent.closeActiveTurn("worker_post_turn_fallback");
|
|
15578
15649
|
finalizeSession(sessionId, "completed", { finishedBy: "post-turn-fallback" });
|
|
15579
15650
|
writeAgentEvent(sessionId, {
|
|
15580
15651
|
event_type: "result",
|
|
@@ -15592,6 +15663,9 @@ async function runAgentMode() {
|
|
|
15592
15663
|
}
|
|
15593
15664
|
} catch (err) {
|
|
15594
15665
|
if (!resultEmitted) {
|
|
15666
|
+
if (agentRef) {
|
|
15667
|
+
await agentRef.closeActiveTurn("worker_exception");
|
|
15668
|
+
}
|
|
15595
15669
|
finalizeSession(sessionId, "error", { finishedBy: "exception" });
|
|
15596
15670
|
writeAgentEvent(sessionId, {
|
|
15597
15671
|
event_type: "result",
|