conare 0.2.3 → 0.3.0

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 +2197 -2153
  2. package/package.json +1 -1
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,2294 @@ 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
383
  }
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
- }
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++;
836
- continue;
837
- }
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);
851
- }
852
- } catch (e) {
853
- console.log(` Cursor ingestion error: ${e.message}`);
854
- } finally {
855
- db.close();
856
- }
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(/\/$/, ""));
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;
959
394
  }
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
- };
1016
- return map[ext] || ext.slice(1);
1017
- }
1018
- function formatFile(relPath, content, ext) {
1019
- const lang = langFromExt(ext);
1020
- return `# File: ${relPath}
1021
-
1022
- \`\`\`${lang}
1023
- ${content}
1024
- \`\`\``;
1025
- }
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;
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;
1039
417
  }
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++;
418
+ if (o + D[E] > u && o > 0 && D[E] > 0) {
419
+ if (t.wordWrap === false && o < u) {
420
+ k(C, a, u);
1072
421
  continue;
1073
422
  }
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;
423
+ C.push("");
424
+ }
425
+ if (o + D[E] > u && t.wordWrap === false) {
426
+ k(C, a, u);
427
+ continue;
428
+ }
429
+ C[C.length - 1] += a;
430
+ }
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;
1081
481
  }
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)
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];
550
+ }
551
+ };
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)}`;
1094
563
  }
1095
564
  });
1096
- fileCount++;
1097
565
  }
1098
- }
1099
- walk(absRoot);
1100
- return { memories, fileCount, skipped };
1101
- }
1102
-
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;
566
+ get cursor() {
567
+ return this._cursor;
1119
568
  }
1120
- current.push(item);
1121
- currentChars += itemChars;
569
+ get masked() {
570
+ return this.value.replaceAll(/./g, this._mask);
571
+ }
572
+ };
573
+ });
574
+
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";
580
+ }
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);
1122
592
  }
1123
- if (current.length > 0) {
1124
- batches.push({ startIndex, items: current });
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
+ `;
1125
621
  }
1126
- return batches;
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
+ `;
638
+ }
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)}` : ""}`;
663
+ }
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
+ `;
672
+ }
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
+ `;
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`;
1127
803
  }
1128
- async function validateKey(apiKey) {
1129
- 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 };
1137
- } catch {
1138
- return { valid: false };
804
+ function ensureValue(value) {
805
+ if (pD(value)) {
806
+ xe("Setup cancelled.");
807
+ process.exit(0);
1139
808
  }
809
+ return value;
1140
810
  }
1141
- async function getRemoteMemoryCount(apiKey) {
1142
- try {
1143
- const res = await fetch(`${API_URL}/api/containers`, {
1144
- headers: { Authorization: `Bearer ${apiKey}` }
1145
- });
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;
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;
1154
824
  }
1155
- }
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));
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;
1191
835
  }
1192
- }
1193
- return items.map(() => ({ success: false, error: "Upload failed" }));
836
+ });
837
+ return ensureValue(keyPrompt).trim() || options.savedApiKey;
1194
838
  }
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);
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
+ }));
868
+ }
869
+ var init_interactive = __esm(() => {
870
+ init_dist2();
871
+ });
872
+
873
+ // src/index.ts
874
+ import { existsSync as existsSync8 } 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++;
1213
890
  }
1214
- batchResults = retriedResults;
1215
- }
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++;
1228
891
  }
1229
- onProgress?.(success + failed, total, failed);
1230
- }
1231
- return { success, failed, results };
892
+ } catch {}
893
+ return count;
1232
894
  }
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) {
895
+ function countCursorSessions(dbPath) {
1247
896
  try {
1248
- return JSON.parse(readFileSync6(path, "utf-8"));
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;
1249
934
  } catch {
1250
- return {};
935
+ return 0;
1251
936
  }
1252
937
  }
1253
- function writeJsonFile(path, data) {
1254
- mkdirSync2(dirname(path), { recursive: true });
1255
- writeFileSync2(path, JSON.stringify(data, null, 2) + `
1256
- `);
1257
- }
1258
- function getServerConfig(apiKey) {
1259
- return {
1260
- type: "http",
1261
- url: `${CONARE_URL}/mcp`,
1262
- headers: {
1263
- Authorization: `Bearer ${apiKey}`
1264
- }
1265
- };
1266
- }
1267
- function upsertMcpServer(path, apiKey) {
1268
- const config = readJsonFile(path);
1269
- if (!config.mcpServers || typeof config.mcpServers !== "object") {
1270
- config.mcpServers = {};
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
949
+ });
950
+ } else {
951
+ tools.push({ name: "Claude Code", available: false, path: claudeDir, sessionCount: 0 });
1271
952
  }
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`";
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 });
1282
981
  }
1283
- upsertMcpServer(claudeConfigPath, apiKey);
1284
- if (existsSync5(join7(homedir5(), ".claude"))) {
1285
- upsertMcpServer(claudeMcpPath, apiKey);
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");
1286
990
  }
1287
- return `Claude Code configured at ${claudeConfigPath}`;
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;
1288
1005
  }
1289
- function configureJsonClient(path, apiKey, label) {
1290
- upsertMcpServer(path, apiKey);
1291
- return `${label} configured at ${path}`;
1006
+
1007
+ // src/ingest/claude.ts
1008
+ import { readdirSync as readdirSync2, readFileSync as readFileSync2 } 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;
1292
1027
  }
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"));
1300
- }
1301
- if (targets.includes("codex")) {
1302
- results.push(configureJsonClient(join7(homedir5(), ".codex", "mcp.json"), apiKey, "Codex"));
1303
- }
1304
- return results;
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
+ return text.trim();
1305
1034
  }
1306
-
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
- }
1035
+ function createContentHash(content) {
1036
+ return createHash("sha256").update(content).digest("hex").slice(0, 16);
1321
1037
  }
1322
- function saveApiKey(apiKey) {
1323
- mkdirSync3(CONFIG_DIR, { recursive: true });
1324
- writeFileSync3(CONFIG_PATH, JSON.stringify({ apiKey }, null, 2) + `
1325
- `);
1038
+ function getIngested() {
1039
+ try {
1040
+ if (existsSync2(MANIFEST_PATH)) {
1041
+ return JSON.parse(readFileSync(MANIFEST_PATH, "utf-8"));
1042
+ }
1043
+ } catch {}
1044
+ return {};
1326
1045
  }
1327
- function getSavedApiKey() {
1328
- return readConfig().apiKey;
1046
+ function markIngested(source, sessionIds) {
1047
+ const manifest = getIngested();
1048
+ const existing = new Set(manifest[source] || []);
1049
+ for (const id of sessionIds)
1050
+ existing.add(id);
1051
+ manifest[source] = [...existing];
1052
+ const dir = join2(homedir2(), ".conare");
1053
+ if (!existsSync2(dir))
1054
+ mkdirSync(dir, { recursive: true });
1055
+ writeFileSync(MANIFEST_PATH, JSON.stringify(manifest, null, 2));
1329
1056
  }
1330
-
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
1347
-
1348
- CONARE_DIR="$HOME/.conare"
1349
- LOCKFILE="$CONARE_DIR/sync.lock"
1350
- LOG="$CONARE_DIR/ingest.log"
1351
-
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
1356
-
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
1375
-
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
1057
+ function isIngested(source, sessionId) {
1058
+ const manifest = getIngested();
1059
+ return (manifest[source] || []).includes(sessionId);
1391
1060
  }
1392
-
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
1398
-
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>`;
1061
+ function clearIngested(source) {
1062
+ const manifest = getIngested();
1063
+ if (source) {
1064
+ delete manifest[source];
1065
+ } else {
1066
+ for (const key of Object.keys(manifest))
1067
+ delete manifest[key];
1068
+ }
1069
+ const dir = join2(homedir2(), ".conare");
1070
+ if (!existsSync2(dir))
1071
+ mkdirSync(dir, { recursive: true });
1072
+ writeFileSync(MANIFEST_PATH, JSON.stringify(manifest, null, 2));
1431
1073
  }
