conare 0.2.3 → 0.3.1

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 +2210 -2133
  2. package/package.json +11 -2
package/dist/index.js CHANGED
@@ -17,6 +17,16 @@ var __toESM = (mod, isNodeMode, target) => {
17
17
  return to;
18
18
  };
19
19
  var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
20
+ var __export = (target, all) => {
21
+ for (var name in all)
22
+ __defProp(target, name, {
23
+ get: all[name],
24
+ enumerable: true,
25
+ configurable: true,
26
+ set: (newValue) => all[name] = () => newValue
27
+ });
28
+ };
29
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
20
30
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
21
31
 
22
32
  // node_modules/sisteransi/src/index.js
@@ -147,2298 +157,2327 @@ var require_picocolors = __commonJS((exports, module) => {
147
157
  module.exports.createColors = createColors;
148
158
  });
149
159
 
150
- // src/index.ts
151
- import { existsSync as existsSync8 } from "node:fs";
152
- import { join as join10 } from "node:path";
153
-
154
- // src/detect.ts
155
- import { existsSync, readdirSync } from "node:fs";
156
- import { spawnSync } from "node:child_process";
157
- import { join } from "node:path";
158
- import { homedir, platform } from "node:os";
159
- function countJsonlFiles(dir) {
160
- let count = 0;
161
- try {
162
- for (const entry of readdirSync(dir, { withFileTypes: true })) {
163
- if (entry.isDirectory()) {
164
- count += countJsonlFiles(join(dir, entry.name));
165
- } else if (entry.name.endsWith(".jsonl")) {
166
- count++;
167
- }
168
- }
169
- } catch {}
170
- return count;
160
+ // node_modules/@clack/core/dist/index.mjs
161
+ import { stdin as j, stdout as M } from "node:process";
162
+ import * as g from "node:readline";
163
+ import O from "node:readline";
164
+ import { Writable as X } from "node:stream";
165
+ function DD({ onlyFirst: e = false } = {}) {
166
+ const t = ["[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?(?:\\u0007|\\u001B\\u005C|\\u009C))", "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))"].join("|");
167
+ return new RegExp(t, e ? undefined : "g");
171
168
  }
172
- function countCursorSessions(dbPath) {
173
- try {
174
- const result = spawnSync("sqlite3", [
175
- dbPath,
176
- `
177
- WITH composer_rows AS (
178
- SELECT substr(key, 14) AS composer_id, value AS composer_json
179
- FROM cursorDiskKV
180
- WHERE key LIKE 'composerData:%'
181
- ),
182
- headers AS (
183
- SELECT
184
- composer_id,
185
- json_extract(j.value, '$.bubbleId') AS bubble_id,
186
- json_extract(j.value, '$.type') AS type
187
- FROM composer_rows, json_each(json_extract(composer_json, '$.fullConversationHeadersOnly')) AS j
188
- ),
189
- messages AS (
190
- SELECT h.composer_id, h.type
191
- FROM headers h
192
- JOIN cursorDiskKV kv
193
- ON kv.key = 'bubbleId:' || h.composer_id || ':' || h.bubble_id
194
- WHERE h.type IN (1, 2)
195
- AND length(COALESCE(json_extract(kv.value, '$.text'), '')) >= 50
196
- )
197
- SELECT count(*)
198
- FROM (
199
- SELECT composer_id
200
- FROM messages
201
- GROUP BY composer_id
202
- HAVING SUM(CASE WHEN type = 1 THEN 1 ELSE 0 END) > 0
203
- AND SUM(CASE WHEN type = 2 THEN 1 ELSE 0 END) > 0
204
- );
205
- `.trim()
206
- ], { encoding: "utf-8" });
207
- if (result.status !== 0)
208
- return 0;
209
- const count = Number.parseInt(result.stdout.trim(), 10);
210
- return Number.isFinite(count) ? count : 0;
211
- } catch {
169
+ function P(e) {
170
+ if (typeof e != "string")
171
+ throw new TypeError(`Expected a \`string\`, got \`${typeof e}\``);
172
+ return e.replace(uD, "");
173
+ }
174
+ function L(e) {
175
+ return e && e.__esModule && Object.prototype.hasOwnProperty.call(e, "default") ? e.default : e;
176
+ }
177
+ function p(e, u = {}) {
178
+ if (typeof e != "string" || e.length === 0 || (u = { ambiguousIsNarrow: true, ...u }, e = P(e), e.length === 0))
212
179
  return 0;
180
+ e = e.replace(sD(), " ");
181
+ const t = u.ambiguousIsNarrow ? 1 : 2;
182
+ let F = 0;
183
+ for (const s of e) {
184
+ const i = s.codePointAt(0);
185
+ if (i <= 31 || i >= 127 && i <= 159 || i >= 768 && i <= 879)
186
+ continue;
187
+ switch (eD.eastAsianWidth(s)) {
188
+ case "F":
189
+ case "W":
190
+ F += 2;
191
+ break;
192
+ case "A":
193
+ F += t;
194
+ break;
195
+ default:
196
+ F += 1;
197
+ }
213
198
  }
199
+ return F;
214
200
  }
215
- function detect() {
216
- const home = homedir();
217
- const tools = [];
218
- const claudeDir = join(home, ".claude", "projects");
219
- if (existsSync(claudeDir)) {
220
- const sessionCount = countJsonlFiles(claudeDir);
221
- tools.push({
222
- name: "Claude Code",
223
- available: sessionCount > 0,
224
- path: claudeDir,
225
- sessionCount
226
- });
227
- } else {
228
- tools.push({ name: "Claude Code", available: false, path: claudeDir, sessionCount: 0 });
201
+ function rD() {
202
+ const e = new Map;
203
+ for (const [u, t] of Object.entries(r)) {
204
+ for (const [F, s] of Object.entries(t))
205
+ r[F] = { open: `\x1B[${s[0]}m`, close: `\x1B[${s[1]}m` }, t[F] = r[F], e.set(s[0], s[1]);
206
+ Object.defineProperty(r, u, { value: t, enumerable: false });
229
207
  }
230
- const codexHistory = join(home, ".codex", "history.jsonl");
231
- const codexSessions = join(home, ".codex", "sessions");
232
- if (existsSync(codexHistory) || existsSync(codexSessions)) {
233
- let sessionCount = 0;
234
- if (existsSync(codexHistory)) {
235
- try {
236
- const { readFileSync } = __require("node:fs");
237
- const lines = readFileSync(codexHistory, "utf-8").split(`
238
- `).filter(Boolean);
239
- const sessions = new Set(lines.map((l) => {
240
- try {
241
- return JSON.parse(l).session_id;
242
- } catch {
243
- return null;
244
- }
245
- }));
246
- sessions.delete(null);
247
- sessionCount = sessions.size;
248
- } catch {}
208
+ return Object.defineProperty(r, "codes", { value: e, enumerable: false }), r.color.close = "\x1B[39m", r.bgColor.close = "\x1B[49m", r.color.ansi = N(), r.color.ansi256 = I(), r.color.ansi16m = R(), r.bgColor.ansi = N(w), r.bgColor.ansi256 = I(w), r.bgColor.ansi16m = R(w), Object.defineProperties(r, { rgbToAnsi256: { value: (u, t, F) => u === t && t === F ? u < 8 ? 16 : u > 248 ? 231 : Math.round((u - 8) / 247 * 24) + 232 : 16 + 36 * Math.round(u / 255 * 5) + 6 * Math.round(t / 255 * 5) + Math.round(F / 255 * 5), enumerable: false }, hexToRgb: { value: (u) => {
209
+ const t = /[a-f\d]{6}|[a-f\d]{3}/i.exec(u.toString(16));
210
+ if (!t)
211
+ return [0, 0, 0];
212
+ let [F] = t;
213
+ F.length === 3 && (F = [...F].map((i) => i + i).join(""));
214
+ const s = Number.parseInt(F, 16);
215
+ return [s >> 16 & 255, s >> 8 & 255, s & 255];
216
+ }, enumerable: false }, hexToAnsi256: { value: (u) => r.rgbToAnsi256(...r.hexToRgb(u)), enumerable: false }, ansi256ToAnsi: { value: (u) => {
217
+ if (u < 8)
218
+ return 30 + u;
219
+ if (u < 16)
220
+ return 90 + (u - 8);
221
+ let t, F, s;
222
+ if (u >= 232)
223
+ t = ((u - 232) * 10 + 8) / 255, F = t, s = t;
224
+ else {
225
+ u -= 16;
226
+ const C = u % 36;
227
+ t = Math.floor(u / 36) / 5, F = Math.floor(C / 6) / 5, s = C % 6 / 5;
249
228
  }
250
- tools.push({
251
- name: "Codex",
252
- available: true,
253
- path: existsSync(codexHistory) ? codexHistory : codexSessions,
254
- sessionCount
255
- });
256
- } else {
257
- tools.push({ name: "Codex", available: false, path: codexHistory, sessionCount: 0 });
258
- }
259
- const os = platform();
260
- let cursorDbPath;
261
- if (os === "darwin") {
262
- cursorDbPath = join(home, "Library", "Application Support", "Cursor", "User", "globalStorage", "state.vscdb");
263
- } else if (os === "win32") {
264
- cursorDbPath = join(process.env.APPDATA || join(home, "AppData", "Roaming"), "Cursor", "User", "globalStorage", "state.vscdb");
265
- } else {
266
- cursorDbPath = join(home, ".config", "Cursor", "User", "globalStorage", "state.vscdb");
267
- }
268
- tools.push({
269
- name: "Cursor",
270
- available: existsSync(cursorDbPath),
271
- path: cursorDbPath,
272
- sessionCount: existsSync(cursorDbPath) ? countCursorSessions(cursorDbPath) : 0
273
- });
274
- return tools;
229
+ const i = Math.max(t, F, s) * 2;
230
+ if (i === 0)
231
+ return 30;
232
+ let D = 30 + (Math.round(s) << 2 | Math.round(F) << 1 | Math.round(t));
233
+ return i === 2 && (D += 60), D;
234
+ }, enumerable: false }, rgbToAnsi: { value: (u, t, F) => r.ansi256ToAnsi(r.rgbToAnsi256(u, t, F)), enumerable: false }, hexToAnsi: { value: (u) => r.ansi256ToAnsi(r.hexToAnsi256(u)), enumerable: false } }), r;
275
235
  }
276
-
277
- // src/ingest/claude.ts
278
- import { readdirSync as readdirSync2, readFileSync as readFileSync2 } from "node:fs";
279
- import { join as join3, basename } from "node:path";
280
- import { homedir as homedir3 } from "node:os";
281
-
282
- // src/ingest/shared.ts
283
- import { existsSync as existsSync2, readFileSync, writeFileSync, mkdirSync } from "node:fs";
284
- import { createHash } from "node:crypto";
285
- import { join as join2 } from "node:path";
286
- import { homedir as homedir2 } from "node:os";
287
- var MANIFEST_PATH = join2(homedir2(), ".conare", "ingested.json");
288
- var MIN_SUBSTANTIVE = 200;
289
- var NARRATION_RE = /^[\s\n]*(Let me |Now let me |Now I['\u2019]|Now add |Now fix |Now replace |Now integrate |Now update |Now pass |Now clean |Now build|Update the |Builds clean|Deployed\.|Wait, I |Let['\u2019]s test |Good —|Great\.|Perfect\.|Alright|OK,? let me|I[''\u2019]ll |Starting |I need to |Need |I found |I read |I[''\u2019]ve (loaded|confirmed|verified)|Context loaded|Next (I[''\u2019]|step)|Deps confirm|Diff check|Still missing|I[''\u2019]ll (do|check|inspect|trace|run|grab|pull|read|verify))/;
290
- function isNarration(text) {
291
- const stripped = text.trim();
292
- if (stripped.length < MIN_SUBSTANTIVE)
293
- return true;
294
- if (stripped.length <= 300 && NARRATION_RE.test(stripped))
295
- return true;
236
+ function Y(e, u, t) {
237
+ return String(e).normalize().replace(/\r\n/g, `
238
+ `).split(`
239
+ `).map((F) => lD(F, u, t)).join(`
240
+ `);
241
+ }
242
+ function $(e, u) {
243
+ if (typeof e == "string")
244
+ return B.aliases.get(e) === u;
245
+ for (const t of e)
246
+ if (t !== undefined && $(t, u))
247
+ return true;
296
248
  return false;
297
249
  }
298
- function cleanText(raw) {
299
- let text = raw;
300
- text = text.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g, "");
301
- text = text.replace(/<attached-context[\s\S]*?<\/attached-context>/g, "");
302
- text = text.replace(/<environment_context>[\s\S]*?<\/environment_context>/g, "");
303
- return text.trim();
250
+ function BD(e, u) {
251
+ if (e === u)
252
+ return;
253
+ const t = e.split(`
254
+ `), F = u.split(`
255
+ `), s = [];
256
+ for (let i = 0;i < Math.max(t.length, F.length); i++)
257
+ t[i] !== F[i] && s.push(i);
258
+ return s;
304
259
  }
305
- function createContentHash(content) {
306
- return createHash("sha256").update(content).digest("hex").slice(0, 16);
260
+ function pD(e) {
261
+ return e === S;
307
262
  }
308
- function getIngested() {
309
- try {
310
- if (existsSync2(MANIFEST_PATH)) {
311
- return JSON.parse(readFileSync(MANIFEST_PATH, "utf-8"));
312
- }
313
- } catch {}
314
- return {};
263
+ function m(e, u) {
264
+ const t = e;
265
+ t.isTTY && t.setRawMode(u);
315
266
  }
316
- function markIngested(source, sessionIds) {
317
- const manifest = getIngested();
318
- const existing = new Set(manifest[source] || []);
319
- for (const id of sessionIds)
320
- existing.add(id);
321
- manifest[source] = [...existing];
322
- const dir = join2(homedir2(), ".conare");
323
- if (!existsSync2(dir))
324
- mkdirSync(dir, { recursive: true });
325
- writeFileSync(MANIFEST_PATH, JSON.stringify(manifest, null, 2));
326
- }
327
- function isIngested(source, sessionId) {
328
- const manifest = getIngested();
329
- return (manifest[source] || []).includes(sessionId);
330
- }
331
- function clearIngested(source) {
332
- const manifest = getIngested();
333
- if (source) {
334
- delete manifest[source];
335
- } else {
336
- for (const key of Object.keys(manifest))
337
- delete manifest[key];
338
- }
339
- const dir = join2(homedir2(), ".conare");
340
- if (!existsSync2(dir))
341
- mkdirSync(dir, { recursive: true });
342
- writeFileSync(MANIFEST_PATH, JSON.stringify(manifest, null, 2));
267
+ function fD({ input: e = j, output: u = M, overwrite: t = true, hideCursor: F = true } = {}) {
268
+ const s = g.createInterface({ input: e, output: u, prompt: "", tabSize: 1 });
269
+ g.emitKeypressEvents(e, s), e.isTTY && e.setRawMode(true);
270
+ const i = (D, { name: C, sequence: n }) => {
271
+ const E = String(D);
272
+ if ($([E, C, n], "cancel")) {
273
+ F && u.write(import_sisteransi.cursor.show), process.exit(0);
274
+ return;
275
+ }
276
+ if (!t)
277
+ return;
278
+ const a = C === "return" ? 0 : -1, o = C === "return" ? -1 : 0;
279
+ g.moveCursor(u, a, o, () => {
280
+ g.clearLine(u, 1, () => {
281
+ e.once("keypress", i);
282
+ });
283
+ });
284
+ };
285
+ return F && u.write(import_sisteransi.cursor.hide), e.once("keypress", i), () => {
286
+ e.off("keypress", i), F && u.write(import_sisteransi.cursor.show), e.isTTY && !AD && e.setRawMode(false), s.terminal = false, s.close();
287
+ };
343
288
  }
344
289
 
345
- // src/ingest/claude.ts
346
- var MAX_CONTENT = 48000;
347
- var MIN_TURN_LEN = 50;
348
- function extractText(content) {
349
- if (typeof content === "string")
350
- return content;
351
- if (!Array.isArray(content))
352
- return "";
353
- return content.filter((b) => b.type === "text" && b.text).map((b) => b.text).join(`
354
- `);
355
- }
356
- function parseSession(lines) {
357
- const rounds = [];
358
- let date = null;
359
- let currentUser = null;
360
- let currentAssistant = [];
361
- for (const line of lines) {
362
- if (!line.trim())
363
- continue;
364
- let obj;
365
- try {
366
- obj = JSON.parse(line);
367
- } catch {
368
- continue;
369
- }
370
- if (!date && obj.timestamp)
371
- date = obj.timestamp.slice(0, 10);
372
- if (obj.type === "user") {
373
- const text = cleanText(extractText(obj.message?.content));
374
- if (text.length >= MIN_TURN_LEN) {
375
- if (currentUser !== null && currentAssistant.length > 0) {
376
- rounds.push({ user: currentUser, assistantParts: currentAssistant });
377
- }
378
- currentUser = text;
379
- currentAssistant = [];
290
+ class x {
291
+ constructor(u, t = true) {
292
+ h(this, "input"), h(this, "output"), h(this, "_abortSignal"), h(this, "rl"), h(this, "opts"), h(this, "_render"), h(this, "_track", false), h(this, "_prevFrame", ""), h(this, "_subscribers", new Map), h(this, "_cursor", 0), h(this, "state", "initial"), h(this, "error", ""), h(this, "value");
293
+ const { input: F = j, output: s = M, render: i, signal: D, ...C } = u;
294
+ this.opts = C, this.onKeypress = this.onKeypress.bind(this), this.close = this.close.bind(this), this.render = this.render.bind(this), this._render = i.bind(this), this._track = t, this._abortSignal = D, this.input = F, this.output = s;
295
+ }
296
+ unsubscribe() {
297
+ this._subscribers.clear();
298
+ }
299
+ setSubscriber(u, t) {
300
+ const F = this._subscribers.get(u) ?? [];
301
+ F.push(t), this._subscribers.set(u, F);
302
+ }
303
+ on(u, t) {
304
+ this.setSubscriber(u, { cb: t });
305
+ }
306
+ once(u, t) {
307
+ this.setSubscriber(u, { cb: t, once: true });
308
+ }
309
+ emit(u, ...t) {
310
+ const F = this._subscribers.get(u) ?? [], s = [];
311
+ for (const i of F)
312
+ i.cb(...t), i.once && s.push(() => F.splice(F.indexOf(i), 1));
313
+ for (const i of s)
314
+ i();
315
+ }
316
+ prompt() {
317
+ return new Promise((u, t) => {
318
+ if (this._abortSignal) {
319
+ if (this._abortSignal.aborted)
320
+ return this.state = "cancel", this.close(), u(S);
321
+ this._abortSignal.addEventListener("abort", () => {
322
+ this.state = "cancel", this.close();
323
+ }, { once: true });
380
324
  }
381
- } else if (obj.type === "assistant") {
382
- const text = cleanText(extractText(obj.message?.content));
383
- if (text.length >= MIN_TURN_LEN) {
384
- currentAssistant.push(text);
325
+ const F = new X;
326
+ F._write = (s, i, D) => {
327
+ this._track && (this.value = this.rl?.line.replace(/\t/g, ""), this._cursor = this.rl?.cursor ?? 0, this.emit("value", this.value)), D();
328
+ }, this.input.pipe(F), this.rl = O.createInterface({ input: this.input, output: F, tabSize: 2, prompt: "", escapeCodeTimeout: 50, terminal: true }), O.emitKeypressEvents(this.input, this.rl), this.rl.prompt(), this.opts.initialValue !== undefined && this._track && this.rl.write(this.opts.initialValue), this.input.on("keypress", this.onKeypress), m(this.input, true), this.output.on("resize", this.render), this.render(), this.once("submit", () => {
329
+ this.output.write(import_sisteransi.cursor.show), this.output.off("resize", this.render), m(this.input, false), u(this.value);
330
+ }), this.once("cancel", () => {
331
+ this.output.write(import_sisteransi.cursor.show), this.output.off("resize", this.render), m(this.input, false), u(S);
332
+ });
333
+ });
334
+ }
335
+ onKeypress(u, t) {
336
+ if (this.state === "error" && (this.state = "active"), t?.name && (!this._track && B.aliases.has(t.name) && this.emit("cursor", B.aliases.get(t.name)), B.actions.has(t.name) && this.emit("cursor", t.name)), u && (u.toLowerCase() === "y" || u.toLowerCase() === "n") && this.emit("confirm", u.toLowerCase() === "y"), u === "\t" && this.opts.placeholder && (this.value || (this.rl?.write(this.opts.placeholder), this.emit("value", this.opts.placeholder))), u && this.emit("key", u.toLowerCase()), t?.name === "return") {
337
+ if (this.opts.validate) {
338
+ const F = this.opts.validate(this.value);
339
+ F && (this.error = F instanceof Error ? F.message : F, this.state = "error", this.rl?.write(this.value));
385
340
  }
341
+ this.state !== "error" && (this.state = "submit");
386
342
  }
343
+ $([u, t?.name, t?.sequence], "cancel") && (this.state = "cancel"), (this.state === "submit" || this.state === "cancel") && this.emit("finalize"), this.render(), (this.state === "submit" || this.state === "cancel") && this.close();
387
344
  }
388
- if (currentUser !== null && currentAssistant.length > 0) {
389
- rounds.push({ user: currentUser, assistantParts: currentAssistant });
345
+ close() {
346
+ this.input.unpipe(), this.input.removeListener("keypress", this.onKeypress), this.output.write(`
347
+ `), m(this.input, false), this.rl?.close(), this.rl = undefined, this.emit(`${this.state}`, this.value), this.unsubscribe();
390
348
  }
391
- const turns = rounds.map((r) => ({
392
- user: r.user,
393
- assistant: r.assistantParts.filter((p) => !isNarration(p)).join(`
394
-
395
- `)
396
- })).filter((t) => t.assistant.length >= MIN_TURN_LEN);
397
- return { turns, date };
398
- }
399
- function ingestClaude() {
400
- const projectsDir = join3(homedir3(), ".claude", "projects");
401
- const memories = [];
402
- const sessionIds = [];
403
- let filtered = 0;
404
- let deduped = 0;
405
- let projectDirs;
406
- try {
407
- projectDirs = readdirSync2(projectsDir);
408
- } catch {
409
- return { memories, sessionIds, skipped: 0, filtered, deduped };
349
+ restoreCursor() {
350
+ const u = Y(this._prevFrame, process.stdout.columns, { hard: true }).split(`
351
+ `).length - 1;
352
+ this.output.write(import_sisteransi.cursor.move(-999, u * -1));
410
353
  }
411
- for (const projDir of projectDirs) {
412
- const projPath = join3(projectsDir, projDir);
413
- const project = projDir.replace(/^-Users-[^-]+-/, "").replace(/-/g, "/") || projDir;
414
- let files;
415
- try {
416
- files = readdirSync2(projPath).filter((f) => f.endsWith(".jsonl"));
417
- } catch {
418
- continue;
419
- }
420
- for (const file of files) {
421
- const sessionId = basename(file, ".jsonl");
422
- const raw = readFileSync2(join3(projPath, file), "utf-8");
423
- const { turns, date } = parseSession(raw.split(`
424
- `));
425
- if (turns.length === 0) {
426
- filtered++;
427
- continue;
428
- }
429
- const header = `# Chat: ${project}${date ? ` | ${date}` : ""}`;
430
- const body = turns.map((t) => {
431
- const q = t.user.length > 300 ? t.user.slice(0, 300) + "..." : t.user;
432
- return `## Q: ${q}
433
-
434
- ${t.assistant}`;
435
- }).join(`
436
-
437
- ---
438
-
354
+ render() {
355
+ const u = Y(this._render(this) ?? "", process.stdout.columns, { hard: true });
356
+ if (u !== this._prevFrame) {
357
+ if (this.state === "initial")
358
+ this.output.write(import_sisteransi.cursor.hide);
359
+ else {
360
+ const t = BD(this._prevFrame, u);
361
+ if (this.restoreCursor(), t && t?.length === 1) {
362
+ const F = t[0];
363
+ this.output.write(import_sisteransi.cursor.move(0, F)), this.output.write(import_sisteransi.erase.lines(1));
364
+ const s = u.split(`
439
365
  `);
440
- let content = `${header}
441
-
442
- ${body}`;
443
- if (content.length > MAX_CONTENT)
444
- content = content.slice(0, MAX_CONTENT) + `
445
-
446
- [truncated]`;
447
- const contentHash = createContentHash(content);
448
- const dedupKey = `claude:${sessionId}`;
449
- const fingerprint = `${dedupKey}:${contentHash}`;
450
- if (isIngested("claude", fingerprint)) {
451
- deduped++;
452
- continue;
453
- }
454
- memories.push({
455
- content,
456
- containerTag: "claude-chats",
457
- metadata: {
458
- dedupKey,
459
- contentHash,
460
- source: "claude-code",
461
- sessionId,
462
- project,
463
- date: date || "unknown"
366
+ this.output.write(s[F]), this._prevFrame = u, this.output.write(import_sisteransi.cursor.move(0, s.length - F - 1));
367
+ return;
464
368
  }
465
- });
466
- sessionIds.push(sessionId);
369
+ if (t && t?.length > 1) {
370
+ const F = t[0];
371
+ this.output.write(import_sisteransi.cursor.move(0, F)), this.output.write(import_sisteransi.erase.down());
372
+ const s = u.split(`
373
+ `).slice(F);
374
+ this.output.write(s.join(`
375
+ `)), this._prevFrame = u;
376
+ return;
377
+ }
378
+ this.output.write(import_sisteransi.erase.down());
379
+ }
380
+ this.output.write(u), this.state === "initial" && (this.state = "active"), this._prevFrame = u;
467
381
  }
468
382
  }
469
- return { memories, sessionIds, skipped: filtered + deduped, filtered, deduped };
470
- }
471
-
472
- // src/ingest/codex.ts
473
- import { existsSync as existsSync3, readFileSync as readFileSync3, readdirSync as readdirSync3 } from "node:fs";
474
- import { join as join4, basename as basename2 } from "node:path";
475
- import { homedir as homedir4 } from "node:os";
476
- var MAX_CONTENT2 = 48000;
477
- function isCodexBoilerplate(text) {
478
- return text.startsWith("# AGENTS.md instructions for") || text.startsWith("<INSTRUCTIONS>") || text.startsWith("<user_instructions>") || text.startsWith("<user_action>");
479
- }
480
- function stripEnvironmentContext(text) {
481
- let cwd = null;
482
- const cwdMatch = text.match(/<cwd>([^<]+)<\/cwd>/);
483
- if (cwdMatch)
484
- cwd = cwdMatch[1];
485
- const cleaned = text.replace(/<environment_context>[\s\S]*?<\/environment_context>/g, "").trim();
486
- return { text: cleaned, cwd };
487
383
  }
488
- function projectFromCwd(cwd) {
489
- return cwd.replace(/^\/Users\/[^/]+\//, "");
490
- }
491
- function ingestCodex() {
492
- const memories = [];
493
- const sessionIds = [];
494
- let filtered = 0;
495
- let deduped = 0;
496
- const historyPath = join4(homedir4(), ".codex", "history.jsonl");
497
- if (existsSync3(historyPath)) {
498
- try {
499
- const lines = readFileSync3(historyPath, "utf-8").split(`
500
- `).filter(Boolean);
501
- const sessions = new Map;
502
- for (const line of lines) {
503
- try {
504
- const obj = JSON.parse(line);
505
- if (!obj.session_id || !obj.text)
506
- continue;
507
- if (!sessions.has(obj.session_id))
508
- sessions.set(obj.session_id, []);
509
- sessions.get(obj.session_id).push({ ts: obj.ts, text: obj.text });
510
- } catch {
511
- continue;
512
- }
513
- }
514
- for (const [sessionId, entries] of sessions) {
515
- entries.sort((a, b) => a.ts - b.ts);
516
- const date = new Date(entries[0].ts * 1000).toISOString().slice(0, 10);
517
- let project = null;
518
- const cleanEntries = [];
519
- for (const e of entries) {
520
- let text = cleanText(e.text);
521
- if (isCodexBoilerplate(text))
522
- continue;
523
- const env = stripEnvironmentContext(text);
524
- text = env.text;
525
- if (!project && env.cwd)
526
- project = projectFromCwd(env.cwd);
527
- if (text.length === 0)
528
- continue;
529
- cleanEntries.push(text.length > 300 ? text.slice(0, 300) + "..." : text);
530
- }
531
- const body = cleanEntries.filter(Boolean).join(`
532
-
533
- ---
534
-
535
- `);
536
- let content = `# Codex Chat | ${date}
537
-
538
- ${body}`;
539
- if (content.length > MAX_CONTENT2)
540
- content = content.slice(0, MAX_CONTENT2) + `
541
-
542
- [truncated]`;
543
- if (content.length < 100) {
544
- filtered++;
545
- continue;
546
- }
547
- const contentHash = createContentHash(content);
548
- const dedupKey = `codex:${sessionId}`;
549
- const fingerprint = `${dedupKey}:${contentHash}`;
550
- if (isIngested("codex", fingerprint)) {
551
- deduped++;
552
- continue;
553
- }
554
- memories.push({
555
- content,
556
- containerTag: "codex-chats",
557
- metadata: {
558
- dedupKey,
559
- contentHash,
560
- source: "codex",
561
- sessionId,
562
- date,
563
- ...project ? { project } : {}
564
- }
565
- });
566
- sessionIds.push(sessionId);
567
- }
568
- } catch {}
569
- }
570
- const sessionsDir = join4(homedir4(), ".codex", "sessions");
571
- if (existsSync3(sessionsDir)) {
572
- try {
573
- const stats = { filtered: 0, deduped: 0 };
574
- walkCodexSessions(sessionsDir, memories, sessionIds, stats);
575
- filtered += stats.filtered;
576
- deduped += stats.deduped;
577
- } catch {}
578
- }
579
- return { memories, sessionIds, skipped: filtered + deduped, filtered, deduped };
580
- }
581
- function walkCodexSessions(dir, memories, sessionIds, stats) {
582
- try {
583
- for (const entry of readdirSync3(dir, { withFileTypes: true })) {
584
- if (entry.isDirectory()) {
585
- walkCodexSessions(join4(dir, entry.name), memories, sessionIds, stats);
586
- } else if (entry.name.endsWith(".jsonl")) {
587
- const sessionId = basename2(entry.name, ".jsonl");
588
- if (sessionIds.includes(sessionId))
589
- continue;
590
- try {
591
- const lines = readFileSync3(join4(dir, entry.name), "utf-8").split(`
592
- `).filter(Boolean);
593
- let date = null;
594
- let project = null;
595
- const rounds = [];
596
- let currentUser = null;
597
- let currentAssistant = [];
598
- for (const line of lines) {
599
- try {
600
- const obj = JSON.parse(line);
601
- if (!date && obj.timestamp)
602
- date = obj.timestamp.slice(0, 10);
603
- if (obj.type === "session_meta" && obj.payload?.cwd) {
604
- project = projectFromCwd(obj.payload.cwd);
605
- }
606
- if (obj.type !== "response_item" || obj.payload?.type !== "message")
607
- continue;
608
- const role = obj.payload.role;
609
- const msgContent = obj.payload.content;
610
- if (!Array.isArray(msgContent))
611
- continue;
612
- if (role === "user") {
613
- for (const block of msgContent) {
614
- if (block.type === "input_text" && block.text) {
615
- const text = cleanText(block.text);
616
- if (isCodexBoilerplate(text))
617
- continue;
618
- if (text.length >= 50) {
619
- if (currentUser !== null && currentAssistant.length > 0) {
620
- rounds.push({ user: currentUser, assistantParts: currentAssistant });
621
- }
622
- currentUser = text;
623
- currentAssistant = [];
624
- }
625
- }
626
- }
627
- } else if (role === "assistant") {
628
- for (const block of msgContent) {
629
- if (block.type === "output_text" && block.text) {
630
- const text = cleanText(block.text);
631
- if (!isNarration(text)) {
632
- currentAssistant.push(text);
633
- }
634
- }
635
- }
636
- }
637
- } catch {
638
- continue;
639
- }
640
- }
641
- if (currentUser !== null && currentAssistant.length > 0) {
642
- rounds.push({ user: currentUser, assistantParts: currentAssistant });
643
- }
644
- if (rounds.length === 0) {
645
- stats.filtered++;
646
- continue;
647
- }
648
- const body = rounds.map((r) => {
649
- const q = r.user.length > 300 ? r.user.slice(0, 300) + "..." : r.user;
650
- const assistant = r.assistantParts.join(`
651
-
652
- `);
653
- return `## Q: ${q}
654
-
655
- ${assistant}`;
656
- }).join(`
657
-
658
- ---
659
-
660
- `);
661
- let content = `# Codex Session${project ? `: ${project}` : ""} | ${date || "unknown"}
662
-
663
- ${body}`;
664
- if (content.length > MAX_CONTENT2)
665
- content = content.slice(0, MAX_CONTENT2) + `
666
-
667
- [truncated]`;
668
- const contentHash = createContentHash(content);
669
- const dedupKey = `codex:${sessionId}`;
670
- const fingerprint = `${dedupKey}:${contentHash}`;
671
- if (isIngested("codex", fingerprint)) {
672
- stats.deduped++;
673
- continue;
674
- }
675
- memories.push({
676
- content,
677
- containerTag: "codex-chats",
678
- metadata: {
679
- dedupKey,
680
- contentHash,
681
- source: "codex-session",
682
- sessionId,
683
- date: date || "unknown",
684
- ...project ? { project } : {}
685
- }
686
- });
687
- sessionIds.push(sessionId);
688
- } catch {}
689
- }
690
- }
691
- } catch {}
692
- }
693
-
694
- // src/ingest/cursor.ts
695
- import { readFileSync as readFileSync4, statSync } from "node:fs";
696
- import { join as join5 } from "node:path";
697
- import { createRequire as createRequire2 } from "node:module";
698
- var MAX_CONTENT3 = 48000;
699
- var MAX_DB_SIZE = 2 * 1024 * 1024 * 1024;
700
- var WARN_DB_SIZE = 500 * 1024 * 1024;
701
- var MIN_TURN_LEN2 = 50;
702
- function loadSqlJs(wasmDir) {
703
- try {
704
- if (wasmDir) {
705
- const require2 = createRequire2(join5(wasmDir, "sql.js", "package.json"));
706
- return require2("sql.js");
707
- } else {
708
- const require2 = createRequire2(import.meta.url);
709
- return require2("sql.js");
710
- }
711
- } catch {
712
- return null;
713
- }
714
- }
715
- function openDb(initSqlJs, dbPath, wasmDir) {
716
- const locateOpts = {};
717
- if (wasmDir) {
718
- locateOpts.locateFile = (file) => join5(wasmDir, "sql.js", "dist", file);
719
- }
720
- return initSqlJs(locateOpts).then((SQL) => {
721
- const buffer = readFileSync4(dbPath);
722
- return new SQL.Database(buffer);
723
- });
724
- }
725
- function extractTurns(db, composerId, bubbleHeaders) {
726
- const turns = [];
727
- let pendingUser = null;
728
- for (const header of bubbleHeaders) {
729
- let text = "";
730
- try {
731
- const result = db.exec(`SELECT value FROM cursorDiskKV WHERE key = 'bubbleId:${composerId}:${header.bubbleId}'`);
732
- if (result.length > 0) {
733
- const bubble = JSON.parse(result[0].values[0][0]);
734
- text = cleanText(bubble.text || "");
735
- }
736
- } catch {
737
- continue;
738
- }
739
- if (text.length < MIN_TURN_LEN2)
740
- continue;
741
- if (header.type === 1) {
742
- pendingUser = text;
743
- } else if (header.type === 2 && pendingUser) {
744
- turns.push({ user: pendingUser, assistant: text });
745
- pendingUser = null;
746
- }
747
- }
748
- return turns;
749
- }
750
- async function ingestCursor(dbPath, wasmDir) {
751
- const memories = [];
752
- const sessionIds = [];
753
- let filtered = 0;
754
- let deduped = 0;
755
- let fileSize;
756
- try {
757
- fileSize = statSync(dbPath).size;
758
- } catch {
759
- console.log(" Skipping Cursor: database not accessible");
760
- return { memories, sessionIds, skipped: 0, filtered, deduped };
761
- }
762
- if (fileSize > MAX_DB_SIZE) {
763
- console.log(` Skipping Cursor: database too large (${(fileSize / 1024 / 1024 / 1024).toFixed(1)}GB)`);
764
- return { memories, sessionIds, skipped: 0, filtered, deduped };
765
- }
766
- if (fileSize > WARN_DB_SIZE) {
767
- console.log(` Warning: large database (${(fileSize / 1024 / 1024).toFixed(0)}MB), loading into memory...`);
768
- }
769
- const initSqlJs = loadSqlJs(wasmDir);
770
- if (!initSqlJs) {
771
- console.log(" Skipping Cursor: sql.js not available");
772
- return { memories, sessionIds, skipped: 0, filtered, deduped };
773
- }
774
- let db;
775
- try {
776
- db = await openDb(initSqlJs, dbPath, wasmDir);
777
- } catch (e) {
778
- console.log(` Skipping Cursor: cannot open database (${e.message})`);
779
- return { memories, sessionIds, skipped: 0, filtered, deduped };
780
- }
781
- try {
782
- let rows = [];
783
- try {
784
- const results = db.exec("SELECT key, value FROM cursorDiskKV WHERE key LIKE 'composerData:%'");
785
- if (results.length > 0)
786
- rows = results[0].values;
787
- } catch {}
788
- for (const [key, value] of rows) {
789
- const composerId = key.replace("composerData:", "");
790
- let parsed;
791
- try {
792
- parsed = JSON.parse(value);
793
- if (!parsed || typeof parsed !== "object") {
794
- filtered++;
795
- continue;
796
- }
797
- } catch {
798
- filtered++;
799
- continue;
800
- }
801
- const bubbleHeaders = parsed.fullConversationHeadersOnly;
802
- if (!Array.isArray(bubbleHeaders) || bubbleHeaders.length === 0) {
803
- filtered++;
804
- continue;
805
- }
806
- const turns = extractTurns(db, composerId, bubbleHeaders);
807
- if (turns.length === 0) {
808
- filtered++;
809
- continue;
810
- }
811
- const sessionName = parsed.name || "Cursor Chat";
812
- const date = parsed.createdAt ? new Date(parsed.createdAt).toISOString().slice(0, 10) : "unknown";
813
- const header = `# ${sessionName} | ${date}`;
814
- const body = turns.map((t) => {
815
- const q = t.user.length > 300 ? t.user.slice(0, 300) + "..." : t.user;
816
- return `## Q: ${q}
817
-
818
- ${t.assistant}`;
819
- }).join(`
820
-
821
- ---
822
-
823
- `);
824
- let content = `${header}
825
-
826
- ${body}`;
827
- if (content.length > MAX_CONTENT3)
828
- content = content.slice(0, MAX_CONTENT3) + `
829
-
830
- [truncated]`;
831
- const contentHash = createContentHash(content);
832
- const dedupKey = `cursor:${composerId}`;
833
- const fingerprint = `${dedupKey}:${contentHash}`;
834
- if (isIngested("cursor", fingerprint)) {
835
- deduped++;
384
+ var import_sisteransi, import_picocolors, uD, W, tD, eD, FD = function() {
385
+ return /\uD83C\uDFF4\uDB40\uDC67\uDB40\uDC62(?:\uDB40\uDC77\uDB40\uDC6C\uDB40\uDC73|\uDB40\uDC73\uDB40\uDC63\uDB40\uDC74|\uDB40\uDC65\uDB40\uDC6E\uDB40\uDC67)\uDB40\uDC7F|(?:\uD83E\uDDD1\uD83C\uDFFF\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB-\uDFFE])|(?:\uD83E\uDDD1\uD83C\uDFFE\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFE\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB-\uDFFD\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFD\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFC\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB\uDFFD-\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFB\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFB\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFC-\uDFFF])|\uD83D\uDC68(?:\uD83C\uDFFB(?:\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF]))|\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFC-\uDFFF])|[\u2695\u2696\u2708]\uFE0F|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))?|(?:\uD83C[\uDFFC-\uDFFF])\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF]))|\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83D\uDC68|(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFE])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFD\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFD-\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])\uFE0F|\u200D(?:(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D[\uDC66\uDC67])|\uD83D[\uDC66\uDC67])|\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC)?|(?:\uD83D\uDC69(?:\uD83C\uDFFB\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69])|(?:\uD83C[\uDFFC-\uDFFF])\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69]))|\uD83E\uDDD1(?:\uD83C[\uDFFB-\uDFFF])\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1)(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|\uD83D\uDC69(?:\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFB\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))|\uD83E\uDDD1(?:\u200D(?:\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFB\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))|\uD83D\uDC69\u200D\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D[\uDC66\uDC67])|\uD83D\uDC69\u200D\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|(?:\uD83D\uDC41\uFE0F\u200D\uD83D\uDDE8|\uD83E\uDDD1(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])|\uD83D\uDC69(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])|\uD83D\uDE36\u200D\uD83C\uDF2B|\uD83C\uDFF3\uFE0F\u200D\u26A7|\uD83D\uDC3B\u200D\u2744|(?:(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC6F|\uD83E[\uDD3C\uDDDE\uDDDF])\u200D[\u2640\u2642]|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])\u200D[\u2640\u2642]|\uD83C\uDFF4\u200D\u2620|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])\u200D[\u2640\u2642]|[\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u2328\u23CF\u23ED-\u23EF\u23F1\u23F2\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB\u25FC\u2600-\u2604\u260E\u2611\u2618\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u2692\u2694-\u2697\u2699\u269B\u269C\u26A0\u26A7\u26B0\u26B1\u26C8\u26CF\u26D1\u26D3\u26E9\u26F0\u26F1\u26F4\u26F7\u26F8\u2702\u2708\u2709\u270F\u2712\u2714\u2716\u271D\u2721\u2733\u2734\u2744\u2747\u2763\u27A1\u2934\u2935\u2B05-\u2B07\u3030\u303D\u3297\u3299]|\uD83C[\uDD70\uDD71\uDD7E\uDD7F\uDE02\uDE37\uDF21\uDF24-\uDF2C\uDF36\uDF7D\uDF96\uDF97\uDF99-\uDF9B\uDF9E\uDF9F\uDFCD\uDFCE\uDFD4-\uDFDF\uDFF5\uDFF7]|\uD83D[\uDC3F\uDCFD\uDD49\uDD4A\uDD6F\uDD70\uDD73\uDD76-\uDD79\uDD87\uDD8A-\uDD8D\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA\uDECB\uDECD-\uDECF\uDEE0-\uDEE5\uDEE9\uDEF0\uDEF3])\uFE0F|\uD83C\uDFF3\uFE0F\u200D\uD83C\uDF08|\uD83D\uDC69\u200D\uD83D\uDC67|\uD83D\uDC69\u200D\uD83D\uDC66|\uD83D\uDE35\u200D\uD83D\uDCAB|\uD83D\uDE2E\u200D\uD83D\uDCA8|\uD83D\uDC15\u200D\uD83E\uDDBA|\uD83E\uDDD1(?:\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC|\uD83C\uDFFB)?|\uD83D\uDC69(?:\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC|\uD83C\uDFFB)?|\uD83C\uDDFD\uD83C\uDDF0|\uD83C\uDDF6\uD83C\uDDE6|\uD83C\uDDF4\uD83C\uDDF2|\uD83D\uDC08\u200D\u2B1B|\u2764\uFE0F\u200D(?:\uD83D\uDD25|\uD83E\uDE79)|\uD83D\uDC41\uFE0F|\uD83C\uDFF3\uFE0F|\uD83C\uDDFF(?:\uD83C[\uDDE6\uDDF2\uDDFC])|\uD83C\uDDFE(?:\uD83C[\uDDEA\uDDF9])|\uD83C\uDDFC(?:\uD83C[\uDDEB\uDDF8])|\uD83C\uDDFB(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA])|\uD83C\uDDFA(?:\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF])|\uD83C\uDDF9(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF])|\uD83C\uDDF8(?:\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF])|\uD83C\uDDF7(?:\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC])|\uD83C\uDDF5(?:\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE])|\uD83C\uDDF3(?:\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF])|\uD83C\uDDF2(?:\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF])|\uD83C\uDDF1(?:\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE])|\uD83C\uDDF0(?:\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF])|\uD83C\uDDEF(?:\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5])|\uD83C\uDDEE(?:\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9])|\uD83C\uDDED(?:\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA])|\uD83C\uDDEC(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE])|\uD83C\uDDEB(?:\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7])|\uD83C\uDDEA(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA])|\uD83C\uDDE9(?:\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF])|\uD83C\uDDE8(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF])|\uD83C\uDDE7(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF])|\uD83C\uDDE6(?:\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF])|[#\*0-9]\uFE0F\u20E3|\u2764\uFE0F|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])|\uD83C\uDFF4|(?:[\u270A\u270B]|\uD83C[\uDF85\uDFC2\uDFC7]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE4C\uDE4F\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1C\uDD1E\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5])(?:\uD83C[\uDFFB-\uDFFF])|(?:[\u261D\u270C\u270D]|\uD83D[\uDD74\uDD90])(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])|[\u270A\u270B]|\uD83C[\uDF85\uDFC2\uDFC7]|\uD83D[\uDC08\uDC15\uDC3B\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE2E\uDE35\uDE36\uDE4C\uDE4F\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1C\uDD1E\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5]|\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD]|\uD83D\uDC6F|\uD83E[\uDD3C\uDDDE\uDDDF]|[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF84\uDF86-\uDF93\uDFA0-\uDFC1\uDFC5\uDFC6\uDFC8\uDFC9\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC07\uDC09-\uDC14\uDC16-\uDC3A\uDC3C-\uDC3E\uDC40\uDC44\uDC45\uDC51-\uDC65\uDC6A\uDC79-\uDC7B\uDC7D-\uDC80\uDC84\uDC88-\uDC8E\uDC90\uDC92-\uDCA9\uDCAB-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDDA4\uDDFB-\uDE2D\uDE2F-\uDE34\uDE37-\uDE44\uDE48-\uDE4A\uDE80-\uDEA2\uDEA4-\uDEB3\uDEB7-\uDEBF\uDEC1-\uDEC5\uDED0-\uDED2\uDED5-\uDED7\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0D\uDD0E\uDD10-\uDD17\uDD1D\uDD20-\uDD25\uDD27-\uDD2F\uDD3A\uDD3F-\uDD45\uDD47-\uDD76\uDD78\uDD7A-\uDDB4\uDDB7\uDDBA\uDDBC-\uDDCB\uDDD0\uDDE0-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6]|(?:[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u270A\u270B\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF93\uDFA0-\uDFCA\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF4\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC3E\uDC40\uDC42-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDD7A\uDD95\uDD96\uDDA4\uDDFB-\uDE4F\uDE80-\uDEC5\uDECC\uDED0-\uDED2\uDED5-\uDED7\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0C-\uDD3A\uDD3C-\uDD45\uDD47-\uDD78\uDD7A-\uDDCB\uDDCD-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6])|(?:[#\*0-9\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u267F\u2692-\u2697\u2699\u269B\u269C\u26A0\u26A1\u26A7\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753-\u2755\u2757\u2763\u2764\u2795-\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]|\uD83C[\uDC04\uDCCF\uDD70\uDD71\uDD7E\uDD7F\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE02\uDE1A\uDE2F\uDE32-\uDE3A\uDE50\uDE51\uDF00-\uDF21\uDF24-\uDF93\uDF96\uDF97\uDF99-\uDF9B\uDF9E-\uDFF0\uDFF3-\uDFF5\uDFF7-\uDFFF]|\uD83D[\uDC00-\uDCFD\uDCFF-\uDD3D\uDD49-\uDD4E\uDD50-\uDD67\uDD6F\uDD70\uDD73-\uDD7A\uDD87\uDD8A-\uDD8D\uDD90\uDD95\uDD96\uDDA4\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA-\uDE4F\uDE80-\uDEC5\uDECB-\uDED2\uDED5-\uDED7\uDEE0-\uDEE5\uDEE9\uDEEB\uDEEC\uDEF0\uDEF3-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0C-\uDD3A\uDD3C-\uDD45\uDD47-\uDD78\uDD7A-\uDDCB\uDDCD-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6])\uFE0F|(?:[\u261D\u26F9\u270A-\u270D]|\uD83C[\uDF85\uDFC2-\uDFC4\uDFC7\uDFCA-\uDFCC]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66-\uDC78\uDC7C\uDC81-\uDC83\uDC85-\uDC87\uDC8F\uDC91\uDCAA\uDD74\uDD75\uDD7A\uDD90\uDD95\uDD96\uDE45-\uDE47\uDE4B-\uDE4F\uDEA3\uDEB4-\uDEB6\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1F\uDD26\uDD30-\uDD39\uDD3C-\uDD3E\uDD77\uDDB5\uDDB6\uDDB8\uDDB9\uDDBB\uDDCD-\uDDCF\uDDD1-\uDDDD])/g;
386
+ }, sD, w = 10, N = (e = 0) => (u) => `\x1B[${u + e}m`, I = (e = 0) => (u) => `\x1B[${38 + e};5;${u}m`, R = (e = 0) => (u, t, F) => `\x1B[${38 + e};2;${u};${t};${F}m`, r, iD, CD, ED, d, oD = 39, y = "\x07", V = "[", nD = "]", G = "m", _, z = (e) => `${d.values().next().value}${V}${e}${G}`, K = (e) => `${d.values().next().value}${_}${e}${y}`, aD = (e) => e.split(" ").map((u) => p(u)), k = (e, u, t) => {
387
+ const F = [...u];
388
+ let s = false, i = false, D = p(P(e[e.length - 1]));
389
+ for (const [C, n] of F.entries()) {
390
+ const E = p(n);
391
+ if (D + E <= t ? e[e.length - 1] += n : (e.push(n), D = 0), d.has(n) && (s = true, i = F.slice(C + 1).join("").startsWith(_)), s) {
392
+ i ? n === y && (s = false, i = false) : n === G && (s = false);
393
+ continue;
394
+ }
395
+ D += E, D === t && C < F.length - 1 && (e.push(""), D = 0);
396
+ }
397
+ !D && e[e.length - 1].length > 0 && e.length > 1 && (e[e.length - 2] += e.pop());
398
+ }, hD = (e) => {
399
+ const u = e.split(" ");
400
+ let t = u.length;
401
+ for (;t > 0 && !(p(u[t - 1]) > 0); )
402
+ t--;
403
+ return t === u.length ? e : u.slice(0, t).join(" ") + u.slice(t).join("");
404
+ }, lD = (e, u, t = {}) => {
405
+ if (t.trim !== false && e.trim() === "")
406
+ return "";
407
+ let F = "", s, i;
408
+ const D = aD(e);
409
+ let C = [""];
410
+ for (const [E, a] of e.split(" ").entries()) {
411
+ t.trim !== false && (C[C.length - 1] = C[C.length - 1].trimStart());
412
+ let o = p(C[C.length - 1]);
413
+ if (E !== 0 && (o >= u && (t.wordWrap === false || t.trim === false) && (C.push(""), o = 0), (o > 0 || t.trim === false) && (C[C.length - 1] += " ", o++)), t.hard && D[E] > u) {
414
+ const c = u - o, f = 1 + Math.floor((D[E] - c - 1) / u);
415
+ Math.floor((D[E] - 1) / u) < f && C.push(""), k(C, a, u);
416
+ continue;
417
+ }
418
+ if (o + D[E] > u && o > 0 && D[E] > 0) {
419
+ if (t.wordWrap === false && o < u) {
420
+ k(C, a, u);
836
421
  continue;
837
422
  }
838
- memories.push({
839
- content,
840
- containerTag: "cursor-chats",
841
- metadata: {
842
- dedupKey,
843
- contentHash,
844
- source: "cursor",
845
- sessionId: composerId,
846
- name: sessionName,
847
- date
848
- }
849
- });
850
- sessionIds.push(composerId);
423
+ C.push("");
851
424
  }
852
- } catch (e) {
853
- console.log(` Cursor ingestion error: ${e.message}`);
854
- } finally {
855
- db.close();
425
+ if (o + D[E] > u && t.wordWrap === false) {
426
+ k(C, a, u);
427
+ continue;
428
+ }
429
+ C[C.length - 1] += a;
856
430
  }
857
- return { memories, sessionIds, skipped: filtered + deduped, filtered, deduped };
858
- }
859
-
860
- // src/ingest/codebase.ts
861
- import { createHash as createHash2 } from "node:crypto";
862
- import { readdirSync as readdirSync4, readFileSync as readFileSync5, statSync as statSync2, existsSync as existsSync4 } from "node:fs";
863
- import { join as join6, relative, extname, resolve } from "node:path";
864
- var DEFAULT_IGNORE = new Set([
865
- "node_modules",
866
- ".git",
867
- ".next",
868
- ".nuxt",
869
- ".output",
870
- "dist",
871
- "build",
872
- ".cache",
873
- "__pycache__",
874
- ".venv",
875
- "venv",
876
- "vendor",
877
- "target",
878
- ".turbo",
879
- ".DS_Store",
880
- ".claude",
881
- ".conare"
882
- ]);
883
- var IGNORE_FILES = new Set([
884
- "package-lock.json",
885
- "bun.lockb",
886
- "yarn.lock",
887
- "pnpm-lock.yaml"
888
- ]);
889
- var CODE_EXTENSIONS = new Set([
890
- ".ts",
891
- ".tsx",
892
- ".js",
893
- ".jsx",
894
- ".mjs",
895
- ".cjs",
896
- ".vue",
897
- ".svelte",
898
- ".astro",
899
- ".py",
900
- ".rb",
901
- ".go",
902
- ".rs",
903
- ".java",
904
- ".kt",
905
- ".swift",
906
- ".c",
907
- ".cpp",
908
- ".h",
909
- ".css",
910
- ".scss",
911
- ".less",
912
- ".html",
913
- ".json",
914
- ".yaml",
915
- ".yml",
916
- ".toml",
917
- ".md",
918
- ".mdx",
919
- ".txt",
920
- ".sql",
921
- ".graphql",
922
- ".prisma",
923
- ".sh",
924
- ".bash",
925
- ".zsh",
926
- ".lua",
927
- ".zig",
928
- ".ex",
929
- ".exs"
930
- ]);
931
- var SPECIAL_FILES = new Set([
932
- "Dockerfile",
933
- "Makefile",
934
- "Procfile",
935
- "Justfile",
936
- ".gitignore",
937
- ".dockerignore",
938
- "CLAUDE.md",
939
- "AGENTS.md",
940
- "README.md",
941
- "ARCHITECTURE.md",
942
- "wrangler.toml",
943
- "wrangler.json"
944
- ]);
945
- var MAX_FILE_SIZE = 1e5;
946
- function parseGitignore(rootPath) {
947
- const patterns = new Set;
948
- const gitignorePath = join6(rootPath, ".gitignore");
949
- if (!existsSync4(gitignorePath))
950
- return patterns;
951
- try {
952
- const content = readFileSync5(gitignorePath, "utf-8");
953
- for (const line of content.split(`
954
- `)) {
955
- const trimmed = line.trim();
956
- if (!trimmed || trimmed.startsWith("#"))
957
- continue;
958
- patterns.add(trimmed.replace(/\/$/, ""));
431
+ t.trim !== false && (C = C.map((E) => hD(E)));
432
+ const n = [...C.join(`
433
+ `)];
434
+ for (const [E, a] of n.entries()) {
435
+ if (F += a, d.has(a)) {
436
+ const { groups: c } = new RegExp(`(?:\\${V}(?<code>\\d+)m|\\${_}(?<uri>.*)${y})`).exec(n.slice(E).join("")) || { groups: {} };
437
+ if (c.code !== undefined) {
438
+ const f = Number.parseFloat(c.code);
439
+ s = f === oD ? undefined : f;
440
+ } else
441
+ c.uri !== undefined && (i = c.uri.length === 0 ? undefined : c.uri);
442
+ }
443
+ const o = ED.codes.get(Number(s));
444
+ n[E + 1] === `
445
+ ` ? (i && (F += K("")), s && o && (F += z(o))) : a === `
446
+ ` && (s && o && (F += z(s)), i && (F += K(i)));
447
+ }
448
+ return F;
449
+ }, xD, B, AD, S, gD, vD = (e, u, t) => (u in e) ? gD(e, u, { enumerable: true, configurable: true, writable: true, value: t }) : e[u] = t, h = (e, u, t) => (vD(e, typeof u != "symbol" ? u + "" : u, t), t), dD, A, kD, $D = (e, u, t) => (u in e) ? kD(e, u, { enumerable: true, configurable: true, writable: true, value: t }) : e[u] = t, H = (e, u, t) => ($D(e, typeof u != "symbol" ? u + "" : u, t), t), SD, TD, jD = (e, u, t) => (u in e) ? TD(e, u, { enumerable: true, configurable: true, writable: true, value: t }) : e[u] = t, U = (e, u, t) => (jD(e, typeof u != "symbol" ? u + "" : u, t), t), MD;
450
+ var init_dist = __esm(() => {
451
+ import_sisteransi = __toESM(require_src(), 1);
452
+ import_picocolors = __toESM(require_picocolors(), 1);
453
+ uD = DD();
454
+ W = { exports: {} };
455
+ (function(e) {
456
+ var u = {};
457
+ e.exports = u, u.eastAsianWidth = function(F) {
458
+ var s = F.charCodeAt(0), i = F.length == 2 ? F.charCodeAt(1) : 0, D = s;
459
+ return 55296 <= s && s <= 56319 && 56320 <= i && i <= 57343 && (s &= 1023, i &= 1023, D = s << 10 | i, D += 65536), D == 12288 || 65281 <= D && D <= 65376 || 65504 <= D && D <= 65510 ? "F" : D == 8361 || 65377 <= D && D <= 65470 || 65474 <= D && D <= 65479 || 65482 <= D && D <= 65487 || 65490 <= D && D <= 65495 || 65498 <= D && D <= 65500 || 65512 <= D && D <= 65518 ? "H" : 4352 <= D && D <= 4447 || 4515 <= D && D <= 4519 || 4602 <= D && D <= 4607 || 9001 <= D && D <= 9002 || 11904 <= D && D <= 11929 || 11931 <= D && D <= 12019 || 12032 <= D && D <= 12245 || 12272 <= D && D <= 12283 || 12289 <= D && D <= 12350 || 12353 <= D && D <= 12438 || 12441 <= D && D <= 12543 || 12549 <= D && D <= 12589 || 12593 <= D && D <= 12686 || 12688 <= D && D <= 12730 || 12736 <= D && D <= 12771 || 12784 <= D && D <= 12830 || 12832 <= D && D <= 12871 || 12880 <= D && D <= 13054 || 13056 <= D && D <= 19903 || 19968 <= D && D <= 42124 || 42128 <= D && D <= 42182 || 43360 <= D && D <= 43388 || 44032 <= D && D <= 55203 || 55216 <= D && D <= 55238 || 55243 <= D && D <= 55291 || 63744 <= D && D <= 64255 || 65040 <= D && D <= 65049 || 65072 <= D && D <= 65106 || 65108 <= D && D <= 65126 || 65128 <= D && D <= 65131 || 110592 <= D && D <= 110593 || 127488 <= D && D <= 127490 || 127504 <= D && D <= 127546 || 127552 <= D && D <= 127560 || 127568 <= D && D <= 127569 || 131072 <= D && D <= 194367 || 177984 <= D && D <= 196605 || 196608 <= D && D <= 262141 ? "W" : 32 <= D && D <= 126 || 162 <= D && D <= 163 || 165 <= D && D <= 166 || D == 172 || D == 175 || 10214 <= D && D <= 10221 || 10629 <= D && D <= 10630 ? "Na" : D == 161 || D == 164 || 167 <= D && D <= 168 || D == 170 || 173 <= D && D <= 174 || 176 <= D && D <= 180 || 182 <= D && D <= 186 || 188 <= D && D <= 191 || D == 198 || D == 208 || 215 <= D && D <= 216 || 222 <= D && D <= 225 || D == 230 || 232 <= D && D <= 234 || 236 <= D && D <= 237 || D == 240 || 242 <= D && D <= 243 || 247 <= D && D <= 250 || D == 252 || D == 254 || D == 257 || D == 273 || D == 275 || D == 283 || 294 <= D && D <= 295 || D == 299 || 305 <= D && D <= 307 || D == 312 || 319 <= D && D <= 322 || D == 324 || 328 <= D && D <= 331 || D == 333 || 338 <= D && D <= 339 || 358 <= D && D <= 359 || D == 363 || D == 462 || D == 464 || D == 466 || D == 468 || D == 470 || D == 472 || D == 474 || D == 476 || D == 593 || D == 609 || D == 708 || D == 711 || 713 <= D && D <= 715 || D == 717 || D == 720 || 728 <= D && D <= 731 || D == 733 || D == 735 || 768 <= D && D <= 879 || 913 <= D && D <= 929 || 931 <= D && D <= 937 || 945 <= D && D <= 961 || 963 <= D && D <= 969 || D == 1025 || 1040 <= D && D <= 1103 || D == 1105 || D == 8208 || 8211 <= D && D <= 8214 || 8216 <= D && D <= 8217 || 8220 <= D && D <= 8221 || 8224 <= D && D <= 8226 || 8228 <= D && D <= 8231 || D == 8240 || 8242 <= D && D <= 8243 || D == 8245 || D == 8251 || D == 8254 || D == 8308 || D == 8319 || 8321 <= D && D <= 8324 || D == 8364 || D == 8451 || D == 8453 || D == 8457 || D == 8467 || D == 8470 || 8481 <= D && D <= 8482 || D == 8486 || D == 8491 || 8531 <= D && D <= 8532 || 8539 <= D && D <= 8542 || 8544 <= D && D <= 8555 || 8560 <= D && D <= 8569 || D == 8585 || 8592 <= D && D <= 8601 || 8632 <= D && D <= 8633 || D == 8658 || D == 8660 || D == 8679 || D == 8704 || 8706 <= D && D <= 8707 || 8711 <= D && D <= 8712 || D == 8715 || D == 8719 || D == 8721 || D == 8725 || D == 8730 || 8733 <= D && D <= 8736 || D == 8739 || D == 8741 || 8743 <= D && D <= 8748 || D == 8750 || 8756 <= D && D <= 8759 || 8764 <= D && D <= 8765 || D == 8776 || D == 8780 || D == 8786 || 8800 <= D && D <= 8801 || 8804 <= D && D <= 8807 || 8810 <= D && D <= 8811 || 8814 <= D && D <= 8815 || 8834 <= D && D <= 8835 || 8838 <= D && D <= 8839 || D == 8853 || D == 8857 || D == 8869 || D == 8895 || D == 8978 || 9312 <= D && D <= 9449 || 9451 <= D && D <= 9547 || 9552 <= D && D <= 9587 || 9600 <= D && D <= 9615 || 9618 <= D && D <= 9621 || 9632 <= D && D <= 9633 || 9635 <= D && D <= 9641 || 9650 <= D && D <= 9651 || 9654 <= D && D <= 9655 || 9660 <= D && D <= 9661 || 9664 <= D && D <= 9665 || 9670 <= D && D <= 9672 || D == 9675 || 9678 <= D && D <= 9681 || 9698 <= D && D <= 9701 || D == 9711 || 9733 <= D && D <= 9734 || D == 9737 || 9742 <= D && D <= 9743 || 9748 <= D && D <= 9749 || D == 9756 || D == 9758 || D == 9792 || D == 9794 || 9824 <= D && D <= 9825 || 9827 <= D && D <= 9829 || 9831 <= D && D <= 9834 || 9836 <= D && D <= 9837 || D == 9839 || 9886 <= D && D <= 9887 || 9918 <= D && D <= 9919 || 9924 <= D && D <= 9933 || 9935 <= D && D <= 9953 || D == 9955 || 9960 <= D && D <= 9983 || D == 10045 || D == 10071 || 10102 <= D && D <= 10111 || 11093 <= D && D <= 11097 || 12872 <= D && D <= 12879 || 57344 <= D && D <= 63743 || 65024 <= D && D <= 65039 || D == 65533 || 127232 <= D && D <= 127242 || 127248 <= D && D <= 127277 || 127280 <= D && D <= 127337 || 127344 <= D && D <= 127386 || 917760 <= D && D <= 917999 || 983040 <= D && D <= 1048573 || 1048576 <= D && D <= 1114109 ? "A" : "N";
460
+ }, u.characterLength = function(F) {
461
+ var s = this.eastAsianWidth(F);
462
+ return s == "F" || s == "W" || s == "A" ? 2 : 1;
463
+ };
464
+ function t(F) {
465
+ return F.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[^\uD800-\uDFFF]/g) || [];
466
+ }
467
+ u.length = function(F) {
468
+ for (var s = t(F), i = 0, D = 0;D < s.length; D++)
469
+ i = i + this.characterLength(s[D]);
470
+ return i;
471
+ }, u.slice = function(F, s, i) {
472
+ textLen = u.length(F), s = s || 0, i = i || 1, s < 0 && (s = textLen + s), i < 0 && (i = textLen + i);
473
+ for (var D = "", C = 0, n = t(F), E = 0;E < n.length; E++) {
474
+ var a = n[E], o = u.length(a);
475
+ if (C >= s - (o == 2 ? 1 : 0))
476
+ if (C + o <= i)
477
+ D += a;
478
+ else
479
+ break;
480
+ C += o;
481
+ }
482
+ return D;
483
+ };
484
+ })(W);
485
+ tD = W.exports;
486
+ eD = L(tD);
487
+ sD = L(FD);
488
+ r = { modifier: { reset: [0, 0], bold: [1, 22], dim: [2, 22], italic: [3, 23], underline: [4, 24], overline: [53, 55], inverse: [7, 27], hidden: [8, 28], strikethrough: [9, 29] }, color: { black: [30, 39], red: [31, 39], green: [32, 39], yellow: [33, 39], blue: [34, 39], magenta: [35, 39], cyan: [36, 39], white: [37, 39], blackBright: [90, 39], gray: [90, 39], grey: [90, 39], redBright: [91, 39], greenBright: [92, 39], yellowBright: [93, 39], blueBright: [94, 39], magentaBright: [95, 39], cyanBright: [96, 39], whiteBright: [97, 39] }, bgColor: { bgBlack: [40, 49], bgRed: [41, 49], bgGreen: [42, 49], bgYellow: [43, 49], bgBlue: [44, 49], bgMagenta: [45, 49], bgCyan: [46, 49], bgWhite: [47, 49], bgBlackBright: [100, 49], bgGray: [100, 49], bgGrey: [100, 49], bgRedBright: [101, 49], bgGreenBright: [102, 49], bgYellowBright: [103, 49], bgBlueBright: [104, 49], bgMagentaBright: [105, 49], bgCyanBright: [106, 49], bgWhiteBright: [107, 49] } };
489
+ Object.keys(r.modifier);
490
+ iD = Object.keys(r.color);
491
+ CD = Object.keys(r.bgColor);
492
+ [...iD, ...CD];
493
+ ED = rD();
494
+ d = new Set(["\x1B", "›"]);
495
+ _ = `${nD}8;;`;
496
+ xD = ["up", "down", "left", "right", "space", "enter", "cancel"];
497
+ B = { actions: new Set(xD), aliases: new Map([["k", "up"], ["j", "down"], ["h", "left"], ["l", "right"], ["\x03", "cancel"], ["escape", "cancel"]]) };
498
+ AD = globalThis.process.platform.startsWith("win");
499
+ S = Symbol("clack:cancel");
500
+ gD = Object.defineProperty;
501
+ dD = class dD extends x {
502
+ get cursor() {
503
+ return this.value ? 0 : 1;
504
+ }
505
+ get _value() {
506
+ return this.cursor === 0;
507
+ }
508
+ constructor(u) {
509
+ super(u, false), this.value = !!u.initialValue, this.on("value", () => {
510
+ this.value = this._value;
511
+ }), this.on("confirm", (t) => {
512
+ this.output.write(import_sisteransi.cursor.move(0, -1)), this.value = t, this.state = "submit", this.close();
513
+ }), this.on("cursor", () => {
514
+ this.value = !this.value;
515
+ });
516
+ }
517
+ };
518
+ A = new WeakMap;
519
+ kD = Object.defineProperty;
520
+ SD = class extends x {
521
+ constructor(u) {
522
+ super(u, false), H(this, "options"), H(this, "cursor", 0), this.options = u.options, this.value = [...u.initialValues ?? []], this.cursor = Math.max(this.options.findIndex(({ value: t }) => t === u.cursorAt), 0), this.on("key", (t) => {
523
+ t === "a" && this.toggleAll();
524
+ }), this.on("cursor", (t) => {
525
+ switch (t) {
526
+ case "left":
527
+ case "up":
528
+ this.cursor = this.cursor === 0 ? this.options.length - 1 : this.cursor - 1;
529
+ break;
530
+ case "down":
531
+ case "right":
532
+ this.cursor = this.cursor === this.options.length - 1 ? 0 : this.cursor + 1;
533
+ break;
534
+ case "space":
535
+ this.toggleValue();
536
+ break;
537
+ }
538
+ });
539
+ }
540
+ get _value() {
541
+ return this.options[this.cursor].value;
542
+ }
543
+ toggleAll() {
544
+ const u = this.value.length === this.options.length;
545
+ this.value = u ? [] : this.options.map((t) => t.value);
546
+ }
547
+ toggleValue() {
548
+ const u = this.value.includes(this._value);
549
+ this.value = u ? this.value.filter((t) => t !== this._value) : [...this.value, this._value];
959
550
  }
960
- } catch {}
961
- return patterns;
962
- }
963
- function shouldIgnore(name, ignorePatterns) {
964
- if (DEFAULT_IGNORE.has(name))
965
- return true;
966
- if (IGNORE_FILES.has(name))
967
- return true;
968
- if (name.startsWith(".env"))
969
- return true;
970
- if (ignorePatterns.has(name))
971
- return true;
972
- return false;
973
- }
974
- function langFromExt(ext) {
975
- const map = {
976
- ".ts": "typescript",
977
- ".tsx": "tsx",
978
- ".js": "javascript",
979
- ".jsx": "jsx",
980
- ".mjs": "javascript",
981
- ".cjs": "javascript",
982
- ".vue": "vue",
983
- ".svelte": "svelte",
984
- ".astro": "astro",
985
- ".py": "python",
986
- ".rb": "ruby",
987
- ".go": "go",
988
- ".rs": "rust",
989
- ".java": "java",
990
- ".kt": "kotlin",
991
- ".swift": "swift",
992
- ".c": "c",
993
- ".cpp": "cpp",
994
- ".h": "c",
995
- ".css": "css",
996
- ".scss": "scss",
997
- ".less": "less",
998
- ".html": "html",
999
- ".json": "json",
1000
- ".yaml": "yaml",
1001
- ".yml": "yaml",
1002
- ".toml": "toml",
1003
- ".md": "markdown",
1004
- ".mdx": "mdx",
1005
- ".sql": "sql",
1006
- ".graphql": "graphql",
1007
- ".prisma": "prisma",
1008
- ".sh": "bash",
1009
- ".bash": "bash",
1010
- ".zsh": "zsh",
1011
- ".lua": "lua",
1012
- ".zig": "zig",
1013
- ".ex": "elixir",
1014
- ".exs": "elixir"
1015
551
  };
1016
- return map[ext] || ext.slice(1);
1017
- }
1018
- function formatFile(relPath, content, ext) {
1019
- const lang = langFromExt(ext);
1020
- return `# File: ${relPath}
552
+ TD = Object.defineProperty;
553
+ MD = class MD extends x {
554
+ constructor({ mask: u, ...t }) {
555
+ super(t), U(this, "valueWithCursor", ""), U(this, "_mask", "•"), this._mask = u ?? "•", this.on("finalize", () => {
556
+ this.valueWithCursor = this.masked;
557
+ }), this.on("value", () => {
558
+ if (this.cursor >= this.value.length)
559
+ this.valueWithCursor = `${this.masked}${import_picocolors.default.inverse(import_picocolors.default.hidden("_"))}`;
560
+ else {
561
+ const F = this.masked.slice(0, this.cursor), s = this.masked.slice(this.cursor);
562
+ this.valueWithCursor = `${F}${import_picocolors.default.inverse(s[0])}${s.slice(1)}`;
563
+ }
564
+ });
565
+ }
566
+ get cursor() {
567
+ return this._cursor;
568
+ }
569
+ get masked() {
570
+ return this.value.replaceAll(/./g, this._mask);
571
+ }
572
+ };
573
+ });
1021
574
 
1022
- \`\`\`${lang}
1023
- ${content}
1024
- \`\`\``;
575
+ // node_modules/@clack/prompts/dist/index.mjs
576
+ import { stripVTControlCharacters as S2 } from "node:util";
577
+ import y2 from "node:process";
578
+ function ce() {
579
+ return y2.platform !== "win32" ? y2.env.TERM !== "linux" : !!y2.env.CI || !!y2.env.WT_SESSION || !!y2.env.TERMINUS_SUBLIME || y2.env.ConEmuTask === "{cmd::Cmder}" || y2.env.TERM_PROGRAM === "Terminus-Sublime" || y2.env.TERM_PROGRAM === "vscode" || y2.env.TERM === "xterm-256color" || y2.env.TERM === "alacritty" || y2.env.TERMINAL_EMULATOR === "JetBrains-JediTerm";
1025
580
  }
1026
- function indexCodebase(rootPath) {
1027
- const absRoot = resolve(rootPath);
1028
- const repoHash = createHash2("sha256").update(absRoot).digest("hex").slice(0, 12);
1029
- const gitignorePatterns = parseGitignore(absRoot);
1030
- const memories = [];
1031
- let fileCount = 0;
1032
- let skipped = 0;
1033
- function walk(dir) {
1034
- let entries;
1035
- try {
1036
- entries = readdirSync4(dir, { withFileTypes: true });
1037
- } catch {
1038
- return;
581
+ var import_picocolors2, import_sisteransi2, V2, u = (t, n) => V2 ? t : n, le, L2, W2, C, ue, o, d2, k2, P2, A2, T, F, $e, _2, me, de, pe, q, D, U2, K2, b2 = (t) => {
582
+ switch (t) {
583
+ case "initial":
584
+ case "active":
585
+ return import_picocolors2.default.cyan(le);
586
+ case "cancel":
587
+ return import_picocolors2.default.red(L2);
588
+ case "error":
589
+ return import_picocolors2.default.yellow(W2);
590
+ case "submit":
591
+ return import_picocolors2.default.green(C);
592
+ }
593
+ }, G2 = (t) => {
594
+ const { cursor: n, options: r2, style: i } = t, s = t.maxItems ?? Number.POSITIVE_INFINITY, c = Math.max(process.stdout.rows - 4, 0), a = Math.min(c, Math.max(s, 5));
595
+ let l2 = 0;
596
+ n >= l2 + a - 3 ? l2 = Math.max(Math.min(n - a + 3, r2.length - a), 0) : n < l2 + 2 && (l2 = Math.max(n - 2, 0));
597
+ const $2 = a < r2.length && l2 > 0, g2 = a < r2.length && l2 + a < r2.length;
598
+ return r2.slice(l2, l2 + a).map((p2, v2, f) => {
599
+ const j2 = v2 === 0 && $2, E = v2 === f.length - 1 && g2;
600
+ return j2 || E ? import_picocolors2.default.dim("...") : i(p2, v2 + l2 === n);
601
+ });
602
+ }, ge = (t) => new MD({ validate: t.validate, mask: t.mask ?? $e, render() {
603
+ const n = `${import_picocolors2.default.gray(o)}
604
+ ${b2(this.state)} ${t.message}
605
+ `, r2 = this.valueWithCursor, i = this.masked;
606
+ switch (this.state) {
607
+ case "error":
608
+ return `${n.trim()}
609
+ ${import_picocolors2.default.yellow(o)} ${i}
610
+ ${import_picocolors2.default.yellow(d2)} ${import_picocolors2.default.yellow(this.error)}
611
+ `;
612
+ case "submit":
613
+ return `${n}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.dim(i)}`;
614
+ case "cancel":
615
+ return `${n}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(i ?? ""))}${i ? `
616
+ ${import_picocolors2.default.gray(o)}` : ""}`;
617
+ default:
618
+ return `${n}${import_picocolors2.default.cyan(o)} ${r2}
619
+ ${import_picocolors2.default.cyan(d2)}
620
+ `;
621
+ }
622
+ } }).prompt(), ye = (t) => {
623
+ const n = t.active ?? "Yes", r2 = t.inactive ?? "No";
624
+ return new dD({ active: n, inactive: r2, initialValue: t.initialValue ?? true, render() {
625
+ const i = `${import_picocolors2.default.gray(o)}
626
+ ${b2(this.state)} ${t.message}
627
+ `, s = this.value ? n : r2;
628
+ switch (this.state) {
629
+ case "submit":
630
+ return `${i}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.dim(s)}`;
631
+ case "cancel":
632
+ return `${i}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(s))}
633
+ ${import_picocolors2.default.gray(o)}`;
634
+ default:
635
+ return `${i}${import_picocolors2.default.cyan(o)} ${this.value ? `${import_picocolors2.default.green(k2)} ${n}` : `${import_picocolors2.default.dim(P2)} ${import_picocolors2.default.dim(n)}`} ${import_picocolors2.default.dim("/")} ${this.value ? `${import_picocolors2.default.dim(P2)} ${import_picocolors2.default.dim(r2)}` : `${import_picocolors2.default.green(k2)} ${r2}`}
636
+ ${import_picocolors2.default.cyan(d2)}
637
+ `;
1039
638
  }
1040
- for (const entry of entries) {
1041
- if (shouldIgnore(entry.name, gitignorePatterns))
1042
- continue;
1043
- const fullPath = join6(dir, entry.name);
1044
- if (entry.isDirectory()) {
1045
- walk(fullPath);
1046
- continue;
1047
- }
1048
- if (!entry.isFile())
1049
- continue;
1050
- const ext = extname(entry.name).toLowerCase();
1051
- if (!CODE_EXTENSIONS.has(ext) && !SPECIAL_FILES.has(entry.name))
1052
- continue;
1053
- let stat;
1054
- try {
1055
- stat = statSync2(fullPath);
1056
- } catch {
1057
- continue;
1058
- }
1059
- if (stat.size > MAX_FILE_SIZE || stat.size === 0) {
1060
- skipped++;
1061
- continue;
1062
- }
1063
- let raw;
1064
- try {
1065
- raw = readFileSync5(fullPath, "utf-8");
1066
- } catch {
1067
- skipped++;
1068
- continue;
1069
- }
1070
- if (raw.includes("\x00")) {
1071
- skipped++;
1072
- continue;
639
+ } }).prompt();
640
+ }, fe = (t) => {
641
+ const n = (r2, i) => {
642
+ const s = r2.label ?? String(r2.value);
643
+ return i === "active" ? `${import_picocolors2.default.cyan(A2)} ${s} ${r2.hint ? import_picocolors2.default.dim(`(${r2.hint})`) : ""}` : i === "selected" ? `${import_picocolors2.default.green(T)} ${import_picocolors2.default.dim(s)} ${r2.hint ? import_picocolors2.default.dim(`(${r2.hint})`) : ""}` : i === "cancelled" ? `${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(s))}` : i === "active-selected" ? `${import_picocolors2.default.green(T)} ${s} ${r2.hint ? import_picocolors2.default.dim(`(${r2.hint})`) : ""}` : i === "submitted" ? `${import_picocolors2.default.dim(s)}` : `${import_picocolors2.default.dim(F)} ${import_picocolors2.default.dim(s)}`;
644
+ };
645
+ return new SD({ options: t.options, initialValues: t.initialValues, required: t.required ?? true, cursorAt: t.cursorAt, validate(r2) {
646
+ if (this.required && r2.length === 0)
647
+ return `Please select at least one option.
648
+ ${import_picocolors2.default.reset(import_picocolors2.default.dim(`Press ${import_picocolors2.default.gray(import_picocolors2.default.bgWhite(import_picocolors2.default.inverse(" space ")))} to select, ${import_picocolors2.default.gray(import_picocolors2.default.bgWhite(import_picocolors2.default.inverse(" enter ")))} to submit`))}`;
649
+ }, render() {
650
+ const r2 = `${import_picocolors2.default.gray(o)}
651
+ ${b2(this.state)} ${t.message}
652
+ `, i = (s, c) => {
653
+ const a = this.value.includes(s.value);
654
+ return c && a ? n(s, "active-selected") : a ? n(s, "selected") : n(s, c ? "active" : "inactive");
655
+ };
656
+ switch (this.state) {
657
+ case "submit":
658
+ return `${r2}${import_picocolors2.default.gray(o)} ${this.options.filter(({ value: s }) => this.value.includes(s)).map((s) => n(s, "submitted")).join(import_picocolors2.default.dim(", ")) || import_picocolors2.default.dim("none")}`;
659
+ case "cancel": {
660
+ const s = this.options.filter(({ value: c }) => this.value.includes(c)).map((c) => n(c, "cancelled")).join(import_picocolors2.default.dim(", "));
661
+ return `${r2}${import_picocolors2.default.gray(o)} ${s.trim() ? `${s}
662
+ ${import_picocolors2.default.gray(o)}` : ""}`;
1073
663
  }
1074
- const relPath = relative(absRoot, fullPath);
1075
- const contentHash = createContentHash(raw);
1076
- const dedupKey = `codebase:${repoHash}:${relPath}`;
1077
- const fingerprint = `${dedupKey}:${contentHash}`;
1078
- if (isIngested("codebase", fingerprint)) {
1079
- skipped++;
1080
- continue;
664
+ case "error": {
665
+ const s = this.error.split(`
666
+ `).map((c, a) => a === 0 ? `${import_picocolors2.default.yellow(d2)} ${import_picocolors2.default.yellow(c)}` : ` ${c}`).join(`
667
+ `);
668
+ return `${r2 + import_picocolors2.default.yellow(o)} ${G2({ options: this.options, cursor: this.cursor, maxItems: t.maxItems, style: i }).join(`
669
+ ${import_picocolors2.default.yellow(o)} `)}
670
+ ${s}
671
+ `;
1081
672
  }
1082
- const content = formatFile(relPath, raw, ext);
1083
- memories.push({
1084
- content,
1085
- containerTag: "codebase",
1086
- metadata: {
1087
- dedupKey,
1088
- contentHash,
1089
- source: "codebase-index",
1090
- repoHash,
1091
- filePath: relPath,
1092
- fileHash: `${relPath}:${contentHash}`,
1093
- language: langFromExt(ext)
1094
- }
1095
- });
1096
- fileCount++;
673
+ default:
674
+ return `${r2}${import_picocolors2.default.cyan(o)} ${G2({ options: this.options, cursor: this.cursor, maxItems: t.maxItems, style: i }).join(`
675
+ ${import_picocolors2.default.cyan(o)} `)}
676
+ ${import_picocolors2.default.cyan(d2)}
677
+ `;
1097
678
  }
679
+ } }).prompt();
680
+ }, Me = (t = "", n = "") => {
681
+ const r2 = `
682
+ ${t}
683
+ `.split(`
684
+ `), i = S2(n).length, s = Math.max(r2.reduce((a, l2) => {
685
+ const $2 = S2(l2);
686
+ return $2.length > a ? $2.length : a;
687
+ }, 0), i) + 2, c = r2.map((a) => `${import_picocolors2.default.gray(o)} ${import_picocolors2.default.dim(a)}${" ".repeat(s - S2(a).length)}${import_picocolors2.default.gray(o)}`).join(`
688
+ `);
689
+ process.stdout.write(`${import_picocolors2.default.gray(o)}
690
+ ${import_picocolors2.default.green(C)} ${import_picocolors2.default.reset(n)} ${import_picocolors2.default.gray(_2.repeat(Math.max(s - i - 1, 1)) + me)}
691
+ ${c}
692
+ ${import_picocolors2.default.gray(de + _2.repeat(s + 2) + pe)}
693
+ `);
694
+ }, xe = (t = "") => {
695
+ process.stdout.write(`${import_picocolors2.default.gray(d2)} ${import_picocolors2.default.red(t)}
696
+
697
+ `);
698
+ }, Ie = (t = "") => {
699
+ process.stdout.write(`${import_picocolors2.default.gray(ue)} ${t}
700
+ `);
701
+ }, Se = (t = "") => {
702
+ process.stdout.write(`${import_picocolors2.default.gray(o)}
703
+ ${import_picocolors2.default.gray(d2)} ${t}
704
+
705
+ `);
706
+ }, J, Y2 = ({ indicator: t = "dots" } = {}) => {
707
+ const n = V2 ? ["◒", "◐", "◓", "◑"] : ["•", "o", "O", "0"], r2 = V2 ? 80 : 120, i = process.env.CI === "true";
708
+ let s, c, a = false, l2 = "", $2, g2 = performance.now();
709
+ const p2 = (m2) => {
710
+ const h2 = m2 > 1 ? "Something went wrong" : "Canceled";
711
+ a && N2(h2, m2);
712
+ }, v2 = () => p2(2), f = () => p2(1), j2 = () => {
713
+ process.on("uncaughtExceptionMonitor", v2), process.on("unhandledRejection", v2), process.on("SIGINT", f), process.on("SIGTERM", f), process.on("exit", p2);
714
+ }, E = () => {
715
+ process.removeListener("uncaughtExceptionMonitor", v2), process.removeListener("unhandledRejection", v2), process.removeListener("SIGINT", f), process.removeListener("SIGTERM", f), process.removeListener("exit", p2);
716
+ }, B2 = () => {
717
+ if ($2 === undefined)
718
+ return;
719
+ i && process.stdout.write(`
720
+ `);
721
+ const m2 = $2.split(`
722
+ `);
723
+ process.stdout.write(import_sisteransi2.cursor.move(-999, m2.length - 1)), process.stdout.write(import_sisteransi2.erase.down(m2.length));
724
+ }, R2 = (m2) => m2.replace(/\.+$/, ""), O2 = (m2) => {
725
+ const h2 = (performance.now() - m2) / 1000, w2 = Math.floor(h2 / 60), I2 = Math.floor(h2 % 60);
726
+ return w2 > 0 ? `[${w2}m ${I2}s]` : `[${I2}s]`;
727
+ }, H2 = (m2 = "") => {
728
+ a = true, s = fD(), l2 = R2(m2), g2 = performance.now(), process.stdout.write(`${import_picocolors2.default.gray(o)}
729
+ `);
730
+ let h2 = 0, w2 = 0;
731
+ j2(), c = setInterval(() => {
732
+ if (i && l2 === $2)
733
+ return;
734
+ B2(), $2 = l2;
735
+ const I2 = import_picocolors2.default.magenta(n[h2]);
736
+ if (i)
737
+ process.stdout.write(`${I2} ${l2}...`);
738
+ else if (t === "timer")
739
+ process.stdout.write(`${I2} ${l2} ${O2(g2)}`);
740
+ else {
741
+ const z2 = ".".repeat(Math.floor(w2)).slice(0, 3);
742
+ process.stdout.write(`${I2} ${l2}${z2}`);
743
+ }
744
+ h2 = h2 + 1 < n.length ? h2 + 1 : 0, w2 = w2 < n.length ? w2 + 0.125 : 0;
745
+ }, r2);
746
+ }, N2 = (m2 = "", h2 = 0) => {
747
+ a = false, clearInterval(c), B2();
748
+ const w2 = h2 === 0 ? import_picocolors2.default.green(C) : h2 === 1 ? import_picocolors2.default.red(L2) : import_picocolors2.default.red(W2);
749
+ l2 = R2(m2 ?? l2), t === "timer" ? process.stdout.write(`${w2} ${l2} ${O2(g2)}
750
+ `) : process.stdout.write(`${w2} ${l2}
751
+ `), E(), s();
752
+ };
753
+ return { start: H2, stop: N2, message: (m2 = "") => {
754
+ l2 = R2(m2 ?? l2);
755
+ } };
756
+ };
757
+ var init_dist2 = __esm(() => {
758
+ init_dist();
759
+ init_dist();
760
+ import_picocolors2 = __toESM(require_picocolors(), 1);
761
+ import_sisteransi2 = __toESM(require_src(), 1);
762
+ V2 = ce();
763
+ le = u("◆", "*");
764
+ L2 = u("■", "x");
765
+ W2 = u("▲", "x");
766
+ C = u("◇", "o");
767
+ ue = u("┌", "T");
768
+ o = u("│", "|");
769
+ d2 = u("└", "—");
770
+ k2 = u("●", ">");
771
+ P2 = u("○", " ");
772
+ A2 = u("◻", "[•]");
773
+ T = u("◼", "[+]");
774
+ F = u("◻", "[ ]");
775
+ $e = u("▪", "•");
776
+ _2 = u("─", "-");
777
+ me = u("╮", "+");
778
+ de = u("├", "+");
779
+ pe = u("╯", "+");
780
+ q = u("●", "•");
781
+ D = u("◆", "*");
782
+ U2 = u("▲", "!");
783
+ K2 = u("■", "x");
784
+ J = `${import_picocolors2.default.gray(o)} `;
785
+ });
786
+
787
+ // src/interactive.ts
788
+ var exports_interactive = {};
789
+ __export(exports_interactive, {
790
+ startSetup: () => startSetup,
791
+ spinner: () => Y2,
792
+ showDetectedApps: () => showDetectedApps,
793
+ selectMcpTargets: () => selectMcpTargets,
794
+ selectChatSources: () => selectChatSources,
795
+ promptApiKey: () => promptApiKey,
796
+ finishSetup: () => finishSetup,
797
+ confirmIndexCodebase: () => confirmIndexCodebase
798
+ });
799
+ function formatDetectedCount(count) {
800
+ if (count === undefined)
801
+ return "available";
802
+ return `${count.toLocaleString()} chats`;
803
+ }
804
+ function ensureValue(value) {
805
+ if (pD(value)) {
806
+ xe("Setup cancelled.");
807
+ process.exit(0);
1098
808
  }
1099
- walk(absRoot);
1100
- return { memories, fileCount, skipped };
809
+ return value;
810
+ }
811
+ function startSetup() {
812
+ Ie("Conare setup");
813
+ }
814
+ function finishSetup() {
815
+ Se("Starting setup...");
816
+ }
817
+ function showDetectedApps(targets) {
818
+ Me(targets.map((target) => `• ${target.label}: ${target.available === false ? "not detected" : formatDetectedCount(target.detectedCount)}`).join(`
819
+ `), "Detected apps");
820
+ }
821
+ async function promptApiKey(options) {
822
+ if (options.providedApiKey) {
823
+ return options.providedApiKey;
824
+ }
825
+ const keyPrompt = await ge({
826
+ message: options.savedApiKey ? `API key (press Enter to use saved key ending in ${options.savedApiKey.slice(-6)})` : "API key",
827
+ mask: "*",
828
+ validate(value) {
829
+ const resolved = value.trim() || options.savedApiKey || "";
830
+ if (!resolved)
831
+ return "Enter an API key from https://mcp.conare.ai";
832
+ if (!resolved.startsWith("cmem_"))
833
+ return "API keys start with cmem_";
834
+ return;
835
+ }
836
+ });
837
+ return ensureValue(keyPrompt).trim() || options.savedApiKey;
838
+ }
839
+ async function selectChatSources(targets) {
840
+ return ensureValue(await fe({
841
+ message: "Select chat sources",
842
+ required: false,
843
+ initialValues: targets.filter((target) => target.recommended).map((target) => target.id),
844
+ options: targets.map((target) => ({
845
+ value: target.id,
846
+ label: target.label,
847
+ hint: target.available === false ? "not detected" : formatDetectedCount(target.detectedCount)
848
+ }))
849
+ }));
850
+ }
851
+ async function selectMcpTargets(targets) {
852
+ return ensureValue(await fe({
853
+ message: "Select where to install the MCP",
854
+ required: false,
855
+ initialValues: targets.filter((target) => target.recommended).map((target) => target.id),
856
+ options: targets.map((target) => ({
857
+ value: target.id,
858
+ label: target.label,
859
+ hint: target.available === false ? "not detected" : "recommended"
860
+ }))
861
+ }));
862
+ }
863
+ async function confirmIndexCodebase() {
864
+ return ensureValue(await ye({
865
+ message: "Index this codebase too?",
866
+ initialValue: false
867
+ }));
1101
868
  }
869
+ var init_interactive = __esm(() => {
870
+ init_dist2();
871
+ });
1102
872
 
1103
- // src/api.ts
1104
- var API_URL = "https://mcp.conare.ai";
1105
- function createUploadBatches(memories, maxItems = 50, maxChars = 1500000) {
1106
- const batches = [];
1107
- let current = [];
1108
- let currentChars = 0;
1109
- let startIndex = 0;
1110
- for (let i = 0;i < memories.length; i++) {
1111
- const item = memories[i];
1112
- const itemChars = item.content.length;
1113
- const exceedsBatch = current.length > 0 && (current.length >= maxItems || currentChars + itemChars > maxChars);
1114
- if (exceedsBatch) {
1115
- batches.push({ startIndex, items: current });
1116
- current = [];
1117
- currentChars = 0;
1118
- startIndex = i;
873
+ // src/index.ts
874
+ import { existsSync as existsSync9 } from "node:fs";
875
+ import { join as join10 } from "node:path";
876
+
877
+ // src/detect.ts
878
+ import { existsSync, readdirSync } from "node:fs";
879
+ import { spawnSync } from "node:child_process";
880
+ import { join } from "node:path";
881
+ import { homedir, platform } from "node:os";
882
+ function countJsonlFiles(dir) {
883
+ let count = 0;
884
+ try {
885
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
886
+ if (entry.isDirectory()) {
887
+ count += countJsonlFiles(join(dir, entry.name));
888
+ } else if (entry.name.endsWith(".jsonl")) {
889
+ count++;
890
+ }
1119
891
  }
1120
- current.push(item);
1121
- currentChars += itemChars;
1122
- }
1123
- if (current.length > 0) {
1124
- batches.push({ startIndex, items: current });
1125
- }
1126
- return batches;
892
+ } catch {}
893
+ return count;
1127
894
  }
1128
- async function validateKey(apiKey) {
895
+ function countCursorSessions(dbPath) {
1129
896
  try {
1130
- const res = await fetch(`${API_URL}/api/auth/me`, {
1131
- headers: { Authorization: `Bearer ${apiKey}` }
1132
- });
1133
- if (!res.ok)
1134
- return { valid: false };
1135
- const data = await res.json();
1136
- return { valid: true, email: data.user.email, name: data.user.name };
897
+ const result = spawnSync("sqlite3", [
898
+ dbPath,
899
+ `
900
+ WITH composer_rows AS (
901
+ SELECT substr(key, 14) AS composer_id, value AS composer_json
902
+ FROM cursorDiskKV
903
+ WHERE key LIKE 'composerData:%'
904
+ ),
905
+ headers AS (
906
+ SELECT
907
+ composer_id,
908
+ json_extract(j.value, '$.bubbleId') AS bubble_id,
909
+ json_extract(j.value, '$.type') AS type
910
+ FROM composer_rows, json_each(json_extract(composer_json, '$.fullConversationHeadersOnly')) AS j
911
+ ),
912
+ messages AS (
913
+ SELECT h.composer_id, h.type
914
+ FROM headers h
915
+ JOIN cursorDiskKV kv
916
+ ON kv.key = 'bubbleId:' || h.composer_id || ':' || h.bubble_id
917
+ WHERE h.type IN (1, 2)
918
+ AND length(COALESCE(json_extract(kv.value, '$.text'), '')) >= 50
919
+ )
920
+ SELECT count(*)
921
+ FROM (
922
+ SELECT composer_id
923
+ FROM messages
924
+ GROUP BY composer_id
925
+ HAVING SUM(CASE WHEN type = 1 THEN 1 ELSE 0 END) > 0
926
+ AND SUM(CASE WHEN type = 2 THEN 1 ELSE 0 END) > 0
927
+ );
928
+ `.trim()
929
+ ], { encoding: "utf-8" });
930
+ if (result.status !== 0)
931
+ return 0;
932
+ const count = Number.parseInt(result.stdout.trim(), 10);
933
+ return Number.isFinite(count) ? count : 0;
1137
934
  } catch {
1138
- return { valid: false };
935
+ return 0;
1139
936
  }
1140
937
  }
1141
- async function getRemoteMemoryCount(apiKey) {
1142
- try {
1143
- const res = await fetch(`${API_URL}/api/containers`, {
1144
- headers: { Authorization: `Bearer ${apiKey}` }
938
+ function detect() {
939
+ const home = homedir();
940
+ const tools = [];
941
+ const claudeDir = join(home, ".claude", "projects");
942
+ if (existsSync(claudeDir)) {
943
+ const sessionCount = countJsonlFiles(claudeDir);
944
+ tools.push({
945
+ name: "Claude Code",
946
+ available: sessionCount > 0,
947
+ path: claudeDir,
948
+ sessionCount
1145
949
  });
1146
- if (!res.ok)
1147
- return null;
1148
- const data = await res.json();
1149
- if (!Array.isArray(data.containers))
1150
- return 0;
1151
- return data.containers.reduce((sum, container) => sum + (container.count || 0), 0);
1152
- } catch {
1153
- return null;
950
+ } else {
951
+ tools.push({ name: "Claude Code", available: false, path: claudeDir, sessionCount: 0 });
952
+ }
953
+ const codexHistory = join(home, ".codex", "history.jsonl");
954
+ const codexSessions = join(home, ".codex", "sessions");
955
+ if (existsSync(codexHistory) || existsSync(codexSessions)) {
956
+ let sessionCount = 0;
957
+ if (existsSync(codexHistory)) {
958
+ try {
959
+ const { readFileSync } = __require("node:fs");
960
+ const lines = readFileSync(codexHistory, "utf-8").split(`
961
+ `).filter(Boolean);
962
+ const sessions = new Set(lines.map((l) => {
963
+ try {
964
+ return JSON.parse(l).session_id;
965
+ } catch {
966
+ return null;
967
+ }
968
+ }));
969
+ sessions.delete(null);
970
+ sessionCount = sessions.size;
971
+ } catch {}
972
+ }
973
+ tools.push({
974
+ name: "Codex",
975
+ available: true,
976
+ path: existsSync(codexHistory) ? codexHistory : codexSessions,
977
+ sessionCount
978
+ });
979
+ } else {
980
+ tools.push({ name: "Codex", available: false, path: codexHistory, sessionCount: 0 });
981
+ }
982
+ const os = platform();
983
+ let cursorDbPath;
984
+ if (os === "darwin") {
985
+ cursorDbPath = join(home, "Library", "Application Support", "Cursor", "User", "globalStorage", "state.vscdb");
986
+ } else if (os === "win32") {
987
+ cursorDbPath = join(process.env.APPDATA || join(home, "AppData", "Roaming"), "Cursor", "User", "globalStorage", "state.vscdb");
988
+ } else {
989
+ cursorDbPath = join(home, ".config", "Cursor", "User", "globalStorage", "state.vscdb");
1154
990
  }
991
+ tools.push({
992
+ name: "Cursor",
993
+ available: existsSync(cursorDbPath),
994
+ path: cursorDbPath,
995
+ sessionCount: existsSync(cursorDbPath) ? countCursorSessions(cursorDbPath) : 0
996
+ });
997
+ const openclawDir = join(home, ".openclaw");
998
+ tools.push({
999
+ name: "OpenClaw",
1000
+ available: existsSync(openclawDir),
1001
+ path: openclawDir,
1002
+ sessionCount: 0
1003
+ });
1004
+ return tools;
1005
+ }
1006
+
1007
+ // src/ingest/claude.ts
1008
+ import { readdirSync as readdirSync2, readFileSync as readFileSync2, existsSync as existsSync3 } from "node:fs";
1009
+ import { join as join3, basename } from "node:path";
1010
+ import { homedir as homedir3 } from "node:os";
1011
+
1012
+ // src/ingest/shared.ts
1013
+ import { existsSync as existsSync2, readFileSync, writeFileSync, mkdirSync } from "node:fs";
1014
+ import { createHash } from "node:crypto";
1015
+ import { join as join2 } from "node:path";
1016
+ import { homedir as homedir2 } from "node:os";
1017
+ var MANIFEST_PATH = join2(homedir2(), ".conare", "ingested.json");
1018
+ var MIN_SUBSTANTIVE = 200;
1019
+ var NARRATION_RE = /^[\s\n]*(Let me |Now let me |Now I['\u2019]|Now add |Now fix |Now replace |Now integrate |Now update |Now pass |Now clean |Now build|Update the |Builds clean|Deployed\.|Wait, I |Let['\u2019]s test |Good —|Great\.|Perfect\.|Alright|OK,? let me|I[''\u2019]ll |Starting |I need to |Need |I found |I read |I[''\u2019]ve (loaded|confirmed|verified)|Context loaded|Next (I[''\u2019]|step)|Deps confirm|Diff check|Still missing|I[''\u2019]ll (do|check|inspect|trace|run|grab|pull|read|verify))/;
1020
+ function isNarration(text) {
1021
+ const stripped = text.trim();
1022
+ if (stripped.length < MIN_SUBSTANTIVE)
1023
+ return true;
1024
+ if (stripped.length <= 300 && NARRATION_RE.test(stripped))
1025
+ return true;
1026
+ return false;
1155
1027
  }
1156
- async function uploadItems(apiKey, items, asyncEmbed = false) {
1157
- let retries = 4;
1158
- while (retries > 0) {
1159
- try {
1160
- const res = await fetch(`${API_URL}/api/memories/bulk`, {
1161
- method: "POST",
1162
- headers: {
1163
- "Content-Type": "application/json",
1164
- Authorization: `Bearer ${apiKey}`
1165
- },
1166
- body: JSON.stringify(asyncEmbed ? { items, async: true } : items)
1167
- });
1168
- if (res.status === 429) {
1169
- retries--;
1170
- await new Promise((r) => setTimeout(r, 5000));
1171
- continue;
1172
- }
1173
- if (!res.ok) {
1174
- const body = await res.text().catch(() => "");
1175
- throw new Error(`HTTP ${res.status}: ${body.slice(0, 120)}`);
1176
- }
1177
- const data = await res.json();
1178
- if (!Array.isArray(data.results) || data.results.length !== items.length) {
1179
- throw new Error("Unexpected bulk upload response");
1180
- }
1181
- return data.results;
1182
- } catch (error) {
1183
- retries--;
1184
- if (retries === 0) {
1185
- return items.map(() => ({
1186
- success: false,
1187
- error: error instanceof Error ? error.message : String(error)
1188
- }));
1189
- }
1190
- await new Promise((r) => setTimeout(r, 2000));
1028
+ function cleanText(raw) {
1029
+ let text = raw;
1030
+ text = text.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g, "");
1031
+ text = text.replace(/<attached-context[\s\S]*?<\/attached-context>/g, "");
1032
+ text = text.replace(/<environment_context>[\s\S]*?<\/environment_context>/g, "");
1033
+ text = text.replace(/^\s*Base directory for this skill:[\s\S]*/g, "");
1034
+ text = text.replace(/\nBase directory for this skill:[\s\S]*/g, "");
1035
+ text = text.replace(/<!-- vibe-rules Integration -->[\s\S]*?<!-- \/vibe-rules Integration -->/g, "");
1036
+ text = text.replace(/<good-behaviour>[\s\S]*?<\/good-behaviour>/g, "");
1037
+ text = text.replace(/<frontend-design>[\s\S]*?<\/frontend-design>/g, "");
1038
+ text = text.replace(/<architecture>[\s\S]*?<\/architecture>/g, "");
1039
+ return text.trim();
1040
+ }
1041
+ function createContentHash(content) {
1042
+ return createHash("sha256").update(content).digest("hex").slice(0, 16);
1043
+ }
1044
+ function getIngested() {
1045
+ try {
1046
+ if (existsSync2(MANIFEST_PATH)) {
1047
+ return JSON.parse(readFileSync(MANIFEST_PATH, "utf-8"));
1191
1048
  }
1049
+ } catch {}
1050
+ return {};
1051
+ }
1052
+ function markIngested(source, sessionIds) {
1053
+ const manifest = getIngested();
1054
+ const existing = new Set(manifest[source] || []);
1055
+ for (const id of sessionIds)
1056
+ existing.add(id);
1057
+ manifest[source] = [...existing];
1058
+ const dir = join2(homedir2(), ".conare");
1059
+ if (!existsSync2(dir))
1060
+ mkdirSync(dir, { recursive: true });
1061
+ writeFileSync(MANIFEST_PATH, JSON.stringify(manifest, null, 2));
1062
+ }
1063
+ function isIngested(source, sessionId) {
1064
+ const manifest = getIngested();
1065
+ return (manifest[source] || []).includes(sessionId);
1066
+ }
1067
+ function clearIngested(source) {
1068
+ const manifest = getIngested();
1069
+ if (source) {
1070
+ delete manifest[source];
1071
+ } else {
1072
+ for (const key of Object.keys(manifest))
1073
+ delete manifest[key];
1192
1074
  }
1193
- return items.map(() => ({ success: false, error: "Upload failed" }));
1075
+ const dir = join2(homedir2(), ".conare");
1076
+ if (!existsSync2(dir))
1077
+ mkdirSync(dir, { recursive: true });
1078
+ writeFileSync(MANIFEST_PATH, JSON.stringify(manifest, null, 2));
1194
1079
  }
1195
- async function uploadBulk(apiKey, memories, onProgress) {
1196
- let success = 0;
1197
- let failed = 0;
1198
- const total = memories.length;
1199
- const results = [];
1200
- const batches = createUploadBatches(memories);
1201
- for (const batch of batches) {
1202
- let batchResults = await uploadItems(apiKey, batch.items, true);
1203
- if (batch.items.length > 1 && batchResults.some((result) => !result.success)) {
1204
- const retriedResults = [];
1205
- for (let i = 0;i < batch.items.length; i++) {
1206
- const result = batchResults[i];
1207
- if (result.success) {
1208
- retriedResults.push(result);
1209
- continue;
1210
- }
1211
- const [singleResult] = await uploadItems(apiKey, [batch.items[i]], true);
1212
- retriedResults.push(singleResult);
1080
+
1081
+ // src/ingest/claude.ts
1082
+ var MAX_CONTENT = 48000;
1083
+ var MIN_TURN_LEN = 50;
1084
+ function resolveProjectName(dirName) {
1085
+ const segments = dirName.replace(/^-/, "").split("-");
1086
+ let resolved = "/";
1087
+ let i = 0;
1088
+ while (i < segments.length) {
1089
+ let found = false;
1090
+ for (let end = segments.length;end > i; end--) {
1091
+ const candidate = segments.slice(i, end).join("-");
1092
+ const candidatePath = join3(resolved, candidate);
1093
+ if (existsSync3(candidatePath)) {
1094
+ resolved = candidatePath;
1095
+ i = end;
1096
+ found = true;
1097
+ break;
1213
1098
  }
1214
- batchResults = retriedResults;
1215
1099
  }
1216
- for (let i = 0;i < batchResults.length; i++) {
1217
- const result = batchResults[i];
1218
- results.push({
1219
- index: batch.startIndex + i,
1220
- success: result.success,
1221
- deduped: result.deduped,
1222
- error: result.error
1223
- });
1224
- if (result.success)
1225
- success++;
1226
- else
1227
- failed++;
1100
+ if (!found) {
1101
+ resolved = join3(resolved, segments[i]);
1102
+ i++;
1228
1103
  }
1229
- onProgress?.(success + failed, total, failed);
1230
1104
  }
1231
- return { success, failed, results };
1232
- }
1233
-
1234
- // src/configure.ts
1235
- import { existsSync as existsSync5, mkdirSync as mkdirSync2, readFileSync as readFileSync6, writeFileSync as writeFileSync2 } from "node:fs";
1236
- import { dirname, join as join7 } from "node:path";
1237
- import { homedir as homedir5 } from "node:os";
1238
- import { spawnSync as spawnSync2 } from "node:child_process";
1239
- var CONARE_URL = "https://mcp.conare.ai";
1240
- var SERVER_NAME = "conare-memory";
1241
- var MCP_TARGETS = [
1242
- { id: "claude", label: "Claude Code" },
1243
- { id: "cursor", label: "Cursor" },
1244
- { id: "codex", label: "Codex" }
1245
- ];
1246
- function readJsonFile(path) {
1247
- try {
1248
- return JSON.parse(readFileSync6(path, "utf-8"));
1249
- } catch {
1250
- return {};
1105
+ const home = homedir3();
1106
+ if (resolved.startsWith(home + "/")) {
1107
+ return resolved.slice(home.length + 1);
1251
1108
  }
1109
+ return resolved;
1252
1110
  }
1253
- function writeJsonFile(path, data) {
1254
- mkdirSync2(dirname(path), { recursive: true });
1255
- writeFileSync2(path, JSON.stringify(data, null, 2) + `
1111
+ function extractText(content) {
1112
+ if (typeof content === "string")
1113
+ return content;
1114
+ if (!Array.isArray(content))
1115
+ return "";
1116
+ return content.filter((b) => b.type === "text" && b.text).map((b) => b.text).join(`
1256
1117
  `);
1257
1118
  }
1258
- function getServerConfig(apiKey) {
1259
- return {
1260
- type: "http",
1261
- url: `${CONARE_URL}/mcp`,
1262
- headers: {
1263
- Authorization: `Bearer ${apiKey}`
1119
+ function parseSession(lines) {
1120
+ const rounds = [];
1121
+ let date = null;
1122
+ let currentUser = null;
1123
+ let currentAssistant = [];
1124
+ for (const line of lines) {
1125
+ if (!line.trim())
1126
+ continue;
1127
+ let obj;
1128
+ try {
1129
+ obj = JSON.parse(line);
1130
+ } catch {
1131
+ continue;
1132
+ }
1133
+ if (!date && obj.timestamp)
1134
+ date = obj.timestamp.slice(0, 10);
1135
+ if (obj.type === "user") {
1136
+ const text = cleanText(extractText(obj.message?.content));
1137
+ if (text.length >= MIN_TURN_LEN) {
1138
+ if (currentUser !== null && currentAssistant.length > 0) {
1139
+ rounds.push({ user: currentUser, assistantParts: currentAssistant });
1140
+ }
1141
+ currentUser = text;
1142
+ currentAssistant = [];
1143
+ }
1144
+ } else if (obj.type === "assistant") {
1145
+ const text = cleanText(extractText(obj.message?.content));
1146
+ if (text.length >= MIN_TURN_LEN) {
1147
+ currentAssistant.push(text);
1148
+ }
1264
1149
  }
1265
- };
1266
- }
1267
- function upsertMcpServer(path, apiKey) {
1268
- const config = readJsonFile(path);
1269
- if (!config.mcpServers || typeof config.mcpServers !== "object") {
1270
- config.mcpServers = {};
1271
- }
1272
- config.mcpServers[SERVER_NAME] = getServerConfig(apiKey);
1273
- writeJsonFile(path, config);
1274
- }
1275
- function configureClaude(apiKey) {
1276
- const claudeConfigPath = join7(homedir5(), ".claude.json");
1277
- const claudeMcpPath = join7(homedir5(), ".claude", "mcp.json");
1278
- if (spawnSync2("claude", ["mcp", "add-json", SERVER_NAME, "--scope", "user", JSON.stringify(getServerConfig(apiKey))], {
1279
- stdio: "ignore"
1280
- }).status === 0) {
1281
- return "Claude Code configured via `claude mcp add-json`";
1282
1150
  }
1283
- upsertMcpServer(claudeConfigPath, apiKey);
1284
- if (existsSync5(join7(homedir5(), ".claude"))) {
1285
- upsertMcpServer(claudeMcpPath, apiKey);
1151
+ if (currentUser !== null && currentAssistant.length > 0) {
1152
+ rounds.push({ user: currentUser, assistantParts: currentAssistant });
1286
1153
  }
1287
- return `Claude Code configured at ${claudeConfigPath}`;
1288
- }
1289
- function configureJsonClient(path, apiKey, label) {
1290
- upsertMcpServer(path, apiKey);
1291
- return `${label} configured at ${path}`;
1154
+ const turns = rounds.map((r) => ({
1155
+ user: r.user,
1156
+ assistant: r.assistantParts.filter((p) => !isNarration(p)).join(`
1157
+
1158
+ `)
1159
+ })).filter((t) => t.assistant.length >= MIN_TURN_LEN);
1160
+ return { turns, date };
1292
1161
  }
1293
- function configureMcp(apiKey, targets = ["claude", "cursor", "codex"]) {
1294
- const results = [];
1295
- if (targets.includes("claude")) {
1296
- results.push(configureClaude(apiKey));
1297
- }
1298
- if (targets.includes("cursor")) {
1299
- results.push(configureJsonClient(join7(homedir5(), ".cursor", "mcp.json"), apiKey, "Cursor"));
1162
+ function ingestClaude() {
1163
+ const projectsDir = join3(homedir3(), ".claude", "projects");
1164
+ const memories = [];
1165
+ const sessionIds = [];
1166
+ let filtered = 0;
1167
+ let deduped = 0;
1168
+ let projectDirs;
1169
+ try {
1170
+ projectDirs = readdirSync2(projectsDir);
1171
+ } catch {
1172
+ return { memories, sessionIds, skipped: 0, filtered, deduped };
1300
1173
  }
1301
- if (targets.includes("codex")) {
1302
- results.push(configureJsonClient(join7(homedir5(), ".codex", "mcp.json"), apiKey, "Codex"));
1174
+ for (const projDir of projectDirs) {
1175
+ const projPath = join3(projectsDir, projDir);
1176
+ const project = resolveProjectName(projDir);
1177
+ let files;
1178
+ try {
1179
+ files = readdirSync2(projPath).filter((f) => f.endsWith(".jsonl"));
1180
+ } catch {
1181
+ continue;
1182
+ }
1183
+ for (const file of files) {
1184
+ const sessionId = basename(file, ".jsonl");
1185
+ const raw = readFileSync2(join3(projPath, file), "utf-8");
1186
+ const { turns, date } = parseSession(raw.split(`
1187
+ `));
1188
+ if (turns.length === 0) {
1189
+ filtered++;
1190
+ continue;
1191
+ }
1192
+ const header = `# Chat: ${project}${date ? ` | ${date}` : ""}`;
1193
+ const body = turns.map((t) => {
1194
+ const q = t.user.length > 300 ? t.user.slice(0, 300) + "..." : t.user;
1195
+ return `## Q: ${q}
1196
+
1197
+ ${t.assistant}`;
1198
+ }).join(`
1199
+
1200
+ ---
1201
+
1202
+ `);
1203
+ let content = `${header}
1204
+
1205
+ ${body}`;
1206
+ if (content.length > MAX_CONTENT)
1207
+ content = content.slice(0, MAX_CONTENT) + `
1208
+
1209
+ [truncated]`;
1210
+ const contentHash = createContentHash(content);
1211
+ const dedupKey = `claude:${sessionId}`;
1212
+ const fingerprint = `${dedupKey}:${contentHash}`;
1213
+ if (isIngested("claude", fingerprint)) {
1214
+ deduped++;
1215
+ continue;
1216
+ }
1217
+ memories.push({
1218
+ content,
1219
+ containerTag: "claude-chats",
1220
+ metadata: {
1221
+ dedupKey,
1222
+ contentHash,
1223
+ source: "claude-code",
1224
+ sessionId,
1225
+ project,
1226
+ date: date || "unknown"
1227
+ }
1228
+ });
1229
+ sessionIds.push(sessionId);
1230
+ }
1303
1231
  }
1304
- return results;
1232
+ return { memories, sessionIds, skipped: filtered + deduped, filtered, deduped };
1305
1233
  }
1306
1234
 
1307
- // src/config.ts
1308
- import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync7, writeFileSync as writeFileSync3 } from "node:fs";
1309
- import { join as join8 } from "node:path";
1310
- import { homedir as homedir6 } from "node:os";
1311
- var CONFIG_DIR = join8(homedir6(), ".conare");
1312
- var CONFIG_PATH = join8(CONFIG_DIR, "config.json");
1313
- function readConfig() {
1314
- try {
1315
- if (!existsSync6(CONFIG_PATH))
1316
- return {};
1317
- return JSON.parse(readFileSync7(CONFIG_PATH, "utf-8"));
1318
- } catch {
1319
- return {};
1320
- }
1235
+ // src/ingest/codex.ts
1236
+ import { existsSync as existsSync4, readFileSync as readFileSync3, readdirSync as readdirSync3 } from "node:fs";
1237
+ import { join as join4, basename as basename2 } from "node:path";
1238
+ import { homedir as homedir4 } from "node:os";
1239
+ var MAX_CONTENT2 = 48000;
1240
+ function isCodexBoilerplate(text) {
1241
+ return text.startsWith("# AGENTS.md instructions for") || text.startsWith("<INSTRUCTIONS>") || text.startsWith("<user_instructions>") || text.startsWith("<user_action>");
1321
1242
  }
1322
- function saveApiKey(apiKey) {
1323
- mkdirSync3(CONFIG_DIR, { recursive: true });
1324
- writeFileSync3(CONFIG_PATH, JSON.stringify({ apiKey }, null, 2) + `
1325
- `);
1243
+ function stripEnvironmentContext(text) {
1244
+ let cwd = null;
1245
+ const cwdMatch = text.match(/<cwd>([^<]+)<\/cwd>/);
1246
+ if (cwdMatch)
1247
+ cwd = cwdMatch[1];
1248
+ const cleaned = text.replace(/<environment_context>[\s\S]*?<\/environment_context>/g, "").trim();
1249
+ return { text: cleaned, cwd };
1326
1250
  }
1327
- function getSavedApiKey() {
1328
- return readConfig().apiKey;
1251
+ function projectFromCwd(cwd) {
1252
+ return cwd.replace(/^\/Users\/[^/]+\//, "");
1329
1253
  }
1254
+ function ingestCodex() {
1255
+ const memories = [];
1256
+ const sessionIds = [];
1257
+ let filtered = 0;
1258
+ let deduped = 0;
1259
+ const historyPath = join4(homedir4(), ".codex", "history.jsonl");
1260
+ if (existsSync4(historyPath)) {
1261
+ try {
1262
+ const lines = readFileSync3(historyPath, "utf-8").split(`
1263
+ `).filter(Boolean);
1264
+ const sessions = new Map;
1265
+ for (const line of lines) {
1266
+ try {
1267
+ const obj = JSON.parse(line);
1268
+ if (!obj.session_id || !obj.text)
1269
+ continue;
1270
+ if (!sessions.has(obj.session_id))
1271
+ sessions.set(obj.session_id, []);
1272
+ sessions.get(obj.session_id).push({ ts: obj.ts, text: obj.text });
1273
+ } catch {
1274
+ continue;
1275
+ }
1276
+ }
1277
+ for (const [sessionId, entries] of sessions) {
1278
+ entries.sort((a, b) => a.ts - b.ts);
1279
+ const date = new Date(entries[0].ts * 1000).toISOString().slice(0, 10);
1280
+ let project = null;
1281
+ const cleanEntries = [];
1282
+ for (const e of entries) {
1283
+ let text = cleanText(e.text);
1284
+ if (isCodexBoilerplate(text))
1285
+ continue;
1286
+ const env = stripEnvironmentContext(text);
1287
+ text = env.text;
1288
+ if (!project && env.cwd)
1289
+ project = projectFromCwd(env.cwd);
1290
+ if (text.length === 0)
1291
+ continue;
1292
+ cleanEntries.push(text.length > 300 ? text.slice(0, 300) + "..." : text);
1293
+ }
1294
+ const body = cleanEntries.filter(Boolean).join(`
1330
1295
 
1331
- // src/sync.ts
1332
- import { existsSync as existsSync7, mkdirSync as mkdirSync4, writeFileSync as writeFileSync4, unlinkSync, readFileSync as readFileSync8, chmodSync, cpSync, rmSync, symlinkSync, readlinkSync, appendFileSync } from "node:fs";
1333
- import { join as join9, dirname as dirname2 } from "node:path";
1334
- import { homedir as homedir7, platform as platform2 } from "node:os";
1335
- import { execSync } from "node:child_process";
1336
- var CONARE_DIR = join9(homedir7(), ".conare");
1337
- var BIN_DIR = join9(CONARE_DIR, "bin");
1338
- var CONFIG_PATH2 = join9(CONARE_DIR, "config.json");
1339
- var PLIST_LABEL = "ai.conare.ingest";
1340
- var PLIST_PATH = join9(homedir7(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
1341
- var SYSTEMD_DIR = join9(homedir7(), ".config", "systemd", "user");
1342
- var SYSTEMD_SERVICE = join9(SYSTEMD_DIR, "conare-sync.service");
1343
- var SYSTEMD_TIMER = join9(SYSTEMD_DIR, "conare-sync.timer");
1344
- var RUN_SH = `#!/bin/bash
1345
- # Conare Memory — background sync wrapper
1346
- # Resolves node at runtime to survive nvm/fnm upgrades
1296
+ ---
1347
1297
 
1348
- CONARE_DIR="$HOME/.conare"
1349
- LOCKFILE="$CONARE_DIR/sync.lock"
1350
- LOG="$CONARE_DIR/ingest.log"
1298
+ `);
1299
+ let content = `# Codex Chat | ${date}
1351
1300
 
1352
- # Log rotation: truncate if > 1MB
1353
- if [ -f "$LOG" ] && [ "$(wc -c < "$LOG" 2>/dev/null)" -gt 1048576 ]; then
1354
- tail -100 "$LOG" > "$LOG.tmp" && mv "$LOG.tmp" "$LOG"
1355
- fi
1301
+ ${body}`;
1302
+ if (content.length > MAX_CONTENT2)
1303
+ content = content.slice(0, MAX_CONTENT2) + `
1356
1304
 
1357
- # File lock: prevent concurrent runs
1358
- # macOS doesn't have flock — use mkdir as atomic lock
1359
- if ! mkdir "$LOCKFILE.d" 2>/dev/null; then
1360
- # Check if stale (older than 30 min)
1361
- if [ "$(uname)" = "Darwin" ]; then
1362
- LOCK_AGE=$(( $(date +%s) - $(stat -f %m "$LOCKFILE.d" 2>/dev/null || echo 0) ))
1363
- else
1364
- LOCK_AGE=$(( $(date +%s) - $(stat -c %Y "$LOCKFILE.d" 2>/dev/null || echo 0) ))
1365
- fi
1366
- if [ "$LOCK_AGE" -gt 1800 ]; then
1367
- rm -rf "$LOCKFILE.d"
1368
- mkdir "$LOCKFILE.d" 2>/dev/null || true
1369
- else
1370
- echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) SKIP: another instance running" >> "$LOG"
1371
- exit 0
1372
- fi
1373
- fi
1374
- trap 'rm -rf "$LOCKFILE.d"' EXIT
1305
+ [truncated]`;
1306
+ if (content.length < 100) {
1307
+ filtered++;
1308
+ continue;
1309
+ }
1310
+ const contentHash = createContentHash(content);
1311
+ const dedupKey = `codex:${sessionId}`;
1312
+ const fingerprint = `${dedupKey}:${contentHash}`;
1313
+ if (isIngested("codex", fingerprint)) {
1314
+ deduped++;
1315
+ continue;
1316
+ }
1317
+ memories.push({
1318
+ content,
1319
+ containerTag: "codex-chats",
1320
+ metadata: {
1321
+ dedupKey,
1322
+ contentHash,
1323
+ source: "codex",
1324
+ sessionId,
1325
+ date,
1326
+ ...project ? { project } : {}
1327
+ }
1328
+ });
1329
+ sessionIds.push(sessionId);
1330
+ }
1331
+ } catch {}
1332
+ }
1333
+ const sessionsDir = join4(homedir4(), ".codex", "sessions");
1334
+ if (existsSync4(sessionsDir)) {
1335
+ try {
1336
+ const stats = { filtered: 0, deduped: 0 };
1337
+ walkCodexSessions(sessionsDir, memories, sessionIds, stats);
1338
+ filtered += stats.filtered;
1339
+ deduped += stats.deduped;
1340
+ } catch {}
1341
+ }
1342
+ return { memories, sessionIds, skipped: filtered + deduped, filtered, deduped };
1343
+ }
1344
+ function walkCodexSessions(dir, memories, sessionIds, stats) {
1345
+ try {
1346
+ for (const entry of readdirSync3(dir, { withFileTypes: true })) {
1347
+ if (entry.isDirectory()) {
1348
+ walkCodexSessions(join4(dir, entry.name), memories, sessionIds, stats);
1349
+ } else if (entry.name.endsWith(".jsonl")) {
1350
+ const sessionId = basename2(entry.name, ".jsonl");
1351
+ if (sessionIds.includes(sessionId))
1352
+ continue;
1353
+ try {
1354
+ const lines = readFileSync3(join4(dir, entry.name), "utf-8").split(`
1355
+ `).filter(Boolean);
1356
+ let date = null;
1357
+ let project = null;
1358
+ const rounds = [];
1359
+ let currentUser = null;
1360
+ let currentAssistant = [];
1361
+ for (const line of lines) {
1362
+ try {
1363
+ const obj = JSON.parse(line);
1364
+ if (!date && obj.timestamp)
1365
+ date = obj.timestamp.slice(0, 10);
1366
+ if (obj.type === "session_meta" && obj.payload?.cwd) {
1367
+ project = projectFromCwd(obj.payload.cwd);
1368
+ }
1369
+ if (obj.type !== "response_item" || obj.payload?.type !== "message")
1370
+ continue;
1371
+ const role = obj.payload.role;
1372
+ const msgContent = obj.payload.content;
1373
+ if (!Array.isArray(msgContent))
1374
+ continue;
1375
+ if (role === "user") {
1376
+ for (const block of msgContent) {
1377
+ if (block.type === "input_text" && block.text) {
1378
+ const text = cleanText(block.text);
1379
+ if (isCodexBoilerplate(text))
1380
+ continue;
1381
+ if (text.length >= 50) {
1382
+ if (currentUser !== null && currentAssistant.length > 0) {
1383
+ rounds.push({ user: currentUser, assistantParts: currentAssistant });
1384
+ }
1385
+ currentUser = text;
1386
+ currentAssistant = [];
1387
+ }
1388
+ }
1389
+ }
1390
+ } else if (role === "assistant") {
1391
+ for (const block of msgContent) {
1392
+ if (block.type === "output_text" && block.text) {
1393
+ const text = cleanText(block.text);
1394
+ if (!isNarration(text)) {
1395
+ currentAssistant.push(text);
1396
+ }
1397
+ }
1398
+ }
1399
+ }
1400
+ } catch {
1401
+ continue;
1402
+ }
1403
+ }
1404
+ if (currentUser !== null && currentAssistant.length > 0) {
1405
+ rounds.push({ user: currentUser, assistantParts: currentAssistant });
1406
+ }
1407
+ if (rounds.length === 0) {
1408
+ stats.filtered++;
1409
+ continue;
1410
+ }
1411
+ const body = rounds.map((r) => {
1412
+ const q = r.user.length > 300 ? r.user.slice(0, 300) + "..." : r.user;
1413
+ const assistant = r.assistantParts.join(`
1375
1414
 
1376
- # Resolve node binary
1377
- resolve_node() {
1378
- command -v node >/dev/null 2>&1 && { command -v node; return; }
1379
- if [ -s "$HOME/.nvm/nvm.sh" ]; then
1380
- . "$HOME/.nvm/nvm.sh" >/dev/null 2>&1
1381
- command -v node >/dev/null 2>&1 && { command -v node; return; }
1382
- fi
1383
- if command -v fnm >/dev/null 2>&1; then
1384
- eval "$(fnm env)" >/dev/null 2>&1
1385
- command -v node >/dev/null 2>&1 && { command -v node; return; }
1386
- fi
1387
- for p in /opt/homebrew/bin/node /usr/local/bin/node /usr/bin/node; do
1388
- [ -x "$p" ] && { echo "$p"; return; }
1389
- done
1390
- return 1
1391
- }
1415
+ `);
1416
+ return `## Q: ${q}
1392
1417
 
1393
- NODE=$(resolve_node)
1394
- if [ -z "$NODE" ]; then
1395
- echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) ERROR: node not found" >> "$LOG"
1396
- exit 1
1397
- fi
1418
+ ${assistant}`;
1419
+ }).join(`
1398
1420
 
1399
- echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) START sync" >> "$LOG"
1400
- "$NODE" "$CONARE_DIR/bin/conare-ingest.mjs" \\
1401
- --config-file "$CONARE_DIR/config.json" \\
1402
- --ingest-only \\
1403
- --quiet \\
1404
- 2>> "$LOG"
1405
- echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) DONE sync (exit $?)" >> "$LOG"
1406
- `;
1407
- function makePlist(intervalMinutes) {
1408
- const home = homedir7();
1409
- return `<?xml version="1.0" encoding="UTF-8"?>
1410
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
1411
- "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
1412
- <plist version="1.0">
1413
- <dict>
1414
- <key>Label</key>
1415
- <string>${PLIST_LABEL}</string>
1416
- <key>ProgramArguments</key>
1417
- <array>
1418
- <string>/bin/bash</string>
1419
- <string>${home}/.conare/bin/run.sh</string>
1420
- </array>
1421
- <key>StartInterval</key>
1422
- <integer>${intervalMinutes * 60}</integer>
1423
- <key>StandardOutPath</key>
1424
- <string>${home}/.conare/ingest.log</string>
1425
- <key>StandardErrorPath</key>
1426
- <string>${home}/.conare/ingest.log</string>
1427
- <key>RunAtLoad</key>
1428
- <true/>
1429
- </dict>
1430
- </plist>`;
1431
- }
1432
- var SYSTEMD_SERVICE_CONTENT = `[Unit]
1433
- Description=Conare Memory — background sync
1421
+ ---
1434
1422
 
1435
- [Service]
1436
- Type=oneshot
1437
- ExecStart=%h/.conare/bin/run.sh
1438
- `;
1439
- function makeSystemdTimer(intervalMinutes) {
1440
- return `[Unit]
1441
- Description=Conare Memory — sync every ${intervalMinutes} minutes
1423
+ `);
1424
+ let content = `# Codex Session${project ? `: ${project}` : ""} | ${date || "unknown"}
1442
1425
 
1443
- [Timer]
1444
- OnBootSec=2min
1445
- OnUnitActiveSec=${intervalMinutes}min
1446
- Persistent=true
1426
+ ${body}`;
1427
+ if (content.length > MAX_CONTENT2)
1428
+ content = content.slice(0, MAX_CONTENT2) + `
1447
1429
 
1448
- [Install]
1449
- WantedBy=timers.target
1450
- `;
1430
+ [truncated]`;
1431
+ const contentHash = createContentHash(content);
1432
+ const dedupKey = `codex:${sessionId}`;
1433
+ const fingerprint = `${dedupKey}:${contentHash}`;
1434
+ if (isIngested("codex", fingerprint)) {
1435
+ stats.deduped++;
1436
+ continue;
1437
+ }
1438
+ memories.push({
1439
+ content,
1440
+ containerTag: "codex-chats",
1441
+ metadata: {
1442
+ dedupKey,
1443
+ contentHash,
1444
+ source: "codex-session",
1445
+ sessionId,
1446
+ date: date || "unknown",
1447
+ ...project ? { project } : {}
1448
+ }
1449
+ });
1450
+ sessionIds.push(sessionId);
1451
+ } catch {}
1452
+ }
1453
+ }
1454
+ } catch {}
1451
1455
  }
1452
- function hasSystemd() {
1456
+
1457
+ // src/ingest/cursor.ts
1458
+ import { readFileSync as readFileSync4, statSync } from "node:fs";
1459
+ import { join as join5 } from "node:path";
1460
+ import { createRequire as createRequire2 } from "node:module";
1461
+ var MAX_CONTENT3 = 48000;
1462
+ var MAX_DB_SIZE = 2 * 1024 * 1024 * 1024;
1463
+ var WARN_DB_SIZE = 500 * 1024 * 1024;
1464
+ var MIN_TURN_LEN2 = 50;
1465
+ function loadSqlJs(wasmDir) {
1453
1466
  try {
1454
- execSync("systemctl --user status 2>/dev/null", { stdio: "ignore" });
1455
- return true;
1467
+ if (wasmDir) {
1468
+ const require2 = createRequire2(join5(wasmDir, "sql.js", "package.json"));
1469
+ return require2("sql.js");
1470
+ } else {
1471
+ const require2 = createRequire2(import.meta.url);
1472
+ return require2("sql.js");
1473
+ }
1456
1474
  } catch {
1457
- return false;
1475
+ return null;
1458
1476
  }
1459
1477
  }
1460
- function uid() {
1461
- try {
1462
- return execSync("id -u", { encoding: "utf-8" }).trim();
1463
- } catch {
1464
- return "501";
1478
+ function openDb(initSqlJs, dbPath, wasmDir) {
1479
+ const locateOpts = {};
1480
+ if (wasmDir) {
1481
+ locateOpts.locateFile = (file) => join5(wasmDir, "sql.js", "dist", file);
1465
1482
  }
1483
+ return initSqlJs(locateOpts).then((SQL) => {
1484
+ const buffer = readFileSync4(dbPath);
1485
+ return new SQL.Database(buffer);
1486
+ });
1466
1487
  }
1467
- function persistBinary(apiKey) {
1468
- mkdirSync4(BIN_DIR, { recursive: true });
1469
- const cliEntry = findCliBundle();
1470
- if (!cliEntry) {
1471
- throw new Error("Could not locate CLI bundle. Run from an installed conare package.");
1472
- }
1473
- const dest = join9(BIN_DIR, "conare-ingest.mjs");
1474
- const content = readFileSync8(cliEntry, "utf-8");
1475
- writeFileSync4(dest, content);
1476
- const sqlJsDir = findSqlJs();
1477
- if (sqlJsDir) {
1478
- const targetDir = join9(BIN_DIR, "node_modules", "sql.js");
1479
- mkdirSync4(targetDir, { recursive: true });
1488
+ function extractTurns(db, composerId, bubbleHeaders) {
1489
+ const turns = [];
1490
+ let pendingUser = null;
1491
+ for (const header of bubbleHeaders) {
1492
+ let text = "";
1480
1493
  try {
1481
- cpSync(sqlJsDir, targetDir, { recursive: true });
1482
- } catch {}
1483
- }
1484
- const runShPath = join9(BIN_DIR, "run.sh");
1485
- writeFileSync4(runShPath, RUN_SH);
1486
- chmodSync(runShPath, 493);
1487
- writeFileSync4(CONFIG_PATH2, JSON.stringify({ apiKey }, null, 2) + `
1488
- `);
1489
- }
1490
- function findCliBundle() {
1491
- const entry = process.argv[1];
1492
- if (entry && existsSync7(entry))
1493
- return entry;
1494
- const candidates = [
1495
- join9(dirname2(new URL(import.meta.url).pathname), "index.js"),
1496
- join9(dirname2(new URL(import.meta.url).pathname), "..", "dist", "index.js")
1497
- ];
1498
- for (const c of candidates) {
1499
- if (existsSync7(c))
1500
- return c;
1501
- }
1502
- return null;
1503
- }
1504
- function findSqlJs() {
1505
- const candidates = [
1506
- join9(process.cwd(), "node_modules", "sql.js"),
1507
- join9(dirname2(new URL(import.meta.url).pathname), "..", "node_modules", "sql.js"),
1508
- join9(dirname2(new URL(import.meta.url).pathname), "..", "..", "node_modules", "sql.js")
1509
- ];
1510
- for (const c of candidates) {
1511
- if (existsSync7(c))
1512
- return c;
1494
+ const result = db.exec(`SELECT value FROM cursorDiskKV WHERE key = 'bubbleId:${composerId}:${header.bubbleId}'`);
1495
+ if (result.length > 0) {
1496
+ const bubble = JSON.parse(result[0].values[0][0]);
1497
+ text = cleanText(bubble.text || "");
1498
+ }
1499
+ } catch {
1500
+ continue;
1501
+ }
1502
+ if (text.length < MIN_TURN_LEN2)
1503
+ continue;
1504
+ if (header.type === 1) {
1505
+ pendingUser = text;
1506
+ } else if (header.type === 2 && pendingUser) {
1507
+ turns.push({ user: pendingUser, assistant: text });
1508
+ pendingUser = null;
1509
+ }
1513
1510
  }
1514
- return null;
1511
+ return turns;
1515
1512
  }
1516
- function setupMacOS(intervalMinutes) {
1517
- const plistDir = dirname2(PLIST_PATH);
1518
- mkdirSync4(plistDir, { recursive: true });
1519
- writeFileSync4(PLIST_PATH, makePlist(intervalMinutes));
1520
- const id = uid();
1521
- try {
1522
- execSync(`launchctl bootout gui/${id} "${PLIST_PATH}" 2>/dev/null`, { stdio: "ignore" });
1523
- } catch {}
1513
+ async function ingestCursor(dbPath, wasmDir) {
1514
+ const memories = [];
1515
+ const sessionIds = [];
1516
+ let filtered = 0;
1517
+ let deduped = 0;
1518
+ let fileSize;
1524
1519
  try {
1525
- execSync(`launchctl bootstrap gui/${id} "${PLIST_PATH}"`, { stdio: "ignore" });
1520
+ fileSize = statSync(dbPath).size;
1526
1521
  } catch {
1527
- try {
1528
- execSync(`launchctl load "${PLIST_PATH}"`, { stdio: "ignore" });
1529
- } catch {
1530
- throw new Error("Failed to load launchd agent. Try manually: launchctl load " + PLIST_PATH);
1531
- }
1522
+ console.log(" Skipping Cursor: database not accessible");
1523
+ return { memories, sessionIds, skipped: 0, filtered, deduped };
1532
1524
  }
1533
- }
1534
- function setupLinuxSystemd(intervalMinutes) {
1535
- mkdirSync4(SYSTEMD_DIR, { recursive: true });
1536
- writeFileSync4(SYSTEMD_SERVICE, SYSTEMD_SERVICE_CONTENT);
1537
- writeFileSync4(SYSTEMD_TIMER, makeSystemdTimer(intervalMinutes));
1538
- execSync("systemctl --user daemon-reload", { stdio: "ignore" });
1539
- execSync("systemctl --user enable --now conare-sync.timer", { stdio: "ignore" });
1540
- }
1541
- function setupLinuxCron(intervalMinutes) {
1542
- const cronCmd = `${homedir7()}/.conare/bin/run.sh`;
1543
- const cronLine = `*/${intervalMinutes} * * * * ${cronCmd}`;
1525
+ if (fileSize > MAX_DB_SIZE) {
1526
+ console.log(` Skipping Cursor: database too large (${(fileSize / 1024 / 1024 / 1024).toFixed(1)}GB)`);
1527
+ return { memories, sessionIds, skipped: 0, filtered, deduped };
1528
+ }
1529
+ if (fileSize > WARN_DB_SIZE) {
1530
+ console.log(` Warning: large database (${(fileSize / 1024 / 1024).toFixed(0)}MB), loading into memory...`);
1531
+ }
1532
+ const initSqlJs = loadSqlJs(wasmDir);
1533
+ if (!initSqlJs) {
1534
+ console.log(" Skipping Cursor: sql.js not available");
1535
+ return { memories, sessionIds, skipped: 0, filtered, deduped };
1536
+ }
1537
+ let db;
1544
1538
  try {
1545
- const existing = execSync("crontab -l 2>/dev/null", { encoding: "utf-8" });
1546
- const filtered = existing.split(`
1547
- `).filter((l) => !l.includes("conare")).join(`
1548
- `);
1549
- const newCrontab = (filtered.trim() ? filtered.trim() + `
1550
- ` : "") + cronLine + `
1551
- `;
1552
- execSync("crontab -", { input: newCrontab, stdio: ["pipe", "ignore", "ignore"] });
1553
- } catch {
1554
- execSync("crontab -", { input: cronLine + `
1555
- `, stdio: ["pipe", "ignore", "ignore"] });
1539
+ db = await openDb(initSqlJs, dbPath, wasmDir);
1540
+ } catch (e) {
1541
+ console.log(` Skipping Cursor: cannot open database (${e.message})`);
1542
+ return { memories, sessionIds, skipped: 0, filtered, deduped };
1556
1543
  }
1557
- }
1558
- function installGlobalCommand() {
1559
- const wrapper = join9(BIN_DIR, "conare");
1560
- const content = `#!/bin/bash
1561
- # Conare global command — runs the persisted CLI bundle
1562
- CONARE_DIR="$HOME/.conare"
1563
- NODE=$(command -v node || echo "")
1564
- if [ -z "$NODE" ]; then
1565
- if [ -s "$HOME/.nvm/nvm.sh" ]; then
1566
- . "$HOME/.nvm/nvm.sh" >/dev/null 2>&1
1567
- NODE=$(command -v node || echo "")
1568
- fi
1569
- fi
1570
- if [ -z "$NODE" ]; then
1571
- echo "Error: node not found. Install Node.js first." >&2
1572
- exit 1
1573
- fi
1574
- exec "$NODE" "$CONARE_DIR/bin/conare-ingest.mjs" "$@"
1575
- `;
1576
- writeFileSync4(wrapper, content);
1577
- chmodSync(wrapper, 493);
1578
- const symlinkTarget = "/usr/local/bin/conare";
1579
1544
  try {
1580
- if (existsSync7(symlinkTarget)) {
1581
- try {
1582
- const existing = readlinkSync(symlinkTarget);
1583
- if (existing === wrapper)
1584
- return "Global command: conare (already linked)";
1585
- } catch {}
1586
- unlinkSync(symlinkTarget);
1587
- }
1588
- symlinkSync(wrapper, symlinkTarget);
1589
- return "Global command: conare (linked to /usr/local/bin)";
1590
- } catch {
1591
- const pathDirs = (process.env.PATH || "").split(":");
1592
- if (pathDirs.includes(BIN_DIR)) {
1593
- return "Global command: conare (via ~/.conare/bin in PATH)";
1594
- }
1595
- const shellProfile = getShellProfile();
1596
- if (shellProfile) {
1545
+ let rows = [];
1546
+ try {
1547
+ const results = db.exec("SELECT key, value FROM cursorDiskKV WHERE key LIKE 'composerData:%'");
1548
+ if (results.length > 0)
1549
+ rows = results[0].values;
1550
+ } catch {}
1551
+ for (const [key, value] of rows) {
1552
+ const composerId = key.replace("composerData:", "");
1553
+ let parsed;
1597
1554
  try {
1598
- const profileContent = existsSync7(shellProfile) ? readFileSync8(shellProfile, "utf-8") : "";
1599
- const exportLine = `export PATH="$HOME/.conare/bin:$PATH"`;
1600
- if (!profileContent.includes(".conare/bin")) {
1601
- appendFileSync(shellProfile, `
1602
- # Conare CLI
1603
- ${exportLine}
1604
- `);
1605
- return `Global command: conare (added ~/.conare/bin to ${shellProfile} — restart shell)`;
1555
+ parsed = JSON.parse(value);
1556
+ if (!parsed || typeof parsed !== "object") {
1557
+ filtered++;
1558
+ continue;
1606
1559
  }
1607
- return "Global command: conare (via ~/.conare/bin in PATH)";
1608
1560
  } catch {
1609
- return `Global command: add ~/.conare/bin to your PATH manually`;
1561
+ filtered++;
1562
+ continue;
1563
+ }
1564
+ const bubbleHeaders = parsed.fullConversationHeadersOnly;
1565
+ if (!Array.isArray(bubbleHeaders) || bubbleHeaders.length === 0) {
1566
+ filtered++;
1567
+ continue;
1568
+ }
1569
+ const turns = extractTurns(db, composerId, bubbleHeaders);
1570
+ if (turns.length === 0) {
1571
+ filtered++;
1572
+ continue;
1573
+ }
1574
+ const sessionName = parsed.name || "Cursor Chat";
1575
+ const date = parsed.createdAt ? new Date(parsed.createdAt).toISOString().slice(0, 10) : "unknown";
1576
+ const header = `# ${sessionName} | ${date}`;
1577
+ const body = turns.map((t) => {
1578
+ const q = t.user.length > 300 ? t.user.slice(0, 300) + "..." : t.user;
1579
+ return `## Q: ${q}
1580
+
1581
+ ${t.assistant}`;
1582
+ }).join(`
1583
+
1584
+ ---
1585
+
1586
+ `);
1587
+ let content = `${header}
1588
+
1589
+ ${body}`;
1590
+ if (content.length > MAX_CONTENT3)
1591
+ content = content.slice(0, MAX_CONTENT3) + `
1592
+
1593
+ [truncated]`;
1594
+ const contentHash = createContentHash(content);
1595
+ const dedupKey = `cursor:${composerId}`;
1596
+ const fingerprint = `${dedupKey}:${contentHash}`;
1597
+ if (isIngested("cursor", fingerprint)) {
1598
+ deduped++;
1599
+ continue;
1610
1600
  }
1601
+ memories.push({
1602
+ content,
1603
+ containerTag: "cursor-chats",
1604
+ metadata: {
1605
+ dedupKey,
1606
+ contentHash,
1607
+ source: "cursor",
1608
+ sessionId: composerId,
1609
+ name: sessionName,
1610
+ date
1611
+ }
1612
+ });
1613
+ sessionIds.push(composerId);
1611
1614
  }
1612
- return `Global command: add ~/.conare/bin to your PATH manually`;
1613
- }
1614
- }
1615
- function getShellProfile() {
1616
- const home = homedir7();
1617
- const shell = process.env.SHELL || "";
1618
- if (shell.includes("zsh"))
1619
- return join9(home, ".zshrc");
1620
- if (shell.includes("bash")) {
1621
- const profile = join9(home, ".bash_profile");
1622
- if (platform2() === "darwin" && existsSync7(profile))
1623
- return profile;
1624
- return join9(home, ".bashrc");
1615
+ } catch (e) {
1616
+ console.log(` Cursor ingestion error: ${e.message}`);
1617
+ } finally {
1618
+ db.close();
1625
1619
  }
1626
- if (existsSync7(join9(home, ".zshrc")))
1627
- return join9(home, ".zshrc");
1628
- if (existsSync7(join9(home, ".bashrc")))
1629
- return join9(home, ".bashrc");
1630
- return null;
1620
+ return { memories, sessionIds, skipped: filtered + deduped, filtered, deduped };
1631
1621
  }
1632
- function installSync(apiKey, intervalMinutes = 10) {
1633
- const messages = [];
1634
- const os = platform2();
1635
- persistBinary(apiKey);
1636
- messages.push("Persisted CLI to ~/.conare/bin/");
1637
- messages.push("Saved config to ~/.conare/config.json");
1638
- const globalMsg = installGlobalCommand();
1639
- if (globalMsg)
1640
- messages.push(globalMsg);
1641
- if (os === "darwin") {
1642
- setupMacOS(intervalMinutes);
1643
- messages.push(`Installed launchd agent (every ${intervalMinutes} min)`);
1644
- messages.push(`Plist: ${PLIST_PATH}`);
1645
- } else if (os === "linux") {
1646
- if (hasSystemd()) {
1647
- setupLinuxSystemd(intervalMinutes);
1648
- messages.push(`Installed systemd timer (every ${intervalMinutes} min)`);
1649
- } else {
1650
- setupLinuxCron(intervalMinutes);
1651
- messages.push(`Installed cron job (every ${intervalMinutes} min)`);
1622
+
1623
+ // src/ingest/codebase.ts
1624
+ import { createHash as createHash2 } from "node:crypto";
1625
+ import { readdirSync as readdirSync4, readFileSync as readFileSync5, statSync as statSync2, existsSync as existsSync5 } from "node:fs";
1626
+ import { join as join6, relative, extname, resolve } from "node:path";
1627
+ var DEFAULT_IGNORE = new Set([
1628
+ "node_modules",
1629
+ ".git",
1630
+ ".next",
1631
+ ".nuxt",
1632
+ ".output",
1633
+ "dist",
1634
+ "build",
1635
+ ".cache",
1636
+ "__pycache__",
1637
+ ".venv",
1638
+ "venv",
1639
+ "vendor",
1640
+ "target",
1641
+ ".turbo",
1642
+ ".DS_Store",
1643
+ ".claude",
1644
+ ".conare"
1645
+ ]);
1646
+ var IGNORE_FILES = new Set([
1647
+ "package-lock.json",
1648
+ "bun.lockb",
1649
+ "yarn.lock",
1650
+ "pnpm-lock.yaml"
1651
+ ]);
1652
+ var CODE_EXTENSIONS = new Set([
1653
+ ".ts",
1654
+ ".tsx",
1655
+ ".js",
1656
+ ".jsx",
1657
+ ".mjs",
1658
+ ".cjs",
1659
+ ".vue",
1660
+ ".svelte",
1661
+ ".astro",
1662
+ ".py",
1663
+ ".rb",
1664
+ ".go",
1665
+ ".rs",
1666
+ ".java",
1667
+ ".kt",
1668
+ ".swift",
1669
+ ".c",
1670
+ ".cpp",
1671
+ ".h",
1672
+ ".css",
1673
+ ".scss",
1674
+ ".less",
1675
+ ".html",
1676
+ ".json",
1677
+ ".yaml",
1678
+ ".yml",
1679
+ ".toml",
1680
+ ".md",
1681
+ ".mdx",
1682
+ ".txt",
1683
+ ".sql",
1684
+ ".graphql",
1685
+ ".prisma",
1686
+ ".sh",
1687
+ ".bash",
1688
+ ".zsh",
1689
+ ".lua",
1690
+ ".zig",
1691
+ ".ex",
1692
+ ".exs"
1693
+ ]);
1694
+ var SPECIAL_FILES = new Set([
1695
+ "Dockerfile",
1696
+ "Makefile",
1697
+ "Procfile",
1698
+ "Justfile",
1699
+ ".gitignore",
1700
+ ".dockerignore",
1701
+ "CLAUDE.md",
1702
+ "AGENTS.md",
1703
+ "README.md",
1704
+ "ARCHITECTURE.md",
1705
+ "wrangler.toml",
1706
+ "wrangler.json"
1707
+ ]);
1708
+ var MAX_FILE_SIZE = 1e5;
1709
+ function parseGitignore(rootPath) {
1710
+ const patterns = new Set;
1711
+ const gitignorePath = join6(rootPath, ".gitignore");
1712
+ if (!existsSync5(gitignorePath))
1713
+ return patterns;
1714
+ try {
1715
+ const content = readFileSync5(gitignorePath, "utf-8");
1716
+ for (const line of content.split(`
1717
+ `)) {
1718
+ const trimmed = line.trim();
1719
+ if (!trimmed || trimmed.startsWith("#"))
1720
+ continue;
1721
+ patterns.add(trimmed.replace(/\/$/, ""));
1652
1722
  }
1653
- } else {
1654
- messages.push(`Unsupported platform: ${os}. Run manually: ~/.conare/bin/run.sh`);
1655
- }
1656
- return messages;
1723
+ } catch {}
1724
+ return patterns;
1657
1725
  }
1658
- function uninstallSync() {
1659
- const messages = [];
1660
- const os = platform2();
1661
- if (os === "darwin") {
1726
+ function shouldIgnore(name, ignorePatterns) {
1727
+ if (DEFAULT_IGNORE.has(name))
1728
+ return true;
1729
+ if (IGNORE_FILES.has(name))
1730
+ return true;
1731
+ if (name.startsWith(".env"))
1732
+ return true;
1733
+ if (ignorePatterns.has(name))
1734
+ return true;
1735
+ return false;
1736
+ }
1737
+ function langFromExt(ext) {
1738
+ const map = {
1739
+ ".ts": "typescript",
1740
+ ".tsx": "tsx",
1741
+ ".js": "javascript",
1742
+ ".jsx": "jsx",
1743
+ ".mjs": "javascript",
1744
+ ".cjs": "javascript",
1745
+ ".vue": "vue",
1746
+ ".svelte": "svelte",
1747
+ ".astro": "astro",
1748
+ ".py": "python",
1749
+ ".rb": "ruby",
1750
+ ".go": "go",
1751
+ ".rs": "rust",
1752
+ ".java": "java",
1753
+ ".kt": "kotlin",
1754
+ ".swift": "swift",
1755
+ ".c": "c",
1756
+ ".cpp": "cpp",
1757
+ ".h": "c",
1758
+ ".css": "css",
1759
+ ".scss": "scss",
1760
+ ".less": "less",
1761
+ ".html": "html",
1762
+ ".json": "json",
1763
+ ".yaml": "yaml",
1764
+ ".yml": "yaml",
1765
+ ".toml": "toml",
1766
+ ".md": "markdown",
1767
+ ".mdx": "mdx",
1768
+ ".sql": "sql",
1769
+ ".graphql": "graphql",
1770
+ ".prisma": "prisma",
1771
+ ".sh": "bash",
1772
+ ".bash": "bash",
1773
+ ".zsh": "zsh",
1774
+ ".lua": "lua",
1775
+ ".zig": "zig",
1776
+ ".ex": "elixir",
1777
+ ".exs": "elixir"
1778
+ };
1779
+ return map[ext] || ext.slice(1);
1780
+ }
1781
+ function formatFile(relPath, content, ext) {
1782
+ const lang = langFromExt(ext);
1783
+ return `# File: ${relPath}
1784
+
1785
+ \`\`\`${lang}
1786
+ ${content}
1787
+ \`\`\``;
1788
+ }
1789
+ function indexCodebase(rootPath) {
1790
+ const absRoot = resolve(rootPath);
1791
+ const repoHash = createHash2("sha256").update(absRoot).digest("hex").slice(0, 12);
1792
+ const gitignorePatterns = parseGitignore(absRoot);
1793
+ const memories = [];
1794
+ let fileCount = 0;
1795
+ let skipped = 0;
1796
+ function walk(dir) {
1797
+ let entries;
1662
1798
  try {
1663
- execSync(`launchctl bootout gui/${uid()} "${PLIST_PATH}" 2>/dev/null`, { stdio: "ignore" });
1664
- } catch {}
1665
- if (existsSync7(PLIST_PATH)) {
1666
- unlinkSync(PLIST_PATH);
1667
- messages.push("Removed launchd agent");
1799
+ entries = readdirSync4(dir, { withFileTypes: true });
1800
+ } catch {
1801
+ return;
1668
1802
  }
1669
- } else if (os === "linux") {
1670
- if (hasSystemd()) {
1671
- try {
1672
- execSync("systemctl --user disable --now conare-sync.timer 2>/dev/null", { stdio: "ignore" });
1673
- } catch {}
1674
- if (existsSync7(SYSTEMD_SERVICE))
1675
- unlinkSync(SYSTEMD_SERVICE);
1676
- if (existsSync7(SYSTEMD_TIMER))
1677
- unlinkSync(SYSTEMD_TIMER);
1803
+ for (const entry of entries) {
1804
+ if (shouldIgnore(entry.name, gitignorePatterns))
1805
+ continue;
1806
+ const fullPath = join6(dir, entry.name);
1807
+ if (entry.isDirectory()) {
1808
+ walk(fullPath);
1809
+ continue;
1810
+ }
1811
+ if (!entry.isFile())
1812
+ continue;
1813
+ const ext = extname(entry.name).toLowerCase();
1814
+ if (!CODE_EXTENSIONS.has(ext) && !SPECIAL_FILES.has(entry.name))
1815
+ continue;
1816
+ let stat;
1678
1817
  try {
1679
- execSync("systemctl --user daemon-reload", { stdio: "ignore" });
1680
- } catch {}
1681
- messages.push("Removed systemd timer");
1682
- } else {
1818
+ stat = statSync2(fullPath);
1819
+ } catch {
1820
+ continue;
1821
+ }
1822
+ if (stat.size > MAX_FILE_SIZE || stat.size === 0) {
1823
+ skipped++;
1824
+ continue;
1825
+ }
1826
+ let raw;
1683
1827
  try {
1684
- const existing = execSync("crontab -l 2>/dev/null", { encoding: "utf-8" });
1685
- const filtered = existing.split(`
1686
- `).filter((l) => !l.includes("conare")).join(`
1687
- `);
1688
- execSync("crontab -", { input: filtered.trim() + `
1689
- `, stdio: ["pipe", "ignore", "ignore"] });
1690
- messages.push("Removed cron job");
1691
- } catch {}
1828
+ raw = readFileSync5(fullPath, "utf-8");
1829
+ } catch {
1830
+ skipped++;
1831
+ continue;
1832
+ }
1833
+ if (raw.includes("\x00")) {
1834
+ skipped++;
1835
+ continue;
1836
+ }
1837
+ const relPath = relative(absRoot, fullPath);
1838
+ const contentHash = createContentHash(raw);
1839
+ const dedupKey = `codebase:${repoHash}:${relPath}`;
1840
+ const fingerprint = `${dedupKey}:${contentHash}`;
1841
+ if (isIngested("codebase", fingerprint)) {
1842
+ skipped++;
1843
+ continue;
1844
+ }
1845
+ const content = formatFile(relPath, raw, ext);
1846
+ memories.push({
1847
+ content,
1848
+ containerTag: "codebase",
1849
+ metadata: {
1850
+ dedupKey,
1851
+ contentHash,
1852
+ source: "codebase-index",
1853
+ repoHash,
1854
+ filePath: relPath,
1855
+ fileHash: `${relPath}:${contentHash}`,
1856
+ language: langFromExt(ext)
1857
+ }
1858
+ });
1859
+ fileCount++;
1692
1860
  }
1693
1861
  }
1694
- const filesToRemove = [
1695
- join9(CONARE_DIR, "config.json"),
1696
- join9(CONARE_DIR, "sync.lock")
1697
- ];
1698
- for (const f of filesToRemove) {
1699
- if (existsSync7(f))
1700
- unlinkSync(f);
1701
- }
1702
- if (existsSync7(BIN_DIR)) {
1703
- rmSync(BIN_DIR, { recursive: true, force: true });
1704
- messages.push("Removed ~/.conare/bin/");
1705
- }
1706
- if (messages.length === 0) {
1707
- messages.push("Nothing to uninstall (no sync timer found)");
1708
- }
1709
- return messages;
1862
+ walk(absRoot);
1863
+ return { memories, fileCount, skipped };
1710
1864
  }
1711
1865
 
1712
- // node_modules/@clack/prompts/dist/index.mjs
1713
- import { stripVTControlCharacters as S2 } from "node:util";
1714
-
1715
- // node_modules/@clack/core/dist/index.mjs
1716
- var import_sisteransi = __toESM(require_src(), 1);
1717
- var import_picocolors = __toESM(require_picocolors(), 1);
1718
- import { stdin as j, stdout as M } from "node:process";
1719
- import * as g from "node:readline";
1720
- import O from "node:readline";
1721
- import { Writable as X } from "node:stream";
1722
- function DD({ onlyFirst: e = false } = {}) {
1723
- const t = ["[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?(?:\\u0007|\\u001B\\u005C|\\u009C))", "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))"].join("|");
1724
- return new RegExp(t, e ? undefined : "g");
1725
- }
1726
- var uD = DD();
1727
- function P(e) {
1728
- if (typeof e != "string")
1729
- throw new TypeError(`Expected a \`string\`, got \`${typeof e}\``);
1730
- return e.replace(uD, "");
1731
- }
1732
- function L(e) {
1733
- return e && e.__esModule && Object.prototype.hasOwnProperty.call(e, "default") ? e.default : e;
1734
- }
1735
- var W = { exports: {} };
1736
- (function(e) {
1737
- var u = {};
1738
- e.exports = u, u.eastAsianWidth = function(F) {
1739
- var s = F.charCodeAt(0), i = F.length == 2 ? F.charCodeAt(1) : 0, D = s;
1740
- return 55296 <= s && s <= 56319 && 56320 <= i && i <= 57343 && (s &= 1023, i &= 1023, D = s << 10 | i, D += 65536), D == 12288 || 65281 <= D && D <= 65376 || 65504 <= D && D <= 65510 ? "F" : D == 8361 || 65377 <= D && D <= 65470 || 65474 <= D && D <= 65479 || 65482 <= D && D <= 65487 || 65490 <= D && D <= 65495 || 65498 <= D && D <= 65500 || 65512 <= D && D <= 65518 ? "H" : 4352 <= D && D <= 4447 || 4515 <= D && D <= 4519 || 4602 <= D && D <= 4607 || 9001 <= D && D <= 9002 || 11904 <= D && D <= 11929 || 11931 <= D && D <= 12019 || 12032 <= D && D <= 12245 || 12272 <= D && D <= 12283 || 12289 <= D && D <= 12350 || 12353 <= D && D <= 12438 || 12441 <= D && D <= 12543 || 12549 <= D && D <= 12589 || 12593 <= D && D <= 12686 || 12688 <= D && D <= 12730 || 12736 <= D && D <= 12771 || 12784 <= D && D <= 12830 || 12832 <= D && D <= 12871 || 12880 <= D && D <= 13054 || 13056 <= D && D <= 19903 || 19968 <= D && D <= 42124 || 42128 <= D && D <= 42182 || 43360 <= D && D <= 43388 || 44032 <= D && D <= 55203 || 55216 <= D && D <= 55238 || 55243 <= D && D <= 55291 || 63744 <= D && D <= 64255 || 65040 <= D && D <= 65049 || 65072 <= D && D <= 65106 || 65108 <= D && D <= 65126 || 65128 <= D && D <= 65131 || 110592 <= D && D <= 110593 || 127488 <= D && D <= 127490 || 127504 <= D && D <= 127546 || 127552 <= D && D <= 127560 || 127568 <= D && D <= 127569 || 131072 <= D && D <= 194367 || 177984 <= D && D <= 196605 || 196608 <= D && D <= 262141 ? "W" : 32 <= D && D <= 126 || 162 <= D && D <= 163 || 165 <= D && D <= 166 || D == 172 || D == 175 || 10214 <= D && D <= 10221 || 10629 <= D && D <= 10630 ? "Na" : D == 161 || D == 164 || 167 <= D && D <= 168 || D == 170 || 173 <= D && D <= 174 || 176 <= D && D <= 180 || 182 <= D && D <= 186 || 188 <= D && D <= 191 || D == 198 || D == 208 || 215 <= D && D <= 216 || 222 <= D && D <= 225 || D == 230 || 232 <= D && D <= 234 || 236 <= D && D <= 237 || D == 240 || 242 <= D && D <= 243 || 247 <= D && D <= 250 || D == 252 || D == 254 || D == 257 || D == 273 || D == 275 || D == 283 || 294 <= D && D <= 295 || D == 299 || 305 <= D && D <= 307 || D == 312 || 319 <= D && D <= 322 || D == 324 || 328 <= D && D <= 331 || D == 333 || 338 <= D && D <= 339 || 358 <= D && D <= 359 || D == 363 || D == 462 || D == 464 || D == 466 || D == 468 || D == 470 || D == 472 || D == 474 || D == 476 || D == 593 || D == 609 || D == 708 || D == 711 || 713 <= D && D <= 715 || D == 717 || D == 720 || 728 <= D && D <= 731 || D == 733 || D == 735 || 768 <= D && D <= 879 || 913 <= D && D <= 929 || 931 <= D && D <= 937 || 945 <= D && D <= 961 || 963 <= D && D <= 969 || D == 1025 || 1040 <= D && D <= 1103 || D == 1105 || D == 8208 || 8211 <= D && D <= 8214 || 8216 <= D && D <= 8217 || 8220 <= D && D <= 8221 || 8224 <= D && D <= 8226 || 8228 <= D && D <= 8231 || D == 8240 || 8242 <= D && D <= 8243 || D == 8245 || D == 8251 || D == 8254 || D == 8308 || D == 8319 || 8321 <= D && D <= 8324 || D == 8364 || D == 8451 || D == 8453 || D == 8457 || D == 8467 || D == 8470 || 8481 <= D && D <= 8482 || D == 8486 || D == 8491 || 8531 <= D && D <= 8532 || 8539 <= D && D <= 8542 || 8544 <= D && D <= 8555 || 8560 <= D && D <= 8569 || D == 8585 || 8592 <= D && D <= 8601 || 8632 <= D && D <= 8633 || D == 8658 || D == 8660 || D == 8679 || D == 8704 || 8706 <= D && D <= 8707 || 8711 <= D && D <= 8712 || D == 8715 || D == 8719 || D == 8721 || D == 8725 || D == 8730 || 8733 <= D && D <= 8736 || D == 8739 || D == 8741 || 8743 <= D && D <= 8748 || D == 8750 || 8756 <= D && D <= 8759 || 8764 <= D && D <= 8765 || D == 8776 || D == 8780 || D == 8786 || 8800 <= D && D <= 8801 || 8804 <= D && D <= 8807 || 8810 <= D && D <= 8811 || 8814 <= D && D <= 8815 || 8834 <= D && D <= 8835 || 8838 <= D && D <= 8839 || D == 8853 || D == 8857 || D == 8869 || D == 8895 || D == 8978 || 9312 <= D && D <= 9449 || 9451 <= D && D <= 9547 || 9552 <= D && D <= 9587 || 9600 <= D && D <= 9615 || 9618 <= D && D <= 9621 || 9632 <= D && D <= 9633 || 9635 <= D && D <= 9641 || 9650 <= D && D <= 9651 || 9654 <= D && D <= 9655 || 9660 <= D && D <= 9661 || 9664 <= D && D <= 9665 || 9670 <= D && D <= 9672 || D == 9675 || 9678 <= D && D <= 9681 || 9698 <= D && D <= 9701 || D == 9711 || 9733 <= D && D <= 9734 || D == 9737 || 9742 <= D && D <= 9743 || 9748 <= D && D <= 9749 || D == 9756 || D == 9758 || D == 9792 || D == 9794 || 9824 <= D && D <= 9825 || 9827 <= D && D <= 9829 || 9831 <= D && D <= 9834 || 9836 <= D && D <= 9837 || D == 9839 || 9886 <= D && D <= 9887 || 9918 <= D && D <= 9919 || 9924 <= D && D <= 9933 || 9935 <= D && D <= 9953 || D == 9955 || 9960 <= D && D <= 9983 || D == 10045 || D == 10071 || 10102 <= D && D <= 10111 || 11093 <= D && D <= 11097 || 12872 <= D && D <= 12879 || 57344 <= D && D <= 63743 || 65024 <= D && D <= 65039 || D == 65533 || 127232 <= D && D <= 127242 || 127248 <= D && D <= 127277 || 127280 <= D && D <= 127337 || 127344 <= D && D <= 127386 || 917760 <= D && D <= 917999 || 983040 <= D && D <= 1048573 || 1048576 <= D && D <= 1114109 ? "A" : "N";
1741
- }, u.characterLength = function(F) {
1742
- var s = this.eastAsianWidth(F);
1743
- return s == "F" || s == "W" || s == "A" ? 2 : 1;
1744
- };
1745
- function t(F) {
1746
- return F.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[^\uD800-\uDFFF]/g) || [];
1747
- }
1748
- u.length = function(F) {
1749
- for (var s = t(F), i = 0, D = 0;D < s.length; D++)
1750
- i = i + this.characterLength(s[D]);
1751
- return i;
1752
- }, u.slice = function(F, s, i) {
1753
- textLen = u.length(F), s = s || 0, i = i || 1, s < 0 && (s = textLen + s), i < 0 && (i = textLen + i);
1754
- for (var D = "", C = 0, n = t(F), E = 0;E < n.length; E++) {
1755
- var a = n[E], o = u.length(a);
1756
- if (C >= s - (o == 2 ? 1 : 0))
1757
- if (C + o <= i)
1758
- D += a;
1759
- else
1760
- break;
1761
- C += o;
1762
- }
1763
- return D;
1764
- };
1765
- })(W);
1766
- var tD = W.exports;
1767
- var eD = L(tD);
1768
- var FD = function() {
1769
- return /\uD83C\uDFF4\uDB40\uDC67\uDB40\uDC62(?:\uDB40\uDC77\uDB40\uDC6C\uDB40\uDC73|\uDB40\uDC73\uDB40\uDC63\uDB40\uDC74|\uDB40\uDC65\uDB40\uDC6E\uDB40\uDC67)\uDB40\uDC7F|(?:\uD83E\uDDD1\uD83C\uDFFF\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB-\uDFFE])|(?:\uD83E\uDDD1\uD83C\uDFFE\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFE\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB-\uDFFD\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFD\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFC\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB\uDFFD-\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFB\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFB\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFC-\uDFFF])|\uD83D\uDC68(?:\uD83C\uDFFB(?:\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF]))|\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFC-\uDFFF])|[\u2695\u2696\u2708]\uFE0F|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))?|(?:\uD83C[\uDFFC-\uDFFF])\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF]))|\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83D\uDC68|(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFE])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFD\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFD-\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])\uFE0F|\u200D(?:(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D[\uDC66\uDC67])|\uD83D[\uDC66\uDC67])|\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC)?|(?:\uD83D\uDC69(?:\uD83C\uDFFB\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69])|(?:\uD83C[\uDFFC-\uDFFF])\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69]))|\uD83E\uDDD1(?:\uD83C[\uDFFB-\uDFFF])\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1)(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|\uD83D\uDC69(?:\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFB\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))|\uD83E\uDDD1(?:\u200D(?:\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFB\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))|\uD83D\uDC69\u200D\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D[\uDC66\uDC67])|\uD83D\uDC69\u200D\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|(?:\uD83D\uDC41\uFE0F\u200D\uD83D\uDDE8|\uD83E\uDDD1(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])|\uD83D\uDC69(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])|\uD83D\uDE36\u200D\uD83C\uDF2B|\uD83C\uDFF3\uFE0F\u200D\u26A7|\uD83D\uDC3B\u200D\u2744|(?:(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC6F|\uD83E[\uDD3C\uDDDE\uDDDF])\u200D[\u2640\u2642]|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])\u200D[\u2640\u2642]|\uD83C\uDFF4\u200D\u2620|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])\u200D[\u2640\u2642]|[\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u2328\u23CF\u23ED-\u23EF\u23F1\u23F2\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB\u25FC\u2600-\u2604\u260E\u2611\u2618\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u2692\u2694-\u2697\u2699\u269B\u269C\u26A0\u26A7\u26B0\u26B1\u26C8\u26CF\u26D1\u26D3\u26E9\u26F0\u26F1\u26F4\u26F7\u26F8\u2702\u2708\u2709\u270F\u2712\u2714\u2716\u271D\u2721\u2733\u2734\u2744\u2747\u2763\u27A1\u2934\u2935\u2B05-\u2B07\u3030\u303D\u3297\u3299]|\uD83C[\uDD70\uDD71\uDD7E\uDD7F\uDE02\uDE37\uDF21\uDF24-\uDF2C\uDF36\uDF7D\uDF96\uDF97\uDF99-\uDF9B\uDF9E\uDF9F\uDFCD\uDFCE\uDFD4-\uDFDF\uDFF5\uDFF7]|\uD83D[\uDC3F\uDCFD\uDD49\uDD4A\uDD6F\uDD70\uDD73\uDD76-\uDD79\uDD87\uDD8A-\uDD8D\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA\uDECB\uDECD-\uDECF\uDEE0-\uDEE5\uDEE9\uDEF0\uDEF3])\uFE0F|\uD83C\uDFF3\uFE0F\u200D\uD83C\uDF08|\uD83D\uDC69\u200D\uD83D\uDC67|\uD83D\uDC69\u200D\uD83D\uDC66|\uD83D\uDE35\u200D\uD83D\uDCAB|\uD83D\uDE2E\u200D\uD83D\uDCA8|\uD83D\uDC15\u200D\uD83E\uDDBA|\uD83E\uDDD1(?:\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC|\uD83C\uDFFB)?|\uD83D\uDC69(?:\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC|\uD83C\uDFFB)?|\uD83C\uDDFD\uD83C\uDDF0|\uD83C\uDDF6\uD83C\uDDE6|\uD83C\uDDF4\uD83C\uDDF2|\uD83D\uDC08\u200D\u2B1B|\u2764\uFE0F\u200D(?:\uD83D\uDD25|\uD83E\uDE79)|\uD83D\uDC41\uFE0F|\uD83C\uDFF3\uFE0F|\uD83C\uDDFF(?:\uD83C[\uDDE6\uDDF2\uDDFC])|\uD83C\uDDFE(?:\uD83C[\uDDEA\uDDF9])|\uD83C\uDDFC(?:\uD83C[\uDDEB\uDDF8])|\uD83C\uDDFB(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA])|\uD83C\uDDFA(?:\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF])|\uD83C\uDDF9(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF])|\uD83C\uDDF8(?:\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF])|\uD83C\uDDF7(?:\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC])|\uD83C\uDDF5(?:\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE])|\uD83C\uDDF3(?:\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF])|\uD83C\uDDF2(?:\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF])|\uD83C\uDDF1(?:\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE])|\uD83C\uDDF0(?:\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF])|\uD83C\uDDEF(?:\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5])|\uD83C\uDDEE(?:\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9])|\uD83C\uDDED(?:\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA])|\uD83C\uDDEC(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE])|\uD83C\uDDEB(?:\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7])|\uD83C\uDDEA(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA])|\uD83C\uDDE9(?:\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF])|\uD83C\uDDE8(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF])|\uD83C\uDDE7(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF])|\uD83C\uDDE6(?:\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF])|[#\*0-9]\uFE0F\u20E3|\u2764\uFE0F|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])|\uD83C\uDFF4|(?:[\u270A\u270B]|\uD83C[\uDF85\uDFC2\uDFC7]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE4C\uDE4F\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1C\uDD1E\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5])(?:\uD83C[\uDFFB-\uDFFF])|(?:[\u261D\u270C\u270D]|\uD83D[\uDD74\uDD90])(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])|[\u270A\u270B]|\uD83C[\uDF85\uDFC2\uDFC7]|\uD83D[\uDC08\uDC15\uDC3B\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE2E\uDE35\uDE36\uDE4C\uDE4F\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1C\uDD1E\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5]|\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD]|\uD83D\uDC6F|\uD83E[\uDD3C\uDDDE\uDDDF]|[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF84\uDF86-\uDF93\uDFA0-\uDFC1\uDFC5\uDFC6\uDFC8\uDFC9\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC07\uDC09-\uDC14\uDC16-\uDC3A\uDC3C-\uDC3E\uDC40\uDC44\uDC45\uDC51-\uDC65\uDC6A\uDC79-\uDC7B\uDC7D-\uDC80\uDC84\uDC88-\uDC8E\uDC90\uDC92-\uDCA9\uDCAB-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDDA4\uDDFB-\uDE2D\uDE2F-\uDE34\uDE37-\uDE44\uDE48-\uDE4A\uDE80-\uDEA2\uDEA4-\uDEB3\uDEB7-\uDEBF\uDEC1-\uDEC5\uDED0-\uDED2\uDED5-\uDED7\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0D\uDD0E\uDD10-\uDD17\uDD1D\uDD20-\uDD25\uDD27-\uDD2F\uDD3A\uDD3F-\uDD45\uDD47-\uDD76\uDD78\uDD7A-\uDDB4\uDDB7\uDDBA\uDDBC-\uDDCB\uDDD0\uDDE0-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6]|(?:[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u270A\u270B\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF93\uDFA0-\uDFCA\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF4\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC3E\uDC40\uDC42-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDD7A\uDD95\uDD96\uDDA4\uDDFB-\uDE4F\uDE80-\uDEC5\uDECC\uDED0-\uDED2\uDED5-\uDED7\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0C-\uDD3A\uDD3C-\uDD45\uDD47-\uDD78\uDD7A-\uDDCB\uDDCD-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6])|(?:[#\*0-9\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u267F\u2692-\u2697\u2699\u269B\u269C\u26A0\u26A1\u26A7\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753-\u2755\u2757\u2763\u2764\u2795-\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]|\uD83C[\uDC04\uDCCF\uDD70\uDD71\uDD7E\uDD7F\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE02\uDE1A\uDE2F\uDE32-\uDE3A\uDE50\uDE51\uDF00-\uDF21\uDF24-\uDF93\uDF96\uDF97\uDF99-\uDF9B\uDF9E-\uDFF0\uDFF3-\uDFF5\uDFF7-\uDFFF]|\uD83D[\uDC00-\uDCFD\uDCFF-\uDD3D\uDD49-\uDD4E\uDD50-\uDD67\uDD6F\uDD70\uDD73-\uDD7A\uDD87\uDD8A-\uDD8D\uDD90\uDD95\uDD96\uDDA4\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA-\uDE4F\uDE80-\uDEC5\uDECB-\uDED2\uDED5-\uDED7\uDEE0-\uDEE5\uDEE9\uDEEB\uDEEC\uDEF0\uDEF3-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0C-\uDD3A\uDD3C-\uDD45\uDD47-\uDD78\uDD7A-\uDDCB\uDDCD-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6])\uFE0F|(?:[\u261D\u26F9\u270A-\u270D]|\uD83C[\uDF85\uDFC2-\uDFC4\uDFC7\uDFCA-\uDFCC]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66-\uDC78\uDC7C\uDC81-\uDC83\uDC85-\uDC87\uDC8F\uDC91\uDCAA\uDD74\uDD75\uDD7A\uDD90\uDD95\uDD96\uDE45-\uDE47\uDE4B-\uDE4F\uDEA3\uDEB4-\uDEB6\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1F\uDD26\uDD30-\uDD39\uDD3C-\uDD3E\uDD77\uDDB5\uDDB6\uDDB8\uDDB9\uDDBB\uDDCD-\uDDCF\uDDD1-\uDDDD])/g;
1770
- };
1771
- var sD = L(FD);
1772
- function p(e, u = {}) {
1773
- if (typeof e != "string" || e.length === 0 || (u = { ambiguousIsNarrow: true, ...u }, e = P(e), e.length === 0))
1774
- return 0;
1775
- e = e.replace(sD(), " ");
1776
- const t = u.ambiguousIsNarrow ? 1 : 2;
1777
- let F = 0;
1778
- for (const s of e) {
1779
- const i = s.codePointAt(0);
1780
- if (i <= 31 || i >= 127 && i <= 159 || i >= 768 && i <= 879)
1781
- continue;
1782
- switch (eD.eastAsianWidth(s)) {
1783
- case "F":
1784
- case "W":
1785
- F += 2;
1786
- break;
1787
- case "A":
1788
- F += t;
1789
- break;
1790
- default:
1791
- F += 1;
1866
+ // src/api.ts
1867
+ var API_URL = "https://mcp.conare.ai";
1868
+ function createUploadBatches(memories, maxItems = 50, maxChars = 1500000) {
1869
+ const batches = [];
1870
+ let current = [];
1871
+ let currentChars = 0;
1872
+ let startIndex = 0;
1873
+ for (let i = 0;i < memories.length; i++) {
1874
+ const item = memories[i];
1875
+ const itemChars = item.content.length;
1876
+ const exceedsBatch = current.length > 0 && (current.length >= maxItems || currentChars + itemChars > maxChars);
1877
+ if (exceedsBatch) {
1878
+ batches.push({ startIndex, items: current });
1879
+ current = [];
1880
+ currentChars = 0;
1881
+ startIndex = i;
1792
1882
  }
1883
+ current.push(item);
1884
+ currentChars += itemChars;
1885
+ }
1886
+ if (current.length > 0) {
1887
+ batches.push({ startIndex, items: current });
1793
1888
  }
1794
- return F;
1889
+ return batches;
1795
1890
  }
1796
- var w = 10;
1797
- var N = (e = 0) => (u) => `\x1B[${u + e}m`;
1798
- var I = (e = 0) => (u) => `\x1B[${38 + e};5;${u}m`;
1799
- var R = (e = 0) => (u, t, F) => `\x1B[${38 + e};2;${u};${t};${F}m`;
1800
- var r = { modifier: { reset: [0, 0], bold: [1, 22], dim: [2, 22], italic: [3, 23], underline: [4, 24], overline: [53, 55], inverse: [7, 27], hidden: [8, 28], strikethrough: [9, 29] }, color: { black: [30, 39], red: [31, 39], green: [32, 39], yellow: [33, 39], blue: [34, 39], magenta: [35, 39], cyan: [36, 39], white: [37, 39], blackBright: [90, 39], gray: [90, 39], grey: [90, 39], redBright: [91, 39], greenBright: [92, 39], yellowBright: [93, 39], blueBright: [94, 39], magentaBright: [95, 39], cyanBright: [96, 39], whiteBright: [97, 39] }, bgColor: { bgBlack: [40, 49], bgRed: [41, 49], bgGreen: [42, 49], bgYellow: [43, 49], bgBlue: [44, 49], bgMagenta: [45, 49], bgCyan: [46, 49], bgWhite: [47, 49], bgBlackBright: [100, 49], bgGray: [100, 49], bgGrey: [100, 49], bgRedBright: [101, 49], bgGreenBright: [102, 49], bgYellowBright: [103, 49], bgBlueBright: [104, 49], bgMagentaBright: [105, 49], bgCyanBright: [106, 49], bgWhiteBright: [107, 49] } };
1801
- Object.keys(r.modifier);
1802
- var iD = Object.keys(r.color);
1803
- var CD = Object.keys(r.bgColor);
1804
- [...iD, ...CD];
1805
- function rD() {
1806
- const e = new Map;
1807
- for (const [u, t] of Object.entries(r)) {
1808
- for (const [F, s] of Object.entries(t))
1809
- r[F] = { open: `\x1B[${s[0]}m`, close: `\x1B[${s[1]}m` }, t[F] = r[F], e.set(s[0], s[1]);
1810
- Object.defineProperty(r, u, { value: t, enumerable: false });
1891
+ async function validateKey(apiKey) {
1892
+ try {
1893
+ const res = await fetch(`${API_URL}/api/auth/me`, {
1894
+ headers: { Authorization: `Bearer ${apiKey}` }
1895
+ });
1896
+ if (!res.ok)
1897
+ return { valid: false };
1898
+ const data = await res.json();
1899
+ return { valid: true, email: data.user.email, name: data.user.name };
1900
+ } catch {
1901
+ return { valid: false };
1811
1902
  }
1812
- return Object.defineProperty(r, "codes", { value: e, enumerable: false }), r.color.close = "\x1B[39m", r.bgColor.close = "\x1B[49m", r.color.ansi = N(), r.color.ansi256 = I(), r.color.ansi16m = R(), r.bgColor.ansi = N(w), r.bgColor.ansi256 = I(w), r.bgColor.ansi16m = R(w), Object.defineProperties(r, { rgbToAnsi256: { value: (u, t, F) => u === t && t === F ? u < 8 ? 16 : u > 248 ? 231 : Math.round((u - 8) / 247 * 24) + 232 : 16 + 36 * Math.round(u / 255 * 5) + 6 * Math.round(t / 255 * 5) + Math.round(F / 255 * 5), enumerable: false }, hexToRgb: { value: (u) => {
1813
- const t = /[a-f\d]{6}|[a-f\d]{3}/i.exec(u.toString(16));
1814
- if (!t)
1815
- return [0, 0, 0];
1816
- let [F] = t;
1817
- F.length === 3 && (F = [...F].map((i) => i + i).join(""));
1818
- const s = Number.parseInt(F, 16);
1819
- return [s >> 16 & 255, s >> 8 & 255, s & 255];
1820
- }, enumerable: false }, hexToAnsi256: { value: (u) => r.rgbToAnsi256(...r.hexToRgb(u)), enumerable: false }, ansi256ToAnsi: { value: (u) => {
1821
- if (u < 8)
1822
- return 30 + u;
1823
- if (u < 16)
1824
- return 90 + (u - 8);
1825
- let t, F, s;
1826
- if (u >= 232)
1827
- t = ((u - 232) * 10 + 8) / 255, F = t, s = t;
1828
- else {
1829
- u -= 16;
1830
- const C = u % 36;
1831
- t = Math.floor(u / 36) / 5, F = Math.floor(C / 6) / 5, s = C % 6 / 5;
1832
- }
1833
- const i = Math.max(t, F, s) * 2;
1834
- if (i === 0)
1835
- return 30;
1836
- let D = 30 + (Math.round(s) << 2 | Math.round(F) << 1 | Math.round(t));
1837
- return i === 2 && (D += 60), D;
1838
- }, enumerable: false }, rgbToAnsi: { value: (u, t, F) => r.ansi256ToAnsi(r.rgbToAnsi256(u, t, F)), enumerable: false }, hexToAnsi: { value: (u) => r.ansi256ToAnsi(r.hexToAnsi256(u)), enumerable: false } }), r;
1839
1903
  }
1840
- var ED = rD();
1841
- var d = new Set(["\x1B", "›"]);
1842
- var oD = 39;
1843
- var y = "\x07";
1844
- var V = "[";
1845
- var nD = "]";
1846
- var G = "m";
1847
- var _ = `${nD}8;;`;
1848
- var z = (e) => `${d.values().next().value}${V}${e}${G}`;
1849
- var K = (e) => `${d.values().next().value}${_}${e}${y}`;
1850
- var aD = (e) => e.split(" ").map((u) => p(u));
1851
- var k = (e, u, t) => {
1852
- const F = [...u];
1853
- let s = false, i = false, D = p(P(e[e.length - 1]));
1854
- for (const [C, n] of F.entries()) {
1855
- const E = p(n);
1856
- if (D + E <= t ? e[e.length - 1] += n : (e.push(n), D = 0), d.has(n) && (s = true, i = F.slice(C + 1).join("").startsWith(_)), s) {
1857
- i ? n === y && (s = false, i = false) : n === G && (s = false);
1858
- continue;
1859
- }
1860
- D += E, D === t && C < F.length - 1 && (e.push(""), D = 0);
1904
+ async function getRemoteMemoryCount(apiKey) {
1905
+ try {
1906
+ const res = await fetch(`${API_URL}/api/containers`, {
1907
+ headers: { Authorization: `Bearer ${apiKey}` }
1908
+ });
1909
+ if (!res.ok)
1910
+ return null;
1911
+ const data = await res.json();
1912
+ if (!Array.isArray(data.containers))
1913
+ return 0;
1914
+ return data.containers.reduce((sum, container) => sum + (container.count || 0), 0);
1915
+ } catch {
1916
+ return null;
1861
1917
  }
1862
- !D && e[e.length - 1].length > 0 && e.length > 1 && (e[e.length - 2] += e.pop());
1863
- };
1864
- var hD = (e) => {
1865
- const u = e.split(" ");
1866
- let t = u.length;
1867
- for (;t > 0 && !(p(u[t - 1]) > 0); )
1868
- t--;
1869
- return t === u.length ? e : u.slice(0, t).join(" ") + u.slice(t).join("");
1870
- };
1871
- var lD = (e, u, t = {}) => {
1872
- if (t.trim !== false && e.trim() === "")
1873
- return "";
1874
- let F = "", s, i;
1875
- const D = aD(e);
1876
- let C = [""];
1877
- for (const [E, a] of e.split(" ").entries()) {
1878
- t.trim !== false && (C[C.length - 1] = C[C.length - 1].trimStart());
1879
- let o = p(C[C.length - 1]);
1880
- if (E !== 0 && (o >= u && (t.wordWrap === false || t.trim === false) && (C.push(""), o = 0), (o > 0 || t.trim === false) && (C[C.length - 1] += " ", o++)), t.hard && D[E] > u) {
1881
- const c = u - o, f = 1 + Math.floor((D[E] - c - 1) / u);
1882
- Math.floor((D[E] - 1) / u) < f && C.push(""), k(C, a, u);
1883
- continue;
1884
- }
1885
- if (o + D[E] > u && o > 0 && D[E] > 0) {
1886
- if (t.wordWrap === false && o < u) {
1887
- k(C, a, u);
1918
+ }
1919
+ async function uploadItems(apiKey, items, asyncEmbed = false) {
1920
+ let retries = 4;
1921
+ while (retries > 0) {
1922
+ try {
1923
+ const res = await fetch(`${API_URL}/api/memories/bulk`, {
1924
+ method: "POST",
1925
+ headers: {
1926
+ "Content-Type": "application/json",
1927
+ Authorization: `Bearer ${apiKey}`
1928
+ },
1929
+ body: JSON.stringify(asyncEmbed ? { items, async: true } : items)
1930
+ });
1931
+ if (res.status === 429) {
1932
+ retries--;
1933
+ await new Promise((r) => setTimeout(r, 5000));
1888
1934
  continue;
1889
1935
  }
1890
- C.push("");
1891
- }
1892
- if (o + D[E] > u && t.wordWrap === false) {
1893
- k(C, a, u);
1894
- continue;
1936
+ if (!res.ok) {
1937
+ const body = await res.text().catch(() => "");
1938
+ throw new Error(`HTTP ${res.status}: ${body.slice(0, 120)}`);
1939
+ }
1940
+ const data = await res.json();
1941
+ if (!Array.isArray(data.results) || data.results.length !== items.length) {
1942
+ throw new Error("Unexpected bulk upload response");
1943
+ }
1944
+ return data.results;
1945
+ } catch (error) {
1946
+ retries--;
1947
+ if (retries === 0) {
1948
+ return items.map(() => ({
1949
+ success: false,
1950
+ error: error instanceof Error ? error.message : String(error)
1951
+ }));
1952
+ }
1953
+ await new Promise((r) => setTimeout(r, 2000));
1895
1954
  }
1896
- C[C.length - 1] += a;
1897
1955
  }
1898
- t.trim !== false && (C = C.map((E) => hD(E)));
1899
- const n = [...C.join(`
1900
- `)];
1901
- for (const [E, a] of n.entries()) {
1902
- if (F += a, d.has(a)) {
1903
- const { groups: c } = new RegExp(`(?:\\${V}(?<code>\\d+)m|\\${_}(?<uri>.*)${y})`).exec(n.slice(E).join("")) || { groups: {} };
1904
- if (c.code !== undefined) {
1905
- const f = Number.parseFloat(c.code);
1906
- s = f === oD ? undefined : f;
1907
- } else
1908
- c.uri !== undefined && (i = c.uri.length === 0 ? undefined : c.uri);
1956
+ return items.map(() => ({ success: false, error: "Upload failed" }));
1957
+ }
1958
+ async function uploadBulk(apiKey, memories, onProgress) {
1959
+ let success = 0;
1960
+ let failed = 0;
1961
+ const total = memories.length;
1962
+ const results = [];
1963
+ const batches = createUploadBatches(memories);
1964
+ for (const batch of batches) {
1965
+ let batchResults = await uploadItems(apiKey, batch.items, true);
1966
+ if (batch.items.length > 1 && batchResults.some((result) => !result.success)) {
1967
+ const retriedResults = [];
1968
+ for (let i = 0;i < batch.items.length; i++) {
1969
+ const result = batchResults[i];
1970
+ if (result.success) {
1971
+ retriedResults.push(result);
1972
+ continue;
1973
+ }
1974
+ const [singleResult] = await uploadItems(apiKey, [batch.items[i]], true);
1975
+ retriedResults.push(singleResult);
1976
+ }
1977
+ batchResults = retriedResults;
1909
1978
  }
1910
- const o = ED.codes.get(Number(s));
1911
- n[E + 1] === `
1912
- ` ? (i && (F += K("")), s && o && (F += z(o))) : a === `
1913
- ` && (s && o && (F += z(s)), i && (F += K(i)));
1979
+ for (let i = 0;i < batchResults.length; i++) {
1980
+ const result = batchResults[i];
1981
+ results.push({
1982
+ index: batch.startIndex + i,
1983
+ success: result.success,
1984
+ deduped: result.deduped,
1985
+ error: result.error
1986
+ });
1987
+ if (result.success)
1988
+ success++;
1989
+ else
1990
+ failed++;
1991
+ }
1992
+ onProgress?.(success + failed, total, failed);
1914
1993
  }
1915
- return F;
1916
- };
1917
- function Y(e, u, t) {
1918
- return String(e).normalize().replace(/\r\n/g, `
1919
- `).split(`
1920
- `).map((F) => lD(F, u, t)).join(`
1921
- `);
1922
- }
1923
- var xD = ["up", "down", "left", "right", "space", "enter", "cancel"];
1924
- var B = { actions: new Set(xD), aliases: new Map([["k", "up"], ["j", "down"], ["h", "left"], ["l", "right"], ["\x03", "cancel"], ["escape", "cancel"]]) };
1925
- function $(e, u) {
1926
- if (typeof e == "string")
1927
- return B.aliases.get(e) === u;
1928
- for (const t of e)
1929
- if (t !== undefined && $(t, u))
1930
- return true;
1931
- return false;
1932
- }
1933
- function BD(e, u) {
1934
- if (e === u)
1935
- return;
1936
- const t = e.split(`
1937
- `), F = u.split(`
1938
- `), s = [];
1939
- for (let i = 0;i < Math.max(t.length, F.length); i++)
1940
- t[i] !== F[i] && s.push(i);
1941
- return s;
1994
+ return { success, failed, results };
1942
1995
  }
1943
- var AD = globalThis.process.platform.startsWith("win");
1944
- var S = Symbol("clack:cancel");
1945
- function pD(e) {
1946
- return e === S;
1996
+
1997
+ // src/configure.ts
1998
+ import { existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as readFileSync6, writeFileSync as writeFileSync2 } from "node:fs";
1999
+ import { dirname, join as join7 } from "node:path";
2000
+ import { homedir as homedir5 } from "node:os";
2001
+ import { spawnSync as spawnSync2 } from "node:child_process";
2002
+ var CONARE_URL = "https://mcp.conare.ai";
2003
+ var SERVER_NAME = "conare-memory";
2004
+ var MCP_TARGETS = [
2005
+ { id: "claude", label: "Claude Code" },
2006
+ { id: "cursor", label: "Cursor" },
2007
+ { id: "codex", label: "Codex" },
2008
+ { id: "openclaw", label: "OpenClaw" }
2009
+ ];
2010
+ function readJsonFile(path) {
2011
+ try {
2012
+ return JSON.parse(readFileSync6(path, "utf-8"));
2013
+ } catch {
2014
+ return {};
2015
+ }
1947
2016
  }
1948
- function m(e, u) {
1949
- const t = e;
1950
- t.isTTY && t.setRawMode(u);
2017
+ function writeJsonFile(path, data) {
2018
+ mkdirSync2(dirname(path), { recursive: true });
2019
+ writeFileSync2(path, JSON.stringify(data, null, 2) + `
2020
+ `);
1951
2021
  }
1952
- function fD({ input: e = j, output: u = M, overwrite: t = true, hideCursor: F = true } = {}) {
1953
- const s = g.createInterface({ input: e, output: u, prompt: "", tabSize: 1 });
1954
- g.emitKeypressEvents(e, s), e.isTTY && e.setRawMode(true);
1955
- const i = (D, { name: C, sequence: n }) => {
1956
- const E = String(D);
1957
- if ($([E, C, n], "cancel")) {
1958
- F && u.write(import_sisteransi.cursor.show), process.exit(0);
1959
- return;
1960
- }
1961
- if (!t)
1962
- return;
1963
- const a = C === "return" ? 0 : -1, o = C === "return" ? -1 : 0;
1964
- g.moveCursor(u, a, o, () => {
1965
- g.clearLine(u, 1, () => {
1966
- e.once("keypress", i);
1967
- });
1968
- });
1969
- };
1970
- return F && u.write(import_sisteransi.cursor.hide), e.once("keypress", i), () => {
1971
- e.off("keypress", i), F && u.write(import_sisteransi.cursor.show), e.isTTY && !AD && e.setRawMode(false), s.terminal = false, s.close();
2022
+ function getServerConfig(apiKey) {
2023
+ return {
2024
+ type: "http",
2025
+ url: `${CONARE_URL}/mcp`,
2026
+ headers: {
2027
+ Authorization: `Bearer ${apiKey}`
2028
+ }
1972
2029
  };
1973
2030
  }
1974
- var gD = Object.defineProperty;
1975
- var vD = (e, u, t) => (u in e) ? gD(e, u, { enumerable: true, configurable: true, writable: true, value: t }) : e[u] = t;
1976
- var h = (e, u, t) => (vD(e, typeof u != "symbol" ? u + "" : u, t), t);
1977
-
1978
- class x {
1979
- constructor(u, t = true) {
1980
- h(this, "input"), h(this, "output"), h(this, "_abortSignal"), h(this, "rl"), h(this, "opts"), h(this, "_render"), h(this, "_track", false), h(this, "_prevFrame", ""), h(this, "_subscribers", new Map), h(this, "_cursor", 0), h(this, "state", "initial"), h(this, "error", ""), h(this, "value");
1981
- const { input: F = j, output: s = M, render: i, signal: D, ...C } = u;
1982
- this.opts = C, this.onKeypress = this.onKeypress.bind(this), this.close = this.close.bind(this), this.render = this.render.bind(this), this._render = i.bind(this), this._track = t, this._abortSignal = D, this.input = F, this.output = s;
1983
- }
1984
- unsubscribe() {
1985
- this._subscribers.clear();
1986
- }
1987
- setSubscriber(u, t) {
1988
- const F = this._subscribers.get(u) ?? [];
1989
- F.push(t), this._subscribers.set(u, F);
2031
+ function upsertMcpServer(path, apiKey) {
2032
+ const config = readJsonFile(path);
2033
+ if (!config.mcpServers || typeof config.mcpServers !== "object") {
2034
+ config.mcpServers = {};
1990
2035
  }
1991
- on(u, t) {
1992
- this.setSubscriber(u, { cb: t });
2036
+ config.mcpServers[SERVER_NAME] = getServerConfig(apiKey);
2037
+ writeJsonFile(path, config);
2038
+ }
2039
+ function configureClaude(apiKey) {
2040
+ const claudeConfigPath = join7(homedir5(), ".claude.json");
2041
+ const claudeMcpPath = join7(homedir5(), ".claude", "mcp.json");
2042
+ if (spawnSync2("claude", ["mcp", "add-json", SERVER_NAME, "--scope", "user", JSON.stringify(getServerConfig(apiKey))], {
2043
+ stdio: "ignore"
2044
+ }).status === 0) {
2045
+ return "Claude Code configured via `claude mcp add-json`";
1993
2046
  }
1994
- once(u, t) {
1995
- this.setSubscriber(u, { cb: t, once: true });
2047
+ upsertMcpServer(claudeConfigPath, apiKey);
2048
+ if (existsSync6(join7(homedir5(), ".claude"))) {
2049
+ upsertMcpServer(claudeMcpPath, apiKey);
1996
2050
  }
1997
- emit(u, ...t) {
1998
- const F = this._subscribers.get(u) ?? [], s = [];
1999
- for (const i of F)
2000
- i.cb(...t), i.once && s.push(() => F.splice(F.indexOf(i), 1));
2001
- for (const i of s)
2002
- i();
2051
+ return `Claude Code configured at ${claudeConfigPath}`;
2052
+ }
2053
+ function configureJsonClient(path, apiKey, label) {
2054
+ upsertMcpServer(path, apiKey);
2055
+ return `${label} configured at ${path}`;
2056
+ }
2057
+ function configureMcp(apiKey, targets = ["claude", "cursor", "codex"]) {
2058
+ const results = [];
2059
+ if (targets.includes("claude")) {
2060
+ results.push(configureClaude(apiKey));
2003
2061
  }
2004
- prompt() {
2005
- return new Promise((u, t) => {
2006
- if (this._abortSignal) {
2007
- if (this._abortSignal.aborted)
2008
- return this.state = "cancel", this.close(), u(S);
2009
- this._abortSignal.addEventListener("abort", () => {
2010
- this.state = "cancel", this.close();
2011
- }, { once: true });
2012
- }
2013
- const F = new X;
2014
- F._write = (s, i, D) => {
2015
- this._track && (this.value = this.rl?.line.replace(/\t/g, ""), this._cursor = this.rl?.cursor ?? 0, this.emit("value", this.value)), D();
2016
- }, this.input.pipe(F), this.rl = O.createInterface({ input: this.input, output: F, tabSize: 2, prompt: "", escapeCodeTimeout: 50, terminal: true }), O.emitKeypressEvents(this.input, this.rl), this.rl.prompt(), this.opts.initialValue !== undefined && this._track && this.rl.write(this.opts.initialValue), this.input.on("keypress", this.onKeypress), m(this.input, true), this.output.on("resize", this.render), this.render(), this.once("submit", () => {
2017
- this.output.write(import_sisteransi.cursor.show), this.output.off("resize", this.render), m(this.input, false), u(this.value);
2018
- }), this.once("cancel", () => {
2019
- this.output.write(import_sisteransi.cursor.show), this.output.off("resize", this.render), m(this.input, false), u(S);
2020
- });
2021
- });
2062
+ if (targets.includes("cursor")) {
2063
+ results.push(configureJsonClient(join7(homedir5(), ".cursor", "mcp.json"), apiKey, "Cursor"));
2022
2064
  }
2023
- onKeypress(u, t) {
2024
- if (this.state === "error" && (this.state = "active"), t?.name && (!this._track && B.aliases.has(t.name) && this.emit("cursor", B.aliases.get(t.name)), B.actions.has(t.name) && this.emit("cursor", t.name)), u && (u.toLowerCase() === "y" || u.toLowerCase() === "n") && this.emit("confirm", u.toLowerCase() === "y"), u === "\t" && this.opts.placeholder && (this.value || (this.rl?.write(this.opts.placeholder), this.emit("value", this.opts.placeholder))), u && this.emit("key", u.toLowerCase()), t?.name === "return") {
2025
- if (this.opts.validate) {
2026
- const F = this.opts.validate(this.value);
2027
- F && (this.error = F instanceof Error ? F.message : F, this.state = "error", this.rl?.write(this.value));
2028
- }
2029
- this.state !== "error" && (this.state = "submit");
2030
- }
2031
- $([u, t?.name, t?.sequence], "cancel") && (this.state = "cancel"), (this.state === "submit" || this.state === "cancel") && this.emit("finalize"), this.render(), (this.state === "submit" || this.state === "cancel") && this.close();
2065
+ if (targets.includes("codex")) {
2066
+ results.push(configureJsonClient(join7(homedir5(), ".codex", "mcp.json"), apiKey, "Codex"));
2032
2067
  }
2033
- close() {
2034
- this.input.unpipe(), this.input.removeListener("keypress", this.onKeypress), this.output.write(`
2035
- `), m(this.input, false), this.rl?.close(), this.rl = undefined, this.emit(`${this.state}`, this.value), this.unsubscribe();
2068
+ if (targets.includes("openclaw")) {
2069
+ results.push(configureJsonClient(join7(homedir5(), ".openclaw", "mcp.json"), apiKey, "OpenClaw"));
2036
2070
  }
2037
- restoreCursor() {
2038
- const u = Y(this._prevFrame, process.stdout.columns, { hard: true }).split(`
2039
- `).length - 1;
2040
- this.output.write(import_sisteransi.cursor.move(-999, u * -1));
2071
+ return results;
2072
+ }
2073
+
2074
+ // src/config.ts
2075
+ import { existsSync as existsSync7, mkdirSync as mkdirSync3, readFileSync as readFileSync7, writeFileSync as writeFileSync3 } from "node:fs";
2076
+ import { join as join8 } from "node:path";
2077
+ import { homedir as homedir6 } from "node:os";
2078
+ var CONFIG_DIR = join8(homedir6(), ".conare");
2079
+ var CONFIG_PATH = join8(CONFIG_DIR, "config.json");
2080
+ function readConfig() {
2081
+ try {
2082
+ if (!existsSync7(CONFIG_PATH))
2083
+ return {};
2084
+ return JSON.parse(readFileSync7(CONFIG_PATH, "utf-8"));
2085
+ } catch {
2086
+ return {};
2041
2087
  }
2042
- render() {
2043
- const u = Y(this._render(this) ?? "", process.stdout.columns, { hard: true });
2044
- if (u !== this._prevFrame) {
2045
- if (this.state === "initial")
2046
- this.output.write(import_sisteransi.cursor.hide);
2047
- else {
2048
- const t = BD(this._prevFrame, u);
2049
- if (this.restoreCursor(), t && t?.length === 1) {
2050
- const F = t[0];
2051
- this.output.write(import_sisteransi.cursor.move(0, F)), this.output.write(import_sisteransi.erase.lines(1));
2052
- const s = u.split(`
2088
+ }
2089
+ function saveApiKey(apiKey) {
2090
+ mkdirSync3(CONFIG_DIR, { recursive: true });
2091
+ writeFileSync3(CONFIG_PATH, JSON.stringify({ apiKey }, null, 2) + `
2053
2092
  `);
2054
- this.output.write(s[F]), this._prevFrame = u, this.output.write(import_sisteransi.cursor.move(0, s.length - F - 1));
2055
- return;
2056
- }
2057
- if (t && t?.length > 1) {
2058
- const F = t[0];
2059
- this.output.write(import_sisteransi.cursor.move(0, F)), this.output.write(import_sisteransi.erase.down());
2060
- const s = u.split(`
2061
- `).slice(F);
2062
- this.output.write(s.join(`
2063
- `)), this._prevFrame = u;
2064
- return;
2065
- }
2066
- this.output.write(import_sisteransi.erase.down());
2067
- }
2068
- this.output.write(u), this.state === "initial" && (this.state = "active"), this._prevFrame = u;
2069
- }
2070
- }
2071
2093
  }
2094
+ function getSavedApiKey() {
2095
+ return readConfig().apiKey;
2096
+ }
2097
+
2098
+ // src/sync.ts
2099
+ import { existsSync as existsSync8, mkdirSync as mkdirSync4, writeFileSync as writeFileSync4, unlinkSync, readFileSync as readFileSync8, chmodSync, cpSync, rmSync, symlinkSync, readlinkSync, appendFileSync } from "node:fs";
2100
+ import { join as join9, dirname as dirname2 } from "node:path";
2101
+ import { homedir as homedir7, platform as platform2 } from "node:os";
2102
+ import { execSync } from "node:child_process";
2103
+ var CONARE_DIR = join9(homedir7(), ".conare");
2104
+ var BIN_DIR = join9(CONARE_DIR, "bin");
2105
+ var CONFIG_PATH2 = join9(CONARE_DIR, "config.json");
2106
+ var PLIST_LABEL = "ai.conare.ingest";
2107
+ var PLIST_PATH = join9(homedir7(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
2108
+ var SYSTEMD_DIR = join9(homedir7(), ".config", "systemd", "user");
2109
+ var SYSTEMD_SERVICE = join9(SYSTEMD_DIR, "conare-sync.service");
2110
+ var SYSTEMD_TIMER = join9(SYSTEMD_DIR, "conare-sync.timer");
2111
+ var RUN_SH = `#!/bin/bash
2112
+ # Conare Memory — background sync wrapper
2113
+ # Resolves node at runtime to survive nvm/fnm upgrades
2114
+
2115
+ CONARE_DIR="$HOME/.conare"
2116
+ LOCKFILE="$CONARE_DIR/sync.lock"
2117
+ LOG="$CONARE_DIR/ingest.log"
2118
+
2119
+ # Log rotation: truncate if > 1MB
2120
+ if [ -f "$LOG" ] && [ "$(wc -c < "$LOG" 2>/dev/null)" -gt 1048576 ]; then
2121
+ tail -100 "$LOG" > "$LOG.tmp" && mv "$LOG.tmp" "$LOG"
2122
+ fi
2123
+
2124
+ # File lock: prevent concurrent runs
2125
+ # macOS doesn't have flock — use mkdir as atomic lock
2126
+ if ! mkdir "$LOCKFILE.d" 2>/dev/null; then
2127
+ # Check if stale (older than 30 min)
2128
+ if [ "$(uname)" = "Darwin" ]; then
2129
+ LOCK_AGE=$(( $(date +%s) - $(stat -f %m "$LOCKFILE.d" 2>/dev/null || echo 0) ))
2130
+ else
2131
+ LOCK_AGE=$(( $(date +%s) - $(stat -c %Y "$LOCKFILE.d" 2>/dev/null || echo 0) ))
2132
+ fi
2133
+ if [ "$LOCK_AGE" -gt 1800 ]; then
2134
+ rm -rf "$LOCKFILE.d"
2135
+ mkdir "$LOCKFILE.d" 2>/dev/null || true
2136
+ else
2137
+ echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) SKIP: another instance running" >> "$LOG"
2138
+ exit 0
2139
+ fi
2140
+ fi
2141
+ trap 'rm -rf "$LOCKFILE.d"' EXIT
2142
+
2143
+ # Resolve node binary
2144
+ resolve_node() {
2145
+ command -v node >/dev/null 2>&1 && { command -v node; return; }
2146
+ if [ -s "$HOME/.nvm/nvm.sh" ]; then
2147
+ . "$HOME/.nvm/nvm.sh" >/dev/null 2>&1
2148
+ command -v node >/dev/null 2>&1 && { command -v node; return; }
2149
+ fi
2150
+ if command -v fnm >/dev/null 2>&1; then
2151
+ eval "$(fnm env)" >/dev/null 2>&1
2152
+ command -v node >/dev/null 2>&1 && { command -v node; return; }
2153
+ fi
2154
+ for p in /opt/homebrew/bin/node /usr/local/bin/node /usr/bin/node; do
2155
+ [ -x "$p" ] && { echo "$p"; return; }
2156
+ done
2157
+ return 1
2158
+ }
2159
+
2160
+ NODE=$(resolve_node)
2161
+ if [ -z "$NODE" ]; then
2162
+ echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) ERROR: node not found" >> "$LOG"
2163
+ exit 1
2164
+ fi
2165
+
2166
+ echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) START sync" >> "$LOG"
2167
+ "$NODE" "$CONARE_DIR/bin/conare-ingest.mjs" \\
2168
+ --config-file "$CONARE_DIR/config.json" \\
2169
+ --ingest-only \\
2170
+ --quiet \\
2171
+ 2>> "$LOG"
2172
+ echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) DONE sync (exit $?)" >> "$LOG"
2173
+ `;
2174
+ function makePlist(intervalMinutes) {
2175
+ const home = homedir7();
2176
+ return `<?xml version="1.0" encoding="UTF-8"?>
2177
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
2178
+ "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
2179
+ <plist version="1.0">
2180
+ <dict>
2181
+ <key>Label</key>
2182
+ <string>${PLIST_LABEL}</string>
2183
+ <key>ProgramArguments</key>
2184
+ <array>
2185
+ <string>/bin/bash</string>
2186
+ <string>${home}/.conare/bin/run.sh</string>
2187
+ </array>
2188
+ <key>StartInterval</key>
2189
+ <integer>${intervalMinutes * 60}</integer>
2190
+ <key>StandardOutPath</key>
2191
+ <string>${home}/.conare/ingest.log</string>
2192
+ <key>StandardErrorPath</key>
2193
+ <string>${home}/.conare/ingest.log</string>
2194
+ <key>RunAtLoad</key>
2195
+ <true/>
2196
+ </dict>
2197
+ </plist>`;
2198
+ }
2199
+ var SYSTEMD_SERVICE_CONTENT = `[Unit]
2200
+ Description=Conare Memory — background sync
2201
+
2202
+ [Service]
2203
+ Type=oneshot
2204
+ ExecStart=%h/.conare/bin/run.sh
2205
+ `;
2206
+ function makeSystemdTimer(intervalMinutes) {
2207
+ return `[Unit]
2208
+ Description=Conare Memory — sync every ${intervalMinutes} minutes
2209
+
2210
+ [Timer]
2211
+ OnBootSec=2min
2212
+ OnUnitActiveSec=${intervalMinutes}min
2213
+ Persistent=true
2072
2214
 
2073
- class dD extends x {
2074
- get cursor() {
2075
- return this.value ? 0 : 1;
2076
- }
2077
- get _value() {
2078
- return this.cursor === 0;
2079
- }
2080
- constructor(u) {
2081
- super(u, false), this.value = !!u.initialValue, this.on("value", () => {
2082
- this.value = this._value;
2083
- }), this.on("confirm", (t) => {
2084
- this.output.write(import_sisteransi.cursor.move(0, -1)), this.value = t, this.state = "submit", this.close();
2085
- }), this.on("cursor", () => {
2086
- this.value = !this.value;
2087
- });
2088
- }
2215
+ [Install]
2216
+ WantedBy=timers.target
2217
+ `;
2089
2218
  }
2090
- var A;
2091
- A = new WeakMap;
2092
- var kD = Object.defineProperty;
2093
- var $D = (e, u, t) => (u in e) ? kD(e, u, { enumerable: true, configurable: true, writable: true, value: t }) : e[u] = t;
2094
- var H = (e, u, t) => ($D(e, typeof u != "symbol" ? u + "" : u, t), t);
2095
- var SD = class extends x {
2096
- constructor(u) {
2097
- super(u, false), H(this, "options"), H(this, "cursor", 0), this.options = u.options, this.value = [...u.initialValues ?? []], this.cursor = Math.max(this.options.findIndex(({ value: t }) => t === u.cursorAt), 0), this.on("key", (t) => {
2098
- t === "a" && this.toggleAll();
2099
- }), this.on("cursor", (t) => {
2100
- switch (t) {
2101
- case "left":
2102
- case "up":
2103
- this.cursor = this.cursor === 0 ? this.options.length - 1 : this.cursor - 1;
2104
- break;
2105
- case "down":
2106
- case "right":
2107
- this.cursor = this.cursor === this.options.length - 1 ? 0 : this.cursor + 1;
2108
- break;
2109
- case "space":
2110
- this.toggleValue();
2111
- break;
2112
- }
2113
- });
2114
- }
2115
- get _value() {
2116
- return this.options[this.cursor].value;
2117
- }
2118
- toggleAll() {
2119
- const u = this.value.length === this.options.length;
2120
- this.value = u ? [] : this.options.map((t) => t.value);
2121
- }
2122
- toggleValue() {
2123
- const u = this.value.includes(this._value);
2124
- this.value = u ? this.value.filter((t) => t !== this._value) : [...this.value, this._value];
2125
- }
2126
- };
2127
- var TD = Object.defineProperty;
2128
- var jD = (e, u, t) => (u in e) ? TD(e, u, { enumerable: true, configurable: true, writable: true, value: t }) : e[u] = t;
2129
- var U = (e, u, t) => (jD(e, typeof u != "symbol" ? u + "" : u, t), t);
2130
-
2131
- class MD extends x {
2132
- constructor({ mask: u, ...t }) {
2133
- super(t), U(this, "valueWithCursor", ""), U(this, "_mask", "•"), this._mask = u ?? "•", this.on("finalize", () => {
2134
- this.valueWithCursor = this.masked;
2135
- }), this.on("value", () => {
2136
- if (this.cursor >= this.value.length)
2137
- this.valueWithCursor = `${this.masked}${import_picocolors.default.inverse(import_picocolors.default.hidden("_"))}`;
2138
- else {
2139
- const F = this.masked.slice(0, this.cursor), s = this.masked.slice(this.cursor);
2140
- this.valueWithCursor = `${F}${import_picocolors.default.inverse(s[0])}${s.slice(1)}`;
2141
- }
2142
- });
2143
- }
2144
- get cursor() {
2145
- return this._cursor;
2146
- }
2147
- get masked() {
2148
- return this.value.replaceAll(/./g, this._mask);
2219
+ function hasSystemd() {
2220
+ try {
2221
+ execSync("systemctl --user status 2>/dev/null", { stdio: "ignore" });
2222
+ return true;
2223
+ } catch {
2224
+ return false;
2149
2225
  }
2150
2226
  }
2151
-
2152
- // node_modules/@clack/prompts/dist/index.mjs
2153
- var import_picocolors2 = __toESM(require_picocolors(), 1);
2154
- var import_sisteransi2 = __toESM(require_src(), 1);
2155
- import y2 from "node:process";
2156
- function ce() {
2157
- return y2.platform !== "win32" ? y2.env.TERM !== "linux" : !!y2.env.CI || !!y2.env.WT_SESSION || !!y2.env.TERMINUS_SUBLIME || y2.env.ConEmuTask === "{cmd::Cmder}" || y2.env.TERM_PROGRAM === "Terminus-Sublime" || y2.env.TERM_PROGRAM === "vscode" || y2.env.TERM === "xterm-256color" || y2.env.TERM === "alacritty" || y2.env.TERMINAL_EMULATOR === "JetBrains-JediTerm";
2227
+ function uid() {
2228
+ try {
2229
+ return execSync("id -u", { encoding: "utf-8" }).trim();
2230
+ } catch {
2231
+ return "501";
2232
+ }
2158
2233
  }
2159
- var V2 = ce();
2160
- var u = (t, n) => V2 ? t : n;
2161
- var le = u("◆", "*");
2162
- var L2 = u("■", "x");
2163
- var W2 = u("▲", "x");
2164
- var C = u("◇", "o");
2165
- var ue = u("┌", "T");
2166
- var o = u("│", "|");
2167
- var d2 = u("└", "—");
2168
- var k2 = u("●", ">");
2169
- var P2 = u("○", " ");
2170
- var A2 = u("◻", "[•]");
2171
- var T = u("◼", "[+]");
2172
- var F = u("◻", "[ ]");
2173
- var $e = u("▪", "•");
2174
- var _2 = u("─", "-");
2175
- var me = u("╮", "+");
2176
- var de = u("├", "+");
2177
- var pe = u("╯", "+");
2178
- var q = u("●", "•");
2179
- var D = u("◆", "*");
2180
- var U2 = u("▲", "!");
2181
- var K2 = u("■", "x");
2182
- var b2 = (t) => {
2183
- switch (t) {
2184
- case "initial":
2185
- case "active":
2186
- return import_picocolors2.default.cyan(le);
2187
- case "cancel":
2188
- return import_picocolors2.default.red(L2);
2189
- case "error":
2190
- return import_picocolors2.default.yellow(W2);
2191
- case "submit":
2192
- return import_picocolors2.default.green(C);
2234
+ function persistBinary(apiKey) {
2235
+ mkdirSync4(BIN_DIR, { recursive: true });
2236
+ const cliEntry = findCliBundle();
2237
+ if (!cliEntry) {
2238
+ throw new Error("Could not locate CLI bundle. Run from an installed conare package.");
2193
2239
  }
2194
- };
2195
- var G2 = (t) => {
2196
- const { cursor: n, options: r2, style: i } = t, s = t.maxItems ?? Number.POSITIVE_INFINITY, c = Math.max(process.stdout.rows - 4, 0), a = Math.min(c, Math.max(s, 5));
2197
- let l2 = 0;
2198
- n >= l2 + a - 3 ? l2 = Math.max(Math.min(n - a + 3, r2.length - a), 0) : n < l2 + 2 && (l2 = Math.max(n - 2, 0));
2199
- const $2 = a < r2.length && l2 > 0, g2 = a < r2.length && l2 + a < r2.length;
2200
- return r2.slice(l2, l2 + a).map((p2, v2, f) => {
2201
- const j2 = v2 === 0 && $2, E = v2 === f.length - 1 && g2;
2202
- return j2 || E ? import_picocolors2.default.dim("...") : i(p2, v2 + l2 === n);
2203
- });
2204
- };
2205
- var ge = (t) => new MD({ validate: t.validate, mask: t.mask ?? $e, render() {
2206
- const n = `${import_picocolors2.default.gray(o)}
2207
- ${b2(this.state)} ${t.message}
2208
- `, r2 = this.valueWithCursor, i = this.masked;
2209
- switch (this.state) {
2210
- case "error":
2211
- return `${n.trim()}
2212
- ${import_picocolors2.default.yellow(o)} ${i}
2213
- ${import_picocolors2.default.yellow(d2)} ${import_picocolors2.default.yellow(this.error)}
2214
- `;
2215
- case "submit":
2216
- return `${n}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.dim(i)}`;
2217
- case "cancel":
2218
- return `${n}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(i ?? ""))}${i ? `
2219
- ${import_picocolors2.default.gray(o)}` : ""}`;
2220
- default:
2221
- return `${n}${import_picocolors2.default.cyan(o)} ${r2}
2222
- ${import_picocolors2.default.cyan(d2)}
2223
- `;
2240
+ const dest = join9(BIN_DIR, "conare-ingest.mjs");
2241
+ const content = readFileSync8(cliEntry, "utf-8");
2242
+ writeFileSync4(dest, content);
2243
+ const sqlJsDir = findSqlJs();
2244
+ if (sqlJsDir) {
2245
+ const targetDir = join9(BIN_DIR, "node_modules", "sql.js");
2246
+ mkdirSync4(targetDir, { recursive: true });
2247
+ try {
2248
+ cpSync(sqlJsDir, targetDir, { recursive: true });
2249
+ } catch {}
2224
2250
  }
2225
- } }).prompt();
2226
- var ye = (t) => {
2227
- const n = t.active ?? "Yes", r2 = t.inactive ?? "No";
2228
- return new dD({ active: n, inactive: r2, initialValue: t.initialValue ?? true, render() {
2229
- const i = `${import_picocolors2.default.gray(o)}
2230
- ${b2(this.state)} ${t.message}
2231
- `, s = this.value ? n : r2;
2232
- switch (this.state) {
2233
- case "submit":
2234
- return `${i}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.dim(s)}`;
2235
- case "cancel":
2236
- return `${i}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(s))}
2237
- ${import_picocolors2.default.gray(o)}`;
2238
- default:
2239
- return `${i}${import_picocolors2.default.cyan(o)} ${this.value ? `${import_picocolors2.default.green(k2)} ${n}` : `${import_picocolors2.default.dim(P2)} ${import_picocolors2.default.dim(n)}`} ${import_picocolors2.default.dim("/")} ${this.value ? `${import_picocolors2.default.dim(P2)} ${import_picocolors2.default.dim(r2)}` : `${import_picocolors2.default.green(k2)} ${r2}`}
2240
- ${import_picocolors2.default.cyan(d2)}
2241
- `;
2242
- }
2243
- } }).prompt();
2244
- };
2245
- var fe = (t) => {
2246
- const n = (r2, i) => {
2247
- const s = r2.label ?? String(r2.value);
2248
- return i === "active" ? `${import_picocolors2.default.cyan(A2)} ${s} ${r2.hint ? import_picocolors2.default.dim(`(${r2.hint})`) : ""}` : i === "selected" ? `${import_picocolors2.default.green(T)} ${import_picocolors2.default.dim(s)} ${r2.hint ? import_picocolors2.default.dim(`(${r2.hint})`) : ""}` : i === "cancelled" ? `${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(s))}` : i === "active-selected" ? `${import_picocolors2.default.green(T)} ${s} ${r2.hint ? import_picocolors2.default.dim(`(${r2.hint})`) : ""}` : i === "submitted" ? `${import_picocolors2.default.dim(s)}` : `${import_picocolors2.default.dim(F)} ${import_picocolors2.default.dim(s)}`;
2249
- };
2250
- return new SD({ options: t.options, initialValues: t.initialValues, required: t.required ?? true, cursorAt: t.cursorAt, validate(r2) {
2251
- if (this.required && r2.length === 0)
2252
- return `Please select at least one option.
2253
- ${import_picocolors2.default.reset(import_picocolors2.default.dim(`Press ${import_picocolors2.default.gray(import_picocolors2.default.bgWhite(import_picocolors2.default.inverse(" space ")))} to select, ${import_picocolors2.default.gray(import_picocolors2.default.bgWhite(import_picocolors2.default.inverse(" enter ")))} to submit`))}`;
2254
- }, render() {
2255
- const r2 = `${import_picocolors2.default.gray(o)}
2256
- ${b2(this.state)} ${t.message}
2257
- `, i = (s, c) => {
2258
- const a = this.value.includes(s.value);
2259
- return c && a ? n(s, "active-selected") : a ? n(s, "selected") : n(s, c ? "active" : "inactive");
2260
- };
2261
- switch (this.state) {
2262
- case "submit":
2263
- return `${r2}${import_picocolors2.default.gray(o)} ${this.options.filter(({ value: s }) => this.value.includes(s)).map((s) => n(s, "submitted")).join(import_picocolors2.default.dim(", ")) || import_picocolors2.default.dim("none")}`;
2264
- case "cancel": {
2265
- const s = this.options.filter(({ value: c }) => this.value.includes(c)).map((c) => n(c, "cancelled")).join(import_picocolors2.default.dim(", "));
2266
- return `${r2}${import_picocolors2.default.gray(o)} ${s.trim() ? `${s}
2267
- ${import_picocolors2.default.gray(o)}` : ""}`;
2268
- }
2269
- case "error": {
2270
- const s = this.error.split(`
2271
- `).map((c, a) => a === 0 ? `${import_picocolors2.default.yellow(d2)} ${import_picocolors2.default.yellow(c)}` : ` ${c}`).join(`
2272
- `);
2273
- return `${r2 + import_picocolors2.default.yellow(o)} ${G2({ options: this.options, cursor: this.cursor, maxItems: t.maxItems, style: i }).join(`
2274
- ${import_picocolors2.default.yellow(o)} `)}
2275
- ${s}
2276
- `;
2277
- }
2278
- default:
2279
- return `${r2}${import_picocolors2.default.cyan(o)} ${G2({ options: this.options, cursor: this.cursor, maxItems: t.maxItems, style: i }).join(`
2280
- ${import_picocolors2.default.cyan(o)} `)}
2281
- ${import_picocolors2.default.cyan(d2)}
2282
- `;
2283
- }
2284
- } }).prompt();
2285
- };
2286
- var Me = (t = "", n = "") => {
2287
- const r2 = `
2288
- ${t}
2289
- `.split(`
2290
- `), i = S2(n).length, s = Math.max(r2.reduce((a, l2) => {
2291
- const $2 = S2(l2);
2292
- return $2.length > a ? $2.length : a;
2293
- }, 0), i) + 2, c = r2.map((a) => `${import_picocolors2.default.gray(o)} ${import_picocolors2.default.dim(a)}${" ".repeat(s - S2(a).length)}${import_picocolors2.default.gray(o)}`).join(`
2294
- `);
2295
- process.stdout.write(`${import_picocolors2.default.gray(o)}
2296
- ${import_picocolors2.default.green(C)} ${import_picocolors2.default.reset(n)} ${import_picocolors2.default.gray(_2.repeat(Math.max(s - i - 1, 1)) + me)}
2297
- ${c}
2298
- ${import_picocolors2.default.gray(de + _2.repeat(s + 2) + pe)}
2299
- `);
2300
- };
2301
- var xe = (t = "") => {
2302
- process.stdout.write(`${import_picocolors2.default.gray(d2)} ${import_picocolors2.default.red(t)}
2303
-
2304
- `);
2305
- };
2306
- var Ie = (t = "") => {
2307
- process.stdout.write(`${import_picocolors2.default.gray(ue)} ${t}
2308
- `);
2309
- };
2310
- var Se = (t = "") => {
2311
- process.stdout.write(`${import_picocolors2.default.gray(o)}
2312
- ${import_picocolors2.default.gray(d2)} ${t}
2313
-
2314
- `);
2315
- };
2316
- var J = `${import_picocolors2.default.gray(o)} `;
2317
- var Y2 = ({ indicator: t = "dots" } = {}) => {
2318
- const n = V2 ? ["◒", "◐", "◓", "◑"] : ["•", "o", "O", "0"], r2 = V2 ? 80 : 120, i = process.env.CI === "true";
2319
- let s, c, a = false, l2 = "", $2, g2 = performance.now();
2320
- const p2 = (m2) => {
2321
- const h2 = m2 > 1 ? "Something went wrong" : "Canceled";
2322
- a && N2(h2, m2);
2323
- }, v2 = () => p2(2), f = () => p2(1), j2 = () => {
2324
- process.on("uncaughtExceptionMonitor", v2), process.on("unhandledRejection", v2), process.on("SIGINT", f), process.on("SIGTERM", f), process.on("exit", p2);
2325
- }, E = () => {
2326
- process.removeListener("uncaughtExceptionMonitor", v2), process.removeListener("unhandledRejection", v2), process.removeListener("SIGINT", f), process.removeListener("SIGTERM", f), process.removeListener("exit", p2);
2327
- }, B2 = () => {
2328
- if ($2 === undefined)
2329
- return;
2330
- i && process.stdout.write(`
2331
- `);
2332
- const m2 = $2.split(`
2333
- `);
2334
- process.stdout.write(import_sisteransi2.cursor.move(-999, m2.length - 1)), process.stdout.write(import_sisteransi2.erase.down(m2.length));
2335
- }, R2 = (m2) => m2.replace(/\.+$/, ""), O2 = (m2) => {
2336
- const h2 = (performance.now() - m2) / 1000, w2 = Math.floor(h2 / 60), I2 = Math.floor(h2 % 60);
2337
- return w2 > 0 ? `[${w2}m ${I2}s]` : `[${I2}s]`;
2338
- }, H2 = (m2 = "") => {
2339
- a = true, s = fD(), l2 = R2(m2), g2 = performance.now(), process.stdout.write(`${import_picocolors2.default.gray(o)}
2251
+ const runShPath = join9(BIN_DIR, "run.sh");
2252
+ writeFileSync4(runShPath, RUN_SH);
2253
+ chmodSync(runShPath, 493);
2254
+ writeFileSync4(CONFIG_PATH2, JSON.stringify({ apiKey }, null, 2) + `
2340
2255
  `);
2341
- let h2 = 0, w2 = 0;
2342
- j2(), c = setInterval(() => {
2343
- if (i && l2 === $2)
2344
- return;
2345
- B2(), $2 = l2;
2346
- const I2 = import_picocolors2.default.magenta(n[h2]);
2347
- if (i)
2348
- process.stdout.write(`${I2} ${l2}...`);
2349
- else if (t === "timer")
2350
- process.stdout.write(`${I2} ${l2} ${O2(g2)}`);
2351
- else {
2352
- const z2 = ".".repeat(Math.floor(w2)).slice(0, 3);
2353
- process.stdout.write(`${I2} ${l2}${z2}`);
2354
- }
2355
- h2 = h2 + 1 < n.length ? h2 + 1 : 0, w2 = w2 < n.length ? w2 + 0.125 : 0;
2356
- }, r2);
2357
- }, N2 = (m2 = "", h2 = 0) => {
2358
- a = false, clearInterval(c), B2();
2359
- const w2 = h2 === 0 ? import_picocolors2.default.green(C) : h2 === 1 ? import_picocolors2.default.red(L2) : import_picocolors2.default.red(W2);
2360
- l2 = R2(m2 ?? l2), t === "timer" ? process.stdout.write(`${w2} ${l2} ${O2(g2)}
2361
- `) : process.stdout.write(`${w2} ${l2}
2362
- `), E(), s();
2363
- };
2364
- return { start: H2, stop: N2, message: (m2 = "") => {
2365
- l2 = R2(m2 ?? l2);
2366
- } };
2367
- };
2368
-
2369
- // src/interactive.ts
2370
- function formatDetectedCount(count) {
2371
- if (count === undefined)
2372
- return "available";
2373
- return `${count.toLocaleString()} chats`;
2374
2256
  }
2375
- function ensureValue(value) {
2376
- if (pD(value)) {
2377
- xe("Setup cancelled.");
2378
- process.exit(0);
2257
+ function findCliBundle() {
2258
+ const entry = process.argv[1];
2259
+ if (entry && existsSync8(entry))
2260
+ return entry;
2261
+ const candidates = [
2262
+ join9(dirname2(new URL(import.meta.url).pathname), "index.js"),
2263
+ join9(dirname2(new URL(import.meta.url).pathname), "..", "dist", "index.js")
2264
+ ];
2265
+ for (const c of candidates) {
2266
+ if (existsSync8(c))
2267
+ return c;
2268
+ }
2269
+ return null;
2270
+ }
2271
+ function findSqlJs() {
2272
+ const candidates = [
2273
+ join9(process.cwd(), "node_modules", "sql.js"),
2274
+ join9(dirname2(new URL(import.meta.url).pathname), "..", "node_modules", "sql.js"),
2275
+ join9(dirname2(new URL(import.meta.url).pathname), "..", "..", "node_modules", "sql.js")
2276
+ ];
2277
+ for (const c of candidates) {
2278
+ if (existsSync8(c))
2279
+ return c;
2379
2280
  }
2380
- return value;
2381
- }
2382
- function startSetup() {
2383
- Ie("Conare setup");
2281
+ return null;
2384
2282
  }
2385
- function finishSetup() {
2386
- Se("Starting setup...");
2283
+ function setupMacOS(intervalMinutes) {
2284
+ const plistDir = dirname2(PLIST_PATH);
2285
+ mkdirSync4(plistDir, { recursive: true });
2286
+ writeFileSync4(PLIST_PATH, makePlist(intervalMinutes));
2287
+ const id = uid();
2288
+ try {
2289
+ execSync(`launchctl bootout gui/${id} "${PLIST_PATH}" 2>/dev/null`, { stdio: "ignore" });
2290
+ } catch {}
2291
+ try {
2292
+ execSync(`launchctl bootstrap gui/${id} "${PLIST_PATH}"`, { stdio: "ignore" });
2293
+ } catch {
2294
+ try {
2295
+ execSync(`launchctl load "${PLIST_PATH}"`, { stdio: "ignore" });
2296
+ } catch {
2297
+ throw new Error("Failed to load launchd agent. Try manually: launchctl load " + PLIST_PATH);
2298
+ }
2299
+ }
2387
2300
  }
2388
- function showDetectedApps(targets) {
2389
- Me(targets.map((target) => `• ${target.label}: ${target.available === false ? "not detected" : formatDetectedCount(target.detectedCount)}`).join(`
2390
- `), "Detected apps");
2301
+ function setupLinuxSystemd(intervalMinutes) {
2302
+ mkdirSync4(SYSTEMD_DIR, { recursive: true });
2303
+ writeFileSync4(SYSTEMD_SERVICE, SYSTEMD_SERVICE_CONTENT);
2304
+ writeFileSync4(SYSTEMD_TIMER, makeSystemdTimer(intervalMinutes));
2305
+ execSync("systemctl --user daemon-reload", { stdio: "ignore" });
2306
+ execSync("systemctl --user enable --now conare-sync.timer", { stdio: "ignore" });
2391
2307
  }
2392
- async function promptApiKey(options) {
2393
- if (options.providedApiKey) {
2394
- return options.providedApiKey;
2308
+ function setupLinuxCron(intervalMinutes) {
2309
+ const cronCmd = `${homedir7()}/.conare/bin/run.sh`;
2310
+ const cronLine = `*/${intervalMinutes} * * * * ${cronCmd}`;
2311
+ try {
2312
+ const existing = execSync("crontab -l 2>/dev/null", { encoding: "utf-8" });
2313
+ const filtered = existing.split(`
2314
+ `).filter((l) => !l.includes("conare")).join(`
2315
+ `);
2316
+ const newCrontab = (filtered.trim() ? filtered.trim() + `
2317
+ ` : "") + cronLine + `
2318
+ `;
2319
+ execSync("crontab -", { input: newCrontab, stdio: ["pipe", "ignore", "ignore"] });
2320
+ } catch {
2321
+ execSync("crontab -", { input: cronLine + `
2322
+ `, stdio: ["pipe", "ignore", "ignore"] });
2395
2323
  }
2396
- const keyPrompt = await ge({
2397
- message: options.savedApiKey ? `API key (press Enter to use saved key ending in ${options.savedApiKey.slice(-6)})` : "API key",
2398
- mask: "*",
2399
- validate(value) {
2400
- const resolved = value.trim() || options.savedApiKey || "";
2401
- if (!resolved)
2402
- return "Enter an API key from https://mcp.conare.ai";
2403
- if (!resolved.startsWith("cmem_"))
2404
- return "API keys start with cmem_";
2405
- return;
2324
+ }
2325
+ function installGlobalCommand() {
2326
+ const wrapper = join9(BIN_DIR, "conare");
2327
+ const content = `#!/bin/bash
2328
+ # Conare global command runs the persisted CLI bundle
2329
+ CONARE_DIR="$HOME/.conare"
2330
+ NODE=$(command -v node || echo "")
2331
+ if [ -z "$NODE" ]; then
2332
+ if [ -s "$HOME/.nvm/nvm.sh" ]; then
2333
+ . "$HOME/.nvm/nvm.sh" >/dev/null 2>&1
2334
+ NODE=$(command -v node || echo "")
2335
+ fi
2336
+ fi
2337
+ if [ -z "$NODE" ]; then
2338
+ echo "Error: node not found. Install Node.js first." >&2
2339
+ exit 1
2340
+ fi
2341
+ exec "$NODE" "$CONARE_DIR/bin/conare-ingest.mjs" "$@"
2342
+ `;
2343
+ writeFileSync4(wrapper, content);
2344
+ chmodSync(wrapper, 493);
2345
+ const symlinkTarget = "/usr/local/bin/conare";
2346
+ try {
2347
+ if (existsSync8(symlinkTarget)) {
2348
+ try {
2349
+ const existing = readlinkSync(symlinkTarget);
2350
+ if (existing === wrapper)
2351
+ return "Global command: conare (already linked)";
2352
+ } catch {}
2353
+ unlinkSync(symlinkTarget);
2406
2354
  }
2407
- });
2408
- return ensureValue(keyPrompt).trim() || options.savedApiKey;
2355
+ symlinkSync(wrapper, symlinkTarget);
2356
+ return "Global command: conare (linked to /usr/local/bin)";
2357
+ } catch {
2358
+ const pathDirs = (process.env.PATH || "").split(":");
2359
+ if (pathDirs.includes(BIN_DIR)) {
2360
+ return "Global command: conare (via ~/.conare/bin in PATH)";
2361
+ }
2362
+ const shellProfile = getShellProfile();
2363
+ if (shellProfile) {
2364
+ try {
2365
+ const profileContent = existsSync8(shellProfile) ? readFileSync8(shellProfile, "utf-8") : "";
2366
+ const exportLine = `export PATH="$HOME/.conare/bin:$PATH"`;
2367
+ if (!profileContent.includes(".conare/bin")) {
2368
+ appendFileSync(shellProfile, `
2369
+ # Conare CLI
2370
+ ${exportLine}
2371
+ `);
2372
+ return `Global command: conare (added ~/.conare/bin to ${shellProfile} — restart shell)`;
2373
+ }
2374
+ return "Global command: conare (via ~/.conare/bin in PATH)";
2375
+ } catch {
2376
+ return `Global command: add ~/.conare/bin to your PATH manually`;
2377
+ }
2378
+ }
2379
+ return `Global command: add ~/.conare/bin to your PATH manually`;
2380
+ }
2409
2381
  }
2410
- async function selectChatSources(targets) {
2411
- return ensureValue(await fe({
2412
- message: "Select chat sources",
2413
- required: false,
2414
- initialValues: targets.filter((target) => target.recommended).map((target) => target.id),
2415
- options: targets.map((target) => ({
2416
- value: target.id,
2417
- label: target.label,
2418
- hint: target.available === false ? "not detected" : formatDetectedCount(target.detectedCount)
2419
- }))
2420
- }));
2382
+ function getShellProfile() {
2383
+ const home = homedir7();
2384
+ const shell = process.env.SHELL || "";
2385
+ if (shell.includes("zsh"))
2386
+ return join9(home, ".zshrc");
2387
+ if (shell.includes("bash")) {
2388
+ const profile = join9(home, ".bash_profile");
2389
+ if (platform2() === "darwin" && existsSync8(profile))
2390
+ return profile;
2391
+ return join9(home, ".bashrc");
2392
+ }
2393
+ if (existsSync8(join9(home, ".zshrc")))
2394
+ return join9(home, ".zshrc");
2395
+ if (existsSync8(join9(home, ".bashrc")))
2396
+ return join9(home, ".bashrc");
2397
+ return null;
2421
2398
  }
2422
- async function selectMcpTargets(targets) {
2423
- return ensureValue(await fe({
2424
- message: "Select where to install the MCP",
2425
- required: false,
2426
- initialValues: targets.filter((target) => target.recommended).map((target) => target.id),
2427
- options: targets.map((target) => ({
2428
- value: target.id,
2429
- label: target.label,
2430
- hint: target.available === false ? "not detected" : "recommended"
2431
- }))
2432
- }));
2399
+ function installSync(apiKey, intervalMinutes = 10) {
2400
+ const messages = [];
2401
+ const os = platform2();
2402
+ persistBinary(apiKey);
2403
+ messages.push("Persisted CLI to ~/.conare/bin/");
2404
+ messages.push("Saved config to ~/.conare/config.json");
2405
+ const globalMsg = installGlobalCommand();
2406
+ if (globalMsg)
2407
+ messages.push(globalMsg);
2408
+ if (os === "darwin") {
2409
+ setupMacOS(intervalMinutes);
2410
+ messages.push(`Installed launchd agent (every ${intervalMinutes} min)`);
2411
+ messages.push(`Plist: ${PLIST_PATH}`);
2412
+ } else if (os === "linux") {
2413
+ if (hasSystemd()) {
2414
+ setupLinuxSystemd(intervalMinutes);
2415
+ messages.push(`Installed systemd timer (every ${intervalMinutes} min)`);
2416
+ } else {
2417
+ setupLinuxCron(intervalMinutes);
2418
+ messages.push(`Installed cron job (every ${intervalMinutes} min)`);
2419
+ }
2420
+ } else {
2421
+ messages.push(`Unsupported platform: ${os}. Run manually: ~/.conare/bin/run.sh`);
2422
+ }
2423
+ return messages;
2433
2424
  }
2434
- async function confirmIndexCodebase() {
2435
- return ensureValue(await ye({
2436
- message: "Index this codebase too?",
2437
- initialValue: false
2438
- }));
2425
+ function uninstallSync() {
2426
+ const messages = [];
2427
+ const os = platform2();
2428
+ if (os === "darwin") {
2429
+ try {
2430
+ execSync(`launchctl bootout gui/${uid()} "${PLIST_PATH}" 2>/dev/null`, { stdio: "ignore" });
2431
+ } catch {}
2432
+ if (existsSync8(PLIST_PATH)) {
2433
+ unlinkSync(PLIST_PATH);
2434
+ messages.push("Removed launchd agent");
2435
+ }
2436
+ } else if (os === "linux") {
2437
+ if (hasSystemd()) {
2438
+ try {
2439
+ execSync("systemctl --user disable --now conare-sync.timer 2>/dev/null", { stdio: "ignore" });
2440
+ } catch {}
2441
+ if (existsSync8(SYSTEMD_SERVICE))
2442
+ unlinkSync(SYSTEMD_SERVICE);
2443
+ if (existsSync8(SYSTEMD_TIMER))
2444
+ unlinkSync(SYSTEMD_TIMER);
2445
+ try {
2446
+ execSync("systemctl --user daemon-reload", { stdio: "ignore" });
2447
+ } catch {}
2448
+ messages.push("Removed systemd timer");
2449
+ } else {
2450
+ try {
2451
+ const existing = execSync("crontab -l 2>/dev/null", { encoding: "utf-8" });
2452
+ const filtered = existing.split(`
2453
+ `).filter((l) => !l.includes("conare")).join(`
2454
+ `);
2455
+ execSync("crontab -", { input: filtered.trim() + `
2456
+ `, stdio: ["pipe", "ignore", "ignore"] });
2457
+ messages.push("Removed cron job");
2458
+ } catch {}
2459
+ }
2460
+ }
2461
+ const filesToRemove = [
2462
+ join9(CONARE_DIR, "config.json"),
2463
+ join9(CONARE_DIR, "sync.lock")
2464
+ ];
2465
+ for (const f of filesToRemove) {
2466
+ if (existsSync8(f))
2467
+ unlinkSync(f);
2468
+ }
2469
+ if (existsSync8(BIN_DIR)) {
2470
+ rmSync(BIN_DIR, { recursive: true, force: true });
2471
+ messages.push("Removed ~/.conare/bin/");
2472
+ }
2473
+ if (messages.length === 0) {
2474
+ messages.push("Nothing to uninstall (no sync timer found)");
2475
+ }
2476
+ return messages;
2439
2477
  }
2440
2478
 
2441
2479
  // src/index.ts
2480
+ init_interactive();
2442
2481
  function getManifestFingerprint(memory) {
2443
2482
  const metadata = memory.metadata;
2444
2483
  if (metadata?.dedupKey && metadata?.contentHash) {
@@ -2539,9 +2578,11 @@ function parseArgs() {
2539
2578
  interactive = true;
2540
2579
  } else if (args[i] === "--help" || args[i] === "-h") {
2541
2580
  console.log(`
2542
- conare — Ingest AI chat history into Conare
2581
+ conare — AI memory for your coding tools
2543
2582
 
2544
2583
  Usage:
2584
+ conare install Just install the MCP (simplest)
2585
+ conare install --key <api_key> Install MCP with key
2545
2586
  conare --key <api_key> Ingest chat history
2546
2587
  conare --key <api_key> --index [path] Index codebase
2547
2588
 
@@ -2576,7 +2617,43 @@ Get your API key at https://mcp.conare.ai
2576
2617
  }
2577
2618
  return { key, configFile, dryRun, force, ingestOnly, configOnly, interactive, quiet, installSync: installSyncFlag, uninstallSync: uninstallSyncFlag, syncInterval, source, wasmDir, indexPath };
2578
2619
  }
2620
+ async function runInstall() {
2621
+ const args = process.argv.slice(3);
2622
+ let key = "";
2623
+ for (let i = 0;i < args.length; i++) {
2624
+ if (args[i] === "--key" && args[i + 1]) {
2625
+ key = args[++i];
2626
+ }
2627
+ }
2628
+ const savedApiKey = getSavedApiKey();
2629
+ let apiKey = key || process.env.CONARE_API_KEY || savedApiKey;
2630
+ const hasTty = !!process.stdin.isTTY && !!process.stdout.isTTY;
2631
+ if (!apiKey && hasTty) {
2632
+ const { promptApiKey: promptKey } = await Promise.resolve().then(() => (init_interactive(), exports_interactive));
2633
+ apiKey = await promptKey({ savedApiKey }) || "";
2634
+ }
2635
+ if (!apiKey) {
2636
+ printMissingKeyError();
2637
+ process.exit(1);
2638
+ }
2639
+ const auth = await validateKey(apiKey);
2640
+ if (!auth.valid) {
2641
+ console.error("Invalid API key. Check your key at https://mcp.conare.ai");
2642
+ process.exit(1);
2643
+ }
2644
+ saveApiKey(apiKey);
2645
+ const allTargets = MCP_TARGETS.map((t) => t.id);
2646
+ const lines = configureMcp(apiKey, allTargets);
2647
+ for (const line of lines)
2648
+ console.log(` ${line}`);
2649
+ console.log("");
2650
+ console.log(" \x1B[32m✓\x1B[0m MCP installed. Restart your AI tool to connect.");
2651
+ console.log("");
2652
+ }
2579
2653
  async function main() {
2654
+ if (process.argv[2] === "install") {
2655
+ return runInstall();
2656
+ }
2580
2657
  const opts = parseArgs();
2581
2658
  let configFileKey;
2582
2659
  if (opts.configFile) {
@@ -2616,7 +2693,7 @@ async function main() {
2616
2693
  if (shouldRunInteractive) {
2617
2694
  const detectedTools = detect();
2618
2695
  interactiveTargets = MCP_TARGETS.map((target) => {
2619
- const detected = detectedTools.find((tool) => target.id === "claude" && tool.name === "Claude Code" || target.id === "cursor" && tool.name === "Cursor" || target.id === "codex" && tool.name === "Codex");
2696
+ const detected = detectedTools.find((tool) => target.id === "claude" && tool.name === "Claude Code" || target.id === "cursor" && tool.name === "Cursor" || target.id === "codex" && tool.name === "Codex" || target.id === "openclaw" && tool.name === "OpenClaw");
2620
2697
  return {
2621
2698
  id: target.id,
2622
2699
  label: target.label,
@@ -2674,7 +2751,7 @@ async function main() {
2674
2751
  log("");
2675
2752
  }
2676
2753
  }
2677
- if (!opts.wasmDir && existsSync8(join10(process.cwd(), "node_modules", "sql.js"))) {
2754
+ if (!opts.wasmDir && existsSync9(join10(process.cwd(), "node_modules", "sql.js"))) {
2678
2755
  opts.wasmDir = join10(process.cwd(), "node_modules");
2679
2756
  }
2680
2757
  if (effectiveConfigOnly) {