chat-recall 0.5.28 → 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
  }
@@ -13266,9 +13266,9 @@ function doResolve(realPath) {
13266
13266
  const bot = resolveBotWorktree(realPath);
13267
13267
  if (bot)
13268
13268
  return bot;
13269
- const git = resolveGit(realPath);
13270
- if (git)
13271
- return git;
13269
+ const git2 = resolveGit(realPath);
13270
+ if (git2)
13271
+ return git2;
13272
13272
  const ws = resolveAutoWorkspace(realPath, cfg.autoWorkspaceMinRepos ?? DEFAULT_AUTO_WORKSPACE_MIN_REPOS);
13273
13273
  if (ws)
13274
13274
  return ws;
@@ -13337,9 +13337,9 @@ function resolveGit(realPath) {
13337
13337
  const toplevel = findGitToplevel(realPath);
13338
13338
  if (!toplevel)
13339
13339
  return null;
13340
- const remote = getGitRemote(toplevel);
13341
- if (remote) {
13342
- const parsed = parseGitRemote(remote);
13340
+ const probe = getGitRemote(toplevel);
13341
+ if (probe.kind === "remote") {
13342
+ const parsed = parseGitRemote(probe.url);
13343
13343
  if (parsed) {
13344
13344
  return {
13345
13345
  id: `git:${parsed.host}/${parsed.owner}/${parsed.repo}`,
@@ -13348,6 +13348,9 @@ function resolveGit(realPath) {
13348
13348
  };
13349
13349
  }
13350
13350
  }
13351
+ if (probe.kind === "failed") {
13352
+ console.error(`[project] could not read git remotes in ${toplevel} \u2014 filing it as a local-only repo for now, which is probably wrong: ${probe.reason}`);
13353
+ }
13351
13354
  const hash = createHash6("sha1").update(toplevel).digest("hex").slice(0, 12);
13352
13355
  return {
13353
13356
  id: `git-local:${hash}`,
@@ -13366,23 +13369,39 @@ function findGitToplevel(realPath) {
13366
13369
  }
13367
13370
  return null;
13368
13371
  }
13372
+ function git(toplevel, args) {
13373
+ return execSync(`git ${args}`, {
13374
+ cwd: toplevel,
13375
+ stdio: ["ignore", "pipe", "ignore"],
13376
+ encoding: "utf-8",
13377
+ timeout: GIT_TIMEOUT_MS
13378
+ });
13379
+ }
13380
+ function probeGitRemote(toplevel) {
13381
+ let names;
13382
+ try {
13383
+ names = git(toplevel, "remote").split("\n").map((n) => n.trim()).filter(Boolean);
13384
+ } catch (err) {
13385
+ return { kind: "failed", reason: err instanceof Error ? err.message : String(err) };
13386
+ }
13387
+ if (names.length === 0)
13388
+ return { kind: "none" };
13389
+ const pick = names.includes("origin") ? "origin" : names[0];
13390
+ try {
13391
+ const url = git(toplevel, `remote get-url ${pick}`).trim();
13392
+ return url ? { kind: "remote", url } : { kind: "none" };
13393
+ } catch (err) {
13394
+ return { kind: "failed", reason: err instanceof Error ? err.message : String(err) };
13395
+ }
13396
+ }
13369
13397
  function getGitRemote(toplevel) {
13370
13398
  const cached = gitCache.get(toplevel);
13371
13399
  if (cached)
13372
- return cached.remote;
13373
- let remote = null;
13374
- try {
13375
- remote = execSync("git remote get-url origin", {
13376
- cwd: toplevel,
13377
- stdio: ["ignore", "pipe", "ignore"],
13378
- encoding: "utf-8",
13379
- timeout: 2e3
13380
- }).trim() || null;
13381
- } catch {
13382
- remote = null;
13383
- }
13384
- gitCache.set(toplevel, { remote });
13385
- return remote;
13400
+ return cached;
13401
+ const probe = probeGitRemote(toplevel);
13402
+ if (probe.kind !== "failed")
13403
+ gitCache.set(toplevel, probe);
13404
+ return probe;
13386
13405
  }
13387
13406
  function parseGitRemote(url) {
13388
13407
  const trimmed = url.trim().replace(/\.git$/, "");
@@ -13512,7 +13531,7 @@ function globToRegex(glob) {
13512
13531
  function escapeRe(s) {
13513
13532
  return s.replace(/[.+^${}()|[\]\\]/g, "\\$&");
13514
13533
  }
13515
- var DEFAULT_AUTO_WORKSPACE_MIN_REPOS, BOT_WORKTREE_MARKERS, resolveCache, gitCache, workspaceCache, wsIdCache, cachedConfig, AUTO_WORKSPACE_MAX_DEPTH;
13534
+ var DEFAULT_AUTO_WORKSPACE_MIN_REPOS, BOT_WORKTREE_MARKERS, resolveCache, gitCache, workspaceCache, wsIdCache, cachedConfig, GIT_TIMEOUT_MS, AUTO_WORKSPACE_MAX_DEPTH;
13516
13535
  var init_project_resolver = __esm({
13517
13536
  "../engine/dist/core/project-resolver.js"() {
13518
13537
  "use strict";
@@ -13524,6 +13543,7 @@ var init_project_resolver = __esm({
13524
13543
  workspaceCache = /* @__PURE__ */ new Map();
13525
13544
  wsIdCache = /* @__PURE__ */ new Map();
13526
13545
  cachedConfig = null;
13546
+ GIT_TIMEOUT_MS = 1e4;
13527
13547
  AUTO_WORKSPACE_MAX_DEPTH = 2;
13528
13548
  }
13529
13549
  });
@@ -19730,7 +19750,7 @@ var init_http = __esm({
19730
19750
  CLI_VERSION = JSON.parse(readFileSync33(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
19731
19751
  } catch {
19732
19752
  try {
19733
- if (true) CLI_VERSION = "0.5.28";
19753
+ if (true) CLI_VERSION = "0.5.30";
19734
19754
  } catch {
19735
19755
  }
19736
19756
  }
@@ -20242,7 +20262,7 @@ var init_telemetry = __esm({
20242
20262
  init_sync_client();
20243
20263
  cliVersion2 = () => {
20244
20264
  try {
20245
- return true ? "0.5.28" : "dev";
20265
+ return true ? "0.5.30" : "dev";
20246
20266
  } catch {
20247
20267
  return "dev";
20248
20268
  }
@@ -20579,12 +20599,13 @@ __export(auto_update_exports, {
20579
20599
  planAutoUpdate: () => planAutoUpdate,
20580
20600
  runAutoUpdate: () => runAutoUpdate,
20581
20601
  runningPrefix: () => runningPrefix,
20602
+ sweepStaleStaging: () => sweepStaleStaging,
20582
20603
  tarballUrl: () => tarballUrl
20583
20604
  });
20584
20605
  import { execSync as execSync2 } from "node:child_process";
20585
20606
  import { readFileSync as readFileSync36 } from "node:fs";
20586
20607
  import { fileURLToPath as fileURLToPath2 } from "node:url";
20587
- 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";
20588
20609
  import { join as join43, dirname as dirname18, sep as sep2 } from "node:path";
20589
20610
  import { tmpdir as tmpdir2 } from "node:os";
20590
20611
  import { createHash as createHash12 } from "node:crypto";
@@ -20623,6 +20644,31 @@ function planAutoUpdate(base2, caps, ownVersion3, flag) {
20623
20644
  if (compareVersions(rel.version, ownVersion3) <= 0) return { update: false, reason: `already current (own ${ownVersion3} >= server ${rel.version})` };
20624
20645
  return { update: true, reason: `server ${rel.version} > own ${ownVersion3}`, url: tarballUrl(base2), sha256: rel.sha256, from: ownVersion3, to: rel.version };
20625
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
+ }
20626
20672
  async function executeAutoUpdate(plan, deps) {
20627
20673
  if (!plan.update || !plan.url || !plan.sha256) return { updated: false, reason: plan.reason };
20628
20674
  let buf;
@@ -20634,13 +20680,21 @@ async function executeAutoUpdate(plan, deps) {
20634
20680
  const got = createHash12("sha256").update(buf).digest("hex");
20635
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` };
20636
20682
  const dir = mkdtempSync3(join43(tmpdir2(), "cr-update-"));
20683
+ const discardStaging = () => {
20684
+ try {
20685
+ rmSync5(dir, { recursive: true, force: true });
20686
+ } catch {
20687
+ }
20688
+ };
20637
20689
  const tgz = join43(dir, "chat-recall.tgz");
20638
20690
  writeFileSync8(tgz, buf);
20639
20691
  try {
20640
20692
  deps.install(tgz);
20641
20693
  } catch (e) {
20694
+ discardStaging();
20642
20695
  return { updated: false, reason: `install failed: ${e instanceof Error ? e.message : e}` };
20643
20696
  }
20697
+ discardStaging();
20644
20698
  const landed = (deps.verify ?? installedVersion)();
20645
20699
  if (landed && plan.to && compareVersions(landed, plan.to) < 0) {
20646
20700
  return {
@@ -20747,7 +20801,7 @@ __export(sync_client_exports, {
20747
20801
  syncSessions: () => syncSessions
20748
20802
  });
20749
20803
  import { join as join44, dirname as dirname19, basename as basename22 } from "node:path";
20750
- 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";
20751
20805
  import { tmpdir as tmpdir3, hostname as hostname2 } from "node:os";
20752
20806
  import { createHash as createHash13 } from "node:crypto";
20753
20807
  import { fileURLToPath as fileURLToPath3 } from "node:url";
@@ -21119,7 +21173,7 @@ function reapStaleScanDirs(dir = tmpdir3(), maxAgeMs = 6 * 36e5, now = Date.now(
21119
21173
  let reaped = 0;
21120
21174
  let names;
21121
21175
  try {
21122
- names = readdirSync32(dir);
21176
+ names = readdirSync33(dir);
21123
21177
  } catch {
21124
21178
  return 0;
21125
21179
  }
@@ -21127,8 +21181,8 @@ function reapStaleScanDirs(dir = tmpdir3(), maxAgeMs = 6 * 36e5, now = Date.now(
21127
21181
  if (!name.startsWith("cr-batchscan-")) continue;
21128
21182
  const p = join44(dir, name);
21129
21183
  try {
21130
- if (now - statSync38(p).mtimeMs < maxAgeMs) continue;
21131
- rmSync5(p, { recursive: true, force: true });
21184
+ if (now - statSync39(p).mtimeMs < maxAgeMs) continue;
21185
+ rmSync6(p, { recursive: true, force: true });
21132
21186
  reaped++;
21133
21187
  } catch {
21134
21188
  }
@@ -21160,7 +21214,7 @@ function batchScanExternal(items, opts = {}) {
21160
21214
  slices++;
21161
21215
  }
21162
21216
  try {
21163
- rmSync5(scanDir, { recursive: true, force: true });
21217
+ rmSync6(scanDir, { recursive: true, force: true });
21164
21218
  } catch {
21165
21219
  }
21166
21220
  safeToId = /* @__PURE__ */ new Map();
@@ -21185,7 +21239,7 @@ function batchScanExternal(items, opts = {}) {
21185
21239
  flushSlice();
21186
21240
  } finally {
21187
21241
  try {
21188
- rmSync5(scanDir, { recursive: true, force: true });
21242
+ rmSync6(scanDir, { recursive: true, force: true });
21189
21243
  } catch {
21190
21244
  }
21191
21245
  }
@@ -21318,9 +21372,10 @@ async function syncToTargetInScope(cred, opts = {}) {
21318
21372
  setServerIngestConcurrency(base2, Math.floor(adv));
21319
21373
  }
21320
21374
  if (body2.cli && body2.cli.version) {
21321
- 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));
21322
21376
  const authHeaders = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
21323
21377
  const plan = planAutoUpdate2(base2, { cli: body2.cli }, ownVersion, process.env.CHAT_RECALL_AUTO_UPDATE);
21378
+ sweepStaleStaging2();
21324
21379
  if (plan.update) {
21325
21380
  void runAutoUpdate2(base2, authHeaders, ownVersion).catch(() => {
21326
21381
  });
@@ -21446,9 +21501,10 @@ async function syncToTargetInScope(cred, opts = {}) {
21446
21501
  if (!res.ok) throw new Error(`append sync failed: HTTP ${res.status} ${await res.text().catch(() => "")}`);
21447
21502
  const body = await res.json().catch(() => ({}));
21448
21503
  if (body.cli && body.cli.version) {
21449
- 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));
21450
21505
  const authHeaders = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
21451
21506
  const plan = planAutoUpdate2(base2, { cli: body.cli }, ownVersion, process.env.CHAT_RECALL_AUTO_UPDATE);
21507
+ sweepStaleStaging2();
21452
21508
  if (plan.update) {
21453
21509
  void runAutoUpdate2(base2, authHeaders, ownVersion).catch(() => {
21454
21510
  });
@@ -22250,7 +22306,7 @@ var init_sync_client = __esm({
22250
22306
  ownVersion = JSON.parse(readFileSync37(join44(dir, "../package.json"), "utf-8")).version || ownVersion;
22251
22307
  } catch {
22252
22308
  try {
22253
- if (true) ownVersion = "0.5.28";
22309
+ if (true) ownVersion = "0.5.30";
22254
22310
  } catch {
22255
22311
  }
22256
22312
  }
@@ -22364,11 +22420,11 @@ var init_update_notice = __esm({
22364
22420
  });
22365
22421
 
22366
22422
  // ../engine/dist/core/which.js
22367
- 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";
22368
22424
  import { join as join46, isAbsolute as isAbsolute2, delimiter as delimiter2, sep as sep3 } from "node:path";
22369
22425
  function executable(p) {
22370
22426
  try {
22371
- if (!statSync39(p).isFile())
22427
+ if (!statSync40(p).isFile())
22372
22428
  return false;
22373
22429
  } catch {
22374
22430
  return false;
@@ -22479,11 +22535,17 @@ function writeFileMkdir(path, body) {
22479
22535
  mkdirSync10(dirname20(path), { recursive: true });
22480
22536
  writeFileSync11(path, body);
22481
22537
  }
22538
+ function readJsonObject(path) {
22539
+ const raw = readFileSync39(path, "utf-8");
22540
+ if (raw.trim() === "")
22541
+ return {};
22542
+ return JSON.parse(raw);
22543
+ }
22482
22544
  function registerMcpServersJson(target, path, spec) {
22483
22545
  let cfg = {};
22484
22546
  if (existsSync44(path)) {
22485
22547
  try {
22486
- cfg = JSON.parse(readFileSync39(path, "utf-8"));
22548
+ cfg = readJsonObject(path);
22487
22549
  } catch (err) {
22488
22550
  return { id: target.id, label: target.label, path, state: "unparseable", error: String(err) };
22489
22551
  }
@@ -22498,7 +22560,7 @@ function registerMcpServersJson(target, path, spec) {
22498
22560
  entry.alwaysAllow = existing?.alwaysAllow ?? spec.alwaysAllow;
22499
22561
  if (spec.env)
22500
22562
  entry.env = { ...existing?.env, ...spec.env };
22501
- 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);
22502
22564
  if (isCurrent)
22503
22565
  return { id: target.id, label: target.label, path, state: "current" };
22504
22566
  servers[MCP_SERVER_NAME] = entry;
@@ -22512,7 +22574,7 @@ function registerOpencodeJson(path, spec) {
22512
22574
  let cfg = {};
22513
22575
  if (existsSync44(path)) {
22514
22576
  try {
22515
- cfg = JSON.parse(readFileSync39(path, "utf-8"));
22577
+ cfg = readJsonObject(path);
22516
22578
  } catch (err) {
22517
22579
  return { id, label, path, state: "unparseable", error: String(err) };
22518
22580
  }
@@ -22525,7 +22587,7 @@ function registerOpencodeJson(path, spec) {
22525
22587
  const entry = { type: "local", command: argv, enabled: true };
22526
22588
  if (spec.env)
22527
22589
  entry.environment = { ...existing?.environment, ...spec.env };
22528
- 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);
22529
22591
  if (isCurrent)
22530
22592
  return { id, label, path, state: "current" };
22531
22593
  mcp[MCP_SERVER_NAME] = entry;
@@ -22704,7 +22766,7 @@ __export(companions_exports, {
22704
22766
  uninstallCodeindex: () => uninstallCodeindex,
22705
22767
  unregisterCodeindexMcp: () => unregisterCodeindexMcp
22706
22768
  });
22707
- 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";
22708
22770
  import { homedir as homedir16 } from "node:os";
22709
22771
  import { join as join48 } from "node:path";
22710
22772
  import { execSync as execSync3 } from "node:child_process";
@@ -22755,7 +22817,7 @@ function checkCodeindexStatus() {
22755
22817
  status.installed = true;
22756
22818
  status.path = foundPath;
22757
22819
  try {
22758
- status.size = statSync40(foundPath).size;
22820
+ status.size = statSync41(foundPath).size;
22759
22821
  } catch {
22760
22822
  }
22761
22823
  try {
@@ -22905,7 +22967,7 @@ __export(install_skills_exports, {
22905
22967
  skillsSourceDir: () => skillsSourceDir,
22906
22968
  uninstallSkills: () => uninstallSkills
22907
22969
  });
22908
- 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";
22909
22971
  import { createHash as createHash15 } from "crypto";
22910
22972
  import { join as join49, basename as basename23 } from "path";
22911
22973
  function skillsSourceDir() {
@@ -22931,7 +22993,7 @@ function skillsFingerprint() {
22931
22993
  }
22932
22994
  function filesUnder(dir, prefix = "") {
22933
22995
  const out = [];
22934
- for (const e of readdirSync33(dir, { withFileTypes: true })) {
22996
+ for (const e of readdirSync34(dir, { withFileTypes: true })) {
22935
22997
  if (e.name === MARKER) continue;
22936
22998
  const rel = prefix ? `${prefix}/${e.name}` : e.name;
22937
22999
  if (e.isDirectory()) out.push(...filesUnder(join49(dir, e.name), rel));
@@ -22945,7 +23007,7 @@ function skillStamp() {
22945
23007
  function bundledSkillNames() {
22946
23008
  const src = skillsSourceDir();
22947
23009
  if (!existsSync46(src)) return [];
22948
- 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();
22949
23011
  }
22950
23012
  function realPathOrSelf(p) {
22951
23013
  try {
@@ -23018,7 +23080,7 @@ function installSkills(opts = {}) {
23018
23080
  continue;
23019
23081
  }
23020
23082
  mkdirSync12(t.dir, { recursive: true });
23021
- rmSync6(dest, { recursive: true, force: true });
23083
+ rmSync7(dest, { recursive: true, force: true });
23022
23084
  cpSync(join49(src, name), dest, { recursive: true });
23023
23085
  writeFileSync13(join49(dest, MARKER), `${stamp}
23024
23086
  `);
@@ -23037,11 +23099,11 @@ function uninstallSkills() {
23037
23099
  perTarget.push({ id: t.id, label: t.label, removed });
23038
23100
  continue;
23039
23101
  }
23040
- for (const entry of readdirSync33(t.dir, { withFileTypes: true })) {
23102
+ for (const entry of readdirSync34(t.dir, { withFileTypes: true })) {
23041
23103
  if (!entry.isDirectory()) continue;
23042
23104
  const dir = join49(t.dir, entry.name);
23043
23105
  if (isManaged(dir) && (names.has(entry.name) || entry.name.startsWith("chat-recall"))) {
23044
- rmSync6(dir, { recursive: true, force: true });
23106
+ rmSync7(dir, { recursive: true, force: true });
23045
23107
  removed.push(entry.name);
23046
23108
  }
23047
23109
  }
@@ -23722,11 +23784,11 @@ __export(toolkit_pull_exports, {
23722
23784
  planPull: () => planPull,
23723
23785
  portableCommand: () => portableCommand
23724
23786
  });
23725
- 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";
23726
23788
  import { dirname as dirname22, join as join52, basename as basename26, isAbsolute as isAbsolute3 } from "node:path";
23727
23789
  function isExecutableFile(p) {
23728
23790
  try {
23729
- return statSync42(p).isFile();
23791
+ return statSync43(p).isFile();
23730
23792
  } catch {
23731
23793
  return false;
23732
23794
  }
@@ -25647,7 +25709,7 @@ __export(project_tasks_exports, {
25647
25709
  pushProjectTaskStatuses: () => pushProjectTaskStatuses,
25648
25710
  renderTeamTasksMd: () => renderTeamTasksMd
25649
25711
  });
25650
- 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";
25651
25713
  import { join as join54, dirname as dirname23 } from "node:path";
25652
25714
  import { homedir as homedir19 } from "node:os";
25653
25715
  function isTeamTaskStatus(v) {
@@ -25736,7 +25798,7 @@ async function pushProjectTaskStatuses(base2, authHeaders, opts = {}) {
25736
25798
  if (!existsSync50(file)) continue;
25737
25799
  let mtime;
25738
25800
  try {
25739
- mtime = statSync43(file).mtimeMs;
25801
+ mtime = statSync44(file).mtimeMs;
25740
25802
  } catch {
25741
25803
  continue;
25742
25804
  }
@@ -25946,8 +26008,9 @@ async function drainSyncIntents(opts = {}) {
25946
26008
  const data = await res.json();
25947
26009
  pending = data.intents || [];
25948
26010
  if (data.cli && data.cli.version) {
25949
- 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));
25950
26012
  const plan = planAutoUpdate2(base2, { cli: data.cli }, ownVersion2, process.env.CHAT_RECALL_AUTO_UPDATE);
26013
+ sweepStaleStaging2();
25951
26014
  if (plan.update) {
25952
26015
  void runAutoUpdate2(base2, authHeaders, ownVersion2).catch(() => {
25953
26016
  });
@@ -26001,7 +26064,7 @@ var init_intent_drain = __esm({
26001
26064
  ownVersion2 = JSON.parse(readFileSync46(join55(dir, "../package.json"), "utf-8")).version || ownVersion2;
26002
26065
  } catch {
26003
26066
  try {
26004
- if (true) ownVersion2 = "0.5.28";
26067
+ if (true) ownVersion2 = "0.5.30";
26005
26068
  } catch {
26006
26069
  }
26007
26070
  }
@@ -26202,7 +26265,7 @@ var team_merge_exports = {};
26202
26265
  __export(team_merge_exports, {
26203
26266
  mergePullResult: () => mergePullResult
26204
26267
  });
26205
- 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";
26206
26269
  import { dirname as dirname25, join as join56 } from "path";
26207
26270
  import { createHash as createHash18 } from "crypto";
26208
26271
  function installPathFor(art, tool) {
@@ -26319,7 +26382,7 @@ async function mergePullResult(opts) {
26319
26382
  continue;
26320
26383
  try {
26321
26384
  if (existsSync52(path))
26322
- rmSync7(path, { force: true });
26385
+ rmSync8(path, { force: true });
26323
26386
  await teamInstallsForget(id, row.tool);
26324
26387
  report.removed.push({ artifactId: id, path });
26325
26388
  } catch (err) {
@@ -26338,7 +26401,7 @@ function readFileIfExists(path) {
26338
26401
  try {
26339
26402
  if (!existsSync52(path))
26340
26403
  return null;
26341
- const s = statSync44(path);
26404
+ const s = statSync45(path);
26342
26405
  if (!s.isFile())
26343
26406
  return null;
26344
26407
  return readFileSync47(path);
@@ -26423,7 +26486,7 @@ var init_vault_crypto = __esm({
26423
26486
  });
26424
26487
 
26425
26488
  // ../engine/dist/core/vault-source.js
26426
- 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";
26427
26490
  import { extname, join as join57 } from "path";
26428
26491
  function* walkVaultSources() {
26429
26492
  const t = loadSettings().team.vault;
@@ -26441,7 +26504,7 @@ function* walkVaultSources() {
26441
26504
  }
26442
26505
  function safeStat(path) {
26443
26506
  try {
26444
- const s = statSync45(path);
26507
+ const s = statSync46(path);
26445
26508
  if (!s.isFile())
26446
26509
  return null;
26447
26510
  return { mtimeMs: s.mtimeMs, size: s.size };
@@ -26455,7 +26518,7 @@ function* walkClaude() {
26455
26518
  return;
26456
26519
  let projectDirs = [];
26457
26520
  try {
26458
- projectDirs = readdirSync34(root);
26521
+ projectDirs = readdirSync35(root);
26459
26522
  } catch {
26460
26523
  return;
26461
26524
  }
@@ -26466,7 +26529,7 @@ function* walkClaude() {
26466
26529
  const projDir = join57(root, proj);
26467
26530
  let entries = [];
26468
26531
  try {
26469
- entries = readdirSync34(projDir);
26532
+ entries = readdirSync35(projDir);
26470
26533
  } catch {
26471
26534
  continue;
26472
26535
  }
@@ -26488,7 +26551,7 @@ function* walkGemini() {
26488
26551
  return;
26489
26552
  let hashDirs = [];
26490
26553
  try {
26491
- hashDirs = readdirSync34(tmp);
26554
+ hashDirs = readdirSync35(tmp);
26492
26555
  } catch {
26493
26556
  return;
26494
26557
  }
@@ -26498,7 +26561,7 @@ function* walkGemini() {
26498
26561
  continue;
26499
26562
  let entries = [];
26500
26563
  try {
26501
- entries = readdirSync34(chatsDir);
26564
+ entries = readdirSync35(chatsDir);
26502
26565
  } catch {
26503
26566
  continue;
26504
26567
  }
@@ -26544,7 +26607,7 @@ function* walkCodex() {
26544
26607
  const dir = stack.pop();
26545
26608
  let entries = [];
26546
26609
  try {
26547
- entries = readdirSync34(dir, { withFileTypes: true });
26610
+ entries = readdirSync35(dir, { withFileTypes: true });
26548
26611
  } catch {
26549
26612
  continue;
26550
26613
  }
@@ -26570,14 +26633,14 @@ function* walkAgy() {
26570
26633
  return;
26571
26634
  let sessionDirs = [];
26572
26635
  try {
26573
- sessionDirs = readdirSync34(brainDir);
26636
+ sessionDirs = readdirSync35(brainDir);
26574
26637
  } catch {
26575
26638
  return;
26576
26639
  }
26577
26640
  for (const rawId of sessionDirs) {
26578
26641
  const sessionPath = join57(brainDir, rawId);
26579
26642
  try {
26580
- if (!statSync45(sessionPath).isDirectory())
26643
+ if (!statSync46(sessionPath).isDirectory())
26581
26644
  continue;
26582
26645
  } catch {
26583
26646
  continue;
@@ -27058,7 +27121,7 @@ __export(service_installer_exports, {
27058
27121
  uninstallService: () => uninstallService
27059
27122
  });
27060
27123
  import { execSync as execSync5 } from "child_process";
27061
- 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";
27062
27125
  import { homedir as homedir21 } from "os";
27063
27126
  import { join as join59 } from "path";
27064
27127
  import { fileURLToPath as fileURLToPath5 } from "url";
@@ -27214,7 +27277,7 @@ function uninstallService() {
27214
27277
  }
27215
27278
  const unitPath = join59(homedir21(), ".config", "systemd", "user", "chat-recall-watch.service");
27216
27279
  if (existsSync55(unitPath)) {
27217
- rmSync8(unitPath, { force: true });
27280
+ rmSync9(unitPath, { force: true });
27218
27281
  removed = true;
27219
27282
  }
27220
27283
  try {
@@ -27231,7 +27294,7 @@ function uninstallService() {
27231
27294
  }
27232
27295
  let removed = false;
27233
27296
  if (existsSync55(plistPath)) {
27234
- rmSync8(plistPath, { force: true });
27297
+ rmSync9(plistPath, { force: true });
27235
27298
  removed = true;
27236
27299
  }
27237
27300
  return removed;
@@ -27508,7 +27571,7 @@ init_tool_paths();
27508
27571
  init_project_resolver();
27509
27572
  import { config } from "dotenv";
27510
27573
  import { Command } from "commander";
27511
- import chalk from "chalk";
27574
+ import chalk2 from "chalk";
27512
27575
  import { existsSync as existsSync56, readFileSync as readFileSync49, writeFileSync as writeFileSync21, realpathSync as realpathSync5 } from "fs";
27513
27576
  import { homedir as homedir22 } from "os";
27514
27577
  import { join as join60, resolve as resolve2, dirname as dirname27, basename as basename29 } from "path";
@@ -27569,16 +27632,64 @@ function openBrowser(url) {
27569
27632
  init_which();
27570
27633
  init_collector_health();
27571
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
27572
27683
  function matchLabel(tier) {
27573
27684
  switch (tier) {
27574
27685
  case "strong":
27575
- return chalk.green("strong");
27686
+ return chalk2.green("strong");
27576
27687
  case "good":
27577
- return chalk.yellow("good");
27688
+ return chalk2.yellow("good");
27578
27689
  case "weak":
27579
- return chalk.dim("weak");
27690
+ return chalk2.dim("weak");
27580
27691
  default:
27581
- return chalk.dim("unranked");
27692
+ return chalk2.dim("unranked");
27582
27693
  }
27583
27694
  }
27584
27695
  config({ quiet: true });
@@ -27613,13 +27724,13 @@ function describeProbeError(err) {
27613
27724
  }
27614
27725
  function failLogin(opts, message) {
27615
27726
  if (opts.fromInit) throw new Error(message);
27616
- console.error(chalk.red("login failed:"), message);
27727
+ console.error(chalk2.red("login failed:"), message);
27617
27728
  process.exit(1);
27618
27729
  }
27619
27730
  function requireTarget() {
27620
27731
  const t = firstTarget();
27621
27732
  if (!t) {
27622
- 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.");
27623
27734
  process.exit(1);
27624
27735
  }
27625
27736
  return t;
@@ -27777,7 +27888,7 @@ var program = new Command();
27777
27888
  program.name("chat-recall").description("Semantic search for Claude Code sessions - recall and resume past conversations").version(pkgVersion);
27778
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) => {
27779
27890
  try {
27780
- console.log(chalk.bold("chat-recall init") + chalk.dim(` v${pkgVersion}`));
27891
+ console.log(chalk2.bold("chat-recall init") + chalk2.dim(` v${pkgVersion}`));
27781
27892
  const { createInitReporter: createInitReporter2 } = await Promise.resolve().then(() => (init_init_report(), init_report_exports));
27782
27893
  const rep = createInitReporter2({
27783
27894
  tty: process.stdout.isTTY === true,
@@ -27801,8 +27912,8 @@ program.command("init").description("Set up chat-recall: connect to your server,
27801
27912
  }
27802
27913
  }
27803
27914
  const foundTools = clis.filter((c) => c.available).map((c) => c.name.replace(/ (CLI|Code)$/, ""));
27804
- if (!foundTools.length) rep.warn(chalk.yellow("No AI tools detected \u2014 chat-recall indexes their transcripts, so there is nothing to ship yet."));
27805
- 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}`);
27806
27917
  let target = firstTarget();
27807
27918
  let deadTarget = false;
27808
27919
  if (options.server) {
@@ -27826,24 +27937,24 @@ program.command("init").description("Set up chat-recall: connect to your server,
27826
27937
  if (probeOk2(probe)) {
27827
27938
  } else if (probe.kind === "moved" || probe.kind === "not_api") {
27828
27939
  const retired = target.base;
27829
- 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}`);
27830
27941
  console.log(` ${probeAdvice2(probe, retired)}`);
27831
- 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.`);
27832
27943
  try {
27833
27944
  await runLogin(DEFAULT_SERVER, { token: options.token, fromInit: true, promptJson: options.promptJson });
27834
27945
  const { removeCredentials: removeCredentials2 } = await Promise.resolve().then(() => (init_sync_client(), sync_client_exports));
27835
27946
  if (removeCredentials2(retired)) {
27836
- 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).`)}`);
27837
27948
  }
27838
27949
  target = firstTarget();
27839
- if (target) console.log(` ${chalk.green("Connected")} \u2192 ${target.base}`);
27950
+ if (target) console.log(` ${chalk2.green("Connected")} \u2192 ${target.base}`);
27840
27951
  } catch (e) {
27841
27952
  serverBad(describeProbeError(e));
27842
- 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}`)}.`)}`);
27843
27954
  deadTarget = true;
27844
27955
  }
27845
27956
  } else {
27846
- 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}`);
27847
27958
  console.log(` ${probeAdvice2(probe, target.base)}`);
27848
27959
  }
27849
27960
  } else if (target) {
@@ -27872,7 +27983,9 @@ program.command("init").description("Set up chat-recall: connect to your server,
27872
27983
  if (ok.length) {
27873
27984
  }
27874
27985
  for (const r of bad) {
27875
- rep.warn(`${chalk.yellow(`${r.label} config left alone \u2014 the file does not parse`)} ${chalk.dim(r.path)}`);
27986
+ const why = (r.error ?? "").replace(/^SyntaxError:\s*/, "").split("\n")[0];
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)`)}`);
27876
27989
  }
27877
27990
  if (process.env.CHAT_RECALL_VERBOSE) {
27878
27991
  }
@@ -27904,14 +28017,14 @@ program.command("init").description("Set up chat-recall: connect to your server,
27904
28017
  const reg = registerCodeindexMcp2(mcpJsonPath, CODEINDEX_BIN_PATH2);
27905
28018
  }
27906
28019
  } else if (!result.prebuiltAvailable) {
27907
- rep.warn(`${chalk.yellow("codeindex")}: ${result.unsupportedReason}`);
28020
+ rep.warn(`${chalk2.yellow("codeindex")}: ${result.unsupportedReason}`);
27908
28021
  }
27909
28022
  } catch (err) {
27910
28023
  const msg = String(err);
27911
- rep.warn(`${chalk.yellow("codeindex install failed")}: ${msg}`);
28024
+ rep.warn(`${chalk2.yellow("codeindex install failed")}: ${msg}`);
27912
28025
  if (msg.includes("404")) {
27913
- console.log(chalk.dim(" The codeindex release returned 404. If the repo is private,"));
27914
- 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."));
27915
28028
  }
27916
28029
  }
27917
28030
  } else {
@@ -27927,7 +28040,7 @@ program.command("init").description("Set up chat-recall: connect to your server,
27927
28040
  }
27928
28041
  const userOwned = [...new Set(r.perTarget.flatMap((t) => t.skippedUserOwned))];
27929
28042
  } catch (err) {
27930
- 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}`);
27931
28044
  }
27932
28045
  if (!options.skipMcp && firstTarget()) {
27933
28046
  try {
@@ -27965,28 +28078,30 @@ program.command("init").description("Set up chat-recall: connect to your server,
27965
28078
  const written = report.outcomes.filter((o) => o.status === "written");
27966
28079
  const present = report.outcomes.filter((o) => o.status === "present").length;
27967
28080
  if (answered === 0) {
27968
- rep.warn(chalk.yellow("Could not ask your server what MCP servers are on your account"));
27969
- for (const f of askFailed) console.log(` ${chalk.dim(f)}`);
27970
- 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.")}`);
27971
28084
  } else if (written.length === 0 && present === 0) {
27972
28085
  } else {
27973
- const envVars = [...new Set(written.flatMap((o) => o.needsEnv || []))].sort();
27974
- if (envVars.length) {
27975
- 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);
27976
28091
  }
27977
28092
  }
27978
28093
  } catch (err) {
27979
- rep.warn(`${chalk.yellow("Could not install account MCPs")} \u2014 ${err instanceof Error ? err.message : err}`);
27980
- 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.")}`);
27981
28096
  }
27982
28097
  }
27983
28098
  if (deadTarget) {
27984
- console.log(chalk.bold("6. Skipping first sync \u2014 the saved server is not serving chat-recall"));
27985
- 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")}.`)}`);
27986
28101
  } else if (!options.skipSync && firstTarget()) {
27987
28102
  const { watchFirstSync: watchFirstSync2, spawnDetachedSync: spawnDetachedSync2, handOffLine: handOffLine2, progressLine: renderProgress } = await Promise.resolve().then(() => (init_init_progress(), init_progress_exports));
27988
28103
  const { readCollectorHealth: readCollectorHealth2 } = await Promise.resolve().then(() => (init_collector_health(), collector_health_exports));
27989
- const label = (text) => `${chalk.bold("6. Indexing")} ${text}`;
28104
+ const label = (text) => `${chalk2.bold("Indexing")} ${text}`;
27990
28105
  const tty = process.stdout.isTTY === true;
27991
28106
  const outcome = await watchFirstSync2({
27992
28107
  startWorker: () => spawnDetachedSync2(),
@@ -28004,22 +28119,22 @@ program.command("init").description("Set up chat-recall: connect to your server,
28004
28119
  });
28005
28120
  if (tty) process.stdout.write("\r");
28006
28121
  if (outcome.finished) {
28007
- console.log(label(chalk.green(renderProgress(outcome.snapshot))));
28122
+ console.log(label(chalk2.green(renderProgress(outcome.snapshot))));
28008
28123
  } else {
28009
- console.log(label(chalk.dim(handOffLine2(outcome.snapshot))));
28010
- 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"))}`);
28011
28126
  }
28012
28127
  const failed = Object.entries(readCollectorHealth2()?.targets ?? {}).filter(([, t]) => (t.failures ?? 0) > 0 && t.lastError);
28013
28128
  for (const [server, t] of failed) {
28014
- console.log(` ${chalk.yellow("sync error")} ${chalk.dim(server)}: ${t.lastError}`);
28129
+ console.log(` ${chalk2.yellow("sync error")} ${chalk2.dim(server)}: ${t.lastError}`);
28015
28130
  }
28016
28131
  } else if (!options.skipSync) {
28017
28132
  } else {
28018
28133
  }
28019
28134
  void options.skipService;
28020
- rep.done(chalk.green.bold("\u2713 Done"));
28135
+ rep.done(chalk2.green.bold("\u2713 Done"));
28021
28136
  } catch (err) {
28022
- console.error(chalk.red("Error:"), err);
28137
+ console.error(chalk2.red("Error:"), err);
28023
28138
  process.exit(1);
28024
28139
  }
28025
28140
  });
