conare 0.0.6 → 0.0.7

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 +111 -128
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -153,6 +153,7 @@ import { join as join9 } from "node:path";
153
153
 
154
154
  // src/detect.ts
155
155
  import { existsSync, readdirSync } from "node:fs";
156
+ import { spawnSync } from "node:child_process";
156
157
  import { join } from "node:path";
157
158
  import { homedir, platform } from "node:os";
158
159
  function countJsonlFiles(dir) {
@@ -168,6 +169,17 @@ function countJsonlFiles(dir) {
168
169
  } catch {}
169
170
  return count;
170
171
  }
172
+ function countCursorSessions(dbPath) {
173
+ try {
174
+ const result = spawnSync("sqlite3", [dbPath, "SELECT COUNT(*) FROM cursorDiskKV WHERE key LIKE 'composerData:%';"], { encoding: "utf-8" });
175
+ if (result.status !== 0)
176
+ return 0;
177
+ const count = Number.parseInt(result.stdout.trim(), 10);
178
+ return Number.isFinite(count) ? count : 0;
179
+ } catch {
180
+ return 0;
181
+ }
182
+ }
171
183
  function detect() {
172
184
  const home = homedir();
173
185
  const tools = [];
@@ -225,7 +237,7 @@ function detect() {
225
237
  name: "Cursor",
226
238
  available: existsSync(cursorDbPath),
227
239
  path: cursorDbPath,
228
- sessionCount: 0
240
+ sessionCount: existsSync(cursorDbPath) ? countCursorSessions(cursorDbPath) : 0
229
241
  });
230
242
  return tools;
231
243
  }