1432
- var SYSTEMD_SERVICE_CONTENT = `[Unit]
1433
- Description=Conare Memory — background sync
1434
1074
 
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
1442
-
1443
- [Timer]
1444
- OnBootSec=2min
1445
- OnUnitActiveSec=${intervalMinutes}min
1446
- Persistent=true
1447
-
1448
- [Install]
1449
- WantedBy=timers.target
1450
- `;
1451
- }
1452
- function hasSystemd() {
1453
- try {
1454
- execSync("systemctl --user status 2>/dev/null", { stdio: "ignore" });
1455
- return true;
1456
- } catch {
1457
- return false;
1075
+ // src/ingest/claude.ts
1076
+ var MAX_CONTENT = 48000;
1077
+ var MIN_TURN_LEN = 50;
1078
+ function extractText(content) {
1079
+ if (typeof content === "string")
1080
+ return content;
1081
+ if (!Array.isArray(content))
1082
+ return "";
1083
+ return content.filter((b) => b.type === "text" && b.text).map((b) => b.text).join(`
1084
+ `);
1085
+ }
1086
+ function parseSession(lines) {
1087
+ const rounds = [];
1088
+ let date = null;
1089
+ let currentUser = null;
1090
+ let currentAssistant = [];
1091
+ for (const line of lines) {
1092
+ if (!line.trim())
1093
+ continue;
1094
+ let obj;
1095
+ try {
1096
+ obj = JSON.parse(line);
1097
+ } catch {
1098
+ continue;
1099
+ }
1100
+ if (!date && obj.timestamp)
1101
+ date = obj.timestamp.slice(0, 10);
1102
+ if (obj.type === "user") {
1103
+ const text = cleanText(extractText(obj.message?.content));
1104
+ if (text.length >= MIN_TURN_LEN) {
1105
+ if (currentUser !== null && currentAssistant.length > 0) {
1106
+ rounds.push({ user: currentUser, assistantParts: currentAssistant });
1107
+ }
1108
+ currentUser = text;
1109
+ currentAssistant = [];
1110
+ }
1111
+ } else if (obj.type === "assistant") {
1112
+ const text = cleanText(extractText(obj.message?.content));
1113
+ if (text.length >= MIN_TURN_LEN) {
1114
+ currentAssistant.push(text);
1115
+ }
1116
+ }
1117
+ }
1118
+ if (currentUser !== null && currentAssistant.length > 0) {
1119
+ rounds.push({ user: currentUser, assistantParts: currentAssistant });
1458
1120
  }
1121
+ const turns = rounds.map((r) => ({
1122
+ user: r.user,
1123
+ assistant: r.assistantParts.filter((p) => !isNarration(p)).join(`
1124
+
1125
+ `)
1126
+ })).filter((t) => t.assistant.length >= MIN_TURN_LEN);
1127
+ return { turns, date };
1459
1128
  }
1460
- function uid() {
1129
+ function ingestClaude() {
1130
+ const projectsDir = join3(homedir3(), ".claude", "projects");
1131
+ const memories = [];
1132
+ const sessionIds = [];
1133
+ let filtered = 0;
1134
+ let deduped = 0;
1135
+ let projectDirs;
1461
1136
  try {
1462
- return execSync("id -u", { encoding: "utf-8" }).trim();
1137
+ projectDirs = readdirSync2(projectsDir);
1463
1138
  } catch {
1464
- return "501";
1465
- }
1466
- }
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.");
1139
+ return { memories, sessionIds, skipped: 0, filtered, deduped };
1472
1140
  }
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 });
1141
+ for (const projDir of projectDirs) {
1142
+ const projPath = join3(projectsDir, projDir);
1143
+ const project = projDir.replace(/^-Users-[^-]+-/, "").replace(/-/g, "/") || projDir;
1144
+ let files;
1480
1145
  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) + `
1146
+ files = readdirSync2(projPath).filter((f) => f.endsWith(".jsonl"));
1147
+ } catch {
1148
+ continue;
1149
+ }
1150
+ for (const file of files) {
1151
+ const sessionId = basename(file, ".jsonl");
1152
+ const raw = readFileSync2(join3(projPath, file), "utf-8");
1153
+ const { turns, date } = parseSession(raw.split(`
1154
+ `));
1155
+ if (turns.length === 0) {
1156
+ filtered++;
1157
+ continue;
1158
+ }
1159
+ const header = `# Chat: ${project}${date ? ` | ${date}` : ""}`;
1160
+ const body = turns.map((t) => {
1161
+ const q = t.user.length > 300 ? t.user.slice(0, 300) + "..." : t.user;
1162
+ return `## Q: ${q}
1163
+
1164
+ ${t.assistant}`;
1165
+ }).join(`
1166
+
1167
+ ---
1168
+
1488
1169
  `);
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;
1170
+ let content = `${header}
1171
+
1172
+ ${body}`;
1173
+ if (content.length > MAX_CONTENT)
1174
+ content = content.slice(0, MAX_CONTENT) + `
1175
+
1176
+ [truncated]`;
1177
+ const contentHash = createContentHash(content);
1178
+ const dedupKey = `claude:${sessionId}`;
1179
+ const fingerprint = `${dedupKey}:${contentHash}`;
1180
+ if (isIngested("claude", fingerprint)) {
1181
+ deduped++;
1182
+ continue;
1183
+ }
1184
+ memories.push({
1185
+ content,
1186
+ containerTag: "claude-chats",
1187
+ metadata: {
1188
+ dedupKey,
1189
+ contentHash,
1190
+ source: "claude-code",
1191
+ sessionId,
1192
+ project,
1193
+ date: date || "unknown"
1194
+ }
1195
+ });
1196
+ sessionIds.push(sessionId);
1197
+ }
1501
1198
  }
1502
- return null;
1199
+ return { memories, sessionIds, skipped: filtered + deduped, filtered, deduped };
1503
1200
  }
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;
1513
- }
1514
- return null;
1201
+
1202
+ // src/ingest/codex.ts
1203
+ import { existsSync as existsSync3, readFileSync as readFileSync3, readdirSync as readdirSync3 } from "node:fs";
1204
+ import { join as join4, basename as basename2 } from "node:path";
1205
+ import { homedir as homedir4 } from "node:os";
1206
+ var MAX_CONTENT2 = 48000;
1207
+ function isCodexBoilerplate(text) {
1208
+ return text.startsWith("# AGENTS.md instructions for") || text.startsWith("<INSTRUCTIONS>") || text.startsWith("<user_instructions>") || text.startsWith("<user_action>");
1515
1209
  }
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 {}
1524
- try {
1525
- execSync(`launchctl bootstrap gui/${id} "${PLIST_PATH}"`, { stdio: "ignore" });
1526
- } catch {
1210
+ function stripEnvironmentContext(text) {
1211
+ let cwd = null;
1212
+ const cwdMatch = text.match(/<cwd>([^<]+)<\/cwd>/);
1213
+ if (cwdMatch)
1214
+ cwd = cwdMatch[1];
1215
+ const cleaned = text.replace(/<environment_context>[\s\S]*?<\/environment_context>/g, "").trim();
1216
+ return { text: cleaned, cwd };
1217
+ }
1218
+ function projectFromCwd(cwd) {
1219
+ return cwd.replace(/^\/Users\/[^/]+\//, "");
1220
+ }
1221
+ function ingestCodex() {
1222
+ const memories = [];
1223
+ const sessionIds = [];
1224
+ let filtered = 0;
1225
+ let deduped = 0;
1226
+ const historyPath = join4(homedir4(), ".codex", "history.jsonl");
1227
+ if (existsSync3(historyPath)) {
1228
+ try {
1229
+ const lines = readFileSync3(historyPath, "utf-8").split(`
1230
+ `).filter(Boolean);
1231
+ const sessions = new Map;
1232
+ for (const line of lines) {
1233
+ try {
1234
+ const obj = JSON.parse(line);
1235
+ if (!obj.session_id || !obj.text)
1236
+ continue;
1237
+ if (!sessions.has(obj.session_id))
1238
+ sessions.set(obj.session_id, []);
1239
+ sessions.get(obj.session_id).push({ ts: obj.ts, text: obj.text });
1240
+ } catch {
1241
+ continue;
1242
+ }
1243
+ }
1244
+ for (const [sessionId, entries] of sessions) {
1245
+ entries.sort((a, b) => a.ts - b.ts);
1246
+ const date = new Date(entries[0].ts * 1000).toISOString().slice(0, 10);
1247
+ let project = null;
1248
+ const cleanEntries = [];
1249
+ for (const e of entries) {
1250
+ let text = cleanText(e.text);
1251
+ if (isCodexBoilerplate(text))
1252
+ continue;
1253
+ const env = stripEnvironmentContext(text);
1254
+ text = env.text;
1255
+ if (!project && env.cwd)
1256
+ project = projectFromCwd(env.cwd);
1257
+ if (text.length === 0)
1258
+ continue;
1259
+ cleanEntries.push(text.length > 300 ? text.slice(0, 300) + "..." : text);
1260
+ }
1261
+ const body = cleanEntries.filter(Boolean).join(`
1262
+
1263
+ ---
1264
+
1265
+ `);
1266
+ let content = `# Codex Chat | ${date}
1267
+
1268
+ ${body}`;
1269
+ if (content.length > MAX_CONTENT2)
1270
+ content = content.slice(0, MAX_CONTENT2) + `
1271
+
1272
+ [truncated]`;
1273
+ if (content.length < 100) {
1274
+ filtered++;
1275
+ continue;
1276
+ }
1277
+ const contentHash = createContentHash(content);
1278
+ const dedupKey = `codex:${sessionId}`;
1279
+ const fingerprint = `${dedupKey}:${contentHash}`;
1280
+ if (isIngested("codex", fingerprint)) {
1281
+ deduped++;
1282
+ continue;
1283
+ }
1284
+ memories.push({
1285
+ content,
1286
+ containerTag: "codex-chats",
1287
+ metadata: {
1288
+ dedupKey,
1289
+ contentHash,
1290
+ source: "codex",
1291
+ sessionId,
1292
+ date,
1293
+ ...project ? { project } : {}
1294
+ }
1295
+ });
1296
+ sessionIds.push(sessionId);
1297
+ }
1298
+ } catch {}
1299
+ }
1300
+ const sessionsDir = join4(homedir4(), ".codex", "sessions");
1301
+ if (existsSync3(sessionsDir)) {
1527
1302
  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
- }
1303
+ const stats = { filtered: 0, deduped: 0 };
1304
+ walkCodexSessions(sessionsDir, memories, sessionIds, stats);
1305
+ filtered += stats.filtered;
1306
+ deduped += stats.deduped;
1307
+ } catch {}
1532
1308
  }
1309
+ return { memories, sessionIds, skipped: filtered + deduped, filtered, deduped };
1533
1310
  }
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}`;
1311
+ function walkCodexSessions(dir, memories, sessionIds, stats) {
1544
1312
  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(`