@@ -28029,57 +28144,57 @@ program.command("install-skills").description("Install the chat-recall skills in
28029
28144
  const r2 = mod.uninstallSkills();
28030
28145
  const hits2 = r2.perTarget.filter((t) => t.removed.length > 0);
28031
28146
  if (!hits2.length) {
28032
- console.log(chalk.dim("No chat-recall skills were installed."));
28147
+ console.log(chalk2.dim("No chat-recall skills were installed."));
28033
28148
  return;
28034
28149
  }
28035
- 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)`);
28036
28151
  return;
28037
28152
  }
28038
28153
  const r = mod.installSkills({ onlyAvailable: !opts.allTools });
28039
28154
  const names = mod.bundledSkillNames();
28040
- 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(", ")));
28041
28156
  const hits = r.perTarget.filter((t) => t.installed.length > 0);
28042
28157
  if (!hits.length) {
28043
- 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."));
28044
28159
  return;
28045
28160
  }
28046
- 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)}`);
28047
28162
  const userOwned = [...new Set(r.perTarget.flatMap((t) => t.skippedUserOwned))];
28048
- 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(", ")}`));
28049
28164
  });
28050
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) => {
28051
28166
  try {
28052
28167
  const { syncSessions: syncSessions2 } = await Promise.resolve().then(() => (init_sync_client(), sync_client_exports));
28053
28168
  const r = await syncSessions2(options.force ? { useLedger: false } : {});
28054
- 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)` : ""}`));
28055
28170
  } catch (err) {
28056
- console.error(chalk.red("Error:"), err instanceof Error ? err.message : err);
28171
+ console.error(chalk2.red("Error:"), err instanceof Error ? err.message : err);
28057
28172
  process.exit(1);
28058
28173
  }
28059
28174
  });
28060
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) => {
28061
28176
  try {
28062
- 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)");
28063
28178
  const render = (r) => {
28064
28179
  const head = `${r.sessionId.slice(0, 8)}\u2026`;
28065
28180
  if (r.status === "no-archive") {
28066
- console.log(chalk.yellow(` ? ${head} no archive found`));
28181
+ console.log(chalk2.yellow(` ? ${head} no archive found`));
28067
28182
  return;
28068
28183
  }
28069
28184
  if (r.status === "already-full") {
28070
- console.log(chalk.dim(` = ${head} already full (${r.fullestMessages} msgs)`));
28185
+ console.log(chalk2.dim(` = ${head} already full (${r.fullestMessages} msgs)`));
28071
28186
  return;
28072
28187
  }
28073
28188
  if (r.status === "error") {
28074
- console.log(chalk.red(` \u2717 ${head} ${r.note}`));
28189
+ console.log(chalk2.red(` \u2717 ${head} ${r.note}`));
28075
28190
  return;
28076
28191
  }
28077
28192
  const verb = r.status === "would-repair" ? "would recover" : "recovered";
28078
- console.log(chalk.green(` ${r.status === "would-repair" ? "\xB7" : "+"} ${head} ${verb} ${r.fullestMessages} msgs`) + chalk.dim(` from ${r.fullestSource}`));
28079
- 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}`));
28080
28195
  };
