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/watch.js CHANGED
@@ -4458,7 +4458,7 @@ var require_pino = __commonJS({
4458
4458
  messageKey,
4459
4459
  errorKey,
4460
4460
  nestedKey,
4461
- base: base2,
4461
+ base: base3,
4462
4462
  name,
4463
4463
  level: level2,
4464
4464
  customLevels,
@@ -4497,11 +4497,11 @@ var require_pino = __commonJS({
4497
4497
  [formattersSym]: allFormatters
4498
4498
  });
4499
4499
  let chindings = "";
4500
- if (base2 !== null) {
4500
+ if (base3 !== null) {
4501
4501
  if (name === void 0) {
4502
- chindings = coreChindings(base2);
4502
+ chindings = coreChindings(base3);
4503
4503
  } else {
4504
- chindings = coreChindings(Object.assign({}, base2, { name }));
4504
+ chindings = coreChindings(Object.assign({}, base3, { name }));
4505
4505
  }
4506
4506
  }
4507
4507
  const time2 = timestamp instanceof Function ? timestamp : timestamp ? epochTime : nullTime;
@@ -4881,57 +4881,57 @@ function freshDefaults() {
4881
4881
  team: defaultTeam()
4882
4882
  };
4883
4883
  }
4884
- function mergeSources(base2, partial) {
4884
+ function mergeSources(base3, partial) {
4885
4885
  if (!partial)
4886
- return base2;
4886
+ return base3;
4887
4887
  const legacyGemini = partial.enabled?.gemini;
4888
4888
  const inherited = legacyGemini && typeof legacyGemini === "object" ? (({ sessions: _s, plans: _p, ...rest }) => rest)(legacyGemini) : {};
4889
4889
  const enabled = {
4890
- claude: { ...base2.enabled.claude, ...partial.enabled?.claude ?? {} },
4891
- opencode: { ...base2.enabled.opencode, ...partial.enabled?.opencode ?? {} },
4892
- codex: { ...base2.enabled.codex, ...partial.enabled?.codex ?? {} },
4893
- agy: { ...base2.enabled.agy, ...inherited, ...partial.enabled?.agy ?? {} },
4894
- cursor: { ...base2.enabled.cursor, ...partial.enabled?.cursor ?? {} },
4895
- shared: { ...base2.enabled.shared, ...partial.enabled?.shared ?? {} },
4896
- common: { ...base2.enabled.common, ...partial.enabled?.common ?? {} }
4890
+ claude: { ...base3.enabled.claude, ...partial.enabled?.claude ?? {} },
4891
+ opencode: { ...base3.enabled.opencode, ...partial.enabled?.opencode ?? {} },
4892
+ codex: { ...base3.enabled.codex, ...partial.enabled?.codex ?? {} },
4893
+ agy: { ...base3.enabled.agy, ...inherited, ...partial.enabled?.agy ?? {} },
4894
+ cursor: { ...base3.enabled.cursor, ...partial.enabled?.cursor ?? {} },
4895
+ shared: { ...base3.enabled.shared, ...partial.enabled?.shared ?? {} },
4896
+ common: { ...base3.enabled.common, ...partial.enabled?.common ?? {} }
4897
4897
  };
4898
4898
  return {
4899
- claudeHome: partial.claudeHome ?? base2.claudeHome,
4900
- geminiHome: partial.geminiHome ?? base2.geminiHome,
4901
- codexHome: partial.codexHome ?? base2.codexHome,
4902
- opencodeDbPath: partial.opencodeDbPath ?? base2.opencodeDbPath,
4903
- agyHome: partial.agyHome ?? base2.agyHome,
4904
- cursorHome: partial.cursorHome ?? base2.cursorHome,
4905
- cursorIdeHome: partial.cursorIdeHome ?? base2.cursorIdeHome,
4906
- extraClaudeHomes: partial.extraClaudeHomes ?? base2.extraClaudeHomes,
4907
- approvedHomes: partial.approvedHomes ?? base2.approvedHomes,
4908
- declinedHomes: partial.declinedHomes ?? base2.declinedHomes,
4909
- homesGrandfathered: partial.homesGrandfathered ?? base2.homesGrandfathered,
4899
+ claudeHome: partial.claudeHome ?? base3.claudeHome,
4900
+ geminiHome: partial.geminiHome ?? base3.geminiHome,
4901
+ codexHome: partial.codexHome ?? base3.codexHome,
4902
+ opencodeDbPath: partial.opencodeDbPath ?? base3.opencodeDbPath,
4903
+ agyHome: partial.agyHome ?? base3.agyHome,
4904
+ cursorHome: partial.cursorHome ?? base3.cursorHome,
4905
+ cursorIdeHome: partial.cursorIdeHome ?? base3.cursorIdeHome,
4906
+ extraClaudeHomes: partial.extraClaudeHomes ?? base3.extraClaudeHomes,
4907
+ approvedHomes: partial.approvedHomes ?? base3.approvedHomes,
4908
+ declinedHomes: partial.declinedHomes ?? base3.declinedHomes,
4909
+ homesGrandfathered: partial.homesGrandfathered ?? base3.homesGrandfathered,
4910
4910
  enabled
4911
4911
  };
4912
4912
  }
4913
- function mergePrivacy(base2, partial) {
4913
+ function mergePrivacy(base3, partial) {
4914
4914
  if (!partial)
4915
- return base2;
4916
- return { ...base2, ...partial };
4915
+ return base3;
4916
+ return { ...base3, ...partial };
4917
4917
  }
4918
- function mergeSync(base2, partial) {
4918
+ function mergeSync(base3, partial) {
4919
4919
  if (!partial)
4920
- return base2;
4920
+ return base3;
4921
4921
  return {
4922
- ...base2,
4922
+ ...base3,
4923
4923
  ...partial,
4924
- upload: { ...base2.upload, ...partial.upload ?? {} }
4924
+ upload: { ...base3.upload, ...partial.upload ?? {} }
4925
4925
  };
4926
4926
  }
4927
- function mergeTeam(base2, partial) {
4927
+ function mergeTeam(base3, partial) {
4928
4928
  if (!partial)
4929
- return base2;
4929
+ return base3;
4930
4930
  return {
4931
- ...base2,
4931
+ ...base3,
4932
4932
  ...partial,
4933
- publishAllowed: { ...base2.publishAllowed, ...partial.publishAllowed ?? {} },
4934
- vault: { ...base2.vault, ...partial.vault ?? {} }
4933
+ publishAllowed: { ...base3.publishAllowed, ...partial.publishAllowed ?? {} },
4934
+ vault: { ...base3.vault, ...partial.vault ?? {} }
4935
4935
  };
4936
4936
  }
4937
4937
  function settingsFilePath() {
@@ -5040,15 +5040,15 @@ function loadSettings() {
5040
5040
  }
5041
5041
  try {
5042
5042
  const parsed = JSON.parse(readFileSync(path, "utf-8"));
5043
- const base2 = freshDefaults();
5043
+ const base3 = freshDefaults();
5044
5044
  const result = {
5045
5045
  v: SCHEMA_VERSION,
5046
- embedding: { ...base2.embedding, ...parsed.embedding ?? {} },
5047
- summary: { ...base2.summary, ...parsed.summary ?? {} },
5048
- sources: mergeSources(base2.sources, parsed.sources),
5049
- privacy: mergePrivacy(base2.privacy, parsed.privacy),
5050
- sync: mergeSync(base2.sync, parsed.sync),
5051
- team: mergeTeam(base2.team, parsed.team)
5046
+ embedding: { ...base3.embedding, ...parsed.embedding ?? {} },
5047
+ summary: { ...base3.summary, ...parsed.summary ?? {} },
5048
+ sources: mergeSources(base3.sources, parsed.sources),
5049
+ privacy: mergePrivacy(base3.privacy, parsed.privacy),
5050
+ sync: mergeSync(base3.sync, parsed.sync),
5051
+ team: mergeTeam(base3.team, parsed.team)
5052
5052
  };
5053
5053
  if (mtimeMs >= 0)
5054
5054
  _settingsCache = { mtimeMs, size, value: structuredClone(result) };
@@ -5154,10 +5154,10 @@ function legacyAutoSyncedHomes() {
5154
5154
  { base: join3(home, ".local", "share", "opencode"), marker: "opencode.db" },
5155
5155
  { base: join3(home, ".cursor"), marker: "chats" }
5156
5156
  ];
5157
- for (const { base: base2, marker } of bases) {
5158
- add(base2, marker);
5159
- const parent = dirname3(base2);
5160
- const leaf = base2.slice(parent.length + 1);
5157
+ for (const { base: base3, marker } of bases) {
5158
+ add(base3, marker);
5159
+ const parent = dirname3(base3);
5160
+ const leaf = base3.slice(parent.length + 1);
5161
5161
  try {
5162
5162
  for (const e of readdirSync2(parent, { withFileTypes: true })) {
5163
5163
  if (!e.isDirectory())
@@ -5338,17 +5338,17 @@ function cursorHomeDir() {
5338
5338
  function cursorIdeHomeDir() {
5339
5339
  return process.env.CHAT_RECALL_CURSOR_IDE_HOME || sources().cursorIdeHome || (process.platform === "darwin" ? join4(homedir3(), "Library", "Application Support", "Cursor") : join4(homedir3(), ".config", "Cursor"));
5340
5340
  }
5341
- function siblingHomes(base2, overridden, suffix) {
5341
+ function siblingHomes(base3, overridden, suffix) {
5342
5342
  const roots = [];
5343
5343
  const add = (home) => {
5344
5344
  const root = suffix ? join4(home, suffix) : home;
5345
5345
  if (existsSync4(root) && !roots.includes(root))
5346
5346
  roots.push(root);
5347
5347
  };
5348
- add(base2);
5348
+ add(base3);
5349
5349
  if (!overridden) {
5350
- const parent = dirname4(base2);
5351
- const leaf = basename(base2);
5350
+ const parent = dirname4(base3);
5351
+ const leaf = basename(base3);
5352
5352
  try {
5353
5353
  for (const entry of readdirSync3(parent, { withFileTypes: true })) {
5354
5354
  if (!entry.isDirectory())
@@ -5844,9 +5844,9 @@ async function parseSessionFile(sessionPath, maxMessages = 50) {
5844
5844
  content.metadata.durationMs += obj.durationMs;
5845
5845
  }
5846
5846
  if (msgType === "file-history-snapshot") {
5847
- const snapshot = obj.snapshot;
5848
- if (snapshot && typeof snapshot === "object") {
5849
- const backups = snapshot.trackedFileBackups;
5847
+ const snapshot2 = obj.snapshot;
5848
+ if (snapshot2 && typeof snapshot2 === "object") {
5849
+ const backups = snapshot2.trackedFileBackups;
5850
5850
  if (backups && typeof backups === "object") {
5851
5851
  for (const filePath2 of Object.keys(backups)) {
5852
5852
  filesModified.add(filePath2);
@@ -6850,12 +6850,14 @@ function lineKey(line) {
6850
6850
  try {
6851
6851
  const o = JSON.parse(line);
6852
6852
  if (typeof o?.uuid === "string" && o.uuid)
6853
- return { key: `u:${o.uuid}`, singleton: false };
6854
- if (typeof o?.type === "string" && SINGLETON_META.has(o.type))
6855
- return { key: `m:${o.type}`, singleton: true };
6853
+ return { key: `u:${o.uuid}`, meta: false, json: true };
6854
+ return { key: `h:${sha1(line)}`, meta: typeof o?.type === "string" && STATE_META.has(o.type), json: true };
6856
6855
  } catch {
6857
6856
  }
6858
- return { key: `h:${sha1(line)}`, singleton: false };
6857
+ return { key: `h:${sha1(line)}`, meta: false, json: false };
6858
+ }
6859
+ function isHalfWritten(line, currentLines) {
6860
+ return currentLines.some((c) => c.length > line.length && c.startsWith(line));
6859
6861
  }
6860
6862
  function mergeLineText(shadowText, currentText) {
6861
6863
  const shadowLines = shadowText.split("\n").filter((l) => l.trim());
@@ -6863,27 +6865,24 @@ function mergeLineText(shadowText, currentText) {
6863
6865
  const currentKeys = /* @__PURE__ */ new Set();
6864
6866
  for (const l of currentLines)
6865
6867
  currentKeys.add(lineKey(l).key);
6866
- const shadowKeys = /* @__PURE__ */ new Set();
6867
- for (const l of shadowLines)
6868
- shadowKeys.add(lineKey(l).key);
6869
- let recovered = 0;
6870
- for (const k of shadowKeys)
6871
- if (!currentKeys.has(k))
6872
- recovered++;
6873
- if (recovered === 0) {
6874
- return { text: currentText.endsWith("\n") ? currentText : currentText + "\n", recovered: 0, totalRecords: currentKeys.size };
6875
- }
6876
- const out = [];
6877
- const emitted = /* @__PURE__ */ new Set();
6868
+ const kept = [];
6869
+ const keptKeys = /* @__PURE__ */ new Set();
6870
+ const counted = /* @__PURE__ */ new Set();
6878
6871
  for (const l of shadowLines) {
6879
- const { key: key2, singleton } = lineKey(l);
6880
- if (singleton && currentKeys.has(key2))
6881
- continue;
6882
- if (emitted.has(key2))
6872
+ const { key: key2, meta, json } = lineKey(l);
6873
+ if (!json && isHalfWritten(l, currentLines))
6883
6874
  continue;
6884
- out.push(l);
6885
- emitted.add(key2);
6875
+ kept.push(l);
6876
+ keptKeys.add(key2);
6877
+ if (!meta && !currentKeys.has(key2))
6878
+ counted.add(key2);
6886
6879
  }
6880
+ const recovered = counted.size;
6881
+ if (recovered === 0) {
6882
+ return { text: currentText.endsWith("\n") ? currentText : currentText + "\n", recovered: 0, totalRecords: currentKeys.size };
6883
+ }
6884
+ const out = [...kept];
6885
+ const emitted = keptKeys;
6887
6886
  for (const l of currentLines) {
6888
6887
  const { key: key2 } = lineKey(l);
6889
6888
  if (emitted.has(key2))
@@ -7068,14 +7067,14 @@ function shadowSizeOnDisk(tool, rawId) {
7068
7067
  return 0;
7069
7068
  }
7070
7069
  }
7071
- var WHOLE_FILE_TOOLS, SINGLETON_META, lastLiveFingerprint;
7070
+ var WHOLE_FILE_TOOLS, STATE_META, lastLiveFingerprint;
7072
7071
  var init_shadow = __esm({
7073
7072
  "../engine/dist/transcript/shadow.js"() {
7074
7073
  "use strict";
7075
7074
  init_paths();
7076
7075
  init_raw();
7077
7076
  WHOLE_FILE_TOOLS = /* @__PURE__ */ new Set(["cursor"]);
7078
- SINGLETON_META = /* @__PURE__ */ new Set(["mode", "permission-mode", "ai-title", "last-prompt", "pr-link", "summary"]);
7077
+ STATE_META = /* @__PURE__ */ new Set(["mode", "permission-mode", "ai-title", "last-prompt", "pr-link", "summary"]);
7079
7078
  lastLiveFingerprint = /* @__PURE__ */ new Map();
7080
7079
  }
7081
7080
  });
@@ -12281,8 +12280,8 @@ function serverRulePackVersion() {
12281
12280
  return serverPack ? serverPack.version || "unversioned" : null;
12282
12281
  }
12283
12282
  function activeRules() {
12284
- const base2 = settingsView().rules;
12285
- return serverPack && serverPack.rules.length > 0 ? [...base2, ...serverPack.rules] : base2;
12283
+ const base3 = settingsView().rules;
12284
+ return serverPack && serverPack.rules.length > 0 ? [...base3, ...serverPack.rules] : base3;
12286
12285
  }
12287
12286
  function isRedactionEnabled() {
12288
12287
  const env = isEnvRedactionRequested();
@@ -18065,7 +18064,7 @@ __export(sync_ledger_exports, {
18065
18064
  syncMode: () => syncMode,
18066
18065
  unackedCursorAttemptCount: () => unackedCursorAttemptCount
18067
18066
  });
18068
- import { readFileSync as readFileSync30, writeFileSync as writeFileSync6, renameSync as renameSync4, mkdirSync as mkdirSync7 } from "node:fs";
18067
+ import { readFileSync as readFileSync30, writeFileSync as writeFileSync6, renameSync as renameSync4, mkdirSync as mkdirSync7, statSync as statSync35 } from "node:fs";
18069
18068
  import { join as join39, dirname as dirname16 } from "node:path";
18070
18069
  function toRow(entry) {
18071
18070
  if (entry === void 0) return void 0;
@@ -18074,32 +18073,94 @@ function toRow(entry) {
18074
18073
  function ledgerFilePath() {
18075
18074
  return ledgerPath();
18076
18075
  }
18077
- function load() {
18078
- if (cache3) return cache3;
18076
+ function stampOf(path) {
18079
18077
  try {
18080
- const parsed = JSON.parse(readFileSync30(ledgerPath(), "utf-8"));
18081
- cache3 = parsed && typeof parsed === "object" ? parsed : {};
18078
+ const st = statSync35(path);
18079
+ return `${st.mtimeMs}:${st.size}`;
18082
18080
  } catch {
18083
- cache3 = {};
18081
+ return null;
18084
18082
  }
18083
+ }
18084
+ function readDisk(path) {
18085
+ try {
18086
+ const parsed = JSON.parse(readFileSync30(path, "utf-8"));
18087
+ return parsed && typeof parsed === "object" ? parsed : {};
18088
+ } catch {
18089
+ return {};
18090
+ }
18091
+ }
18092
+ function snapshot(data) {
18093
+ const out = /* @__PURE__ */ new Map();
18094
+ for (const [server, rows] of Object.entries(data)) {
18095
+ for (const [id, entry] of Object.entries(rows)) out.set(rowKey(server, id), JSON.stringify(entry));
18096
+ }
18097
+ return out;
18098
+ }
18099
+ function mergeOnto(disk) {
18100
+ const out = {};
18101
+ const put = (server, id, entry) => {
18102
+ (out[server] ??= {})[id] = entry;
18103
+ };
18104
+ const mine = cache3 ?? {};
18105
+ for (const [server, rows] of Object.entries(disk)) {
18106
+ for (const [id, entry] of Object.entries(rows)) {
18107
+ const k = rowKey(server, id);
18108
+ const own = mine[server]?.[id];
18109
+ const was = base.get(k);
18110
+ if (own === void 0) {
18111
+ if (was === void 0) put(server, id, entry);
18112
+ } else {
18113
+ put(server, id, JSON.stringify(own) === was ? entry : own);
18114
+ }
18115
+ }
18116
+ }
18117
+ for (const [server, rows] of Object.entries(mine)) {
18118
+ for (const [id, entry] of Object.entries(rows)) {
18119
+ if (disk[server]?.[id] !== void 0) continue;
18120
+ if (JSON.stringify(entry) !== base.get(rowKey(server, id))) put(server, id, entry);
18121
+ }
18122
+ }
18123
+ return out;
18124
+ }
18125
+ function load() {
18126
+ const path = ledgerPath();
18127
+ const stamp2 = stampOf(path);
18128
+ if (cache3 && stamp2 === diskStamp) return cache3;
18129
+ const disk = readDisk(path);
18130
+ const merged = cache3 ? mergeOnto(disk) : disk;
18131
+ if (cache3) {
18132
+ for (const server of Object.keys(cache3)) if (!(server in merged)) delete cache3[server];
18133
+ for (const [server, rows] of Object.entries(merged)) {
18134
+ const target = cache3[server] ?? (cache3[server] = {});
18135
+ for (const id of Object.keys(target)) if (!(id in rows)) delete target[id];
18136
+ Object.assign(target, rows);
18137
+ }
18138
+ } else {
18139
+ cache3 = merged;
18140
+ }
18141
+ base = snapshot(disk);
18142
+ diskStamp = stamp2;
18085
18143
  return cache3;
18086
18144
  }
18087
- function persistNow(data) {
18145
+ function persistNow() {
18088
18146
  const path = ledgerPath();
18089
18147
  mkdirSync7(dirname16(path), { recursive: true });
18090
- const tmp = `${path}.tmp`;
18091
- writeFileSync6(tmp, JSON.stringify(data));
18148
+ load();
18149
+ const tmp = `${path}.tmp-${process.pid}`;
18150
+ writeFileSync6(tmp, JSON.stringify(cache3 ?? {}));
18092
18151
  renameSync4(tmp, path);
18152
+ base = snapshot(cache3 ?? {});
18153
+ diskStamp = stampOf(path);
18093
18154
  pendingWrite = false;
18094
18155
  }
18095
- function persist(data) {
18156
+ function persist(_data) {
18096
18157
  pendingWrite = true;
18097
18158
  if (flushTimer) return;
18098
18159
  flushTimer = setTimeout(() => {
18099
18160
  flushTimer = null;
18100
18161
  if (pendingWrite) {
18101
18162
  try {
18102
- persistNow(data);
18163
+ persistNow();
18103
18164
  } catch {
18104
18165
  }
18105
18166
  }
@@ -18133,7 +18194,7 @@ function pruneLedgerTargets(configuredServers) {
18133
18194
  }
18134
18195
  const rows = names.reduce((n, s) => n + Object.keys(orphans[s]).length, 0);
18135
18196
  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.`);
18136
- persistNow(data);
18197
+ persistNow();
18137
18198
  return names.length;
18138
18199
  }
18139
18200
  function flushLedger() {
@@ -18142,7 +18203,7 @@ function flushLedger() {
18142
18203
  flushTimer = null;
18143
18204
  }
18144
18205
  if (!pendingWrite || !cache3) return;
18145
- persistNow(cache3);
18206
+ persistNow();
18146
18207
  }
18147
18208
  function loadItemVersionsAll() {
18148
18209
  if (itemVersionsCache) return itemVersionsCache;
@@ -18230,13 +18291,13 @@ function markSynced(server, rows) {
18230
18291
  const o = (cursorFromCaller ? r.offset : void 0) ?? prevOS.o ?? 0;
18231
18292
  const s = (cursorFromCaller ? r.size : void 0) ?? prevOS.s ?? 0;
18232
18293
  const ev = extractorVersionForId(r.id);
18233
- const base2 = prevF ? { m: Math.floor(r.mtime), v: ev, f: prevF } : { m: Math.floor(r.mtime), v: ev };
18294
+ const base3 = prevF ? { m: Math.floor(r.mtime), v: ev, f: prevF } : { m: Math.floor(r.mtime), v: ev };
18234
18295
  if (o > 0 || s > 0) {
18235
- base2.o = o;
18236
- base2.s = s;
18296
+ base3.o = o;
18297
+ base3.s = s;
18237
18298
  }
18238
- if (r.hash !== void 0) base2.h = r.hash;
18239
- forServer[r.id] = base2;
18299
+ if (r.hash !== void 0) base3.h = r.hash;
18300
+ forServer[r.id] = base3;
18240
18301
  }
18241
18302
  persist(data);
18242
18303
  }
@@ -18305,6 +18366,8 @@ function forceFieldRescan(fieldName, server) {
18305
18366
  function _resetLedgerCacheForTests() {
18306
18367
  flushLedger();
18307
18368
  cache3 = null;
18369
+ base = /* @__PURE__ */ new Map();
18370
+ diskStamp = null;
18308
18371
  reconcileCache = null;
18309
18372
  }
18310
18373
  function markFullResync(server, sessionId) {
@@ -18326,7 +18389,7 @@ function syncMode(row, mtime, fileSize, extractorVersion, isAppendOnly) {
18326
18389
  if (row.m >= Math.floor(mtime)) return "skip";
18327
18390
  return "full";
18328
18391
  }
18329
- var ledgerPath, cache3, LEDGER_FLUSH_MS, pendingWrite, flushTimer, itemVersionsPath, itemVersionsCache, inventoryPath, unackedCursorAttempts, reconcilePath, reconcileCache;
18392
+ var ledgerPath, cache3, base, diskStamp, rowKey, LEDGER_FLUSH_MS, pendingWrite, flushTimer, itemVersionsPath, itemVersionsCache, inventoryPath, unackedCursorAttempts, reconcilePath, reconcileCache;
18330
18393
  var init_sync_ledger = __esm({
18331
18394
  "src/sync-ledger.ts"() {
18332
18395
  "use strict";
@@ -18334,6 +18397,9 @@ var init_sync_ledger = __esm({
18334
18397
  init_extractor_version();
18335
18398
  ledgerPath = () => join39(getDataDir(), "sync-ledger.json");
18336
18399
  cache3 = null;
18400
+ base = /* @__PURE__ */ new Map();
18401
+ diskStamp = null;
18402
+ rowKey = (server, id) => `${server}\0${id}`;
18337
18403
  LEDGER_FLUSH_MS = 2e3;
18338
18404
  pendingWrite = false;
18339
18405
  flushTimer = null;
@@ -18372,7 +18438,7 @@ var init_sync_fields = __esm({
18372
18438
  });
18373
18439
 
18374
18440
  // ../engine/dist/core/index-lock.js
18375
- import { existsSync as existsSync39, mkdirSync as mkdirSync8, openSync as openSync8, writeFileSync as writeFileSync7, readFileSync as readFileSync31, rmSync as rmSync4, statSync as statSync35, closeSync as closeSync8 } from "fs";
18441
+ import { existsSync as existsSync39, mkdirSync as mkdirSync8, openSync as openSync8, writeFileSync as writeFileSync7, readFileSync as readFileSync31, rmSync as rmSync4, statSync as statSync36, closeSync as closeSync8 } from "fs";
18376
18442
  import { dirname as dirname17, join as join40 } from "path";
18377
18443
  function acquireIndexLock(opts) {
18378
18444
  const lockPath = lockFilePath(opts.file);
@@ -18422,7 +18488,7 @@ function lockFilePath(file = ".compact.lock") {
18422
18488
  }
18423
18489
  function stealStaleLock(lockPath, staleAfterMs) {
18424
18490
  try {
18425
- const s = statSync35(lockPath);
18491
+ const s = statSync36(lockPath);
18426
18492
  const age = Date.now() - s.mtimeMs;
18427
18493
  let payload;
18428
18494
  try {
@@ -18485,7 +18551,7 @@ var init_http = __esm({
18485
18551
  CLI_VERSION = JSON.parse(readFileSync32(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
18486
18552
  } catch {
18487
18553
  try {
18488
- if (true) CLI_VERSION = "0.7.13";
18554
+ if (true) CLI_VERSION = "0.7.15";
18489
18555
  } catch {
18490
18556
  }
18491
18557
  }
@@ -18979,7 +19045,7 @@ var init_telemetry = __esm({
18979
19045
  init_sync_client();
18980
19046
  cliVersion = () => {
18981
19047
  try {
18982
- return true ? "0.7.13" : "dev";
19048
+ return true ? "0.7.15" : "dev";
18983
19049
  } catch {
18984
19050
  return "dev";
18985
19051
  }
@@ -19002,11 +19068,11 @@ __export(server_probe_exports, {
19002
19068
  function probeOk(r) {
19003
19069
  return r.kind === "ok" && r.apiVersion >= 2;
19004
19070
  }
19005
- async function probeServer(base2, opts = {}) {
19071
+ async function probeServer(base3, opts = {}) {
19006
19072
  const f = opts.fetchImpl || fetch;
19007
19073
  let res;
19008
19074
  try {
19009
- res = await f(`${base2.replace(/\/+$/, "")}/api/capabilities`, {
19075
+ res = await f(`${base3.replace(/\/+$/, "")}/api/capabilities`, {
19010
19076
  signal: AbortSignal.timeout(opts.timeoutMs ?? 1e4)
19011
19077
  });
19012
19078
  } catch (err) {
@@ -19043,34 +19109,34 @@ async function probeServer(base2, opts = {}) {
19043
19109
  raw: parsed
19044
19110
  };
19045
19111
  }
19046
- function probeAdvice(r, base2) {
19112
+ function probeAdvice(r, base3) {
19047
19113
  switch (r.kind) {
19048
19114
  case "ok":
19049
19115
  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`;
19050
19116
  case "moved":
19051
- return `HTTP ${r.status} \u2014 nothing is served at ${base2}. If the host moved, re-point it: \`chat-recall login <new-server-url>\``;
19117
+ return `HTTP ${r.status} \u2014 nothing is served at ${base3}. If the host moved, re-point it: \`chat-recall login <new-server-url>\``;
19052
19118
  case "unauthorized":
19053
- return `HTTP ${r.status} \u2014 ${base2} rejected the credential. Re-login: \`chat-recall login ` + base2 + "`";
19119
+ return `HTTP ${r.status} \u2014 ${base3} rejected the credential. Re-login: \`chat-recall login ` + base3 + "`";
19054
19120
  case "server_error":
19055
- return `HTTP ${r.status} \u2014 ${base2} is up but failing. Nothing to fix locally; check the server.`;
19121
+ return `HTTP ${r.status} \u2014 ${base3} is up but failing. Nothing to fix locally; check the server.`;
19056
19122
  case "not_api":
19057
- 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`;
19123
+ return `${base3} 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`;
19058
19124
  case "unreachable":
19059
19125
  switch (r.reason) {
19060
19126
  case "dns":
19061
- return `cannot resolve the host in ${base2} (${r.error}) \u2014 check the URL for a typo, and your DNS or VPN`;
19127
+ return `cannot resolve the host in ${base3} (${r.error}) \u2014 check the URL for a typo, and your DNS or VPN`;
19062
19128
  case "refused":
19063
- return `${base2} resolves but refused the connection (${r.error}) \u2014 the server is not running, or the port is wrong`;
19129
+ return `${base3} resolves but refused the connection (${r.error}) \u2014 the server is not running, or the port is wrong`;
19064
19130
  case "tls":
19065
- 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.`;
19131
+ return `the TLS certificate at ${base3} was rejected (${r.error}) \u2014 expired, self-signed, or issued for another host. A corporate proxy that re-signs traffic does this.`;
19066
19132
  case "timeout":
19067
- return `${base2} did not answer in time (${r.error}) \u2014 a firewall or proxy that drops traffic silently looks exactly like this`;
19133
+ return `${base3} did not answer in time (${r.error}) \u2014 a firewall or proxy that drops traffic silently looks exactly like this`;
19068
19134
  case "reset":
19069
- return `the connection to ${base2} was cut (${r.error}) \u2014 often a proxy or a captive portal`;
19135
+ return `the connection to ${base3} was cut (${r.error}) \u2014 often a proxy or a captive portal`;
19070
19136
  case "bad_port":
19071
- 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`;
19137
+ return `${base3} names a port that Node and every browser refuse to open (the WHATWG bad-port list) \u2014 use the server's real port`;
19072
19138
  default:
19073
- return `no HTTP response from ${base2} (${r.error}) \u2014 check the URL, DNS, or that the server is running`;
19139
+ return `no HTTP response from ${base3} (${r.error}) \u2014 check the URL, DNS, or that the server is running`;
19074
19140
  }
19075
19141
  }
19076
19142
  }
@@ -19103,8 +19169,8 @@ function describeCause(err) {
19103
19169
  const code = e.code;
19104
19170
  if (typeof code === "string" && code && !parts.includes(code)) parts.push(code);
19105
19171
  }
19106
- const base2 = err instanceof Error ? err.message : String(err);
19107
- return parts.length ? `${base2}: ${parts.join(" \u2192 ")}` : base2;
19172
+ const base3 = err instanceof Error ? err.message : String(err);
19173
+ return parts.length ? `${base3}: ${parts.join(" \u2192 ")}` : base3;
19108
19174
  }
19109
19175
  function describeUnreachable(err) {
19110
19176
  const reason = classifyUnreachable(err);
@@ -19217,7 +19283,7 @@ __export(auto_update_exports, {
19217
19283
  import { execSync as execSync2, execFileSync as execFileSync3 } from "node:child_process";
19218
19284
  import { readFileSync as readFileSync34, existsSync as existsSync41 } from "node:fs";
19219
19285
  import { fileURLToPath as fileURLToPath2 } from "node:url";
19220
- import { writeFileSync as writeFileSync8, mkdtempSync as mkdtempSync3, rmSync as rmSync5, readdirSync as readdirSync30, statSync as statSync36, mkdirSync as mkdirSync9 } from "node:fs";
19286
+ import { writeFileSync as writeFileSync8, mkdtempSync as mkdtempSync3, rmSync as rmSync5, readdirSync as readdirSync30, statSync as statSync37, mkdirSync as mkdirSync9 } from "node:fs";
19221
19287
  import { join as join41, dirname as dirname18, sep as sep2, posix as pathPosix, win32 as pathWin32 } from "node:path";
19222
19288
  import { tmpdir as tmpdir2, homedir as homedir15 } from "node:os";
19223
19289
  import { createHash as createHash7 } from "node:crypto";
@@ -19249,12 +19315,12 @@ function installedVersion() {
19249
19315
  return null;
19250
19316
  }
19251
19317
  }
19252
- function planAutoUpdate(base2, caps, ownVersion3, flag) {
19318
+ function planAutoUpdate(base3, caps, ownVersion3, flag) {
19253
19319
  const rel = caps.cli;
19254
19320
  if (!rel || !rel.version || !rel.sha256) return { update: false, reason: "server advertises no CLI release" };
19255
19321
  if (!isAutoUpdateEnabled(caps.edition, flag)) return { update: false, reason: `auto-update disabled (edition ${caps.edition ?? "?"})` };
19256
19322
  if (compareVersions(rel.version, ownVersion3) <= 0) return { update: false, reason: `already current (own ${ownVersion3} >= server ${rel.version})` };
19257
- return { update: true, reason: `server ${rel.version} > own ${ownVersion3}`, url: tarballUrl(base2, rel.version), fallbackUrl: tarballUrl(base2), sha256: rel.sha256, from: ownVersion3, to: rel.version };
19323
+ return { update: true, reason: `server ${rel.version} > own ${ownVersion3}`, url: tarballUrl(base3, rel.version), fallbackUrl: tarballUrl(base3), sha256: rel.sha256, from: ownVersion3, to: rel.version };
19258
19324
  }
19259
19325
  function sweepStaleStaging(root = tmpdir2(), now = Date.now()) {
19260
19326
  const MKDTEMP_SUFFIX = /^cr-update-.{6}$/s;
@@ -19270,7 +19336,7 @@ function sweepStaleStaging(root = tmpdir2(), now = Date.now()) {
19270
19336
  if (!MKDTEMP_SUFFIX.test(name)) continue;
19271
19337
  const dir = join41(root, name);
19272
19338
  try {
19273
- const st = statSync36(dir);
19339
+ const st = statSync37(dir);
19274
19340
  if (!st.isDirectory() || now - st.mtimeMs < COLD_MS) continue;
19275
19341
  const inside = readdirSync30(dir);
19276
19342
  if (inside.length > 1 || inside.length === 1 && inside[0] !== "chat-recall.tgz") continue;
@@ -19434,20 +19500,20 @@ function clearUpdateFailures() {
19434
19500
  function stopAutoUpdates() {
19435
19501
  stopRequested = true;
19436
19502
  }
19437
- async function runAutoUpdate(base2, authHeaders, ownVersion3, deps) {
19503
+ async function runAutoUpdate(base3, authHeaders, ownVersion3, deps) {
19438
19504
  let caps;
19439
19505
  try {
19440
- const res = await fetchWithTimeout(`${base2.replace(/\/+$/, "")}/api/capabilities`, { headers: authHeaders });
19506
+ const res = await fetchWithTimeout(`${base3.replace(/\/+$/, "")}/api/capabilities`, { headers: authHeaders });
19441
19507
  if (!res.ok) return { updated: false, reason: `capabilities HTTP ${res.status}` };
19442
19508
  caps = await res.json();
19443
19509
  } catch (e) {
19444
19510
  return { updated: false, reason: `capabilities unreachable: ${e instanceof Error ? e.message : e}` };
19445
19511
  }
19446
19512
  const effectiveOwn = newerOf(ownVersion3, installedVersion());
19447
- const plan = planAutoUpdate(base2, caps, effectiveOwn, process.env.CHAT_RECALL_AUTO_UPDATE);
19513
+ const plan = planAutoUpdate(base3, caps, effectiveOwn, process.env.CHAT_RECALL_AUTO_UPDATE);
19448
19514
  if (!plan.update) {
19449
- if (/disabled|no CLI release/.test(plan.reason) && !reportedStandingSkip.has(base2)) {
19450
- reportedStandingSkip.add(base2);
19515
+ if (/disabled|no CLI release/.test(plan.reason) && !reportedStandingSkip.has(base3)) {
19516
+ reportedStandingSkip.add(base3);
19451
19517
  try {
19452
19518
  const { reportClientEvent: reportClientEvent2 } = await Promise.resolve().then(() => (init_client_events(), client_events_exports));
19453
19519
  reportClientEvent2("auto_update_skipped", { message: `${plan.reason} (server offers ${caps.cli?.version ?? "?"}, this device runs ${effectiveOwn})` });
@@ -19503,7 +19569,7 @@ var init_auto_update = __esm({
19503
19569
  "use strict";
19504
19570
  init_http();
19505
19571
  init_index_lock();
19506
- tarballUrl = (base2, version) => `${base2.replace(/\/+$/, "")}/install/${version ? `chat-recall-${version}.tgz` : "chat-recall.tgz"}`;
19572
+ tarballUrl = (base3, version) => `${base3.replace(/\/+$/, "")}/install/${version ? `chat-recall-${version}.tgz` : "chat-recall.tgz"}`;
19507
19573
  GIVE_UP_AFTER = 3;
19508
19574
  reportedStandingSkip = /* @__PURE__ */ new Set();
19509
19575
  STOPPING_REASON = "not installed: this process is shutting down";
@@ -19514,7 +19580,7 @@ var init_auto_update = __esm({
19514
19580
 
19515
19581
  // src/sync-client.ts
19516
19582
  import { join as join42, dirname as dirname19, basename as basename20 } from "node:path";
19517
- import { readFileSync as readFileSync35, writeFileSync as writeFileSync9, mkdirSync as mkdirSync10, mkdtempSync as mkdtempSync4, rmSync as rmSync6, chmodSync as chmodSync3, unlinkSync as unlinkSync2, readdirSync as readdirSync31, statSync as statSync37 } from "node:fs";
19583
+ import { readFileSync as readFileSync35, writeFileSync as writeFileSync9, mkdirSync as mkdirSync10, mkdtempSync as mkdtempSync4, rmSync as rmSync6, chmodSync as chmodSync3, unlinkSync as unlinkSync2, readdirSync as readdirSync31, statSync as statSync38 } from "node:fs";
19518
19584
  import { tmpdir as tmpdir3, hostname as hostname2 } from "node:os";
19519
19585
  import { createHash as createHash8 } from "node:crypto";
19520
19586
  import { fileURLToPath as fileURLToPath3 } from "node:url";
@@ -19559,15 +19625,15 @@ function loadAllCredentials() {
19559
19625
  return [];
19560
19626
  }
19561
19627
  async function fetchTenantSecurityConfig(cred) {
19562
- const base2 = cred.serverUrl.replace(/\/+$/, "");
19563
- const cached = _securityConfigCache.get(base2);
19628
+ const base3 = cred.serverUrl.replace(/\/+$/, "");
19629
+ const cached = _securityConfigCache.get(base3);
19564
19630
  if (cached && Date.now() - cached.fetchedAt < SECURITY_CONFIG_TTL_MS) return cached.config;
19565
19631
  const headers = { "content-type": "application/json" };
19566
19632
  if (cred.token) headers.authorization = `Bearer ${cred.token}`;
19567
19633
  try {
19568
19634
  const [rulesRes, settingsRes] = await Promise.all([
19569
- fetchWithTimeout(`${base2}/api/secrets/rules`, { headers }),
19570
- fetchWithTimeout(`${base2}/api/teams/security-config`, { headers }).catch(() => null)
19635
+ fetchWithTimeout(`${base3}/api/secrets/rules`, { headers }),
19636
+ fetchWithTimeout(`${base3}/api/teams/security-config`, { headers }).catch(() => null)
19571
19637
  ]);
19572
19638
  let tenantRules = [];
19573
19639
  let rulePackVersion = null;
@@ -19592,18 +19658,18 @@ async function fetchTenantSecurityConfig(cred) {
19592
19658
  const body = await settingsRes.json().catch(() => ({}));
19593
19659
  if (typeof body.verifySecrets === "boolean") verifySecrets = body.verifySecrets;
19594
19660
  if (typeof body.telemetry === "boolean") {
19595
- setTelemetryEligible(base2, body.telemetry);
19661
+ setTelemetryEligible(base3, body.telemetry);
19596
19662
  try {
19597
19663
  const prior = readCollectorHealth()?.telemetryEligible ?? {};
19598
19664
  updateCollectorHealth({
19599
- telemetryEligible: { ...prior, [base2]: { allowed: body.telemetry, at: Date.now() } }
19665
+ telemetryEligible: { ...prior, [base3]: { allowed: body.telemetry, at: Date.now() } }
19600
19666
  });
19601
19667
  } catch {
19602
19668
  }
19603
19669
  }
19604
19670
  }
19605
19671
  const config = { tenantRules, verifySecrets, rulePackVersion };
19606
- _securityConfigCache.set(base2, { fetchedAt: Date.now(), config });
19672
+ _securityConfigCache.set(base3, { fetchedAt: Date.now(), config });
19607
19673
  return config;
19608
19674
  } catch {
19609
19675
  return { tenantRules: [], verifySecrets: true, rulePackVersion: null };
@@ -19619,18 +19685,18 @@ function readPersistedSyncConfigs() {
19619
19685
  return {};
19620
19686
  }
19621
19687
  }
19622
- function persistSyncConfig(base2, config) {
19688
+ function persistSyncConfig(base3, config) {
19623
19689
  try {
19624
19690
  const all = readPersistedSyncConfigs();
19625
- all[base2] = { fetchedAt: Date.now(), config };
19691
+ all[base3] = { fetchedAt: Date.now(), config };
19626
19692
  mkdirSync10(dirname19(syncConfigCachePath()), { recursive: true });
19627
19693
  writeFileSync9(syncConfigCachePath(), JSON.stringify(all, null, 2));
19628
19694
  } catch {
19629
19695
  }
19630
19696
  }
19631
19697
  async function fetchTenantSyncConfig(cred) {
19632
- const base2 = cred.serverUrl.replace(/\/+$/, "");
19633
- const cached = _syncConfigCache.get(base2);
19698
+ const base3 = cred.serverUrl.replace(/\/+$/, "");
19699
+ const cached = _syncConfigCache.get(base3);
19634
19700
  if (cached && Date.now() - cached.fetchedAt < SECURITY_CONFIG_TTL_MS) return cached.config;
19635
19701
  const headers = { "content-type": "application/json" };
19636
19702
  if (cred.token) headers.authorization = `Bearer ${cred.token}`;
@@ -19638,7 +19704,7 @@ async function fetchTenantSyncConfig(cred) {
19638
19704
  try {
19639
19705
  const sources2 = discoverSessionSources();
19640
19706
  if (sources2.length > 0) {
19641
- await fetchWithTimeout(`${base2}/api/sync-config/sources`, {
19707
+ await fetchWithTimeout(`${base3}/api/sync-config/sources`, {
19642
19708
  method: "POST",
19643
19709
  headers,
19644
19710
  body: JSON.stringify({ device: deviceLabel(), sources: sources2 })
@@ -19646,12 +19712,12 @@ async function fetchTenantSyncConfig(cred) {
19646
19712
  }
19647
19713
  } catch {
19648
19714
  }
19649
- const res = await fetchWithTimeout(`${base2}/api/sync-config`, { headers });
19715
+ const res = await fetchWithTimeout(`${base3}/api/sync-config`, { headers });
19650
19716
  if (res.status === 404) {
19651
- _syncConfigCache.set(base2, { fetchedAt: Date.now(), config: EMPTY_SYNC_CONFIG });
19717
+ _syncConfigCache.set(base3, { fetchedAt: Date.now(), config: EMPTY_SYNC_CONFIG });
19652
19718
  return EMPTY_SYNC_CONFIG;
19653
19719
  }
19654
- if (!res.ok) return lastKnownSyncConfig(base2, `HTTP ${res.status}`);
19720
+ if (!res.ok) return lastKnownSyncConfig(base3, `HTTP ${res.status}`);
19655
19721
  const body = await res.json().catch(() => ({}));
19656
19722
  const config = {
19657
19723
  excludeTools: Array.isArray(body.excludeTools) ? body.excludeTools.filter((t) => typeof t === "string") : [],
@@ -19688,22 +19754,22 @@ async function fetchTenantSyncConfig(cred) {
19688
19754
  if (decided > 0) console.error(`[sync] applied ${decided} folder decision(s) from the dashboard`);
19689
19755
  } catch {
19690
19756
  }
19691
- _syncConfigCache.set(base2, { fetchedAt: Date.now(), config });
19692
- persistSyncConfig(base2, config);
19757
+ _syncConfigCache.set(base3, { fetchedAt: Date.now(), config });
19758
+ persistSyncConfig(base3, config);
19693
19759
  return config;
19694
19760
  } catch (err) {
19695
19761
  if (isSyncRulesRefusal(err)) throw err;
19696
- return lastKnownSyncConfig(base2, err instanceof Error ? err.message : "request failed");
19762
+ return lastKnownSyncConfig(base3, err instanceof Error ? err.message : "request failed");
19697
19763
  }
19698
19764
  }
19699
- function lastKnownSyncConfig(base2, reason) {
19700
- const remembered = _syncConfigCache.get(base2) ?? readPersistedSyncConfigs()[base2];
19765
+ function lastKnownSyncConfig(base3, reason) {
19766
+ const remembered = _syncConfigCache.get(base3) ?? readPersistedSyncConfigs()[base3];
19701
19767
  if (remembered) {
19702
19768
  console.error(`[sync] could not read server-side sync rules (${reason}) \u2014 applying the last known set from ${new Date(remembered.fetchedAt).toISOString()}`);
19703
19769
  return remembered.config;
19704
19770
  }
19705
19771
  const refusal = new Error(
19706
- `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.`
19772
+ `Cannot read the server-side sync rules from ${base3} (${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.`
19707
19773
  );
19708
19774
  refusal[SYNC_RULES_REFUSAL] = true;
19709
19775
  throw refusal;
@@ -19811,25 +19877,25 @@ async function syncSessions(opts = {}) {
19811
19877
  ${errors.join("\n ")}`);
19812
19878
  return { ...agg, perTarget };
19813
19879
  }
19814
- async function postFieldBatch(base2, token, rows) {
19880
+ async function postFieldBatch(base3, token, rows) {
19815
19881
  const headers = { "content-type": "application/json" };
19816
19882
  if (token) headers.authorization = `Bearer ${token}`;
19817
19883
  const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
19818
19884
  for (let attempt = 0; ; attempt++) {
19819
- const res = await fetchWithTimeout(`${base2}/api/sync`, { method: "POST", headers, body: JSON.stringify({ fields: rows }) }, 6e4);
19885
+ const res = await fetchWithTimeout(`${base3}/api/sync`, { method: "POST", headers, body: JSON.stringify({ fields: rows }) }, 6e4);
19820
19886
  if (res.ok) return;
19821
19887
  const retryable = res.status === 429 || res.status >= 500;
19822
- if (!retryable || attempt >= 5) throw new Error(`${base2}: fields batch HTTP ${res.status} ${await res.text().catch(() => "")}`);
19888
+ if (!retryable || attempt >= 5) throw new Error(`${base3}: fields batch HTTP ${res.status} ${await res.text().catch(() => "")}`);
19823
19889
  const ra = Number(res.headers.get("retry-after")) || 0;
19824
19890
  await sleep(ra > 0 ? ra * 1e3 : [500, 1500, 4e3, 8e3, 15e3][Math.min(attempt, 4)]);
19825
19891
  }
19826
19892
  }
19827
19893
  async function reconcileFieldsForTarget(cred, fullRefs, opts = {}) {
19828
- const base2 = cred.serverUrl.replace(/\/+$/, "");
19829
- const ledger = getSyncedRows(base2);
19894
+ const base3 = cred.serverUrl.replace(/\/+$/, "");
19895
+ const ledger = getSyncedRows(base3);
19830
19896
  let pushed = 0, absent = 0, scanned = 0;
19831
19897
  for (const field of SYNC_FIELDS) {
19832
- const needFull = !!opts.force || fieldNeedsFullPass(base2, field);
19898
+ const needFull = !!opts.force || fieldNeedsFullPass(base3, field);
19833
19899
  const candidates2 = needFull ? fullRefs() : opts.convRefs ?? fullRefs();
19834
19900
  const send = [];
19835
19901
  const mtimeById = /* @__PURE__ */ new Map();
@@ -19845,15 +19911,15 @@ async function reconcileFieldsForTarget(cred, fullRefs, opts = {}) {
19845
19911
  }
19846
19912
  for (let i = 0; i < send.length; i += 200) {
19847
19913
  const chunk = send.slice(i, i + 200);
19848
- await postFieldBatch(base2, cred.token, chunk);
19849
- markFieldCoverage(base2, field, chunk.map((r) => ({ id: r.session_id, present: true, mtime: mtimeById.get(r.session_id) ?? 0 })));
19914
+ await postFieldBatch(base3, cred.token, chunk);
19915
+ markFieldCoverage(base3, field, chunk.map((r) => ({ id: r.session_id, present: true, mtime: mtimeById.get(r.session_id) ?? 0 })));
19850
19916
  pushed += chunk.length;
19851
19917
  }
19852
19918
  if (absentIds.length) {
19853
- markFieldCoverage(base2, field, absentIds.map((id) => ({ id, present: false, mtime: mtimeById.get(id) ?? 0 })));
19919
+ markFieldCoverage(base3, field, absentIds.map((id) => ({ id, present: false, mtime: mtimeById.get(id) ?? 0 })));
19854
19920
  absent += absentIds.length;
19855
19921
  }
19856
- if (needFull) markFieldFullPassDone(base2, field);
19922
+ if (needFull) markFieldFullPassDone(base3, field);
19857
19923
  }
19858
19924
  return { pushed, absent, scanned };
19859
19925
  }
@@ -19869,7 +19935,7 @@ function reapStaleScanDirs(dir = tmpdir3(), maxAgeMs = 6 * 36e5, now = Date.now(
19869
19935
  if (!name.startsWith("cr-batchscan-")) continue;
19870
19936
  const p = join42(dir, name);
19871
19937
  try {
19872
- if (now - statSync37(p).mtimeMs < maxAgeMs) continue;
19938
+ if (now - statSync38(p).mtimeMs < maxAgeMs) continue;
19873
19939
  rmSync6(p, { recursive: true, force: true });
19874
19940
  reaped++;
19875
19941
  } catch {
@@ -19943,25 +20009,25 @@ function serverIngestConcurrency(serverUrl) {
19943
20009
  return advertisedIngestConc.get(serverUrl.replace(/\/$/, "")) ?? null;
19944
20010
  }
19945
20011
  async function verifyServerApi(serverUrl, minApi) {
19946
- const base2 = serverUrl.replace(/\/$/, "");
19947
- const seen = capsOk.get(base2);
20012
+ const base3 = serverUrl.replace(/\/$/, "");
20013
+ const seen = capsOk.get(base3);
19948
20014
  if (seen !== void 0 && Date.now() - seen < CAPS_TTL_MS) return true;
19949
20015
  const { probeServer: probeServer2, probeAdvice: probeAdvice2 } = await Promise.resolve().then(() => (init_server_probe(), server_probe_exports));
19950
- const probe = await probeServer2(base2, {
20016
+ const probe = await probeServer2(base3, {
19951
20017
  fetchImpl: ((url, init) => fetchWithTimeout(String(url), init ?? {}))
19952
20018
  });
19953
- if (probe.kind !== "ok") throw new Error(probeAdvice2(probe, base2));
20019
+ if (probe.kind !== "ok") throw new Error(probeAdvice2(probe, base3));
19954
20020
  const caps = probe.raw;
19955
20021
  if ((caps.apiVersion ?? 0) < minApi) {
19956
20022
  throw new Error(`server too old: apiVersion ${caps.apiVersion ?? "none"} < required ${minApi} \u2014 update the server image before syncing`);
19957
20023
  }
19958
20024
  const adv = caps.limits?.ingestConcurrencyPerTenant;
19959
20025
  if (typeof adv === "number" && Number.isFinite(adv) && adv >= 1) {
19960
- advertisedIngestConc.set(base2, Math.floor(adv));
20026
+ advertisedIngestConc.set(base3, Math.floor(adv));
19961
20027
  }
19962
- if (caps.limits?.acceptsGzipBody === true) advertisedGzipBody.add(base2);
19963
- else advertisedGzipBody.delete(base2);
19964
- capsOk.set(base2, Date.now());
20028
+ if (caps.limits?.acceptsGzipBody === true) advertisedGzipBody.add(base3);
20029
+ else advertisedGzipBody.delete(base3);
20030
+ capsOk.set(base3, Date.now());
19965
20031
  return true;
19966
20032
  }
19967
20033
  async function syncToTarget(cred, opts = {}) {
@@ -20026,7 +20092,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20026
20092
  const ac = new AbortController();
20027
20093
  const timer = setTimeout(() => ac.abort(new Error(`upload timed out after ${UPLOAD_TIMEOUT_MS}ms`)), UPLOAD_TIMEOUT_MS);
20028
20094
  try {
20029
- const res = await fetch(`${base2}/api/sync`, {
20095
+ const res = await fetch(`${base3}/api/sync`, {
20030
20096
  method: "POST",
20031
20097
  // No token ⇒ no auth header: a no-auth local server (AUTH_PROVIDER=none)
20032
20098
  // accepts it as the single 'default' tenant.
@@ -20042,26 +20108,26 @@ async function syncToTargetInScope(cred, opts = {}) {
20042
20108
  acceptedUploads.set(cred.serverUrl, (acceptedUploads.get(cred.serverUrl) ?? 0) + 1);
20043
20109
  const body2 = await res.json().catch(() => ({}));
20044
20110
  if (typeof body2.telemetry === "boolean") {
20045
- setTelemetryEligible(base2, body2.telemetry);
20111
+ setTelemetryEligible(base3, body2.telemetry);
20046
20112
  try {
20047
20113
  const prior = readCollectorHealth()?.telemetryEligible ?? {};
20048
20114
  updateCollectorHealth({
20049
- telemetryEligible: { ...prior, [base2]: { allowed: body2.telemetry, at: Date.now() } }
20115
+ telemetryEligible: { ...prior, [base3]: { allowed: body2.telemetry, at: Date.now() } }
20050
20116
  });
20051
20117
  } catch {
20052
20118
  }
20053
20119
  }
20054
20120
  const adv = body2.limits?.ingestConcurrencyPerTenant;
20055
20121
  if (typeof adv === "number" && Number.isFinite(adv) && adv >= 1) {
20056
- setServerIngestConcurrency(base2, Math.floor(adv));
20122
+ setServerIngestConcurrency(base3, Math.floor(adv));
20057
20123
  }
20058
20124
  if (body2.cli && body2.cli.version) {
20059
20125
  const { planAutoUpdate: planAutoUpdate2, runAutoUpdate: runAutoUpdate2, sweepStaleStaging: sweepStaleStaging2 } = await Promise.resolve().then(() => (init_auto_update(), auto_update_exports));
20060
20126
  const authHeaders = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
20061
- const plan = planAutoUpdate2(base2, { cli: body2.cli }, ownVersion, process.env.CHAT_RECALL_AUTO_UPDATE);
20127
+ const plan = planAutoUpdate2(base3, { cli: body2.cli }, ownVersion, process.env.CHAT_RECALL_AUTO_UPDATE);
20062
20128
  sweepStaleStaging2();
20063
20129
  if (plan.update) {
20064
- void runAutoUpdate2(base2, authHeaders, ownVersion).catch(() => {
20130
+ void runAutoUpdate2(base3, authHeaders, ownVersion).catch(() => {
20065
20131
  });
20066
20132
  }
20067
20133
  }
@@ -20070,7 +20136,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20070
20136
  const retryable = res.status === 429 || res.status >= 500;
20071
20137
  const text = await res.text().catch(() => "");
20072
20138
  if (res.status === 401 || res.status === 403) {
20073
- throw classedError("auth", `server rejected this machine's device token (HTTP ${res.status} \u2014 revoked?). Reconnect with: chat-recall login ${base2}`);
20139
+ throw classedError("auth", `server rejected this machine's device token (HTTP ${res.status} \u2014 revoked?). Reconnect with: chat-recall login ${base3}`);
20074
20140
  }
20075
20141
  if (res.status === 402) {
20076
20142
  let detail = text;
@@ -20091,7 +20157,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20091
20157
  const retryAfterS = Number(res.headers.get("retry-after"));
20092
20158
  const waitMs = res.status === 429 && retryAfterS > 0 ? retryAfterS * 1e3 : RETRY_DELAYS_MS[attempt];
20093
20159
  const why = res.status === 524 ? ` \u2014 the proxy cut the request at its time limit; the batch is too big for one request` : "";
20094
- console.error(`[sync] HTTP ${res.status} from ${base2}${why} \u2014 backing off ${Math.round(waitMs / 1e3)}s (attempt ${attempt + 1})`);
20160
+ console.error(`[sync] HTTP ${res.status} from ${base3}${why} \u2014 backing off ${Math.round(waitMs / 1e3)}s (attempt ${attempt + 1})`);
20095
20161
  await sleep(waitMs);
20096
20162
  continue;
20097
20163
  } catch (err) {
@@ -20159,11 +20225,11 @@ async function syncToTargetInScope(cred, opts = {}) {
20159
20225
  }
20160
20226
  };
20161
20227
  };
20162
- const base2 = cred.serverUrl.replace(/\/$/, "");
20163
- const ledger = opts.useLedger ? getSyncedRows(base2) : null;
20228
+ const base3 = cred.serverUrl.replace(/\/$/, "");
20229
+ const ledger = opts.useLedger ? getSyncedRows(base3) : null;
20164
20230
  const convBatch = makeBatcher("conversations", 25, false, (rows) => {
20165
20231
  try {
20166
- markSynced(base2, rows.map((r) => {
20232
+ markSynced(base3, rows.map((r) => {
20167
20233
  const off = typeof r.from_offset === "number" ? r.from_offset : 0;
20168
20234
  const hash = shippedHash.get(r.session_id);
20169
20235
  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 };
@@ -20178,7 +20244,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20178
20244
  const ac = new AbortController();
20179
20245
  const timer = setTimeout(() => ac.abort(new Error(`upload timed out after ${UPLOAD_TIMEOUT_MS}ms`)), UPLOAD_TIMEOUT_MS);
20180
20246
  try {
20181
- const res = await fetch(`${base2}/api/sync`, {
20247
+ const res = await fetch(`${base3}/api/sync`, {
20182
20248
  method: "POST",
20183
20249
  headers,
20184
20250
  body: JSON.stringify({ conversations: convs }),
@@ -20189,10 +20255,10 @@ async function syncToTargetInScope(cred, opts = {}) {
20189
20255
  if (body.cli && body.cli.version) {
20190
20256
  const { planAutoUpdate: planAutoUpdate2, runAutoUpdate: runAutoUpdate2, sweepStaleStaging: sweepStaleStaging2 } = await Promise.resolve().then(() => (init_auto_update(), auto_update_exports));
20191
20257
  const authHeaders = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
20192
- const plan = planAutoUpdate2(base2, { cli: body.cli }, ownVersion, process.env.CHAT_RECALL_AUTO_UPDATE);
20258
+ const plan = planAutoUpdate2(base3, { cli: body.cli }, ownVersion, process.env.CHAT_RECALL_AUTO_UPDATE);
20193
20259
  sweepStaleStaging2();
20194
20260
  if (plan.update) {
20195
- void runAutoUpdate2(base2, authHeaders, ownVersion).catch(() => {
20261
+ void runAutoUpdate2(base3, authHeaders, ownVersion).catch(() => {
20196
20262
  });
20197
20263
  }
20198
20264
  }
@@ -20200,7 +20266,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20200
20266
  const acked = convs.filter((c) => !fullNeeded.has(c.session_id));
20201
20267
  if (acked.length > 0) {
20202
20268
  try {
20203
- markSynced(base2, acked.map((c) => ({
20269
+ markSynced(base3, acked.map((c) => ({
20204
20270
  id: c.session_id,
20205
20271
  mtime: c.mtime,
20206
20272
  offset: c.from_offset,
@@ -20224,7 +20290,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20224
20290
  const ac = new AbortController();
20225
20291
  const timer = setTimeout(() => ac.abort(new Error(`upload timed out after ${UPLOAD_TIMEOUT_MS}ms`)), UPLOAD_TIMEOUT_MS);
20226
20292
  try {
20227
- const res = await fetch(`${base2}/api/sync`, {
20293
+ const res = await fetch(`${base3}/api/sync`, {
20228
20294
  method: "POST",
20229
20295
  headers,
20230
20296
  body: JSON.stringify({ conversations: [conv] }),
@@ -20237,11 +20303,11 @@ async function syncToTargetInScope(cred, opts = {}) {
20237
20303
  const mtime = conv.mtime;
20238
20304
  try {
20239
20305
  if (!guarded) {
20240
- markSynced(base2, [{ id, mtime, offset: conv.from_offset, size: conv.from_offset, acked: true }]);
20306
+ markSynced(base3, [{ id, mtime, offset: conv.from_offset, size: conv.from_offset, acked: true }]);
20241
20307
  } else if (typeof guarded.o === "number" && guarded.o > 0 && guarded.o <= fileSize) {
20242
- markSynced(base2, [{ id, mtime, offset: guarded.o, size: guarded.o, acked: true }]);
20308
+ markSynced(base3, [{ id, mtime, offset: guarded.o, size: guarded.o, acked: true }]);
20243
20309
  } else {
20244
- markSynced(base2, [{ id, mtime }]);
20310
+ markSynced(base3, [{ id, mtime }]);
20245
20311
  }
20246
20312
  } catch {
20247
20313
  }
@@ -20307,7 +20373,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20307
20373
  const m = process.memoryUsage();
20308
20374
  console.error(`[sync-trace] ${msg} \xB7 heap=${(m.heapUsed / 1048576).toFixed(0)}MB rss=${(m.rss / 1048576).toFixed(0)}MB`);
20309
20375
  } : null;
20310
- trace?.(`walk start: ${slice.length} ref(s) \u2192 ${base2}`);
20376
+ trace?.(`walk start: ${slice.length} ref(s) \u2192 ${base3}`);
20311
20377
  if (upload.sessionMeta) {
20312
20378
  try {
20313
20379
  await reconcileFieldsForTarget(
@@ -20322,7 +20388,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20322
20388
  { convRefs: slice }
20323
20389
  );
20324
20390
  } catch (e) {
20325
- console.error(`[sync] field reconcile (${base2}): ${e instanceof Error ? e.message : e}`);
20391
+ console.error(`[sync] field reconcile (${base3}): ${e instanceof Error ? e.message : e}`);
20326
20392
  }
20327
20393
  }
20328
20394
  trace?.("field reconcile done");
@@ -20364,7 +20430,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20364
20430
  }
20365
20431
  trace?.("conversation walk start");
20366
20432
  const walkStartedAt = Date.now();
20367
- const firstWalk = (ledger ?? getSyncedRows(base2)).size === 0;
20433
+ const firstWalk = (ledger ?? getSyncedRows(base3)).size === 0;
20368
20434
  reportWalkProgress({ done: 0, total: slice.length, startedAt: walkStartedAt, complete: false, first: firstWalk });
20369
20435
  walkProgressForUpload = { done: 0, total: slice.length, complete: false };
20370
20436
  let traceN = 0;
@@ -20404,7 +20470,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20404
20470
  continue;
20405
20471
  } else {
20406
20472
  try {
20407
- markSynced(base2, [{ id: ref.prefixedId, mtime: ref.mtime }]);
20473
+ markSynced(base3, [{ id: ref.prefixedId, mtime: ref.mtime }]);
20408
20474
  } catch {
20409
20475
  }
20410
20476
  skipped++;
@@ -20427,7 +20493,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20427
20493
  const off = getBackendForId(ref.prefixedId)?.fileSize?.(ref.rawId) ?? 0;
20428
20494
  const priorCursor = ackRow?.s ?? 0;
20429
20495
  const safeToAck = off > 0 && off <= priorCursor;
20430
- 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 }]);
20496
+ markSynced(base3, [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 }]);
20431
20497
  } catch {
20432
20498
  }
20433
20499
  }
@@ -20437,7 +20503,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20437
20503
  if (!built) {
20438
20504
  if (ledger) {
20439
20505
  try {
20440
- markSynced(base2, [{ id: ref.prefixedId, mtime: ref.mtime }]);
20506
+ markSynced(base3, [{ id: ref.prefixedId, mtime: ref.mtime }]);
20441
20507
  } catch {
20442
20508
  }
20443
20509
  }
@@ -20494,7 +20560,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20494
20560
  walked++;
20495
20561
  if (walked % 250 === 0) console.error(`[sync] ${walked}/${slice.length} sessions\u2026`);
20496
20562
  }
20497
- const itemVersions = loadItemVersions(base2);
20563
+ const itemVersions = loadItemVersions(base3);
20498
20564
  const seenTools = /* @__PURE__ */ new Set();
20499
20565
  const seenItemKeys = /* @__PURE__ */ new Map();
20500
20566
  const registry = buildSourceRegistry();
@@ -20588,7 +20654,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20588
20654
  await appendFlush();
20589
20655
  for (const id of appendResults.fullResyncNeeded) {
20590
20656
  try {
20591
- markFullResync(base2, id);
20657
+ markFullResync(base3, id);
20592
20658
  } catch {
20593
20659
  }
20594
20660
  }
@@ -20601,7 +20667,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20601
20667
  await findingsBatch.drain();
20602
20668
  await drainInflight();
20603
20669
  {
20604
- const sentHashes = loadInventoryHashes(base2);
20670
+ const sentHashes = loadInventoryHashes(base3);
20605
20671
  const entries = [];
20606
20672
  const hashes = {};
20607
20673
  for (const [sourceType, ids] of inventory) {
@@ -20615,7 +20681,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20615
20681
  if (entries.length > 0) {
20616
20682
  try {
20617
20683
  await post({ inventory: entries });
20618
- saveInventoryHashes(base2, hashes);
20684
+ saveInventoryHashes(base3, hashes);
20619
20685
  } catch (err) {
20620
20686
  console.error(`[sync] toolkit inventory not sent (it is retried next sync): ${err instanceof Error ? err.message : err}`);
20621
20687
  }
@@ -20626,7 +20692,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20626
20692
  const rec = {};
20627
20693
  for (const t of seenTools) rec[t] = extractorVersionForTool(t);
20628
20694
  for (const [k, v] of seenItemKeys) rec[k] = v;
20629
- saveItemVersions(base2, rec);
20695
+ saveItemVersions(base3, rec);
20630
20696
  } catch {
20631
20697
  }
20632
20698
  }
@@ -20639,9 +20705,9 @@ async function syncToTargetInScope(cred, opts = {}) {
20639
20705
  }
20640
20706
  if (tombstones.length > 0) {
20641
20707
  await post({ tombstones });
20642
- const data = getLedgerData(base2);
20708
+ const data = getLedgerData(base3);
20643
20709
  for (const t of tombstones) delete data[t.session_id];
20644
- persistLedgerData(base2, data);
20710
+ persistLedgerData(base3, data);
20645
20711
  }
20646
20712
  }
20647
20713
  if (opts.prune) await post({ prune_empty_sessions: true });
@@ -21112,7 +21178,7 @@ var init_sync_client = __esm({
21112
21178
  ownVersion = JSON.parse(readFileSync35(join42(dir, "../package.json"), "utf-8")).version || ownVersion;
21113
21179
  } catch {
21114
21180
  try {
21115
- if (true) ownVersion = "0.7.13";
21181
+ if (true) ownVersion = "0.7.15";
21116
21182
  } catch {
21117
21183
  }
21118
21184
  }
@@ -21171,10 +21237,10 @@ function parseAgentText(content, format, fallbackName) {
21171
21237
  return { name: fm.name || fallbackName, description: fm.description || "", tools: fm.tools, body: body.trim() };
21172
21238
  }
21173
21239
  function readCommand(filePath, format) {
21174
- return parseCommandText(readFileSync36(filePath, "utf-8"), format, base(filePath));
21240
+ return parseCommandText(readFileSync36(filePath, "utf-8"), format, base2(filePath));
21175
21241
  }
21176
21242
  function readAgent(filePath, format) {
21177
- return parseAgentText(readFileSync36(filePath, "utf-8"), format, base(filePath));
21243
+ return parseAgentText(readFileSync36(filePath, "utf-8"), format, base2(filePath));
21178
21244
  }
21179
21245
  function readInstructions(filePath, name) {
21180
21246
  const content = readFileSync36(filePath, "utf-8");
@@ -21274,7 +21340,7 @@ function emit(type, art, toTool, projectPath) {
21274
21340
  content: stringifyFrontmatter({ name: art.name, description: art.description, ...art.tools ? { tools: art.tools } : {} }, art.body)
21275
21341
  };
21276
21342
  }
21277
- function base(filePath) {
21343
+ function base2(filePath) {
21278
21344
  return basename21(filePath).replace(/\.(md|toml)$/, "");
21279
21345
  }
21280
21346
  var init_artifact_codec = __esm({
@@ -21712,11 +21778,11 @@ var init_toolkit_sync = __esm({
21712
21778
  });
21713
21779
 
21714
21780
  // ../engine/dist/core/which.js
21715
- import { existsSync as existsSync44, statSync as statSync39, accessSync, constants } from "node:fs";
21781
+ import { existsSync as existsSync44, statSync as statSync40, accessSync, constants } from "node:fs";
21716
21782
  import { join as join46, isAbsolute as isAbsolute2, delimiter as delimiter2, sep as sep3 } from "node:path";
21717
21783
  function executable(p) {
21718
21784
  try {
21719
- if (!statSync39(p).isFile())
21785
+ if (!statSync40(p).isFile())
21720
21786
  return false;
21721
21787
  } catch {
21722
21788
  return false;
@@ -21779,11 +21845,11 @@ __export(toolkit_pull_exports, {
21779
21845
  platformRefusal: () => platformRefusal,
21780
21846
  portableCommand: () => portableCommand
21781
21847
  });
21782
- import { existsSync as existsSync45, mkdirSync as mkdirSync13, statSync as statSync40, writeFileSync as writeFileSync12 } from "node:fs";
21848
+ import { existsSync as existsSync45, mkdirSync as mkdirSync13, statSync as statSync41, writeFileSync as writeFileSync12 } from "node:fs";
21783
21849
  import { dirname as dirname22, join as join47, basename as basename23, isAbsolute as isAbsolute3 } from "node:path";
21784
21850
  function isExecutableFile(p) {
21785
21851
  try {
21786
- return statSync40(p).isFile();
21852
+ return statSync41(p).isFile();
21787
21853
  } catch {
21788
21854
  return false;
21789
21855
  }
@@ -21797,9 +21863,9 @@ function portableCommand(cmd) {
21797
21863
  }
21798
21864
  if (isExecutableFile(cmd))
21799
21865
  return { command: cmd, rewritten: false };
21800
- const base2 = basename23(cmd);
21801
- if (onPath(base2))
21802
- return { command: base2, rewritten: true };
21866
+ const base3 = basename23(cmd);
21867
+ if (onPath(base3))
21868
+ return { command: base3, rewritten: true };
21803
21869
  return { missing: cmd };
21804
21870
  }
21805
21871
  function entryFromSpec(spec) {
@@ -22316,7 +22382,7 @@ __export(shadow_prune_exports, {
22316
22382
  DEFAULT_MAX_TOTAL_BYTES: () => DEFAULT_MAX_TOTAL_BYTES,
22317
22383
  pruneShadow: () => pruneShadow
22318
22384
  });
22319
- import { readdirSync as readdirSync32, statSync as statSync43, unlinkSync as unlinkSync3 } from "fs";
22385
+ import { readdirSync as readdirSync32, statSync as statSync44, unlinkSync as unlinkSync3 } from "fs";
22320
22386
  import { join as join50 } from "path";
22321
22387
  function listShadows(isFullyAcked) {
22322
22388
  const out = [];
@@ -22341,7 +22407,7 @@ function listShadows(isFullyAcked) {
22341
22407
  const path = join50(dir, name);
22342
22408
  let st;
22343
22409
  try {
22344
- st = statSync43(path);
22410
+ st = statSync44(path);
22345
22411
  } catch {
22346
22412
  continue;
22347
22413
  }
@@ -22456,7 +22522,7 @@ var init_code_intel = __esm({
22456
22522
  });
22457
22523
 
22458
22524
  // ../engine/dist/core/companions.js
22459
- import { existsSync as existsSync48, mkdirSync as mkdirSync16, statSync as statSync44, chmodSync as chmodSync4, unlinkSync as unlinkSync4, renameSync as renameSync5, createWriteStream, readFileSync as readFileSync42, writeFileSync as writeFileSync15 } from "node:fs";
22525
+ import { existsSync as existsSync48, mkdirSync as mkdirSync16, statSync as statSync45, chmodSync as chmodSync4, unlinkSync as unlinkSync4, renameSync as renameSync5, createWriteStream, readFileSync as readFileSync42, writeFileSync as writeFileSync15 } from "node:fs";
22460
22526
  import { homedir as homedir19 } from "node:os";
22461
22527
  import { join as join51 } from "node:path";
22462
22528
  import { execSync as execSync3 } from "node:child_process";
@@ -22507,7 +22573,7 @@ function checkCodeindexStatus() {
22507
22573
  status.installed = true;
22508
22574
  status.path = foundPath;
22509
22575
  try {
22510
- status.size = statSync44(foundPath).size;
22576
+ status.size = statSync45(foundPath).size;
22511
22577
  } catch {
22512
22578
  }
22513
22579
  try {
@@ -22847,17 +22913,17 @@ async function collectCode(opts) {
22847
22913
  return r;
22848
22914
  };
22849
22915
  log6(`indexing ${ws} + analyses \u2026`);
22850
- const base2 = await runMcp(bin, ws, [
22916
+ const base3 = await runMcp(bin, ws, [
22851
22917
  call(1, "index_workspace", { path: ws }),
22852
22918
  call(2, "status"),
22853
22919
  call(3, "get_tree"),
22854
22920
  ...ANALYSES.map((a, i) => call(10 + i, "analyze", { analysis: a }))
22855
22921
  ]);
22856
- const st = parseJson(base2, 2, {});
22857
- const tree = parseJson(base2, 3, []);
22922
+ const st = parseJson(base3, 2, {});
22923
+ const tree = parseJson(base3, 3, []);
22858
22924
  const A = {};
22859
22925
  ANALYSES.forEach((a, i) => {
22860
- A[a] = parseJson(base2, 10 + i, {});
22926
+ A[a] = parseJson(base3, 10 + i, {});
22861
22927
  });
22862
22928
  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;
22863
22929
  if (tree.length === 0) {
@@ -23950,7 +24016,7 @@ import { join as join48 } from "node:path";
23950
24016
 
23951
24017
  // src/project-tasks.ts
23952
24018
  init_http();
23953
- import { existsSync as existsSync43, readFileSync as readFileSync38, writeFileSync as writeFileSync11, mkdirSync as mkdirSync12, statSync as statSync38 } from "node:fs";
24019
+ import { existsSync as existsSync43, readFileSync as readFileSync38, writeFileSync as writeFileSync11, mkdirSync as mkdirSync12, statSync as statSync39 } from "node:fs";
23954
24020
  import { join as join45, dirname as dirname21 } from "node:path";
23955
24021
  import { homedir as homedir18 } from "node:os";
23956
24022
 
@@ -24043,14 +24109,14 @@ var FILE_KINDS = [
24043
24109
  { kind: "secret", filename: "SECURITY_TASKS.md", trackedPath: "/api/secrets/tasks/tracked", statusPath: "/api/secrets/tasks/status" },
24044
24110
  { kind: "code", filename: "CODE_TASKS.md", trackedPath: "/api/code/tasks/tracked", statusPath: "/api/code/tasks/status" }
24045
24111
  ];
24046
- async function pushProjectTaskStatuses(base2, authHeaders, opts = {}) {
24112
+ async function pushProjectTaskStatuses(base3, authHeaders, opts = {}) {
24047
24113
  const out = { files: 0, pushedTasks: 0 };
24048
24114
  const ledger = readLedger();
24049
24115
  let ledgerDirty = false;
24050
24116
  for (const fk of FILE_KINDS) {
24051
24117
  let projects;
24052
24118
  try {
24053
- const res = await fetchWithTimeout(`${base2}${fk.trackedPath}`, { headers: authHeaders });
24119
+ const res = await fetchWithTimeout(`${base3}${fk.trackedPath}`, { headers: authHeaders });
24054
24120
  if (!res.ok) continue;
24055
24121
  projects = (await res.json()).projects || [];
24056
24122
  } catch {
@@ -24061,7 +24127,7 @@ async function pushProjectTaskStatuses(base2, authHeaders, opts = {}) {
24061
24127
  if (!existsSync43(file)) continue;
24062
24128
  let mtime;
24063
24129
  try {
24064
- mtime = statSync38(file).mtimeMs;
24130
+ mtime = statSync39(file).mtimeMs;
24065
24131
  } catch {
24066
24132
  continue;
24067
24133
  }
@@ -24078,7 +24144,7 @@ async function pushProjectTaskStatuses(base2, authHeaders, opts = {}) {
24078
24144
  continue;
24079
24145
  }
24080
24146
  try {
24081
- const res = await fetchWithTimeout(`${base2}${fk.statusPath}`, {
24147
+ const res = await fetchWithTimeout(`${base3}${fk.statusPath}`, {
24082
24148
  method: "POST",
24083
24149
  headers: { "content-type": "application/json", ...authHeaders },
24084
24150
  body: JSON.stringify({ project, items: changed.map((t) => ({ id: t.id, status: t.intent })) })
@@ -24168,16 +24234,16 @@ ${block}`);
24168
24234
  return { status: "error", result: JSON.stringify({ error: e instanceof Error ? e.message : "failed" }) };
24169
24235
  }
24170
24236
  }
24171
- async function runPull(base2, opts) {
24237
+ async function runPull(base3, opts) {
24172
24238
  const { executePull: executePull2 } = await Promise.resolve().then(() => (init_toolkit_pull(), toolkit_pull_exports));
24173
24239
  const { hostname: hostname3 } = await import("node:os");
24174
- const creds = loadAllCredentials().find((c) => c.serverUrl.replace(/\/+$/, "") === base2.replace(/\/+$/, ""));
24240
+ const creds = loadAllCredentials().find((c) => c.serverUrl.replace(/\/+$/, "") === base3.replace(/\/+$/, ""));
24175
24241
  const headers = creds?.token ? { authorization: `Bearer ${creds.token}` } : {};
24176
24242
  const wanted = opts.types?.length ? opts.types : ["mcp", "skill", "command", "agent", "instructions"];
24177
24243
  const rows = [];
24178
24244
  for (const type of wanted) {
24179
24245
  try {
24180
- const res = await fetchWithTimeout(`${base2}/api/toolkit/browse/${type}?limit=1000`, { headers });
24246
+ const res = await fetchWithTimeout(`${base3}/api/toolkit/browse/${type}?limit=1000`, { headers });
24181
24247
  if (!res.ok) continue;
24182
24248
  const body = await res.json();
24183
24249
  for (const it of body.items || []) rows.push(it);
@@ -24249,27 +24315,27 @@ try {
24249
24315
  ownVersion2 = JSON.parse(readFileSync39(join48(dir, "../package.json"), "utf-8")).version || ownVersion2;
24250
24316
  } catch {
24251
24317
  try {
24252
- if (true) ownVersion2 = "0.7.13";
24318
+ if (true) ownVersion2 = "0.7.15";
24253
24319
  } catch {
24254
24320
  }
24255
24321
  }
24256
24322
  async function drainSyncIntents(opts = {}) {
24257
24323
  const out = { processed: 0, done: 0, errored: 0 };
24258
24324
  for (const cred of loadAllCredentials()) {
24259
- const base2 = cred.serverUrl.replace(/\/+$/, "");
24325
+ const base3 = cred.serverUrl.replace(/\/+$/, "");
24260
24326
  const authHeaders = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
24261
24327
  let pending;
24262
24328
  try {
24263
- const res = await fetchWithTimeout(`${base2}/api/sync-intents/pending`, { headers: authHeaders });
24329
+ const res = await fetchWithTimeout(`${base3}/api/sync-intents/pending`, { headers: authHeaders });
24264
24330
  if (!res.ok) continue;
24265
24331
  const data = await res.json();
24266
24332
  pending = data.intents || [];
24267
24333
  if (data.cli && data.cli.version) {
24268
24334
  const { planAutoUpdate: planAutoUpdate2, runAutoUpdate: runAutoUpdate2, sweepStaleStaging: sweepStaleStaging2 } = await Promise.resolve().then(() => (init_auto_update(), auto_update_exports));
24269
- const plan = planAutoUpdate2(base2, { cli: data.cli }, ownVersion2, process.env.CHAT_RECALL_AUTO_UPDATE);
24335
+ const plan = planAutoUpdate2(base3, { cli: data.cli }, ownVersion2, process.env.CHAT_RECALL_AUTO_UPDATE);
24270
24336
  sweepStaleStaging2();
24271
24337
  if (plan.update) {
24272
- void runAutoUpdate2(base2, authHeaders, ownVersion2).catch(() => {
24338
+ void runAutoUpdate2(base3, authHeaders, ownVersion2).catch(() => {
24273
24339
  });
24274
24340
  }
24275
24341
  }
@@ -24277,7 +24343,7 @@ async function drainSyncIntents(opts = {}) {
24277
24343
  continue;
24278
24344
  }
24279
24345
  for (const intent of pending) {
24280
- const { status, result } = await runIntent(intent, { base: base2 });
24346
+ const { status, result } = await runIntent(intent, { base: base3 });
24281
24347
  out.processed++;
24282
24348
  if (status === "done") out.done++;
24283
24349
  else out.errored++;
@@ -24286,7 +24352,7 @@ async function drainSyncIntents(opts = {}) {
24286
24352
  console.error(`[sync-intent] ${label}: ${status}`);
24287
24353
  }
24288
24354
  try {
24289
- await fetchWithTimeout(`${base2}/api/sync-intents/${intent.id}/ack`, {
24355
+ await fetchWithTimeout(`${base3}/api/sync-intents/${intent.id}/ack`, {
24290
24356
  method: "POST",
24291
24357
  headers: { "content-type": "application/json", ...authHeaders },
24292
24358
  body: JSON.stringify({ status, result })
@@ -24295,7 +24361,7 @@ async function drainSyncIntents(opts = {}) {
24295
24361
  }
24296
24362
  }
24297
24363
  try {
24298
- await pushProjectTaskStatuses(base2, authHeaders, { verbose: opts.verbose });
24364
+ await pushProjectTaskStatuses(base3, authHeaders, { verbose: opts.verbose });
24299
24365
  } catch {
24300
24366
  }
24301
24367
  }
@@ -24314,7 +24380,7 @@ init_auto_update();
24314
24380
 
24315
24381
  // src/code-index-cursor.ts
24316
24382
  init_paths();
24317
- import { readFileSync as readFileSync40, writeFileSync as writeFileSync14, mkdirSync as mkdirSync15, statSync as statSync41 } from "fs";
24383
+ import { readFileSync as readFileSync40, writeFileSync as writeFileSync14, mkdirSync as mkdirSync15, statSync as statSync42 } from "fs";
24318
24384
  import { execFileSync as execFileSync4 } from "child_process";
24319
24385
  import { createHash as createHash10 } from "crypto";
24320
24386
  import { join as join49, dirname as dirname24 } from "path";
@@ -24365,7 +24431,7 @@ function workspaceFingerprint(workspace, collectorVersion) {
24365
24431
  const rel = entry.slice(3);
24366
24432
  let stamp2 = "gone";
24367
24433
  try {
24368
- const s = statSync41(join49(workspace, rel));
24434
+ const s = statSync42(join49(workspace, rel));
24369
24435
  stamp2 = `${s.size}:${Math.floor(s.mtimeMs)}`;
24370
24436
  } catch {
24371
24437
  }
@@ -24574,11 +24640,11 @@ function checkSelfRestart(opts) {
24574
24640
  }
24575
24641
 
24576
24642
  // src/log-rotate.ts
24577
- import { statSync as statSync42, copyFileSync as copyFileSync3, truncateSync } from "fs";
24643
+ import { statSync as statSync43, copyFileSync as copyFileSync3, truncateSync } from "fs";
24578
24644
  var LOG_MAX_BYTES = 32 * 1024 * 1024;
24579
24645
  function rotateLogIfLarge(logPath, maxBytes = LOG_MAX_BYTES) {
24580
24646
  try {
24581
- const size = statSync42(logPath).size;
24647
+ const size = statSync43(logPath).size;
24582
24648
  if (size < maxBytes) return { rotated: false, sizeBefore: 0 };
24583
24649
  copyFileSync3(logPath, `${logPath}.1`);
24584
24650
  truncateSync(logPath, 0);
@@ -24633,8 +24699,8 @@ async function runCollectorMigration(opts) {
24633
24699
  // auto-indexer/indexer.ts
24634
24700
  init_sync_ledger();
24635
24701
  init_collector_health();
24636
- import { existsSync as existsSync50, readFileSync as readFileSync45, statSync as statSync45 } from "fs";
24637
- var CLI_VERSION3 = true ? "0.7.13" : "0.0.0";
24702
+ import { existsSync as existsSync50, readFileSync as readFileSync45, statSync as statSync46 } from "fs";
24703
+ var CLI_VERSION3 = true ? "0.7.15" : "0.0.0";
24638
24704
  var DEBOUNCE_MS = 5e3;
24639
24705
  var PLANS_DIR = claudeBackend.plansDir();
24640
24706
  var TASKS_DIR = claudeBackend.tasksDir();
@@ -24739,7 +24805,7 @@ var CLAUDE_SESSION_ROOTS = claudeProjectDirs();
24739
24805
  var sessionWatcher = watchWithFallback("sessions", CLAUDE_SESSION_ROOTS.map((root) => `${root}/**/*.jsonl`), {
24740
24806
  ignored: (p, stats) => {
24741
24807
  if (/agent-/.test(p) || /^\./.test(basename25(p))) return true;
24742
- const st = stats ?? statSync45(p, { throwIfNoEntry: false });
24808
+ const st = stats ?? statSync46(p, { throwIfNoEntry: false });
24743
24809
  if (!st || st.isDirectory()) return false;
24744
24810
  return st.mtimeMs < Date.now() - WATCH_WINDOW_MS;
24745
24811
  },
@@ -25109,10 +25175,10 @@ async function codeIndexTick() {
25109
25175
  continue;
25110
25176
  }
25111
25177
  for (const cred of creds) {
25112
- const base2 = cred.serverUrl.replace(/\/+$/, "");
25178
+ const base3 = cred.serverUrl.replace(/\/+$/, "");
25113
25179
  const headers = { "content-type": "application/json", ...cred.token ? { authorization: `Bearer ${cred.token}` } : {} };
25114
25180
  try {
25115
- await fetchWithTimeout(`${base2}/api/code/index`, { method: "POST", headers, body: JSON.stringify(result) }, 6e4);
25181
+ await fetchWithTimeout(`${base3}/api/code/index`, { method: "POST", headers, body: JSON.stringify(result) }, 6e4);
25116
25182
  } catch {
25117
25183
  }
25118
25184
  }
@@ -25135,12 +25201,12 @@ if (CODE_INDEX_ON) {
25135
25201
  }
25136
25202
  async function autoUpdateTick() {
25137
25203
  for (const cred of loadAllCredentials()) {
25138
- const base2 = cred.serverUrl.replace(/\/+$/, "");
25204
+ const base3 = cred.serverUrl.replace(/\/+$/, "");
25139
25205
  const headers = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
25140
25206
  try {
25141
- const r = await runAutoUpdate(base2, headers, CLI_VERSION3);
25142
- if (r.updated) daemonLog.info(`auto-update: ${r.reason} (${base2}) \u2014 restarting service`);
25143
- else if (!/already current|disabled|no CLI release/.test(r.reason)) daemonLog.info(`auto-update: ${r.reason} (${base2})`);
25207
+ const r = await runAutoUpdate(base3, headers, CLI_VERSION3);
25208
+ if (r.updated) daemonLog.info(`auto-update: ${r.reason} (${base3}) \u2014 restarting service`);
25209
+ else if (!/already current|disabled|no CLI release/.test(r.reason)) daemonLog.info(`auto-update: ${r.reason} (${base3})`);
25144
25210
  } catch {
25145
25211
  }
25146
25212
  }
@@ -25167,20 +25233,20 @@ async function collectorMigrationOnce() {
25167
25233
  return;
25168
25234
  }
25169
25235
  for (const cred of creds) {
25170
- const base2 = cred.serverUrl.replace(/\/+$/, "");
25236
+ const base3 = cred.serverUrl.replace(/\/+$/, "");
25171
25237
  const headers = { "content-type": "application/json", ...cred.token ? { authorization: `Bearer ${cred.token}` } : {} };
25172
25238
  const reindex = async (rootPath) => {
25173
25239
  try {
25174
25240
  const result = await collectCode2({ workspace: rootPath, binPath: bin });
25175
- const res = await fetchWithTimeout(`${base2}/api/code/index`, { method: "POST", headers, body: JSON.stringify(result) }, 6e4);
25241
+ const res = await fetchWithTimeout(`${base3}/api/code/index`, { method: "POST", headers, body: JSON.stringify(result) }, 6e4);
25176
25242
  return res.ok;
25177
25243
  } catch {
25178
25244
  return false;
25179
25245
  }
25180
25246
  };
25181
25247
  try {
25182
- const r = await runCollectorMigration({ base: base2, authHeaders: headers, current: COLLECTOR_VERSION2, reindex, log: (m) => daemonLog.info(`${m}`) });
25183
- if (r.reindexed || r.failed || r.missing) daemonLog.info(`collector migration (${base2}): re-derived ${r.reindexed}, failed ${r.failed}, skipped-missing ${r.missing}`);
25248
+ const r = await runCollectorMigration({ base: base3, authHeaders: headers, current: COLLECTOR_VERSION2, reindex, log: (m) => daemonLog.info(`${m}`) });
25249
+ if (r.reindexed || r.failed || r.missing) daemonLog.info(`collector migration (${base3}): re-derived ${r.reindexed}, failed ${r.failed}, skipped-missing ${r.missing}`);
25184
25250
  } catch {
25185
25251
  }
25186
25252
  }