conare 0.5.11 → 0.5.13

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 +102 -22
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1789,7 +1789,12 @@ var exports_interactive = {};
1789
1789
  __export(exports_interactive, {
1790
1790
  startSetup: () => startSetup,
1791
1791
  spinner: () => Y2,
1792
+ showLocalChatsCounted: () => showLocalChatsCounted,
1792
1793
  showDetectedApps: () => showDetectedApps,
1794
+ showCountingToolProgress: () => showCountingToolProgress,
1795
+ showCountingToolDone: () => showCountingToolDone,
1796
+ showCountingToolChats: () => showCountingToolChats,
1797
+ showCountingLocalChats: () => showCountingLocalChats,
1793
1798
  selectMcpTargets: () => selectMcpTargets,
1794
1799
  selectChatSources: () => selectChatSources,
1795
1800
  promptAuth: () => promptAuth,
@@ -1819,6 +1824,22 @@ function showDetectedApps(targets) {
1819
1824
  Me(targets.map((target) => `• ${target.label}: ${target.available === false ? "not detected" : formatDetectedCount(target.detectedCount, target.detectedCountApproximate)}`).join(`
1820
1825
  `), "Detected apps");
1821
1826
  }
1827
+ function showCountingLocalChats() {
1828
+ M2.step("Counting local chats...");
1829
+ }
1830
+ function showCountingToolChats(tool) {
1831
+ M2.step(`Counting ${tool} chats...`);
1832
+ }
1833
+ function showCountingToolProgress(tool, checked, found, total) {
1834
+ const checkedText = total ? `${checked.toLocaleString()}/${total.toLocaleString()} checked` : `${checked.toLocaleString()} checked`;
1835
+ M2.message(`${tool}: ${checkedText}, ${found.toLocaleString()} importable`);
1836
+ }
1837
+ function showCountingToolDone(tool, count) {
1838
+ M2.success(`${tool}: ~${count.toLocaleString()} chats`);
1839
+ }
1840
+ function showLocalChatsCounted() {
1841
+ M2.success("Local chats counted");
1842
+ }
1822
1843
  async function promptApiKey(options) {
1823
1844
  if (options.providedApiKey) {
1824
1845
  return options.providedApiKey;
@@ -2041,39 +2062,54 @@ function getParentUuid(lines) {
2041
2062
  }
2042
2063
  return;
2043
2064
  }
2044
- function countImportableClaudeSessions() {
2065
+ function countImportableClaudeSessions(onProgress) {
2045
2066
  const projectsDir = join2(homedir2(), ".claude", "projects");
2046
2067
  let count = 0;
2068
+ let checked = 0;
2069
+ let total = 0;
2047
2070
  let projectDirs;
2048
2071
  try {
2049
2072
  projectDirs = readdirSync(projectsDir);
2050
2073
  } catch {
2051
2074
  return 0;
2052
2075
  }
2053
- for (const projDir of projectDirs) {
2076
+ const projectFiles = projectDirs.map((projDir) => {
2054
2077
  const projPath = join2(projectsDir, projDir);
2055
- let files;
2056
2078
  try {
2057
- files = readdirSync(projPath).filter((f) => f.endsWith(".jsonl"));
2079
+ const files = readdirSync(projPath).filter((f) => f.endsWith(".jsonl"));
2080
+ total += files.length;
2081
+ return { projPath, files };
2058
2082
  } catch {
2059
- continue;
2083
+ return { projPath, files: [] };
2060
2084
  }
2085
+ });
2086
+ const report = () => onProgress?.({ checked, found: count, total });
2087
+ for (const { projPath, files } of projectFiles) {
2061
2088
  for (const file of files) {
2089
+ checked++;
2062
2090
  try {
2063
2091
  const raw = readFileSync2(join2(projPath, file), "utf-8");
2064
2092
  const lines = raw.split(`
2065
2093
  `);
2066
2094
  const parentUuid = getParentUuid(lines);
2067
- if (parentUuid != null)
2095
+ if (parentUuid != null) {
2096
+ if (checked % 100 === 0)
2097
+ report();
2068
2098
  continue;
2099
+ }
2069
2100
  const { turns } = parseSession(lines);
2070
2101
  if (turns.length > 0)
2071
2102
  count++;
2072
2103
  } catch {
2104
+ if (checked % 100 === 0)
2105
+ report();
2073
2106
  continue;
2074
2107
  }
2108
+ if (checked % 100 === 0)
2109
+ report();
2075
2110
  }
2076
2111
  }
2112
+ report();
2077
2113
  return count;
2078
2114
  }
2079
2115
  function ingestClaude() {
@@ -2266,12 +2302,14 @@ function walkCodexSessionFiles(dir, visit) {
2266
2302
  }
2267
2303
  } catch {}
2268
2304
  }
2269
- function countImportableCodexSessions() {
2305
+ function countImportableCodexSessions(onProgress) {
2270
2306
  const sessionsDir = join3(homedir3(), ".codex", "sessions");
2271
2307
  if (!existsSync3(sessionsDir))
2272
2308
  return 0;
2273
2309
  let count = 0;
2310
+ let checked = 0;
2274
2311
  walkCodexSessionFiles(sessionsDir, (filePath) => {
2312
+ checked++;
2275
2313
  try {
2276
2314
  const lines = readFileSync3(filePath, "utf-8").split(`
2277
2315
  `).filter(Boolean);
@@ -2279,7 +2317,10 @@ function countImportableCodexSessions() {
2279
2317
  if (rounds.length > 0)
2280
2318
  count++;
2281
2319
  } catch {}
2320
+ if (checked % 100 === 0)
2321
+ onProgress?.({ checked, found: count });
2282
2322
  });
2323
+ onProgress?.({ checked, found: count });
2283
2324
  return count;
2284
2325
  }
2285
2326
  function walkCodexSessions(dir, memories, sessionIds, stats) {
@@ -2572,7 +2613,7 @@ async function openCursorKvDb(dbPath, fileSize, wasmDir) {
2572
2613
  function formatMiB(bytes) {
2573
2614
  return (bytes / 1024 / 1024).toFixed(0);
2574
2615
  }
2575
- async function countImportableCursorSessions(dbPath, wasmDir) {
2616
+ async function countImportableCursorSessions(dbPath, wasmDir, onProgress) {
2576
2617
  let fileSize;
2577
2618
  try {
2578
2619
  fileSize = statSync(dbPath).size;
@@ -2586,22 +2627,36 @@ async function countImportableCursorSessions(dbPath, wasmDir) {
2586
2627
  try {
2587
2628
  const rows = db.selectComposerData();
2588
2629
  let count = 0;
2630
+ let checked = 0;
2631
+ const total = rows.length;
2632
+ const report = () => {
2633
+ if (checked % 50 === 0 || checked === total) {
2634
+ onProgress?.({ checked, found: count, total });
2635
+ }
2636
+ };
2589
2637
  for (const { key, value } of rows) {
2638
+ checked++;
2590
2639
  const composerId = key.replace("composerData:", "");
2591
2640
  let parsed;
2592
2641
  try {
2593
2642
  parsed = JSON.parse(value);
2594
- if (!parsed || typeof parsed !== "object")
2643
+ if (!parsed || typeof parsed !== "object") {
2644
+ report();
2595
2645
  continue;
2646
+ }
2596
2647
  } catch {
2648
+ report();
2597
2649
  continue;
2598
2650
  }
2599
2651
  const bubbleHeaders = parsed.fullConversationHeadersOnly;
2600
- if (!Array.isArray(bubbleHeaders) || bubbleHeaders.length === 0)
2652
+ if (!Array.isArray(bubbleHeaders) || bubbleHeaders.length === 0) {
2653
+ report();
2601
2654
  continue;
2655
+ }
2602
2656
  const turns = extractTurns(db, composerId, bubbleHeaders);
2603
2657
  if (turns.length > 0)
2604
2658
  count++;
2659
+ report();
2605
2660
  }
2606
2661
  return count;
2607
2662
  } finally {
@@ -2734,23 +2789,34 @@ async function ingestCursor(dbPath, wasmDir) {
2734
2789
  }
2735
2790
 
2736
2791
  // src/detect.ts
2737
- async function detect() {
2792
+ async function detect(options = {}) {
2738
2793
  const home = homedir5();
2739
2794
  const os = platform3();
2740
2795
  const tools = [];
2796
+ const onProgress = options.onProgress;
2741
2797
  const claudeDir = join5(home, ".claude", "projects");
2742
2798
  if (existsSync5(claudeDir)) {
2743
- const sessionCount = countImportableClaudeSessions();
2799
+ onProgress?.({ tool: "Claude Code", status: "start" });
2800
+ const sessionCount = countImportableClaudeSessions((progress) => {
2801
+ onProgress?.({ tool: "Claude Code", status: "progress", ...progress });
2802
+ });
2803
+ onProgress?.({ tool: "Claude Code", status: "done", count: sessionCount });
2744
2804
  tools.push({ name: "Claude Code", id: "claude", available: sessionCount > 0, path: claudeDir, sessionCount, sessionCountApproximate: true });
2745
2805
  } else {
2806
+ onProgress?.({ tool: "Claude Code", status: "skip", reason: "not found" });
2746
2807
  tools.push({ name: "Claude Code", id: "claude", available: false, path: claudeDir, sessionCount: 0 });
2747
2808
  }
2748
2809
  const codexConfig = join5(home, ".codex", "config.toml");
2749
2810
  const codexSessions = join5(home, ".codex", "sessions");
2750
2811
  if (existsSync5(codexConfig) || existsSync5(codexSessions)) {
2751
- const sessionCount = countImportableCodexSessions();
2812
+ onProgress?.({ tool: "Codex", status: "start" });
2813
+ const sessionCount = countImportableCodexSessions((progress) => {
2814
+ onProgress?.({ tool: "Codex", status: "progress", ...progress });
2815
+ });
2816
+ onProgress?.({ tool: "Codex", status: "done", count: sessionCount });
2752
2817
  tools.push({ name: "Codex", id: "codex", available: true, path: codexConfig, sessionCount, sessionCountApproximate: true });
2753
2818
  } else {
2819
+ onProgress?.({ tool: "Codex", status: "skip", reason: "not found" });
2754
2820
  tools.push({ name: "Codex", id: "codex", available: false, path: codexConfig, sessionCount: 0 });
2755
2821
  }
2756
2822
  let cursorDbPath;
@@ -2761,12 +2827,22 @@ async function detect() {
2761
2827
  } else {
2762
2828
  cursorDbPath = join5(home, ".config", "Cursor", "User", "globalStorage", "state.vscdb");
2763
2829
  }
2830
+ const cursorExists = existsSync5(cursorDbPath);
2831
+ if (cursorExists)
2832
+ onProgress?.({ tool: "Cursor", status: "start" });
2833
+ else
2834
+ onProgress?.({ tool: "Cursor", status: "skip", reason: "not found" });
2835
+ const cursorCount = cursorExists ? await countImportableCursorSessions(cursorDbPath, undefined, (progress) => {
2836
+ onProgress?.({ tool: "Cursor", status: "progress", ...progress });
2837
+ }) : 0;
2838
+ if (cursorExists)
2839
+ onProgress?.({ tool: "Cursor", status: "done", count: cursorCount });
2764
2840
  tools.push({
2765
2841
  name: "Cursor",
2766
2842
  id: "cursor",
2767
- available: existsSync5(cursorDbPath),
2843
+ available: cursorExists,
2768
2844
  path: cursorDbPath,
2769
- sessionCount: existsSync5(cursorDbPath) ? await countImportableCursorSessions(cursorDbPath) : 0,
2845
+ sessionCount: cursorCount,
2770
2846
  sessionCountApproximate: true
2771
2847
  });
2772
2848
  const windsurfDir = join5(home, ".codeium", "windsurf");
@@ -3920,8 +3996,14 @@ function renderSourceBreakdown(memories) {
3920
3996
  function formatSessionCount(count, approximate) {
3921
3997
  return `${approximate ? "~" : ""}${count} sessions`;
3922
3998
  }
3923
- function nextTick() {
3924
- return new Promise((resolve2) => setTimeout(resolve2, 0));
3999
+ function renderDetectProgress(event) {
4000
+ if (event.status === "start") {
4001
+ showCountingToolChats(event.tool);
4002
+ } else if (event.status === "progress" && event.checked !== undefined && event.found !== undefined) {
4003
+ showCountingToolProgress(event.tool, event.checked, event.found, event.total);
4004
+ } else if (event.status === "done") {
4005
+ showCountingToolDone(event.tool, event.count ?? 0);
4006
+ }
3925
4007
  }
3926
4008
  function parseArgs() {
3927
4009
  const args = process.argv.slice(2);
@@ -4155,11 +4237,9 @@ async function main() {
4155
4237
  apiKey = authResult || apiKey;
4156
4238
  }
4157
4239
  }
4158
- const detectSpinner = Y2();
4159
- detectSpinner.start("Counting local chats...");
4160
- await nextTick();
4161
- const detectedTools = await detect();
4162
- detectSpinner.stop("Local chats counted");
4240
+ showCountingLocalChats();
4241
+ const detectedTools = await detect({ onProgress: renderDetectProgress });
4242
+ showLocalChatsCounted();
4163
4243
  interactiveTargets = MCP_TARGETS.map((target) => {
4164
4244
  const detected = detectedTools.find((tool) => tool.id === target.id);
4165
4245
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "conare",
3
- "version": "0.5.11",
3
+ "version": "0.5.13",
4
4
  "description": "Conare CLI for indexing AI chat history and configuring memory at conare.ai",
5
5
  "type": "module",
6
6
  "bin": {