28081
28196
  if (options.all) {
28082
- 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`));
28083
28198
  const { repairAll: repairAll2 } = await Promise.resolve().then(() => (init_repair(), repair_exports));
28084
28199
  const report = await repairAll2({
28085
28200
  sinceHours: Number(options.sinceHours) || 72,
@@ -28090,24 +28205,24 @@ program.command("repair [sessionIds...]").description("Rebuild sessions an upstr
28090
28205
  report.candidates.forEach(render);
28091
28206
  const fixed2 = report.candidates.filter((r) => r.status === "repaired").length;
28092
28207
  const would2 = report.candidates.filter((r) => r.status === "would-repair").length;
28093
- console.log(chalk.bold(
28208
+ console.log(chalk2.bold(
28094
28209
  `Scanned ${report.scanned} session(s) on ${report.discoveryServer}; ` + (options.apply ? `repaired ${fixed2}.` : `${would2} damaged, would repair. Re-run with --apply to write.`)
28095
28210
  ));
28096
28211
  return;
28097
28212
  }
28098
28213
  if (!sessionIds || sessionIds.length === 0) {
28099
- 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`."));
28100
28215
  process.exit(1);
28101
28216
  }
28102
- console.log(chalk.bold(`repair \xB7 ${mode}`));
28217
+ console.log(chalk2.bold(`repair \xB7 ${mode}`));
28103
28218
  const { repairSessions: repairSessions2 } = await Promise.resolve().then(() => (init_repair(), repair_exports));
28104
28219
  const results = await repairSessions2(sessionIds, { dryRun: !options.apply, force: options.force, verbose: options.verbose, server: options.server });
28105
28220
  results.forEach(render);
28106
28221
  const fixed = results.filter((r) => r.status === "repaired").length;
28107
28222
  const would = results.filter((r) => r.status === "would-repair").length;
28108
- 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.`));
28109
28224
  } catch (err) {
28110
- console.error(chalk.red("Error:"), err instanceof Error ? err.message : err);
28225
+ console.error(chalk2.red("Error:"), err instanceof Error ? err.message : err);
28111
28226
  process.exit(1);
28112
28227
  }
28113
28228
  });
@@ -28117,11 +28232,11 @@ program.command("search <query>").description("Search your server for relevant s
28117
28232
  const remote = await serverPost("/api/search", { query, topK, projectFilter: options.project });
28118
28233
  const results = remote.results;
28119
28234
  if (results.length === 0) {
28120
- console.log(chalk.yellow("No matching sessions found."));
28235
+ console.log(chalk2.yellow("No matching sessions found."));
28121
28236
  process.exit(0);
28122
28237
  }
28123
28238
  console.log();
28124
- console.log(`${chalk.bold("Results for:")} "${query}"`);
28239
+ console.log(`${chalk2.bold("Results for:")} "${query}"`);
28125
28240
  console.log();
28126
28241
  const tiers = tierAll(results);
28127
28242
  for (let i = 0; i < results.length; i++) {
@@ -28130,13 +28245,13 @@ program.command("search <query>").description("Search your server for relevant s
28130
28245
  if (projectPath.length > 50) projectPath = "..." + projectPath.slice(-47);
28131
28246
  let title = (result.firstPrompt || "").replace(/\n/g, " ").trim();
28132
28247
  if (title.length > 80) title = title.slice(0, 80) + "...";
28133
- console.log(`${chalk.bold.cyan(`#${i + 1}`)} ${title}`);
28134
- if (projectPath) console.log(` ${chalk.dim("Project:")} ${projectPath}`);
28135
- 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])}`);
28136
28251
  if (result.summary) {
28137
28252
  let summary = result.summary.replace(/\n/g, " ").trim();
28138
28253
  if (summary.length > 200) summary = summary.slice(0, 200) + "...";
28139
- console.log(` ${chalk.yellow("Summary:")} ${summary}`);
28254
+ console.log(` ${chalk2.yellow("Summary:")} ${summary}`);
28140
28255
  }
28141
28256
  const chunk = (result.matchedChunks || []).find(
28142
28257
  (c) => c.chunkType !== "summary" && c.chunkType !== "first_prompt"
@@ -28145,16 +28260,16 @@ program.command("search <query>").description("Search your server for relevant s
28145
28260
  const label = chunk.chunkType === "assistant" ? "Discussed" : chunk.chunkType === "user_context" ? "Asked about" : chunk.chunkType === "tool_result" ? "Tool result" : "Context";
28146
28261
  let text = chunk.text.replace(/\n/g, " ").trim();
28147
28262
  if (text.length > 150) text = text.slice(0, 150) + "...";
28148
- console.log(` ${chalk.magenta(label + ":")} ${text}`);
28263
+ console.log(` ${chalk2.magenta(label + ":")} ${text}`);
28149
28264
  }
28150
28265
  {
28151
28266
  const rc = resumeCommandFor(result.sessionId);
28152
- if (rc) console.log(` ${chalk.green("Resume:")} ${rc}`);
28267
+ if (rc) console.log(` ${chalk2.green("Resume:")} ${rc}`);
28153
28268
  }
28154
28269
  console.log();
28155
28270
  }
28156
28271
  } catch (err) {
28157
- console.error(chalk.red("Error:"), err instanceof Error ? err.message : err);
28272
+ console.error(chalk2.red("Error:"), err instanceof Error ? err.message : err);
28158
28273
  process.exit(1);
28159
28274
  }
28160
28275
  });
@@ -28162,7 +28277,7 @@ program.command("status").description("Show your server's sync status and statis
28162
28277
  try {
28163
28278
  const status = await serverGet("/api/status");
28164
28279
  const sync = await serverGet("/api/status/sync");
28165
- console.log(chalk.bold("Chat-Recall Server Status"));
28280
+ console.log(chalk2.bold("Chat-Recall Server Status"));
28166
28281
  console.log();
28167
28282
  console.log(`Synced sessions: ${sync.sessions}`);
28168
28283
  console.log(`FTS5 chunks: ${status.totalChunks}`);
@@ -28174,34 +28289,34 @@ program.command("status").description("Show your server's sync status and statis
28174
28289
  const types = Object.entries(sync.sourceTypes).filter(([, n]) => Number(n) > 0);
28175
28290
  if (types.length > 0) {
28176
28291
  console.log();
28177
- console.log(chalk.bold("By source type:"));
28292
+ console.log(chalk2.bold("By source type:"));
28178
28293
  for (const [type, n] of types) console.log(` ${type}: ${n} items`);
28179
28294
  }
28180
28295
  const projects = Object.entries(status.projects || {}).sort((a, b) => b[1] - a[1]).slice(0, 10);
28181
28296
  if (projects.length > 0) {
28182
28297
  console.log();
28183
- console.log(chalk.bold("Top projects:"));
28298
+ console.log(chalk2.bold("Top projects:"));
28184
28299
  for (const [proj, n] of projects) console.log(` ${proj}: ${n} sessions`);
28185
28300
  }
28186
28301
  } catch (err) {
28187
- console.error(chalk.red("Error:"), err instanceof Error ? err.message : err);
28302
+ console.error(chalk2.red("Error:"), err instanceof Error ? err.message : err);
28188
28303
  process.exit(1);
28189
28304
  }
28190
28305
  });
28191
28306
  program.command("optimize").description("Deprecated: storage is server-side now, nothing to optimize locally").action(() => {
28192
- console.log(chalk.dim("Storage is server-side now; there is no local index to optimize."));
28193
- 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."));
28194
28309
  process.exit(0);
28195
28310
  });
28196
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) => {
28197
28312
  try {
28198
28313
  const soft = await serverGetSoft(`/api/conversations/${encodeURIComponent(sessionId)}?limit=0`);
28199
28314
  if (!soft.data || soft.data.messages.length === 0) {
28200
- console.log(chalk.yellow(soft.message || `Session not found: ${sessionId}`));
28315
+ console.log(chalk2.yellow(soft.message || `Session not found: ${sessionId}`));
28201
28316
  process.exit(soft.status === 404 ? 1 : 0);
28202
28317
  }
28203
28318
  const messagesList = soft.data.messages;
28204
- console.log(chalk.bold("Session:"), sessionId);
28319
+ console.log(chalk2.bold("Session:"), sessionId);
28205
28320
  console.log();
28206
28321
  const maxMessages = parseInt(options.messages, 10);
28207
28322
  const displayMessages = options.full ? messagesList : messagesList.slice(0, maxMessages);
@@ -28209,22 +28324,22 @@ program.command("show <session_id>").description("Show conversation content from
28209
28324
  let text = msg.content;
28210
28325
  if (!options.full && text.length > 1e3) text = text.slice(0, 1e3) + "...";
28211
28326
  if (msg.role === "user") {
28212
- console.log(`${chalk.bold.blue("User")} ${chalk.dim(`(line ${msg.line})`)}`);
28327
+ console.log(`${chalk2.bold.blue("User")} ${chalk2.dim(`(line ${msg.line})`)}`);
28213
28328
  } else if (msg.role === "assistant") {
28214
- console.log(`${chalk.bold.green("Assistant")} ${chalk.dim(`(line ${msg.line})`)}`);
28329
+ console.log(`${chalk2.bold.green("Assistant")} ${chalk2.dim(`(line ${msg.line})`)}`);
28215
28330
  } else {
28216
- console.log(chalk.bold.yellow(msg.role));
28331
+ console.log(chalk2.bold.yellow(msg.role));
28217
28332
  }
28218
28333
  console.log(text);
28219
28334
  console.log();
28220
28335
  }
28221
- 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.`));
28222
28337
  {
28223
28338
  const rc = resumeCommandFor(sessionId);
28224
- if (rc) console.log(chalk.dim(`Resume: ${rc}`));
28339
+ if (rc) console.log(chalk2.dim(`Resume: ${rc}`));
28225
28340
  }
28226
28341
  } catch (err) {
28227
- console.error(chalk.red("Error:"), err instanceof Error ? err.message : err);
28342
+ console.error(chalk2.red("Error:"), err instanceof Error ? err.message : err);
28228
28343
  process.exit(1);
28229
28344
  }
28230
28345
  });
@@ -28233,9 +28348,9 @@ memory.command("index").description("Collect local sessions and ship them to you
28233
28348
  try {
28234
28349
  const { syncSessions: syncSessions2 } = await Promise.resolve().then(() => (init_sync_client(), sync_client_exports));
28235
28350
  const r = await syncSessions2(options.force ? { useLedger: false } : {});
28236
- 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)` : ""}`));
28237
28352
  } catch (err) {
28238
- console.error(chalk.red("Error:"), err instanceof Error ? err.message : err);
28353
+ console.error(chalk2.red("Error:"), err instanceof Error ? err.message : err);
28239
28354
  process.exit(1);
28240
28355
  }
28241
28356
  });
@@ -28246,55 +28361,55 @@ memory.command("search <query>").description("Search across all memory types on
28246
28361
  const remote = await serverPost("/api/memory/search", { query, topK, sourceTypes });
28247
28362
  const results = remote.results;
28248
28363
  if (results.length === 0) {
28249
- console.log(chalk.yellow("No matching results found."));
28364
+ console.log(chalk2.yellow("No matching results found."));
28250
28365
  process.exit(0);
28251
28366
  }
28252
28367
  console.log();
28253
- console.log(`${chalk.bold("Memory search:")} "${query}"`);
28368
+ console.log(`${chalk2.bold("Memory search:")} "${query}"`);
28254
28369
  console.log();
28255
28370
  const tiers = tierAll(results);
28256
28371
  for (let i = 0; i < results.length; i++) {
28257
28372
  const r = results[i];
28258
28373
  const typeColor = {
28259
- session: chalk.blue,
28260
- plan: chalk.green,
28261
- task: chalk.yellow,
28262
- claude_md: chalk.magenta,
28263
- history: chalk.cyan,
28264
- paste: chalk.gray,
28265
- diary: chalk.redBright
28266
- }[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;
28267
28382
  const typeBadge = typeColor(`[${r.sourceType}]`);
28268
28383
  let title = (r.title || "").replace(/\n/g, " ").trim();
28269
28384
  if (title.length > 70) title = title.slice(0, 67) + "...";
28270
- console.log(`${chalk.bold.cyan(`#${i + 1}`)} ${typeBadge} ${title}`);
28385
+ console.log(`${chalk2.bold.cyan(`#${i + 1}`)} ${typeBadge} ${title}`);
28271
28386
  if (r.projectPath) {
28272
28387
  let pp = r.projectPath;
28273
28388
  if (pp.length > 50) pp = "..." + pp.slice(-47);
28274
- console.log(` ${chalk.dim("Project:")} ${pp}`);
28389
+ console.log(` ${chalk2.dim("Project:")} ${pp}`);
28275
28390
  }
28276
- const typeSuffix = r.chunkType ? ` ${chalk.dim("Type:")} ${r.chunkType}` : "";
28277
- 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}`);
28278
28393
  let preview = (r.text || "").replace(/\n/g, " ").trim();
28279
28394
  if (preview.length > 150) preview = preview.slice(0, 147) + "...";
28280
28395
  if (preview) console.log(` ${preview}`);
28281
28396
  if (r.sourceType === "session") {
28282
28397
  {
28283
28398
  const rc = resumeCommandFor(r.itemId);
28284
- if (rc) console.log(` ${chalk.green("Resume:")} ${rc}`);
28399
+ if (rc) console.log(` ${chalk2.green("Resume:")} ${rc}`);
28285
28400
  }
28286
28401
  }