@@ -1029,7 +1041,7 @@ async function uploadBulk(apiKey, memories, onProgress) {
1029
1041
  import { existsSync as existsSync5, mkdirSync as mkdirSync2, readFileSync as readFileSync6, writeFileSync as writeFileSync2 } from "node:fs";
1030
1042
  import { dirname, join as join7 } from "node:path";
1031
1043
  import { homedir as homedir5 } from "node:os";
1032
- import { spawnSync } from "node:child_process";
1044
+ import { spawnSync as spawnSync2 } from "node:child_process";
1033
1045
  var CONARE_URL = "https://mcp.conare.ai";
1034
1046
  var SERVER_NAME = "conare-memory";
1035
1047
  var MCP_TARGETS = [
@@ -1069,7 +1081,7 @@ function upsertMcpServer(path, apiKey) {
1069
1081
  function configureClaude(apiKey) {
1070
1082
  const claudeConfigPath = join7(homedir5(), ".claude.json");
1071
1083
  const claudeMcpPath = join7(homedir5(), ".claude", "mcp.json");
1072
- if (spawnSync("claude", ["mcp", "add-json", SERVER_NAME, "--scope", "user", JSON.stringify(getServerConfig(apiKey))], {
1084
+ if (spawnSync2("claude", ["mcp", "add-json", SERVER_NAME, "--scope", "user", JSON.stringify(getServerConfig(apiKey))], {
1073
1085
  stdio: "ignore"
1074
1086
  }).status === 0) {
1075
1087
  return "Claude Code configured via `claude mcp add-json`";
@@ -1538,24 +1550,6 @@ class MD extends x {
1538
1550
  return this.value.replaceAll(/./g, this._mask);
1539
1551
  }
1540
1552
  }
1541
- class RD extends x {
1542
- get valueWithCursor() {
1543
- if (this.state === "submit")
1544
- return this.value;
1545
- if (this.cursor >= this.value.length)
1546
- return `${this.value}█`;
1547
- const u = this.value.slice(0, this.cursor), [t, ...F] = this.value.slice(this.cursor);
1548
- return `${u}${import_picocolors.default.inverse(t)}${F.join("")}`;
1549
- }
1550
- get cursor() {
1551
- return this._cursor;
1552
- }
1553
- constructor(u) {
1554
- super(u), this.on("finalize", () => {
1555
- this.value || (this.value = u.defaultValue);
1556
- });
1557
- }
1558
- }
1559
1553
 
1560
1554
  // node_modules/@clack/prompts/dist/index.mjs
1561
1555
  var import_picocolors2 = __toESM(require_picocolors(), 1);
@@ -1610,27 +1604,6 @@ var G2 = (t) => {
1610
1604
  return j2 || E ? import_picocolors2.default.dim("...") : i(p2, v2 + l2 === n);
1611
1605
  });
1612
1606
  };
1613
- var he = (t) => new RD({ validate: t.validate, placeholder: t.placeholder, defaultValue: t.defaultValue, initialValue: t.initialValue, render() {
1614
- const n = `${import_picocolors2.default.gray(o)}
1615
- ${b2(this.state)} ${t.message}
1616
- `, r2 = t.placeholder ? import_picocolors2.default.inverse(t.placeholder[0]) + import_picocolors2.default.dim(t.placeholder.slice(1)) : import_picocolors2.default.inverse(import_picocolors2.default.hidden("_")), i = this.value ? this.valueWithCursor : r2;
1617
- switch (this.state) {
1618
- case "error":
1619
- return `${n.trim()}
1620
- ${import_picocolors2.default.yellow(o)} ${i}
1621
- ${import_picocolors2.default.yellow(d2)} ${import_picocolors2.default.yellow(this.error)}
1622
- `;
1623
- case "submit":
1624
- return `${n}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.dim(this.value || t.placeholder)}`;
1625
- case "cancel":
1626
- return `${n}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(this.value ?? ""))}${this.value?.trim() ? `
1627
- ${import_picocolors2.default.gray(o)}` : ""}`;
1628
- default:
1629
- return `${n}${import_picocolors2.default.cyan(o)} ${i}
1630
- ${import_picocolors2.default.cyan(d2)}
1631
- `;
1632
- }
1633
- } }).prompt();
1634
1607
  var ge = (t) => new MD({ validate: t.validate, mask: t.mask ?? $e, render() {
1635
1608
  const n = `${import_picocolors2.default.gray(o)}
1636
1609
  ${b2(this.state)} ${t.message}
@@ -1746,7 +1719,7 @@ var J = `${import_picocolors2.default.gray(o)} `;
1746
1719
 
1747
1720
  // src/interactive.ts
1748
1721
  function formatDetectedCount(count) {
1749
- if (!count || count <= 0)
1722
+ if (count === undefined)
1750
1723
  return "available";
1751
1724
  return `${count.toLocaleString()} found`;
1752
1725
  }
@@ -1757,74 +1730,63 @@ function ensureValue(value) {
1757
1730
  }
1758
1731
  return value;
1759
1732
  }
1760
- async function runInteractiveSetup(options) {
1733
+ function startSetup() {
1761
1734
  Ie("Conare setup");
1762
- let apiKey = options.providedApiKey;
1763
- if (!apiKey) {
1764
- const keyPrompt = await ge({
1765
- message: options.savedApiKey ? `API key (press Enter to use saved key ending in ${options.savedApiKey.slice(-6)})` : "API key",
1766
- mask: "*",
1767
- validate(value) {
1768
- const resolved = value.trim() || options.savedApiKey || "";
1769
- if (!resolved)
1770
- return "Enter an API key from https://mcp.conare.ai";
1771
- if (!resolved.startsWith("cmem_"))
1772
- return "API keys start with cmem_";
1773
- return;
1774
- }
1775
- });
1776
- apiKey = ensureValue(keyPrompt).trim() || options.savedApiKey;
1777
- }
1778
- Me(options.detectedTargets.map((target) => `• ${target.label}: ${target.available === false ? "not detected" : formatDetectedCount(target.detectedCount)}`).join(`
1735
+ }
1736
+ function finishSetup() {
1737
+ Se("Starting setup...");
1738
+ }
1739
+ function showDetectedApps(targets) {
1740
+ Me(targets.map((target) => `• ${target.label}: ${target.available === false ? "not detected" : formatDetectedCount(target.detectedCount)}`).join(`
1779
1741
  `), "Detected apps");
1780
- const ingestChats = ensureValue(await ye({
1781
- message: "Import past chats?",
1782
- initialValue: true
1783
- }));
1784
- let ingestTargets = [];
1785
- if (ingestChats) {
1786
- ingestTargets = ensureValue(await fe({
1787
- message: "Select chat sources",
1788
- required: false,
1789
- initialValues: options.detectedTargets.filter((target) => target.recommended).map((target) => target.id),
1790
- options: options.detectedTargets.map((target) => ({
1791
- value: target.id,
1792
- label: target.label,
1793
- hint: target.available === false ? "not detected" : formatDetectedCount(target.detectedCount)
1794
- }))
1795
- }));
1796
- }
1797
- const indexCodebase2 = ensureValue(await ye({
1798
- message: "Index this codebase too?",
1799
- initialValue: false
1742
+ }
1743
+ async function promptApiKey(options) {
1744
+ if (options.providedApiKey) {
1745
+ return options.providedApiKey;
1746
+ }
1747
+ const keyPrompt = await ge({
1748
+ message: options.savedApiKey ? `API key (press Enter to use saved key ending in ${options.savedApiKey.slice(-6)})` : "API key",
1749
+ mask: "*",
1750
+ validate(value) {
1751
+ const resolved = value.trim() || options.savedApiKey || "";
1752
+ if (!resolved)
1753
+ return "Enter an API key from https://mcp.conare.ai";
1754
+ if (!resolved.startsWith("cmem_"))
1755
+ return "API keys start with cmem_";
1756
+ return;
1757
+ }
1758
+ });
1759
+ return ensureValue(keyPrompt).trim() || options.savedApiKey;
1760
+ }
1761
+ async function selectChatSources(targets) {
1762
+ return ensureValue(await fe({
1763
+ message: "Select chat sources",
1764
+ required: false,
1765
+ initialValues: targets.filter((target) => target.recommended).map((target) => target.id),
1766
+ options: targets.map((target) => ({
1767
+ value: target.id,
1768
+ label: target.label,
1769
+ hint: target.available === false ? "not detected" : formatDetectedCount(target.detectedCount)
1770
+ }))
1800
1771
  }));
1801
- let indexPath;
1802
- if (indexCodebase2) {
1803
- const pathPrompt = await he({
1804
- message: "Project path",
1805
- placeholder: "."
1806
- });
1807
- indexPath = ensureValue(pathPrompt).trim() || ".";
1808
- }
1809
- const configureTargets = ensureValue(await fe({
1772
+ }
1773
+ async function selectMcpTargets(targets) {
1774
+ return ensureValue(await fe({
1810
1775
  message: "Select where to install the MCP",
1811
1776
  required: false,
1812
- initialValues: options.detectedTargets.filter((target) => target.recommended).map((target) => target.id),
1813
- options: options.detectedTargets.map((target) => ({
1777
+ initialValues: targets.filter((target) => target.recommended).map((target) => target.id),
1778
+ options: targets.map((target) => ({
1814
1779
  value: target.id,
1815
1780
  label: target.label,
1816
1781
  hint: target.available === false ? "not detected" : "recommended"
1817
1782
  }))
1818
1783
  }));
1819
- Se("Starting setup...");
1820
- return {
1821
- apiKey,
1822
- configureTargets,
1823
- ingestTargets,
1824
- ingestChats: ingestChats && ingestTargets.length > 0,
1825
- indexCodebase: indexCodebase2,
1826
- indexPath
1827
- };
1784
+ }
1785
+ async function confirmIndexCodebase() {
1786
+ return ensureValue(await ye({
1787
+ message: "Index this codebase too?",
1788
+ initialValue: false
1789
+ }));
1828
1790
  }
1829
1791
 
1830
1792
  // src/index.ts
@@ -1936,29 +1898,34 @@ async function main() {
1936
1898
  let postIngestIndexPath;
1937
1899
  let selectedSources = opts.source ? [opts.source] : ["claude", "cursor", "codex"];
1938
1900
  let apiKey = opts.key || process.env.CONARE_API_KEY || savedApiKey;
1901
+ let interactiveTargets = MCP_TARGETS.map((target) => ({
1902
+ id: target.id,
1903
+ label: target.label,
1904
+ available: true,
1905
+ recommended: true,
1906
+ detectedCount: undefined
1907
+ }));
1908
+ let interactiveMode = false;
1939
1909
  if (shouldRunInteractive) {
1940
1910
  const detectedTools = detect();
1941
- const answers = await runInteractiveSetup({
1942
- savedApiKey,
1943
- providedApiKey: opts.key,
1944
- detectedTargets: MCP_TARGETS.map((target) => {
1945
- const detected = detectedTools.find((tool) => target.id === "claude" && tool.name === "Claude Code" || target.id === "cursor" && tool.name === "Cursor" || target.id === "codex" && tool.name === "Codex");
1946
- return {
1947
- id: target.id,
1948
- label: target.label,
1949
- available: detected?.available,
1950
- recommended: detected?.available !== false,
1951
- detectedCount: detected?.sessionCount
1952
- };
1953
- })
1911
+ interactiveTargets = MCP_TARGETS.map((target) => {
1912
+ const detected = detectedTools.find((tool) => target.id === "claude" && tool.name === "Claude Code" || target.id === "cursor" && tool.name === "Cursor" || target.id === "codex" && tool.name === "Codex");
1913
+ return {
1914
+ id: target.id,
1915
+ label: target.label,
1916
+ available: detected?.available,
1917
+ recommended: detected?.available !== false,
1918
+ detectedCount: detected?.sessionCount
1919
+ };
1954
1920
  });
1955
- apiKey = answers.apiKey || apiKey;
1956
- selectedTargets = answers.configureTargets.length > 0 ? answers.configureTargets : [];
1957
- selectedSources = answers.ingestTargets;
1958
- effectiveConfigOnly = !answers.ingestChats && !answers.indexCodebase;
1959
- effectiveIngestOnly = answers.ingestChats && answers.configureTargets.length === 0;
1960
- effectiveIndexPath = !answers.ingestChats && answers.indexCodebase ? answers.indexPath || "." : undefined;
1961
- postIngestIndexPath = answers.ingestChats && answers.indexCodebase ? answers.indexPath || "." : undefined;
1921
+ startSetup();
1922
+ apiKey = await promptApiKey({
1923
+ savedApiKey,
1924
+ providedApiKey: opts.key
1925
+ }) || apiKey;
1926
+ showDetectedApps(interactiveTargets);
1927
+ selectedSources = await selectChatSources(interactiveTargets);
1928
+ interactiveMode = true;
1962
1929
  }
1963
1930
  if (!apiKey) {
1964
1931
  printMissingKeyError();
@@ -2065,15 +2032,17 @@ Nothing new to index.`);
2065
2032
  console.log();
2066
2033
  }
2067
2034
  const tools = detect();
2068
- console.log("Detected AI tools:");
2069
- for (const t of tools) {
2070
- if (t.available) {
2071
- console.log(` + ${t.name}${t.sessionCount ? ` — ${t.sessionCount} sessions` : ""}`);
2072
- } else {
2073
- console.log(` - ${t.name} (not found)`);
2035
+ if (!interactiveMode) {
2036
+ console.log("Detected AI tools:");
2037
+ for (const t of tools) {
2038
+ if (t.available) {
2039
+ console.log(` + ${t.name}${t.sessionCount || t.sessionCount === 0 ? ` — ${t.sessionCount} sessions` : ""}`);
2040
+ } else {
2041
+ console.log(` - ${t.name} (not found)`);
2042
+ }
2074
2043
  }
2044
+ console.log();
2075
2045
  }
2076
- console.log();
2077
2046
  const allMemories = [];
2078
2047
  const shouldIngest = (name) => selectedSources.includes(name);
2079
2048
  if (shouldIngest("claude") && tools.find((t) => t.name === "Claude Code")?.available) {
@@ -2149,6 +2118,20 @@ Nothing new to index.`);
2149
2118
  }
2150
2119
  }
2151
2120
  console.log();
2121
+ if (interactiveMode) {
2122
+ selectedTargets = await selectMcpTargets(interactiveTargets);
2123
+ const shouldIndexCurrentCodebase = await confirmIndexCodebase();
2124
+ if (selectedTargets.length === 0 && selectedSources.length === 0 && !shouldIndexCurrentCodebase) {
2125
+ effectiveConfigOnly = false;
2126
+ effectiveIngestOnly = false;
2127
+ } else {
2128
+ effectiveIngestOnly = selectedTargets.length === 0;
2129
+ }
2130
+ if (shouldIndexCurrentCodebase) {
2131
+ postIngestIndexPath = ".";
2132
+ }
2133
+ finishSetup();
2134
+ }
2152
2135
  if (!opts.dryRun && !effectiveIngestOnly) {
2153
2136
  console.log("─── Configuring MCP ───");
2154
2137
  console.log("");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "conare",
3
- "version": "0.0.6",
3
+ "version": "0.0.7",
4
4
  "description": "Conare CLI for ingesting AI chat history and configuring memory at conare.ai",
5
5
  "type": "module",
6
6
  "bin": {