1313
+ for (const entry of readdirSync3(dir, { withFileTypes: true })) {
1314
+ if (entry.isDirectory()) {
1315
+ walkCodexSessions(join4(dir, entry.name), memories, sessionIds, stats);
1316
+ } else if (entry.name.endsWith(".jsonl")) {
1317
+ const sessionId = basename2(entry.name, ".jsonl");
1318
+ if (sessionIds.includes(sessionId))
1319
+ continue;
1320
+ try {
1321
+ const lines = readFileSync3(join4(dir, entry.name), "utf-8").split(`
1322
+ `).filter(Boolean);
1323
+ let date = null;
1324
+ let project = null;
1325
+ const rounds = [];
1326
+ let currentUser = null;
1327
+ let currentAssistant = [];
1328
+ for (const line of lines) {
1329
+ try {
1330
+ const obj = JSON.parse(line);
1331
+ if (!date && obj.timestamp)
1332
+ date = obj.timestamp.slice(0, 10);
1333
+ if (obj.type === "session_meta" && obj.payload?.cwd) {
1334
+ project = projectFromCwd(obj.payload.cwd);
1335
+ }
1336
+ if (obj.type !== "response_item" || obj.payload?.type !== "message")
1337
+ continue;
1338
+ const role = obj.payload.role;
1339
+ const msgContent = obj.payload.content;
1340
+ if (!Array.isArray(msgContent))
1341
+ continue;
1342
+ if (role === "user") {
1343
+ for (const block of msgContent) {
1344
+ if (block.type === "input_text" && block.text) {
1345
+ const text = cleanText(block.text);
1346
+ if (isCodexBoilerplate(text))
1347
+ continue;
1348
+ if (text.length >= 50) {
1349
+ if (currentUser !== null && currentAssistant.length > 0) {
1350
+ rounds.push({ user: currentUser, assistantParts: currentAssistant });
1351
+ }
1352
+ currentUser = text;
1353
+ currentAssistant = [];
1354
+ }
1355
+ }
1356
+ }
1357
+ } else if (role === "assistant") {
1358
+ for (const block of msgContent) {
1359
+ if (block.type === "output_text" && block.text) {
1360
+ const text = cleanText(block.text);
1361
+ if (!isNarration(text)) {
1362
+ currentAssistant.push(text);
1363
+ }
1364
+ }
1365
+ }
1366
+ }
1367
+ } catch {
1368
+ continue;
1369
+ }
1370
+ }
1371
+ if (currentUser !== null && currentAssistant.length > 0) {
1372
+ rounds.push({ user: currentUser, assistantParts: currentAssistant });
1373
+ }
1374
+ if (rounds.length === 0) {
1375
+ stats.filtered++;
1376
+ continue;
1377
+ }
1378
+ const body = rounds.map((r) => {
1379
+ const q = r.user.length > 300 ? r.user.slice(0, 300) + "..." : r.user;
1380
+ const assistant = r.assistantParts.join(`
1381
+
1548
1382
  `);
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"] });
1556
- }
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
- 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) {
1597
- 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}
1383
+ return `## Q: ${q}
1384
+
1385
+ ${assistant}`;
1386
+ }).join(`
1387
+
1388
+ ---
1389
+
1604
1390
  `);
1605
- return `Global command: conare (added ~/.conare/bin to ${shellProfile} restart shell)`;
1606
- }
1607
- return "Global command: conare (via ~/.conare/bin in PATH)";
1608
- } catch {
1609
- return `Global command: add ~/.conare/bin to your PATH manually`;
1391
+ let content = `# Codex Session${project ? `: ${project}` : ""} | ${date || "unknown"}
1392
+
1393
+ ${body}`;
1394
+ if (content.length > MAX_CONTENT2)
1395
+ content = content.slice(0, MAX_CONTENT2) + `
1396
+
1397
+ [truncated]`;
1398
+ const contentHash = createContentHash(content);
1399
+ const dedupKey = `codex:${sessionId}`;
1400
+ const fingerprint = `${dedupKey}:${contentHash}`;
1401
+ if (isIngested("codex", fingerprint)) {
1402
+ stats.deduped++;
1403
+ continue;
1404
+ }
1405
+ memories.push({
1406
+ content,
1407
+ containerTag: "codex-chats",
1408
+ metadata: {
1409
+ dedupKey,
1410
+ contentHash,
1411
+ source: "codex-session",
1412
+ sessionId,
1413
+ date: date || "unknown",
1414
+ ...project ? { project } : {}
1415
+ }
1416
+ });
1417
+ sessionIds.push(sessionId);
1418
+ } catch {}
1610
1419
  }
1611
1420
  }
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");
1625
- }
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;
1421
+ } catch {}
1631
1422
  }
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)`);
1423
+
1424
+ // src/ingest/cursor.ts
1425
+ import { readFileSync as readFileSync4, statSync } from "node:fs";
1426
+ import { join as join5 } from "node:path";
1427
+ import { createRequire as createRequire2 } from "node:module";
1428
+ var MAX_CONTENT3 = 48000;
1429
+ var MAX_DB_SIZE = 2 * 1024 * 1024 * 1024;
1430
+ var WARN_DB_SIZE = 500 * 1024 * 1024;
1431
+ var MIN_TURN_LEN2 = 50;
1432
+ function loadSqlJs(wasmDir) {
1433
+ try {
1434
+ if (wasmDir) {
1435
+ const require2 = createRequire2(join5(wasmDir, "sql.js", "package.json"));
1436
+ return require2("sql.js");
1649
1437
  } else {
1650
- setupLinuxCron(intervalMinutes);
1651
- messages.push(`Installed cron job (every ${intervalMinutes} min)`);
1438
+ const require2 = createRequire2(import.meta.url);
1439
+ return require2("sql.js");
1440
+ }
1441
+ } catch {
1442
+ return null;
1443
+ }
1444
+ }
1445
+ function openDb(initSqlJs, dbPath, wasmDir) {
1446
+ const locateOpts = {};
1447
+ if (wasmDir) {
1448
+ locateOpts.locateFile = (file) => join5(wasmDir, "sql.js", "dist", file);
1449
+ }
1450
+ return initSqlJs(locateOpts).then((SQL) => {
1451
+ const buffer = readFileSync4(dbPath);
1452
+ return new SQL.Database(buffer);
1453
+ });
1454
+ }
1455
+ function extractTurns(db, composerId, bubbleHeaders) {
1456
+ const turns = [];
1457
+ let pendingUser = null;
1458
+ for (const header of bubbleHeaders) {
1459
+ let text = "";
1460
+ try {
1461
+ const result = db.exec(`SELECT value FROM cursorDiskKV WHERE key = 'bubbleId:${composerId}:${header.bubbleId}'`);
1462
+ if (result.length > 0) {
1463
+ const bubble = JSON.parse(result[0].values[0][0]);
1464
+ text = cleanText(bubble.text || "");
1465
+ }
1466
+ } catch {
1467
+ continue;
1468
+ }
1469
+ if (text.length < MIN_TURN_LEN2)
1470
+ continue;
1471
+ if (header.type === 1) {
1472
+ pendingUser = text;
1473
+ } else if (header.type === 2 && pendingUser) {
1474
+ turns.push({ user: pendingUser, assistant: text });
1475
+ pendingUser = null;
1652
1476
  }
1653
- } else {
1654
- messages.push(`Unsupported platform: ${os}. Run manually: ~/.conare/bin/run.sh`);
1655
1477
  }
1656
- return messages;
1478
+ return turns;
1657
1479
  }
1658
- function uninstallSync() {
1659
- const messages = [];
1660
- const os = platform2();
1661
- if (os === "darwin") {
1480
+ async function ingestCursor(dbPath, wasmDir) {
1481
+ const memories = [];
1482
+ const sessionIds = [];
1483
+ let filtered = 0;
1484
+ let deduped = 0;
1485
+ let fileSize;
1486
+ try {
1487
+ fileSize = statSync(dbPath).size;
1488
+ } catch {
1489
+ console.log(" Skipping Cursor: database not accessible");
1490
+ return { memories, sessionIds, skipped: 0, filtered, deduped };
1491
+ }
1492
+ if (fileSize > MAX_DB_SIZE) {
1493
+ console.log(` Skipping Cursor: database too large (${(fileSize / 1024 / 1024 / 1024).toFixed(1)}GB)`);
1494
+ return { memories, sessionIds, skipped: 0, filtered, deduped };
1495
+ }
1496
+ if (fileSize > WARN_DB_SIZE) {
1497
+ console.log(` Warning: large database (${(fileSize / 1024 / 1024).toFixed(0)}MB), loading into memory...`);
1498
+ }
1499
+ const initSqlJs = loadSqlJs(wasmDir);
1500
+ if (!initSqlJs) {
1501
+ console.log(" Skipping Cursor: sql.js not available");
1502
+ return { memories, sessionIds, skipped: 0, filtered, deduped };
1503
+ }
1504
+ let db;
1505
+ try {
1506
+ db = await openDb(initSqlJs, dbPath, wasmDir);
1507
+ } catch (e) {
1508
+ console.log(` Skipping Cursor: cannot open database (${e.message})`);
1509
+ return { memories, sessionIds, skipped: 0, filtered, deduped };
1510
+ }
1511
+ try {
1512
+ let rows = [];
1662
1513
  try {
1663
- execSync(`launchctl bootout gui/${uid()} "${PLIST_PATH}" 2>/dev/null`, { stdio: "ignore" });
1514
+ const results = db.exec("SELECT key, value FROM cursorDiskKV WHERE key LIKE 'composerData:%'");
1515
+ if (results.length > 0)
1516
+ rows = results[0].values;
1664
1517
  } catch {}
1665
- if (existsSync7(PLIST_PATH)) {
1666
- unlinkSync(PLIST_PATH);
1667
- messages.push("Removed launchd agent");
1668
- }
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);
1678
- try {
1679
- execSync("systemctl --user daemon-reload", { stdio: "ignore" });
1680
- } catch {}
1681
- messages.push("Removed systemd timer");
1682
- } else {
1518
+ for (const [key, value] of rows) {
1519
+ const composerId = key.replace("composerData:", "");
1520
+ let parsed;
1683
1521
  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(`