28287
28402
  console.log();
28288
28403
  }
28289
28404
  } catch (err) {
28290
- console.error(chalk.red("Error:"), err instanceof Error ? err.message : err);
28405
+ console.error(chalk2.red("Error:"), err instanceof Error ? err.message : err);
28291
28406
  process.exit(1);
28292
28407
  }
28293
28408
  });
28294
28409
  memory.command("status").description("Show your server's memory statistics across all source types (requires login)").action(async () => {
28295
28410
  try {
28296
28411
  const status = await serverGet("/api/memory/status");
28297
- console.log(chalk.bold("Memory System Status"));
28412
+ console.log(chalk2.bold("Memory System Status"));
28298
28413
  console.log();
28299
28414
  console.log(`Total items: ${status.totalItems}`);
28300
28415
  console.log(`FTS5 chunks: ${status.totalChunks}`);
@@ -28302,7 +28417,7 @@ memory.command("status").description("Show your server's memory statistics acros
28302
28417
  const bySource = Object.entries(status.bySourceType || {});
28303
28418
  if (bySource.length > 0) {
28304
28419
  console.log();
28305
- console.log(chalk.bold("By source type:"));
28420
+ console.log(chalk2.bold("By source type:"));
28306
28421
  for (const [type, data] of bySource) {
28307
28422
  console.log(` ${type}: ${data.items} items, ${data.chunks} chunks`);
28308
28423
  }
@@ -28310,14 +28425,14 @@ memory.command("status").description("Show your server's memory statistics acros
28310
28425
  const byTool = Object.entries(status.bySourceAndTool || {});
28311
28426
  if (byTool.length > 0) {
28312
28427
  console.log();
28313
- console.log(chalk.bold("By source type and tool:"));
28428
+ console.log(chalk2.bold("By source type and tool:"));
28314
28429
  for (const [type, tools] of byTool) {
28315
28430
  const parts = Object.entries(tools).map(([t, n]) => `${t}: ${n}`).join(", ");
28316
28431
  console.log(` ${type}: ${parts}`);
28317
28432
  }
28318
28433
  }
28319
28434
  } catch (err) {
28320
- console.error(chalk.red("Error:"), err instanceof Error ? err.message : err);
28435
+ console.error(chalk2.red("Error:"), err instanceof Error ? err.message : err);
28321
28436
  process.exit(1);
28322
28437
  }
28323
28438
  });
@@ -28325,20 +28440,20 @@ memory.command("links <source_type> <item_id>").description("Show relationships
28325
28440
  try {
28326
28441
  const { links } = await serverGet(`/api/memory/links/${encodeURIComponent(sourceType)}/${encodeURIComponent(itemId)}`);
28327
28442
  if (links.length === 0) {
28328
- console.log(chalk.yellow("No links found."));
28443
+ console.log(chalk2.yellow("No links found."));
28329
28444
  return;
28330
28445
  }
28331
- console.log(chalk.bold(`Links for ${sourceType}:${itemId}`));
28446
+ console.log(chalk2.bold(`Links for ${sourceType}:${itemId}`));
28332
28447
  console.log();
28333
28448
  for (const link of links) {
28334
28449
  const direction = link.source_id === itemId ? "->" : "<-";
28335
28450
  const otherType = link.source_id === itemId ? link.target_type : link.source_type;
28336
28451
  const otherId = link.source_id === itemId ? link.target_id : link.source_id;
28337
28452
  const confidence = Math.round(link.confidence * 100);
28338
- 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}%)`);
28339
28454
  }
28340
28455
  } catch (err) {
28341
- console.error(chalk.red("Error:"), err instanceof Error ? err.message : err);
28456
+ console.error(chalk2.red("Error:"), err instanceof Error ? err.message : err);
28342
28457
  process.exit(1);
28343
28458
  }
28344
28459
  });
@@ -28350,27 +28465,27 @@ memory.command("wake-up").description("Generate wake-up context (high-importance
28350
28465
  identity = readFileSync49(identityFile, "utf-8").trim();
28351
28466
  }
28352
28467
  const lines = [
28353
- chalk.bold("# Wake-Up Context"),
28354
- 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"),
28355
28470
  "",
28356
- chalk.bold("## Identity"),
28471
+ chalk2.bold("## Identity"),
28357
28472
  identity,
28358
28473
  ""
28359
28474
  ];
28360
28475
  const qs = options.project ? `?project_filter=${encodeURIComponent(options.project)}` : "";
28361
28476
  const wake = await serverGet(`/api/memory/wake-up${qs}`);
28362
28477
  if (wake.highFacts.length > 0) {
28363
- lines.push(chalk.bold("## High-Importance Facts"));
28478
+ lines.push(chalk2.bold("## High-Importance Facts"));
28364
28479
  for (const fact of wake.highFacts) {
28365
28480
  lines.push(` [${fact.type}] ${fact.text}`);
28366
28481
  }
28367
28482
  lines.push("");
28368
28483
  }
28369
28484
  if (wake.kg.facts.length > 0) {
28370
- lines.push(chalk.bold("## Knowledge Graph"));
28485
+ lines.push(chalk2.bold("## Knowledge Graph"));
28371
28486
  const { entities, current_facts } = wake.kg.stats;
28372
28487
  if (entities !== void 0 || current_facts !== void 0) {
28373
- 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`));
28374
28489
  }
28375
28490
  for (const fact of wake.kg.facts) {
28376
28491
  lines.push(` ${fact.subject} \u2192 ${fact.predicate} \u2192 ${fact.object}`);
@@ -28379,32 +28494,75 @@ memory.command("wake-up").description("Generate wake-up context (high-importance
28379
28494
  }
28380
28495
  console.log(lines.join("\n"));
28381
28496
  } catch (err) {
28382
- console.error(chalk.red("Error:"), err instanceof Error ? err.message : err);
28497
+ console.error(chalk2.red("Error:"), err instanceof Error ? err.message : err);
28383
28498
  process.exit(1);
28384
28499
  }
28385
28500
  });
28386
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) => {
28387
28502
  if (!sessionId && !opts.latest) {
28388
- console.error(chalk.red("Pass a session id or --latest."));
28503
+ console.error(chalk2.red("Pass a session id or --latest."));
28389
28504
  process.exit(1);
28390
28505
  }
28391
28506
  const target = firstTarget();
28392
28507
  if (!target) {
28393
- 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."));
28394
28509
  return;
28395
28510
  }
28396
28511
  try {
28397
28512
  const { runEscalate: runEscalate2 } = await Promise.resolve().then(() => (init_escalate(), escalate_exports));
28398
28513
  await runEscalate2(
28399
- { 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)) },
28400
28515
  { sessionId, latest: opts.latest, project: opts.project, dryRun: opts.dryRun, cwd: process.cwd() }
28401
28516
  );
28402
28517
  } catch (err) {
28403
- 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;
28404
28562
  }
28405
28563
  });
28406
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) => {
28407
- const { existsSync: existsSync57, readFileSync: readFileSync50, statSync: statSync46 } = await import("fs");
28565
+ const { existsSync: existsSync57, readFileSync: readFileSync50, statSync: statSync47 } = await import("fs");
28408
28566
  const { execSync: execSync6 } = await import("child_process");
28409
28567
  const rows = [];
28410
28568
  const note = (ok, label, detail) => rows.push({ ok, label, detail });
@@ -28472,7 +28630,7 @@ program.command("doctor").description("Quick health check across login, server,
28472
28630
  note(false, "Credentials file", `missing \u2014 run \`chat-recall login <server-url>\``);
28473
28631
  } else {
28474
28632
  try {
28475
- const mode = statSync46(credFile).mode & 511;
28633
+ const mode = statSync47(credFile).mode & 511;
28476
28634
  const isWin = process.platform === "win32";
28477
28635
  const safe = isWin || (mode & 63) === 0;
28478
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"})`);
@@ -28610,11 +28768,11 @@ program.command("doctor").description("Quick health check across login, server,
28610
28768
  } else if (legacyPresent.length === 0) {
28611
28769
  note(true, "Purge legacy index", "nothing to remove");
28612
28770
  } else {
28613
- const { rmSync: rmSync9 } = await import("fs");
28771
+ const { rmSync: rmSync10 } = await import("fs");
28614
28772
  let removed = 0;
28615
28773
  for (const p of legacyPresent) {
28616
28774
  try {
28617
- rmSync9(p, { recursive: true, force: true });
28775
+ rmSync10(p, { recursive: true, force: true });
28618
28776
  removed++;
28619
28777
  } catch {
28620
28778
  }
@@ -28626,67 +28784,67 @@ program.command("doctor").description("Quick health check across login, server,
28626
28784
  } else {
28627
28785
  note(true, "Legacy local index", "none (clean)");
28628
28786
  }
28629
- console.log(chalk.bold("\nchat-recall doctor\n"));
28787
+ console.log(chalk2.bold("\nchat-recall doctor\n"));
28630
28788
  for (const r of rows) {
28631
- const icon = r.ok ? chalk.green("\u2713") : chalk.yellow("\u2022");
28632
- 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 || "")}`);
28633
28791
  }
28634
28792
  const failures = rows.filter((r) => !r.ok).length;
28635
28793
  console.log();
28636
28794
  if (failures === 0) {
28637
- console.log(chalk.green("All systems green."));
28795
+ console.log(chalk2.green("All systems green."));
28638
28796
  } else {
28639
- console.log(chalk.dim(`${failures} item${failures === 1 ? "" : "s"} need attention.`));
28797
+ console.log(chalk2.dim(`${failures} item${failures === 1 ? "" : "s"} need attention.`));
28640
28798
  }
28641
28799
  });
28642
28800
  var companions = program.command("companions").description("Manage companion tools (codeindex)");
28643
28801
  companions.command("status").description("Show whether codeindex is installed and what it provides").action(async () => {
28644
28802
  const { checkCodeindexStatus: checkCodeindexStatus2 } = await Promise.resolve().then(() => (init_companions(), companions_exports));
28645
28803
  const s = checkCodeindexStatus2();
28646
- console.log(chalk.bold("codeindex status"));
28804
+ console.log(chalk2.bold("codeindex status"));
28647
28805
  if (s.installed) {
28648
- console.log(` ${chalk.green("\u2713 installed")}`);
28806
+ console.log(` ${chalk2.green("\u2713 installed")}`);
28649
28807
  if (s.path) console.log(` path: ${s.path}`);
28650
28808
  if (s.size) console.log(` size: ${(s.size / 1024 / 1024).toFixed(1)} MB`);
28651
28809
  if (s.version) console.log(` version: ${s.version}`);
28652
28810
  } else {
28653
- console.log(` ${chalk.yellow("not installed")}`);
28811
+ console.log(` ${chalk2.yellow("not installed")}`);
28654
28812
  if (!s.prebuiltAvailable) {
28655
- 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")}`);
28656
28814
  } else {
28657
- 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}`)}`);
28658
28816
  }
28659
28817
  }
28660
28818
  console.log();
28661
- console.log(chalk.dim("codeindex provides code-level lookup as a separate MCP server:"));
28662
- console.log(chalk.dim(" find_symbol, find_callers, get_imports, plan_change,"));
28663
- 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/...)"));
28664
28822
  });
28665
28823
  companions.command("install").description("Install codeindex (downloads from munhq/codeindex GitHub release)").option("--force", "Re-download even if already installed").action(async (opts) => {
28666
28824
  const { installCodeindex: installCodeindex2, registerCodeindexMcp: registerCodeindexMcp2, CODEINDEX_BIN_PATH: CODEINDEX_BIN_PATH2 } = await Promise.resolve().then(() => (init_companions(), companions_exports));
28667
28825
  try {
28668
28826
  const result = await installCodeindex2({ force: opts.force });
28669
28827
  if (!result.prebuiltAvailable && !result.installed) {
28670
- console.log(chalk.yellow(`codeindex: ${result.unsupportedReason}`));
28671
- 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"));
28672
28830
  return;
28673
28831
  }
28674
28832
  if (result.installed) {
28675
28833
  const sizeMb = result.size ? `${(result.size / 1024 / 1024).toFixed(1)} MB` : "?";
28676
- console.log(chalk.green(`\u2713 codeindex installed (${sizeMb}) \u2192 ${result.path}`));
28834
+ console.log(chalk2.green(`\u2713 codeindex installed (${sizeMb}) \u2192 ${result.path}`));
28677
28835
  const mcpJsonPath = join60(homedir22(), ".mcp.json");
28678
28836
  const reg = registerCodeindexMcp2(mcpJsonPath, CODEINDEX_BIN_PATH2);
28679
- if (reg.added) console.log(chalk.dim(` Registered as MCP server in ${mcpJsonPath}`));
28680
- 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`));
28681
28839
  }
28682
28840
  } catch (err) {
28683
28841
  const msg = String(err);
28684
- console.error(chalk.red(`codeindex install failed: ${msg}`));
28842
+ console.error(chalk2.red(`codeindex install failed: ${msg}`));
28685
28843
  if (msg.includes("404")) {
28686
- console.error(chalk.dim(" The codeindex release is currently private. Either authenticate `gh`"));
28687
- 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"));
28688
28846
  } else {
28689
- 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."));
28690
28848
  }
28691
28849
  process.exit(1);
28692
28850
  }
@@ -28694,15 +28852,15 @@ companions.command("install").description("Install codeindex (downloads from mun
28694
28852
  companions.command("uninstall").description("Remove the codeindex binary chat-recall installed (does not touch your other tools)").action(async () => {
28695
28853
  const { uninstallCodeindex: uninstallCodeindex2, unregisterCodeindexMcp: unregisterCodeindexMcp2 } = await Promise.resolve().then(() => (init_companions(), companions_exports));
28696
28854
  const r = uninstallCodeindex2();
28697
- if (r.removed) console.log(chalk.green(`\u2713 Removed ${r.path}`));
28698
- 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}`));
28699
28857
  const mcpJsonPath = join60(homedir22(), ".mcp.json");
28700
28858
  const u = unregisterCodeindexMcp2(mcpJsonPath);
28701
- 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}`));
28702
28860
  });
28703
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) => {
28704
28862
  if (!opts.deep) {
28705
- 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."));
28706
28864
  return;
28707
28865
  }
28708
28866
  const { verifyAgainstServer: verifyAgainstServer2, verifyTargets: verifyTargets2 } = await Promise.resolve().then(() => (init_verify_deep(), verify_deep_exports));
@@ -28713,7 +28871,7 @@ program.command("verify").description("Check that the server holds everything th
28713
28871
  const { forceFullResync: forceFullResync2 } = await Promise.resolve().then(() => (init_verify_repair(), verify_repair_exports));
28714
28872
  const targets = verifyTargets2();
28715
28873
  if (targets.length === 0) {
28716
- 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."));
28717
28875
  process.exit(1);
28718
28876
  }
28719
28877
  const sinceMs = opts.sinceHours ? Date.now() - Number(opts.sinceHours) * 36e5 : 0;
@@ -28778,37 +28936,37 @@ program.command("verify").description("Check that the server holds everything th
28778
28936
  try {
28779
28937
  report = await verifyAgainstServer2(t.serverUrl, t.token, sinceMs, deps);
28780
28938
  } catch (e) {
28781
- 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}`));
28782
28940
  exitCode = 1;
28783
28941
  continue;
28784
28942
  }
28785
28943
  reports.push(report);
28786
28944
  if (opts.json) continue;
28787
- console.log(chalk.bold(`
28945
+ console.log(chalk2.bold(`
28788
28946
  ${t.serverUrl}`));
28789
28947
  console.log(` checked ${report.checked} \xB7 complete ${report.complete} \xB7 no archive ${report.missingArchive}`);
28790
28948
  if (report.pending.length > 0) {
28791
- 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)`));
28792
28950
  }
28793
28951
  if (report.stranded.length === 0) {
28794
- console.log(chalk.green(" \u2713 nothing stranded"));
28952
+ console.log(chalk2.green(" \u2713 nothing stranded"));
28795
28953
  } else {
28796
28954
  exitCode = 2;
28797
- 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:`));
28798
28956
  for (const f of report.stranded.slice(0, 25)) {
28799
28957
  console.log(` ${f.sessionId.slice(0, 8)} server short by ${String(f.deficit).padStart(9)} B ${(f.projectPath || "").slice(-44)}`);
28800
28958
  }
28801
- 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`));
28802
28960
  if (!opts.repair) {
28803
- 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."));
28804
28962
  }
28805
28963
  }
28806
28964
  if (opts.records) {
28807
28965
  const suspects = [...report.stranded, ...report.pending];
28808
28966
  if (suspects.length === 0) {
28809
- 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)"));
28810
28968
  } else {
28811
- console.log(chalk.bold(`
28969
+ console.log(chalk2.bold(`
28812
28970
  record-level diff (${suspects.length} session(s)):`));
28813
28971
  for (const f of suspects) {
28814
28972
  let serverIds;
@@ -28833,9 +28991,9 @@ ${t.serverUrl}`));
28833
28991
  }
28834
28992
  const missing = [...localIds].filter((u) => !serverIds.has(u)).length;
28835
28993
  const onlyServer = [...serverIds].filter((u) => !localIds.has(u)).length;
28836
- 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`);
28837
28995
  console.log(
28838
- ` ${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)`) : "")
28839
28997
  );
28840
28998
  if (missing > 0) exitCode = 2;
28841
28999
  }
@@ -28843,7 +29001,7 @@ ${t.serverUrl}`));
28843
29001
  }
28844
29002
  if (opts.repair && report.stranded.length > 0) {
28845
29003
  const n = forceFullResync2(t.serverUrl, report.stranded.map((f) => f.sessionId));
28846
- 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`));
28847
29005
  }
28848
29006
  }
28849
29007
  if (opts.json) console.log(JSON.stringify({ reports }, null, 2));
@@ -28851,19 +29009,19 @@ ${t.serverUrl}`));
28851
29009
  });
28852
29010
  var sources2 = program.command("sources").description("See and choose which AI-tool transcript folders get synced");
28853
29011
  function decisionBadge(d) {
28854
- if (d === "primary") return chalk.green("syncing") + chalk.dim(" (main)");
28855
- if (d === "approved") return chalk.green("syncing");
28856
- if (d === "declined") return chalk.dim("not syncing");
28857
- 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");
28858
29016
  }
