@nomad-e/bluma-cli 0.1.1 → 0.1.2

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.
Files changed (2) hide show
  1. package/dist/main.js +424 -144
  2. package/package.json +1 -1
package/dist/main.js CHANGED
@@ -328,14 +328,14 @@ var init_async_command = __esm({
328
328
  });
329
329
 
330
330
  // src/main.ts
331
- import React10 from "react";
331
+ import React11 from "react";
332
332
  import { render } from "ink";
333
333
  import { EventEmitter as EventEmitter2 } from "events";
334
334
  import { v4 as uuidv43 } from "uuid";
335
335
 
336
336
  // src/app/ui/App.tsx
337
- import { useState as useState6, useEffect as useEffect5, useRef as useRef4, useCallback as useCallback2, memo as memo10 } from "react";
338
- import { Box as Box16, Text as Text15, Static } from "ink";
337
+ import { useState as useState7, useEffect as useEffect6, useRef as useRef5, useCallback as useCallback2, memo as memo11 } from "react";
338
+ import { Box as Box17, Text as Text16, Static } from "ink";
339
339
 
340
340
  // src/app/ui/layout.tsx
341
341
  import { Box, Text } from "ink";
@@ -3374,9 +3374,17 @@ async function loadSkill(args) {
3374
3374
  message: `Skill "${skill_name}" not found. Available skills: ${availableNames}`
3375
3375
  };
3376
3376
  }
3377
+ if (globalContext.history) {
3378
+ globalContext.history.push({
3379
+ role: "user",
3380
+ content: `[SKILL:${skill.name}]
3381
+
3382
+ ${skill.content}`
3383
+ });
3384
+ }
3377
3385
  return {
3378
3386
  success: true,
3379
- message: `Skill "${skill_name}" loaded.`,
3387
+ message: `Skill "${skill_name}" loaded successfully. Follow the instructions in the skill content above.`,
3380
3388
  skill_name: skill.name,
3381
3389
  description: skill.description
3382
3390
  };
@@ -3823,7 +3831,13 @@ async function doSaveSessionHistory(sessionFile, history) {
3823
3831
  });
3824
3832
  }
3825
3833
  async function saveSessionHistory(sessionFile, history) {
3826
- debouncedSave(sessionFile, history);
3834
+ const cleanHistory = history.filter((msg) => {
3835
+ if (msg.role === "user" && typeof msg.content === "string") {
3836
+ return !msg.content.startsWith("[SKILL:");
3837
+ }
3838
+ return true;
3839
+ });
3840
+ debouncedSave(sessionFile, cleanHistory);
3827
3841
  }
3828
3842
 
3829
3843
  // src/app/agent/core/prompt/prompt_builder.ts
@@ -4940,6 +4954,19 @@ var BluMaAgent = class {
4940
4954
  this.eventBus.emit("backend_message", { type: "info", message: "Agent task cancelled before tool execution." });
4941
4955
  return;
4942
4956
  }
4957
+ const actionMap = {
4958
+ "edit_tool": "Editing",
4959
+ "shell_command": "Executing",
4960
+ "command_status": "Waiting",
4961
+ "ls_tool": "Reading",
4962
+ "read_file_lines": "Reading",
4963
+ "message": "Responding",
4964
+ "load_skill": "Loading skill",
4965
+ "search_web": "Searching",
4966
+ "todo": "Planning"
4967
+ };
4968
+ const action = actionMap[toolName] || "Processing";
4969
+ this.eventBus.emit("action_status", { action });
4943
4970
  const result = await this.mcpClient.invoke(toolName, toolArgs);
4944
4971
  let finalResult = result;
