chat-recall 0.7.13 → 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);
@@ -12022,12 +12022,14 @@ function lineKey(line) {
12022
12022
  try {
12023
12023
  const o = JSON.parse(line);
12024
12024
  if (typeof o?.uuid === "string" && o.uuid)
12025
- return { key: `u:${o.uuid}`, singleton: false };
12026
- if (typeof o?.type === "string" && SINGLETON_META.has(o.type))
12027
- return { key: `m:${o.type}`, singleton: true };
12025
+ return { key: `u:${o.uuid}`, meta: false, json: true };
12026
+ return { key: `h:${sha1(line)}`, meta: typeof o?.type === "string" && STATE_META.has(o.type), json: true };
12028
12027
  } catch {
12029
12028
  }
12030
- return { key: `h:${sha1(line)}`, singleton: false };
12029
+ return { key: `h:${sha1(line)}`, meta: false, json: false };
12030
+ }
12031
+ function isHalfWritten(line, currentLines) {
12032
+ return currentLines.some((c) => c.length > line.length && c.startsWith(line));
12031
12033
  }
12032
12034
  function mergeLineText(shadowText, currentText) {
12033
12035
  const shadowLines = shadowText.split("\n").filter((l) => l.trim());
@@ -12035,27 +12037,24 @@ function mergeLineText(shadowText, currentText) {
12035
12037
  const currentKeys = /* @__PURE__ */ new Set();
12036
12038
  for (const l of currentLines)
12037
12039
  currentKeys.add(lineKey(l).key);
12038
- const shadowKeys = /* @__PURE__ */ new Set();
12039
- for (const l of shadowLines)
12040
- shadowKeys.add(lineKey(l).key);
12041
- let recovered = 0;
12042
- for (const k of shadowKeys)
12043
- if (!currentKeys.has(k))
12044
- recovered++;
12045
- if (recovered === 0) {
12046
- return { text: currentText.endsWith("\n") ? currentText : currentText + "\n", recovered: 0, totalRecords: currentKeys.size };
12047
- }
12048
- const out = [];
12049
- const emitted = /* @__PURE__ */ new Set();
12040
+ const kept = [];
12041
+ const keptKeys = /* @__PURE__ */ new Set();
12042
+ const counted = /* @__PURE__ */ new Set();
12050
12043
  for (const l of shadowLines) {
12051
- const { key: key2, singleton } = lineKey(l);
12052
- if (singleton && currentKeys.has(key2))
12053
- continue;
12054
- if (emitted.has(key2))
12044
+ const { key: key2, meta, json } = lineKey(l);
12045
+ if (!json && isHalfWritten(l, currentLines))
12055
12046
  continue;
12056
- out.push(l);
12057
- emitted.add(key2);
12047
+ kept.push(l);
12048
+ keptKeys.add(key2);
12049
+ if (!meta && !currentKeys.has(key2))
12050
+ counted.add(key2);
12058
12051
  }
12052
+ const recovered = counted.size;
12053
+ if (recovered === 0) {
12054
+ return { text: currentText.endsWith("\n") ? currentText : currentText + "\n", recovered: 0, totalRecords: currentKeys.size };
12055
+ }
12056
+ const out = [...kept];
12057
+ const emitted = keptKeys;
12059
12058
  for (const l of currentLines) {
12060
12059
  const { key: key2 } = lineKey(l);
12061
12060
  if (emitted.has(key2))
@@ -12185,14 +12184,14 @@ function shadowUncompressedBytes(tool, rawId) {
12185
12184
  }
12186
12185
  }
12187
12186
  }
12188
- var WHOLE_FILE_TOOLS, SINGLETON_META;
12187
+ var WHOLE_FILE_TOOLS, STATE_META;
12189
12188
  var init_shadow = __esm({
12190
12189
  "../engine/dist/transcript/shadow.js"() {
12191
12190
  "use strict";
12192
12191
  init_paths();
12193
12192
  init_raw();
12194
12193
  WHOLE_FILE_TOOLS = /* @__PURE__ */ new Set(["cursor"]);
12195
- SINGLETON_META = /* @__PURE__ */ new Set(["mode", "permission-mode", "ai-title", "last-prompt", "pr-link", "summary"]);
12194
+ STATE_META = /* @__PURE__ */ new Set(["mode", "permission-mode", "ai-title", "last-prompt", "pr-link", "summary"]);
12196
12195
  }
12197
12196
  });
12198
12197
 
@@ -13291,8 +13290,8 @@ function serverRulePackVersion() {
13291
13290
  return serverPack ? serverPack.version || "unversioned" : null;
13292
13291
  }
13293
13292
  function activeRules() {
13294
- const base = settingsView().rules;
13295
- 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;
13296
13295
  }
13297
13296
  function isRedactionEnabled() {
13298
13297
  const env = isEnvRedactionRequested();
@@ -14155,17 +14154,17 @@ async function collectCode(opts) {
14155
14154
  return r;
14156
14155
  };
14157
14156
  log6(`indexing ${ws} + analyses \u2026`);
14158
- const base = await runMcp(bin, ws, [
14157
+ const base2 = await runMcp(bin, ws, [
14159
14158
  call(1, "index_workspace", { path: ws }),
14160
14159
  call(2, "status"),
14161
14160
  call(3, "get_tree"),
14162
14161
  ...ANALYSES.map((a, i) => call(10 + i, "analyze", { analysis: a }))
14163
14162
  ]);
14164
- const st = parseJson(base, 2, {});
14165
- const tree = parseJson(base, 3, []);
14163
+ const st = parseJson(base2, 2, {});
14164
+ const tree = parseJson(base2, 3, []);
14166
14165
  const A = {};
14167
14166
  ANALYSES.forEach((a, i) => {
14168
- A[a] = parseJson(base, 10 + i, {});
14167
+ A[a] = parseJson(base2, 10 + i, {});
14169
14168
  });
14170
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;
14171
14170
  if (tree.length === 0) {
@@ -19453,38 +19452,100 @@ var init_extractor_version = __esm({
19453
19452
  });
19454
19453
 
19455
19454
  // src/sync-ledger.ts
19456
- 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";
19457
19456
  import { join as join46, dirname as dirname17 } from "node:path";
19458
19457
  function toRow(entry) {
19459
19458
  if (entry === void 0) return void 0;
19460
19459
  return typeof entry === "number" ? { m: entry, v: 0 } : entry;
19461
19460
  }
19462
- function load() {
19463
- if (cache3) return cache3;
19461
+ function stampOf(path2) {
19464
19462
  try {
19465
- const parsed = JSON.parse(readFileSync34(ledgerPath(), "utf-8"));
19466
- cache3 = parsed && typeof parsed === "object" ? parsed : {};
19463
+ const st = statSync40(path2);
19464
+ return `${st.mtimeMs}:${st.size}`;
19467
19465
  } catch {
19468
- cache3 = {};
19466
+ return null;
19467
+ }
19468
+ }
19469
+ function readDisk(path2) {
19470
+ try {
19471
+ const parsed = JSON.parse(readFileSync34(path2, "utf-8"));
19472
+ return parsed && typeof parsed === "object" ? parsed : {};
19473
+ } catch {
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
+ }
19469
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;
19470
19528
  return cache3;
19471
19529
  }
19472
- function persistNow(data) {
19530
+ function persistNow() {
19473
19531
  const path2 = ledgerPath();
19474
19532
  mkdirSync10(dirname17(path2), { recursive: true });
19475
- const tmp = `${path2}.tmp`;
19476
- writeFileSync7(tmp, JSON.stringify(data));
19533
+ load();
19534
+ const tmp = `${path2}.tmp-${process.pid}`;
19535
+ writeFileSync7(tmp, JSON.stringify(cache3 ?? {}));
19477
19536
  renameSync5(tmp, path2);
19537
+ base = snapshot(cache3 ?? {});
19538
+ diskStamp = stampOf(path2);
19478
19539
  pendingWrite = false;
19479
19540
  }
19480
- function persist(data) {
19541
+ function persist(_data) {
19481
19542
  pendingWrite = true;
19482
19543
  if (flushTimer) return;
19483
19544
  flushTimer = setTimeout(() => {
19484
19545
  flushTimer = null;
19485
19546
  if (pendingWrite) {
19486
19547
  try {
19487
- persistNow(data);
19548
+ persistNow();
19488
19549
  } catch {
19489
19550
  }
19490
19551
  }
@@ -19518,7 +19579,7 @@ function pruneLedgerTargets(configuredServers) {
19518
19579
  }
19519
19580
  const rows = names.reduce((n, s) => n + Object.keys(orphans[s]).length, 0);
19520
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.`);
19521
- persistNow(data);
19582
+ persistNow();
19522
19583
  return names.length;
19523
19584
  }
19524
19585
  function flushLedger() {
@@ -19527,7 +19588,7 @@ function flushLedger() {
19527
19588
  flushTimer = null;
19528
19589
  }
19529
19590
  if (!pendingWrite || !cache3) return;
19530
- persistNow(cache3);
19591
+ persistNow();
19531
19592
  }
19532
19593
  function loadItemVersionsAll() {
19533
19594
  if (itemVersionsCache) return itemVersionsCache;
@@ -19603,13 +19664,13 @@ function markSynced(server, rows) {
19603
19664
  const o = (cursorFromCaller ? r.offset : void 0) ?? prevOS.o ?? 0;
19604
19665
  const s = (cursorFromCaller ? r.size : void 0) ?? prevOS.s ?? 0;
19605
19666
  const ev = extractorVersionForId(r.id);
19606
- 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 };
19607
19668
  if (o > 0 || s > 0) {
19608
- base.o = o;
19609
- base.s = s;
19669
+ base2.o = o;
19670
+ base2.s = s;
19610
19671
  }
19611
- if (r.hash !== void 0) base.h = r.hash;
19612
- forServer[r.id] = base;
19672
+ if (r.hash !== void 0) base2.h = r.hash;
19673
+ forServer[r.id] = base2;
19613
19674
  }
19614
19675
  persist(data);
19615
19676
  }
@@ -19684,7 +19745,7 @@ function syncMode(row, mtime, fileSize, extractorVersion, isAppendOnly) {
19684
19745
  if (row.m >= Math.floor(mtime)) return "skip";
19685
19746
  return "full";
19686
19747
  }
19687
- 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;
19688
19749
  var init_sync_ledger = __esm({
19689
19750
  "src/sync-ledger.ts"() {
19690
19751
  "use strict";
@@ -19692,6 +19753,9 @@ var init_sync_ledger = __esm({
19692
19753
  init_extractor_version();
19693
19754
  ledgerPath = () => join46(getDataDir(), "sync-ledger.json");
19694
19755
  cache3 = null;
19756
+ base = /* @__PURE__ */ new Map();
19757
+ diskStamp = null;
19758
+ rowKey = (server, id) => `${server}\0${id}`;
19695
19759
  LEDGER_FLUSH_MS = 2e3;
19696
19760
  pendingWrite = false;
19697
19761
  flushTimer = null;
@@ -19730,7 +19794,7 @@ var init_sync_fields = __esm({
19730
19794
  });
19731
19795
 
19732
19796
  // ../engine/dist/core/index-lock.js
19733
- 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";
19734
19798
  import { dirname as dirname18, join as join47 } from "path";
19735
19799
  function acquireIndexLock(opts) {
19736
19800
  const lockPath = lockFilePath(opts.file);
@@ -19780,7 +19844,7 @@ function lockFilePath(file = ".compact.lock") {
19780
19844
  }
19781
19845
  function stealStaleLock(lockPath, staleAfterMs) {
19782
19846
  try {
19783
- const s = statSync40(lockPath);
19847
+ const s = statSync41(lockPath);
19784
19848
  const age = Date.now() - s.mtimeMs;
19785
19849
  let payload;
19786
19850
  try {
@@ -19846,7 +19910,7 @@ var init_http = __esm({
19846
19910
  CLI_VERSION = JSON.parse(readFileSync36(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
19847
19911
  } catch {
19848
19912
  try {
19849
- if (true) CLI_VERSION = "0.7.13";
19913
+ if (true) CLI_VERSION = "0.7.15";
19850
19914
  } catch {
19851
19915
  }
19852
19916
  }
@@ -20344,7 +20408,7 @@ var init_telemetry = __esm({
20344
20408
  init_sync_client();
20345
20409
  cliVersion2 = () => {
20346
20410
  try {
20347
- return true ? "0.7.13" : "dev";
20411
+ return true ? "0.7.15" : "dev";
20348
20412
  } catch {
20349
20413
  return "dev";
20350
20414
  }
@@ -20367,11 +20431,11 @@ __export(server_probe_exports, {
20367
20431
  function probeOk(r) {
20368
20432
  return r.kind === "ok" && r.apiVersion >= 2;
20369
20433
  }
20370
- async function probeServer(base, opts = {}) {
20434
+ async function probeServer(base2, opts = {}) {
20371
20435
  const f = opts.fetchImpl || fetch;
20372
20436
  let res;
20373
20437
  try {
20374
- res = await f(`${base.replace(/\/+$/, "")}/api/capabilities`, {
20438
+ res = await f(`${base2.replace(/\/+$/, "")}/api/capabilities`, {
20375
20439
  signal: AbortSignal.timeout(opts.timeoutMs ?? 1e4)
20376
20440
  });
20377
20441
  } catch (err) {
@@ -20408,34 +20472,34 @@ async function probeServer(base, opts = {}) {
20408
20472
  raw: parsed
20409
20473
  };
20410
20474
  }
20411
- function probeAdvice(r, base) {
20475
+ function probeAdvice(r, base2) {
20412
20476
  switch (r.kind) {
20413
20477
  case "ok":
20414
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`;
20415
20479
  case "moved":
20416
- 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>\``;
20417
20481
  case "unauthorized":
20418
- 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 + "`";
20419
20483
  case "server_error":
20420
- 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.`;
20421
20485
  case "not_api":
20422
- 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`;
20423
20487
  case "unreachable":
20424
20488
  switch (r.reason) {
20425
20489
  case "dns":
20426
- 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`;
20427
20491
  case "refused":
20428
- 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`;
20429
20493
  case "tls":
20430
- 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.`;
20431
20495
  case "timeout":
20432
- 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`;
20433
20497
  case "reset":
20434
- 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`;
20435
20499
  case "bad_port":
20436
- 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`;
20437
20501
  default:
20438
- 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`;
20439
20503
  }
20440
20504
  }
20441
20505
  }
@@ -20468,8 +20532,8 @@ function describeCause(err) {
20468
20532
  const code = e.code;
20469
20533
  if (typeof code === "string" && code && !parts.includes(code)) parts.push(code);
20470
20534
  }
20471
- const base = err instanceof Error ? err.message : String(err);
20472
- 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;
20473
20537
  }
20474
20538
  function describeUnreachable(err) {
20475
20539
  const reason = classifyUnreachable(err);
@@ -20517,7 +20581,7 @@ __export(auto_update_exports, {
20517
20581
  import { execSync as execSync4, execFileSync as execFileSync3 } from "node:child_process";
20518
20582
  import { readFileSync as readFileSync37, existsSync as existsSync45 } from "node:fs";
20519
20583
  import { fileURLToPath as fileURLToPath2 } from "node:url";
20520
- 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";
20521
20585
  import { join as join48, dirname as dirname19, sep as sep3, posix as pathPosix, win32 as pathWin32 } from "node:path";
20522
20586
  import { tmpdir as tmpdir3, homedir as homedir17 } from "node:os";
20523
20587
  import { createHash as createHash10 } from "node:crypto";
@@ -20549,12 +20613,12 @@ function installedVersion() {
20549
20613
  return null;
20550
20614
  }
20551
20615
  }
20552
- function planAutoUpdate(base, caps, ownVersion2, flag) {
20616
+ function planAutoUpdate(base2, caps, ownVersion2, flag) {
20553
20617
  const rel = caps.cli;
20554
20618
  if (!rel || !rel.version || !rel.sha256) return { update: false, reason: "server advertises no CLI release" };
20555
20619
  if (!isAutoUpdateEnabled(caps.edition, flag)) return { update: false, reason: `auto-update disabled (edition ${caps.edition ?? "?"})` };
20556
20620
  if (compareVersions(rel.version, ownVersion2) <= 0) return { update: false, reason: `already current (own ${ownVersion2} >= server ${rel.version})` };
20557
- 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 };
20558
20622
  }
20559
20623
  function sweepStaleStaging(root = tmpdir3(), now = Date.now()) {
20560
20624
  const MKDTEMP_SUFFIX = /^cr-update-.{6}$/s;
@@ -20570,7 +20634,7 @@ function sweepStaleStaging(root = tmpdir3(), now = Date.now()) {
20570
20634
  if (!MKDTEMP_SUFFIX.test(name)) continue;
20571
20635
  const dir = join48(root, name);
20572
20636
  try {
20573
- const st = statSync41(dir);
20637
+ const st = statSync42(dir);
20574
20638
  if (!st.isDirectory() || now - st.mtimeMs < COLD_MS) continue;
20575
20639
  const inside = readdirSync31(dir);
20576
20640
  if (inside.length > 1 || inside.length === 1 && inside[0] !== "chat-recall.tgz") continue;
@@ -20734,20 +20798,20 @@ function clearUpdateFailures() {
20734
20798
  function stopAutoUpdates() {
20735
20799
  stopRequested = true;
20736
20800
  }
20737
- async function runAutoUpdate(base, authHeaders, ownVersion2, deps) {
20801
+ async function runAutoUpdate(base2, authHeaders, ownVersion2, deps) {
20738
20802
  let caps;
20739
20803
  try {
20740
- const res = await fetchWithTimeout(`${base.replace(/\/+$/, "")}/api/capabilities`, { headers: authHeaders });
20804
+ const res = await fetchWithTimeout(`${base2.replace(/\/+$/, "")}/api/capabilities`, { headers: authHeaders });
20741
20805
  if (!res.ok) return { updated: false, reason: `capabilities HTTP ${res.status}` };
20742
20806
  caps = await res.json();
20743
20807
  } catch (e) {
20744
20808
  return { updated: false, reason: `capabilities unreachable: ${e instanceof Error ? e.message : e}` };
20745
20809
  }
20746
20810
  const effectiveOwn = newerOf(ownVersion2, installedVersion());
20747
- 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);
20748
20812
  if (!plan.update) {
20749
- if (/disabled|no CLI release/.test(plan.reason) && !reportedStandingSkip.has(base)) {
20750
- reportedStandingSkip.add(base);
20813
+ if (/disabled|no CLI release/.test(plan.reason) && !reportedStandingSkip.has(base2)) {
20814
+ reportedStandingSkip.add(base2);
20751
20815
  try {
20752
20816
  const { reportClientEvent: reportClientEvent3 } = await Promise.resolve().then(() => (init_client_events(), client_events_exports));
20753
20817
  reportClientEvent3("auto_update_skipped", { message: `${plan.reason} (server offers ${caps.cli?.version ?? "?"}, this device runs ${effectiveOwn})` });
@@ -20803,7 +20867,7 @@ var init_auto_update = __esm({
20803
20867
  "use strict";
20804
20868
  init_http();
20805
20869
  init_index_lock();
20806
- 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"}`;
20807
20871
  GIVE_UP_AFTER = 3;
20808
20872
  reportedStandingSkip = /* @__PURE__ */ new Set();
20809
20873
  STOPPING_REASON = "not installed: this process is shutting down";
@@ -20848,7 +20912,7 @@ __export(sync_client_exports, {
20848
20912
  syncSessions: () => syncSessions
20849
20913
  });
20850
20914
  import { join as join49, dirname as dirname20, basename as basename22 } from "node:path";
20851
- 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";
20852
20916
  import { tmpdir as tmpdir4, hostname as hostname2 } from "node:os";
20853
20917
  import { createHash as createHash11 } from "node:crypto";
20854
20918
  import { fileURLToPath as fileURLToPath3 } from "node:url";
@@ -20911,15 +20975,15 @@ function loadAllCredentials() {
20911
20975
  return [];
20912
20976
  }
20913
20977
  async function fetchTenantSecurityConfig(cred) {
20914
- const base = cred.serverUrl.replace(/\/+$/, "");
20915
- const cached = _securityConfigCache.get(base);
20978
+ const base2 = cred.serverUrl.replace(/\/+$/, "");
20979
+ const cached = _securityConfigCache.get(base2);
20916
20980
  if (cached && Date.now() - cached.fetchedAt < SECURITY_CONFIG_TTL_MS) return cached.config;
20917
20981
  const headers = { "content-type": "application/json" };
20918
20982
  if (cred.token) headers.authorization = `Bearer ${cred.token}`;
20919
20983
  try {
20920
20984
  const [rulesRes, settingsRes] = await Promise.all([
20921
- fetchWithTimeout(`${base}/api/secrets/rules`, { headers }),
20922
- 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)
20923
20987
  ]);
20924
20988
  let tenantRules = [];
20925
20989
  let rulePackVersion = null;
@@ -20944,18 +21008,18 @@ async function fetchTenantSecurityConfig(cred) {
20944
21008
  const body2 = await settingsRes.json().catch(() => ({}));
20945
21009
  if (typeof body2.verifySecrets === "boolean") verifySecrets = body2.verifySecrets;
20946
21010
  if (typeof body2.telemetry === "boolean") {
20947
- setTelemetryEligible(base, body2.telemetry);
21011
+ setTelemetryEligible(base2, body2.telemetry);
20948
21012
  try {
20949
21013
  const prior = readCollectorHealth()?.telemetryEligible ?? {};
20950
21014
  updateCollectorHealth({
20951
- telemetryEligible: { ...prior, [base]: { allowed: body2.telemetry, at: Date.now() } }
21015
+ telemetryEligible: { ...prior, [base2]: { allowed: body2.telemetry, at: Date.now() } }
20952
21016
  });
20953
21017
  } catch {
20954
21018
  }
20955
21019
  }
20956
21020
  }
20957
21021
  const config2 = { tenantRules, verifySecrets, rulePackVersion };
20958
- _securityConfigCache.set(base, { fetchedAt: Date.now(), config: config2 });
21022
+ _securityConfigCache.set(base2, { fetchedAt: Date.now(), config: config2 });
20959
21023
  return config2;
20960
21024
  } catch {
20961
21025
  return { tenantRules: [], verifySecrets: true, rulePackVersion: null };
@@ -20974,18 +21038,18 @@ function readPersistedSyncConfigs() {
20974
21038
  return {};
20975
21039
  }
20976
21040
  }
20977
- function persistSyncConfig(base, config2) {
21041
+ function persistSyncConfig(base2, config2) {
20978
21042
  try {
20979
21043
  const all = readPersistedSyncConfigs();
20980
- all[base] = { fetchedAt: Date.now(), config: config2 };
21044
+ all[base2] = { fetchedAt: Date.now(), config: config2 };
20981
21045
  mkdirSync13(dirname20(syncConfigCachePath()), { recursive: true });
20982
21046
  writeFileSync10(syncConfigCachePath(), JSON.stringify(all, null, 2));
20983
21047
  } catch {
20984
21048
  }
20985
21049
  }
20986
21050
  async function fetchTenantSyncConfig(cred) {
20987
- const base = cred.serverUrl.replace(/\/+$/, "");
20988
- const cached = _syncConfigCache.get(base);
21051
+ const base2 = cred.serverUrl.replace(/\/+$/, "");
21052
+ const cached = _syncConfigCache.get(base2);
20989
21053
  if (cached && Date.now() - cached.fetchedAt < SECURITY_CONFIG_TTL_MS) return cached.config;
20990
21054
  const headers = { "content-type": "application/json" };
20991
21055
  if (cred.token) headers.authorization = `Bearer ${cred.token}`;
@@ -20993,7 +21057,7 @@ async function fetchTenantSyncConfig(cred) {
20993
21057
  try {
20994
21058
  const sources2 = discoverSessionSources();
20995
21059
  if (sources2.length > 0) {
20996
- await fetchWithTimeout(`${base}/api/sync-config/sources`, {
21060
+ await fetchWithTimeout(`${base2}/api/sync-config/sources`, {
20997
21061
  method: "POST",
20998
21062
  headers,
20999
21063
  body: JSON.stringify({ device: deviceLabel(), sources: sources2 })
@@ -21001,12 +21065,12 @@ async function fetchTenantSyncConfig(cred) {
21001
21065
  }
21002
21066
  } catch {
21003
21067
  }
21004
- const res = await fetchWithTimeout(`${base}/api/sync-config`, { headers });
21068
+ const res = await fetchWithTimeout(`${base2}/api/sync-config`, { headers });
21005
21069
  if (res.status === 404) {
21006
- _syncConfigCache.set(base, { fetchedAt: Date.now(), config: EMPTY_SYNC_CONFIG });
21070
+ _syncConfigCache.set(base2, { fetchedAt: Date.now(), config: EMPTY_SYNC_CONFIG });
21007
21071
  return EMPTY_SYNC_CONFIG;
21008
21072
  }
21009
- if (!res.ok) return lastKnownSyncConfig(base, `HTTP ${res.status}`);
21073
+ if (!res.ok) return lastKnownSyncConfig(base2, `HTTP ${res.status}`);
21010
21074
  const body2 = await res.json().catch(() => ({}));
21011
21075
  const config2 = {
21012
21076
  excludeTools: Array.isArray(body2.excludeTools) ? body2.excludeTools.filter((t) => typeof t === "string") : [],
@@ -21043,22 +21107,22 @@ async function fetchTenantSyncConfig(cred) {
21043
21107
  if (decided > 0) console.error(`[sync] applied ${decided} folder decision(s) from the dashboard`);
21044
21108
  } catch {
21045
21109
  }
21046
- _syncConfigCache.set(base, { fetchedAt: Date.now(), config: config2 });
21047
- persistSyncConfig(base, config2);
21110
+ _syncConfigCache.set(base2, { fetchedAt: Date.now(), config: config2 });
21111
+ persistSyncConfig(base2, config2);
21048
21112
  return config2;
21049
21113
  } catch (err) {
21050
21114
  if (isSyncRulesRefusal(err)) throw err;
21051
- return lastKnownSyncConfig(base, err instanceof Error ? err.message : "request failed");
21115
+ return lastKnownSyncConfig(base2, err instanceof Error ? err.message : "request failed");
21052
21116
  }
21053
21117
  }
21054
- function lastKnownSyncConfig(base, reason) {
21055
- const remembered = _syncConfigCache.get(base) ?? readPersistedSyncConfigs()[base];
21118
+ function lastKnownSyncConfig(base2, reason) {
21119
+ const remembered = _syncConfigCache.get(base2) ?? readPersistedSyncConfigs()[base2];
21056
21120
  if (remembered) {
21057
21121
  console.error(`[sync] could not read server-side sync rules (${reason}) \u2014 applying the last known set from ${new Date(remembered.fetchedAt).toISOString()}`);
21058
21122
  return remembered.config;
21059
21123
  }
21060
21124
  const refusal = new Error(
21061
- `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.`
21062
21126
  );
21063
21127
  refusal[SYNC_RULES_REFUSAL] = true;
21064
21128
  throw refusal;
@@ -21179,25 +21243,25 @@ async function syncSessions(opts = {}) {
21179
21243
  ${errors.join("\n ")}`);
21180
21244
  return { ...agg, perTarget };
21181
21245
  }
21182
- async function postFieldBatch(base, token, rows) {
21246
+ async function postFieldBatch(base2, token, rows) {
21183
21247
  const headers = { "content-type": "application/json" };
21184
21248
  if (token) headers.authorization = `Bearer ${token}`;
21185
21249
  const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
21186
21250
  for (let attempt = 0; ; attempt++) {
21187
- 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);
21188
21252
  if (res.ok) return;
21189
21253
  const retryable = res.status === 429 || res.status >= 500;
21190
- 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(() => "")}`);
21191
21255
  const ra = Number(res.headers.get("retry-after")) || 0;
21192
21256
  await sleep(ra > 0 ? ra * 1e3 : [500, 1500, 4e3, 8e3, 15e3][Math.min(attempt, 4)]);
21193
21257
  }
21194
21258
  }
21195
21259
  async function reconcileFieldsForTarget(cred, fullRefs, opts = {}) {
21196
- const base = cred.serverUrl.replace(/\/+$/, "");
21197
- const ledger = getSyncedRows(base);
21260
+ const base2 = cred.serverUrl.replace(/\/+$/, "");
21261
+ const ledger = getSyncedRows(base2);
21198
21262
  let pushed = 0, absent = 0, scanned = 0;
21199
21263
  for (const field of SYNC_FIELDS) {
21200
- const needFull = !!opts.force || fieldNeedsFullPass(base, field);
21264
+ const needFull = !!opts.force || fieldNeedsFullPass(base2, field);
21201
21265
  const candidates2 = needFull ? fullRefs() : opts.convRefs ?? fullRefs();
21202
21266
  const send = [];
21203
21267
  const mtimeById = /* @__PURE__ */ new Map();
@@ -21213,15 +21277,15 @@ async function reconcileFieldsForTarget(cred, fullRefs, opts = {}) {
21213
21277
  }
21214
21278
  for (let i = 0; i < send.length; i += 200) {
21215
21279
  const chunk = send.slice(i, i + 200);
21216
- await postFieldBatch(base, cred.token, chunk);
21217
- 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 })));
21218
21282
  pushed += chunk.length;
21219
21283
  }
21220
21284
  if (absentIds.length) {
21221
- 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 })));
21222
21286
  absent += absentIds.length;
21223
21287
  }
21224
- if (needFull) markFieldFullPassDone(base, field);
21288
+ if (needFull) markFieldFullPassDone(base2, field);
21225
21289
  }
21226
21290
  return { pushed, absent, scanned };
21227
21291
  }
@@ -21259,7 +21323,7 @@ function reapStaleScanDirs(dir = tmpdir4(), maxAgeMs = 6 * 36e5, now = Date.now(
21259
21323
  if (!name.startsWith("cr-batchscan-")) continue;
21260
21324
  const p = join49(dir, name);
21261
21325
  try {
21262
- if (now - statSync42(p).mtimeMs < maxAgeMs) continue;
21326
+ if (now - statSync43(p).mtimeMs < maxAgeMs) continue;
21263
21327
  rmSync6(p, { recursive: true, force: true });
21264
21328
  reaped++;
21265
21329
  } catch {
@@ -21338,25 +21402,25 @@ function serverIngestConcurrency(serverUrl) {
21338
21402
  return advertisedIngestConc.get(serverUrl.replace(/\/$/, "")) ?? null;
21339
21403
  }
21340
21404
  async function verifyServerApi(serverUrl, minApi) {
21341
- const base = serverUrl.replace(/\/$/, "");
21342
- const seen = capsOk.get(base);
21405
+ const base2 = serverUrl.replace(/\/$/, "");
21406
+ const seen = capsOk.get(base2);
21343
21407
  if (seen !== void 0 && Date.now() - seen < CAPS_TTL_MS) return true;
21344
21408
  const { probeServer: probeServer2, probeAdvice: probeAdvice2 } = await Promise.resolve().then(() => (init_server_probe(), server_probe_exports));
21345
- const probe = await probeServer2(base, {
21409
+ const probe = await probeServer2(base2, {
21346
21410
  fetchImpl: ((url, init) => fetchWithTimeout(String(url), init ?? {}))
21347
21411
  });
21348
- if (probe.kind !== "ok") throw new Error(probeAdvice2(probe, base));
21412
+ if (probe.kind !== "ok") throw new Error(probeAdvice2(probe, base2));
21349
21413
  const caps = probe.raw;
21350
21414
  if ((caps.apiVersion ?? 0) < minApi) {
21351
21415
  throw new Error(`server too old: apiVersion ${caps.apiVersion ?? "none"} < required ${minApi} \u2014 update the server image before syncing`);
21352
21416
  }
21353
21417
  const adv = caps.limits?.ingestConcurrencyPerTenant;
21354
21418
  if (typeof adv === "number" && Number.isFinite(adv) && adv >= 1) {
21355
- advertisedIngestConc.set(base, Math.floor(adv));
21419
+ advertisedIngestConc.set(base2, Math.floor(adv));
21356
21420
  }
21357
- if (caps.limits?.acceptsGzipBody === true) advertisedGzipBody.add(base);
21358
- else advertisedGzipBody.delete(base);
21359
- 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());
21360
21424
  return true;
21361
21425
  }
21362
21426
  async function syncToTarget(cred, opts = {}) {
@@ -21421,7 +21485,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21421
21485
  const ac = new AbortController();
21422
21486
  const timer = setTimeout(() => ac.abort(new Error(`upload timed out after ${UPLOAD_TIMEOUT_MS}ms`)), UPLOAD_TIMEOUT_MS);
21423
21487
  try {
21424
- const res = await fetch(`${base}/api/sync`, {
21488
+ const res = await fetch(`${base2}/api/sync`, {
21425
21489
  method: "POST",
21426
21490
  // No token ⇒ no auth header: a no-auth local server (AUTH_PROVIDER=none)
21427
21491
  // accepts it as the single 'default' tenant.
@@ -21437,26 +21501,26 @@ async function syncToTargetInScope(cred, opts = {}) {
21437
21501
  acceptedUploads.set(cred.serverUrl, (acceptedUploads.get(cred.serverUrl) ?? 0) + 1);
21438
21502
  const body3 = await res.json().catch(() => ({}));
21439
21503
  if (typeof body3.telemetry === "boolean") {
21440
- setTelemetryEligible(base, body3.telemetry);
21504
+ setTelemetryEligible(base2, body3.telemetry);
21441
21505
  try {
21442
21506
  const prior = readCollectorHealth()?.telemetryEligible ?? {};
21443
21507
  updateCollectorHealth({
21444
- telemetryEligible: { ...prior, [base]: { allowed: body3.telemetry, at: Date.now() } }
21508
+ telemetryEligible: { ...prior, [base2]: { allowed: body3.telemetry, at: Date.now() } }
21445
21509
  });
21446
21510
  } catch {
21447
21511
  }
21448
21512
  }
21449
21513
  const adv = body3.limits?.ingestConcurrencyPerTenant;
21450
21514
  if (typeof adv === "number" && Number.isFinite(adv) && adv >= 1) {
21451
- setServerIngestConcurrency(base, Math.floor(adv));
21515
+ setServerIngestConcurrency(base2, Math.floor(adv));
21452
21516
  }
21453
21517
  if (body3.cli && body3.cli.version) {
21454
21518
  const { planAutoUpdate: planAutoUpdate2, runAutoUpdate: runAutoUpdate2, sweepStaleStaging: sweepStaleStaging2 } = await Promise.resolve().then(() => (init_auto_update(), auto_update_exports));
21455
21519
  const authHeaders = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
21456
- 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);
21457
21521
  sweepStaleStaging2();
21458
21522
  if (plan.update) {
21459
- void runAutoUpdate2(base, authHeaders, ownVersion).catch(() => {
21523
+ void runAutoUpdate2(base2, authHeaders, ownVersion).catch(() => {
21460
21524
  });
21461
21525
  }
21462
21526
  }
@@ -21465,7 +21529,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21465
21529
  const retryable = res.status === 429 || res.status >= 500;
21466
21530
  const text = await res.text().catch(() => "");
21467
21531
  if (res.status === 401 || res.status === 403) {
21468
- 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}`);
21469
21533
  }
21470
21534
  if (res.status === 402) {
21471
21535
  let detail = text;
@@ -21486,7 +21550,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21486
21550
  const retryAfterS = Number(res.headers.get("retry-after"));
21487
21551
  const waitMs = res.status === 429 && retryAfterS > 0 ? retryAfterS * 1e3 : RETRY_DELAYS_MS[attempt];
21488
21552
  const why = res.status === 524 ? ` \u2014 the proxy cut the request at its time limit; the batch is too big for one request` : "";
21489
- 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})`);
21490
21554
  await sleep(waitMs);
21491
21555
  continue;
21492
21556
  } catch (err) {
@@ -21554,11 +21618,11 @@ async function syncToTargetInScope(cred, opts = {}) {
21554
21618
  }
21555
21619
  };
21556
21620
  };
21557
- const base = cred.serverUrl.replace(/\/$/, "");
21558
- const ledger = opts.useLedger ? getSyncedRows(base) : null;
21621
+ const base2 = cred.serverUrl.replace(/\/$/, "");
21622
+ const ledger = opts.useLedger ? getSyncedRows(base2) : null;
21559
21623
  const convBatch = makeBatcher("conversations", 25, false, (rows) => {
21560
21624
  try {
21561
- markSynced(base, rows.map((r) => {
21625
+ markSynced(base2, rows.map((r) => {
21562
21626
  const off = typeof r.from_offset === "number" ? r.from_offset : 0;
21563
21627
  const hash = shippedHash.get(r.session_id);
21564
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 };
@@ -21573,7 +21637,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21573
21637
  const ac = new AbortController();
21574
21638
  const timer = setTimeout(() => ac.abort(new Error(`upload timed out after ${UPLOAD_TIMEOUT_MS}ms`)), UPLOAD_TIMEOUT_MS);
21575
21639
  try {
21576
- const res = await fetch(`${base}/api/sync`, {
21640
+ const res = await fetch(`${base2}/api/sync`, {
21577
21641
  method: "POST",
21578
21642
  headers,
21579
21643
  body: JSON.stringify({ conversations: convs }),
@@ -21584,10 +21648,10 @@ async function syncToTargetInScope(cred, opts = {}) {
21584
21648
  if (body2.cli && body2.cli.version) {
21585
21649
  const { planAutoUpdate: planAutoUpdate2, runAutoUpdate: runAutoUpdate2, sweepStaleStaging: sweepStaleStaging2 } = await Promise.resolve().then(() => (init_auto_update(), auto_update_exports));
21586
21650
  const authHeaders = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
21587
- 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);
21588
21652
  sweepStaleStaging2();
21589
21653
  if (plan.update) {
21590
- void runAutoUpdate2(base, authHeaders, ownVersion).catch(() => {
21654
+ void runAutoUpdate2(base2, authHeaders, ownVersion).catch(() => {
21591
21655
  });
21592
21656
  }
21593
21657
  }
@@ -21595,7 +21659,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21595
21659
  const acked = convs.filter((c) => !fullNeeded.has(c.session_id));
21596
21660
  if (acked.length > 0) {
21597
21661
  try {
21598
- markSynced(base, acked.map((c) => ({
21662
+ markSynced(base2, acked.map((c) => ({
21599
21663
  id: c.session_id,
21600
21664
  mtime: c.mtime,
21601
21665
  offset: c.from_offset,
@@ -21619,7 +21683,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21619
21683
  const ac = new AbortController();
21620
21684
  const timer = setTimeout(() => ac.abort(new Error(`upload timed out after ${UPLOAD_TIMEOUT_MS}ms`)), UPLOAD_TIMEOUT_MS);
21621
21685
  try {
21622
- const res = await fetch(`${base}/api/sync`, {
21686
+ const res = await fetch(`${base2}/api/sync`, {
21623
21687
  method: "POST",
21624
21688
  headers,
21625
21689
  body: JSON.stringify({ conversations: [conv] }),
@@ -21632,11 +21696,11 @@ async function syncToTargetInScope(cred, opts = {}) {
21632
21696
  const mtime = conv.mtime;
21633
21697
  try {
21634
21698
  if (!guarded) {
21635
- 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 }]);
21636
21700
  } else if (typeof guarded.o === "number" && guarded.o > 0 && guarded.o <= fileSize) {
21637
- 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 }]);
21638
21702
  } else {
21639
- markSynced(base, [{ id, mtime }]);
21703
+ markSynced(base2, [{ id, mtime }]);
21640
21704
  }
21641
21705
  } catch {
21642
21706
  }
@@ -21702,7 +21766,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21702
21766
  const m = process.memoryUsage();
21703
21767
  console.error(`[sync-trace] ${msg} \xB7 heap=${(m.heapUsed / 1048576).toFixed(0)}MB rss=${(m.rss / 1048576).toFixed(0)}MB`);
21704
21768
  } : null;
21705
- trace?.(`walk start: ${slice.length} ref(s) \u2192 ${base}`);
21769
+ trace?.(`walk start: ${slice.length} ref(s) \u2192 ${base2}`);
21706
21770
  if (upload.sessionMeta) {
21707
21771
  try {
21708
21772
  await reconcileFieldsForTarget(
@@ -21717,7 +21781,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21717
21781
  { convRefs: slice }
21718
21782
  );
21719
21783
  } catch (e) {
21720
- 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}`);
21721
21785
  }
21722
21786
  }
21723
21787
  trace?.("field reconcile done");
@@ -21759,7 +21823,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21759
21823
  }
21760
21824
  trace?.("conversation walk start");
21761
21825
  const walkStartedAt = Date.now();
21762
- const firstWalk = (ledger ?? getSyncedRows(base)).size === 0;
21826
+ const firstWalk = (ledger ?? getSyncedRows(base2)).size === 0;
21763
21827
  reportWalkProgress({ done: 0, total: slice.length, startedAt: walkStartedAt, complete: false, first: firstWalk });
21764
21828
  walkProgressForUpload = { done: 0, total: slice.length, complete: false };
21765
21829
  let traceN = 0;
@@ -21799,7 +21863,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21799
21863
  continue;
21800
21864
  } else {
21801
21865
  try {
21802
- markSynced(base, [{ id: ref.prefixedId, mtime: ref.mtime }]);
21866
+ markSynced(base2, [{ id: ref.prefixedId, mtime: ref.mtime }]);
21803
21867
  } catch {
21804
21868
  }
21805
21869
  skipped++;
@@ -21822,7 +21886,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21822
21886
  const off = getBackendForId(ref.prefixedId)?.fileSize?.(ref.rawId) ?? 0;
21823
21887
  const priorCursor = ackRow?.s ?? 0;
21824
21888
  const safeToAck = off > 0 && off <= priorCursor;
21825
- 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 }]);
21826
21890
  } catch {
21827
21891
  }
21828
21892
  }
@@ -21832,7 +21896,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21832
21896
  if (!built) {
21833
21897
  if (ledger) {
21834
21898
  try {
21835
- markSynced(base, [{ id: ref.prefixedId, mtime: ref.mtime }]);
21899
+ markSynced(base2, [{ id: ref.prefixedId, mtime: ref.mtime }]);
21836
21900
  } catch {
21837
21901
  }
21838
21902
  }
@@ -21889,7 +21953,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21889
21953
  walked++;
21890
21954
  if (walked % 250 === 0) console.error(`[sync] ${walked}/${slice.length} sessions\u2026`);
21891
21955
  }
21892
- const itemVersions = loadItemVersions(base);
21956
+ const itemVersions = loadItemVersions(base2);
21893
21957
  const seenTools = /* @__PURE__ */ new Set();
21894
21958
  const seenItemKeys = /* @__PURE__ */ new Map();
21895
21959
  const registry = buildSourceRegistry();
@@ -21983,7 +22047,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21983
22047
  await appendFlush();
21984
22048
  for (const id of appendResults.fullResyncNeeded) {
21985
22049
  try {
21986
- markFullResync(base, id);
22050
+ markFullResync(base2, id);
21987
22051
  } catch {
21988
22052
  }
21989
22053
  }
@@ -21996,7 +22060,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21996
22060
  await findingsBatch.drain();
21997
22061
  await drainInflight();
21998
22062
  {
21999
- const sentHashes = loadInventoryHashes(base);
22063
+ const sentHashes = loadInventoryHashes(base2);
22000
22064
  const entries = [];
22001
22065
  const hashes = {};
22002
22066
  for (const [sourceType, ids] of inventory) {
@@ -22010,7 +22074,7 @@ async function syncToTargetInScope(cred, opts = {}) {
22010
22074
  if (entries.length > 0) {
22011
22075
  try {
22012
22076
  await post({ inventory: entries });
22013
- saveInventoryHashes(base, hashes);
22077
+ saveInventoryHashes(base2, hashes);
22014
22078
  } catch (err) {
22015
22079
  console.error(`[sync] toolkit inventory not sent (it is retried next sync): ${err instanceof Error ? err.message : err}`);
22016
22080
  }
@@ -22021,7 +22085,7 @@ async function syncToTargetInScope(cred, opts = {}) {
22021
22085
  const rec = {};
22022
22086
  for (const t of seenTools) rec[t] = extractorVersionForTool(t);
22023
22087
  for (const [k, v] of seenItemKeys) rec[k] = v;
22024
- saveItemVersions(base, rec);
22088
+ saveItemVersions(base2, rec);
22025
22089
  } catch {
22026
22090
  }
22027
22091
  }
@@ -22034,9 +22098,9 @@ async function syncToTargetInScope(cred, opts = {}) {
22034
22098
  }
22035
22099
  if (tombstones.length > 0) {
22036
22100
  await post({ tombstones });
22037
- const data = getLedgerData(base);
22101
+ const data = getLedgerData(base2);
22038
22102
  for (const t of tombstones) delete data[t.session_id];
22039
- persistLedgerData(base, data);
22103
+ persistLedgerData(base2, data);
22040
22104
  }
22041
22105
  }
22042
22106
  if (opts.prune) await post({ prune_empty_sessions: true });
@@ -22507,7 +22571,7 @@ var init_sync_client = __esm({
22507
22571
  ownVersion = JSON.parse(readFileSync38(join49(dir, "../package.json"), "utf-8")).version || ownVersion;
22508
22572
  } catch {
22509
22573
  try {
22510
- if (true) ownVersion = "0.7.13";
22574
+ if (true) ownVersion = "0.7.15";
22511
22575
  } catch {
22512
22576
  }
22513
22577
  }
@@ -22666,9 +22730,9 @@ async function refreshUpdateCheck(force = false) {
22666
22730
  const { loadAllCredentials: loadAllCredentials2 } = await Promise.resolve().then(() => (init_sync_client(), sync_client_exports));
22667
22731
  for (const cred of loadAllCredentials2()) {
22668
22732
  if (!cred.serverUrl) continue;
22669
- const base = cred.serverUrl.replace(/\/+$/, "");
22733
+ const base2 = cred.serverUrl.replace(/\/+$/, "");
22670
22734
  try {
22671
- const res = await fetchWithTimeout(`${base}/api/capabilities`, {
22735
+ const res = await fetchWithTimeout(`${base2}/api/capabilities`, {
22672
22736
  headers: cred.token ? { authorization: `Bearer ${cred.token}` } : {}
22673
22737
  }, 5e3);
22674
22738
  if (!res.ok) continue;
@@ -23057,7 +23121,7 @@ __export(install_skills_exports, {
23057
23121
  skillsSourceDir: () => skillsSourceDir,
23058
23122
  uninstallSkills: () => uninstallSkills
23059
23123
  });
23060
- 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";
23061
23125
  import { createHash as createHash12 } from "crypto";
23062
23126
  import { join as join52, basename as basename23 } from "path";
23063
23127
  function skillsSourceDir() {
@@ -23298,18 +23362,18 @@ function usableDir(dir) {
23298
23362
  if (!isDir(dir)) {
23299
23363
  const missing = [];
23300
23364
  let cur = dir;
23301
- let base = false;
23365
+ let base2 = false;
23302
23366
  while (missing.length < MAX_MISSING_LEVELS) {
23303
23367
  const parent = dirname(cur);
23304
23368
  if (parent === cur) break;
23305
23369
  missing.push(cur);
23306
23370
  if (isDir(parent)) {
23307
- base = true;
23371
+ base2 = true;
23308
23372
  break;
23309
23373
  }
23310
23374
  cur = parent;
23311
23375
  }
23312
- if (!base) return false;
23376
+ if (!base2) return false;
23313
23377
  for (let i = missing.length - 1; i >= 0; i--) {
23314
23378
  try {
23315
23379
  mkdirSync(missing[i]);
@@ -29498,7 +29562,7 @@ function installCrashGuards() {
29498
29562
  reportClientEvent2("mcp_crash", { message: err.stack || err.message });
29499
29563
  });
29500
29564
  }
29501
- var RELAY_VERSION = true ? "0.7.13" : "0.0.0";
29565
+ var RELAY_VERSION = true ? "0.7.15" : "0.0.0";
29502
29566
  function daemonIdleSecs() {
29503
29567
  const raw = process.env.CHAT_RECALL_DAEMON_IDLE_SECS;
29504
29568
  if (raw === void 0) return 900;