@nomad-e/bluma-cli 0.1.26 → 0.1.28
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 +386 -142
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -178,16 +178,16 @@ async function commandStatus(args) {
|
|
|
178
178
|
}
|
|
179
179
|
const maxWait = Math.min(wait_seconds, 15);
|
|
180
180
|
if (maxWait > 0 && entry.status === "running") {
|
|
181
|
-
await new Promise((
|
|
181
|
+
await new Promise((resolve2) => {
|
|
182
182
|
const checkInterval = setInterval(() => {
|
|
183
183
|
if (entry.status !== "running") {
|
|
184
184
|
clearInterval(checkInterval);
|
|
185
|
-
|
|
185
|
+
resolve2();
|
|
186
186
|
}
|
|
187
187
|
}, 100);
|
|
188
188
|
setTimeout(() => {
|
|
189
189
|
clearInterval(checkInterval);
|
|
190
|
-
|
|
190
|
+
resolve2();
|
|
191
191
|
}, maxWait * 1e3);
|
|
192
192
|
});
|
|
193
193
|
}
|
|
@@ -331,7 +331,7 @@ var init_async_command = __esm({
|
|
|
331
331
|
import React11 from "react";
|
|
332
332
|
import { render } from "ink";
|
|
333
333
|
import { EventEmitter as EventEmitter2 } from "events";
|
|
334
|
-
import
|
|
334
|
+
import fs15 from "fs";
|
|
335
335
|
import { v4 as uuidv46 } from "uuid";
|
|
336
336
|
|
|
337
337
|
// src/app/ui/App.tsx
|
|
@@ -1484,12 +1484,12 @@ var ConfirmationPrompt = memo4(ConfirmationPromptComponent);
|
|
|
1484
1484
|
|
|
1485
1485
|
// src/app/agent/agent.ts
|
|
1486
1486
|
import * as dotenv from "dotenv";
|
|
1487
|
-
import
|
|
1488
|
-
import
|
|
1487
|
+
import path17 from "path";
|
|
1488
|
+
import os11 from "os";
|
|
1489
1489
|
|
|
1490
1490
|
// src/app/agent/tool_invoker.ts
|
|
1491
|
-
import { promises as
|
|
1492
|
-
import
|
|
1491
|
+
import { promises as fs9 } from "fs";
|
|
1492
|
+
import path11 from "path";
|
|
1493
1493
|
import { fileURLToPath } from "url";
|
|
1494
1494
|
|
|
1495
1495
|
// src/app/agent/tools/natives/edit.ts
|
|
@@ -3077,7 +3077,7 @@ var MAX_RESULTS_DEFAULT = 5;
|
|
|
3077
3077
|
var REQUEST_TIMEOUT = 15e3;
|
|
3078
3078
|
var MAX_CONTENT_LENGTH = 4e3;
|
|
3079
3079
|
function httpGet(url, customHeaders) {
|
|
3080
|
-
return new Promise((
|
|
3080
|
+
return new Promise((resolve2, reject) => {
|
|
3081
3081
|
const protocol = url.startsWith("https") ? https : http;
|
|
3082
3082
|
const defaultHeaders = {
|
|
3083
3083
|
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
|
|
@@ -3093,14 +3093,14 @@ function httpGet(url, customHeaders) {
|
|
|
3093
3093
|
timeout: REQUEST_TIMEOUT
|
|
3094
3094
|
}, (res) => {
|
|
3095
3095
|
if (res.statusCode && res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
3096
|
-
httpGet(res.headers.location, customHeaders).then(
|
|
3096
|
+
httpGet(res.headers.location, customHeaders).then(resolve2).catch(reject);
|
|
3097
3097
|
return;
|
|
3098
3098
|
}
|
|
3099
3099
|
let data = "";
|
|
3100
3100
|
res.on("data", (chunk) => data += chunk);
|
|
3101
3101
|
res.on("end", () => {
|
|
3102
3102
|
if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
|
|
3103
|
-
|
|
3103
|
+
resolve2(data);
|
|
3104
3104
|
} else {
|
|
3105
3105
|
reject(new Error(`HTTP ${res.statusCode}: ${data.substring(0, 200)}`));
|
|
3106
3106
|
}
|
|
@@ -3424,6 +3424,218 @@ ${skill.content}`;
|
|
|
3424
3424
|
};
|
|
3425
3425
|
}
|
|
3426
3426
|
|
|
3427
|
+
// src/app/agent/tools/natives/coding_memory.ts
|
|
3428
|
+
import * as fs8 from "fs";
|
|
3429
|
+
import * as path10 from "path";
|
|
3430
|
+
import os4 from "os";
|
|
3431
|
+
var PROMPT_DEFAULT_MAX_TOTAL = 1e4;
|
|
3432
|
+
var PROMPT_DEFAULT_MAX_NOTES = 25;
|
|
3433
|
+
var PROMPT_DEFAULT_PREVIEW = 500;
|
|
3434
|
+
function readCodingMemoryForPrompt(options) {
|
|
3435
|
+
const maxTotal = options?.maxTotalChars ?? PROMPT_DEFAULT_MAX_TOTAL;
|
|
3436
|
+
const maxNotes = options?.maxNotes ?? PROMPT_DEFAULT_MAX_NOTES;
|
|
3437
|
+
const preview = options?.previewCharsPerNote ?? PROMPT_DEFAULT_PREVIEW;
|
|
3438
|
+
const globalPath = path10.join(os4.homedir(), ".bluma", "coding_memory.json");
|
|
3439
|
+
const legacyPath = path10.join(process.cwd(), ".bluma", "coding_memory.json");
|
|
3440
|
+
let raw = null;
|
|
3441
|
+
try {
|
|
3442
|
+
if (fs8.existsSync(globalPath)) {
|
|
3443
|
+
raw = fs8.readFileSync(globalPath, "utf-8");
|
|
3444
|
+
} else if (path10.resolve(globalPath) !== path10.resolve(legacyPath) && fs8.existsSync(legacyPath)) {
|
|
3445
|
+
raw = fs8.readFileSync(legacyPath, "utf-8");
|
|
3446
|
+
}
|
|
3447
|
+
} catch {
|
|
3448
|
+
return "";
|
|
3449
|
+
}
|
|
3450
|
+
if (!raw) return "";
|
|
3451
|
+
let data;
|
|
3452
|
+
try {
|
|
3453
|
+
data = JSON.parse(raw);
|
|
3454
|
+
} catch {
|
|
3455
|
+
return "";
|
|
3456
|
+
}
|
|
3457
|
+
const entries = Array.isArray(data.entries) ? [...data.entries] : [];
|
|
3458
|
+
if (entries.length === 0) return "";
|
|
3459
|
+
entries.sort((a, b) => (b.id ?? 0) - (a.id ?? 0));
|
|
3460
|
+
const parts = [];
|
|
3461
|
+
let used = 0;
|
|
3462
|
+
for (let i = 0; i < entries.length && i < maxNotes; i++) {
|
|
3463
|
+
const e = entries[i];
|
|
3464
|
+
const full = e.note || "";
|
|
3465
|
+
const body = full.length > preview ? `${full.slice(0, preview)}\u2026` : full;
|
|
3466
|
+
const block = `### id ${e.id} \xB7 tags: ${(e.tags || []).join(", ") || "(none)"}
|
|
3467
|
+
${body}`;
|
|
3468
|
+
const piece = parts.length > 0 ? `
|
|
3469
|
+
|
|
3470
|
+
---
|
|
3471
|
+
|
|
3472
|
+
${block}` : block;
|
|
3473
|
+
if (used + piece.length > maxTotal) break;
|
|
3474
|
+
parts.push(piece);
|
|
3475
|
+
used += piece.length;
|
|
3476
|
+
}
|
|
3477
|
+
return parts.join("");
|
|
3478
|
+
}
|
|
3479
|
+
var memoryStore = [];
|
|
3480
|
+
var nextId2 = 1;
|
|
3481
|
+
var loaded = false;
|
|
3482
|
+
function getMemoryFilePath() {
|
|
3483
|
+
return path10.join(os4.homedir(), ".bluma", "coding_memory.json");
|
|
3484
|
+
}
|
|
3485
|
+
function getLegacyMemoryFilePath() {
|
|
3486
|
+
return path10.join(process.cwd(), ".bluma", "coding_memory.json");
|
|
3487
|
+
}
|
|
3488
|
+
function loadMemoryFromFile() {
|
|
3489
|
+
if (loaded) return;
|
|
3490
|
+
loaded = true;
|
|
3491
|
+
memoryStore = [];
|
|
3492
|
+
nextId2 = 1;
|
|
3493
|
+
try {
|
|
3494
|
+
const filePath = getMemoryFilePath();
|
|
3495
|
+
const legacy = getLegacyMemoryFilePath();
|
|
3496
|
+
const legacyDistinct = path10.resolve(legacy) !== path10.resolve(filePath);
|
|
3497
|
+
const readIntoStore = (p) => {
|
|
3498
|
+
const raw = fs8.readFileSync(p, "utf-8");
|
|
3499
|
+
const parsed = JSON.parse(raw);
|
|
3500
|
+
if (Array.isArray(parsed.entries)) {
|
|
3501
|
+
memoryStore = parsed.entries;
|
|
3502
|
+
nextId2 = typeof parsed.nextId === "number" ? parsed.nextId : memoryStore.length + 1;
|
|
3503
|
+
}
|
|
3504
|
+
};
|
|
3505
|
+
if (fs8.existsSync(filePath)) {
|
|
3506
|
+
readIntoStore(filePath);
|
|
3507
|
+
}
|
|
3508
|
+
if (memoryStore.length === 0 && legacyDistinct && fs8.existsSync(legacy)) {
|
|
3509
|
+
readIntoStore(legacy);
|
|
3510
|
+
if (memoryStore.length > 0) {
|
|
3511
|
+
saveMemoryToFile();
|
|
3512
|
+
}
|
|
3513
|
+
}
|
|
3514
|
+
} catch {
|
|
3515
|
+
memoryStore = [];
|
|
3516
|
+
nextId2 = 1;
|
|
3517
|
+
}
|
|
3518
|
+
}
|
|
3519
|
+
function saveMemoryToFile() {
|
|
3520
|
+
try {
|
|
3521
|
+
const filePath = getMemoryFilePath();
|
|
3522
|
+
const dir = path10.dirname(filePath);
|
|
3523
|
+
if (!fs8.existsSync(dir)) {
|
|
3524
|
+
fs8.mkdirSync(dir, { recursive: true });
|
|
3525
|
+
}
|
|
3526
|
+
const payload = {
|
|
3527
|
+
entries: memoryStore,
|
|
3528
|
+
nextId: nextId2,
|
|
3529
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3530
|
+
};
|
|
3531
|
+
fs8.writeFileSync(filePath, JSON.stringify(payload, null, 2));
|
|
3532
|
+
} catch {
|
|
3533
|
+
}
|
|
3534
|
+
}
|
|
3535
|
+
function normalizeTags(tags) {
|
|
3536
|
+
if (!tags) return [];
|
|
3537
|
+
return tags.map((t) => typeof t === "string" ? t.trim() : "").filter((t) => t.length > 0).slice(0, 10);
|
|
3538
|
+
}
|
|
3539
|
+
function addNote(args) {
|
|
3540
|
+
loadMemoryFromFile();
|
|
3541
|
+
const note = (args.note || "").trim();
|
|
3542
|
+
if (!note) {
|
|
3543
|
+
return {
|
|
3544
|
+
success: false,
|
|
3545
|
+
message: "note is required for action=add",
|
|
3546
|
+
entries: memoryStore
|
|
3547
|
+
};
|
|
3548
|
+
}
|
|
3549
|
+
if (note.length > 4e3) {
|
|
3550
|
+
return {
|
|
3551
|
+
success: false,
|
|
3552
|
+
message: "note too long (max 4000 chars)",
|
|
3553
|
+
entries: memoryStore
|
|
3554
|
+
};
|
|
3555
|
+
}
|
|
3556
|
+
const entry = {
|
|
3557
|
+
id: nextId2++,
|
|
3558
|
+
note,
|
|
3559
|
+
tags: normalizeTags(args.tags),
|
|
3560
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3561
|
+
usageCount: 0
|
|
3562
|
+
};
|
|
3563
|
+
memoryStore.push(entry);
|
|
3564
|
+
saveMemoryToFile();
|
|
3565
|
+
return {
|
|
3566
|
+
success: true,
|
|
3567
|
+
message: "Memory entry added",
|
|
3568
|
+
entries: memoryStore
|
|
3569
|
+
};
|
|
3570
|
+
}
|
|
3571
|
+
function listNotes() {
|
|
3572
|
+
loadMemoryFromFile();
|
|
3573
|
+
return {
|
|
3574
|
+
success: true,
|
|
3575
|
+
message: memoryStore.length === 0 ? "No coding memory entries yet" : `Listing ${memoryStore.length} coding memory entries`,
|
|
3576
|
+
entries: memoryStore
|
|
3577
|
+
};
|
|
3578
|
+
}
|
|
3579
|
+
function searchNotes(args) {
|
|
3580
|
+
loadMemoryFromFile();
|
|
3581
|
+
const query = (args.query || "").trim();
|
|
3582
|
+
if (!query) {
|
|
3583
|
+
return {
|
|
3584
|
+
success: false,
|
|
3585
|
+
message: "query is required for action=search",
|
|
3586
|
+
entries: memoryStore,
|
|
3587
|
+
matched: []
|
|
3588
|
+
};
|
|
3589
|
+
}
|
|
3590
|
+
const lower = query.toLowerCase();
|
|
3591
|
+
const matches = memoryStore.filter((e) => {
|
|
3592
|
+
if (e.note.toLowerCase().includes(lower)) return true;
|
|
3593
|
+
return e.tags.some((t) => t.toLowerCase().includes(lower));
|
|
3594
|
+
});
|
|
3595
|
+
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
3596
|
+
for (const entry of matches) {
|
|
3597
|
+
entry.lastUsedAt = nowIso;
|
|
3598
|
+
entry.usageCount = (entry.usageCount || 0) + 1;
|
|
3599
|
+
}
|
|
3600
|
+
saveMemoryToFile();
|
|
3601
|
+
return {
|
|
3602
|
+
success: true,
|
|
3603
|
+
message: matches.length === 0 ? "No matching coding memory entries" : `Found ${matches.length} matching entries`,
|
|
3604
|
+
entries: memoryStore,
|
|
3605
|
+
matched: matches
|
|
3606
|
+
};
|
|
3607
|
+
}
|
|
3608
|
+
function clearNotes() {
|
|
3609
|
+
loadMemoryFromFile();
|
|
3610
|
+
memoryStore = [];
|
|
3611
|
+
nextId2 = 1;
|
|
3612
|
+
saveMemoryToFile();
|
|
3613
|
+
return {
|
|
3614
|
+
success: true,
|
|
3615
|
+
message: "All coding memory entries cleared",
|
|
3616
|
+
entries: memoryStore
|
|
3617
|
+
};
|
|
3618
|
+
}
|
|
3619
|
+
async function coding_memory(args) {
|
|
3620
|
+
const action = args.action;
|
|
3621
|
+
switch (action) {
|
|
3622
|
+
case "add":
|
|
3623
|
+
return addNote(args);
|
|
3624
|
+
case "list":
|
|
3625
|
+
return listNotes();
|
|
3626
|
+
case "search":
|
|
3627
|
+
return searchNotes(args);
|
|
3628
|
+
case "clear":
|
|
3629
|
+
return clearNotes();
|
|
3630
|
+
default:
|
|
3631
|
+
return {
|
|
3632
|
+
success: false,
|
|
3633
|
+
message: `Unknown action: ${String(action)}`,
|
|
3634
|
+
entries: memoryStore
|
|
3635
|
+
};
|
|
3636
|
+
}
|
|
3637
|
+
}
|
|
3638
|
+
|
|
3427
3639
|
// src/app/agent/tool_invoker.ts
|
|
3428
3640
|
var ToolInvoker = class {
|
|
3429
3641
|
// Mapa privado para associar nomes de ferramentas às suas funções de implementação.
|
|
@@ -3441,9 +3653,9 @@ var ToolInvoker = class {
|
|
|
3441
3653
|
async initialize() {
|
|
3442
3654
|
try {
|
|
3443
3655
|
const __filename = fileURLToPath(import.meta.url);
|
|
3444
|
-
const __dirname2 =
|
|
3445
|
-
const configPath =
|
|
3446
|
-
const fileContent = await
|
|
3656
|
+
const __dirname2 = path11.dirname(__filename);
|
|
3657
|
+
const configPath = path11.resolve(__dirname2, "config", "native_tools.json");
|
|
3658
|
+
const fileContent = await fs9.readFile(configPath, "utf-8");
|
|
3447
3659
|
const config2 = JSON.parse(fileContent);
|
|
3448
3660
|
this.toolDefinitions = config2.nativeTools;
|
|
3449
3661
|
} catch (error) {
|
|
@@ -3474,6 +3686,7 @@ var ToolInvoker = class {
|
|
|
3474
3686
|
this.toolImplementations.set("read_artifact", readArtifact);
|
|
3475
3687
|
this.toolImplementations.set("search_web", searchWeb);
|
|
3476
3688
|
this.toolImplementations.set("load_skill", loadSkill);
|
|
3689
|
+
this.toolImplementations.set("coding_memory", coding_memory);
|
|
3477
3690
|
}
|
|
3478
3691
|
/**
|
|
3479
3692
|
* Retorna a lista de definições de todas as ferramentas nativas carregadas.
|
|
@@ -3503,9 +3716,9 @@ var ToolInvoker = class {
|
|
|
3503
3716
|
};
|
|
3504
3717
|
|
|
3505
3718
|
// src/app/agent/tools/mcp/mcp_client.ts
|
|
3506
|
-
import { promises as
|
|
3507
|
-
import
|
|
3508
|
-
import
|
|
3719
|
+
import { promises as fs10 } from "fs";
|
|
3720
|
+
import path12 from "path";
|
|
3721
|
+
import os5 from "os";
|
|
3509
3722
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
3510
3723
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
3511
3724
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
@@ -3532,9 +3745,9 @@ var MCPClient = class {
|
|
|
3532
3745
|
});
|
|
3533
3746
|
}
|
|
3534
3747
|
const __filename = fileURLToPath2(import.meta.url);
|
|
3535
|
-
const __dirname2 =
|
|
3536
|
-
const defaultConfigPath =
|
|
3537
|
-
const userConfigPath =
|
|
3748
|
+
const __dirname2 = path12.dirname(__filename);
|
|
3749
|
+
const defaultConfigPath = path12.resolve(__dirname2, "config", "bluma-mcp.json");
|
|
3750
|
+
const userConfigPath = path12.join(os5.homedir(), ".bluma", "bluma-mcp.json");
|
|
3538
3751
|
const defaultConfig = await this.loadMcpConfig(defaultConfigPath, "Default");
|
|
3539
3752
|
const userConfig = await this.loadMcpConfig(userConfigPath, "User");
|
|
3540
3753
|
const mergedConfig = {
|
|
@@ -3568,7 +3781,7 @@ var MCPClient = class {
|
|
|
3568
3781
|
}
|
|
3569
3782
|
async loadMcpConfig(configPath, configType) {
|
|
3570
3783
|
try {
|
|
3571
|
-
const fileContent = await
|
|
3784
|
+
const fileContent = await fs10.readFile(configPath, "utf-8");
|
|
3572
3785
|
const processedContent = this.replaceEnvPlaceholders(fileContent);
|
|
3573
3786
|
return JSON.parse(processedContent);
|
|
3574
3787
|
} catch (error) {
|
|
@@ -3587,7 +3800,7 @@ var MCPClient = class {
|
|
|
3587
3800
|
async connectToStdioServer(serverName, config2) {
|
|
3588
3801
|
let commandToExecute = config2.command;
|
|
3589
3802
|
let argsToExecute = config2.args || [];
|
|
3590
|
-
const isWindows =
|
|
3803
|
+
const isWindows = os5.platform() === "win32";
|
|
3591
3804
|
if (!isWindows && commandToExecute.toLowerCase() === "cmd") {
|
|
3592
3805
|
if (argsToExecute.length >= 2 && argsToExecute[0].toLowerCase() === "/c") {
|
|
3593
3806
|
commandToExecute = argsToExecute[1];
|
|
@@ -3703,13 +3916,13 @@ var AdvancedFeedbackSystem = class {
|
|
|
3703
3916
|
};
|
|
3704
3917
|
|
|
3705
3918
|
// src/app/agent/bluma/core/bluma.ts
|
|
3706
|
-
import
|
|
3919
|
+
import path16 from "path";
|
|
3707
3920
|
import { v4 as uuidv43 } from "uuid";
|
|
3708
3921
|
|
|
3709
3922
|
// src/app/agent/session_manager/session_manager.ts
|
|
3710
|
-
import
|
|
3711
|
-
import
|
|
3712
|
-
import { promises as
|
|
3923
|
+
import path13 from "path";
|
|
3924
|
+
import os6 from "os";
|
|
3925
|
+
import { promises as fs11 } from "fs";
|
|
3713
3926
|
var fileLocks = /* @__PURE__ */ new Map();
|
|
3714
3927
|
async function withFileLock(file, fn) {
|
|
3715
3928
|
const prev = fileLocks.get(file) || Promise.resolve();
|
|
@@ -3744,13 +3957,13 @@ function debouncedSave(sessionFile, history) {
|
|
|
3744
3957
|
function expandHome(p) {
|
|
3745
3958
|
if (!p) return p;
|
|
3746
3959
|
if (p.startsWith("~")) {
|
|
3747
|
-
return
|
|
3960
|
+
return path13.join(os6.homedir(), p.slice(1));
|
|
3748
3961
|
}
|
|
3749
3962
|
return p;
|
|
3750
3963
|
}
|
|
3751
3964
|
function getPreferredAppDir() {
|
|
3752
|
-
const fixed =
|
|
3753
|
-
return
|
|
3965
|
+
const fixed = path13.join(os6.homedir(), ".bluma");
|
|
3966
|
+
return path13.resolve(expandHome(fixed));
|
|
3754
3967
|
}
|
|
3755
3968
|
async function safeRenameWithRetry(src, dest, maxRetries = 6) {
|
|
3756
3969
|
let attempt = 0;
|
|
@@ -3758,10 +3971,10 @@ async function safeRenameWithRetry(src, dest, maxRetries = 6) {
|
|
|
3758
3971
|
const isWin = process.platform === "win32";
|
|
3759
3972
|
while (attempt <= maxRetries) {
|
|
3760
3973
|
try {
|
|
3761
|
-
const dir =
|
|
3762
|
-
await
|
|
3974
|
+
const dir = path13.dirname(dest);
|
|
3975
|
+
await fs11.mkdir(dir, { recursive: true }).catch(() => {
|
|
3763
3976
|
});
|
|
3764
|
-
await
|
|
3977
|
+
await fs11.rename(src, dest);
|
|
3765
3978
|
return;
|
|
3766
3979
|
} catch (e) {
|
|
3767
3980
|
lastErr = e;
|
|
@@ -3774,13 +3987,13 @@ async function safeRenameWithRetry(src, dest, maxRetries = 6) {
|
|
|
3774
3987
|
}
|
|
3775
3988
|
}
|
|
3776
3989
|
try {
|
|
3777
|
-
await
|
|
3778
|
-
const data = await
|
|
3779
|
-
const dir =
|
|
3780
|
-
await
|
|
3990
|
+
await fs11.access(src);
|
|
3991
|
+
const data = await fs11.readFile(src);
|
|
3992
|
+
const dir = path13.dirname(dest);
|
|
3993
|
+
await fs11.mkdir(dir, { recursive: true }).catch(() => {
|
|
3781
3994
|
});
|
|
3782
|
-
await
|
|
3783
|
-
await
|
|
3995
|
+
await fs11.writeFile(dest, data);
|
|
3996
|
+
await fs11.unlink(src).catch(() => {
|
|
3784
3997
|
});
|
|
3785
3998
|
return;
|
|
3786
3999
|
} catch (fallbackErr) {
|
|
@@ -3793,16 +4006,16 @@ async function safeRenameWithRetry(src, dest, maxRetries = 6) {
|
|
|
3793
4006
|
}
|
|
3794
4007
|
async function ensureSessionDir() {
|
|
3795
4008
|
const appDir = getPreferredAppDir();
|
|
3796
|
-
const sessionDir =
|
|
3797
|
-
await
|
|
4009
|
+
const sessionDir = path13.join(appDir, "sessions");
|
|
4010
|
+
await fs11.mkdir(sessionDir, { recursive: true });
|
|
3798
4011
|
return sessionDir;
|
|
3799
4012
|
}
|
|
3800
4013
|
async function loadOrcreateSession(sessionId) {
|
|
3801
4014
|
const sessionDir = await ensureSessionDir();
|
|
3802
|
-
const sessionFile =
|
|
4015
|
+
const sessionFile = path13.join(sessionDir, `${sessionId}.json`);
|
|
3803
4016
|
try {
|
|
3804
|
-
await
|
|
3805
|
-
const fileContent = await
|
|
4017
|
+
await fs11.access(sessionFile);
|
|
4018
|
+
const fileContent = await fs11.readFile(sessionFile, "utf-8");
|
|
3806
4019
|
const sessionData = JSON.parse(fileContent);
|
|
3807
4020
|
return [sessionFile, sessionData.conversation_history || [], []];
|
|
3808
4021
|
} catch (error) {
|
|
@@ -3811,7 +4024,7 @@ async function loadOrcreateSession(sessionId) {
|
|
|
3811
4024
|
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3812
4025
|
conversation_history: []
|
|
3813
4026
|
};
|
|
3814
|
-
await
|
|
4027
|
+
await fs11.writeFile(sessionFile, JSON.stringify(newSessionData, null, 2), "utf-8");
|
|
3815
4028
|
return [sessionFile, [], []];
|
|
3816
4029
|
}
|
|
3817
4030
|
}
|
|
@@ -3819,12 +4032,12 @@ async function doSaveSessionHistory(sessionFile, history) {
|
|
|
3819
4032
|
await withFileLock(sessionFile, async () => {
|
|
3820
4033
|
let sessionData;
|
|
3821
4034
|
try {
|
|
3822
|
-
const dir =
|
|
3823
|
-
await
|
|
4035
|
+
const dir = path13.dirname(sessionFile);
|
|
4036
|
+
await fs11.mkdir(dir, { recursive: true });
|
|
3824
4037
|
} catch {
|
|
3825
4038
|
}
|
|
3826
4039
|
try {
|
|
3827
|
-
const fileContent = await
|
|
4040
|
+
const fileContent = await fs11.readFile(sessionFile, "utf-8");
|
|
3828
4041
|
sessionData = JSON.parse(fileContent);
|
|
3829
4042
|
} catch (error) {
|
|
3830
4043
|
const code = error && error.code;
|
|
@@ -3835,14 +4048,14 @@ async function doSaveSessionHistory(sessionFile, history) {
|
|
|
3835
4048
|
console.warn(`An unknown error occurred while reading ${sessionFile}. Re-initializing.`, error);
|
|
3836
4049
|
}
|
|
3837
4050
|
}
|
|
3838
|
-
const sessionId =
|
|
4051
|
+
const sessionId = path13.basename(sessionFile, ".json");
|
|
3839
4052
|
sessionData = {
|
|
3840
4053
|
session_id: sessionId,
|
|
3841
4054
|
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3842
4055
|
conversation_history: []
|
|
3843
4056
|
};
|
|
3844
4057
|
try {
|
|
3845
|
-
await
|
|
4058
|
+
await fs11.writeFile(sessionFile, JSON.stringify(sessionData, null, 2), "utf-8");
|
|
3846
4059
|
} catch {
|
|
3847
4060
|
}
|
|
3848
4061
|
}
|
|
@@ -3850,7 +4063,7 @@ async function doSaveSessionHistory(sessionFile, history) {
|
|
|
3850
4063
|
sessionData.last_updated = (/* @__PURE__ */ new Date()).toISOString();
|
|
3851
4064
|
const tempSessionFile = `${sessionFile}.${Date.now()}.tmp`;
|
|
3852
4065
|
try {
|
|
3853
|
-
await
|
|
4066
|
+
await fs11.writeFile(tempSessionFile, JSON.stringify(sessionData, null, 2), "utf-8");
|
|
3854
4067
|
await safeRenameWithRetry(tempSessionFile, sessionFile);
|
|
3855
4068
|
} catch (writeError) {
|
|
3856
4069
|
if (writeError instanceof Error) {
|
|
@@ -3859,7 +4072,7 @@ async function doSaveSessionHistory(sessionFile, history) {
|
|
|
3859
4072
|
console.error(`An unknown fatal error occurred while saving session to ${sessionFile}:`, writeError);
|
|
3860
4073
|
}
|
|
3861
4074
|
try {
|
|
3862
|
-
await
|
|
4075
|
+
await fs11.unlink(tempSessionFile);
|
|
3863
4076
|
} catch {
|
|
3864
4077
|
}
|
|
3865
4078
|
}
|
|
@@ -3876,15 +4089,15 @@ async function saveSessionHistory(sessionFile, history) {
|
|
|
3876
4089
|
}
|
|
3877
4090
|
|
|
3878
4091
|
// src/app/agent/core/prompt/prompt_builder.ts
|
|
3879
|
-
import
|
|
3880
|
-
import
|
|
3881
|
-
import
|
|
4092
|
+
import os8 from "os";
|
|
4093
|
+
import fs13 from "fs";
|
|
4094
|
+
import path15 from "path";
|
|
3882
4095
|
import { execSync } from "child_process";
|
|
3883
4096
|
|
|
3884
4097
|
// src/app/agent/skills/skill_loader.ts
|
|
3885
|
-
import
|
|
3886
|
-
import
|
|
3887
|
-
import
|
|
4098
|
+
import fs12 from "fs";
|
|
4099
|
+
import path14 from "path";
|
|
4100
|
+
import os7 from "os";
|
|
3888
4101
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
3889
4102
|
var SkillLoader = class _SkillLoader {
|
|
3890
4103
|
bundledSkillsDir;
|
|
@@ -3893,8 +4106,8 @@ var SkillLoader = class _SkillLoader {
|
|
|
3893
4106
|
cache = /* @__PURE__ */ new Map();
|
|
3894
4107
|
conflicts = [];
|
|
3895
4108
|
constructor(projectRoot, bundledDir) {
|
|
3896
|
-
this.projectSkillsDir =
|
|
3897
|
-
this.globalSkillsDir =
|
|
4109
|
+
this.projectSkillsDir = path14.join(projectRoot, ".bluma", "skills");
|
|
4110
|
+
this.globalSkillsDir = path14.join(os7.homedir(), ".bluma", "skills");
|
|
3898
4111
|
this.bundledSkillsDir = bundledDir || _SkillLoader.resolveBundledDir();
|
|
3899
4112
|
}
|
|
3900
4113
|
/**
|
|
@@ -3904,16 +4117,16 @@ var SkillLoader = class _SkillLoader {
|
|
|
3904
4117
|
static resolveBundledDir() {
|
|
3905
4118
|
if (process.env.NODE_ENV === "test" || process.env.JEST_WORKER_ID !== void 0) {
|
|
3906
4119
|
if (typeof __dirname !== "undefined") {
|
|
3907
|
-
return
|
|
4120
|
+
return path14.join(__dirname, "config", "skills");
|
|
3908
4121
|
}
|
|
3909
|
-
return
|
|
4122
|
+
return path14.join(process.cwd(), "dist", "config", "skills");
|
|
3910
4123
|
}
|
|
3911
4124
|
try {
|
|
3912
4125
|
const currentFile = fileURLToPath3(import.meta.url);
|
|
3913
|
-
const distDir =
|
|
3914
|
-
return
|
|
4126
|
+
const distDir = path14.dirname(currentFile);
|
|
4127
|
+
return path14.join(distDir, "config", "skills");
|
|
3915
4128
|
} catch {
|
|
3916
|
-
return
|
|
4129
|
+
return path14.join(process.cwd(), "dist", "config", "skills");
|
|
3917
4130
|
}
|
|
3918
4131
|
}
|
|
3919
4132
|
/**
|
|
@@ -3942,8 +4155,8 @@ var SkillLoader = class _SkillLoader {
|
|
|
3942
4155
|
this.conflicts.push({
|
|
3943
4156
|
name: skill.name,
|
|
3944
4157
|
userSource: source,
|
|
3945
|
-
userPath:
|
|
3946
|
-
bundledPath:
|
|
4158
|
+
userPath: path14.join(dir, skill.name, "SKILL.md"),
|
|
4159
|
+
bundledPath: path14.join(this.bundledSkillsDir, skill.name, "SKILL.md")
|
|
3947
4160
|
});
|
|
3948
4161
|
continue;
|
|
3949
4162
|
}
|
|
@@ -3951,20 +4164,20 @@ var SkillLoader = class _SkillLoader {
|
|
|
3951
4164
|
}
|
|
3952
4165
|
}
|
|
3953
4166
|
listFromDir(dir, source) {
|
|
3954
|
-
if (!
|
|
4167
|
+
if (!fs12.existsSync(dir)) return [];
|
|
3955
4168
|
try {
|
|
3956
|
-
return
|
|
3957
|
-
const fullPath =
|
|
3958
|
-
return
|
|
3959
|
-
}).map((d) => this.loadMetadataFromPath(
|
|
4169
|
+
return fs12.readdirSync(dir).filter((d) => {
|
|
4170
|
+
const fullPath = path14.join(dir, d);
|
|
4171
|
+
return fs12.statSync(fullPath).isDirectory() && fs12.existsSync(path14.join(fullPath, "SKILL.md"));
|
|
4172
|
+
}).map((d) => this.loadMetadataFromPath(path14.join(dir, d, "SKILL.md"), d, source)).filter((m) => m !== null);
|
|
3960
4173
|
} catch {
|
|
3961
4174
|
return [];
|
|
3962
4175
|
}
|
|
3963
4176
|
}
|
|
3964
4177
|
loadMetadataFromPath(skillPath, skillName, source) {
|
|
3965
|
-
if (!
|
|
4178
|
+
if (!fs12.existsSync(skillPath)) return null;
|
|
3966
4179
|
try {
|
|
3967
|
-
const raw =
|
|
4180
|
+
const raw = fs12.readFileSync(skillPath, "utf-8");
|
|
3968
4181
|
const parsed = this.parseFrontmatter(raw);
|
|
3969
4182
|
return {
|
|
3970
4183
|
name: parsed.name || skillName,
|
|
@@ -3986,12 +4199,12 @@ var SkillLoader = class _SkillLoader {
|
|
|
3986
4199
|
*/
|
|
3987
4200
|
load(name) {
|
|
3988
4201
|
if (this.cache.has(name)) return this.cache.get(name);
|
|
3989
|
-
const bundledPath =
|
|
3990
|
-
const projectPath =
|
|
3991
|
-
const globalPath =
|
|
3992
|
-
const existsBundled =
|
|
3993
|
-
const existsProject =
|
|
3994
|
-
const existsGlobal =
|
|
4202
|
+
const bundledPath = path14.join(this.bundledSkillsDir, name, "SKILL.md");
|
|
4203
|
+
const projectPath = path14.join(this.projectSkillsDir, name, "SKILL.md");
|
|
4204
|
+
const globalPath = path14.join(this.globalSkillsDir, name, "SKILL.md");
|
|
4205
|
+
const existsBundled = fs12.existsSync(bundledPath);
|
|
4206
|
+
const existsProject = fs12.existsSync(projectPath);
|
|
4207
|
+
const existsGlobal = fs12.existsSync(globalPath);
|
|
3995
4208
|
if (existsBundled && (existsProject || existsGlobal)) {
|
|
3996
4209
|
const conflictSource = existsProject ? "project" : "global";
|
|
3997
4210
|
const conflictPath = existsProject ? projectPath : globalPath;
|
|
@@ -4030,9 +4243,9 @@ var SkillLoader = class _SkillLoader {
|
|
|
4030
4243
|
}
|
|
4031
4244
|
loadFromPath(skillPath, name, source) {
|
|
4032
4245
|
try {
|
|
4033
|
-
const raw =
|
|
4246
|
+
const raw = fs12.readFileSync(skillPath, "utf-8");
|
|
4034
4247
|
const parsed = this.parseFrontmatter(raw);
|
|
4035
|
-
const skillDir =
|
|
4248
|
+
const skillDir = path14.dirname(skillPath);
|
|
4036
4249
|
return {
|
|
4037
4250
|
name: parsed.name || name,
|
|
4038
4251
|
description: parsed.description || "",
|
|
@@ -4041,22 +4254,22 @@ var SkillLoader = class _SkillLoader {
|
|
|
4041
4254
|
version: parsed.version,
|
|
4042
4255
|
author: parsed.author,
|
|
4043
4256
|
license: parsed.license,
|
|
4044
|
-
references: this.scanAssets(
|
|
4045
|
-
scripts: this.scanAssets(
|
|
4257
|
+
references: this.scanAssets(path14.join(skillDir, "references")),
|
|
4258
|
+
scripts: this.scanAssets(path14.join(skillDir, "scripts"))
|
|
4046
4259
|
};
|
|
4047
4260
|
} catch {
|
|
4048
4261
|
return null;
|
|
4049
4262
|
}
|
|
4050
4263
|
}
|
|
4051
4264
|
scanAssets(dir) {
|
|
4052
|
-
if (!
|
|
4265
|
+
if (!fs12.existsSync(dir)) return [];
|
|
4053
4266
|
try {
|
|
4054
|
-
return
|
|
4055
|
-
const fp =
|
|
4056
|
-
return
|
|
4267
|
+
return fs12.readdirSync(dir).filter((f) => {
|
|
4268
|
+
const fp = path14.join(dir, f);
|
|
4269
|
+
return fs12.statSync(fp).isFile();
|
|
4057
4270
|
}).map((f) => ({
|
|
4058
4271
|
name: f,
|
|
4059
|
-
path:
|
|
4272
|
+
path: path14.resolve(dir, f)
|
|
4060
4273
|
}));
|
|
4061
4274
|
} catch {
|
|
4062
4275
|
return [];
|
|
@@ -4113,10 +4326,10 @@ var SkillLoader = class _SkillLoader {
|
|
|
4113
4326
|
this.cache.clear();
|
|
4114
4327
|
}
|
|
4115
4328
|
exists(name) {
|
|
4116
|
-
const bundledPath =
|
|
4117
|
-
const projectPath =
|
|
4118
|
-
const globalPath =
|
|
4119
|
-
return
|
|
4329
|
+
const bundledPath = path14.join(this.bundledSkillsDir, name, "SKILL.md");
|
|
4330
|
+
const projectPath = path14.join(this.projectSkillsDir, name, "SKILL.md");
|
|
4331
|
+
const globalPath = path14.join(this.globalSkillsDir, name, "SKILL.md");
|
|
4332
|
+
return fs12.existsSync(bundledPath) || fs12.existsSync(projectPath) || fs12.existsSync(globalPath);
|
|
4120
4333
|
}
|
|
4121
4334
|
/**
|
|
4122
4335
|
* Retorna conflitos detetados (skills do utilizador com mesmo nome de nativas).
|
|
@@ -4175,10 +4388,10 @@ function getGitBranch(dir) {
|
|
|
4175
4388
|
}
|
|
4176
4389
|
function getPackageManager(dir) {
|
|
4177
4390
|
try {
|
|
4178
|
-
if (
|
|
4179
|
-
if (
|
|
4180
|
-
if (
|
|
4181
|
-
if (
|
|
4391
|
+
if (fs13.existsSync(path15.join(dir, "pnpm-lock.yaml"))) return "pnpm";
|
|
4392
|
+
if (fs13.existsSync(path15.join(dir, "yarn.lock"))) return "yarn";
|
|
4393
|
+
if (fs13.existsSync(path15.join(dir, "bun.lockb"))) return "bun";
|
|
4394
|
+
if (fs13.existsSync(path15.join(dir, "package-lock.json"))) return "npm";
|
|
4182
4395
|
return "unknown";
|
|
4183
4396
|
} catch {
|
|
4184
4397
|
return "unknown";
|
|
@@ -4186,9 +4399,9 @@ function getPackageManager(dir) {
|
|
|
4186
4399
|
}
|
|
4187
4400
|
function getProjectType(dir) {
|
|
4188
4401
|
try {
|
|
4189
|
-
const files =
|
|
4402
|
+
const files = fs13.readdirSync(dir);
|
|
4190
4403
|
if (files.includes("package.json")) {
|
|
4191
|
-
const pkg = JSON.parse(
|
|
4404
|
+
const pkg = JSON.parse(fs13.readFileSync(path15.join(dir, "package.json"), "utf-8"));
|
|
4192
4405
|
if (pkg.dependencies?.next || pkg.devDependencies?.next) return "Next.js";
|
|
4193
4406
|
if (pkg.dependencies?.react || pkg.devDependencies?.react) return "React";
|
|
4194
4407
|
if (pkg.dependencies?.express || pkg.devDependencies?.express) return "Express";
|
|
@@ -4207,9 +4420,9 @@ function getProjectType(dir) {
|
|
|
4207
4420
|
}
|
|
4208
4421
|
function getTestFramework(dir) {
|
|
4209
4422
|
try {
|
|
4210
|
-
const pkgPath =
|
|
4211
|
-
if (
|
|
4212
|
-
const pkg = JSON.parse(
|
|
4423
|
+
const pkgPath = path15.join(dir, "package.json");
|
|
4424
|
+
if (fs13.existsSync(pkgPath)) {
|
|
4425
|
+
const pkg = JSON.parse(fs13.readFileSync(pkgPath, "utf-8"));
|
|
4213
4426
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
4214
4427
|
if (deps.jest) return "jest";
|
|
4215
4428
|
if (deps.vitest) return "vitest";
|
|
@@ -4218,7 +4431,7 @@ function getTestFramework(dir) {
|
|
|
4218
4431
|
if (deps["@playwright/test"]) return "playwright";
|
|
4219
4432
|
if (deps.cypress) return "cypress";
|
|
4220
4433
|
}
|
|
4221
|
-
if (
|
|
4434
|
+
if (fs13.existsSync(path15.join(dir, "pytest.ini")) || fs13.existsSync(path15.join(dir, "conftest.py"))) return "pytest";
|
|
4222
4435
|
return "unknown";
|
|
4223
4436
|
} catch {
|
|
4224
4437
|
return "unknown";
|
|
@@ -4226,9 +4439,9 @@ function getTestFramework(dir) {
|
|
|
4226
4439
|
}
|
|
4227
4440
|
function getTestCommand(dir) {
|
|
4228
4441
|
try {
|
|
4229
|
-
const pkgPath =
|
|
4230
|
-
if (
|
|
4231
|
-
const pkg = JSON.parse(
|
|
4442
|
+
const pkgPath = path15.join(dir, "package.json");
|
|
4443
|
+
if (fs13.existsSync(pkgPath)) {
|
|
4444
|
+
const pkg = JSON.parse(fs13.readFileSync(pkgPath, "utf-8"));
|
|
4232
4445
|
if (pkg.scripts?.test) return `npm test`;
|
|
4233
4446
|
if (pkg.scripts?.["test:unit"]) return `npm run test:unit`;
|
|
4234
4447
|
}
|
|
@@ -4337,6 +4550,26 @@ You MUST adapt all commands to this environment. Use the correct package manager
|
|
|
4337
4550
|
|
|
4338
4551
|
---
|
|
4339
4552
|
|
|
4553
|
+
<coding_memory>
|
|
4554
|
+
## Persistent coding memory (tool: \`coding_memory\`)
|
|
4555
|
+
|
|
4556
|
+
You have **durable notes** on disk (typically \`~/.bluma/coding_memory.json\`), separate from chat history. They **survive new sessions**.
|
|
4557
|
+
|
|
4558
|
+
### Baseline vs live refresh
|
|
4559
|
+
- The **<coding_memory_snapshot>** block (appended after this prompt) is loaded **once at session start** from disk. It can become stale if memory changes later or if the topic was never saved.
|
|
4560
|
+
- Act like a teammate who **checks their notes**: before relying on "what we agreed" or project-specific lore, use \`coding_memory\` with \`action: "search"\` and a short \`query\` \u2014 especially when the user asks if you remember something, or when switching back to a topic after a long stretch of work.
|
|
4561
|
+
|
|
4562
|
+
### When to write
|
|
4563
|
+
- After you learn **stable** facts (architecture, conventions, important URLs, decisions, repeated user preferences), call \`coding_memory\` with \`action: "add"\`, a concise \`note\`, and \`tags\` for later search.
|
|
4564
|
+
- When something **changes**, add an updated note (and do not treat outdated snapshot text as truth without searching).
|
|
4565
|
+
|
|
4566
|
+
### Habits (continuity)
|
|
4567
|
+
- Prefer **search** or **list** over guessing when answering "remember / last time / what we did".
|
|
4568
|
+
- Long specs belong in the repo or artifacts; use \`coding_memory\` for **short** reminders and pointers.
|
|
4569
|
+
</coding_memory>
|
|
4570
|
+
|
|
4571
|
+
---
|
|
4572
|
+
|
|
4340
4573
|
<workflow>
|
|
4341
4574
|
## How You Work
|
|
4342
4575
|
|
|
@@ -4664,12 +4897,12 @@ In sandbox mode you are a Python-focused, non-interactive, deterministic agent t
|
|
|
4664
4897
|
function getUnifiedSystemPrompt(availableSkills) {
|
|
4665
4898
|
const cwd = process.cwd();
|
|
4666
4899
|
const env = {
|
|
4667
|
-
os_type:
|
|
4668
|
-
os_version:
|
|
4669
|
-
architecture:
|
|
4900
|
+
os_type: os8.type(),
|
|
4901
|
+
os_version: os8.release(),
|
|
4902
|
+
architecture: os8.arch(),
|
|
4670
4903
|
workdir: cwd,
|
|
4671
4904
|
shell_type: process.env.SHELL || process.env.COMSPEC || "unknown",
|
|
4672
|
-
username:
|
|
4905
|
+
username: os8.userInfo().username,
|
|
4673
4906
|
current_date: (/* @__PURE__ */ new Date()).toISOString().split("T")[0],
|
|
4674
4907
|
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
4675
4908
|
is_git_repo: isGitRepo(cwd) ? "yes" : "no",
|
|
@@ -4839,12 +5072,23 @@ User: "Publish the package"
|
|
|
4839
5072
|
</available_skills>
|
|
4840
5073
|
`;
|
|
4841
5074
|
}
|
|
5075
|
+
const memorySnapshot = readCodingMemoryForPrompt();
|
|
5076
|
+
prompt += `
|
|
5077
|
+
|
|
5078
|
+
---
|
|
5079
|
+
|
|
5080
|
+
<coding_memory_snapshot>
|
|
5081
|
+
## Persistent notes (loaded at session start from disk)
|
|
5082
|
+
|
|
5083
|
+
${memorySnapshot.trim().length > 0 ? memorySnapshot : "(No entries yet. Use coding_memory with action add or search to build continuity across sessions.)"}
|
|
5084
|
+
</coding_memory_snapshot>
|
|
5085
|
+
`;
|
|
4842
5086
|
return prompt;
|
|
4843
5087
|
}
|
|
4844
5088
|
function isGitRepo(dir) {
|
|
4845
5089
|
try {
|
|
4846
|
-
const gitPath =
|
|
4847
|
-
return
|
|
5090
|
+
const gitPath = path15.join(dir, ".git");
|
|
5091
|
+
return fs13.existsSync(gitPath) && fs13.lstatSync(gitPath).isDirectory();
|
|
4848
5092
|
} catch {
|
|
4849
5093
|
return false;
|
|
4850
5094
|
}
|
|
@@ -4915,7 +5159,7 @@ function createApiContextWindow(fullHistory, maxTurns) {
|
|
|
4915
5159
|
}
|
|
4916
5160
|
|
|
4917
5161
|
// src/app/agent/core/llm/llm.ts
|
|
4918
|
-
import
|
|
5162
|
+
import os9 from "os";
|
|
4919
5163
|
import OpenAI from "openai";
|
|
4920
5164
|
function defaultBlumaUserContextInput(sessionId, userMessage) {
|
|
4921
5165
|
const msg = String(userMessage || "").slice(0, 300);
|
|
@@ -4932,7 +5176,7 @@ function defaultBlumaUserContextInput(sessionId, userMessage) {
|
|
|
4932
5176
|
}
|
|
4933
5177
|
function getPreferredMacAddress() {
|
|
4934
5178
|
try {
|
|
4935
|
-
const ifaces =
|
|
5179
|
+
const ifaces = os9.networkInterfaces();
|
|
4936
5180
|
for (const name of Object.keys(ifaces)) {
|
|
4937
5181
|
const addrs = ifaces[name];
|
|
4938
5182
|
if (!addrs) continue;
|
|
@@ -4947,7 +5191,7 @@ function getPreferredMacAddress() {
|
|
|
4947
5191
|
} catch {
|
|
4948
5192
|
}
|
|
4949
5193
|
try {
|
|
4950
|
-
return `host:${
|
|
5194
|
+
return `host:${os9.hostname()}`;
|
|
4951
5195
|
} catch {
|
|
4952
5196
|
return "unknown";
|
|
4953
5197
|
}
|
|
@@ -4957,7 +5201,7 @@ function defaultInteractiveCliUserContextInput(sessionId, userMessage) {
|
|
|
4957
5201
|
const machineId = getPreferredMacAddress();
|
|
4958
5202
|
let userName = null;
|
|
4959
5203
|
try {
|
|
4960
|
-
userName =
|
|
5204
|
+
userName = os9.userInfo().username || null;
|
|
4961
5205
|
} catch {
|
|
4962
5206
|
userName = null;
|
|
4963
5207
|
}
|
|
@@ -5532,7 +5776,7 @@ var BluMaAgent = class {
|
|
|
5532
5776
|
|
|
5533
5777
|
${editData.error.display}`;
|
|
5534
5778
|
}
|
|
5535
|
-
const filename =
|
|
5779
|
+
const filename = path16.basename(toolArgs.file_path);
|
|
5536
5780
|
return createDiff(filename, editData.currentContent || "", editData.newContent);
|
|
5537
5781
|
} catch (e) {
|
|
5538
5782
|
return `An unexpected error occurred while generating the edit preview: ${e.message}`;
|
|
@@ -5770,7 +6014,7 @@ import { v4 as uuidv45 } from "uuid";
|
|
|
5770
6014
|
import { v4 as uuidv44 } from "uuid";
|
|
5771
6015
|
|
|
5772
6016
|
// src/app/agent/subagents/init/init_system_prompt.ts
|
|
5773
|
-
import
|
|
6017
|
+
import os10 from "os";
|
|
5774
6018
|
var SYSTEM_PROMPT2 = `
|
|
5775
6019
|
|
|
5776
6020
|
### YOU ARE BluMa CLI \u2014 INIT SUBAGENT \u2014 AUTONOMOUS SENIOR SOFTWARE ENGINEER @ NOMADENGENUITY
|
|
@@ -5933,12 +6177,12 @@ Rule Summary:
|
|
|
5933
6177
|
function getInitPrompt() {
|
|
5934
6178
|
const now = /* @__PURE__ */ new Date();
|
|
5935
6179
|
const collectedData = {
|
|
5936
|
-
os_type:
|
|
5937
|
-
os_version:
|
|
5938
|
-
architecture:
|
|
6180
|
+
os_type: os10.type(),
|
|
6181
|
+
os_version: os10.release(),
|
|
6182
|
+
architecture: os10.arch(),
|
|
5939
6183
|
workdir: process.cwd(),
|
|
5940
6184
|
shell_type: process.env.SHELL || process.env.COMSPEC || "Unknown",
|
|
5941
|
-
username:
|
|
6185
|
+
username: os10.userInfo().username || "Unknown",
|
|
5942
6186
|
current_date: now.toISOString().split("T")[0],
|
|
5943
6187
|
// Formato YYYY-MM-DD
|
|
5944
6188
|
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone || "Unknown",
|
|
@@ -6219,14 +6463,14 @@ var RouteManager = class {
|
|
|
6219
6463
|
this.subAgents = subAgents;
|
|
6220
6464
|
this.core = core;
|
|
6221
6465
|
}
|
|
6222
|
-
registerRoute(
|
|
6223
|
-
this.routeHandlers.set(
|
|
6466
|
+
registerRoute(path19, handler) {
|
|
6467
|
+
this.routeHandlers.set(path19, handler);
|
|
6224
6468
|
}
|
|
6225
6469
|
async handleRoute(payload) {
|
|
6226
6470
|
const inputText = String(payload.content || "").trim();
|
|
6227
6471
|
const { userContext } = payload;
|
|
6228
|
-
for (const [
|
|
6229
|
-
if (inputText ===
|
|
6472
|
+
for (const [path19, handler] of this.routeHandlers) {
|
|
6473
|
+
if (inputText === path19 || inputText.startsWith(`${path19} `)) {
|
|
6230
6474
|
return handler({ content: inputText, userContext });
|
|
6231
6475
|
}
|
|
6232
6476
|
}
|
|
@@ -6235,7 +6479,7 @@ var RouteManager = class {
|
|
|
6235
6479
|
};
|
|
6236
6480
|
|
|
6237
6481
|
// src/app/agent/agent.ts
|
|
6238
|
-
var globalEnvPath =
|
|
6482
|
+
var globalEnvPath = path17.join(os11.homedir(), ".bluma", ".env");
|
|
6239
6483
|
dotenv.config({ path: globalEnvPath });
|
|
6240
6484
|
var Agent = class {
|
|
6241
6485
|
sessionId;
|
|
@@ -6462,12 +6706,12 @@ var renderShellCommand2 = ({ args }) => {
|
|
|
6462
6706
|
};
|
|
6463
6707
|
var renderLsTool2 = ({ args }) => {
|
|
6464
6708
|
const parsed = parseArgs(args);
|
|
6465
|
-
const
|
|
6709
|
+
const path19 = parsed.directory_path || ".";
|
|
6466
6710
|
return /* @__PURE__ */ jsxs8(Box8, { paddingX: 1, children: [
|
|
6467
6711
|
/* @__PURE__ */ jsx8(Text8, { color: "white", bold: true, children: "ls" }),
|
|
6468
6712
|
/* @__PURE__ */ jsxs8(Text8, { children: [
|
|
6469
6713
|
" ",
|
|
6470
|
-
|
|
6714
|
+
path19
|
|
6471
6715
|
] })
|
|
6472
6716
|
] });
|
|
6473
6717
|
};
|
|
@@ -6598,7 +6842,7 @@ var renderFindByName = ({ args }) => {
|
|
|
6598
6842
|
var renderGrepSearch = ({ args }) => {
|
|
6599
6843
|
const parsed = parseArgs(args);
|
|
6600
6844
|
const query = parsed.query || "";
|
|
6601
|
-
const
|
|
6845
|
+
const path19 = parsed.path || ".";
|
|
6602
6846
|
return /* @__PURE__ */ jsxs8(Box8, { paddingX: 1, children: [
|
|
6603
6847
|
/* @__PURE__ */ jsx8(Text8, { color: "white", bold: true, children: "grep" }),
|
|
6604
6848
|
/* @__PURE__ */ jsxs8(Text8, { color: "white", children: [
|
|
@@ -6608,7 +6852,7 @@ var renderGrepSearch = ({ args }) => {
|
|
|
6608
6852
|
] }),
|
|
6609
6853
|
/* @__PURE__ */ jsxs8(Text8, { children: [
|
|
6610
6854
|
" ",
|
|
6611
|
-
|
|
6855
|
+
path19
|
|
6612
6856
|
] })
|
|
6613
6857
|
] });
|
|
6614
6858
|
};
|
|
@@ -7226,16 +7470,16 @@ var SlashCommands_default = SlashCommands;
|
|
|
7226
7470
|
// src/app/agent/utils/update_check.ts
|
|
7227
7471
|
import updateNotifier from "update-notifier";
|
|
7228
7472
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
7229
|
-
import
|
|
7230
|
-
import
|
|
7473
|
+
import path18 from "path";
|
|
7474
|
+
import fs14 from "fs";
|
|
7231
7475
|
var BLUMA_PACKAGE_NAME = "@nomad-e/bluma-cli";
|
|
7232
7476
|
function findBlumaPackageJson(startDir) {
|
|
7233
7477
|
let dir = startDir;
|
|
7234
7478
|
for (let i = 0; i < 10; i++) {
|
|
7235
|
-
const candidate =
|
|
7236
|
-
if (
|
|
7479
|
+
const candidate = path18.join(dir, "package.json");
|
|
7480
|
+
if (fs14.existsSync(candidate)) {
|
|
7237
7481
|
try {
|
|
7238
|
-
const raw =
|
|
7482
|
+
const raw = fs14.readFileSync(candidate, "utf8");
|
|
7239
7483
|
const parsed = JSON.parse(raw);
|
|
7240
7484
|
if (parsed?.name === BLUMA_PACKAGE_NAME && parsed?.version) {
|
|
7241
7485
|
return { name: parsed.name, version: parsed.version };
|
|
@@ -7243,7 +7487,7 @@ function findBlumaPackageJson(startDir) {
|
|
|
7243
7487
|
} catch {
|
|
7244
7488
|
}
|
|
7245
7489
|
}
|
|
7246
|
-
const parent =
|
|
7490
|
+
const parent = path18.dirname(dir);
|
|
7247
7491
|
if (parent === dir) break;
|
|
7248
7492
|
dir = parent;
|
|
7249
7493
|
}
|
|
@@ -7256,12 +7500,12 @@ async function checkForUpdates() {
|
|
|
7256
7500
|
}
|
|
7257
7501
|
const binPath = process.argv?.[1];
|
|
7258
7502
|
let pkg = null;
|
|
7259
|
-
if (binPath &&
|
|
7260
|
-
pkg = findBlumaPackageJson(
|
|
7503
|
+
if (binPath && fs14.existsSync(binPath)) {
|
|
7504
|
+
pkg = findBlumaPackageJson(path18.dirname(binPath));
|
|
7261
7505
|
}
|
|
7262
7506
|
if (!pkg) {
|
|
7263
7507
|
const __filename = fileURLToPath4(import.meta.url);
|
|
7264
|
-
const __dirname2 =
|
|
7508
|
+
const __dirname2 = path18.dirname(__filename);
|
|
7265
7509
|
pkg = findBlumaPackageJson(__dirname2);
|
|
7266
7510
|
}
|
|
7267
7511
|
if (!pkg) {
|
|
@@ -7733,7 +7977,7 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
7733
7977
|
}
|
|
7734
7978
|
);
|
|
7735
7979
|
} else if (parsed.type === "tool_call") {
|
|
7736
|
-
const
|
|
7980
|
+
const nextId3 = history.length;
|
|
7737
7981
|
newComponent = /* @__PURE__ */ jsx17(
|
|
7738
7982
|
ToolCallDisplay,
|
|
7739
7983
|
{
|
|
@@ -7926,9 +8170,9 @@ async function runAgentMode() {
|
|
|
7926
8170
|
try {
|
|
7927
8171
|
if (inputFileIndex !== -1 && args[inputFileIndex + 1]) {
|
|
7928
8172
|
const filePath = args[inputFileIndex + 1];
|
|
7929
|
-
rawPayload =
|
|
8173
|
+
rawPayload = fs15.readFileSync(filePath, "utf-8");
|
|
7930
8174
|
} else {
|
|
7931
|
-
rawPayload =
|
|
8175
|
+
rawPayload = fs15.readFileSync(0, "utf-8");
|
|
7932
8176
|
}
|
|
7933
8177
|
} catch (err) {
|
|
7934
8178
|
writeJsonl({
|