chat-recall 0.5.29 → 0.5.30

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.
package/dist/cli.js CHANGED
@@ -7487,7 +7487,7 @@ async function archiveRawSession(store, sessionId) {
7487
7487
  return await store.putRawSession(sessionId, exp.tool, Math.floor(exp.mtime), gz, size);
7488
7488
  }
7489
7489
  function detectForkPredecessor(sessionPath) {
7490
- const { readFileSync: readFileSync50, readdirSync: readdirSync35 } = requireFs();
7490
+ const { readFileSync: readFileSync50, readdirSync: readdirSync36 } = requireFs();
7491
7491
  const { dirname: dirname28, join: join61, basename: basename30 } = requirePath();
7492
7492
  let text;
7493
7493
  try {
@@ -7517,7 +7517,7 @@ function detectForkPredecessor(sessionPath) {
7517
7517
  const self = basename30(sessionPath);
7518
7518
  let entries;
7519
7519
  try {
7520
- entries = readdirSync35(dir);
7520
+ entries = readdirSync36(dir);
7521
7521
  } catch {
7522
7522
  return null;
7523
7523
  }
@@ -19750,7 +19750,7 @@ var init_http = __esm({
19750
19750
  CLI_VERSION = JSON.parse(readFileSync33(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
19751
19751
  } catch {
19752
19752
  try {
19753
- if (true) CLI_VERSION = "0.5.29";
19753
+ if (true) CLI_VERSION = "0.5.30";
19754
19754
  } catch {
19755
19755
  }
19756
19756
  }
@@ -20262,7 +20262,7 @@ var init_telemetry = __esm({
20262
20262
  init_sync_client();
20263
20263
  cliVersion2 = () => {
20264
20264
  try {
20265
- return true ? "0.5.29" : "dev";
20265
+ return true ? "0.5.30" : "dev";
20266
20266
  } catch {
20267
20267
  return "dev";
20268
20268
  }
@@ -20599,12 +20599,13 @@ __export(auto_update_exports, {
20599
20599
  planAutoUpdate: () => planAutoUpdate,
20600
20600
  runAutoUpdate: () => runAutoUpdate,
20601
20601
  runningPrefix: () => runningPrefix,
20602
+ sweepStaleStaging: () => sweepStaleStaging,
20602
20603
  tarballUrl: () => tarballUrl
20603
20604
  });
20604
20605
  import { execSync as execSync2 } from "node:child_process";
20605
20606
  import { readFileSync as readFileSync36 } from "node:fs";
20606
20607
  import { fileURLToPath as fileURLToPath2 } from "node:url";
20607
- import { writeFileSync as writeFileSync8, mkdtempSync as mkdtempSync3 } from "node:fs";
20608
+ import { writeFileSync as writeFileSync8, mkdtempSync as mkdtempSync3, rmSync as rmSync5, readdirSync as readdirSync32, statSync as statSync38 } from "node:fs";
20608
20609
  import { join as join43, dirname as dirname18, sep as sep2 } from "node:path";
20609
20610
  import { tmpdir as tmpdir2 } from "node:os";
20610
20611
  import { createHash as createHash12 } from "node:crypto";
@@ -20643,6 +20644,31 @@ function planAutoUpdate(base2, caps, ownVersion3, flag) {
20643
20644
  if (compareVersions(rel.version, ownVersion3) <= 0) return { update: false, reason: `already current (own ${ownVersion3} >= server ${rel.version})` };
20644
20645
  return { update: true, reason: `server ${rel.version} > own ${ownVersion3}`, url: tarballUrl(base2), sha256: rel.sha256, from: ownVersion3, to: rel.version };
20645
20646
  }
20647
+ function sweepStaleStaging(root = tmpdir2(), now = Date.now()) {
20648
+ const MKDTEMP_SUFFIX = /^cr-update-.{6}$/s;
20649
+ const COLD_MS = 60 * 60 * 1e3;
20650
+ let removed = 0;
20651
+ let entries;
20652
+ try {
20653
+ entries = readdirSync32(root);
20654
+ } catch {
20655
+ return 0;
20656
+ }
20657
+ for (const name of entries) {
20658
+ if (!MKDTEMP_SUFFIX.test(name)) continue;
20659
+ const dir = join43(root, name);
20660
+ try {
20661
+ const st = statSync38(dir);
20662
+ if (!st.isDirectory() || now - st.mtimeMs < COLD_MS) continue;
20663
+ const inside = readdirSync32(dir);
20664
+ if (inside.length > 1 || inside.length === 1 && inside[0] !== "chat-recall.tgz") continue;
20665
+ rmSync5(dir, { recursive: true, force: true });
20666
+ removed++;
20667
+ } catch {
20668
+ }
20669
+ }
20670
+ return removed;
20671
+ }
20646
20672
  async function executeAutoUpdate(plan, deps) {
20647
20673
  if (!plan.update || !plan.url || !plan.sha256) return { updated: false, reason: plan.reason };
20648
20674
  let buf;
@@ -20654,13 +20680,21 @@ async function executeAutoUpdate(plan, deps) {
20654
20680
  const got = createHash12("sha256").update(buf).digest("hex");
20655
20681
  if (got !== plan.sha256) return { updated: false, reason: `checksum mismatch (expected ${plan.sha256.slice(0, 12)}\u2026, got ${got.slice(0, 12)}\u2026) \u2014 NOT installing` };
20656
20682
  const dir = mkdtempSync3(join43(tmpdir2(), "cr-update-"));
20683
+ const discardStaging = () => {
20684
+ try {
20685
+ rmSync5(dir, { recursive: true, force: true });
20686
+ } catch {
20687
+ }
20688
+ };
20657
20689
  const tgz = join43(dir, "chat-recall.tgz");
20658
20690
  writeFileSync8(tgz, buf);
20659
20691
  try {
20660
20692
  deps.install(tgz);
20661
20693
  } catch (e) {
20694
+ discardStaging();
20662
20695
  return { updated: false, reason: `install failed: ${e instanceof Error ? e.message : e}` };
20663
20696
  }
20697
+ discardStaging();
20664
20698
  const landed = (deps.verify ?? installedVersion)();
20665
20699
  if (landed && plan.to && compareVersions(landed, plan.to) < 0) {
20666
20700
  return {
@@ -20767,7 +20801,7 @@ __export(sync_client_exports, {
20767
20801
  syncSessions: () => syncSessions
20768
20802
  });
20769
20803
  import { join as join44, dirname as dirname19, basename as basename22 } from "node:path";
20770
- import { readFileSync as readFileSync37, writeFileSync as writeFileSync9, mkdirSync as mkdirSync9, mkdtempSync as mkdtempSync4, rmSync as rmSync5, chmodSync as chmodSync3, unlinkSync as unlinkSync2, readdirSync as readdirSync32, statSync as statSync38 } from "node:fs";
20804
+ import { readFileSync as readFileSync37, writeFileSync as writeFileSync9, mkdirSync as mkdirSync9, mkdtempSync as mkdtempSync4, rmSync as rmSync6, chmodSync as chmodSync3, unlinkSync as unlinkSync2, readdirSync as readdirSync33, statSync as statSync39 } from "node:fs";
20771
20805
  import { tmpdir as tmpdir3, hostname as hostname2 } from "node:os";
20772
20806
  import { createHash as createHash13 } from "node:crypto";
20773
20807
  import { fileURLToPath as fileURLToPath3 } from "node:url";
@@ -21139,7 +21173,7 @@ function reapStaleScanDirs(dir = tmpdir3(), maxAgeMs = 6 * 36e5, now = Date.now(
21139
21173
  let reaped = 0;
21140
21174
  let names;
21141
21175
  try {
21142
- names = readdirSync32(dir);
21176
+ names = readdirSync33(dir);
21143
21177
  } catch {
21144
21178
  return 0;
21145
21179
  }
@@ -21147,8 +21181,8 @@ function reapStaleScanDirs(dir = tmpdir3(), maxAgeMs = 6 * 36e5, now = Date.now(
21147
21181
  if (!name.startsWith("cr-batchscan-")) continue;
21148
21182
  const p = join44(dir, name);
21149
21183
  try {
21150
- if (now - statSync38(p).mtimeMs < maxAgeMs) continue;
21151
- rmSync5(p, { recursive: true, force: true });
21184
+ if (now - statSync39(p).mtimeMs < maxAgeMs) continue;
21185
+ rmSync6(p, { recursive: true, force: true });
21152
21186
  reaped++;
21153
21187
  } catch {
21154
21188
  }
@@ -21180,7 +21214,7 @@ function batchScanExternal(items, opts = {}) {
21180
21214
  slices++;
21181
21215
  }
21182
21216
  try {
21183
- rmSync5(scanDir, { recursive: true, force: true });
21217
+ rmSync6(scanDir, { recursive: true, force: true });
21184
21218
  } catch {
21185
21219
  }
21186
21220
  safeToId = /* @__PURE__ */ new Map();
@@ -21205,7 +21239,7 @@ function batchScanExternal(items, opts = {}) {
21205
21239
  flushSlice();
21206
21240
  } finally {
21207
21241
  try {
21208
- rmSync5(scanDir, { recursive: true, force: true });
21242
+ rmSync6(scanDir, { recursive: true, force: true });
21209
21243
  } catch {
21210
21244
  }
21211
21245
  }
@@ -21338,9 +21372,10 @@ async function syncToTargetInScope(cred, opts = {}) {
21338
21372
  setServerIngestConcurrency(base2, Math.floor(adv));
21339
21373
  }
21340
21374
  if (body2.cli && body2.cli.version) {
21341
- const { planAutoUpdate: planAutoUpdate2, runAutoUpdate: runAutoUpdate2 } = await Promise.resolve().then(() => (init_auto_update(), auto_update_exports));
21375
+ const { planAutoUpdate: planAutoUpdate2, runAutoUpdate: runAutoUpdate2, sweepStaleStaging: sweepStaleStaging2 } = await Promise.resolve().then(() => (init_auto_update(), auto_update_exports));
21342
21376
  const authHeaders = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
21343
21377
  const plan = planAutoUpdate2(base2, { cli: body2.cli }, ownVersion, process.env.CHAT_RECALL_AUTO_UPDATE);
21378
+ sweepStaleStaging2();
21344
21379
  if (plan.update) {
21345
21380
  void runAutoUpdate2(base2, authHeaders, ownVersion).catch(() => {
21346
21381
  });
@@ -21466,9 +21501,10 @@ async function syncToTargetInScope(cred, opts = {}) {
21466
21501
  if (!res.ok) throw new Error(`append sync failed: HTTP ${res.status} ${await res.text().catch(() => "")}`);
21467
21502
  const body = await res.json().catch(() => ({}));
21468
21503
  if (body.cli && body.cli.version) {
21469
- const { planAutoUpdate: planAutoUpdate2, runAutoUpdate: runAutoUpdate2 } = await Promise.resolve().then(() => (init_auto_update(), auto_update_exports));
21504
+ const { planAutoUpdate: planAutoUpdate2, runAutoUpdate: runAutoUpdate2, sweepStaleStaging: sweepStaleStaging2 } = await Promise.resolve().then(() => (init_auto_update(), auto_update_exports));
21470
21505
  const authHeaders = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
21471
21506
  const plan = planAutoUpdate2(base2, { cli: body.cli }, ownVersion, process.env.CHAT_RECALL_AUTO_UPDATE);
21507
+ sweepStaleStaging2();
21472
21508
  if (plan.update) {
21473
21509
  void runAutoUpdate2(base2, authHeaders, ownVersion).catch(() => {
21474
21510
  });
@@ -22270,7 +22306,7 @@ var init_sync_client = __esm({
22270
22306
  ownVersion = JSON.parse(readFileSync37(join44(dir, "../package.json"), "utf-8")).version || ownVersion;
22271
22307
  } catch {
22272
22308
  try {
22273
- if (true) ownVersion = "0.5.29";
22309
+ if (true) ownVersion = "0.5.30";
22274
22310
  } catch {
22275
22311
  }
22276
22312
  }
@@ -22384,11 +22420,11 @@ var init_update_notice = __esm({
22384
22420
  });
22385
22421
 
22386
22422
  // ../engine/dist/core/which.js
22387
- import { existsSync as existsSync43, statSync as statSync39, accessSync, constants } from "node:fs";
22423
+ import { existsSync as existsSync43, statSync as statSync40, accessSync, constants } from "node:fs";
22388
22424
  import { join as join46, isAbsolute as isAbsolute2, delimiter as delimiter2, sep as sep3 } from "node:path";
22389
22425
  function executable(p) {
22390
22426
  try {
22391
- if (!statSync39(p).isFile())
22427
+ if (!statSync40(p).isFile())
22392
22428
  return false;
22393
22429
  } catch {
22394
22430
  return false;
@@ -22524,7 +22560,7 @@ function registerMcpServersJson(target, path, spec) {
22524
22560
  entry.alwaysAllow = existing?.alwaysAllow ?? spec.alwaysAllow;
22525
22561
  if (spec.env)
22526
22562
  entry.env = { ...existing?.env, ...spec.env };
22527
- const isCurrent = !!existing && existing.command === spec.command && JSON.stringify(existing.args ?? null) === JSON.stringify(spec.args ?? null) && Object.entries(spec.env ?? {}).every(([k, v]) => existing.env?.[k] === v);
22563
+ const isCurrent = !!existing && !existing.disabled && existing.command === spec.command && JSON.stringify(existing.args ?? null) === JSON.stringify(spec.args ?? null) && Object.entries(spec.env ?? {}).every(([k, v]) => existing.env?.[k] === v);
22528
22564
  if (isCurrent)
22529
22565
  return { id: target.id, label: target.label, path, state: "current" };
22530
22566
  servers[MCP_SERVER_NAME] = entry;
@@ -22551,7 +22587,7 @@ function registerOpencodeJson(path, spec) {
22551
22587
  const entry = { type: "local", command: argv, enabled: true };
22552
22588
  if (spec.env)
22553
22589
  entry.environment = { ...existing?.environment, ...spec.env };
22554
- const isCurrent = !!existing && JSON.stringify(existing.command ?? null) === JSON.stringify(argv) && existing.enabled !== false && Object.entries(spec.env ?? {}).every(([k, v]) => existing.environment?.[k] === v);
22590
+ const isCurrent = !!existing && existing.type === "local" && existing.enabled === true && JSON.stringify(existing.command ?? null) === JSON.stringify(argv) && Object.entries(spec.env ?? {}).every(([k, v]) => existing.environment?.[k] === v);
22555
22591
  if (isCurrent)
22556
22592
  return { id, label, path, state: "current" };
22557
22593
  mcp[MCP_SERVER_NAME] = entry;
@@ -22730,7 +22766,7 @@ __export(companions_exports, {
22730
22766
  uninstallCodeindex: () => uninstallCodeindex,
22731
22767
  unregisterCodeindexMcp: () => unregisterCodeindexMcp
22732
22768
  });
22733
- import { existsSync as existsSync45, mkdirSync as mkdirSync11, statSync as statSync40, chmodSync as chmodSync4, unlinkSync as unlinkSync3, renameSync as renameSync5, createWriteStream, readFileSync as readFileSync40, writeFileSync as writeFileSync12 } from "node:fs";
22769
+ import { existsSync as existsSync45, mkdirSync as mkdirSync11, statSync as statSync41, chmodSync as chmodSync4, unlinkSync as unlinkSync3, renameSync as renameSync5, createWriteStream, readFileSync as readFileSync40, writeFileSync as writeFileSync12 } from "node:fs";
22734
22770
  import { homedir as homedir16 } from "node:os";
22735
22771
  import { join as join48 } from "node:path";
22736
22772
  import { execSync as execSync3 } from "node:child_process";
@@ -22781,7 +22817,7 @@ function checkCodeindexStatus() {
22781
22817
  status.installed = true;
22782
22818
  status.path = foundPath;
22783
22819
  try {
22784
- status.size = statSync40(foundPath).size;
22820
+ status.size = statSync41(foundPath).size;
22785
22821
  } catch {
22786
22822
  }
22787
22823
  try {
@@ -22931,7 +22967,7 @@ __export(install_skills_exports, {
22931
22967
  skillsSourceDir: () => skillsSourceDir,
22932
22968
  uninstallSkills: () => uninstallSkills
22933
22969
  });
22934
- import { readdirSync as readdirSync33, existsSync as existsSync46, mkdirSync as mkdirSync12, rmSync as rmSync6, cpSync, writeFileSync as writeFileSync13, readFileSync as readFileSync41, statSync as statSync41, realpathSync as realpathSync4 } from "fs";
22970
+ import { readdirSync as readdirSync34, existsSync as existsSync46, mkdirSync as mkdirSync12, rmSync as rmSync7, cpSync, writeFileSync as writeFileSync13, readFileSync as readFileSync41, statSync as statSync42, realpathSync as realpathSync4 } from "fs";
22935
22971
  import { createHash as createHash15 } from "crypto";
22936
22972
  import { join as join49, basename as basename23 } from "path";
22937
22973
  function skillsSourceDir() {
@@ -22957,7 +22993,7 @@ function skillsFingerprint() {
22957
22993
  }
22958
22994
  function filesUnder(dir, prefix = "") {
22959
22995
  const out = [];
22960
- for (const e of readdirSync33(dir, { withFileTypes: true })) {
22996
+ for (const e of readdirSync34(dir, { withFileTypes: true })) {
22961
22997
  if (e.name === MARKER) continue;
22962
22998
  const rel = prefix ? `${prefix}/${e.name}` : e.name;
22963
22999
  if (e.isDirectory()) out.push(...filesUnder(join49(dir, e.name), rel));
@@ -22971,7 +23007,7 @@ function skillStamp() {
22971
23007
  function bundledSkillNames() {
22972
23008
  const src = skillsSourceDir();
22973
23009
  if (!existsSync46(src)) return [];
22974
- return readdirSync33(src, { withFileTypes: true }).filter((e) => e.isDirectory() && existsSync46(join49(src, e.name, "SKILL.md"))).map((e) => e.name).sort();
23010
+ return readdirSync34(src, { withFileTypes: true }).filter((e) => e.isDirectory() && existsSync46(join49(src, e.name, "SKILL.md"))).map((e) => e.name).sort();
22975
23011
  }
22976
23012
  function realPathOrSelf(p) {
22977
23013
  try {
@@ -23044,7 +23080,7 @@ function installSkills(opts = {}) {
23044
23080
  continue;
23045
23081
  }
23046
23082
  mkdirSync12(t.dir, { recursive: true });
23047
- rmSync6(dest, { recursive: true, force: true });
23083
+ rmSync7(dest, { recursive: true, force: true });
23048
23084
  cpSync(join49(src, name), dest, { recursive: true });
23049
23085
  writeFileSync13(join49(dest, MARKER), `${stamp}
23050
23086
  `);
@@ -23063,11 +23099,11 @@ function uninstallSkills() {
23063
23099
  perTarget.push({ id: t.id, label: t.label, removed });
23064
23100
  continue;
23065
23101
  }
23066
- for (const entry of readdirSync33(t.dir, { withFileTypes: true })) {
23102
+ for (const entry of readdirSync34(t.dir, { withFileTypes: true })) {
23067
23103
  if (!entry.isDirectory()) continue;
23068
23104
  const dir = join49(t.dir, entry.name);
23069
23105
  if (isManaged(dir) && (names.has(entry.name) || entry.name.startsWith("chat-recall"))) {
23070
- rmSync6(dir, { recursive: true, force: true });
23106
+ rmSync7(dir, { recursive: true, force: true });
23071
23107
  removed.push(entry.name);
23072
23108
  }
23073
23109
  }
@@ -23748,11 +23784,11 @@ __export(toolkit_pull_exports, {
23748
23784
  planPull: () => planPull,
23749
23785
  portableCommand: () => portableCommand
23750
23786
  });
23751
- import { existsSync as existsSync48, mkdirSync as mkdirSync14, statSync as statSync42, writeFileSync as writeFileSync15 } from "node:fs";
23787
+ import { existsSync as existsSync48, mkdirSync as mkdirSync14, statSync as statSync43, writeFileSync as writeFileSync15 } from "node:fs";
23752
23788
  import { dirname as dirname22, join as join52, basename as basename26, isAbsolute as isAbsolute3 } from "node:path";
23753
23789
  function isExecutableFile(p) {
23754
23790
  try {
23755
- return statSync42(p).isFile();
23791
+ return statSync43(p).isFile();
23756
23792
  } catch {
23757
23793
  return false;
23758
23794
  }
@@ -25673,7 +25709,7 @@ __export(project_tasks_exports, {
25673
25709
  pushProjectTaskStatuses: () => pushProjectTaskStatuses,
25674
25710
  renderTeamTasksMd: () => renderTeamTasksMd
25675
25711
  });
25676
- import { existsSync as existsSync50, readFileSync as readFileSync45, writeFileSync as writeFileSync16, mkdirSync as mkdirSync15, statSync as statSync43 } from "node:fs";
25712
+ import { existsSync as existsSync50, readFileSync as readFileSync45, writeFileSync as writeFileSync16, mkdirSync as mkdirSync15, statSync as statSync44 } from "node:fs";
25677
25713
  import { join as join54, dirname as dirname23 } from "node:path";
25678
25714
  import { homedir as homedir19 } from "node:os";
25679
25715
  function isTeamTaskStatus(v) {
@@ -25762,7 +25798,7 @@ async function pushProjectTaskStatuses(base2, authHeaders, opts = {}) {
25762
25798
  if (!existsSync50(file)) continue;
25763
25799
  let mtime;
25764
25800
  try {
25765
- mtime = statSync43(file).mtimeMs;
25801
+ mtime = statSync44(file).mtimeMs;
25766
25802
  } catch {
25767
25803
  continue;
25768
25804
  }
@@ -25972,8 +26008,9 @@ async function drainSyncIntents(opts = {}) {
25972
26008
  const data = await res.json();
25973
26009
  pending = data.intents || [];
25974
26010
  if (data.cli && data.cli.version) {
25975
- const { planAutoUpdate: planAutoUpdate2, runAutoUpdate: runAutoUpdate2 } = await Promise.resolve().then(() => (init_auto_update(), auto_update_exports));
26011
+ const { planAutoUpdate: planAutoUpdate2, runAutoUpdate: runAutoUpdate2, sweepStaleStaging: sweepStaleStaging2 } = await Promise.resolve().then(() => (init_auto_update(), auto_update_exports));
25976
26012
  const plan = planAutoUpdate2(base2, { cli: data.cli }, ownVersion2, process.env.CHAT_RECALL_AUTO_UPDATE);
26013
+ sweepStaleStaging2();
25977
26014
  if (plan.update) {
25978
26015
  void runAutoUpdate2(base2, authHeaders, ownVersion2).catch(() => {
25979
26016
  });
@@ -26027,7 +26064,7 @@ var init_intent_drain = __esm({
26027
26064
  ownVersion2 = JSON.parse(readFileSync46(join55(dir, "../package.json"), "utf-8")).version || ownVersion2;
26028
26065
  } catch {
26029
26066
  try {
26030
- if (true) ownVersion2 = "0.5.29";
26067
+ if (true) ownVersion2 = "0.5.30";
26031
26068
  } catch {
26032
26069
  }
26033
26070
  }
@@ -26228,7 +26265,7 @@ var team_merge_exports = {};
26228
26265
  __export(team_merge_exports, {
26229
26266
  mergePullResult: () => mergePullResult
26230
26267
  });
26231
- import { existsSync as existsSync52, mkdirSync as mkdirSync17, readFileSync as readFileSync47, rmSync as rmSync7, writeFileSync as writeFileSync18, statSync as statSync44 } from "fs";
26268
+ import { existsSync as existsSync52, mkdirSync as mkdirSync17, readFileSync as readFileSync47, rmSync as rmSync8, writeFileSync as writeFileSync18, statSync as statSync45 } from "fs";
26232
26269
  import { dirname as dirname25, join as join56 } from "path";
26233
26270
  import { createHash as createHash18 } from "crypto";
26234
26271
  function installPathFor(art, tool) {
@@ -26345,7 +26382,7 @@ async function mergePullResult(opts) {
26345
26382
  continue;
26346
26383
  try {
26347
26384
  if (existsSync52(path))
26348
- rmSync7(path, { force: true });
26385
+ rmSync8(path, { force: true });
26349
26386
  await teamInstallsForget(id, row.tool);
26350
26387
  report.removed.push({ artifactId: id, path });
26351
26388
  } catch (err) {
@@ -26364,7 +26401,7 @@ function readFileIfExists(path) {
26364
26401
  try {
26365
26402
  if (!existsSync52(path))
26366
26403
  return null;
26367
- const s = statSync44(path);
26404
+ const s = statSync45(path);
26368
26405
  if (!s.isFile())
26369
26406
  return null;
26370
26407
  return readFileSync47(path);
@@ -26449,7 +26486,7 @@ var init_vault_crypto = __esm({
26449
26486
  });
26450
26487
 
26451
26488
  // ../engine/dist/core/vault-source.js
26452
- import { existsSync as existsSync53, readdirSync as readdirSync34, statSync as statSync45 } from "fs";
26489
+ import { existsSync as existsSync53, readdirSync as readdirSync35, statSync as statSync46 } from "fs";
26453
26490
  import { extname, join as join57 } from "path";
26454
26491
  function* walkVaultSources() {
26455
26492
  const t = loadSettings().team.vault;
@@ -26467,7 +26504,7 @@ function* walkVaultSources() {
26467
26504
  }
26468
26505
  function safeStat(path) {
26469
26506
  try {
26470
- const s = statSync45(path);
26507
+ const s = statSync46(path);
26471
26508
  if (!s.isFile())
26472
26509
  return null;
26473
26510
  return { mtimeMs: s.mtimeMs, size: s.size };
@@ -26481,7 +26518,7 @@ function* walkClaude() {
26481
26518
  return;
26482
26519
  let projectDirs = [];
26483
26520
  try {
26484
- projectDirs = readdirSync34(root);
26521
+ projectDirs = readdirSync35(root);
26485
26522
  } catch {
26486
26523
  return;
26487
26524
  }
@@ -26492,7 +26529,7 @@ function* walkClaude() {
26492
26529
  const projDir = join57(root, proj);
26493
26530
  let entries = [];
26494
26531
  try {
26495
- entries = readdirSync34(projDir);
26532
+ entries = readdirSync35(projDir);
26496
26533
  } catch {
26497
26534
  continue;
26498
26535
  }
@@ -26514,7 +26551,7 @@ function* walkGemini() {
26514
26551
  return;
26515
26552
  let hashDirs = [];
26516
26553
  try {
26517
- hashDirs = readdirSync34(tmp);
26554
+ hashDirs = readdirSync35(tmp);
26518
26555
  } catch {
26519
26556
  return;
26520
26557
  }
@@ -26524,7 +26561,7 @@ function* walkGemini() {
26524
26561
  continue;
26525
26562
  let entries = [];
26526
26563
  try {
26527
- entries = readdirSync34(chatsDir);
26564
+ entries = readdirSync35(chatsDir);
26528
26565
  } catch {
26529
26566
  continue;
26530
26567
  }
@@ -26570,7 +26607,7 @@ function* walkCodex() {
26570
26607
  const dir = stack.pop();
26571
26608
  let entries = [];
26572
26609
  try {
26573
- entries = readdirSync34(dir, { withFileTypes: true });
26610
+ entries = readdirSync35(dir, { withFileTypes: true });
26574
26611
  } catch {
26575
26612
  continue;
26576
26613
  }
@@ -26596,14 +26633,14 @@ function* walkAgy() {
26596
26633
  return;
26597
26634
  let sessionDirs = [];
26598
26635
  try {
26599
- sessionDirs = readdirSync34(brainDir);
26636
+ sessionDirs = readdirSync35(brainDir);
26600
26637
  } catch {
26601
26638
  return;
26602
26639
  }
26603
26640
  for (const rawId of sessionDirs) {
26604
26641
  const sessionPath = join57(brainDir, rawId);
26605
26642
  try {
26606
- if (!statSync45(sessionPath).isDirectory())
26643
+ if (!statSync46(sessionPath).isDirectory())
26607
26644
  continue;
26608
26645
  } catch {
26609
26646
  continue;
@@ -27084,7 +27121,7 @@ __export(service_installer_exports, {
27084
27121
  uninstallService: () => uninstallService
27085
27122
  });
27086
27123
  import { execSync as execSync5 } from "child_process";
27087
- import { existsSync as existsSync55, mkdirSync as mkdirSync19, rmSync as rmSync8, writeFileSync as writeFileSync20 } from "fs";
27124
+ import { existsSync as existsSync55, mkdirSync as mkdirSync19, rmSync as rmSync9, writeFileSync as writeFileSync20 } from "fs";
27088
27125
  import { homedir as homedir21 } from "os";
27089
27126
  import { join as join59 } from "path";
27090
27127
  import { fileURLToPath as fileURLToPath5 } from "url";
@@ -27240,7 +27277,7 @@ function uninstallService() {
27240
27277
  }
27241
27278
  const unitPath = join59(homedir21(), ".config", "systemd", "user", "chat-recall-watch.service");
27242
27279
  if (existsSync55(unitPath)) {
27243
- rmSync8(unitPath, { force: true });
27280
+ rmSync9(unitPath, { force: true });
27244
27281
  removed = true;
27245
27282
  }
27246
27283
  try {
@@ -27257,7 +27294,7 @@ function uninstallService() {
27257
27294
  }
27258
27295
  let removed = false;
27259
27296
  if (existsSync55(plistPath)) {
27260
- rmSync8(plistPath, { force: true });
27297
+ rmSync9(plistPath, { force: true });
27261
27298
  removed = true;
27262
27299
  }
27263
27300
  return removed;
@@ -27534,7 +27571,7 @@ init_tool_paths();
27534
27571
  init_project_resolver();
27535
27572
  import { config } from "dotenv";
27536
27573
  import { Command } from "commander";
27537
- import chalk from "chalk";
27574
+ import chalk2 from "chalk";
27538
27575
  import { existsSync as existsSync56, readFileSync as readFileSync49, writeFileSync as writeFileSync21, realpathSync as realpathSync5 } from "fs";
27539
27576
  import { homedir as homedir22 } from "os";
27540
27577
  import { join as join60, resolve as resolve2, dirname as dirname27, basename as basename29 } from "path";
@@ -27595,16 +27632,64 @@ function openBrowser(url) {
27595
27632
  init_which();
27596
27633
  init_collector_health();
27597
27634
  init_telemetry_consent();
27635
+
27636
+ // src/env-needed.ts
27637
+ import chalk from "chalk";
27638
+ function isSecret(name) {
27639
+ return /(TOKEN|KEY|SECRET|PASSWORD|CREDENTIAL|API_?KEY|PAT)\b/i.test(name);
27640
+ }
27641
+ function unusableHere(server) {
27642
+ const mac = /xcode|swift|apple|ios|macos/i.test(server);
27643
+ if (mac && process.platform !== "darwin") return "macOS only \u2014 nothing to do on this machine";
27644
+ return null;
27645
+ }
27646
+ function collectEnvNeeds(outcomes) {
27647
+ const byServer = /* @__PURE__ */ new Map();
27648
+ for (const o of outcomes) {
27649
+ if (!o.needsEnv?.length) continue;
27650
+ const set = byServer.get(o.name) ?? /* @__PURE__ */ new Set();
27651
+ for (const v of o.needsEnv) set.add(v);
27652
+ byServer.set(o.name, set);
27653
+ }
27654
+ return [...byServer.entries()].map(([server, vars]) => ({ server, vars: [...vars].sort() })).sort((a, b) => a.server.localeCompare(b.server));
27655
+ }
27656
+ function renderEnvNeeds(needs, installedCount) {
27657
+ if (!needs.length) return [];
27658
+ const lines = [];
27659
+ const plural = installedCount === 1 ? "server" : "servers";
27660
+ lines.push(
27661
+ chalk.yellow(`Installed ${installedCount} MCP ${plural} from your account. `) + chalk.yellow(`${needs.length === 1 ? "One needs" : `${needs.length} need`} values you must set here:`)
27662
+ );
27663
+ lines.push("");
27664
+ const width = Math.max(...needs.map((n) => n.server.length));
27665
+ let anySecret = false;
27666
+ for (const n of needs) {
27667
+ const note = unusableHere(n.server);
27668
+ anySecret ||= n.vars.some(isSecret);
27669
+ const name = chalk.bold(n.server.padEnd(width));
27670
+ const vars = n.vars.join(", ");
27671
+ lines.push(` ${name} ${vars}${note ? chalk.dim(` (${note})`) : ""}`);
27672
+ }
27673
+ lines.push("");
27674
+ lines.push(chalk.dim(" Add them to your shell profile, then restart your AI tool."));
27675
+ lines.push(chalk.dim(" Until then these servers will fail to start."));
27676
+ if (anySecret) {
27677
+ lines.push(chalk.dim(" chat-recall never uploads secret values \u2014 only the variable names."));
27678
+ }
27679
+ return lines;
27680
+ }
27681
+
27682
+ // src/cli.ts
27598
27683
  function matchLabel(tier) {
27599
27684
  switch (tier) {
27600
27685
  case "strong":
27601
- return chalk.green("strong");
27686
+ return chalk2.green("strong");
27602
27687
  case "good":
27603
- return chalk.yellow("good");
27688
+ return chalk2.yellow("good");
27604
27689
  case "weak":
27605
- return chalk.dim("weak");
27690
+ return chalk2.dim("weak");
27606
27691
  default:
27607
- return chalk.dim("unranked");
27692
+ return chalk2.dim("unranked");
27608
27693
  }
27609
27694
  }
27610
27695
  config({ quiet: true });
@@ -27639,13 +27724,13 @@ function describeProbeError(err) {
27639
27724
  }
27640
27725
  function failLogin(opts, message) {
27641
27726
  if (opts.fromInit) throw new Error(message);
27642
- console.error(chalk.red("login failed:"), message);
27727
+ console.error(chalk2.red("login failed:"), message);
27643
27728
  process.exit(1);
27644
27729
  }
27645
27730
  function requireTarget() {
27646
27731
  const t = firstTarget();
27647
27732
  if (!t) {
27648
- console.error(chalk.red("Not logged in."), "Run", chalk.bold("chat-recall login <server-url>"), "first.");
27733
+ console.error(chalk2.red("Not logged in."), "Run", chalk2.bold("chat-recall login <server-url>"), "first.");
27649
27734
  process.exit(1);
27650
27735
  }
27651
27736
  return t;
@@ -27803,7 +27888,7 @@ var program = new Command();
27803
27888
  program.name("chat-recall").description("Semantic search for Claude Code sessions - recall and resume past conversations").version(pkgVersion);
27804
27889
  program.command("init").description("Set up chat-recall: connect to your server, configure MCP, ship your local sessions").option("--server <url>", "chat-recall server URL to connect this machine to").option("--token <token>", "Self-host device token (skips the interactive OIDC login)").option("--skip-mcp", "Skip MCP server configuration").option("--skip-sync", "Skip the first session sync").option("--with-codeindex", "Force-download the codeindex binary during init. Default behavior is to detect an already-installed codeindex on PATH and register it as an MCP server.").option("--skip-codeindex", "Skip the codeindex companion entirely (no detection, no registration).").option("--skip-service", "Skip installing the per-user background sync service (Linux/macOS/Windows). By default init installs it so new conversations ship automatically.").option("--yes", "Do not pause before the first upload. The scope summary still prints.", false).option("--prompt-json", "Print the device prompt as one JSON line on stdout, then continue", false).action(async (options) => {
27805
27890
  try {
27806
- console.log(chalk.bold("chat-recall init") + chalk.dim(` v${pkgVersion}`));
27891
+ console.log(chalk2.bold("chat-recall init") + chalk2.dim(` v${pkgVersion}`));
27807
27892
  const { createInitReporter: createInitReporter2 } = await Promise.resolve().then(() => (init_init_report(), init_report_exports));
27808
27893
  const rep = createInitReporter2({
27809
27894
  tty: process.stdout.isTTY === true,
@@ -27827,8 +27912,8 @@ program.command("init").description("Set up chat-recall: connect to your server,
27827
27912
  }
27828
27913
  }
27829
27914
  const foundTools = clis.filter((c) => c.available).map((c) => c.name.replace(/ (CLI|Code)$/, ""));
27830
- if (!foundTools.length) rep.warn(chalk.yellow("No AI tools detected \u2014 chat-recall indexes their transcripts, so there is nothing to ship yet."));
27831
- const serverBad = (text) => rep.warn(`${chalk.yellow("Not connected")} \u2014 ${text}`);
27915
+ if (!foundTools.length) rep.warn(chalk2.yellow("No AI tools detected \u2014 chat-recall indexes their transcripts, so there is nothing to ship yet."));
27916
+ const serverBad = (text) => rep.warn(`${chalk2.yellow("Not connected")} \u2014 ${text}`);
27832
27917
  let target = firstTarget();
27833
27918
  let deadTarget = false;
27834
27919
  if (options.server) {
@@ -27852,24 +27937,24 @@ program.command("init").description("Set up chat-recall: connect to your server,
27852
27937
  if (probeOk2(probe)) {
27853
27938
  } else if (probe.kind === "moved" || probe.kind === "not_api") {
27854
27939
  const retired = target.base;
27855
- console.log(` ${chalk.yellow("The saved server no longer serves chat-recall")} \u2192 ${retired}`);
27940
+ console.log(` ${chalk2.yellow("The saved server no longer serves chat-recall")} \u2192 ${retired}`);
27856
27941
  console.log(` ${probeAdvice2(probe, retired)}`);
27857
- console.log(` Switching to ${chalk.bold(DEFAULT_SERVER)} \u2014 sign in to approve this machine.`);
27942
+ console.log(` Switching to ${chalk2.bold(DEFAULT_SERVER)} \u2014 sign in to approve this machine.`);
27858
27943
  try {
27859
27944
  await runLogin(DEFAULT_SERVER, { token: options.token, fromInit: true, promptJson: options.promptJson });
27860
27945
  const { removeCredentials: removeCredentials2 } = await Promise.resolve().then(() => (init_sync_client(), sync_client_exports));
27861
27946
  if (removeCredentials2(retired)) {
27862
- console.log(` ${chalk.dim(`Removed the retired target ${retired} (log in there again any time).`)}`);
27947
+ console.log(` ${chalk2.dim(`Removed the retired target ${retired} (log in there again any time).`)}`);
27863
27948
  }
27864
27949
  target = firstTarget();
27865
- if (target) console.log(` ${chalk.green("Connected")} \u2192 ${target.base}`);
27950
+ if (target) console.log(` ${chalk2.green("Connected")} \u2192 ${target.base}`);
27866
27951
  } catch (e) {
27867
27952
  serverBad(describeProbeError(e));
27868
- console.log(` ${chalk.dim(`Run ${chalk.bold(`chat-recall login ${DEFAULT_SERVER}`)} when ready, then ${chalk.bold(`chat-recall logout ${retired}`)}.`)}`);
27953
+ console.log(` ${chalk2.dim(`Run ${chalk2.bold(`chat-recall login ${DEFAULT_SERVER}`)} when ready, then ${chalk2.bold(`chat-recall logout ${retired}`)}.`)}`);
27869
27954
  deadTarget = true;
27870
27955
  }
27871
27956
  } else {
27872
- console.log(` ${chalk.yellow("Saved server did not answer")} \u2192 ${target.base}`);
27957
+ console.log(` ${chalk2.yellow("Saved server did not answer")} \u2192 ${target.base}`);
27873
27958
  console.log(` ${probeAdvice2(probe, target.base)}`);
27874
27959
  }
27875
27960
  } else if (target) {
@@ -27899,8 +27984,8 @@ program.command("init").description("Set up chat-recall: connect to your server,
27899
27984
  }
27900
27985
  for (const r of bad) {
27901
27986
  const why = (r.error ?? "").replace(/^SyntaxError:\s*/, "").split("\n")[0];
27902
- rep.warn(`${chalk.yellow(`${r.label} config left alone \u2014 ${why || "the file does not parse"}`)} ${chalk.dim(r.path)}`);
27903
- rep.warn(`${chalk.dim(` fix that file, then: chat-recall init (nothing else needs redoing)`)}`);
27987
+ rep.warn(`${chalk2.yellow(`${r.label} config left alone \u2014 ${why || "the file does not parse"}`)} ${chalk2.dim(r.path)}`);
27988
+ rep.warn(`${chalk2.dim(` fix that file, then: chat-recall init (nothing else needs redoing)`)}`);
27904
27989
  }
27905
27990
  if (process.env.CHAT_RECALL_VERBOSE) {
27906
27991
  }
@@ -27932,14 +28017,14 @@ program.command("init").description("Set up chat-recall: connect to your server,
27932
28017
  const reg = registerCodeindexMcp2(mcpJsonPath, CODEINDEX_BIN_PATH2);
27933
28018
  }
27934
28019
  } else if (!result.prebuiltAvailable) {
27935
- rep.warn(`${chalk.yellow("codeindex")}: ${result.unsupportedReason}`);
28020
+ rep.warn(`${chalk2.yellow("codeindex")}: ${result.unsupportedReason}`);
27936
28021
  }
27937
28022
  } catch (err) {
27938
28023
  const msg = String(err);
27939
- rep.warn(`${chalk.yellow("codeindex install failed")}: ${msg}`);
28024
+ rep.warn(`${chalk2.yellow("codeindex install failed")}: ${msg}`);
27940
28025
  if (msg.includes("404")) {
27941
- console.log(chalk.dim(" The codeindex release returned 404. If the repo is private,"));
27942
- console.log(chalk.dim(" authenticate `gh` to it, or build from source."));
28026
+ console.log(chalk2.dim(" The codeindex release returned 404. If the repo is private,"));
28027
+ console.log(chalk2.dim(" authenticate `gh` to it, or build from source."));
27943
28028
  }
27944
28029
  }
27945
28030
  } else {
@@ -27955,7 +28040,7 @@ program.command("init").description("Set up chat-recall: connect to your server,
27955
28040
  }
27956
28041
  const userOwned = [...new Set(r.perTarget.flatMap((t) => t.skippedUserOwned))];
27957
28042
  } catch (err) {
27958
- rep.warn(`${chalk.yellow("Skill install failed")} \u2014 ${err instanceof Error ? err.message : err}`);
28043
+ rep.warn(`${chalk2.yellow("Skill install failed")} \u2014 ${err instanceof Error ? err.message : err}`);
27959
28044
  }
27960
28045
  if (!options.skipMcp && firstTarget()) {
27961
28046
  try {
@@ -27993,28 +28078,30 @@ program.command("init").description("Set up chat-recall: connect to your server,
27993
28078
  const written = report.outcomes.filter((o) => o.status === "written");
27994
28079
  const present = report.outcomes.filter((o) => o.status === "present").length;
27995
28080
  if (answered === 0) {
27996
- rep.warn(chalk.yellow("Could not ask your server what MCP servers are on your account"));
27997
- for (const f of askFailed) console.log(` ${chalk.dim(f)}`);
27998
- console.log(` ${chalk.dim("Re-run `chat-recall toolkit pull` once the server answers.")}`);
28081
+ rep.warn(chalk2.yellow("Could not ask your server what MCP servers are on your account"));
28082
+ for (const f of askFailed) console.log(` ${chalk2.dim(f)}`);
28083
+ console.log(` ${chalk2.dim("Re-run `chat-recall toolkit pull` once the server answers.")}`);
27999
28084
  } else if (written.length === 0 && present === 0) {
28000
28085
  } else {
28001
- const envVars = [...new Set(written.flatMap((o) => o.needsEnv || []))].sort();
28002
- if (envVars.length) {
28003
- rep.warn(`${chalk.yellow("Set these env vars \u2014 their values were never uploaded:")} ${envVars.join(", ")}`);
28086
+ const needs = collectEnvNeeds(written);
28087
+ if (needs.length) {
28088
+ const [head, ...rest] = renderEnvNeeds(needs, written.length);
28089
+ rep.warn(head);
28090
+ for (const line of rest) console.log(line);
28004
28091
  }
28005
28092
  }
28006
28093
  } catch (err) {
28007
- rep.warn(`${chalk.yellow("Could not install account MCPs")} \u2014 ${err instanceof Error ? err.message : err}`);
28008
- console.log(` ${chalk.dim("Re-run `chat-recall toolkit pull` later.")}`);
28094
+ rep.warn(`${chalk2.yellow("Could not install account MCPs")} \u2014 ${err instanceof Error ? err.message : err}`);
28095
+ console.log(` ${chalk2.dim("Re-run `chat-recall toolkit pull` later.")}`);
28009
28096
  }
28010
28097
  }
28011
28098
  if (deadTarget) {
28012
- console.log(chalk.bold("Skipping first sync \u2014 the saved server is not serving chat-recall"));
28013
- console.log(` ${chalk.dim(`Re-point with the two commands above, then run ${chalk.bold("chat-recall sync")}.`)}`);
28099
+ console.log(chalk2.bold("Skipping first sync \u2014 the saved server is not serving chat-recall"));
28100
+ console.log(` ${chalk2.dim(`Re-point with the two commands above, then run ${chalk2.bold("chat-recall sync")}.`)}`);
28014
28101
  } else if (!options.skipSync && firstTarget()) {
28015
28102
  const { watchFirstSync: watchFirstSync2, spawnDetachedSync: spawnDetachedSync2, handOffLine: handOffLine2, progressLine: renderProgress } = await Promise.resolve().then(() => (init_init_progress(), init_progress_exports));
28016
28103
  const { readCollectorHealth: readCollectorHealth2 } = await Promise.resolve().then(() => (init_collector_health(), collector_health_exports));
28017
- const label = (text) => `${chalk.bold("Indexing")} ${text}`;
28104
+ const label = (text) => `${chalk2.bold("Indexing")} ${text}`;
28018
28105
  const tty = process.stdout.isTTY === true;
28019
28106
  const outcome = await watchFirstSync2({
28020
28107
  startWorker: () => spawnDetachedSync2(),
@@ -28032,22 +28119,22 @@ program.command("init").description("Set up chat-recall: connect to your server,
28032
28119
  });
28033
28120
  if (tty) process.stdout.write("\r");
28034
28121
  if (outcome.finished) {
28035
- console.log(label(chalk.green(renderProgress(outcome.snapshot))));
28122
+ console.log(label(chalk2.green(renderProgress(outcome.snapshot))));
28036
28123
  } else {
28037
- console.log(label(chalk.dim(handOffLine2(outcome.snapshot))));
28038
- console.log(` ${chalk.dim("watch it with: " + chalk.bold("chat-recall status"))}`);
28124
+ console.log(label(chalk2.dim(handOffLine2(outcome.snapshot))));
28125
+ console.log(` ${chalk2.dim("watch it with: " + chalk2.bold("chat-recall status"))}`);
28039
28126
  }
28040
28127
  const failed = Object.entries(readCollectorHealth2()?.targets ?? {}).filter(([, t]) => (t.failures ?? 0) > 0 && t.lastError);
28041
28128
  for (const [server, t] of failed) {
28042
- console.log(` ${chalk.yellow("sync error")} ${chalk.dim(server)}: ${t.lastError}`);
28129
+ console.log(` ${chalk2.yellow("sync error")} ${chalk2.dim(server)}: ${t.lastError}`);
28043
28130
  }
28044
28131
  } else if (!options.skipSync) {
28045
28132
  } else {
28046
28133
  }
28047
28134
  void options.skipService;
28048
- rep.done(chalk.green.bold("\u2713 Done"));
28135
+ rep.done(chalk2.green.bold("\u2713 Done"));
28049
28136
  } catch (err) {
28050
- console.error(chalk.red("Error:"), err);
28137
+ console.error(chalk2.red("Error:"), err);
28051
28138
  process.exit(1);
28052
28139
  }
28053
28140
  });
@@ -28057,57 +28144,57 @@ program.command("install-skills").description("Install the chat-recall skills in
28057
28144
  const r2 = mod.uninstallSkills();
28058
28145
  const hits2 = r2.perTarget.filter((t) => t.removed.length > 0);
28059
28146
  if (!hits2.length) {
28060
- console.log(chalk.dim("No chat-recall skills were installed."));
28147
+ console.log(chalk2.dim("No chat-recall skills were installed."));
28061
28148
  return;
28062
28149
  }
28063
- for (const t of hits2) console.log(`${chalk.green("\u2713")} ${t.label}: removed ${t.removed.length} skill(s)`);
28150
+ for (const t of hits2) console.log(`${chalk2.green("\u2713")} ${t.label}: removed ${t.removed.length} skill(s)`);
28064
28151
  return;
28065
28152
  }
28066
28153
  const r = mod.installSkills({ onlyAvailable: !opts.allTools });
28067
28154
  const names = mod.bundledSkillNames();
28068
- console.log(chalk.bold(`Installing ${names.length} chat-recall skill(s) (v${r.version}):`), chalk.dim(names.join(", ")));
28155
+ console.log(chalk2.bold(`Installing ${names.length} chat-recall skill(s) (v${r.version}):`), chalk2.dim(names.join(", ")));
28069
28156
  const hits = r.perTarget.filter((t) => t.installed.length > 0);
28070
28157
  if (!hits.length) {
28071
- console.log(chalk.yellow("No supported AI tools detected. Use --all-tools to install anyway."));
28158
+ console.log(chalk2.yellow("No supported AI tools detected. Use --all-tools to install anyway."));
28072
28159
  return;
28073
28160
  }
28074
- for (const t of hits) console.log(`${chalk.green("\u2713")} ${t.label}: ${t.installed.length} \u2192 ${chalk.dim(t.dir)}`);
28161
+ for (const t of hits) console.log(`${chalk2.green("\u2713")} ${t.label}: ${t.installed.length} \u2192 ${chalk2.dim(t.dir)}`);
28075
28162
  const userOwned = [...new Set(r.perTarget.flatMap((t) => t.skippedUserOwned))];
28076
- if (userOwned.length) console.log(chalk.yellow(`Kept your existing skill(s) of the same name: ${userOwned.join(", ")}`));
28163
+ if (userOwned.length) console.log(chalk2.yellow(`Kept your existing skill(s) of the same name: ${userOwned.join(", ")}`));
28077
28164
  });
28078
28165
  program.command("index").description("Collect local sessions and ship them to your server (alias for sync)").option("-f, --force", "Ignore the per-server ledger and re-ship everything", false).action(async (options) => {
28079
28166
  try {
28080
28167
  const { syncSessions: syncSessions2 } = await Promise.resolve().then(() => (init_sync_client(), sync_client_exports));
28081
28168
  const r = await syncSessions2(options.force ? { useLedger: false } : {});
28082
- console.log(chalk.green(`\u2713 Synced ${r.uploaded} session(s), ${r.items} item(s)`) + chalk.dim(` \u2014 ${r.links} links, ${r.derived} derived rows, ${r.kgTriples} KG triples, ${r.skipped} skipped, ${r.redactions} secrets redacted, ${r.findings} secret findings${r.scanned ? ` (scanned ${r.scanned} in ${r.scanMs}ms)` : ""}`));
28169
+ console.log(chalk2.green(`\u2713 Synced ${r.uploaded} session(s), ${r.items} item(s)`) + chalk2.dim(` \u2014 ${r.links} links, ${r.derived} derived rows, ${r.kgTriples} KG triples, ${r.skipped} skipped, ${r.redactions} secrets redacted, ${r.findings} secret findings${r.scanned ? ` (scanned ${r.scanned} in ${r.scanMs}ms)` : ""}`));
28083
28170
  } catch (err) {
28084
- console.error(chalk.red("Error:"), err instanceof Error ? err.message : err);
28171
+ console.error(chalk2.red("Error:"), err instanceof Error ? err.message : err);
28085
28172
  process.exit(1);
28086
28173
  }
28087
28174
  });
28088
28175
  program.command("repair [sessionIds...]").description("Rebuild sessions an upstream tool truncated in place (e.g. Claude Code resume rewrite) from the shrink-protected raw archive. DRY-RUN by default \u2014 pass --apply to write.").option("--all", "Scan the recency window and repair EVERY damaged session (no ids needed)", false).option("--since-hours <n>", "With --all: only scan sessions modified in the last N hours", "72").option("--apply", "Actually write the recovered conversations to the server(s). Without this, nothing is mutated.", false).option("--server <url>", "Target ONLY this server (e.g. the SaaS), instead of every configured sync endpoint").option("--force", "Push even to servers that already look full", false).option("-v, --verbose", "Per-session detail", false).action(async (sessionIds, options) => {
28089
28176
  try {
28090
- const mode = options.apply ? chalk.red("APPLY (writing to server)") : chalk.cyan("DRY-RUN (read-only)");
28177
+ const mode = options.apply ? chalk2.red("APPLY (writing to server)") : chalk2.cyan("DRY-RUN (read-only)");
28091
28178
  const render = (r) => {
28092
28179
  const head = `${r.sessionId.slice(0, 8)}\u2026`;
28093
28180
  if (r.status === "no-archive") {
28094
- console.log(chalk.yellow(` ? ${head} no archive found`));
28181
+ console.log(chalk2.yellow(` ? ${head} no archive found`));
28095
28182
  return;
28096
28183
  }
28097
28184
  if (r.status === "already-full") {
28098
- console.log(chalk.dim(` = ${head} already full (${r.fullestMessages} msgs)`));
28185
+ console.log(chalk2.dim(` = ${head} already full (${r.fullestMessages} msgs)`));
28099
28186
  return;
28100
28187
  }
28101
28188
  if (r.status === "error") {
28102
- console.log(chalk.red(` \u2717 ${head} ${r.note}`));
28189
+ console.log(chalk2.red(` \u2717 ${head} ${r.note}`));
28103
28190
  return;
28104
28191
  }
28105
28192
  const verb = r.status === "would-repair" ? "would recover" : "recovered";
28106
- console.log(chalk.green(` ${r.status === "would-repair" ? "\xB7" : "+"} ${head} ${verb} ${r.fullestMessages} msgs`) + chalk.dim(` from ${r.fullestSource}`));
28107
- for (const p of r.pushed) console.log(chalk.dim(` ${p.server}: ${p.before} \u2192 ${p.after}`));
28193
+ console.log(chalk2.green(` ${r.status === "would-repair" ? "\xB7" : "+"} ${head} ${verb} ${r.fullestMessages} msgs`) + chalk2.dim(` from ${r.fullestSource}`));
28194
+ for (const p of r.pushed) console.log(chalk2.dim(` ${p.server}: ${p.before} \u2192 ${p.after}`));
28108
28195
  };
28109
28196
  if (options.all) {
28110
- console.log(chalk.bold(`repair --all \xB7 ${mode} \xB7 window ${options.sinceHours}h`));
28197
+ console.log(chalk2.bold(`repair --all \xB7 ${mode} \xB7 window ${options.sinceHours}h`));
28111
28198
  const { repairAll: repairAll2 } = await Promise.resolve().then(() => (init_repair(), repair_exports));
28112
28199
  const report = await repairAll2({
28113
28200
  sinceHours: Number(options.sinceHours) || 72,
@@ -28118,24 +28205,24 @@ program.command("repair [sessionIds...]").description("Rebuild sessions an upstr
28118
28205
  report.candidates.forEach(render);
28119
28206
  const fixed2 = report.candidates.filter((r) => r.status === "repaired").length;
28120
28207
  const would2 = report.candidates.filter((r) => r.status === "would-repair").length;
28121
- console.log(chalk.bold(
28208
+ console.log(chalk2.bold(
28122
28209
  `Scanned ${report.scanned} session(s) on ${report.discoveryServer}; ` + (options.apply ? `repaired ${fixed2}.` : `${would2} damaged, would repair. Re-run with --apply to write.`)
28123
28210
  ));
28124
28211
  return;
28125
28212
  }
28126
28213
  if (!sessionIds || sessionIds.length === 0) {
28127
- console.error(chalk.red("Give session ids, or use --all. e.g. `chat-recall repair <uuid>` or `chat-recall repair --all`."));
28214
+ console.error(chalk2.red("Give session ids, or use --all. e.g. `chat-recall repair <uuid>` or `chat-recall repair --all`."));
28128
28215
  process.exit(1);
28129
28216
  }
28130
- console.log(chalk.bold(`repair \xB7 ${mode}`));
28217
+ console.log(chalk2.bold(`repair \xB7 ${mode}`));
28131
28218
  const { repairSessions: repairSessions2 } = await Promise.resolve().then(() => (init_repair(), repair_exports));
28132
28219
  const results = await repairSessions2(sessionIds, { dryRun: !options.apply, force: options.force, verbose: options.verbose, server: options.server });
28133
28220
  results.forEach(render);
28134
28221
  const fixed = results.filter((r) => r.status === "repaired").length;
28135
28222
  const would = results.filter((r) => r.status === "would-repair").length;
28136
- console.log(chalk.bold(options.apply ? `Repaired ${fixed} session(s).` : `${would} session(s) would be repaired. Re-run with --apply to write.`));
28223
+ console.log(chalk2.bold(options.apply ? `Repaired ${fixed} session(s).` : `${would} session(s) would be repaired. Re-run with --apply to write.`));
28137
28224
  } catch (err) {
28138
- console.error(chalk.red("Error:"), err instanceof Error ? err.message : err);
28225
+ console.error(chalk2.red("Error:"), err instanceof Error ? err.message : err);
28139
28226
  process.exit(1);
28140
28227
  }
28141
28228
  });
@@ -28145,11 +28232,11 @@ program.command("search <query>").description("Search your server for relevant s
28145
28232
  const remote = await serverPost("/api/search", { query, topK, projectFilter: options.project });
28146
28233
  const results = remote.results;
28147
28234
  if (results.length === 0) {
28148
- console.log(chalk.yellow("No matching sessions found."));
28235
+ console.log(chalk2.yellow("No matching sessions found."));
28149
28236
  process.exit(0);
28150
28237
  }
28151
28238
  console.log();
28152
- console.log(`${chalk.bold("Results for:")} "${query}"`);
28239
+ console.log(`${chalk2.bold("Results for:")} "${query}"`);
28153
28240
  console.log();
28154
28241
  const tiers = tierAll(results);
28155
28242
  for (let i = 0; i < results.length; i++) {
@@ -28158,13 +28245,13 @@ program.command("search <query>").description("Search your server for relevant s
28158
28245
  if (projectPath.length > 50) projectPath = "..." + projectPath.slice(-47);
28159
28246
  let title = (result.firstPrompt || "").replace(/\n/g, " ").trim();
28160
28247
  if (title.length > 80) title = title.slice(0, 80) + "...";
28161
- console.log(`${chalk.bold.cyan(`#${i + 1}`)} ${title}`);
28162
- if (projectPath) console.log(` ${chalk.dim("Project:")} ${projectPath}`);
28163
- console.log(` ${chalk.dim("Match:")} ${matchLabel(tiers[i])}`);
28248
+ console.log(`${chalk2.bold.cyan(`#${i + 1}`)} ${title}`);
28249
+ if (projectPath) console.log(` ${chalk2.dim("Project:")} ${projectPath}`);
28250
+ console.log(` ${chalk2.dim("Match:")} ${matchLabel(tiers[i])}`);
28164
28251
  if (result.summary) {
28165
28252
  let summary = result.summary.replace(/\n/g, " ").trim();
28166
28253
  if (summary.length > 200) summary = summary.slice(0, 200) + "...";
28167
- console.log(` ${chalk.yellow("Summary:")} ${summary}`);
28254
+ console.log(` ${chalk2.yellow("Summary:")} ${summary}`);
28168
28255
  }
28169
28256
  const chunk = (result.matchedChunks || []).find(
28170
28257
  (c) => c.chunkType !== "summary" && c.chunkType !== "first_prompt"
@@ -28173,16 +28260,16 @@ program.command("search <query>").description("Search your server for relevant s
28173
28260
  const label = chunk.chunkType === "assistant" ? "Discussed" : chunk.chunkType === "user_context" ? "Asked about" : chunk.chunkType === "tool_result" ? "Tool result" : "Context";
28174
28261
  let text = chunk.text.replace(/\n/g, " ").trim();
28175
28262
  if (text.length > 150) text = text.slice(0, 150) + "...";
28176
- console.log(` ${chalk.magenta(label + ":")} ${text}`);
28263
+ console.log(` ${chalk2.magenta(label + ":")} ${text}`);
28177
28264
  }
28178
28265
  {
28179
28266
  const rc = resumeCommandFor(result.sessionId);
28180
- if (rc) console.log(` ${chalk.green("Resume:")} ${rc}`);
28267
+ if (rc) console.log(` ${chalk2.green("Resume:")} ${rc}`);
28181
28268
  }
28182
28269
  console.log();
28183
28270
  }
28184
28271
  } catch (err) {
28185
- console.error(chalk.red("Error:"), err instanceof Error ? err.message : err);
28272
+ console.error(chalk2.red("Error:"), err instanceof Error ? err.message : err);
28186
28273
  process.exit(1);
28187
28274
  }
28188
28275
  });
@@ -28190,7 +28277,7 @@ program.command("status").description("Show your server's sync status and statis
28190
28277
  try {
28191
28278
  const status = await serverGet("/api/status");
28192
28279
  const sync = await serverGet("/api/status/sync");
28193
- console.log(chalk.bold("Chat-Recall Server Status"));
28280
+ console.log(chalk2.bold("Chat-Recall Server Status"));
28194
28281
  console.log();
28195
28282
  console.log(`Synced sessions: ${sync.sessions}`);
28196
28283
  console.log(`FTS5 chunks: ${status.totalChunks}`);
@@ -28202,34 +28289,34 @@ program.command("status").description("Show your server's sync status and statis
28202
28289
  const types = Object.entries(sync.sourceTypes).filter(([, n]) => Number(n) > 0);
28203
28290
  if (types.length > 0) {
28204
28291
  console.log();
28205
- console.log(chalk.bold("By source type:"));
28292
+ console.log(chalk2.bold("By source type:"));
28206
28293
  for (const [type, n] of types) console.log(` ${type}: ${n} items`);
28207
28294
  }
28208
28295
  const projects = Object.entries(status.projects || {}).sort((a, b) => b[1] - a[1]).slice(0, 10);
28209
28296
  if (projects.length > 0) {
28210
28297
  console.log();
28211
- console.log(chalk.bold("Top projects:"));
28298
+ console.log(chalk2.bold("Top projects:"));
28212
28299
  for (const [proj, n] of projects) console.log(` ${proj}: ${n} sessions`);
28213
28300
  }
28214
28301
  } catch (err) {
28215
- console.error(chalk.red("Error:"), err instanceof Error ? err.message : err);
28302
+ console.error(chalk2.red("Error:"), err instanceof Error ? err.message : err);
28216
28303
  process.exit(1);
28217
28304
  }
28218
28305
  });
28219
28306
  program.command("optimize").description("Deprecated: storage is server-side now, nothing to optimize locally").action(() => {
28220
- console.log(chalk.dim("Storage is server-side now; there is no local index to optimize."));
28221
- console.log(chalk.dim("Run `chat-recall sync` to ship sessions; the server manages its own storage."));
28307
+ console.log(chalk2.dim("Storage is server-side now; there is no local index to optimize."));
28308
+ console.log(chalk2.dim("Run `chat-recall sync` to ship sessions; the server manages its own storage."));
28222
28309
  process.exit(0);
28223
28310
  });
28224
28311
  program.command("show <session_id>").description("Show conversation content from a session (requires login)").option("-m, --messages <number>", "Number of messages to show", "10").option("-f, --full", "Show full conversation (all messages)", false).action(async (sessionId, options) => {
28225
28312
  try {
28226
28313
  const soft = await serverGetSoft(`/api/conversations/${encodeURIComponent(sessionId)}?limit=0`);
28227
28314
  if (!soft.data || soft.data.messages.length === 0) {
28228
- console.log(chalk.yellow(soft.message || `Session not found: ${sessionId}`));
28315
+ console.log(chalk2.yellow(soft.message || `Session not found: ${sessionId}`));
28229
28316
  process.exit(soft.status === 404 ? 1 : 0);
28230
28317
  }
28231
28318
  const messagesList = soft.data.messages;
28232
- console.log(chalk.bold("Session:"), sessionId);
28319
+ console.log(chalk2.bold("Session:"), sessionId);
28233
28320
  console.log();
28234
28321
  const maxMessages = parseInt(options.messages, 10);
28235
28322
  const displayMessages = options.full ? messagesList : messagesList.slice(0, maxMessages);
@@ -28237,22 +28324,22 @@ program.command("show <session_id>").description("Show conversation content from
28237
28324
  let text = msg.content;
28238
28325
  if (!options.full && text.length > 1e3) text = text.slice(0, 1e3) + "...";
28239
28326
  if (msg.role === "user") {
28240
- console.log(`${chalk.bold.blue("User")} ${chalk.dim(`(line ${msg.line})`)}`);
28327
+ console.log(`${chalk2.bold.blue("User")} ${chalk2.dim(`(line ${msg.line})`)}`);
28241
28328
  } else if (msg.role === "assistant") {
28242
- console.log(`${chalk.bold.green("Assistant")} ${chalk.dim(`(line ${msg.line})`)}`);
28329
+ console.log(`${chalk2.bold.green("Assistant")} ${chalk2.dim(`(line ${msg.line})`)}`);
28243
28330
  } else {
28244
- console.log(chalk.bold.yellow(msg.role));
28331
+ console.log(chalk2.bold.yellow(msg.role));
28245
28332
  }
28246
28333
  console.log(text);
28247
28334
  console.log();
28248
28335
  }
28249
- console.log(chalk.dim(`Showing ${displayMessages.length} of ${messagesList.length} messages. Use --full for the complete conversation.`));
28336
+ console.log(chalk2.dim(`Showing ${displayMessages.length} of ${messagesList.length} messages. Use --full for the complete conversation.`));
28250
28337
  {
28251
28338
  const rc = resumeCommandFor(sessionId);
28252
- if (rc) console.log(chalk.dim(`Resume: ${rc}`));
28339
+ if (rc) console.log(chalk2.dim(`Resume: ${rc}`));
28253
28340
  }
28254
28341
  } catch (err) {
28255
- console.error(chalk.red("Error:"), err instanceof Error ? err.message : err);
28342
+ console.error(chalk2.red("Error:"), err instanceof Error ? err.message : err);
28256
28343
  process.exit(1);
28257
28344
  }
28258
28345
  });
@@ -28261,9 +28348,9 @@ memory.command("index").description("Collect local sessions and ship them to you
28261
28348
  try {
28262
28349
  const { syncSessions: syncSessions2 } = await Promise.resolve().then(() => (init_sync_client(), sync_client_exports));
28263
28350
  const r = await syncSessions2(options.force ? { useLedger: false } : {});
28264
- console.log(chalk.green(`\u2713 Synced ${r.uploaded} session(s), ${r.items} item(s)`) + chalk.dim(` \u2014 ${r.links} links, ${r.derived} derived rows, ${r.kgTriples} KG triples, ${r.skipped} skipped, ${r.redactions} secrets redacted, ${r.findings} secret findings${r.scanned ? ` (scanned ${r.scanned} in ${r.scanMs}ms)` : ""}`));
28351
+ console.log(chalk2.green(`\u2713 Synced ${r.uploaded} session(s), ${r.items} item(s)`) + chalk2.dim(` \u2014 ${r.links} links, ${r.derived} derived rows, ${r.kgTriples} KG triples, ${r.skipped} skipped, ${r.redactions} secrets redacted, ${r.findings} secret findings${r.scanned ? ` (scanned ${r.scanned} in ${r.scanMs}ms)` : ""}`));
28265
28352
  } catch (err) {
28266
- console.error(chalk.red("Error:"), err instanceof Error ? err.message : err);
28353
+ console.error(chalk2.red("Error:"), err instanceof Error ? err.message : err);
28267
28354
  process.exit(1);
28268
28355
  }
28269
28356
  });
@@ -28274,55 +28361,55 @@ memory.command("search <query>").description("Search across all memory types on
28274
28361
  const remote = await serverPost("/api/memory/search", { query, topK, sourceTypes });
28275
28362
  const results = remote.results;
28276
28363
  if (results.length === 0) {
28277
- console.log(chalk.yellow("No matching results found."));
28364
+ console.log(chalk2.yellow("No matching results found."));
28278
28365
  process.exit(0);
28279
28366
  }
28280
28367
  console.log();
28281
- console.log(`${chalk.bold("Memory search:")} "${query}"`);
28368
+ console.log(`${chalk2.bold("Memory search:")} "${query}"`);
28282
28369
  console.log();
28283
28370
  const tiers = tierAll(results);
28284
28371
  for (let i = 0; i < results.length; i++) {
28285
28372
  const r = results[i];
28286
28373
  const typeColor = {
28287
- session: chalk.blue,
28288
- plan: chalk.green,
28289
- task: chalk.yellow,
28290
- claude_md: chalk.magenta,
28291
- history: chalk.cyan,
28292
- paste: chalk.gray,
28293
- diary: chalk.redBright
28294
- }[r.sourceType] || chalk.white;
28374
+ session: chalk2.blue,
28375
+ plan: chalk2.green,
28376
+ task: chalk2.yellow,
28377
+ claude_md: chalk2.magenta,
28378
+ history: chalk2.cyan,
28379
+ paste: chalk2.gray,
28380
+ diary: chalk2.redBright
28381
+ }[r.sourceType] || chalk2.white;
28295
28382
  const typeBadge = typeColor(`[${r.sourceType}]`);
28296
28383
  let title = (r.title || "").replace(/\n/g, " ").trim();
28297
28384
  if (title.length > 70) title = title.slice(0, 67) + "...";
28298
- console.log(`${chalk.bold.cyan(`#${i + 1}`)} ${typeBadge} ${title}`);
28385
+ console.log(`${chalk2.bold.cyan(`#${i + 1}`)} ${typeBadge} ${title}`);
28299
28386
  if (r.projectPath) {
28300
28387
  let pp = r.projectPath;
28301
28388
  if (pp.length > 50) pp = "..." + pp.slice(-47);
28302
- console.log(` ${chalk.dim("Project:")} ${pp}`);
28389
+ console.log(` ${chalk2.dim("Project:")} ${pp}`);
28303
28390
  }
28304
- const typeSuffix = r.chunkType ? ` ${chalk.dim("Type:")} ${r.chunkType}` : "";
28305
- console.log(` ${chalk.dim("Match:")} ${matchLabel(tiers[i])}${typeSuffix}`);
28391
+ const typeSuffix = r.chunkType ? ` ${chalk2.dim("Type:")} ${r.chunkType}` : "";
28392
+ console.log(` ${chalk2.dim("Match:")} ${matchLabel(tiers[i])}${typeSuffix}`);
28306
28393
  let preview = (r.text || "").replace(/\n/g, " ").trim();
28307
28394
  if (preview.length > 150) preview = preview.slice(0, 147) + "...";
28308
28395
  if (preview) console.log(` ${preview}`);
28309
28396
  if (r.sourceType === "session") {
28310
28397
  {
28311
28398
  const rc = resumeCommandFor(r.itemId);
28312
- if (rc) console.log(` ${chalk.green("Resume:")} ${rc}`);
28399
+ if (rc) console.log(` ${chalk2.green("Resume:")} ${rc}`);
28313
28400
  }
28314
28401
  }
28315
28402
  console.log();
28316
28403
  }
28317
28404
  } catch (err) {
28318
- console.error(chalk.red("Error:"), err instanceof Error ? err.message : err);
28405
+ console.error(chalk2.red("Error:"), err instanceof Error ? err.message : err);
28319
28406
  process.exit(1);
28320
28407
  }
28321
28408
  });
28322
28409
  memory.command("status").description("Show your server's memory statistics across all source types (requires login)").action(async () => {
28323
28410
  try {
28324
28411
  const status = await serverGet("/api/memory/status");
28325
- console.log(chalk.bold("Memory System Status"));
28412
+ console.log(chalk2.bold("Memory System Status"));
28326
28413
  console.log();
28327
28414
  console.log(`Total items: ${status.totalItems}`);
28328
28415
  console.log(`FTS5 chunks: ${status.totalChunks}`);
@@ -28330,7 +28417,7 @@ memory.command("status").description("Show your server's memory statistics acros
28330
28417
  const bySource = Object.entries(status.bySourceType || {});
28331
28418
  if (bySource.length > 0) {
28332
28419
  console.log();
28333
- console.log(chalk.bold("By source type:"));
28420
+ console.log(chalk2.bold("By source type:"));
28334
28421
  for (const [type, data] of bySource) {
28335
28422
  console.log(` ${type}: ${data.items} items, ${data.chunks} chunks`);
28336
28423
  }
@@ -28338,14 +28425,14 @@ memory.command("status").description("Show your server's memory statistics acros
28338
28425
  const byTool = Object.entries(status.bySourceAndTool || {});
28339
28426
  if (byTool.length > 0) {
28340
28427
  console.log();
28341
- console.log(chalk.bold("By source type and tool:"));
28428
+ console.log(chalk2.bold("By source type and tool:"));
28342
28429
  for (const [type, tools] of byTool) {
28343
28430
  const parts = Object.entries(tools).map(([t, n]) => `${t}: ${n}`).join(", ");
28344
28431
  console.log(` ${type}: ${parts}`);
28345
28432
  }
28346
28433
  }
28347
28434
  } catch (err) {
28348
- console.error(chalk.red("Error:"), err instanceof Error ? err.message : err);
28435
+ console.error(chalk2.red("Error:"), err instanceof Error ? err.message : err);
28349
28436
  process.exit(1);
28350
28437
  }
28351
28438
  });
@@ -28353,20 +28440,20 @@ memory.command("links <source_type> <item_id>").description("Show relationships
28353
28440
  try {
28354
28441
  const { links } = await serverGet(`/api/memory/links/${encodeURIComponent(sourceType)}/${encodeURIComponent(itemId)}`);
28355
28442
  if (links.length === 0) {
28356
- console.log(chalk.yellow("No links found."));
28443
+ console.log(chalk2.yellow("No links found."));
28357
28444
  return;
28358
28445
  }
28359
- console.log(chalk.bold(`Links for ${sourceType}:${itemId}`));
28446
+ console.log(chalk2.bold(`Links for ${sourceType}:${itemId}`));
28360
28447
  console.log();
28361
28448
  for (const link of links) {
28362
28449
  const direction = link.source_id === itemId ? "->" : "<-";
28363
28450
  const otherType = link.source_id === itemId ? link.target_type : link.source_type;
28364
28451
  const otherId = link.source_id === itemId ? link.target_id : link.source_id;
28365
28452
  const confidence = Math.round(link.confidence * 100);
28366
- console.log(` ${direction} ${chalk.bold(otherType)}:${otherId.slice(0, 20)} [${link.link_type}] (${confidence}%)`);
28453
+ console.log(` ${direction} ${chalk2.bold(otherType)}:${otherId.slice(0, 20)} [${link.link_type}] (${confidence}%)`);
28367
28454
  }
28368
28455
  } catch (err) {
28369
- console.error(chalk.red("Error:"), err instanceof Error ? err.message : err);
28456
+ console.error(chalk2.red("Error:"), err instanceof Error ? err.message : err);
28370
28457
  process.exit(1);
28371
28458
  }
28372
28459
  });
@@ -28378,27 +28465,27 @@ memory.command("wake-up").description("Generate wake-up context (high-importance
28378
28465
  identity = readFileSync49(identityFile, "utf-8").trim();
28379
28466
  }
28380
28467
  const lines = [
28381
- chalk.bold("# Wake-Up Context"),
28382
- chalk.bold("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),
28468
+ chalk2.bold("# Wake-Up Context"),
28469
+ chalk2.bold("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),
28383
28470
  "",
28384
- chalk.bold("## Identity"),
28471
+ chalk2.bold("## Identity"),
28385
28472
  identity,
28386
28473
  ""
28387
28474
  ];
28388
28475
  const qs = options.project ? `?project_filter=${encodeURIComponent(options.project)}` : "";
28389
28476
  const wake = await serverGet(`/api/memory/wake-up${qs}`);
28390
28477
  if (wake.highFacts.length > 0) {
28391
- lines.push(chalk.bold("## High-Importance Facts"));
28478
+ lines.push(chalk2.bold("## High-Importance Facts"));
28392
28479
  for (const fact of wake.highFacts) {
28393
28480
  lines.push(` [${fact.type}] ${fact.text}`);
28394
28481
  }
28395
28482
  lines.push("");
28396
28483
  }
28397
28484
  if (wake.kg.facts.length > 0) {
28398
- lines.push(chalk.bold("## Knowledge Graph"));
28485
+ lines.push(chalk2.bold("## Knowledge Graph"));
28399
28486
  const { entities, current_facts } = wake.kg.stats;
28400
28487
  if (entities !== void 0 || current_facts !== void 0) {
28401
- lines.push(chalk.dim(`${entities ?? 0} entities, ${current_facts ?? 0} current facts`));
28488
+ lines.push(chalk2.dim(`${entities ?? 0} entities, ${current_facts ?? 0} current facts`));
28402
28489
  }
28403
28490
  for (const fact of wake.kg.facts) {
28404
28491
  lines.push(` ${fact.subject} \u2192 ${fact.predicate} \u2192 ${fact.object}`);
@@ -28407,32 +28494,75 @@ memory.command("wake-up").description("Generate wake-up context (high-importance
28407
28494
  }
28408
28495
  console.log(lines.join("\n"));
28409
28496
  } catch (err) {
28410
- console.error(chalk.red("Error:"), err instanceof Error ? err.message : err);
28497
+ console.error(chalk2.red("Error:"), err instanceof Error ? err.message : err);
28411
28498
  process.exit(1);
28412
28499
  }
28413
28500
  });
28414
28501
  program.command("escalate [sessionId]").description("Escalate a finished session's learnings (decisions, user corrections, outcome) into the knowledge graph (requires login)").option("--latest", "Pick the most recent synced session of the current project").option("-p, --project <name>", "Knowledge-graph entity name for the facts (default: project folder name)").option("--dry-run", "Extract and print the learnings without writing them").action(async (sessionId, opts) => {
28415
28502
  if (!sessionId && !opts.latest) {
28416
- console.error(chalk.red("Pass a session id or --latest."));
28503
+ console.error(chalk2.red("Pass a session id or --latest."));
28417
28504
  process.exit(1);
28418
28505
  }
28419
28506
  const target = firstTarget();
28420
28507
  if (!target) {
28421
- console.log(chalk.dim("escalate: not logged in \u2014 nothing to do. Run `chat-recall login <server-url>` to enable learnings escalation."));
28508
+ console.log(chalk2.dim("escalate: not logged in \u2014 nothing to do. Run `chat-recall login <server-url>` to enable learnings escalation."));
28422
28509
  return;
28423
28510
  }
28424
28511
  try {
28425
28512
  const { runEscalate: runEscalate2 } = await Promise.resolve().then(() => (init_escalate(), escalate_exports));
28426
28513
  await runEscalate2(
28427
- { get: serverGet, getSoft: serverGetSoft, post: serverPost, log: (line) => console.log(chalk.dim(line)) },
28514
+ { get: serverGet, getSoft: serverGetSoft, post: serverPost, log: (line) => console.log(chalk2.dim(line)) },
28428
28515
  { sessionId, latest: opts.latest, project: opts.project, dryRun: opts.dryRun, cwd: process.cwd() }
28429
28516
  );
28430
28517
  } catch (err) {
28431
- console.log(chalk.dim(`escalate: skipped \u2014 ${err instanceof Error ? err.message : err}`));
28518
+ console.log(chalk2.dim(`escalate: skipped \u2014 ${err instanceof Error ? err.message : err}`));
28519
+ }
28520
+ });
28521
+ program.command("feedback").argument("<message...>", "what you want to say \u2014 anything at all").description("Send a message to the people who build chat-recall. No account needed.").option("--email <address>", "so we can reply; optional").action(async (words, opts) => {
28522
+ const message = words.join(" ").trim();
28523
+ if (message.length < 3) {
28524
+ console.error(chalk2.red("Say a little more than that."));
28525
+ process.exitCode = 1;
28526
+ return;
28527
+ }
28528
+ const target = firstTarget();
28529
+ const base2 = target?.base || (process.env.CHAT_RECALL_SERVER || "https://chatrecall.dev").replace(/\/+$/, "");
28530
+ try {
28531
+ const res = await fetch(`${base2}/api/contact/feedback`, {
28532
+ method: "POST",
28533
+ headers: {
28534
+ "content-type": "application/json",
28535
+ // Attached when logged in so a reply can find the account. Absent is
28536
+ // fine and expected.
28537
+ ...target ? { authorization: `Bearer ${target.token}` } : {}
28538
+ },
28539
+ body: JSON.stringify({
28540
+ message,
28541
+ email: opts.email ?? null,
28542
+ cliVersion: pkgVersion,
28543
+ os: `${process.platform}-${process.arch}`
28544
+ }),
28545
+ signal: AbortSignal.timeout(1e4)
28546
+ });
28547
+ if (!res.ok) {
28548
+ const body = await res.json().catch(() => ({}));
28549
+ console.error(chalk2.red(`Could not send: ${body.error || res.status}`));
28550
+ process.exitCode = 1;
28551
+ return;
28552
+ }
28553
+ console.log(chalk2.green("Sent. Thank you \u2014 this genuinely gets read."));
28554
+ if (!opts.email) {
28555
+ console.log(chalk2.dim(" Add --email <address> next time if you want a reply."));
28556
+ }
28557
+ } catch (err) {
28558
+ console.error(chalk2.red(`Could not reach ${base2}.`));
28559
+ console.error(chalk2.dim(" Your message, so it is not lost:"));
28560
+ console.error(chalk2.dim(` ${message}`));
28561
+ process.exitCode = 1;
28432
28562
  }
28433
28563
  });
28434
28564
  program.command("doctor").description("Quick health check across login, server, credentials, hooks, MCP server, and codeindex").option("--purge-local", "Remove the legacy local index (cache.db + vector/KG files) left by pre-thin-collector versions \u2014 storage is server-side now. Requires login; keeps credentials, sync ledger, identity, and the audit log.").action(async (opts) => {
28435
- const { existsSync: existsSync57, readFileSync: readFileSync50, statSync: statSync46 } = await import("fs");
28565
+ const { existsSync: existsSync57, readFileSync: readFileSync50, statSync: statSync47 } = await import("fs");
28436
28566
  const { execSync: execSync6 } = await import("child_process");
28437
28567
  const rows = [];
28438
28568
  const note = (ok, label, detail) => rows.push({ ok, label, detail });
@@ -28500,7 +28630,7 @@ program.command("doctor").description("Quick health check across login, server,
28500
28630
  note(false, "Credentials file", `missing \u2014 run \`chat-recall login <server-url>\``);
28501
28631
  } else {
28502
28632
  try {
28503
- const mode = statSync46(credFile).mode & 511;
28633
+ const mode = statSync47(credFile).mode & 511;
28504
28634
  const isWin = process.platform === "win32";
28505
28635
  const safe = isWin || (mode & 63) === 0;
28506
28636
  note(safe, "Credentials file", isWin ? `${credFile} (Windows ACL \u2014 POSIX mode does not apply)` : `${credFile} (mode ${mode.toString(8).padStart(3, "0")}${safe ? "" : " \u2014 should be 600"})`);
@@ -28638,11 +28768,11 @@ program.command("doctor").description("Quick health check across login, server,
28638
28768
  } else if (legacyPresent.length === 0) {
28639
28769
  note(true, "Purge legacy index", "nothing to remove");
28640
28770
  } else {
28641
- const { rmSync: rmSync9 } = await import("fs");
28771
+ const { rmSync: rmSync10 } = await import("fs");
28642
28772
  let removed = 0;
28643
28773
  for (const p of legacyPresent) {
28644
28774
  try {
28645
- rmSync9(p, { recursive: true, force: true });
28775
+ rmSync10(p, { recursive: true, force: true });
28646
28776
  removed++;
28647
28777
  } catch {
28648
28778
  }
@@ -28654,67 +28784,67 @@ program.command("doctor").description("Quick health check across login, server,
28654
28784
  } else {
28655
28785
  note(true, "Legacy local index", "none (clean)");
28656
28786
  }
28657
- console.log(chalk.bold("\nchat-recall doctor\n"));
28787
+ console.log(chalk2.bold("\nchat-recall doctor\n"));
28658
28788
  for (const r of rows) {
28659
- const icon = r.ok ? chalk.green("\u2713") : chalk.yellow("\u2022");
28660
- console.log(` ${icon} ${r.label.padEnd(28)} ${chalk.dim(r.detail || "")}`);
28789
+ const icon = r.ok ? chalk2.green("\u2713") : chalk2.yellow("\u2022");
28790
+ console.log(` ${icon} ${r.label.padEnd(28)} ${chalk2.dim(r.detail || "")}`);
28661
28791
  }
28662
28792
  const failures = rows.filter((r) => !r.ok).length;
28663
28793
  console.log();
28664
28794
  if (failures === 0) {
28665
- console.log(chalk.green("All systems green."));
28795
+ console.log(chalk2.green("All systems green."));
28666
28796
  } else {
28667
- console.log(chalk.dim(`${failures} item${failures === 1 ? "" : "s"} need attention.`));
28797
+ console.log(chalk2.dim(`${failures} item${failures === 1 ? "" : "s"} need attention.`));
28668
28798
  }
28669
28799
  });
28670
28800
  var companions = program.command("companions").description("Manage companion tools (codeindex)");
28671
28801
  companions.command("status").description("Show whether codeindex is installed and what it provides").action(async () => {
28672
28802
  const { checkCodeindexStatus: checkCodeindexStatus2 } = await Promise.resolve().then(() => (init_companions(), companions_exports));
28673
28803
  const s = checkCodeindexStatus2();
28674
- console.log(chalk.bold("codeindex status"));
28804
+ console.log(chalk2.bold("codeindex status"));
28675
28805
  if (s.installed) {
28676
- console.log(` ${chalk.green("\u2713 installed")}`);
28806
+ console.log(` ${chalk2.green("\u2713 installed")}`);
28677
28807
  if (s.path) console.log(` path: ${s.path}`);
28678
28808
  if (s.size) console.log(` size: ${(s.size / 1024 / 1024).toFixed(1)} MB`);
28679
28809
  if (s.version) console.log(` version: ${s.version}`);
28680
28810
  } else {
28681
- console.log(` ${chalk.yellow("not installed")}`);
28811
+ console.log(` ${chalk2.yellow("not installed")}`);
28682
28812
  if (!s.prebuiltAvailable) {
28683
- console.log(` ${chalk.dim(s.unsupportedReason || "no prebuilt binary for this platform")}`);
28813
+ console.log(` ${chalk2.dim(s.unsupportedReason || "no prebuilt binary for this platform")}`);
28684
28814
  } else {
28685
- console.log(` ${chalk.dim(`run \`chat-recall companions install\` to fetch ${s.artifactName}`)}`);
28815
+ console.log(` ${chalk2.dim(`run \`chat-recall companions install\` to fetch ${s.artifactName}`)}`);
28686
28816
  }
28687
28817
  }
28688
28818
  console.log();
28689
- console.log(chalk.dim("codeindex provides code-level lookup as a separate MCP server:"));
28690
- console.log(chalk.dim(" find_symbol, find_callers, get_imports, plan_change,"));
28691
- console.log(chalk.dim(" get_change_impact, analyze (security/dead_code/coupling/cycles/...)"));
28819
+ console.log(chalk2.dim("codeindex provides code-level lookup as a separate MCP server:"));
28820
+ console.log(chalk2.dim(" find_symbol, find_callers, get_imports, plan_change,"));
28821
+ console.log(chalk2.dim(" get_change_impact, analyze (security/dead_code/coupling/cycles/...)"));
28692
28822
  });
28693
28823
  companions.command("install").description("Install codeindex (downloads from munhq/codeindex GitHub release)").option("--force", "Re-download even if already installed").action(async (opts) => {
28694
28824
  const { installCodeindex: installCodeindex2, registerCodeindexMcp: registerCodeindexMcp2, CODEINDEX_BIN_PATH: CODEINDEX_BIN_PATH2 } = await Promise.resolve().then(() => (init_companions(), companions_exports));
28695
28825
  try {
28696
28826
  const result = await installCodeindex2({ force: opts.force });
28697
28827
  if (!result.prebuiltAvailable && !result.installed) {
28698
- console.log(chalk.yellow(`codeindex: ${result.unsupportedReason}`));
28699
- console.log(chalk.dim(" Build from source: https://github.com/munhq/codeindex#install"));
28828
+ console.log(chalk2.yellow(`codeindex: ${result.unsupportedReason}`));
28829
+ console.log(chalk2.dim(" Build from source: https://github.com/munhq/codeindex#install"));
28700
28830
  return;
28701
28831
  }
28702
28832
  if (result.installed) {
28703
28833
  const sizeMb = result.size ? `${(result.size / 1024 / 1024).toFixed(1)} MB` : "?";
28704
- console.log(chalk.green(`\u2713 codeindex installed (${sizeMb}) \u2192 ${result.path}`));
28834
+ console.log(chalk2.green(`\u2713 codeindex installed (${sizeMb}) \u2192 ${result.path}`));
28705
28835
  const mcpJsonPath = join60(homedir22(), ".mcp.json");
28706
28836
  const reg = registerCodeindexMcp2(mcpJsonPath, CODEINDEX_BIN_PATH2);
28707
- if (reg.added) console.log(chalk.dim(` Registered as MCP server in ${mcpJsonPath}`));
28708
- else console.log(chalk.dim(` Already registered as MCP server`));
28837
+ if (reg.added) console.log(chalk2.dim(` Registered as MCP server in ${mcpJsonPath}`));
28838
+ else console.log(chalk2.dim(` Already registered as MCP server`));
28709
28839
  }
28710
28840
  } catch (err) {
28711
28841
  const msg = String(err);
28712
- console.error(chalk.red(`codeindex install failed: ${msg}`));
28842
+ console.error(chalk2.red(`codeindex install failed: ${msg}`));
28713
28843
  if (msg.includes("404")) {
28714
- console.error(chalk.dim(" The codeindex release is currently private. Either authenticate `gh`"));
28715
- console.error(chalk.dim(" to munhq/codeindex, or build from source: https://github.com/munhq/codeindex"));
28844
+ console.error(chalk2.dim(" The codeindex release is currently private. Either authenticate `gh`"));
28845
+ console.error(chalk2.dim(" to munhq/codeindex, or build from source: https://github.com/munhq/codeindex"));
28716
28846
  } else {
28717
- console.error(chalk.dim(" This does not block chat-recall \u2014 it just disables code-level lookup."));
28847
+ console.error(chalk2.dim(" This does not block chat-recall \u2014 it just disables code-level lookup."));
28718
28848
  }
28719
28849
  process.exit(1);
28720
28850
  }
@@ -28722,15 +28852,15 @@ companions.command("install").description("Install codeindex (downloads from mun
28722
28852
  companions.command("uninstall").description("Remove the codeindex binary chat-recall installed (does not touch your other tools)").action(async () => {
28723
28853
  const { uninstallCodeindex: uninstallCodeindex2, unregisterCodeindexMcp: unregisterCodeindexMcp2 } = await Promise.resolve().then(() => (init_companions(), companions_exports));
28724
28854
  const r = uninstallCodeindex2();
28725
- if (r.removed) console.log(chalk.green(`\u2713 Removed ${r.path}`));
28726
- else console.log(chalk.dim(` Nothing to remove at ${r.path}`));
28855
+ if (r.removed) console.log(chalk2.green(`\u2713 Removed ${r.path}`));
28856
+ else console.log(chalk2.dim(` Nothing to remove at ${r.path}`));
28727
28857
  const mcpJsonPath = join60(homedir22(), ".mcp.json");
28728
28858
  const u = unregisterCodeindexMcp2(mcpJsonPath);
28729
- if (u.removed) console.log(chalk.dim(` Unregistered MCP server from ${mcpJsonPath}`));
28859
+ if (u.removed) console.log(chalk2.dim(` Unregistered MCP server from ${mcpJsonPath}`));
28730
28860
  });
28731
28861
  program.command("verify").description("Check that the server holds everything this machine has, per session").option("--deep", "Compare per-session content size against each server", false).option("--records", "With --deep: also diff the exact record (uuid) sets \u2014 proof, not inference", false).option("--since-hours <n>", "Only check sessions modified in the last N hours (default: all)").option("--repair", "Re-ship every STRANDED session found (clears its ledger cursor)", false).option("--json", "Machine-readable output", false).action(async (opts) => {
28732
28862
  if (!opts.deep) {
28733
- console.log(chalk.yellow("verify currently implements only --deep; re-run with --deep."));
28863
+ console.log(chalk2.yellow("verify currently implements only --deep; re-run with --deep."));
28734
28864
  return;
28735
28865
  }
28736
28866
  const { verifyAgainstServer: verifyAgainstServer2, verifyTargets: verifyTargets2 } = await Promise.resolve().then(() => (init_verify_deep(), verify_deep_exports));
@@ -28741,7 +28871,7 @@ program.command("verify").description("Check that the server holds everything th
28741
28871
  const { forceFullResync: forceFullResync2 } = await Promise.resolve().then(() => (init_verify_repair(), verify_repair_exports));
28742
28872
  const targets = verifyTargets2();
28743
28873
  if (targets.length === 0) {
28744
- console.error(chalk.red("No server configured \u2014 run `chat-recall login` first."));
28874
+ console.error(chalk2.red("No server configured \u2014 run `chat-recall login` first."));
28745
28875
  process.exit(1);
28746
28876
  }
28747
28877
  const sinceMs = opts.sinceHours ? Date.now() - Number(opts.sinceHours) * 36e5 : 0;
@@ -28806,37 +28936,37 @@ program.command("verify").description("Check that the server holds everything th
28806
28936
  try {
28807
28937
  report = await verifyAgainstServer2(t.serverUrl, t.token, sinceMs, deps);
28808
28938
  } catch (e) {
28809
- console.error(chalk.red(`${t.serverUrl}: ${e instanceof Error ? e.message : e}`));
28939
+ console.error(chalk2.red(`${t.serverUrl}: ${e instanceof Error ? e.message : e}`));
28810
28940
  exitCode = 1;
28811
28941
  continue;
28812
28942
  }
28813
28943
  reports.push(report);
28814
28944
  if (opts.json) continue;
28815
- console.log(chalk.bold(`
28945
+ console.log(chalk2.bold(`
28816
28946
  ${t.serverUrl}`));
28817
28947
  console.log(` checked ${report.checked} \xB7 complete ${report.complete} \xB7 no archive ${report.missingArchive}`);
28818
28948
  if (report.pending.length > 0) {
28819
- console.log(chalk.dim(` ${report.pending.length} pending (the ledger knows there is more to send \u2014 these go on their own)`));
28949
+ console.log(chalk2.dim(` ${report.pending.length} pending (the ledger knows there is more to send \u2014 these go on their own)`));
28820
28950
  }
28821
28951
  if (report.stranded.length === 0) {
28822
- console.log(chalk.green(" \u2713 nothing stranded"));
28952
+ console.log(chalk2.green(" \u2713 nothing stranded"));
28823
28953
  } else {
28824
28954
  exitCode = 2;
28825
- console.log(chalk.red(` \u2717 ${report.stranded.length} STRANDED \u2014 the ledger claims complete while the server holds less:`));
28955
+ console.log(chalk2.red(` \u2717 ${report.stranded.length} STRANDED \u2014 the ledger claims complete while the server holds less:`));
28826
28956
  for (const f of report.stranded.slice(0, 25)) {
28827
28957
  console.log(` ${f.sessionId.slice(0, 8)} server short by ${String(f.deficit).padStart(9)} B ${(f.projectPath || "").slice(-44)}`);
28828
28958
  }
28829
- if (report.stranded.length > 25) console.log(chalk.dim(` \u2026and ${report.stranded.length - 25} more`));
28959
+ if (report.stranded.length > 25) console.log(chalk2.dim(` \u2026and ${report.stranded.length - 25} more`));
28830
28960
  if (!opts.repair) {
28831
- console.log(chalk.dim(" Re-run with --repair to clear their cursors and re-ship."));
28961
+ console.log(chalk2.dim(" Re-run with --repair to clear their cursors and re-ship."));
28832
28962
  }
28833
28963
  }
28834
28964
  if (opts.records) {
28835
28965
  const suspects = [...report.stranded, ...report.pending];
28836
28966
  if (suspects.length === 0) {
28837
- console.log(chalk.dim(" --records: nothing to deep-check (size pass found no gaps)"));
28967
+ console.log(chalk2.dim(" --records: nothing to deep-check (size pass found no gaps)"));
28838
28968
  } else {
28839
- console.log(chalk.bold(`
28969
+ console.log(chalk2.bold(`
28840
28970
  record-level diff (${suspects.length} session(s)):`));
28841
28971
  for (const f of suspects) {
28842
28972
  let serverIds;
@@ -28861,9 +28991,9 @@ ${t.serverUrl}`));
28861
28991
  }
28862
28992
  const missing = [...localIds].filter((u) => !serverIds.has(u)).length;
28863
28993
  const onlyServer = [...serverIds].filter((u) => !localIds.has(u)).length;
28864
- const verdict = missing === 0 ? chalk.green("in sync") : chalk.red(`${missing} MISSING server-side`);
28994
+ const verdict = missing === 0 ? chalk2.green("in sync") : chalk2.red(`${missing} MISSING server-side`);
28865
28995
  console.log(
28866
- ` ${f.sessionId.slice(0, 8)} local ${String(localIds.size).padStart(6)} server ${String(serverIds.size).padStart(6)} ${verdict}` + (onlyServer > 0 ? chalk.dim(` (+${onlyServer} server-only \u2014 resume truncation)`) : "")
28996
+ ` ${f.sessionId.slice(0, 8)} local ${String(localIds.size).padStart(6)} server ${String(serverIds.size).padStart(6)} ${verdict}` + (onlyServer > 0 ? chalk2.dim(` (+${onlyServer} server-only \u2014 resume truncation)`) : "")
28867
28997
  );
28868
28998
  if (missing > 0) exitCode = 2;
28869
28999
  }
@@ -28871,7 +29001,7 @@ ${t.serverUrl}`));
28871
29001
  }
28872
29002
  if (opts.repair && report.stranded.length > 0) {
28873
29003
  const n = forceFullResync2(t.serverUrl, report.stranded.map((f) => f.sessionId));
28874
- console.log(chalk.green(` \u21BB cleared ${n} ledger cursor(s) \u2014 run \`chat-recall sync\` to re-ship`));
29004
+ console.log(chalk2.green(` \u21BB cleared ${n} ledger cursor(s) \u2014 run \`chat-recall sync\` to re-ship`));
28875
29005
  }
28876
29006
  }
28877
29007
  if (opts.json) console.log(JSON.stringify({ reports }, null, 2));
@@ -28879,19 +29009,19 @@ ${t.serverUrl}`));
28879
29009
  });
28880
29010
  var sources2 = program.command("sources").description("See and choose which AI-tool transcript folders get synced");
28881
29011
  function decisionBadge(d) {
28882
- if (d === "primary") return chalk.green("syncing") + chalk.dim(" (main)");
28883
- if (d === "approved") return chalk.green("syncing");
28884
- if (d === "declined") return chalk.dim("not syncing");
28885
- return chalk.yellow("NEEDS A DECISION");
29012
+ if (d === "primary") return chalk2.green("syncing") + chalk2.dim(" (main)");
29013
+ if (d === "approved") return chalk2.green("syncing");
29014
+ if (d === "declined") return chalk2.dim("not syncing");
29015
+ return chalk2.yellow("NEEDS A DECISION");
28886
29016
  }
28887
29017
  async function listSources() {
28888
29018
  const { discoverHomes: discoverHomes2 } = await Promise.resolve().then(() => (init_home_discovery(), home_discovery_exports));
28889
29019
  const { homeDecision: homeDecision2, grandfatherLegacyHomes: grandfatherLegacyHomes3 } = await Promise.resolve().then(() => (init_home_approval(), home_approval_exports));
28890
29020
  grandfatherLegacyHomes3();
28891
29021
  const homes = discoverHomes2();
28892
- console.log(chalk.bold("Transcript folders found on this machine"));
29022
+ console.log(chalk2.bold("Transcript folders found on this machine"));
28893
29023
  if (homes.length === 0) {
28894
- console.log(chalk.dim(" none \u2014 no AI tool transcripts detected"));
29024
+ console.log(chalk2.dim(" none \u2014 no AI tool transcripts detected"));
28895
29025
  return { pending: 0 };
28896
29026
  }
28897
29027
  let pending = 0;
@@ -28900,14 +29030,14 @@ async function listSources() {
28900
29030
  if (d === "pending") pending++;
28901
29031
  const count = h.sessions > 0 ? `${h.sessions} session${h.sessions === 1 ? "" : "s"}` : "\u2014";
28902
29032
  console.log(
28903
- ` ${h.tool.padEnd(9)} ${count.padStart(14)} ${decisionBadge(d).padEnd(30)} ${h.path}` + (h.via === "declared" ? chalk.dim(" (you configured this)") : "")
29033
+ ` ${h.tool.padEnd(9)} ${count.padStart(14)} ${decisionBadge(d).padEnd(30)} ${h.path}` + (h.via === "declared" ? chalk2.dim(" (you configured this)") : "")
28904
29034
  );
28905
29035
  }
28906
29036
  if (pending > 0) {
28907
29037
  console.log();
28908
- console.log(chalk.yellow(` ${pending} folder(s) need a decision \u2014 they are NOT being synced yet.`));
28909
- console.log(chalk.dim(" chat-recall sources approve <path> start syncing it"));
28910
- console.log(chalk.dim(" chat-recall sources decline <path> keep it out (e.g. a work account)"));
29038
+ console.log(chalk2.yellow(` ${pending} folder(s) need a decision \u2014 they are NOT being synced yet.`));
29039
+ console.log(chalk2.dim(" chat-recall sources approve <path> start syncing it"));
29040
+ console.log(chalk2.dim(" chat-recall sources decline <path> keep it out (e.g. a work account)"));
28911
29041
  }
28912
29042
  return { pending };
28913
29043
  }
@@ -28920,74 +29050,74 @@ sources2.command("add <path>").description("Sync a transcript folder we did not
28920
29050
  const abs = normalizeHomePath2(path);
28921
29051
  const tool = identifyHome2(abs);
28922
29052
  if (!tool) {
28923
- console.error(chalk.red(`Not a transcript folder: ${abs}`));
28924
- console.error(chalk.dim(" Expected one of:"));
28925
- console.error(chalk.dim(" <dir>/projects/<project>/<uuid>.jsonl (Claude Code)"));
28926
- console.error(chalk.dim(" <dir>/sessions/YYYY/MM/DD/rollout-*.jsonl (Codex)"));
28927
- console.error(chalk.dim(" <dir>/tmp/<project>/chats/session-*.json (Gemini)"));
28928
- console.error(chalk.dim(" <dir>/brain/<id>/.system_generated/logs/* (Antigravity)"));
28929
- console.error(chalk.dim(" <dir>/opencode.db (OpenCode)"));
29053
+ console.error(chalk2.red(`Not a transcript folder: ${abs}`));
29054
+ console.error(chalk2.dim(" Expected one of:"));
29055
+ console.error(chalk2.dim(" <dir>/projects/<project>/<uuid>.jsonl (Claude Code)"));
29056
+ console.error(chalk2.dim(" <dir>/sessions/YYYY/MM/DD/rollout-*.jsonl (Codex)"));
29057
+ console.error(chalk2.dim(" <dir>/tmp/<project>/chats/session-*.json (Gemini)"));
29058
+ console.error(chalk2.dim(" <dir>/brain/<id>/.system_generated/logs/* (Antigravity)"));
29059
+ console.error(chalk2.dim(" <dir>/opencode.db (OpenCode)"));
28930
29060
  process.exit(1);
28931
29061
  }
28932
29062
  if (!approveHome2(abs)) {
28933
- console.error(chalk.red("Could not write settings."));
29063
+ console.error(chalk2.red("Could not write settings."));
28934
29064
  process.exit(1);
28935
29065
  }
28936
- console.log(chalk.green(`\u2713 syncing ${tool} transcripts from ${abs}`));
28937
- console.log(chalk.dim(" Takes effect on the next sync; run `chat-recall sync` to do it now."));
29066
+ console.log(chalk2.green(`\u2713 syncing ${tool} transcripts from ${abs}`));
29067
+ console.log(chalk2.dim(" Takes effect on the next sync; run `chat-recall sync` to do it now."));
28938
29068
  });
28939
29069
  sources2.command("approve <path>").description("Start syncing a folder that was waiting for a decision").action(async (path) => {
28940
29070
  const { approveHome: approveHome2, normalizeHomePath: normalizeHomePath2 } = await Promise.resolve().then(() => (init_home_approval(), home_approval_exports));
28941
29071
  const abs = normalizeHomePath2(path);
28942
29072
  if (!approveHome2(abs)) {
28943
- console.error(chalk.red("Could not write settings."));
29073
+ console.error(chalk2.red("Could not write settings."));
28944
29074
  process.exit(1);
28945
29075
  }
28946
- console.log(chalk.green(`\u2713 now syncing ${abs}`));
29076
+ console.log(chalk2.green(`\u2713 now syncing ${abs}`));
28947
29077
  });
28948
29078
  sources2.command("decline <path>").description("Keep a folder out of sync (e.g. a work account you do not want here)").option("--delete-remote", "Also delete sessions already uploaded FROM this folder (irreversible)", false).option("--yes", "Skip the confirmation prompt for --delete-remote", false).action(async (path, opts) => {
28949
29079
  const { declineHome: declineHome2, normalizeHomePath: normalizeHomePath2 } = await Promise.resolve().then(() => (init_home_approval(), home_approval_exports));
28950
29080
  const { identifyHome: identifyHome2, sessionIdsInHome: sessionIdsInHome2 } = await Promise.resolve().then(() => (init_home_discovery(), home_discovery_exports));
28951
29081
  const abs = normalizeHomePath2(path);
28952
29082
  if (!declineHome2(abs)) {
28953
- console.error(chalk.red("Could not write settings."));
29083
+ console.error(chalk2.red("Could not write settings."));
28954
29084
  process.exit(1);
28955
29085
  }
28956
- console.log(chalk.green(`\u2713 not syncing ${abs}`));
29086
+ console.log(chalk2.green(`\u2713 not syncing ${abs}`));
28957
29087
  if (!opts.deleteRemote) {
28958
- console.log(chalk.dim(" Sessions already uploaded from it stay on the server."));
28959
- console.log(chalk.dim(` To remove those too: chat-recall sources decline ${path} --delete-remote`));
29088
+ console.log(chalk2.dim(" Sessions already uploaded from it stay on the server."));
29089
+ console.log(chalk2.dim(` To remove those too: chat-recall sources decline ${path} --delete-remote`));
28960
29090
  return;
28961
29091
  }
28962
29092
  const tool = identifyHome2(abs);
28963
29093
  if (!tool) {
28964
- console.error(chalk.red(`Not a transcript folder: ${abs}`));
29094
+ console.error(chalk2.red(`Not a transcript folder: ${abs}`));
28965
29095
  process.exit(1);
28966
29096
  }
28967
29097
  const ids = sessionIdsInHome2(abs, tool);
28968
29098
  if (ids.length === 0) {
28969
- console.log(chalk.dim(" Nothing to delete \u2014 no session files found in that folder."));
29099
+ console.log(chalk2.dim(" Nothing to delete \u2014 no session files found in that folder."));
28970
29100
  if (tool === "opencode") {
28971
- console.log(chalk.dim(" (OpenCode keys sessions by database row, so they cannot be enumerated from the path.)"));
29101
+ console.log(chalk2.dim(" (OpenCode keys sessions by database row, so they cannot be enumerated from the path.)"));
28972
29102
  }
28973
29103
  return;
28974
29104
  }
28975
29105
  const targets = loadAllCredentials();
28976
29106
  if (targets.length === 0) {
28977
- console.error(chalk.red("Not logged in \u2014 nothing to delete from."));
29107
+ console.error(chalk2.red("Not logged in \u2014 nothing to delete from."));
28978
29108
  process.exit(1);
28979
29109
  }
28980
29110
  if (!opts.yes) {
28981
29111
  console.log();
28982
- console.log(chalk.yellow(`About to DELETE ${ids.length} session(s) from ${targets.length} server(s).`));
28983
- console.log(chalk.yellow("This is irreversible \u2014 the transcripts stay on this machine, but the"));
28984
- console.log(chalk.yellow("server copies (search index, conversation view, archive) are removed."));
29112
+ console.log(chalk2.yellow(`About to DELETE ${ids.length} session(s) from ${targets.length} server(s).`));
29113
+ console.log(chalk2.yellow("This is irreversible \u2014 the transcripts stay on this machine, but the"));
29114
+ console.log(chalk2.yellow("server copies (search index, conversation view, archive) are removed."));
28985
29115
  const { createInterface: createInterface3 } = await import("node:readline/promises");
28986
29116
  const rl = createInterface3({ input: process.stdin, output: process.stdout });
28987
29117
  const answer = (await rl.question("Type the number of sessions to confirm: ")).trim();
28988
29118
  rl.close();
28989
29119
  if (answer !== String(ids.length)) {
28990
- console.log(chalk.dim("Cancelled \u2014 nothing deleted."));
29120
+ console.log(chalk2.dim("Cancelled \u2014 nothing deleted."));
28991
29121
  return;
28992
29122
  }
28993
29123
  }
@@ -29007,8 +29137,8 @@ sources2.command("decline <path>").description("Keep a folder out of sync (e.g.
29007
29137
  failed++;
29008
29138
  }
29009
29139
  }
29010
- const line = ` ${base2}: deleted ${deleted}` + (missing ? `, ${missing} were not there` : "") + (failed ? chalk.red(`, ${failed} FAILED`) : "");
29011
- console.log(failed ? chalk.yellow(line) : chalk.green(line));
29140
+ const line = ` ${base2}: deleted ${deleted}` + (missing ? `, ${missing} were not there` : "") + (failed ? chalk2.red(`, ${failed} FAILED`) : "");
29141
+ console.log(failed ? chalk2.yellow(line) : chalk2.green(line));
29012
29142
  if (failed) process.exitCode = 1;
29013
29143
  }
29014
29144
  });
@@ -29016,30 +29146,30 @@ sources2.command("forget <path>").description("Undo a decision, so the folder is
29016
29146
  const { resetHomeDecision: resetHomeDecision2, normalizeHomePath: normalizeHomePath2 } = await Promise.resolve().then(() => (init_home_approval(), home_approval_exports));
29017
29147
  const abs = normalizeHomePath2(path);
29018
29148
  resetHomeDecision2(abs);
29019
- console.log(chalk.green(`\u2713 ${abs} is undecided again (not syncing until approved)`));
29149
+ console.log(chalk2.green(`\u2713 ${abs} is undecided again (not syncing until approved)`));
29020
29150
  });
29021
29151
  var detectors = program.command("detectors").description("Manage the optional external secret detectors (gitleaks, trufflehog)");
29022
29152
  detectors.command("status").description("Show which detectors are installed, pinned and verified").action(async () => {
29023
29153
  const { detectorStatus: detectorStatus2 } = await Promise.resolve().then(() => (init_detector_install(), detector_install_exports));
29024
29154
  const { externalScannersEnabled: externalScannersEnabled2 } = await Promise.resolve().then(() => (init_secret_scanner(), secret_scanner_exports));
29025
- console.log(chalk.bold("external secret detectors"));
29155
+ console.log(chalk2.bold("external secret detectors"));
29026
29156
  console.log(
29027
- externalScannersEnabled2() ? ` gate: ${chalk.green("enabled")} (CHAT_RECALL_EXTERNAL_SCANNERS)` : ` gate: ${chalk.yellow("disabled")} \u2014 set CHAT_RECALL_EXTERNAL_SCANNERS=1 to use them`
29157
+ externalScannersEnabled2() ? ` gate: ${chalk2.green("enabled")} (CHAT_RECALL_EXTERNAL_SCANNERS)` : ` gate: ${chalk2.yellow("disabled")} \u2014 set CHAT_RECALL_EXTERNAL_SCANNERS=1 to use them`
29028
29158
  );
29029
29159
  if (process.env.CHAT_RECALL_DETECTOR_DIR) {
29030
- console.log(` dir: ${chalk.dim(process.env.CHAT_RECALL_DETECTOR_DIR)} ${chalk.dim("(operator-supplied, unverified)")}`);
29160
+ console.log(` dir: ${chalk2.dim(process.env.CHAT_RECALL_DETECTOR_DIR)} ${chalk2.dim("(operator-supplied, unverified)")}`);
29031
29161
  }
29032
29162
  console.log();
29033
29163
  for (const d of detectorStatus2()) {
29034
- const label = `${d.name} ${chalk.dim(d.pinnedVersion)} ${chalk.dim(`[${d.license}]`)}`;
29035
- if (d.state === "ready") console.log(` ${chalk.green("\u2713")} ${label} \u2192 ${chalk.dim(d.path)}`);
29036
- else if (d.state === "configured") console.log(` ${chalk.green("\u2713")} ${label} \u2192 ${chalk.dim(d.path)} ${chalk.dim("(operator-supplied)")}`);
29037
- else if (d.state === "not-installed") console.log(` ${chalk.dim("\xB7")} ${label} \u2014 not installed`);
29038
- else if (!d.supported) console.log(` ${chalk.dim("\xB7")} ${label} \u2014 no build for this platform`);
29039
- else console.log(` ${chalk.red("\u2717")} ${label} \u2014 ${d.state}, reinstall with \`chat-recall detectors install ${d.name}\``);
29164
+ const label = `${d.name} ${chalk2.dim(d.pinnedVersion)} ${chalk2.dim(`[${d.license}]`)}`;
29165
+ if (d.state === "ready") console.log(` ${chalk2.green("\u2713")} ${label} \u2192 ${chalk2.dim(d.path)}`);
29166
+ else if (d.state === "configured") console.log(` ${chalk2.green("\u2713")} ${label} \u2192 ${chalk2.dim(d.path)} ${chalk2.dim("(operator-supplied)")}`);
29167
+ else if (d.state === "not-installed") console.log(` ${chalk2.dim("\xB7")} ${label} \u2014 not installed`);
29168
+ else if (!d.supported) console.log(` ${chalk2.dim("\xB7")} ${label} \u2014 no build for this platform`);
29169
+ else console.log(` ${chalk2.red("\u2717")} ${label} \u2014 ${d.state}, reinstall with \`chat-recall detectors install ${d.name}\``);
29040
29170
  }
29041
29171
  console.log();
29042
- console.log(chalk.dim("Builtin in-process detection runs for every user and needs none of this."));
29172
+ console.log(chalk2.dim("Builtin in-process detection runs for every user and needs none of this."));
29043
29173
  });
29044
29174
  detectors.command("install [name]").description("Download + verify a pinned detector into ~/.chat-recall/bin (default: both)").option("--force", "Re-download even if the pinned version is already installed").action(async (name, opts) => {
29045
29175
  const { installDetector: installDetector2, DETECTOR_MANIFEST: DETECTOR_MANIFEST2 } = await Promise.resolve().then(() => (init_detector_install(), detector_install_exports));
@@ -29048,33 +29178,33 @@ detectors.command("install [name]").description("Download + verify a pinned dete
29048
29178
  let failed = false;
29049
29179
  for (const n of names) {
29050
29180
  if (!valid.includes(n)) {
29051
- console.error(chalk.red(`unknown detector "${n}" \u2014 expected one of: ${valid.join(", ")}`));
29181
+ console.error(chalk2.red(`unknown detector "${n}" \u2014 expected one of: ${valid.join(", ")}`));
29052
29182
  failed = true;
29053
29183
  continue;
29054
29184
  }
29055
29185
  try {
29056
29186
  const r = await installDetector2(n, { force: opts.force });
29057
- console.log(r.installed ? chalk.green(`\u2713 ${r.name} ${r.version} installed \u2192 ${r.path}`) : chalk.dim(`\xB7 ${r.name} ${r.version} already installed and verified \u2192 ${r.path}`));
29058
- if (r.installed) console.log(chalk.dim(` sha256 ${r.binarySha256}`));
29187
+ console.log(r.installed ? chalk2.green(`\u2713 ${r.name} ${r.version} installed \u2192 ${r.path}`) : chalk2.dim(`\xB7 ${r.name} ${r.version} already installed and verified \u2192 ${r.path}`));
29188
+ if (r.installed) console.log(chalk2.dim(` sha256 ${r.binarySha256}`));
29059
29189
  } catch (err) {
29060
29190
  failed = true;
29061
- console.error(chalk.red(`${n} install failed: ${err instanceof Error ? err.message : String(err)}`));
29191
+ console.error(chalk2.red(`${n} install failed: ${err instanceof Error ? err.message : String(err)}`));
29062
29192
  }
29063
29193
  }
29064
29194
  if (failed) process.exit(1);
29065
29195
  console.log();
29066
- console.log(chalk.dim("Enable them with CHAT_RECALL_EXTERNAL_SCANNERS=1. They enrich the findings"));
29067
- console.log(chalk.dim("dashboard; they are not what redacts your data before it syncs."));
29196
+ console.log(chalk2.dim("Enable them with CHAT_RECALL_EXTERNAL_SCANNERS=1. They enrich the findings"));
29197
+ console.log(chalk2.dim("dashboard; they are not what redacts your data before it syncs."));
29068
29198
  });
29069
29199
  detectors.command("remove [name]").description("Remove detectors chat-recall installed (never touches your own binaries)").action(async (name) => {
29070
29200
  const { removeDetector: removeDetector2, DETECTOR_MANIFEST: DETECTOR_MANIFEST2, managedDetectorPath: managedDetectorPath2 } = await Promise.resolve().then(() => (init_detector_install(), detector_install_exports));
29071
29201
  for (const n of name ? [name] : Object.keys(DETECTOR_MANIFEST2)) {
29072
29202
  if (!(n in DETECTOR_MANIFEST2)) {
29073
- console.error(chalk.red(`unknown detector "${n}"`));
29203
+ console.error(chalk2.red(`unknown detector "${n}"`));
29074
29204
  continue;
29075
29205
  }
29076
29206
  const removed = removeDetector2(n);
29077
- console.log(removed ? chalk.green(`\u2713 removed ${n}`) : chalk.dim(`\xB7 nothing to remove at ${managedDetectorPath2(n)}`));
29207
+ console.log(removed ? chalk2.green(`\u2713 removed ${n}`) : chalk2.dim(`\xB7 nothing to remove at ${managedDetectorPath2(n)}`));
29078
29208
  }
29079
29209
  });
29080
29210
  var code = program.command("code").description("Index a codebase with codeindex and ship findings/hotspots/actions to your server");
@@ -29083,22 +29213,22 @@ code.command("index [path]").description("Run codeindex on a repo (default: cwd)
29083
29213
  const target = requireTarget();
29084
29214
  const { collectCode: collectCode2 } = await Promise.resolve().then(() => (init_collector(), collector_exports));
29085
29215
  const workspace = resolve2(path || process.cwd());
29086
- console.log(chalk.bold(`code index ${workspace}`));
29216
+ console.log(chalk2.bold(`code index ${workspace}`));
29087
29217
  const result = await collectCode2({
29088
29218
  workspace,
29089
29219
  autoInstall: opts.install !== false,
29090
- log: (m) => console.log(chalk.dim(" \xB7 " + m))
29220
+ log: (m) => console.log(chalk2.dim(" \xB7 " + m))
29091
29221
  });
29092
29222
  const resp = await serverPost(
29093
29223
  "/api/code/index",
29094
29224
  result
29095
29225
  );
29096
- console.log(chalk.green("\u2713 synced"), chalk.dim(`\u2192 ${target.base}`));
29226
+ console.log(chalk2.green("\u2713 synced"), chalk2.dim(`\u2192 ${target.base}`));
29097
29227
  console.log(` project: ${resp.projectId}`);
29098
29228
  console.log(` health: ${result.project.health.score}/100`);
29099
29229
  console.log(` findings: ${resp.findings} hotspots: ${resp.hotspots} actions: ${resp.actions}`);
29100
29230
  } catch (err) {
29101
- console.error(chalk.red("code index failed:"), err instanceof Error ? err.message : err);
29231
+ console.error(chalk2.red("code index failed:"), err instanceof Error ? err.message : err);
29102
29232
  process.exit(1);
29103
29233
  }
29104
29234
  });
@@ -29106,17 +29236,17 @@ code.command("status").description("List code-indexed projects on your server").
29106
29236
  try {
29107
29237
  const { projects } = await serverGet("/api/code/projects");
29108
29238
  if (!projects.length) {
29109
- console.log(chalk.dim("No code-indexed projects yet. Run `chat-recall code index` in a repo."));
29239
+ console.log(chalk2.dim("No code-indexed projects yet. Run `chat-recall code index` in a repo."));
29110
29240
  return;
29111
29241
  }
29112
- console.log(chalk.bold(`${projects.length} code project(s)`));
29242
+ console.log(chalk2.bold(`${projects.length} code project(s)`));
29113
29243
  for (const p of projects) {
29114
29244
  const when = new Date(p.lastIndexedAt).toISOString().slice(0, 16).replace("T", " ");
29115
- console.log(` ${chalk.bold(p.projectId)}${p.label ? chalk.cyan(` [${p.label}]`) : ""}`);
29116
- console.log(chalk.dim(` health ${p.health.score}/100 \xB7 ${p.health.findings} findings \xB7 ${when}`));
29245
+ console.log(` ${chalk2.bold(p.projectId)}${p.label ? chalk2.cyan(` [${p.label}]`) : ""}`);
29246
+ console.log(chalk2.dim(` health ${p.health.score}/100 \xB7 ${p.health.findings} findings \xB7 ${when}`));
29117
29247
  }
29118
29248
  } catch (err) {
29119
- console.error(chalk.red("code status failed:"), err instanceof Error ? err.message : err);
29249
+ console.error(chalk2.red("code status failed:"), err instanceof Error ? err.message : err);
29120
29250
  process.exit(1);
29121
29251
  }
29122
29252
  });
@@ -29125,12 +29255,12 @@ code.command("show <project>").description("Show a project: health, findings sum
29125
29255
  const enc = encodeURIComponent(project);
29126
29256
  const p = await serverGet(`/api/code/projects/${enc}`);
29127
29257
  const { actions } = await serverGet(`/api/code/actions?project=${enc}&limit=12`);
29128
- console.log(chalk.bold(p.projectId), chalk.dim(p.rootPath));
29258
+ console.log(chalk2.bold(p.projectId), chalk2.dim(p.rootPath));
29129
29259
  console.log(` health ${p.health.score}/100 \u2014 ${p.health.critical}C ${p.health.high}H ${p.health.medium}M ${p.health.low}L \xB7 ${p.health.hotspots} hotspots \xB7 ${Math.round((p.health.aiAuthoredPct || 0) * 100)}% AI-authored`);
29130
- console.log(chalk.bold("\n Top actions:"));
29131
- for (const a of actions) console.log(` ${chalk.yellow("P" + a.pri)} [${a.category}] ${a.title}`);
29260
+ console.log(chalk2.bold("\n Top actions:"));
29261
+ for (const a of actions) console.log(` ${chalk2.yellow("P" + a.pri)} [${a.category}] ${a.title}`);
29132
29262
  } catch (err) {
29133
- console.error(chalk.red("code show failed:"), err instanceof Error ? err.message : err);
29263
+ console.error(chalk2.red("code show failed:"), err instanceof Error ? err.message : err);
29134
29264
  process.exit(1);
29135
29265
  }
29136
29266
  });
@@ -29139,18 +29269,18 @@ async function pushToolkitToServer() {
29139
29269
  try {
29140
29270
  const { syncIncremental: syncIncremental2, isSyncSkip: isSyncSkip2 } = await Promise.resolve().then(() => (init_sync_client(), sync_client_exports));
29141
29271
  const res = await syncIncremental2();
29142
- if (!isSyncSkip2(res) && res.items > 0) console.log(chalk.dim(` synced ${res.items} toolkit item(s) to the server.`));
29272
+ if (!isSyncSkip2(res) && res.items > 0) console.log(chalk2.dim(` synced ${res.items} toolkit item(s) to the server.`));
29143
29273
  } catch (err) {
29144
- console.error(chalk.dim(` (could not sync to server: ${err instanceof Error ? err.message : err})`));
29274
+ console.error(chalk2.dim(` (could not sync to server: ${err instanceof Error ? err.message : err})`));
29145
29275
  }
29146
29276
  }
29147
29277
  toolkit.command("sync").description("Fan every artifact out to every tool that is missing it (runs locally now)").option("--types <list>", "comma-separated subset: skill,mcp,command,agent").action(async (options) => {
29148
29278
  const { executeSyncAll: executeSyncAll2 } = await Promise.resolve().then(() => (init_toolkit_sync(), toolkit_sync_exports));
29149
29279
  const types = options.types ? options.types.split(",").map((s) => s.trim()).filter(Boolean) : void 0;
29150
29280
  const r = await executeSyncAll2(types);
29151
- for (const c of r.copied) console.log(chalk.green(` + ${c.type} ${c.name} \u2192 ${c.toTool}`) + chalk.dim(` ${c.path || ""}`));
29152
- for (const f of r.failed) console.log(chalk.red(` \u2717 ${f.type} ${f.name} \u2192 ${f.toTool}: ${f.error}`));
29153
- console.log(chalk.bold(`Synced: ${r.copied.length} copied, ${r.skipped.length} already present, ${r.failed.length} failed.`));
29281
+ for (const c of r.copied) console.log(chalk2.green(` + ${c.type} ${c.name} \u2192 ${c.toTool}`) + chalk2.dim(` ${c.path || ""}`));
29282
+ for (const f of r.failed) console.log(chalk2.red(` \u2717 ${f.type} ${f.name} \u2192 ${f.toTool}: ${f.error}`));
29283
+ console.log(chalk2.bold(`Synced: ${r.copied.length} copied, ${r.skipped.length} already present, ${r.failed.length} failed.`));
29154
29284
  if (r.copied.length > 0) await pushToolkitToServer();
29155
29285
  });
29156
29286
  toolkit.command("pull").description("Install artifacts this device is missing, from the server (cross-device setup)").option("--types <list>", "comma-separated subset: mcp").option("--dry-run", "report what would change, write nothing").action(async (options) => {
@@ -29159,7 +29289,7 @@ toolkit.command("pull").description("Install artifacts this device is missing, f
29159
29289
  const { hostname: hostname3 } = await import("node:os");
29160
29290
  const targets = loadAllCredentials2();
29161
29291
  if (targets.length === 0) {
29162
- console.error(chalk.red("Not logged in."), "Run `chat-recall login <server-url>` first.");
29292
+ console.error(chalk2.red("Not logged in."), "Run `chat-recall login <server-url>` first.");
29163
29293
  process.exit(1);
29164
29294
  }
29165
29295
  const rows = [];
@@ -29173,7 +29303,7 @@ toolkit.command("pull").description("Install artifacts this device is missing, f
29173
29303
  const body = await res.json();
29174
29304
  for (const it of body.items || []) rows.push(it);
29175
29305
  } catch (err) {
29176
- console.log(chalk.dim(` (${t.serverUrl} ${type}: ${err instanceof Error ? err.message : err})`));
29306
+ console.log(chalk2.dim(` (${t.serverUrl} ${type}: ${err instanceof Error ? err.message : err})`));
29177
29307
  }
29178
29308
  }
29179
29309
  }
@@ -29188,41 +29318,40 @@ toolkit.command("pull").description("Install artifacts this device is missing, f
29188
29318
  const failed = report.outcomes.filter((o) => o.status === "failed");
29189
29319
  const skipped = report.outcomes.filter((o) => o.status === "skipped");
29190
29320
  for (const o of written) {
29191
- const note = o.rewrittenCommand ? chalk.cyan(` [using this machine's ${o.rewrittenCommand}]`) : "";
29192
- console.log(chalk.green(` + ${o.type} ${o.name} \u2192 ${o.tool}`) + chalk.dim(` ${o.path || "(dry run)"}`) + note);
29321
+ const note = o.rewrittenCommand ? chalk2.cyan(` [using this machine's ${o.rewrittenCommand}]`) : "";
29322
+ console.log(chalk2.green(` + ${o.type} ${o.name} \u2192 ${o.tool}`) + chalk2.dim(` ${o.path || "(dry run)"}`) + note);
29193
29323
  }
29194
- for (const o of failed) console.log(chalk.red(` \u2717 ${o.type} ${o.name} \u2192 ${o.tool}: ${o.reason}`));
29195
- for (const o of skipped) console.log(chalk.yellow(` ~ ${o.type} ${o.name} \u2192 ${o.tool}: ${o.reason}`));
29196
- console.log(chalk.bold(
29324
+ for (const o of failed) console.log(chalk2.red(` \u2717 ${o.type} ${o.name} \u2192 ${o.tool}: ${o.reason}`));
29325
+ for (const o of skipped) console.log(chalk2.yellow(` ~ ${o.type} ${o.name} \u2192 ${o.tool}: ${o.reason}`));
29326
+ console.log(chalk2.bold(
29197
29327
  `${options.dryRun ? "Would install" : "Installed"}: ${written.length} \xB7 already present: ${present.length} \xB7 failed: ${failed.length} \xB7 skipped: ${skipped.length}`
29198
29328
  ));
29199
- const envVars = [...new Set(written.flatMap((o) => o.needsEnv || []))].sort();
29200
- if (envVars.length) {
29329
+ const needs = collectEnvNeeds(written);
29330
+ if (needs.length) {
29201
29331
  console.log("");
29202
- console.log(chalk.yellow.bold("Set these environment variables \u2014 their values were never uploaded:"));
29203
- for (const v of envVars) console.log(` ${v}`);
29332
+ for (const line of renderEnvNeeds(needs, written.length)) console.log(line);
29204
29333
  }
29205
29334
  if (report.unsupported.length) {
29206
29335
  console.log("");
29207
- console.log(chalk.dim("Not installable from the server yet:"));
29336
+ console.log(chalk2.dim("Not installable from the server yet:"));
29208
29337
  for (const u of report.unsupported) {
29209
- console.log(chalk.dim(` ${u.type} (${u.rows} on the server) \u2014 ${u.reason}`));
29338
+ console.log(chalk2.dim(` ${u.type} (${u.rows} on the server) \u2014 ${u.reason}`));
29210
29339
  }
29211
- console.log(chalk.dim(" Those need artifact content upload; the server holds an inventory only."));
29340
+ console.log(chalk2.dim(" Those need artifact content upload; the server holds an inventory only."));
29212
29341
  }
29213
29342
  });
29214
29343
  toolkit.command("drain").description("Process cross-tool sync intents queued from the web UI, now").action(async () => {
29215
29344
  const { drainSyncIntents: drainSyncIntents2 } = await Promise.resolve().then(() => (init_intent_drain(), intent_drain_exports));
29216
29345
  const r = await drainSyncIntents2({ verbose: true });
29217
- console.log(chalk.bold(`Processed ${r.processed} intent(s): ${r.done} done, ${r.errored} errored.`));
29346
+ console.log(chalk2.bold(`Processed ${r.processed} intent(s): ${r.done} done, ${r.errored} errored.`));
29218
29347
  if (r.done > 0) await pushToolkitToServer();
29219
29348
  });
29220
29349
  toolkit.command("copy <type> <name> <fromTool> <toTool>").description("Copy one artifact (skill|mcp|command|agent) from one tool to another").action(async (type, name, fromTool, toTool) => {
29221
29350
  const { executeCopy: executeCopy2 } = await Promise.resolve().then(() => (init_toolkit_sync(), toolkit_sync_exports));
29222
29351
  const r = await executeCopy2(type, name, fromTool, toTool);
29223
- if (r.ok) console.log(chalk.green(`Copied to ${r.targetPath}`));
29352
+ if (r.ok) console.log(chalk2.green(`Copied to ${r.targetPath}`));
29224
29353
  else {
29225
- console.error(chalk.red(r.error || "failed"));
29354
+ console.error(chalk2.red(r.error || "failed"));
29226
29355
  process.exit(1);
29227
29356
  }
29228
29357
  });
@@ -29230,31 +29359,31 @@ program.command("shares").description("List the projects you share with your tea
29230
29359
  try {
29231
29360
  const { shares } = await serverGet("/api/shares");
29232
29361
  if (!shares.length) {
29233
- console.log(chalk.gray("You are not sharing any projects. Share one with"), chalk.bold("chat-recall share <project_id>"));
29362
+ console.log(chalk2.gray("You are not sharing any projects. Share one with"), chalk2.bold("chat-recall share <project_id>"));
29234
29363
  return;
29235
29364
  }
29236
- console.log(chalk.bold(`Shared projects (${shares.length}):`));
29237
- for (const s of shares) console.log(` ${chalk.cyan(s.projectId)} ${chalk.gray(s.scope)}`);
29365
+ console.log(chalk2.bold(`Shared projects (${shares.length}):`));
29366
+ for (const s of shares) console.log(` ${chalk2.cyan(s.projectId)} ${chalk2.gray(s.scope)}`);
29238
29367
  } catch (e) {
29239
- console.error(chalk.red(e instanceof Error ? e.message : String(e)));
29368
+ console.error(chalk2.red(e instanceof Error ? e.message : String(e)));
29240
29369
  process.exit(1);
29241
29370
  }
29242
29371
  });
29243
29372
  program.command("share <project_id>").description("Share a project with your team (teammates can then see your work on it)").action(async (projectId) => {
29244
29373
  try {
29245
29374
  await serverPost("/api/shares", { project_id: projectId });
29246
- console.log(chalk.green("\u2713 shared"), chalk.cyan(projectId), chalk.gray("with your team"));
29375
+ console.log(chalk2.green("\u2713 shared"), chalk2.cyan(projectId), chalk2.gray("with your team"));
29247
29376
  } catch (e) {
29248
- console.error(chalk.red(e instanceof Error ? e.message : String(e)));
29377
+ console.error(chalk2.red(e instanceof Error ? e.message : String(e)));
29249
29378
  process.exit(1);
29250
29379
  }
29251
29380
  });
29252
29381
  program.command("unshare <project_id>").description("Stop sharing a project with your team").action(async (projectId) => {
29253
29382
  try {
29254
29383
  const r = await serverDelete("/api/shares", { project_id: projectId });
29255
- console.log(r.removed ? chalk.green("\u2713 unshared") : chalk.yellow("was not shared"), chalk.cyan(projectId));
29384
+ console.log(r.removed ? chalk2.green("\u2713 unshared") : chalk2.yellow("was not shared"), chalk2.cyan(projectId));
29256
29385
  } catch (e) {
29257
- console.error(chalk.red(e instanceof Error ? e.message : String(e)));
29386
+ console.error(chalk2.red(e instanceof Error ? e.message : String(e)));
29258
29387
  process.exit(1);
29259
29388
  }
29260
29389
  });
@@ -29263,12 +29392,12 @@ tasks.command("list").description("List team tasks assigned to you").action(asyn
29263
29392
  try {
29264
29393
  const { tasks: tasks2 } = await serverGet("/api/tasks?assignee=@me");
29265
29394
  if (!tasks2.length) {
29266
- console.log(chalk.gray("No tasks assigned to you."));
29395
+ console.log(chalk2.gray("No tasks assigned to you."));
29267
29396
  return;
29268
29397
  }
29269
- for (const t of tasks2) console.log(` [${t.status}] ${t.title} ${chalk.gray(t.id)}${t.projectId ? chalk.gray(" \xB7 " + t.projectId) : ""}`);
29398
+ for (const t of tasks2) console.log(` [${t.status}] ${t.title} ${chalk2.gray(t.id)}${t.projectId ? chalk2.gray(" \xB7 " + t.projectId) : ""}`);
29270
29399
  } catch (e) {
29271
- console.error(chalk.red(e instanceof Error ? e.message : String(e)));
29400
+ console.error(chalk2.red(e instanceof Error ? e.message : String(e)));
29272
29401
  process.exit(1);
29273
29402
  }
29274
29403
  });
@@ -29281,7 +29410,7 @@ tasks.command("pull [dir]").description("Write TEAM_TASKS.md for your tasks in t
29281
29410
  const { join: join61 } = await import("node:path");
29282
29411
  const file = join61(cwd, "TEAM_TASKS.md");
29283
29412
  if (!opts.force && existsSync57(file) && parseTeamTasksFile2(readFileSync50(file, "utf8")).length > 0) {
29284
- console.error(chalk.red("TEAM_TASKS.md has unpushed edits."), "Run", chalk.bold("chat-recall tasks push"), "first, or", chalk.bold("tasks pull --force"), "to discard.");
29413
+ console.error(chalk2.red("TEAM_TASKS.md has unpushed edits."), "Run", chalk2.bold("chat-recall tasks push"), "first, or", chalk2.bold("tasks pull --force"), "to discard.");
29285
29414
  process.exit(1);
29286
29415
  }
29287
29416
  const resolved = resolveProjectId2(cwd);
@@ -29289,9 +29418,9 @@ tasks.command("pull [dir]").description("Write TEAM_TASKS.md for your tasks in t
29289
29418
  const { tasks: tasks2 } = await serverGet("/api/tasks?assignee=@me");
29290
29419
  const mine = tasks2.filter((t) => !pid || !t.projectId || t.projectId === pid);
29291
29420
  writeFileSync22(file, renderTeamTasksMd2(mine));
29292
- console.log(chalk.green("\u2713 wrote"), "TEAM_TASKS.md", chalk.gray(`(${mine.length} task(s))`), "\u2014 edit, then", chalk.bold("chat-recall tasks push"));
29421
+ console.log(chalk2.green("\u2713 wrote"), "TEAM_TASKS.md", chalk2.gray(`(${mine.length} task(s))`), "\u2014 edit, then", chalk2.bold("chat-recall tasks push"));
29293
29422
  } catch (e) {
29294
- console.error(chalk.red(e instanceof Error ? e.message : String(e)));
29423
+ console.error(chalk2.red(e instanceof Error ? e.message : String(e)));
29295
29424
  process.exit(1);
29296
29425
  }
29297
29426
  });
@@ -29303,7 +29432,7 @@ tasks.command("push [dir]").description("Push TEAM_TASKS.md status edits back to
29303
29432
  const { join: join61 } = await import("node:path");
29304
29433
  const file = join61(cwd, "TEAM_TASKS.md");
29305
29434
  if (!existsSync57(file)) {
29306
- console.error(chalk.red("no TEAM_TASKS.md here \u2014"), "run", chalk.bold("chat-recall tasks pull"), "first");
29435
+ console.error(chalk2.red("no TEAM_TASKS.md here \u2014"), "run", chalk2.bold("chat-recall tasks pull"), "first");
29307
29436
  process.exit(1);
29308
29437
  }
29309
29438
  const edits = parseTeamTasksFile2(readFileSync50(file, "utf8"));
@@ -29312,9 +29441,9 @@ tasks.command("push [dir]").description("Push TEAM_TASKS.md status edits back to
29312
29441
  await serverPatch(`/api/tasks/${encodeURIComponent(e.id)}`, { status: e.intent });
29313
29442
  n++;
29314
29443
  }
29315
- console.log(n ? chalk.green(`\u2713 pushed ${n} status change(s)`) : chalk.gray("no changes to push"));
29444
+ console.log(n ? chalk2.green(`\u2713 pushed ${n} status change(s)`) : chalk2.gray("no changes to push"));
29316
29445
  } catch (e) {
29317
- console.error(chalk.red(e instanceof Error ? e.message : String(e)));
29446
+ console.error(chalk2.red(e instanceof Error ? e.message : String(e)));
29318
29447
  process.exit(1);
29319
29448
  }
29320
29449
  });
@@ -29325,12 +29454,12 @@ async function runTeam(label, fn) {
29325
29454
  await fn();
29326
29455
  } catch (err) {
29327
29456
  if (err instanceof TeamConfigError2) {
29328
- console.error(chalk.red(`${label}: ${err.message}`));
29457
+ console.error(chalk2.red(`${label}: ${err.message}`));
29329
29458
  } else if (err instanceof TeamAuthError2) {
29330
- console.error(chalk.red(`${label}: auth failed \u2014 ${err.message}`));
29331
- console.error(chalk.dim(" Check the env var named in settings.team.tokenRef holds a valid Keycloak access token."));
29459
+ console.error(chalk2.red(`${label}: auth failed \u2014 ${err.message}`));
29460
+ console.error(chalk2.dim(" Check the env var named in settings.team.tokenRef holds a valid Keycloak access token."));
29332
29461
  } else if (err instanceof TeamHttpError2) {
29333
- console.error(chalk.red(`${label}: ${err.message}`));
29462
+ console.error(chalk2.red(`${label}: ${err.message}`));
29334
29463
  } else {
29335
29464
  throw err;
29336
29465
  }
@@ -29340,76 +29469,76 @@ async function runTeam(label, fn) {
29340
29469
  team.command("whoami").description("Show the user + team memberships the server sees for your token").action(async () => runTeam("team whoami", async () => {
29341
29470
  const { teamMe: teamMe2 } = await Promise.resolve().then(() => (init_team_client(), team_client_exports));
29342
29471
  const me = await teamMe2();
29343
- console.log(chalk.bold(me.user.email) + chalk.dim(` (${me.user.id})`));
29472
+ console.log(chalk2.bold(me.user.email) + chalk2.dim(` (${me.user.id})`));
29344
29473
  if (me.memberships.length === 0) {
29345
- console.log(chalk.dim(" no team memberships yet \u2014 run `chat-recall team create <name>` or `team join <token>`"));
29474
+ console.log(chalk2.dim(" no team memberships yet \u2014 run `chat-recall team create <name>` or `team join <token>`"));
29346
29475
  return;
29347
29476
  }
29348
29477
  for (const m of me.memberships) {
29349
- const role = m.role === "owner" ? chalk.yellow(m.role) : chalk.dim(m.role);
29350
- console.log(` ${chalk.cyan(m.teamName)} ${role} ${chalk.dim(m.plan)} ${chalk.dim(m.teamId)}`);
29478
+ const role = m.role === "owner" ? chalk2.yellow(m.role) : chalk2.dim(m.role);
29479
+ console.log(` ${chalk2.cyan(m.teamName)} ${role} ${chalk2.dim(m.plan)} ${chalk2.dim(m.teamId)}`);
29351
29480
  }
29352
29481
  }));
29353
29482
  team.command("create <name>").description("Create a new team. You become the owner. Stores teamId in settings.").action(async (name) => runTeam("team create", async () => {
29354
29483
  const { teamCreate: teamCreate2 } = await Promise.resolve().then(() => (init_team_client(), team_client_exports));
29355
29484
  const t = await teamCreate2(name);
29356
- console.log(chalk.green(`\u2713 Team created: ${chalk.bold(t.name)}`));
29357
- console.log(chalk.dim(` id: ${t.id}`));
29358
- console.log(chalk.dim(` Now generate an invite: chat-recall team invite`));
29485
+ console.log(chalk2.green(`\u2713 Team created: ${chalk2.bold(t.name)}`));
29486
+ console.log(chalk2.dim(` id: ${t.id}`));
29487
+ console.log(chalk2.dim(` Now generate an invite: chat-recall team invite`));
29359
29488
  }));
29360
29489
  team.command("invite").description("Generate a single-use invite token for your team (owner-only)").option("--email <hint>", "Display hint (e.g. teammate@company.com); not validated").action(async (opts) => runTeam("team invite", async () => {
29361
29490
  const { teamInvite: teamInvite2 } = await Promise.resolve().then(() => (init_team_client(), team_client_exports));
29362
29491
  const r = await teamInvite2(opts.email);
29363
- console.log(chalk.bold("Invite token (copy now \u2014 shown once):"));
29364
- console.log(" " + chalk.cyan(r.inviteToken));
29365
- console.log(chalk.dim(` expires: ${r.expiresAt}`));
29492
+ console.log(chalk2.bold("Invite token (copy now \u2014 shown once):"));
29493
+ console.log(" " + chalk2.cyan(r.inviteToken));
29494
+ console.log(chalk2.dim(` expires: ${r.expiresAt}`));
29366
29495
  console.log();
29367
- console.log(chalk.dim("Recipient runs: chat-recall team join <token>"));
29496
+ console.log(chalk2.dim("Recipient runs: chat-recall team join <token>"));
29368
29497
  }));
29369
29498
  team.command("join <invite-token>").description("Accept a team invite. Stores team id locally.").action(async (inviteToken) => runTeam("team join", async () => {
29370
29499
  const { teamJoin: teamJoin2 } = await Promise.resolve().then(() => (init_team_client(), team_client_exports));
29371
29500
  const t = await teamJoin2(inviteToken);
29372
- console.log(chalk.green(`\u2713 Joined team: ${chalk.bold(t.name)}`));
29373
- console.log(chalk.dim(` id: ${t.id}`));
29374
- console.log(chalk.dim(" Run `chat-recall team pull` to fetch the team library."));
29501
+ console.log(chalk2.green(`\u2713 Joined team: ${chalk2.bold(t.name)}`));
29502
+ console.log(chalk2.dim(` id: ${t.id}`));
29503
+ console.log(chalk2.dim(" Run `chat-recall team pull` to fetch the team library."));
29375
29504
  }));
29376
29505
  team.command("pull").description("Pull artifacts changed since the last pull and write them into your local ~/.claude/, ~/.gemini/, ~/.codex/ dirs").option("--dry-run", "Fetch but don't write to disk (preview only)").action(async (opts) => runTeam("team pull", async () => {
29377
29506
  const { teamPull: teamPull2 } = await Promise.resolve().then(() => (init_team_client(), team_client_exports));
29378
29507
  const r = await teamPull2();
29379
29508
  if (r.pulled.length === 0 && r.removed.length === 0) {
29380
- console.log(chalk.dim("Up to date."));
29509
+ console.log(chalk2.dim("Up to date."));
29381
29510
  return;
29382
29511
  }
29383
29512
  for (const a of r.pulled) {
29384
- console.log(` ${chalk.green("+")} ${chalk.cyan(a.type + "/" + a.name)} v${a.version} ${chalk.dim("(" + a.tool + ")")}`);
29513
+ console.log(` ${chalk2.green("+")} ${chalk2.cyan(a.type + "/" + a.name)} v${a.version} ${chalk2.dim("(" + a.tool + ")")}`);
29385
29514
  }
29386
29515
  for (const id of r.removed) {
29387
- console.log(` ${chalk.red("-")} ${chalk.dim(id + " (revoked)")}`);
29516
+ console.log(` ${chalk2.red("-")} ${chalk2.dim(id + " (revoked)")}`);
29388
29517
  }
29389
29518
  if (opts.dryRun) {
29390
- console.log(chalk.dim(`Watermark: ${r.serverNow} (dry-run \u2014 nothing written)`));
29519
+ console.log(chalk2.dim(`Watermark: ${r.serverNow} (dry-run \u2014 nothing written)`));
29391
29520
  return;
29392
29521
  }
29393
29522
  const { mergePullResult: mergePullResult2 } = await Promise.resolve().then(() => (init_team_merge(), team_merge_exports));
29394
29523
  const m = await mergePullResult2({ pulled: r.pulled, removed: r.removed });
29395
29524
  console.log();
29396
- if (m.written.length) console.log(chalk.green(`\u2713 Wrote ${m.written.length} file${m.written.length === 1 ? "" : "s"}`));
29397
- if (m.skipped.length) console.log(chalk.dim(` Skipped ${m.skipped.length} (unchanged or no target tool)`));
29398
- if (m.removed.length) console.log(chalk.yellow(` Removed ${m.removed.length} revoked file${m.removed.length === 1 ? "" : "s"}`));
29525
+ if (m.written.length) console.log(chalk2.green(`\u2713 Wrote ${m.written.length} file${m.written.length === 1 ? "" : "s"}`));
29526
+ if (m.skipped.length) console.log(chalk2.dim(` Skipped ${m.skipped.length} (unchanged or no target tool)`));
29527
+ if (m.removed.length) console.log(chalk2.yellow(` Removed ${m.removed.length} revoked file${m.removed.length === 1 ? "" : "s"}`));
29399
29528
  for (const f of m.failures) {
29400
- console.log(chalk.red(` ! ${f.path}: ${f.error}`));
29529
+ console.log(chalk2.red(` ! ${f.path}: ${f.error}`));
29401
29530
  }
29402
- console.log(chalk.dim(`Watermark: ${r.serverNow}`));
29531
+ console.log(chalk2.dim(`Watermark: ${r.serverNow}`));
29403
29532
  }));
29404
29533
  team.command("publish <type> <name> <file>").description("Publish a local file as an artifact (skill|command|agent|mcp|plan|plugin|instructions|hook)").option("--tool <tool>", "Target tool: claude|gemini|opencode|codex|agy|cursor|cross_tool", "cross_tool").option("--pinned-to <glob>", "Limit which projects pull this artifact").action(async (type, name, file, opts) => runTeam("team publish", async () => {
29405
29534
  const validTypes = ["skill", "command", "agent", "mcp", "plan", "plugin", "instructions", "hook"];
29406
29535
  if (!validTypes.includes(type)) {
29407
- console.error(chalk.red(`Invalid type: ${type}. Must be one of: ${validTypes.join(", ")}`));
29536
+ console.error(chalk2.red(`Invalid type: ${type}. Must be one of: ${validTypes.join(", ")}`));
29408
29537
  process.exit(1);
29409
29538
  }
29410
29539
  const validTools = ["claude", "gemini", "opencode", "codex", "agy", "cursor", "cross_tool"];
29411
29540
  if (!validTools.includes(opts.tool)) {
29412
- console.error(chalk.red(`Invalid tool: ${opts.tool}. Must be one of: ${validTools.join(", ")}`));
29541
+ console.error(chalk2.red(`Invalid tool: ${opts.tool}. Must be one of: ${validTools.join(", ")}`));
29413
29542
  process.exit(1);
29414
29543
  }
29415
29544
  const { readFileSync: readFileSync50 } = await import("fs");
@@ -29422,32 +29551,32 @@ team.command("publish <type> <name> <file>").description("Publish a local file a
29422
29551
  body,
29423
29552
  pinnedTo: opts.pinnedTo
29424
29553
  });
29425
- console.log(chalk.green(`\u2713 Published ${chalk.bold(type + "/" + name)} v${a.version}`));
29426
- console.log(chalk.dim(` id: ${a.id}`));
29427
- console.log(chalk.dim(` sha256: ${a.sha256}`));
29554
+ console.log(chalk2.green(`\u2713 Published ${chalk2.bold(type + "/" + name)} v${a.version}`));
29555
+ console.log(chalk2.dim(` id: ${a.id}`));
29556
+ console.log(chalk2.dim(` sha256: ${a.sha256}`));
29428
29557
  }));
29429
29558
  team.command("list").description("List artifacts in the team library (metadata only, no bodies)").action(async () => runTeam("team list", async () => {
29430
29559
  const { teamList: teamList2 } = await Promise.resolve().then(() => (init_team_client(), team_client_exports));
29431
29560
  const items = await teamList2();
29432
29561
  if (items.length === 0) {
29433
- console.log(chalk.dim("Library is empty. Try `chat-recall team publish <type> <name> <file>`."));
29562
+ console.log(chalk2.dim("Library is empty. Try `chat-recall team publish <type> <name> <file>`."));
29434
29563
  return;
29435
29564
  }
29436
29565
  for (const a of items) {
29437
- const pinned = a.pinnedTo ? chalk.dim(` pinned=${a.pinnedTo}`) : "";
29438
- console.log(` ${chalk.cyan(a.type + "/" + a.name)} v${a.version} ${chalk.dim("(" + a.tool + ", " + a.bytes + " bytes)")}${pinned}`);
29566
+ const pinned = a.pinnedTo ? chalk2.dim(` pinned=${a.pinnedTo}`) : "";
29567
+ console.log(` ${chalk2.cyan(a.type + "/" + a.name)} v${a.version} ${chalk2.dim("(" + a.tool + ", " + a.bytes + " bytes)")}${pinned}`);
29439
29568
  }
29440
29569
  }));
29441
29570
  team.command("revoke <artifact-id>").alias("unpublish").description("Revoke an artifact from the team library (owner-only)").action(async (artifactId) => runTeam("team revoke", async () => {
29442
29571
  const { teamRevoke: teamRevoke2 } = await Promise.resolve().then(() => (init_team_client(), team_client_exports));
29443
29572
  const r = await teamRevoke2(artifactId);
29444
- console.log(chalk.green(`\u2713 Revoked ${chalk.bold(r.type + "/" + r.name)} (${r.id})`));
29573
+ console.log(chalk2.green(`\u2713 Revoked ${chalk2.bold(r.type + "/" + r.name)} (${r.id})`));
29445
29574
  }));
29446
29575
  team.command("leave").description("Clear local team config (does not delete pulled artifacts; does not remove your server-side membership)").action(async () => runTeam("team leave", async () => {
29447
29576
  const { teamLeave: teamLeave2 } = await Promise.resolve().then(() => (init_team_client(), team_client_exports));
29448
29577
  await teamLeave2();
29449
- console.log(chalk.green("\u2713 Local team config cleared."));
29450
- console.log(chalk.dim(" Server-side membership unchanged. Owner must remove you to fully leave."));
29578
+ console.log(chalk2.green("\u2713 Local team config cleared."));
29579
+ console.log(chalk2.dim(" Server-side membership unchanged. Owner must remove you to fully leave."));
29451
29580
  }));
29452
29581
  var vault = program.command("vault").description("Encrypted multi-device chat backup (E2EE \u2014 server cannot decrypt)");
29453
29582
  async function runVault(label, fn) {
@@ -29455,9 +29584,9 @@ async function runVault(label, fn) {
29455
29584
  try {
29456
29585
  await fn();
29457
29586
  } catch (err) {
29458
- if (err instanceof VaultConfigError2) console.error(chalk.red(`${label}: ${err.message}`));
29459
- else if (err instanceof VaultAuthError2) console.error(chalk.red(`${label}: auth failed \u2014 ${err.message}`));
29460
- else if (err instanceof VaultHttpError2) console.error(chalk.red(`${label}: ${err.message}`));
29587
+ if (err instanceof VaultConfigError2) console.error(chalk2.red(`${label}: ${err.message}`));
29588
+ else if (err instanceof VaultAuthError2) console.error(chalk2.red(`${label}: auth failed \u2014 ${err.message}`));
29589
+ else if (err instanceof VaultHttpError2) console.error(chalk2.red(`${label}: ${err.message}`));
29461
29590
  else throw err;
29462
29591
  process.exit(1);
29463
29592
  }
@@ -29467,7 +29596,7 @@ async function resolvePassphrase(opts) {
29467
29596
  if (opts.envVar) {
29468
29597
  const v = process.env[opts.envVar];
29469
29598
  if (v) return v;
29470
- console.error(chalk.red(`Env var ${opts.envVar} is not set.`));
29599
+ console.error(chalk2.red(`Env var ${opts.envVar} is not set.`));
29471
29600
  process.exit(1);
29472
29601
  }
29473
29602
  if (!opts.noKeyring) {
@@ -29504,49 +29633,49 @@ vault.command("enable").description("Set up the Vault on this device. Generates
29504
29633
  r = await vaultEnableWithRemote2(passphrase, { baseUrl: cred.serverUrl, token: cred.token });
29505
29634
  } catch (err) {
29506
29635
  if (err instanceof VaultPassphraseMismatchError2) {
29507
- console.error(chalk.red(`vault enable: ${err.message}`));
29636
+ console.error(chalk2.red(`vault enable: ${err.message}`));
29508
29637
  process.exit(1);
29509
29638
  }
29510
29639
  throw err;
29511
29640
  }
29512
29641
  }
29513
- console.log(chalk.green("\u2713 Vault enabled on this device."));
29514
- console.log(chalk.dim(` keyId: ${r.keyId}`));
29515
- console.log(chalk.dim(` salt: ${r.saltHex}`) + (r.saltSource === "server" ? chalk.dim(" (from your workspace)") : ""));
29642
+ console.log(chalk2.green("\u2713 Vault enabled on this device."));
29643
+ console.log(chalk2.dim(` keyId: ${r.keyId}`));
29644
+ console.log(chalk2.dim(` salt: ${r.saltHex}`) + (r.saltSource === "server" ? chalk2.dim(" (from your workspace)") : ""));
29516
29645
  if (opts.keyring === false) {
29517
- console.log(chalk.yellow(" keyring: skipped (--no-keyring) \u2014 the background daemon will not be able to decrypt."));
29646
+ console.log(chalk2.yellow(" keyring: skipped (--no-keyring) \u2014 the background daemon will not be able to decrypt."));
29518
29647
  } else {
29519
29648
  const { keyringSet: keyringSet2, probeKeyring: probeKeyring2 } = await Promise.resolve().then(() => (init_keyring(), keyring_exports));
29520
29649
  try {
29521
29650
  keyringSet2(passphrase);
29522
- console.log(chalk.dim(` keyring: stored (${probeKeyring2().backend}) \u2014 the daemon can decrypt unattended.`));
29651
+ console.log(chalk2.dim(` keyring: stored (${probeKeyring2().backend}) \u2014 the daemon can decrypt unattended.`));
29523
29652
  } catch (err) {
29524
- console.log(chalk.yellow(` keyring: unavailable \u2014 ${err instanceof Error ? err.message : err}`));
29525
- console.log(chalk.yellow(" The vault still works for foreground commands; cross-device artifacts will not apply on this machine."));
29653
+ console.log(chalk2.yellow(` keyring: unavailable \u2014 ${err instanceof Error ? err.message : err}`));
29654
+ console.log(chalk2.yellow(" The vault still works for foreground commands; cross-device artifacts will not apply on this machine."));
29526
29655
  }
29527
29656
  }
29528
29657
  console.log();
29529
29658
  if (r.saltSource === "server") {
29530
- console.log(chalk.dim("This device joined your existing vault \u2014 same passphrase, same key."));
29659
+ console.log(chalk2.dim("This device joined your existing vault \u2014 same passphrase, same key."));
29531
29660
  } else {
29532
- console.log(chalk.yellow("To set up another device, run there:"));
29661
+ console.log(chalk2.yellow("To set up another device, run there:"));
29533
29662
  console.log(" chat-recall vault enable");
29534
- console.log(chalk.dim(" (it picks up this workspace's salt automatically \u2014 only the passphrase is needed)"));
29663
+ console.log(chalk2.dim(" (it picks up this workspace's salt automatically \u2014 only the passphrase is needed)"));
29535
29664
  }
29536
- console.log(chalk.yellow("Lose the passphrase = lose encrypted history. There is no recovery."));
29665
+ console.log(chalk2.yellow("Lose the passphrase = lose encrypted history. There is no recovery."));
29537
29666
  }));
29538
29667
  vault.command("sync").description("Walk local chat sources, encrypt new/changed sessions, upload ciphertext to the server").option("--passphrase <s>", "Passphrase (insecure \u2014 prefer interactive or --passphrase-env)").option("--passphrase-env <name>", "Read passphrase from this env var").action(async (opts) => runVault("vault sync", async () => {
29539
29668
  const passphrase = await resolvePassphrase({ passphrase: opts.passphrase, envVar: opts.passphraseEnv });
29540
29669
  const { vaultSync: vaultSync2 } = await Promise.resolve().then(() => (init_vault_client(), vault_client_exports));
29541
29670
  const r = await vaultSync2(passphrase);
29542
29671
  if (r.uploaded.length === 0 && r.skipped.length === 0 && r.failures.length === 0) {
29543
- console.log(chalk.dim("No chat sources found."));
29672
+ console.log(chalk2.dim("No chat sources found."));
29544
29673
  return;
29545
29674
  }
29546
- if (r.uploaded.length) console.log(chalk.green(`\u2713 Uploaded ${r.uploaded.length} session${r.uploaded.length === 1 ? "" : "s"}`));
29547
- if (r.skipped.length) console.log(chalk.dim(` Skipped ${r.skipped.length} (unchanged or denylisted)`));
29675
+ if (r.uploaded.length) console.log(chalk2.green(`\u2713 Uploaded ${r.uploaded.length} session${r.uploaded.length === 1 ? "" : "s"}`));
29676
+ if (r.skipped.length) console.log(chalk2.dim(` Skipped ${r.skipped.length} (unchanged or denylisted)`));
29548
29677
  for (const f of r.failures) {
29549
- console.log(chalk.red(` ! ${f.tool}/${f.sessionId}: ${f.error}`));
29678
+ console.log(chalk2.red(` ! ${f.tool}/${f.sessionId}: ${f.error}`));
29550
29679
  }
29551
29680
  }));
29552
29681
  vault.command("restore").description("Pull encrypted blobs from the server, decrypt locally, write them where chat-recall can index them").option("--passphrase <s>", "Passphrase (insecure \u2014 prefer interactive or --passphrase-env)").option("--passphrase-env <name>", "Read passphrase from this env var").option("--since <ms>", "Only restore blobs uploaded after this ms-epoch (default 0 = all)").action(async (opts) => runVault("vault restore", async () => {
@@ -29554,13 +29683,13 @@ vault.command("restore").description("Pull encrypted blobs from the server, decr
29554
29683
  const { vaultRestore: vaultRestore2 } = await Promise.resolve().then(() => (init_vault_client(), vault_client_exports));
29555
29684
  const r = await vaultRestore2(passphrase, { since: opts.since ? Number(opts.since) : void 0 });
29556
29685
  if (r.restored.length === 0 && r.skipped.length === 0 && r.failures.length === 0) {
29557
- console.log(chalk.dim("No blobs to restore."));
29686
+ console.log(chalk2.dim("No blobs to restore."));
29558
29687
  return;
29559
29688
  }
29560
- if (r.restored.length) console.log(chalk.green(`\u2713 Restored ${r.restored.length} session${r.restored.length === 1 ? "" : "s"}`));
29561
- if (r.skipped.length) console.log(chalk.dim(` Skipped ${r.skipped.length} (unchanged or different key)`));
29689
+ if (r.restored.length) console.log(chalk2.green(`\u2713 Restored ${r.restored.length} session${r.restored.length === 1 ? "" : "s"}`));
29690
+ if (r.skipped.length) console.log(chalk2.dim(` Skipped ${r.skipped.length} (unchanged or different key)`));
29562
29691
  for (const f of r.failures) {
29563
- console.log(chalk.red(` ! ${f.tool}/${f.sessionId}: ${f.error}`));
29692
+ console.log(chalk2.red(` ! ${f.tool}/${f.sessionId}: ${f.error}`));
29564
29693
  }
29565
29694
  }));
29566
29695
  vault.command("status").description("Show whether the Vault is enabled, salt fingerprint, last sync time, and whether this machine can decrypt unattended").action(async () => runVault("vault status", async () => {
@@ -29570,8 +29699,8 @@ vault.command("status").description("Show whether the Vault is enabled, salt fin
29570
29699
  const probe = probeKeyring2();
29571
29700
  const reportKeyring = () => {
29572
29701
  if (!probe.available) {
29573
- console.log(chalk.yellow(` keyring: unavailable (${probe.backend}) \u2014 cross-device artifacts will not apply on this machine`));
29574
- if (probe.hint) console.log(chalk.dim(` ${probe.hint}`));
29702
+ console.log(chalk2.yellow(` keyring: unavailable (${probe.backend}) \u2014 cross-device artifacts will not apply on this machine`));
29703
+ if (probe.hint) console.log(chalk2.dim(` ${probe.hint}`));
29575
29704
  return;
29576
29705
  }
29577
29706
  let stored = false;
@@ -29580,27 +29709,27 @@ vault.command("status").description("Show whether the Vault is enabled, salt fin
29580
29709
  } catch {
29581
29710
  stored = false;
29582
29711
  }
29583
- console.log(stored ? chalk.dim(` keyring: ${probe.backend}, passphrase stored \u2014 the daemon can decrypt unattended`) : chalk.yellow(` keyring: ${probe.backend}, no passphrase stored \u2014 run \`chat-recall vault enable\` to let the daemon decrypt`));
29712
+ console.log(stored ? chalk2.dim(` keyring: ${probe.backend}, passphrase stored \u2014 the daemon can decrypt unattended`) : chalk2.yellow(` keyring: ${probe.backend}, no passphrase stored \u2014 run \`chat-recall vault enable\` to let the daemon decrypt`));
29584
29713
  };
29585
29714
  if (!s.enabled) {
29586
- console.log(chalk.dim("Vault: disabled. Run `chat-recall vault enable`."));
29715
+ console.log(chalk2.dim("Vault: disabled. Run `chat-recall vault enable`."));
29587
29716
  reportKeyring();
29588
29717
  return;
29589
29718
  }
29590
- console.log(chalk.green("Vault: enabled"));
29591
- console.log(chalk.dim(` keyId: ${s.keyId ?? "(unknown \u2014 re-enable)"}`));
29592
- console.log(chalk.dim(` salt: ${s.saltHex ? s.saltHex.slice(0, 16) + "\u2026" : "(missing)"}`));
29593
- console.log(chalk.dim(` lastSyncAt: ${s.lastSyncAt ? new Date(s.lastSyncAt).toISOString() : "never"}`));
29594
- console.log(chalk.dim(` syncTools: ${s.syncTools.join(", ")}`));
29595
- console.log(chalk.dim(` excludeProj: ${s.excludeProjects.length ? s.excludeProjects.join(", ") : "(none)"}`));
29719
+ console.log(chalk2.green("Vault: enabled"));
29720
+ console.log(chalk2.dim(` keyId: ${s.keyId ?? "(unknown \u2014 re-enable)"}`));
29721
+ console.log(chalk2.dim(` salt: ${s.saltHex ? s.saltHex.slice(0, 16) + "\u2026" : "(missing)"}`));
29722
+ console.log(chalk2.dim(` lastSyncAt: ${s.lastSyncAt ? new Date(s.lastSyncAt).toISOString() : "never"}`));
29723
+ console.log(chalk2.dim(` syncTools: ${s.syncTools.join(", ")}`));
29724
+ console.log(chalk2.dim(` excludeProj: ${s.excludeProjects.length ? s.excludeProjects.join(", ") : "(none)"}`));
29596
29725
  reportKeyring();
29597
29726
  }));
29598
29727
  vault.command("forget").description("Remove the stored passphrase from this machine's OS keyring (the vault stays enabled; the daemon stops being able to decrypt)").action(async () => runVault("vault forget", async () => {
29599
29728
  const { keyringDelete: keyringDelete2 } = await Promise.resolve().then(() => (init_keyring(), keyring_exports));
29600
- console.log(keyringDelete2() ? chalk.green("\u2713 Passphrase removed from the OS keyring.") : chalk.dim("Nothing stored in the OS keyring."));
29729
+ console.log(keyringDelete2() ? chalk2.green("\u2713 Passphrase removed from the OS keyring.") : chalk2.dim("Nothing stored in the OS keyring."));
29601
29730
  }));
29602
29731
  program.command("install-hooks").description("Install Claude Code hooks (Stop + PreCompact + UserPromptSubmit + SessionEnd + SessionStart) into every Claude profile").option("--uninstall", "Remove hooks instead of installing them").option("--no-resume-hint", "Don't install the UserPromptSubmit resume-hint hook").option("--no-escalate", "Don't install the SessionEnd learnings-escalation hook").option("--no-wakeup", "Don't install the SessionStart wake-up hook").action(async (opts) => {
29603
- const { mkdirSync: mkdirSync20, copyFileSync: copyFileSync4, chmodSync: chmodSync5, existsSync: existsSync57, readFileSync: readFileSync50, writeFileSync: writeFileSync22, statSync: statSync46 } = await import("fs");
29732
+ const { mkdirSync: mkdirSync20, copyFileSync: copyFileSync4, chmodSync: chmodSync5, existsSync: existsSync57, readFileSync: readFileSync50, writeFileSync: writeFileSync22, statSync: statSync47 } = await import("fs");
29604
29733
  const { fileURLToPath: fileURLToPath6 } = await import("url");
29605
29734
  const here = fileURLToPath6(new URL(".", import.meta.url));
29606
29735
  const findHook = (name) => {
@@ -29615,7 +29744,7 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
29615
29744
  const sourceEscalateHook = findHook("chat_recall_escalate_hook.sh");
29616
29745
  const sourceWakeupHook = findHook("chat_recall_wakeup_hook.sh");
29617
29746
  if (!sourceSaveHook) {
29618
- console.error(chalk.red("Could not locate chat_recall_save_hook.sh in the package."));
29747
+ console.error(chalk2.red("Could not locate chat_recall_save_hook.sh in the package."));
29619
29748
  process.exit(1);
29620
29749
  }
29621
29750
  const hooksDir = getHooksDir();
@@ -29642,8 +29771,8 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
29642
29771
  if (!c.hooks || typeof c.hooks !== "object") c.hooks = {};
29643
29772
  return c;
29644
29773
  } catch (err) {
29645
- console.error(chalk.red(`Could not parse ${file}: ${err}`));
29646
- console.error(chalk.dim("Fix the file or move it aside before re-running."));
29774
+ console.error(chalk2.red(`Could not parse ${file}: ${err}`));
29775
+ console.error(chalk2.dim("Fix the file or move it aside before re-running."));
29647
29776
  process.exit(1);
29648
29777
  }
29649
29778
  };
@@ -29667,23 +29796,23 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
29667
29796
  if (removed === 0 && !existsSync57(hooksJson)) continue;
29668
29797
  writeFileSync22(hooksJson, JSON.stringify(config2, null, 2) + "\n");
29669
29798
  total += removed;
29670
- console.log(chalk.green(`\u2713 Removed ${removed} chat-recall hook entr${removed === 1 ? "y" : "ies"} from ${hooksJson}`));
29799
+ console.log(chalk2.green(`\u2713 Removed ${removed} chat-recall hook entr${removed === 1 ? "y" : "ies"} from ${hooksJson}`));
29671
29800
  }
29672
- if (total === 0) console.log(chalk.dim("No chat-recall hook entries were registered."));
29673
- console.log(chalk.dim(` (Hook scripts left in ${hooksDir} \u2014 delete manually if you want.)`));
29801
+ if (total === 0) console.log(chalk2.dim("No chat-recall hook entries were registered."));
29802
+ console.log(chalk2.dim(` (Hook scripts left in ${hooksDir} \u2014 delete manually if you want.)`));
29674
29803
  return;
29675
29804
  }
29676
29805
  if (process.platform === "win32") {
29677
- console.log(chalk.yellow("Hooks are not installed on Windows."));
29678
- console.log(chalk.dim(" They are POSIX shell scripts, and Claude Code runs hook commands through"));
29679
- console.log(chalk.dim(" cmd.exe, which cannot execute them. Registering them would put an error on"));
29680
- console.log(chalk.dim(" every turn instead of saving anything."));
29681
- console.log(chalk.dim(""));
29682
- console.log(chalk.dim(" Everything else works: indexing, sync, search and the MCP server are"));
29683
- console.log(chalk.dim(" unaffected. Hooks only add automatic fact-saving and the wake-up bundle,"));
29684
- console.log(chalk.dim(" and you can get the same context by calling recall_wake_up from the agent."));
29685
- console.log(chalk.dim(""));
29686
- console.log(chalk.dim(" Under WSL, run this from inside the WSL shell and it installs normally."));
29806
+ console.log(chalk2.yellow("Hooks are not installed on Windows."));
29807
+ console.log(chalk2.dim(" They are POSIX shell scripts, and Claude Code runs hook commands through"));
29808
+ console.log(chalk2.dim(" cmd.exe, which cannot execute them. Registering them would put an error on"));
29809
+ console.log(chalk2.dim(" every turn instead of saving anything."));
29810
+ console.log(chalk2.dim(""));
29811
+ console.log(chalk2.dim(" Everything else works: indexing, sync, search and the MCP server are"));
29812
+ console.log(chalk2.dim(" unaffected. Hooks only add automatic fact-saving and the wake-up bundle,"));
29813
+ console.log(chalk2.dim(" and you can get the same context by calling recall_wake_up from the agent."));
29814
+ console.log(chalk2.dim(""));
29815
+ console.log(chalk2.dim(" Under WSL, run this from inside the WSL shell and it installs normally."));
29687
29816
  return;
29688
29817
  }
29689
29818
  mkdirSync20(hooksDir, { recursive: true });
@@ -29733,35 +29862,35 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
29733
29862
  mkdirSync20(dirname27(hooksJson), { recursive: true });
29734
29863
  writeFileSync22(hooksJson, JSON.stringify(config2, null, 2) + "\n");
29735
29864
  }
29736
- const saveSz = statSync46(installedSaveHook).size;
29737
- console.log(chalk.green(`\u2713 Installed chat-recall save hook (${saveSz} bytes)`));
29865
+ const saveSz = statSync47(installedSaveHook).size;
29866
+ console.log(chalk2.green(`\u2713 Installed chat-recall save hook (${saveSz} bytes)`));
29738
29867
  if (installResume) {
29739
- const resumeSz = statSync46(installedResumeHook).size;
29740
- console.log(chalk.green(`\u2713 Installed chat-recall resume-hint hook (${resumeSz} bytes)`));
29868
+ const resumeSz = statSync47(installedResumeHook).size;
29869
+ console.log(chalk2.green(`\u2713 Installed chat-recall resume-hint hook (${resumeSz} bytes)`));
29741
29870
  }
29742
29871
  if (installEscalate) {
29743
- const escalateSz = statSync46(installedEscalateHook).size;
29744
- console.log(chalk.green(`\u2713 Installed chat-recall learnings-escalation hook (${escalateSz} bytes)`));
29872
+ const escalateSz = statSync47(installedEscalateHook).size;
29873
+ console.log(chalk2.green(`\u2713 Installed chat-recall learnings-escalation hook (${escalateSz} bytes)`));
29745
29874
  }
29746
29875
  if (installWakeup) {
29747
- const wakeupSz = statSync46(installedWakeupHook).size;
29748
- console.log(chalk.green(`\u2713 Installed chat-recall wake-up hook (${wakeupSz} bytes)`));
29876
+ const wakeupSz = statSync47(installedWakeupHook).size;
29877
+ console.log(chalk2.green(`\u2713 Installed chat-recall wake-up hook (${wakeupSz} bytes)`));
29749
29878
  for (const f of wakeupSkipped) {
29750
- console.log(chalk.dim(` (SessionStart already wired in ${f} \u2014 left as is, not duplicated)`));
29879
+ console.log(chalk2.dim(` (SessionStart already wired in ${f} \u2014 left as is, not duplicated)`));
29751
29880
  }
29752
29881
  }
29753
- console.log(chalk.dim(` scripts: ${hooksDir}`));
29882
+ console.log(chalk2.dim(` scripts: ${hooksDir}`));
29754
29883
  for (const [i, f] of hookConfigFiles.entries()) {
29755
- console.log(chalk.dim(` ${i === 0 ? "config: " : " "} ${f}`));
29884
+ console.log(chalk2.dim(` ${i === 0 ? "config: " : " "} ${f}`));
29756
29885
  }
29757
- console.log(chalk.dim(` events: Stop, PreCompact${installResume ? ", UserPromptSubmit" : ""}${installEscalate ? ", SessionEnd" : ""}${installWakeup ? ", SessionStart" : ""}`));
29886
+ console.log(chalk2.dim(` events: Stop, PreCompact${installResume ? ", UserPromptSubmit" : ""}${installEscalate ? ", SessionEnd" : ""}${installWakeup ? ", SessionStart" : ""}`));
29758
29887
  console.log();
29759
- console.log(chalk.dim("Run `chat-recall install-hooks --uninstall` to remove later."));
29888
+ console.log(chalk2.dim("Run `chat-recall install-hooks --uninstall` to remove later."));
29760
29889
  if (!installResume) {
29761
- console.log(chalk.dim("(--no-resume-hint passed \u2014 UserPromptSubmit hook skipped)"));
29890
+ console.log(chalk2.dim("(--no-resume-hint passed \u2014 UserPromptSubmit hook skipped)"));
29762
29891
  }
29763
29892
  if (!installEscalate) {
29764
- console.log(chalk.dim("(--no-escalate passed \u2014 SessionEnd hook skipped)"));
29893
+ console.log(chalk2.dim("(--no-escalate passed \u2014 SessionEnd hook skipped)"));
29765
29894
  }
29766
29895
  });
29767
29896
  program.command("dossier <project>").description("Generate a project dossier (overview/architecture/decisions/etc) as markdown (requires login)").option("--sessions <n>", "Max sessions to enumerate", "10").option("--tasks <n>", "Max open tasks to list", "20").option("--plans <n>", "Max plans to list", "20").option("--out <file>", "Write report to this file instead of stdout").action(async (project, options) => {
@@ -29777,12 +29906,12 @@ program.command("dossier <project>").description("Generate a project dossier (ov
29777
29906
  const md = dossier.markdown;
29778
29907
  if (options.out) {
29779
29908
  writeFileSync21(options.out, md);
29780
- console.log(chalk.green(`Wrote dossier to ${options.out} (${md.length} chars)`));
29909
+ console.log(chalk2.green(`Wrote dossier to ${options.out} (${md.length} chars)`));
29781
29910
  } else {
29782
29911
  console.log(md);
29783
29912
  }
29784
29913
  } catch (err) {
29785
- console.error(chalk.red("Error:"), err instanceof Error ? err.message : err);
29914
+ console.error(chalk2.red("Error:"), err instanceof Error ? err.message : err);
29786
29915
  process.exit(1);
29787
29916
  }
29788
29917
  });
@@ -29795,17 +29924,17 @@ program.command("watch").description("Run the live indexer daemon (watches all A
29795
29924
  try {
29796
29925
  const { installService: installService2, isServiceRunning: isServiceRunning2, platformName: platformName2 } = await Promise.resolve().then(() => (init_service_installer(), service_installer_exports));
29797
29926
  if (isServiceRunning2()) {
29798
- console.log(chalk.green(`\u2713 chat-recall-watch service already running (${platformName2()}).`));
29927
+ console.log(chalk2.green(`\u2713 chat-recall-watch service already running (${platformName2()}).`));
29799
29928
  return;
29800
29929
  }
29801
29930
  const paths = installService2();
29802
- console.log(chalk.green(`\u2713 chat-recall-watch service installed and started (${platformName2()}).`));
29803
- if (paths.definitionPath) console.log(chalk.dim(` unit: ${paths.definitionPath}`));
29804
- console.log(chalk.dim(` logs: ${paths.logFile} \xB7 manage: \`chat-recall service status\``));
29931
+ console.log(chalk2.green(`\u2713 chat-recall-watch service installed and started (${platformName2()}).`));
29932
+ if (paths.definitionPath) console.log(chalk2.dim(` unit: ${paths.definitionPath}`));
29933
+ console.log(chalk2.dim(` logs: ${paths.logFile} \xB7 manage: \`chat-recall service status\``));
29805
29934
  } catch (err) {
29806
29935
  const se = err;
29807
- console.error(chalk.red(se.message || String(err)));
29808
- if (se.hint) console.error(chalk.dim(` ${se.hint}`));
29936
+ console.error(chalk2.red(se.message || String(err)));
29937
+ if (se.hint) console.error(chalk2.dim(` ${se.hint}`));
29809
29938
  process.exit(1);
29810
29939
  }
29811
29940
  return;
@@ -29823,7 +29952,7 @@ program.command("watch").description("Run the live indexer daemon (watches all A
29823
29952
  lastErr = err;
29824
29953
  }
29825
29954
  }
29826
- console.error(chalk.red("Could not load the watch daemon:"), lastErr instanceof Error ? lastErr.message : lastErr);
29955
+ console.error(chalk2.red("Could not load the watch daemon:"), lastErr instanceof Error ? lastErr.message : lastErr);
29827
29956
  process.exit(1);
29828
29957
  });
29829
29958
  program.command("service <action>").description("Manage the per-user background sync service (Linux: systemd --user \xB7 macOS: launchd \xB7 Windows: Scheduled Task). No admin rights.").action(async (action) => {
@@ -29832,25 +29961,25 @@ program.command("service <action>").description("Manage the per-user background
29832
29961
  if (action === "install") {
29833
29962
  const wasRunning = isServiceRunning2();
29834
29963
  const paths = installService2();
29835
- console.log(chalk.green(wasRunning ? `\u2713 chat-recall-watch service restarted with the current binary (${platformName2()}).` : `\u2713 chat-recall-watch service installed and started (${platformName2()}).`));
29836
- if (paths.definitionPath) console.log(chalk.dim(` unit: ${paths.definitionPath}`));
29837
- console.log(chalk.dim(` logs: ${paths.logFile}`));
29964
+ console.log(chalk2.green(wasRunning ? `\u2713 chat-recall-watch service restarted with the current binary (${platformName2()}).` : `\u2713 chat-recall-watch service installed and started (${platformName2()}).`));
29965
+ if (paths.definitionPath) console.log(chalk2.dim(` unit: ${paths.definitionPath}`));
29966
+ console.log(chalk2.dim(` logs: ${paths.logFile}`));
29838
29967
  } else if (action === "uninstall") {
29839
29968
  const removed = uninstallService2();
29840
- if (removed) console.log(chalk.green(`\u2713 chat-recall-watch service removed (${platformName2()}).`));
29841
- else console.log(chalk.dim("Service was not installed \u2014 nothing to remove."));
29969
+ if (removed) console.log(chalk2.green(`\u2713 chat-recall-watch service removed (${platformName2()}).`));
29970
+ else console.log(chalk2.dim("Service was not installed \u2014 nothing to remove."));
29842
29971
  } else if (action === "status") {
29843
29972
  const running = isServiceRunning2();
29844
- console.log(`chat-recall-watch service (${platformName2()}): ${running ? chalk.green("running") : chalk.yellow("not running")}`);
29845
- if (!running) console.log(chalk.dim(" install: `chat-recall service install`"));
29973
+ console.log(`chat-recall-watch service (${platformName2()}): ${running ? chalk2.green("running") : chalk2.yellow("not running")}`);
29974
+ if (!running) console.log(chalk2.dim(" install: `chat-recall service install`"));
29846
29975
  } else {
29847
- console.error(chalk.red(`Unknown action '${action}'.`) + chalk.dim(" Use: install | uninstall | status"));
29976
+ console.error(chalk2.red(`Unknown action '${action}'.`) + chalk2.dim(" Use: install | uninstall | status"));
29848
29977
  process.exit(1);
29849
29978
  }
29850
29979
  } catch (err) {
29851
29980
  const se = err;
29852
- console.error(chalk.red(se.message || String(err)));
29853
- if (se.hint) console.error(chalk.dim(` ${se.hint}`));
29981
+ console.error(chalk2.red(se.message || String(err)));
29982
+ if (se.hint) console.error(chalk2.dim(` ${se.hint}`));
29854
29983
  process.exit(1);
29855
29984
  }
29856
29985
  });
@@ -29871,7 +30000,7 @@ async function runLogin(serverUrl, opts) {
29871
30000
  if (opts.token) {
29872
30001
  const token = opts.token.trim();
29873
30002
  if (/[^\x21-\x7e]/.test(token)) {
29874
- console.error(chalk.dim("Use the Copy button next to the token in the dashboard and paste the full line."));
30003
+ console.error(chalk2.dim("Use the Copy button next to the token in the dashboard and paste the full line."));
29875
30004
  return failLogin(opts, 'the token contains non-ASCII characters \u2014 this looks like a masked/truncated copy (e.g. "ct_12345678\u2026")');
29876
30005
  }
29877
30006
  const { probeServer: identifyServer, probeOk: identified, probeAdvice: identifyAdvice } = await Promise.resolve().then(() => (init_server_probe(), server_probe_exports));
@@ -29880,7 +30009,7 @@ async function runLogin(serverUrl, opts) {
29880
30009
  const check = await verifyToken(token);
29881
30010
  if (!check.ok) {
29882
30011
  if (check.status === 401 || check.status === 403) {
29883
- console.error(chalk.dim("Tokens are shown once \u2014 mint a fresh one (Account \u2192 Connect your machine) and copy the whole line."));
30012
+ console.error(chalk2.dim("Tokens are shown once \u2014 mint a fresh one (Account \u2192 Connect your machine) and copy the whole line."));
29884
30013
  return failLogin(opts, `${base2} rejected the token (HTTP ${check.status})`);
29885
30014
  }
29886
30015
  if (check.status !== void 0 && check.status >= 500) {
@@ -29892,12 +30021,12 @@ async function runLogin(serverUrl, opts) {
29892
30021
  return failLogin(opts, `could not verify the token against ${base2}: ${check.error || `HTTP ${check.status}`}`);
29893
30022
  }
29894
30023
  saveCredentials2({ serverUrl, token });
29895
- console.log(chalk.green("\u2713 Logged in.") + chalk.dim(` server: ${serverUrl} (token verified)`));
30024
+ console.log(chalk2.green("\u2713 Logged in.") + chalk2.dim(` server: ${serverUrl} (token verified)`));
29896
30025
  return;
29897
30026
  }
29898
30027
  const existing = loadAllCredentials2().find((t) => t.serverUrl.replace(/\/+$/, "") === base2);
29899
30028
  if (existing && (await verifyToken(existing.token)).ok) {
29900
- console.log(chalk.green("\u2713 Already connected.") + chalk.dim(` server: ${serverUrl} (existing token verified)`));
30029
+ console.log(chalk2.green("\u2713 Already connected.") + chalk2.dim(` server: ${serverUrl} (existing token verified)`));
29901
30030
  return;
29902
30031
  }
29903
30032
  try {
@@ -29907,14 +30036,14 @@ async function runLogin(serverUrl, opts) {
29907
30036
  const probe = await fetch(`${base2}/api/status`, { signal: AbortSignal.timeout(8e3) });
29908
30037
  if (probe.status === 200) {
29909
30038
  saveCredentials2({ serverUrl, token: "" });
29910
- console.log(chalk.green("\u2713 Logged in.") + chalk.dim(` ${serverUrl} (local server \u2014 no auth, no token needed)`));
30039
+ console.log(chalk2.green("\u2713 Logged in.") + chalk2.dim(` ${serverUrl} (local server \u2014 no auth, no token needed)`));
29911
30040
  return;
29912
30041
  }
29913
30042
  }
29914
30043
  } catch {
29915
30044
  }
29916
30045
  if (opts.check) {
29917
- console.error(chalk.dim(`Not connected to ${serverUrl}.`));
30046
+ console.error(chalk2.dim(`Not connected to ${serverUrl}.`));
29918
30047
  process.exit(1);
29919
30048
  }
29920
30049
  try {
@@ -29942,7 +30071,7 @@ async function runLogin(serverUrl, opts) {
29942
30071
  if (!authProvider && !issuer) {
29943
30072
  authProvider = "better-auth";
29944
30073
  if (capsError) {
29945
- console.log(` ${chalk.yellow("Could not read the server's capabilities")} (${capsError}) \u2014 assuming the standard sign-in flow.`);
30074
+ console.log(` ${chalk2.yellow("Could not read the server's capabilities")} (${capsError}) \u2014 assuming the standard sign-in flow.`);
29946
30075
  void Promise.resolve().then(() => (init_install_report(), install_report_exports)).then(({ reportInstallFailure: reportInstallFailure2 }) => reportInstallFailure2(base2, {
29947
30076
  step: "cli_login_probe",
29948
30077
  reason: capsError?.slice(0, 40) ?? null,
@@ -29957,13 +30086,13 @@ async function runLogin(serverUrl, opts) {
29957
30086
  return;
29958
30087
  }
29959
30088
  console.log();
29960
- console.log(chalk.bold("Open this to approve the machine:"));
29961
- console.log(" " + chalk.cyan(p.url));
30089
+ console.log(chalk2.bold("Open this to approve the machine:"));
30090
+ console.log(" " + chalk2.cyan(p.url));
29962
30091
  if (openBrowser(p.url)) {
29963
- console.log(chalk.dim(" (tried to open it for you \u2014 if no window appeared, use the link above)"));
30092
+ console.log(chalk2.dim(" (tried to open it for you \u2014 if no window appeared, use the link above)"));
29964
30093
  }
29965
- console.log(chalk.dim(` If the page asks for a code: ${chalk.bold(p.userCode)}`));
29966
- console.log(chalk.dim("Then come back here \u2014 this finishes on its own. Waiting\u2026"));
30094
+ console.log(chalk2.dim(` If the page asks for a code: ${chalk2.bold(p.userCode)}`));
30095
+ console.log(chalk2.dim("Then come back here \u2014 this finishes on its own. Waiting\u2026"));
29967
30096
  };
29968
30097
  const tokens = authProvider === "better-auth" ? await betterAuthDeviceLogin2(base2, onPrompt) : await deviceLogin2({ issuer, clientId: opts.clientId }, onPrompt);
29969
30098
  const authHdr = { authorization: `Bearer ${tokens.accessToken}`, "content-type": "application/json" };
@@ -29979,9 +30108,9 @@ async function runLogin(serverUrl, opts) {
29979
30108
  const created = await fetch(`${base2}/api/teams`, { method: "POST", headers: authHdr, body: JSON.stringify({ name }) });
29980
30109
  if (!created.ok) throw new Error(`workspace create failed: HTTP ${created.status} ${await created.text().catch(() => "")}`);
29981
30110
  slug = (await readJsonBody(created, base2, "POST /api/teams")).slug;
29982
- console.log(chalk.dim(`Created workspace "${name}" (${slug}) \u2014 you're its owner.`));
30111
+ console.log(chalk2.dim(`Created workspace "${name}" (${slug}) \u2014 you're its owner.`));
29983
30112
  } else {
29984
- teams.forEach((t) => console.error(` ${t.team_slug} ${chalk.dim(t.name)}`));
30113
+ teams.forEach((t) => console.error(` ${t.team_slug} ${chalk2.dim(t.name)}`));
29985
30114
  throw new Error("you belong to multiple teams \u2014 pass --team <slug> (listed above)");
29986
30115
  }
29987
30116
  }
@@ -29994,13 +30123,13 @@ async function runLogin(serverUrl, opts) {
29994
30123
  if (!mint.ok) throw new Error(`token mint failed: HTTP ${mint.status} ${await mint.text().catch(() => "")}`);
29995
30124
  const { token } = await readJsonBody(mint, base2, "POST /api/teams/:slug/tokens");
29996
30125
  saveCredentials2({ serverUrl, token });
29997
- console.log(chalk.green(`\u2713 Logged in to ${chalk.bold(slug)}`) + chalk.dim(` (device: ${deviceId}) server: ${serverUrl}`));
30126
+ console.log(chalk2.green(`\u2713 Logged in to ${chalk2.bold(slug)}`) + chalk2.dim(` (device: ${deviceId}) server: ${serverUrl}`));
29998
30127
  if (!opts.fromInit) {
29999
- console.log(chalk.dim("Run `chat-recall sync` to push redacted conversations."));
30128
+ console.log(chalk2.dim("Run `chat-recall sync` to push redacted conversations."));
30000
30129
  }
30001
30130
  } catch (err) {
30002
30131
  if (opts.fromInit) throw err instanceof Error ? err : new Error(String(err));
30003
- console.error(chalk.red("login failed:"), err instanceof Error ? err.message : err);
30132
+ console.error(chalk2.red("login failed:"), err instanceof Error ? err.message : err);
30004
30133
  process.exit(1);
30005
30134
  }
30006
30135
  }
@@ -30008,15 +30137,15 @@ var exclude = program.command("exclude").description("Control what never leaves
30008
30137
  exclude.command("list", { isDefault: true }).description("Show current exclusions").action(async () => {
30009
30138
  const { loadSettings: loadSettings2 } = await Promise.resolve().then(() => (init_settings(), settings_exports));
30010
30139
  const s = loadSettings2();
30011
- console.log(chalk.bold("Sync exclusions") + chalk.dim(" (~/.chat-recall/settings/settings.json)"));
30012
- console.log(` tools: ${s.sync.excludeTools.length ? s.sync.excludeTools.join(", ") : chalk.dim("none")}`);
30013
- console.log(` projects: ${s.sync.excludeProjects.length ? "" : chalk.dim("none")}`);
30140
+ console.log(chalk2.bold("Sync exclusions") + chalk2.dim(" (~/.chat-recall/settings/settings.json)"));
30141
+ console.log(` tools: ${s.sync.excludeTools.length ? s.sync.excludeTools.join(", ") : chalk2.dim("none")}`);
30142
+ console.log(` projects: ${s.sync.excludeProjects.length ? "" : chalk2.dim("none")}`);
30014
30143
  for (const p of s.sync.excludeProjects) console.log(` ${p}`);
30015
30144
  const deny = s.privacy.projectDenylist || [];
30016
- console.log(` index denylist (never even indexed): ${deny.length ? "" : chalk.dim("none")}`);
30145
+ console.log(` index denylist (never even indexed): ${deny.length ? "" : chalk2.dim("none")}`);
30017
30146
  for (const p of deny) console.log(` ${p}`);
30018
- console.log(chalk.dim("\nPersonal folders (Pictures, Music, Documents, Desktop, Downloads, \u2026) are"));
30019
- console.log(chalk.dim("skipped from code indexing by default. Opt one back in: `chat-recall include project <path>`."));
30147
+ console.log(chalk2.dim("\nPersonal folders (Pictures, Music, Documents, Desktop, Downloads, \u2026) are"));
30148
+ console.log(chalk2.dim("skipped from code indexing by default. Opt one back in: `chat-recall include project <path>`."));
30020
30149
  const inc = s.sync.includeProjects || [];
30021
30150
  if (inc.length) {
30022
30151
  console.log(` personal paths opted back in:`);
@@ -30027,8 +30156,8 @@ var include = program.command("include").description("Opt a personal folder (Pic
30027
30156
  include.command("list", { isDefault: true }).description("Show paths opted back into indexing").action(async () => {
30028
30157
  const { loadSettings: loadSettings2 } = await Promise.resolve().then(() => (init_settings(), settings_exports));
30029
30158
  const inc = loadSettings2().sync.includeProjects || [];
30030
- console.log(chalk.bold("Personal paths opted back into code indexing"));
30031
- if (!inc.length) console.log(chalk.dim(" none \u2014 personal folders are all skipped"));
30159
+ console.log(chalk2.bold("Personal paths opted back into code indexing"));
30160
+ if (!inc.length) console.log(chalk2.dim(" none \u2014 personal folders are all skipped"));
30032
30161
  for (const p of inc) console.log(` ${p}`);
30033
30162
  });
30034
30163
  include.command("project <path>").description("Re-permit a path under a personal folder (substring match; e.g. ~/Documents/code)").action(async (path) => {
@@ -30039,12 +30168,12 @@ include.command("project <path>").description("Re-permit a path under a personal
30039
30168
  const s = loadSettings2();
30040
30169
  s.sync.includeProjects = s.sync.includeProjects || [];
30041
30170
  if (s.sync.includeProjects.includes(abs)) {
30042
- console.log(chalk.dim(`Already included: ${abs}`));
30171
+ console.log(chalk2.dim(`Already included: ${abs}`));
30043
30172
  return;
30044
30173
  }
30045
30174
  s.sync.includeProjects.push(abs);
30046
30175
  saveSettings2(s);
30047
- console.log(chalk.green(`\u2713 Included ${abs}`) + chalk.dim(" \u2014 code indexing may now walk it (takes effect next discovery tick)."));
30176
+ console.log(chalk2.green(`\u2713 Included ${abs}`) + chalk2.dim(" \u2014 code indexing may now walk it (takes effect next discovery tick)."));
30048
30177
  });
30049
30178
  include.command("remove <path>").description("Undo an opt-in (personal folder goes back to skipped)").action(async (path) => {
30050
30179
  const { loadSettings: loadSettings2, saveSettings: saveSettings2 } = await Promise.resolve().then(() => (init_settings(), settings_exports));
@@ -30055,30 +30184,30 @@ include.command("remove <path>").description("Undo an opt-in (personal folder go
30055
30184
  const before = (s.sync.includeProjects || []).length;
30056
30185
  s.sync.includeProjects = (s.sync.includeProjects || []).filter((p) => p !== path && p !== abs);
30057
30186
  if (s.sync.includeProjects.length === before) {
30058
- console.error(chalk.red(`Not in the include list: ${path}`));
30187
+ console.error(chalk2.red(`Not in the include list: ${path}`));
30059
30188
  process.exit(1);
30060
30189
  }
30061
30190
  saveSettings2(s);
30062
- console.log(chalk.green(`\u2713 Removed ${path}`) + chalk.dim(" \u2014 back to skipped."));
30191
+ console.log(chalk2.green(`\u2713 Removed ${path}`) + chalk2.dim(" \u2014 back to skipped."));
30063
30192
  });
30064
30193
  var retention = program.command("retention").description("How long the server keeps your synced sessions. Bare `retention` shows the current window.");
30065
30194
  retention.command("show", { isDefault: true }).description("Show the window and how many sessions it would delete").action(async () => {
30066
30195
  const t = requireTarget();
30067
30196
  const r = await serverGet("/api/data/retention");
30068
- console.log(chalk.bold("Retention") + chalk.dim(` (server: ${t.base})`));
30197
+ console.log(chalk2.bold("Retention") + chalk2.dim(` (server: ${t.base})`));
30069
30198
  if (!r.days) {
30070
- console.log(` window: ${chalk.green("none")} \u2014 the server keeps everything you sync`);
30199
+ console.log(` window: ${chalk2.green("none")} \u2014 the server keeps everything you sync`);
30071
30200
  } else {
30072
- console.log(` window: ${chalk.yellow(`${r.days} days`)}`);
30201
+ console.log(` window: ${chalk2.yellow(`${r.days} days`)}`);
30073
30202
  console.log(` sessions currently outside it: ${r.wouldDelete}`);
30074
30203
  }
30075
- console.log(chalk.dim(` Set one: chat-recall retention set <${r.min}-${r.max}> \xB7 clear it: chat-recall retention set 0`));
30204
+ console.log(chalk2.dim(` Set one: chat-recall retention set <${r.min}-${r.max}> \xB7 clear it: chat-recall retention set 0`));
30076
30205
  });
30077
30206
  retention.command("set <days>").description("Set the window in days, or 0 to keep everything. Prints what it would delete and asks first.").option("--yes", "Skip the confirmation (for scripts). The warning still prints.", false).action(async (daysArg, opts) => {
30078
30207
  requireTarget();
30079
30208
  const days = Number(daysArg);
30080
30209
  if (!Number.isInteger(days) || days < 0) {
30081
- console.error(chalk.red(`'${daysArg}' is not a whole number of days.`));
30210
+ console.error(chalk2.red(`'${daysArg}' is not a whole number of days.`));
30082
30211
  process.exit(1);
30083
30212
  }
30084
30213
  const preview = await serverGet(
@@ -30086,23 +30215,23 @@ retention.command("set <days>").description("Set the window in days, or 0 to kee
30086
30215
  );
30087
30216
  if (days === 0) {
30088
30217
  await serverPost("/api/data/retention", { days: 0 });
30089
- console.log(chalk.green("\u2713 Window cleared") + chalk.dim(" \u2014 the server keeps everything you sync."));
30218
+ console.log(chalk2.green("\u2713 Window cleared") + chalk2.dim(" \u2014 the server keeps everything you sync."));
30090
30219
  return;
30091
30220
  }
30092
30221
  if (preview.wouldDelete > 0) {
30093
30222
  console.log();
30094
- console.log(chalk.yellow(`This deletes ${preview.wouldDelete} session(s) from the server, and keeps deleting`));
30095
- console.log(chalk.yellow(`anything older than ${days} days from now on.`));
30223
+ console.log(chalk2.yellow(`This deletes ${preview.wouldDelete} session(s) from the server, and keeps deleting`));
30224
+ console.log(chalk2.yellow(`anything older than ${days} days from now on.`));
30096
30225
  console.log();
30097
- console.log(chalk.dim(" Re-syncing can restore a session ONLY if its transcript is still on a"));
30098
- console.log(chalk.dim(" machine you have. For a laptop you no longer own, history your AI tool"));
30099
- console.log(chalk.dim(" has rotated, or files you deleted, our copy is the only copy."));
30100
- console.log(chalk.dim(" Take one first if you want it: chat-recall export"));
30226
+ console.log(chalk2.dim(" Re-syncing can restore a session ONLY if its transcript is still on a"));
30227
+ console.log(chalk2.dim(" machine you have. For a laptop you no longer own, history your AI tool"));
30228
+ console.log(chalk2.dim(" has rotated, or files you deleted, our copy is the only copy."));
30229
+ console.log(chalk2.dim(" Take one first if you want it: chat-recall export"));
30101
30230
  console.log();
30102
30231
  if (!opts.yes) {
30103
30232
  if (!process.stdin.isTTY) {
30104
- console.error(chalk.red("Refusing: this would delete data and there is no terminal to confirm at."));
30105
- console.error(chalk.dim("Pass --yes if you mean it."));
30233
+ console.error(chalk2.red("Refusing: this would delete data and there is no terminal to confirm at."));
30234
+ console.error(chalk2.dim("Pass --yes if you mean it."));
30106
30235
  process.exit(1);
30107
30236
  }
30108
30237
  const { createInterface: createInterface3 } = await import("node:readline/promises");
@@ -30110,7 +30239,7 @@ retention.command("set <days>").description("Set the window in days, or 0 to kee
30110
30239
  const answer = (await rl.question(`Type ${preview.wouldDelete} to confirm: `)).trim();
30111
30240
  rl.close();
30112
30241
  if (answer !== String(preview.wouldDelete)) {
30113
- console.log(chalk.dim("Cancelled \u2014 nothing changed."));
30242
+ console.log(chalk2.dim("Cancelled \u2014 nothing changed."));
30114
30243
  return;
30115
30244
  }
30116
30245
  }
@@ -30119,20 +30248,20 @@ retention.command("set <days>").description("Set the window in days, or 0 to kee
30119
30248
  "/api/data/retention",
30120
30249
  { days, acknowledge: true }
30121
30250
  );
30122
- console.log(chalk.green(`\u2713 Window set to ${res.days} days`) + chalk.dim(` \u2014 ${res.wouldDelete} session(s) will be removed on the next sweep.`));
30251
+ console.log(chalk2.green(`\u2713 Window set to ${res.days} days`) + chalk2.dim(` \u2014 ${res.wouldDelete} session(s) will be removed on the next sweep.`));
30123
30252
  });
30124
30253
  var syncOnly = program.command("sync-only").description("Opt-in sync: ship ONLY chosen projects. Bare `sync-only` shows the mode + allowlist.");
30125
30254
  syncOnly.command("list", { isDefault: true }).description("Show the sync mode and allowlisted projects").action(async () => {
30126
30255
  const { loadSettings: loadSettings2 } = await Promise.resolve().then(() => (init_settings(), settings_exports));
30127
30256
  const s = loadSettings2();
30128
30257
  const mode = s.sync.syncMode ?? "all";
30129
- console.log(chalk.bold("Selective sync") + chalk.dim(" (~/.chat-recall/settings/settings.json)"));
30130
- console.log(` mode: ${mode === "only" ? chalk.yellow("only (allowlist)") : chalk.green("all (default)")}`);
30258
+ console.log(chalk2.bold("Selective sync") + chalk2.dim(" (~/.chat-recall/settings/settings.json)"));
30259
+ console.log(` mode: ${mode === "only" ? chalk2.yellow("only (allowlist)") : chalk2.green("all (default)")}`);
30131
30260
  const list = s.sync.syncOnlyProjects ?? [];
30132
- console.log(` projects: ${list.length ? "" : chalk.dim("none")}`);
30261
+ console.log(` projects: ${list.length ? "" : chalk2.dim("none")}`);
30133
30262
  for (const p of list) console.log(` ${p}`);
30134
- if (mode === "only" && list.length === 0) console.log(chalk.red(' \u26A0 mode is "only" but the allowlist is empty \u2192 NOTHING syncs.'));
30135
- console.log(chalk.dim("\nList ids with `chat-recall projects`, then `chat-recall sync-only add <id>`."));
30263
+ if (mode === "only" && list.length === 0) console.log(chalk2.red(' \u26A0 mode is "only" but the allowlist is empty \u2192 NOTHING syncs.'));
30264
+ console.log(chalk2.dim("\nList ids with `chat-recall projects`, then `chat-recall sync-only add <id>`."));
30136
30265
  });
30137
30266
  syncOnly.command("add <project>").description('Add a project id (git:\u2026/ws:\u2026/path:\u2026) or path substring to the allowlist (switches mode to "only")').action(async (project) => {
30138
30267
  const { loadSettings: loadSettings2, saveSettings: saveSettings2 } = await Promise.resolve().then(() => (init_settings(), settings_exports));
@@ -30141,7 +30270,7 @@ syncOnly.command("add <project>").description('Add a project id (git:\u2026/ws:\
30141
30270
  if (!s.sync.syncOnlyProjects.includes(project)) s.sync.syncOnlyProjects.push(project);
30142
30271
  s.sync.syncMode = "only";
30143
30272
  saveSettings2(s);
30144
- console.log(chalk.green(`\u2713 Added ${project}`) + chalk.dim(' \u2014 mode is now "only"; next sync ships only allowlisted projects.'));
30273
+ console.log(chalk2.green(`\u2713 Added ${project}`) + chalk2.dim(' \u2014 mode is now "only"; next sync ships only allowlisted projects.'));
30145
30274
  });
30146
30275
  syncOnly.command("remove <project>").description("Remove a project from the allowlist").action(async (project) => {
30147
30276
  const { loadSettings: loadSettings2, saveSettings: saveSettings2 } = await Promise.resolve().then(() => (init_settings(), settings_exports));
@@ -30149,18 +30278,18 @@ syncOnly.command("remove <project>").description("Remove a project from the allo
30149
30278
  const before = (s.sync.syncOnlyProjects || []).length;
30150
30279
  s.sync.syncOnlyProjects = (s.sync.syncOnlyProjects || []).filter((p) => p !== project);
30151
30280
  if (s.sync.syncOnlyProjects.length === before) {
30152
- console.error(chalk.red(`Not in the allowlist: ${project}`));
30281
+ console.error(chalk2.red(`Not in the allowlist: ${project}`));
30153
30282
  process.exit(1);
30154
30283
  }
30155
30284
  saveSettings2(s);
30156
- console.log(chalk.green(`\u2713 Removed ${project}`));
30285
+ console.log(chalk2.green(`\u2713 Removed ${project}`));
30157
30286
  });
30158
30287
  syncOnly.command("all").description("Switch back to syncing ALL non-excluded projects (keeps the list, just disables opt-in mode)").action(async () => {
30159
30288
  const { loadSettings: loadSettings2, saveSettings: saveSettings2 } = await Promise.resolve().then(() => (init_settings(), settings_exports));
30160
30289
  const s = loadSettings2();
30161
30290
  s.sync.syncMode = "all";
30162
30291
  saveSettings2(s);
30163
- console.log(chalk.green("\u2713 Sync mode: all") + chalk.dim(" \u2014 every non-excluded project syncs again."));
30292
+ console.log(chalk2.green("\u2713 Sync mode: all") + chalk2.dim(" \u2014 every non-excluded project syncs again."));
30164
30293
  });
30165
30294
  program.command("projects").description("List distinct project ids discovered on this machine (for `sync-only add`)").action(async () => {
30166
30295
  const { listAvailableBackends: listAvailableBackends2 } = await Promise.resolve().then(() => (init_tool_backend(), tool_backend_exports));
@@ -30180,11 +30309,11 @@ program.command("projects").description("List distinct project ids discovered on
30180
30309
  }
30181
30310
  const rows = [...counts.entries()].sort((a, b) => b[1] - a[1]);
30182
30311
  if (!rows.length) {
30183
- console.log(chalk.dim("No projects discovered."));
30312
+ console.log(chalk2.dim("No projects discovered."));
30184
30313
  return;
30185
30314
  }
30186
- console.log(chalk.bold("Discovered projects") + chalk.dim(" (id \xB7 sessions)"));
30187
- for (const [id, n] of rows) console.log(` ${chalk.cyan(id)} ${chalk.dim("\xB7 " + n)}`);
30315
+ console.log(chalk2.bold("Discovered projects") + chalk2.dim(" (id \xB7 sessions)"));
30316
+ for (const [id, n] of rows) console.log(` ${chalk2.cyan(id)} ${chalk2.dim("\xB7 " + n)}`);
30188
30317
  });
30189
30318
  exclude.command("project <path>").description("Exclude a project path from syncing (substring match on the project path; e.g. ~/.claude-pr-bot)").action(async (path) => {
30190
30319
  const { loadSettings: loadSettings2, saveSettings: saveSettings2 } = await Promise.resolve().then(() => (init_settings(), settings_exports));
@@ -30193,28 +30322,28 @@ exclude.command("project <path>").description("Exclude a project path from synci
30193
30322
  const abs = resolve3(path.replace(/^~(?=\/|$)/, homedir23()));
30194
30323
  const s = loadSettings2();
30195
30324
  if (s.sync.excludeProjects.includes(abs)) {
30196
- console.log(chalk.dim(`Already excluded: ${abs}`));
30325
+ console.log(chalk2.dim(`Already excluded: ${abs}`));
30197
30326
  return;
30198
30327
  }
30199
30328
  s.sync.excludeProjects.push(abs);
30200
30329
  saveSettings2(s);
30201
- console.log(chalk.green(`\u2713 Excluded ${abs}`) + chalk.dim(" \u2014 takes effect next sync; already-synced rows stay until deleted."));
30330
+ console.log(chalk2.green(`\u2713 Excluded ${abs}`) + chalk2.dim(" \u2014 takes effect next sync; already-synced rows stay until deleted."));
30202
30331
  });
30203
30332
  exclude.command("tool <tool>").description("Exclude an AI tool entirely (claude | gemini | codex | opencode | agy | cursor)").action(async (tool) => {
30204
30333
  const valid = ["claude", "gemini", "codex", "opencode", "agy", "cursor"];
30205
30334
  if (!valid.includes(tool)) {
30206
- console.error(chalk.red(`Unknown tool '${tool}'.`) + chalk.dim(` Use one of: ${valid.join(" | ")}`));
30335
+ console.error(chalk2.red(`Unknown tool '${tool}'.`) + chalk2.dim(` Use one of: ${valid.join(" | ")}`));
30207
30336
  process.exit(1);
30208
30337
  }
30209
30338
  const { loadSettings: loadSettings2, saveSettings: saveSettings2 } = await Promise.resolve().then(() => (init_settings(), settings_exports));
30210
30339
  const s = loadSettings2();
30211
30340
  if (s.sync.excludeTools.includes(tool)) {
30212
- console.log(chalk.dim(`Already excluded: ${tool}`));
30341
+ console.log(chalk2.dim(`Already excluded: ${tool}`));
30213
30342
  return;
30214
30343
  }
30215
30344
  s.sync.excludeTools.push(tool);
30216
30345
  saveSettings2(s);
30217
- console.log(chalk.green(`\u2713 Excluded ${tool}`) + chalk.dim(" \u2014 nothing from it leaves this machine from the next sync on."));
30346
+ console.log(chalk2.green(`\u2713 Excluded ${tool}`) + chalk2.dim(" \u2014 nothing from it leaves this machine from the next sync on."));
30218
30347
  });
30219
30348
  exclude.command("remove <value>").description("Remove an exclusion (tool name or project path)").action(async (value) => {
30220
30349
  const { loadSettings: loadSettings2, saveSettings: saveSettings2 } = await Promise.resolve().then(() => (init_settings(), settings_exports));
@@ -30227,20 +30356,20 @@ exclude.command("remove <value>").description("Remove an exclusion (tool name or
30227
30356
  s.sync.excludeTools = s.sync.excludeTools.filter((t) => t !== value);
30228
30357
  s.sync.excludeProjects = s.sync.excludeProjects.filter((p) => p !== value && p !== abs);
30229
30358
  if (s.sync.excludeTools.length === beforeTools && s.sync.excludeProjects.length === beforeProjects) {
30230
- console.error(chalk.red(`No exclusion matches '${value}'.`) + chalk.dim(" See: chat-recall exclude list"));
30359
+ console.error(chalk2.red(`No exclusion matches '${value}'.`) + chalk2.dim(" See: chat-recall exclude list"));
30231
30360
  process.exit(1);
30232
30361
  }
30233
30362
  saveSettings2(s);
30234
- console.log(chalk.green(`\u2713 Removed ${value}`));
30363
+ console.log(chalk2.green(`\u2713 Removed ${value}`));
30235
30364
  });
30236
30365
  program.command("login [server-url]").description(`Log in (device flow) and mint a sync device token \u2192 ~/.chat-recall/credentials.json (0600). Defaults to ${DEFAULT_SERVER}.`).option("--token <token>", "Self-host: skip OIDC and save this device token directly").option("--check", "Report-only: exit 0 if a working credential for this server exists, 1 otherwise (never interactive)").option("--issuer <url>", "OIDC issuer URL (default: learned from the server via /api/capabilities)").option("--client-id <id>", "OIDC client id (default: chat-recall-web)").option("--team <slug>", "Team to mint the device token for (default: your only team)").option("--device-id <id>", "Device id for this machine (default: hostname)").option("--prompt-json", "Print the device prompt as one JSON line on stdout, then wait for approval", false).action((serverUrl, opts) => runLogin(serverUrl || DEFAULT_SERVER, opts));
30237
30366
  program.command("logout <server-url>").description("Remove one sync target (other targets keep syncing)").action(async (serverUrl) => {
30238
30367
  const { removeCredentials: removeCredentials2, loadAllCredentials: loadAllCredentials2 } = await Promise.resolve().then(() => (init_sync_client(), sync_client_exports));
30239
30368
  if (removeCredentials2(serverUrl)) {
30240
30369
  const left = loadAllCredentials2();
30241
- console.log(chalk.green(`\u2713 Removed ${serverUrl}`) + chalk.dim(` \u2014 ${left.length} target(s) remain`));
30370
+ console.log(chalk2.green(`\u2713 Removed ${serverUrl}`) + chalk2.dim(` \u2014 ${left.length} target(s) remain`));
30242
30371
  } else {
30243
- console.error(chalk.red(`No such target: ${serverUrl}`));
30372
+ console.error(chalk2.red(`No such target: ${serverUrl}`));
30244
30373
  process.exit(1);
30245
30374
  }
30246
30375
  });
@@ -30248,7 +30377,7 @@ program.command("delete <session-id>").description("Delete a session from chat-r
30248
30377
  const { loadAllCredentials: loadAllCredentials2 } = await Promise.resolve().then(() => (init_sync_client(), sync_client_exports));
30249
30378
  const targets = loadAllCredentials2();
30250
30379
  if (targets.length === 0) {
30251
- console.error(chalk.red("Not logged in \u2014 run `chat-recall login <server-url>` first."));
30380
+ console.error(chalk2.red("Not logged in \u2014 run `chat-recall login <server-url>` first."));
30252
30381
  process.exit(1);
30253
30382
  }
30254
30383
  let ok = 0;
@@ -30260,20 +30389,20 @@ program.command("delete <session-id>").description("Delete a session from chat-r
30260
30389
  });
30261
30390
  if (res.ok) {
30262
30391
  ok++;
30263
- console.log(chalk.green(`\u2713 Deleted on ${t.serverUrl}`));
30264
- } else console.error(chalk.red(`\u2717 ${t.serverUrl}: HTTP ${res.status}`));
30392
+ console.log(chalk2.green(`\u2713 Deleted on ${t.serverUrl}`));
30393
+ } else console.error(chalk2.red(`\u2717 ${t.serverUrl}: HTTP ${res.status}`));
30265
30394
  } catch (e) {
30266
- console.error(chalk.red(`\u2717 ${t.serverUrl}: ${e instanceof Error ? e.message : "failed"}`));
30395
+ console.error(chalk2.red(`\u2717 ${t.serverUrl}: ${e instanceof Error ? e.message : "failed"}`));
30267
30396
  }
30268
30397
  }
30269
30398
  if (ok === 0) process.exit(1);
30270
- console.log(chalk.dim(`Tombstoned on ${ok}/${targets.length} server(s) \u2014 re-sync cannot resurrect it.`));
30399
+ console.log(chalk2.dim(`Tombstoned on ${ok}/${targets.length} server(s) \u2014 re-sync cannot resurrect it.`));
30271
30400
  });
30272
30401
  program.command("rename <session-id> <name>").description('Give a session a memorable name on every logged-in server (mirrors Claude Code\'s /rename \u2014 shows in `recall recent` and the web UI in place of the auto summary). Pass an empty name "" to clear it and revert to the auto title.').action(async (sessionId, name) => {
30273
30402
  const { loadAllCredentials: loadAllCredentials2 } = await Promise.resolve().then(() => (init_sync_client(), sync_client_exports));
30274
30403
  const targets = loadAllCredentials2();
30275
30404
  if (targets.length === 0) {
30276
- console.error(chalk.red("Not logged in \u2014 run `chat-recall login <server-url>` first."));
30405
+ console.error(chalk2.red("Not logged in \u2014 run `chat-recall login <server-url>` first."));
30277
30406
  process.exit(1);
30278
30407
  }
30279
30408
  let ok = 0;
@@ -30286,14 +30415,14 @@ program.command("rename <session-id> <name>").description('Give a session a memo
30286
30415
  });
30287
30416
  if (res.ok) {
30288
30417
  ok++;
30289
- console.log(chalk.green(`\u2713 ${name.trim() ? "Named" : "Cleared name"} on ${t.serverUrl}`));
30290
- } else console.error(chalk.red(`\u2717 ${t.serverUrl}: HTTP ${res.status}`));
30418
+ console.log(chalk2.green(`\u2713 ${name.trim() ? "Named" : "Cleared name"} on ${t.serverUrl}`));
30419
+ } else console.error(chalk2.red(`\u2717 ${t.serverUrl}: HTTP ${res.status}`));
30291
30420
  } catch (e) {
30292
- console.error(chalk.red(`\u2717 ${t.serverUrl}: ${e instanceof Error ? e.message : "failed"}`));
30421
+ console.error(chalk2.red(`\u2717 ${t.serverUrl}: ${e instanceof Error ? e.message : "failed"}`));
30293
30422
  }
30294
30423
  }
30295
30424
  if (ok === 0) process.exit(1);
30296
- console.log(chalk.dim(name.trim() ? `Named "${name.trim()}" on ${ok}/${targets.length} server(s).` : `Cleared name on ${ok}/${targets.length} server(s).`));
30425
+ console.log(chalk2.dim(name.trim() ? `Named "${name.trim()}" on ${ok}/${targets.length} server(s).` : `Cleared name on ${ok}/${targets.length} server(s).`));
30297
30426
  });
30298
30427
  program.command("sync").description("Push redacted conversations to the configured server (secrets always masked). Bare `sync` is incremental (watermark-based); flags force an explicit window.").option("--since-hours <n>", "Only sync sessions modified in the last N hours").option("--limit <n>", "Max sessions to sync").option("--full", "Ignore the watermark and push everything").option("--paths-cleartext", "Send project paths in cleartext (self-host only; default hashes them)").option("--throttle <ms>", "Pause between upload batches in ms (default: 1000, or 3000 with --full)").option("--prune", "After syncing, drop server-side session rows that have no content (ghost rows)").action(async (opts) => {
30299
30428
  const { syncSessions: syncSessions2, syncIncremental: syncIncremental2, isSyncSkip: isSyncSkip2 } = await Promise.resolve().then(() => (init_sync_client(), sync_client_exports));
@@ -30302,17 +30431,17 @@ program.command("sync").description("Push redacted conversations to the configur
30302
30431
  const r2 = await syncIncremental2();
30303
30432
  if (isSyncSkip2(r2)) {
30304
30433
  if (r2.skipped === "lock-held") {
30305
- console.log(chalk.dim("Another sync is already running (MCP tick or watch daemon) \u2014 your data is on its way."));
30434
+ console.log(chalk2.dim("Another sync is already running (MCP tick or watch daemon) \u2014 your data is on its way."));
30306
30435
  return;
30307
30436
  }
30308
30437
  const msg = {
30309
30438
  "no-credentials": "Not logged in \u2014 run `chat-recall login <server-url>` first.",
30310
30439
  "paused": "Sync is paused in settings \u2014 re-run `chat-recall login <server-url>` to resume."
30311
30440
  }[r2.skipped];
30312
- console.error(chalk.red(msg));
30441
+ console.error(chalk2.red(msg));
30313
30442
  process.exit(1);
30314
30443
  }
30315
- console.log(chalk.green(`\u2713 Synced ${r2.uploaded} session(s), ${r2.items} item(s)`) + chalk.dim(` \u2014 ${r2.links} links, ${r2.derived} derived rows, ${r2.kgTriples} KG triples, ${r2.skipped} skipped, ${r2.redactions} secrets redacted, ${r2.findings} secret findings${r2.scanned ? ` (scanned ${r2.scanned} in ${r2.scanMs}ms)` : ""} (incremental)`));
30444
+ console.log(chalk2.green(`\u2713 Synced ${r2.uploaded} session(s), ${r2.items} item(s)`) + chalk2.dim(` \u2014 ${r2.links} links, ${r2.derived} derived rows, ${r2.kgTriples} KG triples, ${r2.skipped} skipped, ${r2.redactions} secrets redacted, ${r2.findings} secret findings${r2.scanned ? ` (scanned ${r2.scanned} in ${r2.scanMs}ms)` : ""} (incremental)`));
30316
30445
  return;
30317
30446
  }
30318
30447
  const sinceMs = opts.sinceHours ? Date.now() - Number(opts.sinceHours) * 36e5 : void 0;
@@ -30327,9 +30456,9 @@ program.command("sync").description("Push redacted conversations to the configur
30327
30456
  throttleMs: opts.throttle !== void 0 ? Number(opts.throttle) : opts.full ? 3e3 : void 0,
30328
30457
  prune: !!opts.prune
30329
30458
  });
30330
- console.log(chalk.green(`\u2713 Synced ${r.uploaded} session(s), ${r.items} item(s)`) + chalk.dim(` \u2014 ${r.links} links, ${r.derived} derived rows, ${r.kgTriples} KG triples, ${r.skipped} skipped, ${r.redactions} secrets redacted, ${r.findings} secret findings${r.scanned ? ` (scanned ${r.scanned} in ${r.scanMs}ms)` : ""}`));
30459
+ console.log(chalk2.green(`\u2713 Synced ${r.uploaded} session(s), ${r.items} item(s)`) + chalk2.dim(` \u2014 ${r.links} links, ${r.derived} derived rows, ${r.kgTriples} KG triples, ${r.skipped} skipped, ${r.redactions} secrets redacted, ${r.findings} secret findings${r.scanned ? ` (scanned ${r.scanned} in ${r.scanMs}ms)` : ""}`));
30331
30460
  } catch (err) {
30332
- console.error(chalk.red("sync failed:"), err instanceof Error ? err.message : err);
30461
+ console.error(chalk2.red("sync failed:"), err instanceof Error ? err.message : err);
30333
30462
  process.exit(1);
30334
30463
  }
30335
30464
  });
@@ -30338,11 +30467,11 @@ program.command("reconcile").description("Reconcile DERIVED FIELDS (e.g. native
30338
30467
  try {
30339
30468
  const r = await reconcileFields2({ force: !!opts.force });
30340
30469
  const per = Object.entries(r.perTarget).map(([s, v]) => `${s}: ${v.pushed} pushed`).join(", ");
30341
- console.log(chalk.green(`\u2713 Reconciled derived fields`) + chalk.dim(
30470
+ console.log(chalk2.green(`\u2713 Reconciled derived fields`) + chalk2.dim(
30342
30471
  ` \u2014 ${r.sessions} sessions, ${r.scanned} scanned, ${r.pushed} pushed, ${r.absent} absent${per ? ` (${per})` : ""}`
30343
30472
  ));
30344
30473
  } catch (err) {
30345
- console.error(chalk.red("reconcile failed:"), err instanceof Error ? err.message : err);
30474
+ console.error(chalk2.red("reconcile failed:"), err instanceof Error ? err.message : err);
30346
30475
  process.exit(1);
30347
30476
  }
30348
30477
  });
@@ -30352,7 +30481,7 @@ program.command("update").description("Update this CLI now from the server you s
30352
30481
  const { cliVersion: cliVersion3 } = await Promise.resolve().then(() => (init_http(), http_exports));
30353
30482
  const targets = loadAllCredentials();
30354
30483
  if (!targets.length) {
30355
- console.error(chalk.red("Not logged in \u2014 run `chat-recall login <server-url>` first."));
30484
+ console.error(chalk2.red("Not logged in \u2014 run `chat-recall login <server-url>` first."));
30356
30485
  process.exit(1);
30357
30486
  }
30358
30487
  let installFailed = false;
@@ -30361,17 +30490,17 @@ program.command("update").description("Update this CLI now from the server you s
30361
30490
  const headers = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
30362
30491
  const r = await runAutoUpdate2(base2, headers, cliVersion3());
30363
30492
  if (r.updated) {
30364
- console.log(chalk.green(`\u2713 ${r.reason}`) + chalk.dim(` (${base2})`));
30493
+ console.log(chalk2.green(`\u2713 ${r.reason}`) + chalk2.dim(` (${base2})`));
30365
30494
  continue;
30366
30495
  }
30367
30496
  const benign = /already current|no CLI release|disabled/.test(r.reason);
30368
30497
  if (/install failed|download failed|checksum/.test(r.reason)) installFailed = true;
30369
- console.log((benign ? chalk.dim("\u2022 ") : chalk.red("\u2717 ")) + r.reason + chalk.dim(` (${base2})`));
30498
+ console.log((benign ? chalk2.dim("\u2022 ") : chalk2.red("\u2717 ")) + r.reason + chalk2.dim(` (${base2})`));
30370
30499
  }
30371
30500
  await refreshUpdateCheck2(true);
30372
30501
  if (installFailed) {
30373
- console.log(chalk.dim("\nThe update was available but did not install \u2014 usually npm cannot write the global prefix. Retry with:"));
30374
- console.log(chalk.dim(` npm install -g chat-recall (or re-run the installer: curl -fsSL ${targets[0].serverUrl.replace(/\/+$/, "")}/install | sh)`));
30502
+ console.log(chalk2.dim("\nThe update was available but did not install \u2014 usually npm cannot write the global prefix. Retry with:"));
30503
+ console.log(chalk2.dim(` npm install -g chat-recall (or re-run the installer: curl -fsSL ${targets[0].serverUrl.replace(/\/+$/, "")}/install | sh)`));
30375
30504
  }
30376
30505
  });
30377
30506
  program.hook("preAction", () => {