1522
+ parsed = JSON.parse(value);
1523
+ if (!parsed || typeof parsed !== "object") {
1524
+ filtered++;
1525
+ continue;
1526
+ }
1527
+ } catch {
1528
+ filtered++;
1529
+ continue;
1530
+ }
1531
+ const bubbleHeaders = parsed.fullConversationHeadersOnly;
1532
+ if (!Array.isArray(bubbleHeaders) || bubbleHeaders.length === 0) {
1533
+ filtered++;
1534
+ continue;
1535
+ }
1536
+ const turns = extractTurns(db, composerId, bubbleHeaders);
1537
+ if (turns.length === 0) {
1538
+ filtered++;
1539
+ continue;
1540
+ }
1541
+ const sessionName = parsed.name || "Cursor Chat";
1542
+ const date = parsed.createdAt ? new Date(parsed.createdAt).toISOString().slice(0, 10) : "unknown";
1543
+ const header = `# ${sessionName} | ${date}`;
1544
+ const body = turns.map((t) => {
1545
+ const q = t.user.length > 300 ? t.user.slice(0, 300) + "..." : t.user;
1546
+ return `## Q: ${q}
1547
+
1548
+ ${t.assistant}`;
1549
+ }).join(`
1550
+
1551
+ ---
1552
+
1687
1553
  `);
1688
- execSync("crontab -", { input: filtered.trim() + `
1689
- `, stdio: ["pipe", "ignore", "ignore"] });
1690
- messages.push("Removed cron job");
1691
- } catch {}
1554
+ let content = `${header}
1555
+
1556
+ ${body}`;
1557
+ if (content.length > MAX_CONTENT3)
1558
+ content = content.slice(0, MAX_CONTENT3) + `
1559
+
1560
+ [truncated]`;
1561
+ const contentHash = createContentHash(content);
1562
+ const dedupKey = `cursor:${composerId}`;
1563
+ const fingerprint = `${dedupKey}:${contentHash}`;
1564
+ if (isIngested("cursor", fingerprint)) {
1565
+ deduped++;
1566
+ continue;
1567
+ }
1568
+ memories.push({
1569
+ content,
1570
+ containerTag: "cursor-chats",
1571
+ metadata: {
1572
+ dedupKey,
1573
+ contentHash,
1574
+ source: "cursor",
1575
+ sessionId: composerId,
1576
+ name: sessionName,
1577
+ date
1578
+ }
1579
+ });
1580
+ sessionIds.push(composerId);
1581
+ }
1582
+ } catch (e) {
1583
+ console.log(` Cursor ingestion error: ${e.message}`);
1584
+ } finally {
1585
+ db.close();
1586
+ }
1587
+ return { memories, sessionIds, skipped: filtered + deduped, filtered, deduped };
1588
+ }
1589
+
1590
+ // src/ingest/codebase.ts
1591
+ import { createHash as createHash2 } from "node:crypto";
1592
+ import { readdirSync as readdirSync4, readFileSync as readFileSync5, statSync as statSync2, existsSync as existsSync4 } from "node:fs";
1593
+ import { join as join6, relative, extname, resolve } from "node:path";
1594
+ var DEFAULT_IGNORE = new Set([
1595
+ "node_modules",
1596
+ ".git",
1597
+ ".next",
1598
+ ".nuxt",
1599
+ ".output",
1600
+ "dist",
1601
+ "build",
1602
+ ".cache",
1603
+ "__pycache__",
1604
+ ".venv",
1605
+ "venv",
1606
+ "vendor",
1607
+ "target",
1608
+ ".turbo",
1609
+ ".DS_Store",
1610
+ ".claude",
1611
+ ".conare"
1612
+ ]);
1613
+ var IGNORE_FILES = new Set([
1614
+ "package-lock.json",
1615
+ "bun.lockb",
1616
+ "yarn.lock",
1617
+ "pnpm-lock.yaml"
1618
+ ]);
1619
+ var CODE_EXTENSIONS = new Set([
1620
+ ".ts",
1621
+ ".tsx",
1622
+ ".js",
1623
+ ".jsx",
1624
+ ".mjs",
1625
+ ".cjs",
1626
+ ".vue",
1627
+ ".svelte",
1628
+ ".astro",
1629
+ ".py",
1630
+ ".rb",
1631
+ ".go",
1632
+ ".rs",
1633
+ ".java",
1634
+ ".kt",
1635
+ ".swift",
1636
+ ".c",
1637
+ ".cpp",
1638
+ ".h",
1639
+ ".css",
1640
+ ".scss",
1641
+ ".less",
1642
+ ".html",
1643
+ ".json",
1644
+ ".yaml",
1645
+ ".yml",
1646
+ ".toml",
1647
+ ".md",
1648
+ ".mdx",
1649
+ ".txt",
1650
+ ".sql",
1651
+ ".graphql",
1652
+ ".prisma",
1653
+ ".sh",
1654
+ ".bash",
1655
+ ".zsh",
1656
+ ".lua",
1657
+ ".zig",
1658
+ ".ex",
1659
+ ".exs"
1660
+ ]);
1661
+ var SPECIAL_FILES = new Set([
1662
+ "Dockerfile",
1663
+ "Makefile",
1664
+ "Procfile",
1665
+ "Justfile",
1666
+ ".gitignore",
1667
+ ".dockerignore",
1668
+ "CLAUDE.md",
1669
+ "AGENTS.md",
1670
+ "README.md",
1671
+ "ARCHITECTURE.md",
1672
+ "wrangler.toml",
1673
+ "wrangler.json"
1674
+ ]);
1675
+ var MAX_FILE_SIZE = 1e5;
1676
+ function parseGitignore(rootPath) {
1677
+ const patterns = new Set;
1678
+ const gitignorePath = join6(rootPath, ".gitignore");
1679
+ if (!existsSync4(gitignorePath))
1680
+ return patterns;
1681
+ try {
1682
+ const content = readFileSync5(gitignorePath, "utf-8");
1683
+ for (const line of content.split(`
1684
+ `)) {
1685
+ const trimmed = line.trim();
1686
+ if (!trimmed || trimmed.startsWith("#"))
1687
+ continue;
1688
+ patterns.add(trimmed.replace(/\/$/, ""));
1692
1689
  }
1693
- }
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;
1710
- }
1711
-
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, "");
1690
+ } catch {}
1691
+ return patterns;
1731
1692
  }
