chat-recall 0.7.14 → 0.7.16

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);
@@ -7973,7 +7973,64 @@ var init_first_prompt = __esm({
7973
7973
  });
7974
7974
 
7975
7975
  // ../engine/dist/core/backends/tail-read.js
7976
- import { openSync as openSync5, readSync as readSync5, closeSync as closeSync5, statSync as statSync6 } from "node:fs";
7976
+ import { openSync as openSync5, readSync as readSync5, closeSync as closeSync5, statSync as statSync6, fstatSync } from "node:fs";
7977
+ function readAt(fd, pos, len) {
7978
+ const buf = Buffer.alloc(len);
7979
+ let got = 0;
7980
+ while (got < len) {
7981
+ const n = readSync5(fd, buf, got, len - got, pos + got);
7982
+ if (n <= 0)
7983
+ break;
7984
+ got += n;
7985
+ }
7986
+ return buf.subarray(0, got);
7987
+ }
7988
+ function linesBeforeOffset(path, offset) {
7989
+ if (offset <= 0)
7990
+ return 0;
7991
+ let fd = null;
7992
+ try {
7993
+ fd = openSync5(path, "r");
7994
+ const ino = fstatSync(fd).ino;
7995
+ const known = lineCounts.get(path);
7996
+ let pos = 0;
7997
+ let lines = 0;
7998
+ if (known && known.ino === ino && known.offset <= offset) {
7999
+ const edgeStart2 = Math.max(0, known.offset - EDGE_BYTES);
8000
+ if (readAt(fd, edgeStart2, known.offset - edgeStart2).equals(known.edge)) {
8001
+ pos = known.offset;
8002
+ lines = known.lines;
8003
+ }
8004
+ }
8005
+ const block = Buffer.allocUnsafe(SKIP_SCAN_BYTES);
8006
+ while (pos < offset) {
8007
+ const n = readSync5(fd, block, 0, Math.min(SKIP_SCAN_BYTES, offset - pos), pos);
8008
+ if (n <= 0)
8009
+ return void 0;
8010
+ for (let i = block.indexOf(10, 0); i >= 0 && i < n; i = block.indexOf(10, i + 1))
8011
+ lines++;
8012
+ pos += n;
8013
+ }
8014
+ const edgeStart = Math.max(0, offset - EDGE_BYTES);
8015
+ const edge = readAt(fd, edgeStart, offset - edgeStart);
8016
+ if (lineCounts.size >= LINE_COUNT_CACHE_MAX && !lineCounts.has(path)) {
8017
+ const oldest = lineCounts.keys().next().value;
8018
+ if (oldest !== void 0)
8019
+ lineCounts.delete(oldest);
8020
+ }
8021
+ lineCounts.set(path, { offset, lines, ino, edge });
8022
+ return lines;
8023
+ } catch {
8024
+ return void 0;
8025
+ } finally {
8026
+ if (fd !== null) {
8027
+ try {
8028
+ closeSync5(fd);
8029
+ } catch {
8030
+ }
8031
+ }
8032
+ }
8033
+ }
7977
8034
  function readTailFromOffset(path, offset, maxBytes = TAIL_READ_MAX_BYTES) {
7978
8035
  let size = 0;
7979
8036
  try {
@@ -8001,7 +8058,7 @@ function readTailFromOffset(path, offset, maxBytes = TAIL_READ_MAX_BYTES) {
8001
8058
  const lastNl = slice.lastIndexOf(10);
8002
8059
  if (lastNl >= 0) {
8003
8060
  const text = slice.subarray(0, lastNl + 1).toString("utf-8");
8004
- return { text, newOffset: offset + lastNl + 1 };
8061
+ return { text, newOffset: offset + lastNl + 1, baseLine: linesBeforeOffset(path, offset) };
8005
8062
  }
8006
8063
  if (offset + got >= size)
8007
8064
  return { text: "", newOffset: offset };
@@ -8034,12 +8091,15 @@ function findNewline(fd, from, size) {
8034
8091
  }
8035
8092
  return -1;
8036
8093
  }
8037
- var TAIL_READ_MAX_BYTES, SKIP_SCAN_BYTES;
8094
+ var TAIL_READ_MAX_BYTES, SKIP_SCAN_BYTES, lineCounts, LINE_COUNT_CACHE_MAX, EDGE_BYTES;
8038
8095
  var init_tail_read = __esm({
8039
8096
  "../engine/dist/core/backends/tail-read.js"() {
8040
8097
  "use strict";
8041
8098
  TAIL_READ_MAX_BYTES = 16 * 1024 * 1024;
8042
8099
  SKIP_SCAN_BYTES = 1024 * 1024;
8100
+ lineCounts = /* @__PURE__ */ new Map();
8101
+ LINE_COUNT_CACHE_MAX = 2048;
8102
+ EDGE_BYTES = 64;
8043
8103
  }
8044
8104
  });
8045
8105
 
@@ -12280,8 +12340,8 @@ function serverRulePackVersion() {
12280
12340
  return serverPack ? serverPack.version || "unversioned" : null;
12281
12341
  }
12282
12342
  function activeRules() {
12283
- const base2 = settingsView().rules;
12284
- return serverPack && serverPack.rules.length > 0 ? [...base2, ...serverPack.rules] : base2;
12343
+ const base3 = settingsView().rules;
12344
+ return serverPack && serverPack.rules.length > 0 ? [...base3, ...serverPack.rules] : base3;
12285
12345
  }
12286
12346
  function isRedactionEnabled() {
12287
12347
  const env = isEnvRedactionRequested();
@@ -18064,7 +18124,7 @@ __export(sync_ledger_exports, {
18064
18124
  syncMode: () => syncMode,
18065
18125
  unackedCursorAttemptCount: () => unackedCursorAttemptCount
18066
18126
  });
18067
- import { readFileSync as readFileSync30, writeFileSync as writeFileSync6, renameSync as renameSync4, mkdirSync as mkdirSync7 } from "node:fs";
18127
+ import { readFileSync as readFileSync30, writeFileSync as writeFileSync6, renameSync as renameSync4, mkdirSync as mkdirSync7, statSync as statSync35 } from "node:fs";
18068
18128
  import { join as join39, dirname as dirname16 } from "node:path";
18069
18129
  function toRow(entry) {
18070
18130
  if (entry === void 0) return void 0;
@@ -18073,32 +18133,94 @@ function toRow(entry) {
18073
18133
  function ledgerFilePath() {
18074
18134
  return ledgerPath();
18075
18135
  }
18076
- function load() {
18077
- if (cache3) return cache3;
18136
+ function stampOf(path) {
18137
+ try {
18138
+ const st = statSync35(path);
18139
+ return `${st.mtimeMs}:${st.size}`;
18140
+ } catch {
18141
+ return null;
18142
+ }
18143
+ }
18144
+ function readDisk(path) {
18078
18145
  try {
18079
- const parsed = JSON.parse(readFileSync30(ledgerPath(), "utf-8"));
18080
- cache3 = parsed && typeof parsed === "object" ? parsed : {};
18146
+ const parsed = JSON.parse(readFileSync30(path, "utf-8"));
18147
+ return parsed && typeof parsed === "object" ? parsed : {};
18081
18148
  } catch {
18082
- cache3 = {};
18149
+ return {};
18150
+ }
18151
+ }
18152
+ function snapshot(data) {
18153
+ const out = /* @__PURE__ */ new Map();
18154
+ for (const [server, rows] of Object.entries(data)) {
18155
+ for (const [id, entry] of Object.entries(rows)) out.set(rowKey(server, id), JSON.stringify(entry));
18156
+ }
18157
+ return out;
18158
+ }
18159
+ function mergeOnto(disk) {
18160
+ const out = {};
18161
+ const put = (server, id, entry) => {
18162
+ (out[server] ??= {})[id] = entry;
18163
+ };
18164
+ const mine = cache3 ?? {};
18165
+ for (const [server, rows] of Object.entries(disk)) {
18166
+ for (const [id, entry] of Object.entries(rows)) {
18167
+ const k = rowKey(server, id);
18168
+ const own = mine[server]?.[id];
18169
+ const was = base.get(k);
18170
+ if (own === void 0) {
18171
+ if (was === void 0) put(server, id, entry);
18172
+ } else {
18173
+ put(server, id, JSON.stringify(own) === was ? entry : own);
18174
+ }
18175
+ }
18176
+ }
18177
+ for (const [server, rows] of Object.entries(mine)) {
18178
+ for (const [id, entry] of Object.entries(rows)) {
18179
+ if (disk[server]?.[id] !== void 0) continue;
18180
+ if (JSON.stringify(entry) !== base.get(rowKey(server, id))) put(server, id, entry);
18181
+ }
18083
18182
  }
18183
+ return out;
18184
+ }
18185
+ function load() {
18186
+ const path = ledgerPath();
18187
+ const stamp2 = stampOf(path);
18188
+ if (cache3 && stamp2 === diskStamp) return cache3;
18189
+ const disk = readDisk(path);
18190
+ const merged = cache3 ? mergeOnto(disk) : disk;
18191
+ if (cache3) {
18192
+ for (const server of Object.keys(cache3)) if (!(server in merged)) delete cache3[server];
18193
+ for (const [server, rows] of Object.entries(merged)) {
18194
+ const target = cache3[server] ?? (cache3[server] = {});
18195
+ for (const id of Object.keys(target)) if (!(id in rows)) delete target[id];
18196
+ Object.assign(target, rows);
18197
+ }
18198
+ } else {
18199
+ cache3 = merged;
18200
+ }
18201
+ base = snapshot(disk);
18202
+ diskStamp = stamp2;
18084
18203
  return cache3;
18085
18204
  }
18086
- function persistNow(data) {
18205
+ function persistNow() {
18087
18206
  const path = ledgerPath();
18088
18207
  mkdirSync7(dirname16(path), { recursive: true });
18089
- const tmp = `${path}.tmp`;
18090
- writeFileSync6(tmp, JSON.stringify(data));
18208
+ load();
18209
+ const tmp = `${path}.tmp-${process.pid}`;
18210
+ writeFileSync6(tmp, JSON.stringify(cache3 ?? {}));
18091
18211
  renameSync4(tmp, path);
18212
+ base = snapshot(cache3 ?? {});
18213
+ diskStamp = stampOf(path);
18092
18214
  pendingWrite = false;
18093
18215
  }
18094
- function persist(data) {
18216
+ function persist(_data) {
18095
18217
  pendingWrite = true;
18096
18218
  if (flushTimer) return;
18097
18219
  flushTimer = setTimeout(() => {
18098
18220
  flushTimer = null;
18099
18221
  if (pendingWrite) {
18100
18222
  try {
18101
- persistNow(data);
18223
+ persistNow();
18102
18224
  } catch {
18103
18225
  }
18104
18226
  }
@@ -18132,7 +18254,7 @@ function pruneLedgerTargets(configuredServers) {
18132
18254
  }
18133
18255
  const rows = names.reduce((n, s) => n + Object.keys(orphans[s]).length, 0);
18134
18256
  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.`);
18135
- persistNow(data);
18257
+ persistNow();
18136
18258
  return names.length;
18137
18259
  }
18138
18260
  function flushLedger() {
@@ -18141,7 +18263,7 @@ function flushLedger() {
18141
18263
  flushTimer = null;
18142
18264
  }
18143
18265
  if (!pendingWrite || !cache3) return;
18144
- persistNow(cache3);
18266
+ persistNow();
18145
18267
  }
18146
18268
  function loadItemVersionsAll() {
18147
18269
  if (itemVersionsCache) return itemVersionsCache;
@@ -18207,6 +18329,7 @@ function persistLedgerData(server, serverData) {
18207
18329
  const data = load();
18208
18330
  data[server] = serverData;
18209
18331
  persist(data);
18332
+ flushLedger();
18210
18333
  }
18211
18334
  function unackedCursorAttemptCount() {
18212
18335
  return unackedCursorAttempts;
@@ -18229,13 +18352,13 @@ function markSynced(server, rows) {
18229
18352
  const o = (cursorFromCaller ? r.offset : void 0) ?? prevOS.o ?? 0;
18230
18353
  const s = (cursorFromCaller ? r.size : void 0) ?? prevOS.s ?? 0;
18231
18354
  const ev = extractorVersionForId(r.id);
18232
- const base2 = prevF ? { m: Math.floor(r.mtime), v: ev, f: prevF } : { m: Math.floor(r.mtime), v: ev };
18355
+ const base3 = prevF ? { m: Math.floor(r.mtime), v: ev, f: prevF } : { m: Math.floor(r.mtime), v: ev };
18233
18356
  if (o > 0 || s > 0) {
18234
- base2.o = o;
18235
- base2.s = s;
18357
+ base3.o = o;
18358
+ base3.s = s;
18236
18359
  }
18237
- if (r.hash !== void 0) base2.h = r.hash;
18238
- forServer[r.id] = base2;
18360
+ if (r.hash !== void 0) base3.h = r.hash;
18361
+ forServer[r.id] = base3;
18239
18362
  }
18240
18363
  persist(data);
18241
18364
  }
@@ -18304,6 +18427,8 @@ function forceFieldRescan(fieldName, server) {
18304
18427
  function _resetLedgerCacheForTests() {
18305
18428
  flushLedger();
18306
18429
  cache3 = null;
18430
+ base = /* @__PURE__ */ new Map();
18431
+ diskStamp = null;
18307
18432
  reconcileCache = null;
18308
18433
  }
18309
18434
  function markFullResync(server, sessionId) {
@@ -18325,7 +18450,7 @@ function syncMode(row, mtime, fileSize, extractorVersion, isAppendOnly) {
18325
18450
  if (row.m >= Math.floor(mtime)) return "skip";
18326
18451
  return "full";
18327
18452
  }
18328
- var ledgerPath, cache3, LEDGER_FLUSH_MS, pendingWrite, flushTimer, itemVersionsPath, itemVersionsCache, inventoryPath, unackedCursorAttempts, reconcilePath, reconcileCache;
18453
+ var ledgerPath, cache3, base, diskStamp, rowKey, LEDGER_FLUSH_MS, pendingWrite, flushTimer, itemVersionsPath, itemVersionsCache, inventoryPath, unackedCursorAttempts, reconcilePath, reconcileCache;
18329
18454
  var init_sync_ledger = __esm({
18330
18455
  "src/sync-ledger.ts"() {
18331
18456
  "use strict";
@@ -18333,6 +18458,9 @@ var init_sync_ledger = __esm({
18333
18458
  init_extractor_version();
18334
18459
  ledgerPath = () => join39(getDataDir(), "sync-ledger.json");
18335
18460
  cache3 = null;
18461
+ base = /* @__PURE__ */ new Map();
18462
+ diskStamp = null;
18463
+ rowKey = (server, id) => `${server}\0${id}`;
18336
18464
  LEDGER_FLUSH_MS = 2e3;
18337
18465
  pendingWrite = false;
18338
18466
  flushTimer = null;
@@ -18371,7 +18499,7 @@ var init_sync_fields = __esm({
18371
18499
  });
18372
18500
 
18373
18501
  // ../engine/dist/core/index-lock.js
18374
- 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";
18502
+ 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";
18375
18503
  import { dirname as dirname17, join as join40 } from "path";
18376
18504
  function acquireIndexLock(opts) {
18377
18505
  const lockPath = lockFilePath(opts.file);
@@ -18421,7 +18549,7 @@ function lockFilePath(file = ".compact.lock") {
18421
18549
  }
18422
18550
  function stealStaleLock(lockPath, staleAfterMs) {
18423
18551
  try {
18424
- const s = statSync35(lockPath);
18552
+ const s = statSync36(lockPath);
18425
18553
  const age = Date.now() - s.mtimeMs;
18426
18554
  let payload;
18427
18555
  try {
@@ -18484,7 +18612,7 @@ var init_http = __esm({
18484
18612
  CLI_VERSION = JSON.parse(readFileSync32(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
18485
18613
  } catch {
18486
18614
  try {
18487
- if (true) CLI_VERSION = "0.7.14";
18615
+ if (true) CLI_VERSION = "0.7.16";
18488
18616
  } catch {
18489
18617
  }
18490
18618
  }
@@ -18978,7 +19106,7 @@ var init_telemetry = __esm({
18978
19106
  init_sync_client();
18979
19107
  cliVersion = () => {
18980
19108
  try {
18981
- return true ? "0.7.14" : "dev";
19109
+ return true ? "0.7.16" : "dev";
18982
19110
  } catch {
18983
19111
  return "dev";
18984
19112
  }
@@ -19001,11 +19129,11 @@ __export(server_probe_exports, {
19001
19129
  function probeOk(r) {
19002
19130
  return r.kind === "ok" && r.apiVersion >= 2;
19003
19131
  }
19004
- async function probeServer(base2, opts = {}) {
19132
+ async function probeServer(base3, opts = {}) {
19005
19133
  const f = opts.fetchImpl || fetch;
19006
19134
  let res;
19007
19135
  try {
19008
- res = await f(`${base2.replace(/\/+$/, "")}/api/capabilities`, {
19136
+ res = await f(`${base3.replace(/\/+$/, "")}/api/capabilities`, {
19009
19137
  signal: AbortSignal.timeout(opts.timeoutMs ?? 1e4)
19010
19138
  });
19011
19139
  } catch (err) {
@@ -19042,34 +19170,34 @@ async function probeServer(base2, opts = {}) {
19042
19170
  raw: parsed
19043
19171
  };
19044
19172
  }
19045
- function probeAdvice(r, base2) {
19173
+ function probeAdvice(r, base3) {
19046
19174
  switch (r.kind) {
19047
19175
  case "ok":
19048
19176
  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`;
19049
19177
  case "moved":
19050
- return `HTTP ${r.status} \u2014 nothing is served at ${base2}. If the host moved, re-point it: \`chat-recall login <new-server-url>\``;
19178
+ return `HTTP ${r.status} \u2014 nothing is served at ${base3}. If the host moved, re-point it: \`chat-recall login <new-server-url>\``;
19051
19179
  case "unauthorized":
19052
- return `HTTP ${r.status} \u2014 ${base2} rejected the credential. Re-login: \`chat-recall login ` + base2 + "`";
19180
+ return `HTTP ${r.status} \u2014 ${base3} rejected the credential. Re-login: \`chat-recall login ` + base3 + "`";
19053
19181
  case "server_error":
19054
- return `HTTP ${r.status} \u2014 ${base2} is up but failing. Nothing to fix locally; check the server.`;
19182
+ return `HTTP ${r.status} \u2014 ${base3} is up but failing. Nothing to fix locally; check the server.`;
19055
19183
  case "not_api":
19056
- 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`;
19184
+ 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`;
19057
19185
  case "unreachable":
19058
19186
  switch (r.reason) {
19059
19187
  case "dns":
19060
- return `cannot resolve the host in ${base2} (${r.error}) \u2014 check the URL for a typo, and your DNS or VPN`;
19188
+ return `cannot resolve the host in ${base3} (${r.error}) \u2014 check the URL for a typo, and your DNS or VPN`;
19061
19189
  case "refused":
19062
- return `${base2} resolves but refused the connection (${r.error}) \u2014 the server is not running, or the port is wrong`;
19190
+ return `${base3} resolves but refused the connection (${r.error}) \u2014 the server is not running, or the port is wrong`;
19063
19191
  case "tls":
19064
- 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.`;
19192
+ 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.`;
19065
19193
  case "timeout":
19066
- return `${base2} did not answer in time (${r.error}) \u2014 a firewall or proxy that drops traffic silently looks exactly like this`;
19194
+ return `${base3} did not answer in time (${r.error}) \u2014 a firewall or proxy that drops traffic silently looks exactly like this`;
19067
19195
  case "reset":
19068
- return `the connection to ${base2} was cut (${r.error}) \u2014 often a proxy or a captive portal`;
19196
+ return `the connection to ${base3} was cut (${r.error}) \u2014 often a proxy or a captive portal`;
19069
19197
  case "bad_port":
19070
- 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`;
19198
+ 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`;
19071
19199
  default:
19072
- return `no HTTP response from ${base2} (${r.error}) \u2014 check the URL, DNS, or that the server is running`;
19200
+ return `no HTTP response from ${base3} (${r.error}) \u2014 check the URL, DNS, or that the server is running`;
19073
19201
  }
19074
19202
  }
19075
19203
  }
@@ -19102,8 +19230,8 @@ function describeCause(err) {
19102
19230
  const code = e.code;
19103
19231
  if (typeof code === "string" && code && !parts.includes(code)) parts.push(code);
19104
19232
  }
19105
- const base2 = err instanceof Error ? err.message : String(err);
19106
- return parts.length ? `${base2}: ${parts.join(" \u2192 ")}` : base2;
19233
+ const base3 = err instanceof Error ? err.message : String(err);
19234
+ return parts.length ? `${base3}: ${parts.join(" \u2192 ")}` : base3;
19107
19235
  }
19108
19236
  function describeUnreachable(err) {
19109
19237
  const reason = classifyUnreachable(err);
@@ -19216,7 +19344,7 @@ __export(auto_update_exports, {
19216
19344
  import { execSync as execSync2, execFileSync as execFileSync3 } from "node:child_process";
19217
19345
  import { readFileSync as readFileSync34, existsSync as existsSync41 } from "node:fs";
19218
19346
  import { fileURLToPath as fileURLToPath2 } from "node:url";
19219
- import { writeFileSync as writeFileSync8, mkdtempSync as mkdtempSync3, rmSync as rmSync5, readdirSync as readdirSync30, statSync as statSync36, mkdirSync as mkdirSync9 } from "node:fs";
19347
+ import { writeFileSync as writeFileSync8, mkdtempSync as mkdtempSync3, rmSync as rmSync5, readdirSync as readdirSync30, statSync as statSync37, mkdirSync as mkdirSync9 } from "node:fs";
19220
19348
  import { join as join41, dirname as dirname18, sep as sep2, posix as pathPosix, win32 as pathWin32 } from "node:path";
19221
19349
  import { tmpdir as tmpdir2, homedir as homedir15 } from "node:os";
19222
19350
  import { createHash as createHash7 } from "node:crypto";
@@ -19248,12 +19376,12 @@ function installedVersion() {
19248
19376
  return null;
19249
19377
  }
19250
19378
  }
19251
- function planAutoUpdate(base2, caps, ownVersion3, flag) {
19379
+ function planAutoUpdate(base3, caps, ownVersion3, flag) {
19252
19380
  const rel = caps.cli;
19253
19381
  if (!rel || !rel.version || !rel.sha256) return { update: false, reason: "server advertises no CLI release" };
19254
19382
  if (!isAutoUpdateEnabled(caps.edition, flag)) return { update: false, reason: `auto-update disabled (edition ${caps.edition ?? "?"})` };
19255
19383
  if (compareVersions(rel.version, ownVersion3) <= 0) return { update: false, reason: `already current (own ${ownVersion3} >= server ${rel.version})` };
19256
- 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 };
19384
+ 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 };
19257
19385
  }
19258
19386
  function sweepStaleStaging(root = tmpdir2(), now = Date.now()) {
19259
19387
  const MKDTEMP_SUFFIX = /^cr-update-.{6}$/s;
@@ -19269,7 +19397,7 @@ function sweepStaleStaging(root = tmpdir2(), now = Date.now()) {
19269
19397
  if (!MKDTEMP_SUFFIX.test(name)) continue;
19270
19398
  const dir = join41(root, name);
19271
19399
  try {
19272
- const st = statSync36(dir);
19400
+ const st = statSync37(dir);
19273
19401
  if (!st.isDirectory() || now - st.mtimeMs < COLD_MS) continue;
19274
19402
  const inside = readdirSync30(dir);
19275
19403
  if (inside.length > 1 || inside.length === 1 && inside[0] !== "chat-recall.tgz") continue;
@@ -19433,20 +19561,20 @@ function clearUpdateFailures() {
19433
19561
  function stopAutoUpdates() {
19434
19562
  stopRequested = true;
19435
19563
  }
19436
- async function runAutoUpdate(base2, authHeaders, ownVersion3, deps) {
19564
+ async function runAutoUpdate(base3, authHeaders, ownVersion3, deps) {
19437
19565
  let caps;
19438
19566
  try {
19439
- const res = await fetchWithTimeout(`${base2.replace(/\/+$/, "")}/api/capabilities`, { headers: authHeaders });
19567
+ const res = await fetchWithTimeout(`${base3.replace(/\/+$/, "")}/api/capabilities`, { headers: authHeaders });
19440
19568
  if (!res.ok) return { updated: false, reason: `capabilities HTTP ${res.status}` };
19441
19569
  caps = await res.json();
19442
19570
  } catch (e) {
19443
19571
  return { updated: false, reason: `capabilities unreachable: ${e instanceof Error ? e.message : e}` };
19444
19572
  }
19445
19573
  const effectiveOwn = newerOf(ownVersion3, installedVersion());
19446
- const plan = planAutoUpdate(base2, caps, effectiveOwn, process.env.CHAT_RECALL_AUTO_UPDATE);
19574
+ const plan = planAutoUpdate(base3, caps, effectiveOwn, process.env.CHAT_RECALL_AUTO_UPDATE);
19447
19575
  if (!plan.update) {
19448
- if (/disabled|no CLI release/.test(plan.reason) && !reportedStandingSkip.has(base2)) {
19449
- reportedStandingSkip.add(base2);
19576
+ if (/disabled|no CLI release/.test(plan.reason) && !reportedStandingSkip.has(base3)) {
19577
+ reportedStandingSkip.add(base3);
19450
19578
  try {
19451
19579
  const { reportClientEvent: reportClientEvent2 } = await Promise.resolve().then(() => (init_client_events(), client_events_exports));
19452
19580
  reportClientEvent2("auto_update_skipped", { message: `${plan.reason} (server offers ${caps.cli?.version ?? "?"}, this device runs ${effectiveOwn})` });
@@ -19502,7 +19630,7 @@ var init_auto_update = __esm({
19502
19630
  "use strict";
19503
19631
  init_http();
19504
19632
  init_index_lock();
19505
- tarballUrl = (base2, version) => `${base2.replace(/\/+$/, "")}/install/${version ? `chat-recall-${version}.tgz` : "chat-recall.tgz"}`;
19633
+ tarballUrl = (base3, version) => `${base3.replace(/\/+$/, "")}/install/${version ? `chat-recall-${version}.tgz` : "chat-recall.tgz"}`;
19506
19634
  GIVE_UP_AFTER = 3;
19507
19635
  reportedStandingSkip = /* @__PURE__ */ new Set();
19508
19636
  STOPPING_REASON = "not installed: this process is shutting down";
@@ -19513,7 +19641,7 @@ var init_auto_update = __esm({
19513
19641
 
19514
19642
  // src/sync-client.ts
19515
19643
  import { join as join42, dirname as dirname19, basename as basename20 } from "node:path";
19516
- 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";
19644
+ 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";
19517
19645
  import { tmpdir as tmpdir3, hostname as hostname2 } from "node:os";
19518
19646
  import { createHash as createHash8 } from "node:crypto";
19519
19647
  import { fileURLToPath as fileURLToPath3 } from "node:url";
@@ -19558,15 +19686,15 @@ function loadAllCredentials() {
19558
19686
  return [];
19559
19687
  }
19560
19688
  async function fetchTenantSecurityConfig(cred) {
19561
- const base2 = cred.serverUrl.replace(/\/+$/, "");
19562
- const cached = _securityConfigCache.get(base2);
19689
+ const base3 = cred.serverUrl.replace(/\/+$/, "");
19690
+ const cached = _securityConfigCache.get(base3);
19563
19691
  if (cached && Date.now() - cached.fetchedAt < SECURITY_CONFIG_TTL_MS) return cached.config;
19564
19692
  const headers = { "content-type": "application/json" };
19565
19693
  if (cred.token) headers.authorization = `Bearer ${cred.token}`;
19566
19694
  try {
19567
19695
  const [rulesRes, settingsRes] = await Promise.all([
19568
- fetchWithTimeout(`${base2}/api/secrets/rules`, { headers }),
19569
- fetchWithTimeout(`${base2}/api/teams/security-config`, { headers }).catch(() => null)
19696
+ fetchWithTimeout(`${base3}/api/secrets/rules`, { headers }),
19697
+ fetchWithTimeout(`${base3}/api/teams/security-config`, { headers }).catch(() => null)
19570
19698
  ]);
19571
19699
  let tenantRules = [];
19572
19700
  let rulePackVersion = null;
@@ -19591,18 +19719,18 @@ async function fetchTenantSecurityConfig(cred) {
19591
19719
  const body = await settingsRes.json().catch(() => ({}));
19592
19720
  if (typeof body.verifySecrets === "boolean") verifySecrets = body.verifySecrets;
19593
19721
  if (typeof body.telemetry === "boolean") {
19594
- setTelemetryEligible(base2, body.telemetry);
19722
+ setTelemetryEligible(base3, body.telemetry);
19595
19723
  try {
19596
19724
  const prior = readCollectorHealth()?.telemetryEligible ?? {};
19597
19725
  updateCollectorHealth({
19598
- telemetryEligible: { ...prior, [base2]: { allowed: body.telemetry, at: Date.now() } }
19726
+ telemetryEligible: { ...prior, [base3]: { allowed: body.telemetry, at: Date.now() } }
19599
19727
  });
19600
19728
  } catch {
19601
19729
  }
19602
19730
  }
19603
19731
  }
19604
19732
  const config = { tenantRules, verifySecrets, rulePackVersion };
19605
- _securityConfigCache.set(base2, { fetchedAt: Date.now(), config });
19733
+ _securityConfigCache.set(base3, { fetchedAt: Date.now(), config });
19606
19734
  return config;
19607
19735
  } catch {
19608
19736
  return { tenantRules: [], verifySecrets: true, rulePackVersion: null };
@@ -19618,18 +19746,18 @@ function readPersistedSyncConfigs() {
19618
19746
  return {};
19619
19747
  }
19620
19748
  }
19621
- function persistSyncConfig(base2, config) {
19749
+ function persistSyncConfig(base3, config) {
19622
19750
  try {
19623
19751
  const all = readPersistedSyncConfigs();
19624
- all[base2] = { fetchedAt: Date.now(), config };
19752
+ all[base3] = { fetchedAt: Date.now(), config };
19625
19753
  mkdirSync10(dirname19(syncConfigCachePath()), { recursive: true });
19626
19754
  writeFileSync9(syncConfigCachePath(), JSON.stringify(all, null, 2));
19627
19755
  } catch {
19628
19756
  }
19629
19757
  }
19630
19758
  async function fetchTenantSyncConfig(cred) {
19631
- const base2 = cred.serverUrl.replace(/\/+$/, "");
19632
- const cached = _syncConfigCache.get(base2);
19759
+ const base3 = cred.serverUrl.replace(/\/+$/, "");
19760
+ const cached = _syncConfigCache.get(base3);
19633
19761
  if (cached && Date.now() - cached.fetchedAt < SECURITY_CONFIG_TTL_MS) return cached.config;
19634
19762
  const headers = { "content-type": "application/json" };
19635
19763
  if (cred.token) headers.authorization = `Bearer ${cred.token}`;
@@ -19637,7 +19765,7 @@ async function fetchTenantSyncConfig(cred) {
19637
19765
  try {
19638
19766
  const sources2 = discoverSessionSources();
19639
19767
  if (sources2.length > 0) {
19640
- await fetchWithTimeout(`${base2}/api/sync-config/sources`, {
19768
+ await fetchWithTimeout(`${base3}/api/sync-config/sources`, {
19641
19769
  method: "POST",
19642
19770
  headers,
19643
19771
  body: JSON.stringify({ device: deviceLabel(), sources: sources2 })
@@ -19645,12 +19773,12 @@ async function fetchTenantSyncConfig(cred) {
19645
19773
  }
19646
19774
  } catch {
19647
19775
  }
19648
- const res = await fetchWithTimeout(`${base2}/api/sync-config`, { headers });
19776
+ const res = await fetchWithTimeout(`${base3}/api/sync-config`, { headers });
19649
19777
  if (res.status === 404) {
19650
- _syncConfigCache.set(base2, { fetchedAt: Date.now(), config: EMPTY_SYNC_CONFIG });
19778
+ _syncConfigCache.set(base3, { fetchedAt: Date.now(), config: EMPTY_SYNC_CONFIG });
19651
19779
  return EMPTY_SYNC_CONFIG;
19652
19780
  }
19653
- if (!res.ok) return lastKnownSyncConfig(base2, `HTTP ${res.status}`);
19781
+ if (!res.ok) return lastKnownSyncConfig(base3, `HTTP ${res.status}`);
19654
19782
  const body = await res.json().catch(() => ({}));
19655
19783
  const config = {
19656
19784
  excludeTools: Array.isArray(body.excludeTools) ? body.excludeTools.filter((t) => typeof t === "string") : [],
@@ -19687,22 +19815,22 @@ async function fetchTenantSyncConfig(cred) {
19687
19815
  if (decided > 0) console.error(`[sync] applied ${decided} folder decision(s) from the dashboard`);
19688
19816
  } catch {
19689
19817
  }
19690
- _syncConfigCache.set(base2, { fetchedAt: Date.now(), config });
19691
- persistSyncConfig(base2, config);
19818
+ _syncConfigCache.set(base3, { fetchedAt: Date.now(), config });
19819
+ persistSyncConfig(base3, config);
19692
19820
  return config;
19693
19821
  } catch (err) {
19694
19822
  if (isSyncRulesRefusal(err)) throw err;
19695
- return lastKnownSyncConfig(base2, err instanceof Error ? err.message : "request failed");
19823
+ return lastKnownSyncConfig(base3, err instanceof Error ? err.message : "request failed");
19696
19824
  }
19697
19825
  }
19698
- function lastKnownSyncConfig(base2, reason) {
19699
- const remembered = _syncConfigCache.get(base2) ?? readPersistedSyncConfigs()[base2];
19826
+ function lastKnownSyncConfig(base3, reason) {
19827
+ const remembered = _syncConfigCache.get(base3) ?? readPersistedSyncConfigs()[base3];
19700
19828
  if (remembered) {
19701
19829
  console.error(`[sync] could not read server-side sync rules (${reason}) \u2014 applying the last known set from ${new Date(remembered.fetchedAt).toISOString()}`);
19702
19830
  return remembered.config;
19703
19831
  }
19704
19832
  const refusal = new Error(
19705
- `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.`
19833
+ `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.`
19706
19834
  );
19707
19835
  refusal[SYNC_RULES_REFUSAL] = true;
19708
19836
  throw refusal;
@@ -19810,25 +19938,25 @@ async function syncSessions(opts = {}) {
19810
19938
  ${errors.join("\n ")}`);
19811
19939
  return { ...agg, perTarget };
19812
19940
  }
19813
- async function postFieldBatch(base2, token, rows) {
19941
+ async function postFieldBatch(base3, token, rows) {
19814
19942
  const headers = { "content-type": "application/json" };
19815
19943
  if (token) headers.authorization = `Bearer ${token}`;
19816
19944
  const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
19817
19945
  for (let attempt = 0; ; attempt++) {
19818
- const res = await fetchWithTimeout(`${base2}/api/sync`, { method: "POST", headers, body: JSON.stringify({ fields: rows }) }, 6e4);
19946
+ const res = await fetchWithTimeout(`${base3}/api/sync`, { method: "POST", headers, body: JSON.stringify({ fields: rows }) }, 6e4);
19819
19947
  if (res.ok) return;
19820
19948
  const retryable = res.status === 429 || res.status >= 500;
19821
- if (!retryable || attempt >= 5) throw new Error(`${base2}: fields batch HTTP ${res.status} ${await res.text().catch(() => "")}`);
19949
+ if (!retryable || attempt >= 5) throw new Error(`${base3}: fields batch HTTP ${res.status} ${await res.text().catch(() => "")}`);
19822
19950
  const ra = Number(res.headers.get("retry-after")) || 0;
19823
19951
  await sleep(ra > 0 ? ra * 1e3 : [500, 1500, 4e3, 8e3, 15e3][Math.min(attempt, 4)]);
19824
19952
  }
19825
19953
  }
19826
19954
  async function reconcileFieldsForTarget(cred, fullRefs, opts = {}) {
19827
- const base2 = cred.serverUrl.replace(/\/+$/, "");
19828
- const ledger = getSyncedRows(base2);
19955
+ const base3 = cred.serverUrl.replace(/\/+$/, "");
19956
+ const ledger = getSyncedRows(base3);
19829
19957
  let pushed = 0, absent = 0, scanned = 0;
19830
19958
  for (const field of SYNC_FIELDS) {
19831
- const needFull = !!opts.force || fieldNeedsFullPass(base2, field);
19959
+ const needFull = !!opts.force || fieldNeedsFullPass(base3, field);
19832
19960
  const candidates2 = needFull ? fullRefs() : opts.convRefs ?? fullRefs();
19833
19961
  const send = [];
19834
19962
  const mtimeById = /* @__PURE__ */ new Map();
@@ -19844,15 +19972,15 @@ async function reconcileFieldsForTarget(cred, fullRefs, opts = {}) {
19844
19972
  }
19845
19973
  for (let i = 0; i < send.length; i += 200) {
19846
19974
  const chunk = send.slice(i, i + 200);
19847
- await postFieldBatch(base2, cred.token, chunk);
19848
- markFieldCoverage(base2, field, chunk.map((r) => ({ id: r.session_id, present: true, mtime: mtimeById.get(r.session_id) ?? 0 })));
19975
+ await postFieldBatch(base3, cred.token, chunk);
19976
+ markFieldCoverage(base3, field, chunk.map((r) => ({ id: r.session_id, present: true, mtime: mtimeById.get(r.session_id) ?? 0 })));
19849
19977
  pushed += chunk.length;
19850
19978
  }
19851
19979
  if (absentIds.length) {
19852
- markFieldCoverage(base2, field, absentIds.map((id) => ({ id, present: false, mtime: mtimeById.get(id) ?? 0 })));
19980
+ markFieldCoverage(base3, field, absentIds.map((id) => ({ id, present: false, mtime: mtimeById.get(id) ?? 0 })));
19853
19981
  absent += absentIds.length;
19854
19982
  }
19855
- if (needFull) markFieldFullPassDone(base2, field);
19983
+ if (needFull) markFieldFullPassDone(base3, field);
19856
19984
  }
19857
19985
  return { pushed, absent, scanned };
19858
19986
  }
@@ -19868,7 +19996,7 @@ function reapStaleScanDirs(dir = tmpdir3(), maxAgeMs = 6 * 36e5, now = Date.now(
19868
19996
  if (!name.startsWith("cr-batchscan-")) continue;
19869
19997
  const p = join42(dir, name);
19870
19998
  try {
19871
- if (now - statSync37(p).mtimeMs < maxAgeMs) continue;
19999
+ if (now - statSync38(p).mtimeMs < maxAgeMs) continue;
19872
20000
  rmSync6(p, { recursive: true, force: true });
19873
20001
  reaped++;
19874
20002
  } catch {
@@ -19942,25 +20070,25 @@ function serverIngestConcurrency(serverUrl) {
19942
20070
  return advertisedIngestConc.get(serverUrl.replace(/\/$/, "")) ?? null;
19943
20071
  }
19944
20072
  async function verifyServerApi(serverUrl, minApi) {
19945
- const base2 = serverUrl.replace(/\/$/, "");
19946
- const seen = capsOk.get(base2);
20073
+ const base3 = serverUrl.replace(/\/$/, "");
20074
+ const seen = capsOk.get(base3);
19947
20075
  if (seen !== void 0 && Date.now() - seen < CAPS_TTL_MS) return true;
19948
20076
  const { probeServer: probeServer2, probeAdvice: probeAdvice2 } = await Promise.resolve().then(() => (init_server_probe(), server_probe_exports));
19949
- const probe = await probeServer2(base2, {
20077
+ const probe = await probeServer2(base3, {
19950
20078
  fetchImpl: ((url, init) => fetchWithTimeout(String(url), init ?? {}))
19951
20079
  });
19952
- if (probe.kind !== "ok") throw new Error(probeAdvice2(probe, base2));
20080
+ if (probe.kind !== "ok") throw new Error(probeAdvice2(probe, base3));
19953
20081
  const caps = probe.raw;
19954
20082
  if ((caps.apiVersion ?? 0) < minApi) {
19955
20083
  throw new Error(`server too old: apiVersion ${caps.apiVersion ?? "none"} < required ${minApi} \u2014 update the server image before syncing`);
19956
20084
  }
19957
20085
  const adv = caps.limits?.ingestConcurrencyPerTenant;
19958
20086
  if (typeof adv === "number" && Number.isFinite(adv) && adv >= 1) {
19959
- advertisedIngestConc.set(base2, Math.floor(adv));
20087
+ advertisedIngestConc.set(base3, Math.floor(adv));
19960
20088
  }
19961
- if (caps.limits?.acceptsGzipBody === true) advertisedGzipBody.add(base2);
19962
- else advertisedGzipBody.delete(base2);
19963
- capsOk.set(base2, Date.now());
20089
+ if (caps.limits?.acceptsGzipBody === true) advertisedGzipBody.add(base3);
20090
+ else advertisedGzipBody.delete(base3);
20091
+ capsOk.set(base3, Date.now());
19964
20092
  return true;
19965
20093
  }
19966
20094
  async function syncToTarget(cred, opts = {}) {
@@ -20025,7 +20153,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20025
20153
  const ac = new AbortController();
20026
20154
  const timer = setTimeout(() => ac.abort(new Error(`upload timed out after ${UPLOAD_TIMEOUT_MS}ms`)), UPLOAD_TIMEOUT_MS);
20027
20155
  try {
20028
- const res = await fetch(`${base2}/api/sync`, {
20156
+ const res = await fetch(`${base3}/api/sync`, {
20029
20157
  method: "POST",
20030
20158
  // No token ⇒ no auth header: a no-auth local server (AUTH_PROVIDER=none)
20031
20159
  // accepts it as the single 'default' tenant.
@@ -20041,26 +20169,26 @@ async function syncToTargetInScope(cred, opts = {}) {
20041
20169
  acceptedUploads.set(cred.serverUrl, (acceptedUploads.get(cred.serverUrl) ?? 0) + 1);
20042
20170
  const body2 = await res.json().catch(() => ({}));
20043
20171
  if (typeof body2.telemetry === "boolean") {
20044
- setTelemetryEligible(base2, body2.telemetry);
20172
+ setTelemetryEligible(base3, body2.telemetry);
20045
20173
  try {
20046
20174
  const prior = readCollectorHealth()?.telemetryEligible ?? {};
20047
20175
  updateCollectorHealth({
20048
- telemetryEligible: { ...prior, [base2]: { allowed: body2.telemetry, at: Date.now() } }
20176
+ telemetryEligible: { ...prior, [base3]: { allowed: body2.telemetry, at: Date.now() } }
20049
20177
  });
20050
20178
  } catch {
20051
20179
  }
20052
20180
  }
20053
20181
  const adv = body2.limits?.ingestConcurrencyPerTenant;
20054
20182
  if (typeof adv === "number" && Number.isFinite(adv) && adv >= 1) {
20055
- setServerIngestConcurrency(base2, Math.floor(adv));
20183
+ setServerIngestConcurrency(base3, Math.floor(adv));
20056
20184
  }
20057
20185
  if (body2.cli && body2.cli.version) {
20058
20186
  const { planAutoUpdate: planAutoUpdate2, runAutoUpdate: runAutoUpdate2, sweepStaleStaging: sweepStaleStaging2 } = await Promise.resolve().then(() => (init_auto_update(), auto_update_exports));
20059
20187
  const authHeaders = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
20060
- const plan = planAutoUpdate2(base2, { cli: body2.cli }, ownVersion, process.env.CHAT_RECALL_AUTO_UPDATE);
20188
+ const plan = planAutoUpdate2(base3, { cli: body2.cli }, ownVersion, process.env.CHAT_RECALL_AUTO_UPDATE);
20061
20189
  sweepStaleStaging2();
20062
20190
  if (plan.update) {
20063
- void runAutoUpdate2(base2, authHeaders, ownVersion).catch(() => {
20191
+ void runAutoUpdate2(base3, authHeaders, ownVersion).catch(() => {
20064
20192
  });
20065
20193
  }
20066
20194
  }
@@ -20069,7 +20197,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20069
20197
  const retryable = res.status === 429 || res.status >= 500;
20070
20198
  const text = await res.text().catch(() => "");
20071
20199
  if (res.status === 401 || res.status === 403) {
20072
- throw classedError("auth", `server rejected this machine's device token (HTTP ${res.status} \u2014 revoked?). Reconnect with: chat-recall login ${base2}`);
20200
+ throw classedError("auth", `server rejected this machine's device token (HTTP ${res.status} \u2014 revoked?). Reconnect with: chat-recall login ${base3}`);
20073
20201
  }
20074
20202
  if (res.status === 402) {
20075
20203
  let detail = text;
@@ -20090,7 +20218,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20090
20218
  const retryAfterS = Number(res.headers.get("retry-after"));
20091
20219
  const waitMs = res.status === 429 && retryAfterS > 0 ? retryAfterS * 1e3 : RETRY_DELAYS_MS[attempt];
20092
20220
  const why = res.status === 524 ? ` \u2014 the proxy cut the request at its time limit; the batch is too big for one request` : "";
20093
- console.error(`[sync] HTTP ${res.status} from ${base2}${why} \u2014 backing off ${Math.round(waitMs / 1e3)}s (attempt ${attempt + 1})`);
20221
+ console.error(`[sync] HTTP ${res.status} from ${base3}${why} \u2014 backing off ${Math.round(waitMs / 1e3)}s (attempt ${attempt + 1})`);
20094
20222
  await sleep(waitMs);
20095
20223
  continue;
20096
20224
  } catch (err) {
@@ -20158,11 +20286,11 @@ async function syncToTargetInScope(cred, opts = {}) {
20158
20286
  }
20159
20287
  };
20160
20288
  };
20161
- const base2 = cred.serverUrl.replace(/\/$/, "");
20162
- const ledger = opts.useLedger ? getSyncedRows(base2) : null;
20289
+ const base3 = cred.serverUrl.replace(/\/$/, "");
20290
+ const ledger = opts.useLedger ? getSyncedRows(base3) : null;
20163
20291
  const convBatch = makeBatcher("conversations", 25, false, (rows) => {
20164
20292
  try {
20165
- markSynced(base2, rows.map((r) => {
20293
+ markSynced(base3, rows.map((r) => {
20166
20294
  const off = typeof r.from_offset === "number" ? r.from_offset : 0;
20167
20295
  const hash = shippedHash.get(r.session_id);
20168
20296
  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 };
@@ -20177,7 +20305,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20177
20305
  const ac = new AbortController();
20178
20306
  const timer = setTimeout(() => ac.abort(new Error(`upload timed out after ${UPLOAD_TIMEOUT_MS}ms`)), UPLOAD_TIMEOUT_MS);
20179
20307
  try {
20180
- const res = await fetch(`${base2}/api/sync`, {
20308
+ const res = await fetch(`${base3}/api/sync`, {
20181
20309
  method: "POST",
20182
20310
  headers,
20183
20311
  body: JSON.stringify({ conversations: convs }),
@@ -20188,10 +20316,10 @@ async function syncToTargetInScope(cred, opts = {}) {
20188
20316
  if (body.cli && body.cli.version) {
20189
20317
  const { planAutoUpdate: planAutoUpdate2, runAutoUpdate: runAutoUpdate2, sweepStaleStaging: sweepStaleStaging2 } = await Promise.resolve().then(() => (init_auto_update(), auto_update_exports));
20190
20318
  const authHeaders = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
20191
- const plan = planAutoUpdate2(base2, { cli: body.cli }, ownVersion, process.env.CHAT_RECALL_AUTO_UPDATE);
20319
+ const plan = planAutoUpdate2(base3, { cli: body.cli }, ownVersion, process.env.CHAT_RECALL_AUTO_UPDATE);
20192
20320
  sweepStaleStaging2();
20193
20321
  if (plan.update) {
20194
- void runAutoUpdate2(base2, authHeaders, ownVersion).catch(() => {
20322
+ void runAutoUpdate2(base3, authHeaders, ownVersion).catch(() => {
20195
20323
  });
20196
20324
  }
20197
20325
  }
@@ -20199,7 +20327,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20199
20327
  const acked = convs.filter((c) => !fullNeeded.has(c.session_id));
20200
20328
  if (acked.length > 0) {
20201
20329
  try {
20202
- markSynced(base2, acked.map((c) => ({
20330
+ markSynced(base3, acked.map((c) => ({
20203
20331
  id: c.session_id,
20204
20332
  mtime: c.mtime,
20205
20333
  offset: c.from_offset,
@@ -20217,13 +20345,14 @@ async function syncToTargetInScope(cred, opts = {}) {
20217
20345
  clearTimeout(timer);
20218
20346
  }
20219
20347
  };
20220
- const postChunkedHead = async (conv, fileSize) => {
20348
+ const postChunkedHead = async (head, fileSize) => {
20349
+ const conv = { ...head, chunk_head: true };
20221
20350
  const headers = { "content-type": "application/json" };
20222
20351
  if (cred.token) headers.authorization = `Bearer ${cred.token}`;
20223
20352
  const ac = new AbortController();
20224
20353
  const timer = setTimeout(() => ac.abort(new Error(`upload timed out after ${UPLOAD_TIMEOUT_MS}ms`)), UPLOAD_TIMEOUT_MS);
20225
20354
  try {
20226
- const res = await fetch(`${base2}/api/sync`, {
20355
+ const res = await fetch(`${base3}/api/sync`, {
20227
20356
  method: "POST",
20228
20357
  headers,
20229
20358
  body: JSON.stringify({ conversations: [conv] }),
@@ -20233,14 +20362,15 @@ async function syncToTargetInScope(cred, opts = {}) {
20233
20362
  const body = await res.json().catch(() => ({}));
20234
20363
  const id = conv.session_id;
20235
20364
  const guarded = (body.shrink_guarded ?? []).find((g) => g.session_id === id);
20365
+ const staged = (body.rebuild_staged ?? []).includes(id);
20236
20366
  const mtime = conv.mtime;
20237
20367
  try {
20238
- if (!guarded) {
20239
- markSynced(base2, [{ id, mtime, offset: conv.from_offset, size: conv.from_offset, acked: true }]);
20368
+ if (staged || !guarded) {
20369
+ markSynced(base3, [{ id, mtime, offset: conv.from_offset, size: conv.from_offset, acked: true }]);
20240
20370
  } else if (typeof guarded.o === "number" && guarded.o > 0 && guarded.o <= fileSize) {
20241
- markSynced(base2, [{ id, mtime, offset: guarded.o, size: guarded.o, acked: true }]);
20371
+ markSynced(base3, [{ id, mtime, offset: guarded.o, size: guarded.o, acked: true }]);
20242
20372
  } else {
20243
- markSynced(base2, [{ id, mtime }]);
20373
+ markSynced(base3, [{ id, mtime }]);
20244
20374
  }
20245
20375
  } catch {
20246
20376
  }
@@ -20306,7 +20436,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20306
20436
  const m = process.memoryUsage();
20307
20437
  console.error(`[sync-trace] ${msg} \xB7 heap=${(m.heapUsed / 1048576).toFixed(0)}MB rss=${(m.rss / 1048576).toFixed(0)}MB`);
20308
20438
  } : null;
20309
- trace?.(`walk start: ${slice.length} ref(s) \u2192 ${base2}`);
20439
+ trace?.(`walk start: ${slice.length} ref(s) \u2192 ${base3}`);
20310
20440
  if (upload.sessionMeta) {
20311
20441
  try {
20312
20442
  await reconcileFieldsForTarget(
@@ -20321,7 +20451,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20321
20451
  { convRefs: slice }
20322
20452
  );
20323
20453
  } catch (e) {
20324
- console.error(`[sync] field reconcile (${base2}): ${e instanceof Error ? e.message : e}`);
20454
+ console.error(`[sync] field reconcile (${base3}): ${e instanceof Error ? e.message : e}`);
20325
20455
  }
20326
20456
  }
20327
20457
  trace?.("field reconcile done");
@@ -20363,7 +20493,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20363
20493
  }
20364
20494
  trace?.("conversation walk start");
20365
20495
  const walkStartedAt = Date.now();
20366
- const firstWalk = (ledger ?? getSyncedRows(base2)).size === 0;
20496
+ const firstWalk = (ledger ?? getSyncedRows(base3)).size === 0;
20367
20497
  reportWalkProgress({ done: 0, total: slice.length, startedAt: walkStartedAt, complete: false, first: firstWalk });
20368
20498
  walkProgressForUpload = { done: 0, total: slice.length, complete: false };
20369
20499
  let traceN = 0;
@@ -20403,7 +20533,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20403
20533
  continue;
20404
20534
  } else {
20405
20535
  try {
20406
- markSynced(base2, [{ id: ref.prefixedId, mtime: ref.mtime }]);
20536
+ markSynced(base3, [{ id: ref.prefixedId, mtime: ref.mtime }]);
20407
20537
  } catch {
20408
20538
  }
20409
20539
  skipped++;
@@ -20426,7 +20556,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20426
20556
  const off = getBackendForId(ref.prefixedId)?.fileSize?.(ref.rawId) ?? 0;
20427
20557
  const priorCursor = ackRow?.s ?? 0;
20428
20558
  const safeToAck = off > 0 && off <= priorCursor;
20429
- 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 }]);
20559
+ 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 }]);
20430
20560
  } catch {
20431
20561
  }
20432
20562
  }
@@ -20436,7 +20566,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20436
20566
  if (!built) {
20437
20567
  if (ledger) {
20438
20568
  try {
20439
- markSynced(base2, [{ id: ref.prefixedId, mtime: ref.mtime }]);
20569
+ markSynced(base3, [{ id: ref.prefixedId, mtime: ref.mtime }]);
20440
20570
  } catch {
20441
20571
  }
20442
20572
  }
@@ -20493,7 +20623,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20493
20623
  walked++;
20494
20624
  if (walked % 250 === 0) console.error(`[sync] ${walked}/${slice.length} sessions\u2026`);
20495
20625
  }
20496
- const itemVersions = loadItemVersions(base2);
20626
+ const itemVersions = loadItemVersions(base3);
20497
20627
  const seenTools = /* @__PURE__ */ new Set();
20498
20628
  const seenItemKeys = /* @__PURE__ */ new Map();
20499
20629
  const registry = buildSourceRegistry();
@@ -20587,7 +20717,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20587
20717
  await appendFlush();
20588
20718
  for (const id of appendResults.fullResyncNeeded) {
20589
20719
  try {
20590
- markFullResync(base2, id);
20720
+ markFullResync(base3, id);
20591
20721
  } catch {
20592
20722
  }
20593
20723
  }
@@ -20600,7 +20730,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20600
20730
  await findingsBatch.drain();
20601
20731
  await drainInflight();
20602
20732
  {
20603
- const sentHashes = loadInventoryHashes(base2);
20733
+ const sentHashes = loadInventoryHashes(base3);
20604
20734
  const entries = [];
20605
20735
  const hashes = {};
20606
20736
  for (const [sourceType, ids] of inventory) {
@@ -20614,7 +20744,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20614
20744
  if (entries.length > 0) {
20615
20745
  try {
20616
20746
  await post({ inventory: entries });
20617
- saveInventoryHashes(base2, hashes);
20747
+ saveInventoryHashes(base3, hashes);
20618
20748
  } catch (err) {
20619
20749
  console.error(`[sync] toolkit inventory not sent (it is retried next sync): ${err instanceof Error ? err.message : err}`);
20620
20750
  }
@@ -20625,7 +20755,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20625
20755
  const rec = {};
20626
20756
  for (const t of seenTools) rec[t] = extractorVersionForTool(t);
20627
20757
  for (const [k, v] of seenItemKeys) rec[k] = v;
20628
- saveItemVersions(base2, rec);
20758
+ saveItemVersions(base3, rec);
20629
20759
  } catch {
20630
20760
  }
20631
20761
  }
@@ -20638,9 +20768,9 @@ async function syncToTargetInScope(cred, opts = {}) {
20638
20768
  }
20639
20769
  if (tombstones.length > 0) {
20640
20770
  await post({ tombstones });
20641
- const data = getLedgerData(base2);
20771
+ const data = getLedgerData(base3);
20642
20772
  for (const t of tombstones) delete data[t.session_id];
20643
- persistLedgerData(base2, data);
20773
+ persistLedgerData(base3, data);
20644
20774
  }
20645
20775
  }
20646
20776
  if (opts.prune) await post({ prune_empty_sessions: true });
@@ -20968,8 +21098,13 @@ async function buildConversationTail(ref, fromOffset, opts = {}) {
20968
21098
  const backend = getBackendForId(ref.prefixedId);
20969
21099
  if (!backend?.readFromOffset) return null;
20970
21100
  const mapPath = opts.mapPath ?? ((p) => p);
20971
- const { text: tailText, newOffset, skippedBytes } = await backend.readFromOffset(ref.prefixedId, fromOffset, SYNC_CHUNK_BYTES);
21101
+ const { text: tailText, newOffset, skippedBytes, baseLine } = await backend.readFromOffset(ref.prefixedId, fromOffset, SYNC_CHUNK_BYTES);
20972
21102
  if (newOffset <= fromOffset) return null;
21103
+ const fileSize = backend.fileSize?.(ref.prefixedId) ?? 0;
21104
+ const position = {
21105
+ ...typeof baseLine === "number" ? { base_line: baseLine } : {},
21106
+ final: fileSize > 0 && newOffset >= fileSize
21107
+ };
20973
21108
  const messages = skippedBytes ? [] : parseTailMessages(ref.toolId, tailText);
20974
21109
  const textMessages = messages.filter((m) => m.role !== "summary" && m.content?.trim());
20975
21110
  const hasContent = textMessages.length > 0 || messages.some((m) => m.toolCalls?.length);
@@ -20982,6 +21117,7 @@ async function buildConversationTail(ref, fromOffset, opts = {}) {
20982
21117
  append: true,
20983
21118
  base_offset: fromOffset,
20984
21119
  from_offset: newOffset,
21120
+ ...position,
20985
21121
  redacted_text: "",
20986
21122
  envelope: { v: TRANSCRIPT_VERSION, messages: [], subagents: [] },
20987
21123
  mtime: Math.floor(ref.mtime) || 0
@@ -21028,6 +21164,7 @@ async function buildConversationTail(ref, fromOffset, opts = {}) {
21028
21164
  // equals its stored synced-through offset.
21029
21165
  from_offset: newOffset,
21030
21166
  // where it ends → new synced-through offset.
21167
+ ...position,
21031
21168
  redacted_text: redactedText,
21032
21169
  envelope,
21033
21170
  mtime: Math.floor(ref.mtime) || 0
@@ -21111,7 +21248,7 @@ var init_sync_client = __esm({
21111
21248
  ownVersion = JSON.parse(readFileSync35(join42(dir, "../package.json"), "utf-8")).version || ownVersion;
21112
21249
  } catch {
21113
21250
  try {
21114
- if (true) ownVersion = "0.7.14";
21251
+ if (true) ownVersion = "0.7.16";
21115
21252
  } catch {
21116
21253
  }
21117
21254
  }
@@ -21170,10 +21307,10 @@ function parseAgentText(content, format, fallbackName) {
21170
21307
  return { name: fm.name || fallbackName, description: fm.description || "", tools: fm.tools, body: body.trim() };
21171
21308
  }
21172
21309
  function readCommand(filePath, format) {
21173
- return parseCommandText(readFileSync36(filePath, "utf-8"), format, base(filePath));
21310
+ return parseCommandText(readFileSync36(filePath, "utf-8"), format, base2(filePath));
21174
21311
  }
21175
21312
  function readAgent(filePath, format) {
21176
- return parseAgentText(readFileSync36(filePath, "utf-8"), format, base(filePath));
21313
+ return parseAgentText(readFileSync36(filePath, "utf-8"), format, base2(filePath));
21177
21314
  }
21178
21315
  function readInstructions(filePath, name) {
21179
21316
  const content = readFileSync36(filePath, "utf-8");
@@ -21273,7 +21410,7 @@ function emit(type, art, toTool, projectPath) {
21273
21410
  content: stringifyFrontmatter({ name: art.name, description: art.description, ...art.tools ? { tools: art.tools } : {} }, art.body)
21274
21411
  };
21275
21412
  }
21276
- function base(filePath) {
21413
+ function base2(filePath) {
21277
21414
  return basename21(filePath).replace(/\.(md|toml)$/, "");
21278
21415
  }
21279
21416
  var init_artifact_codec = __esm({
@@ -21711,11 +21848,11 @@ var init_toolkit_sync = __esm({
21711
21848
  });
21712
21849
 
21713
21850
  // ../engine/dist/core/which.js
21714
- import { existsSync as existsSync44, statSync as statSync39, accessSync, constants } from "node:fs";
21851
+ import { existsSync as existsSync44, statSync as statSync40, accessSync, constants } from "node:fs";
21715
21852
  import { join as join46, isAbsolute as isAbsolute2, delimiter as delimiter2, sep as sep3 } from "node:path";
21716
21853
  function executable(p) {
21717
21854
  try {
21718
- if (!statSync39(p).isFile())
21855
+ if (!statSync40(p).isFile())
21719
21856
  return false;
21720
21857
  } catch {
21721
21858
  return false;
@@ -21778,11 +21915,11 @@ __export(toolkit_pull_exports, {
21778
21915
  platformRefusal: () => platformRefusal,
21779
21916
  portableCommand: () => portableCommand
21780
21917
  });
21781
- import { existsSync as existsSync45, mkdirSync as mkdirSync13, statSync as statSync40, writeFileSync as writeFileSync12 } from "node:fs";
21918
+ import { existsSync as existsSync45, mkdirSync as mkdirSync13, statSync as statSync41, writeFileSync as writeFileSync12 } from "node:fs";
21782
21919
  import { dirname as dirname22, join as join47, basename as basename23, isAbsolute as isAbsolute3 } from "node:path";
21783
21920
  function isExecutableFile(p) {
21784
21921
  try {
21785
- return statSync40(p).isFile();
21922
+ return statSync41(p).isFile();
21786
21923
  } catch {
21787
21924
  return false;
21788
21925
  }
@@ -21796,9 +21933,9 @@ function portableCommand(cmd) {
21796
21933
  }
21797
21934
  if (isExecutableFile(cmd))
21798
21935
  return { command: cmd, rewritten: false };
21799
- const base2 = basename23(cmd);
21800
- if (onPath(base2))
21801
- return { command: base2, rewritten: true };
21936
+ const base3 = basename23(cmd);
21937
+ if (onPath(base3))
21938
+ return { command: base3, rewritten: true };
21802
21939
  return { missing: cmd };
21803
21940
  }
21804
21941
  function entryFromSpec(spec) {
@@ -22315,7 +22452,7 @@ __export(shadow_prune_exports, {
22315
22452
  DEFAULT_MAX_TOTAL_BYTES: () => DEFAULT_MAX_TOTAL_BYTES,
22316
22453
  pruneShadow: () => pruneShadow
22317
22454
  });
22318
- import { readdirSync as readdirSync32, statSync as statSync43, unlinkSync as unlinkSync3 } from "fs";
22455
+ import { readdirSync as readdirSync32, statSync as statSync44, unlinkSync as unlinkSync3 } from "fs";
22319
22456
  import { join as join50 } from "path";
22320
22457
  function listShadows(isFullyAcked) {
22321
22458
  const out = [];
@@ -22340,7 +22477,7 @@ function listShadows(isFullyAcked) {
22340
22477
  const path = join50(dir, name);
22341
22478
  let st;
22342
22479
  try {
22343
- st = statSync43(path);
22480
+ st = statSync44(path);
22344
22481
  } catch {
22345
22482
  continue;
22346
22483
  }
@@ -22455,7 +22592,7 @@ var init_code_intel = __esm({
22455
22592
  });
22456
22593
 
22457
22594
  // ../engine/dist/core/companions.js
22458
- 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";
22595
+ 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";
22459
22596
  import { homedir as homedir19 } from "node:os";
22460
22597
  import { join as join51 } from "node:path";
22461
22598
  import { execSync as execSync3 } from "node:child_process";
@@ -22506,7 +22643,7 @@ function checkCodeindexStatus() {
22506
22643
  status.installed = true;
22507
22644
  status.path = foundPath;
22508
22645
  try {
22509
- status.size = statSync44(foundPath).size;
22646
+ status.size = statSync45(foundPath).size;
22510
22647
  } catch {
22511
22648
  }
22512
22649
  try {
@@ -22846,17 +22983,17 @@ async function collectCode(opts) {
22846
22983
  return r;
22847
22984
  };
22848
22985
  log6(`indexing ${ws} + analyses \u2026`);
22849
- const base2 = await runMcp(bin, ws, [
22986
+ const base3 = await runMcp(bin, ws, [
22850
22987
  call(1, "index_workspace", { path: ws }),
22851
22988
  call(2, "status"),
22852
22989
  call(3, "get_tree"),
22853
22990
  ...ANALYSES.map((a, i) => call(10 + i, "analyze", { analysis: a }))
22854
22991
  ]);
22855
- const st = parseJson(base2, 2, {});
22856
- const tree = parseJson(base2, 3, []);
22992
+ const st = parseJson(base3, 2, {});
22993
+ const tree = parseJson(base3, 3, []);
22857
22994
  const A = {};
22858
22995
  ANALYSES.forEach((a, i) => {
22859
- A[a] = parseJson(base2, 10 + i, {});
22996
+ A[a] = parseJson(base3, 10 + i, {});
22860
22997
  });
22861
22998
  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;
22862
22999
  if (tree.length === 0) {
@@ -23949,7 +24086,7 @@ import { join as join48 } from "node:path";
23949
24086
 
23950
24087
  // src/project-tasks.ts
23951
24088
  init_http();
23952
- import { existsSync as existsSync43, readFileSync as readFileSync38, writeFileSync as writeFileSync11, mkdirSync as mkdirSync12, statSync as statSync38 } from "node:fs";
24089
+ import { existsSync as existsSync43, readFileSync as readFileSync38, writeFileSync as writeFileSync11, mkdirSync as mkdirSync12, statSync as statSync39 } from "node:fs";
23953
24090
  import { join as join45, dirname as dirname21 } from "node:path";
23954
24091
  import { homedir as homedir18 } from "node:os";
23955
24092
 
@@ -24042,14 +24179,14 @@ var FILE_KINDS = [
24042
24179
  { kind: "secret", filename: "SECURITY_TASKS.md", trackedPath: "/api/secrets/tasks/tracked", statusPath: "/api/secrets/tasks/status" },
24043
24180
  { kind: "code", filename: "CODE_TASKS.md", trackedPath: "/api/code/tasks/tracked", statusPath: "/api/code/tasks/status" }
24044
24181
  ];
24045
- async function pushProjectTaskStatuses(base2, authHeaders, opts = {}) {
24182
+ async function pushProjectTaskStatuses(base3, authHeaders, opts = {}) {
24046
24183
  const out = { files: 0, pushedTasks: 0 };
24047
24184
  const ledger = readLedger();
24048
24185
  let ledgerDirty = false;
24049
24186
  for (const fk of FILE_KINDS) {
24050
24187
  let projects;
24051
24188
  try {
24052
- const res = await fetchWithTimeout(`${base2}${fk.trackedPath}`, { headers: authHeaders });
24189
+ const res = await fetchWithTimeout(`${base3}${fk.trackedPath}`, { headers: authHeaders });
24053
24190
  if (!res.ok) continue;
24054
24191
  projects = (await res.json()).projects || [];
24055
24192
  } catch {
@@ -24060,7 +24197,7 @@ async function pushProjectTaskStatuses(base2, authHeaders, opts = {}) {
24060
24197
  if (!existsSync43(file)) continue;
24061
24198
  let mtime;
24062
24199
  try {
24063
- mtime = statSync38(file).mtimeMs;
24200
+ mtime = statSync39(file).mtimeMs;
24064
24201
  } catch {
24065
24202
  continue;
24066
24203
  }
@@ -24077,7 +24214,7 @@ async function pushProjectTaskStatuses(base2, authHeaders, opts = {}) {
24077
24214
  continue;
24078
24215
  }
24079
24216
  try {
24080
- const res = await fetchWithTimeout(`${base2}${fk.statusPath}`, {
24217
+ const res = await fetchWithTimeout(`${base3}${fk.statusPath}`, {
24081
24218
  method: "POST",
24082
24219
  headers: { "content-type": "application/json", ...authHeaders },
24083
24220
  body: JSON.stringify({ project, items: changed.map((t) => ({ id: t.id, status: t.intent })) })
@@ -24167,16 +24304,16 @@ ${block}`);
24167
24304
  return { status: "error", result: JSON.stringify({ error: e instanceof Error ? e.message : "failed" }) };
24168
24305
  }
24169
24306
  }
24170
- async function runPull(base2, opts) {
24307
+ async function runPull(base3, opts) {
24171
24308
  const { executePull: executePull2 } = await Promise.resolve().then(() => (init_toolkit_pull(), toolkit_pull_exports));
24172
24309
  const { hostname: hostname3 } = await import("node:os");
24173
- const creds = loadAllCredentials().find((c) => c.serverUrl.replace(/\/+$/, "") === base2.replace(/\/+$/, ""));
24310
+ const creds = loadAllCredentials().find((c) => c.serverUrl.replace(/\/+$/, "") === base3.replace(/\/+$/, ""));
24174
24311
  const headers = creds?.token ? { authorization: `Bearer ${creds.token}` } : {};
24175
24312
  const wanted = opts.types?.length ? opts.types : ["mcp", "skill", "command", "agent", "instructions"];
24176
24313
  const rows = [];
24177
24314
  for (const type of wanted) {
24178
24315
  try {
24179
- const res = await fetchWithTimeout(`${base2}/api/toolkit/browse/${type}?limit=1000`, { headers });
24316
+ const res = await fetchWithTimeout(`${base3}/api/toolkit/browse/${type}?limit=1000`, { headers });
24180
24317
  if (!res.ok) continue;
24181
24318
  const body = await res.json();
24182
24319
  for (const it of body.items || []) rows.push(it);
@@ -24248,27 +24385,27 @@ try {
24248
24385
  ownVersion2 = JSON.parse(readFileSync39(join48(dir, "../package.json"), "utf-8")).version || ownVersion2;
24249
24386
  } catch {
24250
24387
  try {
24251
- if (true) ownVersion2 = "0.7.14";
24388
+ if (true) ownVersion2 = "0.7.16";
24252
24389
  } catch {
24253
24390
  }
24254
24391
  }
24255
24392
  async function drainSyncIntents(opts = {}) {
24256
24393
  const out = { processed: 0, done: 0, errored: 0 };
24257
24394
  for (const cred of loadAllCredentials()) {
24258
- const base2 = cred.serverUrl.replace(/\/+$/, "");
24395
+ const base3 = cred.serverUrl.replace(/\/+$/, "");
24259
24396
  const authHeaders = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
24260
24397
  let pending;
24261
24398
  try {
24262
- const res = await fetchWithTimeout(`${base2}/api/sync-intents/pending`, { headers: authHeaders });
24399
+ const res = await fetchWithTimeout(`${base3}/api/sync-intents/pending`, { headers: authHeaders });
24263
24400
  if (!res.ok) continue;
24264
24401
  const data = await res.json();
24265
24402
  pending = data.intents || [];
24266
24403
  if (data.cli && data.cli.version) {
24267
24404
  const { planAutoUpdate: planAutoUpdate2, runAutoUpdate: runAutoUpdate2, sweepStaleStaging: sweepStaleStaging2 } = await Promise.resolve().then(() => (init_auto_update(), auto_update_exports));
24268
- const plan = planAutoUpdate2(base2, { cli: data.cli }, ownVersion2, process.env.CHAT_RECALL_AUTO_UPDATE);
24405
+ const plan = planAutoUpdate2(base3, { cli: data.cli }, ownVersion2, process.env.CHAT_RECALL_AUTO_UPDATE);
24269
24406
  sweepStaleStaging2();
24270
24407
  if (plan.update) {
24271
- void runAutoUpdate2(base2, authHeaders, ownVersion2).catch(() => {
24408
+ void runAutoUpdate2(base3, authHeaders, ownVersion2).catch(() => {
24272
24409
  });
24273
24410
  }
24274
24411
  }
@@ -24276,7 +24413,7 @@ async function drainSyncIntents(opts = {}) {
24276
24413
  continue;
24277
24414
  }
24278
24415
  for (const intent of pending) {
24279
- const { status, result } = await runIntent(intent, { base: base2 });
24416
+ const { status, result } = await runIntent(intent, { base: base3 });
24280
24417
  out.processed++;
24281
24418
  if (status === "done") out.done++;
24282
24419
  else out.errored++;
@@ -24285,7 +24422,7 @@ async function drainSyncIntents(opts = {}) {
24285
24422
  console.error(`[sync-intent] ${label}: ${status}`);
24286
24423
  }
24287
24424
  try {
24288
- await fetchWithTimeout(`${base2}/api/sync-intents/${intent.id}/ack`, {
24425
+ await fetchWithTimeout(`${base3}/api/sync-intents/${intent.id}/ack`, {
24289
24426
  method: "POST",
24290
24427
  headers: { "content-type": "application/json", ...authHeaders },
24291
24428
  body: JSON.stringify({ status, result })
@@ -24294,7 +24431,7 @@ async function drainSyncIntents(opts = {}) {
24294
24431
  }
24295
24432
  }
24296
24433
  try {
24297
- await pushProjectTaskStatuses(base2, authHeaders, { verbose: opts.verbose });
24434
+ await pushProjectTaskStatuses(base3, authHeaders, { verbose: opts.verbose });
24298
24435
  } catch {
24299
24436
  }
24300
24437
  }
@@ -24313,7 +24450,7 @@ init_auto_update();
24313
24450
 
24314
24451
  // src/code-index-cursor.ts
24315
24452
  init_paths();
24316
- import { readFileSync as readFileSync40, writeFileSync as writeFileSync14, mkdirSync as mkdirSync15, statSync as statSync41 } from "fs";
24453
+ import { readFileSync as readFileSync40, writeFileSync as writeFileSync14, mkdirSync as mkdirSync15, statSync as statSync42 } from "fs";
24317
24454
  import { execFileSync as execFileSync4 } from "child_process";
24318
24455
  import { createHash as createHash10 } from "crypto";
24319
24456
  import { join as join49, dirname as dirname24 } from "path";
@@ -24364,7 +24501,7 @@ function workspaceFingerprint(workspace, collectorVersion) {
24364
24501
  const rel = entry.slice(3);
24365
24502
  let stamp2 = "gone";
24366
24503
  try {
24367
- const s = statSync41(join49(workspace, rel));
24504
+ const s = statSync42(join49(workspace, rel));
24368
24505
  stamp2 = `${s.size}:${Math.floor(s.mtimeMs)}`;
24369
24506
  } catch {
24370
24507
  }
@@ -24573,11 +24710,11 @@ function checkSelfRestart(opts) {
24573
24710
  }
24574
24711
 
24575
24712
  // src/log-rotate.ts
24576
- import { statSync as statSync42, copyFileSync as copyFileSync3, truncateSync } from "fs";
24713
+ import { statSync as statSync43, copyFileSync as copyFileSync3, truncateSync } from "fs";
24577
24714
  var LOG_MAX_BYTES = 32 * 1024 * 1024;
24578
24715
  function rotateLogIfLarge(logPath, maxBytes = LOG_MAX_BYTES) {
24579
24716
  try {
24580
- const size = statSync42(logPath).size;
24717
+ const size = statSync43(logPath).size;
24581
24718
  if (size < maxBytes) return { rotated: false, sizeBefore: 0 };
24582
24719
  copyFileSync3(logPath, `${logPath}.1`);
24583
24720
  truncateSync(logPath, 0);
@@ -24632,8 +24769,8 @@ async function runCollectorMigration(opts) {
24632
24769
  // auto-indexer/indexer.ts
24633
24770
  init_sync_ledger();
24634
24771
  init_collector_health();
24635
- import { existsSync as existsSync50, readFileSync as readFileSync45, statSync as statSync45 } from "fs";
24636
- var CLI_VERSION3 = true ? "0.7.14" : "0.0.0";
24772
+ import { existsSync as existsSync50, readFileSync as readFileSync45, statSync as statSync46 } from "fs";
24773
+ var CLI_VERSION3 = true ? "0.7.16" : "0.0.0";
24637
24774
  var DEBOUNCE_MS = 5e3;
24638
24775
  var PLANS_DIR = claudeBackend.plansDir();
24639
24776
  var TASKS_DIR = claudeBackend.tasksDir();
@@ -24738,7 +24875,7 @@ var CLAUDE_SESSION_ROOTS = claudeProjectDirs();
24738
24875
  var sessionWatcher = watchWithFallback("sessions", CLAUDE_SESSION_ROOTS.map((root) => `${root}/**/*.jsonl`), {
24739
24876
  ignored: (p, stats) => {
24740
24877
  if (/agent-/.test(p) || /^\./.test(basename25(p))) return true;
24741
- const st = stats ?? statSync45(p, { throwIfNoEntry: false });
24878
+ const st = stats ?? statSync46(p, { throwIfNoEntry: false });
24742
24879
  if (!st || st.isDirectory()) return false;
24743
24880
  return st.mtimeMs < Date.now() - WATCH_WINDOW_MS;
24744
24881
  },
@@ -25108,10 +25245,10 @@ async function codeIndexTick() {
25108
25245
  continue;
25109
25246
  }
25110
25247
  for (const cred of creds) {
25111
- const base2 = cred.serverUrl.replace(/\/+$/, "");
25248
+ const base3 = cred.serverUrl.replace(/\/+$/, "");
25112
25249
  const headers = { "content-type": "application/json", ...cred.token ? { authorization: `Bearer ${cred.token}` } : {} };
25113
25250
  try {
25114
- await fetchWithTimeout(`${base2}/api/code/index`, { method: "POST", headers, body: JSON.stringify(result) }, 6e4);
25251
+ await fetchWithTimeout(`${base3}/api/code/index`, { method: "POST", headers, body: JSON.stringify(result) }, 6e4);
25115
25252
  } catch {
25116
25253
  }
25117
25254
  }
@@ -25134,12 +25271,12 @@ if (CODE_INDEX_ON) {
25134
25271
  }
25135
25272
  async function autoUpdateTick() {
25136
25273
  for (const cred of loadAllCredentials()) {
25137
- const base2 = cred.serverUrl.replace(/\/+$/, "");
25274
+ const base3 = cred.serverUrl.replace(/\/+$/, "");
25138
25275
  const headers = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
25139
25276
  try {
25140
- const r = await runAutoUpdate(base2, headers, CLI_VERSION3);
25141
- if (r.updated) daemonLog.info(`auto-update: ${r.reason} (${base2}) \u2014 restarting service`);
25142
- else if (!/already current|disabled|no CLI release/.test(r.reason)) daemonLog.info(`auto-update: ${r.reason} (${base2})`);
25277
+ const r = await runAutoUpdate(base3, headers, CLI_VERSION3);
25278
+ if (r.updated) daemonLog.info(`auto-update: ${r.reason} (${base3}) \u2014 restarting service`);
25279
+ else if (!/already current|disabled|no CLI release/.test(r.reason)) daemonLog.info(`auto-update: ${r.reason} (${base3})`);
25143
25280
  } catch {
25144
25281
  }
25145
25282
  }
@@ -25166,20 +25303,20 @@ async function collectorMigrationOnce() {
25166
25303
  return;
25167
25304
  }
25168
25305
  for (const cred of creds) {
25169
- const base2 = cred.serverUrl.replace(/\/+$/, "");
25306
+ const base3 = cred.serverUrl.replace(/\/+$/, "");
25170
25307
  const headers = { "content-type": "application/json", ...cred.token ? { authorization: `Bearer ${cred.token}` } : {} };
25171
25308
  const reindex = async (rootPath) => {
25172
25309
  try {
25173
25310
  const result = await collectCode2({ workspace: rootPath, binPath: bin });
25174
- const res = await fetchWithTimeout(`${base2}/api/code/index`, { method: "POST", headers, body: JSON.stringify(result) }, 6e4);
25311
+ const res = await fetchWithTimeout(`${base3}/api/code/index`, { method: "POST", headers, body: JSON.stringify(result) }, 6e4);
25175
25312
  return res.ok;
25176
25313
  } catch {
25177
25314
  return false;
25178
25315
  }
25179
25316
  };
25180
25317
  try {
25181
- const r = await runCollectorMigration({ base: base2, authHeaders: headers, current: COLLECTOR_VERSION2, reindex, log: (m) => daemonLog.info(`${m}`) });
25182
- if (r.reindexed || r.failed || r.missing) daemonLog.info(`collector migration (${base2}): re-derived ${r.reindexed}, failed ${r.failed}, skipped-missing ${r.missing}`);
25318
+ const r = await runCollectorMigration({ base: base3, authHeaders: headers, current: COLLECTOR_VERSION2, reindex, log: (m) => daemonLog.info(`${m}`) });
25319
+ if (r.reindexed || r.failed || r.missing) daemonLog.info(`collector migration (${base3}): re-derived ${r.reindexed}, failed ${r.failed}, skipped-missing ${r.missing}`);
25183
25320
  } catch {
25184
25321
  }
25185
25322
  }