conare 0.5.13 → 0.5.15

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 +108 -53
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1825,20 +1825,27 @@ function showDetectedApps(targets) {
1825
1825
  `), "Detected apps");
1826
1826
  }
1827
1827
  function showCountingLocalChats() {
1828
- M2.step("Counting local chats...");
1828
+ countingSpinner = Y2();
1829
+ countingSpinner.start("Scanning local chats");
1829
1830
  }
1830
1831
  function showCountingToolChats(tool) {
1831
- M2.step(`Counting ${tool} chats...`);
1832
+ countingSpinner?.message(`Scanning ${tool} chats`);
1832
1833
  }
1833
1834
  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`);
1835
+ const checkedText = total ? `${checked.toLocaleString()}/${total.toLocaleString()}` : checked.toLocaleString();
1836
+ countingSpinner?.message(`Scanning ${tool}: ${checkedText} files, ${found.toLocaleString()} importable`);
1836
1837
  }
1837
1838
  function showCountingToolDone(tool, count) {
1838
- M2.success(`${tool}: ~${count.toLocaleString()} chats`);
1839
+ toolTotals[tool] = count;
1840
+ countingSpinner?.message(`${tool}: ${count.toLocaleString()} chats`);
1839
1841
  }
1840
1842
  function showLocalChatsCounted() {
1841
- M2.success("Local chats counted");
1843
+ if (!countingSpinner)
1844
+ return;
1845
+ const entries = Object.entries(toolTotals).filter(([, n]) => n > 0);
1846
+ const summary = entries.length ? entries.map(([tool, n]) => `${tool} ${n.toLocaleString()}`).join(", ") : "no chats found";
1847
+ countingSpinner.stop(`Found ${summary}`);
1848
+ countingSpinner = null;
1842
1849
  }
1843
1850
  async function promptApiKey(options) {
1844
1851
  if (options.providedApiKey) {
@@ -1929,8 +1936,10 @@ async function confirmBackgroundSync() {
1929
1936
  }));
1930
1937
  return value === "yes";
1931
1938
  }
1939
+ var countingSpinner = null, toolTotals;
1932
1940
  var init_interactive = __esm(() => {
1933
1941
  init_dist2();
1942
+ toolTotals = {};
1934
1943
  });
1935
1944
 
1936
1945
  // src/index.ts
@@ -2046,6 +2055,42 @@ function parseSession(lines) {
2046
2055
  })).filter((t) => t.assistant.length >= MIN_TURN_LEN);
2047
2056
  return { turns, date, sourceTimestamp, startedAt, updatedAt };
2048
2057
  }
2058
+ function hasAnyImportableTurn(lines) {
2059
+ let currentUser = null;
2060
+ let currentAssistant = [];
2061
+ const closeRound = () => {
2062
+ if (currentUser === null || currentAssistant.length === 0)
2063
+ return false;
2064
+ const assistant = currentAssistant.filter((p) => !isNarration(p)).join(`
2065
+
2066
+ `);
2067
+ return assistant.length >= MIN_TURN_LEN;
2068
+ };
2069
+ for (const line of lines) {
2070
+ if (!line.trim())
2071
+ continue;
2072
+ let obj;
2073
+ try {
2074
+ obj = JSON.parse(line);
2075
+ } catch {
2076
+ continue;
2077
+ }
2078
+ if (obj.type === "user") {
2079
+ const text = cleanText(extractText(obj.message?.content));
2080
+ if (text.length >= MIN_TURN_LEN) {
2081
+ if (closeRound())
2082
+ return true;
2083
+ currentUser = text;
2084
+ currentAssistant = [];
2085
+ }
2086
+ } else if (obj.type === "assistant") {
2087
+ const text = cleanText(extractText(obj.message?.content));
2088
+ if (text.length >= MIN_TURN_LEN)
2089
+ currentAssistant.push(text);
2090
+ }
2091
+ }
2092
+ return closeRound();
2093
+ }
2049
2094
  function getParentUuid(lines) {
2050
2095
  for (const line of lines) {
2051
2096
  if (!line.trim())
@@ -2062,54 +2107,50 @@ function getParentUuid(lines) {
2062
2107
  }
2063
2108
  return;
2064
2109
  }
2065
- function countImportableClaudeSessions(onProgress) {
2110
+ async function countImportableClaudeSessions(onProgress) {
2111
+ const { readFile } = await import("node:fs/promises");
2066
2112
  const projectsDir = join2(homedir2(), ".claude", "projects");
2067
- let count = 0;
2068
- let checked = 0;
2069
- let total = 0;
2070
2113
  let projectDirs;
2071
2114
  try {
2072
2115
  projectDirs = readdirSync(projectsDir);
2073
2116
  } catch {
2074
2117
  return 0;
2075
2118
  }
2076
- const projectFiles = projectDirs.map((projDir) => {
2119
+ const allFiles = [];
2120
+ for (const projDir of projectDirs) {
2077
2121
  const projPath = join2(projectsDir, projDir);
2078
2122
  try {
2079
- const files = readdirSync(projPath).filter((f) => f.endsWith(".jsonl"));
2080
- total += files.length;
2081
- return { projPath, files };
2082
- } catch {
2083
- return { projPath, files: [] };
2084
- }
2085
- });
2086
- const report = () => onProgress?.({ checked, found: count, total });
2087
- for (const { projPath, files } of projectFiles) {
2088
- for (const file of files) {
2089
- checked++;
2123
+ for (const f of readdirSync(projPath)) {
2124
+ if (f.endsWith(".jsonl"))
2125
+ allFiles.push(join2(projPath, f));
2126
+ }
2127
+ } catch {}
2128
+ }
2129
+ const total = allFiles.length;
2130
+ let count = 0;
2131
+ let checked = 0;
2132
+ const CONCURRENCY = 16;
2133
+ let nextIdx = 0;
2134
+ const worker = async () => {
2135
+ while (true) {
2136
+ const i = nextIdx++;
2137
+ if (i >= allFiles.length)
2138
+ return;
2090
2139
  try {
2091
- const raw = readFileSync2(join2(projPath, file), "utf-8");
2140
+ const raw = await readFile(allFiles[i], "utf-8");
2092
2141
  const lines = raw.split(`
2093
2142
  `);
2094
2143
  const parentUuid = getParentUuid(lines);
2095
- if (parentUuid != null) {
2096
- if (checked % 100 === 0)
2097
- report();
2098
- continue;
2099
- }
2100
- const { turns } = parseSession(lines);
2101
- if (turns.length > 0)
2144
+ if (parentUuid == null && hasAnyImportableTurn(lines))
2102
2145
  count++;
2103
- } catch {
2104
- if (checked % 100 === 0)
2105
- report();
2106
- continue;
2107
- }
2146
+ } catch {}
2147
+ checked++;
2108
2148
  if (checked % 100 === 0)
2109
- report();
2149
+ onProgress?.({ checked, found: count, total });
2110
2150
  }
2111
- }
2112
- report();
2151
+ };
2152
+ await Promise.all(Array.from({ length: CONCURRENCY }, () => worker()));
2153
+ onProgress?.({ checked, found: count, total });
2113
2154
  return count;
2114
2155
  }
2115
2156
  function ingestClaude() {
@@ -2302,25 +2343,39 @@ function walkCodexSessionFiles(dir, visit) {
2302
2343
  }
2303
2344
  } catch {}
2304
2345
  }
