conare 0.4.3 → 0.4.5

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 +467 -210
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -34,6 +34,27 @@ import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync
34
34
  import { createHash } from "node:crypto";
35
35
  import { join as join2 } from "node:path";
36
36
  import { homedir as homedir2 } from "node:os";
37
+ function fitContent(header, rounds) {
38
+ const buildContent = (maxUser) => {
39
+ const body = rounds.map((r) => {
40
+ const user = maxUser > 0 && r.user.length > maxUser ? r.user.slice(0, maxUser) + "..." : r.user;
41
+ return `## Q: ${user}
42
+
43
+ ${r.assistant}`;
44
+ }).join(`
45
+
46
+ ---
47
+
48
+ `);
49
+ return `${header}
50
+
51
+ ${body}`;
52
+ };
53
+ const full = buildContent(0);
54
+ if (full.length <= MAX_MEMORY_CONTENT)
55
+ return full;
56
+ return buildContent(TRUNCATED_USER_MSG);
57
+ }
37
58
  function isNarration(text) {
38
59
  const stripped = text.trim();
39
60
  if (stripped.length < MIN_SUBSTANTIVE)
@@ -97,7 +118,7 @@ function clearIngested(source) {
97
118
  mkdirSync(dir, { recursive: true });
98
119
  writeFileSync(MANIFEST_PATH, JSON.stringify(manifest, null, 2));
99
120
  }
100
- var MANIFEST_PATH, MIN_SUBSTANTIVE = 200, NARRATION_RE;
121
+ var MANIFEST_PATH, MAX_MEMORY_CONTENT = 200000, TRUNCATED_USER_MSG = 3000, MIN_SUBSTANTIVE = 200, NARRATION_RE;
101
122
  var init_shared = __esm(() => {
102
123
  MANIFEST_PATH = join2(homedir2(), ".conare", "ingested.json");
103
124
  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))/;
@@ -817,6 +838,21 @@ function Y(e, u, t) {
817
838
  `).map((F) => lD(F, u, t)).join(`
818
839
  `);
819
840
  }
841
+ function cD(e) {
842
+ for (const u in e) {
843
+ const t = u;
844
+ if (!Object.hasOwn(e, t))
845
+ continue;
846
+ const F = e[t];
847
+ switch (t) {
848
+ case "aliases": {
849
+ for (const s in F)
850
+ Object.hasOwn(F, s) && (B.aliases.has(s) || B.aliases.set(s, F[s]));
851
+ break;
852
+ }
853
+ }
854
+ }
855
+ }
820
856
  function $(e, u) {
821
857
  if (typeof e == "string")
822
858
  return B.aliases.get(e) === u;
@@ -1024,7 +1060,14 @@ var import_sisteransi, import_picocolors, uD, W, tD, eD, FD = function() {
1024
1060
  ` && (s && o && (F += z(s)), i && (F += K(i)));
1025
1061
  }
1026
1062
  return F;
1027
- }, 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, OD, PD = (e, u, t) => (u in e) ? OD(e, u, { enumerable: true, configurable: true, writable: true, value: t }) : e[u] = t, J = (e, u, t) => (PD(e, typeof u != "symbol" ? u + "" : u, t), t), LD;
1063
+ }, 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, mD, bD = (e, u, t) => (u in e) ? mD(e, u, { enumerable: true, configurable: true, writable: true, value: t }) : e[u] = t, Z = (e, u, t) => (bD(e, typeof u != "symbol" ? u + "" : u, t), t), q = (e, u, t) => {
1064
+ if (!u.has(e))
1065
+ throw TypeError("Cannot " + t);
1066
+ }, T = (e, u, t) => (q(e, u, "read from private field"), t ? t.call(e) : u.get(e)), wD = (e, u, t) => {
1067
+ if (u.has(e))
1068
+ throw TypeError("Cannot add the same private member more than once");
1069
+ u instanceof WeakSet ? u.add(e) : u.set(e, t);
1070
+ }, yD = (e, u, t, F) => (q(e, u, "write to private field"), F ? F.call(e, t) : u.set(e, t), t), A, _D, 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, OD, PD = (e, u, t) => (u in e) ? OD(e, u, { enumerable: true, configurable: true, writable: true, value: t }) : e[u] = t, J = (e, u, t) => (PD(e, typeof u != "symbol" ? u + "" : u, t), t), LD, WD, ND = (e, u, t) => (u in e) ? WD(e, u, { enumerable: true, configurable: true, writable: true, value: t }) : e[u] = t, Q = (e, u, t) => (ND(e, typeof u != "symbol" ? u + "" : u, t), t), ID, RD;
1028
1071
  var init_dist = __esm(() => {
1029
1072
  import_sisteransi = __toESM(require_src(), 1);
1030
1073
  import_picocolors = __toESM(require_picocolors(), 1);
@@ -1093,6 +1136,50 @@ var init_dist = __esm(() => {
1093
1136
  });
1094
1137
  }
1095
1138
  };
1139
+ mD = Object.defineProperty;
1140
+ _D = class extends x {
1141
+ constructor(u) {
1142
+ super(u, false), Z(this, "options"), Z(this, "cursor", 0), wD(this, A, undefined);
1143
+ const { options: t } = u;
1144
+ yD(this, A, u.selectableGroups !== false), this.options = Object.entries(t).flatMap(([F, s]) => [{ value: F, group: true, label: F }, ...s.map((i) => ({ ...i, group: F }))]), this.value = [...u.initialValues ?? []], this.cursor = Math.max(this.options.findIndex(({ value: F }) => F === u.cursorAt), T(this, A) ? 0 : 1), this.on("cursor", (F) => {
1145
+ switch (F) {
1146
+ case "left":
1147
+ case "up": {
1148
+ this.cursor = this.cursor === 0 ? this.options.length - 1 : this.cursor - 1;
1149
+ const s = this.options[this.cursor]?.group === true;
1150
+ !T(this, A) && s && (this.cursor = this.cursor === 0 ? this.options.length - 1 : this.cursor - 1);
1151
+ break;
1152
+ }
1153
+ case "down":
1154
+ case "right": {
1155
+ this.cursor = this.cursor === this.options.length - 1 ? 0 : this.cursor + 1;
1156
+ const s = this.options[this.cursor]?.group === true;
1157
+ !T(this, A) && s && (this.cursor = this.cursor === this.options.length - 1 ? 0 : this.cursor + 1);
1158
+ break;
1159
+ }
1160
+ case "space":
1161
+ this.toggleValue();
1162
+ break;
1163
+ }
1164
+ });
1165
+ }
1166
+ getGroupItems(u) {
1167
+ return this.options.filter((t) => t.group === u);
1168
+ }
1169
+ isGroupSelected(u) {
1170
+ return this.getGroupItems(u).every((t) => this.value.includes(t.value));
1171
+ }
1172
+ toggleValue() {
1173
+ const u = this.options[this.cursor];
1174
+ if (u.group === true) {
1175
+ const t = u.value, F = this.getGroupItems(t);
1176
+ this.isGroupSelected(t) ? this.value = this.value.filter((s) => F.findIndex((i) => i.value === s) === -1) : this.value = [...this.value, ...F.map((s) => s.value)], this.value = Array.from(new Set(this.value));
1177
+ } else {
1178
+ const t = this.value.includes(u.value);
1179
+ this.value = t ? this.value.filter((F) => F !== u.value) : [...this.value, u.value];
1180
+ }
1181
+ }
1182
+ };
1096
1183
  A = new WeakMap;
