conare 0.5.12 → 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 +93 -16
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1791,6 +1791,9 @@ __export(exports_interactive, {
1791
1791
  spinner: () => Y2,
1792
1792
  showLocalChatsCounted: () => showLocalChatsCounted,
1793
1793
  showDetectedApps: () => showDetectedApps,
1794
+ showCountingToolProgress: () => showCountingToolProgress,
1795
+ showCountingToolDone: () => showCountingToolDone,
1796
+ showCountingToolChats: () => showCountingToolChats,
1794
1797
  showCountingLocalChats: () => showCountingLocalChats,
1795
1798
  selectMcpTargets: () => selectMcpTargets,
1796
1799
  selectChatSources: () => selectChatSources,
@@ -1824,6 +1827,16 @@ function showDetectedApps(targets) {
1824
1827
  function showCountingLocalChats() {
1825
1828
  M2.step("Counting local chats...");
1826
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
+ }
1827
1840
  function showLocalChatsCounted() {
1828
1841
  M2.success("Local chats counted");
1829
1842
  }
@@ -2049,39 +2062,54 @@ function getParentUuid(lines) {
2049
2062
  }
2050
2063
  return;
2051
2064
  }
2052
- function countImportableClaudeSessions() {
2065
+ function countImportableClaudeSessions(onProgress) {
2053
2066
  const projectsDir = join2(homedir2(), ".claude", "projects");
2054
2067
  let count = 0;
2068
+ let checked = 0;
2069
+ let total = 0;
2055
2070
  let projectDirs;
2056
2071
  try {
2057
2072
  projectDirs = readdirSync(projectsDir);
2058
2073
  } catch {
2059
2074
  return 0;
2060
2075
  }
2061
- for (const projDir of projectDirs) {
2076
+ const projectFiles = projectDirs.map((projDir) => {
2062
2077
  const projPath = join2(projectsDir, projDir);
2063
- let files;
2064
2078
  try {
2065
- 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 };
2066
2082
  } catch {
2067
- continue;
2083
+ return { projPath, files: [] };
2068
2084
  }
2085
+ });
2086
+ const report = () => onProgress?.({ checked, found: count, total });
2087
+ for (const { projPath, files } of projectFiles) {
2069
2088
  for (const file of files) {
2089
+ checked++;
2070
2090
  try {
2071
2091
  const raw = readFileSync2(join2(projPath, file), "utf-8");
2072
2092
  const lines = raw.split(`
2073
2093
  `);
2074
2094
  const parentUuid = getParentUuid(lines);
2075
- if (parentUuid != null)
2095
+ if (parentUuid != null) {
2096
+ if (checked % 100 === 0)
2097
+ report();
2076
2098
  continue;
2099
+ }
2077
2100
  const { turns } = parseSession(lines);
2078
2101
  if (turns.length > 0)
2079
2102
  count++;
2080
2103
  } catch {
2104
+ if (checked % 100 === 0)
2105
+ report();
2081
2106
  continue;
2082
2107
  }
2108
+ if (checked % 100 === 0)
2109
+ report();
2083
2110
  }
2084
2111
  }
2112
+ report();
2085
2113
  return count;
2086
2114
  }
2087
2115
  function ingestClaude() {
@@ -2274,12 +2302,14 @@ function walkCodexSessionFiles(dir, visit) {
2274
2302
  }
2275
2303
  } catch {}
2276
2304
  }
2277
- function countImportableCodexSessions() {
2305
+ function countImportableCodexSessions(onProgress) {
2278
2306
  const sessionsDir = join3(homedir3(), ".codex", "sessions");
2279
2307
  if (!existsSync3(sessionsDir))
2280
2308
  return 0;
2281
2309
  let count = 0;
2310
+ let checked = 0;
2282
2311
  walkCodexSessionFiles(sessionsDir, (filePath) => {
2312
+ checked++;
2283
2313
  try {
2284
2314
  const lines = readFileSync3(filePath, "utf-8").split(`
2285
2315
  `).filter(Boolean);
@@ -2287,7 +2317,10 @@ function countImportableCodexSessions() {
2287
2317
  if (rounds.length > 0)
2288
2318
  count++;
2289
2319
  } catch {}
2320
+ if (checked % 100 === 0)
2321
+ onProgress?.({ checked, found: count });
2290
2322
  });
2323
+ onProgress?.({ checked, found: count });
2291
2324
  return count;
2292
2325
  }
2293
2326
  function walkCodexSessions(dir, memories, sessionIds, stats) {
@@ -2580,7 +2613,7 @@ async function openCursorKvDb(dbPath, fileSize, wasmDir) {
2580
2613
  function formatMiB(bytes) {
2581
2614
  return (bytes / 1024 / 1024).toFixed(0);
2582
2615
  }
2583
- async function countImportableCursorSessions(dbPath, wasmDir) {
2616
+ async function countImportableCursorSessions(dbPath, wasmDir, onProgress) {
2584
2617
  let fileSize;
2585
2618
  try {
2586
2619
  fileSize = statSync(dbPath).size;
@@ -2594,22 +2627,36 @@ async function countImportableCursorSessions(dbPath, wasmDir) {
2594
2627
  try {
2595
2628
  const rows = db.selectComposerData();
2596
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
+ };
2597
2637
  for (const { key, value } of rows) {
2638
+ checked++;
2598
2639
  const composerId = key.replace("composerData:", "");
2599
2640
  let parsed;
2600
2641
  try {
2601
2642
  parsed = JSON.parse(value);
2602
- if (!parsed || typeof parsed !== "object")
2643
+ if (!parsed || typeof parsed !== "object") {
2644
+ report();
2603
2645
  continue;
2646
+ }
2604
2647
  } catch {
2648
+ report();
2605
2649
  continue;
2606
2650
  }
2607
2651
  const bubbleHeaders = parsed.fullConversationHeadersOnly;
2608
- if (!Array.isArray(bubbleHeaders) || bubbleHeaders.length === 0)
2652
+ if (!Array.isArray(bubbleHeaders) || bubbleHeaders.length === 0) {
2653
+ report();
2609
2654
  continue;
2655
+ }
2610
2656
  const turns = extractTurns(db, composerId, bubbleHeaders);
2611
2657
  if (turns.length > 0)
2612
2658
  count++;
2659
+ report();
2613
2660
  }
2614
2661
  return count;
2615
2662
  } finally {
@@ -2742,23 +2789,34 @@ async function ingestCursor(dbPath, wasmDir) {
2742
2789
  }
2743
2790
 
2744
2791
  // src/detect.ts
2745
- async function detect() {
2792
+ async function detect(options = {}) {
2746
2793
  const home = homedir5();
2747
2794
  const os = platform3();
2748
2795
  const tools = [];
2796
+ const onProgress = options.onProgress;
2749
2797
  const claudeDir = join5(home, ".claude", "projects");
2750
2798
  if (existsSync5(claudeDir)) {
2751
- 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 });
2752
2804
  tools.push({ name: "Claude Code", id: "claude", available: sessionCount > 0, path: claudeDir, sessionCount, sessionCountApproximate: true });
2753
2805
  } else {
2806
+ onProgress?.({ tool: "Claude Code", status: "skip", reason: "not found" });
2754
2807
  tools.push({ name: "Claude Code", id: "claude", available: false, path: claudeDir, sessionCount: 0 });
2755
2808
  }
2756
2809
  const codexConfig = join5(home, ".codex", "config.toml");
2757
2810
  const codexSessions = join5(home, ".codex", "sessions");
2758
2811
  if (existsSync5(codexConfig) || existsSync5(codexSessions)) {
2759
- 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 });
2760
2817
  tools.push({ name: "Codex", id: "codex", available: true, path: codexConfig, sessionCount, sessionCountApproximate: true });
2761
2818
  } else {
2819
+ onProgress?.({ tool: "Codex", status: "skip", reason: "not found" });
2762
2820
  tools.push({ name: "Codex", id: "codex", available: false, path: codexConfig, sessionCount: 0 });
2763
2821
  }
2764
2822
  let cursorDbPath;
@@ -2769,12 +2827,22 @@ async function detect() {
2769
2827
  } else {
2770
2828
  cursorDbPath = join5(home, ".config", "Cursor", "User", "globalStorage", "state.vscdb");
2771
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 });
2772
2840
  tools.push({
2773
2841
  name: "Cursor",
2774
2842
  id: "cursor",
2775
- available: existsSync5(cursorDbPath),
2843
+ available: cursorExists,
2776
2844
  path: cursorDbPath,
2777
- sessionCount: existsSync5(cursorDbPath) ? await countImportableCursorSessions(cursorDbPath) : 0,
2845
+ sessionCount: cursorCount,
2778
2846
  sessionCountApproximate: true
2779
2847
  });
2780
2848
  const windsurfDir = join5(home, ".codeium", "windsurf");
@@ -3928,6 +3996,15 @@ function renderSourceBreakdown(memories) {
3928
3996
  function formatSessionCount(count, approximate) {
3929
3997
  return `${approximate ? "~" : ""}${count} sessions`;
3930
3998
  }
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
+ }
4007
+ }
3931
4008
  function parseArgs() {
3932
4009
  const args = process.argv.slice(2);
3933
4010
  let key = "";
@@ -4161,7 +4238,7 @@ async function main() {
4161
4238
  }
4162
4239
  }
4163
4240
  showCountingLocalChats();
4164
- const detectedTools = await detect();
4241
+ const detectedTools = await detect({ onProgress: renderDetectProgress });
4165
4242
  showLocalChatsCounted();
4166
4243
  interactiveTargets = MCP_TARGETS.map((target) => {
4167
4244
  const detected = detectedTools.find((tool) => tool.id === target.id);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "conare",
3
- "version": "0.5.12",
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": {