@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 +5 -2
- package/dist/main.js +8 -86
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
[](LICENSE)
|
|
5
5
|
[](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
|
-
- **
|
|
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
|
-
|
|
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"
|
|
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:
|
|
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:
|
|
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 {
|
|
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
|
|
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:
|
|
15259
|
+
editPreviewAlreadyShown: false
|
|
15338
15260
|
});
|
|
15339
15261
|
}
|
|
15340
15262
|
}
|