1732
- function L(e) {
1733
- return e && e.__esModule && Object.prototype.hasOwnProperty.call(e, "default") ? e.default : e;
1693
+ function shouldIgnore(name, ignorePatterns) {
1694
+ if (DEFAULT_IGNORE.has(name))
1695
+ return true;
1696
+ if (IGNORE_FILES.has(name))
1697
+ return true;
1698
+ if (name.startsWith(".env"))
1699
+ return true;
1700
+ if (ignorePatterns.has(name))
1701
+ return true;
1702
+ return false;
1734
1703
  }
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;
1704
+ function langFromExt(ext) {
1705
+ const map = {
1706
+ ".ts": "typescript",
1707
+ ".tsx": "tsx",
1708
+ ".js": "javascript",
1709
+ ".jsx": "jsx",
1710
+ ".mjs": "javascript",
1711
+ ".cjs": "javascript",
1712
+ ".vue": "vue",
1713
+ ".svelte": "svelte",
1714
+ ".astro": "astro",
1715
+ ".py": "python",
1716
+ ".rb": "ruby",
1717
+ ".go": "go",
1718
+ ".rs": "rust",
1719
+ ".java": "java",
1720
+ ".kt": "kotlin",
1721
+ ".swift": "swift",
1722
+ ".c": "c",
1723
+ ".cpp": "cpp",
1724
+ ".h": "c",
1725
+ ".css": "css",
1726
+ ".scss": "scss",
1727
+ ".less": "less",
1728
+ ".html": "html",
1729
+ ".json": "json",
1730
+ ".yaml": "yaml",
1731
+ ".yml": "yaml",
1732
+ ".toml": "toml",
1733
+ ".md": "markdown",
1734
+ ".mdx": "mdx",
1735
+ ".sql": "sql",
1736
+ ".graphql": "graphql",
1737
+ ".prisma": "prisma",
1738
+ ".sh": "bash",
1739
+ ".bash": "bash",
1740
+ ".zsh": "zsh",
1741
+ ".lua": "lua",
1742
+ ".zig": "zig",
1743
+ ".ex": "elixir",
1744
+ ".exs": "elixir"
1764
1745
  };
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;
1792
- }
1793
- }
1794
- return F;
1746
+ return map[ext] || ext.slice(1);
1795
1747
  }
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 });
1811
- }
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;
1748
+ function formatFile(relPath, content, ext) {
1749
+ const lang = langFromExt(ext);
1750
+ return `# File: ${relPath}
1751
+
1752
+ \`\`\`${lang}
1753
+ ${content}
1754
+ \`\`\``;
1839
1755
  }
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);
1861
- }
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;
1756
+ function indexCodebase(rootPath) {
1757
+ const absRoot = resolve(rootPath);
1758
+ const repoHash = createHash2("sha256").update(absRoot).digest("hex").slice(0, 12);
1759
+ const gitignorePatterns = parseGitignore(absRoot);
1760
+ const memories = [];
1761
+ let fileCount = 0;
1762
+ let skipped = 0;
1763
+ function walk(dir) {
1764
+ let entries;
1765
+ try {
1766
+ entries = readdirSync4(dir, { withFileTypes: true });
1767
+ } catch {
1768
+ return;
1884
1769
  }
1885
- if (o + D[E] > u && o > 0 && D[E] > 0) {
1886
- if (t.wordWrap === false && o < u) {
1887
- k(C, a, u);
1770
+ for (const entry of entries) {
1771
+ if (shouldIgnore(entry.name, gitignorePatterns))
1772
+ continue;
1773
+ const fullPath = join6(dir, entry.name);
1774
+ if (entry.isDirectory()) {
1775
+ walk(fullPath);
1776
+ continue;
1777
+ }
1778
+ if (!entry.isFile())
1779
+ continue;
1780
+ const ext = extname(entry.name).toLowerCase();
1781
+ if (!CODE_EXTENSIONS.has(ext) && !SPECIAL_FILES.has(entry.name))
1782
+ continue;
1783
+ let stat;
1784
+ try {
1785
+ stat = statSync2(fullPath);
1786
+ } catch {
1787
+ continue;
1788
+ }
1789
+ if (stat.size > MAX_FILE_SIZE || stat.size === 0) {
1790
+ skipped++;
1791
+ continue;
1792
+ }
1793
+ let raw;
1794
+ try {
1795
+ raw = readFileSync5(fullPath, "utf-8");
1796
+ } catch {
1797
+ skipped++;
1798
+ continue;
1799
+ }
1800
+ if (raw.includes("\x00")) {
1801
+ skipped++;
1802
+ continue;
1803
+ }
1804
+ const relPath = relative(absRoot, fullPath);
1805
+ const contentHash = createContentHash(raw);
1806
+ const dedupKey = `codebase:${repoHash}:${relPath}`;
1807
+ const fingerprint = `${dedupKey}:${contentHash}`;
1808
+ if (isIngested("codebase", fingerprint)) {
1809
+ skipped++;
1888
1810
  continue;
1889
1811
  }
1890
- C.push("");
1891
- }
1892
- if (o + D[E] > u && t.wordWrap === false) {
1893
- k(C, a, u);
1894
- continue;
1812
+ const content = formatFile(relPath, raw, ext);
1813
+ memories.push({
1814
+ content,
1815
+ containerTag: "codebase",
1816
+ metadata: {
1817
+ dedupKey,
1818
+ contentHash,
1819
+ source: "codebase-index",
1820
+ repoHash,
1821
+ filePath: relPath,
1822
+ fileHash: `${relPath}:${contentHash}`,
1823
+ language: langFromExt(ext)
1824
+ }
1825
+ });
1826
+ fileCount++;
1895
1827
  }
1896
- C[C.length - 1] += a;
1897
1828
  }
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);
1829
+ walk(absRoot);
1830
+ return { memories, fileCount, skipped };
1831
+ }
1832
+
1833
+ // src/api.ts
1834
+ var API_URL = "https://mcp.conare.ai";
1835
+ function createUploadBatches(memories, maxItems = 50, maxChars = 1500000) {
1836
+ const batches = [];
1837
+ let current = [];
1838
+ let currentChars = 0;
1839
+ let startIndex = 0;
1840
+ for (let i = 0;i < memories.length; i++) {
1841
+ const item = memories[i];
1842
+ const itemChars = item.content.length;
1843
+ const exceedsBatch = current.length > 0 && (current.length >= maxItems || currentChars + itemChars > maxChars);
1844
+ if (exceedsBatch) {
1845
+ batches.push({ startIndex, items: current });
1846
+ current = [];
1847
+ currentChars = 0;
1848
+ startIndex = i;
1909
1849
  }
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)));
1850
+ current.push(item);
1851
+ currentChars += itemChars;
1914
1852
  }
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;
1853
+ if (current.length > 0) {
1854
+ batches.push({ startIndex, items: current });
1855
+ }
1856
+ return batches;
1932
1857
  }
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;
1858
+ async function validateKey(apiKey) {
1859
+ try {
1860
+ const res = await fetch(`${API_URL}/api/auth/me`, {
1861
+ headers: { Authorization: `Bearer ${apiKey}` }
1862
+ });
1863
+ if (!res.ok)
1864
+ return { valid: false };
1865
+ const data = await res.json();
1866
+ return { valid: true, email: data.user.email, name: data.user.name };
1867
+ } catch {
1868
+ return { valid: false };
1869
+ }
1942
1870
  }
