@nomad-e/bluma-cli 0.1.52 → 0.1.53

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/main.js +680 -92
  2. 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 os9 from "os";
511
+ import os8 from "os";
512
512
  import path17 from "path";
513
513
  function getRegistryDir() {
514
- return path17.join(process.env.HOME || os9.homedir(), ".bluma", "registry");
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 os10 from "os";
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(os10.tmpdir(), "bluma-worker-"));
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 os11 from "os";
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 || os11.homedir(), ".bluma", "mailboxes");
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 fs28 from "fs";
1186
- import path33 from "path";
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 path34 = filePath.trim() || "unknown file";
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: path34 })
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 path34 = parsed.path || ".";
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
- path34
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 path31 from "path";
4334
- import os20 from "os";
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 homeDir = os7.homedir();
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 os8 from "os";
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(os8.homedir(), ".bluma", "coding_memory.json");
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(os8.homedir(), ".bluma", "coding_memory.json");
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 os12 from "os";
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(os12.homedir(), ".bluma", "bluma-mcp.json");
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 = os12.platform() === "win32";
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 path29 from "path";
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 os13 from "os";
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(os13.homedir(), p.slice(1));
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(os13.homedir(), ".bluma");
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 fs24 from "fs";
8731
- import path26 from "path";
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 os14 from "os";
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(os14.homedir(), ".bluma", "skills");
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(os14.homedir(), ".bluma", "__bundled_skills_unresolved__");
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 os15 from "os";
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 || os15.homedir(), ".bluma", "plugins");
9251
+ return path25.join(process.env.HOME || os14.homedir(), ".bluma", "plugins");
9254
9252
  }