4945
4972
  if (Array.isArray(result) && result.length > 0 && result[0].type === "text" && typeof result[0].text === "string") {
@@ -5006,82 +5033,200 @@ ${editData.error.display}`;
5006
5033
  return;
5007
5034
  }
5008
5035
  const contextWindow = createApiContextWindow(this.history, this.maxContextTurns);
5009
- const response = await this.llm.chatCompletion({
5010
- model: "x-ai/grok-code-fast-1",
5011
- // model: "openrouter/polaris-alpha", //OpenRouter Openai training model
5012
- messages: contextWindow,
5013
- temperature: 0.3,
5014
- tools: this.mcpClient.getAvailableTools(),
5015
- tool_choice: "required",
5016
- parallel_tool_calls: false
5017
- });
5036
+ const llmService = this.llm;
5037
+ if (typeof llmService.chatCompletionStream === "function") {
5038
+ await this._handleStreamingResponse(contextWindow);
5039
+ } else {
5040
+ await this._handleNonStreamingResponse(contextWindow);
5041
+ }
5042
+ } catch (error) {
5043
+ const errorMessage = error instanceof Error ? error.message : "An unknown API error occurred.";
5044
+ this.eventBus.emit("backend_message", { type: "error", message: errorMessage });
5045
+ } finally {
5046
+ await saveSessionHistory(this.sessionFile, this.history);
5047
+ }
5048
+ }
5049
+ async _handleStreamingResponse(contextWindow) {
5050
+ const llmService = this.llm;
5051
+ this.eventBus.emit("action_status", { action: "Thinking" });
5052
+ let accumulatedContent = "";
5053
+ let toolCalls;
5054
+ let hasEmittedStart = false;
5055
+ let reasoningContent = "";
5056
+ const stream = llmService.chatCompletionStream({
5057
+ model: "x-ai/grok-code-fast-1",
5058
+ messages: contextWindow,
5059
+ temperature: 0.3,
5060
+ tools: this.mcpClient.getAvailableTools(),
5061
+ tool_choice: "required",
5062
+ parallel_tool_calls: false
5063
+ });
5064
+ for await (const chunk of stream) {
5018
5065
  if (this.isInterrupted) {
5066
+ this.eventBus.emit("stream_end", {});
5019
5067
  this.eventBus.emit("backend_message", { type: "info", message: "Agent task cancelled by user." });
5020
5068
  return;
5021
5069
  }
5022
- let message2 = response.choices[0].message;
5023
- message2 = ToolCallNormalizer.normalizeAssistantMessage(message2);
5024
- if (message2.reasoning_content || message2.reasoning) {
5025
- const reasoningText = message2.reasoning_content || message2.reasoning;
5070
+ if (chunk.reasoning) {
5071
+ if (!hasEmittedStart) {
5072
+ this.eventBus.emit("stream_start", {});
5073
+ hasEmittedStart = true;
5074
+ }
5075
+ reasoningContent += chunk.reasoning;
5076
+ this.eventBus.emit("stream_reasoning_chunk", { delta: chunk.reasoning });
5077
+ }
5078
+ if (chunk.delta) {
5079
+ if (!hasEmittedStart) {
5080
+ this.eventBus.emit("stream_start", {});
5081
+ hasEmittedStart = true;
5082
+ }
5083
+ accumulatedContent += chunk.delta;
5084
+ this.eventBus.emit("stream_chunk", { delta: chunk.delta });
5085
+ }
5086
+ if (chunk.tool_calls) {
5087
+ toolCalls = chunk.tool_calls;
5088
+ }
5089
+ if (chunk.finish_reason) {
5090
+ if (hasEmittedStart) {
5091
+ this.eventBus.emit("stream_end", {});
5092
+ }
5093
+ }
5094
+ }
5095
+ const message2 = {
5096
+ role: "assistant",
5097
+ content: accumulatedContent || null
5098
+ };
5099
+ if (toolCalls && toolCalls.length > 0) {
5100
+ message2.tool_calls = toolCalls;
5101
+ }
5102
+ const normalizedMessage = ToolCallNormalizer.normalizeAssistantMessage(message2);
5103
+ if (normalizedMessage.reasoning_content || normalizedMessage.reasoning) {
5104
+ const reasoningText = normalizedMessage.reasoning_content || normalizedMessage.reasoning;
5105
+ this.eventBus.emit("backend_message", {
5106
+ type: "reasoning",
5107
+ content: typeof reasoningText === "string" ? reasoningText : JSON.stringify(reasoningText)
5108
+ });
5109
+ }
5110
+ this.history.push(normalizedMessage);
5111
+ if (normalizedMessage.tool_calls && normalizedMessage.tool_calls.length > 0) {
5112
+ const validToolCalls = normalizedMessage.tool_calls.filter(
5113
+ (call) => ToolCallNormalizer.isValidToolCall(call)
5114
+ );
5115
+ if (validToolCalls.length === 0) {
5026
5116
  this.eventBus.emit("backend_message", {
5027
- type: "reasoning",
5028
- content: typeof reasoningText === "string" ? reasoningText : JSON.stringify(reasoningText)
5117
+ type: "error",
5118
+ message: "Model returned invalid tool calls. Retrying..."
5029
5119
  });
5120
+ await this._continueConversation();
5121
+ return;
5030
5122
  }
5031
- this.history.push(message2);
5032
- if (message2.tool_calls && message2.tool_calls.length > 0) {
5033
- const validToolCalls = message2.tool_calls.filter(
5034
- (call) => ToolCallNormalizer.isValidToolCall(call)
5035
- );
5036
- if (validToolCalls.length === 0) {
5037
- this.eventBus.emit("backend_message", {
5038
- type: "error",
5039
- message: "Model returned invalid tool calls. Retrying..."
5040
- });
5041
- await this._continueConversation();
5042
- return;
5043
- }
5044
- const autoApprovedTools = [
5045
- "message",
5046
- "ls_tool",
5047
- "count_file_lines",
5048
- "read_file_lines",
5049
- "todo",
5050
- "load_skill",
5051
- "search_web"
5052
- ];
5053
- const toolToCall = validToolCalls[0];
5054
- const isSafeTool = autoApprovedTools.some((safeTool) => toolToCall.function.name.includes(safeTool));
5055
- if (isSafeTool) {
5056
- await this.handleToolResponse({ type: "user_decision_execute", tool_calls: validToolCalls });
5123
+ const autoApprovedTools = [
5124
+ "message",
5125
+ "ls_tool",
5126
+ "count_file_lines",
5127
+ "read_file_lines",
5128
+ "todo",
5129
+ "load_skill",
5130
+ "search_web"
5131
+ ];
5132
+ const toolToCall = validToolCalls[0];
5133
+ const isSafeTool = autoApprovedTools.some((safeTool) => toolToCall.function.name.includes(safeTool));
5134
+ if (isSafeTool) {
5135
+ await this.handleToolResponse({ type: "user_decision_execute", tool_calls: validToolCalls });
5136
+ } else {
5137
+ const toolName = toolToCall.function.name;
5138
+ if (toolName === "edit_tool") {
5139
+ const args = JSON.parse(toolToCall.function.arguments);
5140
+ const previewContent = await this._generateEditPreview(args);
5141
+ this.eventBus.emit("backend_message", { type: "confirmation_request", tool_calls: validToolCalls, preview: previewContent });
5057
5142
  } else {
5058
- const toolName = toolToCall.function.name;
5059
- if (toolName === "edit_tool") {
5060
- const args = JSON.parse(toolToCall.function.arguments);
5061
- const previewContent = await this._generateEditPreview(args);
5062
- this.eventBus.emit("backend_message", { type: "confirmation_request", tool_calls: validToolCalls, preview: previewContent });
5063
- } else {
5064
- this.eventBus.emit("backend_message", { type: "confirmation_request", tool_calls: validToolCalls });
5065
- }
5143
+ this.eventBus.emit("backend_message", { type: "confirmation_request", tool_calls: validToolCalls });
5066
5144
  }
5067
- } else if (message2.content) {
5068
- this.eventBus.emit("backend_message", { type: "assistant_message", content: message2.content });
5069
- const feedback = this.feedbackSystem.generateFeedback({
5070
- event: "protocol_violation_direct_text",
5071
- details: { violationContent: message2.content }
5145
+ }
5146
+ } else if (accumulatedContent) {
5147
+ this.eventBus.emit("backend_message", { type: "assistant_message", content: accumulatedContent });
5148
+ const feedback = this.feedbackSystem.generateFeedback({
5149
+ event: "protocol_violation_direct_text",
5150
+ details: { violationContent: accumulatedContent }
5151
+ });
5152
+ this.eventBus.emit("backend_message", { type: "protocol_violation", message: feedback.message, content: accumulatedContent });
5153
+ this.history.push({ role: "system", content: feedback.correction });
5154
+ await this._continueConversation();
5155
+ } else {
5156
+ this.eventBus.emit("backend_message", { type: "info", message: "Agent is thinking... continuing reasoning cycle." });
5157
+ await this._continueConversation();
5158
+ }
5159
+ }
5160
+ async _handleNonStreamingResponse(contextWindow) {
5161
+ const response = await this.llm.chatCompletion({
5162
+ model: "x-ai/grok-code-fast-1",
5163
+ messages: contextWindow,
5164
+ temperature: 0.3,
5165
+ tools: this.mcpClient.getAvailableTools(),
5166
+ tool_choice: "required",
5167
+ parallel_tool_calls: false
5168
+ });
5169
+ if (this.isInterrupted) {
5170
+ this.eventBus.emit("backend_message", { type: "info", message: "Agent task cancelled by user." });
5171
+ return;
5172
+ }
5173
+ let message2 = response.choices[0].message;
5174
+ message2 = ToolCallNormalizer.normalizeAssistantMessage(message2);
5175
+ if (message2.reasoning_content || message2.reasoning) {
5176
+ const reasoningText = message2.reasoning_content || message2.reasoning;
5177
+ this.eventBus.emit("backend_message", {
5178
+ type: "reasoning",
5179
+ content: typeof reasoningText === "string" ? reasoningText : JSON.stringify(reasoningText)
5180
+ });
5181
+ }
5182
+ this.history.push(message2);
5183
+ if (message2.tool_calls && message2.tool_calls.length > 0) {
5184
+ const validToolCalls = message2.tool_calls.filter(
5185
+ (call) => ToolCallNormalizer.isValidToolCall(call)
5186
+ );
5187
+ if (validToolCalls.length === 0) {
5188
+ this.eventBus.emit("backend_message", {
5189
+ type: "error",
5190
+ message: "Model returned invalid tool calls. Retrying..."
5072
5191
  });
5073
- this.eventBus.emit("backend_message", { type: "protocol_violation", message: feedback.message, content: message2.content });
5074
- this.history.push({ role: "system", content: feedback.correction });
5075
5192
  await this._continueConversation();
5193
+ return;
5194
+ }
5195
+ const autoApprovedTools = [
5196
+ "message",
5197
+ "ls_tool",
5198
+ "count_file_lines",
5199
+ "read_file_lines",
5200
+ "todo",
5201
+ "load_skill",
5202
+ "search_web"
5203
+ ];
5204
+ const toolToCall = validToolCalls[0];
5205
+ const isSafeTool = autoApprovedTools.some((safeTool) => toolToCall.function.name.includes(safeTool));
5206
+ if (isSafeTool) {
5207
+ await this.handleToolResponse({ type: "user_decision_execute", tool_calls: validToolCalls });
5076
5208
  } else {
5077
- this.eventBus.emit("backend_message", { type: "info", message: "Agent is thinking... continuing reasoning cycle." });
5078
- await this._continueConversation();
5209
+ const toolName = toolToCall.function.name;
5210
+ if (toolName === "edit_tool") {
5211
+ const args = JSON.parse(toolToCall.function.arguments);
5212
+ const previewContent = await this._generateEditPreview(args);
5213
+ this.eventBus.emit("backend_message", { type: "confirmation_request", tool_calls: validToolCalls, preview: previewContent });
5214
+ } else {
5215
+ this.eventBus.emit("backend_message", { type: "confirmation_request", tool_calls: validToolCalls });
5216
+ }
5079
5217
  }
5080
- } catch (error) {
5081
- const errorMessage = error instanceof Error ? error.message : "An unknown API error occurred.";
5082
- this.eventBus.emit("backend_message", { type: "error", message: errorMessage });
5083
- } finally {
5084
- await saveSessionHistory(this.sessionFile, this.history);
5218
+ } else if (message2.content) {
5219
+ this.eventBus.emit("backend_message", { type: "assistant_message", content: message2.content });
5220
+ const feedback = this.feedbackSystem.generateFeedback({
5221
+ event: "protocol_violation_direct_text",
5222
+ details: { violationContent: message2.content }
5223
+ });
5224
+ this.eventBus.emit("backend_message", { type: "protocol_violation", message: feedback.message, content: message2.content });
5225
+ this.history.push({ role: "system", content: feedback.correction });
5226
+ await this._continueConversation();
5227
+ } else {
5228
+ this.eventBus.emit("backend_message", { type: "info", message: "Agent is thinking... continuing reasoning cycle." });
5229
+ await this._continueConversation();
5085
5230
  }
5086
5231
  }
5087
5232
  };
@@ -5098,6 +5243,9 @@ var LLMService = class {
5098
5243
  });
5099
5244
  this.defaultModel = config2.model || "";
5100
5245
  }
5246
+ /**
5247
+ * Chamada tradicional (não-streaming) - retorna resposta completa
5248
+ */
5101
5249
  async chatCompletion(params) {
5102
5250
  const resp = await this.client.chat.completions.create({
5103
5251
  model: params.model || this.defaultModel,
@@ -5110,6 +5258,64 @@ var LLMService = class {
5110
5258
  });
5111
5259
  return resp;
5112
5260
  }
5261
+ /**
5262
+ * Chamada com streaming - retorna chunks em tempo real
5263
+ *
5264
+ * Uso:
5265
+ * ```
5266
+ * for await (const chunk of llm.chatCompletionStream(params)) {
5267
+ * process.stdout.write(chunk.delta);
5268
+ * }
5269
+ * ```
5270
+ */
5271
+ async *chatCompletionStream(params) {
5272
+ const stream = await this.client.chat.completions.create({
5273
+ model: params.model || this.defaultModel,
5274
+ messages: params.messages,
5275
+ tools: params.tools,
5276
+ tool_choice: params.tool_choice,
5277
+ parallel_tool_calls: params.parallel_tool_calls,
5278
+ temperature: params.temperature,
5279
+ max_tokens: params.max_tokens,
5280
+ stream: true
5281
+ });
5282
+ const toolCallsAccumulator = /* @__PURE__ */ new Map();
5283
+ for await (const chunk of stream) {
5284
+ const choice = chunk.choices[0];
5285
+ if (!choice) continue;
5286
+ const delta = choice.delta;
5287
+ if (delta?.tool_calls) {
5288
+ for (const tc of delta.tool_calls) {
5289
+ const idx = tc.index;
5290
+ if (!toolCallsAccumulator.has(idx)) {
5291
+ toolCallsAccumulator.set(idx, {
5292
+ id: tc.id || "",
5293
+ type: tc.type || "function",
5294
+ function: { name: "", arguments: "" }
5295
+ });
5296
+ }
5297
+ const acc = toolCallsAccumulator.get(idx);
5298
+ if (tc.id) acc.id = tc.id;
5299
+ if (tc.function?.name) acc.function.name = tc.function.name;
5300
+ if (tc.function?.arguments) acc.function.arguments += tc.function.arguments;
5301
+ }
5302
+ }
5303
+ const reasoning = delta?.reasoning_content || delta?.reasoning || "";
5304
+ yield {
5305
+ delta: delta?.content || "",
5306
+ reasoning,
5307
+ tool_calls: choice.finish_reason === "tool_calls" ? Array.from(toolCallsAccumulator.values()) : void 0,
5308
+ finish_reason: choice.finish_reason
5309
+ };
5310
+ }
5311
+ if (toolCallsAccumulator.size > 0) {
5312
+ yield {
5313
+ delta: "",
5314
+ tool_calls: Array.from(toolCallsAccumulator.values()),
5315
+ finish_reason: "tool_calls"
5316
+ };
5317
+ }
5318
+ }
5113
5319
  /**
5114
5320
  * Retorna o modelo padrão configurado
5115
5321
  */
@@ -5691,41 +5897,52 @@ var Agent = class {
5691
5897
  import { useState as useState4, useEffect as useEffect4, memo as memo5 } from "react";
5692
5898
  import { Box as Box7, Text as Text7 } from "ink";
5693
5899
  import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
5694
- var WorkingTimerComponent = ({ taskName, taskStatus }) => {
5695
- const [seconds, setSeconds] = useState4(0);
5696
- const [frame, setFrame] = useState4(0);
5900
+ var WorkingTimerComponent = ({ eventBus: eventBus2, taskName, taskStatus }) => {
5901
+ const [currentAction, setCurrentAction] = useState4("Thinking...");
5902
+ const [shinePosition, setShinePosition] = useState4(0);
5903
+ const [dots, setDots] = useState4("");
5904
+ useEffect4(() => {
5905
+ if (!eventBus2) return;
5906
+ const handleActionStatus = (data) => {
5907
+ if (data.action) {
5908
+ setCurrentAction(data.action);
5909
+ }
5910
+ };
5911
+ eventBus2.on("action_status", handleActionStatus);
5912
+ return () => {
5913
+ eventBus2.off("action_status", handleActionStatus);
5914
+ };
5915
+ }, [eventBus2]);
5697
5916
  useEffect4(() => {
5698
- const timer = setInterval(() => {
5699
- setSeconds((prev) => prev + 1);
5700
- }, 1e3);
5701
- return () => clearInterval(timer);
5917
+ const shineTimer = setInterval(() => {
5918
+ setShinePosition((prev) => (prev + 1) % 30);
5919
+ }, 75);
5920
+ return () => clearInterval(shineTimer);
5702
5921
  }, []);
5703
5922
  useEffect4(() => {
5704
- const animator = setInterval(() => {
5705
- setFrame((prev) => (prev + 1) % 4);
5706
- }, 150);
5707
- return () => clearInterval(animator);
5923
+ const dotsTimer = setInterval(() => {
5924
+ setDots((prev) => prev.length >= 3 ? "" : prev + ".");
5925
+ }, 500);
5926
+ return () => clearInterval(dotsTimer);
5708
5927
  }, []);
5709
- const spinners = ["|", "/", "-", "\\"];
5710
- const spinner = spinners[frame];
5711
- const formatTime = (s) => {
5712
- if (s < 60) return `${s}s`;
5713
- return `${Math.floor(s / 60)}m${s % 60}s`;
5928
+ const displayAction = taskStatus || currentAction;
5929
+ const renderShineText = (text) => {
5930
+ const chars = text.split("");
5931
+ const textLen = text.length;
5932
+ const shineIdx = shinePosition % (textLen + 6);
5933
+ return chars.map((char, i) => {
5934
+ const distance = Math.abs(i - shineIdx);
5935
+ if (distance <= 1) {
5936
+ return /* @__PURE__ */ jsx7(Text7, { color: "white", dimColor: true, children: char }, i);
5937
+ } else {
5938
+ return /* @__PURE__ */ jsx7(Text7, { color: "gray", dimColor: true, children: char }, i);
5939
+ }
5940
+ });
5714
5941
  };
5715
5942
  return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", paddingX: 1, children: [
5716
- /* @__PURE__ */ jsxs7(Box7, { children: [
5717
- /* @__PURE__ */ jsx7(Text7, { color: "cyan", children: spinner }),
5718
- /* @__PURE__ */ jsxs7(Text7, { dimColor: true, children: [
5719
- " ",
5720
- taskStatus || "thinking"
5721
- ] }),
5722
- /* @__PURE__ */ jsxs7(Text7, { color: "gray", children: [
5723
- " ",
5724
- formatTime(seconds)
5725
- ] })
5726
- ] }),
5943
+ /* @__PURE__ */ jsx7(Box7, { children: renderShineText(displayAction) }),
5727
5944
  taskName && /* @__PURE__ */ jsx7(Box7, { paddingLeft: 2, children: /* @__PURE__ */ jsxs7(Text7, { dimColor: true, children: [
5728
- "^ ",
5945
+ "\u203A ",
5729
5946
  taskName
5730
5947
  ] }) })
5731
5948
  ] });
@@ -6658,14 +6875,60 @@ var ReasoningDisplayComponent = ({
6658
6875
  const lines = reasoning.split("\n");
6659
6876
  const displayText = isExpanded ? reasoning : lines.slice(0, maxLines).join("\n") + (lines.length > maxLines ? "..." : "");
6660
6877
  return /* @__PURE__ */ jsxs14(Box15, { flexDirection: "column", paddingX: 1, marginBottom: 1, marginTop: 1, children: [
6661
- /* @__PURE__ */ jsx15(Box15, { children: /* @__PURE__ */ jsx15(Text14, { color: "white", bold: true, children: "Thinking" }) }),
6878
+ /* @__PURE__ */ jsx15(Box15, {}),
6662
6879
  /* @__PURE__ */ jsx15(Box15, { paddingLeft: 2, flexDirection: "column", children: displayText.split("\n").map((line, i) => /* @__PURE__ */ jsx15(Text14, { color: "gray", dimColor: true, children: line }, i)) })
6663
6880
  ] });
6664
6881
  };
6665
6882
  var ReasoningDisplay = memo9(ReasoningDisplayComponent);
6666
6883
 
6884
+ // src/app/ui/components/StreamingText.tsx
6885
+ import { useState as useState6, useEffect as useEffect5, useRef as useRef4, memo as memo10 } from "react";
6886
+ import { Box as Box16, Text as Text15 } from "ink";
6887
+ import { jsx as jsx16 } from "react/jsx-runtime";
6888
+ var StreamingTextComponent = ({ eventBus: eventBus2, onReasoningComplete }) => {
6889
+ const [reasoning, setReasoning] = useState6("");
6890
+ const [isStreaming, setIsStreaming] = useState6(false);
6891
+ const reasoningRef = useRef4("");
6892
+ useEffect5(() => {
6893
+ const handleStart = () => {
6894
+ setReasoning("");
6895
+ reasoningRef.current = "";
6896
+ setIsStreaming(true);
6897
+ };
6898
+ const handleReasoningChunk = (data) => {
6899
+ if (data.delta) {
6900
+ reasoningRef.current += data.delta;
6901
+ setReasoning(reasoningRef.current);
6902
+ }
6903
+ };
6904
+ const handleEnd = () => {
6905
+ setIsStreaming(false);
6906
+ const finalReasoning = reasoningRef.current;
6907
+ if (finalReasoning && onReasoningComplete) {
6908
+ onReasoningComplete(finalReasoning);
6909
+ }
6910
+ setReasoning("");
6911
+ reasoningRef.current = "";
6912
+ };
6913
+ eventBus2.on("stream_start", handleStart);
6914
+ eventBus2.on("stream_reasoning_chunk", handleReasoningChunk);
6915
+ eventBus2.on("stream_end", handleEnd);
6916
+ return () => {
6917
+ eventBus2.off("stream_start", handleStart);
6918
+ eventBus2.off("stream_reasoning_chunk", handleReasoningChunk);
6919
+ eventBus2.off("stream_end", handleEnd);
6920
+ };
6921
+ }, [eventBus2, onReasoningComplete]);
6922
+ if (!isStreaming || !reasoning) {
6923
+ return null;
6924
+ }
6925
+ const lines = reasoning.split("\n");
6926
+ return /* @__PURE__ */ jsx16(Box16, { flexDirection: "column", paddingX: 1, marginBottom: 1, marginTop: 1, children: /* @__PURE__ */ jsx16(Box16, { paddingLeft: 2, flexDirection: "column", children: lines.map((line, i) => /* @__PURE__ */ jsx16(Text15, { color: "gray", dimColor: true, children: line }, i)) }) });
6927
+ };
6928
+ var StreamingText = memo10(StreamingTextComponent);
6929
+
6667
6930
  // src/app/ui/App.tsx
6668
- import { jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
6931
+ import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
6669
6932
  var SAFE_AUTO_APPROVE_TOOLS = [
6670
6933
  // Comunicação/UI
6671
6934
  "message",
@@ -6683,28 +6946,28 @@ var SAFE_AUTO_APPROVE_TOOLS = [
6683
6946
  "command_status"
6684
6947
  ];
6685
6948
  var AppComponent = ({ eventBus: eventBus2, sessionId: sessionId2 }) => {
6686
- const agentInstance = useRef4(null);
6687
- const [history, setHistory] = useState6([]);
6688
- const [statusMessage, setStatusMessage] = useState6(
6949
+ const agentInstance = useRef5(null);
6950
+ const [history, setHistory] = useState7([]);
6951
+ const [statusMessage, setStatusMessage] = useState7(
6689
6952
  "Initializing agent..."
6690
6953
  );
6691
- const [toolsCount, setToolsCount] = useState6(null);
6692
- const [mcpStatus, setMcpStatus] = useState6(
6954
+ const [toolsCount, setToolsCount] = useState7(null);
6955
+ const [mcpStatus, setMcpStatus] = useState7(
6693
6956
  "connecting"
6694
6957
  );
6695
- const [isProcessing, setIsProcessing] = useState6(true);
6696
- const [pendingConfirmation, setPendingConfirmation] = useState6(
6958
+ const [isProcessing, setIsProcessing] = useState7(true);
6959
+ const [pendingConfirmation, setPendingConfirmation] = useState7(
6697
6960
  null
6698
6961
  );
6699
- const [confirmationPreview, setConfirmationPreview] = useState6(
6962
+ const [confirmationPreview, setConfirmationPreview] = useState7(
6700
6963
  null
6701
6964
  );
6702
- const [isInitAgentActive, setIsInitAgentActive] = useState6(false);
6703
- const alwaysAcceptList = useRef4([]);
6965
+ const [isInitAgentActive, setIsInitAgentActive] = useState7(false);
6966
+ const alwaysAcceptList = useRef5([]);
6704
6967
  const workdir = process.cwd();
6705
- const updateCheckRan = useRef4(false);
6706
- const sessionStartTime = useRef4(Date.now());
6707
- const [toolCallCount, setToolCallCount] = useState6(0);
6968
+ const updateCheckRan = useRef5(false);
6969
+ const sessionStartTime = useRef5(Date.now());
6970
+ const [toolCallCount, setToolCallCount] = useState7(0);
6708
6971
  const handleInterrupt = useCallback2(() => {
6709
6972
  if (!isProcessing) return;
6710
6973
  eventBus2.emit("user_interrupt");
@@ -6713,7 +6976,7 @@ var AppComponent = ({ eventBus: eventBus2, sessionId: sessionId2 }) => {
6713
6976
  ...prev,
6714
6977
  {
6715
6978
  id: prev.length,
6716
- component: /* @__PURE__ */ jsx16(Text15, { color: "yellow", children: "-- Task cancelled by dev. --" })
6979
+ component: /* @__PURE__ */ jsx17(Text16, { color: "yellow", children: "-- Task cancelled by dev. --" })
6717
6980
  }
6718
6981
  ]);
6719
6982
  }, [isProcessing, eventBus2]);
@@ -6737,11 +7000,11 @@ var AppComponent = ({ eventBus: eventBus2, sessionId: sessionId2 }) => {
6737
7000
  ...prev,
6738
7001
  {
6739
7002
  id: prev.length,
6740
- component: /* @__PURE__ */ jsx16(Box16, { marginBottom: 1, children: /* @__PURE__ */ jsx16(Text15, { color: "white", dimColor: true, children: text }) })
7003
+ component: /* @__PURE__ */ jsx17(Box17, { marginBottom: 1, children: /* @__PURE__ */ jsx17(Text16, { color: "white", dimColor: true, children: text }) })
6741
7004
  },
6742
7005
  {
6743
7006
  id: prev.length + 1,
6744
- component: /* @__PURE__ */ jsx16(
7007
+ component: /* @__PURE__ */ jsx17(
6745
7008
  SlashCommands_default,
6746
7009
  {
6747
7010
  input: text,
@@ -6763,9 +7026,9 @@ var AppComponent = ({ eventBus: eventBus2, sessionId: sessionId2 }) => {
6763
7026
  ...prev,
6764
7027
  {
6765
7028
  id: prev.length,
6766
- component: /* @__PURE__ */ jsxs15(Box16, { marginBottom: 1, children: [
6767
- /* @__PURE__ */ jsx16(Text15, { color: "white", bold: true, children: "$ " }),
6768
- /* @__PURE__ */ jsx16(Text15, { color: "white", children: command })
7029
+ component: /* @__PURE__ */ jsxs15(Box17, { marginBottom: 1, children: [
7030
+ /* @__PURE__ */ jsx17(Text16, { color: "white", bold: true, children: "$ " }),
7031
+ /* @__PURE__ */ jsx17(Text16, { color: "white", children: command })
6769
7032
  ] })
6770
7033
  }
6771
7034
  ]);
@@ -6784,7 +7047,7 @@ Please use command_status to check the result and report back to the user.`;
6784
7047
  ...prev,
6785
7048
  {
6786
7049
  id: prev.length,
6787
- component: /* @__PURE__ */ jsxs15(Text15, { color: "red", children: [
7050
+ component: /* @__PURE__ */ jsxs15(Text16, { color: "red", children: [
6788
7051
  "Failed to execute: ",
6789
7052
  result.error || result.message
6790
7053
  ] })
@@ -6797,7 +7060,7 @@ Please use command_status to check the result and report back to the user.`;
6797
7060
  ...prev,
6798
7061
  {
6799
7062
  id: prev.length,
6800
- component: /* @__PURE__ */ jsxs15(Text15, { color: "red", children: [
7063
+ component: /* @__PURE__ */ jsxs15(Text16, { color: "red", children: [
6801
7064
  "Error: ",
6802
7065
  err.message
6803
7066
  ] })
@@ -6816,8 +7079,8 @@ Please use command_status to check the result and report back to the user.`;
6816
7079
  id: prev.length,
6817
7080
  component: (
6818
7081
  // Uma única Box para o espaçamento
6819
- /* @__PURE__ */ jsx16(Box16, { marginBottom: 1, children: /* @__PURE__ */ jsxs15(Text15, { color: "white", dimColor: true, children: [
6820
- /* @__PURE__ */ jsxs15(Text15, { color: "white", children: [
7082
+ /* @__PURE__ */ jsx17(Box17, { marginBottom: 1, children: /* @__PURE__ */ jsxs15(Text16, { color: "white", dimColor: true, children: [
7083
+ /* @__PURE__ */ jsxs15(Text16, { color: "white", children: [
6821
7084
  ">",
6822
7085
  " "
6823
7086
  ] }),
@@ -6851,8 +7114,8 @@ Please use command_status to check the result and report back to the user.`;
6851
7114
  },
6852
7115
  []
6853
7116
  );
6854
- useEffect5(() => {
6855
- setHistory([{ id: 0, component: /* @__PURE__ */ jsx16(Header, { sessionId: sessionId2, workdir }) }]);
7117
+ useEffect6(() => {
7118
+ setHistory([{ id: 0, component: /* @__PURE__ */ jsx17(Header, { sessionId: sessionId2, workdir }) }]);
6856
7119
  const initializeAgent = async () => {
6857
7120
  try {
6858
7121
  agentInstance.current = new Agent(sessionId2, eventBus2);
@@ -6918,7 +7181,7 @@ Please use command_status to check the result and report back to the user.`;
6918
7181
  ...prev,
6919
7182
  {
6920
7183
  id: prev.length,
6921
- component: /* @__PURE__ */ jsx16(UpdateNotice_default, { message: msg })
7184
+ component: /* @__PURE__ */ jsx17(UpdateNotice_default, { message: msg })
6922
7185
  }
6923
7186
  ]);
6924
7187
  }
@@ -6932,10 +7195,10 @@ Please use command_status to check the result and report back to the user.`;
6932
7195
  }
6933
7196
  let newComponent = null;
6934
7197
  if (parsed.type === "debug") {
6935
- newComponent = /* @__PURE__ */ jsx16(Text15, { color: "gray", children: parsed.message });
7198
+ newComponent = /* @__PURE__ */ jsx17(Text16, { color: "gray", children: parsed.message });
6936
7199
  } else if (parsed.type === "protocol_violation") {
6937
7200
  newComponent = /* @__PURE__ */ jsxs15(
6938
- Box16,
7201
+ Box17,
6939
7202
  {
6940
7203
  borderStyle: "round",
6941
7204
  borderColor: "yellow",
@@ -6943,14 +7206,14 @@ Please use command_status to check the result and report back to the user.`;
6943
7206
  marginBottom: 1,
6944
7207
  paddingX: 1,
6945
7208
  children: [
6946
- /* @__PURE__ */ jsx16(Text15, { color: "yellow", bold: true, children: "Protocol Violation" }),
6947
- /* @__PURE__ */ jsx16(Text15, { color: "gray", children: parsed.content }),
6948
- /* @__PURE__ */ jsx16(Text15, { color: "yellow", children: parsed.message })
7209
+ /* @__PURE__ */ jsx17(Text16, { color: "yellow", bold: true, children: "Protocol Violation" }),
7210
+ /* @__PURE__ */ jsx17(Text16, { color: "gray", children: parsed.content }),
7211
+ /* @__PURE__ */ jsx17(Text16, { color: "yellow", children: parsed.message })
6949
7212
  ]
6950
7213
  }
6951
7214
  );
6952
7215
  } else if (parsed.type === "error") {
6953
- newComponent = /* @__PURE__ */ jsx16(
7216
+ newComponent = /* @__PURE__ */ jsx17(
6954
7217
  ErrorMessage_default,
6955
7218
  {
6956
7219
  message: parsed.message,
@@ -6960,7 +7223,7 @@ Please use command_status to check the result and report back to the user.`;
6960
7223
  );
6961
7224
  } else if (parsed.type === "tool_call") {
6962
7225
  const nextId2 = history.length;
6963
- newComponent = /* @__PURE__ */ jsx16(
7226
+ newComponent = /* @__PURE__ */ jsx17(
6964
7227
  ToolCallDisplay,
6965
7228
  {
6966
7229
  toolName: parsed.tool_name,
@@ -6969,7 +7232,7 @@ Please use command_status to check the result and report back to the user.`;
6969
7232
  }
6970
7233
  );
6971
7234
  } else if (parsed.type === "tool_result") {
6972
- newComponent = /* @__PURE__ */ jsx16(
7235
+ newComponent = /* @__PURE__ */ jsx17(
6973
7236
  ToolResultDisplay,
6974
7237
  {
6975
7238
  toolName: parsed.tool_name,
@@ -6977,17 +7240,17 @@ Please use command_status to check the result and report back to the user.`;
6977
7240
  }
6978
7241
  );
6979
7242
  } else if (parsed.type === "user_overlay") {
6980
- newComponent = /* @__PURE__ */ jsx16(Box16, { marginBottom: 1, children: /* @__PURE__ */ jsxs15(Text15, { color: "gray", children: [
6981
- /* @__PURE__ */ jsxs15(Text15, { color: "magenta", children: [
7243
+ newComponent = /* @__PURE__ */ jsx17(Box17, { marginBottom: 1, children: /* @__PURE__ */ jsxs15(Text16, { color: "gray", children: [
7244
+ /* @__PURE__ */ jsxs15(Text16, { color: "magenta", children: [
6982
7245
  ">",
6983
7246
  " "
6984
7247
  ] }),
6985
7248
  parsed.payload
6986
7249
  ] }) });
6987
7250
  } else if (parsed.type === "reasoning") {
6988
- newComponent = /* @__PURE__ */ jsx16(ReasoningDisplay, { reasoning: parsed.content });
7251
+ newComponent = /* @__PURE__ */ jsx17(ReasoningDisplay, { reasoning: parsed.content });
6989
7252
  } else if (parsed.type === "log") {
6990
- newComponent = /* @__PURE__ */ jsxs15(Text15, { color: "gray", children: [
7253
+ newComponent = /* @__PURE__ */ jsxs15(Text16, { color: "gray", children: [
6991
7254
  "\u2139\uFE0F ",
6992
7255
  parsed.message,
6993
7256
  parsed.payload ? `: ${parsed.payload}` : ""
@@ -7020,7 +7283,7 @@ Please use command_status to check the result and report back to the user.`;
7020
7283
  return;
7021
7284
  }
7022
7285
  if (pendingConfirmation) {
7023
- return /* @__PURE__ */ jsx16(
7286
+ return /* @__PURE__ */ jsx17(
7024
7287
  ConfirmationPrompt,
7025
7288
  {
7026
7289
  toolCalls: pendingConfirmation,
@@ -7032,9 +7295,9 @@ Please use command_status to check the result and report back to the user.`;
7032
7295
  }
7033
7296
  );
7034
7297
  }
7035
- return /* @__PURE__ */ jsxs15(Box16, { flexDirection: "column", children: [
7036
- isProcessing && !pendingConfirmation && /* @__PURE__ */ jsx16(WorkingTimer, {}),
7037
- /* @__PURE__ */ jsx16(
7298
+ return /* @__PURE__ */ jsxs15(Box17, { flexDirection: "column", children: [
7299
+ isProcessing && !pendingConfirmation && /* @__PURE__ */ jsx17(WorkingTimer, { eventBus: eventBus2 }),
7300
+ /* @__PURE__ */ jsx17(
7038
7301
  InputPrompt,
7039
7302
  {
7040
7303
  onSubmit: handleSubmit,
@@ -7045,12 +7308,29 @@ Please use command_status to check the result and report back to the user.`;
7045
7308
  )
7046
7309
  ] });
7047
7310
  };
7048
- return /* @__PURE__ */ jsxs15(Box16, { flexDirection: "column", children: [
7049
- /* @__PURE__ */ jsx16(Static, { items: history, children: (item) => /* @__PURE__ */ jsx16(Box16, { children: item.component }, item.id) }),
7311
+ return /* @__PURE__ */ jsxs15(Box17, { flexDirection: "column", children: [
7312
+ /* @__PURE__ */ jsx17(Static, { items: history, children: (item) => /* @__PURE__ */ jsx17(Box17, { children: item.component }, item.id) }),
7313
+ /* @__PURE__ */ jsx17(
7314
+ StreamingText,
7315
+ {
7316
+ eventBus: eventBus2,
7317
+ onReasoningComplete: (reasoning) => {
7318
+ if (reasoning) {
7319
+ setHistory((prev) => [
7320
+ ...prev,
7321
+ {
7322
+ id: prev.length,
7323
+ component: /* @__PURE__ */ jsx17(ReasoningDisplay, { reasoning })
7324
+ }
7325
+ ]);
7326
+ }
7327
+ }
7328
+ }
7329
+ ),
7050
7330
  renderInteractiveComponent()
7051
7331
  ] });
7052
7332
  };
7053
- var App = memo10(AppComponent);
7333
+ var App = memo11(AppComponent);
7054
7334
  var App_default = App;
7055
7335
 
7056
7336
  // src/app/ui/utils/terminalTitle.ts
@@ -7117,4 +7397,4 @@ var props = {
7117
7397
  eventBus,
7118
7398
  sessionId
7119
7399
  };
7120
- render(React10.createElement(App_default, props));
7400
+ render(React11.createElement(App_default, props));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nomad-e/bluma-cli",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "BluMa independent agent for automation and advanced software engineering.",
5
5
  "author": "Alex Fonseca",
6
6
  "license": "Apache-2.0",