@nomad-e/bluma-cli 0.1.46 → 0.1.48

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,7 +4,9 @@
4
4
  [![License: Apache 2.0](https://img.shields.io/badge/license-Apache%202.0-blue.svg?style=flat-square)](LICENSE)
5
5
  [![Node.js >=20](https://img.shields.io/badge/node-%3E%3D20-brightgreen?style=flat-square)](https://nodejs.org/)
6
6
 
7
- **BluMa** is a CLI-based model agent for advanced software engineering workflows. Built with React/Ink 5, it provides an interactive terminal interface for LLM-powered automation, code generation, refactoring, and task execution. Features persistent sessions, contextual reasoning, smart feedback, and extensible tools/skills architecture.
7
+ **BluMa** is a CLI-based model agent for advanced software engineering workflows. Built with React/Ink 5, it provides an interactive terminal interface for LLM-powered automation, code generation, refactoring, and task execution. Features persistent sessions, contextual reasoning, smart feedback, coordinator mode for worker orchestration, and extensible tools/skills architecture.
8
+
9
+ **Current Version:** 0.1.47
8
10
 
9
11
  ---
10
12
 
@@ -60,7 +62,8 @@ The agent maintains persistent conversation history, workspace snapshots, and co
60
62
  - **Tool Execution Policy**: Intelligent decisions based on sandbox mode and safety
61
63
 
62
64
  ### Tools & Skills
63
- - **25+ Native Tools**: File operations, search, shell commands, web fetch, agent coordination
65
+ - **40+ Native Tools**: File operations, search, shell commands, web fetch, agent coordination, task management, MCP resources, cron scheduling, LSP queries, notebook editing
66
+ - **Coordinator Mode**: Orchestrator playbook for delegating work to background workers
64
67
  - **MCP Integration**: Model Context Protocol SDK for external tool servers
65
68
  - **Skills System**: Pluggable knowledge modules (git, PDF, Excel, etc.)
66
69
  - **Agent Coordination**: Spawn/wait/list subagents for parallel work
package/dist/main.js CHANGED
@@ -9526,7 +9526,6 @@ function buildFactorHeaders(ctx) {
9526
9526
  "X-Company-Name": encodeHeader(ctx.companyName)
9527
9527
  };
9528
9528
  }
9529
- var STREAM_TOOL_PARTIAL_THROTTLE_MS = 75;
9530
9529
  function applyDeltaToolCallsToAccumulator(toolCallsAccumulator, deltaToolCalls) {
9531
9530
  if (!deltaToolCalls?.length) {
9532
9531
  return false;
@@ -9547,28 +9546,6 @@ function applyDeltaToolCallsToAccumulator(toolCallsAccumulator, deltaToolCalls)
9547
9546
  }
9548
9547
  return true;
9549
9548
  }
9550
- function snapshotPartialToolCalls(toolCallsAccumulator) {
9551
- return Array.from(toolCallsAccumulator.entries()).sort((a, b) => a[0] - b[0]).map(([index, acc]) => ({
9552
- index,
9553
- id: acc.id,
9554
- type: acc.type,
9555
- function: {
9556
- name: acc.function.name,
9557
- arguments: acc.function.arguments
9558
- }
9559
- }));
9560
- }
9561
- function normalizedMessageToolCallsToPartial(toolCalls) {
9562
- return toolCalls.map((tc, i) => ({
9563
- index: typeof tc.index === "number" ? tc.index : i,
9564
- id: String(tc.id ?? ""),
9565
- type: String(tc.type ?? "function"),
9566
- function: {
9567
- name: String(tc.function?.name ?? ""),
9568
- arguments: typeof tc.function?.arguments === "string" ? tc.function.arguments : JSON.stringify(tc.function?.arguments ?? {})
9569
- }
9570
- }));
9571
- }
9572
9549
  function normalizeFactorBaseUrl(raw) {
9573
9550
  let u = raw.trim().replace(/\/$/, "");
9574
9551
  u = u.replace(/^http:\/\/http:\/\//i, "http://");
@@ -9669,24 +9646,17 @@ var LLMService = class {
9669
9646
  { headers: this.requestHeaders(params.userContext) }
9670
9647
  );
9671
9648
  const toolCallsAccumulator = /* @__PURE__ */ new Map();
9672
- let lastPartialEmitAt = 0;
9673
9649
  for await (const chunk of stream) {
9674
9650
  const choice = chunk.choices[0];
9675
9651
  if (!choice) continue;
9676
9652
  const delta = choice.delta;
9677
- const hadToolDelta = applyDeltaToolCallsToAccumulator(toolCallsAccumulator, delta?.tool_calls);
9653
+ applyDeltaToolCallsToAccumulator(toolCallsAccumulator, delta?.tool_calls);
9678
9654
  const reasoning = delta?.reasoning_content || delta?.reasoning || "";
9679
9655
  const fullToolCalls = choice.finish_reason === "tool_calls" ? Array.from(toolCallsAccumulator.values()) : void 0;
9680
- let tool_calls_partial;
9681
- if (hadToolDelta && toolCallsAccumulator.size > 0 && !fullToolCalls && Date.now() - lastPartialEmitAt >= STREAM_TOOL_PARTIAL_THROTTLE_MS) {
9682
- lastPartialEmitAt = Date.now();
9683
- tool_calls_partial = snapshotPartialToolCalls(toolCallsAccumulator);
9684
- }
9685
9656
  yield {
9686
9657
  delta: delta?.content || "",
9687
9658
  reasoning,
9688
9659
  tool_calls: fullToolCalls,
9689
- tool_calls_partial,
9690
9660
  finish_reason: choice.finish_reason
9691
9661
  };
9692
9662
  }
@@ -10505,9 +10475,8 @@ var BluMaAgent = class {
10505
10475
  }
10506
10476
  }
10507
10477
  }
10508
- const skipEditDiffRepeat = toolName === "edit_tool" && decisionData.editPreviewAlreadyShown === true;
10509
10478
  let previewContent;
10510
- if (toolName === "edit_tool" && !skipEditDiffRepeat) {
10479
+ if (toolName === "edit_tool") {
10511
10480
  try {
10512
10481
  previewContent = await this._generateEditPreview(toolArgs);
10513
10482
  } catch (previewError) {
@@ -10520,7 +10489,7 @@ var BluMaAgent = class {
10520
10489
  tool_name: toolName,
10521
10490
  arguments: toolArgs,
10522
10491
  preview: previewContent,
10523
- suppress_edit_diff_preview: skipEditDiffRepeat,
10492
+ suppress_edit_diff_preview: false,
10524
10493
  tool_policy: this.buildToolPolicyForUi(toolName, toolArgs)
10525
10494
  });
10526
10495
  try {
@@ -10583,7 +10552,7 @@ var BluMaAgent = class {
10583
10552
  tool_name: toolName,
10584
10553
  arguments: toolArgs,
10585
10554
  result: toolResultContent,
10586
- suppress_edit_diff: skipEditDiffRepeat
10555
+ suppress_edit_diff: false
10587
10556
  });
10588
10557
  if (toolName === "message") {
10589
10558
  try {
@@ -10877,11 +10846,6 @@ ${editData.error.display}`;
10877
10846
  if (hasContent) {
10878
10847
  this.eventBus.emit("stream_chunk", { delta: content });
10879
10848
  }
10880
- if (hasTools) {
10881
- this.eventBus.emit("stream_tool_calls_partial", {
10882
- calls: normalizedMessageToolCallsToPartial(message2.tool_calls)
10883
- });
10884
- }
10885
10849
  const omitAssistantFlush = hasTools && message2.tool_calls.some((tc) => String(tc?.function?.name ?? "").includes("message"));
10886
10850
  this.eventBus.emit("stream_end", { omitAssistantFlush });
10887
10851
  }
@@ -10922,13 +10886,6 @@ ${editData.error.display}`;
10922
10886
  if (chunk.tool_calls) {
10923
10887
  toolCalls = chunk.tool_calls;
10924
10888
  }
10925
- if (chunk.tool_calls_partial && chunk.tool_calls_partial.length > 0) {
10926
- if (!hasEmittedStart) {
10927
- this.eventBus.emit("stream_start", {});
10928
- hasEmittedStart = true;
10929
- }
10930
- this.eventBus.emit("stream_tool_calls_partial", { calls: chunk.tool_calls_partial });
10931
- }
10932
10889
  }
10933
10890
  const omitAssistantFlush = Array.isArray(toolCalls) && toolCalls.some((tc) => String(tc?.function?.name ?? "").includes("message"));
10934
10891
  if (hasEmittedStart) {
@@ -14408,10 +14365,9 @@ function applyStreamEndFlush(params) {
14408
14365
  }
14409
14366
 
14410
14367
  // src/app/ui/components/StreamingText.tsx
14411
- import { Fragment as Fragment7, jsx as jsx21, jsxs as jsxs19 } from "react/jsx-runtime";
14368
+ import { jsx as jsx21, jsxs as jsxs19 } from "react/jsx-runtime";
14412
14369
  var THROTTLE_MS = 50;
14413
14370
  var MAX_VISIBLE_LINES = 20;
14414
- var ARGS_PREVIEW_MAX = 72;
14415
14371
  var StreamingTextComponent = ({
14416
14372
  eventBus,
14417
14373
  onReasoningComplete,
@@ -14419,7 +14375,6 @@ var StreamingTextComponent = ({
14419
14375
  }) => {
14420
14376
  const [reasoning, setReasoning] = useState6("");
14421
14377
  const [assistantContent, setAssistantContent] = useState6("");
14422
- const [partialToolCalls, setPartialToolCalls] = useState6([]);
14423
14378
  const [isStreaming, setIsStreaming] = useState6(false);
14424
14379
  const reasoningRef = useRef5("");
14425
14380
  const contentRef = useRef5("");
@@ -14452,7 +14407,6 @@ var StreamingTextComponent = ({
14452
14407
  contentRef.current = "";
14453
14408
  setReasoning("");
14454
14409
  setAssistantContent("");
14455
- setPartialToolCalls([]);
14456
14410
  lastUpdateRef.current = 0;
14457
14411
  setIsStreaming(true);
14458
14412
  };
@@ -14468,11 +14422,6 @@ var StreamingTextComponent = ({
14468
14422
  scheduleFlush();
14469
14423
  }
14470
14424
  };
14471
- const handleToolCallsPartial = (data) => {
14472
- if (Array.isArray(data.calls) && data.calls.length > 0) {
14473
- setPartialToolCalls(data.calls);
14474
- }
14475
- };
14476
14425
  const handleEnd = (payload) => {
14477
14426
  if (streamEndHandledRef.current) return;
14478
14427
  streamEndHandledRef.current = true;
@@ -14490,24 +14439,21 @@ var StreamingTextComponent = ({
14490
14439
  });
14491
14440
  setReasoning("");
14492
14441
  setAssistantContent("");
14493
- setPartialToolCalls([]);
14494
14442
  reasoningRef.current = "";
14495
14443
  contentRef.current = "";
14496
14444
  };
14497
14445
  eventBus.on("stream_start", handleStart);
14498
14446
  eventBus.on("stream_reasoning_chunk", handleReasoningChunk);
14499
14447
  eventBus.on("stream_chunk", handleContentChunk);
14500
- eventBus.on("stream_tool_calls_partial", handleToolCallsPartial);
14501
14448
  eventBus.on("stream_end", handleEnd);
14502
14449
  return () => {
14503
14450
  eventBus.off("stream_start", handleStart);
14504
14451
  eventBus.off("stream_reasoning_chunk", handleReasoningChunk);
14505
14452
  eventBus.off("stream_chunk", handleContentChunk);
14506
- eventBus.off("stream_tool_calls_partial", handleToolCallsPartial);
14507
14453
  eventBus.off("stream_end", handleEnd);
14508
14454
  };
14509
14455
  }, [eventBus]);
14510
- if (!isStreaming || !reasoning && !assistantContent && partialToolCalls.length === 0) {
14456
+ if (!isStreaming || !reasoning && !assistantContent) {
14511
14457
  return null;
14512
14458
  }
14513
14459
  const renderLines = (text, dim) => {
@@ -14527,31 +14473,9 @@ var StreamingTextComponent = ({
14527
14473
  displayLines.map((line, i) => /* @__PURE__ */ jsx21(Text19, { dimColor: dim, color: dim ? void 0 : BLUMA_TERMINAL.m3OnSurface, children: line }, i))
14528
14474
  ] });
14529
14475
  };
14530
- const formatArgsPreview = (raw) => {
14531
- const s = String(raw ?? "");
14532
- if (s.length <= ARGS_PREVIEW_MAX) return s;
14533
- return `${s.slice(0, ARGS_PREVIEW_MAX - 1)}\u2026`;
14534
- };
14535
14476
  return /* @__PURE__ */ jsxs19(ChatBlock, { marginBottom: 1, children: [
14536
14477
  reasoning ? /* @__PURE__ */ jsx21(Box20, { flexDirection: "column", paddingLeft: 2, children: renderLines(reasoning, true) }) : null,
14537
- assistantContent ? /* @__PURE__ */ jsx21(MessageResponse, { children: renderLines(assistantContent, false) }) : null,
14538
- partialToolCalls.length > 0 ? /* @__PURE__ */ jsxs19(Box20, { flexDirection: "column", paddingLeft: 2, marginTop: assistantContent || reasoning ? 1 : 0, children: [
14539
- /* @__PURE__ */ jsx21(Text19, { dimColor: true, children: "tools (streaming)" }),
14540
- partialToolCalls.map((tc) => {
14541
- const name = tc.function?.name?.trim() || "\u2026";
14542
- const args = formatArgsPreview(tc.function?.arguments ?? "");
14543
- return /* @__PURE__ */ jsxs19(Text19, { dimColor: true, wrap: "wrap", children: [
14544
- /* @__PURE__ */ jsxs19(Text19, { color: BLUMA_TERMINAL.suggestion, children: [
14545
- "\u2022 ",
14546
- name
14547
- ] }),
14548
- args ? /* @__PURE__ */ jsxs19(Fragment7, { children: [
14549
- /* @__PURE__ */ jsx21(Text19, { dimColor: true, children: " " }),
14550
- /* @__PURE__ */ jsx21(Text19, { dimColor: true, italic: true, children: args })
14551
- ] }) : null
14552
- ] }, `${tc.index}-${tc.id}`);
14553
- })
14554
- ] }) : null
14478
+ assistantContent ? /* @__PURE__ */ jsx21(MessageResponse, { children: renderLines(assistantContent, false) }) : null
14555
14479
  ] });
14556
14480
  };
14557
14481
  var StreamingText = memo12(StreamingTextComponent);
@@ -15330,11 +15254,9 @@ Please use command_status to check the result and report back to the user.`;
15330
15254
  toolCalls: pendingConfirmation,
15331
15255
  preview: confirmationPreview,
15332
15256
  onDecision: (decision) => {
15333
- const hadPreview = confirmationPreview != null && String(confirmationPreview).trim().length > 0;
15334
- const tname = pendingConfirmation?.[0]?.function?.name ?? "";
15335
15257
  setConfirmationPreview(null);
15336
15258
  handleConfirmation(decision, pendingConfirmation, {
15337
- editPreviewAlreadyShown: (decision === "accept" || decision === "accept_always") && tname === "edit_tool" && hadPreview
15259
+ editPreviewAlreadyShown: false
15338
15260
  });
15339
15261
  }
15340
15262
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nomad-e/bluma-cli",
3
- "version": "0.1.46",
3
+ "version": "0.1.48",
4
4
  "description": "BluMa independent agent for automation and advanced software engineering.",
5
5
  "author": "Alex Fonseca",
6
6
  "license": "Apache-2.0",