chat-recall 0.7.14 → 0.7.15

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/mcp.js CHANGED
@@ -4259,7 +4259,7 @@ var require_pino = __commonJS({
4259
4259
  messageKey,
4260
4260
  errorKey,
4261
4261
  nestedKey,
4262
- base,
4262
+ base: base2,
4263
4263
  name,
4264
4264
  level: level2,
4265
4265
  customLevels,
@@ -4298,11 +4298,11 @@ var require_pino = __commonJS({
4298
4298
  [formattersSym]: allFormatters
4299
4299
  });
4300
4300
  let chindings = "";
4301
- if (base !== null) {
4301
+ if (base2 !== null) {
4302
4302
  if (name === void 0) {
4303
- chindings = coreChindings(base);
4303
+ chindings = coreChindings(base2);
4304
4304
  } else {
4305
- chindings = coreChindings(Object.assign({}, base, { name }));
4305
+ chindings = coreChindings(Object.assign({}, base2, { name }));
4306
4306
  }
4307
4307
  }
4308
4308
  const time2 = timestamp instanceof Function ? timestamp : timestamp ? epochTime : nullTime;
@@ -5271,57 +5271,57 @@ function freshDefaults() {
5271
5271
  team: defaultTeam()
5272
5272
  };
5273
5273
  }
5274
- function mergeSources(base, partial) {
5274
+ function mergeSources(base2, partial) {
5275
5275
  if (!partial)
5276
- return base;
5276
+ return base2;
5277
5277
  const legacyGemini = partial.enabled?.gemini;
5278
5278
  const inherited = legacyGemini && typeof legacyGemini === "object" ? (({ sessions: _s, plans: _p, ...rest }) => rest)(legacyGemini) : {};
5279
5279
  const enabled = {
5280
- claude: { ...base.enabled.claude, ...partial.enabled?.claude ?? {} },
5281
- opencode: { ...base.enabled.opencode, ...partial.enabled?.opencode ?? {} },
5282
- codex: { ...base.enabled.codex, ...partial.enabled?.codex ?? {} },
5283
- agy: { ...base.enabled.agy, ...inherited, ...partial.enabled?.agy ?? {} },
5284
- cursor: { ...base.enabled.cursor, ...partial.enabled?.cursor ?? {} },
5285
- shared: { ...base.enabled.shared, ...partial.enabled?.shared ?? {} },
5286
- common: { ...base.enabled.common, ...partial.enabled?.common ?? {} }
5280
+ claude: { ...base2.enabled.claude, ...partial.enabled?.claude ?? {} },
5281
+ opencode: { ...base2.enabled.opencode, ...partial.enabled?.opencode ?? {} },
5282
+ codex: { ...base2.enabled.codex, ...partial.enabled?.codex ?? {} },
5283
+ agy: { ...base2.enabled.agy, ...inherited, ...partial.enabled?.agy ?? {} },
5284
+ cursor: { ...base2.enabled.cursor, ...partial.enabled?.cursor ?? {} },
5285
+ shared: { ...base2.enabled.shared, ...partial.enabled?.shared ?? {} },
5286
+ common: { ...base2.enabled.common, ...partial.enabled?.common ?? {} }
5287
5287
  };
5288
5288
  return {
5289
- claudeHome: partial.claudeHome ?? base.claudeHome,
5290
- geminiHome: partial.geminiHome ?? base.geminiHome,
5291
- codexHome: partial.codexHome ?? base.codexHome,
5292
- opencodeDbPath: partial.opencodeDbPath ?? base.opencodeDbPath,
5293
- agyHome: partial.agyHome ?? base.agyHome,
5294
- cursorHome: partial.cursorHome ?? base.cursorHome,
5295
- cursorIdeHome: partial.cursorIdeHome ?? base.cursorIdeHome,
5296
- extraClaudeHomes: partial.extraClaudeHomes ?? base.extraClaudeHomes,
5297
- approvedHomes: partial.approvedHomes ?? base.approvedHomes,
5298
- declinedHomes: partial.declinedHomes ?? base.declinedHomes,
5299
- homesGrandfathered: partial.homesGrandfathered ?? base.homesGrandfathered,
5289
+ claudeHome: partial.claudeHome ?? base2.claudeHome,
5290
+ geminiHome: partial.geminiHome ?? base2.geminiHome,
5291
+ codexHome: partial.codexHome ?? base2.codexHome,
5292
+ opencodeDbPath: partial.opencodeDbPath ?? base2.opencodeDbPath,
5293
+ agyHome: partial.agyHome ?? base2.agyHome,
5294
+ cursorHome: partial.cursorHome ?? base2.cursorHome,
5295
+ cursorIdeHome: partial.cursorIdeHome ?? base2.cursorIdeHome,
5296
+ extraClaudeHomes: partial.extraClaudeHomes ?? base2.extraClaudeHomes,
5297
+ approvedHomes: partial.approvedHomes ?? base2.approvedHomes,
5298
+ declinedHomes: partial.declinedHomes ?? base2.declinedHomes,
5299
+ homesGrandfathered: partial.homesGrandfathered ?? base2.homesGrandfathered,
5300
5300
  enabled
5301
5301
  };
5302
5302
  }
5303
- function mergePrivacy(base, partial) {
5303
+ function mergePrivacy(base2, partial) {
5304
5304
  if (!partial)
5305
- return base;
5306
- return { ...base, ...partial };
5305
+ return base2;
5306
+ return { ...base2, ...partial };
5307
5307
  }
5308
- function mergeSync(base, partial) {
5308
+ function mergeSync(base2, partial) {
5309
5309
  if (!partial)
5310
- return base;
5310
+ return base2;
5311
5311
  return {
5312
- ...base,
5312
+ ...base2,
5313
5313
  ...partial,
5314
- upload: { ...base.upload, ...partial.upload ?? {} }
5314
+ upload: { ...base2.upload, ...partial.upload ?? {} }
5315
5315
  };
5316
5316
  }
5317
- function mergeTeam(base, partial) {
5317
+ function mergeTeam(base2, partial) {
5318
5318
  if (!partial)
5319
- return base;
5319
+ return base2;
5320
5320
  return {
5321
- ...base,
5321
+ ...base2,
5322
5322
  ...partial,
5323
- publishAllowed: { ...base.publishAllowed, ...partial.publishAllowed ?? {} },
5324
- vault: { ...base.vault, ...partial.vault ?? {} }
5323
+ publishAllowed: { ...base2.publishAllowed, ...partial.publishAllowed ?? {} },
5324
+ vault: { ...base2.vault, ...partial.vault ?? {} }
5325
5325
  };
5326
5326
  }
5327
5327
  function settingsFilePath() {
@@ -5439,15 +5439,15 @@ function loadSettings() {
5439
5439
  }
5440
5440
  try {
5441
5441
  const parsed = JSON.parse(readFileSync3(path2, "utf-8"));
5442
- const base = freshDefaults();
5442
+ const base2 = freshDefaults();
5443
5443
  const result = {
5444
5444
  v: SCHEMA_VERSION,
5445
- embedding: { ...base.embedding, ...parsed.embedding ?? {} },
5446
- summary: { ...base.summary, ...parsed.summary ?? {} },
5447
- sources: mergeSources(base.sources, parsed.sources),
5448
- privacy: mergePrivacy(base.privacy, parsed.privacy),
5449
- sync: mergeSync(base.sync, parsed.sync),
5450
- team: mergeTeam(base.team, parsed.team)
5445
+ embedding: { ...base2.embedding, ...parsed.embedding ?? {} },
5446
+ summary: { ...base2.summary, ...parsed.summary ?? {} },
5447
+ sources: mergeSources(base2.sources, parsed.sources),
5448
+ privacy: mergePrivacy(base2.privacy, parsed.privacy),
5449
+ sync: mergeSync(base2.sync, parsed.sync),
5450
+ team: mergeTeam(base2.team, parsed.team)
5451
5451
  };
5452
5452
  if (mtimeMs >= 0)
5453
5453
  _settingsCache = { mtimeMs, size, value: structuredClone(result) };
@@ -5643,10 +5643,10 @@ function legacyAutoSyncedHomes() {
5643
5643
  { base: join6(home, ".local", "share", "opencode"), marker: "opencode.db" },
5644
5644
  { base: join6(home, ".cursor"), marker: "chats" }
5645
5645
  ];
5646
- for (const { base, marker } of bases) {
5647
- add(base, marker);
5648
- const parent = dirname5(base);
5649
- const leaf = base.slice(parent.length + 1);
5646
+ for (const { base: base2, marker } of bases) {
5647
+ add(base2, marker);
5648
+ const parent = dirname5(base2);
5649
+ const leaf = base2.slice(parent.length + 1);
5650
5650
  try {
5651
5651
  for (const e of readdirSync4(parent, { withFileTypes: true })) {
5652
5652
  if (!e.isDirectory())
@@ -5827,17 +5827,17 @@ function cursorHomeDir() {
5827
5827
  function cursorIdeHomeDir() {
5828
5828
  return process.env.CHAT_RECALL_CURSOR_IDE_HOME || sources().cursorIdeHome || (process.platform === "darwin" ? join7(homedir3(), "Library", "Application Support", "Cursor") : join7(homedir3(), ".config", "Cursor"));
5829
5829
  }
5830
- function siblingHomes(base, overridden, suffix) {
5830
+ function siblingHomes(base2, overridden, suffix) {
5831
5831
  const roots = [];
5832
5832
  const add = (home) => {
5833
5833
  const root = suffix ? join7(home, suffix) : home;
5834
5834
  if (existsSync5(root) && !roots.includes(root))
5835
5835
  roots.push(root);
5836
5836
  };
5837
- add(base);
5837
+ add(base2);
5838
5838
  if (!overridden) {
5839
- const parent = dirname6(base);
5840
- const leaf = basename3(base);
5839
+ const parent = dirname6(base2);
5840
+ const leaf = basename3(base2);
5841
5841
  try {
5842
5842
  for (const entry of readdirSync5(parent, { withFileTypes: true })) {
5843
5843
  if (!entry.isDirectory())
@@ -11019,9 +11019,9 @@ async function parseSessionFile(sessionPath, maxMessages = 50) {
11019
11019
  content.metadata.durationMs += obj.durationMs;
11020
11020
  }
11021
11021
  if (msgType === "file-history-snapshot") {
11022
- const snapshot = obj.snapshot;
11023
- if (snapshot && typeof snapshot === "object") {
11024
- const backups = snapshot.trackedFileBackups;
11022
+ const snapshot2 = obj.snapshot;
11023
+ if (snapshot2 && typeof snapshot2 === "object") {
11024
+ const backups = snapshot2.trackedFileBackups;
11025
11025
  if (backups && typeof backups === "object") {
11026
11026
  for (const filePath2 of Object.keys(backups)) {
11027
11027
  filesModified.add(filePath2);
@@ -13290,8 +13290,8 @@ function serverRulePackVersion() {
13290
13290
  return serverPack ? serverPack.version || "unversioned" : null;
13291
13291
  }
13292
13292
  function activeRules() {
13293
- const base = settingsView().rules;
13294
- return serverPack && serverPack.rules.length > 0 ? [...base, ...serverPack.rules] : base;
13293
+ const base2 = settingsView().rules;
13294
+ return serverPack && serverPack.rules.length > 0 ? [...base2, ...serverPack.rules] : base2;
13295
13295
  }
13296
13296
  function isRedactionEnabled() {
13297
13297
  const env = isEnvRedactionRequested();
@@ -14154,17 +14154,17 @@ async function collectCode(opts) {
14154
14154
  return r;
14155
14155
  };
14156
14156
  log6(`indexing ${ws} + analyses \u2026`);
14157
- const base = await runMcp(bin, ws, [
14157
+ const base2 = await runMcp(bin, ws, [
14158
14158
  call(1, "index_workspace", { path: ws }),
14159
14159
  call(2, "status"),
14160
14160
  call(3, "get_tree"),
14161
14161
  ...ANALYSES.map((a, i) => call(10 + i, "analyze", { analysis: a }))
14162
14162
  ]);
14163
- const st = parseJson(base, 2, {});
14164
- const tree = parseJson(base, 3, []);
14163
+ const st = parseJson(base2, 2, {});
14164
+ const tree = parseJson(base2, 3, []);
14165
14165
  const A = {};
14166
14166
  ANALYSES.forEach((a, i) => {
14167
- A[a] = parseJson(base, 10 + i, {});
14167
+ A[a] = parseJson(base2, 10 + i, {});
14168
14168
  });
14169
14169
  const { health, security: sec, duplication: dup, clones, literal_scan: lit, coupling: coup, cycles: cyc, dead_code: dead, unwrap_audit: unwrap, test_coverage: coverage, architecture: arch, crossref, type_drift: typeDrift, db_schema: dbSchema, migration_parity: migParity, manifest_compliance: manifest } = A;
14170
14170
  if (tree.length === 0) {
@@ -19452,38 +19452,100 @@ var init_extractor_version = __esm({
19452
19452
  });
19453
19453
 
19454
19454
  // src/sync-ledger.ts
19455
- import { readFileSync as readFileSync34, writeFileSync as writeFileSync7, renameSync as renameSync5, mkdirSync as mkdirSync10 } from "node:fs";
19455
+ import { readFileSync as readFileSync34, writeFileSync as writeFileSync7, renameSync as renameSync5, mkdirSync as mkdirSync10, statSync as statSync40 } from "node:fs";
19456
19456
  import { join as join46, dirname as dirname17 } from "node:path";
19457
19457
  function toRow(entry) {
19458
19458
  if (entry === void 0) return void 0;
19459
19459
  return typeof entry === "number" ? { m: entry, v: 0 } : entry;
19460
19460
  }
19461
- function load() {
19462
- if (cache3) return cache3;
19461
+ function stampOf(path2) {
19462
+ try {
19463
+ const st = statSync40(path2);
19464
+ return `${st.mtimeMs}:${st.size}`;
19465
+ } catch {
19466
+ return null;
19467
+ }
19468
+ }
19469
+ function readDisk(path2) {
19463
19470
  try {
19464
- const parsed = JSON.parse(readFileSync34(ledgerPath(), "utf-8"));
19465
- cache3 = parsed && typeof parsed === "object" ? parsed : {};
19471
+ const parsed = JSON.parse(readFileSync34(path2, "utf-8"));
19472
+ return parsed && typeof parsed === "object" ? parsed : {};
19466
19473
  } catch {
19467
- cache3 = {};
19474
+ return {};
19475
+ }
19476
+ }
19477
+ function snapshot(data) {
19478
+ const out = /* @__PURE__ */ new Map();
19479
+ for (const [server, rows] of Object.entries(data)) {
19480
+ for (const [id, entry] of Object.entries(rows)) out.set(rowKey(server, id), JSON.stringify(entry));
19481
+ }
19482
+ return out;
19483
+ }
19484
+ function mergeOnto(disk) {
19485
+ const out = {};
19486
+ const put = (server, id, entry) => {
19487
+ (out[server] ??= {})[id] = entry;
19488
+ };
19489
+ const mine = cache3 ?? {};
19490
+ for (const [server, rows] of Object.entries(disk)) {
19491
+ for (const [id, entry] of Object.entries(rows)) {
19492
+ const k = rowKey(server, id);
19493
+ const own = mine[server]?.[id];
19494
+ const was = base.get(k);
19495
+ if (own === void 0) {
19496
+ if (was === void 0) put(server, id, entry);
19497
+ } else {
19498
+ put(server, id, JSON.stringify(own) === was ? entry : own);
19499
+ }
19500
+ }
19501
+ }
19502
+ for (const [server, rows] of Object.entries(mine)) {
19503
+ for (const [id, entry] of Object.entries(rows)) {
19504
+ if (disk[server]?.[id] !== void 0) continue;
19505
+ if (JSON.stringify(entry) !== base.get(rowKey(server, id))) put(server, id, entry);
19506
+ }
19468
19507
  }
19508
+ return out;
19509
+ }
19510
+ function load() {
19511
+ const path2 = ledgerPath();
19512
+ const stamp = stampOf(path2);
19513
+ if (cache3 && stamp === diskStamp) return cache3;
19514
+ const disk = readDisk(path2);
19515
+ const merged = cache3 ? mergeOnto(disk) : disk;
19516
+ if (cache3) {
19517
+ for (const server of Object.keys(cache3)) if (!(server in merged)) delete cache3[server];
19518
+ for (const [server, rows] of Object.entries(merged)) {
19519
+ const target = cache3[server] ?? (cache3[server] = {});
19520
+ for (const id of Object.keys(target)) if (!(id in rows)) delete target[id];
19521
+ Object.assign(target, rows);
19522
+ }
19523
+ } else {
19524
+ cache3 = merged;
19525
+ }
19526
+ base = snapshot(disk);
19527
+ diskStamp = stamp;
19469
19528
  return cache3;
19470
19529
  }
19471
- function persistNow(data) {
19530
+ function persistNow() {
19472
19531
  const path2 = ledgerPath();
19473
19532
  mkdirSync10(dirname17(path2), { recursive: true });
19474
- const tmp = `${path2}.tmp`;
19475
- writeFileSync7(tmp, JSON.stringify(data));
19533
+ load();
19534
+ const tmp = `${path2}.tmp-${process.pid}`;
19535
+ writeFileSync7(tmp, JSON.stringify(cache3 ?? {}));
19476
19536
  renameSync5(tmp, path2);
19537
+ base = snapshot(cache3 ?? {});
19538
+ diskStamp = stampOf(path2);
19477
19539
  pendingWrite = false;
19478
19540
  }
19479
- function persist(data) {
19541
+ function persist(_data) {
19480
19542
  pendingWrite = true;
19481
19543
  if (flushTimer) return;
19482
19544
  flushTimer = setTimeout(() => {
19483
19545
  flushTimer = null;
19484
19546
  if (pendingWrite) {
19485
19547
  try {
19486
- persistNow(data);
19548
+ persistNow();
19487
19549
  } catch {
19488
19550
  }
19489
19551
  }
@@ -19517,7 +19579,7 @@ function pruneLedgerTargets(configuredServers) {
19517
19579
  }
19518
19580
  const rows = names.reduce((n, s) => n + Object.keys(orphans[s]).length, 0);
19519
19581
  console.error(`[sync] tidied local bookkeeping: ${rows} already-synced marker(s) for ${names.length} server(s) you no longer sync to (${names.join(", ")}) moved to ${side}. Nothing was uploaded there; the file is kept so logging back in re-ships nothing.`);
19520
- persistNow(data);
19582
+ persistNow();
19521
19583
  return names.length;
19522
19584
  }
19523
19585
  function flushLedger() {
@@ -19526,7 +19588,7 @@ function flushLedger() {
19526
19588
  flushTimer = null;
19527
19589
  }
19528
19590
  if (!pendingWrite || !cache3) return;
19529
- persistNow(cache3);
19591
+ persistNow();
19530
19592
  }
19531
19593
  function loadItemVersionsAll() {
19532
19594
  if (itemVersionsCache) return itemVersionsCache;
@@ -19602,13 +19664,13 @@ function markSynced(server, rows) {
19602
19664
  const o = (cursorFromCaller ? r.offset : void 0) ?? prevOS.o ?? 0;
19603
19665
  const s = (cursorFromCaller ? r.size : void 0) ?? prevOS.s ?? 0;
19604
19666
  const ev = extractorVersionForId(r.id);
19605
- const base = prevF ? { m: Math.floor(r.mtime), v: ev, f: prevF } : { m: Math.floor(r.mtime), v: ev };
19667
+ const base2 = prevF ? { m: Math.floor(r.mtime), v: ev, f: prevF } : { m: Math.floor(r.mtime), v: ev };
19606
19668
  if (o > 0 || s > 0) {
19607
- base.o = o;
19608
- base.s = s;
19669
+ base2.o = o;
19670
+ base2.s = s;
19609
19671
  }
19610
- if (r.hash !== void 0) base.h = r.hash;
19611
- forServer[r.id] = base;
19672
+ if (r.hash !== void 0) base2.h = r.hash;
19673
+ forServer[r.id] = base2;
19612
19674
  }
19613
19675
  persist(data);
19614
19676
  }
@@ -19683,7 +19745,7 @@ function syncMode(row, mtime, fileSize, extractorVersion, isAppendOnly) {
19683
19745
  if (row.m >= Math.floor(mtime)) return "skip";
19684
19746
  return "full";
19685
19747
  }
19686
- var ledgerPath, cache3, LEDGER_FLUSH_MS, pendingWrite, flushTimer, itemVersionsPath, itemVersionsCache, inventoryPath, unackedCursorAttempts, reconcilePath, reconcileCache;
19748
+ var ledgerPath, cache3, base, diskStamp, rowKey, LEDGER_FLUSH_MS, pendingWrite, flushTimer, itemVersionsPath, itemVersionsCache, inventoryPath, unackedCursorAttempts, reconcilePath, reconcileCache;
19687
19749
  var init_sync_ledger = __esm({
19688
19750
  "src/sync-ledger.ts"() {
19689
19751
  "use strict";
@@ -19691,6 +19753,9 @@ var init_sync_ledger = __esm({
19691
19753
  init_extractor_version();
19692
19754
  ledgerPath = () => join46(getDataDir(), "sync-ledger.json");
19693
19755
  cache3 = null;
19756
+ base = /* @__PURE__ */ new Map();
19757
+ diskStamp = null;
19758
+ rowKey = (server, id) => `${server}\0${id}`;
19694
19759
  LEDGER_FLUSH_MS = 2e3;
19695
19760
  pendingWrite = false;
19696
19761
  flushTimer = null;
@@ -19729,7 +19794,7 @@ var init_sync_fields = __esm({
19729
19794
  });
19730
19795
 
19731
19796
  // ../engine/dist/core/index-lock.js
19732
- import { existsSync as existsSync43, mkdirSync as mkdirSync11, openSync as openSync9, writeFileSync as writeFileSync8, readFileSync as readFileSync35, rmSync as rmSync4, statSync as statSync40, closeSync as closeSync9 } from "fs";
19797
+ import { existsSync as existsSync43, mkdirSync as mkdirSync11, openSync as openSync9, writeFileSync as writeFileSync8, readFileSync as readFileSync35, rmSync as rmSync4, statSync as statSync41, closeSync as closeSync9 } from "fs";
19733
19798
  import { dirname as dirname18, join as join47 } from "path";
19734
19799
  function acquireIndexLock(opts) {
19735
19800
  const lockPath = lockFilePath(opts.file);
@@ -19779,7 +19844,7 @@ function lockFilePath(file = ".compact.lock") {
19779
19844
  }
19780
19845
  function stealStaleLock(lockPath, staleAfterMs) {
19781
19846
  try {
19782
- const s = statSync40(lockPath);
19847
+ const s = statSync41(lockPath);
19783
19848
  const age = Date.now() - s.mtimeMs;
19784
19849
  let payload;
19785
19850
  try {
@@ -19845,7 +19910,7 @@ var init_http = __esm({
19845
19910
  CLI_VERSION = JSON.parse(readFileSync36(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
19846
19911
  } catch {
19847
19912
  try {
19848
- if (true) CLI_VERSION = "0.7.14";
19913
+ if (true) CLI_VERSION = "0.7.15";
19849
19914
  } catch {
19850
19915
  }
19851
19916
  }
@@ -20343,7 +20408,7 @@ var init_telemetry = __esm({
20343
20408
  init_sync_client();
20344
20409
  cliVersion2 = () => {
20345
20410
  try {
20346
- return true ? "0.7.14" : "dev";
20411
+ return true ? "0.7.15" : "dev";
20347
20412
  } catch {
20348
20413
  return "dev";
20349
20414
  }
@@ -20366,11 +20431,11 @@ __export(server_probe_exports, {
20366
20431
  function probeOk(r) {
20367
20432
  return r.kind === "ok" && r.apiVersion >= 2;
20368
20433
  }
20369
- async function probeServer(base, opts = {}) {
20434
+ async function probeServer(base2, opts = {}) {
20370
20435
  const f = opts.fetchImpl || fetch;
20371
20436
  let res;
20372
20437
  try {
20373
- res = await f(`${base.replace(/\/+$/, "")}/api/capabilities`, {
20438
+ res = await f(`${base2.replace(/\/+$/, "")}/api/capabilities`, {
20374
20439
  signal: AbortSignal.timeout(opts.timeoutMs ?? 1e4)
20375
20440
  });
20376
20441
  } catch (err) {
@@ -20407,34 +20472,34 @@ async function probeServer(base, opts = {}) {
20407
20472
  raw: parsed
20408
20473
  };
20409
20474
  }
20410
- function probeAdvice(r, base) {
20475
+ function probeAdvice(r, base2) {
20411
20476
  switch (r.kind) {
20412
20477
  case "ok":
20413
20478
  return r.apiVersion >= 2 ? `apiVersion ${r.apiVersion}${r.edition ? `, edition ${r.edition}` : ""}` : `apiVersion ${r.apiVersion} is too old for this CLI \u2014 upgrade the server`;
20414
20479
  case "moved":
20415
- return `HTTP ${r.status} \u2014 nothing is served at ${base}. If the host moved, re-point it: \`chat-recall login <new-server-url>\``;
20480
+ return `HTTP ${r.status} \u2014 nothing is served at ${base2}. If the host moved, re-point it: \`chat-recall login <new-server-url>\``;
20416
20481
  case "unauthorized":
20417
- return `HTTP ${r.status} \u2014 ${base} rejected the credential. Re-login: \`chat-recall login ` + base + "`";
20482
+ return `HTTP ${r.status} \u2014 ${base2} rejected the credential. Re-login: \`chat-recall login ` + base2 + "`";
20418
20483
  case "server_error":
20419
- return `HTTP ${r.status} \u2014 ${base} is up but failing. Nothing to fix locally; check the server.`;
20484
+ return `HTTP ${r.status} \u2014 ${base2} is up but failing. Nothing to fix locally; check the server.`;
20420
20485
  case "not_api":
20421
- return `${base} answered ${r.status} with something that is not the chat-recall API (${JSON.stringify(r.snippet)}) \u2014 check the URL, a proxy or a captive portal`;
20486
+ return `${base2} answered ${r.status} with something that is not the chat-recall API (${JSON.stringify(r.snippet)}) \u2014 check the URL, a proxy or a captive portal`;
20422
20487
  case "unreachable":
20423
20488
  switch (r.reason) {
20424
20489
  case "dns":
20425
- return `cannot resolve the host in ${base} (${r.error}) \u2014 check the URL for a typo, and your DNS or VPN`;
20490
+ return `cannot resolve the host in ${base2} (${r.error}) \u2014 check the URL for a typo, and your DNS or VPN`;
20426
20491
  case "refused":
20427
- return `${base} resolves but refused the connection (${r.error}) \u2014 the server is not running, or the port is wrong`;
20492
+ return `${base2} resolves but refused the connection (${r.error}) \u2014 the server is not running, or the port is wrong`;
20428
20493
  case "tls":
20429
- return `the TLS certificate at ${base} was rejected (${r.error}) \u2014 expired, self-signed, or issued for another host. A corporate proxy that re-signs traffic does this.`;
20494
+ return `the TLS certificate at ${base2} was rejected (${r.error}) \u2014 expired, self-signed, or issued for another host. A corporate proxy that re-signs traffic does this.`;
20430
20495
  case "timeout":
20431
- return `${base} did not answer in time (${r.error}) \u2014 a firewall or proxy that drops traffic silently looks exactly like this`;
20496
+ return `${base2} did not answer in time (${r.error}) \u2014 a firewall or proxy that drops traffic silently looks exactly like this`;
20432
20497
  case "reset":
20433
- return `the connection to ${base} was cut (${r.error}) \u2014 often a proxy or a captive portal`;
20498
+ return `the connection to ${base2} was cut (${r.error}) \u2014 often a proxy or a captive portal`;
20434
20499
  case "bad_port":
20435
- return `${base} names a port that Node and every browser refuse to open (the WHATWG bad-port list) \u2014 use the server's real port`;
20500
+ return `${base2} names a port that Node and every browser refuse to open (the WHATWG bad-port list) \u2014 use the server's real port`;
20436
20501
  default:
20437
- return `no HTTP response from ${base} (${r.error}) \u2014 check the URL, DNS, or that the server is running`;
20502
+ return `no HTTP response from ${base2} (${r.error}) \u2014 check the URL, DNS, or that the server is running`;
20438
20503
  }
20439
20504
  }
20440
20505
  }
@@ -20467,8 +20532,8 @@ function describeCause(err) {
20467
20532
  const code = e.code;
20468
20533
  if (typeof code === "string" && code && !parts.includes(code)) parts.push(code);
20469
20534
  }
20470
- const base = err instanceof Error ? err.message : String(err);
20471
- return parts.length ? `${base}: ${parts.join(" \u2192 ")}` : base;
20535
+ const base2 = err instanceof Error ? err.message : String(err);
20536
+ return parts.length ? `${base2}: ${parts.join(" \u2192 ")}` : base2;
20472
20537
  }
20473
20538
  function describeUnreachable(err) {
20474
20539
  const reason = classifyUnreachable(err);
@@ -20516,7 +20581,7 @@ __export(auto_update_exports, {
20516
20581
  import { execSync as execSync4, execFileSync as execFileSync3 } from "node:child_process";
20517
20582
  import { readFileSync as readFileSync37, existsSync as existsSync45 } from "node:fs";
20518
20583
  import { fileURLToPath as fileURLToPath2 } from "node:url";
20519
- import { writeFileSync as writeFileSync9, mkdtempSync as mkdtempSync3, rmSync as rmSync5, readdirSync as readdirSync31, statSync as statSync41, mkdirSync as mkdirSync12 } from "node:fs";
20584
+ import { writeFileSync as writeFileSync9, mkdtempSync as mkdtempSync3, rmSync as rmSync5, readdirSync as readdirSync31, statSync as statSync42, mkdirSync as mkdirSync12 } from "node:fs";
20520
20585
  import { join as join48, dirname as dirname19, sep as sep3, posix as pathPosix, win32 as pathWin32 } from "node:path";
20521
20586
  import { tmpdir as tmpdir3, homedir as homedir17 } from "node:os";
20522
20587
  import { createHash as createHash10 } from "node:crypto";
@@ -20548,12 +20613,12 @@ function installedVersion() {
20548
20613
  return null;
20549
20614
  }
20550
20615
  }
20551
- function planAutoUpdate(base, caps, ownVersion2, flag) {
20616
+ function planAutoUpdate(base2, caps, ownVersion2, flag) {
20552
20617
  const rel = caps.cli;
20553
20618
  if (!rel || !rel.version || !rel.sha256) return { update: false, reason: "server advertises no CLI release" };
20554
20619
  if (!isAutoUpdateEnabled(caps.edition, flag)) return { update: false, reason: `auto-update disabled (edition ${caps.edition ?? "?"})` };
20555
20620
  if (compareVersions(rel.version, ownVersion2) <= 0) return { update: false, reason: `already current (own ${ownVersion2} >= server ${rel.version})` };
20556
- return { update: true, reason: `server ${rel.version} > own ${ownVersion2}`, url: tarballUrl(base, rel.version), fallbackUrl: tarballUrl(base), sha256: rel.sha256, from: ownVersion2, to: rel.version };
20621
+ return { update: true, reason: `server ${rel.version} > own ${ownVersion2}`, url: tarballUrl(base2, rel.version), fallbackUrl: tarballUrl(base2), sha256: rel.sha256, from: ownVersion2, to: rel.version };
20557
20622
  }
20558
20623
  function sweepStaleStaging(root = tmpdir3(), now = Date.now()) {
20559
20624
  const MKDTEMP_SUFFIX = /^cr-update-.{6}$/s;
@@ -20569,7 +20634,7 @@ function sweepStaleStaging(root = tmpdir3(), now = Date.now()) {
20569
20634
  if (!MKDTEMP_SUFFIX.test(name)) continue;
20570
20635
  const dir = join48(root, name);
20571
20636
  try {
20572
- const st = statSync41(dir);
20637
+ const st = statSync42(dir);
20573
20638
  if (!st.isDirectory() || now - st.mtimeMs < COLD_MS) continue;
20574
20639
  const inside = readdirSync31(dir);
20575
20640
  if (inside.length > 1 || inside.length === 1 && inside[0] !== "chat-recall.tgz") continue;
@@ -20733,20 +20798,20 @@ function clearUpdateFailures() {
20733
20798
  function stopAutoUpdates() {
20734
20799
  stopRequested = true;
20735
20800
  }
20736
- async function runAutoUpdate(base, authHeaders, ownVersion2, deps) {
20801
+ async function runAutoUpdate(base2, authHeaders, ownVersion2, deps) {
20737
20802
  let caps;
20738
20803
  try {
20739
- const res = await fetchWithTimeout(`${base.replace(/\/+$/, "")}/api/capabilities`, { headers: authHeaders });
20804
+ const res = await fetchWithTimeout(`${base2.replace(/\/+$/, "")}/api/capabilities`, { headers: authHeaders });
20740
20805
  if (!res.ok) return { updated: false, reason: `capabilities HTTP ${res.status}` };
20741
20806
  caps = await res.json();
20742
20807
  } catch (e) {
20743
20808
  return { updated: false, reason: `capabilities unreachable: ${e instanceof Error ? e.message : e}` };
20744
20809
  }
20745
20810
  const effectiveOwn = newerOf(ownVersion2, installedVersion());
20746
- const plan = planAutoUpdate(base, caps, effectiveOwn, process.env.CHAT_RECALL_AUTO_UPDATE);
20811
+ const plan = planAutoUpdate(base2, caps, effectiveOwn, process.env.CHAT_RECALL_AUTO_UPDATE);
20747
20812
  if (!plan.update) {
20748
- if (/disabled|no CLI release/.test(plan.reason) && !reportedStandingSkip.has(base)) {
20749
- reportedStandingSkip.add(base);
20813
+ if (/disabled|no CLI release/.test(plan.reason) && !reportedStandingSkip.has(base2)) {
20814
+ reportedStandingSkip.add(base2);
20750
20815
  try {
20751
20816
  const { reportClientEvent: reportClientEvent3 } = await Promise.resolve().then(() => (init_client_events(), client_events_exports));
20752
20817
  reportClientEvent3("auto_update_skipped", { message: `${plan.reason} (server offers ${caps.cli?.version ?? "?"}, this device runs ${effectiveOwn})` });
@@ -20802,7 +20867,7 @@ var init_auto_update = __esm({
20802
20867
  "use strict";
20803
20868
  init_http();
20804
20869
  init_index_lock();
20805
- tarballUrl = (base, version2) => `${base.replace(/\/+$/, "")}/install/${version2 ? `chat-recall-${version2}.tgz` : "chat-recall.tgz"}`;
20870
+ tarballUrl = (base2, version2) => `${base2.replace(/\/+$/, "")}/install/${version2 ? `chat-recall-${version2}.tgz` : "chat-recall.tgz"}`;
20806
20871
  GIVE_UP_AFTER = 3;
20807
20872
  reportedStandingSkip = /* @__PURE__ */ new Set();
20808
20873
  STOPPING_REASON = "not installed: this process is shutting down";
@@ -20847,7 +20912,7 @@ __export(sync_client_exports, {
20847
20912
  syncSessions: () => syncSessions
20848
20913
  });
20849
20914
  import { join as join49, dirname as dirname20, basename as basename22 } from "node:path";
20850
- import { readFileSync as readFileSync38, writeFileSync as writeFileSync10, mkdirSync as mkdirSync13, mkdtempSync as mkdtempSync4, rmSync as rmSync6, chmodSync as chmodSync6, unlinkSync as unlinkSync3, readdirSync as readdirSync32, statSync as statSync42 } from "node:fs";
20915
+ import { readFileSync as readFileSync38, writeFileSync as writeFileSync10, mkdirSync as mkdirSync13, mkdtempSync as mkdtempSync4, rmSync as rmSync6, chmodSync as chmodSync6, unlinkSync as unlinkSync3, readdirSync as readdirSync32, statSync as statSync43 } from "node:fs";
20851
20916
  import { tmpdir as tmpdir4, hostname as hostname2 } from "node:os";
20852
20917
  import { createHash as createHash11 } from "node:crypto";
20853
20918
  import { fileURLToPath as fileURLToPath3 } from "node:url";
@@ -20910,15 +20975,15 @@ function loadAllCredentials() {
20910
20975
  return [];
20911
20976
  }
20912
20977
  async function fetchTenantSecurityConfig(cred) {
20913
- const base = cred.serverUrl.replace(/\/+$/, "");
20914
- const cached = _securityConfigCache.get(base);
20978
+ const base2 = cred.serverUrl.replace(/\/+$/, "");
20979
+ const cached = _securityConfigCache.get(base2);
20915
20980
  if (cached && Date.now() - cached.fetchedAt < SECURITY_CONFIG_TTL_MS) return cached.config;
20916
20981
  const headers = { "content-type": "application/json" };
20917
20982
  if (cred.token) headers.authorization = `Bearer ${cred.token}`;
20918
20983
  try {
20919
20984
  const [rulesRes, settingsRes] = await Promise.all([
20920
- fetchWithTimeout(`${base}/api/secrets/rules`, { headers }),
20921
- fetchWithTimeout(`${base}/api/teams/security-config`, { headers }).catch(() => null)
20985
+ fetchWithTimeout(`${base2}/api/secrets/rules`, { headers }),
20986
+ fetchWithTimeout(`${base2}/api/teams/security-config`, { headers }).catch(() => null)
20922
20987
  ]);
20923
20988
  let tenantRules = [];
20924
20989
  let rulePackVersion = null;
@@ -20943,18 +21008,18 @@ async function fetchTenantSecurityConfig(cred) {
20943
21008
  const body2 = await settingsRes.json().catch(() => ({}));
20944
21009
  if (typeof body2.verifySecrets === "boolean") verifySecrets = body2.verifySecrets;
20945
21010
  if (typeof body2.telemetry === "boolean") {
20946
- setTelemetryEligible(base, body2.telemetry);
21011
+ setTelemetryEligible(base2, body2.telemetry);
20947
21012
  try {
20948
21013
  const prior = readCollectorHealth()?.telemetryEligible ?? {};
20949
21014
  updateCollectorHealth({
20950
- telemetryEligible: { ...prior, [base]: { allowed: body2.telemetry, at: Date.now() } }
21015
+ telemetryEligible: { ...prior, [base2]: { allowed: body2.telemetry, at: Date.now() } }
20951
21016
  });
20952
21017
  } catch {
20953
21018
  }
20954
21019
  }
20955
21020
  }
20956
21021
  const config2 = { tenantRules, verifySecrets, rulePackVersion };
20957
- _securityConfigCache.set(base, { fetchedAt: Date.now(), config: config2 });
21022
+ _securityConfigCache.set(base2, { fetchedAt: Date.now(), config: config2 });
20958
21023
  return config2;
20959
21024
  } catch {
20960
21025
  return { tenantRules: [], verifySecrets: true, rulePackVersion: null };
@@ -20973,18 +21038,18 @@ function readPersistedSyncConfigs() {
20973
21038
  return {};
20974
21039
  }
20975
21040
  }
20976
- function persistSyncConfig(base, config2) {
21041
+ function persistSyncConfig(base2, config2) {
20977
21042
  try {
20978
21043
  const all = readPersistedSyncConfigs();
20979
- all[base] = { fetchedAt: Date.now(), config: config2 };
21044
+ all[base2] = { fetchedAt: Date.now(), config: config2 };
20980
21045
  mkdirSync13(dirname20(syncConfigCachePath()), { recursive: true });
20981
21046
  writeFileSync10(syncConfigCachePath(), JSON.stringify(all, null, 2));
20982
21047
  } catch {
20983
21048
  }
20984
21049
  }
20985
21050
  async function fetchTenantSyncConfig(cred) {
20986
- const base = cred.serverUrl.replace(/\/+$/, "");
20987
- const cached = _syncConfigCache.get(base);
21051
+ const base2 = cred.serverUrl.replace(/\/+$/, "");
21052
+ const cached = _syncConfigCache.get(base2);
20988
21053
  if (cached && Date.now() - cached.fetchedAt < SECURITY_CONFIG_TTL_MS) return cached.config;
20989
21054
  const headers = { "content-type": "application/json" };
20990
21055
  if (cred.token) headers.authorization = `Bearer ${cred.token}`;
@@ -20992,7 +21057,7 @@ async function fetchTenantSyncConfig(cred) {
20992
21057
  try {
20993
21058
  const sources2 = discoverSessionSources();
20994
21059
  if (sources2.length > 0) {
20995
- await fetchWithTimeout(`${base}/api/sync-config/sources`, {
21060
+ await fetchWithTimeout(`${base2}/api/sync-config/sources`, {
20996
21061
  method: "POST",
20997
21062
  headers,
20998
21063
  body: JSON.stringify({ device: deviceLabel(), sources: sources2 })
@@ -21000,12 +21065,12 @@ async function fetchTenantSyncConfig(cred) {
21000
21065
  }
21001
21066
  } catch {
21002
21067
  }
21003
- const res = await fetchWithTimeout(`${base}/api/sync-config`, { headers });
21068
+ const res = await fetchWithTimeout(`${base2}/api/sync-config`, { headers });
21004
21069
  if (res.status === 404) {
21005
- _syncConfigCache.set(base, { fetchedAt: Date.now(), config: EMPTY_SYNC_CONFIG });
21070
+ _syncConfigCache.set(base2, { fetchedAt: Date.now(), config: EMPTY_SYNC_CONFIG });
21006
21071
  return EMPTY_SYNC_CONFIG;
21007
21072
  }
21008
- if (!res.ok) return lastKnownSyncConfig(base, `HTTP ${res.status}`);
21073
+ if (!res.ok) return lastKnownSyncConfig(base2, `HTTP ${res.status}`);
21009
21074
  const body2 = await res.json().catch(() => ({}));
21010
21075
  const config2 = {
21011
21076
  excludeTools: Array.isArray(body2.excludeTools) ? body2.excludeTools.filter((t) => typeof t === "string") : [],
@@ -21042,22 +21107,22 @@ async function fetchTenantSyncConfig(cred) {
21042
21107
  if (decided > 0) console.error(`[sync] applied ${decided} folder decision(s) from the dashboard`);
21043
21108
  } catch {
21044
21109
  }
21045
- _syncConfigCache.set(base, { fetchedAt: Date.now(), config: config2 });
21046
- persistSyncConfig(base, config2);
21110
+ _syncConfigCache.set(base2, { fetchedAt: Date.now(), config: config2 });
21111
+ persistSyncConfig(base2, config2);
21047
21112
  return config2;
21048
21113
  } catch (err) {
21049
21114
  if (isSyncRulesRefusal(err)) throw err;
21050
- return lastKnownSyncConfig(base, err instanceof Error ? err.message : "request failed");
21115
+ return lastKnownSyncConfig(base2, err instanceof Error ? err.message : "request failed");
21051
21116
  }
21052
21117
  }
21053
- function lastKnownSyncConfig(base, reason) {
21054
- const remembered = _syncConfigCache.get(base) ?? readPersistedSyncConfigs()[base];
21118
+ function lastKnownSyncConfig(base2, reason) {
21119
+ const remembered = _syncConfigCache.get(base2) ?? readPersistedSyncConfigs()[base2];
21055
21120
  if (remembered) {
21056
21121
  console.error(`[sync] could not read server-side sync rules (${reason}) \u2014 applying the last known set from ${new Date(remembered.fetchedAt).toISOString()}`);
21057
21122
  return remembered.config;
21058
21123
  }
21059
21124
  const refusal = new Error(
21060
- `Cannot read the server-side sync rules from ${base} (${reason}), and this machine has never successfully read them. Refusing to sync: uploading without knowing your exclusions could ship a project you told the dashboard to hold back. Fix the server or retry.`
21125
+ `Cannot read the server-side sync rules from ${base2} (${reason}), and this machine has never successfully read them. Refusing to sync: uploading without knowing your exclusions could ship a project you told the dashboard to hold back. Fix the server or retry.`
21061
21126
  );
21062
21127
  refusal[SYNC_RULES_REFUSAL] = true;
21063
21128
  throw refusal;
@@ -21178,25 +21243,25 @@ async function syncSessions(opts = {}) {
21178
21243
  ${errors.join("\n ")}`);
21179
21244
  return { ...agg, perTarget };
21180
21245
  }
21181
- async function postFieldBatch(base, token, rows) {
21246
+ async function postFieldBatch(base2, token, rows) {
21182
21247
  const headers = { "content-type": "application/json" };
21183
21248
  if (token) headers.authorization = `Bearer ${token}`;
21184
21249
  const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
21185
21250
  for (let attempt = 0; ; attempt++) {
21186
- const res = await fetchWithTimeout(`${base}/api/sync`, { method: "POST", headers, body: JSON.stringify({ fields: rows }) }, 6e4);
21251
+ const res = await fetchWithTimeout(`${base2}/api/sync`, { method: "POST", headers, body: JSON.stringify({ fields: rows }) }, 6e4);
21187
21252
  if (res.ok) return;
21188
21253
  const retryable = res.status === 429 || res.status >= 500;
21189
- if (!retryable || attempt >= 5) throw new Error(`${base}: fields batch HTTP ${res.status} ${await res.text().catch(() => "")}`);
21254
+ if (!retryable || attempt >= 5) throw new Error(`${base2}: fields batch HTTP ${res.status} ${await res.text().catch(() => "")}`);
21190
21255
  const ra = Number(res.headers.get("retry-after")) || 0;
21191
21256
  await sleep(ra > 0 ? ra * 1e3 : [500, 1500, 4e3, 8e3, 15e3][Math.min(attempt, 4)]);
21192
21257
  }
21193
21258
  }
21194
21259
  async function reconcileFieldsForTarget(cred, fullRefs, opts = {}) {
21195
- const base = cred.serverUrl.replace(/\/+$/, "");
21196
- const ledger = getSyncedRows(base);
21260
+ const base2 = cred.serverUrl.replace(/\/+$/, "");
21261
+ const ledger = getSyncedRows(base2);
21197
21262
  let pushed = 0, absent = 0, scanned = 0;
21198
21263
  for (const field of SYNC_FIELDS) {
21199
- const needFull = !!opts.force || fieldNeedsFullPass(base, field);
21264
+ const needFull = !!opts.force || fieldNeedsFullPass(base2, field);
21200
21265
  const candidates2 = needFull ? fullRefs() : opts.convRefs ?? fullRefs();
21201
21266
  const send = [];
21202
21267
  const mtimeById = /* @__PURE__ */ new Map();
@@ -21212,15 +21277,15 @@ async function reconcileFieldsForTarget(cred, fullRefs, opts = {}) {
21212
21277
  }
21213
21278
  for (let i = 0; i < send.length; i += 200) {
21214
21279
  const chunk = send.slice(i, i + 200);
21215
- await postFieldBatch(base, cred.token, chunk);
21216
- markFieldCoverage(base, field, chunk.map((r) => ({ id: r.session_id, present: true, mtime: mtimeById.get(r.session_id) ?? 0 })));
21280
+ await postFieldBatch(base2, cred.token, chunk);
21281
+ markFieldCoverage(base2, field, chunk.map((r) => ({ id: r.session_id, present: true, mtime: mtimeById.get(r.session_id) ?? 0 })));
21217
21282
  pushed += chunk.length;
21218
21283
  }
21219
21284
  if (absentIds.length) {
21220
- markFieldCoverage(base, field, absentIds.map((id) => ({ id, present: false, mtime: mtimeById.get(id) ?? 0 })));
21285
+ markFieldCoverage(base2, field, absentIds.map((id) => ({ id, present: false, mtime: mtimeById.get(id) ?? 0 })));
21221
21286
  absent += absentIds.length;
21222
21287
  }
21223
- if (needFull) markFieldFullPassDone(base, field);
21288
+ if (needFull) markFieldFullPassDone(base2, field);
21224
21289
  }
21225
21290
  return { pushed, absent, scanned };
21226
21291
  }
@@ -21258,7 +21323,7 @@ function reapStaleScanDirs(dir = tmpdir4(), maxAgeMs = 6 * 36e5, now = Date.now(
21258
21323
  if (!name.startsWith("cr-batchscan-")) continue;
21259
21324
  const p = join49(dir, name);
21260
21325
  try {
21261
- if (now - statSync42(p).mtimeMs < maxAgeMs) continue;
21326
+ if (now - statSync43(p).mtimeMs < maxAgeMs) continue;
21262
21327
  rmSync6(p, { recursive: true, force: true });
21263
21328
  reaped++;
21264
21329
  } catch {
@@ -21337,25 +21402,25 @@ function serverIngestConcurrency(serverUrl) {
21337
21402
  return advertisedIngestConc.get(serverUrl.replace(/\/$/, "")) ?? null;
21338
21403
  }
21339
21404
  async function verifyServerApi(serverUrl, minApi) {
21340
- const base = serverUrl.replace(/\/$/, "");
21341
- const seen = capsOk.get(base);
21405
+ const base2 = serverUrl.replace(/\/$/, "");
21406
+ const seen = capsOk.get(base2);
21342
21407
  if (seen !== void 0 && Date.now() - seen < CAPS_TTL_MS) return true;
21343
21408
  const { probeServer: probeServer2, probeAdvice: probeAdvice2 } = await Promise.resolve().then(() => (init_server_probe(), server_probe_exports));
21344
- const probe = await probeServer2(base, {
21409
+ const probe = await probeServer2(base2, {
21345
21410
  fetchImpl: ((url, init) => fetchWithTimeout(String(url), init ?? {}))
21346
21411
  });
21347
- if (probe.kind !== "ok") throw new Error(probeAdvice2(probe, base));
21412
+ if (probe.kind !== "ok") throw new Error(probeAdvice2(probe, base2));
21348
21413
  const caps = probe.raw;
21349
21414
  if ((caps.apiVersion ?? 0) < minApi) {
21350
21415
  throw new Error(`server too old: apiVersion ${caps.apiVersion ?? "none"} < required ${minApi} \u2014 update the server image before syncing`);
21351
21416
  }
21352
21417
  const adv = caps.limits?.ingestConcurrencyPerTenant;
21353
21418
  if (typeof adv === "number" && Number.isFinite(adv) && adv >= 1) {
21354
- advertisedIngestConc.set(base, Math.floor(adv));
21419
+ advertisedIngestConc.set(base2, Math.floor(adv));
21355
21420
  }
21356
- if (caps.limits?.acceptsGzipBody === true) advertisedGzipBody.add(base);
21357
- else advertisedGzipBody.delete(base);
21358
- capsOk.set(base, Date.now());
21421
+ if (caps.limits?.acceptsGzipBody === true) advertisedGzipBody.add(base2);
21422
+ else advertisedGzipBody.delete(base2);
21423
+ capsOk.set(base2, Date.now());
21359
21424
  return true;
21360
21425
  }
21361
21426
  async function syncToTarget(cred, opts = {}) {
@@ -21420,7 +21485,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21420
21485
  const ac = new AbortController();
21421
21486
  const timer = setTimeout(() => ac.abort(new Error(`upload timed out after ${UPLOAD_TIMEOUT_MS}ms`)), UPLOAD_TIMEOUT_MS);
21422
21487
  try {
21423
- const res = await fetch(`${base}/api/sync`, {
21488
+ const res = await fetch(`${base2}/api/sync`, {
21424
21489
  method: "POST",
21425
21490
  // No token ⇒ no auth header: a no-auth local server (AUTH_PROVIDER=none)
21426
21491
  // accepts it as the single 'default' tenant.
@@ -21436,26 +21501,26 @@ async function syncToTargetInScope(cred, opts = {}) {
21436
21501
  acceptedUploads.set(cred.serverUrl, (acceptedUploads.get(cred.serverUrl) ?? 0) + 1);
21437
21502
  const body3 = await res.json().catch(() => ({}));
21438
21503
  if (typeof body3.telemetry === "boolean") {
21439
- setTelemetryEligible(base, body3.telemetry);
21504
+ setTelemetryEligible(base2, body3.telemetry);
21440
21505
  try {
21441
21506
  const prior = readCollectorHealth()?.telemetryEligible ?? {};
21442
21507
  updateCollectorHealth({
21443
- telemetryEligible: { ...prior, [base]: { allowed: body3.telemetry, at: Date.now() } }
21508
+ telemetryEligible: { ...prior, [base2]: { allowed: body3.telemetry, at: Date.now() } }
21444
21509
  });
21445
21510
  } catch {
21446
21511
  }
21447
21512
  }
21448
21513
  const adv = body3.limits?.ingestConcurrencyPerTenant;
21449
21514
  if (typeof adv === "number" && Number.isFinite(adv) && adv >= 1) {
21450
- setServerIngestConcurrency(base, Math.floor(adv));
21515
+ setServerIngestConcurrency(base2, Math.floor(adv));
21451
21516
  }
21452
21517
  if (body3.cli && body3.cli.version) {
21453
21518
  const { planAutoUpdate: planAutoUpdate2, runAutoUpdate: runAutoUpdate2, sweepStaleStaging: sweepStaleStaging2 } = await Promise.resolve().then(() => (init_auto_update(), auto_update_exports));
21454
21519
  const authHeaders = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
21455
- const plan = planAutoUpdate2(base, { cli: body3.cli }, ownVersion, process.env.CHAT_RECALL_AUTO_UPDATE);
21520
+ const plan = planAutoUpdate2(base2, { cli: body3.cli }, ownVersion, process.env.CHAT_RECALL_AUTO_UPDATE);
21456
21521
  sweepStaleStaging2();
21457
21522
  if (plan.update) {
21458
- void runAutoUpdate2(base, authHeaders, ownVersion).catch(() => {
21523
+ void runAutoUpdate2(base2, authHeaders, ownVersion).catch(() => {
21459
21524
  });
21460
21525
  }
21461
21526
  }
@@ -21464,7 +21529,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21464
21529
  const retryable = res.status === 429 || res.status >= 500;
21465
21530
  const text = await res.text().catch(() => "");
21466
21531
  if (res.status === 401 || res.status === 403) {
21467
- throw classedError("auth", `server rejected this machine's device token (HTTP ${res.status} \u2014 revoked?). Reconnect with: chat-recall login ${base}`);
21532
+ throw classedError("auth", `server rejected this machine's device token (HTTP ${res.status} \u2014 revoked?). Reconnect with: chat-recall login ${base2}`);
21468
21533
  }
21469
21534
  if (res.status === 402) {
21470
21535
  let detail = text;
@@ -21485,7 +21550,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21485
21550
  const retryAfterS = Number(res.headers.get("retry-after"));
21486
21551
  const waitMs = res.status === 429 && retryAfterS > 0 ? retryAfterS * 1e3 : RETRY_DELAYS_MS[attempt];
21487
21552
  const why = res.status === 524 ? ` \u2014 the proxy cut the request at its time limit; the batch is too big for one request` : "";
21488
- console.error(`[sync] HTTP ${res.status} from ${base}${why} \u2014 backing off ${Math.round(waitMs / 1e3)}s (attempt ${attempt + 1})`);
21553
+ console.error(`[sync] HTTP ${res.status} from ${base2}${why} \u2014 backing off ${Math.round(waitMs / 1e3)}s (attempt ${attempt + 1})`);
21489
21554
  await sleep(waitMs);
21490
21555
  continue;
21491
21556
  } catch (err) {
@@ -21553,11 +21618,11 @@ async function syncToTargetInScope(cred, opts = {}) {
21553
21618
  }
21554
21619
  };
21555
21620
  };
21556
- const base = cred.serverUrl.replace(/\/$/, "");
21557
- const ledger = opts.useLedger ? getSyncedRows(base) : null;
21621
+ const base2 = cred.serverUrl.replace(/\/$/, "");
21622
+ const ledger = opts.useLedger ? getSyncedRows(base2) : null;
21558
21623
  const convBatch = makeBatcher("conversations", 25, false, (rows) => {
21559
21624
  try {
21560
- markSynced(base, rows.map((r) => {
21625
+ markSynced(base2, rows.map((r) => {
21561
21626
  const off = typeof r.from_offset === "number" ? r.from_offset : 0;
21562
21627
  const hash = shippedHash.get(r.session_id);
21563
21628
  return off > 0 ? { id: r.session_id, mtime: r.mtime, offset: off, size: off, hash, acked: true } : { id: r.session_id, mtime: r.mtime, hash };
@@ -21572,7 +21637,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21572
21637
  const ac = new AbortController();
21573
21638
  const timer = setTimeout(() => ac.abort(new Error(`upload timed out after ${UPLOAD_TIMEOUT_MS}ms`)), UPLOAD_TIMEOUT_MS);
21574
21639
  try {
21575
- const res = await fetch(`${base}/api/sync`, {
21640
+ const res = await fetch(`${base2}/api/sync`, {
21576
21641
  method: "POST",
21577
21642
  headers,
21578
21643
  body: JSON.stringify({ conversations: convs }),
@@ -21583,10 +21648,10 @@ async function syncToTargetInScope(cred, opts = {}) {
21583
21648
  if (body2.cli && body2.cli.version) {
21584
21649
  const { planAutoUpdate: planAutoUpdate2, runAutoUpdate: runAutoUpdate2, sweepStaleStaging: sweepStaleStaging2 } = await Promise.resolve().then(() => (init_auto_update(), auto_update_exports));
21585
21650
  const authHeaders = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
21586
- const plan = planAutoUpdate2(base, { cli: body2.cli }, ownVersion, process.env.CHAT_RECALL_AUTO_UPDATE);
21651
+ const plan = planAutoUpdate2(base2, { cli: body2.cli }, ownVersion, process.env.CHAT_RECALL_AUTO_UPDATE);
21587
21652
  sweepStaleStaging2();
21588
21653
  if (plan.update) {
21589
- void runAutoUpdate2(base, authHeaders, ownVersion).catch(() => {
21654
+ void runAutoUpdate2(base2, authHeaders, ownVersion).catch(() => {
21590
21655
  });
21591
21656
  }
21592
21657
  }
@@ -21594,7 +21659,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21594
21659
  const acked = convs.filter((c) => !fullNeeded.has(c.session_id));
21595
21660
  if (acked.length > 0) {
21596
21661
  try {
21597
- markSynced(base, acked.map((c) => ({
21662
+ markSynced(base2, acked.map((c) => ({
21598
21663
  id: c.session_id,
21599
21664
  mtime: c.mtime,
21600
21665
  offset: c.from_offset,
@@ -21618,7 +21683,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21618
21683
  const ac = new AbortController();
21619
21684
  const timer = setTimeout(() => ac.abort(new Error(`upload timed out after ${UPLOAD_TIMEOUT_MS}ms`)), UPLOAD_TIMEOUT_MS);
21620
21685
  try {
21621
- const res = await fetch(`${base}/api/sync`, {
21686
+ const res = await fetch(`${base2}/api/sync`, {
21622
21687
  method: "POST",
21623
21688
  headers,
21624
21689
  body: JSON.stringify({ conversations: [conv] }),
@@ -21631,11 +21696,11 @@ async function syncToTargetInScope(cred, opts = {}) {
21631
21696
  const mtime = conv.mtime;
21632
21697
  try {
21633
21698
  if (!guarded) {
21634
- markSynced(base, [{ id, mtime, offset: conv.from_offset, size: conv.from_offset, acked: true }]);
21699
+ markSynced(base2, [{ id, mtime, offset: conv.from_offset, size: conv.from_offset, acked: true }]);
21635
21700
  } else if (typeof guarded.o === "number" && guarded.o > 0 && guarded.o <= fileSize) {
21636
- markSynced(base, [{ id, mtime, offset: guarded.o, size: guarded.o, acked: true }]);
21701
+ markSynced(base2, [{ id, mtime, offset: guarded.o, size: guarded.o, acked: true }]);
21637
21702
  } else {
21638
- markSynced(base, [{ id, mtime }]);
21703
+ markSynced(base2, [{ id, mtime }]);
21639
21704
  }
21640
21705
  } catch {
21641
21706
  }
@@ -21701,7 +21766,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21701
21766
  const m = process.memoryUsage();
21702
21767
  console.error(`[sync-trace] ${msg} \xB7 heap=${(m.heapUsed / 1048576).toFixed(0)}MB rss=${(m.rss / 1048576).toFixed(0)}MB`);
21703
21768
  } : null;
21704
- trace?.(`walk start: ${slice.length} ref(s) \u2192 ${base}`);
21769
+ trace?.(`walk start: ${slice.length} ref(s) \u2192 ${base2}`);
21705
21770
  if (upload.sessionMeta) {
21706
21771
  try {
21707
21772
  await reconcileFieldsForTarget(
@@ -21716,7 +21781,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21716
21781
  { convRefs: slice }
21717
21782
  );
21718
21783
  } catch (e) {
21719
- console.error(`[sync] field reconcile (${base}): ${e instanceof Error ? e.message : e}`);
21784
+ console.error(`[sync] field reconcile (${base2}): ${e instanceof Error ? e.message : e}`);
21720
21785
  }
21721
21786
  }
21722
21787
  trace?.("field reconcile done");
@@ -21758,7 +21823,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21758
21823
  }
21759
21824
  trace?.("conversation walk start");
21760
21825
  const walkStartedAt = Date.now();
21761
- const firstWalk = (ledger ?? getSyncedRows(base)).size === 0;
21826
+ const firstWalk = (ledger ?? getSyncedRows(base2)).size === 0;
21762
21827
  reportWalkProgress({ done: 0, total: slice.length, startedAt: walkStartedAt, complete: false, first: firstWalk });
21763
21828
  walkProgressForUpload = { done: 0, total: slice.length, complete: false };
21764
21829
  let traceN = 0;
@@ -21798,7 +21863,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21798
21863
  continue;
21799
21864
  } else {
21800
21865
  try {
21801
- markSynced(base, [{ id: ref.prefixedId, mtime: ref.mtime }]);
21866
+ markSynced(base2, [{ id: ref.prefixedId, mtime: ref.mtime }]);
21802
21867
  } catch {
21803
21868
  }
21804
21869
  skipped++;
@@ -21821,7 +21886,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21821
21886
  const off = getBackendForId(ref.prefixedId)?.fileSize?.(ref.rawId) ?? 0;
21822
21887
  const priorCursor = ackRow?.s ?? 0;
21823
21888
  const safeToAck = off > 0 && off <= priorCursor;
21824
- markSynced(base, [safeToAck ? { id: ref.prefixedId, mtime: ref.mtime, offset: off, size: off, hash: built.srcHash, acked: true } : { id: ref.prefixedId, mtime: ref.mtime, hash: built.srcHash }]);
21889
+ markSynced(base2, [safeToAck ? { id: ref.prefixedId, mtime: ref.mtime, offset: off, size: off, hash: built.srcHash, acked: true } : { id: ref.prefixedId, mtime: ref.mtime, hash: built.srcHash }]);
21825
21890
  } catch {
21826
21891
  }
21827
21892
  }
@@ -21831,7 +21896,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21831
21896
  if (!built) {
21832
21897
  if (ledger) {
21833
21898
  try {
21834
- markSynced(base, [{ id: ref.prefixedId, mtime: ref.mtime }]);
21899
+ markSynced(base2, [{ id: ref.prefixedId, mtime: ref.mtime }]);
21835
21900
  } catch {
21836
21901
  }
21837
21902
  }
@@ -21888,7 +21953,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21888
21953
  walked++;
21889
21954
  if (walked % 250 === 0) console.error(`[sync] ${walked}/${slice.length} sessions\u2026`);
21890
21955
  }
21891
- const itemVersions = loadItemVersions(base);
21956
+ const itemVersions = loadItemVersions(base2);
21892
21957
  const seenTools = /* @__PURE__ */ new Set();
21893
21958
  const seenItemKeys = /* @__PURE__ */ new Map();
21894
21959
  const registry = buildSourceRegistry();
@@ -21982,7 +22047,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21982
22047
  await appendFlush();
21983
22048
  for (const id of appendResults.fullResyncNeeded) {
21984
22049
  try {
21985
- markFullResync(base, id);
22050
+ markFullResync(base2, id);
21986
22051
  } catch {
21987
22052
  }
21988
22053
  }
@@ -21995,7 +22060,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21995
22060
  await findingsBatch.drain();
21996
22061
  await drainInflight();
21997
22062
  {
21998
- const sentHashes = loadInventoryHashes(base);
22063
+ const sentHashes = loadInventoryHashes(base2);
21999
22064
  const entries = [];
22000
22065
  const hashes = {};
22001
22066
  for (const [sourceType, ids] of inventory) {
@@ -22009,7 +22074,7 @@ async function syncToTargetInScope(cred, opts = {}) {
22009
22074
  if (entries.length > 0) {
22010
22075
  try {
22011
22076
  await post({ inventory: entries });
22012
- saveInventoryHashes(base, hashes);
22077
+ saveInventoryHashes(base2, hashes);
22013
22078
  } catch (err) {
22014
22079
  console.error(`[sync] toolkit inventory not sent (it is retried next sync): ${err instanceof Error ? err.message : err}`);
22015
22080
  }
@@ -22020,7 +22085,7 @@ async function syncToTargetInScope(cred, opts = {}) {
22020
22085
  const rec = {};
22021
22086
  for (const t of seenTools) rec[t] = extractorVersionForTool(t);
22022
22087
  for (const [k, v] of seenItemKeys) rec[k] = v;
22023
- saveItemVersions(base, rec);
22088
+ saveItemVersions(base2, rec);
22024
22089
  } catch {
22025
22090
  }
22026
22091
  }
@@ -22033,9 +22098,9 @@ async function syncToTargetInScope(cred, opts = {}) {
22033
22098
  }
22034
22099
  if (tombstones.length > 0) {
22035
22100
  await post({ tombstones });
22036
- const data = getLedgerData(base);
22101
+ const data = getLedgerData(base2);
22037
22102
  for (const t of tombstones) delete data[t.session_id];
22038
- persistLedgerData(base, data);
22103
+ persistLedgerData(base2, data);
22039
22104
  }
22040
22105
  }
22041
22106
  if (opts.prune) await post({ prune_empty_sessions: true });
@@ -22506,7 +22571,7 @@ var init_sync_client = __esm({
22506
22571
  ownVersion = JSON.parse(readFileSync38(join49(dir, "../package.json"), "utf-8")).version || ownVersion;
22507
22572
  } catch {
22508
22573
  try {
22509
- if (true) ownVersion = "0.7.14";
22574
+ if (true) ownVersion = "0.7.15";
22510
22575
  } catch {
22511
22576
  }
22512
22577
  }
@@ -22665,9 +22730,9 @@ async function refreshUpdateCheck(force = false) {
22665
22730
  const { loadAllCredentials: loadAllCredentials2 } = await Promise.resolve().then(() => (init_sync_client(), sync_client_exports));
22666
22731
  for (const cred of loadAllCredentials2()) {
22667
22732
  if (!cred.serverUrl) continue;
22668
- const base = cred.serverUrl.replace(/\/+$/, "");
22733
+ const base2 = cred.serverUrl.replace(/\/+$/, "");
22669
22734
  try {
22670
- const res = await fetchWithTimeout(`${base}/api/capabilities`, {
22735
+ const res = await fetchWithTimeout(`${base2}/api/capabilities`, {
22671
22736
  headers: cred.token ? { authorization: `Bearer ${cred.token}` } : {}
22672
22737
  }, 5e3);
22673
22738
  if (!res.ok) continue;
@@ -23056,7 +23121,7 @@ __export(install_skills_exports, {
23056
23121
  skillsSourceDir: () => skillsSourceDir,
23057
23122
  uninstallSkills: () => uninstallSkills
23058
23123
  });
23059
- import { readdirSync as readdirSync33, existsSync as existsSync47, mkdirSync as mkdirSync15, rmSync as rmSync8, cpSync, writeFileSync as writeFileSync13, readFileSync as readFileSync42, statSync as statSync43, realpathSync as realpathSync4 } from "fs";
23124
+ import { readdirSync as readdirSync33, existsSync as existsSync47, mkdirSync as mkdirSync15, rmSync as rmSync8, cpSync, writeFileSync as writeFileSync13, readFileSync as readFileSync42, statSync as statSync44, realpathSync as realpathSync4 } from "fs";
23060
23125
  import { createHash as createHash12 } from "crypto";
23061
23126
  import { join as join52, basename as basename23 } from "path";
23062
23127
  function skillsSourceDir() {
@@ -23297,18 +23362,18 @@ function usableDir(dir) {
23297
23362
  if (!isDir(dir)) {
23298
23363
  const missing = [];
23299
23364
  let cur = dir;
23300
- let base = false;
23365
+ let base2 = false;
23301
23366
  while (missing.length < MAX_MISSING_LEVELS) {
23302
23367
  const parent = dirname(cur);
23303
23368
  if (parent === cur) break;
23304
23369
  missing.push(cur);
23305
23370
  if (isDir(parent)) {
23306
- base = true;
23371
+ base2 = true;
23307
23372
  break;
23308
23373
  }
23309
23374
  cur = parent;
23310
23375
  }
23311
- if (!base) return false;
23376
+ if (!base2) return false;
23312
23377
  for (let i = missing.length - 1; i >= 0; i--) {
23313
23378
  try {
23314
23379
  mkdirSync(missing[i]);
@@ -29497,7 +29562,7 @@ function installCrashGuards() {
29497
29562
  reportClientEvent2("mcp_crash", { message: err.stack || err.message });
29498
29563
  });
29499
29564
  }
29500
- var RELAY_VERSION = true ? "0.7.14" : "0.0.0";
29565
+ var RELAY_VERSION = true ? "0.7.15" : "0.0.0";
29501
29566
  function daemonIdleSecs() {
29502
29567
  const raw = process.env.CHAT_RECALL_DAEMON_IDLE_SECS;
29503
29568
  if (raw === void 0) return 900;