28859
29017
  async function listSources() {
28860
29018
  const { discoverHomes: discoverHomes2 } = await Promise.resolve().then(() => (init_home_discovery(), home_discovery_exports));
28861
29019
  const { homeDecision: homeDecision2, grandfatherLegacyHomes: grandfatherLegacyHomes3 } = await Promise.resolve().then(() => (init_home_approval(), home_approval_exports));
28862
29020
  grandfatherLegacyHomes3();
28863
29021
  const homes = discoverHomes2();
28864
- console.log(chalk.bold("Transcript folders found on this machine"));
29022
+ console.log(chalk2.bold("Transcript folders found on this machine"));
28865
29023
  if (homes.length === 0) {
28866
- console.log(chalk.dim(" none \u2014 no AI tool transcripts detected"));
29024
+ console.log(chalk2.dim(" none \u2014 no AI tool transcripts detected"));
28867
29025
  return { pending: 0 };
28868
29026
  }
28869
29027
  let pending = 0;
@@ -28872,14 +29030,14 @@ async function listSources() {
28872
29030
  if (d === "pending") pending++;
28873
29031
  const count = h.sessions > 0 ? `${h.sessions} session${h.sessions === 1 ? "" : "s"}` : "\u2014";
28874
29032
  console.log(
28875
- ` ${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)") : "")
28876
29034
  );
28877
29035
  }
28878
29036
  if (pending > 0) {
28879
29037
  console.log();
28880
- console.log(chalk.yellow(` ${pending} folder(s) need a decision \u2014 they are NOT being synced yet.`));
28881
- console.log(chalk.dim(" chat-recall sources approve <path> start syncing it"));
28882
- 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)"));
28883
29041
  }
28884
29042
  return { pending };
28885
29043
  }
@@ -28892,74 +29050,74 @@ sources2.command("add <path>").description("Sync a transcript folder we did not
28892
29050
  const abs = normalizeHomePath2(path);
28893
29051
  const tool = identifyHome2(abs);
28894
29052
  if (!tool) {
28895
- console.error(chalk.red(`Not a transcript folder: ${abs}`));
28896
- console.error(chalk.dim(" Expected one of:"));
28897
- console.error(chalk.dim(" <dir>/projects/<project>/<uuid>.jsonl (Claude Code)"));
28898
- console.error(chalk.dim(" <dir>/sessions/YYYY/MM/DD/rollout-*.jsonl (Codex)"));
28899
- console.error(chalk.dim(" <dir>/tmp/<project>/chats/session-*.json (Gemini)"));
28900
- console.error(chalk.dim(" <dir>/brain/<id>/.system_generated/logs/* (Antigravity)"));
28901
- 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)"));
28902
29060
  process.exit(1);
28903
29061
  }
28904
29062
  if (!approveHome2(abs)) {
28905
- console.error(chalk.red("Could not write settings."));
29063
+ console.error(chalk2.red("Could not write settings."));
28906
29064
  process.exit(1);
28907
29065
  }
28908
- console.log(chalk.green(`\u2713 syncing ${tool} transcripts from ${abs}`));
28909
- 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."));
28910
29068
  });
28911
29069
  sources2.command("approve <path>").description("Start syncing a folder that was waiting for a decision").action(async (path) => {
28912
29070
  const { approveHome: approveHome2, normalizeHomePath: normalizeHomePath2 } = await Promise.resolve().then(() => (init_home_approval(), home_approval_exports));
28913
29071
  const abs = normalizeHomePath2(path);
28914
29072
  if (!approveHome2(abs)) {
28915
- console.error(chalk.red("Could not write settings."));
29073
+ console.error(chalk2.red("Could not write settings."));
28916
29074
  process.exit(1);
28917
29075
  }
28918
- console.log(chalk.green(`\u2713 now syncing ${abs}`));
29076
+ console.log(chalk2.green(`\u2713 now syncing ${abs}`));
28919
29077
  });
28920
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) => {
28921
29079
  const { declineHome: declineHome2, normalizeHomePath: normalizeHomePath2 } = await Promise.resolve().then(() => (init_home_approval(), home_approval_exports));
28922
29080
  const { identifyHome: identifyHome2, sessionIdsInHome: sessionIdsInHome2 } = await Promise.resolve().then(() => (init_home_discovery(), home_discovery_exports));
28923
29081
  const abs = normalizeHomePath2(path);
28924
29082
  if (!declineHome2(abs)) {
28925
- console.error(chalk.red("Could not write settings."));
29083
+ console.error(chalk2.red("Could not write settings."));
28926
29084
  process.exit(1);
28927
29085
  }
28928
- console.log(chalk.green(`\u2713 not syncing ${abs}`));
29086
+ console.log(chalk2.green(`\u2713 not syncing ${abs}`));
28929
29087
  if (!opts.deleteRemote) {
28930
- console.log(chalk.dim(" Sessions already uploaded from it stay on the server."));
28931
- 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`));
28932
29090
  return;
28933
29091
  }
28934
29092
  const tool = identifyHome2(abs);
28935
29093
  if (!tool) {
28936
- console.error(chalk.red(`Not a transcript folder: ${abs}`));
29094
+ console.error(chalk2.red(`Not a transcript folder: ${abs}`));
28937
29095
  process.exit(1);
28938
29096
  }
28939
29097
  const ids = sessionIdsInHome2(abs, tool);
28940
29098
  if (ids.length === 0) {
28941
- 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."));
28942
29100
  if (tool === "opencode") {
28943
- 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.)"));
28944
29102
  }
28945
29103
  return;
28946
29104
  }
28947
29105
  const targets = loadAllCredentials();
28948
29106
  if (targets.length === 0) {
28949
- 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."));
28950
29108
  process.exit(1);
28951
29109
  }
28952
29110
  if (!opts.yes) {
28953
29111
  console.log();
28954
- console.log(chalk.yellow(`About to DELETE ${ids.length} session(s) from ${targets.length} server(s).`));
28955
- console.log(chalk.yellow("This is irreversible \u2014 the transcripts stay on this machine, but the"));
28956
- 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."));
28957
29115
  const { createInterface: createInterface3 } = await import("node:readline/promises");
28958
29116
  const rl = createInterface3({ input: process.stdin, output: process.stdout });
28959
29117
  const answer = (await rl.question("Type the number of sessions to confirm: ")).trim();
28960
29118
  rl.close();
28961
29119
  if (answer !== String(ids.length)) {
28962
- console.log(chalk.dim("Cancelled \u2014 nothing deleted."));
29120
+ console.log(chalk2.dim("Cancelled \u2014 nothing deleted."));
28963
29121
  return;
28964
29122
  }
28965
29123
  }
@@ -28979,8 +29137,8 @@ sources2.command("decline <path>").description("Keep a folder out of sync (e.g.
28979
29137
  failed++;
28980
29138
  }
28981
29139
  }
28982
- const line = ` ${base2}: deleted ${deleted}` + (missing ? `, ${missing} were not there` : "") + (failed ? chalk.red(`, ${failed} FAILED`) : "");
28983
- 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));
28984
29142
  if (failed) process.exitCode = 1;
28985
29143
  }
28986
29144
  });
@@ -28988,30 +29146,30 @@ sources2.command("forget <path>").description("Undo a decision, so the folder is
28988
29146
  const { resetHomeDecision: resetHomeDecision2, normalizeHomePath: normalizeHomePath2 } = await Promise.resolve().then(() => (init_home_approval(), home_approval_exports));
28989
29147
  const abs = normalizeHomePath2(path);
28990
29148
  resetHomeDecision2(abs);
28991
- 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)`));
28992
29150
  });
28993
29151
  var detectors = program.command("detectors").description("Manage the optional external secret detectors (gitleaks, trufflehog)");
28994
29152
  detectors.command("status").description("Show which detectors are installed, pinned and verified").action(async () => {
28995
29153
  const { detectorStatus: detectorStatus2 } = await Promise.resolve().then(() => (init_detector_install(), detector_install_exports));
28996
29154
  const { externalScannersEnabled: externalScannersEnabled2 } = await Promise.resolve().then(() => (init_secret_scanner(), secret_scanner_exports));
28997
- console.log(chalk.bold("external secret detectors"));
29155
+ console.log(chalk2.bold("external secret detectors"));
28998
29156
  console.log(
28999
- 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`
29000
29158
  );
29001
29159
  if (process.env.CHAT_RECALL_DETECTOR_DIR) {
29002
- 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)")}`);
29003
29161
  }
29004
29162
  console.log();
29005
29163
  for (const d of detectorStatus2()) {
29006
- const label = `${d.name} ${chalk.dim(d.pinnedVersion)} ${chalk.dim(`[${d.license}]`)}`;
29007
- if (d.state === "ready") console.log(` ${chalk.green("\u2713")} ${label} \u2192 ${chalk.dim(d.path)}`);
29008
- else if (d.state === "configured") console.log(` ${chalk.green("\u2713")} ${label} \u2192 ${chalk.dim(d.path)} ${chalk.dim("(operator-supplied)")}`);
29009
- else if (d.state === "not-installed") console.log(` ${chalk.dim("\xB7")} ${label} \u2014 not installed`);
29010
- else if (!d.supported) console.log(` ${chalk.dim("\xB7")} ${label} \u2014 no build for this platform`);
29011
- 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}\``);
29012
29170
  }
29013
29171
  console.log();
29014
- 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."));
29015
29173
  });
29016
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) => {
29017
29175
  const { installDetector: installDetector2, DETECTOR_MANIFEST: DETECTOR_MANIFEST2 } = await Promise.resolve().then(() => (init_detector_install(), detector_install_exports));
@@ -29020,33 +29178,33 @@ detectors.command("install [name]").description("Download + verify a pinned dete
29020
29178
  let failed = false;
29021
29179
  for (const n of names) {
29022
29180
  if (!valid.includes(n)) {
29023
- 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(", ")}`));
29024
29182
  failed = true;
29025
29183
  continue;
29026
29184
  }
29027
29185
  try {
29028
29186
  const r = await installDetector2(n, { force: opts.force });
29029
- 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}`));
29030
- 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}`));
29031
29189
  } catch (err) {
29032
29190
  failed = true;
29033
- 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)}`));
29034
29192
  }
29035
29193
  }
29036
29194
  if (failed) process.exit(1);
29037
29195
  console.log();
29038
- console.log(chalk.dim("Enable them with CHAT_RECALL_EXTERNAL_SCANNERS=1. They enrich the findings"));
29039
- 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."));
29040
29198
  });
29041
29199
  detectors.command("remove [name]").description("Remove detectors chat-recall installed (never touches your own binaries)").action(async (name) => {
29042
29200
  const { removeDetector: removeDetector2, DETECTOR_MANIFEST: DETECTOR_MANIFEST2, managedDetectorPath: managedDetectorPath2 } = await Promise.resolve().then(() => (init_detector_install(), detector_install_exports));
29043
29201
  for (const n of name ? [name] : Object.keys(DETECTOR_MANIFEST2)) {
29044
29202
  if (!(n in DETECTOR_MANIFEST2)) {
29045
- console.error(chalk.red(`unknown detector "${n}"`));
29203
+ console.error(chalk2.red(`unknown detector "${n}"`));
29046
29204
  continue;
29047
29205
  }
29048
29206
  const removed = removeDetector2(n);
29049
- 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)}`));
29050
29208
  }
29051
29209
  });
29052
29210
  var code = program.command("code").description("Index a codebase with codeindex and ship findings/hotspots/actions to your server");
@@ -29055,22 +29213,22 @@ code.command("index [path]").description("Run codeindex on a repo (default: cwd)
29055
29213
  const target = requireTarget();
29056
29214
  const { collectCode: collectCode2 } = await Promise.resolve().then(() => (init_collector(), collector_exports));
29057
29215
  const workspace = resolve2(path || process.cwd());
29058
- console.log(chalk.bold(`code index ${workspace}`));
29216
+ console.log(chalk2.bold(`code index ${workspace}`));
29059
29217
  const result = await collectCode2({
29060
29218
  workspace,
29061
29219
  autoInstall: opts.install !== false,
29062
- log: (m) => console.log(chalk.dim(" \xB7 " + m))
29220
+ log: (m) => console.log(chalk2.dim(" \xB7 " + m))
29063
29221
  });
29064
29222
  const resp = await serverPost(
29065
29223
  "/api/code/index",
29066
29224
  result
29067
29225
  );
29068
- console.log(chalk.green("\u2713 synced"), chalk.dim(`\u2192 ${target.base}`));
29226
+ console.log(chalk2.green("\u2713 synced"), chalk2.dim(`\u2192 ${target.base}`));
29069
29227
  console.log(` project: ${resp.projectId}`);
29070
29228
  console.log(` health: ${result.project.health.score}/100`);
29071
29229
  console.log(` findings: ${resp.findings} hotspots: ${resp.hotspots} actions: ${resp.actions}`);
29072
29230
  } catch (err) {
29073
- 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);
29074
29232
  process.exit(1);
29075
29233
  }
29076
29234
  });
@@ -29078,17 +29236,17 @@ code.command("status").description("List code-indexed projects on your server").
29078
29236
  try {
29079
29237
  const { projects } = await serverGet("/api/code/projects");
29080
29238
  if (!projects.length) {
29081
- 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."));
29082
29240
  return;
29083
29241
  }
29084
- console.log(chalk.bold(`${projects.length} code project(s)`));
29242
+ console.log(chalk2.bold(`${projects.length} code project(s)`));
29085
29243
  for (const p of projects) {
29086
29244
  const when = new Date(p.lastIndexedAt).toISOString().slice(0, 16).replace("T", " ");
29087
- console.log(` ${chalk.bold(p.projectId)}${p.label ? chalk.cyan(` [${p.label}]`) : ""}`);
29088
- 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}`));
29089
29247
  }
29090
29248
  } catch (err) {
29091
- 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);
29092
29250
  process.exit(1);
29093
29251
  }
29094
29252
  });
@@ -29097,12 +29255,12 @@ code.command("show <project>").description("Show a project: health, findings sum
29097
29255
  const enc = encodeURIComponent(project);
29098
29256
  const p = await serverGet(`/api/code/projects/${enc}`);
29099
29257
  const { actions } = await serverGet(`/api/code/actions?project=${enc}&limit=12`);
29100
- console.log(chalk.bold(p.projectId), chalk.dim(p.rootPath));
29258
+ console.log(chalk2.bold(p.projectId), chalk2.dim(p.rootPath));
29101
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`);
29102
- console.log(chalk.bold("\n Top actions:"));
29103
- 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}`);
29104
29262
  } catch (err) {
29105
- 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);
29106
29264
  process.exit(1);
29107
29265
  }
29108
29266
  });
@@ -29111,18 +29269,18 @@ async function pushToolkitToServer() {
29111
29269
  try {
29112
29270
  const { syncIncremental: syncIncremental2, isSyncSkip: isSyncSkip2 } = await Promise.resolve().then(() => (init_sync_client(), sync_client_exports));
29113
29271
  const res = await syncIncremental2();
29114
- 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.`));
29115
29273
  } catch (err) {
29116
- 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})`));
29117
29275
  }
29118
29276
  }
29119
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) => {
29120
29278
  const { executeSyncAll: executeSyncAll2 } = await Promise.resolve().then(() => (init_toolkit_sync(), toolkit_sync_exports));
29121
29279
  const types = options.types ? options.types.split(",").map((s) => s.trim()).filter(Boolean) : void 0;
29122
29280
  const r = await executeSyncAll2(types);
29123
- for (const c of r.copied) console.log(chalk.green(` + ${c.type} ${c.name} \u2192 ${c.toTool}`) + chalk.dim(` ${c.path || ""}`));
29124
- for (const f of r.failed) console.log(chalk.red(` \u2717 ${f.type} ${f.name} \u2192 ${f.toTool}: ${f.error}`));
29125
- 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.`));
29126
29284
  if (r.copied.length > 0) await pushToolkitToServer();
29127
29285
  });
29128
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) => {
@@ -29131,7 +29289,7 @@ toolkit.command("pull").description("Install artifacts this device is missing, f
29131
29289
  const { hostname: hostname3 } = await import("node:os");
29132
29290
  const targets = loadAllCredentials2();
29133
29291
  if (targets.length === 0) {
29134
- 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.");
29135
29293
  process.exit(1);
29136
29294
  }
29137
29295
  const rows = [];
@@ -29145,7 +29303,7 @@ toolkit.command("pull").description("Install artifacts this device is missing, f
29145
29303
  const body = await res.json();
29146
29304
  for (const it of body.items || []) rows.push(it);
29147
29305
  } catch (err) {
29148
- 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})`));
29149
29307
  }
29150
29308
  }
29151
29309
  }
@@ -29160,41 +29318,40 @@ toolkit.command("pull").description("Install artifacts this device is missing, f
29160
29318
  const failed = report.outcomes.filter((o) => o.status === "failed");
29161
29319
  const skipped = report.outcomes.filter((o) => o.status === "skipped");
29162
29320
  for (const o of written) {
29163
- const note = o.rewrittenCommand ? chalk.cyan(` [using this machine's ${o.rewrittenCommand}]`) : "";
29164
- 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);
29165
29323
  }
29166
- for (const o of failed) console.log(chalk.red(` \u2717 ${o.type} ${o.name} \u2192 ${o.tool}: ${o.reason}`));
29167
- for (const o of skipped) console.log(chalk.yellow(` ~ ${o.type} ${o.name} \u2192 ${o.tool}: ${o.reason}`));
29168
- 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(
29169
29327
  `${options.dryRun ? "Would install" : "Installed"}: ${written.length} \xB7 already present: ${present.length} \xB7 failed: ${failed.length} \xB7 skipped: ${skipped.length}`
29170
29328
  ));
