@nomad-e/bluma-cli 0.14.1 → 0.15.0
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/config/native_tools.json +15 -3
- package/dist/main.js +400 -306
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -2479,7 +2479,7 @@ var init_CtxInspectTool = __esm({
|
|
|
2479
2479
|
});
|
|
2480
2480
|
|
|
2481
2481
|
// src/app/agent/session_manager/session_index_db.ts
|
|
2482
|
-
import
|
|
2482
|
+
import path32 from "path";
|
|
2483
2483
|
import { mkdirSync as mkdirSync3 } from "fs";
|
|
2484
2484
|
import { promises as fs28 } from "fs";
|
|
2485
2485
|
import { createRequire } from "module";
|
|
@@ -2488,10 +2488,10 @@ function loadSqlite() {
|
|
|
2488
2488
|
return nodeRequire("better-sqlite3");
|
|
2489
2489
|
}
|
|
2490
2490
|
function getSessionDbPath(appDir = getPreferredAppDir()) {
|
|
2491
|
-
return
|
|
2491
|
+
return path32.join(appDir, BLUMA_SESSION_DB_FILE);
|
|
2492
2492
|
}
|
|
2493
2493
|
function normalizeRelativePath(relativePath) {
|
|
2494
|
-
return relativePath.split(
|
|
2494
|
+
return relativePath.split(path32.sep).join("/");
|
|
2495
2495
|
}
|
|
2496
2496
|
async function walkSessionJsonFiles(dir, onFile) {
|
|
2497
2497
|
let entries;
|
|
@@ -2502,7 +2502,7 @@ async function walkSessionJsonFiles(dir, onFile) {
|
|
|
2502
2502
|
}
|
|
2503
2503
|
for (const e of entries) {
|
|
2504
2504
|
const name = String(e.name);
|
|
2505
|
-
const full =
|
|
2505
|
+
const full = path32.join(dir, name);
|
|
2506
2506
|
if (e.isDirectory()) {
|
|
2507
2507
|
await walkSessionJsonFiles(full, onFile);
|
|
2508
2508
|
} else if (e.isFile() && name.endsWith(".json") && !name.includes(".tmp")) {
|
|
@@ -2512,7 +2512,7 @@ async function walkSessionJsonFiles(dir, onFile) {
|
|
|
2512
2512
|
}
|
|
2513
2513
|
async function loadJsonlEntries(appDir) {
|
|
2514
2514
|
const map = /* @__PURE__ */ new Map();
|
|
2515
|
-
const indexFile =
|
|
2515
|
+
const indexFile = path32.join(appDir, AGENT_SESSION_PATHS_JSONL);
|
|
2516
2516
|
let raw;
|
|
2517
2517
|
try {
|
|
2518
2518
|
raw = await fs28.readFile(indexFile, "utf-8");
|
|
@@ -2592,7 +2592,7 @@ async function runMigrationV1(db, appDir) {
|
|
|
2592
2592
|
const insertFromPath = async (sessionId, absPath, jsonlUpdatedAt) => {
|
|
2593
2593
|
let rel;
|
|
2594
2594
|
try {
|
|
2595
|
-
rel = normalizeRelativePath(
|
|
2595
|
+
rel = normalizeRelativePath(path32.relative(appDir, absPath));
|
|
2596
2596
|
} catch {
|
|
2597
2597
|
return;
|
|
2598
2598
|
}
|
|
@@ -2607,7 +2607,7 @@ async function runMigrationV1(db, appDir) {
|
|
|
2607
2607
|
});
|
|
2608
2608
|
};
|
|
2609
2609
|
for (const [sessionId, entry] of jsonl) {
|
|
2610
|
-
const full =
|
|
2610
|
+
const full = path32.join(appDir, entry.relativePath.replace(/\//g, path32.sep));
|
|
2611
2611
|
try {
|
|
2612
2612
|
await fs28.access(full);
|
|
2613
2613
|
await insertFromPath(sessionId, full, entry.updatedAt);
|
|
@@ -2621,11 +2621,11 @@ async function runMigrationV1(db, appDir) {
|
|
|
2621
2621
|
});
|
|
2622
2622
|
}
|
|
2623
2623
|
}
|
|
2624
|
-
const sessionsRoot =
|
|
2624
|
+
const sessionsRoot = path32.join(appDir, "sessions");
|
|
2625
2625
|
const existing = db.prepare("SELECT session_id FROM agent_sessions").all();
|
|
2626
2626
|
const seen = new Set(existing.map((r) => r.session_id));
|
|
2627
2627
|
await walkSessionJsonFiles(sessionsRoot, async (absPath) => {
|
|
2628
|
-
const sessionId =
|
|
2628
|
+
const sessionId = path32.basename(absPath, ".json");
|
|
2629
2629
|
if (!sessionId || seen.has(sessionId)) return;
|
|
2630
2630
|
seen.add(sessionId);
|
|
2631
2631
|
await insertFromPath(sessionId, absPath);
|
|
@@ -2660,7 +2660,7 @@ async function ensureSessionIndexDb(appDir = getPreferredAppDir()) {
|
|
|
2660
2660
|
}
|
|
2661
2661
|
const BetterSqlite3 = loadSqlite();
|
|
2662
2662
|
const dbPath = getSessionDbPath(appDir);
|
|
2663
|
-
mkdirSync3(
|
|
2663
|
+
mkdirSync3(path32.dirname(dbPath), { recursive: true });
|
|
2664
2664
|
const db = new BetterSqlite3(dbPath);
|
|
2665
2665
|
db.pragma("journal_mode = WAL");
|
|
2666
2666
|
applySchema(db);
|
|
@@ -2696,7 +2696,7 @@ async function upsertSessionIndexRow(row, appDir = getPreferredAppDir()) {
|
|
|
2696
2696
|
async function getSessionPathFromIndex(sessionId, appDir = getPreferredAppDir()) {
|
|
2697
2697
|
const db = await ensureSessionIndexDb(appDir);
|
|
2698
2698
|
const row = db.prepare("SELECT relative_path FROM agent_sessions WHERE session_id = ?").get(sessionId);
|
|
2699
|
-
return row?.relative_path?.replace(/\//g,
|
|
2699
|
+
return row?.relative_path?.replace(/\//g, path32.sep) ?? null;
|
|
2700
2700
|
}
|
|
2701
2701
|
async function listSessionsFromIndex(limit = 50, appDir = getPreferredAppDir()) {
|
|
2702
2702
|
const db = await ensureSessionIndexDb(appDir);
|
|
@@ -2708,7 +2708,7 @@ async function listSessionsFromIndex(limit = 50, appDir = getPreferredAppDir())
|
|
|
2708
2708
|
).all(limit);
|
|
2709
2709
|
return rows.map((r) => ({
|
|
2710
2710
|
sessionId: r.session_id,
|
|
2711
|
-
relativePath: r.relative_path.replace(/\//g,
|
|
2711
|
+
relativePath: r.relative_path.replace(/\//g, path32.sep),
|
|
2712
2712
|
createdAt: r.created_at,
|
|
2713
2713
|
updatedAt: r.updated_at,
|
|
2714
2714
|
preview: r.preview
|
|
@@ -2729,12 +2729,12 @@ var init_session_index_db = __esm({
|
|
|
2729
2729
|
});
|
|
2730
2730
|
|
|
2731
2731
|
// src/app/agent/session_manager/agent_session_paths.ts
|
|
2732
|
-
import
|
|
2732
|
+
import path33 from "path";
|
|
2733
2733
|
import { promises as fs29 } from "fs";
|
|
2734
2734
|
async function appendAgentSessionPath(sessionId, relativePath) {
|
|
2735
2735
|
const app = getPreferredAppDir();
|
|
2736
2736
|
const now2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
2737
|
-
const rel = relativePath.split(
|
|
2737
|
+
const rel = relativePath.split(path33.sep).join("/");
|
|
2738
2738
|
await upsertSessionIndexRow({
|
|
2739
2739
|
sessionId,
|
|
2740
2740
|
relativePath: rel,
|
|
@@ -2744,7 +2744,7 @@ async function appendAgentSessionPath(sessionId, relativePath) {
|
|
|
2744
2744
|
});
|
|
2745
2745
|
}
|
|
2746
2746
|
async function resolveSessionRelativePathFromJsonl(sessionId) {
|
|
2747
|
-
const indexFile =
|
|
2747
|
+
const indexFile = path33.join(getPreferredAppDir(), AGENT_SESSION_PATHS_JSONL2);
|
|
2748
2748
|
let raw;
|
|
2749
2749
|
try {
|
|
2750
2750
|
raw = await fs29.readFile(indexFile, "utf-8");
|
|
@@ -2756,7 +2756,7 @@ async function resolveSessionRelativePathFromJsonl(sessionId) {
|
|
|
2756
2756
|
try {
|
|
2757
2757
|
const row = JSON.parse(lines[i]);
|
|
2758
2758
|
if (row.sessionId === sessionId && typeof row.relativePath === "string") {
|
|
2759
|
-
return row.relativePath.replace(/\//g,
|
|
2759
|
+
return row.relativePath.replace(/\//g, path33.sep);
|
|
2760
2760
|
}
|
|
2761
2761
|
} catch {
|
|
2762
2762
|
}
|
|
@@ -2777,7 +2777,7 @@ async function walkSessionJsonFiles2(dir, onFile) {
|
|
|
2777
2777
|
}
|
|
2778
2778
|
for (const e of entries) {
|
|
2779
2779
|
const name = String(e.name);
|
|
2780
|
-
const full =
|
|
2780
|
+
const full = path33.join(dir, name);
|
|
2781
2781
|
if (e.isDirectory()) {
|
|
2782
2782
|
await walkSessionJsonFiles2(full, onFile);
|
|
2783
2783
|
} else if (e.isFile() && name.endsWith(".json") && !name.includes(".tmp")) {
|
|
@@ -2786,10 +2786,10 @@ async function walkSessionJsonFiles2(dir, onFile) {
|
|
|
2786
2786
|
}
|
|
2787
2787
|
}
|
|
2788
2788
|
async function findSessionFileGlobFallback(sessionId) {
|
|
2789
|
-
const sessionsRoot =
|
|
2789
|
+
const sessionsRoot = path33.join(getPreferredAppDir(), "sessions");
|
|
2790
2790
|
const state2 = { best: null };
|
|
2791
2791
|
await walkSessionJsonFiles2(sessionsRoot, async (abs) => {
|
|
2792
|
-
if (
|
|
2792
|
+
if (path33.basename(abs, ".json") !== sessionId) return;
|
|
2793
2793
|
try {
|
|
2794
2794
|
const st = await fs29.stat(abs);
|
|
2795
2795
|
if (!st.isFile()) return;
|
|
@@ -2802,7 +2802,7 @@ async function findSessionFileGlobFallback(sessionId) {
|
|
|
2802
2802
|
return state2.best !== null ? state2.best.p : null;
|
|
2803
2803
|
}
|
|
2804
2804
|
async function loadLatestIndexEntriesBySessionId() {
|
|
2805
|
-
const indexFile =
|
|
2805
|
+
const indexFile = path33.join(getPreferredAppDir(), AGENT_SESSION_PATHS_JSONL2);
|
|
2806
2806
|
const map = /* @__PURE__ */ new Map();
|
|
2807
2807
|
let raw;
|
|
2808
2808
|
try {
|
|
@@ -2842,11 +2842,11 @@ function dateFolderFromRelativePath(relativePath) {
|
|
|
2842
2842
|
async function enrichCandidateFromFile(absPath, sessionId, lastMtimeMs, opts) {
|
|
2843
2843
|
let rel;
|
|
2844
2844
|
try {
|
|
2845
|
-
rel =
|
|
2845
|
+
rel = path33.relative(getPreferredAppDir(), absPath);
|
|
2846
2846
|
} catch {
|
|
2847
2847
|
rel = absPath;
|
|
2848
2848
|
}
|
|
2849
|
-
const dateFolder = dateFolderFromRelativePath(rel.split(
|
|
2849
|
+
const dateFolder = dateFolderFromRelativePath(rel.split(path33.sep).join("/"));
|
|
2850
2850
|
let preview = opts?.preview ?? "(no messages)";
|
|
2851
2851
|
let lastActivityMs = lastMtimeMs;
|
|
2852
2852
|
if (opts?.updatedAtIso) {
|
|
@@ -2885,7 +2885,7 @@ async function listAgentSessionsForResume(limit = 50) {
|
|
|
2885
2885
|
const fromIndex = await listSessionsFromIndex(limit * 2, appDir);
|
|
2886
2886
|
const map = /* @__PURE__ */ new Map();
|
|
2887
2887
|
for (const row of fromIndex) {
|
|
2888
|
-
const full =
|
|
2888
|
+
const full = path33.join(appDir, row.relativePath);
|
|
2889
2889
|
try {
|
|
2890
2890
|
const st = await fs29.stat(full);
|
|
2891
2891
|
if (!st.isFile()) continue;
|
|
@@ -2898,9 +2898,9 @@ async function listAgentSessionsForResume(limit = 50) {
|
|
|
2898
2898
|
} catch {
|
|
2899
2899
|
}
|
|
2900
2900
|
}
|
|
2901
|
-
const sessionsRoot =
|
|
2901
|
+
const sessionsRoot = path33.join(appDir, "sessions");
|
|
2902
2902
|
await walkSessionJsonFiles2(sessionsRoot, async (absPath) => {
|
|
2903
|
-
const id =
|
|
2903
|
+
const id = path33.basename(absPath, ".json");
|
|
2904
2904
|
if (!id) return;
|
|
2905
2905
|
try {
|
|
2906
2906
|
const st = await fs29.stat(absPath);
|
|
@@ -2915,7 +2915,7 @@ async function listAgentSessionsForResume(limit = 50) {
|
|
|
2915
2915
|
const index = await loadLatestIndexEntriesBySessionId();
|
|
2916
2916
|
for (const [sessionId, entry] of index) {
|
|
2917
2917
|
if (map.has(sessionId)) continue;
|
|
2918
|
-
const full =
|
|
2918
|
+
const full = path33.join(appDir, entry.relativePath.replace(/\//g, path33.sep));
|
|
2919
2919
|
try {
|
|
2920
2920
|
const st = await fs29.stat(full);
|
|
2921
2921
|
if (st.isFile()) {
|
|
@@ -2945,7 +2945,7 @@ var init_agent_session_paths = __esm({
|
|
|
2945
2945
|
});
|
|
2946
2946
|
|
|
2947
2947
|
// src/app/agent/session_manager/session_manager.ts
|
|
2948
|
-
import
|
|
2948
|
+
import path34 from "path";
|
|
2949
2949
|
import { promises as fs30 } from "fs";
|
|
2950
2950
|
async function withFileLock(file, fn) {
|
|
2951
2951
|
const prev = fileLocks.get(file) || Promise.resolve();
|
|
@@ -2982,7 +2982,7 @@ async function safeRenameWithRetry(src, dest, maxRetries = 6) {
|
|
|
2982
2982
|
const isWin = process.platform === "win32";
|
|
2983
2983
|
while (attempt <= maxRetries) {
|
|
2984
2984
|
try {
|
|
2985
|
-
const dir =
|
|
2985
|
+
const dir = path34.dirname(dest);
|
|
2986
2986
|
await fs30.mkdir(dir, { recursive: true }).catch(() => {
|
|
2987
2987
|
});
|
|
2988
2988
|
await fs30.rename(src, dest);
|
|
@@ -3000,7 +3000,7 @@ async function safeRenameWithRetry(src, dest, maxRetries = 6) {
|
|
|
3000
3000
|
try {
|
|
3001
3001
|
await fs30.access(src);
|
|
3002
3002
|
const data = await fs30.readFile(src);
|
|
3003
|
-
const dir =
|
|
3003
|
+
const dir = path34.dirname(dest);
|
|
3004
3004
|
await fs30.mkdir(dir, { recursive: true }).catch(() => {
|
|
3005
3005
|
});
|
|
3006
3006
|
await fs30.writeFile(dest, data);
|
|
@@ -3017,13 +3017,13 @@ async function safeRenameWithRetry(src, dest, maxRetries = 6) {
|
|
|
3017
3017
|
}
|
|
3018
3018
|
async function ensureSessionDir() {
|
|
3019
3019
|
const appDir = getPreferredAppDir();
|
|
3020
|
-
const sessionDir =
|
|
3020
|
+
const sessionDir = path34.join(appDir, "sessions");
|
|
3021
3021
|
await fs30.mkdir(sessionDir, { recursive: true });
|
|
3022
3022
|
return sessionDir;
|
|
3023
3023
|
}
|
|
3024
3024
|
async function resolveAgentSessionFilePath(sessionId) {
|
|
3025
3025
|
const appDir = getPreferredAppDir();
|
|
3026
|
-
const legacy =
|
|
3026
|
+
const legacy = path34.join(appDir, "sessions", `${sessionId}.json`);
|
|
3027
3027
|
try {
|
|
3028
3028
|
await fs30.access(legacy);
|
|
3029
3029
|
return legacy;
|
|
@@ -3031,7 +3031,7 @@ async function resolveAgentSessionFilePath(sessionId) {
|
|
|
3031
3031
|
}
|
|
3032
3032
|
const rel = await resolveSessionRelativePathFromIndex(sessionId);
|
|
3033
3033
|
if (rel) {
|
|
3034
|
-
const full =
|
|
3034
|
+
const full = path34.join(appDir, rel);
|
|
3035
3035
|
try {
|
|
3036
3036
|
await fs30.access(full);
|
|
3037
3037
|
return full;
|
|
@@ -3067,16 +3067,16 @@ async function loadOrcreateSession(sessionId) {
|
|
|
3067
3067
|
const y = String(now2.getFullYear());
|
|
3068
3068
|
const mo = String(now2.getMonth() + 1).padStart(2, "0");
|
|
3069
3069
|
const d = String(now2.getDate()).padStart(2, "0");
|
|
3070
|
-
const datedDir =
|
|
3070
|
+
const datedDir = path34.join(sessionsRoot, y, mo, d);
|
|
3071
3071
|
await fs30.mkdir(datedDir, { recursive: true });
|
|
3072
|
-
const sessionFile =
|
|
3072
|
+
const sessionFile = path34.join(datedDir, `${sessionId}.json`);
|
|
3073
3073
|
const newSessionData = {
|
|
3074
3074
|
session_id: sessionId,
|
|
3075
3075
|
created_at: now2.toISOString(),
|
|
3076
3076
|
conversation_history: []
|
|
3077
3077
|
};
|
|
3078
3078
|
await fs30.writeFile(sessionFile, JSON.stringify(newSessionData, null, 2), "utf-8");
|
|
3079
|
-
const relToApp =
|
|
3079
|
+
const relToApp = path34.relative(getPreferredAppDir(), sessionFile);
|
|
3080
3080
|
await appendAgentSessionPath(sessionId, relToApp);
|
|
3081
3081
|
const emptyMemory = {
|
|
3082
3082
|
historyAnchor: null,
|
|
@@ -3088,7 +3088,7 @@ async function doSaveSessionHistory(sessionFile, history, memory) {
|
|
|
3088
3088
|
await withFileLock(sessionFile, async () => {
|
|
3089
3089
|
let sessionData;
|
|
3090
3090
|
try {
|
|
3091
|
-
const dir =
|
|
3091
|
+
const dir = path34.dirname(sessionFile);
|
|
3092
3092
|
await fs30.mkdir(dir, { recursive: true });
|
|
3093
3093
|
} catch {
|
|
3094
3094
|
}
|
|
@@ -3104,7 +3104,7 @@ async function doSaveSessionHistory(sessionFile, history, memory) {
|
|
|
3104
3104
|
console.warn(`An unknown error occurred while reading ${sessionFile}. Re-initializing.`, error);
|
|
3105
3105
|
}
|
|
3106
3106
|
}
|
|
3107
|
-
const sessionId =
|
|
3107
|
+
const sessionId = path34.basename(sessionFile, ".json");
|
|
3108
3108
|
sessionData = {
|
|
3109
3109
|
session_id: sessionId,
|
|
3110
3110
|
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -3129,12 +3129,12 @@ async function doSaveSessionHistory(sessionFile, history, memory) {
|
|
|
3129
3129
|
try {
|
|
3130
3130
|
await fs30.writeFile(tempSessionFile, JSON.stringify(sessionData, null, 2), "utf-8");
|
|
3131
3131
|
await safeRenameWithRetry(tempSessionFile, sessionFile);
|
|
3132
|
-
const sessionId = sessionData.session_id ??
|
|
3132
|
+
const sessionId = sessionData.session_id ?? path34.basename(sessionFile, ".json");
|
|
3133
3133
|
const updatedAt = sessionData.last_updated ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
3134
3134
|
const createdAt = sessionData.created_at ?? updatedAt;
|
|
3135
3135
|
let relToApp;
|
|
3136
3136
|
try {
|
|
3137
|
-
relToApp =
|
|
3137
|
+
relToApp = path34.relative(getPreferredAppDir(), sessionFile);
|
|
3138
3138
|
} catch {
|
|
3139
3139
|
relToApp = sessionFile;
|
|
3140
3140
|
}
|
|
@@ -3205,7 +3205,7 @@ __export(exportConversation_exports, {
|
|
|
3205
3205
|
resolveExportOutputPath: () => resolveExportOutputPath
|
|
3206
3206
|
});
|
|
3207
3207
|
import { promises as fs48 } from "fs";
|
|
3208
|
-
import
|
|
3208
|
+
import path55 from "path";
|
|
3209
3209
|
function extractTextParts2(content) {
|
|
3210
3210
|
if (typeof content === "string") {
|
|
3211
3211
|
const trimmed = content.trim();
|
|
@@ -3363,12 +3363,12 @@ function resolveExportOutputPath(sessionId, options) {
|
|
|
3363
3363
|
const { outputPath, defaultExportDir } = options ?? {};
|
|
3364
3364
|
if (outputPath?.trim()) {
|
|
3365
3365
|
const raw = outputPath.trim();
|
|
3366
|
-
return
|
|
3366
|
+
return path55.isAbsolute(raw) ? raw : path55.resolve(process.cwd(), raw);
|
|
3367
3367
|
}
|
|
3368
3368
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
3369
3369
|
const safeId = sessionId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 48) || "session";
|
|
3370
3370
|
const baseDir = defaultExportDir ?? getSandboxPolicy().workspaceRoot;
|
|
3371
|
-
return
|
|
3371
|
+
return path55.join(baseDir, `bluma-export-${safeId}-${stamp}.md`);
|
|
3372
3372
|
}
|
|
3373
3373
|
async function resolveHistory(sessionId, fallbackHistory) {
|
|
3374
3374
|
const loaded2 = await loadSession(sessionId);
|
|
@@ -3390,7 +3390,7 @@ async function exportConversationToFile(options) {
|
|
|
3390
3390
|
}
|
|
3391
3391
|
const markdown = formatConversationMarkdown(sessionId, history);
|
|
3392
3392
|
const filePath = resolveExportOutputPath(sessionId, { outputPath, defaultExportDir });
|
|
3393
|
-
await fs48.mkdir(
|
|
3393
|
+
await fs48.mkdir(path55.dirname(filePath), { recursive: true });
|
|
3394
3394
|
await fs48.writeFile(filePath, markdown, "utf-8");
|
|
3395
3395
|
return {
|
|
3396
3396
|
success: true,
|
|
@@ -3916,11 +3916,11 @@ var NodeFsOperations = {
|
|
|
3916
3916
|
if (fd) fs.closeSync(fd);
|
|
3917
3917
|
}
|
|
3918
3918
|
},
|
|
3919
|
-
appendFileSync(
|
|
3920
|
-
const _ = slowLogging`fs.appendFileSync(${
|
|
3919
|
+
appendFileSync(path60, data, options) {
|
|
3920
|
+
const _ = slowLogging`fs.appendFileSync(${path60}, ${data.length} chars)`;
|
|
3921
3921
|
if (options?.mode !== void 0) {
|
|
3922
3922
|
try {
|
|
3923
|
-
const fd = fs.openSync(
|
|
3923
|
+
const fd = fs.openSync(path60, "ax", options.mode);
|
|
3924
3924
|
try {
|
|
3925
3925
|
fs.appendFileSync(fd, data);
|
|
3926
3926
|
} finally {
|
|
@@ -3931,35 +3931,35 @@ var NodeFsOperations = {
|
|
|
3931
3931
|
if (getErrnoCode(e) !== "EEXIST") throw e;
|
|
3932
3932
|
}
|
|
3933
3933
|
}
|
|
3934
|
-
fs.appendFileSync(
|
|
3934
|
+
fs.appendFileSync(path60, data);
|
|
3935
3935
|
},
|
|
3936
3936
|
copyFileSync(src, dest) {
|
|
3937
3937
|
const _ = slowLogging`fs.copyFileSync(${src} → ${dest})`;
|
|
3938
3938
|
fs.copyFileSync(src, dest);
|
|
3939
3939
|
},
|
|
3940
|
-
unlinkSync(
|
|
3941
|
-
const _ = slowLogging`fs.unlinkSync(${
|
|
3942
|
-
fs.unlinkSync(
|
|
3940
|
+
unlinkSync(path60) {
|
|
3941
|
+
const _ = slowLogging`fs.unlinkSync(${path60})`;
|
|
3942
|
+
fs.unlinkSync(path60);
|
|
3943
3943
|
},
|
|
3944
3944
|
renameSync(oldPath, newPath) {
|
|
3945
3945
|
const _ = slowLogging`fs.renameSync(${oldPath} → ${newPath})`;
|
|
3946
3946
|
fs.renameSync(oldPath, newPath);
|
|
3947
3947
|
},
|
|
3948
|
-
linkSync(target,
|
|
3949
|
-
const _ = slowLogging`fs.linkSync(${target} → ${
|
|
3950
|
-
fs.linkSync(target,
|
|
3948
|
+
linkSync(target, path60) {
|
|
3949
|
+
const _ = slowLogging`fs.linkSync(${target} → ${path60})`;
|
|
3950
|
+
fs.linkSync(target, path60);
|
|
3951
3951
|
},
|
|
3952
|
-
symlinkSync(target,
|
|
3953
|
-
const _ = slowLogging`fs.symlinkSync(${target} → ${
|
|
3954
|
-
fs.symlinkSync(target,
|
|
3952
|
+
symlinkSync(target, path60, type) {
|
|
3953
|
+
const _ = slowLogging`fs.symlinkSync(${target} → ${path60})`;
|
|
3954
|
+
fs.symlinkSync(target, path60, type);
|
|
3955
3955
|
},
|
|
3956
|
-
readlinkSync(
|
|
3957
|
-
const _ = slowLogging`fs.readlinkSync(${
|
|
3958
|
-
return fs.readlinkSync(
|
|
3956
|
+
readlinkSync(path60) {
|
|
3957
|
+
const _ = slowLogging`fs.readlinkSync(${path60})`;
|
|
3958
|
+
return fs.readlinkSync(path60);
|
|
3959
3959
|
},
|
|
3960
|
-
realpathSync(
|
|
3961
|
-
const _ = slowLogging`fs.realpathSync(${
|
|
3962
|
-
return fs.realpathSync(
|
|
3960
|
+
realpathSync(path60) {
|
|
3961
|
+
const _ = slowLogging`fs.realpathSync(${path60})`;
|
|
3962
|
+
return fs.realpathSync(path60).normalize("NFC");
|
|
3963
3963
|
},
|
|
3964
3964
|
mkdirSync(dirPath, options) {
|
|
3965
3965
|
const _ = slowLogging`fs.mkdirSync(${dirPath})`;
|
|
@@ -3992,12 +3992,12 @@ var NodeFsOperations = {
|
|
|
3992
3992
|
const _ = slowLogging`fs.rmdirSync(${dirPath})`;
|
|
3993
3993
|
fs.rmdirSync(dirPath);
|
|
3994
3994
|
},
|
|
3995
|
-
rmSync(
|
|
3996
|
-
const _ = slowLogging`fs.rmSync(${
|
|
3997
|
-
fs.rmSync(
|
|
3995
|
+
rmSync(path60, options) {
|
|
3996
|
+
const _ = slowLogging`fs.rmSync(${path60})`;
|
|
3997
|
+
fs.rmSync(path60, options);
|
|
3998
3998
|
},
|
|
3999
|
-
createWriteStream(
|
|
4000
|
-
return fs.createWriteStream(
|
|
3999
|
+
createWriteStream(path60) {
|
|
4000
|
+
return fs.createWriteStream(path60);
|
|
4001
4001
|
},
|
|
4002
4002
|
async readFileBytes(fsPath, maxBytes) {
|
|
4003
4003
|
if (maxBytes === void 0) {
|
|
@@ -4104,12 +4104,12 @@ function shouldLogDebugMessage(message2) {
|
|
|
4104
4104
|
var hasFormattedOutput = false;
|
|
4105
4105
|
var debugWriter = null;
|
|
4106
4106
|
var pendingWrite = Promise.resolve();
|
|
4107
|
-
async function appendAsync(needMkdir, dir,
|
|
4107
|
+
async function appendAsync(needMkdir, dir, path60, content) {
|
|
4108
4108
|
if (needMkdir) {
|
|
4109
4109
|
await mkdir(dir, { recursive: true }).catch(() => {
|
|
4110
4110
|
});
|
|
4111
4111
|
}
|
|
4112
|
-
await appendFile(
|
|
4112
|
+
await appendFile(path60, content);
|
|
4113
4113
|
void updateLatestDebugLogSymlink();
|
|
4114
4114
|
}
|
|
4115
4115
|
function noop() {
|
|
@@ -4119,8 +4119,8 @@ function getDebugWriter() {
|
|
|
4119
4119
|
let ensuredDir = null;
|
|
4120
4120
|
debugWriter = createBufferedWriter({
|
|
4121
4121
|
writeFn: (content) => {
|
|
4122
|
-
const
|
|
4123
|
-
const dir = dirname(
|
|
4122
|
+
const path60 = getDebugLogPath();
|
|
4123
|
+
const dir = dirname(path60);
|
|
4124
4124
|
const needMkdir = ensuredDir !== dir;
|
|
4125
4125
|
ensuredDir = dir;
|
|
4126
4126
|
if (isDebugMode()) {
|
|
@@ -4130,11 +4130,11 @@ function getDebugWriter() {
|
|
|
4130
4130
|
} catch {
|
|
4131
4131
|
}
|
|
4132
4132
|
}
|
|
4133
|
-
getFsImplementation().appendFileSync(
|
|
4133
|
+
getFsImplementation().appendFileSync(path60, content);
|
|
4134
4134
|
void updateLatestDebugLogSymlink();
|
|
4135
4135
|
return;
|
|
4136
4136
|
}
|
|
4137
|
-
pendingWrite = pendingWrite.then(appendAsync.bind(null, needMkdir, dir,
|
|
4137
|
+
pendingWrite = pendingWrite.then(appendAsync.bind(null, needMkdir, dir, path60, content)).catch(noop);
|
|
4138
4138
|
},
|
|
4139
4139
|
flushIntervalMs: 1e3,
|
|
4140
4140
|
maxBufferSize: 100,
|
|
@@ -10321,8 +10321,8 @@ import codeExcerpt from "code-excerpt";
|
|
|
10321
10321
|
import { readFileSync as readFileSync2 } from "fs";
|
|
10322
10322
|
import StackUtils from "stack-utils";
|
|
10323
10323
|
import { jsx as jsx6, jsxs } from "react/jsx-runtime";
|
|
10324
|
-
var cleanupPath = (
|
|
10325
|
-
return
|
|
10324
|
+
var cleanupPath = (path60) => {
|
|
10325
|
+
return path60?.replace(`file://${process.cwd()}/`, "");
|
|
10326
10326
|
};
|
|
10327
10327
|
var stackUtils;
|
|
10328
10328
|
function getStackUtils() {
|
|
@@ -14300,7 +14300,7 @@ var getInstance = (stdout, createInstance) => {
|
|
|
14300
14300
|
// src/main.ts
|
|
14301
14301
|
import { EventEmitter as EventEmitter7 } from "events";
|
|
14302
14302
|
import fs52 from "fs";
|
|
14303
|
-
import
|
|
14303
|
+
import path59 from "path";
|
|
14304
14304
|
import { fileURLToPath as fileURLToPath8 } from "url";
|
|
14305
14305
|
import { spawn as spawn6 } from "child_process";
|
|
14306
14306
|
import { v4 as uuidv412 } from "uuid";
|
|
@@ -14979,12 +14979,12 @@ function cancelSlashSubmenu() {
|
|
|
14979
14979
|
|
|
14980
14980
|
// src/app/agent/agent.ts
|
|
14981
14981
|
import * as dotenv from "dotenv";
|
|
14982
|
-
import
|
|
14982
|
+
import path49 from "path";
|
|
14983
14983
|
import os30 from "os";
|
|
14984
14984
|
|
|
14985
14985
|
// src/app/agent/tool_invoker.ts
|
|
14986
14986
|
import { promises as fs26 } from "fs";
|
|
14987
|
-
import
|
|
14987
|
+
import path30 from "path";
|
|
14988
14988
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
14989
14989
|
|
|
14990
14990
|
// src/app/agent/tools/EditTool/EditTool.ts
|
|
@@ -20113,7 +20113,7 @@ async function createNextApp(args) {
|
|
|
20113
20113
|
// src/app/agent/tools/DeployAppTool/DeployAppTool.ts
|
|
20114
20114
|
init_sandbox_policy();
|
|
20115
20115
|
import { promises as fs25 } from "fs";
|
|
20116
|
-
import
|
|
20116
|
+
import path29 from "path";
|
|
20117
20117
|
|
|
20118
20118
|
// src/app/agent/tools/DeployAppTool/createDeployProjectZip.ts
|
|
20119
20119
|
import { lstat, readdir, readFile as readFile2, writeFile } from "fs/promises";
|
|
@@ -20211,6 +20211,91 @@ async function createDeployProjectZip(projectDir, zipPath) {
|
|
|
20211
20211
|
return zipPath;
|
|
20212
20212
|
}
|
|
20213
20213
|
|
|
20214
|
+
// src/app/agent/tools/DeployAppTool/nextDeployConfig.ts
|
|
20215
|
+
import { access, readFile as readFile3, writeFile as writeFile2 } from "fs/promises";
|
|
20216
|
+
import path28 from "path";
|
|
20217
|
+
var FACTORAI_NEXT_CONFIG_JS = `/** @type {import('next').NextConfig} */
|
|
20218
|
+
module.exports = {
|
|
20219
|
+
output: "standalone",
|
|
20220
|
+
reactStrictMode: true,
|
|
20221
|
+
};
|
|
20222
|
+
`;
|
|
20223
|
+
var FACTORAI_NEXT_CONFIG_JSON = `${JSON.stringify(
|
|
20224
|
+
{
|
|
20225
|
+
output: "standalone",
|
|
20226
|
+
reactStrictMode: true
|
|
20227
|
+
},
|
|
20228
|
+
null,
|
|
20229
|
+
2
|
|
20230
|
+
)}
|
|
20231
|
+
`;
|
|
20232
|
+
var STANDALONE_RE = /output\s*:\s*["']standalone["']/;
|
|
20233
|
+
async function fileExists(filePath) {
|
|
20234
|
+
try {
|
|
20235
|
+
await access(filePath);
|
|
20236
|
+
return true;
|
|
20237
|
+
} catch {
|
|
20238
|
+
return false;
|
|
20239
|
+
}
|
|
20240
|
+
}
|
|
20241
|
+
function hasStandaloneInJs(source) {
|
|
20242
|
+
return STANDALONE_RE.test(source);
|
|
20243
|
+
}
|
|
20244
|
+
function hasStandaloneInJson(source) {
|
|
20245
|
+
try {
|
|
20246
|
+
const parsed = JSON.parse(source);
|
|
20247
|
+
return parsed.output === "standalone";
|
|
20248
|
+
} catch {
|
|
20249
|
+
return false;
|
|
20250
|
+
}
|
|
20251
|
+
}
|
|
20252
|
+
async function ensureNextStandaloneConfig(projectDir) {
|
|
20253
|
+
const warnings = [];
|
|
20254
|
+
const jsPath = path28.join(projectDir, "next.config.js");
|
|
20255
|
+
const jsonPath = path28.join(projectDir, "next.config.json");
|
|
20256
|
+
const mjsPath = path28.join(projectDir, "next.config.mjs");
|
|
20257
|
+
const hasJs = await fileExists(jsPath);
|
|
20258
|
+
const hasJson = await fileExists(jsonPath);
|
|
20259
|
+
const hasMjs = await fileExists(mjsPath);
|
|
20260
|
+
if (hasMjs) {
|
|
20261
|
+
const mjs = await readFile3(mjsPath, "utf-8");
|
|
20262
|
+
if (!hasStandaloneInJs(mjs)) {
|
|
20263
|
+
warnings.push('next.config.mjs missing output: "standalone" \u2014 update manually for FactorAI deploy');
|
|
20264
|
+
return { ok: false, warnings };
|
|
20265
|
+
}
|
|
20266
|
+
return { ok: true, warnings };
|
|
20267
|
+
}
|
|
20268
|
+
if (hasJs) {
|
|
20269
|
+
const js = await readFile3(jsPath, "utf-8");
|
|
20270
|
+
const directExport = /module\.exports\s*=\s*\{/.test(js) && hasStandaloneInJs(js);
|
|
20271
|
+
if (directExport) {
|
|
20272
|
+
return { ok: true, warnings };
|
|
20273
|
+
}
|
|
20274
|
+
if (hasStandaloneInJs(js)) {
|
|
20275
|
+
await writeFile2(jsPath, FACTORAI_NEXT_CONFIG_JS, "utf-8");
|
|
20276
|
+
warnings.push(
|
|
20277
|
+
"next.config.js reescrito em formato compat\xEDvel com o deploy FactorAI (module.exports direto)"
|
|
20278
|
+
);
|
|
20279
|
+
return { ok: true, warnings };
|
|
20280
|
+
}
|
|
20281
|
+
await writeFile2(jsPath, FACTORAI_NEXT_CONFIG_JS, "utf-8");
|
|
20282
|
+
warnings.push('next.config.js atualizado com output: "standalone"');
|
|
20283
|
+
return { ok: true, warnings };
|
|
20284
|
+
}
|
|
20285
|
+
if (hasJson) {
|
|
20286
|
+
const json = await readFile3(jsonPath, "utf-8");
|
|
20287
|
+
if (hasStandaloneInJson(json)) {
|
|
20288
|
+
return { ok: true, warnings };
|
|
20289
|
+
}
|
|
20290
|
+
await writeFile2(jsonPath, FACTORAI_NEXT_CONFIG_JSON, "utf-8");
|
|
20291
|
+
warnings.push('next.config.json atualizado com output: "standalone"');
|
|
20292
|
+
return { ok: true, warnings };
|
|
20293
|
+
}
|
|
20294
|
+
await writeFile2(jsonPath, FACTORAI_NEXT_CONFIG_JSON, "utf-8");
|
|
20295
|
+
warnings.push('Criado next.config.json com output: "standalone"');
|
|
20296
|
+
return { ok: true, warnings };
|
|
20297
|
+
}
|
|
20298
|
+
|
|
20214
20299
|
// src/app/agent/tools/DeployAppTool/DeployAppTool.ts
|
|
20215
20300
|
async function uploadToSeverino(zipPath, severinoUrl, name, apiKey, appId) {
|
|
20216
20301
|
const deployUrl = `${severinoUrl.replace(/\/$/, "")}/api/v1/deploy`;
|
|
@@ -20219,7 +20304,7 @@ async function uploadToSeverino(zipPath, severinoUrl, name, apiKey, appId) {
|
|
|
20219
20304
|
form.append(
|
|
20220
20305
|
"file",
|
|
20221
20306
|
new Blob([zipBytes], { type: "application/zip" }),
|
|
20222
|
-
|
|
20307
|
+
path29.basename(zipPath)
|
|
20223
20308
|
);
|
|
20224
20309
|
if (name) form.append("name", name);
|
|
20225
20310
|
if (appId) form.append("appId", appId);
|
|
@@ -20328,7 +20413,7 @@ function buildFactorAiManifest(appContext, deployResult, appName) {
|
|
|
20328
20413
|
}
|
|
20329
20414
|
async function writeFactorAiManifest(projectDir, appContext, deployResult, appName) {
|
|
20330
20415
|
const manifest = buildFactorAiManifest(appContext, deployResult, appName);
|
|
20331
|
-
const manifestPath =
|
|
20416
|
+
const manifestPath = path29.join(projectDir, "factorai.sh.json");
|
|
20332
20417
|
await fs25.writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}
|
|
20333
20418
|
`, "utf-8");
|
|
20334
20419
|
return manifest;
|
|
@@ -20356,7 +20441,7 @@ async function deployApp(args) {
|
|
|
20356
20441
|
error: `Project directory not found: ${resolvedProjectDir}`
|
|
20357
20442
|
};
|
|
20358
20443
|
}
|
|
20359
|
-
const packageJsonPath =
|
|
20444
|
+
const packageJsonPath = path29.join(resolvedProjectDir, "package.json");
|
|
20360
20445
|
try {
|
|
20361
20446
|
await fs25.access(packageJsonPath);
|
|
20362
20447
|
} catch {
|
|
@@ -20374,10 +20459,20 @@ async function deployApp(args) {
|
|
|
20374
20459
|
error: "Not a Next.js project: next not found in dependencies"
|
|
20375
20460
|
};
|
|
20376
20461
|
}
|
|
20377
|
-
const
|
|
20378
|
-
|
|
20462
|
+
const standaloneCheck = await ensureNextStandaloneConfig(resolvedProjectDir);
|
|
20463
|
+
if (!standaloneCheck.ok) {
|
|
20464
|
+
return {
|
|
20465
|
+
success: false,
|
|
20466
|
+
error: `Next.js config invalid for FactorAI deploy: ${standaloneCheck.warnings.join("; ")}`
|
|
20467
|
+
};
|
|
20468
|
+
}
|
|
20469
|
+
for (const w of standaloneCheck.warnings) {
|
|
20470
|
+
console.warn(`[deploy-app] ${w}`);
|
|
20471
|
+
}
|
|
20472
|
+
const appName = name || packageJson.name || path29.basename(resolvedProjectDir);
|
|
20473
|
+
const tempDir = path29.join(resolvedProjectDir, ".tmp");
|
|
20379
20474
|
await fs25.mkdir(tempDir, { recursive: true });
|
|
20380
|
-
const zipPath =
|
|
20475
|
+
const zipPath = path29.join(tempDir, `${appName}-${Date.now()}.zip`);
|
|
20381
20476
|
console.log(`[deploy-app] Creating ZIP: ${zipPath}`);
|
|
20382
20477
|
await createDeployProjectZip(resolvedProjectDir, zipPath);
|
|
20383
20478
|
const zipStats = await fs25.stat(zipPath);
|
|
@@ -20410,7 +20505,7 @@ async function deployApp(args) {
|
|
|
20410
20505
|
appName
|
|
20411
20506
|
);
|
|
20412
20507
|
deployResult.factoraiManifest = manifest;
|
|
20413
|
-
deployResult.factoraiManifestPath =
|
|
20508
|
+
deployResult.factoraiManifestPath = path29.join(resolvedProjectDir, "factorai.sh.json");
|
|
20414
20509
|
}
|
|
20415
20510
|
console.log(`[deploy-app] Deploy iniciado: ${deployResult.appId}`);
|
|
20416
20511
|
}
|
|
@@ -21491,8 +21586,8 @@ var ToolInvoker = class {
|
|
|
21491
21586
|
async initialize() {
|
|
21492
21587
|
try {
|
|
21493
21588
|
const currentFilePath = fileURLToPath2(import.meta.url);
|
|
21494
|
-
const currentDirPath =
|
|
21495
|
-
const configPath =
|
|
21589
|
+
const currentDirPath = path30.dirname(currentFilePath);
|
|
21590
|
+
const configPath = path30.resolve(currentDirPath, "config", "native_tools.json");
|
|
21496
21591
|
const fileContent = await fs26.readFile(configPath, "utf-8");
|
|
21497
21592
|
const config3 = JSON.parse(fileContent);
|
|
21498
21593
|
this.toolDefinitions = applyMetadataToToolDefinitions(config3.nativeTools);
|
|
@@ -21541,7 +21636,7 @@ var ToolInvoker = class {
|
|
|
21541
21636
|
|
|
21542
21637
|
// src/app/agent/tools/mcp/mcp_client.ts
|
|
21543
21638
|
import { promises as fs27 } from "fs";
|
|
21544
|
-
import
|
|
21639
|
+
import path31 from "path";
|
|
21545
21640
|
import os19 from "os";
|
|
21546
21641
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
21547
21642
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
@@ -21569,9 +21664,9 @@ var MCPClient = class {
|
|
|
21569
21664
|
});
|
|
21570
21665
|
}
|
|
21571
21666
|
const __filename = fileURLToPath3(import.meta.url);
|
|
21572
|
-
const __dirname2 =
|
|
21573
|
-
const defaultConfigPath =
|
|
21574
|
-
const userConfigPath =
|
|
21667
|
+
const __dirname2 = path31.dirname(__filename);
|
|
21668
|
+
const defaultConfigPath = path31.resolve(__dirname2, "config", "bluma-mcp.json");
|
|
21669
|
+
const userConfigPath = path31.join(os19.homedir(), ".bluma", "bluma-mcp.json");
|
|
21575
21670
|
const defaultConfig = await this.loadMcpConfig(defaultConfigPath, "Default");
|
|
21576
21671
|
const userConfig = await this.loadMcpConfig(userConfigPath, "User");
|
|
21577
21672
|
const mergedConfig = {
|
|
@@ -21818,19 +21913,19 @@ PENALTY APPLIED: ${penalty.toFixed(1)} points deducted.
|
|
|
21818
21913
|
|
|
21819
21914
|
// src/app/agent/bluma/core/bluma.ts
|
|
21820
21915
|
init_session_manager();
|
|
21821
|
-
import
|
|
21916
|
+
import path46 from "path";
|
|
21822
21917
|
import fs40 from "fs";
|
|
21823
21918
|
import { v4 as uuidv48 } from "uuid";
|
|
21824
21919
|
|
|
21825
21920
|
// src/app/agent/core/prompt/prompt_builder.ts
|
|
21826
21921
|
import os23 from "os";
|
|
21827
21922
|
import fs36 from "fs";
|
|
21828
|
-
import
|
|
21923
|
+
import path40 from "path";
|
|
21829
21924
|
import { execSync as execSync3 } from "child_process";
|
|
21830
21925
|
|
|
21831
21926
|
// src/app/agent/skills/skill_loader.ts
|
|
21832
21927
|
import fs31 from "fs";
|
|
21833
|
-
import
|
|
21928
|
+
import path35 from "path";
|
|
21834
21929
|
import os20 from "os";
|
|
21835
21930
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
21836
21931
|
var SkillLoader = class _SkillLoader {
|
|
@@ -21840,8 +21935,8 @@ var SkillLoader = class _SkillLoader {
|
|
|
21840
21935
|
cache = /* @__PURE__ */ new Map();
|
|
21841
21936
|
conflicts = [];
|
|
21842
21937
|
constructor(projectRoot, bundledDir) {
|
|
21843
|
-
this.projectSkillsDir =
|
|
21844
|
-
this.globalSkillsDir =
|
|
21938
|
+
this.projectSkillsDir = path35.join(projectRoot, ".bluma", "skills");
|
|
21939
|
+
this.globalSkillsDir = path35.join(os20.homedir(), ".bluma", "skills");
|
|
21845
21940
|
this.bundledSkillsDir = bundledDir || _SkillLoader.resolveBundledDir();
|
|
21846
21941
|
}
|
|
21847
21942
|
/**
|
|
@@ -21850,32 +21945,32 @@ var SkillLoader = class _SkillLoader {
|
|
|
21850
21945
|
*/
|
|
21851
21946
|
static resolveBundledDir() {
|
|
21852
21947
|
if (process.env.JEST_WORKER_ID !== void 0 || process.env.NODE_ENV === "test") {
|
|
21853
|
-
return
|
|
21948
|
+
return path35.join(process.cwd(), "dist", "config", "skills");
|
|
21854
21949
|
}
|
|
21855
21950
|
const candidates = [];
|
|
21856
21951
|
const push = (p) => {
|
|
21857
|
-
const abs =
|
|
21952
|
+
const abs = path35.resolve(p);
|
|
21858
21953
|
if (!candidates.includes(abs)) {
|
|
21859
21954
|
candidates.push(abs);
|
|
21860
21955
|
}
|
|
21861
21956
|
};
|
|
21862
21957
|
let argvBundled = null;
|
|
21863
21958
|
try {
|
|
21864
|
-
const bundleDir =
|
|
21865
|
-
push(
|
|
21959
|
+
const bundleDir = path35.dirname(fileURLToPath4(import.meta.url));
|
|
21960
|
+
push(path35.join(bundleDir, "config", "skills"));
|
|
21866
21961
|
} catch {
|
|
21867
21962
|
}
|
|
21868
21963
|
const argv1 = process.argv[1];
|
|
21869
21964
|
if (argv1 && !argv1.startsWith("-")) {
|
|
21870
21965
|
try {
|
|
21871
21966
|
let resolved = argv1;
|
|
21872
|
-
if (
|
|
21967
|
+
if (path35.isAbsolute(argv1) && fs31.existsSync(argv1)) {
|
|
21873
21968
|
resolved = fs31.realpathSync(argv1);
|
|
21874
|
-
} else if (!
|
|
21875
|
-
resolved =
|
|
21969
|
+
} else if (!path35.isAbsolute(argv1)) {
|
|
21970
|
+
resolved = path35.resolve(process.cwd(), argv1);
|
|
21876
21971
|
}
|
|
21877
|
-
const scriptDir =
|
|
21878
|
-
argvBundled =
|
|
21972
|
+
const scriptDir = path35.dirname(resolved);
|
|
21973
|
+
argvBundled = path35.join(scriptDir, "config", "skills");
|
|
21879
21974
|
push(argvBundled);
|
|
21880
21975
|
} catch {
|
|
21881
21976
|
}
|
|
@@ -21886,12 +21981,12 @@ var SkillLoader = class _SkillLoader {
|
|
|
21886
21981
|
}
|
|
21887
21982
|
}
|
|
21888
21983
|
try {
|
|
21889
|
-
return
|
|
21984
|
+
return path35.join(path35.dirname(fileURLToPath4(import.meta.url)), "config", "skills");
|
|
21890
21985
|
} catch {
|
|
21891
21986
|
if (argvBundled) {
|
|
21892
21987
|
return argvBundled;
|
|
21893
21988
|
}
|
|
21894
|
-
return
|
|
21989
|
+
return path35.join(os20.homedir(), ".bluma", "__bundled_skills_unresolved__");
|
|
21895
21990
|
}
|
|
21896
21991
|
}
|
|
21897
21992
|
/**
|
|
@@ -21920,8 +22015,8 @@ var SkillLoader = class _SkillLoader {
|
|
|
21920
22015
|
this.conflicts.push({
|
|
21921
22016
|
name: skill.name,
|
|
21922
22017
|
userSource: source,
|
|
21923
|
-
userPath:
|
|
21924
|
-
bundledPath:
|
|
22018
|
+
userPath: path35.join(dir, skill.name, "SKILL.md"),
|
|
22019
|
+
bundledPath: path35.join(this.bundledSkillsDir, skill.name, "SKILL.md")
|
|
21925
22020
|
});
|
|
21926
22021
|
continue;
|
|
21927
22022
|
}
|
|
@@ -21932,9 +22027,9 @@ var SkillLoader = class _SkillLoader {
|
|
|
21932
22027
|
if (!fs31.existsSync(dir)) return [];
|
|
21933
22028
|
try {
|
|
21934
22029
|
return fs31.readdirSync(dir).filter((d) => {
|
|
21935
|
-
const fullPath =
|
|
21936
|
-
return fs31.statSync(fullPath).isDirectory() && fs31.existsSync(
|
|
21937
|
-
}).map((d) => this.loadMetadataFromPath(
|
|
22030
|
+
const fullPath = path35.join(dir, d);
|
|
22031
|
+
return fs31.statSync(fullPath).isDirectory() && fs31.existsSync(path35.join(fullPath, "SKILL.md"));
|
|
22032
|
+
}).map((d) => this.loadMetadataFromPath(path35.join(dir, d, "SKILL.md"), d, source)).filter((m) => m !== null);
|
|
21938
22033
|
} catch {
|
|
21939
22034
|
return [];
|
|
21940
22035
|
}
|
|
@@ -21964,9 +22059,9 @@ var SkillLoader = class _SkillLoader {
|
|
|
21964
22059
|
*/
|
|
21965
22060
|
load(name) {
|
|
21966
22061
|
if (this.cache.has(name)) return this.cache.get(name);
|
|
21967
|
-
const bundledPath =
|
|
21968
|
-
const projectPath =
|
|
21969
|
-
const globalPath =
|
|
22062
|
+
const bundledPath = path35.join(this.bundledSkillsDir, name, "SKILL.md");
|
|
22063
|
+
const projectPath = path35.join(this.projectSkillsDir, name, "SKILL.md");
|
|
22064
|
+
const globalPath = path35.join(this.globalSkillsDir, name, "SKILL.md");
|
|
21970
22065
|
const existsBundled = fs31.existsSync(bundledPath);
|
|
21971
22066
|
const existsProject = fs31.existsSync(projectPath);
|
|
21972
22067
|
const existsGlobal = fs31.existsSync(globalPath);
|
|
@@ -22010,7 +22105,7 @@ var SkillLoader = class _SkillLoader {
|
|
|
22010
22105
|
try {
|
|
22011
22106
|
const raw = fs31.readFileSync(skillPath, "utf-8");
|
|
22012
22107
|
const parsed = this.parseFrontmatter(raw);
|
|
22013
|
-
const skillDir =
|
|
22108
|
+
const skillDir = path35.dirname(skillPath);
|
|
22014
22109
|
return {
|
|
22015
22110
|
name: parsed.name || name,
|
|
22016
22111
|
description: parsed.description || "",
|
|
@@ -22019,8 +22114,8 @@ var SkillLoader = class _SkillLoader {
|
|
|
22019
22114
|
version: parsed.version,
|
|
22020
22115
|
author: parsed.author,
|
|
22021
22116
|
license: parsed.license,
|
|
22022
|
-
references: this.scanAssets(
|
|
22023
|
-
scripts: this.scanAssets(
|
|
22117
|
+
references: this.scanAssets(path35.join(skillDir, "references")),
|
|
22118
|
+
scripts: this.scanAssets(path35.join(skillDir, "scripts"))
|
|
22024
22119
|
};
|
|
22025
22120
|
} catch {
|
|
22026
22121
|
return null;
|
|
@@ -22030,11 +22125,11 @@ var SkillLoader = class _SkillLoader {
|
|
|
22030
22125
|
if (!fs31.existsSync(dir)) return [];
|
|
22031
22126
|
try {
|
|
22032
22127
|
return fs31.readdirSync(dir).filter((f) => {
|
|
22033
|
-
const fp =
|
|
22128
|
+
const fp = path35.join(dir, f);
|
|
22034
22129
|
return fs31.statSync(fp).isFile();
|
|
22035
22130
|
}).map((f) => ({
|
|
22036
22131
|
name: f,
|
|
22037
|
-
path:
|
|
22132
|
+
path: path35.resolve(dir, f)
|
|
22038
22133
|
}));
|
|
22039
22134
|
} catch {
|
|
22040
22135
|
return [];
|
|
@@ -22091,9 +22186,9 @@ var SkillLoader = class _SkillLoader {
|
|
|
22091
22186
|
this.cache.clear();
|
|
22092
22187
|
}
|
|
22093
22188
|
exists(name) {
|
|
22094
|
-
const bundledPath =
|
|
22095
|
-
const projectPath =
|
|
22096
|
-
const globalPath =
|
|
22189
|
+
const bundledPath = path35.join(this.bundledSkillsDir, name, "SKILL.md");
|
|
22190
|
+
const projectPath = path35.join(this.projectSkillsDir, name, "SKILL.md");
|
|
22191
|
+
const globalPath = path35.join(this.globalSkillsDir, name, "SKILL.md");
|
|
22097
22192
|
return fs31.existsSync(bundledPath) || fs31.existsSync(projectPath) || fs31.existsSync(globalPath);
|
|
22098
22193
|
}
|
|
22099
22194
|
/**
|
|
@@ -22127,12 +22222,12 @@ var SkillLoader = class _SkillLoader {
|
|
|
22127
22222
|
|
|
22128
22223
|
// src/app/agent/core/prompt/workspace_snapshot.ts
|
|
22129
22224
|
import fs33 from "fs";
|
|
22130
|
-
import
|
|
22225
|
+
import path37 from "path";
|
|
22131
22226
|
import { execSync as execSync2 } from "child_process";
|
|
22132
22227
|
|
|
22133
22228
|
// src/app/agent/utils/blumamd.ts
|
|
22134
22229
|
import fs32 from "fs";
|
|
22135
|
-
import
|
|
22230
|
+
import path36 from "path";
|
|
22136
22231
|
import os21 from "os";
|
|
22137
22232
|
import { execSync } from "child_process";
|
|
22138
22233
|
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.";
|
|
@@ -22262,12 +22357,12 @@ var TEXT_FILE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
22262
22357
|
function expandIncludePath(includePath, baseDir) {
|
|
22263
22358
|
const cleanPath = includePath.startsWith("@") ? includePath.slice(1) : includePath;
|
|
22264
22359
|
if (cleanPath.startsWith("~")) {
|
|
22265
|
-
return
|
|
22360
|
+
return path36.join(os21.homedir(), cleanPath.slice(1));
|
|
22266
22361
|
}
|
|
22267
|
-
if (
|
|
22362
|
+
if (path36.isAbsolute(cleanPath)) {
|
|
22268
22363
|
return cleanPath;
|
|
22269
22364
|
}
|
|
22270
|
-
return
|
|
22365
|
+
return path36.resolve(baseDir, cleanPath);
|
|
22271
22366
|
}
|
|
22272
22367
|
function processIncludes(content, baseDir, processedFiles) {
|
|
22273
22368
|
const lines = content.split("\n");
|
|
@@ -22276,12 +22371,12 @@ function processIncludes(content, baseDir, processedFiles) {
|
|
|
22276
22371
|
const includeMatch = line.match(/^@\s*([^\s]+)/);
|
|
22277
22372
|
if (includeMatch) {
|
|
22278
22373
|
const includePath = expandIncludePath(includeMatch[1], baseDir);
|
|
22279
|
-
const normalizedPath =
|
|
22374
|
+
const normalizedPath = path36.normalize(includePath);
|
|
22280
22375
|
if (processedFiles.has(normalizedPath)) {
|
|
22281
22376
|
result.push(`<!-- Circular include prevented: ${includeMatch[1]} -->`);
|
|
22282
22377
|
continue;
|
|
22283
22378
|
}
|
|
22284
|
-
const ext =
|
|
22379
|
+
const ext = path36.extname(includePath).toLowerCase();
|
|
22285
22380
|
if (!TEXT_FILE_EXTENSIONS.has(ext)) {
|
|
22286
22381
|
result.push(`<!-- Include skipped (unsupported extension): ${includeMatch[1]} -->`);
|
|
22287
22382
|
continue;
|
|
@@ -22289,7 +22384,7 @@ function processIncludes(content, baseDir, processedFiles) {
|
|
|
22289
22384
|
try {
|
|
22290
22385
|
const includedContent = fs32.readFileSync(includePath, "utf-8");
|
|
22291
22386
|
processedFiles.add(normalizedPath);
|
|
22292
|
-
const processedContent = processIncludes(includedContent,
|
|
22387
|
+
const processedContent = processIncludes(includedContent, path36.dirname(includePath), processedFiles);
|
|
22293
22388
|
result.push(`
|
|
22294
22389
|
<!-- BEGIN INCLUDE ${includeMatch[1]} -->
|
|
22295
22390
|
`);
|
|
@@ -22336,8 +22431,8 @@ function parseFrontmatterPaths(paths2) {
|
|
|
22336
22431
|
function readMemoryFile(filePath, type, includeBasePath) {
|
|
22337
22432
|
try {
|
|
22338
22433
|
const rawContent = fs32.readFileSync(filePath, "utf-8");
|
|
22339
|
-
const baseDir = includeBasePath ||
|
|
22340
|
-
const processedFiles = /* @__PURE__ */ new Set([
|
|
22434
|
+
const baseDir = includeBasePath || path36.dirname(filePath);
|
|
22435
|
+
const processedFiles = /* @__PURE__ */ new Set([path36.normalize(filePath)]);
|
|
22341
22436
|
const { frontmatter, content: withoutFrontmatter } = parseFrontmatter(rawContent);
|
|
22342
22437
|
const globs = parseFrontmatterPaths(frontmatter.paths);
|
|
22343
22438
|
const processedContent = processIncludes(withoutFrontmatter, baseDir, processedFiles);
|
|
@@ -22359,15 +22454,15 @@ function readMemoryFile(filePath, type, includeBasePath) {
|
|
|
22359
22454
|
}
|
|
22360
22455
|
function findGitRoot(startDir) {
|
|
22361
22456
|
let current = startDir;
|
|
22362
|
-
while (current !==
|
|
22363
|
-
const gitPath =
|
|
22457
|
+
while (current !== path36.dirname(current)) {
|
|
22458
|
+
const gitPath = path36.join(current, ".git");
|
|
22364
22459
|
try {
|
|
22365
22460
|
if (fs32.existsSync(gitPath)) {
|
|
22366
22461
|
return current;
|
|
22367
22462
|
}
|
|
22368
22463
|
} catch {
|
|
22369
22464
|
}
|
|
22370
|
-
current =
|
|
22465
|
+
current = path36.dirname(current);
|
|
22371
22466
|
}
|
|
22372
22467
|
return null;
|
|
22373
22468
|
}
|
|
@@ -22398,11 +22493,11 @@ function processRulesDirectory(rulesDir, type, processedPaths, conditionalRule =
|
|
|
22398
22493
|
try {
|
|
22399
22494
|
const entries = fs32.readdirSync(rulesDir, { withFileTypes: true });
|
|
22400
22495
|
for (const entry of entries) {
|
|
22401
|
-
const entryPath =
|
|
22496
|
+
const entryPath = path36.join(rulesDir, entry.name);
|
|
22402
22497
|
if (entry.isDirectory()) {
|
|
22403
22498
|
result.push(...processRulesDirectory(entryPath, type, processedPaths, conditionalRule));
|
|
22404
22499
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
22405
|
-
const normalizedPath =
|
|
22500
|
+
const normalizedPath = path36.normalize(entryPath);
|
|
22406
22501
|
if (processedPaths.has(normalizedPath)) {
|
|
22407
22502
|
continue;
|
|
22408
22503
|
}
|
|
@@ -22438,13 +22533,13 @@ function loadManagedMemory() {
|
|
|
22438
22533
|
function loadUserMemory() {
|
|
22439
22534
|
const files = [];
|
|
22440
22535
|
const homeDir = os21.homedir();
|
|
22441
|
-
const userBlumaDir =
|
|
22442
|
-
const userBlumaMd =
|
|
22536
|
+
const userBlumaDir = path36.join(homeDir, ".bluma");
|
|
22537
|
+
const userBlumaMd = path36.join(userBlumaDir, "BLUMA.md");
|
|
22443
22538
|
const userFile = readMemoryFile(userBlumaMd, "User");
|
|
22444
22539
|
if (userFile && userFile.content.trim()) {
|
|
22445
22540
|
files.push(userFile);
|
|
22446
22541
|
}
|
|
22447
|
-
const userRulesDir =
|
|
22542
|
+
const userRulesDir = path36.join(userBlumaDir, "rules");
|
|
22448
22543
|
const processedPaths = /* @__PURE__ */ new Set();
|
|
22449
22544
|
files.push(...processRulesDirectory(userRulesDir, "User", processedPaths, false));
|
|
22450
22545
|
return files;
|
|
@@ -22456,10 +22551,10 @@ function loadProjectMemory(cwd2) {
|
|
|
22456
22551
|
let currentDir = cwd2;
|
|
22457
22552
|
const MAX_TRAVERSAL_DEPTH = 20;
|
|
22458
22553
|
let depth = 0;
|
|
22459
|
-
const normalizedGitRoot =
|
|
22460
|
-
while (currentDir !==
|
|
22554
|
+
const normalizedGitRoot = path36.resolve(gitRoot);
|
|
22555
|
+
while (currentDir !== path36.dirname(currentDir) && path36.resolve(currentDir).startsWith(normalizedGitRoot) && depth < MAX_TRAVERSAL_DEPTH) {
|
|
22461
22556
|
dirs.push(currentDir);
|
|
22462
|
-
currentDir =
|
|
22557
|
+
currentDir = path36.dirname(currentDir);
|
|
22463
22558
|
depth++;
|
|
22464
22559
|
}
|
|
22465
22560
|
if (!dirs.includes(gitRoot)) {
|
|
@@ -22467,7 +22562,7 @@ function loadProjectMemory(cwd2) {
|
|
|
22467
22562
|
}
|
|
22468
22563
|
const processedPaths = /* @__PURE__ */ new Set();
|
|
22469
22564
|
for (const dir of dirs.reverse()) {
|
|
22470
|
-
const projectBlumaMd =
|
|
22565
|
+
const projectBlumaMd = path36.join(dir, "BLUMA.md");
|
|
22471
22566
|
if (!processedPaths.has(projectBlumaMd)) {
|
|
22472
22567
|
processedPaths.add(projectBlumaMd);
|
|
22473
22568
|
const projectFile = readMemoryFile(projectBlumaMd, "Project");
|
|
@@ -22475,7 +22570,7 @@ function loadProjectMemory(cwd2) {
|
|
|
22475
22570
|
files.push(projectFile);
|
|
22476
22571
|
}
|
|
22477
22572
|
}
|
|
22478
|
-
const blumaDirBlumaMd =
|
|
22573
|
+
const blumaDirBlumaMd = path36.join(dir, ".bluma", "BLUMA.md");
|
|
22479
22574
|
if (!processedPaths.has(blumaDirBlumaMd)) {
|
|
22480
22575
|
processedPaths.add(blumaDirBlumaMd);
|
|
22481
22576
|
const blumaDirFile = readMemoryFile(blumaDirBlumaMd, "Project");
|
|
@@ -22483,10 +22578,10 @@ function loadProjectMemory(cwd2) {
|
|
|
22483
22578
|
files.push(blumaDirFile);
|
|
22484
22579
|
}
|
|
22485
22580
|
}
|
|
22486
|
-
const rulesDir =
|
|
22581
|
+
const rulesDir = path36.join(dir, ".bluma", "rules");
|
|
22487
22582
|
files.push(...processRulesDirectory(rulesDir, "Project", processedPaths, false));
|
|
22488
22583
|
}
|
|
22489
|
-
const localBlumaMd =
|
|
22584
|
+
const localBlumaMd = path36.join(cwd2, "BLUMA.local.md");
|
|
22490
22585
|
if (!processedPaths.has(localBlumaMd)) {
|
|
22491
22586
|
processedPaths.add(localBlumaMd);
|
|
22492
22587
|
const localFile = readMemoryFile(localBlumaMd, "Local");
|
|
@@ -22587,7 +22682,7 @@ function safeReadFile(filePath, maxChars) {
|
|
|
22587
22682
|
}
|
|
22588
22683
|
function tryReadReadme(cwd2) {
|
|
22589
22684
|
for (const name of ["README.md", "README.MD", "readme.md", "Readme.md"]) {
|
|
22590
|
-
const c = safeReadFile(
|
|
22685
|
+
const c = safeReadFile(path37.join(cwd2, name), LIMITS.readme);
|
|
22591
22686
|
if (c) return `(${name})
|
|
22592
22687
|
${c}`;
|
|
22593
22688
|
}
|
|
@@ -22595,14 +22690,14 @@ ${c}`;
|
|
|
22595
22690
|
}
|
|
22596
22691
|
function tryReadBluMaMd(cwd2) {
|
|
22597
22692
|
const paths2 = [
|
|
22598
|
-
|
|
22599
|
-
|
|
22600
|
-
|
|
22693
|
+
path37.join(cwd2, "BluMa.md"),
|
|
22694
|
+
path37.join(cwd2, "BLUMA.md"),
|
|
22695
|
+
path37.join(cwd2, ".bluma", "BluMa.md")
|
|
22601
22696
|
];
|
|
22602
22697
|
for (const p of paths2) {
|
|
22603
22698
|
const c = safeReadFile(p, LIMITS.blumaMd);
|
|
22604
22699
|
if (c) {
|
|
22605
|
-
const rel =
|
|
22700
|
+
const rel = path37.relative(cwd2, p) || p;
|
|
22606
22701
|
return `(${rel})
|
|
22607
22702
|
${c}`;
|
|
22608
22703
|
}
|
|
@@ -22610,7 +22705,7 @@ ${c}`;
|
|
|
22610
22705
|
return null;
|
|
22611
22706
|
}
|
|
22612
22707
|
function summarizePackageJson(cwd2) {
|
|
22613
|
-
const p =
|
|
22708
|
+
const p = path37.join(cwd2, "package.json");
|
|
22614
22709
|
try {
|
|
22615
22710
|
if (!fs33.existsSync(p)) return null;
|
|
22616
22711
|
const pkg = JSON.parse(fs33.readFileSync(p, "utf8"));
|
|
@@ -22704,7 +22799,7 @@ function buildWorkspaceSnapshot(cwd2) {
|
|
|
22704
22799
|
parts.push(pkg);
|
|
22705
22800
|
parts.push("```\n");
|
|
22706
22801
|
}
|
|
22707
|
-
const py = safeReadFile(
|
|
22802
|
+
const py = safeReadFile(path37.join(cwd2, "pyproject.toml"), LIMITS.pyproject);
|
|
22708
22803
|
if (py) {
|
|
22709
22804
|
parts.push("### pyproject.toml (excerpt)\n```toml");
|
|
22710
22805
|
parts.push(py);
|
|
@@ -22722,15 +22817,15 @@ function buildWorkspaceSnapshot(cwd2) {
|
|
|
22722
22817
|
parts.push(bluma);
|
|
22723
22818
|
parts.push("```\n");
|
|
22724
22819
|
}
|
|
22725
|
-
const contrib = safeReadFile(
|
|
22820
|
+
const contrib = safeReadFile(path37.join(cwd2, "CONTRIBUTING.md"), LIMITS.contributing);
|
|
22726
22821
|
if (contrib) {
|
|
22727
22822
|
parts.push("### CONTRIBUTING.md (excerpt)\n```markdown");
|
|
22728
22823
|
parts.push(contrib);
|
|
22729
22824
|
parts.push("```\n");
|
|
22730
22825
|
}
|
|
22731
|
-
const chlog = safeReadFile(
|
|
22826
|
+
const chlog = safeReadFile(path37.join(cwd2, "CHANGELOG.md"), LIMITS.changelog);
|
|
22732
22827
|
if (!chlog) {
|
|
22733
|
-
const alt = safeReadFile(
|
|
22828
|
+
const alt = safeReadFile(path37.join(cwd2, "CHANGES.md"), LIMITS.changelog);
|
|
22734
22829
|
if (alt) {
|
|
22735
22830
|
parts.push("### CHANGES.md (excerpt)\n```markdown");
|
|
22736
22831
|
parts.push(alt);
|
|
@@ -22766,14 +22861,14 @@ function buildWorkspaceSnapshot(cwd2) {
|
|
|
22766
22861
|
} else {
|
|
22767
22862
|
parts.push("### Git\n(not a git work tree, or `git` unavailable)\n");
|
|
22768
22863
|
}
|
|
22769
|
-
const tsconfig = safeReadFile(
|
|
22864
|
+
const tsconfig = safeReadFile(path37.join(cwd2, "tsconfig.json"), LIMITS.tsconfig);
|
|
22770
22865
|
if (tsconfig) {
|
|
22771
22866
|
parts.push("### tsconfig.json (excerpt)\n```json");
|
|
22772
22867
|
parts.push(tsconfig);
|
|
22773
22868
|
parts.push("```\n");
|
|
22774
22869
|
}
|
|
22775
22870
|
for (const name of ["Dockerfile", "dockerfile", "Dockerfile.prod", "Dockerfile.dev"]) {
|
|
22776
|
-
const df = safeReadFile(
|
|
22871
|
+
const df = safeReadFile(path37.join(cwd2, name), LIMITS.dockerfile);
|
|
22777
22872
|
if (df) {
|
|
22778
22873
|
parts.push(`### ${name} (excerpt)
|
|
22779
22874
|
`);
|
|
@@ -22783,7 +22878,7 @@ function buildWorkspaceSnapshot(cwd2) {
|
|
|
22783
22878
|
}
|
|
22784
22879
|
}
|
|
22785
22880
|
for (const name of ["docker-compose.yml", "docker-compose.yaml", "compose.yml", "compose.yaml"]) {
|
|
22786
|
-
const dc = safeReadFile(
|
|
22881
|
+
const dc = safeReadFile(path37.join(cwd2, name), LIMITS.dockerfile);
|
|
22787
22882
|
if (dc) {
|
|
22788
22883
|
parts.push(`### ${name} (excerpt)
|
|
22789
22884
|
`);
|
|
@@ -22798,7 +22893,7 @@ function buildWorkspaceSnapshot(cwd2) {
|
|
|
22798
22893
|
".circleci/config.yml",
|
|
22799
22894
|
"Jenkinsfile"
|
|
22800
22895
|
]) {
|
|
22801
|
-
const ciFile =
|
|
22896
|
+
const ciFile = path37.join(cwd2, ciPath);
|
|
22802
22897
|
if (fs33.existsSync(ciFile)) {
|
|
22803
22898
|
const st = fs33.statSync(ciFile);
|
|
22804
22899
|
if (st.isDirectory()) {
|
|
@@ -22814,7 +22909,7 @@ function buildWorkspaceSnapshot(cwd2) {
|
|
|
22814
22909
|
} else {
|
|
22815
22910
|
const ci = safeReadFile(ciFile, LIMITS.ciConfig);
|
|
22816
22911
|
if (ci) {
|
|
22817
|
-
parts.push(`### CI config (${
|
|
22912
|
+
parts.push(`### CI config (${path37.basename(ciPath)})
|
|
22818
22913
|
`);
|
|
22819
22914
|
parts.push(ci);
|
|
22820
22915
|
parts.push("\n");
|
|
@@ -22823,7 +22918,7 @@ function buildWorkspaceSnapshot(cwd2) {
|
|
|
22823
22918
|
}
|
|
22824
22919
|
}
|
|
22825
22920
|
for (const depFile of ["requirements.txt", "Pipfile", "poetry.lock", "Gemfile", "go.sum", "Cargo.lock"]) {
|
|
22826
|
-
const depPath =
|
|
22921
|
+
const depPath = path37.join(cwd2, depFile);
|
|
22827
22922
|
if (fs33.existsSync(depPath)) {
|
|
22828
22923
|
const depContent = safeReadFile(depPath, 1500);
|
|
22829
22924
|
if (depContent) {
|
|
@@ -22837,7 +22932,7 @@ function buildWorkspaceSnapshot(cwd2) {
|
|
|
22837
22932
|
}
|
|
22838
22933
|
}
|
|
22839
22934
|
for (const envFile of [".env.example", ".env.sample", ".env.template"]) {
|
|
22840
|
-
const envPath =
|
|
22935
|
+
const envPath = path37.join(cwd2, envFile);
|
|
22841
22936
|
if (fs33.existsSync(envPath)) {
|
|
22842
22937
|
try {
|
|
22843
22938
|
const raw = fs33.readFileSync(envPath, "utf-8");
|
|
@@ -22865,13 +22960,13 @@ init_runtime_config();
|
|
|
22865
22960
|
init_sandbox_policy();
|
|
22866
22961
|
import fs34 from "fs";
|
|
22867
22962
|
import os22 from "os";
|
|
22868
|
-
import
|
|
22963
|
+
import path38 from "path";
|
|
22869
22964
|
function getProjectPluginsDir() {
|
|
22870
22965
|
const policy = getSandboxPolicy();
|
|
22871
|
-
return
|
|
22966
|
+
return path38.join(policy.workspaceRoot, ".bluma", "plugins");
|
|
22872
22967
|
}
|
|
22873
22968
|
function getGlobalPluginsDir() {
|
|
22874
|
-
return
|
|
22969
|
+
return path38.join(process.env.HOME || os22.homedir(), ".bluma", "plugins");
|
|
22875
22970
|
}
|
|
22876
22971
|
function getPluginDirs() {
|
|
22877
22972
|
return {
|
|
@@ -22897,8 +22992,8 @@ function readManifest(manifestPath, fallbackName) {
|
|
|
22897
22992
|
}
|
|
22898
22993
|
function findManifestPath(pluginDir) {
|
|
22899
22994
|
const candidates = [
|
|
22900
|
-
|
|
22901
|
-
|
|
22995
|
+
path38.join(pluginDir, ".codex-plugin", "plugin.json"),
|
|
22996
|
+
path38.join(pluginDir, "plugin.json")
|
|
22902
22997
|
];
|
|
22903
22998
|
for (const candidate of candidates) {
|
|
22904
22999
|
if (fs34.existsSync(candidate)) {
|
|
@@ -22912,7 +23007,7 @@ function listFromDir(baseDir, source) {
|
|
|
22912
23007
|
return [];
|
|
22913
23008
|
}
|
|
22914
23009
|
return fs34.readdirSync(baseDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).flatMap((entry) => {
|
|
22915
|
-
const pluginDir =
|
|
23010
|
+
const pluginDir = path38.join(baseDir, entry.name);
|
|
22916
23011
|
const manifestPath = findManifestPath(pluginDir);
|
|
22917
23012
|
if (!manifestPath) {
|
|
22918
23013
|
return [];
|
|
@@ -23358,7 +23453,7 @@ function buildModelInfoSection(modelId) {
|
|
|
23358
23453
|
// src/app/agent/runtime/hook_registry.ts
|
|
23359
23454
|
init_sandbox_policy();
|
|
23360
23455
|
import fs35 from "fs";
|
|
23361
|
-
import
|
|
23456
|
+
import path39 from "path";
|
|
23362
23457
|
var DEFAULT_STATE = {
|
|
23363
23458
|
enabled: true,
|
|
23364
23459
|
maxEvents: 120,
|
|
@@ -23369,7 +23464,7 @@ var cache3 = null;
|
|
|
23369
23464
|
var cachePath2 = null;
|
|
23370
23465
|
function getStatePath() {
|
|
23371
23466
|
const policy = getSandboxPolicy();
|
|
23372
|
-
return
|
|
23467
|
+
return path39.join(policy.workspaceRoot, ".bluma", "hooks.json");
|
|
23373
23468
|
}
|
|
23374
23469
|
function getHookStatePath() {
|
|
23375
23470
|
return getStatePath();
|
|
@@ -23415,7 +23510,7 @@ function ensureLoaded2() {
|
|
|
23415
23510
|
}
|
|
23416
23511
|
function persist2(state2) {
|
|
23417
23512
|
const statePath = getStatePath();
|
|
23418
|
-
fs35.mkdirSync(
|
|
23513
|
+
fs35.mkdirSync(path39.dirname(statePath), { recursive: true });
|
|
23419
23514
|
state2.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
23420
23515
|
fs35.writeFileSync(statePath, JSON.stringify(state2, null, 2), "utf-8");
|
|
23421
23516
|
cache3 = state2;
|
|
@@ -23679,15 +23774,15 @@ init_memdir();
|
|
|
23679
23774
|
|
|
23680
23775
|
// src/app/agent/memory/session_memory_context.ts
|
|
23681
23776
|
init_session_memory_paths();
|
|
23682
|
-
import { readFile as
|
|
23777
|
+
import { readFile as readFile4, writeFile as writeFile3 } from "fs/promises";
|
|
23683
23778
|
async function loadSessionMemoryForPrompt(sessionId, cwd2 = process.cwd()) {
|
|
23684
23779
|
if (!sessionId?.trim()) return "";
|
|
23685
|
-
const
|
|
23780
|
+
const path60 = getSessionMemoryPath(sessionId, cwd2);
|
|
23686
23781
|
try {
|
|
23687
|
-
const content = await
|
|
23782
|
+
const content = await readFile4(path60, "utf-8");
|
|
23688
23783
|
if (!content.trim()) return "";
|
|
23689
23784
|
return `<session_memory>
|
|
23690
|
-
Notes for this conversation (${
|
|
23785
|
+
Notes for this conversation (${path60}):
|
|
23691
23786
|
|
|
23692
23787
|
${content.trim()}
|
|
23693
23788
|
</session_memory>`;
|
|
@@ -23697,11 +23792,11 @@ ${content.trim()}
|
|
|
23697
23792
|
}
|
|
23698
23793
|
async function initSessionMemoryFile(sessionId, cwd2 = process.cwd()) {
|
|
23699
23794
|
await ensureSessionMemoryDir(sessionId, cwd2);
|
|
23700
|
-
const
|
|
23795
|
+
const path60 = getSessionMemoryPath(sessionId, cwd2);
|
|
23701
23796
|
try {
|
|
23702
|
-
await
|
|
23797
|
+
await readFile4(path60, "utf-8");
|
|
23703
23798
|
} catch {
|
|
23704
|
-
await
|
|
23799
|
+
await writeFile3(path60, `${DEFAULT_SESSION_MEMORY_TEMPLATE}
|
|
23705
23800
|
`, "utf-8");
|
|
23706
23801
|
}
|
|
23707
23802
|
}
|
|
@@ -23783,7 +23878,7 @@ Use \`factorai.sh.redeploy_app({ appId })\` only when sources on the server are
|
|
|
23783
23878
|
|
|
23784
23879
|
## Deploy constraints (first deploy)
|
|
23785
23880
|
|
|
23786
|
-
- \`next.config.js\` must
|
|
23881
|
+
- \`next.config.js\` must use direct \`module.exports = { output: "standalone", ... }\` (FactorAI deployer cannot parse \`const nextConfig\` indirection).
|
|
23787
23882
|
- ZIP max ~50MB \u2014 source only; Severino runs \`npm install\` + \`next build\` on the server.
|
|
23788
23883
|
- shadcn components in scaffold must compile (no missing Radix imports).
|
|
23789
23884
|
|
|
@@ -23834,17 +23929,17 @@ function getGitBranch(dir) {
|
|
|
23834
23929
|
}
|
|
23835
23930
|
}
|
|
23836
23931
|
function getPackageManager(dir) {
|
|
23837
|
-
if (fs36.existsSync(
|
|
23838
|
-
if (fs36.existsSync(
|
|
23839
|
-
if (fs36.existsSync(
|
|
23840
|
-
if (fs36.existsSync(
|
|
23932
|
+
if (fs36.existsSync(path40.join(dir, "pnpm-lock.yaml"))) return "pnpm";
|
|
23933
|
+
if (fs36.existsSync(path40.join(dir, "yarn.lock"))) return "yarn";
|
|
23934
|
+
if (fs36.existsSync(path40.join(dir, "bun.lockb"))) return "bun";
|
|
23935
|
+
if (fs36.existsSync(path40.join(dir, "package-lock.json"))) return "npm";
|
|
23841
23936
|
return "unknown";
|
|
23842
23937
|
}
|
|
23843
23938
|
function getProjectType(dir) {
|
|
23844
23939
|
try {
|
|
23845
23940
|
const files = fs36.readdirSync(dir);
|
|
23846
23941
|
if (files.includes("package.json")) {
|
|
23847
|
-
const pkg = JSON.parse(fs36.readFileSync(
|
|
23942
|
+
const pkg = JSON.parse(fs36.readFileSync(path40.join(dir, "package.json"), "utf-8"));
|
|
23848
23943
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
23849
23944
|
if (deps.next) return "Next.js";
|
|
23850
23945
|
if (deps.react) return "React";
|
|
@@ -23864,7 +23959,7 @@ function getProjectType(dir) {
|
|
|
23864
23959
|
}
|
|
23865
23960
|
function getTestFramework(dir) {
|
|
23866
23961
|
try {
|
|
23867
|
-
const pkgPath =
|
|
23962
|
+
const pkgPath = path40.join(dir, "package.json");
|
|
23868
23963
|
if (fs36.existsSync(pkgPath)) {
|
|
23869
23964
|
const pkg = JSON.parse(fs36.readFileSync(pkgPath, "utf-8"));
|
|
23870
23965
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
@@ -23875,7 +23970,7 @@ function getTestFramework(dir) {
|
|
|
23875
23970
|
if (deps["@playwright/test"]) return "playwright";
|
|
23876
23971
|
if (deps.cypress) return "cypress";
|
|
23877
23972
|
}
|
|
23878
|
-
if (fs36.existsSync(
|
|
23973
|
+
if (fs36.existsSync(path40.join(dir, "pytest.ini")) || fs36.existsSync(path40.join(dir, "conftest.py"))) return "pytest";
|
|
23879
23974
|
return "unknown";
|
|
23880
23975
|
} catch {
|
|
23881
23976
|
return "unknown";
|
|
@@ -23883,7 +23978,7 @@ function getTestFramework(dir) {
|
|
|
23883
23978
|
}
|
|
23884
23979
|
function getTestCommand(dir) {
|
|
23885
23980
|
try {
|
|
23886
|
-
const pkgPath =
|
|
23981
|
+
const pkgPath = path40.join(dir, "package.json");
|
|
23887
23982
|
if (fs36.existsSync(pkgPath)) {
|
|
23888
23983
|
const pkg = JSON.parse(fs36.readFileSync(pkgPath, "utf-8"));
|
|
23889
23984
|
if (pkg.scripts?.test) return "npm test";
|
|
@@ -23900,7 +23995,7 @@ function getTestCommand(dir) {
|
|
|
23900
23995
|
}
|
|
23901
23996
|
function isGitRepo(dir) {
|
|
23902
23997
|
try {
|
|
23903
|
-
const p =
|
|
23998
|
+
const p = path40.join(dir, ".git");
|
|
23904
23999
|
return fs36.existsSync(p) && fs36.lstatSync(p).isDirectory();
|
|
23905
24000
|
} catch {
|
|
23906
24001
|
return false;
|
|
@@ -25337,7 +25432,7 @@ var LLMService = class {
|
|
|
25337
25432
|
// src/app/agent/utils/user_message_images.ts
|
|
25338
25433
|
import fs37 from "fs";
|
|
25339
25434
|
import os25 from "os";
|
|
25340
|
-
import
|
|
25435
|
+
import path41 from "path";
|
|
25341
25436
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
25342
25437
|
var IMAGE_EXT = /\.(png|jpe?g|gif|webp|bmp)$/i;
|
|
25343
25438
|
var MAX_IMAGE_BYTES = 4 * 1024 * 1024;
|
|
@@ -25353,22 +25448,22 @@ var MIME = {
|
|
|
25353
25448
|
function expandUserPath(p) {
|
|
25354
25449
|
const t = p.trim();
|
|
25355
25450
|
if (t.startsWith("~")) {
|
|
25356
|
-
return
|
|
25451
|
+
return path41.join(os25.homedir(), t.slice(1).replace(/^\//, ""));
|
|
25357
25452
|
}
|
|
25358
25453
|
return t;
|
|
25359
25454
|
}
|
|
25360
25455
|
function isPathAllowed(absResolved, cwd2) {
|
|
25361
|
-
const resolved =
|
|
25362
|
-
const cwdR =
|
|
25363
|
-
const homeR =
|
|
25364
|
-
const tmpR =
|
|
25365
|
-
const underCwd = resolved === cwdR || resolved.startsWith(cwdR +
|
|
25366
|
-
const underHome = resolved === homeR || resolved.startsWith(homeR +
|
|
25367
|
-
const underTmp = resolved === tmpR || resolved.startsWith(tmpR +
|
|
25456
|
+
const resolved = path41.normalize(path41.resolve(absResolved));
|
|
25457
|
+
const cwdR = path41.normalize(path41.resolve(cwd2));
|
|
25458
|
+
const homeR = path41.normalize(path41.resolve(os25.homedir()));
|
|
25459
|
+
const tmpR = path41.normalize(path41.resolve(os25.tmpdir()));
|
|
25460
|
+
const underCwd = resolved === cwdR || resolved.startsWith(cwdR + path41.sep);
|
|
25461
|
+
const underHome = resolved === homeR || resolved.startsWith(homeR + path41.sep);
|
|
25462
|
+
const underTmp = resolved === tmpR || resolved.startsWith(tmpR + path41.sep);
|
|
25368
25463
|
return underCwd || underHome || underTmp;
|
|
25369
25464
|
}
|
|
25370
25465
|
function mimeFor(abs) {
|
|
25371
|
-
const ext =
|
|
25466
|
+
const ext = path41.extname(abs).toLowerCase();
|
|
25372
25467
|
return MIME[ext] || "application/octet-stream";
|
|
25373
25468
|
}
|
|
25374
25469
|
var IMAGE_EXT_SRC = String.raw`(?:png|jpe?g|gif|webp|bmp)`;
|
|
@@ -25412,7 +25507,7 @@ function collectImagePathStrings(raw) {
|
|
|
25412
25507
|
}
|
|
25413
25508
|
function resolveImagePath(candidate, cwd2) {
|
|
25414
25509
|
const expanded = expandUserPath(candidate);
|
|
25415
|
-
const abs =
|
|
25510
|
+
const abs = path41.isAbsolute(expanded) ? path41.normalize(expanded) : path41.normalize(path41.resolve(cwd2, expanded));
|
|
25416
25511
|
if (!isPathAllowed(abs, cwd2)) return null;
|
|
25417
25512
|
try {
|
|
25418
25513
|
if (!fs37.existsSync(abs) || !fs37.statSync(abs).isFile()) return null;
|
|
@@ -25435,7 +25530,7 @@ function trySingleLineFileUriOrBareImagePath(line, cwd2) {
|
|
|
25435
25530
|
if (s.startsWith('"') && s.endsWith('"') || s.startsWith("'") && s.endsWith("'")) {
|
|
25436
25531
|
s = s.slice(1, -1).trim();
|
|
25437
25532
|
}
|
|
25438
|
-
if (!IMAGE_EXT.test(
|
|
25533
|
+
if (!IMAGE_EXT.test(path41.extname(s))) return null;
|
|
25439
25534
|
const abs = resolveImagePath(s, cwd2);
|
|
25440
25535
|
if (!abs) return null;
|
|
25441
25536
|
try {
|
|
@@ -25538,7 +25633,7 @@ function buildUserMessageContent(raw, cwd2) {
|
|
|
25538
25633
|
init_sandbox_policy();
|
|
25539
25634
|
init_runtime_config();
|
|
25540
25635
|
init_permission_rules();
|
|
25541
|
-
import
|
|
25636
|
+
import path42 from "path";
|
|
25542
25637
|
var LOCAL_EDIT_TOOL_NAMES = /* @__PURE__ */ new Set(["edit_tool", "file_write", "notebook_edit"]);
|
|
25543
25638
|
function getToolPermissionLayer(metadata) {
|
|
25544
25639
|
if (metadata.riskLevel === "safe") return "read";
|
|
@@ -25553,11 +25648,11 @@ function checkFilePermissionRules(toolName, filePath, policy) {
|
|
|
25553
25648
|
if (!filePath) {
|
|
25554
25649
|
return { allowed: false, reason: "No file path provided for permission check." };
|
|
25555
25650
|
}
|
|
25556
|
-
const resolvedPath =
|
|
25651
|
+
const resolvedPath = path42.resolve(filePath);
|
|
25557
25652
|
if (!isPathInsideWorkspace(resolvedPath, policy)) {
|
|
25558
25653
|
return { allowed: false, reason: `File path "${filePath}" is outside workspace root.` };
|
|
25559
25654
|
}
|
|
25560
|
-
const relativePath =
|
|
25655
|
+
const relativePath = path42.relative(policy.workspaceRoot, resolvedPath);
|
|
25561
25656
|
const toolPattern = `${toolName}(${relativePath})`;
|
|
25562
25657
|
const ruleDecision = permissionRulesEngine.checkPermission(toolPattern, { filepath: filePath });
|
|
25563
25658
|
if (ruleDecision === "deny") {
|
|
@@ -25566,7 +25661,7 @@ function checkFilePermissionRules(toolName, filePath, policy) {
|
|
|
25566
25661
|
if (ruleDecision === "allow") {
|
|
25567
25662
|
return { allowed: true, reason: `File "${filePath}" allowed by permission rules.` };
|
|
25568
25663
|
}
|
|
25569
|
-
const dirPath =
|
|
25664
|
+
const dirPath = path42.dirname(relativePath);
|
|
25570
25665
|
const dirPattern = `${toolName}(${dirPath}/**)`;
|
|
25571
25666
|
const dirRuleDecision = permissionRulesEngine.checkPermission(dirPattern, { filepath: filePath });
|
|
25572
25667
|
if (dirRuleDecision === "allow") {
|
|
@@ -25784,10 +25879,10 @@ function effectiveToolAutoApprove(toolCall, sessionId, options) {
|
|
|
25784
25879
|
|
|
25785
25880
|
// src/app/agent/tools/CodingMemoryTool/CodingMemoryConsolidate.ts
|
|
25786
25881
|
import * as fs38 from "fs";
|
|
25787
|
-
import * as
|
|
25882
|
+
import * as path43 from "path";
|
|
25788
25883
|
import os26 from "os";
|
|
25789
25884
|
function memoryPath2() {
|
|
25790
|
-
return
|
|
25885
|
+
return path43.join(process.env.HOME || os26.homedir(), ".bluma", "coding_memory.json");
|
|
25791
25886
|
}
|
|
25792
25887
|
function normalizeNote2(note) {
|
|
25793
25888
|
return note.trim().toLowerCase().replace(/\s+/g, " ");
|
|
@@ -26349,16 +26444,16 @@ var BluMaToolRunner = class {
|
|
|
26349
26444
|
|
|
26350
26445
|
// src/app/agent/session_manager/session_archive.ts
|
|
26351
26446
|
init_bluma_app_dir();
|
|
26352
|
-
import
|
|
26447
|
+
import path44 from "path";
|
|
26353
26448
|
import { promises as fs39 } from "fs";
|
|
26354
26449
|
async function archivePrunedConversationMessages(sessionId, messages) {
|
|
26355
26450
|
if (!sessionId || messages.length === 0) {
|
|
26356
26451
|
return null;
|
|
26357
26452
|
}
|
|
26358
26453
|
const appDir = getPreferredAppDir();
|
|
26359
|
-
const dir =
|
|
26454
|
+
const dir = path44.join(appDir, "sessions", "archive", sessionId);
|
|
26360
26455
|
await fs39.mkdir(dir, { recursive: true });
|
|
26361
|
-
const archiveFile =
|
|
26456
|
+
const archiveFile = path44.join(dir, `${Date.now()}.jsonl`);
|
|
26362
26457
|
const lines = messages.map((m) => JSON.stringify(m)).join("\n") + "\n";
|
|
26363
26458
|
await fs39.appendFile(archiveFile, lines, "utf-8");
|
|
26364
26459
|
return archiveFile;
|
|
@@ -27112,7 +27207,7 @@ init_paths();
|
|
|
27112
27207
|
|
|
27113
27208
|
// src/app/agent/memory/memdir/memory_scan.ts
|
|
27114
27209
|
init_memoryTypes();
|
|
27115
|
-
import { readdir as readdir2, readFile as
|
|
27210
|
+
import { readdir as readdir2, readFile as readFile5, stat } from "fs/promises";
|
|
27116
27211
|
import { join as join12 } from "path";
|
|
27117
27212
|
var MAX_MEMORY_FILES = 200;
|
|
27118
27213
|
var FRONTMATTER_MAX_LINES = 30;
|
|
@@ -27154,7 +27249,7 @@ async function scanMemoryFiles(memoryDir, _signal) {
|
|
|
27154
27249
|
for (const relativePath of mdFiles) {
|
|
27155
27250
|
const filePath = join12(memoryDir, relativePath);
|
|
27156
27251
|
try {
|
|
27157
|
-
const raw = await
|
|
27252
|
+
const raw = await readFile5(filePath, "utf-8");
|
|
27158
27253
|
const head = raw.split("\n").slice(0, FRONTMATTER_MAX_LINES).join("\n");
|
|
27159
27254
|
const frontmatter = parseSimpleFrontmatter(head);
|
|
27160
27255
|
const st = await stat(filePath);
|
|
@@ -27221,7 +27316,7 @@ Update existing files instead of duplicating.` : "";
|
|
|
27221
27316
|
|
|
27222
27317
|
// src/app/agent/memory/memory_tool_policy.ts
|
|
27223
27318
|
init_paths();
|
|
27224
|
-
import
|
|
27319
|
+
import path45 from "path";
|
|
27225
27320
|
var MEMORY_READ_TOOLS = /* @__PURE__ */ new Set([
|
|
27226
27321
|
"read_file_lines",
|
|
27227
27322
|
"grep_search",
|
|
@@ -27248,7 +27343,7 @@ function isReadOnlyShellCommand(command) {
|
|
|
27248
27343
|
return READ_ONLY_SHELL.test(trimmed);
|
|
27249
27344
|
}
|
|
27250
27345
|
function createAutoMemToolGate(memoryDir) {
|
|
27251
|
-
const memRoot = memoryDir.endsWith(
|
|
27346
|
+
const memRoot = memoryDir.endsWith(path45.sep) ? memoryDir : memoryDir + path45.sep;
|
|
27252
27347
|
return (toolName, args) => {
|
|
27253
27348
|
if (MEMORY_READ_TOOLS.has(toolName)) {
|
|
27254
27349
|
return { allowed: true };
|
|
@@ -27261,7 +27356,7 @@ function createAutoMemToolGate(memoryDir) {
|
|
|
27261
27356
|
}
|
|
27262
27357
|
if (MEMORY_WRITE_TOOLS.has(toolName)) {
|
|
27263
27358
|
const fp = extractFilePath(args);
|
|
27264
|
-
if (fp && isAutoMemPath(
|
|
27359
|
+
if (fp && isAutoMemPath(path45.resolve(fp))) {
|
|
27265
27360
|
return { allowed: true };
|
|
27266
27361
|
}
|
|
27267
27362
|
return { allowed: false, reason: `Writes must stay under ${memRoot}` };
|
|
@@ -27270,18 +27365,18 @@ function createAutoMemToolGate(memoryDir) {
|
|
|
27270
27365
|
};
|
|
27271
27366
|
}
|
|
27272
27367
|
function createSessionMemoryToolGate(sessionMemoryPath) {
|
|
27273
|
-
const resolvedTarget =
|
|
27368
|
+
const resolvedTarget = path45.resolve(sessionMemoryPath);
|
|
27274
27369
|
return (toolName, args) => {
|
|
27275
27370
|
if (toolName === "read_file_lines") {
|
|
27276
27371
|
const fp = extractFilePath(args);
|
|
27277
|
-
if (fp &&
|
|
27372
|
+
if (fp && path45.resolve(fp) === resolvedTarget) {
|
|
27278
27373
|
return { allowed: true };
|
|
27279
27374
|
}
|
|
27280
27375
|
return { allowed: false, reason: "Session memory subagent may only read the session summary file" };
|
|
27281
27376
|
}
|
|
27282
27377
|
if (toolName === "edit_tool") {
|
|
27283
27378
|
const fp = extractFilePath(args);
|
|
27284
|
-
if (fp &&
|
|
27379
|
+
if (fp && path45.resolve(fp) === resolvedTarget) {
|
|
27285
27380
|
return { allowed: true };
|
|
27286
27381
|
}
|
|
27287
27382
|
return { allowed: false, reason: "Session memory subagent may only edit the session summary file" };
|
|
@@ -27308,7 +27403,7 @@ function hasAutoMemWritesSinceHistory(history, sinceIndex) {
|
|
|
27308
27403
|
continue;
|
|
27309
27404
|
}
|
|
27310
27405
|
const fp = extractFilePath(args);
|
|
27311
|
-
if (fp && isAutoMemPath(
|
|
27406
|
+
if (fp && isAutoMemPath(path45.resolve(fp))) {
|
|
27312
27407
|
return true;
|
|
27313
27408
|
}
|
|
27314
27409
|
}
|
|
@@ -27527,7 +27622,7 @@ function scheduleExtractMemories(deps) {
|
|
|
27527
27622
|
|
|
27528
27623
|
// src/app/agent/memory/session_memory_update.ts
|
|
27529
27624
|
init_session_memory_paths();
|
|
27530
|
-
import { readFile as
|
|
27625
|
+
import { readFile as readFile6, writeFile as writeFile4 } from "fs/promises";
|
|
27531
27626
|
|
|
27532
27627
|
// src/app/agent/memory/session_memory_prompts.ts
|
|
27533
27628
|
init_session_memory_paths();
|
|
@@ -27639,9 +27734,9 @@ async function runSessionMemoryUpdate(deps) {
|
|
|
27639
27734
|
const memoryPath3 = getSessionMemoryPath(sessionId);
|
|
27640
27735
|
let currentMemory = "";
|
|
27641
27736
|
try {
|
|
27642
|
-
currentMemory = await
|
|
27737
|
+
currentMemory = await readFile6(memoryPath3, "utf-8");
|
|
27643
27738
|
} catch {
|
|
27644
|
-
await
|
|
27739
|
+
await writeFile4(memoryPath3, `${DEFAULT_SESSION_MEMORY_TEMPLATE}
|
|
27645
27740
|
`, "utf-8");
|
|
27646
27741
|
currentMemory = DEFAULT_SESSION_MEMORY_TEMPLATE;
|
|
27647
27742
|
}
|
|
@@ -27776,7 +27871,7 @@ var BluMaAgent = class {
|
|
|
27776
27871
|
if (!this.sessionFile) return;
|
|
27777
27872
|
try {
|
|
27778
27873
|
const sessionData = {
|
|
27779
|
-
session_id:
|
|
27874
|
+
session_id: path46.basename(this.sessionFile, ".json"),
|
|
27780
27875
|
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
27781
27876
|
conversation_history: this.history,
|
|
27782
27877
|
last_updated: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -27988,7 +28083,7 @@ var BluMaAgent = class {
|
|
|
27988
28083
|
|
|
27989
28084
|
${editData.error.display}`;
|
|
27990
28085
|
}
|
|
27991
|
-
const filename =
|
|
28086
|
+
const filename = path46.basename(toolArgs.file_path);
|
|
27992
28087
|
return createDiff(filename, editData.currentContent || "", editData.newContent);
|
|
27993
28088
|
} catch (e) {
|
|
27994
28089
|
return `An unexpected error occurred while generating the edit preview: ${e.message}`;
|
|
@@ -28725,14 +28820,14 @@ async function fullCompact(messages, targetTokens, summarizer, llmClient) {
|
|
|
28725
28820
|
// src/app/agent/core/memory/session_memory.ts
|
|
28726
28821
|
import fs41 from "fs";
|
|
28727
28822
|
import os29 from "os";
|
|
28728
|
-
import
|
|
28823
|
+
import path47 from "path";
|
|
28729
28824
|
import { v4 as uuidv49 } from "uuid";
|
|
28730
28825
|
var SessionMemoryExtractor = class {
|
|
28731
28826
|
llmClient;
|
|
28732
28827
|
memoryFile;
|
|
28733
28828
|
constructor(options = {}) {
|
|
28734
28829
|
this.llmClient = options.llmClient;
|
|
28735
|
-
this.memoryFile = options.memoryFile ||
|
|
28830
|
+
this.memoryFile = options.memoryFile || path47.join(os29.homedir(), ".bluma", "session_memory.json");
|
|
28736
28831
|
}
|
|
28737
28832
|
/**
|
|
28738
28833
|
* Extract memories from conversation using LLM
|
|
@@ -29341,14 +29436,14 @@ var RouteManager = class {
|
|
|
29341
29436
|
this.subAgents = subAgents;
|
|
29342
29437
|
this.core = core;
|
|
29343
29438
|
}
|
|
29344
|
-
registerRoute(
|
|
29345
|
-
this.routeHandlers.set(
|
|
29439
|
+
registerRoute(path60, handler) {
|
|
29440
|
+
this.routeHandlers.set(path60, handler);
|
|
29346
29441
|
}
|
|
29347
29442
|
async handleRoute(payload) {
|
|
29348
29443
|
const inputText = String(payload.content || "").trim();
|
|
29349
29444
|
const { userContext, options } = payload;
|
|
29350
|
-
for (const [
|
|
29351
|
-
if (inputText ===
|
|
29445
|
+
for (const [path60, handler] of this.routeHandlers) {
|
|
29446
|
+
if (inputText === path60 || inputText.startsWith(`${path60} `)) {
|
|
29352
29447
|
return handler({ content: inputText, userContext });
|
|
29353
29448
|
}
|
|
29354
29449
|
}
|
|
@@ -29357,13 +29452,13 @@ var RouteManager = class {
|
|
|
29357
29452
|
};
|
|
29358
29453
|
|
|
29359
29454
|
// src/app/agent/runtime/plugin_runtime.ts
|
|
29360
|
-
import
|
|
29455
|
+
import path48 from "path";
|
|
29361
29456
|
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
29362
29457
|
async function loadPluginsAtStartup() {
|
|
29363
29458
|
for (const p of listPlugins()) {
|
|
29364
29459
|
const entry = p.manifest.entry?.trim();
|
|
29365
29460
|
if (!entry) continue;
|
|
29366
|
-
const abs =
|
|
29461
|
+
const abs = path48.resolve(p.root, entry);
|
|
29367
29462
|
try {
|
|
29368
29463
|
const href = pathToFileURL2(abs).href;
|
|
29369
29464
|
const mod = await import(href);
|
|
@@ -29384,7 +29479,7 @@ async function loadPluginsAtStartup() {
|
|
|
29384
29479
|
}
|
|
29385
29480
|
|
|
29386
29481
|
// src/app/agent/agent.ts
|
|
29387
|
-
var globalEnvPath =
|
|
29482
|
+
var globalEnvPath = path49.join(os30.homedir(), ".bluma", ".env");
|
|
29388
29483
|
dotenv.config({ path: globalEnvPath });
|
|
29389
29484
|
var Agent = class {
|
|
29390
29485
|
sessionId;
|
|
@@ -31240,10 +31335,10 @@ function resolveToolPayload(result) {
|
|
|
31240
31335
|
|
|
31241
31336
|
// src/app/ui/components/FilePathLink.tsx
|
|
31242
31337
|
import { pathToFileURL as pathToFileURL3 } from "node:url";
|
|
31243
|
-
import
|
|
31338
|
+
import path51 from "node:path";
|
|
31244
31339
|
|
|
31245
31340
|
// src/app/ui/utils/pathDisplay.ts
|
|
31246
|
-
import
|
|
31341
|
+
import path50 from "node:path";
|
|
31247
31342
|
import os31 from "node:os";
|
|
31248
31343
|
function formatPathForDisplay(pathInput, cwd2 = process.cwd()) {
|
|
31249
31344
|
let s = String(pathInput ?? "").trim();
|
|
@@ -31251,17 +31346,17 @@ function formatPathForDisplay(pathInput, cwd2 = process.cwd()) {
|
|
|
31251
31346
|
s = s.replace(/[/\\]+$/, "");
|
|
31252
31347
|
}
|
|
31253
31348
|
if (!s) return "";
|
|
31254
|
-
const abs =
|
|
31255
|
-
const resolvedCwd =
|
|
31256
|
-
const rel =
|
|
31257
|
-
if (rel === "" || !rel.startsWith("..") && !
|
|
31349
|
+
const abs = path50.isAbsolute(s) ? path50.normalize(s) : path50.resolve(cwd2, s);
|
|
31350
|
+
const resolvedCwd = path50.resolve(cwd2);
|
|
31351
|
+
const rel = path50.relative(resolvedCwd, abs);
|
|
31352
|
+
if (rel === "" || !rel.startsWith("..") && !path50.isAbsolute(rel)) {
|
|
31258
31353
|
return rel === "" ? "." : rel;
|
|
31259
31354
|
}
|
|
31260
|
-
const home =
|
|
31261
|
-
if (abs === home || abs.startsWith(home +
|
|
31355
|
+
const home = path50.normalize(os31.homedir());
|
|
31356
|
+
if (abs === home || abs.startsWith(home + path50.sep)) {
|
|
31262
31357
|
return "~" + abs.slice(home.length);
|
|
31263
31358
|
}
|
|
31264
|
-
return
|
|
31359
|
+
return path50.basename(abs);
|
|
31265
31360
|
}
|
|
31266
31361
|
|
|
31267
31362
|
// src/app/ui/components/FilePathLink.tsx
|
|
@@ -31271,7 +31366,7 @@ function FilePathLink({ filePath, children, cwd: cwd2 = process.cwd(), color })
|
|
|
31271
31366
|
if (!raw) {
|
|
31272
31367
|
return null;
|
|
31273
31368
|
}
|
|
31274
|
-
const abs =
|
|
31369
|
+
const abs = path51.isAbsolute(raw) ? path51.normalize(raw) : path51.resolve(cwd2, raw);
|
|
31275
31370
|
const href = pathToFileURL3(abs).href;
|
|
31276
31371
|
const label = formatPathForDisplay(abs, cwd2);
|
|
31277
31372
|
const text = typeof children === "string" ? children : label;
|
|
@@ -33906,13 +34001,13 @@ function EditToolDiffPanel({
|
|
|
33906
34001
|
newString,
|
|
33907
34002
|
replaceAll = false
|
|
33908
34003
|
}) {
|
|
33909
|
-
const
|
|
34004
|
+
const path60 = filePath.trim() || "unknown file";
|
|
33910
34005
|
const hasPreviewArgs = oldString !== void 0 && newString !== void 0;
|
|
33911
34006
|
const hasDiffText = diffText && diffText.trim().length > 0;
|
|
33912
34007
|
return /* @__PURE__ */ jsx43(Box_default, { flexDirection: "column", children: hasPreviewArgs ? /* @__PURE__ */ jsx43(Box_default, { marginTop: 0, children: /* @__PURE__ */ jsx43(
|
|
33913
34008
|
FileEditToolDiff,
|
|
33914
34009
|
{
|
|
33915
|
-
filePath:
|
|
34010
|
+
filePath: path60,
|
|
33916
34011
|
oldString,
|
|
33917
34012
|
newString,
|
|
33918
34013
|
replaceAll,
|
|
@@ -33950,7 +34045,7 @@ function renderToolUseMessage12({ args }) {
|
|
|
33950
34045
|
return /* @__PURE__ */ jsx44(Text, { color: BLUMA_TERMINAL.blue, children: p });
|
|
33951
34046
|
}
|
|
33952
34047
|
function renderToolHeader12({ args }) {
|
|
33953
|
-
const
|
|
34048
|
+
const path60 = args?.file_path ?? ".";
|
|
33954
34049
|
const oldText = typeof args?.old_string === "string" ? args.old_string : "";
|
|
33955
34050
|
const newText = typeof args?.new_string === "string" ? args.new_string : "";
|
|
33956
34051
|
const counts = countLineDiff(oldText, newText);
|
|
@@ -33960,7 +34055,7 @@ function renderToolHeader12({ args }) {
|
|
|
33960
34055
|
action,
|
|
33961
34056
|
/* @__PURE__ */ jsxs27(Text, { dimColor: true, children: [
|
|
33962
34057
|
" ",
|
|
33963
|
-
/* @__PURE__ */ jsx44(FilePathLink, { filePath:
|
|
34058
|
+
/* @__PURE__ */ jsx44(FilePathLink, { filePath: path60, color: BLUMA_TERMINAL.dim })
|
|
33964
34059
|
] })
|
|
33965
34060
|
] }),
|
|
33966
34061
|
/* @__PURE__ */ jsxs27(Text, { dimColor: true, children: [
|
|
@@ -34352,11 +34447,11 @@ function userFacingName13() {
|
|
|
34352
34447
|
}
|
|
34353
34448
|
function renderToolUseMessage14({ args }) {
|
|
34354
34449
|
const q = args?.query ? `"${args.query}"` : "...";
|
|
34355
|
-
const
|
|
34450
|
+
const path60 = args?.path || ".";
|
|
34356
34451
|
return /* @__PURE__ */ jsxs30(Box_default, { flexDirection: "row", flexWrap: "wrap", alignItems: "flex-end", children: [
|
|
34357
34452
|
/* @__PURE__ */ jsx47(Text, { color: BLUMA_TERMINAL.blue, children: q }),
|
|
34358
34453
|
/* @__PURE__ */ jsx47(Text, { color: BLUMA_TERMINAL.dim, children: " " }),
|
|
34359
|
-
/* @__PURE__ */ jsx47(FilePathLink, { filePath:
|
|
34454
|
+
/* @__PURE__ */ jsx47(FilePathLink, { filePath: path60, color: BLUMA_TERMINAL.dim })
|
|
34360
34455
|
] });
|
|
34361
34456
|
}
|
|
34362
34457
|
function renderToolHeader14({ args }) {
|
|
@@ -37836,7 +37931,7 @@ import {
|
|
|
37836
37931
|
// src/app/ui/hooks/useAtCompletion.ts
|
|
37837
37932
|
import { useEffect as useEffect11, useRef as useRef4, useState as useState13 } from "react";
|
|
37838
37933
|
import fs44 from "fs";
|
|
37839
|
-
import
|
|
37934
|
+
import path52 from "path";
|
|
37840
37935
|
var MAX_RESULTS3 = 50;
|
|
37841
37936
|
var DEFAULT_RECURSIVE_DEPTH = 2;
|
|
37842
37937
|
function listPathSuggestions(baseDir, pattern) {
|
|
@@ -37844,7 +37939,7 @@ function listPathSuggestions(baseDir, pattern) {
|
|
|
37844
37939
|
const patternEndsWithSlash = raw.endsWith("/");
|
|
37845
37940
|
const relDir = raw.replace(/^\/+|\/+$/g, "");
|
|
37846
37941
|
const filterPrefix = patternEndsWithSlash ? "" : relDir.split("/").slice(-1)[0] || "";
|
|
37847
|
-
const listDir =
|
|
37942
|
+
const listDir = path52.resolve(baseDir, relDir || ".");
|
|
37848
37943
|
const results = [];
|
|
37849
37944
|
const IGNORED_DIRS = ["node_modules", ".git", ".venv", "dist", "build"];
|
|
37850
37945
|
const IGNORED_EXTS = [".pyc", ".class", ".o", ".map", ".log", ".tmp"];
|
|
@@ -37861,7 +37956,7 @@ function listPathSuggestions(baseDir, pattern) {
|
|
|
37861
37956
|
}
|
|
37862
37957
|
function pushEntry(entryPath, label, isDir) {
|
|
37863
37958
|
if (results.length >= MAX_RESULTS3) return;
|
|
37864
|
-
const clean = label.split(
|
|
37959
|
+
const clean = label.split(path52.sep).join("/").replace(/[]+/g, "");
|
|
37865
37960
|
results.push({ label: clean + (isDir ? "/" : ""), fullPath: entryPath, isDir });
|
|
37866
37961
|
}
|
|
37867
37962
|
try {
|
|
@@ -37873,8 +37968,8 @@ function listPathSuggestions(baseDir, pattern) {
|
|
|
37873
37968
|
const entries = fs44.readdirSync(node.dir, { withFileTypes: true });
|
|
37874
37969
|
for (const entry of entries) {
|
|
37875
37970
|
if (isIgnoredName(entry.name)) continue;
|
|
37876
|
-
const entryAbs =
|
|
37877
|
-
const entryRel = node.rel ?
|
|
37971
|
+
const entryAbs = path52.join(node.dir, entry.name);
|
|
37972
|
+
const entryRel = node.rel ? path52.posix.join(node.rel, entry.name) : entry.name;
|
|
37878
37973
|
if (entryRel.split("/").includes("node_modules")) continue;
|
|
37879
37974
|
if (!entry.isDirectory() && isIgnoredFile(entry.name)) continue;
|
|
37880
37975
|
pushEntry(entryAbs, entryRel, entry.isDirectory());
|
|
@@ -37892,8 +37987,8 @@ function listPathSuggestions(baseDir, pattern) {
|
|
|
37892
37987
|
if (filterPrefix && !entry.name.startsWith(filterPrefix)) continue;
|
|
37893
37988
|
if (isIgnoredName(entry.name)) continue;
|
|
37894
37989
|
if (!entry.isDirectory() && isIgnoredFile(entry.name)) continue;
|
|
37895
|
-
const entryAbs =
|
|
37896
|
-
const label = relDir ?
|
|
37990
|
+
const entryAbs = path52.join(listDir, entry.name);
|
|
37991
|
+
const label = relDir ? path52.posix.join(relDir, entry.name) : entry.name;
|
|
37897
37992
|
pushEntry(entryAbs, label, entry.isDirectory());
|
|
37898
37993
|
if (results.length >= MAX_RESULTS3) break;
|
|
37899
37994
|
}
|
|
@@ -38096,7 +38191,7 @@ var SlashSubmenuInline = memo15(SlashSubmenuInlineComponent);
|
|
|
38096
38191
|
// src/app/ui/utils/clipboardImage.ts
|
|
38097
38192
|
import fs45 from "fs";
|
|
38098
38193
|
import os32 from "os";
|
|
38099
|
-
import
|
|
38194
|
+
import path53 from "path";
|
|
38100
38195
|
import { spawn as spawn5, execFile as execFileCb, execSync as execSync4 } from "child_process";
|
|
38101
38196
|
import { promisify as promisify2 } from "util";
|
|
38102
38197
|
|
|
@@ -38225,8 +38320,8 @@ function commandOnPath(cmd) {
|
|
|
38225
38320
|
function unixClipboardHelperDirs() {
|
|
38226
38321
|
const h = os32.homedir();
|
|
38227
38322
|
return [
|
|
38228
|
-
|
|
38229
|
-
|
|
38323
|
+
path53.join(h, ".local", "bin"),
|
|
38324
|
+
path53.join(h, "bin"),
|
|
38230
38325
|
"/usr/bin",
|
|
38231
38326
|
"/usr/local/bin",
|
|
38232
38327
|
"/bin",
|
|
@@ -38244,7 +38339,7 @@ function resolveHelperBinary(cmd) {
|
|
|
38244
38339
|
return cmd;
|
|
38245
38340
|
}
|
|
38246
38341
|
for (const dir of unixClipboardHelperDirs()) {
|
|
38247
|
-
const full =
|
|
38342
|
+
const full = path53.join(dir, cmd);
|
|
38248
38343
|
try {
|
|
38249
38344
|
fs45.accessSync(full, fs45.constants.X_OK);
|
|
38250
38345
|
return full;
|
|
@@ -38252,7 +38347,7 @@ function resolveHelperBinary(cmd) {
|
|
|
38252
38347
|
}
|
|
38253
38348
|
}
|
|
38254
38349
|
for (const dir of unixClipboardHelperDirs()) {
|
|
38255
|
-
const full =
|
|
38350
|
+
const full = path53.join(dir, cmd);
|
|
38256
38351
|
if (fs45.existsSync(full)) {
|
|
38257
38352
|
return full;
|
|
38258
38353
|
}
|
|
@@ -38294,7 +38389,7 @@ function writeBufferIfImage(baseDir, buf) {
|
|
|
38294
38389
|
if (!ext) {
|
|
38295
38390
|
return null;
|
|
38296
38391
|
}
|
|
38297
|
-
const out =
|
|
38392
|
+
const out = path53.join(
|
|
38298
38393
|
baseDir,
|
|
38299
38394
|
`clip-${Date.now()}-${Math.random().toString(36).slice(2, 8)}${ext}`
|
|
38300
38395
|
);
|
|
@@ -38333,9 +38428,9 @@ async function tryDarwinClipboardy(baseDir) {
|
|
|
38333
38428
|
if (st.size < 80 || st.size > CLIPBOARD_MAX_BYTES) {
|
|
38334
38429
|
continue;
|
|
38335
38430
|
}
|
|
38336
|
-
const ext =
|
|
38431
|
+
const ext = path53.extname(src).toLowerCase();
|
|
38337
38432
|
const safeExt = ext && /^\.(png|jpe?g|gif|webp)$/i.test(ext) ? ext : ".png";
|
|
38338
|
-
const out =
|
|
38433
|
+
const out = path53.join(
|
|
38339
38434
|
baseDir,
|
|
38340
38435
|
`clip-${Date.now()}-${Math.random().toString(36).slice(2, 8)}${safeExt}`
|
|
38341
38436
|
);
|
|
@@ -38353,7 +38448,7 @@ async function tryDarwinClipboardy(baseDir) {
|
|
|
38353
38448
|
return null;
|
|
38354
38449
|
}
|
|
38355
38450
|
async function tryWindowsPowerShell(outFile) {
|
|
38356
|
-
const ps = process.env.SystemRoot != null ?
|
|
38451
|
+
const ps = process.env.SystemRoot != null ? path53.join(
|
|
38357
38452
|
process.env.SystemRoot,
|
|
38358
38453
|
"System32",
|
|
38359
38454
|
"WindowsPowerShell",
|
|
@@ -38454,8 +38549,8 @@ function parseClipboardTextAsImagePath(raw) {
|
|
|
38454
38549
|
s = s.slice(1, -1);
|
|
38455
38550
|
}
|
|
38456
38551
|
s = s.trim();
|
|
38457
|
-
if (!CLIPBOARD_PATH_IMAGE_EXT.test(
|
|
38458
|
-
const abs =
|
|
38552
|
+
if (!CLIPBOARD_PATH_IMAGE_EXT.test(path53.extname(s))) return null;
|
|
38553
|
+
const abs = path53.isAbsolute(s) ? path53.normalize(s) : path53.resolve(process.cwd(), s);
|
|
38459
38554
|
return abs;
|
|
38460
38555
|
}
|
|
38461
38556
|
async function tryClipboardTextAsImageFile(baseDir) {
|
|
@@ -38475,8 +38570,8 @@ async function tryClipboardTextAsImageFile(baseDir) {
|
|
|
38475
38570
|
} catch {
|
|
38476
38571
|
return null;
|
|
38477
38572
|
}
|
|
38478
|
-
const ext =
|
|
38479
|
-
const out =
|
|
38573
|
+
const ext = path53.extname(abs).toLowerCase();
|
|
38574
|
+
const out = path53.join(
|
|
38480
38575
|
baseDir,
|
|
38481
38576
|
`clip-${Date.now()}-${Math.random().toString(36).slice(2, 8)}${ext}`
|
|
38482
38577
|
);
|
|
@@ -38491,7 +38586,7 @@ async function tryLinuxShellPipelineSave(baseDir) {
|
|
|
38491
38586
|
if (process.platform !== "linux" && process.platform !== "freebsd") {
|
|
38492
38587
|
return null;
|
|
38493
38588
|
}
|
|
38494
|
-
const outPath =
|
|
38589
|
+
const outPath = path53.join(
|
|
38495
38590
|
baseDir,
|
|
38496
38591
|
`clip-${Date.now()}-${Math.random().toString(36).slice(2, 8)}.tmp`
|
|
38497
38592
|
);
|
|
@@ -38549,7 +38644,7 @@ async function tryNativeClipboardImage() {
|
|
|
38549
38644
|
return null;
|
|
38550
38645
|
}
|
|
38551
38646
|
async function readClipboardImageToTempFile() {
|
|
38552
|
-
const baseDir =
|
|
38647
|
+
const baseDir = path53.join(os32.homedir(), ".cache", "bluma", "clipboard");
|
|
38553
38648
|
fs45.mkdirSync(baseDir, { recursive: true });
|
|
38554
38649
|
const nativeResult = await tryNativeClipboardImage();
|
|
38555
38650
|
if (nativeResult) {
|
|
@@ -38568,7 +38663,7 @@ async function readClipboardImageToTempFile() {
|
|
|
38568
38663
|
}
|
|
38569
38664
|
}
|
|
38570
38665
|
if (process.platform === "win32") {
|
|
38571
|
-
const outFile =
|
|
38666
|
+
const outFile = path53.join(
|
|
38572
38667
|
baseDir,
|
|
38573
38668
|
`clip-${Date.now()}-${Math.random().toString(36).slice(2, 8)}.png`
|
|
38574
38669
|
);
|
|
@@ -40944,7 +41039,7 @@ var renderSettingsEditUsage = () => {
|
|
|
40944
41039
|
|
|
40945
41040
|
// src/app/agent/core/thread/thread_store.ts
|
|
40946
41041
|
init_bluma_app_dir();
|
|
40947
|
-
import
|
|
41042
|
+
import path54 from "path";
|
|
40948
41043
|
import { promises as fs47 } from "fs";
|
|
40949
41044
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
40950
41045
|
var INDEX_VERSION = 1;
|
|
@@ -40970,9 +41065,9 @@ var ThreadStore = class {
|
|
|
40970
41065
|
packageVersion;
|
|
40971
41066
|
constructor() {
|
|
40972
41067
|
const appDir = getPreferredAppDir();
|
|
40973
|
-
this.threadsDir =
|
|
40974
|
-
this.archiveDir =
|
|
40975
|
-
this.indexPath =
|
|
41068
|
+
this.threadsDir = path54.join(appDir, "threads");
|
|
41069
|
+
this.archiveDir = path54.join(this.threadsDir, "archive");
|
|
41070
|
+
this.indexPath = path54.join(this.threadsDir, "index.json");
|
|
40976
41071
|
this.packageVersion = process.env.npm_package_version || "0.0.0";
|
|
40977
41072
|
}
|
|
40978
41073
|
// ==================== Inicialização ====================
|
|
@@ -41094,7 +41189,7 @@ var ThreadStore = class {
|
|
|
41094
41189
|
messages: params.initialMessages || []
|
|
41095
41190
|
};
|
|
41096
41191
|
const historyPath = this.buildDatedThreadHistoryPath(threadId);
|
|
41097
|
-
await fs47.mkdir(
|
|
41192
|
+
await fs47.mkdir(path54.dirname(historyPath), { recursive: true });
|
|
41098
41193
|
await this.saveHistoryAtPath(historyPath, history);
|
|
41099
41194
|
const index = await this.loadIndex();
|
|
41100
41195
|
index.threads.unshift({
|
|
@@ -41149,7 +41244,7 @@ var ThreadStore = class {
|
|
|
41149
41244
|
compressedSliceCount: source.history.compressedSliceCount
|
|
41150
41245
|
};
|
|
41151
41246
|
const historyPath = this.buildDatedThreadHistoryPath(newThreadId);
|
|
41152
|
-
await fs47.mkdir(
|
|
41247
|
+
await fs47.mkdir(path54.dirname(historyPath), { recursive: true });
|
|
41153
41248
|
await this.saveHistoryAtPath(historyPath, history);
|
|
41154
41249
|
const index = await this.loadIndex();
|
|
41155
41250
|
index.threads.unshift({
|
|
@@ -41222,7 +41317,7 @@ var ThreadStore = class {
|
|
|
41222
41317
|
const entry = index.threads[entryIndex];
|
|
41223
41318
|
if (entry.status === "archived") return true;
|
|
41224
41319
|
const oldPath = entry.historyPath || this.getLegacyHistoryPath(threadId);
|
|
41225
|
-
const newPath =
|
|
41320
|
+
const newPath = path54.join(this.archiveDir, `${threadId}.jsonl`);
|
|
41226
41321
|
try {
|
|
41227
41322
|
await fs47.rename(oldPath, newPath);
|
|
41228
41323
|
} catch (e) {
|
|
@@ -41245,9 +41340,9 @@ var ThreadStore = class {
|
|
|
41245
41340
|
if (entryIndex === -1) return false;
|
|
41246
41341
|
const entry = index.threads[entryIndex];
|
|
41247
41342
|
if (entry.status === "active") return true;
|
|
41248
|
-
const oldPath =
|
|
41343
|
+
const oldPath = path54.join(this.archiveDir, `${threadId}.jsonl`);
|
|
41249
41344
|
const newPath = this.buildDatedThreadHistoryPath(threadId);
|
|
41250
|
-
await fs47.mkdir(
|
|
41345
|
+
await fs47.mkdir(path54.dirname(newPath), { recursive: true });
|
|
41251
41346
|
try {
|
|
41252
41347
|
await fs47.rename(oldPath, newPath);
|
|
41253
41348
|
} catch (e) {
|
|
@@ -41280,14 +41375,14 @@ var ThreadStore = class {
|
|
|
41280
41375
|
}
|
|
41281
41376
|
// ==================== Histórico ====================
|
|
41282
41377
|
getLegacyHistoryPath(threadId) {
|
|
41283
|
-
return
|
|
41378
|
+
return path54.join(this.threadsDir, `${threadId}.jsonl`);
|
|
41284
41379
|
}
|
|
41285
41380
|
/** ~/.bluma/threads/YYYY/MM/DD/<threadId>.jsonl (data local de criação). */
|
|
41286
41381
|
buildDatedThreadHistoryPath(threadId, at = /* @__PURE__ */ new Date()) {
|
|
41287
41382
|
const y = String(at.getFullYear());
|
|
41288
41383
|
const mo = String(at.getMonth() + 1).padStart(2, "0");
|
|
41289
41384
|
const d = String(at.getDate()).padStart(2, "0");
|
|
41290
|
-
return
|
|
41385
|
+
return path54.join(this.threadsDir, y, mo, d, `${threadId}.jsonl`);
|
|
41291
41386
|
}
|
|
41292
41387
|
async resolveHistoryPath(threadId) {
|
|
41293
41388
|
const index = await this.loadIndex();
|
|
@@ -41318,7 +41413,7 @@ var ThreadStore = class {
|
|
|
41318
41413
|
for (const msg of history.messages) {
|
|
41319
41414
|
lines.push(JSON.stringify({ type: "message", ...msg }));
|
|
41320
41415
|
}
|
|
41321
|
-
await fs47.mkdir(
|
|
41416
|
+
await fs47.mkdir(path54.dirname(historyPath), { recursive: true }).catch(() => {
|
|
41322
41417
|
});
|
|
41323
41418
|
await fs47.writeFile(historyPath, lines.join("\n") + "\n", "utf-8");
|
|
41324
41419
|
}
|
|
@@ -43814,13 +43909,13 @@ import latestVersion from "latest-version";
|
|
|
43814
43909
|
import semverGt from "semver/functions/gt.js";
|
|
43815
43910
|
import semverValid from "semver/functions/valid.js";
|
|
43816
43911
|
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
43817
|
-
import
|
|
43912
|
+
import path56 from "path";
|
|
43818
43913
|
import fs49 from "fs";
|
|
43819
43914
|
var BLUMA_PACKAGE_NAME = "@nomad-e/bluma-cli";
|
|
43820
43915
|
function findBlumaPackageJson(startDir) {
|
|
43821
43916
|
let dir = startDir;
|
|
43822
43917
|
for (let i = 0; i < 12; i++) {
|
|
43823
|
-
const candidate =
|
|
43918
|
+
const candidate = path56.join(dir, "package.json");
|
|
43824
43919
|
if (fs49.existsSync(candidate)) {
|
|
43825
43920
|
try {
|
|
43826
43921
|
const raw = fs49.readFileSync(candidate, "utf8");
|
|
@@ -43831,7 +43926,7 @@ function findBlumaPackageJson(startDir) {
|
|
|
43831
43926
|
} catch {
|
|
43832
43927
|
}
|
|
43833
43928
|
}
|
|
43834
|
-
const parent =
|
|
43929
|
+
const parent = path56.dirname(dir);
|
|
43835
43930
|
if (parent === dir) break;
|
|
43836
43931
|
dir = parent;
|
|
43837
43932
|
}
|
|
@@ -43840,13 +43935,13 @@ function findBlumaPackageJson(startDir) {
|
|
|
43840
43935
|
function resolveInstalledBlumaPackage() {
|
|
43841
43936
|
const tried = /* @__PURE__ */ new Set();
|
|
43842
43937
|
const tryFrom = (dir) => {
|
|
43843
|
-
const abs =
|
|
43938
|
+
const abs = path56.resolve(dir);
|
|
43844
43939
|
if (tried.has(abs)) return null;
|
|
43845
43940
|
tried.add(abs);
|
|
43846
43941
|
return findBlumaPackageJson(abs);
|
|
43847
43942
|
};
|
|
43848
43943
|
try {
|
|
43849
|
-
const fromBundle = tryFrom(
|
|
43944
|
+
const fromBundle = tryFrom(path56.dirname(fileURLToPath7(import.meta.url)));
|
|
43850
43945
|
if (fromBundle) return fromBundle;
|
|
43851
43946
|
} catch {
|
|
43852
43947
|
}
|
|
@@ -43854,12 +43949,12 @@ function resolveInstalledBlumaPackage() {
|
|
|
43854
43949
|
if (argv1 && !argv1.startsWith("-")) {
|
|
43855
43950
|
try {
|
|
43856
43951
|
let resolved = argv1;
|
|
43857
|
-
if (
|
|
43952
|
+
if (path56.isAbsolute(argv1) && fs49.existsSync(argv1)) {
|
|
43858
43953
|
resolved = fs49.realpathSync(argv1);
|
|
43859
43954
|
} else {
|
|
43860
|
-
resolved =
|
|
43955
|
+
resolved = path56.resolve(process.cwd(), argv1);
|
|
43861
43956
|
}
|
|
43862
|
-
const fromArgv = tryFrom(
|
|
43957
|
+
const fromArgv = tryFrom(path56.dirname(resolved));
|
|
43863
43958
|
if (fromArgv) return fromArgv;
|
|
43864
43959
|
} catch {
|
|
43865
43960
|
}
|
|
@@ -44679,9 +44774,9 @@ function usePlanMode() {
|
|
|
44679
44774
|
// src/app/hooks/useAgentMode.ts
|
|
44680
44775
|
import { useState as useState22, useEffect as useEffect21, useCallback as useCallback9 } from "react";
|
|
44681
44776
|
import * as fs50 from "fs";
|
|
44682
|
-
import * as
|
|
44777
|
+
import * as path57 from "path";
|
|
44683
44778
|
import { homedir as homedir4 } from "os";
|
|
44684
|
-
var SETTINGS_PATH =
|
|
44779
|
+
var SETTINGS_PATH = path57.join(homedir4(), ".bluma", "settings.json");
|
|
44685
44780
|
function readAgentModeFromFile() {
|
|
44686
44781
|
try {
|
|
44687
44782
|
if (!fs50.existsSync(SETTINGS_PATH)) {
|
|
@@ -44707,7 +44802,7 @@ function useAgentMode() {
|
|
|
44707
44802
|
const updateAgentMode = useCallback9((mode) => {
|
|
44708
44803
|
try {
|
|
44709
44804
|
if (!fs50.existsSync(SETTINGS_PATH)) {
|
|
44710
|
-
fs50.mkdirSync(
|
|
44805
|
+
fs50.mkdirSync(path57.dirname(SETTINGS_PATH), { recursive: true });
|
|
44711
44806
|
}
|
|
44712
44807
|
let settings = {};
|
|
44713
44808
|
if (fs50.existsSync(SETTINGS_PATH)) {
|
|
@@ -44839,7 +44934,6 @@ function ScrollBox({
|
|
|
44839
44934
|
// notify/scrollMutated are inline (no useCallback) but only close over
|
|
44840
44935
|
// refs + imports — stable. Empty deps avoids rebuilding the handle on
|
|
44841
44936
|
// every render (which re-registers the ref = churn).
|
|
44842
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
44843
44937
|
[]
|
|
44844
44938
|
);
|
|
44845
44939
|
return /* @__PURE__ */ jsx103("ink-box", { ref: (el) => {
|
|
@@ -45980,10 +46074,10 @@ import { memo as memo26, useCallback as useCallback11, useEffect as useEffect23,
|
|
|
45980
46074
|
|
|
45981
46075
|
// src/app/agent/session_manager/session_resume_browser.ts
|
|
45982
46076
|
init_bluma_app_dir();
|
|
45983
|
-
import
|
|
46077
|
+
import path58 from "path";
|
|
45984
46078
|
import { promises as fs51 } from "fs";
|
|
45985
46079
|
function getSessionsRoot() {
|
|
45986
|
-
return
|
|
46080
|
+
return path58.join(getPreferredAppDir(), "sessions");
|
|
45987
46081
|
}
|
|
45988
46082
|
function normalizeSessionsCwd(cwd2) {
|
|
45989
46083
|
return cwd2.replace(/\\/g, "/").split("/").filter((p) => p && p !== "." && p !== "..").join("/");
|
|
@@ -46034,7 +46128,7 @@ function compareDirNames(a, b) {
|
|
|
46034
46128
|
async function listSessionBrowserEntries(cwdRel) {
|
|
46035
46129
|
const cwd2 = normalizeSessionsCwd(cwdRel);
|
|
46036
46130
|
const root = getSessionsRoot();
|
|
46037
|
-
const absDir = cwd2 ?
|
|
46131
|
+
const absDir = cwd2 ? path58.join(root, ...cwd2.split("/")) : root;
|
|
46038
46132
|
const out = [];
|
|
46039
46133
|
if (cwd2) {
|
|
46040
46134
|
out.push({ kind: "up", label: ".." });
|
|
@@ -46051,7 +46145,7 @@ async function listSessionBrowserEntries(cwdRel) {
|
|
|
46051
46145
|
for (const e of dirents) {
|
|
46052
46146
|
const name = String(e.name);
|
|
46053
46147
|
if (name.startsWith(".")) continue;
|
|
46054
|
-
const full =
|
|
46148
|
+
const full = path58.join(absDir, name);
|
|
46055
46149
|
if (e.isDirectory()) {
|
|
46056
46150
|
dirNames.push(name);
|
|
46057
46151
|
} else if (e.isFile() && name.endsWith(".json") && !name.includes(".tmp")) {
|
|
@@ -46061,7 +46155,7 @@ async function listSessionBrowserEntries(cwdRel) {
|
|
|
46061
46155
|
dirNames.sort(compareDirNames);
|
|
46062
46156
|
const sessions = [];
|
|
46063
46157
|
for (const { name, full } of sessionFiles) {
|
|
46064
|
-
const sessionId =
|
|
46158
|
+
const sessionId = path58.basename(name, ".json");
|
|
46065
46159
|
sessions.push(await sessionEntryFromFile(full, sessionId));
|
|
46066
46160
|
}
|
|
46067
46161
|
sessions.sort((a, b) => {
|
|
@@ -46669,8 +46763,8 @@ async function runAgentMode() {
|
|
|
46669
46763
|
}
|
|
46670
46764
|
function readCliPackageVersion() {
|
|
46671
46765
|
try {
|
|
46672
|
-
const base =
|
|
46673
|
-
const pkgPath =
|
|
46766
|
+
const base = path59.dirname(fileURLToPath8(import.meta.url));
|
|
46767
|
+
const pkgPath = path59.join(base, "..", "package.json");
|
|
46674
46768
|
const j = JSON.parse(fs52.readFileSync(pkgPath, "utf8"));
|
|
46675
46769
|
return String(j.version || "0.0.0");
|
|
46676
46770
|
} catch {
|