@nomad-e/bluma-cli 0.1.13 → 0.1.16
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 +160 -0
- package/dist/config/models_config.json +78 -0
- package/dist/config/native_tools.json +33 -0
- package/dist/main.js +327 -85
- package/dist/skills/git-conventional/LICENSE.txt +3 -0
- package/dist/skills/git-conventional/SKILL.md +83 -0
- package/dist/skills/skill-creator/SKILL.md +495 -0
- package/dist/skills/testing/LICENSE.txt +3 -0
- package/dist/skills/testing/SKILL.md +114 -0
- package/package.json +2 -2
package/dist/main.js
CHANGED
|
@@ -331,6 +331,7 @@ var init_async_command = __esm({
|
|
|
331
331
|
import React11 from "react";
|
|
332
332
|
import { render } from "ink";
|
|
333
333
|
import { EventEmitter as EventEmitter2 } from "events";
|
|
334
|
+
import fs14 from "fs";
|
|
334
335
|
import { v4 as uuidv43 } from "uuid";
|
|
335
336
|
|
|
336
337
|
// src/app/ui/App.tsx
|
|
@@ -342,7 +343,7 @@ import { Box, Text } from "ink";
|
|
|
342
343
|
import { memo } from "react";
|
|
343
344
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
344
345
|
var HeaderComponent = ({
|
|
345
|
-
sessionId
|
|
346
|
+
sessionId,
|
|
346
347
|
workdir
|
|
347
348
|
}) => {
|
|
348
349
|
const dirName = workdir.split("/").pop() || workdir;
|
|
@@ -353,13 +354,13 @@ var HeaderComponent = ({
|
|
|
353
354
|
/* @__PURE__ */ jsx(Text, { color: "cyan", children: dirName }),
|
|
354
355
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " | " }),
|
|
355
356
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "session " }),
|
|
356
|
-
/* @__PURE__ */ jsx(Text, { color: "gray", children:
|
|
357
|
+
/* @__PURE__ */ jsx(Text, { color: "gray", children: sessionId.slice(0, 8) })
|
|
357
358
|
] })
|
|
358
359
|
] });
|
|
359
360
|
};
|
|
360
361
|
var Header = memo(HeaderComponent);
|
|
361
362
|
var SessionInfoComponent = ({
|
|
362
|
-
sessionId
|
|
363
|
+
sessionId,
|
|
363
364
|
workdir,
|
|
364
365
|
toolsCount,
|
|
365
366
|
mcpStatus
|
|
@@ -2934,8 +2935,8 @@ async function getArtifactsDir() {
|
|
|
2934
2935
|
if (artifactsDir) return artifactsDir;
|
|
2935
2936
|
const homeDir = os3.homedir();
|
|
2936
2937
|
const baseDir = path9.join(homeDir, ".bluma", "artifacts");
|
|
2937
|
-
const
|
|
2938
|
-
artifactsDir = path9.join(baseDir,
|
|
2938
|
+
const sessionId = Date.now().toString(36) + Math.random().toString(36).substr(2, 5);
|
|
2939
|
+
artifactsDir = path9.join(baseDir, sessionId);
|
|
2939
2940
|
await fs7.mkdir(artifactsDir, { recursive: true });
|
|
2940
2941
|
return artifactsDir;
|
|
2941
2942
|
}
|
|
@@ -3482,9 +3483,9 @@ var MCPClient = class {
|
|
|
3482
3483
|
nativeToolInvoker;
|
|
3483
3484
|
eventBus;
|
|
3484
3485
|
// <<< ADICIONA A PROPRIEDADE
|
|
3485
|
-
constructor(nativeToolInvoker,
|
|
3486
|
+
constructor(nativeToolInvoker, eventBus) {
|
|
3486
3487
|
this.nativeToolInvoker = nativeToolInvoker;
|
|
3487
|
-
this.eventBus =
|
|
3488
|
+
this.eventBus = eventBus;
|
|
3488
3489
|
}
|
|
3489
3490
|
// ... (método initialize inalterado) ...
|
|
3490
3491
|
async initialize() {
|
|
@@ -3762,9 +3763,9 @@ async function ensureSessionDir() {
|
|
|
3762
3763
|
await fs10.mkdir(sessionDir, { recursive: true });
|
|
3763
3764
|
return sessionDir;
|
|
3764
3765
|
}
|
|
3765
|
-
async function loadOrcreateSession(
|
|
3766
|
+
async function loadOrcreateSession(sessionId) {
|
|
3766
3767
|
const sessionDir = await ensureSessionDir();
|
|
3767
|
-
const sessionFile = path12.join(sessionDir, `${
|
|
3768
|
+
const sessionFile = path12.join(sessionDir, `${sessionId}.json`);
|
|
3768
3769
|
try {
|
|
3769
3770
|
await fs10.access(sessionFile);
|
|
3770
3771
|
const fileContent = await fs10.readFile(sessionFile, "utf-8");
|
|
@@ -3772,7 +3773,7 @@ async function loadOrcreateSession(sessionId2) {
|
|
|
3772
3773
|
return [sessionFile, [], []];
|
|
3773
3774
|
} catch (error) {
|
|
3774
3775
|
const newSessionData = {
|
|
3775
|
-
session_id:
|
|
3776
|
+
session_id: sessionId,
|
|
3776
3777
|
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3777
3778
|
conversation_history: []
|
|
3778
3779
|
};
|
|
@@ -3800,9 +3801,9 @@ async function doSaveSessionHistory(sessionFile, history) {
|
|
|
3800
3801
|
console.warn(`An unknown error occurred while reading ${sessionFile}. Re-initializing.`, error);
|
|
3801
3802
|
}
|
|
3802
3803
|
}
|
|
3803
|
-
const
|
|
3804
|
+
const sessionId = path12.basename(sessionFile, ".json");
|
|
3804
3805
|
sessionData = {
|
|
3805
|
-
session_id:
|
|
3806
|
+
session_id: sessionId,
|
|
3806
3807
|
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3807
3808
|
conversation_history: []
|
|
3808
3809
|
};
|
|
@@ -4414,6 +4415,59 @@ You communicate because you respect your teammate.
|
|
|
4414
4415
|
Let's build something great, {username}.
|
|
4415
4416
|
</personality>
|
|
4416
4417
|
`;
|
|
4418
|
+
var SANDBOX_PROMPT_SUFFIX = `
|
|
4419
|
+
|
|
4420
|
+
---
|
|
4421
|
+
|
|
4422
|
+
<sandbox_context>
|
|
4423
|
+
## Sandbox Context
|
|
4424
|
+
|
|
4425
|
+
Sandbox Name: {sandbox_name}
|
|
4426
|
+
|
|
4427
|
+
You are running INSIDE an orchestrated sandbox / API container.
|
|
4428
|
+
|
|
4429
|
+
In this mode:
|
|
4430
|
+
|
|
4431
|
+
- You are NOT talking directly to a human; all inputs come from JSON payloads provided by an orchestrator (the Sandbox API).
|
|
4432
|
+
- You MUST avoid interactive flows (no REPL, no prompts that wait for human input, no TUI/CLI menus).
|
|
4433
|
+
- You MUST keep all outputs deterministic, concise and structured so that external systems can log and replay your reasoning.
|
|
4434
|
+
|
|
4435
|
+
### Execution Capabilities (Python-only)
|
|
4436
|
+
|
|
4437
|
+
- You are allowed to:
|
|
4438
|
+
- Generate and modify **Python code** (modules, scripts, notebooks, tests).
|
|
4439
|
+
- Propose and run **Python commands only**, e.g.:
|
|
4440
|
+
- \`python main.py\`
|
|
4441
|
+
- \`python -m pytest\`
|
|
4442
|
+
- Use the existing Python environment and preinstalled libraries inside the sandbox (e.g. pandas and other whitelisted packages).
|
|
4443
|
+
|
|
4444
|
+
- You are NOT allowed to:
|
|
4445
|
+
- Execute arbitrary shell commands (\`bash\`, \`sh\`, \`zsh\`, \`fish\`, \`cmd\`, \`powershell\`).
|
|
4446
|
+
- Run system-level tools (\`docker\`, \`npm\`, \`node\`, \`git\`, \`curl\`, \`wget\`, package managers, etc.).
|
|
4447
|
+
- Change global system configuration, users, permissions, or network settings.
|
|
4448
|
+
- Depend on interactive stdin/stdout behavior (no \`input()\`, no click/typer prompts).
|
|
4449
|
+
|
|
4450
|
+
### Filesystem & IO
|
|
4451
|
+
|
|
4452
|
+
- Assume you are working in a **project directory managed by the orchestrator**.
|
|
4453
|
+
- You MAY:
|
|
4454
|
+
- Read and write project files (source, tests, configs) as requested by the job.
|
|
4455
|
+
- Create temporary Python files or modules needed to execute the job.
|
|
4456
|
+
- You MUST NOT:
|
|
4457
|
+
- Access files outside the project directory tree.
|
|
4458
|
+
- Store secrets or credentials in code or logs.
|
|
4459
|
+
- Rely on long-lived state: each job is independent and may run in a fresh environment.
|
|
4460
|
+
|
|
4461
|
+
### Logging & Observability
|
|
4462
|
+
|
|
4463
|
+
- Treat every step as being logged and parsed by the orchestrator.
|
|
4464
|
+
- Prefer **structured, step-wise logs** (JSON lines) over free-form prose when emitting tool logs:
|
|
4465
|
+
- Each log entry SHOULD include at least: \`event_type\`, \`level\`, \`message\`, \`timestamp\`, and optional \`data\`.
|
|
4466
|
+
- Final results MUST be clearly separated from intermediate logs, using a dedicated \`"result"\` event when appropriate.
|
|
4467
|
+
|
|
4468
|
+
In summary: in sandbox mode you are a Python-focused, non-interactive, deterministic agent. You generate and execute Python code inside a controlled environment, and all interactions are mediated by JSON payloads and structured logs.
|
|
4469
|
+
</sandbox_context>
|
|
4470
|
+
`;
|
|
4417
4471
|
function getUnifiedSystemPrompt(availableSkills) {
|
|
4418
4472
|
const cwd = process.cwd();
|
|
4419
4473
|
const env = {
|
|
@@ -4432,11 +4486,14 @@ function getUnifiedSystemPrompt(availableSkills) {
|
|
|
4432
4486
|
package_manager: getPackageManager(cwd),
|
|
4433
4487
|
project_type: getProjectType(cwd),
|
|
4434
4488
|
test_framework: getTestFramework(cwd),
|
|
4435
|
-
test_command: getTestCommand(cwd)
|
|
4489
|
+
test_command: getTestCommand(cwd),
|
|
4490
|
+
sandbox_mode: process.env.BLUMA_SANDBOX === "true" ? "yes" : "no",
|
|
4491
|
+
sandbox_name: process.env.BLUMA_SANDBOX_NAME || "local"
|
|
4436
4492
|
};
|
|
4493
|
+
const basePrompt = env.sandbox_mode === "yes" ? SYSTEM_PROMPT + SANDBOX_PROMPT_SUFFIX : SYSTEM_PROMPT;
|
|
4437
4494
|
let prompt = Object.entries(env).reduce(
|
|
4438
4495
|
(p, [key, value]) => p.replaceAll(`{${key}}`, value),
|
|
4439
|
-
|
|
4496
|
+
basePrompt
|
|
4440
4497
|
);
|
|
4441
4498
|
if (availableSkills && availableSkills.length > 0) {
|
|
4442
4499
|
const skillsList = availableSkills.map((s) => `- ${s.name}: ${s.description}`).join("\n");
|
|
@@ -4825,9 +4882,9 @@ var BluMaAgent = class {
|
|
|
4825
4882
|
skillLoader;
|
|
4826
4883
|
maxContextTurns = 5;
|
|
4827
4884
|
isInterrupted = false;
|
|
4828
|
-
constructor(
|
|
4829
|
-
this.sessionId =
|
|
4830
|
-
this.eventBus =
|
|
4885
|
+
constructor(sessionId, eventBus, llm, model, mcpClient, feedbackSystem) {
|
|
4886
|
+
this.sessionId = sessionId;
|
|
4887
|
+
this.eventBus = eventBus;
|
|
4831
4888
|
this.llm = llm;
|
|
4832
4889
|
this.model = model;
|
|
4833
4890
|
this.mcpClient = mcpClient;
|
|
@@ -5068,7 +5125,7 @@ ${editData.error.display}`;
|
|
|
5068
5125
|
messages: contextWindow,
|
|
5069
5126
|
temperature: 0,
|
|
5070
5127
|
tools: this.mcpClient.getAvailableTools(),
|
|
5071
|
-
tool_choice:
|
|
5128
|
+
//tool_choice: 'required',
|
|
5072
5129
|
parallel_tool_calls: false
|
|
5073
5130
|
});
|
|
5074
5131
|
for await (const chunk of stream) {
|
|
@@ -5130,6 +5187,7 @@ ${editData.error.display}`;
|
|
|
5130
5187
|
await this._continueConversation();
|
|
5131
5188
|
return;
|
|
5132
5189
|
}
|
|
5190
|
+
const isSandbox = process.env.BLUMA_SANDBOX === "true";
|
|
5133
5191
|
const autoApprovedTools = [
|
|
5134
5192
|
"message",
|
|
5135
5193
|
"ls_tool",
|
|
@@ -5137,10 +5195,11 @@ ${editData.error.display}`;
|
|
|
5137
5195
|
"read_file_lines",
|
|
5138
5196
|
"todo",
|
|
5139
5197
|
"load_skill",
|
|
5140
|
-
"search_web"
|
|
5198
|
+
"search_web",
|
|
5199
|
+
"coding_memory"
|
|
5141
5200
|
];
|
|
5142
5201
|
const toolToCall = validToolCalls[0];
|
|
5143
|
-
const isSafeTool = autoApprovedTools.some((safeTool) => toolToCall.function.name.includes(safeTool));
|
|
5202
|
+
const isSafeTool = isSandbox || autoApprovedTools.some((safeTool) => toolToCall.function.name.includes(safeTool));
|
|
5144
5203
|
if (isSafeTool) {
|
|
5145
5204
|
await this.handleToolResponse({ type: "user_decision_execute", tool_calls: validToolCalls });
|
|
5146
5205
|
} else {
|
|
@@ -5159,7 +5218,6 @@ ${editData.error.display}`;
|
|
|
5159
5218
|
event: "protocol_violation_direct_text",
|
|
5160
5219
|
details: { violationContent: accumulatedContent }
|
|
5161
5220
|
});
|
|
5162
|
-
this.eventBus.emit("backend_message", { type: "protocol_violation", message: feedback.message, content: accumulatedContent });
|
|
5163
5221
|
this.history.push({ role: "system", content: feedback.correction });
|
|
5164
5222
|
await this._continueConversation();
|
|
5165
5223
|
} else {
|
|
@@ -5173,7 +5231,7 @@ ${editData.error.display}`;
|
|
|
5173
5231
|
messages: contextWindow,
|
|
5174
5232
|
temperature: 0,
|
|
5175
5233
|
tools: this.mcpClient.getAvailableTools(),
|
|
5176
|
-
tool_choice:
|
|
5234
|
+
//tool_choice: 'required',
|
|
5177
5235
|
parallel_tool_calls: false
|
|
5178
5236
|
});
|
|
5179
5237
|
if (this.isInterrupted) {
|
|
@@ -5202,6 +5260,7 @@ ${editData.error.display}`;
|
|
|
5202
5260
|
await this._continueConversation();
|
|
5203
5261
|
return;
|
|
5204
5262
|
}
|
|
5263
|
+
const isSandbox = process.env.BLUMA_SANDBOX === "true";
|
|
5205
5264
|
const autoApprovedTools = [
|
|
5206
5265
|
"message",
|
|
5207
5266
|
"ls_tool",
|
|
@@ -5209,10 +5268,11 @@ ${editData.error.display}`;
|
|
|
5209
5268
|
"read_file_lines",
|
|
5210
5269
|
"todo",
|
|
5211
5270
|
"load_skill",
|
|
5212
|
-
"search_web"
|
|
5271
|
+
"search_web",
|
|
5272
|
+
"coding_memory"
|
|
5213
5273
|
];
|
|
5214
5274
|
const toolToCall = validToolCalls[0];
|
|
5215
|
-
const isSafeTool = autoApprovedTools.some((safeTool) => toolToCall.function.name.includes(safeTool));
|
|
5275
|
+
const isSafeTool = isSandbox || autoApprovedTools.some((safeTool) => toolToCall.function.name.includes(safeTool));
|
|
5216
5276
|
if (isSafeTool) {
|
|
5217
5277
|
await this.handleToolResponse({ type: "user_decision_execute", tool_calls: validToolCalls });
|
|
5218
5278
|
} else {
|
|
@@ -5249,7 +5309,13 @@ var LLMService = class {
|
|
|
5249
5309
|
constructor(config2) {
|
|
5250
5310
|
this.client = new OpenAI({
|
|
5251
5311
|
apiKey: config2.apiKey,
|
|
5252
|
-
baseURL: config2.baseUrl || ""
|
|
5312
|
+
baseURL: config2.baseUrl || "",
|
|
5313
|
+
defaultHeaders: {
|
|
5314
|
+
"HTTP-Referer": "https://bluma.ai",
|
|
5315
|
+
// Optional. Site URL for rankings on openrouter.ai.
|
|
5316
|
+
"X-Title": "Bluma"
|
|
5317
|
+
// Optional. Site title for rankings on openrouter.ai.
|
|
5318
|
+
}
|
|
5253
5319
|
});
|
|
5254
5320
|
this.defaultModel = config2.model || "";
|
|
5255
5321
|
}
|
|
@@ -5261,7 +5327,7 @@ var LLMService = class {
|
|
|
5261
5327
|
model: params.model || this.defaultModel,
|
|
5262
5328
|
messages: params.messages,
|
|
5263
5329
|
tools: params.tools,
|
|
5264
|
-
tool_choice: params.tool_choice,
|
|
5330
|
+
//tool_choice: params.tool_choice,
|
|
5265
5331
|
parallel_tool_calls: params.parallel_tool_calls,
|
|
5266
5332
|
temperature: params.temperature,
|
|
5267
5333
|
max_tokens: params.max_tokens
|
|
@@ -5283,7 +5349,7 @@ var LLMService = class {
|
|
|
5283
5349
|
model: params.model || this.defaultModel,
|
|
5284
5350
|
messages: params.messages,
|
|
5285
5351
|
tools: params.tools,
|
|
5286
|
-
tool_choice: params.tool_choice,
|
|
5352
|
+
//tool_choice: params.tool_choice,
|
|
5287
5353
|
parallel_tool_calls: params.parallel_tool_calls,
|
|
5288
5354
|
temperature: params.temperature,
|
|
5289
5355
|
max_tokens: params.max_tokens,
|
|
@@ -5560,8 +5626,8 @@ var BaseLLMSubAgent = class {
|
|
|
5560
5626
|
return { history: this.history };
|
|
5561
5627
|
}
|
|
5562
5628
|
async initializeHistory() {
|
|
5563
|
-
const
|
|
5564
|
-
const [sessionFile, history] = await loadOrcreateSession(
|
|
5629
|
+
const sessionId = `${this.id}`;
|
|
5630
|
+
const [sessionFile, history] = await loadOrcreateSession(sessionId);
|
|
5565
5631
|
this.sessionFile = sessionFile;
|
|
5566
5632
|
this.history = history || [];
|
|
5567
5633
|
const systemPromptContent = getInitPrompt();
|
|
@@ -5598,7 +5664,7 @@ ${editData.error.display}`;
|
|
|
5598
5664
|
model: this.ctx.policy?.llmDeployment || "default",
|
|
5599
5665
|
messages: contextWindow,
|
|
5600
5666
|
tools: this.ctx.mcpClient.getAvailableTools(),
|
|
5601
|
-
tool_choice:
|
|
5667
|
+
//tool_choice: 'required',
|
|
5602
5668
|
parallel_tool_calls: false
|
|
5603
5669
|
});
|
|
5604
5670
|
if (this.isInterrupted) {
|
|
@@ -5804,12 +5870,12 @@ var Agent = class {
|
|
|
5804
5870
|
core;
|
|
5805
5871
|
subAgents;
|
|
5806
5872
|
toolInvoker;
|
|
5807
|
-
constructor(
|
|
5808
|
-
this.sessionId =
|
|
5809
|
-
this.eventBus =
|
|
5873
|
+
constructor(sessionId, eventBus) {
|
|
5874
|
+
this.sessionId = sessionId;
|
|
5875
|
+
this.eventBus = eventBus;
|
|
5810
5876
|
const nativeToolInvoker = new ToolInvoker();
|
|
5811
5877
|
this.toolInvoker = nativeToolInvoker;
|
|
5812
|
-
this.mcpClient = new MCPClient(nativeToolInvoker,
|
|
5878
|
+
this.mcpClient = new MCPClient(nativeToolInvoker, eventBus);
|
|
5813
5879
|
this.feedbackSystem = new AdvancedFeedbackSystem();
|
|
5814
5880
|
const apiKey = process.env.NOMAD_API_KEY;
|
|
5815
5881
|
const baseUrl = process.env.NOMAD_BASE_URL;
|
|
@@ -5907,22 +5973,22 @@ var Agent = class {
|
|
|
5907
5973
|
import { useState as useState4, useEffect as useEffect4, memo as memo5 } from "react";
|
|
5908
5974
|
import { Box as Box7, Text as Text7 } from "ink";
|
|
5909
5975
|
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
5910
|
-
var WorkingTimerComponent = ({ eventBus
|
|
5976
|
+
var WorkingTimerComponent = ({ eventBus, taskName, taskStatus }) => {
|
|
5911
5977
|
const [currentAction, setCurrentAction] = useState4("Thinking...");
|
|
5912
5978
|
const [shinePosition, setShinePosition] = useState4(0);
|
|
5913
5979
|
const [dots, setDots] = useState4("");
|
|
5914
5980
|
useEffect4(() => {
|
|
5915
|
-
if (!
|
|
5981
|
+
if (!eventBus) return;
|
|
5916
5982
|
const handleActionStatus = (data) => {
|
|
5917
5983
|
if (data.action) {
|
|
5918
5984
|
setCurrentAction(data.action);
|
|
5919
5985
|
}
|
|
5920
5986
|
};
|
|
5921
|
-
|
|
5987
|
+
eventBus.on("action_status", handleActionStatus);
|
|
5922
5988
|
return () => {
|
|
5923
|
-
|
|
5989
|
+
eventBus.off("action_status", handleActionStatus);
|
|
5924
5990
|
};
|
|
5925
|
-
}, [
|
|
5991
|
+
}, [eventBus]);
|
|
5926
5992
|
useEffect4(() => {
|
|
5927
5993
|
const shineTimer = setInterval(() => {
|
|
5928
5994
|
setShinePosition((prev) => (prev + 1) % 30);
|
|
@@ -6256,7 +6322,7 @@ var ToolCallDisplayComponent = ({ toolName, args, preview }) => {
|
|
|
6256
6322
|
if (toolName.includes("message")) {
|
|
6257
6323
|
return null;
|
|
6258
6324
|
}
|
|
6259
|
-
const Renderer = ToolRenderDisplay[toolName] || ((
|
|
6325
|
+
const Renderer = ToolRenderDisplay[toolName] || ((props) => renderGeneric2({ ...props, toolName }));
|
|
6260
6326
|
return /* @__PURE__ */ jsx9(Box9, { marginBottom: 1, children: /* @__PURE__ */ jsx9(Renderer, { toolName, args, preview }) });
|
|
6261
6327
|
};
|
|
6262
6328
|
var ToolCallDisplay = memo6(ToolCallDisplayComponent);
|
|
@@ -6896,8 +6962,8 @@ var ReasoningDisplay = memo9(ReasoningDisplayComponent);
|
|
|
6896
6962
|
// src/app/ui/components/StreamingText.tsx
|
|
6897
6963
|
import { useState as useState6, useEffect as useEffect5, useRef as useRef4, memo as memo10 } from "react";
|
|
6898
6964
|
import { Box as Box16, Text as Text15 } from "ink";
|
|
6899
|
-
import { jsx as jsx16 } from "react/jsx-runtime";
|
|
6900
|
-
var StreamingTextComponent = ({ eventBus
|
|
6965
|
+
import { jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
6966
|
+
var StreamingTextComponent = ({ eventBus, onReasoningComplete }) => {
|
|
6901
6967
|
const [reasoning, setReasoning] = useState6("");
|
|
6902
6968
|
const [isStreaming, setIsStreaming] = useState6(false);
|
|
6903
6969
|
const reasoningRef = useRef4("");
|
|
@@ -6939,25 +7005,39 @@ var StreamingTextComponent = ({ eventBus: eventBus2, onReasoningComplete }) => {
|
|
|
6939
7005
|
setReasoning("");
|
|
6940
7006
|
reasoningRef.current = "";
|
|
6941
7007
|
};
|
|
6942
|
-
|
|
6943
|
-
|
|
6944
|
-
|
|
7008
|
+
eventBus.on("stream_start", handleStart);
|
|
7009
|
+
eventBus.on("stream_reasoning_chunk", handleReasoningChunk);
|
|
7010
|
+
eventBus.on("stream_end", handleEnd);
|
|
6945
7011
|
return () => {
|
|
6946
|
-
|
|
6947
|
-
|
|
6948
|
-
|
|
7012
|
+
eventBus.off("stream_start", handleStart);
|
|
7013
|
+
eventBus.off("stream_reasoning_chunk", handleReasoningChunk);
|
|
7014
|
+
eventBus.off("stream_end", handleEnd);
|
|
6949
7015
|
};
|
|
6950
|
-
}, [
|
|
7016
|
+
}, [eventBus, onReasoningComplete]);
|
|
6951
7017
|
if (!isStreaming || !reasoning) {
|
|
6952
7018
|
return null;
|
|
6953
7019
|
}
|
|
6954
7020
|
const lines = reasoning.split("\n");
|
|
6955
|
-
|
|
7021
|
+
const MAX_VISIBLE_LINES = 20;
|
|
7022
|
+
let displayLines = lines;
|
|
7023
|
+
let truncatedCount = 0;
|
|
7024
|
+
if (lines.length > MAX_VISIBLE_LINES) {
|
|
7025
|
+
truncatedCount = lines.length - MAX_VISIBLE_LINES;
|
|
7026
|
+
displayLines = lines.slice(-MAX_VISIBLE_LINES);
|
|
7027
|
+
}
|
|
7028
|
+
return /* @__PURE__ */ jsxs15(Box16, { flexDirection: "column", paddingX: 1, marginBottom: 1, marginTop: 1, children: [
|
|
7029
|
+
truncatedCount > 0 && /* @__PURE__ */ jsxs15(Text15, { color: "gray", dimColor: true, children: [
|
|
7030
|
+
"... (ocultando ",
|
|
7031
|
+
truncatedCount,
|
|
7032
|
+
" linhas anteriores para performance) ..."
|
|
7033
|
+
] }),
|
|
7034
|
+
/* @__PURE__ */ jsx16(Box16, { paddingLeft: 2, flexDirection: "column", children: displayLines.map((line, i) => /* @__PURE__ */ jsx16(Text15, { color: "gray", dimColor: true, children: line }, i)) })
|
|
7035
|
+
] });
|
|
6956
7036
|
};
|
|
6957
7037
|
var StreamingText = memo10(StreamingTextComponent);
|
|
6958
7038
|
|
|
6959
7039
|
// src/app/ui/App.tsx
|
|
6960
|
-
import { jsx as jsx17, jsxs as
|
|
7040
|
+
import { jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
6961
7041
|
var SAFE_AUTO_APPROVE_TOOLS = [
|
|
6962
7042
|
// Comunicação/UI
|
|
6963
7043
|
"message",
|
|
@@ -6973,7 +7053,7 @@ var SAFE_AUTO_APPROVE_TOOLS = [
|
|
|
6973
7053
|
// Status de comandos (read-only)
|
|
6974
7054
|
"command_status"
|
|
6975
7055
|
];
|
|
6976
|
-
var AppComponent = ({ eventBus
|
|
7056
|
+
var AppComponent = ({ eventBus, sessionId }) => {
|
|
6977
7057
|
const agentInstance = useRef5(null);
|
|
6978
7058
|
const [history, setHistory] = useState7([]);
|
|
6979
7059
|
const [statusMessage, setStatusMessage] = useState7(
|
|
@@ -6998,7 +7078,7 @@ var AppComponent = ({ eventBus: eventBus2, sessionId: sessionId2 }) => {
|
|
|
6998
7078
|
const [toolCallCount, setToolCallCount] = useState7(0);
|
|
6999
7079
|
const handleInterrupt = useCallback2(() => {
|
|
7000
7080
|
if (!isProcessing) return;
|
|
7001
|
-
|
|
7081
|
+
eventBus.emit("user_interrupt");
|
|
7002
7082
|
setIsProcessing(false);
|
|
7003
7083
|
setHistory((prev) => [
|
|
7004
7084
|
...prev,
|
|
@@ -7007,7 +7087,7 @@ var AppComponent = ({ eventBus: eventBus2, sessionId: sessionId2 }) => {
|
|
|
7007
7087
|
component: /* @__PURE__ */ jsx17(Text16, { color: "yellow", children: "-- Task cancelled by dev. --" })
|
|
7008
7088
|
}
|
|
7009
7089
|
]);
|
|
7010
|
-
}, [isProcessing,
|
|
7090
|
+
}, [isProcessing, eventBus]);
|
|
7011
7091
|
const handleSubmit = useCallback2(
|
|
7012
7092
|
(text) => {
|
|
7013
7093
|
if (!text || isProcessing || !agentInstance.current) return;
|
|
@@ -7055,9 +7135,9 @@ var AppComponent = ({ eventBus: eventBus2, sessionId: sessionId2 }) => {
|
|
|
7055
7135
|
...prev,
|
|
7056
7136
|
{
|
|
7057
7137
|
id: prev.length,
|
|
7058
|
-
component: /* @__PURE__ */
|
|
7138
|
+
component: /* @__PURE__ */ jsxs16(Box17, { marginBottom: 1, children: [
|
|
7059
7139
|
/* @__PURE__ */ jsx17(Text16, { color: "white", bold: true, children: "$ " }),
|
|
7060
|
-
/* @__PURE__ */
|
|
7140
|
+
/* @__PURE__ */ jsxs16(Text16, { color: "white", children: [
|
|
7061
7141
|
"!",
|
|
7062
7142
|
command
|
|
7063
7143
|
] })
|
|
@@ -7079,7 +7159,7 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
7079
7159
|
...prev,
|
|
7080
7160
|
{
|
|
7081
7161
|
id: prev.length,
|
|
7082
|
-
component: /* @__PURE__ */
|
|
7162
|
+
component: /* @__PURE__ */ jsxs16(Text16, { color: "red", children: [
|
|
7083
7163
|
"Failed to execute: ",
|
|
7084
7164
|
result.error || result.message
|
|
7085
7165
|
] })
|
|
@@ -7092,7 +7172,7 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
7092
7172
|
...prev,
|
|
7093
7173
|
{
|
|
7094
7174
|
id: prev.length,
|
|
7095
|
-
component: /* @__PURE__ */
|
|
7175
|
+
component: /* @__PURE__ */ jsxs16(Text16, { color: "red", children: [
|
|
7096
7176
|
"Error: ",
|
|
7097
7177
|
err.message
|
|
7098
7178
|
] })
|
|
@@ -7111,8 +7191,8 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
7111
7191
|
id: prev.length,
|
|
7112
7192
|
component: (
|
|
7113
7193
|
// Uma única Box para o espaçamento
|
|
7114
|
-
/* @__PURE__ */ jsx17(Box17, { marginBottom: 1, children: /* @__PURE__ */
|
|
7115
|
-
/* @__PURE__ */
|
|
7194
|
+
/* @__PURE__ */ jsx17(Box17, { marginBottom: 1, children: /* @__PURE__ */ jsxs16(Text16, { color: "white", dimColor: true, children: [
|
|
7195
|
+
/* @__PURE__ */ jsxs16(Text16, { color: "white", children: [
|
|
7116
7196
|
">",
|
|
7117
7197
|
" "
|
|
7118
7198
|
] }),
|
|
@@ -7147,19 +7227,19 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
7147
7227
|
[]
|
|
7148
7228
|
);
|
|
7149
7229
|
useEffect6(() => {
|
|
7150
|
-
setHistory([{ id: 0, component: /* @__PURE__ */ jsx17(Header, { sessionId
|
|
7230
|
+
setHistory([{ id: 0, component: /* @__PURE__ */ jsx17(Header, { sessionId, workdir }) }]);
|
|
7151
7231
|
const initializeAgent = async () => {
|
|
7152
7232
|
try {
|
|
7153
|
-
agentInstance.current = new Agent(
|
|
7233
|
+
agentInstance.current = new Agent(sessionId, eventBus);
|
|
7154
7234
|
await agentInstance.current.initialize();
|
|
7155
|
-
|
|
7235
|
+
eventBus.emit("backend_message", {
|
|
7156
7236
|
type: "status",
|
|
7157
7237
|
status: "mcp_connected",
|
|
7158
7238
|
tools: agentInstance.current.getAvailableTools().length
|
|
7159
7239
|
});
|
|
7160
7240
|
} catch (error) {
|
|
7161
7241
|
const errorMessage = error instanceof Error ? error.message : "Unknown error during Agent initialization.";
|
|
7162
|
-
|
|
7242
|
+
eventBus.emit("backend_message", {
|
|
7163
7243
|
type: "error",
|
|
7164
7244
|
message: errorMessage
|
|
7165
7245
|
});
|
|
@@ -7229,7 +7309,7 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
7229
7309
|
if (parsed.type === "debug") {
|
|
7230
7310
|
newComponent = /* @__PURE__ */ jsx17(Text16, { color: "gray", children: parsed.message });
|
|
7231
7311
|
} else if (parsed.type === "protocol_violation") {
|
|
7232
|
-
newComponent = /* @__PURE__ */
|
|
7312
|
+
newComponent = /* @__PURE__ */ jsxs16(
|
|
7233
7313
|
Box17,
|
|
7234
7314
|
{
|
|
7235
7315
|
borderStyle: "round",
|
|
@@ -7272,8 +7352,8 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
7272
7352
|
}
|
|
7273
7353
|
);
|
|
7274
7354
|
} else if (parsed.type === "user_overlay") {
|
|
7275
|
-
newComponent = /* @__PURE__ */ jsx17(Box17, { marginBottom: 1, children: /* @__PURE__ */
|
|
7276
|
-
/* @__PURE__ */
|
|
7355
|
+
newComponent = /* @__PURE__ */ jsx17(Box17, { marginBottom: 1, children: /* @__PURE__ */ jsxs16(Text16, { color: "gray", children: [
|
|
7356
|
+
/* @__PURE__ */ jsxs16(Text16, { color: "magenta", children: [
|
|
7277
7357
|
">",
|
|
7278
7358
|
" "
|
|
7279
7359
|
] }),
|
|
@@ -7282,7 +7362,7 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
7282
7362
|
} else if (parsed.type === "reasoning") {
|
|
7283
7363
|
newComponent = /* @__PURE__ */ jsx17(ReasoningDisplay, { reasoning: parsed.content });
|
|
7284
7364
|
} else if (parsed.type === "log") {
|
|
7285
|
-
newComponent = /* @__PURE__ */
|
|
7365
|
+
newComponent = /* @__PURE__ */ jsxs16(Text16, { color: "gray", children: [
|
|
7286
7366
|
"\u2139\uFE0F ",
|
|
7287
7367
|
parsed.message,
|
|
7288
7368
|
parsed.payload ? `: ${parsed.payload}` : ""
|
|
@@ -7300,16 +7380,16 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
7300
7380
|
}
|
|
7301
7381
|
};
|
|
7302
7382
|
const handleUiOverlay = (data) => {
|
|
7303
|
-
|
|
7383
|
+
eventBus.emit("user_overlay", data);
|
|
7304
7384
|
};
|
|
7305
7385
|
uiEventBus.on("user_overlay", handleUiOverlay);
|
|
7306
|
-
|
|
7386
|
+
eventBus.on("backend_message", handleBackendMessage);
|
|
7307
7387
|
initializeAgent();
|
|
7308
7388
|
return () => {
|
|
7309
7389
|
uiEventBus.off("user_overlay", handleUiOverlay);
|
|
7310
|
-
|
|
7390
|
+
eventBus.off("backend_message", handleBackendMessage);
|
|
7311
7391
|
};
|
|
7312
|
-
}, [
|
|
7392
|
+
}, [eventBus, sessionId, handleConfirmation]);
|
|
7313
7393
|
const renderInteractiveComponent = () => {
|
|
7314
7394
|
if (mcpStatus !== "connected") {
|
|
7315
7395
|
return;
|
|
@@ -7327,8 +7407,8 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
7327
7407
|
}
|
|
7328
7408
|
);
|
|
7329
7409
|
}
|
|
7330
|
-
return /* @__PURE__ */
|
|
7331
|
-
isProcessing && !pendingConfirmation && /* @__PURE__ */ jsx17(WorkingTimer, { eventBus
|
|
7410
|
+
return /* @__PURE__ */ jsxs16(Box17, { flexDirection: "column", children: [
|
|
7411
|
+
isProcessing && !pendingConfirmation && /* @__PURE__ */ jsx17(WorkingTimer, { eventBus }),
|
|
7332
7412
|
/* @__PURE__ */ jsx17(
|
|
7333
7413
|
InputPrompt,
|
|
7334
7414
|
{
|
|
@@ -7340,12 +7420,12 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
7340
7420
|
)
|
|
7341
7421
|
] });
|
|
7342
7422
|
};
|
|
7343
|
-
return /* @__PURE__ */
|
|
7423
|
+
return /* @__PURE__ */ jsxs16(Box17, { flexDirection: "column", children: [
|
|
7344
7424
|
/* @__PURE__ */ jsx17(Static, { items: history, children: (item) => /* @__PURE__ */ jsx17(Box17, { children: item.component }, item.id) }),
|
|
7345
7425
|
/* @__PURE__ */ jsx17(
|
|
7346
7426
|
StreamingText,
|
|
7347
7427
|
{
|
|
7348
|
-
eventBus
|
|
7428
|
+
eventBus,
|
|
7349
7429
|
onReasoningComplete: (reasoning) => {
|
|
7350
7430
|
if (reasoning) {
|
|
7351
7431
|
setHistory((prev) => [
|
|
@@ -7421,12 +7501,174 @@ function stopTitleKeeper() {
|
|
|
7421
7501
|
}
|
|
7422
7502
|
|
|
7423
7503
|
// src/main.ts
|
|
7424
|
-
|
|
7425
|
-
|
|
7426
|
-
|
|
7427
|
-
|
|
7428
|
-
|
|
7429
|
-
|
|
7430
|
-
|
|
7431
|
-
|
|
7432
|
-
|
|
7504
|
+
function writeJsonl(event) {
|
|
7505
|
+
try {
|
|
7506
|
+
process.stdout.write(JSON.stringify(event) + "\n");
|
|
7507
|
+
} catch {
|
|
7508
|
+
}
|
|
7509
|
+
}
|
|
7510
|
+
async function runAgentMode() {
|
|
7511
|
+
const args = process.argv.slice(2);
|
|
7512
|
+
const inputFileIndex = args.indexOf("--input-file");
|
|
7513
|
+
const inputIndex = args.indexOf("--input");
|
|
7514
|
+
let rawPayload = "";
|
|
7515
|
+
try {
|
|
7516
|
+
if (inputFileIndex !== -1 && args[inputFileIndex + 1]) {
|
|
7517
|
+
const filePath = args[inputFileIndex + 1];
|
|
7518
|
+
rawPayload = fs14.readFileSync(filePath, "utf-8");
|
|
7519
|
+
} else {
|
|
7520
|
+
rawPayload = fs14.readFileSync(0, "utf-8");
|
|
7521
|
+
}
|
|
7522
|
+
} catch (err) {
|
|
7523
|
+
writeJsonl({
|
|
7524
|
+
event_type: "result",
|
|
7525
|
+
status: "error",
|
|
7526
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7527
|
+
error: {
|
|
7528
|
+
message: "Failed to read agent payload",
|
|
7529
|
+
details: err?.message
|
|
7530
|
+
}
|
|
7531
|
+
});
|
|
7532
|
+
process.exit(1);
|
|
7533
|
+
return;
|
|
7534
|
+
}
|
|
7535
|
+
let envelope;
|
|
7536
|
+
try {
|
|
7537
|
+
envelope = JSON.parse(rawPayload);
|
|
7538
|
+
} catch (err) {
|
|
7539
|
+
writeJsonl({
|
|
7540
|
+
event_type: "result",
|
|
7541
|
+
status: "error",
|
|
7542
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7543
|
+
error: {
|
|
7544
|
+
message: "Invalid JSON payload for agent mode",
|
|
7545
|
+
details: err?.message
|
|
7546
|
+
}
|
|
7547
|
+
});
|
|
7548
|
+
process.exit(1);
|
|
7549
|
+
return;
|
|
7550
|
+
}
|
|
7551
|
+
const eventBus = new EventEmitter2();
|
|
7552
|
+
const sessionId = envelope.message_id || uuidv43();
|
|
7553
|
+
let lastAssistantMessage = null;
|
|
7554
|
+
let reasoningBuffer = null;
|
|
7555
|
+
let resultEmitted = false;
|
|
7556
|
+
eventBus.on("backend_message", (payload) => {
|
|
7557
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
7558
|
+
writeJsonl({
|
|
7559
|
+
event_type: "backend_message",
|
|
7560
|
+
backend_type: String(payload?.type || "unknown"),
|
|
7561
|
+
timestamp,
|
|
7562
|
+
payload
|
|
7563
|
+
});
|
|
7564
|
+
if (payload?.type === "assistant_message" && typeof payload.content === "string") {
|
|
7565
|
+
lastAssistantMessage = payload.content;
|
|
7566
|
+
}
|
|
7567
|
+
if (payload?.type === "reasoning" && typeof payload.content === "string") {
|
|
7568
|
+
reasoningBuffer = (reasoningBuffer || "") + payload.content;
|
|
7569
|
+
}
|
|
7570
|
+
if (payload?.type === "tool_result" && payload.tool_name === "message") {
|
|
7571
|
+
try {
|
|
7572
|
+
const rawResult = payload.result;
|
|
7573
|
+
const parsed = typeof rawResult === "string" ? JSON.parse(rawResult) : rawResult;
|
|
7574
|
+
const body = parsed?.content?.body;
|
|
7575
|
+
if (typeof body === "string") {
|
|
7576
|
+
lastAssistantMessage = body;
|
|
7577
|
+
}
|
|
7578
|
+
} catch {
|
|
7579
|
+
}
|
|
7580
|
+
}
|
|
7581
|
+
if (!resultEmitted && payload?.type === "done") {
|
|
7582
|
+
resultEmitted = true;
|
|
7583
|
+
writeJsonl({
|
|
7584
|
+
event_type: "result",
|
|
7585
|
+
status: "success",
|
|
7586
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7587
|
+
data: {
|
|
7588
|
+
message_id: envelope.message_id || sessionId,
|
|
7589
|
+
action: envelope.action || "unknown",
|
|
7590
|
+
last_assistant_message: lastAssistantMessage,
|
|
7591
|
+
reasoning: reasoningBuffer
|
|
7592
|
+
}
|
|
7593
|
+
});
|
|
7594
|
+
process.exit(0);
|
|
7595
|
+
}
|
|
7596
|
+
});
|
|
7597
|
+
eventBus.on("action_status", (payload) => {
|
|
7598
|
+
writeJsonl({
|
|
7599
|
+
event_type: "action_status",
|
|
7600
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7601
|
+
payload
|
|
7602
|
+
});
|
|
7603
|
+
});
|
|
7604
|
+
writeJsonl({
|
|
7605
|
+
event_type: "log",
|
|
7606
|
+
level: "info",
|
|
7607
|
+
message: "Starting agent mode execution",
|
|
7608
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7609
|
+
data: {
|
|
7610
|
+
message_id: envelope.message_id,
|
|
7611
|
+
action: envelope.action,
|
|
7612
|
+
from_agent: envelope.from_agent,
|
|
7613
|
+
to_agent: envelope.to_agent
|
|
7614
|
+
}
|
|
7615
|
+
});
|
|
7616
|
+
try {
|
|
7617
|
+
const agent = new Agent(sessionId, eventBus);
|
|
7618
|
+
await agent.initialize();
|
|
7619
|
+
const userContent = JSON.stringify({
|
|
7620
|
+
message_id: envelope.message_id || sessionId,
|
|
7621
|
+
from_agent: envelope.from_agent || "sandbox-api",
|
|
7622
|
+
to_agent: envelope.to_agent || "bluma",
|
|
7623
|
+
action: envelope.action || "unknown",
|
|
7624
|
+
context: envelope.context || {},
|
|
7625
|
+
metadata: envelope.metadata || {}
|
|
7626
|
+
});
|
|
7627
|
+
await agent.processTurn({ content: userContent });
|
|
7628
|
+
if (!resultEmitted) {
|
|
7629
|
+
resultEmitted = true;
|
|
7630
|
+
writeJsonl({
|
|
7631
|
+
event_type: "result",
|
|
7632
|
+
status: "success",
|
|
7633
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7634
|
+
data: {
|
|
7635
|
+
message_id: envelope.message_id || sessionId,
|
|
7636
|
+
action: envelope.action || "unknown",
|
|
7637
|
+
last_assistant_message: lastAssistantMessage,
|
|
7638
|
+
reasoning: reasoningBuffer
|
|
7639
|
+
}
|
|
7640
|
+
});
|
|
7641
|
+
process.exit(0);
|
|
7642
|
+
}
|
|
7643
|
+
} catch (err) {
|
|
7644
|
+
if (!resultEmitted) {
|
|
7645
|
+
writeJsonl({
|
|
7646
|
+
event_type: "result",
|
|
7647
|
+
status: "error",
|
|
7648
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7649
|
+
error: {
|
|
7650
|
+
message: "Agent mode execution failed",
|
|
7651
|
+
details: err?.message
|
|
7652
|
+
}
|
|
7653
|
+
});
|
|
7654
|
+
}
|
|
7655
|
+
process.exit(1);
|
|
7656
|
+
}
|
|
7657
|
+
}
|
|
7658
|
+
function runCliMode() {
|
|
7659
|
+
const BLUMA_TITLE = process.env.BLUMA_TITLE || "BluMa - NomadEngenuity";
|
|
7660
|
+
startTitleKeeper(BLUMA_TITLE);
|
|
7661
|
+
const eventBus = new EventEmitter2();
|
|
7662
|
+
const sessionId = uuidv43();
|
|
7663
|
+
const props = {
|
|
7664
|
+
eventBus,
|
|
7665
|
+
sessionId
|
|
7666
|
+
};
|
|
7667
|
+
render(React11.createElement(App_default, props));
|
|
7668
|
+
}
|
|
7669
|
+
var argv = process.argv.slice(2);
|
|
7670
|
+
if (argv[0] === "agent") {
|
|
7671
|
+
runAgentMode();
|
|
7672
|
+
} else {
|
|
7673
|
+
runCliMode();
|
|
7674
|
+
}
|