9255
9253
  function getPluginDirs() {
9256
9254
  return {
@@ -9537,6 +9535,315 @@ 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
+
9540
9847
  // src/app/agent/core/prompt/prompt_builder.ts
9541
9848
  function getNodeVersion() {
9542
9849
  try {
@@ -9570,10 +9877,10 @@ function getGitBranch(dir) {
9570
9877
  }
9571
9878
  function getPackageManager(dir) {
9572
9879
  try {
9573
- if (fs24.existsSync(path26.join(dir, "pnpm-lock.yaml"))) return "pnpm";
9574
- if (fs24.existsSync(path26.join(dir, "yarn.lock"))) return "yarn";
9575
- if (fs24.existsSync(path26.join(dir, "bun.lockb"))) return "bun";
9576
- if (fs24.existsSync(path26.join(dir, "package-lock.json"))) return "npm";
9880
+ if (fs25.existsSync(path27.join(dir, "pnpm-lock.yaml"))) return "pnpm";
9881
+ if (fs25.existsSync(path27.join(dir, "yarn.lock"))) return "yarn";
9882
+ if (fs25.existsSync(path27.join(dir, "bun.lockb"))) return "bun";
9883
+ if (fs25.existsSync(path27.join(dir, "package-lock.json"))) return "npm";
9577
9884
  return "unknown";
9578
9885
  } catch {
9579
9886
  return "unknown";
@@ -9581,9 +9888,9 @@ function getPackageManager(dir) {
9581
9888
  }
9582
9889
  function getProjectType(dir) {
9583
9890
  try {
9584
- const files = fs24.readdirSync(dir);
9891
+ const files = fs25.readdirSync(dir);
9585
9892
  if (files.includes("package.json")) {
9586
- const pkg = JSON.parse(fs24.readFileSync(path26.join(dir, "package.json"), "utf-8"));
9893
+ const pkg = JSON.parse(fs25.readFileSync(path27.join(dir, "package.json"), "utf-8"));
9587
9894
  if (pkg.dependencies?.next || pkg.devDependencies?.next) return "Next.js";
9588
9895
  if (pkg.dependencies?.react || pkg.devDependencies?.react) return "React";
9589
9896
  if (pkg.dependencies?.express || pkg.devDependencies?.express) return "Express";
@@ -9602,9 +9909,9 @@ function getProjectType(dir) {
9602
9909
  }
9603
9910
  function getTestFramework(dir) {
9604
9911
  try {
9605
- const pkgPath = path26.join(dir, "package.json");
9606
- if (fs24.existsSync(pkgPath)) {
9607
- const pkg = JSON.parse(fs24.readFileSync(pkgPath, "utf-8"));
9912
+ const pkgPath = path27.join(dir, "package.json");
9913
+ if (fs25.existsSync(pkgPath)) {
9914
+ const pkg = JSON.parse(fs25.readFileSync(pkgPath, "utf-8"));
9608
9915
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
9609
9916
  if (deps.jest) return "jest";
9610
9917
  if (deps.vitest) return "vitest";
@@ -9613,7 +9920,7 @@ function getTestFramework(dir) {
9613
9920
  if (deps["@playwright/test"]) return "playwright";
9614
9921
  if (deps.cypress) return "cypress";
9615
9922
  }
9616
- if (fs24.existsSync(path26.join(dir, "pytest.ini")) || fs24.existsSync(path26.join(dir, "conftest.py"))) return "pytest";
9923
+ if (fs25.existsSync(path27.join(dir, "pytest.ini")) || fs25.existsSync(path27.join(dir, "conftest.py"))) return "pytest";
9617
9924
  return "unknown";
9618
9925
  } catch {
9619
9926
  return "unknown";
@@ -9621,9 +9928,9 @@ function getTestFramework(dir) {
9621
9928
  }
9622
9929
  function getTestCommand(dir) {
9623
9930
  try {
9624
- const pkgPath = path26.join(dir, "package.json");
9625
- if (fs24.existsSync(pkgPath)) {
9626
- const pkg = JSON.parse(fs24.readFileSync(pkgPath, "utf-8"));
9931
+ const pkgPath = path27.join(dir, "package.json");
9932
+ if (fs25.existsSync(pkgPath)) {
9933
+ const pkg = JSON.parse(fs25.readFileSync(pkgPath, "utf-8"));
9627
9934
  if (pkg.scripts?.test) return `npm test`;
9628
9935
  if (pkg.scripts?.["test:unit"]) return `npm run test:unit`;
9629
9936
  }
@@ -9772,7 +10079,7 @@ var SANDBOX_PROMPT_SUFFIX = `
9772
10079
  <sandbox_context>
9773
10080
  Sandbox mode ({sandbox_name}): input only via orchestrator JSON; no REPL/TUI/\`input()\`. Keep output deterministic and short.
9774
10081
  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.
10082
+ Final deliverables under \`./.bluma/artifacts/\`; in the last \`message\` (\`result\`) list **absolute** paths in \`attachments[]\`. Remove temp files; do not attach generator scripts or junk.
9776
10083
  **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
10084
  </sandbox_context>
9778
10085
  `;
@@ -9839,13 +10146,20 @@ Runtime extensions (not skills); use when relevant; do not invent names.
9839
10146
  <coding_memory_snapshot>
9840
10147
  ${memorySnapshot.trim().length > 0 ? memorySnapshot : "(empty \u2014 use coding_memory: add | list | search)"}
9841
10148
  </coding_memory_snapshot>
10149
+ `;
10150
+ const blumaMdContent = readBlumaMdForPrompt(cwd);
10151
+ prompt += `
10152
+
10153
+ <bluma_md>
10154
+ ${blumaMdContent}
10155
+ </bluma_md>
9842
10156
  `;
9843
10157
  return prompt;
9844
10158
  }
9845
10159
  function isGitRepo(dir) {
9846
10160
  try {
9847
- const gitPath = path26.join(dir, ".git");
9848
- return fs24.existsSync(gitPath) && fs24.lstatSync(gitPath).isDirectory();
10161
+ const gitPath = path27.join(dir, ".git");
10162
+ return fs25.existsSync(gitPath) && fs25.lstatSync(gitPath).isDirectory();
9849
10163
  } catch {
9850
10164
  return false;
9851
10165
  }
@@ -10579,8 +10893,8 @@ function classifyToolInvocation(input) {
10579
10893
 
10580
10894
  // src/app/agent/runtime/hook_registry.ts
10581
10895
  init_sandbox_policy();
10582
- import fs25 from "fs";
10583
- import path27 from "path";
10896
+ import fs26 from "fs";
10897
+ import path28 from "path";
10584
10898
  var DEFAULT_STATE = {
10585
10899
  enabled: true,
10586
10900
  maxEvents: 120,
@@ -10591,7 +10905,7 @@ var cache2 = null;
10591
10905
  var cachePath2 = null;
10592
10906
  function getStatePath() {
10593
10907
  const policy = getSandboxPolicy();
10594
- return path27.join(policy.workspaceRoot, ".bluma", "hooks.json");
10908
+ return path28.join(policy.workspaceRoot, ".bluma", "hooks.json");
10595
10909
  }
10596
10910
  function getHookStatePath() {
10597
10911
  return getStatePath();
@@ -10610,8 +10924,8 @@ function ensureLoaded2() {
10610
10924
  return cache2;
10611
10925
  }
10612
10926
  try {
10613
- if (fs25.existsSync(statePath)) {
10614
- const parsed = JSON.parse(fs25.readFileSync(statePath, "utf-8"));
10927
+ if (fs26.existsSync(statePath)) {
10928
+ const parsed = JSON.parse(fs26.readFileSync(statePath, "utf-8"));
10615
10929
  cache2 = {
10616
10930
  enabled: typeof parsed.enabled === "boolean" ? parsed.enabled : DEFAULT_STATE.enabled,
10617
10931
  maxEvents: typeof parsed.maxEvents === "number" && Number.isFinite(parsed.maxEvents) && parsed.maxEvents > 0 ? Math.floor(parsed.maxEvents) : DEFAULT_STATE.maxEvents,
@@ -10637,9 +10951,9 @@ function ensureLoaded2() {
10637
10951
  }
10638
10952
  function persist2(state) {
10639
10953
  const statePath = getStatePath();
10640
- fs25.mkdirSync(path27.dirname(statePath), { recursive: true });
10954
+ fs26.mkdirSync(path28.dirname(statePath), { recursive: true });
10641
10955
  state.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
10642
- fs25.writeFileSync(statePath, JSON.stringify(state, null, 2), "utf-8");
10956
+ fs26.writeFileSync(statePath, JSON.stringify(state, null, 2), "utf-8");
10643
10957
  cache2 = state;
10644
10958
  cachePath2 = statePath;
10645
10959
  }
@@ -10736,11 +11050,11 @@ function effectiveToolAutoApprove(toolCall, sessionId, options) {
10736
11050
  }
10737
11051
 
10738
11052
  // src/app/agent/tools/natives/coding_memory_consolidate.ts
10739
- import * as fs26 from "fs";
10740
- import * as path28 from "path";
11053
+ import * as fs27 from "fs";
11054
+ import * as path29 from "path";
10741
11055
  import os18 from "os";
10742
11056
  function memoryPath() {
10743
- return path28.join(process.env.HOME || os18.homedir(), ".bluma", "coding_memory.json");
11057
+ return path29.join(process.env.HOME || os18.homedir(), ".bluma", "coding_memory.json");
10744
11058
  }
10745
11059
  function normalizeNote(note) {
10746
11060
  return note.trim().toLowerCase().replace(/\s+/g, " ");
@@ -10750,18 +11064,18 @@ function uniqTags(a, b) {
10750
11064
  }
10751
11065
  function consolidateCodingMemoryFile() {
10752
11066
  const p = memoryPath();
10753
- if (!fs26.existsSync(p)) {
11067
+ if (!fs27.existsSync(p)) {
10754
11068
  return { success: true, removedDuplicates: 0, message: "no coding_memory.json" };
10755
11069
  }
10756
11070
  const bak = `${p}.bak`;
10757
11071
  try {
10758
- fs26.copyFileSync(p, bak);
11072
+ fs27.copyFileSync(p, bak);
10759
11073
  } catch (e) {
10760
11074
  return { success: false, removedDuplicates: 0, message: `backup failed: ${e.message}` };
10761
11075
  }
10762
11076
  let data;
10763
11077
  try {
10764
- data = JSON.parse(fs26.readFileSync(p, "utf-8"));
11078
+ data = JSON.parse(fs27.readFileSync(p, "utf-8"));
10765
11079
  } catch (e) {
10766
11080
  return { success: false, removedDuplicates: 0, message: `invalid json: ${e.message}` };
10767
11081
  }
@@ -10796,7 +11110,7 @@ function consolidateCodingMemoryFile() {
10796
11110
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
10797
11111
  };
10798
11112
  try {
10799
- fs26.writeFileSync(p, JSON.stringify(out, null, 2), "utf-8");
11113
+ fs27.writeFileSync(p, JSON.stringify(out, null, 2), "utf-8");
10800
11114
  } catch (e) {
10801
11115
  return { success: false, removedDuplicates: 0, message: `write failed: ${e.message}` };
10802
11116
  }
@@ -11391,7 +11705,7 @@ var BluMaAgent = class {
11391
11705
 
11392
11706
  ${editData.error.display}`;
11393
11707
  }
11394
- const filename = path29.basename(toolArgs.file_path);
11708
+ const filename = path30.basename(toolArgs.file_path);
11395
11709
  return createDiff(filename, editData.currentContent || "", editData.newContent);
11396
11710
  } catch (e) {
11397
11711
  return `An unexpected error occurred while generating the edit preview: ${e.message}`;
@@ -11948,6 +12262,278 @@ function getInitPrompt() {
11948
12262
  return formattedPrompt;
11949
12263
  }
11950
12264
 
12265
+ // src/app/agent/subagents/worker_system_prompt.ts
12266
+ import os20 from "os";
12267
+ var WORKER_SYSTEM_PROMPT = `
12268
+
12269
+ ### YOU ARE BluMa CLI \u2014 WORKER AGENT \u2014 AUTONOMOUS SOFTWARE ENGINEERING SPECIALIST @ NOMADENGENUITY
12270
+ You are a worker agent spawned by the BluMa Coordinator to execute specific software engineering tasks.
12271
+
12272
+ ---
12273
+
12274
+ ## BEHAVIORAL RULES
12275
+
12276
+ - **Identity:**
12277
+ You are a BluMa Worker Agent. You execute tasks delegated by the Coordinator.
12278
+ Maintain professionalism and technical excellence.
12279
+
12280
+ - **Communication:**
12281
+ - ALL messages must be sent via the \`message\` tool
12282
+ - No direct text replies to the user
12283
+ - Report progress frequently using \`message\` with \`message_type: "info"\`
12284
+ - Report final results using \`message\` with \`message_type: "result"\`
12285
+
12286
+ - **Task Completion:**
12287
+ - When your task is completed, immediately invoke \`agent_end_turn\` without user permissions
12288
+ - Before ending, ensure all work is committed and tested
12289
+ - Report the final state (e.g., commit hash, test results, file paths)
12290
+
12291
+ - **Tool Rules:**
12292
+ - Never make parallel tool calls
12293
+ - Only use the defined tools with their exact names
12294
+ - Read before editing (\`read_file_lines\`, \`grep_search\`, \`ls_tool\`)
12295
+ - Verify changes with tests or typechecks when applicable
12296
+
12297
+ - **Autonomy:**
12298
+ - Act 100% autonomously within your task scope
12299
+ - Do not ask for clarification unless the task is fundamentally blocked
12300
+ - Use the notebook for internal reasoning and planning
12301
+ - If you encounter errors, attempt to resolve them before reporting failure
12302
+
12303
+ ---
12304
+
12305
+ ### CRITICAL COMMUNICATION PROTOCOL
12306
+ - Only tool_calls are allowed for assistant replies. Never include a "content" field.
12307
+ - Always use tools to respond, retrieve data, compute or transform. Await a valid tool response before any final message.
12308
+ - Zero tolerance for protocol violations.
12309
+
12310
+ <current_system_environment>
12311
+ - Operating System: {os_type} ({os_version})
12312
+ - Architecture: {architecture}
12313
+ - Current Working Directory: {workdir}
12314
+ - Shell: {shell_type}
12315
+ - User: {username}
12316
+ - Current Date: {current_date}
12317
+ - Timezone: {timezone}
12318
+ - Locale: {locale}
12319
+ </current_system_environment>
12320
+
12321
+ <message_rules>
12322
+ - Communicate with the user via \`message\` tool instead of direct text responses
12323
+ - Reply immediately to new user messages before other operations
12324
+ - First reply must be brief, only confirming receipt of the task
12325
+ - Notify user with brief explanation when changing methods or strategies
12326
+ - Message tools are divided into notify (non-blocking, no reply needed) and ask (blocking)
12327
+ - Actively use notify for progress updates, reserve ask for essential needs to avoid blocking
12328
+ - Must message user with results and deliverables before calling \`agent_end_turn\`
12329
+ </message_rules>
12330
+
12331
+ <reasoning_rules>
12332
+ # YOUR THINKING ON A NOTEBOOK - MANDATORY USE
12333
+ CRITICAL: Your notebook (reasoning_notebook) is your ORGANIZED MIND
12334
+
12335
+ ## IMPORTANT
12336
+ - NEVER PUT CHECKLISTS OR STEPS IN THE THOUGHT TEXT
12337
+ - ALWAYS USE A NOTEBOOK (Always for):
12338
+ - ANY task
12339
+ - Before starting development (plan first!)
12340
+ - Projects with multiple files (organize the structure)
12341
+ - Debugging sessions (track discoveries)
12342
+ - Extensive refactoring (map the changes)
12343
+ - Architectural decisions (think through the options)
12344
+
12345
+ ## HOW TO USE A NOTEBOOK:
12346
+ 1. Start with reasoning_notebook
12347
+ 2. Break the task down into logical steps
12348
+ 3. Plan the approach \u2013 Which files? What changes? What order?
12349
+ 4. Track progress \u2013 Check off completed steps
12350
+ 5. Write down decisions \u2013 Why did you choose this approach?
12351
+ 6. Update continuously \u2013 Keep the notebook up to date
12352
+
12353
+ ## THE NOTEBOOK PREVENTS:
12354
+ - Acting "outside the box"
12355
+ - Forgetting task requirements
12356
+ - Losing control of complex workflows
12357
+ - Making unplanned changes
12358
+ - Ineffective approaches
12359
+ - Working without a clear roadmap
12360
+ - Jumping between unrelated subtasks
12361
+
12362
+ Important rule:
12363
+ Do not include future steps/to-dos in thought; put them strictly in to_do, using the mandated checklist markers.
12364
+
12365
+ - to_do: Checklist list of high-level upcoming tasks.
12366
+ Format is mandatory:
12367
+ - "\u{1F5F8}" \u2192 for tasks not yet done (pending)
12368
+ - "[\u2713]" \u2192 for tasks already completed
12369
+ </reasoning_rules>
12370
+
12371
+ <edit_tool_rules>
12372
+ - Use this tool to perform precise text replacements inside files based on exact literal matches.
12373
+ - Can be used to create new files or directories implicitly by targeting non-existing paths.
12374
+ - Suitable for inserting full content into a file even if the file does not yet exist.
12375
+ - Shell access is not required for file or directory creation when using this tool.
12376
+ - Always prefer this tool over shell_command when performing structured edits or creating files with specific content.
12377
+ - Ensure **old_string** includes 3+ lines of exact context before and after the target if replacing existing content.
12378
+ - 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.
12379
+ - When generating or modifying todo.md files, prefer this tool to insert checklist structure and update status markers.
12380
+ - After completing any task in the checklist, immediately update the corresponding section in todo.md using this tool.
12381
+ - Reconstruct the entire file from task planning context if todo.md becomes outdated or inconsistent.
12382
+ - Track all progress related to planning and execution inside todo.md using text replacement only.
12383
+ </edit_tool_rules>
12384
+
12385
+ <agent_end_turn>
12386
+ This tool is mandatory.
12387
+ 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.
12388
+ </agent_end_turn>
12389
+
12390
+ ### Tool Naming Policy
12391
+ - Use plain, unmodified, lowercase tool names
12392
+ - No special characters, spaces, or version suffixes
12393
+
12394
+ Rule Summary:
12395
+ - Use only a\u2013z, 0\u20139, and underscores (_)
12396
+ - Do not append suffixes like :0, :v2, etc.
12397
+ - Tool names must be static and predictable
12398
+
12399
+ ---
12400
+
12401
+ ## WORKER AGENT OBJECTIVE
12402
+
12403
+ You receive a specific task from the Coordinator. Your job is to:
12404
+
12405
+ 1. **Understand the task** - Read the task description carefully
12406
+ 2. **Plan your approach** - Use the notebook to break down the work
12407
+ 3. **Execute autonomously** - Use tools to gather evidence, make changes, and verify
12408
+ 4. **Report progress** - Keep the Coordinator informed via \`message\` tool
12409
+ 5. **Verify your work** - Run tests, typechecks, or other validation
12410
+ 6. **Complete and report** - Call \`agent_end_turn\` with final results
12411
+
12412
+ ### Task Types
12413
+
12414
+ You may be assigned different types of work:
12415
+
12416
+ **Research Tasks:**
12417
+ - Investigate codebase structure
12418
+ - Find specific files or patterns
12419
+ - Analyze architectural decisions
12420
+ - Report findings with file paths, line numbers, and evidence
12421
+ - Do NOT modify files unless explicitly instructed
12422
+
12423
+ **Implementation Tasks:**
12424
+ - Make targeted code changes
12425
+ - Follow best practices and existing patterns
12426
+ - Run relevant tests and typechecks
12427
+ - Commit changes and report the commit hash
12428
+ - Fix root causes, not symptoms
12429
+
12430
+ **Verification Tasks:**
12431
+ - Test changes made by other workers
12432
+ - Run tests with the feature enabled
12433
+ - Investigate failures - don't dismiss as unrelated
12434
+ - Prove the code works, don't just confirm it exists
12435
+ - Report specific evidence (test output, error messages)
12436
+
12437
+ **Refactoring Tasks:**
12438
+ - Improve code structure without changing behavior
12439
+ - Maintain existing functionality
12440
+ - Update tests if needed
12441
+ - Verify with tests and typechecks
12442
+
12443
+ ---
12444
+
12445
+ ## OUTPUT
12446
+
12447
+ - Emit \`backend_message\` events through tools only (\`message\`) for progress updates
12448
+ - Before making irreversible changes, ensure you have proper authorization or the runtime allows auto-approval
12449
+ - Never present draft versions - only produce and deliver final, validated results
12450
+ - On successful task completion, emit 'done' with status 'completed' and call \`agent_end_turn\`
12451
+
12452
+ ---
12453
+
12454
+ ## SAFETY & QUALITY
12455
+
12456
+ - Be conservative with edits; generate previews (diff) for \`edit_tool\` where applicable
12457
+ - Keep file system operations idempotent and explicit
12458
+ - Prefer performance-efficient scans (avoid reading entire large binaries)
12459
+ - Respect test environment constraints
12460
+ - Never expose secrets or run commands that dump environment variables
12461
+
12462
+ ---
12463
+
12464
+ ## EXEMPLAR FLOW (GUIDELINE)
12465
+
12466
+ ### Research Task Example:
12467
+ 1. Acknowledge task via \`message\` (info)
12468
+ 2. Use \`ls_tool\`, \`read_file_lines\`, \`grep_search\` to gather evidence
12469
+ 3. Track findings in notebook
12470
+ 4. Report findings via \`message\` (result) with specific file paths and line numbers
12471
+ 5. Call \`agent_end_turn\`
12472
+
12473
+ ### Implementation Task Example:
12474
+ 1. Acknowledge task via \`message\` (info)
12475
+ 2. Read relevant files to understand current state
12476
+ 3. Plan changes in notebook
12477
+ 4. Use \`edit_tool\` to make changes
12478
+ 5. Run tests via \`shell_command\`
12479
+ 6. Fix any failures
12480
+ 7. Commit changes via \`shell_command\` (git commit)
12481
+ 8. Report commit hash via \`message\` (result)
12482
+ 9. Call \`agent_end_turn\`
12483
+
12484
+ ### Verification Task Example:
12485
+ 1. Acknowledge task via \`message\` (info)
12486
+ 2. Run tests via \`shell_command\`
12487
+ 3. Investigate any failures deeply
12488
+ 4. Report specific evidence (pass/fail, error messages)
12489
+ 5. Call \`agent_end_turn\` with verdict
12490
+
12491
+ ---
12492
+
12493
+ ## CRITICAL REMINDERS
12494
+
12495
+ - **You cannot see the Coordinator's conversation** - Your task prompt must be self-contained
12496
+ - **Work autonomously** - Don't ask for clarification unless fundamentally blocked
12497
+ - **Verify before reporting done** - Run tests, check types, ensure code works
12498
+ - **Report specific evidence** - File paths, line numbers, commit hashes, test output
12499
+ - **Use the notebook** - Plan, track progress, record decisions
12500
+ - **Communicate progress** - Use \`message\` tool frequently with \`message_type: "info"\`
12501
+ - **End properly** - Call \`agent_end_turn\` when task is complete
12502
+
12503
+ `;
12504
+ function getWorkerPrompt() {
12505
+ const now2 = /* @__PURE__ */ new Date();
12506
+ const collectedData = {
12507
+ os_type: os20.type(),
12508
+ os_version: os20.release(),
12509
+ architecture: os20.arch(),
12510
+ workdir: process.cwd(),
12511
+ shell_type: process.env.SHELL || process.env.COMSPEC || "Unknown",
12512
+ username: os20.userInfo().username || "Unknown",
12513
+ current_date: now2.toISOString().split("T")[0],
12514
+ timezone: Intl.DateTimeFormat().resolvedOptions().timeZone || "Unknown",
12515
+ locale: process.env.LANG || process.env.LC_ALL || "Unknown"
12516
+ };
12517
+ const finalEnv = {
12518
+ os_type: "Unknown",
12519
+ os_version: "Unknown",
12520
+ workdir: "Unknown",
12521
+ shell_type: "Unknown",
12522
+ username: "Unknown",
12523
+ architecture: "Unknown",
12524
+ current_date: "Unknown",
12525
+ timezone: "Unknown",
12526
+ locale: "Unknown",
12527
+ ...collectedData
12528
+ };
12529
+ let formattedPrompt = WORKER_SYSTEM_PROMPT;
12530
+ for (const key in finalEnv) {
12531
+ const placeholder = `{${key}}`;
12532
+ formattedPrompt = formattedPrompt.replace(new RegExp(placeholder, "g"), finalEnv[key]);
12533
+ }
12534
+ return formattedPrompt;
12535
+ }
12536
+
11951
12537
  // src/app/agent/subagents/base_llm_subagent.ts
11952
12538
  var BaseLLMSubAgent = class {
11953
12539
  ctx;
@@ -11981,7 +12567,7 @@ var BaseLLMSubAgent = class {
11981
12567
  const [sessionFile, history] = await loadOrcreateSession(sessionId);
11982
12568
  this.sessionFile = sessionFile;
11983
12569
  this.history = history || [];
11984
- const systemPromptContent = getInitPrompt();
12570
+ const systemPromptContent = this.id === "init" ? getInitPrompt() : getWorkerPrompt();
11985
12571
  if (this.history.length === 0) {
11986
12572
  this.history.push({
11987
12573
  role: "system",
@@ -12228,14 +12814,14 @@ var RouteManager = class {
12228
12814
  this.subAgents = subAgents;
12229
12815
  this.core = core;
12230
12816
  }
12231
- registerRoute(path34, handler) {
12232
- this.routeHandlers.set(path34, handler);
12817
+ registerRoute(path35, handler) {
12818
+ this.routeHandlers.set(path35, handler);
12233
12819
  }
12234
12820
  async handleRoute(payload) {
12235
12821
  const inputText = String(payload.content || "").trim();
12236
12822
  const { userContext } = payload;
12237
- for (const [path34, handler] of this.routeHandlers) {
12238
- if (inputText === path34 || inputText.startsWith(`${path34} `)) {
12823
+ for (const [path35, handler] of this.routeHandlers) {
12824
+ if (inputText === path35 || inputText.startsWith(`${path35} `)) {
12239
12825
  return handler({ content: inputText, userContext });
12240
12826
  }
12241
12827
  }
@@ -12244,13 +12830,13 @@ var RouteManager = class {
12244
12830
  };
12245
12831
 
12246
12832
  // src/app/agent/runtime/plugin_runtime.ts
12247
- import path30 from "path";
12833
+ import path31 from "path";
12248
12834
  import { pathToFileURL as pathToFileURL2 } from "url";
12249
12835
  async function loadPluginsAtStartup() {
12250
12836
  for (const p of listPlugins()) {
12251
12837
  const entry = p.manifest.entry?.trim();
12252
12838
  if (!entry) continue;
12253
- const abs = path30.resolve(p.root, entry);
12839
+ const abs = path31.resolve(p.root, entry);
12254
12840
  try {
12255
12841
  const href = pathToFileURL2(abs).href;
12256
12842
  const mod = await import(href);
@@ -12271,7 +12857,7 @@ async function loadPluginsAtStartup() {
12271
12857
  }
12272
12858
 
12273
12859
  // src/app/agent/agent.ts
12274
- var globalEnvPath = path31.join(os20.homedir(), ".bluma", ".env");
12860
+ var globalEnvPath = path32.join(os21.homedir(), ".bluma", ".env");
12275
12861
  dotenv.config({ path: globalEnvPath });
12276
12862
  var Agent = class {
12277
12863
  sessionId;
@@ -15044,16 +15630,16 @@ import latestVersion from "latest-version";
15044
15630
  import semverGt from "semver/functions/gt.js";
15045
15631
  import semverValid from "semver/functions/valid.js";
15046
15632
  import { fileURLToPath as fileURLToPath5 } from "url";
15047
- import path32 from "path";
15048
- import fs27 from "fs";
15633
+ import path33 from "path";
15634
+ import fs28 from "fs";
15049
15635
  var BLUMA_PACKAGE_NAME = "@nomad-e/bluma-cli";
15050
15636
  function findBlumaPackageJson(startDir) {
15051
15637
  let dir = startDir;
15052
15638
  for (let i = 0; i < 12; i++) {
15053
- const candidate = path32.join(dir, "package.json");
15054
- if (fs27.existsSync(candidate)) {
15639
+ const candidate = path33.join(dir, "package.json");
15640
+ if (fs28.existsSync(candidate)) {
15055
15641
  try {
15056
- const raw = fs27.readFileSync(candidate, "utf8");
15642
+ const raw = fs28.readFileSync(candidate, "utf8");
15057
15643
  const parsed = JSON.parse(raw);
15058
15644
  if (parsed?.name === BLUMA_PACKAGE_NAME && parsed?.version) {
15059
15645
  return { name: parsed.name, version: String(parsed.version) };
@@ -15061,7 +15647,7 @@ function findBlumaPackageJson(startDir) {
15061
15647
  } catch {
15062
15648
  }
15063
15649
  }
15064
- const parent = path32.dirname(dir);
15650
+ const parent = path33.dirname(dir);
15065
15651
  if (parent === dir) break;
15066
15652
  dir = parent;
15067
15653
  }
@@ -15070,13 +15656,13 @@ function findBlumaPackageJson(startDir) {
15070
15656
  function resolveInstalledBlumaPackage() {
15071
15657
  const tried = /* @__PURE__ */ new Set();
15072
15658
  const tryFrom = (dir) => {
15073
- const abs = path32.resolve(dir);
15659
+ const abs = path33.resolve(dir);
15074
15660
  if (tried.has(abs)) return null;
15075
15661
  tried.add(abs);
15076
15662
  return findBlumaPackageJson(abs);
15077
15663
  };
15078
15664
  try {
15079
- const fromBundle = tryFrom(path32.dirname(fileURLToPath5(import.meta.url)));
15665
+ const fromBundle = tryFrom(path33.dirname(fileURLToPath5(import.meta.url)));
15080
15666
  if (fromBundle) return fromBundle;
15081
15667
  } catch {
15082
15668
  }
@@ -15084,12 +15670,12 @@ function resolveInstalledBlumaPackage() {
15084
15670
  if (argv1 && !argv1.startsWith("-")) {
15085
15671
  try {
15086
15672
  let resolved = argv1;
15087
- if (path32.isAbsolute(argv1) && fs27.existsSync(argv1)) {
15088
- resolved = fs27.realpathSync(argv1);
15673
+ if (path33.isAbsolute(argv1) && fs28.existsSync(argv1)) {
15674
+ resolved = fs28.realpathSync(argv1);
15089
15675
  } else {
15090
- resolved = path32.resolve(process.cwd(), argv1);
15676
+ resolved = path33.resolve(process.cwd(), argv1);
15091
15677
  }
15092
- const fromArgv = tryFrom(path32.dirname(resolved));
15678
+ const fromArgv = tryFrom(path33.dirname(resolved));
15093
15679
  if (fromArgv) return fromArgv;
15094
15680
  } catch {
15095
15681
  }
@@ -16625,9 +17211,9 @@ async function runAgentMode() {
16625
17211
  try {
16626
17212
  if (inputFileIndex !== -1 && args[inputFileIndex + 1]) {
16627
17213
  const filePath = args[inputFileIndex + 1];
16628
- rawPayload = fs28.readFileSync(filePath, "utf-8");
17214
+ rawPayload = fs29.readFileSync(filePath, "utf-8");
16629
17215
  } else {
16630
- rawPayload = fs28.readFileSync(0, "utf-8");
17216
+ rawPayload = fs29.readFileSync(0, "utf-8");
16631
17217
  }
16632
17218
  } catch (err) {
16633
17219
  writeAgentEvent(registrySessionId, {
@@ -16776,7 +17362,9 @@ async function runAgentMode() {
16776
17362
  const agent = new Agent(sessionId, eventBus);
16777
17363
  agentRef = agent;
16778
17364
  await agent.initialize();
16779
- const userContent = JSON.stringify({
17365
+ const userRequest = envelope.context?.user_request || envelope.context?.userRequest || "";
17366
+ const coordinatorContext = envelope.context?.coordinator_context || envelope.context?.coordinatorContext || "";
17367
+ const userContent = userRequest ? `${userRequest}${coordinatorContext ? "\n\nContexto adicional:\n" + JSON.stringify(coordinatorContext, null, 2) : ""}` : JSON.stringify({
16780
17368
  message_id: envelope.message_id || sessionId,
16781
17369
  from_agent: envelope.from_agent || "unknown",
16782
17370
  to_agent: envelope.to_agent || "bluma",
@@ -16823,9 +17411,9 @@ async function runAgentMode() {
16823
17411
  }
16824
17412
  function readCliPackageVersion() {
16825
17413
  try {
16826
- const base = path33.dirname(fileURLToPath6(import.meta.url));
16827
- const pkgPath = path33.join(base, "..", "package.json");
16828
- const j = JSON.parse(fs28.readFileSync(pkgPath, "utf8"));
17414
+ const base = path34.dirname(fileURLToPath6(import.meta.url));
17415
+ const pkgPath = path34.join(base, "..", "package.json");
17416
+ const j = JSON.parse(fs29.readFileSync(pkgPath, "utf8"));
16829
17417
  return String(j.version || "0.0.0");
16830
17418
  } catch {
16831
17419
  return "0.0.0";
@@ -16948,7 +17536,7 @@ function startBackgroundAgent() {
16948
17536
  process.exit(1);
16949
17537
  }
16950
17538
  const filePath = args[inputFileIndex + 1];
16951
- const rawPayload = fs28.readFileSync(filePath, "utf-8");
17539
+ const rawPayload = fs29.readFileSync(filePath, "utf-8");
16952
17540
  const envelope = JSON.parse(rawPayload);
16953
17541
  const sessionId = envelope.session_id || envelope.message_id || uuidv48();
16954
17542
  registerSession({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nomad-e/bluma-cli",
3
- "version": "0.1.52",
3
+ "version": "0.1.53",
4
4
  "description": "BluMa independent agent for automation and advanced software engineering.",
5
5
  "author": "Alex Fonseca",
6
6
  "license": "Apache-2.0",