@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.
Files changed (2) hide show
  1. package/dist/main.js +107 -115
  2. 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
- import { createRequire } from "module";
2620
- function loadSqlite() {
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
- async function runMigrationV1(db, appDir) {
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
- upsert.run({
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
- upsert.run({
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 || seen.has(sessionId)) return;
2764
- seen.add(sessionId);
2774
+ if (!sessionId || store2.sessions[sessionId]) return;
2765
2775
  await insertFromPath(sessionId, absPath);
2766
2776
  });
2767
- db.pragma(`user_version = ${SCHEMA_VERSION}`);
2768
- }
2769
- function applySchema(db) {
2770
- db.exec(`
2771
- CREATE TABLE IF NOT EXISTS agent_sessions (
2772
- session_id TEXT PRIMARY KEY NOT NULL,
2773
- relative_path TEXT NOT NULL,
2774
- created_at TEXT NOT NULL,
2775
- updated_at TEXT NOT NULL,
2776
- preview TEXT NOT NULL DEFAULT '(no messages)'
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 (dbInstance && dbAppDir === appDir) {
2784
- return dbInstance;
2790
+ if (storeCache && storeAppDir === appDir) {
2791
+ return;
2785
2792
  }
2786
- if (!migratePromise || dbAppDir !== appDir) {
2787
- migratePromise = (async () => {
2788
- if (dbInstance) {
2789
- try {
2790
- dbInstance.close();
2791
- } catch {
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
- dbInstance = db;
2806
- dbAppDir = appDir;
2802
+ storeCache = store2;
2803
+ storeAppDir = appDir;
2807
2804
  })();
2808
2805
  }
2809
- await migratePromise;
2810
- return dbInstance;
2806
+ await loadPromise;
2811
2807
  }
2812
2808
  async function upsertSessionIndexRow(row, appDir = getPreferredAppDir()) {
2813
- const db = await ensureSessionIndexDb(appDir);
2814
- const stmt = db.prepare(`
2815
- INSERT INTO agent_sessions (session_id, relative_path, created_at, updated_at, preview)
2816
- VALUES (@sessionId, @relativePath, @createdAt, @updatedAt, @preview)
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
- const db = await ensureSessionIndexDb(appDir);
2832
- const row = db.prepare("SELECT relative_path FROM agent_sessions WHERE session_id = ?").get(sessionId);
2833
- return row?.relative_path?.replace(/\//g, path32.sep) ?? null;
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
- const db = await ensureSessionIndexDb(appDir);
2837
- const rows = db.prepare(
2838
- `SELECT session_id, relative_path, created_at, updated_at, preview
2839
- FROM agent_sessions
2840
- ORDER BY updated_at DESC
2841
- LIMIT ?`
2842
- ).all(limit);
2843
- return rows.map((r) => ({
2844
- sessionId: r.session_id,
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, BLUMA_SESSION_DB_FILE, SCHEMA_VERSION, dbInstance, dbAppDir, migratePromise;
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
- BLUMA_SESSION_DB_FILE = "bluma.sqlite";
2858
- SCHEMA_VERSION = 1;
2859
- dbInstance = null;
2860
- dbAppDir = null;
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
- const rawReasoning = delta?.reasoning_content || delta?.reasoning || "";
26099
- const reasoning = extractStreamingDelta(reasoningSnapshot, rawReasoning);
26100
- if (reasoning) {
26101
- reasoningSnapshot += reasoning;
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 stream = llmService.chatCompletionStream({
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: this.deps.getLlmUserContext()
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
- if (message2.reasoning_content || message2.reasoning) {
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 as createRequire2 } from "module";
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 = createRequire2(import.meta.url);
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.0",
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",