1097
1184
  kD = Object.defineProperty;
1098
1185
  SD = class extends x {
@@ -1172,15 +1259,67 @@ var init_dist = __esm(() => {
1172
1259
  this.value = this._value.value;
1173
1260
  }
1174
1261
  };
1262
+ WD = Object.defineProperty;
1263
+ ID = class ID extends x {
1264
+ constructor(u) {
1265
+ super(u, false), Q(this, "options"), Q(this, "cursor", 0), this.options = u.options;
1266
+ const t = this.options.map(({ value: [F] }) => F?.toLowerCase());
1267
+ this.cursor = Math.max(t.indexOf(u.initialValue), 0), this.on("key", (F) => {
1268
+ if (!t.includes(F))
1269
+ return;
1270
+ const s = this.options.find(({ value: [i] }) => i?.toLowerCase() === F);
1271
+ s && (this.value = s.value, this.state = "submit", this.emit("submit"));
1272
+ });
1273
+ }
1274
+ };
1275
+ RD = class RD extends x {
1276
+ get valueWithCursor() {
1277
+ if (this.state === "submit")
1278
+ return this.value;
1279
+ if (this.cursor >= this.value.length)
1280
+ return `${this.value}█`;
1281
+ const u = this.value.slice(0, this.cursor), [t, ...F] = this.value.slice(this.cursor);
1282
+ return `${u}${import_picocolors.default.inverse(t)}${F.join("")}`;
1283
+ }
1284
+ get cursor() {
1285
+ return this._cursor;
1286
+ }
1287
+ constructor(u) {
1288
+ super(u), this.on("finalize", () => {
1289
+ this.value || (this.value = u.defaultValue);
1290
+ });
1291
+ }
1292
+ };
1175
1293
  });
1176
1294
 
1177
1295
  // node_modules/@clack/prompts/dist/index.mjs
1296
+ var exports_dist = {};
1297
+ __export(exports_dist, {
1298
+ updateSettings: () => cD,
1299
+ text: () => he,
1300
+ tasks: () => Te,
1301
+ stream: () => x2,
1302
+ spinner: () => Y2,
1303
+ selectKey: () => we,
1304
+ select: () => ve,
1305
+ password: () => ge,
1306
+ outro: () => Se,
1307
+ note: () => Me,
1308
+ multiselect: () => fe,
1309
+ log: () => M2,
1310
+ isCancel: () => pD,
1311
+ intro: () => Ie,
1312
+ groupMultiselect: () => be,
1313
+ group: () => Ce,
1314
+ confirm: () => ye,
1315
+ cancel: () => xe
1316
+ });
1178
1317
  import { stripVTControlCharacters as S2 } from "node:util";
1179
1318
  import y2 from "node:process";
1180
1319
  function ce() {
1181
1320
  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";
1182
1321
  }