1943
- var AD = globalThis.process.platform.startsWith("win");
1944
- var S = Symbol("clack:cancel");
1945
- function pD(e) {
1946
- return e === S;
1871
+ async function getRemoteMemoryCount(apiKey) {
1872
+ try {
1873
+ const res = await fetch(`${API_URL}/api/containers`, {
1874
+ headers: { Authorization: `Bearer ${apiKey}` }
1875
+ });
1876
+ if (!res.ok)
1877
+ return null;
1878
+ const data = await res.json();
1879
+ if (!Array.isArray(data.containers))
1880
+ return 0;
1881
+ return data.containers.reduce((sum, container) => sum + (container.count || 0), 0);
1882
+ } catch {
1883
+ return null;
1884
+ }
1947
1885
  }
1948
- function m(e, u) {
1949
- const t = e;
1950
- t.isTTY && t.setRawMode(u);
1886
+ async function uploadItems(apiKey, items, asyncEmbed = false) {
1887
+ let retries = 4;
1888
+ while (retries > 0) {
1889
+ try {
1890
+ const res = await fetch(`${API_URL}/api/memories/bulk`, {
1891
+ method: "POST",
1892
+ headers: {
1893
+ "Content-Type": "application/json",
1894
+ Authorization: `Bearer ${apiKey}`
1895
+ },
1896
+ body: JSON.stringify(asyncEmbed ? { items, async: true } : items)
1897
+ });
1898
+ if (res.status === 429) {
1899
+ retries--;
1900
+ await new Promise((r) => setTimeout(r, 5000));
1901
+ continue;
1902
+ }
1903
+ if (!res.ok) {
1904
+ const body = await res.text().catch(() => "");
1905
+ throw new Error(`HTTP ${res.status}: ${body.slice(0, 120)}`);
1906
+ }
1907
+ const data = await res.json();
1908
+ if (!Array.isArray(data.results) || data.results.length !== items.length) {
1909
+ throw new Error("Unexpected bulk upload response");
1910
+ }
1911
+ return data.results;
1912
+ } catch (error) {
1913
+ retries--;
1914
+ if (retries === 0) {
1915
+ return items.map(() => ({
1916
+ success: false,
1917
+ error: error instanceof Error ? error.message : String(error)
1918
+ }));
1919
+ }
1920
+ await new Promise((r) => setTimeout(r, 2000));
1921
+ }
1922
+ }
1923
+ return items.map(() => ({ success: false, error: "Upload failed" }));
1951
1924
  }
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;
1925
+ async function uploadBulk(apiKey, memories, onProgress) {
1926
+ let success = 0;
1927
+ let failed = 0;
1928
+ const total = memories.length;
1929
+ const results = [];
1930
+ const batches = createUploadBatches(memories);
1931
+ for (const batch of batches) {
1932
+ let batchResults = await uploadItems(apiKey, batch.items, true);
1933
+ if (batch.items.length > 1 && batchResults.some((result) => !result.success)) {
1934
+ const retriedResults = [];
1935
+ for (let i = 0;i < batch.items.length; i++) {
1936
+ const result = batchResults[i];
1937
+ if (result.success) {
1938
+ retriedResults.push(result);
1939
+ continue;
1940
+ }
1941
+ const [singleResult] = await uploadItems(apiKey, [batch.items[i]], true);
1942
+ retriedResults.push(singleResult);
1943
+ }
1944
+ batchResults = retriedResults;
1960
1945
  }
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);
1946
+ for (let i = 0;i < batchResults.length; i++) {
1947
+ const result = batchResults[i];
1948
+ results.push({
1949
+ index: batch.startIndex + i,
1950
+ success: result.success,
1951
+ deduped: result.deduped,
1952
+ error: result.error
1967
1953
  });
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();
1972
- };
1954
+ if (result.success)
1955
+ success++;
1956
+ else
1957
+ failed++;
1958
+ }
1959
+ onProgress?.(success + failed, total, failed);
1960
+ }
1961
+ return { success, failed, results };
1973
1962
  }
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
1963
 
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();
1964
+ // src/configure.ts
1965
+ import { existsSync as existsSync5, mkdirSync as mkdirSync2, readFileSync as readFileSync6, writeFileSync as writeFileSync2 } from "node:fs";
1966
+ import { dirname, join as join7 } from "node:path";
1967
+ import { homedir as homedir5 } from "node:os";
1968
+ import { spawnSync as spawnSync2 } from "node:child_process";
1969
+ var CONARE_URL = "https://mcp.conare.ai";
1970
+ var SERVER_NAME = "conare-memory";
1971
+ var MCP_TARGETS = [
1972
+ { id: "claude", label: "Claude Code" },
1973
+ { id: "cursor", label: "Cursor" },
1974
+ { id: "codex", label: "Codex" },
1975
+ { id: "openclaw", label: "OpenClaw" }
1976
+ ];
1977
+ function readJsonFile(path) {
1978
+ try {
1979
+ return JSON.parse(readFileSync6(path, "utf-8"));
1980
+ } catch {
1981
+ return {};
1986
1982
  }
1987
- setSubscriber(u, t) {
1988
- const F = this._subscribers.get(u) ?? [];
1989
- F.push(t), this._subscribers.set(u, F);
1983
+ }
1984
+ function writeJsonFile(path, data) {
1985
+ mkdirSync2(dirname(path), { recursive: true });
1986
+ writeFileSync2(path, JSON.stringify(data, null, 2) + `
1987
+ `);
1988
+ }
1989
+ function getServerConfig(apiKey) {
1990
+ return {
1991
+ type: "http",
1992
+ url: `${CONARE_URL}/mcp`,
1993
+ headers: {
1994
+ Authorization: `Bearer ${apiKey}`
1995
+ }
1996
+ };
1997
+ }
1998
+ function upsertMcpServer(path, apiKey) {
1999
+ const config = readJsonFile(path);
2000
+ if (!config.mcpServers || typeof config.mcpServers !== "object") {
2001
+ config.mcpServers = {};
1990
2002
  }
1991
- on(u, t) {
1992
- this.setSubscriber(u, { cb: t });
2003
+ config.mcpServers[SERVER_NAME] = getServerConfig(apiKey);
2004
+ writeJsonFile(path, config);
2005
+ }
2006
+ function configureClaude(apiKey) {
2007
+ const claudeConfigPath = join7(homedir5(), ".claude.json");
2008
+ const claudeMcpPath = join7(homedir5(), ".claude", "mcp.json");
2009
+ if (spawnSync2("claude", ["mcp", "add-json", SERVER_NAME, "--scope", "user", JSON.stringify(getServerConfig(apiKey))], {
2010
+ stdio: "ignore"
2011
+ }).status === 0) {
2012
+ return "Claude Code configured via `claude mcp add-json`";
1993
2013
  }
1994
- once(u, t) {
1995
- this.setSubscriber(u, { cb: t, once: true });
2014
+ upsertMcpServer(claudeConfigPath, apiKey);
2015
+ if (existsSync5(join7(homedir5(), ".claude"))) {
2016
+ upsertMcpServer(claudeMcpPath, apiKey);
1996
2017
  }
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();
2018
+ return `Claude Code configured at ${claudeConfigPath}`;
2019
+ }
2020
+ function configureJsonClient(path, apiKey, label) {
2021
+ upsertMcpServer(path, apiKey);
2022
+ return `${label} configured at ${path}`;
2023
+ }
2024
+ function configureMcp(apiKey, targets = ["claude", "cursor", "codex"]) {
2025
+ const results = [];
2026
+ if (targets.includes("claude")) {
2027
+ results.push(configureClaude(apiKey));
2003
2028
  }
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
- });
2029
+ if (targets.includes("cursor")) {
2030
+ results.push(configureJsonClient(join7(homedir5(), ".cursor", "mcp.json"), apiKey, "Cursor"));
2022
2031
  }
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();
2032
+ if (targets.includes("codex")) {
2033
+ results.push(configureJsonClient(join7(homedir5(), ".codex", "mcp.json"), apiKey, "Codex"));
2032
2034
  }
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();
2035
+ if (targets.includes("openclaw")) {
2036
+ results.push(configureJsonClient(join7(homedir5(), ".openclaw", "mcp.json"), apiKey, "OpenClaw"));
2036
2037
  }
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));
2038
+ return results;
2039
+ }
2040
+
2041
+ // src/config.ts
2042
+ import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync7, writeFileSync as writeFileSync3 } from "node:fs";
2043
+ import { join as join8 } from "node:path";
2044
+ import { homedir as homedir6 } from "node:os";
2045
+ var CONFIG_DIR = join8(homedir6(), ".conare");
2046
+ var CONFIG_PATH = join8(CONFIG_DIR, "config.json");
2047
+ function readConfig() {
2048
+ try {
2049
+ if (!existsSync6(CONFIG_PATH))
2050
+ return {};
2051
+ return JSON.parse(readFileSync7(CONFIG_PATH, "utf-8"));
2052
+ } catch {
2053
+ return {};
2041
2054
  }
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(`
2055
+ }
2056
+ function saveApiKey(apiKey) {
2057
+ mkdirSync3(CONFIG_DIR, { recursive: true });
2058
+ writeFileSync3(CONFIG_PATH, JSON.stringify({ apiKey }, null, 2) + `
2053
2059
  `);
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
- }
2060
+ }
2061
+ function getSavedApiKey() {
2062
+ return readConfig().apiKey;
2071
2063
  }
2072
2064
 
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
- });
2065
+ // src/sync.ts
2066
+ import { existsSync as existsSync7, mkdirSync as mkdirSync4, writeFileSync as writeFileSync4, unlinkSync, readFileSync as readFileSync8, chmodSync, cpSync, rmSync, symlinkSync, readlinkSync, appendFileSync } from "node:fs";
2067
+ import { join as join9, dirname as dirname2 } from "node:path";
2068
+ import { homedir as homedir7, platform as platform2 } from "node:os";
2069
+ import { execSync } from "node:child_process";
2070
+ var CONARE_DIR = join9(homedir7(), ".conare");
2071
+ var BIN_DIR = join9(CONARE_DIR, "bin");
2072
+ var CONFIG_PATH2 = join9(CONARE_DIR, "config.json");
2073
+ var PLIST_LABEL = "ai.conare.ingest";
2074
+ var PLIST_PATH = join9(homedir7(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
2075
+ var SYSTEMD_DIR = join9(homedir7(), ".config", "systemd", "user");
2076
+ var SYSTEMD_SERVICE = join9(SYSTEMD_DIR, "conare-sync.service");
2077
+ var SYSTEMD_TIMER = join9(SYSTEMD_DIR, "conare-sync.timer");
2078
+ var RUN_SH = `#!/bin/bash
2079
+ # Conare Memory — background sync wrapper
2080
+ # Resolves node at runtime to survive nvm/fnm upgrades
2081
+
2082
+ CONARE_DIR="$HOME/.conare"
2083
+ LOCKFILE="$CONARE_DIR/sync.lock"
2084
+ LOG="$CONARE_DIR/ingest.log"
2085
+
2086
+ # Log rotation: truncate if > 1MB
2087
+ if [ -f "$LOG" ] && [ "$(wc -c < "$LOG" 2>/dev/null)" -gt 1048576 ]; then
2088
+ tail -100 "$LOG" > "$LOG.tmp" && mv "$LOG.tmp" "$LOG"
2089
+ fi
2090
+
2091
+ # File lock: prevent concurrent runs
2092
+ # macOS doesn't have flock — use mkdir as atomic lock
2093
+ if ! mkdir "$LOCKFILE.d" 2>/dev/null; then
2094
+ # Check if stale (older than 30 min)
2095
+ if [ "$(uname)" = "Darwin" ]; then
2096
+ LOCK_AGE=$(( $(date +%s) - $(stat -f %m "$LOCKFILE.d" 2>/dev/null || echo 0) ))
2097
+ else
2098
+ LOCK_AGE=$(( $(date +%s) - $(stat -c %Y "$LOCKFILE.d" 2>/dev/null || echo 0) ))
2099
+ fi
2100
+ if [ "$LOCK_AGE" -gt 1800 ]; then
2101
+ rm -rf "$LOCKFILE.d"
2102
+ mkdir "$LOCKFILE.d" 2>/dev/null || true
2103
+ else
2104
+ echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) SKIP: another instance running" >> "$LOG"
2105
+ exit 0
2106
+ fi
2107
+ fi
2108
+ trap 'rm -rf "$LOCKFILE.d"' EXIT
2109
+
2110
+ # Resolve node binary
2111
+ resolve_node() {
2112
+ command -v node >/dev/null 2>&1 && { command -v node; return; }
2113
+ if [ -s "$HOME/.nvm/nvm.sh" ]; then
2114
+ . "$HOME/.nvm/nvm.sh" >/dev/null 2>&1
2115
+ command -v node >/dev/null 2>&1 && { command -v node; return; }
2116
+ fi
2117
+ if command -v fnm >/dev/null 2>&1; then
2118
+ eval "$(fnm env)" >/dev/null 2>&1
2119
+ command -v node >/dev/null 2>&1 && { command -v node; return; }
2120
+ fi
2121
+ for p in /opt/homebrew/bin/node /usr/local/bin/node /usr/bin/node; do
2122
+ [ -x "$p" ] && { echo "$p"; return; }
2123
+ done
2124
+ return 1
2125
+ }
2126
+
2127
+ NODE=$(resolve_node)
2128
+ if [ -z "$NODE" ]; then
2129
+ echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) ERROR: node not found" >> "$LOG"
2130
+ exit 1
2131
+ fi
2132
+
2133
+ echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) START sync" >> "$LOG"
2134
+ "$NODE" "$CONARE_DIR/bin/conare-ingest.mjs" \\
2135
+ --config-file "$CONARE_DIR/config.json" \\
2136
+ --ingest-only \\
2137
+ --quiet \\
2138
+ 2>> "$LOG"
2139
+ echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) DONE sync (exit $?)" >> "$LOG"
2140
+ `;
2141
+ function makePlist(intervalMinutes) {
2142
+ const home = homedir7();
2143
+ return `<?xml version="1.0" encoding="UTF-8"?>
2144
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
2145
+ "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
2146
+ <plist version="1.0">
2147
+ <dict>
2148
+ <key>Label</key>
2149
+ <string>${PLIST_LABEL}</string>
2150
+ <key>ProgramArguments</key>
2151
+ <array>
2152
+ <string>/bin/bash</string>
2153
+ <string>${home}/.conare/bin/run.sh</string>
2154
+ </array>
2155
+ <key>StartInterval</key>
2156
+ <integer>${intervalMinutes * 60}</integer>
2157
+ <key>StandardOutPath</key>
2158
+ <string>${home}/.conare/ingest.log</string>
2159
+ <key>StandardErrorPath</key>
2160
+ <string>${home}/.conare/ingest.log</string>
2161
+ <key>RunAtLoad</key>
2162
+ <true/>
2163
+ </dict>
2164
+ </plist>`;
2165
+ }
2166
+ var SYSTEMD_SERVICE_CONTENT = `[Unit]
2167
+ Description=Conare Memory — background sync
2168
+
2169
+ [Service]
2170
+ Type=oneshot
2171
+ ExecStart=%h/.conare/bin/run.sh
2172
+ `;
2173
+ function makeSystemdTimer(intervalMinutes) {
2174
+ return `[Unit]
2175
+ Description=Conare Memory — sync every ${intervalMinutes} minutes
2176
+
2177
+ [Timer]
2178
+ OnBootSec=2min
2179
+ OnUnitActiveSec=${intervalMinutes}min
2180
+ Persistent=true
2181
+
2182
+ [Install]
2183
+ WantedBy=timers.target
2184
+ `;
2185
+ }
2186
+ function hasSystemd() {
2187
+ try {
2188
+ execSync("systemctl --user status 2>/dev/null", { stdio: "ignore" });
2189
+ return true;
2190
+ } catch {
2191
+ return false;
2088
2192
  }
2089
2193
  }
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
- });
2194
+ function uid() {
2195
+ try {
2196
+ return execSync("id -u", { encoding: "utf-8" }).trim();
2197
+ } catch {
2198
+ return "501";
2143
2199
  }
2144
- get cursor() {
2145
- return this._cursor;
2200
+ }
2201
+ function persistBinary(apiKey) {
2202
+ mkdirSync4(BIN_DIR, { recursive: true });
2203
+ const cliEntry = findCliBundle();
2204
+ if (!cliEntry) {
2205
+ throw new Error("Could not locate CLI bundle. Run from an installed conare package.");
2146
2206
  }
2147
- get masked() {
2148
- return this.value.replaceAll(/./g, this._mask);
2207
+ const dest = join9(BIN_DIR, "conare-ingest.mjs");
2208
+ const content = readFileSync8(cliEntry, "utf-8");
2209
+ writeFileSync4(dest, content);
2210
+ const sqlJsDir = findSqlJs();
2211
+ if (sqlJsDir) {
2212
+ const targetDir = join9(BIN_DIR, "node_modules", "sql.js");
2213
+ mkdirSync4(targetDir, { recursive: true });
2214
+ try {
2215
+ cpSync(sqlJsDir, targetDir, { recursive: true });
2216
+ } catch {}
2149
2217
  }
2218
+ const runShPath = join9(BIN_DIR, "run.sh");
2219
+ writeFileSync4(runShPath, RUN_SH);
2220
+ chmodSync(runShPath, 493);
2221
+ writeFileSync4(CONFIG_PATH2, JSON.stringify({ apiKey }, null, 2) + `
2222
+ `);
2150
2223
  }
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";
2158
- }
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);
2224
+ function findCliBundle() {
2225
+ const entry = process.argv[1];
2226
+ if (entry && existsSync7(entry))
2227
+ return entry;
2228
+ const candidates = [
2229
+ join9(dirname2(new URL(import.meta.url).pathname), "index.js"),
2230
+ join9(dirname2(new URL(import.meta.url).pathname), "..", "dist", "index.js")
2231
+ ];
2232
+ for (const c of candidates) {
2233
+ if (existsSync7(c))
2234
+ return c;
2193
2235
  }
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
- `;
2236
+ return null;
2237
+ }
2238
+ function findSqlJs() {
2239
+ const candidates = [
2240
+ join9(process.cwd(), "node_modules", "sql.js"),
2241
+ join9(dirname2(new URL(import.meta.url).pathname), "..", "node_modules", "sql.js"),
2242
+ join9(dirname2(new URL(import.meta.url).pathname), "..", "..", "node_modules", "sql.js")
2243
+ ];
2244
+ for (const c of candidates) {
2245
+ if (existsSync7(c))
2246
+ return c;
2224
2247
  }
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)}
2340
- `);
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`;
2248
+ return null;
2374
2249
  }
