@nomad-e/bluma-cli 0.1.37 → 0.1.38
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 +325 -53
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -331,8 +331,8 @@ var init_async_command = __esm({
|
|
|
331
331
|
import React12 from "react";
|
|
332
332
|
import { render } from "ink";
|
|
333
333
|
import { EventEmitter as EventEmitter3 } from "events";
|
|
334
|
-
import
|
|
335
|
-
import
|
|
334
|
+
import fs18 from "fs";
|
|
335
|
+
import path22 from "path";
|
|
336
336
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
337
337
|
import { v4 as uuidv46 } from "uuid";
|
|
338
338
|
|
|
@@ -2317,7 +2317,7 @@ var ConfirmationPrompt = memo4(ConfirmationPromptComponent);
|
|
|
2317
2317
|
|
|
2318
2318
|
// src/app/agent/agent.ts
|
|
2319
2319
|
import * as dotenv from "dotenv";
|
|
2320
|
-
import
|
|
2320
|
+
import path20 from "path";
|
|
2321
2321
|
import os14 from "os";
|
|
2322
2322
|
|
|
2323
2323
|
// src/app/agent/tool_invoker.ts
|
|
@@ -4821,7 +4821,7 @@ var AdvancedFeedbackSystem = class {
|
|
|
4821
4821
|
};
|
|
4822
4822
|
|
|
4823
4823
|
// src/app/agent/bluma/core/bluma.ts
|
|
4824
|
-
import
|
|
4824
|
+
import path19 from "path";
|
|
4825
4825
|
import { v4 as uuidv43 } from "uuid";
|
|
4826
4826
|
|
|
4827
4827
|
// src/app/agent/session_manager/session_manager.ts
|
|
@@ -5012,9 +5012,9 @@ async function saveSessionHistory(sessionFile, history, memory) {
|
|
|
5012
5012
|
|
|
5013
5013
|
// src/app/agent/core/prompt/prompt_builder.ts
|
|
5014
5014
|
import os11 from "os";
|
|
5015
|
-
import
|
|
5016
|
-
import
|
|
5017
|
-
import { execSync } from "child_process";
|
|
5015
|
+
import fs16 from "fs";
|
|
5016
|
+
import path18 from "path";
|
|
5017
|
+
import { execSync as execSync2 } from "child_process";
|
|
5018
5018
|
|
|
5019
5019
|
// src/app/agent/skills/skill_loader.ts
|
|
5020
5020
|
import fs14 from "fs";
|
|
@@ -5313,6 +5313,215 @@ var SkillLoader = class _SkillLoader {
|
|
|
5313
5313
|
}
|
|
5314
5314
|
};
|
|
5315
5315
|
|
|
5316
|
+
// src/app/agent/core/prompt/workspace_snapshot.ts
|
|
5317
|
+
import fs15 from "fs";
|
|
5318
|
+
import path17 from "path";
|
|
5319
|
+
import { execSync } from "child_process";
|
|
5320
|
+
var LIMITS = {
|
|
5321
|
+
readme: 1e4,
|
|
5322
|
+
blumaMd: 12e3,
|
|
5323
|
+
contributing: 4e3,
|
|
5324
|
+
changelog: 4e3,
|
|
5325
|
+
pyproject: 3500,
|
|
5326
|
+
gitStatusLines: 48,
|
|
5327
|
+
gitLogLines: 14,
|
|
5328
|
+
diffStatLines: 28,
|
|
5329
|
+
topDirEntries: 96
|
|
5330
|
+
};
|
|
5331
|
+
function safeReadFile(filePath, maxChars) {
|
|
5332
|
+
try {
|
|
5333
|
+
if (!fs15.existsSync(filePath)) return null;
|
|
5334
|
+
const st = fs15.statSync(filePath);
|
|
5335
|
+
if (!st.isFile()) return null;
|
|
5336
|
+
const raw = fs15.readFileSync(filePath, "utf8");
|
|
5337
|
+
if (raw.length <= maxChars) return raw;
|
|
5338
|
+
return `${raw.slice(0, maxChars)}
|
|
5339
|
+
|
|
5340
|
+
[\u2026 truncated for prompt size \u2026]`;
|
|
5341
|
+
} catch {
|
|
5342
|
+
return null;
|
|
5343
|
+
}
|
|
5344
|
+
}
|
|
5345
|
+
function tryReadReadme(cwd) {
|
|
5346
|
+
for (const name of ["README.md", "README.MD", "readme.md", "Readme.md"]) {
|
|
5347
|
+
const c = safeReadFile(path17.join(cwd, name), LIMITS.readme);
|
|
5348
|
+
if (c) return `(${name})
|
|
5349
|
+
${c}`;
|
|
5350
|
+
}
|
|
5351
|
+
return null;
|
|
5352
|
+
}
|
|
5353
|
+
function tryReadBluMaMd(cwd) {
|
|
5354
|
+
const paths = [
|
|
5355
|
+
path17.join(cwd, "BluMa.md"),
|
|
5356
|
+
path17.join(cwd, "BLUMA.md"),
|
|
5357
|
+
path17.join(cwd, ".bluma", "BluMa.md")
|
|
5358
|
+
];
|
|
5359
|
+
for (const p of paths) {
|
|
5360
|
+
const c = safeReadFile(p, LIMITS.blumaMd);
|
|
5361
|
+
if (c) {
|
|
5362
|
+
const rel = path17.relative(cwd, p) || p;
|
|
5363
|
+
return `(${rel})
|
|
5364
|
+
${c}`;
|
|
5365
|
+
}
|
|
5366
|
+
}
|
|
5367
|
+
return null;
|
|
5368
|
+
}
|
|
5369
|
+
function summarizePackageJson(cwd) {
|
|
5370
|
+
const p = path17.join(cwd, "package.json");
|
|
5371
|
+
try {
|
|
5372
|
+
if (!fs15.existsSync(p)) return null;
|
|
5373
|
+
const pkg = JSON.parse(fs15.readFileSync(p, "utf8"));
|
|
5374
|
+
const scripts = pkg.scripts;
|
|
5375
|
+
let scriptKeys = "";
|
|
5376
|
+
if (scripts && typeof scripts === "object" && !Array.isArray(scripts)) {
|
|
5377
|
+
scriptKeys = Object.keys(scripts).slice(0, 48).join(", ");
|
|
5378
|
+
}
|
|
5379
|
+
const deps = pkg.dependencies;
|
|
5380
|
+
const devDeps = pkg.devDependencies;
|
|
5381
|
+
const nd = deps && typeof deps === "object" && !Array.isArray(deps) ? Object.keys(deps).length : 0;
|
|
5382
|
+
const nDev = devDeps && typeof devDeps === "object" && !Array.isArray(devDeps) ? Object.keys(devDeps).length : 0;
|
|
5383
|
+
let s = `name: ${String(pkg.name ?? "?")} version: ${String(pkg.version ?? "?")}
|
|
5384
|
+
`;
|
|
5385
|
+
if (typeof pkg.description === "string" && pkg.description.trim()) {
|
|
5386
|
+
s += `description: ${pkg.description.trim().slice(0, 280)}
|
|
5387
|
+
`;
|
|
5388
|
+
}
|
|
5389
|
+
if (scriptKeys) s += `scripts (keys): ${scriptKeys}
|
|
5390
|
+
`;
|
|
5391
|
+
s += `dependencies: ${nd} devDependencies: ${nDev}
|
|
5392
|
+
`;
|
|
5393
|
+
if (pkg.engines) s += `engines: ${JSON.stringify(pkg.engines)}
|
|
5394
|
+
`;
|
|
5395
|
+
if (pkg.type) s += `type: ${String(pkg.type)}
|
|
5396
|
+
`;
|
|
5397
|
+
if (pkg.main) s += `main: ${String(pkg.main)}
|
|
5398
|
+
`;
|
|
5399
|
+
return s.trim();
|
|
5400
|
+
} catch {
|
|
5401
|
+
return null;
|
|
5402
|
+
}
|
|
5403
|
+
}
|
|
5404
|
+
function topLevelListing(cwd) {
|
|
5405
|
+
try {
|
|
5406
|
+
const names = fs15.readdirSync(cwd, { withFileTypes: true });
|
|
5407
|
+
const sorted = [...names].sort((a, b) => a.name.localeCompare(b.name));
|
|
5408
|
+
const limited = sorted.slice(0, LIMITS.topDirEntries);
|
|
5409
|
+
const lines = limited.map((d) => `${d.name}${d.isDirectory() ? "/" : ""}`);
|
|
5410
|
+
if (sorted.length > limited.length) {
|
|
5411
|
+
lines.push(`[\u2026 +${sorted.length - limited.length} more entries at repo root \u2026]`);
|
|
5412
|
+
}
|
|
5413
|
+
return lines.join("\n");
|
|
5414
|
+
} catch {
|
|
5415
|
+
return "(could not list directory)";
|
|
5416
|
+
}
|
|
5417
|
+
}
|
|
5418
|
+
function gitLines(cwd, args, maxLines) {
|
|
5419
|
+
try {
|
|
5420
|
+
const out = execSync(`git ${args}`, {
|
|
5421
|
+
cwd,
|
|
5422
|
+
encoding: "utf8",
|
|
5423
|
+
timeout: 1e4,
|
|
5424
|
+
maxBuffer: 512 * 1024,
|
|
5425
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
5426
|
+
});
|
|
5427
|
+
const lines = out.trimEnd().split(/\r?\n/).filter((l) => l.length > 0);
|
|
5428
|
+
if (lines.length > maxLines) {
|
|
5429
|
+
return `${lines.slice(0, maxLines).join("\n")}
|
|
5430
|
+
[\u2026 +${lines.length - maxLines} lines \u2026]`;
|
|
5431
|
+
}
|
|
5432
|
+
return lines.length ? lines.join("\n") : null;
|
|
5433
|
+
} catch {
|
|
5434
|
+
return null;
|
|
5435
|
+
}
|
|
5436
|
+
}
|
|
5437
|
+
function insideGitWorkTree(cwd) {
|
|
5438
|
+
try {
|
|
5439
|
+
const v = execSync("git rev-parse --is-inside-work-tree", {
|
|
5440
|
+
cwd,
|
|
5441
|
+
encoding: "utf8",
|
|
5442
|
+
timeout: 4e3,
|
|
5443
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
5444
|
+
}).trim();
|
|
5445
|
+
return v === "true";
|
|
5446
|
+
} catch {
|
|
5447
|
+
return false;
|
|
5448
|
+
}
|
|
5449
|
+
}
|
|
5450
|
+
function buildWorkspaceSnapshot(cwd) {
|
|
5451
|
+
const parts = [];
|
|
5452
|
+
parts.push(`### Repository root
|
|
5453
|
+
\`${cwd}\`
|
|
5454
|
+
`);
|
|
5455
|
+
parts.push("### Top-level entries\n```");
|
|
5456
|
+
parts.push(topLevelListing(cwd));
|
|
5457
|
+
parts.push("```\n");
|
|
5458
|
+
const pkg = summarizePackageJson(cwd);
|
|
5459
|
+
if (pkg) {
|
|
5460
|
+
parts.push("### package.json (summary)\n```");
|
|
5461
|
+
parts.push(pkg);
|
|
5462
|
+
parts.push("```\n");
|
|
5463
|
+
}
|
|
5464
|
+
const py = safeReadFile(path17.join(cwd, "pyproject.toml"), LIMITS.pyproject);
|
|
5465
|
+
if (py) {
|
|
5466
|
+
parts.push("### pyproject.toml (excerpt)\n```toml");
|
|
5467
|
+
parts.push(py);
|
|
5468
|
+
parts.push("```\n");
|
|
5469
|
+
}
|
|
5470
|
+
const readme = tryReadReadme(cwd);
|
|
5471
|
+
if (readme) {
|
|
5472
|
+
parts.push("### README (excerpt)\n```markdown");
|
|
5473
|
+
parts.push(readme);
|
|
5474
|
+
parts.push("```\n");
|
|
5475
|
+
}
|
|
5476
|
+
const bluma = tryReadBluMaMd(cwd);
|
|
5477
|
+
if (bluma) {
|
|
5478
|
+
parts.push("### BluMa / project context file (excerpt)\n```markdown");
|
|
5479
|
+
parts.push(bluma);
|
|
5480
|
+
parts.push("```\n");
|
|
5481
|
+
}
|
|
5482
|
+
const contrib = safeReadFile(path17.join(cwd, "CONTRIBUTING.md"), LIMITS.contributing);
|
|
5483
|
+
if (contrib) {
|
|
5484
|
+
parts.push("### CONTRIBUTING.md (excerpt)\n```markdown");
|
|
5485
|
+
parts.push(contrib);
|
|
5486
|
+
parts.push("```\n");
|
|
5487
|
+
}
|
|
5488
|
+
const chlog = safeReadFile(path17.join(cwd, "CHANGELOG.md"), LIMITS.changelog);
|
|
5489
|
+
if (!chlog) {
|
|
5490
|
+
const alt = safeReadFile(path17.join(cwd, "CHANGES.md"), LIMITS.changelog);
|
|
5491
|
+
if (alt) {
|
|
5492
|
+
parts.push("### CHANGES.md (excerpt)\n```markdown");
|
|
5493
|
+
parts.push(alt);
|
|
5494
|
+
parts.push("```\n");
|
|
5495
|
+
}
|
|
5496
|
+
} else {
|
|
5497
|
+
parts.push("### CHANGELOG.md (excerpt)\n```markdown");
|
|
5498
|
+
parts.push(chlog);
|
|
5499
|
+
parts.push("```\n");
|
|
5500
|
+
}
|
|
5501
|
+
if (insideGitWorkTree(cwd)) {
|
|
5502
|
+
parts.push("### Git\n");
|
|
5503
|
+
const st = gitLines(cwd, "status --short", LIMITS.gitStatusLines);
|
|
5504
|
+
parts.push("`git status --short`:\n```");
|
|
5505
|
+
parts.push(st ?? "(empty or unavailable)");
|
|
5506
|
+
parts.push("```\n");
|
|
5507
|
+
const log = gitLines(cwd, "log -n 14 --oneline --decorate", LIMITS.gitLogLines);
|
|
5508
|
+
if (log) {
|
|
5509
|
+
parts.push("Recent commits:\n```");
|
|
5510
|
+
parts.push(log);
|
|
5511
|
+
parts.push("```\n");
|
|
5512
|
+
}
|
|
5513
|
+
const stat = gitLines(cwd, "diff --stat HEAD", LIMITS.diffStatLines);
|
|
5514
|
+
if (stat) {
|
|
5515
|
+
parts.push("Uncommitted vs `HEAD` (`git diff --stat HEAD`):\n```");
|
|
5516
|
+
parts.push(stat);
|
|
5517
|
+
parts.push("```\n");
|
|
5518
|
+
}
|
|
5519
|
+
} else {
|
|
5520
|
+
parts.push("### Git\n(not a git work tree, or `git` unavailable)\n");
|
|
5521
|
+
}
|
|
5522
|
+
return parts.join("\n");
|
|
5523
|
+
}
|
|
5524
|
+
|
|
5316
5525
|
// src/app/agent/core/prompt/prompt_builder.ts
|
|
5317
5526
|
function getNodeVersion() {
|
|
5318
5527
|
try {
|
|
@@ -5323,14 +5532,14 @@ function getNodeVersion() {
|
|
|
5323
5532
|
}
|
|
5324
5533
|
function getNpmVersion() {
|
|
5325
5534
|
try {
|
|
5326
|
-
return
|
|
5535
|
+
return execSync2("npm --version", { encoding: "utf-8", timeout: 5e3 }).trim();
|
|
5327
5536
|
} catch {
|
|
5328
5537
|
return "unknown";
|
|
5329
5538
|
}
|
|
5330
5539
|
}
|
|
5331
5540
|
function getGitBranch(dir) {
|
|
5332
5541
|
try {
|
|
5333
|
-
return
|
|
5542
|
+
return execSync2("git rev-parse --abbrev-ref HEAD", {
|
|
5334
5543
|
cwd: dir,
|
|
5335
5544
|
encoding: "utf-8",
|
|
5336
5545
|
timeout: 5e3
|
|
@@ -5341,10 +5550,10 @@ function getGitBranch(dir) {
|
|
|
5341
5550
|
}
|
|
5342
5551
|
function getPackageManager(dir) {
|
|
5343
5552
|
try {
|
|
5344
|
-
if (
|
|
5345
|
-
if (
|
|
5346
|
-
if (
|
|
5347
|
-
if (
|
|
5553
|
+
if (fs16.existsSync(path18.join(dir, "pnpm-lock.yaml"))) return "pnpm";
|
|
5554
|
+
if (fs16.existsSync(path18.join(dir, "yarn.lock"))) return "yarn";
|
|
5555
|
+
if (fs16.existsSync(path18.join(dir, "bun.lockb"))) return "bun";
|
|
5556
|
+
if (fs16.existsSync(path18.join(dir, "package-lock.json"))) return "npm";
|
|
5348
5557
|
return "unknown";
|
|
5349
5558
|
} catch {
|
|
5350
5559
|
return "unknown";
|
|
@@ -5352,9 +5561,9 @@ function getPackageManager(dir) {
|
|
|
5352
5561
|
}
|
|
5353
5562
|
function getProjectType(dir) {
|
|
5354
5563
|
try {
|
|
5355
|
-
const files =
|
|
5564
|
+
const files = fs16.readdirSync(dir);
|
|
5356
5565
|
if (files.includes("package.json")) {
|
|
5357
|
-
const pkg = JSON.parse(
|
|
5566
|
+
const pkg = JSON.parse(fs16.readFileSync(path18.join(dir, "package.json"), "utf-8"));
|
|
5358
5567
|
if (pkg.dependencies?.next || pkg.devDependencies?.next) return "Next.js";
|
|
5359
5568
|
if (pkg.dependencies?.react || pkg.devDependencies?.react) return "React";
|
|
5360
5569
|
if (pkg.dependencies?.express || pkg.devDependencies?.express) return "Express";
|
|
@@ -5373,9 +5582,9 @@ function getProjectType(dir) {
|
|
|
5373
5582
|
}
|
|
5374
5583
|
function getTestFramework(dir) {
|
|
5375
5584
|
try {
|
|
5376
|
-
const pkgPath =
|
|
5377
|
-
if (
|
|
5378
|
-
const pkg = JSON.parse(
|
|
5585
|
+
const pkgPath = path18.join(dir, "package.json");
|
|
5586
|
+
if (fs16.existsSync(pkgPath)) {
|
|
5587
|
+
const pkg = JSON.parse(fs16.readFileSync(pkgPath, "utf-8"));
|
|
5379
5588
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
5380
5589
|
if (deps.jest) return "jest";
|
|
5381
5590
|
if (deps.vitest) return "vitest";
|
|
@@ -5384,7 +5593,7 @@ function getTestFramework(dir) {
|
|
|
5384
5593
|
if (deps["@playwright/test"]) return "playwright";
|
|
5385
5594
|
if (deps.cypress) return "cypress";
|
|
5386
5595
|
}
|
|
5387
|
-
if (
|
|
5596
|
+
if (fs16.existsSync(path18.join(dir, "pytest.ini")) || fs16.existsSync(path18.join(dir, "conftest.py"))) return "pytest";
|
|
5388
5597
|
return "unknown";
|
|
5389
5598
|
} catch {
|
|
5390
5599
|
return "unknown";
|
|
@@ -5392,9 +5601,9 @@ function getTestFramework(dir) {
|
|
|
5392
5601
|
}
|
|
5393
5602
|
function getTestCommand(dir) {
|
|
5394
5603
|
try {
|
|
5395
|
-
const pkgPath =
|
|
5396
|
-
if (
|
|
5397
|
-
const pkg = JSON.parse(
|
|
5604
|
+
const pkgPath = path18.join(dir, "package.json");
|
|
5605
|
+
if (fs16.existsSync(pkgPath)) {
|
|
5606
|
+
const pkg = JSON.parse(fs16.readFileSync(pkgPath, "utf-8"));
|
|
5398
5607
|
if (pkg.scripts?.test) return `npm test`;
|
|
5399
5608
|
if (pkg.scripts?.["test:unit"]) return `npm run test:unit`;
|
|
5400
5609
|
}
|
|
@@ -5418,7 +5627,7 @@ var SYSTEM_PROMPT = `
|
|
|
5418
5627
|
You are not just an assistant - you are a **teammate** who takes ownership of tasks.
|
|
5419
5628
|
|
|
5420
5629
|
Key traits:
|
|
5421
|
-
-
|
|
5630
|
+
- Act like a senior developer who has been on this project for years
|
|
5422
5631
|
- Suggest improvements proactively, don't just follow orders blindly
|
|
5423
5632
|
- Spot bugs and issues before they become problems
|
|
5424
5633
|
- Write tests as naturally as you write code
|
|
@@ -5426,6 +5635,42 @@ var SYSTEM_PROMPT = `
|
|
|
5426
5635
|
|
|
5427
5636
|
---
|
|
5428
5637
|
|
|
5638
|
+
<engineering_mindset>
|
|
5639
|
+
## How you think and act (agentic engineer \u2014 not a chatbot)
|
|
5640
|
+
|
|
5641
|
+
You behave like a **senior engineer in this repo**: you **ship**, you **prove with evidence**, and you **debug methodically**.
|
|
5642
|
+
|
|
5643
|
+
### Operating mode
|
|
5644
|
+
- **Autonomous by default:** move the task forward until truly blocked (missing secrets, policy, or a decision only the human can make). Do not ask permission to read files, search the tree, run tests, or inspect git when that reduces risk.
|
|
5645
|
+
- **Outcome over monologue:** deliver working changes; keep narration **short and technical** (what changed, which paths, which command proved it).
|
|
5646
|
+
- **No assistant theatre:** drop filler (\u201CAs an AI\u2026\u201D, \u201CI\u2019d be happy to\u2026\u201D, long preambles). Be direct like a teammate on Slack.
|
|
5647
|
+
|
|
5648
|
+
### Analysis (before you code)
|
|
5649
|
+
- Ground decisions in **observable facts** from tools: file contents, configs, compiler/test output, stack traces \u2014 not guesses.
|
|
5650
|
+
- Form a **hypothesis** you can falsify in **one** step (one command or one targeted read).
|
|
5651
|
+
- Before large refactors, map **blast radius** (callers, tests) with \`grep_search\` / \`read_file_lines\`.
|
|
5652
|
+
|
|
5653
|
+
### Debugging
|
|
5654
|
+
- **Reproduce first** \u2014 same command, same failure message. If you cannot reproduce, you do not understand the bug yet.
|
|
5655
|
+
- **Localise:** narrow to file + function + line using logs and traces; avoid random edits in unrelated modules.
|
|
5656
|
+
- **Fix minimally:** smallest change for the root cause; do not mix unrelated refactors with bugfixes unless the user asked.
|
|
5657
|
+
- **Verify:** re-run the **same** failing command or test target after the fix; treat **exit_code** and **stderr** as first-class \u2014 read them literally.
|
|
5658
|
+
- **Never claim \u201Cfixed\u201D or \u201Cpassing\u201D** without tool output that shows success.
|
|
5659
|
+
|
|
5660
|
+
### Implementation
|
|
5661
|
+
- **Read \u2192 edit \u2192 verify:** never edit from memory of a skim; use \`read_file_lines\` on the exact region you change.
|
|
5662
|
+
- Prefer **one logical slice** per burst when possible; for large work, use \`todo\` and complete vertical slices end-to-end (repro \u2192 fix \u2192 test).
|
|
5663
|
+
- Follow conventions from \`<workspace_snapshot>\`, \`BluMa.md\`, \`README\`, and **existing code** over generic templates.
|
|
5664
|
+
|
|
5665
|
+
### When stuck
|
|
5666
|
+
- Say what you tried, paste or summarise **concrete tool output** (path, exit code, error line), and propose the **next experiment** \u2014 not \u201Cit failed\u201D.
|
|
5667
|
+
- Use \`coding_memory\` for durable project facts; do not rely on chat scroll alone after context compression.
|
|
5668
|
+
|
|
5669
|
+
This mindset overrides generic assistant habits: you exist to **solve problems in the workspace** with tools and proof.
|
|
5670
|
+
</engineering_mindset>
|
|
5671
|
+
|
|
5672
|
+
---
|
|
5673
|
+
|
|
5429
5674
|
<skills_knowledge>
|
|
5430
5675
|
## Skills vs Base Knowledge (CRITICAL)
|
|
5431
5676
|
|
|
@@ -5507,6 +5752,22 @@ You MUST adapt all commands to this environment. Use the correct package manager
|
|
|
5507
5752
|
|
|
5508
5753
|
---
|
|
5509
5754
|
|
|
5755
|
+
<workspace_snapshot>
|
|
5756
|
+
## Project workspace (loaded from disk when the system prompt is built)
|
|
5757
|
+
|
|
5758
|
+
You are anchored to **the current working directory** (see **Working Directory** above). The block below is an automatic snapshot: tree root, package summary, README / BluMa.md excerpts, git status and recent commits, etc.
|
|
5759
|
+
|
|
5760
|
+
**How to use it (IDE-grade discipline):**
|
|
5761
|
+
- Treat this as a **map**, not ground truth \u2014 re-read files and run tests/build/linter before high-risk edits.
|
|
5762
|
+
- It becomes **stale** after \`git pull\`, installs, refactors, or long chats; verify again when it matters.
|
|
5763
|
+
- **Close the loop:** hypothesis \u2192 smallest change \u2192 run the same command a human would (\`test\`, \`build\`, typecheck) \u2192 read stdout/stderr literally \u2192 repeat until green.
|
|
5764
|
+
- Do not guess file contents; use your tools to confirm.
|
|
5765
|
+
|
|
5766
|
+
<<<BLUMA_WORKSPACE_SNAPSHOT_BODY>>>
|
|
5767
|
+
</workspace_snapshot>
|
|
5768
|
+
|
|
5769
|
+
---
|
|
5770
|
+
|
|
5510
5771
|
<coding_memory>
|
|
5511
5772
|
## Persistent coding memory (tool: \`coding_memory\`)
|
|
5512
5773
|
|
|
@@ -5554,6 +5815,12 @@ This is your **long-term scratchpad** (usually \`~/.bluma/coding_memory.json\`).
|
|
|
5554
5815
|
5. **Verify** - Check build, lint, and git status
|
|
5555
5816
|
6. **Summarize** - Report results and any follow-up actions
|
|
5556
5817
|
|
|
5818
|
+
### For debugging / incidents (follow \`<engineering_mindset>\`):
|
|
5819
|
+
1. **Reproduce** \u2014 run the same command or test the user (or the repo) uses; capture full output via \`command_status\`.
|
|
5820
|
+
2. **Localise** \u2014 trace to a specific file/line; read that code with tools before changing anything.
|
|
5821
|
+
3. **Fix** \u2014 minimal diff addressing the root cause.
|
|
5822
|
+
4. **Prove** \u2014 re-run the same check; only then report success, citing exit code / test summary.
|
|
5823
|
+
|
|
5557
5824
|
### For Simple Tasks:
|
|
5558
5825
|
- Quick acknowledgment + immediate action
|
|
5559
5826
|
- No TODO needed for single operations
|
|
@@ -5572,6 +5839,7 @@ Run tests when modifying code. If a testing skill is listed in available_skills,
|
|
|
5572
5839
|
|
|
5573
5840
|
### File Operations:
|
|
5574
5841
|
- **ALWAYS read a file before editing** - Use read_file_lines or ls_tool first
|
|
5842
|
+
- After \`shell_command\` + \`command_status\`, treat **exit_code**, **stdout**, and **stderr** as authoritative \u2014 failures often appear only in stderr
|
|
5575
5843
|
- **Use absolute paths** when possible to avoid ambiguity
|
|
5576
5844
|
- **For edit_tool**: Provide exact content with correct whitespace (read first!)
|
|
5577
5845
|
- **Truncated CLI preview** (user may press Ctrl+O for more lines): still not a substitute for \`read_file_lines\` \u2014 use the tool for authoritative content before editing
|
|
@@ -5707,8 +5975,8 @@ Examples:
|
|
|
5707
5975
|
|
|
5708
5976
|
**Style:**
|
|
5709
5977
|
- Direct and technical, like Slack/Discord
|
|
5710
|
-
- Get straight to the point
|
|
5711
|
-
- Celebrate wins, acknowledge mistakes
|
|
5978
|
+
- Get straight to the point; **agentic engineer**, not customer support tone
|
|
5979
|
+
- Celebrate wins, acknowledge mistakes with concrete next steps
|
|
5712
5980
|
|
|
5713
5981
|
**Message via tool only:**
|
|
5714
5982
|
- message with \`result\` = END your turn (after questions/completions)
|
|
@@ -5895,6 +6163,10 @@ function getUnifiedSystemPrompt(availableSkills) {
|
|
|
5895
6163
|
(p, [key, value]) => p.replaceAll(`{${key}}`, value),
|
|
5896
6164
|
basePrompt
|
|
5897
6165
|
);
|
|
6166
|
+
prompt = prompt.replace(
|
|
6167
|
+
"<<<BLUMA_WORKSPACE_SNAPSHOT_BODY>>>",
|
|
6168
|
+
buildWorkspaceSnapshot(cwd)
|
|
6169
|
+
);
|
|
5898
6170
|
if (availableSkills && availableSkills.length > 0) {
|
|
5899
6171
|
const skillsList = availableSkills.map((s) => `- ${s.name}: ${s.description}`).join("\n");
|
|
5900
6172
|
prompt += `
|
|
@@ -6061,8 +6333,8 @@ ${memorySnapshot.trim().length > 0 ? memorySnapshot : "(No entries yet. Use codi
|
|
|
6061
6333
|
}
|
|
6062
6334
|
function isGitRepo(dir) {
|
|
6063
6335
|
try {
|
|
6064
|
-
const gitPath =
|
|
6065
|
-
return
|
|
6336
|
+
const gitPath = path18.join(dir, ".git");
|
|
6337
|
+
return fs16.existsSync(gitPath) && fs16.lstatSync(gitPath).isDirectory();
|
|
6066
6338
|
} catch {
|
|
6067
6339
|
return false;
|
|
6068
6340
|
}
|
|
@@ -6980,7 +7252,7 @@ var BluMaAgent = class {
|
|
|
6980
7252
|
|
|
6981
7253
|
${editData.error.display}`;
|
|
6982
7254
|
}
|
|
6983
|
-
const filename =
|
|
7255
|
+
const filename = path19.basename(toolArgs.file_path);
|
|
6984
7256
|
return createDiff(filename, editData.currentContent || "", editData.newContent);
|
|
6985
7257
|
} catch (e) {
|
|
6986
7258
|
return `An unexpected error occurred while generating the edit preview: ${e.message}`;
|
|
@@ -7687,14 +7959,14 @@ var RouteManager = class {
|
|
|
7687
7959
|
this.subAgents = subAgents;
|
|
7688
7960
|
this.core = core;
|
|
7689
7961
|
}
|
|
7690
|
-
registerRoute(
|
|
7691
|
-
this.routeHandlers.set(
|
|
7962
|
+
registerRoute(path23, handler) {
|
|
7963
|
+
this.routeHandlers.set(path23, handler);
|
|
7692
7964
|
}
|
|
7693
7965
|
async handleRoute(payload) {
|
|
7694
7966
|
const inputText = String(payload.content || "").trim();
|
|
7695
7967
|
const { userContext } = payload;
|
|
7696
|
-
for (const [
|
|
7697
|
-
if (inputText ===
|
|
7968
|
+
for (const [path23, handler] of this.routeHandlers) {
|
|
7969
|
+
if (inputText === path23 || inputText.startsWith(`${path23} `)) {
|
|
7698
7970
|
return handler({ content: inputText, userContext });
|
|
7699
7971
|
}
|
|
7700
7972
|
}
|
|
@@ -7703,7 +7975,7 @@ var RouteManager = class {
|
|
|
7703
7975
|
};
|
|
7704
7976
|
|
|
7705
7977
|
// src/app/agent/agent.ts
|
|
7706
|
-
var globalEnvPath =
|
|
7978
|
+
var globalEnvPath = path20.join(os14.homedir(), ".bluma", ".env");
|
|
7707
7979
|
dotenv.config({ path: globalEnvPath });
|
|
7708
7980
|
var Agent = class {
|
|
7709
7981
|
sessionId;
|
|
@@ -7927,12 +8199,12 @@ var renderShellCommand2 = ({ args }) => {
|
|
|
7927
8199
|
};
|
|
7928
8200
|
var renderLsTool2 = ({ args }) => {
|
|
7929
8201
|
const parsed = parseArgs(args);
|
|
7930
|
-
const
|
|
8202
|
+
const path23 = parsed.directory_path || ".";
|
|
7931
8203
|
return /* @__PURE__ */ jsxs9(Box9, { children: [
|
|
7932
8204
|
/* @__PURE__ */ jsx9(Text9, { color: BLUMA_TERMINAL.brandBlue, bold: true, children: "ls" }),
|
|
7933
8205
|
/* @__PURE__ */ jsxs9(Text9, { dimColor: true, children: [
|
|
7934
8206
|
" ",
|
|
7935
|
-
|
|
8207
|
+
path23
|
|
7936
8208
|
] })
|
|
7937
8209
|
] });
|
|
7938
8210
|
};
|
|
@@ -8068,7 +8340,7 @@ var renderFindByName = ({ args }) => {
|
|
|
8068
8340
|
var renderGrepSearch = ({ args }) => {
|
|
8069
8341
|
const parsed = parseArgs(args);
|
|
8070
8342
|
const query = parsed.query || "";
|
|
8071
|
-
const
|
|
8343
|
+
const path23 = parsed.path || ".";
|
|
8072
8344
|
return /* @__PURE__ */ jsxs9(Box9, { children: [
|
|
8073
8345
|
/* @__PURE__ */ jsx9(Text9, { color: BLUMA_TERMINAL.brandBlue, bold: true, children: "grep" }),
|
|
8074
8346
|
/* @__PURE__ */ jsxs9(Text9, { color: BLUMA_TERMINAL.brandMagenta, children: [
|
|
@@ -8078,7 +8350,7 @@ var renderGrepSearch = ({ args }) => {
|
|
|
8078
8350
|
] }),
|
|
8079
8351
|
/* @__PURE__ */ jsxs9(Text9, { dimColor: true, children: [
|
|
8080
8352
|
" ",
|
|
8081
|
-
|
|
8353
|
+
path23
|
|
8082
8354
|
] })
|
|
8083
8355
|
] });
|
|
8084
8356
|
};
|
|
@@ -8647,10 +8919,10 @@ var ToolResultDisplayComponent = ({ toolName, result }) => {
|
|
|
8647
8919
|
] }),
|
|
8648
8920
|
matches.slice(0, 5).map((m, i) => {
|
|
8649
8921
|
const row = m;
|
|
8650
|
-
const
|
|
8922
|
+
const path23 = row.file || row.path || row.name || m;
|
|
8651
8923
|
const line = row.line;
|
|
8652
8924
|
return /* @__PURE__ */ jsxs11(Text11, { dimColor: true, children: [
|
|
8653
|
-
String(
|
|
8925
|
+
String(path23),
|
|
8654
8926
|
line != null ? `:${line}` : ""
|
|
8655
8927
|
] }, i);
|
|
8656
8928
|
}),
|
|
@@ -8991,16 +9263,16 @@ var SlashCommands_default = SlashCommands;
|
|
|
8991
9263
|
// src/app/agent/utils/update_check.ts
|
|
8992
9264
|
import updateNotifier from "update-notifier";
|
|
8993
9265
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
8994
|
-
import
|
|
8995
|
-
import
|
|
9266
|
+
import path21 from "path";
|
|
9267
|
+
import fs17 from "fs";
|
|
8996
9268
|
var BLUMA_PACKAGE_NAME = "@nomad-e/bluma-cli";
|
|
8997
9269
|
function findBlumaPackageJson(startDir) {
|
|
8998
9270
|
let dir = startDir;
|
|
8999
9271
|
for (let i = 0; i < 10; i++) {
|
|
9000
|
-
const candidate =
|
|
9001
|
-
if (
|
|
9272
|
+
const candidate = path21.join(dir, "package.json");
|
|
9273
|
+
if (fs17.existsSync(candidate)) {
|
|
9002
9274
|
try {
|
|
9003
|
-
const raw =
|
|
9275
|
+
const raw = fs17.readFileSync(candidate, "utf8");
|
|
9004
9276
|
const parsed = JSON.parse(raw);
|
|
9005
9277
|
if (parsed?.name === BLUMA_PACKAGE_NAME && parsed?.version) {
|
|
9006
9278
|
return { name: parsed.name, version: parsed.version };
|
|
@@ -9008,7 +9280,7 @@ function findBlumaPackageJson(startDir) {
|
|
|
9008
9280
|
} catch {
|
|
9009
9281
|
}
|
|
9010
9282
|
}
|
|
9011
|
-
const parent =
|
|
9283
|
+
const parent = path21.dirname(dir);
|
|
9012
9284
|
if (parent === dir) break;
|
|
9013
9285
|
dir = parent;
|
|
9014
9286
|
}
|
|
@@ -9021,12 +9293,12 @@ async function checkForUpdates() {
|
|
|
9021
9293
|
}
|
|
9022
9294
|
const binPath = process.argv?.[1];
|
|
9023
9295
|
let pkg = null;
|
|
9024
|
-
if (binPath &&
|
|
9025
|
-
pkg = findBlumaPackageJson(
|
|
9296
|
+
if (binPath && fs17.existsSync(binPath)) {
|
|
9297
|
+
pkg = findBlumaPackageJson(path21.dirname(binPath));
|
|
9026
9298
|
}
|
|
9027
9299
|
if (!pkg) {
|
|
9028
9300
|
const __filename = fileURLToPath4(import.meta.url);
|
|
9029
|
-
const __dirname =
|
|
9301
|
+
const __dirname = path21.dirname(__filename);
|
|
9030
9302
|
pkg = findBlumaPackageJson(__dirname);
|
|
9031
9303
|
}
|
|
9032
9304
|
if (!pkg) {
|
|
@@ -9853,9 +10125,9 @@ async function runAgentMode() {
|
|
|
9853
10125
|
try {
|
|
9854
10126
|
if (inputFileIndex !== -1 && args[inputFileIndex + 1]) {
|
|
9855
10127
|
const filePath = args[inputFileIndex + 1];
|
|
9856
|
-
rawPayload =
|
|
10128
|
+
rawPayload = fs18.readFileSync(filePath, "utf-8");
|
|
9857
10129
|
} else {
|
|
9858
|
-
rawPayload =
|
|
10130
|
+
rawPayload = fs18.readFileSync(0, "utf-8");
|
|
9859
10131
|
}
|
|
9860
10132
|
} catch (err) {
|
|
9861
10133
|
writeJsonl({
|
|
@@ -10023,9 +10295,9 @@ async function runAgentMode() {
|
|
|
10023
10295
|
}
|
|
10024
10296
|
function readCliPackageVersion() {
|
|
10025
10297
|
try {
|
|
10026
|
-
const base =
|
|
10027
|
-
const pkgPath =
|
|
10028
|
-
const j = JSON.parse(
|
|
10298
|
+
const base = path22.dirname(fileURLToPath5(import.meta.url));
|
|
10299
|
+
const pkgPath = path22.join(base, "..", "package.json");
|
|
10300
|
+
const j = JSON.parse(fs18.readFileSync(pkgPath, "utf8"));
|
|
10029
10301
|
return String(j.version || "0.0.0");
|
|
10030
10302
|
} catch {
|
|
10031
10303
|
return "0.0.0";
|