1183
- 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) => {
1322
+ var import_picocolors2, import_sisteransi2, V2, u = (t, n) => V2 ? t : n, le, L2, W2, C, ue, o, d2, k2, P2, A2, T2, F, $e, _2, me, de, pe, q2, D, U2, K2, b2 = (t) => {
1184
1323
  switch (t) {
1185
1324
  case "initial":
1186
1325
  case "active":
@@ -1201,7 +1340,27 @@ var import_picocolors2, import_sisteransi2, V2, u = (t, n) => V2 ? t : n, le, L2
1201
1340
  const j2 = v2 === 0 && $2, E = v2 === f.length - 1 && g2;
1202
1341
  return j2 || E ? import_picocolors2.default.dim("...") : i(p2, v2 + l2 === n);
1203
1342
  });
1204
- }, ge = (t) => new MD({ validate: t.validate, mask: t.mask ?? $e, render() {
1343
+ }, he = (t) => new RD({ validate: t.validate, placeholder: t.placeholder, defaultValue: t.defaultValue, initialValue: t.initialValue, render() {
1344
+ const n = `${import_picocolors2.default.gray(o)}
1345
+ ${b2(this.state)} ${t.message}
1346
+ `, r2 = t.placeholder ? import_picocolors2.default.inverse(t.placeholder[0]) + import_picocolors2.default.dim(t.placeholder.slice(1)) : import_picocolors2.default.inverse(import_picocolors2.default.hidden("_")), i = this.value ? this.valueWithCursor : r2;
1347
+ switch (this.state) {
1348
+ case "error":
1349
+ return `${n.trim()}
1350
+ ${import_picocolors2.default.yellow(o)} ${i}
1351
+ ${import_picocolors2.default.yellow(d2)} ${import_picocolors2.default.yellow(this.error)}
1352
+ `;
1353
+ case "submit":
1354
+ return `${n}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.dim(this.value || t.placeholder)}`;
1355
+ case "cancel":
1356
+ return `${n}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(this.value ?? ""))}${this.value?.trim() ? `
1357
+ ${import_picocolors2.default.gray(o)}` : ""}`;
1358
+ default:
1359
+ return `${n}${import_picocolors2.default.cyan(o)} ${i}
1360
+ ${import_picocolors2.default.cyan(d2)}
1361
+ `;
1362
+ }
1363
+ } }).prompt(), ge = (t) => new MD({ validate: t.validate, mask: t.mask ?? $e, render() {
1205
1364
  const n = `${import_picocolors2.default.gray(o)}
1206
1365
  ${b2(this.state)} ${t.message}
1207
1366
  `, r2 = this.valueWithCursor, i = this.masked;
@@ -1267,13 +1426,35 @@ ${import_picocolors2.default.gray(o)}`;
1267
1426
  return `${r2}${import_picocolors2.default.cyan(o)} ${G2({ cursor: this.cursor, options: this.options, maxItems: t.maxItems, style: (i, s) => n(i, s ? "active" : "inactive") }).join(`
1268
1427
  ${import_picocolors2.default.cyan(o)} `)}
1269
1428
  ${import_picocolors2.default.cyan(d2)}
1429
+ `;
1430
+ }
1431
+ } }).prompt();
1432
+ }, we = (t) => {
1433
+ const n = (r2, i = "inactive") => {
1434
+ const s = r2.label ?? String(r2.value);
1435
+ return i === "selected" ? `${import_picocolors2.default.dim(s)}` : i === "cancelled" ? `${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(s))}` : i === "active" ? `${import_picocolors2.default.bgCyan(import_picocolors2.default.gray(` ${r2.value} `))} ${s} ${r2.hint ? import_picocolors2.default.dim(`(${r2.hint})`) : ""}` : `${import_picocolors2.default.gray(import_picocolors2.default.bgWhite(import_picocolors2.default.inverse(` ${r2.value} `)))} ${s} ${r2.hint ? import_picocolors2.default.dim(`(${r2.hint})`) : ""}`;
1436
+ };
1437
+ return new ID({ options: t.options, initialValue: t.initialValue, render() {
1438
+ const r2 = `${import_picocolors2.default.gray(o)}
1439
+ ${b2(this.state)} ${t.message}
1440
+ `;
1441
+ switch (this.state) {
1442
+ case "submit":
1443
+ return `${r2}${import_picocolors2.default.gray(o)} ${n(this.options.find((i) => i.value === this.value) ?? t.options[0], "selected")}`;
1444
+ case "cancel":
1445
+ return `${r2}${import_picocolors2.default.gray(o)} ${n(this.options[0], "cancelled")}
1446
+ ${import_picocolors2.default.gray(o)}`;
1447
+ default:
1448
+ return `${r2}${import_picocolors2.default.cyan(o)} ${this.options.map((i, s) => n(i, s === this.cursor ? "active" : "inactive")).join(`
1449
+ ${import_picocolors2.default.cyan(o)} `)}
1450
+ ${import_picocolors2.default.cyan(d2)}
1270
1451
  `;
1271
1452
  }
1272
1453
  } }).prompt();
1273
1454
  }, fe = (t) => {
1274
1455
  const n = (r2, i) => {
1275
1456
  const s = r2.label ?? String(r2.value);
1276
- 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)}`;
1457
+ return i === "active" ? `${import_picocolors2.default.cyan(A2)} ${s} ${r2.hint ? import_picocolors2.default.dim(`(${r2.hint})`) : ""}` : i === "selected" ? `${import_picocolors2.default.green(T2)} ${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(T2)} ${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)}`;
1277
1458
  };
1278
1459
  return new SD({ options: t.options, initialValues: t.initialValues, required: t.required ?? true, cursorAt: t.cursorAt, validate(r2) {
1279
1460
  if (this.required && r2.length === 0)
@@ -1307,6 +1488,66 @@ ${s}
1307
1488
  return `${r2}${import_picocolors2.default.cyan(o)} ${G2({ options: this.options, cursor: this.cursor, maxItems: t.maxItems, style: i }).join(`
1308
1489
  ${import_picocolors2.default.cyan(o)} `)}
1309
1490
  ${import_picocolors2.default.cyan(d2)}
1491
+ `;
1492
+ }
1493
+ } }).prompt();
1494
+ }, be = (t) => {
1495
+ const { selectableGroups: n = true } = t, r2 = (i, s, c = []) => {
1496
+ const a = i.label ?? String(i.value), l2 = typeof i.group == "string", $2 = l2 && (c[c.indexOf(i) + 1] ?? { group: true }), g2 = l2 && $2.group === true, p2 = l2 ? n ? `${g2 ? d2 : o} ` : " " : "";
1497
+ if (s === "active")
1498
+ return `${import_picocolors2.default.dim(p2)}${import_picocolors2.default.cyan(A2)} ${a} ${i.hint ? import_picocolors2.default.dim(`(${i.hint})`) : ""}`;
1499
+ if (s === "group-active")
1500
+ return `${p2}${import_picocolors2.default.cyan(A2)} ${import_picocolors2.default.dim(a)}`;
1501
+ if (s === "group-active-selected")
1502
+ return `${p2}${import_picocolors2.default.green(T2)} ${import_picocolors2.default.dim(a)}`;
1503
+ if (s === "selected") {
1504
+ const f = l2 || n ? import_picocolors2.default.green(T2) : "";
1505
+ return `${import_picocolors2.default.dim(p2)}${f} ${import_picocolors2.default.dim(a)} ${i.hint ? import_picocolors2.default.dim(`(${i.hint})`) : ""}`;
1506
+ }
1507
+ if (s === "cancelled")
1508
+ return `${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(a))}`;
1509
+ if (s === "active-selected")
1510
+ return `${import_picocolors2.default.dim(p2)}${import_picocolors2.default.green(T2)} ${a} ${i.hint ? import_picocolors2.default.dim(`(${i.hint})`) : ""}`;
1511
+ if (s === "submitted")
1512
+ return `${import_picocolors2.default.dim(a)}`;
1513
+ const v2 = l2 || n ? import_picocolors2.default.dim(F) : "";
1514
+ return `${import_picocolors2.default.dim(p2)}${v2} ${import_picocolors2.default.dim(a)}`;
1515
+ };
1516
+ return new _D({ options: t.options, initialValues: t.initialValues, required: t.required ?? true, cursorAt: t.cursorAt, selectableGroups: n, validate(i) {
1517
+ if (this.required && i.length === 0)
1518
+ return `Please select at least one option.
1519
+ ${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`))}`;
1520
+ }, render() {
1521
+ const i = `${import_picocolors2.default.gray(o)}
1522
+ ${b2(this.state)} ${t.message}
1523
+ `;
1524
+ switch (this.state) {
1525
+ case "submit":
1526
+ return `${i}${import_picocolors2.default.gray(o)} ${this.options.filter(({ value: s }) => this.value.includes(s)).map((s) => r2(s, "submitted")).join(import_picocolors2.default.dim(", "))}`;
1527
+ case "cancel": {
1528
+ const s = this.options.filter(({ value: c }) => this.value.includes(c)).map((c) => r2(c, "cancelled")).join(import_picocolors2.default.dim(", "));
1529
+ return `${i}${import_picocolors2.default.gray(o)} ${s.trim() ? `${s}
1530
+ ${import_picocolors2.default.gray(o)}` : ""}`;
1531
+ }
1532
+ case "error": {
1533
+ const s = this.error.split(`
1534
+ `).map((c, a) => a === 0 ? `${import_picocolors2.default.yellow(d2)} ${import_picocolors2.default.yellow(c)}` : ` ${c}`).join(`
1535
+ `);
1536
+ return `${i}${import_picocolors2.default.yellow(o)} ${this.options.map((c, a, l2) => {
1537
+ const $2 = this.value.includes(c.value) || c.group === true && this.isGroupSelected(`${c.value}`), g2 = a === this.cursor;
1538
+ return !g2 && typeof c.group == "string" && this.options[this.cursor].value === c.group ? r2(c, $2 ? "group-active-selected" : "group-active", l2) : g2 && $2 ? r2(c, "active-selected", l2) : $2 ? r2(c, "selected", l2) : r2(c, g2 ? "active" : "inactive", l2);
1539
+ }).join(`
1540
+ ${import_picocolors2.default.yellow(o)} `)}
1541
+ ${s}
1542
+ `;
1543
+ }
1544
+ default:
1545
+ return `${i}${import_picocolors2.default.cyan(o)} ${this.options.map((s, c, a) => {
1546
+ const l2 = this.value.includes(s.value) || s.group === true && this.isGroupSelected(`${s.value}`), $2 = c === this.cursor;
1547
+ return !$2 && typeof s.group == "string" && this.options[this.cursor].value === s.group ? r2(s, l2 ? "group-active-selected" : "group-active", a) : $2 && l2 ? r2(s, "active-selected", a) : l2 ? r2(s, "selected", a) : r2(s, $2 ? "active" : "inactive", a);
1548
+ }).join(`
1549
+ ${import_picocolors2.default.cyan(o)} `)}
1550
+ ${import_picocolors2.default.cyan(d2)}
1310
1551
  `;
1311
1552
  }
1312
1553
  } }).prompt();
@@ -1336,7 +1577,7 @@ ${import_picocolors2.default.gray(de + _2.repeat(s + 2) + pe)}
1336
1577
  ${import_picocolors2.default.gray(d2)} ${t}
1337
1578
 
1338
1579
  `);
1339
- }, J2, Y2 = ({ indicator: t = "dots" } = {}) => {
1580
+ }, M2, J2, x2, Y2 = ({ indicator: t = "dots" } = {}) => {
1340
1581
  const n = V2 ? ["◒", "◐", "◓", "◑"] : ["•", "o", "O", "0"], r2 = V2 ? 80 : 120, i = process.env.CI === "true";
1341
1582
  let s, c, a = false, l2 = "", $2, g2 = performance.now();
1342
1583
  const p2 = (m2) => {
@@ -1386,6 +1627,28 @@ ${import_picocolors2.default.gray(d2)} ${t}
1386
1627
  return { start: H2, stop: N2, message: (m2 = "") => {
1387
1628
  l2 = R2(m2 ?? l2);
1388
1629
  } };
1630
+ }, Ce = async (t, n) => {
1631
+ const r2 = {}, i = Object.keys(t);
1632
+ for (const s of i) {
1633
+ const c = t[s], a = await c({ results: r2 })?.catch((l2) => {
1634
+ throw l2;
1635
+ });
1636
+ if (typeof n?.onCancel == "function" && pD(a)) {
1637
+ r2[s] = "canceled", n.onCancel({ results: r2 });
1638
+ continue;
1639
+ }
1640
+ r2[s] = a;
1641
+ }
1642
+ return r2;
1643
+ }, Te = async (t) => {
1644
+ for (const n of t) {
1645
+ if (n.enabled === false)
1646
+ continue;
1647
+ const r2 = Y2();
1648
+ r2.start(n.title);
1649
+ const i = await n.task(r2.message);
1650
+ r2.stop(i || n.title);
1651
+ }
1389
1652
  };
1390
1653
  var init_dist2 = __esm(() => {
1391
1654
  init_dist();
@@ -1403,18 +1666,57 @@ var init_dist2 = __esm(() => {
1403
1666
  k2 = u("●", ">");
1404
1667
  P2 = u("○", " ");
1405
1668
  A2 = u("◻", "[•]");
1406
- T = u("◼", "[+]");
1669
+ T2 = u("◼", "[+]");
1407
1670
  F = u("◻", "[ ]");
1408
1671
  $e = u("▪", "•");
1409
1672
  _2 = u("─", "-");
1410
1673
  me = u("╮", "+");
1411
1674
  de = u("├", "+");
1412
1675
  pe = u("╯", "+");
1413
- q = u("●", "•");
1676
+ q2 = u("●", "•");
1414
1677
  D = u("◆", "*");
1415
1678
  U2 = u("▲", "!");
1416
1679
  K2 = u("■", "x");
1680
+ M2 = { message: (t = "", { symbol: n = import_picocolors2.default.gray(o) } = {}) => {
1681
+ const r2 = [`${import_picocolors2.default.gray(o)}`];
1682
+ if (t) {
1683
+ const [i, ...s] = t.split(`
1684
+ `);
1685
+ r2.push(`${n} ${i}`, ...s.map((c) => `${import_picocolors2.default.gray(o)} ${c}`));
1686
+ }
1687
+ process.stdout.write(`${r2.join(`
1688
+ `)}
1689
+ `);
1690
+ }, info: (t) => {
1691
+ M2.message(t, { symbol: import_picocolors2.default.blue(q2) });
1692
+ }, success: (t) => {
1693
+ M2.message(t, { symbol: import_picocolors2.default.green(D) });
1694
+ }, step: (t) => {
1695
+ M2.message(t, { symbol: import_picocolors2.default.green(C) });
1696
+ }, warn: (t) => {
1697
+ M2.message(t, { symbol: import_picocolors2.default.yellow(U2) });
1698
+ }, warning: (t) => {
1699
+ M2.warn(t);
1700
+ }, error: (t) => {
1701
+ M2.message(t, { symbol: import_picocolors2.default.red(K2) });
1702
+ } };
1417
1703
  J2 = `${import_picocolors2.default.gray(o)} `;
1704
+ x2 = { message: async (t, { symbol: n = import_picocolors2.default.gray(o) } = {}) => {
1705
+ process.stdout.write(`${import_picocolors2.default.gray(o)}
1706
+ ${n} `);
1707
+ let r2 = 3;
1708
+ for await (let i of t) {
1709
+ i = i.replace(/\n/g, `
1710
+ ${J2}`), i.includes(`
1711
+ `) && (r2 = 3 + S2(i.slice(i.lastIndexOf(`
1712
+ `))).length);
1713
+ const s = S2(i).length;
1714
+ r2 + s < process.stdout.columns ? (r2 += s, process.stdout.write(i)) : (process.stdout.write(`
1715
+ ${J2}${i.trimStart()}`), r2 = 3 + S2(i.trimStart()).length);
1716
+ }
1717
+ process.stdout.write(`
1718
+ `);
1719
+ }, info: (t) => x2.message(t, { symbol: import_picocolors2.default.blue(q2) }), success: (t) => x2.message(t, { symbol: import_picocolors2.default.green(D) }), step: (t) => x2.message(t, { symbol: import_picocolors2.default.green(C) }), warn: (t) => x2.message(t, { symbol: import_picocolors2.default.yellow(U2) }), warning: (t) => x2.warn(t), error: (t) => x2.message(t, { symbol: import_picocolors2.default.red(K2) }) };
1418
1720
  });
1419
1721
 
1420
1722
  // src/interactive.ts
@@ -1428,7 +1730,6 @@ __export(exports_interactive, {
1428
1730
  promptAuth: () => promptAuth,
1429
1731
  promptApiKey: () => promptApiKey,
1430
1732
  finishSetup: () => finishSetup,
1431
- confirmIndexCodebase: () => confirmIndexCodebase,
1432
1733
  confirmBackgroundSync: () => confirmBackgroundSync
1433
1734
  });
1434
1735
  function formatDetectedCount(count) {
@@ -1531,12 +1832,6 @@ async function selectMcpTargets(targets) {
1531
1832
  }))
1532
1833
  }));
