@nomad-e/bluma-cli 0.1.0 → 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 +542 -170
  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";
@@ -3071,8 +3071,9 @@ async function readArtifact(args) {
3071
3071
  import https from "https";
3072
3072
  import http from "http";
3073
3073
  var DEFAULT_SOURCES = ["reddit", "github", "stackoverflow"];
3074
- var MAX_RESULTS_DEFAULT = 10;
3075
- var REQUEST_TIMEOUT = 1e4;
3074
+ var MAX_RESULTS_DEFAULT = 5;
3075
+ var REQUEST_TIMEOUT = 15e3;
3076
+ var MAX_CONTENT_LENGTH = 4e3;
3076
3077
  function httpGet(url, customHeaders) {
3077
3078
  return new Promise((resolve, reject) => {
3078
3079
  const protocol = url.startsWith("https") ? https : http;
@@ -3081,7 +3082,6 @@ function httpGet(url, customHeaders) {
3081
3082
  "Accept": "application/json, text/html, */*",
3082
3083
  "Accept-Language": "en-US,en;q=0.9",
3083
3084
  "Accept-Encoding": "identity",
3084
- // Não usar gzip para simplificar
3085
3085
  "Cache-Control": "no-cache",
3086
3086
  "Connection": "keep-alive",
3087
3087
  ...customHeaders
@@ -3111,10 +3111,18 @@ function httpGet(url, customHeaders) {
3111
3111
  });
3112
3112
  });
3113
3113
  }
3114
+ function cleanContent(text, maxLength = MAX_CONTENT_LENGTH) {
3115
+ if (!text) return "";
3116
+ let cleaned = text.replace(/```[\s\S]*?```/g, (match) => match.substring(0, 500) + (match.length > 500 ? "\n[...code truncated...]" : "")).replace(/\n{3,}/g, "\n\n").trim();
3117
+ if (cleaned.length > maxLength) {
3118
+ cleaned = cleaned.substring(0, maxLength) + "\n\n[...content truncated...]";
3119
+ }
3120
+ return cleaned;
3121
+ }
3114
3122
  async function searchReddit(query, limit) {
3115
3123
  const results = [];
3116
3124
  try {
3117
- const subreddits = "programming+webdev+javascript+typescript+python+node+reactjs+learnprogramming";
3125
+ const subreddits = "programming+webdev+javascript+typescript+python+node+reactjs+learnprogramming+rust+golang+devops";
3118
3126
  const encodedQuery = encodeURIComponent(query);
3119
3127
  const url = `https://www.reddit.com/r/${subreddits}/search.json?q=${encodedQuery}&sort=relevance&limit=${limit}&restrict_sr=on`;
3120
3128
  const response = await httpGet(url);
@@ -3122,12 +3130,46 @@ async function searchReddit(query, limit) {
3122
3130
  if (data.data?.children) {
3123
3131
  for (const child of data.data.children.slice(0, limit)) {
3124
3132
  const post = child.data;
3133
+ let content = `# ${post.title}
3134
+
3135
+ `;
3136
+ content += `**Subreddit:** r/${post.subreddit} | **Score:** ${post.score} | **Comments:** ${post.num_comments}
3137
+
3138
+ `;
3139
+ if (post.selftext) {
3140
+ content += `## Post Content:
3141
+ ${cleanContent(post.selftext, 2e3)}
3142
+
3143
+ `;
3144
+ }
3145
+ try {
3146
+ const commentsUrl = `https://www.reddit.com${post.permalink}.json?limit=3&depth=1`;
3147
+ const commentsResponse = await httpGet(commentsUrl);
3148
+ const commentsData = JSON.parse(commentsResponse);
3149
+ if (commentsData[1]?.data?.children) {
3150
+ content += `## Top Comments:
3151
+ `;
3152
+ for (const comment of commentsData[1].data.children.slice(0, 3)) {
3153
+ if (comment.data?.body) {
3154
+ content += `
3155
+ **[${comment.data.score || 0} pts]** ${cleanContent(comment.data.body, 500)}
3156
+ `;
3157
+ }
3158
+ }
3159
+ }
3160
+ } catch {
3161
+ }
3125
3162
  results.push({
3126
3163
  title: post.title || "",
3127
3164
  url: `https://reddit.com${post.permalink}`,
3128
3165
  source: "reddit",
3129
- snippet: post.selftext?.substring(0, 200) || `r/${post.subreddit} - ${post.score} upvotes`,
3130
- score: post.score
3166
+ content: cleanContent(content),
3167
+ score: post.score,
3168
+ metadata: {
3169
+ author: post.author,
3170
+ date: new Date(post.created_utc * 1e3).toISOString().split("T")[0],
3171
+ comments_count: post.num_comments
3172
+ }
3131
3173
  });
3132
3174
  }
3133
3175
  }
@@ -3145,12 +3187,35 @@ async function searchGitHub(query, limit) {
3145
3187
  const data = JSON.parse(response);
3146
3188
  if (data.items) {
3147
3189
  for (const item of data.items.slice(0, limit)) {
3190
+ let content = `# ${item.title}
3191
+
3192
+ `;
3193
+ content += `**Repo:** ${item.repository_url?.split("/").slice(-2).join("/") || "unknown"}
3194
+ `;
3195
+ content += `**State:** ${item.state} | **Comments:** ${item.comments} | **Reactions:** ${item.reactions?.total_count || 0}
3196
+
3197
+ `;
3198
+ if (item.body) {
3199
+ content += `## Issue Description:
3200
+ ${cleanContent(item.body, 2500)}
3201
+ `;
3202
+ }
3203
+ if (item.labels?.length > 0) {
3204
+ content += `
3205
+ **Labels:** ${item.labels.map((l) => l.name).join(", ")}
3206
+ `;
3207
+ }
3148
3208
  results.push({
3149
3209
  title: item.title || "",
3150
3210
  url: item.html_url || "",
3151
3211
  source: "github",
3152
- snippet: item.body?.substring(0, 200) || `${item.comments} comments`,
3153
- score: item.reactions?.total_count || 0
3212
+ content: cleanContent(content),
3213
+ score: item.reactions?.total_count || 0,
3214
+ metadata: {
3215
+ author: item.user?.login,
3216
+ date: item.created_at?.split("T")[0],
3217
+ comments_count: item.comments
3218
+ }
3154
3219
  });
3155
3220
  }
3156
3221
  }
@@ -3163,17 +3228,56 @@ async function searchStackOverflow(query, limit) {
3163
3228
  const results = [];
3164
3229
  try {
3165
3230
  const encodedQuery = encodeURIComponent(query);
3166
- const url = `https://api.stackexchange.com/2.3/search?order=desc&sort=relevance&intitle=${encodedQuery}&site=stackoverflow&pagesize=${limit}`;
3231
+ const url = `https://api.stackexchange.com/2.3/search/advanced?order=desc&sort=relevance&q=${encodedQuery}&site=stackoverflow&pagesize=${limit}&filter=withbody`;
3167
3232
  const response = await httpGet(url);
3168
3233
  const data = JSON.parse(response);
3169
3234
  if (data.items) {
3170
3235
  for (const item of data.items.slice(0, limit)) {
3236
+ let content = `# ${item.title}
3237
+
3238
+ `;
3239
+ content += `**Score:** ${item.score} | **Answers:** ${item.answer_count} | **Views:** ${item.view_count}`;
3240
+ content += item.is_answered ? " | \u2705 Answered" : "";
3241
+ content += `
3242
+
3243
+ `;
3244
+ if (item.body) {
3245
+ const cleanBody = item.body.replace(/<code>/g, "`").replace(/<\/code>/g, "`").replace(/<pre>/g, "```\n").replace(/<\/pre>/g, "\n```").replace(/<[^>]+>/g, "").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&amp;/g, "&").replace(/&quot;/g, '"');
3246
+ content += `## Question:
3247
+ ${cleanContent(cleanBody, 1500)}
3248
+
3249
+ `;
3250
+ }
3251
+ if (item.tags?.length > 0) {
3252
+ content += `**Tags:** ${item.tags.join(", ")}
3253
+
3254
+ `;
3255
+ }
3256
+ if (item.accepted_answer_id) {
3257
+ try {
3258
+ const answerUrl = `https://api.stackexchange.com/2.3/answers/${item.accepted_answer_id}?site=stackoverflow&filter=withbody`;
3259
+ const answerResponse = await httpGet(answerUrl);
3260
+ const answerData = JSON.parse(answerResponse);
3261
+ if (answerData.items?.[0]?.body) {
3262
+ const cleanAnswer = answerData.items[0].body.replace(/<code>/g, "`").replace(/<\/code>/g, "`").replace(/<pre>/g, "```\n").replace(/<\/pre>/g, "\n```").replace(/<[^>]+>/g, "").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&amp;/g, "&").replace(/&quot;/g, '"');
3263
+ content += `## \u2705 Accepted Answer (${answerData.items[0].score} pts):
3264
+ ${cleanContent(cleanAnswer, 2e3)}
3265
+ `;
3266
+ }
3267
+ } catch {
3268
+ }
3269
+ }
3171
3270
  results.push({
3172
3271
  title: item.title || "",
3173
3272
  url: item.link || "",
3174
3273
  source: "stackoverflow",
3175
- snippet: `${item.score} votes, ${item.answer_count} answers${item.is_answered ? " \u2713" : ""}`,
3176
- score: item.score
3274
+ content: cleanContent(content),
3275
+ score: item.score,
3276
+ metadata: {
3277
+ author: item.owner?.display_name,
3278
+ date: item.creation_date ? new Date(item.creation_date * 1e3).toISOString().split("T")[0] : void 0,
3279
+ is_answered: item.is_answered
3280
+ }
3177
3281
  });
3178
3282
  }
3179
3283
  }
@@ -3182,15 +3286,6 @@ async function searchStackOverflow(query, limit) {
3182
3286
  }
3183
3287
  return results;
3184
3288
  }
3185
- function getXSearchUrl(query) {
3186
- const encodedQuery = encodeURIComponent(query);
3187
- return {
3188
- title: `Search X for: "${query}"`,
3189
- url: `https://twitter.com/search?q=${encodedQuery}&src=typed_query&f=live`,
3190
- source: "x",
3191
- snippet: "X/Twitter requires authentication. Click the link to search manually."
3192
- };
3193
- }
3194
3289
  async function searchWeb(args) {
3195
3290
  try {
3196
3291
  const {
@@ -3224,9 +3319,6 @@ async function searchWeb(args) {
3224
3319
  case "stackoverflow":
3225
3320
  searches.push(searchStackOverflow(query, resultsPerSource));
3226
3321
  break;
3227
- case "x":
3228
- allResults.push(getXSearchUrl(query));
3229
- break;
3230
3322
  }
3231
3323
  }
3232
3324
  const searchResults = await Promise.all(searches);
@@ -3240,8 +3332,7 @@ async function searchWeb(args) {
3240
3332
  query,
3241
3333
  results: limitedResults,
3242
3334
  sources_searched: sourcesSearched,
3243
- total_results: limitedResults.length,
3244
- note: sources.includes("x") ? "X/Twitter requires manual search due to API restrictions" : void 0
3335
+ total_results: limitedResults.length
3245
3336
  };
3246
3337
  } catch (error) {
3247
3338
  return {
@@ -3283,9 +3374,17 @@ async function loadSkill(args) {
3283
3374
  message: `Skill "${skill_name}" not found. Available skills: ${availableNames}`
3284
3375
  };
3285
3376
  }
3377
+ if (globalContext.history) {
3378
+ globalContext.history.push({
3379
+ role: "user",
3380
+ content: `[SKILL:${skill.name}]
3381
+
3382
+ ${skill.content}`
3383
+ });
3384
+ }
3286
3385
  return {
3287
3386
  success: true,
3288
- message: `Skill "${skill_name}" loaded.`,
3387
+ message: `Skill "${skill_name}" loaded successfully. Follow the instructions in the skill content above.`,
3289
3388
  skill_name: skill.name,
3290
3389
  description: skill.description
3291
3390
  };
@@ -3732,7 +3831,13 @@ async function doSaveSessionHistory(sessionFile, history) {
3732
3831
  });
3733
3832
  }
3734
3833
  async function saveSessionHistory(sessionFile, history) {
3735
- 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);
3736
3841
  }
3737
3842
 
3738
3843
  // src/app/agent/core/prompt/prompt_builder.ts
@@ -4644,8 +4749,8 @@ var ToolCallNormalizer = class {
4644
4749
  */
4645
4750
  static extractFromContent(content) {
4646
4751
  const results = [];
4647
- const cleanContent = content.replace(/```(?:json)?\s*([\s\S]*?)```/g, "$1");
4648
- const jsonMatches = this.extractJsonObjects(cleanContent);
4752
+ const cleanContent2 = content.replace(/```(?:json)?\s*([\s\S]*?)```/g, "$1");
4753
+ const jsonMatches = this.extractJsonObjects(cleanContent2);
4649
4754
  for (const jsonStr of jsonMatches) {
4650
4755
  try {
4651
4756
  const parsed = JSON.parse(jsonStr);
@@ -4849,6 +4954,19 @@ var BluMaAgent = class {
4849
4954
  this.eventBus.emit("backend_message", { type: "info", message: "Agent task cancelled before tool execution." });
4850
4955
  return;
4851
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 });
4852
4970
  const result = await this.mcpClient.invoke(toolName, toolArgs);
4853
4971
  let finalResult = result;
4854
4972
  if (Array.isArray(result) && result.length > 0 && result[0].type === "text" && typeof result[0].text === "string") {
@@ -4915,81 +5033,200 @@ ${editData.error.display}`;
4915
5033
  return;
4916
5034
  }
4917
5035
  const contextWindow = createApiContextWindow(this.history, this.maxContextTurns);
4918
- const response = await this.llm.chatCompletion({
4919
- model: "x-ai/grok-code-fast-1",
4920
- // model: "openrouter/polaris-alpha", //OpenRouter Openai training model
4921
- messages: contextWindow,
4922
- temperature: 0.3,
4923
- tools: this.mcpClient.getAvailableTools(),
4924
- tool_choice: "required",
4925
- parallel_tool_calls: false
4926
- });
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) {
4927
5065
  if (this.isInterrupted) {
5066
+ this.eventBus.emit("stream_end", {});
4928
5067
  this.eventBus.emit("backend_message", { type: "info", message: "Agent task cancelled by user." });
4929
5068
  return;
4930
5069
  }
4931
- let message2 = response.choices[0].message;
4932
- message2 = ToolCallNormalizer.normalizeAssistantMessage(message2);
4933
- if (message2.reasoning_content || message2.reasoning) {
4934
- 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) {
4935
5116
  this.eventBus.emit("backend_message", {
4936
- type: "reasoning",
4937
- content: typeof reasoningText === "string" ? reasoningText : JSON.stringify(reasoningText)
5117
+ type: "error",
5118
+ message: "Model returned invalid tool calls. Retrying..."
4938
5119
  });
5120
+ await this._continueConversation();
5121
+ return;
4939
5122
  }
4940
- this.history.push(message2);
4941
- if (message2.tool_calls && message2.tool_calls.length > 0) {
4942
- const validToolCalls = message2.tool_calls.filter(
4943
- (call) => ToolCallNormalizer.isValidToolCall(call)
4944
- );
4945
- if (validToolCalls.length === 0) {
4946
- this.eventBus.emit("backend_message", {
4947
- type: "error",
4948
- message: "Model returned invalid tool calls. Retrying..."
4949
- });
4950
- await this._continueConversation();
4951
- return;
4952
- }
4953
- const autoApprovedTools = [
4954
- "message",
4955
- "ls_tool",
4956
- "count_file_lines",
4957
- "read_file_lines",
4958
- "todo",
4959
- "load_skill"
4960
- ];
4961
- const toolToCall = validToolCalls[0];
4962
- const isSafeTool = autoApprovedTools.some((safeTool) => toolToCall.function.name.includes(safeTool));
4963
- if (isSafeTool) {
4964
- 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 });
4965
5142
  } else {
4966
- const toolName = toolToCall.function.name;
4967
- if (toolName === "edit_tool") {
4968
- const args = JSON.parse(toolToCall.function.arguments);
4969
- const previewContent = await this._generateEditPreview(args);
4970
- this.eventBus.emit("backend_message", { type: "confirmation_request", tool_calls: validToolCalls, preview: previewContent });
4971
- } else {
4972
- this.eventBus.emit("backend_message", { type: "confirmation_request", tool_calls: validToolCalls });
4973
- }
5143
+ this.eventBus.emit("backend_message", { type: "confirmation_request", tool_calls: validToolCalls });
4974
5144
  }
4975
- } else if (message2.content) {
4976
- this.eventBus.emit("backend_message", { type: "assistant_message", content: message2.content });
4977
- const feedback = this.feedbackSystem.generateFeedback({
4978
- event: "protocol_violation_direct_text",
4979
- 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..."
4980
5191
  });
4981
- this.eventBus.emit("backend_message", { type: "protocol_violation", message: feedback.message, content: message2.content });
4982
- this.history.push({ role: "system", content: feedback.correction });
4983
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 });
4984
5208
  } else {
4985
- this.eventBus.emit("backend_message", { type: "info", message: "Agent is thinking... continuing reasoning cycle." });
4986
- 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
+ }
4987
5217
  }
4988
- } catch (error) {
4989
- const errorMessage = error instanceof Error ? error.message : "An unknown API error occurred.";
4990
- this.eventBus.emit("backend_message", { type: "error", message: errorMessage });
4991
- } finally {
4992
- 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();
4993
5230
  }
4994
5231
  }
4995
5232
  };
@@ -5006,6 +5243,9 @@ var LLMService = class {
5006
5243
  });
5007
5244
  this.defaultModel = config2.model || "";
5008
5245
  }
5246
+ /**
5247
+ * Chamada tradicional (não-streaming) - retorna resposta completa
5248
+ */
5009
5249
  async chatCompletion(params) {
5010
5250
  const resp = await this.client.chat.completions.create({
5011
5251
  model: params.model || this.defaultModel,
@@ -5018,6 +5258,64 @@ var LLMService = class {
5018
5258
  });
5019
5259
  return resp;
5020
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
+ }
5021
5319
  /**
5022
5320
  * Retorna o modelo padrão configurado
5023
5321
  */
@@ -5599,41 +5897,52 @@ var Agent = class {
5599
5897
  import { useState as useState4, useEffect as useEffect4, memo as memo5 } from "react";
5600
5898
  import { Box as Box7, Text as Text7 } from "ink";
5601
5899
  import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
5602
- var WorkingTimerComponent = ({ taskName, taskStatus }) => {
5603
- const [seconds, setSeconds] = useState4(0);
5604
- 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("");
5605
5904
  useEffect4(() => {
5606
- const timer = setInterval(() => {
5607
- setSeconds((prev) => prev + 1);
5608
- }, 1e3);
5609
- return () => clearInterval(timer);
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]);
5916
+ useEffect4(() => {
5917
+ const shineTimer = setInterval(() => {
5918
+ setShinePosition((prev) => (prev + 1) % 30);
5919
+ }, 75);
5920
+ return () => clearInterval(shineTimer);
5610
5921
  }, []);
5611
5922
  useEffect4(() => {
5612
- const animator = setInterval(() => {
5613
- setFrame((prev) => (prev + 1) % 4);
5614
- }, 150);
5615
- return () => clearInterval(animator);
5923
+ const dotsTimer = setInterval(() => {
5924
+ setDots((prev) => prev.length >= 3 ? "" : prev + ".");
5925
+ }, 500);
5926
+ return () => clearInterval(dotsTimer);
5616
5927
  }, []);
5617
- const spinners = ["|", "/", "-", "\\"];
5618
- const spinner = spinners[frame];
5619
- const formatTime = (s) => {
5620
- if (s < 60) return `${s}s`;
5621
- 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
+ });
5622
5941
  };
5623
5942
  return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", paddingX: 1, children: [
5624
- /* @__PURE__ */ jsxs7(Box7, { children: [
5625
- /* @__PURE__ */ jsx7(Text7, { color: "cyan", children: spinner }),
5626
- /* @__PURE__ */ jsxs7(Text7, { dimColor: true, children: [
5627
- " ",
5628
- taskStatus || "thinking"
5629
- ] }),
5630
- /* @__PURE__ */ jsxs7(Text7, { color: "gray", children: [
5631
- " ",
5632
- formatTime(seconds)
5633
- ] })
5634
- ] }),
5943
+ /* @__PURE__ */ jsx7(Box7, { children: renderShineText(displayAction) }),
5635
5944
  taskName && /* @__PURE__ */ jsx7(Box7, { paddingLeft: 2, children: /* @__PURE__ */ jsxs7(Text7, { dimColor: true, children: [
5636
- "^ ",
5945
+ "\u203A ",
5637
5946
  taskName
5638
5947
  ] }) })
5639
5948
  ] });
@@ -6566,14 +6875,60 @@ var ReasoningDisplayComponent = ({
6566
6875
  const lines = reasoning.split("\n");
6567
6876
  const displayText = isExpanded ? reasoning : lines.slice(0, maxLines).join("\n") + (lines.length > maxLines ? "..." : "");
6568
6877
  return /* @__PURE__ */ jsxs14(Box15, { flexDirection: "column", paddingX: 1, marginBottom: 1, marginTop: 1, children: [
6569
- /* @__PURE__ */ jsx15(Box15, { children: /* @__PURE__ */ jsx15(Text14, { color: "white", bold: true, children: "Thinking" }) }),
6878
+ /* @__PURE__ */ jsx15(Box15, {}),
6570
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)) })
6571
6880
  ] });
6572
6881
  };
6573
6882
  var ReasoningDisplay = memo9(ReasoningDisplayComponent);
6574
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
+
6575
6930
  // src/app/ui/App.tsx
6576
- import { jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
6931
+ import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
6577
6932
  var SAFE_AUTO_APPROVE_TOOLS = [
6578
6933
  // Comunicação/UI
6579
6934
  "message",
@@ -6591,28 +6946,28 @@ var SAFE_AUTO_APPROVE_TOOLS = [
6591
6946
  "command_status"
6592
6947
  ];
6593
6948
  var AppComponent = ({ eventBus: eventBus2, sessionId: sessionId2 }) => {
6594
- const agentInstance = useRef4(null);
6595
- const [history, setHistory] = useState6([]);
6596
- const [statusMessage, setStatusMessage] = useState6(
6949
+ const agentInstance = useRef5(null);
6950
+ const [history, setHistory] = useState7([]);
6951
+ const [statusMessage, setStatusMessage] = useState7(
6597
6952
  "Initializing agent..."
6598
6953
  );
6599
- const [toolsCount, setToolsCount] = useState6(null);
6600
- const [mcpStatus, setMcpStatus] = useState6(
6954
+ const [toolsCount, setToolsCount] = useState7(null);
6955
+ const [mcpStatus, setMcpStatus] = useState7(
6601
6956
  "connecting"
6602
6957
  );
6603
- const [isProcessing, setIsProcessing] = useState6(true);
6604
- const [pendingConfirmation, setPendingConfirmation] = useState6(
6958
+ const [isProcessing, setIsProcessing] = useState7(true);
6959
+ const [pendingConfirmation, setPendingConfirmation] = useState7(
6605
6960
  null
6606
6961
  );
6607
- const [confirmationPreview, setConfirmationPreview] = useState6(
6962
+ const [confirmationPreview, setConfirmationPreview] = useState7(
6608
6963
  null
6609
6964
  );
6610
- const [isInitAgentActive, setIsInitAgentActive] = useState6(false);
6611
- const alwaysAcceptList = useRef4([]);
6965
+ const [isInitAgentActive, setIsInitAgentActive] = useState7(false);
6966
+ const alwaysAcceptList = useRef5([]);
6612
6967
  const workdir = process.cwd();
6613
- const updateCheckRan = useRef4(false);
6614
- const sessionStartTime = useRef4(Date.now());
6615
- const [toolCallCount, setToolCallCount] = useState6(0);
6968
+ const updateCheckRan = useRef5(false);
6969
+ const sessionStartTime = useRef5(Date.now());
6970
+ const [toolCallCount, setToolCallCount] = useState7(0);
6616
6971
  const handleInterrupt = useCallback2(() => {
6617
6972
  if (!isProcessing) return;
6618
6973
  eventBus2.emit("user_interrupt");
@@ -6621,7 +6976,7 @@ var AppComponent = ({ eventBus: eventBus2, sessionId: sessionId2 }) => {
6621
6976
  ...prev,
6622
6977
  {
6623
6978
  id: prev.length,
6624
- component: /* @__PURE__ */ jsx16(Text15, { color: "yellow", children: "-- Task cancelled by dev. --" })
6979
+ component: /* @__PURE__ */ jsx17(Text16, { color: "yellow", children: "-- Task cancelled by dev. --" })
6625
6980
  }
6626
6981
  ]);
6627
6982
  }, [isProcessing, eventBus2]);
@@ -6645,11 +7000,11 @@ var AppComponent = ({ eventBus: eventBus2, sessionId: sessionId2 }) => {
6645
7000
  ...prev,
6646
7001
  {
6647
7002
  id: prev.length,
6648
- 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 }) })
6649
7004
  },
6650
7005
  {
6651
7006
  id: prev.length + 1,
6652
- component: /* @__PURE__ */ jsx16(
7007
+ component: /* @__PURE__ */ jsx17(
6653
7008
  SlashCommands_default,
6654
7009
  {
6655
7010
  input: text,
@@ -6671,9 +7026,9 @@ var AppComponent = ({ eventBus: eventBus2, sessionId: sessionId2 }) => {
6671
7026
  ...prev,
6672
7027
  {
6673
7028
  id: prev.length,
6674
- component: /* @__PURE__ */ jsxs15(Box16, { marginBottom: 1, children: [
6675
- /* @__PURE__ */ jsx16(Text15, { color: "white", bold: true, children: "$ " }),
6676
- /* @__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 })
6677
7032
  ] })
6678
7033
  }
6679
7034
  ]);
@@ -6692,7 +7047,7 @@ Please use command_status to check the result and report back to the user.`;
6692
7047
  ...prev,
6693
7048
  {
6694
7049
  id: prev.length,
6695
- component: /* @__PURE__ */ jsxs15(Text15, { color: "red", children: [
7050
+ component: /* @__PURE__ */ jsxs15(Text16, { color: "red", children: [
6696
7051
  "Failed to execute: ",
6697
7052
  result.error || result.message
6698
7053
  ] })
@@ -6705,7 +7060,7 @@ Please use command_status to check the result and report back to the user.`;
6705
7060
  ...prev,
6706
7061
  {
6707
7062
  id: prev.length,
6708
- component: /* @__PURE__ */ jsxs15(Text15, { color: "red", children: [
7063
+ component: /* @__PURE__ */ jsxs15(Text16, { color: "red", children: [
6709
7064
  "Error: ",
6710
7065
  err.message
6711
7066
  ] })
@@ -6724,8 +7079,8 @@ Please use command_status to check the result and report back to the user.`;
6724
7079
  id: prev.length,
6725
7080
  component: (
6726
7081
  // Uma única Box para o espaçamento
6727
- /* @__PURE__ */ jsx16(Box16, { marginBottom: 1, children: /* @__PURE__ */ jsxs15(Text15, { color: "white", dimColor: true, children: [
6728
- /* @__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: [
6729
7084
  ">",
6730
7085
  " "
6731
7086
  ] }),
@@ -6759,8 +7114,8 @@ Please use command_status to check the result and report back to the user.`;
6759
7114
  },
6760
7115
  []
6761
7116
  );
6762
- useEffect5(() => {
6763
- setHistory([{ id: 0, component: /* @__PURE__ */ jsx16(Header, { sessionId: sessionId2, workdir }) }]);
7117
+ useEffect6(() => {
7118
+ setHistory([{ id: 0, component: /* @__PURE__ */ jsx17(Header, { sessionId: sessionId2, workdir }) }]);
6764
7119
  const initializeAgent = async () => {
6765
7120
  try {
6766
7121
  agentInstance.current = new Agent(sessionId2, eventBus2);
@@ -6826,7 +7181,7 @@ Please use command_status to check the result and report back to the user.`;
6826
7181
  ...prev,
6827
7182
  {
6828
7183
  id: prev.length,
6829
- component: /* @__PURE__ */ jsx16(UpdateNotice_default, { message: msg })
7184
+ component: /* @__PURE__ */ jsx17(UpdateNotice_default, { message: msg })
6830
7185
  }
6831
7186
  ]);
6832
7187
  }
@@ -6840,10 +7195,10 @@ Please use command_status to check the result and report back to the user.`;
6840
7195
  }
6841
7196
  let newComponent = null;
6842
7197
  if (parsed.type === "debug") {
6843
- newComponent = /* @__PURE__ */ jsx16(Text15, { color: "gray", children: parsed.message });
7198
+ newComponent = /* @__PURE__ */ jsx17(Text16, { color: "gray", children: parsed.message });
6844
7199
  } else if (parsed.type === "protocol_violation") {
6845
7200
  newComponent = /* @__PURE__ */ jsxs15(
6846
- Box16,
7201
+ Box17,
6847
7202
  {
6848
7203
  borderStyle: "round",
6849
7204
  borderColor: "yellow",
@@ -6851,14 +7206,14 @@ Please use command_status to check the result and report back to the user.`;
6851
7206
  marginBottom: 1,
6852
7207
  paddingX: 1,
6853
7208
  children: [
6854
- /* @__PURE__ */ jsx16(Text15, { color: "yellow", bold: true, children: "Protocol Violation" }),
6855
- /* @__PURE__ */ jsx16(Text15, { color: "gray", children: parsed.content }),
6856
- /* @__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 })
6857
7212
  ]
6858
7213
  }
6859
7214
  );
6860
7215
  } else if (parsed.type === "error") {
6861
- newComponent = /* @__PURE__ */ jsx16(
7216
+ newComponent = /* @__PURE__ */ jsx17(
6862
7217
  ErrorMessage_default,
6863
7218
  {
6864
7219
  message: parsed.message,
@@ -6868,7 +7223,7 @@ Please use command_status to check the result and report back to the user.`;
6868
7223
  );
6869
7224
  } else if (parsed.type === "tool_call") {
6870
7225
  const nextId2 = history.length;
6871
- newComponent = /* @__PURE__ */ jsx16(
7226
+ newComponent = /* @__PURE__ */ jsx17(
6872
7227
  ToolCallDisplay,
6873
7228
  {
6874
7229
  toolName: parsed.tool_name,
@@ -6877,7 +7232,7 @@ Please use command_status to check the result and report back to the user.`;
6877
7232
  }
6878
7233
  );
6879
7234
  } else if (parsed.type === "tool_result") {
6880
- newComponent = /* @__PURE__ */ jsx16(
7235
+ newComponent = /* @__PURE__ */ jsx17(
6881
7236
  ToolResultDisplay,
6882
7237
  {
6883
7238
  toolName: parsed.tool_name,
@@ -6885,17 +7240,17 @@ Please use command_status to check the result and report back to the user.`;
6885
7240
  }
6886
7241
  );
6887
7242
  } else if (parsed.type === "user_overlay") {
6888
- newComponent = /* @__PURE__ */ jsx16(Box16, { marginBottom: 1, children: /* @__PURE__ */ jsxs15(Text15, { color: "gray", children: [
6889
- /* @__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: [
6890
7245
  ">",
6891
7246
  " "
6892
7247
  ] }),
6893
7248
  parsed.payload
6894
7249
  ] }) });
6895
7250
  } else if (parsed.type === "reasoning") {
6896
- newComponent = /* @__PURE__ */ jsx16(ReasoningDisplay, { reasoning: parsed.content });
7251
+ newComponent = /* @__PURE__ */ jsx17(ReasoningDisplay, { reasoning: parsed.content });
6897
7252
  } else if (parsed.type === "log") {
6898
- newComponent = /* @__PURE__ */ jsxs15(Text15, { color: "gray", children: [
7253
+ newComponent = /* @__PURE__ */ jsxs15(Text16, { color: "gray", children: [
6899
7254
  "\u2139\uFE0F ",
6900
7255
  parsed.message,
6901
7256
  parsed.payload ? `: ${parsed.payload}` : ""
@@ -6928,7 +7283,7 @@ Please use command_status to check the result and report back to the user.`;
6928
7283
  return;
6929
7284
  }
6930
7285
  if (pendingConfirmation) {
6931
- return /* @__PURE__ */ jsx16(
7286
+ return /* @__PURE__ */ jsx17(
6932
7287
  ConfirmationPrompt,
6933
7288
  {
6934
7289
  toolCalls: pendingConfirmation,
@@ -6940,9 +7295,9 @@ Please use command_status to check the result and report back to the user.`;
6940
7295
  }
6941
7296
  );
6942
7297
  }
6943
- return /* @__PURE__ */ jsxs15(Box16, { flexDirection: "column", children: [
6944
- isProcessing && !pendingConfirmation && /* @__PURE__ */ jsx16(WorkingTimer, {}),
6945
- /* @__PURE__ */ jsx16(
7298
+ return /* @__PURE__ */ jsxs15(Box17, { flexDirection: "column", children: [
7299
+ isProcessing && !pendingConfirmation && /* @__PURE__ */ jsx17(WorkingTimer, { eventBus: eventBus2 }),
7300
+ /* @__PURE__ */ jsx17(
6946
7301
  InputPrompt,
6947
7302
  {
6948
7303
  onSubmit: handleSubmit,
@@ -6953,12 +7308,29 @@ Please use command_status to check the result and report back to the user.`;
6953
7308
  )
6954
7309
  ] });
6955
7310
  };
6956
- return /* @__PURE__ */ jsxs15(Box16, { flexDirection: "column", children: [
6957
- /* @__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
+ ),
6958
7330
  renderInteractiveComponent()
6959
7331
  ] });
6960
7332
  };
6961
- var App = memo10(AppComponent);
7333
+ var App = memo11(AppComponent);
6962
7334
  var App_default = App;
6963
7335
 
6964
7336
  // src/app/ui/utils/terminalTitle.ts
@@ -7025,4 +7397,4 @@ var props = {
7025
7397
  eventBus,
7026
7398
  sessionId
7027
7399
  };
7028
- 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.0",
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",