conare 0.5.10 → 0.5.12

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/index.js +257 -67
  2. package/package.json +5 -2
package/dist/index.js CHANGED
@@ -693,7 +693,7 @@ var init_api = __esm(() => {
693
693
  };
694
694
  });
695
695
 
696
- // ../node_modules/sisteransi/src/index.js
696
+ // node_modules/sisteransi/src/index.js
697
697
  var require_src = __commonJS((exports, module) => {
698
698
  var ESC = "\x1B";
699
699
  var CSI = `${ESC}[`;
@@ -751,7 +751,7 @@ var require_src = __commonJS((exports, module) => {
751
751
  module.exports = { cursor, scroll, erase, beep };
752
752
  });
753
753
 
754
- // ../node_modules/picocolors/picocolors.js
754
+ // node_modules/picocolors/picocolors.js
755
755
  var require_picocolors = __commonJS((exports, module) => {
756
756
  var p = process || {};
757
757
  var argv = p.argv || [];
@@ -821,7 +821,7 @@ var require_picocolors = __commonJS((exports, module) => {
821
821
  module.exports.createColors = createColors;
822
822
  });
823
823
 
824
- // ../node_modules/@clack/core/dist/index.mjs
824
+ // node_modules/@clack/core/dist/index.mjs
825
825
  import { stdin as j, stdout as M } from "node:process";
826
826
  import * as g from "node:readline";
827
827
  import O from "node:readline";
@@ -1357,7 +1357,7 @@ var init_dist = __esm(() => {
1357
1357
  };
1358
1358
  });
1359
1359
 
1360
- // ../node_modules/@clack/prompts/dist/index.mjs
1360
+ // node_modules/@clack/prompts/dist/index.mjs
1361
1361
  var exports_dist = {};
1362
1362
  __export(exports_dist, {
1363
1363
  updateSettings: () => cD,
@@ -1789,7 +1789,9 @@ var exports_interactive = {};
1789
1789
  __export(exports_interactive, {
1790
1790
  startSetup: () => startSetup,
1791
1791
  spinner: () => Y2,
1792
+ showLocalChatsCounted: () => showLocalChatsCounted,
1792
1793
  showDetectedApps: () => showDetectedApps,
1794
+ showCountingLocalChats: () => showCountingLocalChats,
1793
1795
  selectMcpTargets: () => selectMcpTargets,
1794
1796
  selectChatSources: () => selectChatSources,
1795
1797
  promptAuth: () => promptAuth,
@@ -1819,6 +1821,12 @@ function showDetectedApps(targets) {
1819
1821
  Me(targets.map((target) => `• ${target.label}: ${target.available === false ? "not detected" : formatDetectedCount(target.detectedCount, target.detectedCountApproximate)}`).join(`
1820
1822
  `), "Detected apps");
1821
1823
  }
1824
+ function showCountingLocalChats() {
1825
+ M2.step("Counting local chats...");
1826
+ }
1827
+ function showLocalChatsCounted() {
1828
+ M2.success("Local chats counted");
1829
+ }
1822
1830
  async function promptApiKey(options) {
1823
1831
  if (options.providedApiKey) {
1824
1832
  return options.providedApiKey;
@@ -1875,7 +1883,7 @@ async function promptAuth(options) {
1875
1883
  }
1876
1884
  async function selectChatSources(targets) {
1877
1885
  return ensureValue(await fe({
1878
- message: "Select chat sources",
1886
+ message: "Select chat sources to index",
1879
1887
  required: false,
1880
1888
  initialValues: targets.filter((target) => target.available !== false && (target.detectedCount ?? 0) > 0).map((target) => target.id),
1881
1889
  options: targets.map((target) => ({
@@ -2337,12 +2345,13 @@ function walkCodexSessions(dir, memories, sessionIds, stats) {
2337
2345
 
2338
2346
  // src/ingest/cursor.ts
2339
2347
  init_shared();
2348
+ import { Buffer } from "node:buffer";
2340
2349
  import { existsSync as existsSync4, readFileSync as readFileSync4, statSync } from "node:fs";
2341
2350
  import { dirname, join as join4 } from "node:path";
2342
2351
  import { createRequire as createRequire2 } from "node:module";
2343
2352
  import { homedir as homedir4 } from "node:os";
2344
- var MAX_DB_SIZE = 2 * 1024 * 1024 * 1024;
2345
- var WARN_DB_SIZE = 500 * 1024 * 1024;
2353
+ var MAX_SQLJS_DB_SIZE = 2 * 1024 * 1024 * 1024;
2354
+ var LARGE_SQLJS_DB_SIZE = 500 * 1024 * 1024;
2346
2355
  var MIN_TURN_LEN2 = 50;
2347
2356
  function parseCursorTimestamp(value) {
2348
2357
  const parsed = parseTimestampMs(value);
@@ -2375,45 +2384,217 @@ function resolveSqlJsWasmDir(wasmDir) {
2375
2384
  return existsSync4(join4(installedBundleDir, "sql.js", "package.json")) ? installedBundleDir : undefined;
2376
2385
  }
2377
2386
  }
2378
- function openDb(initSqlJs, dbPath, wasmDir) {
2387
+ function toText(value) {
2388
+ if (typeof value === "string")
2389
+ return value;
2390
+ if (value instanceof Uint8Array)
2391
+ return Buffer.from(value).toString("utf-8");
2392
+ if (value === null || value === undefined)
2393
+ return "";
2394
+ return String(value);
2395
+ }
2396
+ function normalizeKvRow(row) {
2397
+ const key = toText(row.key);
2398
+ const value = toText(row.value);
2399
+ return key ? { key, value } : null;
2400
+ }
2401
+ function normalizeRows(rows) {
2402
+ return rows.map(normalizeKvRow).filter((row) => row !== null);
2403
+ }
2404
+ async function openBunSqliteDb(dbPath) {
2405
+ let raw;
2406
+ try {
2407
+ const mod = await import("bun:sqlite");
2408
+ const Database = mod.Database;
2409
+ if (!Database)
2410
+ return null;
2411
+ raw = new Database(dbPath, { readonly: true });
2412
+ const composerStmt = raw.query("SELECT key, value FROM cursorDiskKV WHERE key LIKE ?");
2413
+ const valueStmt = raw.query("SELECT value FROM cursorDiskKV WHERE key = ? LIMIT 1");
2414
+ return {
2415
+ kind: "bun:sqlite",
2416
+ selectComposerData() {
2417
+ return normalizeRows(composerStmt.all("composerData:%"));
2418
+ },
2419
+ selectValue(key) {
2420
+ const row = valueStmt.get(key);
2421
+ if (!row)
2422
+ return null;
2423
+ const value = toText(row.value);
2424
+ return value || null;
2425
+ },
2426
+ close() {
2427
+ raw.close();
2428
+ }
2429
+ };
2430
+ } catch {
2431
+ try {
2432
+ raw?.close();
2433
+ } catch {}
2434
+ return null;
2435
+ }
2436
+ }
2437
+ function openBetterSqliteDb(dbPath) {
2438
+ let raw;
2439
+ try {
2440
+ const require2 = createRequire2(import.meta.url);
2441
+ const BetterSqlite3 = require2("better-sqlite3");
2442
+ raw = new BetterSqlite3(dbPath, { readonly: true, fileMustExist: true });
2443
+ raw.pragma("query_only = ON");
2444
+ const composerStmt = raw.prepare("SELECT key, value FROM cursorDiskKV WHERE key LIKE ?");
2445
+ const valueStmt = raw.prepare("SELECT value FROM cursorDiskKV WHERE key = ? LIMIT 1");
2446
+ return {
2447
+ kind: "better-sqlite3",
2448
+ selectComposerData() {
2449
+ return normalizeRows(composerStmt.all("composerData:%"));
2450
+ },
2451
+ selectValue(key) {
2452
+ const row = valueStmt.get(key);
2453
+ if (!row)
2454
+ return null;
2455
+ const value = toText(row.value);
2456
+ return value || null;
2457
+ },
2458
+ close() {
2459
+ raw.close();
2460
+ }
2461
+ };
2462
+ } catch {
2463
+ try {
2464
+ raw?.close();
2465
+ } catch {}
2466
+ return null;
2467
+ }
2468
+ }
2469
+ async function importNodeSqlite() {
2470
+ const originalEmitWarning = process.emitWarning;
2471
+ try {
2472
+ process.emitWarning = function(warning, ...args) {
2473
+ const message = typeof warning === "string" ? warning : warning && typeof warning === "object" && ("message" in warning) ? String(warning.message) : "";
2474
+ const type = typeof args[0] === "string" ? args[0] : args[0]?.type;
2475
+ if (type === "ExperimentalWarning" && message.includes("SQLite"))
2476
+ return;
2477
+ return originalEmitWarning.call(process, warning, ...args);
2478
+ };
2479
+ return await import("node:sqlite");
2480
+ } catch {
2481
+ return null;
2482
+ } finally {
2483
+ process.emitWarning = originalEmitWarning;
2484
+ }
2485
+ }
2486
+ async function openNodeSqliteDb(dbPath) {
2487
+ let raw;
2488
+ try {
2489
+ const mod = await importNodeSqlite();
2490
+ const DatabaseSync = mod?.DatabaseSync;
2491
+ if (!DatabaseSync)
2492
+ return null;
2493
+ raw = new DatabaseSync(dbPath, { readOnly: true });
2494
+ const composerStmt = raw.prepare("SELECT key, value FROM cursorDiskKV WHERE key LIKE ?");
2495
+ const valueStmt = raw.prepare("SELECT value FROM cursorDiskKV WHERE key = ? LIMIT 1");
2496
+ return {
2497
+ kind: "node:sqlite",
2498
+ selectComposerData() {
2499
+ return normalizeRows(composerStmt.all("composerData:%"));
2500
+ },
2501
+ selectValue(key) {
2502
+ const row = valueStmt.get(key);
2503
+ if (!row)
2504
+ return null;
2505
+ const value = toText(row.value);
2506
+ return value || null;
2507
+ },
2508
+ close() {
2509
+ raw.close();
2510
+ }
2511
+ };
2512
+ } catch {
2513
+ try {
2514
+ raw?.close();
2515
+ } catch {}
2516
+ return null;
2517
+ }
2518
+ }
2519
+ function allowLargeSqlJsLoad() {
2520
+ const value = process.env.CONARE_CURSOR_ALLOW_SQLJS_LARGE;
2521
+ return value === "1" || value === "true";
2522
+ }
2523
+ async function openSqlJsDb(initSqlJs, dbPath, wasmDir) {
2379
2524
  const locateOpts = {};
2380
2525
  if (wasmDir) {
2381
2526
  locateOpts.locateFile = (file) => join4(wasmDir, "sql.js", "dist", file);
2382
2527
  }
2383
- return initSqlJs(locateOpts).then((SQL) => {
2384
- const buffer = readFileSync4(dbPath);
2385
- return new SQL.Database(buffer);
2386
- });
2528
+ const SQL = await initSqlJs(locateOpts);
2529
+ const buffer = readFileSync4(dbPath);
2530
+ const raw = new SQL.Database(buffer);
2531
+ function select(sql, params) {
2532
+ const stmt = raw.prepare(sql);
2533
+ try {
2534
+ stmt.bind(params);
2535
+ const rows = [];
2536
+ while (stmt.step()) {
2537
+ rows.push(stmt.getAsObject());
2538
+ }
2539
+ return rows;
2540
+ } finally {
2541
+ stmt.free();
2542
+ }
2543
+ }
2544
+ return {
2545
+ kind: "sql.js",
2546
+ selectComposerData() {
2547
+ return normalizeRows(select("SELECT key, value FROM cursorDiskKV WHERE key LIKE ?", ["composerData:%"]));
2548
+ },
2549
+ selectValue(key) {
2550
+ const row = select("SELECT value FROM cursorDiskKV WHERE key = ? LIMIT 1", [key])[0];
2551
+ if (!row)
2552
+ return null;
2553
+ const value = toText(row.value);
2554
+ return value || null;
2555
+ },
2556
+ close() {
2557
+ raw.close();
2558
+ }
2559
+ };
2387
2560
  }
2388
- async function countImportableCursorSessions(dbPath, wasmDir) {
2389
- try {
2390
- const fileSize = statSync(dbPath).size;
2391
- if (fileSize > MAX_DB_SIZE)
2392
- return 0;
2393
- } catch {
2394
- return 0;
2561
+ async function openCursorKvDb(dbPath, fileSize, wasmDir) {
2562
+ const nativeDb = await openBunSqliteDb(dbPath) || openBetterSqliteDb(dbPath) || await openNodeSqliteDb(dbPath);
2563
+ if (nativeDb)
2564
+ return { db: nativeDb };
2565
+ if (fileSize > MAX_SQLJS_DB_SIZE)
2566
+ return { db: null, reason: "sqljs-too-large" };
2567
+ if (fileSize > LARGE_SQLJS_DB_SIZE && !allowLargeSqlJsLoad()) {
2568
+ return { db: null, reason: "sqljs-large" };
2395
2569
  }
2396
2570
  const effectiveWasmDir = resolveSqlJsWasmDir(wasmDir);
2397
2571
  const initSqlJs = loadSqlJs(effectiveWasmDir);
2398
2572
  if (!initSqlJs)
2399
- return 0;
2400
- let db;
2573
+ return { db: null, reason: "no-driver" };
2574
+ try {
2575
+ return { db: await openSqlJsDb(initSqlJs, dbPath, effectiveWasmDir) };
2576
+ } catch (e) {
2577
+ return { db: null, reason: "open-failed", message: e?.message || String(e) };
2578
+ }
2579
+ }
2580
+ function formatMiB(bytes) {
2581
+ return (bytes / 1024 / 1024).toFixed(0);
2582
+ }
2583
+ async function countImportableCursorSessions(dbPath, wasmDir) {
2584
+ let fileSize;
2401
2585
  try {
2402
- db = await openDb(initSqlJs, dbPath, effectiveWasmDir);
2586
+ fileSize = statSync(dbPath).size;
2403
2587
  } catch {
2404
2588
  return 0;
2405
2589
  }
2590
+ const openResult = await openCursorKvDb(dbPath, fileSize, wasmDir);
2591
+ if (!openResult.db)
2592
+ return 0;
2593
+ const db = openResult.db;
2406
2594
  try {
2407
- let rows = [];
2408
- try {
2409
- const results = db.exec("SELECT key, value FROM cursorDiskKV WHERE key LIKE 'composerData:%'");
2410
- if (results.length > 0)
2411
- rows = results[0].values;
2412
- } catch {
2413
- return 0;
2414
- }
2595
+ const rows = db.selectComposerData();
2415
2596
  let count = 0;
2416
- for (const [key, value] of rows) {
2597
+ for (const { key, value } of rows) {
2417
2598
  const composerId = key.replace("composerData:", "");
2418
2599
  let parsed;
2419
2600
  try {
@@ -2441,11 +2622,11 @@ function extractTurns(db, composerId, bubbleHeaders) {
2441
2622
  for (const header of bubbleHeaders) {
2442
2623
  let text = "";
2443
2624
  try {
2444
- const result = db.exec(`SELECT value FROM cursorDiskKV WHERE key = 'bubbleId:${composerId}:${header.bubbleId}'`);
2445
- if (result.length > 0) {
2446
- const bubble = JSON.parse(result[0].values[0][0]);
2447
- text = cleanText(bubble.text || "");
2448
- }
2625
+ const rawBubble = db.selectValue(`bubbleId:${composerId}:${header.bubbleId}`);
2626
+ if (!rawBubble)
2627
+ continue;
2628
+ const bubble = JSON.parse(rawBubble);
2629
+ text = cleanText(bubble.text || "");
2449
2630
  } catch {
2450
2631
  continue;
2451
2632
  }
@@ -2472,34 +2653,33 @@ async function ingestCursor(dbPath, wasmDir) {
2472
2653
  console.log(" Skipping Cursor: database not accessible");
2473
2654
  return { memories, sessionIds, skipped: 0, filtered, deduped };
2474
2655
  }
2475
- if (fileSize > MAX_DB_SIZE) {
2476
- console.log(` Skipping Cursor: database too large (${(fileSize / 1024 / 1024 / 1024).toFixed(1)}GB)`);
2656
+ const openResult = await openCursorKvDb(dbPath, fileSize, wasmDir);
2657
+ if (!openResult.db) {
2658
+ if (openResult.reason === "sqljs-too-large") {
2659
+ console.log(` Skipping Cursor: database too large (${(fileSize / 1024 / 1024 / 1024).toFixed(1)}GB)`);
2660
+ } else if (openResult.reason === "sqljs-large") {
2661
+ console.log(` Skipping Cursor: large database (${formatMiB(fileSize)}MB) requires streaming SQLite support; not loading it into memory`);
2662
+ } else if (openResult.reason === "no-driver") {
2663
+ console.log(" Skipping Cursor: SQLite support not available");
2664
+ } else {
2665
+ console.log(` Skipping Cursor: cannot open database (${openResult.message || "unknown error"})`);
2666
+ }
2477
2667
  return { memories, sessionIds, skipped: 0, filtered, deduped };
2478
2668
  }
2479
- if (fileSize > WARN_DB_SIZE) {
2480
- console.log(` Warning: large database (${(fileSize / 1024 / 1024).toFixed(0)}MB), loading into memory...`);
2669
+ if (openResult.db.kind === "sql.js" && fileSize > LARGE_SQLJS_DB_SIZE) {
2670
+ console.log(` Warning: large database (${formatMiB(fileSize)}MB), loading into memory via sql.js fallback...`);
2481
2671
  }
2482
- const effectiveWasmDir = resolveSqlJsWasmDir(wasmDir);
2483
- const initSqlJs = loadSqlJs(effectiveWasmDir);
2484
- if (!initSqlJs) {
2485
- console.log(" Skipping Cursor: sql.js not available");
2486
- return { memories, sessionIds, skipped: 0, filtered, deduped };
2487
- }
2488
- let db;
2489
- try {
2490
- db = await openDb(initSqlJs, dbPath, effectiveWasmDir);
2491
- } catch (e) {
2492
- console.log(` Skipping Cursor: cannot open database (${e.message})`);
2672
+ const db = openResult.db;
2673
+ if (fileSize > MAX_SQLJS_DB_SIZE && db.kind === "sql.js") {
2674
+ console.log(` Skipping Cursor: database too large (${(fileSize / 1024 / 1024 / 1024).toFixed(1)}GB)`);
2493
2675
  return { memories, sessionIds, skipped: 0, filtered, deduped };
2494
2676
  }
2495
2677
  try {
2496
2678
  let rows = [];
2497
2679
  try {
2498
- const results = db.exec("SELECT key, value FROM cursorDiskKV WHERE key LIKE 'composerData:%'");
2499
- if (results.length > 0)
2500
- rows = results[0].values;
2680
+ rows = db.selectComposerData();
2501
2681
  } catch {}
2502
- for (const [key, value] of rows) {
2682
+ for (const { key, value } of rows) {
2503
2683
  const composerId = key.replace("composerData:", "");
2504
2684
  let parsed;
2505
2685
  try {
@@ -3190,6 +3370,7 @@ import { existsSync as existsSync9, mkdirSync as mkdirSync4, writeFileSync as wr
3190
3370
  import { join as join9, dirname as dirname3 } from "node:path";
3191
3371
  import { homedir as homedir8, platform as platform6 } from "node:os";
3192
3372
  import { execSync as execSync3 } from "node:child_process";
3373
+ import { createRequire as createRequire3 } from "node:module";
3193
3374
  var CONARE_DIR = join9(homedir8(), ".conare");
3194
3375
  var BIN_DIR = join9(CONARE_DIR, "bin");
3195
3376
  var CONFIG_PATH2 = join9(CONARE_DIR, "config.json");
@@ -3342,12 +3523,9 @@ function persistBinary(apiKey) {
3342
3523
  const dest = join9(BIN_DIR, "conare-ingest.mjs");
3343
3524
  const content = readFileSync8(cliEntry, "utf-8");
3344
3525
  writeFileSync4(dest, content);
3345
- const sqlJsDir = findSqlJs();
3346
- if (sqlJsDir) {
3347
- const targetDir = join9(BIN_DIR, "node_modules", "sql.js");
3348
- mkdirSync4(targetDir, { recursive: true });
3526
+ for (const moduleName of ["sql.js", "better-sqlite3", "bindings", "file-uri-to-path"]) {
3349
3527
  try {
3350
- cpSync(sqlJsDir, targetDir, { recursive: true });
3528
+ copyNodeModule(moduleName);
3351
3529
  } catch {}
3352
3530
  }
3353
3531
  const runShPath = join9(BIN_DIR, "run.sh");
@@ -3387,11 +3565,15 @@ function findCliBundle() {
3387
3565
  return entry;
3388
3566
  return null;
3389
3567
  }
3390
- function findSqlJs() {
3568
+ function findNodeModule(name) {
3569
+ try {
3570
+ const require2 = createRequire3(import.meta.url);
3571
+ return dirname3(require2.resolve(`${name}/package.json`));
3572
+ } catch {}
3391
3573
  const candidates = [
3392
- join9(process.cwd(), "node_modules", "sql.js"),
3393
- join9(dirname3(new URL(import.meta.url).pathname), "..", "node_modules", "sql.js"),
3394
- join9(dirname3(new URL(import.meta.url).pathname), "..", "..", "node_modules", "sql.js")
3574
+ join9(process.cwd(), "node_modules", name),
3575
+ join9(dirname3(new URL(import.meta.url).pathname), "..", "node_modules", name),
3576
+ join9(dirname3(new URL(import.meta.url).pathname), "..", "..", "node_modules", name)
3395
3577
  ];
3396
3578
  for (const c of candidates) {
3397
3579
  if (existsSync9(c))
@@ -3399,6 +3581,15 @@ function findSqlJs() {
3399
3581
  }
3400
3582
  return null;
3401
3583
  }
3584
+ function copyNodeModule(name) {
3585
+ const sourceDir = findNodeModule(name);
3586
+ if (!sourceDir)
3587
+ return;
3588
+ const targetDir = join9(BIN_DIR, "node_modules", name);
3589
+ rmSync2(targetDir, { recursive: true, force: true });
3590
+ mkdirSync4(dirname3(targetDir), { recursive: true });
3591
+ cpSync(sourceDir, targetDir, { recursive: true });
3592
+ }
3402
3593
  function cleanupOldLaunchAgent() {
3403
3594
  try {
3404
3595
  execSync3(`launchctl bootout gui/${uid()} "${PLIST_PATH}" 2>/dev/null`, { stdio: "ignore" });
@@ -3969,10 +4160,9 @@ async function main() {
3969
4160
  apiKey = authResult || apiKey;
3970
4161
  }
3971
4162
  }
3972
- const detectSpinner = Y2();
3973
- detectSpinner.start("Detecting apps...");
4163
+ showCountingLocalChats();
3974
4164
  const detectedTools = await detect();
3975
- detectSpinner.stop("Apps detected");
4165
+ showLocalChatsCounted();
3976
4166
  interactiveTargets = MCP_TARGETS.map((target) => {
3977
4167
  const detected = detectedTools.find((tool) => tool.id === target.id);
3978
4168
  return {
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "conare",
3
- "version": "0.5.10",
3
+ "version": "0.5.12",
4
4
  "description": "Conare CLI for indexing AI chat history and configuring memory at conare.ai",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "conare": "./dist/index.js"
8
8
  },
9
9
  "scripts": {
10
- "build": "bun build src/index.ts --outdir dist --target node --format esm --external sql.js",
10
+ "build": "bun build src/index.ts --outdir dist --target node --format esm --external sql.js --external better-sqlite3",
11
11
  "prepublishOnly": "bun run build"
12
12
  },
13
13
  "files": [
@@ -28,5 +28,8 @@
28
28
  "dependencies": {
29
29
  "@clack/prompts": "^0.11.0",
30
30
  "sql.js": "^1.12.0"
31
+ },
32
+ "optionalDependencies": {
33
+ "better-sqlite3": "^12.10.0"
31
34
  }
32
35
  }