29171
- const envVars = [...new Set(written.flatMap((o) => o.needsEnv || []))].sort();
29172
- if (envVars.length) {
29329
+ const needs = collectEnvNeeds(written);
29330
+ if (needs.length) {
29173
29331
  console.log("");
29174
- console.log(chalk.yellow.bold("Set these environment variables \u2014 their values were never uploaded:"));
29175
- for (const v of envVars) console.log(` ${v}`);
29332
+ for (const line of renderEnvNeeds(needs, written.length)) console.log(line);
29176
29333
  }
29177
29334
  if (report.unsupported.length) {
29178
29335
  console.log("");
29179
- console.log(chalk.dim("Not installable from the server yet:"));
29336
+ console.log(chalk2.dim("Not installable from the server yet:"));
29180
29337
  for (const u of report.unsupported) {
29181
- 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}`));
29182
29339
  }
29183
- 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."));
29184
29341
  }
29185
29342
  });
29186
29343
  toolkit.command("drain").description("Process cross-tool sync intents queued from the web UI, now").action(async () => {
29187
29344
  const { drainSyncIntents: drainSyncIntents2 } = await Promise.resolve().then(() => (init_intent_drain(), intent_drain_exports));
29188
29345
  const r = await drainSyncIntents2({ verbose: true });
29189
- 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.`));
29190
29347
  if (r.done > 0) await pushToolkitToServer();
29191
29348
  });
29192
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) => {
29193
29350
  const { executeCopy: executeCopy2 } = await Promise.resolve().then(() => (init_toolkit_sync(), toolkit_sync_exports));
29194
29351
  const r = await executeCopy2(type, name, fromTool, toTool);
29195
- if (r.ok) console.log(chalk.green(`Copied to ${r.targetPath}`));
29352
+ if (r.ok) console.log(chalk2.green(`Copied to ${r.targetPath}`));
29196
29353
  else {
29197
- console.error(chalk.red(r.error || "failed"));
29354
+ console.error(chalk2.red(r.error || "failed"));
29198
29355
  process.exit(1);
29199
29356
  }
29200
29357
  });
@@ -29202,31 +29359,31 @@ program.command("shares").description("List the projects you share with your tea
29202
29359
  try {
29203
29360
  const { shares } = await serverGet("/api/shares");
29204
29361
  if (!shares.length) {
29205
- 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>"));
29206
29363
  return;
29207
29364
  }
29208
- console.log(chalk.bold(`Shared projects (${shares.length}):`));
29209
- 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)}`);
29210
29367
  } catch (e) {
29211
- console.error(chalk.red(e instanceof Error ? e.message : String(e)));
29368
+ console.error(chalk2.red(e instanceof Error ? e.message : String(e)));
29212
29369
  process.exit(1);
29213
29370
  }
29214
29371
  });
29215
29372
  program.command("share <project_id>").description("Share a project with your team (teammates can then see your work on it)").action(async (projectId) => {
29216
29373
  try {
29217
29374
  await serverPost("/api/shares", { project_id: projectId });
29218
- 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"));
29219
29376
  } catch (e) {
29220
- console.error(chalk.red(e instanceof Error ? e.message : String(e)));
29377
+ console.error(chalk2.red(e instanceof Error ? e.message : String(e)));
29221
29378
  process.exit(1);
29222
29379
  }
29223
29380
  });
29224
29381
  program.command("unshare <project_id>").description("Stop sharing a project with your team").action(async (projectId) => {
29225
29382
  try {
29226
29383
  const r = await serverDelete("/api/shares", { project_id: projectId });
29227
- 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));
29228
29385
  } catch (e) {
29229
- console.error(chalk.red(e instanceof Error ? e.message : String(e)));
29386
+ console.error(chalk2.red(e instanceof Error ? e.message : String(e)));
29230
29387
  process.exit(1);
29231
29388
  }
29232
29389
  });
@@ -29235,12 +29392,12 @@ tasks.command("list").description("List team tasks assigned to you").action(asyn
29235
29392
  try {
29236
29393
  const { tasks: tasks2 } = await serverGet("/api/tasks?assignee=@me");
29237
29394
  if (!tasks2.length) {
29238
- console.log(chalk.gray("No tasks assigned to you."));
29395
+ console.log(chalk2.gray("No tasks assigned to you."));
29239
29396
  return;
29240
29397
  }
29241
- 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) : ""}`);
29242
29399
  } catch (e) {
29243
- console.error(chalk.red(e instanceof Error ? e.message : String(e)));
29400
+ console.error(chalk2.red(e instanceof Error ? e.message : String(e)));
29244
29401
  process.exit(1);
29245
29402
  }
29246
29403
  });
@@ -29253,7 +29410,7 @@ tasks.command("pull [dir]").description("Write TEAM_TASKS.md for your tasks in t
29253
29410
  const { join: join61 } = await import("node:path");
29254
29411
  const file = join61(cwd, "TEAM_TASKS.md");
29255
29412
  if (!opts.force && existsSync57(file) && parseTeamTasksFile2(readFileSync50(file, "utf8")).length > 0) {
29256
- 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.");
29257
29414
  process.exit(1);
29258
29415
  }
29259
29416
  const resolved = resolveProjectId2(cwd);
@@ -29261,9 +29418,9 @@ tasks.command("pull [dir]").description("Write TEAM_TASKS.md for your tasks in t
29261
29418
  const { tasks: tasks2 } = await serverGet("/api/tasks?assignee=@me");
29262
29419
  const mine = tasks2.filter((t) => !pid || !t.projectId || t.projectId === pid);
29263
29420
  writeFileSync22(file, renderTeamTasksMd2(mine));
29264
- 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"));
29265
29422
  } catch (e) {
29266
- console.error(chalk.red(e instanceof Error ? e.message : String(e)));
29423
+ console.error(chalk2.red(e instanceof Error ? e.message : String(e)));
29267
29424
  process.exit(1);
29268
29425
  }
29269
29426
  });
@@ -29275,7 +29432,7 @@ tasks.command("push [dir]").description("Push TEAM_TASKS.md status edits back to
29275
29432
  const { join: join61 } = await import("node:path");
29276
29433
  const file = join61(cwd, "TEAM_TASKS.md");
29277
29434
  if (!existsSync57(file)) {
29278
- 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");
29279
29436
  process.exit(1);
29280
29437
  }
29281
29438
  const edits = parseTeamTasksFile2(readFileSync50(file, "utf8"));
@@ -29284,9 +29441,9 @@ tasks.command("push [dir]").description("Push TEAM_TASKS.md status edits back to
29284
29441
  await serverPatch(`/api/tasks/${encodeURIComponent(e.id)}`, { status: e.intent });
29285
29442
  n++;
29286
29443
  }
29287
- 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"));
29288
29445
  } catch (e) {
29289
- console.error(chalk.red(e instanceof Error ? e.message : String(e)));
29446
+ console.error(chalk2.red(e instanceof Error ? e.message : String(e)));
29290
29447
  process.exit(1);
29291
29448
  }
29292
29449
  });
@@ -29297,12 +29454,12 @@ async function runTeam(label, fn) {
29297
29454
  await fn();
29298
29455
  } catch (err) {
29299
29456
  if (err instanceof TeamConfigError2) {
29300
- console.error(chalk.red(`${label}: ${err.message}`));
29457
+ console.error(chalk2.red(`${label}: ${err.message}`));
29301
29458
  } else if (err instanceof TeamAuthError2) {
29302
- console.error(chalk.red(`${label}: auth failed \u2014 ${err.message}`));
29303
- 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."));
29304
29461
  } else if (err instanceof TeamHttpError2) {
29305
- console.error(chalk.red(`${label}: ${err.message}`));
29462
+ console.error(chalk2.red(`${label}: ${err.message}`));
29306
29463
  } else {
29307
29464
  throw err;
29308
29465
  }
@@ -29312,76 +29469,76 @@ async function runTeam(label, fn) {
29312
29469
  team.command("whoami").description("Show the user + team memberships the server sees for your token").action(async () => runTeam("team whoami", async () => {
29313
29470
  const { teamMe: teamMe2 } = await Promise.resolve().then(() => (init_team_client(), team_client_exports));
29314
29471
  const me = await teamMe2();
29315
- 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})`));
29316
29473
  if (me.memberships.length === 0) {
29317
- 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>`"));
29318
29475
  return;
29319
29476
  }
29320
29477
  for (const m of me.memberships) {
29321
- const role = m.role === "owner" ? chalk.yellow(m.role) : chalk.dim(m.role);
29322
- 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)}`);
29323
29480
  }
29324
29481
  }));
29325
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 () => {
29326
29483
  const { teamCreate: teamCreate2 } = await Promise.resolve().then(() => (init_team_client(), team_client_exports));
29327
29484
  const t = await teamCreate2(name);
29328
- console.log(chalk.green(`\u2713 Team created: ${chalk.bold(t.name)}`));
29329
- console.log(chalk.dim(` id: ${t.id}`));
29330
- 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`));
29331
29488
  }));
29332
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 () => {
29333
29490
  const { teamInvite: teamInvite2 } = await Promise.resolve().then(() => (init_team_client(), team_client_exports));
29334
29491
  const r = await teamInvite2(opts.email);
29335
- console.log(chalk.bold("Invite token (copy now \u2014 shown once):"));
29336
- console.log(" " + chalk.cyan(r.inviteToken));
29337
- 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}`));
29338
29495
  console.log();
29339
- console.log(chalk.dim("Recipient runs: chat-recall team join <token>"));
29496
+ console.log(chalk2.dim("Recipient runs: chat-recall team join <token>"));
29340
29497
  }));
29341
29498
  team.command("join <invite-token>").description("Accept a team invite. Stores team id locally.").action(async (inviteToken) => runTeam("team join", async () => {
29342
29499
  const { teamJoin: teamJoin2 } = await Promise.resolve().then(() => (init_team_client(), team_client_exports));
29343
29500
  const t = await teamJoin2(inviteToken);
29344
- console.log(chalk.green(`\u2713 Joined team: ${chalk.bold(t.name)}`));
29345
- console.log(chalk.dim(` id: ${t.id}`));
29346
- 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."));
29347
29504
  }));
29348
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 () => {
29349
29506
  const { teamPull: teamPull2 } = await Promise.resolve().then(() => (init_team_client(), team_client_exports));
29350
29507
  const r = await teamPull2();
29351
29508
  if (r.pulled.length === 0 && r.removed.length === 0) {
29352
- console.log(chalk.dim("Up to date."));
29509
+ console.log(chalk2.dim("Up to date."));
29353
29510
  return;
29354
29511
  }
29355
29512
  for (const a of r.pulled) {
29356
- 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 + ")")}`);
29357
29514
  }
29358
29515
  for (const id of r.removed) {
29359
- console.log(` ${chalk.red("-")} ${chalk.dim(id + " (revoked)")}`);
29516
+ console.log(` ${chalk2.red("-")} ${chalk2.dim(id + " (revoked)")}`);
29360
29517
  }
29361
29518
  if (opts.dryRun) {
29362
- 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)`));
29363
29520
  return;
29364
29521
  }
29365
29522
  const { mergePullResult: mergePullResult2 } = await Promise.resolve().then(() => (init_team_merge(), team_merge_exports));
29366
29523
  const m = await mergePullResult2({ pulled: r.pulled, removed: r.removed });
29367
29524
  console.log();
29368
- if (m.written.length) console.log(chalk.green(`\u2713 Wrote ${m.written.length} file${m.written.length === 1 ? "" : "s"}`));
29369
- if (m.skipped.length) console.log(chalk.dim(` Skipped ${m.skipped.length} (unchanged or no target tool)`));
29370
- 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"}`));
29371
29528
  for (const f of m.failures) {
29372
- console.log(chalk.red(` ! ${f.path}: ${f.error}`));
29529
+ console.log(chalk2.red(` ! ${f.path}: ${f.error}`));
29373
29530
  }
29374
- console.log(chalk.dim(`Watermark: ${r.serverNow}`));
29531
+ console.log(chalk2.dim(`Watermark: ${r.serverNow}`));
29375
29532
  }));
29376
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 () => {
29377
29534
  const validTypes = ["skill", "command", "agent", "mcp", "plan", "plugin", "instructions", "hook"];
29378
29535
  if (!validTypes.includes(type)) {
29379
- 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(", ")}`));
29380
29537
  process.exit(1);
29381
29538
  }
29382
29539
  const validTools = ["claude", "gemini", "opencode", "codex", "agy", "cursor", "cross_tool"];
29383
29540
  if (!validTools.includes(opts.tool)) {
29384
- 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(", ")}`));
29385
29542
  process.exit(1);
29386
29543
  }
29387
29544
  const { readFileSync: readFileSync50 } = await import("fs");
@@ -29394,32 +29551,32 @@ team.command("publish <type> <name> <file>").description("Publish a local file a
29394
29551
  body,
29395
29552
  pinnedTo: opts.pinnedTo
29396
29553
  });
29397
- console.log(chalk.green(`\u2713 Published ${chalk.bold(type + "/" + name)} v${a.version}`));
29398
- console.log(chalk.dim(` id: ${a.id}`));
29399
- 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}`));
29400
29557
  }));
29401
29558
  team.command("list").description("List artifacts in the team library (metadata only, no bodies)").action(async () => runTeam("team list", async () => {
29402
29559
  const { teamList: teamList2 } = await Promise.resolve().then(() => (init_team_client(), team_client_exports));
29403
29560
  const items = await teamList2();
29404
29561
  if (items.length === 0) {
29405
- 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>`."));
29406
29563
  return;
29407
29564
  }
29408
29565
  for (const a of items) {
29409
- const pinned = a.pinnedTo ? chalk.dim(` pinned=${a.pinnedTo}`) : "";
29410
- 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}`);
29411
29568
  }
29412
29569
  }));
29413
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 () => {
29414
29571
  const { teamRevoke: teamRevoke2 } = await Promise.resolve().then(() => (init_team_client(), team_client_exports));
29415
29572
  const r = await teamRevoke2(artifactId);
29416
- 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})`));
29417
29574
  }));
29418
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 () => {
29419
29576
  const { teamLeave: teamLeave2 } = await Promise.resolve().then(() => (init_team_client(), team_client_exports));
29420
29577
  await teamLeave2();
29421
- console.log(chalk.green("\u2713 Local team config cleared."));
29422
- 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."));
29423
29580
  }));
29424
29581
  var vault = program.command("vault").description("Encrypted multi-device chat backup (E2EE \u2014 server cannot decrypt)");
29425
29582
  async function runVault(label, fn) {
@@ -29427,9 +29584,9 @@ async function runVault(label, fn) {
29427
29584
  try {
29428
29585
  await fn();
29429
29586
  } catch (err) {
29430
- if (err instanceof VaultConfigError2) console.error(chalk.red(`${label}: ${err.message}`));
29431
- else if (err instanceof VaultAuthError2) console.error(chalk.red(`${label}: auth failed \u2014 ${err.message}`));
29432
- 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}`));
29433
29590
  else throw err;
29434
29591
  process.exit(1);
29435
29592
  }
@@ -29439,7 +29596,7 @@ async function resolvePassphrase(opts) {
29439
29596
  if (opts.envVar) {
29440
29597
  const v = process.env[opts.envVar];
29441
29598
  if (v) return v;
29442
- console.error(chalk.red(`Env var ${opts.envVar} is not set.`));
29599
+ console.error(chalk2.red(`Env var ${opts.envVar} is not set.`));
29443
29600
  process.exit(1);
29444
29601
  }
29445
29602
  if (!opts.noKeyring) {
@@ -29476,49 +29633,49 @@ vault.command("enable").description("Set up the Vault on this device. Generates
29476
29633
  r = await vaultEnableWithRemote2(passphrase, { baseUrl: cred.serverUrl, token: cred.token });
29477
29634
  } catch (err) {
29478
29635
  if (err instanceof VaultPassphraseMismatchError2) {
29479
- console.error(chalk.red(`vault enable: ${err.message}`));
29636
+ console.error(chalk2.red(`vault enable: ${err.message}`));
29480
29637
  process.exit(1);
29481
29638
  }
29482
29639
  throw err;
29483
29640
  }
29484
29641
  }
29485
- console.log(chalk.green("\u2713 Vault enabled on this device."));
29486
- console.log(chalk.dim(` keyId: ${r.keyId}`));
29487
- 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)") : ""));
29488
29645
  if (opts.keyring === false) {
29489
- 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."));
29490
29647
  } else {
29491
29648
  const { keyringSet: keyringSet2, probeKeyring: probeKeyring2 } = await Promise.resolve().then(() => (init_keyring(), keyring_exports));
29492
29649
  try {
29493
29650
  keyringSet2(passphrase);
29494
- 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.`));
29495
29652
  } catch (err) {
29496
- console.log(chalk.yellow(` keyring: unavailable \u2014 ${err instanceof Error ? err.message : err}`));
29497
- 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."));
29498
29655
  }
29499
29656
  }
29500
29657
  console.log();
29501
29658
  if (r.saltSource === "server") {
29502
- 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."));
29503
29660
  } else {
29504
- console.log(chalk.yellow("To set up another device, run there:"));
29661
+ console.log(chalk2.yellow("To set up another device, run there:"));
29505
29662
  console.log(" chat-recall vault enable");
29506
- 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)"));
29507
29664
  }
29508
- 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."));
29509
29666
  }));
29510
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 () => {
29511
29668
  const passphrase = await resolvePassphrase({ passphrase: opts.passphrase, envVar: opts.passphraseEnv });
29512
29669
  const { vaultSync: vaultSync2 } = await Promise.resolve().then(() => (init_vault_client(), vault_client_exports));
29513
29670
  const r = await vaultSync2(passphrase);
29514
29671
  if (r.uploaded.length === 0 && r.skipped.length === 0 && r.failures.length === 0) {
29515
- console.log(chalk.dim("No chat sources found."));
29672
+ console.log(chalk2.dim("No chat sources found."));
29516
29673
  return;
29517
29674
  }
29518
- if (r.uploaded.length) console.log(chalk.green(`\u2713 Uploaded ${r.uploaded.length} session${r.uploaded.length === 1 ? "" : "s"}`));
29519
- 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)`));
29520
29677
  for (const f of r.failures) {
29521
- console.log(chalk.red(` ! ${f.tool}/${f.sessionId}: ${f.error}`));
29678
+ console.log(chalk2.red(` ! ${f.tool}/${f.sessionId}: ${f.error}`));
29522
29679
  }
29523
29680
  }));
29524
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 () => {
@@ -29526,13 +29683,13 @@ vault.command("restore").description("Pull encrypted blobs from the server, decr
29526
29683
  const { vaultRestore: vaultRestore2 } = await Promise.resolve().then(() => (init_vault_client(), vault_client_exports));
29527
29684
  const r = await vaultRestore2(passphrase, { since: opts.since ? Number(opts.since) : void 0 });
29528
29685
  if (r.restored.length === 0 && r.skipped.length === 0 && r.failures.length === 0) {
29529
- console.log(chalk.dim("No blobs to restore."));
29686
+ console.log(chalk2.dim("No blobs to restore."));
29530
29687
  return;
29531
29688
  }
29532
- if (r.restored.length) console.log(chalk.green(`\u2713 Restored ${r.restored.length} session${r.restored.length === 1 ? "" : "s"}`));
29533
- 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)`));
29534
29691
  for (const f of r.failures) {
29535
- console.log(chalk.red(` ! ${f.tool}/${f.sessionId}: ${f.error}`));
29692
+ console.log(chalk2.red(` ! ${f.tool}/${f.sessionId}: ${f.error}`));
29536
29693
  }
