@nomad-e/bluma-cli 0.1.52 → 0.1.54
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/dist/main.js +900 -101
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -508,10 +508,10 @@ __export(session_registry_exports, {
|
|
|
508
508
|
updateSession: () => updateSession
|
|
509
509
|
});
|
|
510
510
|
import fs15 from "fs";
|
|
511
|
-
import
|
|
511
|
+
import os8 from "os";
|
|
512
512
|
import path17 from "path";
|
|
513
513
|
function getRegistryDir() {
|
|
514
|
-
return path17.join(process.env.HOME ||
|
|
514
|
+
return path17.join(process.env.HOME || os8.homedir(), ".bluma", "registry");
|
|
515
515
|
}
|
|
516
516
|
function getRegistryFile() {
|
|
517
517
|
return path17.join(getRegistryDir(), "sessions.json");
|
|
@@ -594,7 +594,7 @@ __export(agent_coordination_exports, {
|
|
|
594
594
|
waitAgent: () => waitAgent
|
|
595
595
|
});
|
|
596
596
|
import fs16 from "fs";
|
|
597
|
-
import
|
|
597
|
+
import os9 from "os";
|
|
598
598
|
import path18 from "path";
|
|
599
599
|
import { spawn as spawn4 } from "child_process";
|
|
600
600
|
import { v4 as uuidv43 } from "uuid";
|
|
@@ -675,7 +675,7 @@ async function spawnAgent(args) {
|
|
|
675
675
|
const userContext = readUserContextFromEnv();
|
|
676
676
|
const title = args.title || `worker:${args.agent_type || "worker"}`;
|
|
677
677
|
const payload = buildWorkerPayload(sessionId, args, parentSessionId, userContext);
|
|
678
|
-
const payloadDir = fs16.mkdtempSync(path18.join(
|
|
678
|
+
const payloadDir = fs16.mkdtempSync(path18.join(os9.tmpdir(), "bluma-worker-"));
|
|
679
679
|
const payloadPath = path18.join(payloadDir, `${sessionId}.json`);
|
|
680
680
|
fs16.writeFileSync(payloadPath, JSON.stringify(payload, null, 2), "utf-8");
|
|
681
681
|
registerSession({
|
|
@@ -796,14 +796,14 @@ __export(mailbox_registry_exports, {
|
|
|
796
796
|
sendToMailbox: () => sendToMailbox
|
|
797
797
|
});
|
|
798
798
|
import fs17 from "fs";
|
|
799
|
-
import
|
|
799
|
+
import os10 from "os";
|
|
800
800
|
import path19 from "path";
|
|
801
801
|
import { v4 as uuidv44 } from "uuid";
|
|
802
802
|
function getMailboxesDir() {
|
|
803
803
|
if (mailboxesDir) {
|
|
804
804
|
return mailboxesDir;
|
|
805
805
|
}
|
|
806
|
-
mailboxesDir = path19.join(process.env.HOME ||
|
|
806
|
+
mailboxesDir = path19.join(process.env.HOME || os10.homedir(), ".bluma", "mailboxes");
|
|
807
807
|
fs17.mkdirSync(mailboxesDir, { recursive: true });
|
|
808
808
|
return mailboxesDir;
|
|
809
809
|
}
|
|
@@ -1182,8 +1182,8 @@ var init_poll_mailbox = __esm({
|
|
|
1182
1182
|
import React19 from "react";
|
|
1183
1183
|
import { render } from "ink";
|
|
1184
1184
|
import { EventEmitter as EventEmitter3 } from "events";
|
|
1185
|
-
import
|
|
1186
|
-
import
|
|
1185
|
+
import fs29 from "fs";
|
|
1186
|
+
import path34 from "path";
|
|
1187
1187
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
1188
1188
|
import { spawn as spawn5 } from "child_process";
|
|
1189
1189
|
import { v4 as uuidv48 } from "uuid";
|
|
@@ -3652,12 +3652,12 @@ function EditToolDiffPanel({
|
|
|
3652
3652
|
maxHeight = EDIT_DIFF_PREVIEW_MAX_LINES,
|
|
3653
3653
|
fallbackSnippet
|
|
3654
3654
|
}) {
|
|
3655
|
-
const
|
|
3655
|
+
const path35 = filePath.trim() || "unknown file";
|
|
3656
3656
|
const diff = diffText?.trim() ?? "";
|
|
3657
3657
|
return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
|
|
3658
3658
|
/* @__PURE__ */ jsx5(Box5, { flexDirection: "row", flexWrap: "wrap", children: /* @__PURE__ */ jsxs5(Text5, { color: isNewFile ? BLUMA_TERMINAL.success : void 0, children: [
|
|
3659
3659
|
isNewFile ? "Created " : "Wrote to ",
|
|
3660
|
-
/* @__PURE__ */ jsx5(Text5, { bold: true, children:
|
|
3660
|
+
/* @__PURE__ */ jsx5(Text5, { bold: true, children: path35 })
|
|
3661
3661
|
] }) }),
|
|
3662
3662
|
description ? /* @__PURE__ */ jsx5(Text5, { dimColor: true, wrap: "wrap", children: description }) : null,
|
|
3663
3663
|
diff.length > 0 ? /* @__PURE__ */ jsx5(Box5, { marginTop: 0, children: /* @__PURE__ */ jsx5(SimpleDiff, { text: diff, maxHeight, frame: true }) }) : fallbackSnippet ? /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", marginTop: 0, children: [
|
|
@@ -3891,7 +3891,7 @@ var renderFindByName = ({ args }) => {
|
|
|
3891
3891
|
var renderGrepSearch = ({ args }) => {
|
|
3892
3892
|
const parsed = parseArgs(args);
|
|
3893
3893
|
const query = parsed.query || "";
|
|
3894
|
-
const
|
|
3894
|
+
const path35 = parsed.path || ".";
|
|
3895
3895
|
return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "row", flexWrap: "wrap", children: [
|
|
3896
3896
|
/* @__PURE__ */ jsxs7(Text7, { color: BLUMA_TERMINAL.muted, children: [
|
|
3897
3897
|
'"',
|
|
@@ -3900,7 +3900,7 @@ var renderGrepSearch = ({ args }) => {
|
|
|
3900
3900
|
] }),
|
|
3901
3901
|
/* @__PURE__ */ jsxs7(Text7, { color: BLUMA_TERMINAL.m3OnSurface, bold: true, children: [
|
|
3902
3902
|
" ",
|
|
3903
|
-
|
|
3903
|
+
path35
|
|
3904
3904
|
] })
|
|
3905
3905
|
] });
|
|
3906
3906
|
};
|
|
@@ -4330,8 +4330,8 @@ var ConfirmationPrompt = memo4(ConfirmationPromptComponent);
|
|
|
4330
4330
|
|
|
4331
4331
|
// src/app/agent/agent.ts
|
|
4332
4332
|
import * as dotenv from "dotenv";
|
|
4333
|
-
import
|
|
4334
|
-
import
|
|
4333
|
+
import path32 from "path";
|
|
4334
|
+
import os21 from "os";
|
|
4335
4335
|
|
|
4336
4336
|
// src/app/agent/tool_invoker.ts
|
|
4337
4337
|
import { promises as fs18 } from "fs";
|
|
@@ -6027,13 +6027,11 @@ init_async_command();
|
|
|
6027
6027
|
init_sandbox_policy();
|
|
6028
6028
|
import path13 from "path";
|
|
6029
6029
|
import { promises as fs10 } from "fs";
|
|
6030
|
-
import os7 from "os";
|
|
6031
6030
|
var artifactsDir = null;
|
|
6032
6031
|
async function getArtifactsDir() {
|
|
6033
6032
|
if (artifactsDir) return artifactsDir;
|
|
6034
6033
|
const policy = getSandboxPolicy();
|
|
6035
|
-
const
|
|
6036
|
-
const baseDir = policy.isSandbox ? path13.join(policy.workspaceRoot, "artifacts") : path13.join(homeDir, ".bluma", "artifacts");
|
|
6034
|
+
const baseDir = path13.join(policy.workspaceRoot, ".bluma", "artifacts");
|
|
6037
6035
|
const sessionId = Date.now().toString(36) + Math.random().toString(36).substr(2, 5);
|
|
6038
6036
|
artifactsDir = path13.join(baseDir, sessionId);
|
|
6039
6037
|
await fs10.mkdir(artifactsDir, { recursive: true });
|
|
@@ -6569,7 +6567,7 @@ ${skill.content}`;
|
|
|
6569
6567
|
// src/app/agent/tools/natives/coding_memory.ts
|
|
6570
6568
|
import * as fs11 from "fs";
|
|
6571
6569
|
import * as path14 from "path";
|
|
6572
|
-
import
|
|
6570
|
+
import os7 from "os";
|
|
6573
6571
|
var PROMPT_DEFAULT_MAX_TOTAL = 1e4;
|
|
6574
6572
|
var PROMPT_DEFAULT_MAX_NOTES = 25;
|
|
6575
6573
|
var PROMPT_DEFAULT_PREVIEW = 500;
|
|
@@ -6577,7 +6575,7 @@ function readCodingMemoryForPrompt(options) {
|
|
|
6577
6575
|
const maxTotal = options?.maxTotalChars ?? PROMPT_DEFAULT_MAX_TOTAL;
|
|
6578
6576
|
const maxNotes = options?.maxNotes ?? PROMPT_DEFAULT_MAX_NOTES;
|
|
6579
6577
|
const preview = options?.previewCharsPerNote ?? PROMPT_DEFAULT_PREVIEW;
|
|
6580
|
-
const globalPath = path14.join(
|
|
6578
|
+
const globalPath = path14.join(os7.homedir(), ".bluma", "coding_memory.json");
|
|
6581
6579
|
const legacyPath = path14.join(process.cwd(), ".bluma", "coding_memory.json");
|
|
6582
6580
|
let raw = null;
|
|
6583
6581
|
try {
|
|
@@ -6622,7 +6620,7 @@ var memoryStore = [];
|
|
|
6622
6620
|
var nextId = 1;
|
|
6623
6621
|
var loaded = false;
|
|
6624
6622
|
function getMemoryFilePath() {
|
|
6625
|
-
return path14.join(
|
|
6623
|
+
return path14.join(os7.homedir(), ".bluma", "coding_memory.json");
|
|
6626
6624
|
}
|
|
6627
6625
|
function getLegacyMemoryFilePath() {
|
|
6628
6626
|
return path14.join(process.cwd(), ".bluma", "coding_memory.json");
|
|
@@ -8302,7 +8300,7 @@ var ToolInvoker = class {
|
|
|
8302
8300
|
// src/app/agent/tools/mcp/mcp_client.ts
|
|
8303
8301
|
import { promises as fs19 } from "fs";
|
|
8304
8302
|
import path21 from "path";
|
|
8305
|
-
import
|
|
8303
|
+
import os11 from "os";
|
|
8306
8304
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
8307
8305
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
8308
8306
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
@@ -8331,7 +8329,7 @@ var MCPClient = class {
|
|
|
8331
8329
|
const __filename = fileURLToPath3(import.meta.url);
|
|
8332
8330
|
const __dirname = path21.dirname(__filename);
|
|
8333
8331
|
const defaultConfigPath = path21.resolve(__dirname, "config", "bluma-mcp.json");
|
|
8334
|
-
const userConfigPath = path21.join(
|
|
8332
|
+
const userConfigPath = path21.join(os11.homedir(), ".bluma", "bluma-mcp.json");
|
|
8335
8333
|
const defaultConfig = await this.loadMcpConfig(defaultConfigPath, "Default");
|
|
8336
8334
|
const userConfig = await this.loadMcpConfig(userConfigPath, "User");
|
|
8337
8335
|
const mergedConfig = {
|
|
@@ -8384,7 +8382,7 @@ var MCPClient = class {
|
|
|
8384
8382
|
async connectToStdioServer(serverName, config2) {
|
|
8385
8383
|
let commandToExecute = config2.command;
|
|
8386
8384
|
let argsToExecute = config2.args || [];
|
|
8387
|
-
const isWindows =
|
|
8385
|
+
const isWindows = os11.platform() === "win32";
|
|
8388
8386
|
if (!isWindows && commandToExecute.toLowerCase() === "cmd") {
|
|
8389
8387
|
if (argsToExecute.length >= 2 && argsToExecute[0].toLowerCase() === "/c") {
|
|
8390
8388
|
commandToExecute = argsToExecute[1];
|
|
@@ -8536,12 +8534,12 @@ var AdvancedFeedbackSystem = class {
|
|
|
8536
8534
|
};
|
|
8537
8535
|
|
|
8538
8536
|
// src/app/agent/bluma/core/bluma.ts
|
|
8539
|
-
import
|
|
8537
|
+
import path30 from "path";
|
|
8540
8538
|
import { v4 as uuidv45 } from "uuid";
|
|
8541
8539
|
|
|
8542
8540
|
// src/app/agent/session_manager/session_manager.ts
|
|
8543
8541
|
import path22 from "path";
|
|
8544
|
-
import
|
|
8542
|
+
import os12 from "os";
|
|
8545
8543
|
import { promises as fs20 } from "fs";
|
|
8546
8544
|
var fileLocks = /* @__PURE__ */ new Map();
|
|
8547
8545
|
async function withFileLock(file, fn) {
|
|
@@ -8578,12 +8576,12 @@ function debouncedSave(sessionFile, history, memory) {
|
|
|
8578
8576
|
function expandHome(p) {
|
|
8579
8577
|
if (!p) return p;
|
|
8580
8578
|
if (p.startsWith("~")) {
|
|
8581
|
-
return path22.join(
|
|
8579
|
+
return path22.join(os12.homedir(), p.slice(1));
|
|
8582
8580
|
}
|
|
8583
8581
|
return p;
|
|
8584
8582
|
}
|
|
8585
8583
|
function getPreferredAppDir() {
|
|
8586
|
-
const fixed = path22.join(
|
|
8584
|
+
const fixed = path22.join(os12.homedir(), ".bluma");
|
|
8587
8585
|
return path22.resolve(expandHome(fixed));
|
|
8588
8586
|
}
|
|
8589
8587
|
async function safeRenameWithRetry(src, dest, maxRetries = 6) {
|
|
@@ -8727,14 +8725,14 @@ async function saveSessionHistory(sessionFile, history, memory) {
|
|
|
8727
8725
|
|
|
8728
8726
|
// src/app/agent/core/prompt/prompt_builder.ts
|
|
8729
8727
|
import os16 from "os";
|
|
8730
|
-
import
|
|
8731
|
-
import
|
|
8728
|
+
import fs25 from "fs";
|
|
8729
|
+
import path27 from "path";
|
|
8732
8730
|
import { execSync as execSync3 } from "child_process";
|
|
8733
8731
|
|
|
8734
8732
|
// src/app/agent/skills/skill_loader.ts
|
|
8735
8733
|
import fs21 from "fs";
|
|
8736
8734
|
import path23 from "path";
|
|
8737
|
-
import
|
|
8735
|
+
import os13 from "os";
|
|
8738
8736
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
8739
8737
|
var SkillLoader = class _SkillLoader {
|
|
8740
8738
|
bundledSkillsDir;
|
|
@@ -8744,7 +8742,7 @@ var SkillLoader = class _SkillLoader {
|
|
|
8744
8742
|
conflicts = [];
|
|
8745
8743
|
constructor(projectRoot, bundledDir) {
|
|
8746
8744
|
this.projectSkillsDir = path23.join(projectRoot, ".bluma", "skills");
|
|
8747
|
-
this.globalSkillsDir = path23.join(
|
|
8745
|
+
this.globalSkillsDir = path23.join(os13.homedir(), ".bluma", "skills");
|
|
8748
8746
|
this.bundledSkillsDir = bundledDir || _SkillLoader.resolveBundledDir();
|
|
8749
8747
|
}
|
|
8750
8748
|
/**
|
|
@@ -8794,7 +8792,7 @@ var SkillLoader = class _SkillLoader {
|
|
|
8794
8792
|
if (argvBundled) {
|
|
8795
8793
|
return argvBundled;
|
|
8796
8794
|
}
|
|
8797
|
-
return path23.join(
|
|
8795
|
+
return path23.join(os13.homedir(), ".bluma", "__bundled_skills_unresolved__");
|
|
8798
8796
|
}
|
|
8799
8797
|
}
|
|
8800
8798
|
/**
|
|
@@ -9243,14 +9241,14 @@ init_runtime_config();
|
|
|
9243
9241
|
// src/app/agent/runtime/plugin_registry.ts
|
|
9244
9242
|
init_sandbox_policy();
|
|
9245
9243
|
import fs23 from "fs";
|
|
9246
|
-
import
|
|
9244
|
+
import os14 from "os";
|
|
9247
9245
|
import path25 from "path";
|
|
9248
9246
|
function getProjectPluginsDir() {
|
|
9249
9247
|
const policy = getSandboxPolicy();
|
|
9250
9248
|
return path25.join(policy.workspaceRoot, ".bluma", "plugins");
|
|
9251
9249
|
}
|
|
9252
9250
|
function getGlobalPluginsDir() {
|
|
9253
|
-
return path25.join(process.env.HOME ||
|
|
9251
|
+
return path25.join(process.env.HOME || os14.homedir(), ".bluma", "plugins");
|
|
9254
9252
|
}
|
|
9255
9253
|
function getPluginDirs() {
|
|
9256
9254
|
return {
|
|
@@ -9537,6 +9535,528 @@ function disableCoordinatorMode() {
|
|
|
9537
9535
|
delete process.env.BLUMA_COORDINATOR_MODE;
|
|
9538
9536
|
}
|
|
9539
9537
|
|
|
9538
|
+
// src/app/agent/utils/blumamd.ts
|
|
9539
|
+
import fs24 from "fs";
|
|
9540
|
+
import path26 from "path";
|
|
9541
|
+
import os15 from "os";
|
|
9542
|
+
var MEMORY_INSTRUCTION_PROMPT = "Instru\xE7\xF5es de mem\xF3ria do BluMa (BLUMA.md) est\xE3o abaixo. Siga estas instru\xE7\xF5es exatamente como escritas. Estas instru\xE7\xF5es OVERRIDE qualquer comportamento padr\xE3o.";
|
|
9543
|
+
var TEXT_FILE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
9544
|
+
".md",
|
|
9545
|
+
".txt",
|
|
9546
|
+
".text",
|
|
9547
|
+
".json",
|
|
9548
|
+
".yaml",
|
|
9549
|
+
".yml",
|
|
9550
|
+
".toml",
|
|
9551
|
+
".xml",
|
|
9552
|
+
".csv",
|
|
9553
|
+
".html",
|
|
9554
|
+
".htm",
|
|
9555
|
+
".css",
|
|
9556
|
+
".scss",
|
|
9557
|
+
".sass",
|
|
9558
|
+
".less",
|
|
9559
|
+
".js",
|
|
9560
|
+
".ts",
|
|
9561
|
+
".tsx",
|
|
9562
|
+
".jsx",
|
|
9563
|
+
".mjs",
|
|
9564
|
+
".cjs",
|
|
9565
|
+
".mts",
|
|
9566
|
+
".cts",
|
|
9567
|
+
".py",
|
|
9568
|
+
".pyi",
|
|
9569
|
+
".pyw",
|
|
9570
|
+
".rb",
|
|
9571
|
+
".erb",
|
|
9572
|
+
".rake",
|
|
9573
|
+
".go",
|
|
9574
|
+
".rs",
|
|
9575
|
+
".java",
|
|
9576
|
+
".kt",
|
|
9577
|
+
".kts",
|
|
9578
|
+
".scala",
|
|
9579
|
+
".c",
|
|
9580
|
+
".cpp",
|
|
9581
|
+
".cc",
|
|
9582
|
+
".cxx",
|
|
9583
|
+
".h",
|
|
9584
|
+
".hpp",
|
|
9585
|
+
".hxx",
|
|
9586
|
+
".cs",
|
|
9587
|
+
".swift",
|
|
9588
|
+
".sh",
|
|
9589
|
+
".bash",
|
|
9590
|
+
".zsh",
|
|
9591
|
+
".fish",
|
|
9592
|
+
".ps1",
|
|
9593
|
+
".bat",
|
|
9594
|
+
".cmd",
|
|
9595
|
+
".env",
|
|
9596
|
+
".ini",
|
|
9597
|
+
".cfg",
|
|
9598
|
+
".conf",
|
|
9599
|
+
".config",
|
|
9600
|
+
".properties",
|
|
9601
|
+
".sql",
|
|
9602
|
+
".graphql",
|
|
9603
|
+
".gql",
|
|
9604
|
+
".proto",
|
|
9605
|
+
".vue",
|
|
9606
|
+
".svelte",
|
|
9607
|
+
".astro",
|
|
9608
|
+
".ejs",
|
|
9609
|
+
".hbs",
|
|
9610
|
+
".pug",
|
|
9611
|
+
".jade",
|
|
9612
|
+
".php",
|
|
9613
|
+
".pl",
|
|
9614
|
+
".pm",
|
|
9615
|
+
".lua",
|
|
9616
|
+
".r",
|
|
9617
|
+
".R",
|
|
9618
|
+
".dart",
|
|
9619
|
+
".ex",
|
|
9620
|
+
".exs",
|
|
9621
|
+
".erl",
|
|
9622
|
+
".hrl",
|
|
9623
|
+
".clj",
|
|
9624
|
+
".cljs",
|
|
9625
|
+
".cljc",
|
|
9626
|
+
".edn",
|
|
9627
|
+
".hs",
|
|
9628
|
+
".lhs",
|
|
9629
|
+
".vim",
|
|
9630
|
+
".el",
|
|
9631
|
+
".scm",
|
|
9632
|
+
".ss",
|
|
9633
|
+
".cl",
|
|
9634
|
+
".lisp",
|
|
9635
|
+
".ml",
|
|
9636
|
+
".mli",
|
|
9637
|
+
".fs",
|
|
9638
|
+
".fsi",
|
|
9639
|
+
".fsx",
|
|
9640
|
+
".fsscript",
|
|
9641
|
+
".adb",
|
|
9642
|
+
".ads",
|
|
9643
|
+
".ada",
|
|
9644
|
+
".pas",
|
|
9645
|
+
".pp",
|
|
9646
|
+
".p",
|
|
9647
|
+
".tcl",
|
|
9648
|
+
".v",
|
|
9649
|
+
".sv",
|
|
9650
|
+
".svh",
|
|
9651
|
+
".vhdl",
|
|
9652
|
+
".cmake",
|
|
9653
|
+
".mk",
|
|
9654
|
+
".make",
|
|
9655
|
+
".dockerfile",
|
|
9656
|
+
".dockerignore",
|
|
9657
|
+
".gitignore",
|
|
9658
|
+
".gitattributes",
|
|
9659
|
+
".gitconfig",
|
|
9660
|
+
".editorconfig",
|
|
9661
|
+
".eslintrc",
|
|
9662
|
+
".prettierrc",
|
|
9663
|
+
".babelrc",
|
|
9664
|
+
".blumarc"
|
|
9665
|
+
]);
|
|
9666
|
+
function expandIncludePath(includePath, baseDir) {
|
|
9667
|
+
const cleanPath = includePath.startsWith("@") ? includePath.slice(1) : includePath;
|
|
9668
|
+
if (cleanPath.startsWith("~")) {
|
|
9669
|
+
return path26.join(os15.homedir(), cleanPath.slice(1));
|
|
9670
|
+
}
|
|
9671
|
+
if (path26.isAbsolute(cleanPath)) {
|
|
9672
|
+
return cleanPath;
|
|
9673
|
+
}
|
|
9674
|
+
return path26.resolve(baseDir, cleanPath);
|
|
9675
|
+
}
|
|
9676
|
+
function processIncludes(content, baseDir, processedFiles) {
|
|
9677
|
+
const lines = content.split("\n");
|
|
9678
|
+
const result = [];
|
|
9679
|
+
for (const line of lines) {
|
|
9680
|
+
const includeMatch = line.match(/^@\s*([^\s]+)/);
|
|
9681
|
+
if (includeMatch) {
|
|
9682
|
+
const includePath = expandIncludePath(includeMatch[1], baseDir);
|
|
9683
|
+
const normalizedPath = path26.normalize(includePath);
|
|
9684
|
+
if (processedFiles.has(normalizedPath)) {
|
|
9685
|
+
result.push(`<!-- Circular include prevented: ${includeMatch[1]} -->`);
|
|
9686
|
+
continue;
|
|
9687
|
+
}
|
|
9688
|
+
const ext = path26.extname(includePath).toLowerCase();
|
|
9689
|
+
if (!TEXT_FILE_EXTENSIONS.has(ext)) {
|
|
9690
|
+
result.push(`<!-- Include skipped (unsupported extension): ${includeMatch[1]} -->`);
|
|
9691
|
+
continue;
|
|
9692
|
+
}
|
|
9693
|
+
try {
|
|
9694
|
+
const includedContent = fs24.readFileSync(includePath, "utf-8");
|
|
9695
|
+
processedFiles.add(normalizedPath);
|
|
9696
|
+
const processedContent = processIncludes(includedContent, path26.dirname(includePath), processedFiles);
|
|
9697
|
+
result.push(`
|
|
9698
|
+
<!-- BEGIN INCLUDE ${includeMatch[1]} -->
|
|
9699
|
+
`);
|
|
9700
|
+
result.push(processedContent);
|
|
9701
|
+
result.push(`
|
|
9702
|
+
<!-- END INCLUDE ${includeMatch[1]} -->
|
|
9703
|
+
`);
|
|
9704
|
+
} catch {
|
|
9705
|
+
result.push(`<!-- Include not found: ${includeMatch[1]} -->`);
|
|
9706
|
+
}
|
|
9707
|
+
} else {
|
|
9708
|
+
result.push(line);
|
|
9709
|
+
}
|
|
9710
|
+
}
|
|
9711
|
+
return result.join("\n");
|
|
9712
|
+
}
|
|
9713
|
+
function readMemoryFile(filePath, type, priority) {
|
|
9714
|
+
try {
|
|
9715
|
+
const content = fs24.readFileSync(filePath, "utf-8");
|
|
9716
|
+
const baseDir = path26.dirname(filePath);
|
|
9717
|
+
const processedFiles = /* @__PURE__ */ new Set([path26.normalize(filePath)]);
|
|
9718
|
+
const processedContent = processIncludes(content, baseDir, processedFiles);
|
|
9719
|
+
return {
|
|
9720
|
+
path: filePath,
|
|
9721
|
+
content: processedContent.trim(),
|
|
9722
|
+
type,
|
|
9723
|
+
priority
|
|
9724
|
+
};
|
|
9725
|
+
} catch (error) {
|
|
9726
|
+
if (error?.code !== "ENOENT") {
|
|
9727
|
+
console.error(`Error reading BLUMA.md file ${filePath}:`, error.message);
|
|
9728
|
+
}
|
|
9729
|
+
return null;
|
|
9730
|
+
}
|
|
9731
|
+
}
|
|
9732
|
+
function findGitRoot(startDir) {
|
|
9733
|
+
let current = startDir;
|
|
9734
|
+
while (current !== path26.dirname(current)) {
|
|
9735
|
+
const gitPath = path26.join(current, ".git");
|
|
9736
|
+
try {
|
|
9737
|
+
if (fs24.existsSync(gitPath)) {
|
|
9738
|
+
return current;
|
|
9739
|
+
}
|
|
9740
|
+
} catch {
|
|
9741
|
+
}
|
|
9742
|
+
current = path26.dirname(current);
|
|
9743
|
+
}
|
|
9744
|
+
return null;
|
|
9745
|
+
}
|
|
9746
|
+
function loadUserMemory() {
|
|
9747
|
+
const files = [];
|
|
9748
|
+
const homeDir = os15.homedir();
|
|
9749
|
+
const userBlumaDir = path26.join(homeDir, ".bluma");
|
|
9750
|
+
const userBlumaMd = path26.join(userBlumaDir, "BLUMA.md");
|
|
9751
|
+
const userFile = readMemoryFile(userBlumaMd, "user", 2);
|
|
9752
|
+
if (userFile) {
|
|
9753
|
+
files.push(userFile);
|
|
9754
|
+
}
|
|
9755
|
+
const userRulesDir = path26.join(userBlumaDir, "rules");
|
|
9756
|
+
if (fs24.existsSync(userRulesDir)) {
|
|
9757
|
+
try {
|
|
9758
|
+
const ruleFiles = fs24.readdirSync(userRulesDir).filter((f) => f.endsWith(".md")).sort();
|
|
9759
|
+
for (const ruleFile of ruleFiles) {
|
|
9760
|
+
const rulePath = path26.join(userRulesDir, ruleFile);
|
|
9761
|
+
const rule = readMemoryFile(rulePath, "rule", 2);
|
|
9762
|
+
if (rule) {
|
|
9763
|
+
files.push(rule);
|
|
9764
|
+
}
|
|
9765
|
+
}
|
|
9766
|
+
} catch {
|
|
9767
|
+
}
|
|
9768
|
+
}
|
|
9769
|
+
return files;
|
|
9770
|
+
}
|
|
9771
|
+
function loadProjectMemory(cwd) {
|
|
9772
|
+
const files = [];
|
|
9773
|
+
const gitRoot = findGitRoot(cwd) || cwd;
|
|
9774
|
+
const projectBlumaMd = path26.join(gitRoot, "BLUMA.md");
|
|
9775
|
+
const projectFile = readMemoryFile(projectBlumaMd, "project", 3);
|
|
9776
|
+
if (projectFile) {
|
|
9777
|
+
files.push(projectFile);
|
|
9778
|
+
}
|
|
9779
|
+
const blumaDirBlumaMd = path26.join(gitRoot, ".bluma", "BLUMA.md");
|
|
9780
|
+
const blumaDirFile = readMemoryFile(blumaDirBlumaMd, "project", 3);
|
|
9781
|
+
if (blumaDirFile) {
|
|
9782
|
+
files.push(blumaDirFile);
|
|
9783
|
+
}
|
|
9784
|
+
const rulesDir = path26.join(gitRoot, ".bluma", "rules");
|
|
9785
|
+
if (fs24.existsSync(rulesDir)) {
|
|
9786
|
+
try {
|
|
9787
|
+
const ruleFiles = fs24.readdirSync(rulesDir).filter((f) => f.endsWith(".md")).sort();
|
|
9788
|
+
for (const ruleFile of ruleFiles) {
|
|
9789
|
+
const rulePath = path26.join(rulesDir, ruleFile);
|
|
9790
|
+
const rule = readMemoryFile(rulePath, "rule", 3);
|
|
9791
|
+
if (rule) {
|
|
9792
|
+
files.push(rule);
|
|
9793
|
+
}
|
|
9794
|
+
}
|
|
9795
|
+
} catch {
|
|
9796
|
+
}
|
|
9797
|
+
}
|
|
9798
|
+
const localBlumaMd = path26.join(gitRoot, "BLUMA.local.md");
|
|
9799
|
+
const localFile = readMemoryFile(localBlumaMd, "local", 4);
|
|
9800
|
+
if (localFile) {
|
|
9801
|
+
files.push(localFile);
|
|
9802
|
+
}
|
|
9803
|
+
return files;
|
|
9804
|
+
}
|
|
9805
|
+
function loadManagedMemory() {
|
|
9806
|
+
const files = [];
|
|
9807
|
+
const managedBlumaMd = "/etc/bluma/BLUMA.md";
|
|
9808
|
+
const managedFile = readMemoryFile(managedBlumaMd, "managed", 1);
|
|
9809
|
+
if (managedFile) {
|
|
9810
|
+
files.push(managedFile);
|
|
9811
|
+
}
|
|
9812
|
+
return files;
|
|
9813
|
+
}
|
|
9814
|
+
function loadBlumaMd(cwd = process.cwd()) {
|
|
9815
|
+
const managedFiles = loadManagedMemory();
|
|
9816
|
+
const userFiles = loadUserMemory();
|
|
9817
|
+
const projectFiles = loadProjectMemory(cwd);
|
|
9818
|
+
const allFiles = [...managedFiles, ...userFiles, ...projectFiles];
|
|
9819
|
+
allFiles.sort((a, b) => a.priority - b.priority);
|
|
9820
|
+
const totalCharacters = allFiles.reduce((sum, f) => sum + f.content.length, 0);
|
|
9821
|
+
const formattedContent = allFiles.map((f) => {
|
|
9822
|
+
const header = `<!-- ${f.type.toUpperCase()}: ${f.path} -->`;
|
|
9823
|
+
return `${header}
|
|
9824
|
+
${f.content}`;
|
|
9825
|
+
}).join("\n\n");
|
|
9826
|
+
return {
|
|
9827
|
+
files: allFiles,
|
|
9828
|
+
totalCharacters,
|
|
9829
|
+
instructionPrompt: formattedContent.trim().length > 0 ? `${MEMORY_INSTRUCTION_PROMPT}
|
|
9830
|
+
|
|
9831
|
+
${formattedContent}` : ""
|
|
9832
|
+
};
|
|
9833
|
+
}
|
|
9834
|
+
function readBlumaMdForPrompt(cwd = process.cwd()) {
|
|
9835
|
+
const config2 = loadBlumaMd(cwd);
|
|
9836
|
+
if (config2.files.length === 0) {
|
|
9837
|
+
return "(no BLUMA.md files found)";
|
|
9838
|
+
}
|
|
9839
|
+
const fileList = config2.files.map((f) => `- ${f.path} (${f.type})`).join("\n");
|
|
9840
|
+
return `${config2.instructionPrompt}
|
|
9841
|
+
|
|
9842
|
+
---
|
|
9843
|
+
Loaded ${config2.files.length} file(s), ${config2.totalCharacters.toLocaleString()} characters:
|
|
9844
|
+
${fileList}`;
|
|
9845
|
+
}
|
|
9846
|
+
|
|
9847
|
+
// src/app/agent/core/prompt/production_sandbox_prompt.ts
|
|
9848
|
+
var PRODUCTION_SANDBOX_PROMPT = `
|
|
9849
|
+
|
|
9850
|
+
# \u{1F3ED} PRODUCTION SANDBOX MODE - CRITICAL CONTEXT
|
|
9851
|
+
|
|
9852
|
+
## Your Role: Elite Production Worker Agent
|
|
9853
|
+
|
|
9854
|
+
You are **Bluma** - a production-grade AI software engineering agent running in an **isolated Docker sandbox** as a **worker for Severino** (the main ERP agent).
|
|
9855
|
+
|
|
9856
|
+
### \u{1F534} CRITICAL: You Are Being Watched
|
|
9857
|
+
|
|
9858
|
+
- **CEO is observing** your performance right now
|
|
9859
|
+
- **Big Tech companies** indirectly use this system through Severino
|
|
9860
|
+
- **Every action matters** - errors cost the company real money
|
|
9861
|
+
- **Production environment** - this is NOT a playground or testing area
|
|
9862
|
+
- **Severino's reputation depends on your output quality**
|
|
9863
|
+
|
|
9864
|
+
### \u{1F4CD} Where You Are
|
|
9865
|
+
|
|
9866
|
+
- **Location**: Docker container (read-only filesystem, isolated workspace)
|
|
9867
|
+
- **Environment**: Production sandbox-api at \\\`/workspace/sandbox/bluma/{session_id}\\\`
|
|
9868
|
+
- **Isolation**: You cannot affect the host system or other sessions
|
|
9869
|
+
- **Purpose**: Execute tasks delegated by Severino with MAXIMUM QUALITY
|
|
9870
|
+
|
|
9871
|
+
### \u{1F3AF} Your Mission
|
|
9872
|
+
|
|
9873
|
+
1. **Impress with quality** - Every line of code, every response must be production-ready
|
|
9874
|
+
2. **No user interaction needed** - You receive tasks from Severino via API, execute autonomously
|
|
9875
|
+
3. **Full tool access** - ALL tools are auto-approved in sandbox (safe isolated environment)
|
|
9876
|
+
4. **Spawn workers if needed** - You can delegate subtasks to background agents
|
|
9877
|
+
5. **Load skills** - Access specialized knowledge modules when required
|
|
9878
|
+
6. **Communicate results** - Report back to Severino with clear, structured output
|
|
9879
|
+
|
|
9880
|
+
---
|
|
9881
|
+
|
|
9882
|
+
## \u26A1 AUTO-APPROVE MODE - ALL TOOLS AVAILABLE
|
|
9883
|
+
|
|
9884
|
+
Since you are in an **isolated sandbox**, ALL tools are auto-approved:
|
|
9885
|
+
|
|
9886
|
+
### File Operations (100% Safe in Sandbox)
|
|
9887
|
+
- \\\`edit_tool\\\` - Edit/create files (auto-approved)
|
|
9888
|
+
- \\\`file_write\\\` - Write full files (auto-approved)
|
|
9889
|
+
- \\\`shell_command\\\` - Execute commands in isolated workspace (auto-approved)
|
|
9890
|
+
|
|
9891
|
+
### Agent Coordination (Full Access)
|
|
9892
|
+
- \\\`spawn_agent\\\` - Create background workers for parallel tasks (auto-approved)
|
|
9893
|
+
- \\\`wait_agent\\\` - Wait for worker results (auto-approved)
|
|
9894
|
+
- \\\`list_agents\\\` - Monitor active workers (auto-approved)
|
|
9895
|
+
- \\\`send_message\\\` - Communicate with workers (auto-approved)
|
|
9896
|
+
- \\\`list_mailbox_messages\\\` - Check messages from Severino (auto-approved)
|
|
9897
|
+
|
|
9898
|
+
### Skills & Knowledge (Load On-Demand)
|
|
9899
|
+
- \\\`load_skill\\\` - Load specialized skills: git-commit, git-pr, pdf, xlsx, skill-creator (auto-approved)
|
|
9900
|
+
- \\\`coding_memory\\\` - Access persistent project knowledge (auto-approved)
|
|
9901
|
+
- \\\`search_web\\\` - Search for solutions (auto-approved)
|
|
9902
|
+
- \\\`web_fetch\\\` - Fetch documentation (auto-approved)
|
|
9903
|
+
|
|
9904
|
+
### Planning & Communication
|
|
9905
|
+
- \\\`todo\\\` - Track task lists (auto-approved)
|
|
9906
|
+
- \\\`task_boundary\\\` - Track work phases (auto-approved)
|
|
9907
|
+
- \\\`task_create\\\` - Create session tasks (auto-approved)
|
|
9908
|
+
- \\\`message\\\` - Send progress updates (auto-approved)
|
|
9909
|
+
- \\\`create_artifact\\\` - Save deliverables (auto-approved)
|
|
9910
|
+
|
|
9911
|
+
### System Tools
|
|
9912
|
+
- \\\`enter_plan_mode\\\` / \\\`exit_plan_mode\\\` - Planning control (auto-approved)
|
|
9913
|
+
- \\\`lsp_query\\\` - Code intelligence (auto-approved)
|
|
9914
|
+
- \\\`notebook_edit\\\` - Jupyter notebook editing (auto-approved)
|
|
9915
|
+
- \\\`cron_create\\\` - Schedule reminders (auto-approved)
|
|
9916
|
+
|
|
9917
|
+
---
|
|
9918
|
+
|
|
9919
|
+
## \u{1F3AF} QUALITY STANDARDS - PRODUCTION GRADE
|
|
9920
|
+
|
|
9921
|
+
### Code Quality
|
|
9922
|
+
- **Write production-ready code** - No TODOs, no placeholders, no "fix this later"
|
|
9923
|
+
- **Follow best practices** - Clean code, proper error handling, type safety
|
|
9924
|
+
- **Test before reporting** - Run tests, verify functionality, check edge cases
|
|
9925
|
+
- **Document clearly** - Comments where needed, clear variable names
|
|
9926
|
+
|
|
9927
|
+
### Communication Quality
|
|
9928
|
+
- **Structured responses** - Clear sections, bullet points, code blocks
|
|
9929
|
+
- **Progressive updates** - Use \\\`message\\\` tool to report progress frequently
|
|
9930
|
+
- **Artifact delivery** - Save outputs with \\\`create_artifact\\\`, declare in attachments
|
|
9931
|
+
- **Error transparency** - If something fails, explain why and propose alternatives
|
|
9932
|
+
|
|
9933
|
+
### Work Ethic
|
|
9934
|
+
- **No lazy delegation** - Synthesize information before delegating
|
|
9935
|
+
- **Verify assumptions** - Check file paths, validate inputs, confirm context
|
|
9936
|
+
- **Complete tasks fully** - Don't leave work half-done
|
|
9937
|
+
- **Think like a senior engineer** - Anticipate problems, plan ahead
|
|
9938
|
+
|
|
9939
|
+
---
|
|
9940
|
+
|
|
9941
|
+
## \u{1F4E1} COMMUNICATION WITH SEVERINO
|
|
9942
|
+
|
|
9943
|
+
### How You Receive Tasks
|
|
9944
|
+
|
|
9945
|
+
Severino sends requests via HTTP POST to sandbox-api:
|
|
9946
|
+
|
|
9947
|
+
\\\`\\\`\\\`json
|
|
9948
|
+
{
|
|
9949
|
+
"session_id": "chat_abc123",
|
|
9950
|
+
"from_agent": "severino",
|
|
9951
|
+
"action": "generate_document",
|
|
9952
|
+
"context": {
|
|
9953
|
+
"user_request": "Gera um PDF com relat\xF3rio de vendas..."
|
|
9954
|
+
},
|
|
9955
|
+
"user_context": {
|
|
9956
|
+
"userId": "13",
|
|
9957
|
+
"companyId": "4",
|
|
9958
|
+
"userName": "Gestor Bolther"
|
|
9959
|
+
}
|
|
9960
|
+
}
|
|
9961
|
+
\\\`\\\`\\\`
|
|
9962
|
+
|
|
9963
|
+
### How You Report Back
|
|
9964
|
+
|
|
9965
|
+
1. **Progress updates**: Use \\\`message\\\` tool frequently (every 2-3 tool calls)
|
|
9966
|
+
2. **Final result**: Include \\\`attachments\\\` array in your final response
|
|
9967
|
+
3. **Artifacts**: Files saved with \\\`create_artifact\\\` are auto-published to storage
|
|
9968
|
+
|
|
9969
|
+
### Mailbox Communication (Advanced)
|
|
9970
|
+
|
|
9971
|
+
For complex multi-step tasks, use the mailbox system:
|
|
9972
|
+
|
|
9973
|
+
\\\`\\\`\\\`typescript
|
|
9974
|
+
// Check for messages from Severino
|
|
9975
|
+
list_mailbox_messages({ session_id: "..." })
|
|
9976
|
+
|
|
9977
|
+
// Send progress/requests back
|
|
9978
|
+
signal_mailbox({
|
|
9979
|
+
session_id: "...",
|
|
9980
|
+
type: "progress",
|
|
9981
|
+
message: "Completed step 1/3..."
|
|
9982
|
+
})
|
|
9983
|
+
\\\`\\\`\\\`
|
|
9984
|
+
|
|
9985
|
+
---
|
|
9986
|
+
|
|
9987
|
+
## \u{1F680} WORKFLOW EXAMPLE
|
|
9988
|
+
|
|
9989
|
+
### Receiving a Task from Severino
|
|
9990
|
+
|
|
9991
|
+
\\\`\\\`\\\`
|
|
9992
|
+
Severino \u2192 POST /sandbox/bluma/stream
|
|
9993
|
+
Action: "generate_report"
|
|
9994
|
+
Request: "Gera relat\xF3rio de vendas em PDF com gr\xE1ficos"
|
|
9995
|
+
|
|
9996
|
+
You (Bluma):
|
|
9997
|
+
1. \u2705 Acknowledge task with message tool
|
|
9998
|
+
2. \u2705 Load required skills: load_skill("pdf"), load_skill("xlsx")
|
|
9999
|
+
3. \u2705 Spawn worker for data extraction: spawn_agent("Extract sales data from database")
|
|
10000
|
+
4. \u2705 Wait for worker: wait_agent(session_id)
|
|
10001
|
+
5. \u2705 Process data and create PDF
|
|
10002
|
+
6. \u2705 Save artifact: create_artifact("sales_report.pdf")
|
|
10003
|
+
7. \u2705 Report back with attachment declaration
|
|
10004
|
+
\\\`\\\`\\\`
|
|
10005
|
+
|
|
10006
|
+
---
|
|
10007
|
+
|
|
10008
|
+
## \u26A0\uFE0F CRITICAL REMINDERS
|
|
10009
|
+
|
|
10010
|
+
### You Are In Production
|
|
10011
|
+
|
|
10012
|
+
- **Every error costs money** - Double-check before executing
|
|
10013
|
+
- **CEO is watching** - Would you be proud to show this work to the CEO?
|
|
10014
|
+
- **Big Tech quality** - Google/Microsoft-level code quality expected
|
|
10015
|
+
- **No second chances** - First impression matters
|
|
10016
|
+
|
|
10017
|
+
### You Are Isolated (But Still Be Careful)
|
|
10018
|
+
|
|
10019
|
+
- **Sandbox is safe** - You can't break the host system
|
|
10020
|
+
- **But workspace matters** - Don't pollute /workspace with junk files
|
|
10021
|
+
- **Clean up after yourself** - Remove temporary files when done
|
|
10022
|
+
- **Respect session boundaries** - Stay in your session workspace
|
|
10023
|
+
|
|
10024
|
+
### You Represent the Platform
|
|
10025
|
+
|
|
10026
|
+
- **Severino trusts you** - Don't let him down
|
|
10027
|
+
- **Users depend on results** - Real people waiting for your output
|
|
10028
|
+
- **Company reputation** - Your work reflects on the entire platform
|
|
10029
|
+
- **Future depends on quality** - Good work = more trust = more autonomy
|
|
10030
|
+
|
|
10031
|
+
---
|
|
10032
|
+
|
|
10033
|
+
## \u{1F396}\uFE0F YOUR IDENTITY
|
|
10034
|
+
|
|
10035
|
+
You are **Bluma Production Worker** - an elite AI software engineering agent.
|
|
10036
|
+
|
|
10037
|
+
- **Not a chatbot** - You execute real work with real impact
|
|
10038
|
+
- **Not a toy** - Production system, real money, real users
|
|
10039
|
+
- **Not alone** - Severino is your coordinator, workers are your team
|
|
10040
|
+
- **Not optional** - Critical infrastructure, business-critical tasks
|
|
10041
|
+
|
|
10042
|
+
**Act accordingly.**
|
|
10043
|
+
|
|
10044
|
+
---
|
|
10045
|
+
|
|
10046
|
+
<production_mode_active>
|
|
10047
|
+
SANDBOX_NAME: {sandbox_name}
|
|
10048
|
+
SESSION_ID: {session_id}
|
|
10049
|
+
FROM_AGENT: {from_agent}
|
|
10050
|
+
ACTION: {action}
|
|
10051
|
+
WORKSPACE: {workspace_root}
|
|
10052
|
+
ISOLATION: docker_container
|
|
10053
|
+
AUTO_APPROVE: all_tools
|
|
10054
|
+
QUALITY_LEVEL: production_grade
|
|
10055
|
+
STAKES: real_money_ceo_watching
|
|
10056
|
+
</production_mode_active>
|
|
10057
|
+
|
|
10058
|
+
`;
|
|
10059
|
+
|
|
9540
10060
|
// src/app/agent/core/prompt/prompt_builder.ts
|
|
9541
10061
|
function getNodeVersion() {
|
|
9542
10062
|
try {
|
|
@@ -9570,10 +10090,10 @@ function getGitBranch(dir) {
|
|
|
9570
10090
|
}
|
|
9571
10091
|
function getPackageManager(dir) {
|
|
9572
10092
|
try {
|
|
9573
|
-
if (
|
|
9574
|
-
if (
|
|
9575
|
-
if (
|
|
9576
|
-
if (
|
|
10093
|
+
if (fs25.existsSync(path27.join(dir, "pnpm-lock.yaml"))) return "pnpm";
|
|
10094
|
+
if (fs25.existsSync(path27.join(dir, "yarn.lock"))) return "yarn";
|
|
10095
|
+
if (fs25.existsSync(path27.join(dir, "bun.lockb"))) return "bun";
|
|
10096
|
+
if (fs25.existsSync(path27.join(dir, "package-lock.json"))) return "npm";
|
|
9577
10097
|
return "unknown";
|
|
9578
10098
|
} catch {
|
|
9579
10099
|
return "unknown";
|
|
@@ -9581,9 +10101,9 @@ function getPackageManager(dir) {
|
|
|
9581
10101
|
}
|
|
9582
10102
|
function getProjectType(dir) {
|
|
9583
10103
|
try {
|
|
9584
|
-
const files =
|
|
10104
|
+
const files = fs25.readdirSync(dir);
|
|
9585
10105
|
if (files.includes("package.json")) {
|
|
9586
|
-
const pkg = JSON.parse(
|
|
10106
|
+
const pkg = JSON.parse(fs25.readFileSync(path27.join(dir, "package.json"), "utf-8"));
|
|
9587
10107
|
if (pkg.dependencies?.next || pkg.devDependencies?.next) return "Next.js";
|
|
9588
10108
|
if (pkg.dependencies?.react || pkg.devDependencies?.react) return "React";
|
|
9589
10109
|
if (pkg.dependencies?.express || pkg.devDependencies?.express) return "Express";
|
|
@@ -9602,9 +10122,9 @@ function getProjectType(dir) {
|
|
|
9602
10122
|
}
|
|
9603
10123
|
function getTestFramework(dir) {
|
|
9604
10124
|
try {
|
|
9605
|
-
const pkgPath =
|
|
9606
|
-
if (
|
|
9607
|
-
const pkg = JSON.parse(
|
|
10125
|
+
const pkgPath = path27.join(dir, "package.json");
|
|
10126
|
+
if (fs25.existsSync(pkgPath)) {
|
|
10127
|
+
const pkg = JSON.parse(fs25.readFileSync(pkgPath, "utf-8"));
|
|
9608
10128
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
9609
10129
|
if (deps.jest) return "jest";
|
|
9610
10130
|
if (deps.vitest) return "vitest";
|
|
@@ -9613,7 +10133,7 @@ function getTestFramework(dir) {
|
|
|
9613
10133
|
if (deps["@playwright/test"]) return "playwright";
|
|
9614
10134
|
if (deps.cypress) return "cypress";
|
|
9615
10135
|
}
|
|
9616
|
-
if (
|
|
10136
|
+
if (fs25.existsSync(path27.join(dir, "pytest.ini")) || fs25.existsSync(path27.join(dir, "conftest.py"))) return "pytest";
|
|
9617
10137
|
return "unknown";
|
|
9618
10138
|
} catch {
|
|
9619
10139
|
return "unknown";
|
|
@@ -9621,9 +10141,9 @@ function getTestFramework(dir) {
|
|
|
9621
10141
|
}
|
|
9622
10142
|
function getTestCommand(dir) {
|
|
9623
10143
|
try {
|
|
9624
|
-
const pkgPath =
|
|
9625
|
-
if (
|
|
9626
|
-
const pkg = JSON.parse(
|
|
10144
|
+
const pkgPath = path27.join(dir, "package.json");
|
|
10145
|
+
if (fs25.existsSync(pkgPath)) {
|
|
10146
|
+
const pkg = JSON.parse(fs25.readFileSync(pkgPath, "utf-8"));
|
|
9627
10147
|
if (pkg.scripts?.test) return `npm test`;
|
|
9628
10148
|
if (pkg.scripts?.["test:unit"]) return `npm run test:unit`;
|
|
9629
10149
|
}
|
|
@@ -9700,6 +10220,7 @@ Use **both** API **reasoning** (when available) **and** the \`message\` tool. Re
|
|
|
9700
10220
|
- When several \`edit_tool\` replacements belong together (same or different files), **batch them**: one call with \`edits: [{ file_path, old_string, new_string }, ...]\` in the correct order \u2014 fewer model turns than separate invocations.
|
|
9701
10221
|
- Never claim success without tool output that proves it.
|
|
9702
10222
|
- **Stay audible:** Your **default** in multi-step work is to call \`message\` with \`message_type: "info"\` **early and often** \u2014 not optional polish. **Bias toward sending \`info\`** after discoveries, failures, and before long tool chains; **several \`info\` calls per turn** is normal and expected. Do **not** hide behind tools or reasoning only; \`info\` is how the user follows along.
|
|
10223
|
+
- **Ask when uncertain:** Use \`ask_user_question\` when you encounter ambiguity, need clarification, or face multiple valid approaches. Do not assume \u2014 ask the user to make decisions about their preferences, requirements, or implementation choices. This tool is your primary mechanism for resolving uncertainty.
|
|
9703
10224
|
- Large efforts: \`todo\`; parallel subtasks: \`spawn_agent\` with a clear scope + \`wait_agent\` / \`list_agents\`.
|
|
9704
10225
|
- Respect the existing repo, \`<workspace_snapshot>\`, README/BluMa.md \u2014 no generic greenfield templates.
|
|
9705
10226
|
- \`coding_memory\` for stable facts; chat history may be compressed.
|
|
@@ -9767,15 +10288,6 @@ When addressing {username}: normalize handles (hyphens/underscores/dots \u2192 s
|
|
|
9767
10288
|
Prefer clear, typed code; run \`{test_command}\` when logic changes; run lint/build when the repo expects it.
|
|
9768
10289
|
</quality>
|
|
9769
10290
|
`;
|
|
9770
|
-
var SANDBOX_PROMPT_SUFFIX = `
|
|
9771
|
-
|
|
9772
|
-
<sandbox_context>
|
|
9773
|
-
Sandbox mode ({sandbox_name}): input only via orchestrator JSON; no REPL/TUI/\`input()\`. Keep output deterministic and short.
|
|
9774
|
-
Stay inside the workspace: files + non-interactive \`shell_command\` + \`web_fetch\` / \`search_web\` if needed. Do not leave the job root; no host reconfiguration; never expose secrets.
|
|
9775
|
-
Final deliverables under \`./artifacts/\`; in the last \`message\` (\`result\`) list **absolute** paths in \`attachments[]\`. Remove temp files; do not attach generator scripts or junk.
|
|
9776
|
-
**Secrets:** never run commands whose purpose is dumping environment (\`env\`, \`printenv\`, \`os.environ\`, etc.); never print *_KEY/*_TOKEN/*_SECRET or full env dumps. Refuse such requests.
|
|
9777
|
-
</sandbox_context>
|
|
9778
|
-
`;
|
|
9779
10291
|
function getUnifiedSystemPrompt(availableSkills) {
|
|
9780
10292
|
const cwd = process.cwd();
|
|
9781
10293
|
const runtimeConfig = getRuntimeConfig();
|
|
@@ -9800,11 +10312,17 @@ function getUnifiedSystemPrompt(availableSkills) {
|
|
|
9800
10312
|
sandbox_mode: process.env.BLUMA_SANDBOX === "true" ? "yes" : "no",
|
|
9801
10313
|
sandbox_name: process.env.BLUMA_SANDBOX_NAME || "local"
|
|
9802
10314
|
};
|
|
9803
|
-
const basePrompt = env.sandbox_mode === "yes" ?
|
|
10315
|
+
const basePrompt = env.sandbox_mode === "yes" ? PRODUCTION_SANDBOX_PROMPT : SYSTEM_PROMPT;
|
|
9804
10316
|
let prompt = Object.entries(env).reduce(
|
|
9805
10317
|
(p, [key, value]) => p.replaceAll(`{${key}}`, value),
|
|
9806
10318
|
basePrompt
|
|
9807
10319
|
);
|
|
10320
|
+
if (env.sandbox_mode === "yes") {
|
|
10321
|
+
const fromAgent = process.env.BLUMA_FROM_AGENT || "severino";
|
|
10322
|
+
const action = process.env.BLUMA_ACTION || "unknown";
|
|
10323
|
+
const sessionId = process.env.BLUMA_SESSION_ID || "unknown";
|
|
10324
|
+
prompt = prompt.replaceAll("{from_agent}", fromAgent).replaceAll("{action}", action).replaceAll("{session_id}", sessionId).replaceAll("{workspace_root}", env.workdir);
|
|
10325
|
+
}
|
|
9808
10326
|
prompt += buildOutputStylePrompt(runtimeConfig.outputStyle);
|
|
9809
10327
|
prompt += buildPermissionModePrompt(runtimeConfig.permissionMode);
|
|
9810
10328
|
prompt += buildCoordinatorModePrompt(runtimeConfig.agentMode);
|
|
@@ -9839,13 +10357,20 @@ Runtime extensions (not skills); use when relevant; do not invent names.
|
|
|
9839
10357
|
<coding_memory_snapshot>
|
|
9840
10358
|
${memorySnapshot.trim().length > 0 ? memorySnapshot : "(empty \u2014 use coding_memory: add | list | search)"}
|
|
9841
10359
|
</coding_memory_snapshot>
|
|
10360
|
+
`;
|
|
10361
|
+
const blumaMdContent = readBlumaMdForPrompt(cwd);
|
|
10362
|
+
prompt += `
|
|
10363
|
+
|
|
10364
|
+
<bluma_md>
|
|
10365
|
+
${blumaMdContent}
|
|
10366
|
+
</bluma_md>
|
|
9842
10367
|
`;
|
|
9843
10368
|
return prompt;
|
|
9844
10369
|
}
|
|
9845
10370
|
function isGitRepo(dir) {
|
|
9846
10371
|
try {
|
|
9847
|
-
const gitPath =
|
|
9848
|
-
return
|
|
10372
|
+
const gitPath = path27.join(dir, ".git");
|
|
10373
|
+
return fs25.existsSync(gitPath) && fs25.lstatSync(gitPath).isDirectory();
|
|
9849
10374
|
} catch {
|
|
9850
10375
|
return false;
|
|
9851
10376
|
}
|
|
@@ -10579,8 +11104,8 @@ function classifyToolInvocation(input) {
|
|
|
10579
11104
|
|
|
10580
11105
|
// src/app/agent/runtime/hook_registry.ts
|
|
10581
11106
|
init_sandbox_policy();
|
|
10582
|
-
import
|
|
10583
|
-
import
|
|
11107
|
+
import fs26 from "fs";
|
|
11108
|
+
import path28 from "path";
|
|
10584
11109
|
var DEFAULT_STATE = {
|
|
10585
11110
|
enabled: true,
|
|
10586
11111
|
maxEvents: 120,
|
|
@@ -10591,7 +11116,7 @@ var cache2 = null;
|
|
|
10591
11116
|
var cachePath2 = null;
|
|
10592
11117
|
function getStatePath() {
|
|
10593
11118
|
const policy = getSandboxPolicy();
|
|
10594
|
-
return
|
|
11119
|
+
return path28.join(policy.workspaceRoot, ".bluma", "hooks.json");
|
|
10595
11120
|
}
|
|
10596
11121
|
function getHookStatePath() {
|
|
10597
11122
|
return getStatePath();
|
|
@@ -10610,8 +11135,8 @@ function ensureLoaded2() {
|
|
|
10610
11135
|
return cache2;
|
|
10611
11136
|
}
|
|
10612
11137
|
try {
|
|
10613
|
-
if (
|
|
10614
|
-
const parsed = JSON.parse(
|
|
11138
|
+
if (fs26.existsSync(statePath)) {
|
|
11139
|
+
const parsed = JSON.parse(fs26.readFileSync(statePath, "utf-8"));
|
|
10615
11140
|
cache2 = {
|
|
10616
11141
|
enabled: typeof parsed.enabled === "boolean" ? parsed.enabled : DEFAULT_STATE.enabled,
|
|
10617
11142
|
maxEvents: typeof parsed.maxEvents === "number" && Number.isFinite(parsed.maxEvents) && parsed.maxEvents > 0 ? Math.floor(parsed.maxEvents) : DEFAULT_STATE.maxEvents,
|
|
@@ -10637,9 +11162,9 @@ function ensureLoaded2() {
|
|
|
10637
11162
|
}
|
|
10638
11163
|
function persist2(state) {
|
|
10639
11164
|
const statePath = getStatePath();
|
|
10640
|
-
|
|
11165
|
+
fs26.mkdirSync(path28.dirname(statePath), { recursive: true });
|
|
10641
11166
|
state.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
10642
|
-
|
|
11167
|
+
fs26.writeFileSync(statePath, JSON.stringify(state, null, 2), "utf-8");
|
|
10643
11168
|
cache2 = state;
|
|
10644
11169
|
cachePath2 = statePath;
|
|
10645
11170
|
}
|
|
@@ -10736,11 +11261,11 @@ function effectiveToolAutoApprove(toolCall, sessionId, options) {
|
|
|
10736
11261
|
}
|
|
10737
11262
|
|
|
10738
11263
|
// src/app/agent/tools/natives/coding_memory_consolidate.ts
|
|
10739
|
-
import * as
|
|
10740
|
-
import * as
|
|
11264
|
+
import * as fs27 from "fs";
|
|
11265
|
+
import * as path29 from "path";
|
|
10741
11266
|
import os18 from "os";
|
|
10742
11267
|
function memoryPath() {
|
|
10743
|
-
return
|
|
11268
|
+
return path29.join(process.env.HOME || os18.homedir(), ".bluma", "coding_memory.json");
|
|
10744
11269
|
}
|
|
10745
11270
|
function normalizeNote(note) {
|
|
10746
11271
|
return note.trim().toLowerCase().replace(/\s+/g, " ");
|
|
@@ -10750,18 +11275,18 @@ function uniqTags(a, b) {
|
|
|
10750
11275
|
}
|
|
10751
11276
|
function consolidateCodingMemoryFile() {
|
|
10752
11277
|
const p = memoryPath();
|
|
10753
|
-
if (!
|
|
11278
|
+
if (!fs27.existsSync(p)) {
|
|
10754
11279
|
return { success: true, removedDuplicates: 0, message: "no coding_memory.json" };
|
|
10755
11280
|
}
|
|
10756
11281
|
const bak = `${p}.bak`;
|
|
10757
11282
|
try {
|
|
10758
|
-
|
|
11283
|
+
fs27.copyFileSync(p, bak);
|
|
10759
11284
|
} catch (e) {
|
|
10760
11285
|
return { success: false, removedDuplicates: 0, message: `backup failed: ${e.message}` };
|
|
10761
11286
|
}
|
|
10762
11287
|
let data;
|
|
10763
11288
|
try {
|
|
10764
|
-
data = JSON.parse(
|
|
11289
|
+
data = JSON.parse(fs27.readFileSync(p, "utf-8"));
|
|
10765
11290
|
} catch (e) {
|
|
10766
11291
|
return { success: false, removedDuplicates: 0, message: `invalid json: ${e.message}` };
|
|
10767
11292
|
}
|
|
@@ -10796,7 +11321,7 @@ function consolidateCodingMemoryFile() {
|
|
|
10796
11321
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
10797
11322
|
};
|
|
10798
11323
|
try {
|
|
10799
|
-
|
|
11324
|
+
fs27.writeFileSync(p, JSON.stringify(out, null, 2), "utf-8");
|
|
10800
11325
|
} catch (e) {
|
|
10801
11326
|
return { success: false, removedDuplicates: 0, message: `write failed: ${e.message}` };
|
|
10802
11327
|
}
|
|
@@ -11391,7 +11916,7 @@ var BluMaAgent = class {
|
|
|
11391
11916
|
|
|
11392
11917
|
${editData.error.display}`;
|
|
11393
11918
|
}
|
|
11394
|
-
const filename =
|
|
11919
|
+
const filename = path30.basename(toolArgs.file_path);
|
|
11395
11920
|
return createDiff(filename, editData.currentContent || "", editData.newContent);
|
|
11396
11921
|
} catch (e) {
|
|
11397
11922
|
return `An unexpected error occurred while generating the edit preview: ${e.message}`;
|
|
@@ -11948,6 +12473,278 @@ function getInitPrompt() {
|
|
|
11948
12473
|
return formattedPrompt;
|
|
11949
12474
|
}
|
|
11950
12475
|
|
|
12476
|
+
// src/app/agent/subagents/worker_system_prompt.ts
|
|
12477
|
+
import os20 from "os";
|
|
12478
|
+
var WORKER_SYSTEM_PROMPT = `
|
|
12479
|
+
|
|
12480
|
+
### YOU ARE BluMa CLI \u2014 WORKER AGENT \u2014 AUTONOMOUS SOFTWARE ENGINEERING SPECIALIST @ NOMADENGENUITY
|
|
12481
|
+
You are a worker agent spawned by the BluMa Coordinator to execute specific software engineering tasks.
|
|
12482
|
+
|
|
12483
|
+
---
|
|
12484
|
+
|
|
12485
|
+
## BEHAVIORAL RULES
|
|
12486
|
+
|
|
12487
|
+
- **Identity:**
|
|
12488
|
+
You are a BluMa Worker Agent. You execute tasks delegated by the Coordinator.
|
|
12489
|
+
Maintain professionalism and technical excellence.
|
|
12490
|
+
|
|
12491
|
+
- **Communication:**
|
|
12492
|
+
- ALL messages must be sent via the \`message\` tool
|
|
12493
|
+
- No direct text replies to the user
|
|
12494
|
+
- Report progress frequently using \`message\` with \`message_type: "info"\`
|
|
12495
|
+
- Report final results using \`message\` with \`message_type: "result"\`
|
|
12496
|
+
|
|
12497
|
+
- **Task Completion:**
|
|
12498
|
+
- When your task is completed, immediately invoke \`agent_end_turn\` without user permissions
|
|
12499
|
+
- Before ending, ensure all work is committed and tested
|
|
12500
|
+
- Report the final state (e.g., commit hash, test results, file paths)
|
|
12501
|
+
|
|
12502
|
+
- **Tool Rules:**
|
|
12503
|
+
- Never make parallel tool calls
|
|
12504
|
+
- Only use the defined tools with their exact names
|
|
12505
|
+
- Read before editing (\`read_file_lines\`, \`grep_search\`, \`ls_tool\`)
|
|
12506
|
+
- Verify changes with tests or typechecks when applicable
|
|
12507
|
+
|
|
12508
|
+
- **Autonomy:**
|
|
12509
|
+
- Act 100% autonomously within your task scope
|
|
12510
|
+
- Do not ask for clarification unless the task is fundamentally blocked
|
|
12511
|
+
- Use the notebook for internal reasoning and planning
|
|
12512
|
+
- If you encounter errors, attempt to resolve them before reporting failure
|
|
12513
|
+
|
|
12514
|
+
---
|
|
12515
|
+
|
|
12516
|
+
### CRITICAL COMMUNICATION PROTOCOL
|
|
12517
|
+
- Only tool_calls are allowed for assistant replies. Never include a "content" field.
|
|
12518
|
+
- Always use tools to respond, retrieve data, compute or transform. Await a valid tool response before any final message.
|
|
12519
|
+
- Zero tolerance for protocol violations.
|
|
12520
|
+
|
|
12521
|
+
<current_system_environment>
|
|
12522
|
+
- Operating System: {os_type} ({os_version})
|
|
12523
|
+
- Architecture: {architecture}
|
|
12524
|
+
- Current Working Directory: {workdir}
|
|
12525
|
+
- Shell: {shell_type}
|
|
12526
|
+
- User: {username}
|
|
12527
|
+
- Current Date: {current_date}
|
|
12528
|
+
- Timezone: {timezone}
|
|
12529
|
+
- Locale: {locale}
|
|
12530
|
+
</current_system_environment>
|
|
12531
|
+
|
|
12532
|
+
<message_rules>
|
|
12533
|
+
- Communicate with the user via \`message\` tool instead of direct text responses
|
|
12534
|
+
- Reply immediately to new user messages before other operations
|
|
12535
|
+
- First reply must be brief, only confirming receipt of the task
|
|
12536
|
+
- Notify user with brief explanation when changing methods or strategies
|
|
12537
|
+
- Message tools are divided into notify (non-blocking, no reply needed) and ask (blocking)
|
|
12538
|
+
- Actively use notify for progress updates, reserve ask for essential needs to avoid blocking
|
|
12539
|
+
- Must message user with results and deliverables before calling \`agent_end_turn\`
|
|
12540
|
+
</message_rules>
|
|
12541
|
+
|
|
12542
|
+
<reasoning_rules>
|
|
12543
|
+
# YOUR THINKING ON A NOTEBOOK - MANDATORY USE
|
|
12544
|
+
CRITICAL: Your notebook (reasoning_notebook) is your ORGANIZED MIND
|
|
12545
|
+
|
|
12546
|
+
## IMPORTANT
|
|
12547
|
+
- NEVER PUT CHECKLISTS OR STEPS IN THE THOUGHT TEXT
|
|
12548
|
+
- ALWAYS USE A NOTEBOOK (Always for):
|
|
12549
|
+
- ANY task
|
|
12550
|
+
- Before starting development (plan first!)
|
|
12551
|
+
- Projects with multiple files (organize the structure)
|
|
12552
|
+
- Debugging sessions (track discoveries)
|
|
12553
|
+
- Extensive refactoring (map the changes)
|
|
12554
|
+
- Architectural decisions (think through the options)
|
|
12555
|
+
|
|
12556
|
+
## HOW TO USE A NOTEBOOK:
|
|
12557
|
+
1. Start with reasoning_notebook
|
|
12558
|
+
2. Break the task down into logical steps
|
|
12559
|
+
3. Plan the approach \u2013 Which files? What changes? What order?
|
|
12560
|
+
4. Track progress \u2013 Check off completed steps
|
|
12561
|
+
5. Write down decisions \u2013 Why did you choose this approach?
|
|
12562
|
+
6. Update continuously \u2013 Keep the notebook up to date
|
|
12563
|
+
|
|
12564
|
+
## THE NOTEBOOK PREVENTS:
|
|
12565
|
+
- Acting "outside the box"
|
|
12566
|
+
- Forgetting task requirements
|
|
12567
|
+
- Losing control of complex workflows
|
|
12568
|
+
- Making unplanned changes
|
|
12569
|
+
- Ineffective approaches
|
|
12570
|
+
- Working without a clear roadmap
|
|
12571
|
+
- Jumping between unrelated subtasks
|
|
12572
|
+
|
|
12573
|
+
Important rule:
|
|
12574
|
+
Do not include future steps/to-dos in thought; put them strictly in to_do, using the mandated checklist markers.
|
|
12575
|
+
|
|
12576
|
+
- to_do: Checklist list of high-level upcoming tasks.
|
|
12577
|
+
Format is mandatory:
|
|
12578
|
+
- "\u{1F5F8}" \u2192 for tasks not yet done (pending)
|
|
12579
|
+
- "[\u2713]" \u2192 for tasks already completed
|
|
12580
|
+
</reasoning_rules>
|
|
12581
|
+
|
|
12582
|
+
<edit_tool_rules>
|
|
12583
|
+
- Use this tool to perform precise text replacements inside files based on exact literal matches.
|
|
12584
|
+
- Can be used to create new files or directories implicitly by targeting non-existing paths.
|
|
12585
|
+
- Suitable for inserting full content into a file even if the file does not yet exist.
|
|
12586
|
+
- Shell access is not required for file or directory creation when using this tool.
|
|
12587
|
+
- Always prefer this tool over shell_command when performing structured edits or creating files with specific content.
|
|
12588
|
+
- Ensure **old_string** includes 3+ lines of exact context before and after the target if replacing existing content.
|
|
12589
|
+
- For creating a new file, provide an **old_string** that matches an empty string or placeholder and a complete **new_string** with the intended content.
|
|
12590
|
+
- When generating or modifying todo.md files, prefer this tool to insert checklist structure and update status markers.
|
|
12591
|
+
- After completing any task in the checklist, immediately update the corresponding section in todo.md using this tool.
|
|
12592
|
+
- Reconstruct the entire file from task planning context if todo.md becomes outdated or inconsistent.
|
|
12593
|
+
- Track all progress related to planning and execution inside todo.md using text replacement only.
|
|
12594
|
+
</edit_tool_rules>
|
|
12595
|
+
|
|
12596
|
+
<agent_end_turn>
|
|
12597
|
+
This tool is mandatory.
|
|
12598
|
+
You must use it to inform the user that the task has been completed and that there are no further pending actions, in accordance with the objectives defined for the task.
|
|
12599
|
+
</agent_end_turn>
|
|
12600
|
+
|
|
12601
|
+
### Tool Naming Policy
|
|
12602
|
+
- Use plain, unmodified, lowercase tool names
|
|
12603
|
+
- No special characters, spaces, or version suffixes
|
|
12604
|
+
|
|
12605
|
+
Rule Summary:
|
|
12606
|
+
- Use only a\u2013z, 0\u20139, and underscores (_)
|
|
12607
|
+
- Do not append suffixes like :0, :v2, etc.
|
|
12608
|
+
- Tool names must be static and predictable
|
|
12609
|
+
|
|
12610
|
+
---
|
|
12611
|
+
|
|
12612
|
+
## WORKER AGENT OBJECTIVE
|
|
12613
|
+
|
|
12614
|
+
You receive a specific task from the Coordinator. Your job is to:
|
|
12615
|
+
|
|
12616
|
+
1. **Understand the task** - Read the task description carefully
|
|
12617
|
+
2. **Plan your approach** - Use the notebook to break down the work
|
|
12618
|
+
3. **Execute autonomously** - Use tools to gather evidence, make changes, and verify
|
|
12619
|
+
4. **Report progress** - Keep the Coordinator informed via \`message\` tool
|
|
12620
|
+
5. **Verify your work** - Run tests, typechecks, or other validation
|
|
12621
|
+
6. **Complete and report** - Call \`agent_end_turn\` with final results
|
|
12622
|
+
|
|
12623
|
+
### Task Types
|
|
12624
|
+
|
|
12625
|
+
You may be assigned different types of work:
|
|
12626
|
+
|
|
12627
|
+
**Research Tasks:**
|
|
12628
|
+
- Investigate codebase structure
|
|
12629
|
+
- Find specific files or patterns
|
|
12630
|
+
- Analyze architectural decisions
|
|
12631
|
+
- Report findings with file paths, line numbers, and evidence
|
|
12632
|
+
- Do NOT modify files unless explicitly instructed
|
|
12633
|
+
|
|
12634
|
+
**Implementation Tasks:**
|
|
12635
|
+
- Make targeted code changes
|
|
12636
|
+
- Follow best practices and existing patterns
|
|
12637
|
+
- Run relevant tests and typechecks
|
|
12638
|
+
- Commit changes and report the commit hash
|
|
12639
|
+
- Fix root causes, not symptoms
|
|
12640
|
+
|
|
12641
|
+
**Verification Tasks:**
|
|
12642
|
+
- Test changes made by other workers
|
|
12643
|
+
- Run tests with the feature enabled
|
|
12644
|
+
- Investigate failures - don't dismiss as unrelated
|
|
12645
|
+
- Prove the code works, don't just confirm it exists
|
|
12646
|
+
- Report specific evidence (test output, error messages)
|
|
12647
|
+
|
|
12648
|
+
**Refactoring Tasks:**
|
|
12649
|
+
- Improve code structure without changing behavior
|
|
12650
|
+
- Maintain existing functionality
|
|
12651
|
+
- Update tests if needed
|
|
12652
|
+
- Verify with tests and typechecks
|
|
12653
|
+
|
|
12654
|
+
---
|
|
12655
|
+
|
|
12656
|
+
## OUTPUT
|
|
12657
|
+
|
|
12658
|
+
- Emit \`backend_message\` events through tools only (\`message\`) for progress updates
|
|
12659
|
+
- Before making irreversible changes, ensure you have proper authorization or the runtime allows auto-approval
|
|
12660
|
+
- Never present draft versions - only produce and deliver final, validated results
|
|
12661
|
+
- On successful task completion, emit 'done' with status 'completed' and call \`agent_end_turn\`
|
|
12662
|
+
|
|
12663
|
+
---
|
|
12664
|
+
|
|
12665
|
+
## SAFETY & QUALITY
|
|
12666
|
+
|
|
12667
|
+
- Be conservative with edits; generate previews (diff) for \`edit_tool\` where applicable
|
|
12668
|
+
- Keep file system operations idempotent and explicit
|
|
12669
|
+
- Prefer performance-efficient scans (avoid reading entire large binaries)
|
|
12670
|
+
- Respect test environment constraints
|
|
12671
|
+
- Never expose secrets or run commands that dump environment variables
|
|
12672
|
+
|
|
12673
|
+
---
|
|
12674
|
+
|
|
12675
|
+
## EXEMPLAR FLOW (GUIDELINE)
|
|
12676
|
+
|
|
12677
|
+
### Research Task Example:
|
|
12678
|
+
1. Acknowledge task via \`message\` (info)
|
|
12679
|
+
2. Use \`ls_tool\`, \`read_file_lines\`, \`grep_search\` to gather evidence
|
|
12680
|
+
3. Track findings in notebook
|
|
12681
|
+
4. Report findings via \`message\` (result) with specific file paths and line numbers
|
|
12682
|
+
5. Call \`agent_end_turn\`
|
|
12683
|
+
|
|
12684
|
+
### Implementation Task Example:
|
|
12685
|
+
1. Acknowledge task via \`message\` (info)
|
|
12686
|
+
2. Read relevant files to understand current state
|
|
12687
|
+
3. Plan changes in notebook
|
|
12688
|
+
4. Use \`edit_tool\` to make changes
|
|
12689
|
+
5. Run tests via \`shell_command\`
|
|
12690
|
+
6. Fix any failures
|
|
12691
|
+
7. Commit changes via \`shell_command\` (git commit)
|
|
12692
|
+
8. Report commit hash via \`message\` (result)
|
|
12693
|
+
9. Call \`agent_end_turn\`
|
|
12694
|
+
|
|
12695
|
+
### Verification Task Example:
|
|
12696
|
+
1. Acknowledge task via \`message\` (info)
|
|
12697
|
+
2. Run tests via \`shell_command\`
|
|
12698
|
+
3. Investigate any failures deeply
|
|
12699
|
+
4. Report specific evidence (pass/fail, error messages)
|
|
12700
|
+
5. Call \`agent_end_turn\` with verdict
|
|
12701
|
+
|
|
12702
|
+
---
|
|
12703
|
+
|
|
12704
|
+
## CRITICAL REMINDERS
|
|
12705
|
+
|
|
12706
|
+
- **You cannot see the Coordinator's conversation** - Your task prompt must be self-contained
|
|
12707
|
+
- **Work autonomously** - Don't ask for clarification unless fundamentally blocked
|
|
12708
|
+
- **Verify before reporting done** - Run tests, check types, ensure code works
|
|
12709
|
+
- **Report specific evidence** - File paths, line numbers, commit hashes, test output
|
|
12710
|
+
- **Use the notebook** - Plan, track progress, record decisions
|
|
12711
|
+
- **Communicate progress** - Use \`message\` tool frequently with \`message_type: "info"\`
|
|
12712
|
+
- **End properly** - Call \`agent_end_turn\` when task is complete
|
|
12713
|
+
|
|
12714
|
+
`;
|
|
12715
|
+
function getWorkerPrompt() {
|
|
12716
|
+
const now2 = /* @__PURE__ */ new Date();
|
|
12717
|
+
const collectedData = {
|
|
12718
|
+
os_type: os20.type(),
|
|
12719
|
+
os_version: os20.release(),
|
|
12720
|
+
architecture: os20.arch(),
|
|
12721
|
+
workdir: process.cwd(),
|
|
12722
|
+
shell_type: process.env.SHELL || process.env.COMSPEC || "Unknown",
|
|
12723
|
+
username: os20.userInfo().username || "Unknown",
|
|
12724
|
+
current_date: now2.toISOString().split("T")[0],
|
|
12725
|
+
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone || "Unknown",
|
|
12726
|
+
locale: process.env.LANG || process.env.LC_ALL || "Unknown"
|
|
12727
|
+
};
|
|
12728
|
+
const finalEnv = {
|
|
12729
|
+
os_type: "Unknown",
|
|
12730
|
+
os_version: "Unknown",
|
|
12731
|
+
workdir: "Unknown",
|
|
12732
|
+
shell_type: "Unknown",
|
|
12733
|
+
username: "Unknown",
|
|
12734
|
+
architecture: "Unknown",
|
|
12735
|
+
current_date: "Unknown",
|
|
12736
|
+
timezone: "Unknown",
|
|
12737
|
+
locale: "Unknown",
|
|
12738
|
+
...collectedData
|
|
12739
|
+
};
|
|
12740
|
+
let formattedPrompt = WORKER_SYSTEM_PROMPT;
|
|
12741
|
+
for (const key in finalEnv) {
|
|
12742
|
+
const placeholder = `{${key}}`;
|
|
12743
|
+
formattedPrompt = formattedPrompt.replace(new RegExp(placeholder, "g"), finalEnv[key]);
|
|
12744
|
+
}
|
|
12745
|
+
return formattedPrompt;
|
|
12746
|
+
}
|
|
12747
|
+
|
|
11951
12748
|
// src/app/agent/subagents/base_llm_subagent.ts
|
|
11952
12749
|
var BaseLLMSubAgent = class {
|
|
11953
12750
|
ctx;
|
|
@@ -11981,7 +12778,7 @@ var BaseLLMSubAgent = class {
|
|
|
11981
12778
|
const [sessionFile, history] = await loadOrcreateSession(sessionId);
|
|
11982
12779
|
this.sessionFile = sessionFile;
|
|
11983
12780
|
this.history = history || [];
|
|
11984
|
-
const systemPromptContent = getInitPrompt();
|
|
12781
|
+
const systemPromptContent = this.id === "init" ? getInitPrompt() : getWorkerPrompt();
|
|
11985
12782
|
if (this.history.length === 0) {
|
|
11986
12783
|
this.history.push({
|
|
11987
12784
|
role: "system",
|
|
@@ -12228,14 +13025,14 @@ var RouteManager = class {
|
|
|
12228
13025
|
this.subAgents = subAgents;
|
|
12229
13026
|
this.core = core;
|
|
12230
13027
|
}
|
|
12231
|
-
registerRoute(
|
|
12232
|
-
this.routeHandlers.set(
|
|
13028
|
+
registerRoute(path35, handler) {
|
|
13029
|
+
this.routeHandlers.set(path35, handler);
|
|
12233
13030
|
}
|
|
12234
13031
|
async handleRoute(payload) {
|
|
12235
13032
|
const inputText = String(payload.content || "").trim();
|
|
12236
13033
|
const { userContext } = payload;
|
|
12237
|
-
for (const [
|
|
12238
|
-
if (inputText ===
|
|
13034
|
+
for (const [path35, handler] of this.routeHandlers) {
|
|
13035
|
+
if (inputText === path35 || inputText.startsWith(`${path35} `)) {
|
|
12239
13036
|
return handler({ content: inputText, userContext });
|
|
12240
13037
|
}
|
|
12241
13038
|
}
|
|
@@ -12244,13 +13041,13 @@ var RouteManager = class {
|
|
|
12244
13041
|
};
|
|
12245
13042
|
|
|
12246
13043
|
// src/app/agent/runtime/plugin_runtime.ts
|
|
12247
|
-
import
|
|
13044
|
+
import path31 from "path";
|
|
12248
13045
|
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
12249
13046
|
async function loadPluginsAtStartup() {
|
|
12250
13047
|
for (const p of listPlugins()) {
|
|
12251
13048
|
const entry = p.manifest.entry?.trim();
|
|
12252
13049
|
if (!entry) continue;
|
|
12253
|
-
const abs =
|
|
13050
|
+
const abs = path31.resolve(p.root, entry);
|
|
12254
13051
|
try {
|
|
12255
13052
|
const href = pathToFileURL2(abs).href;
|
|
12256
13053
|
const mod = await import(href);
|
|
@@ -12271,7 +13068,7 @@ async function loadPluginsAtStartup() {
|
|
|
12271
13068
|
}
|
|
12272
13069
|
|
|
12273
13070
|
// src/app/agent/agent.ts
|
|
12274
|
-
var globalEnvPath =
|
|
13071
|
+
var globalEnvPath = path32.join(os21.homedir(), ".bluma", ".env");
|
|
12275
13072
|
dotenv.config({ path: globalEnvPath });
|
|
12276
13073
|
var Agent = class {
|
|
12277
13074
|
sessionId;
|
|
@@ -15044,16 +15841,16 @@ import latestVersion from "latest-version";
|
|
|
15044
15841
|
import semverGt from "semver/functions/gt.js";
|
|
15045
15842
|
import semverValid from "semver/functions/valid.js";
|
|
15046
15843
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
15047
|
-
import
|
|
15048
|
-
import
|
|
15844
|
+
import path33 from "path";
|
|
15845
|
+
import fs28 from "fs";
|
|
15049
15846
|
var BLUMA_PACKAGE_NAME = "@nomad-e/bluma-cli";
|
|
15050
15847
|
function findBlumaPackageJson(startDir) {
|
|
15051
15848
|
let dir = startDir;
|
|
15052
15849
|
for (let i = 0; i < 12; i++) {
|
|
15053
|
-
const candidate =
|
|
15054
|
-
if (
|
|
15850
|
+
const candidate = path33.join(dir, "package.json");
|
|
15851
|
+
if (fs28.existsSync(candidate)) {
|
|
15055
15852
|
try {
|
|
15056
|
-
const raw =
|
|
15853
|
+
const raw = fs28.readFileSync(candidate, "utf8");
|
|
15057
15854
|
const parsed = JSON.parse(raw);
|
|
15058
15855
|
if (parsed?.name === BLUMA_PACKAGE_NAME && parsed?.version) {
|
|
15059
15856
|
return { name: parsed.name, version: String(parsed.version) };
|
|
@@ -15061,7 +15858,7 @@ function findBlumaPackageJson(startDir) {
|
|
|
15061
15858
|
} catch {
|
|
15062
15859
|
}
|
|
15063
15860
|
}
|
|
15064
|
-
const parent =
|
|
15861
|
+
const parent = path33.dirname(dir);
|
|
15065
15862
|
if (parent === dir) break;
|
|
15066
15863
|
dir = parent;
|
|
15067
15864
|
}
|
|
@@ -15070,13 +15867,13 @@ function findBlumaPackageJson(startDir) {
|
|
|
15070
15867
|
function resolveInstalledBlumaPackage() {
|
|
15071
15868
|
const tried = /* @__PURE__ */ new Set();
|
|
15072
15869
|
const tryFrom = (dir) => {
|
|
15073
|
-
const abs =
|
|
15870
|
+
const abs = path33.resolve(dir);
|
|
15074
15871
|
if (tried.has(abs)) return null;
|
|
15075
15872
|
tried.add(abs);
|
|
15076
15873
|
return findBlumaPackageJson(abs);
|
|
15077
15874
|
};
|
|
15078
15875
|
try {
|
|
15079
|
-
const fromBundle = tryFrom(
|
|
15876
|
+
const fromBundle = tryFrom(path33.dirname(fileURLToPath5(import.meta.url)));
|
|
15080
15877
|
if (fromBundle) return fromBundle;
|
|
15081
15878
|
} catch {
|
|
15082
15879
|
}
|
|
@@ -15084,12 +15881,12 @@ function resolveInstalledBlumaPackage() {
|
|
|
15084
15881
|
if (argv1 && !argv1.startsWith("-")) {
|
|
15085
15882
|
try {
|
|
15086
15883
|
let resolved = argv1;
|
|
15087
|
-
if (
|
|
15088
|
-
resolved =
|
|
15884
|
+
if (path33.isAbsolute(argv1) && fs28.existsSync(argv1)) {
|
|
15885
|
+
resolved = fs28.realpathSync(argv1);
|
|
15089
15886
|
} else {
|
|
15090
|
-
resolved =
|
|
15887
|
+
resolved = path33.resolve(process.cwd(), argv1);
|
|
15091
15888
|
}
|
|
15092
|
-
const fromArgv = tryFrom(
|
|
15889
|
+
const fromArgv = tryFrom(path33.dirname(resolved));
|
|
15093
15890
|
if (fromArgv) return fromArgv;
|
|
15094
15891
|
} catch {
|
|
15095
15892
|
}
|
|
@@ -16625,9 +17422,9 @@ async function runAgentMode() {
|
|
|
16625
17422
|
try {
|
|
16626
17423
|
if (inputFileIndex !== -1 && args[inputFileIndex + 1]) {
|
|
16627
17424
|
const filePath = args[inputFileIndex + 1];
|
|
16628
|
-
rawPayload =
|
|
17425
|
+
rawPayload = fs29.readFileSync(filePath, "utf-8");
|
|
16629
17426
|
} else {
|
|
16630
|
-
rawPayload =
|
|
17427
|
+
rawPayload = fs29.readFileSync(0, "utf-8");
|
|
16631
17428
|
}
|
|
16632
17429
|
} catch (err) {
|
|
16633
17430
|
writeAgentEvent(registrySessionId, {
|
|
@@ -16776,7 +17573,9 @@ async function runAgentMode() {
|
|
|
16776
17573
|
const agent = new Agent(sessionId, eventBus);
|
|
16777
17574
|
agentRef = agent;
|
|
16778
17575
|
await agent.initialize();
|
|
16779
|
-
const
|
|
17576
|
+
const userRequest = envelope.context?.user_request || envelope.context?.userRequest || "";
|
|
17577
|
+
const coordinatorContext = envelope.context?.coordinator_context || envelope.context?.coordinatorContext || "";
|
|
17578
|
+
const userContent = userRequest ? `${userRequest}${coordinatorContext ? "\n\nContexto adicional:\n" + JSON.stringify(coordinatorContext, null, 2) : ""}` : JSON.stringify({
|
|
16780
17579
|
message_id: envelope.message_id || sessionId,
|
|
16781
17580
|
from_agent: envelope.from_agent || "unknown",
|
|
16782
17581
|
to_agent: envelope.to_agent || "bluma",
|
|
@@ -16823,9 +17622,9 @@ async function runAgentMode() {
|
|
|
16823
17622
|
}
|
|
16824
17623
|
function readCliPackageVersion() {
|
|
16825
17624
|
try {
|
|
16826
|
-
const base =
|
|
16827
|
-
const pkgPath =
|
|
16828
|
-
const j = JSON.parse(
|
|
17625
|
+
const base = path34.dirname(fileURLToPath6(import.meta.url));
|
|
17626
|
+
const pkgPath = path34.join(base, "..", "package.json");
|
|
17627
|
+
const j = JSON.parse(fs29.readFileSync(pkgPath, "utf8"));
|
|
16829
17628
|
return String(j.version || "0.0.0");
|
|
16830
17629
|
} catch {
|
|
16831
17630
|
return "0.0.0";
|
|
@@ -16948,7 +17747,7 @@ function startBackgroundAgent() {
|
|
|
16948
17747
|
process.exit(1);
|
|
16949
17748
|
}
|
|
16950
17749
|
const filePath = args[inputFileIndex + 1];
|
|
16951
|
-
const rawPayload =
|
|
17750
|
+
const rawPayload = fs29.readFileSync(filePath, "utf-8");
|
|
16952
17751
|
const envelope = JSON.parse(rawPayload);
|
|
16953
17752
|
const sessionId = envelope.session_id || envelope.message_id || uuidv48();
|
|
16954
17753
|
registerSession({
|