@nomad-e/bluma-cli 0.26.0 → 0.26.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main.js +107 -115
- package/package.json +1 -3
package/dist/main.js
CHANGED
|
@@ -2616,17 +2616,22 @@ var init_CtxInspectTool = __esm({
|
|
|
2616
2616
|
import path32 from "path";
|
|
2617
2617
|
import { mkdirSync as mkdirSync3 } from "fs";
|
|
2618
2618
|
import { promises as fs27 } from "fs";
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
const nodeRequire = createRequire(import.meta.url);
|
|
2622
|
-
return nodeRequire("better-sqlite3");
|
|
2623
|
-
}
|
|
2624
|
-
function getSessionDbPath(appDir = getPreferredAppDir()) {
|
|
2625
|
-
return path32.join(appDir, BLUMA_SESSION_DB_FILE);
|
|
2619
|
+
function getSessionIndexPath(appDir = getPreferredAppDir()) {
|
|
2620
|
+
return path32.join(appDir, SESSION_INDEX_FILE);
|
|
2626
2621
|
}
|
|
2627
2622
|
function normalizeRelativePath(relativePath) {
|
|
2628
2623
|
return relativePath.split(path32.sep).join("/");
|
|
2629
2624
|
}
|
|
2625
|
+
function emptyStore() {
|
|
2626
|
+
return { version: 1, sessions: {} };
|
|
2627
|
+
}
|
|
2628
|
+
async function persistStore(store2, appDir) {
|
|
2629
|
+
mkdirSync3(appDir, { recursive: true });
|
|
2630
|
+
const filePath = getSessionIndexPath(appDir);
|
|
2631
|
+
const tmp = `${filePath}.${Date.now()}.tmp`;
|
|
2632
|
+
await fs27.writeFile(tmp, JSON.stringify(store2, null, 2), "utf-8");
|
|
2633
|
+
await fs27.rename(tmp, filePath);
|
|
2634
|
+
}
|
|
2630
2635
|
async function walkSessionJsonFiles(dir, onFile) {
|
|
2631
2636
|
let entries;
|
|
2632
2637
|
try {
|
|
@@ -2707,22 +2712,30 @@ async function readSessionMetaFromJson(absPath) {
|
|
|
2707
2712
|
}
|
|
2708
2713
|
}
|
|
2709
2714
|
}
|
|
2710
|
-
|
|
2715
|
+
function upsertIntoStore(store2, row) {
|
|
2716
|
+
const rel = normalizeRelativePath(row.relativePath);
|
|
2717
|
+
const existing = store2.sessions[row.sessionId];
|
|
2718
|
+
if (!existing) {
|
|
2719
|
+
store2.sessions[row.sessionId] = {
|
|
2720
|
+
relativePath: rel,
|
|
2721
|
+
createdAt: row.createdAt,
|
|
2722
|
+
updatedAt: row.updatedAt,
|
|
2723
|
+
preview: row.preview
|
|
2724
|
+
};
|
|
2725
|
+
return;
|
|
2726
|
+
}
|
|
2727
|
+
const existingMs = Date.parse(existing.updatedAt);
|
|
2728
|
+
const incomingMs = Date.parse(row.updatedAt);
|
|
2729
|
+
const incomingIsNewer = Number.isFinite(incomingMs) && incomingMs >= (Number.isFinite(existingMs) ? existingMs : 0);
|
|
2730
|
+
store2.sessions[row.sessionId] = {
|
|
2731
|
+
relativePath: incomingIsNewer ? rel : existing.relativePath,
|
|
2732
|
+
createdAt: existing.createdAt || row.createdAt,
|
|
2733
|
+
updatedAt: incomingIsNewer ? row.updatedAt : existing.updatedAt,
|
|
2734
|
+
preview: incomingIsNewer ? row.preview : existing.preview
|
|
2735
|
+
};
|
|
2736
|
+
}
|
|
2737
|
+
async function migrateLegacyIndex(store2, appDir) {
|
|
2711
2738
|
const jsonl = await loadJsonlEntries(appDir);
|
|
2712
|
-
const upsert = db.prepare(`
|
|
2713
|
-
INSERT INTO agent_sessions (session_id, relative_path, created_at, updated_at, preview)
|
|
2714
|
-
VALUES (@sessionId, @relativePath, @createdAt, @updatedAt, @preview)
|
|
2715
|
-
ON CONFLICT(session_id) DO UPDATE SET
|
|
2716
|
-
relative_path = excluded.relative_path,
|
|
2717
|
-
updated_at = CASE
|
|
2718
|
-
WHEN excluded.updated_at > agent_sessions.updated_at THEN excluded.updated_at
|
|
2719
|
-
ELSE agent_sessions.updated_at
|
|
2720
|
-
END,
|
|
2721
|
-
preview = CASE
|
|
2722
|
-
WHEN excluded.updated_at > agent_sessions.updated_at THEN excluded.preview
|
|
2723
|
-
ELSE agent_sessions.preview
|
|
2724
|
-
END
|
|
2725
|
-
`);
|
|
2726
2739
|
const insertFromPath = async (sessionId, absPath, jsonlUpdatedAt) => {
|
|
2727
2740
|
let rel;
|
|
2728
2741
|
try {
|
|
@@ -2732,7 +2745,7 @@ async function runMigrationV1(db, appDir) {
|
|
|
2732
2745
|
}
|
|
2733
2746
|
const meta = await readSessionMetaFromJson(absPath);
|
|
2734
2747
|
const updatedAt = jsonlUpdatedAt && Date.parse(jsonlUpdatedAt) > Date.parse(meta.updatedAt) ? jsonlUpdatedAt : meta.updatedAt;
|
|
2735
|
-
|
|
2748
|
+
upsertIntoStore(store2, {
|
|
2736
2749
|
sessionId,
|
|
2737
2750
|
relativePath: rel,
|
|
2738
2751
|
createdAt: meta.createdAt,
|
|
@@ -2746,7 +2759,7 @@ async function runMigrationV1(db, appDir) {
|
|
|
2746
2759
|
await fs27.access(full);
|
|
2747
2760
|
await insertFromPath(sessionId, full, entry.updatedAt);
|
|
2748
2761
|
} catch {
|
|
2749
|
-
|
|
2762
|
+
upsertIntoStore(store2, {
|
|
2750
2763
|
sessionId,
|
|
2751
2764
|
relativePath: entry.relativePath,
|
|
2752
2765
|
createdAt: entry.updatedAt,
|
|
@@ -2756,109 +2769,74 @@ async function runMigrationV1(db, appDir) {
|
|
|
2756
2769
|
}
|
|
2757
2770
|
}
|
|
2758
2771
|
const sessionsRoot = path32.join(appDir, "sessions");
|
|
2759
|
-
const existing = db.prepare("SELECT session_id FROM agent_sessions").all();
|
|
2760
|
-
const seen = new Set(existing.map((r) => r.session_id));
|
|
2761
2772
|
await walkSessionJsonFiles(sessionsRoot, async (absPath) => {
|
|
2762
2773
|
const sessionId = path32.basename(absPath, ".json");
|
|
2763
|
-
if (!sessionId ||
|
|
2764
|
-
seen.add(sessionId);
|
|
2774
|
+
if (!sessionId || store2.sessions[sessionId]) return;
|
|
2765
2775
|
await insertFromPath(sessionId, absPath);
|
|
2766
2776
|
});
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
CREATE INDEX IF NOT EXISTS idx_agent_sessions_updated
|
|
2779
|
-
ON agent_sessions(updated_at DESC);
|
|
2780
|
-
`);
|
|
2777
|
+
}
|
|
2778
|
+
async function loadStoreFromDisk(appDir) {
|
|
2779
|
+
try {
|
|
2780
|
+
const raw = await fs27.readFile(getSessionIndexPath(appDir), "utf-8");
|
|
2781
|
+
const parsed = JSON.parse(raw);
|
|
2782
|
+
if (parsed.version === 1 && parsed.sessions && typeof parsed.sessions === "object") {
|
|
2783
|
+
return { version: 1, sessions: { ...parsed.sessions } };
|
|
2784
|
+
}
|
|
2785
|
+
} catch {
|
|
2786
|
+
}
|
|
2787
|
+
return emptyStore();
|
|
2781
2788
|
}
|
|
2782
2789
|
async function ensureSessionIndexDb(appDir = getPreferredAppDir()) {
|
|
2783
|
-
if (
|
|
2784
|
-
return
|
|
2790
|
+
if (storeCache && storeAppDir === appDir) {
|
|
2791
|
+
return;
|
|
2785
2792
|
}
|
|
2786
|
-
if (!
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2793
|
+
if (!loadPromise || storeAppDir !== appDir) {
|
|
2794
|
+
loadPromise = (async () => {
|
|
2795
|
+
const store2 = await loadStoreFromDisk(appDir);
|
|
2796
|
+
if (Object.keys(store2.sessions).length === 0) {
|
|
2797
|
+
await migrateLegacyIndex(store2, appDir);
|
|
2798
|
+
if (Object.keys(store2.sessions).length > 0) {
|
|
2799
|
+
await persistStore(store2, appDir);
|
|
2792
2800
|
}
|
|
2793
|
-
dbInstance = null;
|
|
2794
|
-
}
|
|
2795
|
-
const BetterSqlite3 = loadSqlite();
|
|
2796
|
-
const dbPath = getSessionDbPath(appDir);
|
|
2797
|
-
mkdirSync3(path32.dirname(dbPath), { recursive: true });
|
|
2798
|
-
const db = new BetterSqlite3(dbPath);
|
|
2799
|
-
db.pragma("journal_mode = WAL");
|
|
2800
|
-
applySchema(db);
|
|
2801
|
-
const version = db.pragma("user_version", { simple: true });
|
|
2802
|
-
if (version < SCHEMA_VERSION) {
|
|
2803
|
-
await runMigrationV1(db, appDir);
|
|
2804
2801
|
}
|
|
2805
|
-
|
|
2806
|
-
|
|
2802
|
+
storeCache = store2;
|
|
2803
|
+
storeAppDir = appDir;
|
|
2807
2804
|
})();
|
|
2808
2805
|
}
|
|
2809
|
-
await
|
|
2810
|
-
return dbInstance;
|
|
2806
|
+
await loadPromise;
|
|
2811
2807
|
}
|
|
2812
2808
|
async function upsertSessionIndexRow(row, appDir = getPreferredAppDir()) {
|
|
2813
|
-
|
|
2814
|
-
const
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
ON CONFLICT(session_id) DO UPDATE SET
|
|
2818
|
-
relative_path = excluded.relative_path,
|
|
2819
|
-
updated_at = excluded.updated_at,
|
|
2820
|
-
preview = excluded.preview
|
|
2821
|
-
`);
|
|
2822
|
-
stmt.run({
|
|
2823
|
-
sessionId: row.sessionId,
|
|
2824
|
-
relativePath: normalizeRelativePath(row.relativePath),
|
|
2825
|
-
createdAt: row.createdAt,
|
|
2826
|
-
updatedAt: row.updatedAt,
|
|
2827
|
-
preview: row.preview
|
|
2828
|
-
});
|
|
2809
|
+
await ensureSessionIndexDb(appDir);
|
|
2810
|
+
const store2 = storeCache;
|
|
2811
|
+
upsertIntoStore(store2, row);
|
|
2812
|
+
await persistStore(store2, appDir);
|
|
2829
2813
|
}
|
|
2830
2814
|
async function getSessionPathFromIndex(sessionId, appDir = getPreferredAppDir()) {
|
|
2831
|
-
|
|
2832
|
-
const
|
|
2833
|
-
return
|
|
2815
|
+
await ensureSessionIndexDb(appDir);
|
|
2816
|
+
const entry = storeCache?.sessions[sessionId];
|
|
2817
|
+
return entry?.relativePath?.replace(/\//g, path32.sep) ?? null;
|
|
2834
2818
|
}
|
|
2835
2819
|
async function listSessionsFromIndex(limit = 50, appDir = getPreferredAppDir()) {
|
|
2836
|
-
|
|
2837
|
-
const
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
relativePath: r.relative_path.replace(/\//g, path32.sep),
|
|
2846
|
-
createdAt: r.created_at,
|
|
2847
|
-
updatedAt: r.updated_at,
|
|
2848
|
-
preview: r.preview
|
|
2849
|
-
}));
|
|
2820
|
+
await ensureSessionIndexDb(appDir);
|
|
2821
|
+
const sessions = storeCache?.sessions ?? {};
|
|
2822
|
+
return Object.entries(sessions).map(([sessionId, row]) => ({
|
|
2823
|
+
sessionId,
|
|
2824
|
+
relativePath: row.relativePath.replace(/\//g, path32.sep),
|
|
2825
|
+
createdAt: row.createdAt,
|
|
2826
|
+
updatedAt: row.updatedAt,
|
|
2827
|
+
preview: row.preview
|
|
2828
|
+
})).sort((a, b) => Date.parse(b.updatedAt) - Date.parse(a.updatedAt)).slice(0, limit);
|
|
2850
2829
|
}
|
|
2851
|
-
var AGENT_SESSION_PATHS_JSONL,
|
|
2830
|
+
var AGENT_SESSION_PATHS_JSONL, SESSION_INDEX_FILE, storeCache, storeAppDir, loadPromise;
|
|
2852
2831
|
var init_session_index_db = __esm({
|
|
2853
2832
|
"src/app/agent/session_manager/session_index_db.ts"() {
|
|
2854
2833
|
"use strict";
|
|
2855
2834
|
init_bluma_app_dir();
|
|
2856
2835
|
AGENT_SESSION_PATHS_JSONL = "agent_session_paths.jsonl";
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
migratePromise = null;
|
|
2836
|
+
SESSION_INDEX_FILE = "session_index.json";
|
|
2837
|
+
storeCache = null;
|
|
2838
|
+
storeAppDir = null;
|
|
2839
|
+
loadPromise = null;
|
|
2862
2840
|
}
|
|
2863
2841
|
});
|
|
2864
2842
|
|
|
@@ -25733,6 +25711,9 @@ function resolveReasoningEffortForRequest(params, runtimeConfig = getRuntimeConf
|
|
|
25733
25711
|
}
|
|
25734
25712
|
return effort;
|
|
25735
25713
|
}
|
|
25714
|
+
function isReasoningEnabledForRequest(params, runtimeConfig = getRuntimeConfig()) {
|
|
25715
|
+
return resolveReasoningEffortForRequest(params, runtimeConfig) !== void 0;
|
|
25716
|
+
}
|
|
25736
25717
|
function buildChatCompletionRequestBody(params, runtimeConfig = getRuntimeConfig(), stream = false, options) {
|
|
25737
25718
|
const tools = params.tools;
|
|
25738
25719
|
const hasTools = Array.isArray(tools) && tools.length > 0;
|
|
@@ -26090,15 +26071,19 @@ var LLMService = class {
|
|
|
26090
26071
|
}
|
|
26091
26072
|
const toolCallsAccumulator = /* @__PURE__ */ new Map();
|
|
26092
26073
|
let reasoningSnapshot = "";
|
|
26074
|
+
const reasoningEnabled = isReasoningEnabledForRequest(params, runtimeConfig);
|
|
26093
26075
|
for await (const chunk of stream) {
|
|
26094
26076
|
const choice = chunk.choices[0];
|
|
26095
26077
|
if (!choice) continue;
|
|
26096
26078
|
const delta = choice.delta;
|
|
26097
26079
|
applyDeltaToolCallsToAccumulator(toolCallsAccumulator, delta?.tool_calls);
|
|
26098
|
-
|
|
26099
|
-
|
|
26100
|
-
|
|
26101
|
-
reasoningSnapshot
|
|
26080
|
+
let reasoning = "";
|
|
26081
|
+
if (reasoningEnabled) {
|
|
26082
|
+
const rawReasoning = delta?.reasoning_content || delta?.reasoning || "";
|
|
26083
|
+
reasoning = extractStreamingDelta(reasoningSnapshot, rawReasoning);
|
|
26084
|
+
if (reasoning) {
|
|
26085
|
+
reasoningSnapshot += reasoning;
|
|
26086
|
+
}
|
|
26102
26087
|
}
|
|
26103
26088
|
const fullToolCalls = choice.finish_reason === "tool_calls" ? Array.from(toolCallsAccumulator.values()) : void 0;
|
|
26104
26089
|
yield {
|
|
@@ -27824,20 +27809,23 @@ var BluMaTurnCoordinator = class {
|
|
|
27824
27809
|
let toolCalls;
|
|
27825
27810
|
let hasEmittedStart = false;
|
|
27826
27811
|
let currentStreamPhase = "idle";
|
|
27827
|
-
const
|
|
27812
|
+
const llmUserContext = this.deps.getLlmUserContext();
|
|
27813
|
+
const streamParams = {
|
|
27828
27814
|
messages: contextWindow,
|
|
27829
27815
|
temperature: 0,
|
|
27830
27816
|
tools: this.deps.mcpClient.getAvailableTools(),
|
|
27831
27817
|
parallel_tool_calls: true,
|
|
27832
|
-
userContext:
|
|
27833
|
-
}
|
|
27818
|
+
userContext: llmUserContext
|
|
27819
|
+
};
|
|
27820
|
+
const reasoningEnabled = isReasoningEnabledForRequest(streamParams);
|
|
27821
|
+
const stream = llmService.chatCompletionStream(streamParams);
|
|
27834
27822
|
for await (const chunk of stream) {
|
|
27835
27823
|
if (this.deps.isInterrupted()) {
|
|
27836
27824
|
this.deps.eventBus.emit("stream_end", {});
|
|
27837
27825
|
this.deps.eventBus.emit("backend_message", { type: "info", message: "Agent task cancelled by user." });
|
|
27838
27826
|
return;
|
|
27839
27827
|
}
|
|
27840
|
-
if (chunk.reasoning) {
|
|
27828
|
+
if (chunk.reasoning && reasoningEnabled) {
|
|
27841
27829
|
if (!hasEmittedStart) {
|
|
27842
27830
|
this.deps.eventBus.emit("stream_start", {});
|
|
27843
27831
|
hasEmittedStart = true;
|
|
@@ -27958,7 +27946,11 @@ var BluMaTurnCoordinator = class {
|
|
|
27958
27946
|
}
|
|
27959
27947
|
let message2 = response.choices[0].message;
|
|
27960
27948
|
message2 = ToolCallNormalizer.normalizeAssistantMessage(message2);
|
|
27961
|
-
|
|
27949
|
+
const reasoningEnabled = isReasoningEnabledForRequest({
|
|
27950
|
+
messages: contextWindow,
|
|
27951
|
+
userContext: this.deps.getLlmUserContext()
|
|
27952
|
+
});
|
|
27953
|
+
if (reasoningEnabled && (message2.reasoning_content || message2.reasoning)) {
|
|
27962
27954
|
const reasoningText = message2.reasoning_content || message2.reasoning;
|
|
27963
27955
|
this.deps.eventBus.emit("backend_message", {
|
|
27964
27956
|
type: "reasoning",
|
|
@@ -39031,7 +39023,7 @@ import { promisify as promisify2 } from "util";
|
|
|
39031
39023
|
|
|
39032
39024
|
// src/app/utils/clipboardNative.ts
|
|
39033
39025
|
import { existsSync as existsSync7 } from "fs";
|
|
39034
|
-
import { createRequire
|
|
39026
|
+
import { createRequire } from "module";
|
|
39035
39027
|
import { dirname as dirname4, join as join13 } from "path";
|
|
39036
39028
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
39037
39029
|
var __dirname;
|
|
@@ -39079,7 +39071,7 @@ function getNativeModule() {
|
|
|
39079
39071
|
throw loadError;
|
|
39080
39072
|
}
|
|
39081
39073
|
try {
|
|
39082
|
-
const require2 =
|
|
39074
|
+
const require2 = createRequire(import.meta.url);
|
|
39083
39075
|
const mod = require2(nativePath);
|
|
39084
39076
|
nativeModule = mod;
|
|
39085
39077
|
return nativeModule;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nomad-e/bluma-cli",
|
|
3
|
-
"version": "0.26.
|
|
3
|
+
"version": "0.26.3",
|
|
4
4
|
"description": "BluMa independent agent for automation and advanced software engineering.",
|
|
5
5
|
"author": "Alex Fonseca",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
"@babel/preset-env": "^7.28.0",
|
|
12
12
|
"@babel/preset-react": "^7.27.1",
|
|
13
13
|
"@babel/preset-typescript": "^7.27.1",
|
|
14
|
-
"@types/better-sqlite3": "^7.6.13",
|
|
15
14
|
"@types/diff": "^7.0.2",
|
|
16
15
|
"@types/glob": "^8.1.0",
|
|
17
16
|
"@types/jest": "^30.0.0",
|
|
@@ -75,7 +74,6 @@
|
|
|
75
74
|
"@types/react-dom": "^19.2.3",
|
|
76
75
|
"auto-bind": "^5.0.1",
|
|
77
76
|
"axios": "^1.16.0",
|
|
78
|
-
"better-sqlite3": "^11.10.0",
|
|
79
77
|
"bidi-js": "^1.0.3",
|
|
80
78
|
"chalk": "^5.5.0",
|
|
81
79
|
"class-variance-authority": "^0.7.1",
|