2305
- function countImportableCodexSessions(onProgress) {
2346
+ async function countImportableCodexSessions(onProgress) {
2306
2347
  const sessionsDir = join3(homedir3(), ".codex", "sessions");
2307
2348
  if (!existsSync3(sessionsDir))
2308
2349
  return 0;
2350
+ const { readFile } = await import("node:fs/promises");
2351
+ const files = [];
2352
+ walkCodexSessionFiles(sessionsDir, (filePath) => {
2353
+ files.push(filePath);
2354
+ });
2355
+ const total = files.length;
2309
2356
  let count = 0;
2310
2357
  let checked = 0;
2311
- walkCodexSessionFiles(sessionsDir, (filePath) => {
2312
- checked++;
2313
- try {
2314
- const lines = readFileSync3(filePath, "utf-8").split(`
2358
+ const CONCURRENCY = 16;
2359
+ let nextIdx = 0;
2360
+ const worker = async () => {
2361
+ while (true) {
2362
+ const i = nextIdx++;
2363
+ if (i >= files.length)
2364
+ return;
2365
+ try {
2366
+ const lines = (await readFile(files[i], "utf-8")).split(`
2315
2367
  `).filter(Boolean);
2316
- const { rounds } = parseCodexSession(lines);
2317
- if (rounds.length > 0)
2318
- count++;
2319
- } catch {}
2320
- if (checked % 100 === 0)
2321
- onProgress?.({ checked, found: count });
2322
- });
2323
- onProgress?.({ checked, found: count });
2368
+ const { rounds } = parseCodexSession(lines);
2369
+ if (rounds.length > 0)
2370
+ count++;
2371
+ } catch {}
2372
+ checked++;
2373
+ if (checked % 100 === 0)
2374
+ onProgress?.({ checked, found: count, total });
2375
+ }
2376
+ };
2377
+ await Promise.all(Array.from({ length: CONCURRENCY }, () => worker()));
2378
+ onProgress?.({ checked, found: count, total });
2324
2379
  return count;
2325
2380
  }
2326
2381
  function walkCodexSessions(dir, memories, sessionIds, stats) {
@@ -2797,7 +2852,7 @@ async function detect(options = {}) {
2797
2852
  const claudeDir = join5(home, ".claude", "projects");
2798
2853
  if (existsSync5(claudeDir)) {
2799
2854
  onProgress?.({ tool: "Claude Code", status: "start" });
2800
- const sessionCount = countImportableClaudeSessions((progress) => {
2855
+ const sessionCount = await countImportableClaudeSessions((progress) => {
2801
2856
  onProgress?.({ tool: "Claude Code", status: "progress", ...progress });
2802
2857
  });
2803
2858
  onProgress?.({ tool: "Claude Code", status: "done", count: sessionCount });
@@ -2810,7 +2865,7 @@ async function detect(options = {}) {
2810
2865
  const codexSessions = join5(home, ".codex", "sessions");
2811
2866
  if (existsSync5(codexConfig) || existsSync5(codexSessions)) {
2812
2867
  onProgress?.({ tool: "Codex", status: "start" });
2813
- const sessionCount = countImportableCodexSessions((progress) => {
2868
+ const sessionCount = await countImportableCodexSessions((progress) => {
2814
2869
  onProgress?.({ tool: "Codex", status: "progress", ...progress });
2815
2870
  });
2816
2871
  onProgress?.({ tool: "Codex", status: "done", count: sessionCount });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "conare",
3
- "version": "0.5.13",
3
+ "version": "0.5.15",
4
4
  "description": "Conare CLI for indexing AI chat history and configuring memory at conare.ai",
5
5
  "type": "module",
6
6
  "bin": {