29537
29694
  }));
29538
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 () => {
@@ -29542,8 +29699,8 @@ vault.command("status").description("Show whether the Vault is enabled, salt fin
29542
29699
  const probe = probeKeyring2();
29543
29700
  const reportKeyring = () => {
29544
29701
  if (!probe.available) {
29545
- console.log(chalk.yellow(` keyring: unavailable (${probe.backend}) \u2014 cross-device artifacts will not apply on this machine`));
29546
- 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}`));
29547
29704
  return;
29548
29705
  }
29549
29706
  let stored = false;
@@ -29552,27 +29709,27 @@ vault.command("status").description("Show whether the Vault is enabled, salt fin
29552
29709
  } catch {
29553
29710
  stored = false;
29554
29711
  }
29555
- 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`));
29556
29713
  };
29557
29714
  if (!s.enabled) {
29558
- console.log(chalk.dim("Vault: disabled. Run `chat-recall vault enable`."));
29715
+ console.log(chalk2.dim("Vault: disabled. Run `chat-recall vault enable`."));
29559
29716
  reportKeyring();
29560
29717
  return;
29561
29718
  }
29562
- console.log(chalk.green("Vault: enabled"));
29563
- console.log(chalk.dim(` keyId: ${s.keyId ?? "(unknown \u2014 re-enable)"}`));
29564
- console.log(chalk.dim(` salt: ${s.saltHex ? s.saltHex.slice(0, 16) + "\u2026" : "(missing)"}`));
29565
- console.log(chalk.dim(` lastSyncAt: ${s.lastSyncAt ? new Date(s.lastSyncAt).toISOString() : "never"}`));
29566
- console.log(chalk.dim(` syncTools: ${s.syncTools.join(", ")}`));
29567
- 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)"}`));
29568
29725
  reportKeyring();
29569
29726
  }));
29570
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 () => {
29571
29728
  const { keyringDelete: keyringDelete2 } = await Promise.resolve().then(() => (init_keyring(), keyring_exports));
29572
- 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."));
29573
29730
  }));
29574
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) => {
29575
- 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");
29576
29733
  const { fileURLToPath: fileURLToPath6 } = await import("url");
29577
29734
  const here = fileURLToPath6(new URL(".", import.meta.url));
29578
29735
  const findHook = (name) => {
@@ -29587,7 +29744,7 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
29587
29744
  const sourceEscalateHook = findHook("chat_recall_escalate_hook.sh");
29588
29745
  const sourceWakeupHook = findHook("chat_recall_wakeup_hook.sh");
29589
29746
  if (!sourceSaveHook) {
29590
- 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."));
29591
29748
  process.exit(1);
29592
29749
  }
29593
29750
  const hooksDir = getHooksDir();
@@ -29614,8 +29771,8 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
29614
29771
  if (!c.hooks || typeof c.hooks !== "object") c.hooks = {};
29615
29772
  return c;
29616
29773
  } catch (err) {
29617
- console.error(chalk.red(`Could not parse ${file}: ${err}`));
29618
- 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."));
29619
29776
  process.exit(1);
29620
29777
  }
29621
29778
  };
@@ -29639,23 +29796,23 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
29639
29796
  if (removed === 0 && !existsSync57(hooksJson)) continue;
29640
29797
  writeFileSync22(hooksJson, JSON.stringify(config2, null, 2) + "\n");
29641
29798
  total += removed;
29642
- 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}`));
29643
29800
  }
29644
- if (total === 0) console.log(chalk.dim("No chat-recall hook entries were registered."));
29645
- 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.)`));
29646
29803
  return;
29647
29804
  }
29648
29805
  if (process.platform === "win32") {
29649
- console.log(chalk.yellow("Hooks are not installed on Windows."));
29650
- console.log(chalk.dim(" They are POSIX shell scripts, and Claude Code runs hook commands through"));
29651
- console.log(chalk.dim(" cmd.exe, which cannot execute them. Registering them would put an error on"));
29652
- console.log(chalk.dim(" every turn instead of saving anything."));
29653
- console.log(chalk.dim(""));
29654
- console.log(chalk.dim(" Everything else works: indexing, sync, search and the MCP server are"));
29655
- console.log(chalk.dim(" unaffected. Hooks only add automatic fact-saving and the wake-up bundle,"));
29656
- console.log(chalk.dim(" and you can get the same context by calling recall_wake_up from the agent."));
29657
- console.log(chalk.dim(""));
29658
- 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."));
29659
29816
  return;
29660
29817
  }
29661
29818
  mkdirSync20(hooksDir, { recursive: true });
@@ -29705,35 +29862,35 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
29705
29862
  mkdirSync20(dirname27(hooksJson), { recursive: true });
29706
29863
  writeFileSync22(hooksJson, JSON.stringify(config2, null, 2) + "\n");
29707
29864
  }
29708
- const saveSz = statSync46(installedSaveHook).size;
29709
- 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)`));
29710
29867
  if (installResume) {
29711
- const resumeSz = statSync46(installedResumeHook).size;
29712
- 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)`));
29713
29870
  }
29714
29871
  if (installEscalate) {
29715
- const escalateSz = statSync46(installedEscalateHook).size;
29716
- 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)`));
29717
29874
  }
29718
29875
  if (installWakeup) {
29719
- const wakeupSz = statSync46(installedWakeupHook).size;
29720
- 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)`));
29721
29878
  for (const f of wakeupSkipped) {
29722
- 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)`));
29723
29880
  }
29724
29881
  }
29725
- console.log(chalk.dim(` scripts: ${hooksDir}`));
29882
+ console.log(chalk2.dim(` scripts: ${hooksDir}`));
29726
29883
  for (const [i, f] of hookConfigFiles.entries()) {
29727
- console.log(chalk.dim(` ${i === 0 ? "config: " : " "} ${f}`));
29884
+ console.log(chalk2.dim(` ${i === 0 ? "config: " : " "} ${f}`));
29728
29885
  }
29729
- 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" : ""}`));
29730
29887
  console.log();
29731
- 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."));
29732
29889
  if (!installResume) {
29733
- 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)"));
29734
29891
  }
29735
29892
  if (!installEscalate) {
29736
- console.log(chalk.dim("(--no-escalate passed \u2014 SessionEnd hook skipped)"));
29893
+ console.log(chalk2.dim("(--no-escalate passed \u2014 SessionEnd hook skipped)"));
29737
29894
  }
29738
29895
  });
29739
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) => {
@@ -29749,12 +29906,12 @@ program.command("dossier <project>").description("Generate a project dossier (ov
29749
29906
  const md = dossier.markdown;
29750
29907
  if (options.out) {
29751
29908
  writeFileSync21(options.out, md);
29752
- 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)`));
29753
29910
  } else {
29754
29911
  console.log(md);
29755
29912
  }
29756
29913
  } catch (err) {
29757
- console.error(chalk.red("Error:"), err instanceof Error ? err.message : err);
29914
+ console.error(chalk2.red("Error:"), err instanceof Error ? err.message : err);
29758
29915
  process.exit(1);
29759
29916
  }
29760
29917
  });
@@ -29767,17 +29924,17 @@ program.command("watch").description("Run the live indexer daemon (watches all A
29767
29924
  try {
29768
29925
  const { installService: installService2, isServiceRunning: isServiceRunning2, platformName: platformName2 } = await Promise.resolve().then(() => (init_service_installer(), service_installer_exports));
29769
29926
  if (isServiceRunning2()) {
29770
- 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()}).`));
29771
29928
  return;
29772
29929
  }
29773
29930
  const paths = installService2();
29774
- console.log(chalk.green(`\u2713 chat-recall-watch service installed and started (${platformName2()}).`));
29775
- if (paths.definitionPath) console.log(chalk.dim(` unit: ${paths.definitionPath}`));
29776
- 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\``));
29777
29934
  } catch (err) {
29778
29935
  const se = err;
29779
- console.error(chalk.red(se.message || String(err)));
29780
- 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}`));
29781
29938
  process.exit(1);
29782
29939
  }
29783
29940
  return;
@@ -29795,7 +29952,7 @@ program.command("watch").description("Run the live indexer daemon (watches all A
29795
29952
  lastErr = err;
29796
29953
  }
29797
29954
  }
29798
- 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);
29799
29956
  process.exit(1);
29800
29957
  });
29801
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) => {
@@ -29804,25 +29961,25 @@ program.command("service <action>").description("Manage the per-user background
29804
29961
  if (action === "install") {
29805
29962
  const wasRunning = isServiceRunning2();
29806
29963
  const paths = installService2();
29807
- 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()}).`));
29808
- if (paths.definitionPath) console.log(chalk.dim(` unit: ${paths.definitionPath}`));
29809
- 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}`));
29810
29967
  } else if (action === "uninstall") {
29811
29968
  const removed = uninstallService2();
29812
- if (removed) console.log(chalk.green(`\u2713 chat-recall-watch service removed (${platformName2()}).`));
29813
- 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."));
29814
29971
  } else if (action === "status") {
29815
29972
  const running = isServiceRunning2();
29816
- console.log(`chat-recall-watch service (${platformName2()}): ${running ? chalk.green("running") : chalk.yellow("not running")}`);
29817
- 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`"));
29818
29975
  } else {
29819
- 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"));
29820
29977
  process.exit(1);
29821
29978
  }
29822
29979
  } catch (err) {
29823
29980
  const se = err;
29824
- console.error(chalk.red(se.message || String(err)));
29825
- 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}`));
29826
29983
  process.exit(1);
29827
29984
  }
29828
29985
  });
@@ -29843,7 +30000,7 @@ async function runLogin(serverUrl, opts) {
29843
30000
  if (opts.token) {
29844
30001
  const token = opts.token.trim();
29845
30002
  if (/[^\x21-\x7e]/.test(token)) {
29846
- 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."));
29847
30004
  return failLogin(opts, 'the token contains non-ASCII characters \u2014 this looks like a masked/truncated copy (e.g. "ct_12345678\u2026")');
29848
30005
  }
29849
30006
  const { probeServer: identifyServer, probeOk: identified, probeAdvice: identifyAdvice } = await Promise.resolve().then(() => (init_server_probe(), server_probe_exports));
@@ -29852,7 +30009,7 @@ async function runLogin(serverUrl, opts) {
29852
30009
  const check = await verifyToken(token);
29853
30010
  if (!check.ok) {
29854
30011
  if (check.status === 401 || check.status === 403) {
29855
- 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."));
29856
30013
  return failLogin(opts, `${base2} rejected the token (HTTP ${check.status})`);
29857
30014
  }
29858
30015
  if (check.status !== void 0 && check.status >= 500) {
@@ -29864,12 +30021,12 @@ async function runLogin(serverUrl, opts) {
29864
30021
  return failLogin(opts, `could not verify the token against ${base2}: ${check.error || `HTTP ${check.status}`}`);
29865
30022
  }
29866
30023
  saveCredentials2({ serverUrl, token });
29867
- 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)`));
29868
30025
  return;
29869
30026
  }
29870
30027
  const existing = loadAllCredentials2().find((t) => t.serverUrl.replace(/\/+$/, "") === base2);
29871
30028
  if (existing && (await verifyToken(existing.token)).ok) {
29872
- 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)`));
29873
30030
  return;
29874
30031
  }
29875
30032
  try {
@@ -29879,14 +30036,14 @@ async function runLogin(serverUrl, opts) {
29879
30036
  const probe = await fetch(`${base2}/api/status`, { signal: AbortSignal.timeout(8e3) });
29880
30037
  if (probe.status === 200) {
29881
30038
  saveCredentials2({ serverUrl, token: "" });
29882
- 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)`));
29883
30040
  return;
29884
30041
  }
29885
30042
  }
29886
30043
  } catch {
29887
30044
  }
29888
30045
  if (opts.check) {
29889
- console.error(chalk.dim(`Not connected to ${serverUrl}.`));
30046
+ console.error(chalk2.dim(`Not connected to ${serverUrl}.`));
29890
30047
  process.exit(1);
29891
30048
  }
29892
30049
  try {
@@ -29914,7 +30071,7 @@ async function runLogin(serverUrl, opts) {
29914
30071
  if (!authProvider && !issuer) {
29915
30072
  authProvider = "better-auth";
29916
30073
  if (capsError) {
29917
- 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.`);
29918
30075
  void Promise.resolve().then(() => (init_install_report(), install_report_exports)).then(({ reportInstallFailure: reportInstallFailure2 }) => reportInstallFailure2(base2, {
29919
30076
  step: "cli_login_probe",
29920
30077
  reason: capsError?.slice(0, 40) ?? null,
@@ -29929,13 +30086,13 @@ async function runLogin(serverUrl, opts) {
29929
30086
  return;
29930
30087
  }
29931
30088
  console.log();
29932
- console.log(chalk.bold("Open this to approve the machine:"));
29933
- console.log(" " + chalk.cyan(p.url));
30089
+ console.log(chalk2.bold("Open this to approve the machine:"));
30090
+ console.log(" " + chalk2.cyan(p.url));
29934
30091
  if (openBrowser(p.url)) {
29935
- 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)"));
29936
30093
  }
29937
- console.log(chalk.dim(` If the page asks for a code: ${chalk.bold(p.userCode)}`));
29938
- 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"));
29939
30096
  };
29940
30097
  const tokens = authProvider === "better-auth" ? await betterAuthDeviceLogin2(base2, onPrompt) : await deviceLogin2({ issuer, clientId: opts.clientId }, onPrompt);
29941
30098
  const authHdr = { authorization: `Bearer ${tokens.accessToken}`, "content-type": "application/json" };
@@ -29951,9 +30108,9 @@ async function runLogin(serverUrl, opts) {
29951
30108
  const created = await fetch(`${base2}/api/teams`, { method: "POST", headers: authHdr, body: JSON.stringify({ name }) });
29952
30109
  if (!created.ok) throw new Error(`workspace create failed: HTTP ${created.status} ${await created.text().catch(() => "")}`);
29953
30110
  slug = (await readJsonBody(created, base2, "POST /api/teams")).slug;
29954
- 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.`));
29955
30112
  } else {
29956
- 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)}`));
29957
30114
  throw new Error("you belong to multiple teams \u2014 pass --team <slug> (listed above)");
29958
30115
  }
29959
30116
  }
@@ -29966,13 +30123,13 @@ async function runLogin(serverUrl, opts) {
29966
30123
  if (!mint.ok) throw new Error(`token mint failed: HTTP ${mint.status} ${await mint.text().catch(() => "")}`);
29967
30124
  const { token } = await readJsonBody(mint, base2, "POST /api/teams/:slug/tokens");
29968
30125
  saveCredentials2({ serverUrl, token });
29969
- 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}`));
29970
30127
  if (!opts.fromInit) {
29971
- 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."));
29972
30129
  }
29973
30130
  } catch (err) {
29974
30131
  if (opts.fromInit) throw err instanceof Error ? err : new Error(String(err));
29975
- 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);
29976
30133
  process.exit(1);
29977
30134
  }
29978
30135
  }
@@ -29980,15 +30137,15 @@ var exclude = program.command("exclude").description("Control what never leaves
29980
30137
  exclude.command("list", { isDefault: true }).description("Show current exclusions").action(async () => {
29981
30138
  const { loadSettings: loadSettings2 } = await Promise.resolve().then(() => (init_settings(), settings_exports));
29982
30139
  const s = loadSettings2();
29983
- console.log(chalk.bold("Sync exclusions") + chalk.dim(" (~/.chat-recall/settings/settings.json)"));
29984
- console.log(` tools: ${s.sync.excludeTools.length ? s.sync.excludeTools.join(", ") : chalk.dim("none")}`);
29985
- 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")}`);
29986
30143
  for (const p of s.sync.excludeProjects) console.log(` ${p}`);
29987
30144
  const deny = s.privacy.projectDenylist || [];
29988
- 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")}`);
29989
30146
  for (const p of deny) console.log(` ${p}`);
29990
- console.log(chalk.dim("\nPersonal folders (Pictures, Music, Documents, Desktop, Downloads, \u2026) are"));
29991
- 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>`."));
29992
30149
  const inc = s.sync.includeProjects || [];
29993
30150
  if (inc.length) {
29994
30151
  console.log(` personal paths opted back in:`);
@@ -29999,8 +30156,8 @@ var include = program.command("include").description("Opt a personal folder (Pic
29999
30156
  include.command("list", { isDefault: true }).description("Show paths opted back into indexing").action(async () => {
30000
30157
  const { loadSettings: loadSettings2 } = await Promise.resolve().then(() => (init_settings(), settings_exports));
30001
30158
  const inc = loadSettings2().sync.includeProjects || [];
30002
- console.log(chalk.bold("Personal paths opted back into code indexing"));
30003
- 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"));
30004
30161
  for (const p of inc) console.log(` ${p}`);
30005
30162
  });
30006
30163
  include.command("project <path>").description("Re-permit a path under a personal folder (substring match; e.g. ~/Documents/code)").action(async (path) => {
@@ -30011,12 +30168,12 @@ include.command("project <path>").description("Re-permit a path under a personal
30011
30168
  const s = loadSettings2();
30012
30169
  s.sync.includeProjects = s.sync.includeProjects || [];
30013
30170
  if (s.sync.includeProjects.includes(abs)) {
30014
- console.log(chalk.dim(`Already included: ${abs}`));
30171
+ console.log(chalk2.dim(`Already included: ${abs}`));
30015
30172
  return;
30016
30173
  }
30017
30174
  s.sync.includeProjects.push(abs);
30018
30175
  saveSettings2(s);
30019
- 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)."));
30020
30177
  });
30021
30178
  include.command("remove <path>").description("Undo an opt-in (personal folder goes back to skipped)").action(async (path) => {
30022
30179
  const { loadSettings: loadSettings2, saveSettings: saveSettings2 } = await Promise.resolve().then(() => (init_settings(), settings_exports));
@@ -30027,30 +30184,30 @@ include.command("remove <path>").description("Undo an opt-in (personal folder go
30027
30184
  const before = (s.sync.includeProjects || []).length;
30028
30185
  s.sync.includeProjects = (s.sync.includeProjects || []).filter((p) => p !== path && p !== abs);
30029
30186
  if (s.sync.includeProjects.length === before) {
30030
- console.error(chalk.red(`Not in the include list: ${path}`));
30187
+ console.error(chalk2.red(`Not in the include list: ${path}`));
30031
30188
  process.exit(1);
30032
30189
  }
30033
30190
  saveSettings2(s);
30034
- 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."));
30035
30192
  });
30036
30193
  var retention = program.command("retention").description("How long the server keeps your synced sessions. Bare `retention` shows the current window.");
30037
30194
  retention.command("show", { isDefault: true }).description("Show the window and how many sessions it would delete").action(async () => {
30038
30195
  const t = requireTarget();
30039
30196
  const r = await serverGet("/api/data/retention");
30040
- console.log(chalk.bold("Retention") + chalk.dim(` (server: ${t.base})`));
30197
+ console.log(chalk2.bold("Retention") + chalk2.dim(` (server: ${t.base})`));
30041
30198
  if (!r.days) {
30042
- 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`);
30043
30200
  } else {
30044
- console.log(` window: ${chalk.yellow(`${r.days} days`)}`);
30201
+ console.log(` window: ${chalk2.yellow(`${r.days} days`)}`);
30045
30202
  console.log(` sessions currently outside it: ${r.wouldDelete}`);
30046
30203
  }
30047
- 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`));
30048
30205
  });
30049
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) => {
30050
30207
  requireTarget();
30051
30208
  const days = Number(daysArg);
30052
30209
  if (!Number.isInteger(days) || days < 0) {
30053
- 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.`));
30054
30211
  process.exit(1);