1533
1834
  }
1534
- async function confirmIndexCodebase() {
1535
- return ensureValue(await ye({
1536
- message: "Index this codebase too?",
1537
- initialValue: false
1538
- }));
1539
- }
1540
1835
  async function confirmBackgroundSync() {
1541
1836
  const value = ensureValue(await ve({
1542
1837
  message: "Auto-ingest new chats every 10 minutes?",
@@ -1712,6 +2007,21 @@ async function detect() {
1712
2007
  path: join(openclawDir, "openclaw.json"),
1713
2008
  sessionCount: 0
1714
2009
  });
2010
+ const antigravityDir = join(home, ".gemini", "antigravity");
2011
+ const antigravityConvDir = join(antigravityDir, "conversations");
2012
+ let antigravityCount = 0;
2013
+ if (existsSync(antigravityConvDir)) {
2014
+ try {
2015
+ antigravityCount = readdirSync(antigravityConvDir).filter((f) => f.endsWith(".pb")).length;
2016
+ } catch {}
2017
+ }
2018
+ tools.push({
2019
+ name: "Antigravity",
2020
+ id: "antigravity",
2021
+ available: existsSync(antigravityDir),
2022
+ path: join(antigravityDir, "mcp_config.json"),
2023
+ sessionCount: antigravityCount
2024
+ });
1715
2025
  return tools;
1716
2026
  }
1717
2027
 
@@ -1799,7 +2109,6 @@ init_shared();
1799
2109
  import { readdirSync as readdirSync2, readFileSync as readFileSync3, existsSync as existsSync3 } from "node:fs";
1800
2110
  import { join as join3, basename } from "node:path";
1801
2111
  import { homedir as homedir3, platform as platform3 } from "node:os";
1802
- var MAX_CONTENT = 48000;
1803
2112
  var MIN_TURN_LEN = 50;
1804
2113
  function resolveProjectName(dirName) {
1805
2114
  const segments = dirName.replace(/^-/, "").split("-");
@@ -1942,22 +2251,7 @@ function ingestClaude() {
1942
2251
  continue;
1943
2252
  }
1944
2253
  const header = `# Chat: ${project}${date ? ` | ${date}` : ""}`;
1945
- const body = turns.map((t) => {
1946
- return `## Q: ${t.user}
1947
-
1948
- ${t.assistant}`;
1949
- }).join(`
1950
-
1951
- ---
1952
-
1953
- `);
1954
- let content = `${header}
1955
-
1956
- ${body}`;
1957
- if (content.length > MAX_CONTENT)
1958
- content = content.slice(0, MAX_CONTENT) + `
1959
-
1960
- [truncated]`;
2254
+ const content = fitContent(header, turns);
1961
2255
  const contentHash = createContentHash(content);
1962
2256
  const dedupKey = `claude:${sessionId}`;
1963
2257
  const fingerprint = `${dedupKey}:${contentHash}`;
@@ -1988,7 +2282,6 @@ init_shared();
1988
2282
  import { existsSync as existsSync4, readFileSync as readFileSync4, readdirSync as readdirSync3 } from "node:fs";
1989
2283
  import { join as join4, basename as basename2 } from "node:path";
1990
2284
  import { homedir as homedir4 } from "node:os";
1991
- var MAX_CONTENT2 = 48000;
1992
2285
  function isCodexBoilerplate(text) {
1993
2286
  return text.startsWith("# AGENTS.md instructions for") || text.startsWith("<INSTRUCTIONS>") || text.startsWith("<user_instructions>") || text.startsWith("<user_action>");
1994
2287
  }
@@ -2096,25 +2389,14 @@ function walkCodexSessions(dir, memories, sessionIds, stats) {
2096
2389
  stats.filtered++;
2097
2390
  continue;
2098
2391
  }
2099
- const body = rounds.map((r) => {
2100
- const assistant = r.assistantParts.join(`
2101
-
2102
- `);
2103
- return `## Q: ${r.user}
2104
-
2105
- ${assistant}`;
2106
- }).join(`
2107
-
2108
- ---
2392
+ const header = `# Codex Session${project ? `: ${project}` : ""} | ${date || "unknown"}`;
2393
+ const turns = rounds.map((r) => ({
2394
+ user: r.user,
2395
+ assistant: r.assistantParts.join(`
2109
2396
 
2110
- `);
2111
- let content = `# Codex Session${project ? `: ${project}` : ""} | ${date || "unknown"}
2112
-
2113
- ${body}`;
2114
- if (content.length > MAX_CONTENT2)
2115
- content = content.slice(0, MAX_CONTENT2) + `
2116
-
2117
- [truncated]`;
2397
+ `)
2398
+ }));
2399
+ const content = fitContent(header, turns);
2118
2400
  const contentHash = createContentHash(content);
2119
2401
  const dedupKey = `codex:${sessionId}`;
2120
2402
  const fingerprint = `${dedupKey}:${contentHash}`;
@@ -2146,7 +2428,6 @@ init_shared();
2146
2428
  import { readFileSync as readFileSync5, statSync } from "node:fs";
2147
2429
  import { join as join5 } from "node:path";
2148
2430
  import { createRequire as createRequire3 } from "node:module";
2149
- var MAX_CONTENT3 = 48000;
2150
2431
  var MAX_DB_SIZE = 2 * 1024 * 1024 * 1024;
2151
2432
  var WARN_DB_SIZE = 500 * 1024 * 1024;
2152
2433
  var MIN_TURN_LEN2 = 50;
@@ -2262,22 +2543,7 @@ async function ingestCursor(dbPath, wasmDir) {
2262
2543
  const sessionName = parsed.name || "Cursor Chat";
2263
2544
  const date = parsed.createdAt ? new Date(parsed.createdAt).toISOString().slice(0, 10) : "unknown";
2264
2545
  const header = `# ${sessionName} | ${date}`;
2265
- const body = turns.map((t) => {
2266
- return `## Q: ${t.user}
2267
-
2268
- ${t.assistant}`;
2269
- }).join(`
2270
-
2271
- ---
2272
-
2273
- `);
2274
- let content = `${header}
2275
-
2276
- ${body}`;
2277
- if (content.length > MAX_CONTENT3)
2278
- content = content.slice(0, MAX_CONTENT3) + `
2279
-
2280
- [truncated]`;
2546
+ const content = fitContent(header, turns);
2281
2547
  const contentHash = createContentHash(content);
2282
2548
  const dedupKey = `cursor:${composerId}`;
2283
2549
  const fingerprint = `${dedupKey}:${contentHash}`;
@@ -2327,7 +2593,8 @@ var MCP_TARGETS = [
2327
2593
  { id: "vscode", label: "VS Code Copilot", defaultSelected: false },
2328
2594
  { id: "cline", label: "Cline", defaultSelected: false },
2329
2595
  { id: "zed", label: "Zed", defaultSelected: false },
2330
- { id: "openclaw", label: "OpenClaw", defaultSelected: false }
2596
+ { id: "openclaw", label: "OpenClaw", defaultSelected: false },
2597
+ { id: "antigravity", label: "Antigravity", defaultSelected: false }
2331
2598
  ];
2332
2599
  function readJsonFile(path) {
2333
2600
  try {
@@ -2536,6 +2803,19 @@ function configureOpenclaw(apiKey) {
2536
2803
  writeJsonFile(configPath, config);
2537
2804
  return "\x1B[32m✓\x1B[0m OpenClaw";
2538
2805
  }
2806
+ function configureAntigravity(apiKey) {
2807
+ const configPath = join7(homedir5(), ".gemini", "antigravity", "mcp_config.json");
2808
+ const config = readJsonFile(configPath);
2809
+ if (!config.mcpServers || typeof config.mcpServers !== "object") {
2810
+ config.mcpServers = {};
2811
+ }
2812
+ config.mcpServers[SERVER_NAME] = {
2813
+ serverUrl: `${CONARE_URL}/mcp`,
2814
+ headers: { Authorization: `Bearer ${apiKey}` }
2815
+ };
2816
+ writeJsonFile(configPath, config);
2817
+ return "\x1B[32m✓\x1B[0m Antigravity";
2818
+ }
2539
2819
  var CLIENT_CONFIGURATORS = {
2540
2820
  claude: configureClaude,
2541
2821
  codex: configureCodex,
@@ -2544,7 +2824,8 @@ var CLIENT_CONFIGURATORS = {
2544
2824
  vscode: configureVscode,
2545
2825
  cline: configureCline,
2546
2826
  zed: configureZed,
2547
- openclaw: configureOpenclaw
2827
+ openclaw: configureOpenclaw,
2828
+ antigravity: configureAntigravity
2548
2829
  };
2549
2830
  var SKILL_MD = `---
2550
2831
  name: conare
@@ -2697,16 +2978,6 @@ function saveApiKey(apiKey) {
2697
2978
  function getSavedApiKey() {
2698
2979
  return readConfig().apiKey;
2699
2980
  }
2700
- function addIndexedPath(absPath) {
2701
- const config = readConfig();
2702
- const paths = new Set(config.indexedPaths || []);
2703
- paths.add(absPath);
2704
- config.indexedPaths = [...paths];
2705
- writeConfig(config);
2706
- }
2707
- function getIndexedPaths() {
2708
- return readConfig().indexedPaths || [];
2709
- }
2710
2981
 
2711
2982
  // src/sync.ts
2712
2983
  import { existsSync as existsSync8, mkdirSync as mkdirSync4, writeFileSync as writeFileSync4, unlinkSync, readFileSync as readFileSync9, chmodSync, cpSync, rmSync as rmSync2, symlinkSync as symlinkSync2, readlinkSync as readlinkSync2, appendFileSync } from "node:fs";
@@ -2821,31 +3092,6 @@ echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) START sync" >> "$LOG"
2821
3092
  2>> "$LOG"
2822
3093
  echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) DONE sync (exit $?)" >> "$LOG"
2823
3094
  `;
2824
- function makePlist(intervalMinutes) {
2825
- const home = homedir7();
2826
- return `<?xml version="1.0" encoding="UTF-8"?>
2827
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
2828
- "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
2829
- <plist version="1.0">
2830
- <dict>
2831
- <key>Label</key>
2832
- <string>${PLIST_LABEL}</string>
2833
- <key>ProgramArguments</key>
2834
- <array>
2835
- <string>/bin/bash</string>
2836
- <string>${home}/.conare/bin/run.sh</string>
2837
- </array>
2838
- <key>StartInterval</key>
2839
- <integer>${intervalMinutes * 60}</integer>
2840
- <key>StandardOutPath</key>
2841
- <string>${home}/.conare/ingest.log</string>
2842
- <key>StandardErrorPath</key>
2843
- <string>${home}/.conare/ingest.log</string>
2844
- <key>RunAtLoad</key>
2845
- <true/>
2846
- </dict>
2847
- </plist>`;
2848
- }
2849
3095
  var SYSTEMD_SERVICE_CONTENT = `[Unit]
2850
3096
  Description=Conare Memory — background sync
2851
3097
 
@@ -2947,22 +3193,12 @@ function findSqlJs() {
2947
3193
  }
2948
3194
  return null;
2949
3195
  }
2950
- function setupMacOS(intervalMinutes) {
2951
- const plistDir = dirname2(PLIST_PATH);
2952
- mkdirSync4(plistDir, { recursive: true });
2953
- writeFileSync4(PLIST_PATH, makePlist(intervalMinutes));
2954
- const id = uid();
3196
+ function cleanupOldLaunchAgent() {
2955
3197
  try {
2956
- execSync3(`launchctl bootout gui/${id} "${PLIST_PATH}" 2>/dev/null`, { stdio: "ignore" });
3198
+ execSync3(`launchctl bootout gui/${uid()} "${PLIST_PATH}" 2>/dev/null`, { stdio: "ignore" });
2957
3199
  } catch {}
2958
- try {
2959
- execSync3(`launchctl bootstrap gui/${id} "${PLIST_PATH}"`, { stdio: "ignore" });
2960
- } catch {
2961
- try {
2962
- execSync3(`launchctl load "${PLIST_PATH}"`, { stdio: "ignore" });
2963
- } catch {
2964
- throw new Error("Failed to load launchd agent. Try manually: launchctl load " + PLIST_PATH);
2965
- }
3200
+ if (existsSync8(PLIST_PATH)) {
3201
+ unlinkSync(PLIST_PATH);
2966
3202
  }
2967
3203
  }
2968
3204
  function setupLinuxSystemd(intervalMinutes) {
@@ -2972,13 +3208,30 @@ function setupLinuxSystemd(intervalMinutes) {
2972
3208
  execSync3("systemctl --user daemon-reload", { stdio: "ignore" });
2973
3209
  execSync3("systemctl --user enable --now conare-sync.timer", { stdio: "ignore" });
2974
3210
  }
2975
- function setupLinuxCron(intervalMinutes) {
2976
- const cronCmd = `${homedir7()}/.conare/bin/run.sh`;
2977
- const cronLine = `*/${intervalMinutes} * * * * ${cronCmd}`;
3211
+ var CRON_SAFE_INTERVALS = [1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30];
3212
+ function clampCronInterval(intervalMinutes) {
3213
+ const n = Number.isFinite(intervalMinutes) ? Math.round(intervalMinutes) : 10;
3214
+ if (n <= 0)
3215
+ return 10;
3216
+ let best = 10;
3217
+ let bestDist = Infinity;
3218
+ for (const safe of CRON_SAFE_INTERVALS) {
3219
+ const dist = Math.abs(n - safe);
3220
+ if (dist < bestDist) {
3221
+ bestDist = dist;
3222
+ best = safe;
3223
+ }
3224
+ }
3225
+ return best;
3226
+ }
3227
+ function setupCron(intervalMinutes) {
3228
+ const clamped = clampCronInterval(intervalMinutes);
3229
+ const cronCmd = `"${homedir7()}/.conare/bin/run.sh"`;
3230
+ const cronLine = `*/${clamped} * * * * ${cronCmd} # conare-sync`;
2978
3231
  try {
2979
3232
  const existing = execSync3("crontab -l 2>/dev/null", { encoding: "utf-8" });
2980
3233
  const filtered = existing.split(`
2981
- `).filter((l) => !l.includes("conare")).join(`
3234
+ `).filter((l) => !l.endsWith("# conare-sync") && !l.includes(".conare/bin/run.sh")).join(`
2982
3235
  `);
2983
3236
  const newCrontab = (filtered.trim() ? filtered.trim() + `
2984
3237
  ` : "") + cronLine + `
@@ -2989,6 +3242,47 @@ function setupLinuxCron(intervalMinutes) {
2989
3242
  `, stdio: ["pipe", "ignore", "ignore"] });
2990
3243
  }
2991
3244
  }
3245
+ function removeCronEntry() {
3246
+ try {
3247
+ const existing = execSync3("crontab -l 2>/dev/null", { encoding: "utf-8" });
3248
+ const lines = existing.split(`
3249
+ `);
3250
+ const filtered = lines.filter((l) => !l.endsWith("# conare-sync") && !l.includes(".conare/bin/run.sh"));
3251
+ if (filtered.length === lines.length)
3252
+ return false;
3253
+ const newCrontab = filtered.join(`
3254
+ `).trim();
3255
+ if (newCrontab) {
3256
+ execSync3("crontab -", { input: newCrontab + `
3257
+ `, stdio: ["pipe", "ignore", "ignore"] });
3258
+ } else {
3259
+ execSync3("crontab -", { input: `
3260
+ `, stdio: ["pipe", "ignore", "ignore"] });
3261
+ }
3262
+ return true;
3263
+ } catch {
3264
+ return false;
3265
+ }
3266
+ }
3267
+ function runSyncNow() {
3268
+ const os = platform6();
3269
+ try {
3270
+ if (os === "win32") {
3271
+ const runCmd = join9(BIN_DIR, "run.cmd");
3272
+ if (existsSync8(runCmd)) {
3273
+ execSync3(`"${runCmd}"`, { stdio: "ignore", timeout: 60000 });
3274
+ return true;
3275
+ }
3276
+ } else {
3277
+ const runSh = join9(BIN_DIR, "run.sh");
3278
+ if (existsSync8(runSh)) {
3279
+ execSync3(`/bin/bash "${runSh}"`, { stdio: "ignore", timeout: 60000 });
3280
+ return true;
3281
+ }
3282
+ }
3283
+ } catch {}
3284
+ return false;
3285
+ }
2992
3286
  function installGlobalCommand() {
2993
3287
  const isWindows = platform6() === "win32";
2994
3288
  if (isWindows) {
@@ -3104,13 +3398,20 @@ function persistAndInstallGlobal(apiKey) {
3104
3398
  messages.push(globalMsg);
3105
3399
  return messages;
3106
3400
  }
3401
+ function sanitizeInterval(n) {
3402
+ if (!Number.isFinite(n) || n <= 0)
3403
+ return 10;
3404
+ return Math.max(1, Math.round(n));
3405
+ }
3107
3406
  function installSync(apiKey, intervalMinutes = 10) {
3108
3407
  const messages = persistAndInstallGlobal(apiKey);
3109
3408
  const os = platform6();
3409
+ intervalMinutes = sanitizeInterval(intervalMinutes);
3110
3410
  if (os === "darwin") {
3111
- setupMacOS(intervalMinutes);
3112
- messages.push(`Installed launchd agent (every ${intervalMinutes} min)`);
3113
- messages.push(`Plist: ${PLIST_PATH}`);
3411
+ cleanupOldLaunchAgent();
3412
+ const actual = clampCronInterval(intervalMinutes);
3413
+ setupCron(intervalMinutes);
3414
+ messages.push(`Installed cron job (every ${actual} min)`);
3114
3415
  } else if (os === "win32") {
3115
3416
  setupWindows(intervalMinutes);
3116
3417
  messages.push(`Installed Windows Task Scheduler (every ${intervalMinutes} min)`);
@@ -3119,25 +3420,23 @@ function installSync(apiKey, intervalMinutes = 10) {
3119
3420
  setupLinuxSystemd(intervalMinutes);
3120
3421
  messages.push(`Installed systemd timer (every ${intervalMinutes} min)`);
3121
3422
  } else {
3122
- setupLinuxCron(intervalMinutes);
3123
- messages.push(`Installed cron job (every ${intervalMinutes} min)`);
3423
+ const actual = clampCronInterval(intervalMinutes);
3424
+ setupCron(intervalMinutes);
3425
+ messages.push(`Installed cron job (every ${actual} min)`);
3124
3426
  }
3125
3427
  } else {
3126
3428
  messages.push(`Unsupported platform: ${os}. Run manually: ~/.conare/bin/run.sh`);
3127
3429
  }
3430
+ const syncOk = runSyncNow();
3431
+ messages.push(syncOk ? "First sync completed" : "First sync deferred to next timer tick");
3128
3432
  return messages;
3129
3433
  }
3130
3434
  function uninstallSync() {
3131
3435
  const messages = [];
3132
3436
  const os = platform6();
3133
3437
  if (os === "darwin") {
3134
- try {
3135
- execSync3(`launchctl bootout gui/${uid()} "${PLIST_PATH}" 2>/dev/null`, { stdio: "ignore" });
3136
- } catch {}
3137
- if (existsSync8(PLIST_PATH)) {
3138
- unlinkSync(PLIST_PATH);
3139
- messages.push("Removed launchd agent");
3140
- }
3438
+ removeCronEntry() && messages.push("Removed cron job");
3439
+ cleanupOldLaunchAgent();
3141
3440
  } else if (os === "win32") {
3142
3441
  try {
3143
3442
  execSync3(`schtasks /Delete /TN "${TASK_NAME}" /F`, { stdio: "ignore" });
@@ -3157,25 +3456,18 @@ function uninstallSync() {
3157
3456
  } catch {}
3158
3457
  messages.push("Removed systemd timer");
3159
3458
  } else {
3160
- try {
3161
- const existing = execSync3("crontab -l 2>/dev/null", { encoding: "utf-8" });
3162
- const filtered = existing.split(`
3163
- `).filter((l) => !l.includes("conare")).join(`
3164
- `);
3165
- execSync3("crontab -", { input: filtered.trim() + `
3166
- `, stdio: ["pipe", "ignore", "ignore"] });
3167
- messages.push("Removed cron job");
3168
- } catch {}
3459
+ removeCronEntry() && messages.push("Removed cron job");
3169
3460
  }
3170
3461
  }
3171
- const filesToRemove = [
3172
- join9(CONARE_DIR, "config.json"),
3173
- join9(CONARE_DIR, "sync.lock")
3174
- ];
3175
- for (const f of filesToRemove) {
3176
- if (existsSync8(f))
3177
- unlinkSync(f);
3178
- }
3462
+ const configPath = join9(CONARE_DIR, "config.json");
3463
+ if (existsSync8(configPath))
3464
+ unlinkSync(configPath);
3465
+ const lockDir = join9(CONARE_DIR, "sync.lock.d");
3466
+ if (existsSync8(lockDir))
3467
+ rmSync2(lockDir, { recursive: true, force: true });
3468
+ const lockFile = join9(CONARE_DIR, "sync.lock");
3469
+ if (existsSync8(lockFile))
3470
+ unlinkSync(lockFile);
3179
3471
  if (existsSync8(BIN_DIR)) {
3180
3472
  rmSync2(BIN_DIR, { recursive: true, force: true });
3181
3473
  messages.push("Removed ~/.conare/bin/");
@@ -3233,10 +3525,12 @@ function renderProgressSummary(success, failed, noun) {
3233
3525
  return `\r \x1B[32m✓\x1B[0m [\x1B[36m${bar}\x1B[0m] ${success} ${noun}, ${failed} failed (${pct}%)${" ".repeat(12)}
3234
3526
  `;
3235
3527
  }
3236
- function renderDiscoverySummary(discovered, filtered, deduped) {
3237
- const parts = [`${discovered} ingestible`];
3238
- if (filtered > 0)
3239
- parts.push(`${filtered} filtered`);
3528
+ function renderDiscoverySummary(discovered, _filtered, deduped) {
3529
+ if (discovered === 0 && deduped === 0)
3530
+ return "no conversations found";
3531
+ if (discovered === 0 && deduped > 0)
3532
+ return `${deduped} already imported, nothing new`;
3533
+ const parts = [`${discovered} new`];
3240
3534
  if (deduped > 0)
3241
3535
  parts.push(`${deduped} already imported`);
3242
3536
  return parts.join(", ");
@@ -3420,7 +3714,6 @@ async function main() {
3420
3714
  let effectiveConfigOnly = opts.configOnly;
3421
3715
  let effectiveIngestOnly = opts.ingestOnly;
3422
3716
  let effectiveIndexPath = opts.indexPath;
3423
- let postIngestIndexPath;
3424
3717
  let selectedSources = opts.source ? [opts.source] : ["claude", "cursor", "codex"];
3425
3718
  let apiKey = opts.key || configFileKey || process.env.CONARE_API_KEY || savedApiKey;
3426
3719
  let interactiveTargets = MCP_TARGETS.map((target) => ({
@@ -3613,7 +3906,6 @@ Nothing new to index.`);
3613
3906
  write(renderProgressSummary(success, failed, "indexed"));
3614
3907
  const fileHashes = results.filter((result) => result.success).map((result) => getManifestFingerprint(memories[result.index])).filter((key) => !!key);
3615
3908
  markIngested("codebase", fileHashes);
3616
- addIndexedPath(absPath);
3617
3909
  if (!opts.quiet)
3618
3910
  printFailureSummary(results, memories);
3619
3911
  }
@@ -3694,6 +3986,22 @@ Nothing new to index.`);
3694
3986
  return db.localeCompare(da);
3695
3987
  });
3696
3988
  log();
3989
+ if (allMemories.length > 2000 && !opts.dryRun && !opts.quiet) {
3990
+ if (hasTty) {
3991
+ const { confirm: confirm2 } = await Promise.resolve().then(() => (init_dist2(), exports_dist));
3992
+ const proceed = await confirm2({
3993
+ message: `That's ${allMemories.length.toLocaleString()} memories — this may take a while and use significant resources. Continue?`
3994
+ });
3995
+ if (!proceed || typeof proceed === "symbol") {
3996
+ log("Aborted.");
3997
+ process.exit(0);
3998
+ }
3999
+ } else {
4000
+ log(`Warning: ${allMemories.length.toLocaleString()} memories detected. Skipping large upload in non-interactive mode.`);
4001
+ log("Re-run interactively or with --force to proceed.");
4002
+ process.exit(0);
4003
+ }
4004
+ }
3697
4005
  if (allMemories.length === 0) {
3698
4006
  log("Nothing new to upload.");
3699
4007
  } else if (opts.dryRun) {
@@ -3747,36 +4055,14 @@ Nothing new to index.`);
3747
4055
  }
3748
4056
  }
3749
4057
  log();
3750
- if (effectiveIngestOnly && !opts.dryRun) {
3751
- const savedPaths = getIndexedPaths();
3752
- for (const savedPath of savedPaths) {
3753
- if (!existsSync9(savedPath))
3754
- continue;
3755
- try {
3756
- const { memories: codeMemories, project } = indexCodebase(savedPath, { changedOnly: true });
3757
- if (codeMemories.length === 0)
3758
- continue;
3759
- log(` Re-indexing ${project}: ${codeMemories.length} changed files`);
3760
- const { success, failed, results } = await uploadBulk(apiKey, codeMemories, () => {});
3761
- if (!opts.quiet)
3762
- log(` ${project}: ${success} indexed, ${failed} failed`);
3763
- const fileHashes = results.filter((r2) => r2.success).map((r2) => getManifestFingerprint(codeMemories[r2.index])).filter((k3) => !!k3);
3764
- markIngested("codebase", fileHashes);
3765
- } catch {}
3766
- }
3767
- }
3768
4058
  if (interactiveMode) {
3769
4059
  selectedTargets = await selectMcpTargets(interactiveTargets);
3770
- const shouldIndexCurrentCodebase = await confirmIndexCodebase();
3771
- if (selectedTargets.length === 0 && selectedSources.length === 0 && !shouldIndexCurrentCodebase) {
4060
+ if (selectedTargets.length === 0 && selectedSources.length === 0) {
3772
4061
  effectiveConfigOnly = false;
3773
4062
  effectiveIngestOnly = false;
3774
4063
  } else {
3775
4064
  effectiveIngestOnly = selectedTargets.length === 0;
3776
4065
  }
3777
- if (shouldIndexCurrentCodebase) {
3778
- postIngestIndexPath = ".";
3779
- }
3780
4066
  finishSetup();
3781
4067
  }
3782
4068
  if (!opts.dryRun && !effectiveIngestOnly) {
@@ -3787,35 +4073,6 @@ Nothing new to index.`);
3787
4073
  for (const line of mcpLines)
3788
4074
  log(` ${line}`);
3789
4075
  }
3790
- if (postIngestIndexPath) {
3791
- const { resolve: resolve2 } = await import("node:path");
3792
- const absPath = resolve2(postIngestIndexPath);
3793
- const idxSpinner = Y2();
3794
- idxSpinner.start("Indexing codebase...");
3795
- const { memories, fileCount, skipped, project } = indexCodebase(absPath, {
3796
- project: opts.indexProject
3797
- });
3798
- idxSpinner.stop(`Codebase: ${fileCount} files found, ${skipped} skipped (project: ${project})`);
3799
- if (memories.length === 0) {
3800
- log(`
3801
- Nothing new to index.`);
3802
- } else {
3803
- const barWidth = 20;
3804
- const { success, failed, results } = await uploadBulk(apiKey, memories, (uploaded, total, _failed) => {
3805
- const pct = (uploaded / total * 100).toFixed(1);
3806
- const filled = Math.round(uploaded / total * barWidth);
3807
- const bar = "█".repeat(filled) + "░".repeat(barWidth - filled);
3808
- write(`\r Uploading [\x1B[36m${bar}\x1B[0m] ${uploaded}/${total} (${pct}%)`);
3809
- });
3810
- write(renderProgressSummary(success, failed, "indexed"));
3811
- const fileHashes = results.filter((result) => result.success).map((result) => getManifestFingerprint(memories[result.index])).filter((key) => !!key);
3812
- markIngested("codebase", fileHashes);
3813
- addIndexedPath(absPath);
3814
- if (!opts.quiet)
3815
- printFailureSummary(results, memories);
3816
- }
3817
- log("");
3818
- }
3819
4076
  if (!opts.dryRun && !opts.quiet) {
3820
4077
  try {
3821
4078
  persistAndInstallGlobal(apiKey);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "conare",
3
- "version": "0.4.3",
3
+ "version": "0.4.5",
4
4
  "description": "Conare CLI for ingesting AI chat history and configuring memory at conare.ai",
5
5
  "type": "module",
6
6
  "bin": {