2375
- function ensureValue(value) {
2376
- if (pD(value)) {
2377
- xe("Setup cancelled.");
2378
- process.exit(0);
2250
+ function setupMacOS(intervalMinutes) {
2251
+ const plistDir = dirname2(PLIST_PATH);
2252
+ mkdirSync4(plistDir, { recursive: true });
2253
+ writeFileSync4(PLIST_PATH, makePlist(intervalMinutes));
2254
+ const id = uid();
2255
+ try {
2256
+ execSync(`launchctl bootout gui/${id} "${PLIST_PATH}" 2>/dev/null`, { stdio: "ignore" });
2257
+ } catch {}
2258
+ try {
2259
+ execSync(`launchctl bootstrap gui/${id} "${PLIST_PATH}"`, { stdio: "ignore" });
2260
+ } catch {
2261
+ try {
2262
+ execSync(`launchctl load "${PLIST_PATH}"`, { stdio: "ignore" });
2263
+ } catch {
2264
+ throw new Error("Failed to load launchd agent. Try manually: launchctl load " + PLIST_PATH);
2265
+ }
2379
2266
  }
2380
- return value;
2381
- }
2382
- function startSetup() {
2383
- Ie("Conare setup");
2384
- }
2385
- function finishSetup() {
2386
- Se("Starting setup...");
2387
2267
  }
2388
- function showDetectedApps(targets) {
2389
- Me(targets.map((target) => `• ${target.label}: ${target.available === false ? "not detected" : formatDetectedCount(target.detectedCount)}`).join(`
2390
- `), "Detected apps");
2268
+ function setupLinuxSystemd(intervalMinutes) {
2269
+ mkdirSync4(SYSTEMD_DIR, { recursive: true });
2270
+ writeFileSync4(SYSTEMD_SERVICE, SYSTEMD_SERVICE_CONTENT);
2271
+ writeFileSync4(SYSTEMD_TIMER, makeSystemdTimer(intervalMinutes));
2272
+ execSync("systemctl --user daemon-reload", { stdio: "ignore" });
2273
+ execSync("systemctl --user enable --now conare-sync.timer", { stdio: "ignore" });
2391
2274
  }
2392
- async function promptApiKey(options) {
2393
- if (options.providedApiKey) {
2394
- return options.providedApiKey;
2275
+ function setupLinuxCron(intervalMinutes) {
2276
+ const cronCmd = `${homedir7()}/.conare/bin/run.sh`;
2277
+ const cronLine = `*/${intervalMinutes} * * * * ${cronCmd}`;
2278
+ try {
2279
+ const existing = execSync("crontab -l 2>/dev/null", { encoding: "utf-8" });
2280
+ const filtered = existing.split(`
2281
+ `).filter((l) => !l.includes("conare")).join(`
2282
+ `);
2283
+ const newCrontab = (filtered.trim() ? filtered.trim() + `
2284
+ ` : "") + cronLine + `
2285
+ `;
2286
+ execSync("crontab -", { input: newCrontab, stdio: ["pipe", "ignore", "ignore"] });
2287
+ } catch {
2288
+ execSync("crontab -", { input: cronLine + `
2289
+ `, stdio: ["pipe", "ignore", "ignore"] });
2395
2290
  }
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;
2291
+ }
2292
+ function installGlobalCommand() {
2293
+ const wrapper = join9(BIN_DIR, "conare");
2294
+ const content = `#!/bin/bash
2295
+ # Conare global command runs the persisted CLI bundle
2296
+ CONARE_DIR="$HOME/.conare"
2297
+ NODE=$(command -v node || echo "")
2298
+ if [ -z "$NODE" ]; then
2299
+ if [ -s "$HOME/.nvm/nvm.sh" ]; then
2300
+ . "$HOME/.nvm/nvm.sh" >/dev/null 2>&1
2301
+ NODE=$(command -v node || echo "")
2302
+ fi
2303
+ fi
2304
+ if [ -z "$NODE" ]; then
2305
+ echo "Error: node not found. Install Node.js first." >&2
2306
+ exit 1
2307
+ fi
2308
+ exec "$NODE" "$CONARE_DIR/bin/conare-ingest.mjs" "$@"
2309
+ `;
2310
+ writeFileSync4(wrapper, content);
2311
+ chmodSync(wrapper, 493);
2312
+ const symlinkTarget = "/usr/local/bin/conare";
2313
+ try {
2314
+ if (existsSync7(symlinkTarget)) {
2315
+ try {
2316
+ const existing = readlinkSync(symlinkTarget);
2317
+ if (existing === wrapper)
2318
+ return "Global command: conare (already linked)";
2319
+ } catch {}
2320
+ unlinkSync(symlinkTarget);
2406
2321
  }
2407
- });
2408
- return ensureValue(keyPrompt).trim() || options.savedApiKey;
2322
+ symlinkSync(wrapper, symlinkTarget);
2323
+ return "Global command: conare (linked to /usr/local/bin)";
2324
+ } catch {
2325
+ const pathDirs = (process.env.PATH || "").split(":");
2326
+ if (pathDirs.includes(BIN_DIR)) {
2327
+ return "Global command: conare (via ~/.conare/bin in PATH)";
2328
+ }
2329
+ const shellProfile = getShellProfile();
2330
+ if (shellProfile) {
2331
+ try {
2332
+ const profileContent = existsSync7(shellProfile) ? readFileSync8(shellProfile, "utf-8") : "";
2333
+ const exportLine = `export PATH="$HOME/.conare/bin:$PATH"`;
2334
+ if (!profileContent.includes(".conare/bin")) {
2335
+ appendFileSync(shellProfile, `
2336
+ # Conare CLI
2337
+ ${exportLine}
2338
+ `);
2339
+ return `Global command: conare (added ~/.conare/bin to ${shellProfile} — restart shell)`;
2340
+ }
2341
+ return "Global command: conare (via ~/.conare/bin in PATH)";
2342
+ } catch {
2343
+ return `Global command: add ~/.conare/bin to your PATH manually`;
2344
+ }
2345
+ }
2346
+ return `Global command: add ~/.conare/bin to your PATH manually`;
2347
+ }
2409
2348
  }
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
- }));
2349
+ function getShellProfile() {
2350
+ const home = homedir7();
2351
+ const shell = process.env.SHELL || "";
2352
+ if (shell.includes("zsh"))
2353
+ return join9(home, ".zshrc");
2354
+ if (shell.includes("bash")) {
2355
+ const profile = join9(home, ".bash_profile");
2356
+ if (platform2() === "darwin" && existsSync7(profile))
2357
+ return profile;
2358
+ return join9(home, ".bashrc");
2359
+ }
2360
+ if (existsSync7(join9(home, ".zshrc")))
2361
+ return join9(home, ".zshrc");
2362
+ if (existsSync7(join9(home, ".bashrc")))
2363
+ return join9(home, ".bashrc");
2364
+ return null;
2421
2365
  }
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
- }));
2366
+ function installSync(apiKey, intervalMinutes = 10) {
2367
+ const messages = [];
2368
+ const os = platform2();
2369
+ persistBinary(apiKey);
2370
+ messages.push("Persisted CLI to ~/.conare/bin/");
2371
+ messages.push("Saved config to ~/.conare/config.json");
2372
+ const globalMsg = installGlobalCommand();
2373
+ if (globalMsg)
2374
+ messages.push(globalMsg);
2375
+ if (os === "darwin") {
2376
+ setupMacOS(intervalMinutes);
2377
+ messages.push(`Installed launchd agent (every ${intervalMinutes} min)`);
2378
+ messages.push(`Plist: ${PLIST_PATH}`);
2379
+ } else if (os === "linux") {
2380
+ if (hasSystemd()) {
2381
+ setupLinuxSystemd(intervalMinutes);
2382
+ messages.push(`Installed systemd timer (every ${intervalMinutes} min)`);
2383
+ } else {
2384
+ setupLinuxCron(intervalMinutes);
2385
+ messages.push(`Installed cron job (every ${intervalMinutes} min)`);
2386
+ }
2387
+ } else {
2388
+ messages.push(`Unsupported platform: ${os}. Run manually: ~/.conare/bin/run.sh`);
2389
+ }
2390
+ return messages;
2433
2391
  }