30055
30212
  }
30056
30213
  const preview = await serverGet(
@@ -30058,23 +30215,23 @@ retention.command("set <days>").description("Set the window in days, or 0 to kee
30058
30215
  );
30059
30216
  if (days === 0) {
30060
30217
  await serverPost("/api/data/retention", { days: 0 });
30061
- 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."));
30062
30219
  return;
30063
30220
  }
30064
30221
  if (preview.wouldDelete > 0) {
30065
30222
  console.log();
30066
- console.log(chalk.yellow(`This deletes ${preview.wouldDelete} session(s) from the server, and keeps deleting`));
30067
- 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.`));
30068
30225
  console.log();
30069
- console.log(chalk.dim(" Re-syncing can restore a session ONLY if its transcript is still on a"));
30070
- console.log(chalk.dim(" machine you have. For a laptop you no longer own, history your AI tool"));
30071
- console.log(chalk.dim(" has rotated, or files you deleted, our copy is the only copy."));
30072
- 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"));
30073
30230
  console.log();
30074
30231
  if (!opts.yes) {
30075
30232
  if (!process.stdin.isTTY) {
30076
- console.error(chalk.red("Refusing: this would delete data and there is no terminal to confirm at."));
30077
- 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."));
30078
30235
  process.exit(1);
30079
30236
  }
30080
30237
  const { createInterface: createInterface3 } = await import("node:readline/promises");
@@ -30082,7 +30239,7 @@ retention.command("set <days>").description("Set the window in days, or 0 to kee
30082
30239
  const answer = (await rl.question(`Type ${preview.wouldDelete} to confirm: `)).trim();
30083
30240
  rl.close();
30084
30241
  if (answer !== String(preview.wouldDelete)) {
30085
- console.log(chalk.dim("Cancelled \u2014 nothing changed."));
30242
+ console.log(chalk2.dim("Cancelled \u2014 nothing changed."));
30086
30243
  return;
30087
30244
  }
30088
30245
  }
@@ -30091,20 +30248,20 @@ retention.command("set <days>").description("Set the window in days, or 0 to kee
30091
30248
  "/api/data/retention",
30092
30249
  { days, acknowledge: true }
30093
30250
  );
30094
- 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.`));
30095
30252
  });
30096
30253
  var syncOnly = program.command("sync-only").description("Opt-in sync: ship ONLY chosen projects. Bare `sync-only` shows the mode + allowlist.");
30097
30254
  syncOnly.command("list", { isDefault: true }).description("Show the sync mode and allowlisted projects").action(async () => {
30098
30255
  const { loadSettings: loadSettings2 } = await Promise.resolve().then(() => (init_settings(), settings_exports));
30099
30256
  const s = loadSettings2();
30100
30257
  const mode = s.sync.syncMode ?? "all";
30101
- console.log(chalk.bold("Selective sync") + chalk.dim(" (~/.chat-recall/settings/settings.json)"));
30102
- 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)")}`);
30103
30260
  const list = s.sync.syncOnlyProjects ?? [];
30104
- console.log(` projects: ${list.length ? "" : chalk.dim("none")}`);
30261
+ console.log(` projects: ${list.length ? "" : chalk2.dim("none")}`);
30105
30262
  for (const p of list) console.log(` ${p}`);
30106
- if (mode === "only" && list.length === 0) console.log(chalk.red(' \u26A0 mode is "only" but the allowlist is empty \u2192 NOTHING syncs.'));
30107
- 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>`."));
30108
30265
  });
30109
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) => {
30110
30267
  const { loadSettings: loadSettings2, saveSettings: saveSettings2 } = await Promise.resolve().then(() => (init_settings(), settings_exports));
@@ -30113,7 +30270,7 @@ syncOnly.command("add <project>").description('Add a project id (git:\u2026/ws:\
30113
30270
  if (!s.sync.syncOnlyProjects.includes(project)) s.sync.syncOnlyProjects.push(project);
30114
30271
  s.sync.syncMode = "only";
30115
30272
  saveSettings2(s);
30116
- 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.'));
30117
30274
  });
30118
30275
  syncOnly.command("remove <project>").description("Remove a project from the allowlist").action(async (project) => {
30119
30276
  const { loadSettings: loadSettings2, saveSettings: saveSettings2 } = await Promise.resolve().then(() => (init_settings(), settings_exports));
@@ -30121,18 +30278,18 @@ syncOnly.command("remove <project>").description("Remove a project from the allo
30121
30278
  const before = (s.sync.syncOnlyProjects || []).length;
30122
30279
  s.sync.syncOnlyProjects = (s.sync.syncOnlyProjects || []).filter((p) => p !== project);
30123
30280
  if (s.sync.syncOnlyProjects.length === before) {
30124
- console.error(chalk.red(`Not in the allowlist: ${project}`));
30281
+ console.error(chalk2.red(`Not in the allowlist: ${project}`));
30125
30282
  process.exit(1);
30126
30283
  }
30127
30284
  saveSettings2(s);
30128
- console.log(chalk.green(`\u2713 Removed ${project}`));
30285
+ console.log(chalk2.green(`\u2713 Removed ${project}`));
30129
30286
  });
30130
30287
  syncOnly.command("all").description("Switch back to syncing ALL non-excluded projects (keeps the list, just disables opt-in mode)").action(async () => {
30131
30288
  const { loadSettings: loadSettings2, saveSettings: saveSettings2 } = await Promise.resolve().then(() => (init_settings(), settings_exports));
30132
30289
  const s = loadSettings2();
30133
30290
  s.sync.syncMode = "all";
30134
30291
  saveSettings2(s);
30135
- 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."));
30136
30293
  });
30137
30294
  program.command("projects").description("List distinct project ids discovered on this machine (for `sync-only add`)").action(async () => {
30138
30295
  const { listAvailableBackends: listAvailableBackends2 } = await Promise.resolve().then(() => (init_tool_backend(), tool_backend_exports));
@@ -30152,11 +30309,11 @@ program.command("projects").description("List distinct project ids discovered on
30152
30309
  }
30153
30310
  const rows = [...counts.entries()].sort((a, b) => b[1] - a[1]);
30154
30311
  if (!rows.length) {
30155
- console.log(chalk.dim("No projects discovered."));
30312
+ console.log(chalk2.dim("No projects discovered."));
30156
30313
  return;
30157
30314
  }
30158
- console.log(chalk.bold("Discovered projects") + chalk.dim(" (id \xB7 sessions)"));
30159
- 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)}`);
30160
30317
  });
30161
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) => {
30162
30319
  const { loadSettings: loadSettings2, saveSettings: saveSettings2 } = await Promise.resolve().then(() => (init_settings(), settings_exports));
@@ -30165,28 +30322,28 @@ exclude.command("project <path>").description("Exclude a project path from synci
30165
30322
  const abs = resolve3(path.replace(/^~(?=\/|$)/, homedir23()));
30166
30323
  const s = loadSettings2();
30167
30324
  if (s.sync.excludeProjects.includes(abs)) {
30168
- console.log(chalk.dim(`Already excluded: ${abs}`));
30325
+ console.log(chalk2.dim(`Already excluded: ${abs}`));
30169
30326
  return;
30170
30327
  }
30171
30328
  s.sync.excludeProjects.push(abs);
30172
30329
  saveSettings2(s);
30173
- 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."));
30174
30331
  });
30175
30332
  exclude.command("tool <tool>").description("Exclude an AI tool entirely (claude | gemini | codex | opencode | agy | cursor)").action(async (tool) => {
30176
30333
  const valid = ["claude", "gemini", "codex", "opencode", "agy", "cursor"];
30177
30334
  if (!valid.includes(tool)) {
30178
- 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(" | ")}`));
30179
30336
  process.exit(1);
30180
30337
  }
30181
30338
  const { loadSettings: loadSettings2, saveSettings: saveSettings2 } = await Promise.resolve().then(() => (init_settings(), settings_exports));
30182
30339
  const s = loadSettings2();
30183
30340
  if (s.sync.excludeTools.includes(tool)) {
30184
- console.log(chalk.dim(`Already excluded: ${tool}`));
30341
+ console.log(chalk2.dim(`Already excluded: ${tool}`));
30185
30342
  return;
30186
30343
  }
30187
30344
  s.sync.excludeTools.push(tool);
30188
30345
  saveSettings2(s);
30189
- 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."));
30190
30347
  });
30191
30348
  exclude.command("remove <value>").description("Remove an exclusion (tool name or project path)").action(async (value) => {
30192
30349
  const { loadSettings: loadSettings2, saveSettings: saveSettings2 } = await Promise.resolve().then(() => (init_settings(), settings_exports));
@@ -30199,20 +30356,20 @@ exclude.command("remove <value>").description("Remove an exclusion (tool name or
30199
30356
  s.sync.excludeTools = s.sync.excludeTools.filter((t) => t !== value);
30200
30357
  s.sync.excludeProjects = s.sync.excludeProjects.filter((p) => p !== value && p !== abs);
30201
30358
  if (s.sync.excludeTools.length === beforeTools && s.sync.excludeProjects.length === beforeProjects) {
30202
- 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"));
30203
30360
  process.exit(1);
30204
30361
  }
30205
30362
  saveSettings2(s);
30206
- console.log(chalk.green(`\u2713 Removed ${value}`));
30363
+ console.log(chalk2.green(`\u2713 Removed ${value}`));
30207
30364
  });
30208
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));
30209
30366
  program.command("logout <server-url>").description("Remove one sync target (other targets keep syncing)").action(async (serverUrl) => {
30210
30367
  const { removeCredentials: removeCredentials2, loadAllCredentials: loadAllCredentials2 } = await Promise.resolve().then(() => (init_sync_client(), sync_client_exports));
30211
30368
  if (removeCredentials2(serverUrl)) {
30212
30369
  const left = loadAllCredentials2();
30213
- 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`));
30214
30371
  } else {
30215
- console.error(chalk.red(`No such target: ${serverUrl}`));
30372
+ console.error(chalk2.red(`No such target: ${serverUrl}`));
30216
30373
  process.exit(1);
30217
30374
  }
30218
30375
  });
@@ -30220,7 +30377,7 @@ program.command("delete <session-id>").description("Delete a session from chat-r
30220
30377
  const { loadAllCredentials: loadAllCredentials2 } = await Promise.resolve().then(() => (init_sync_client(), sync_client_exports));
30221
30378
  const targets = loadAllCredentials2();
30222
30379
  if (targets.length === 0) {
30223
- 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."));
30224
30381
  process.exit(1);
30225
30382
  }
30226
30383
  let ok = 0;
@@ -30232,20 +30389,20 @@ program.command("delete <session-id>").description("Delete a session from chat-r
30232
30389
  });
30233
30390
  if (res.ok) {
30234
30391
  ok++;
30235
- console.log(chalk.green(`\u2713 Deleted on ${t.serverUrl}`));
30236
- } 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}`));
30237
30394
  } catch (e) {
30238
- 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"}`));
30239
30396
  }
30240
30397
  }
30241
30398
  if (ok === 0) process.exit(1);
30242
- 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.`));
30243
30400
  });
30244
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) => {
30245
30402
  const { loadAllCredentials: loadAllCredentials2 } = await Promise.resolve().then(() => (init_sync_client(), sync_client_exports));
30246
30403
  const targets = loadAllCredentials2();
30247
30404
  if (targets.length === 0) {
30248
- 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."));
30249
30406
  process.exit(1);
30250
30407
  }
30251
30408
  let ok = 0;
@@ -30258,14 +30415,14 @@ program.command("rename <session-id> <name>").description('Give a session a memo
30258
30415
  });
30259
30416
  if (res.ok) {
30260
30417
  ok++;
30261
- console.log(chalk.green(`\u2713 ${name.trim() ? "Named" : "Cleared name"} on ${t.serverUrl}`));
30262
- } 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}`));
30263
30420
  } catch (e) {
30264
- 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"}`));
30265
30422
  }
30266
30423
  }
30267
30424
  if (ok === 0) process.exit(1);
30268
- 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).`));
30269
30426
  });
30270
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) => {
30271
30428
  const { syncSessions: syncSessions2, syncIncremental: syncIncremental2, isSyncSkip: isSyncSkip2 } = await Promise.resolve().then(() => (init_sync_client(), sync_client_exports));
@@ -30274,17 +30431,17 @@ program.command("sync").description("Push redacted conversations to the configur
30274
30431
  const r2 = await syncIncremental2();
30275
30432
  if (isSyncSkip2(r2)) {
30276
30433
  if (r2.skipped === "lock-held") {
30277
- 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."));
30278
30435
  return;
30279
30436
  }
30280
30437
  const msg = {
30281
30438
  "no-credentials": "Not logged in \u2014 run `chat-recall login <server-url>` first.",
30282
30439
  "paused": "Sync is paused in settings \u2014 re-run `chat-recall login <server-url>` to resume."
30283
30440
  }[r2.skipped];
30284
- console.error(chalk.red(msg));
30441
+ console.error(chalk2.red(msg));
30285
30442
  process.exit(1);
30286
30443
  }
30287
- 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)`));
30288
30445
  return;
30289
30446
  }
30290
30447
  const sinceMs = opts.sinceHours ? Date.now() - Number(opts.sinceHours) * 36e5 : void 0;
@@ -30299,9 +30456,9 @@ program.command("sync").description("Push redacted conversations to the configur
30299
30456
  throttleMs: opts.throttle !== void 0 ? Number(opts.throttle) : opts.full ? 3e3 : void 0,
30300
30457
  prune: !!opts.prune
30301
30458
  });
30302
- 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)` : ""}`));
30303
30460
  } catch (err) {
30304
- 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);
30305
30462
  process.exit(1);
30306
30463
  }
30307
30464
  });
@@ -30310,11 +30467,11 @@ program.command("reconcile").description("Reconcile DERIVED FIELDS (e.g. native
30310
30467
  try {
30311
30468
  const r = await reconcileFields2({ force: !!opts.force });
30312
30469
  const per = Object.entries(r.perTarget).map(([s, v]) => `${s}: ${v.pushed} pushed`).join(", ");
30313
- console.log(chalk.green(`\u2713 Reconciled derived fields`) + chalk.dim(
30470
+ console.log(chalk2.green(`\u2713 Reconciled derived fields`) + chalk2.dim(
30314
30471
  ` \u2014 ${r.sessions} sessions, ${r.scanned} scanned, ${r.pushed} pushed, ${r.absent} absent${per ? ` (${per})` : ""}`
30315
30472
  ));
30316
30473
  } catch (err) {
30317
- 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);
30318
30475
  process.exit(1);
30319
30476
  }
30320
30477
  });
@@ -30324,7 +30481,7 @@ program.command("update").description("Update this CLI now from the server you s
30324
30481
  const { cliVersion: cliVersion3 } = await Promise.resolve().then(() => (init_http(), http_exports));
30325
30482
  const targets = loadAllCredentials();
30326
30483
  if (!targets.length) {
30327
- 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."));
30328
30485
  process.exit(1);
30329
30486
  }
30330
30487
  let installFailed = false;
@@ -30333,17 +30490,17 @@ program.command("update").description("Update this CLI now from the server you s
30333
30490
  const headers = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
30334
30491
  const r = await runAutoUpdate2(base2, headers, cliVersion3());
30335
30492
  if (r.updated) {
30336
- console.log(chalk.green(`\u2713 ${r.reason}`) + chalk.dim(` (${base2})`));
30493
+ console.log(chalk2.green(`\u2713 ${r.reason}`) + chalk2.dim(` (${base2})`));
30337
30494
  continue;
30338
30495
  }
30339
30496
  const benign = /already current|no CLI release|disabled/.test(r.reason);
30340
30497
  if (/install failed|download failed|checksum/.test(r.reason)) installFailed = true;
30341
- 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})`));
30342
30499
  }
30343
30500
  await refreshUpdateCheck2(true);
30344
30501
  if (installFailed) {
30345
- console.log(chalk.dim("\nThe update was available but did not install \u2014 usually npm cannot write the global prefix. Retry with:"));
30346
- 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)`));
30347
30504
  }
30348
30505
  });
30349
30506
  program.hook("preAction", () => {