2434
- async function confirmIndexCodebase() {
2435
- return ensureValue(await ye({
2436
- message: "Index this codebase too?",
2437
- initialValue: false
2438
- }));
2392
+ function uninstallSync() {
2393
+ const messages = [];
2394
+ const os = platform2();
2395
+ if (os === "darwin") {
2396
+ try {
2397
+ execSync(`launchctl bootout gui/${uid()} "${PLIST_PATH}" 2>/dev/null`, { stdio: "ignore" });
2398
+ } catch {}
2399
+ if (existsSync7(PLIST_PATH)) {
2400
+ unlinkSync(PLIST_PATH);
2401
+ messages.push("Removed launchd agent");
2402
+ }
2403
+ } else if (os === "linux") {
2404
+ if (hasSystemd()) {
2405
+ try {
2406
+ execSync("systemctl --user disable --now conare-sync.timer 2>/dev/null", { stdio: "ignore" });
2407
+ } catch {}
2408
+ if (existsSync7(SYSTEMD_SERVICE))
2409
+ unlinkSync(SYSTEMD_SERVICE);
2410
+ if (existsSync7(SYSTEMD_TIMER))
2411
+ unlinkSync(SYSTEMD_TIMER);
2412
+ try {
2413
+ execSync("systemctl --user daemon-reload", { stdio: "ignore" });
2414
+ } catch {}
2415
+ messages.push("Removed systemd timer");
2416
+ } else {
2417
+ try {
2418
+ const existing = execSync("crontab -l 2>/dev/null", { encoding: "utf-8" });
2419
+ const filtered = existing.split(`
2420
+ `).filter((l) => !l.includes("conare")).join(`
2421
+ `);
2422
+ execSync("crontab -", { input: filtered.trim() + `
2423
+ `, stdio: ["pipe", "ignore", "ignore"] });
2424
+ messages.push("Removed cron job");
2425
+ } catch {}
2426
+ }
2427
+ }
2428
+ const filesToRemove = [
2429
+ join9(CONARE_DIR, "config.json"),
2430
+ join9(CONARE_DIR, "sync.lock")
2431
+ ];
2432
+ for (const f of filesToRemove) {
2433
+ if (existsSync7(f))
2434
+ unlinkSync(f);
2435
+ }
2436
+ if (existsSync7(BIN_DIR)) {
2437
+ rmSync(BIN_DIR, { recursive: true, force: true });
2438
+ messages.push("Removed ~/.conare/bin/");
2439
+ }
2440
+ if (messages.length === 0) {
2441
+ messages.push("Nothing to uninstall (no sync timer found)");
2442
+ }
2443
+ return messages;
2439
2444
  }
2440
2445
 
2441
2446
  // src/index.ts
2447
+ init_interactive();
2442
2448
  function getManifestFingerprint(memory) {
2443
2449
  const metadata = memory.metadata;
2444
2450
  if (metadata?.dedupKey && metadata?.contentHash) {
@@ -2539,9 +2545,11 @@ function parseArgs() {
2539
2545
  interactive = true;
2540
2546
  } else if (args[i] === "--help" || args[i] === "-h") {
2541
2547
  console.log(`
2542
- conare — Ingest AI chat history into Conare
2548
+ conare — AI memory for your coding tools
2543
2549
 
2544
2550
  Usage:
2551
+ conare install Just install the MCP (simplest)
2552
+ conare install --key <api_key> Install MCP with key
2545
2553
  conare --key <api_key> Ingest chat history
2546
2554
  conare --key <api_key> --index [path] Index codebase
2547
2555
 
@@ -2576,7 +2584,43 @@ Get your API key at https://mcp.conare.ai
2576
2584
  }
2577
2585
  return { key, configFile, dryRun, force, ingestOnly, configOnly, interactive, quiet, installSync: installSyncFlag, uninstallSync: uninstallSyncFlag, syncInterval, source, wasmDir, indexPath };
2578
2586
  }
2587
+ async function runInstall() {
2588
+ const args = process.argv.slice(3);
2589
+ let key = "";
2590
+ for (let i = 0;i < args.length; i++) {
2591
+ if (args[i] === "--key" && args[i + 1]) {
2592
+ key = args[++i];
2593
+ }
2594
+ }
2595
+ const savedApiKey = getSavedApiKey();
2596
+ let apiKey = key || process.env.CONARE_API_KEY || savedApiKey;
2597
+ const hasTty = !!process.stdin.isTTY && !!process.stdout.isTTY;
2598
+ if (!apiKey && hasTty) {
2599
+ const { promptApiKey: promptKey } = await Promise.resolve().then(() => (init_interactive(), exports_interactive));
2600
+ apiKey = await promptKey({ savedApiKey }) || "";
2601
+ }
2602
+ if (!apiKey) {
2603
+ printMissingKeyError();
2604
+ process.exit(1);
2605
+ }
2606
+ const auth = await validateKey(apiKey);
2607
+ if (!auth.valid) {
2608
+ console.error("Invalid API key. Check your key at https://mcp.conare.ai");
2609
+ process.exit(1);
2610
+ }
2611
+ saveApiKey(apiKey);
2612
+ const allTargets = MCP_TARGETS.map((t) => t.id);
2613
+ const lines = configureMcp(apiKey, allTargets);
2614
+ for (const line of lines)
2615
+ console.log(` ${line}`);
2616
+ console.log("");
2617
+ console.log(" \x1B[32m✓\x1B[0m MCP installed. Restart your AI tool to connect.");
2618
+ console.log("");
2619
+ }
2579
2620
  async function main() {
2621
+ if (process.argv[2] === "install") {
2622
+ return runInstall();
2623
+ }
2580
2624
  const opts = parseArgs();
2581
2625
  let configFileKey;
2582
2626
  if (opts.configFile) {
@@ -2616,7 +2660,7 @@ async function main() {
2616
2660
  if (shouldRunInteractive) {
2617
2661
  const detectedTools = detect();
2618
2662
  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");
2663
+ 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
2664
  return {
2621
2665
  id: target.id,
2622
2666
  label: target.label,