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/cli.js CHANGED
@@ -4259,7 +4259,7 @@ var require_pino = __commonJS({
4259
4259
  messageKey,
4260
4260
  errorKey,
4261
4261
  nestedKey,
4262
- base: base3,
4262
+ base: base4,
4263
4263
  name,
4264
4264
  level: level2,
4265
4265
  customLevels,
@@ -4298,11 +4298,11 @@ var require_pino = __commonJS({
4298
4298
  [formattersSym]: allFormatters
4299
4299
  });
4300
4300
  let chindings = "";
4301
- if (base3 !== null) {
4301
+ if (base4 !== null) {
4302
4302
  if (name === void 0) {
4303
- chindings = coreChindings(base3);
4303
+ chindings = coreChindings(base4);
4304
4304
  } else {
4305
- chindings = coreChindings(Object.assign({}, base3, { name }));
4305
+ chindings = coreChindings(Object.assign({}, base4, { name }));
4306
4306
  }
4307
4307
  }
4308
4308
  const time2 = timestamp instanceof Function ? timestamp : timestamp ? epochTime : nullTime;
@@ -4834,57 +4834,57 @@ function freshDefaults() {
4834
4834
  team: defaultTeam()
4835
4835
  };
4836
4836
  }
4837
- function mergeSources(base3, partial) {
4837
+ function mergeSources(base4, partial) {
4838
4838
  if (!partial)
4839
- return base3;
4839
+ return base4;
4840
4840
  const legacyGemini = partial.enabled?.gemini;
4841
4841
  const inherited = legacyGemini && typeof legacyGemini === "object" ? (({ sessions: _s, plans: _p, ...rest }) => rest)(legacyGemini) : {};
4842
4842
  const enabled = {
4843
- claude: { ...base3.enabled.claude, ...partial.enabled?.claude ?? {} },
4844
- opencode: { ...base3.enabled.opencode, ...partial.enabled?.opencode ?? {} },
4845
- codex: { ...base3.enabled.codex, ...partial.enabled?.codex ?? {} },
4846
- agy: { ...base3.enabled.agy, ...inherited, ...partial.enabled?.agy ?? {} },
4847
- cursor: { ...base3.enabled.cursor, ...partial.enabled?.cursor ?? {} },
4848
- shared: { ...base3.enabled.shared, ...partial.enabled?.shared ?? {} },
4849
- common: { ...base3.enabled.common, ...partial.enabled?.common ?? {} }
4843
+ claude: { ...base4.enabled.claude, ...partial.enabled?.claude ?? {} },
4844
+ opencode: { ...base4.enabled.opencode, ...partial.enabled?.opencode ?? {} },
4845
+ codex: { ...base4.enabled.codex, ...partial.enabled?.codex ?? {} },
4846
+ agy: { ...base4.enabled.agy, ...inherited, ...partial.enabled?.agy ?? {} },
4847
+ cursor: { ...base4.enabled.cursor, ...partial.enabled?.cursor ?? {} },
4848
+ shared: { ...base4.enabled.shared, ...partial.enabled?.shared ?? {} },
4849
+ common: { ...base4.enabled.common, ...partial.enabled?.common ?? {} }
4850
4850
  };
4851
4851
  return {
4852
- claudeHome: partial.claudeHome ?? base3.claudeHome,
4853
- geminiHome: partial.geminiHome ?? base3.geminiHome,
4854
- codexHome: partial.codexHome ?? base3.codexHome,
4855
- opencodeDbPath: partial.opencodeDbPath ?? base3.opencodeDbPath,
4856
- agyHome: partial.agyHome ?? base3.agyHome,
4857
- cursorHome: partial.cursorHome ?? base3.cursorHome,
4858
- cursorIdeHome: partial.cursorIdeHome ?? base3.cursorIdeHome,
4859
- extraClaudeHomes: partial.extraClaudeHomes ?? base3.extraClaudeHomes,
4860
- approvedHomes: partial.approvedHomes ?? base3.approvedHomes,
4861
- declinedHomes: partial.declinedHomes ?? base3.declinedHomes,
4862
- homesGrandfathered: partial.homesGrandfathered ?? base3.homesGrandfathered,
4852
+ claudeHome: partial.claudeHome ?? base4.claudeHome,
4853
+ geminiHome: partial.geminiHome ?? base4.geminiHome,
4854
+ codexHome: partial.codexHome ?? base4.codexHome,
4855
+ opencodeDbPath: partial.opencodeDbPath ?? base4.opencodeDbPath,
4856
+ agyHome: partial.agyHome ?? base4.agyHome,
4857
+ cursorHome: partial.cursorHome ?? base4.cursorHome,
4858
+ cursorIdeHome: partial.cursorIdeHome ?? base4.cursorIdeHome,
4859
+ extraClaudeHomes: partial.extraClaudeHomes ?? base4.extraClaudeHomes,
4860
+ approvedHomes: partial.approvedHomes ?? base4.approvedHomes,
4861
+ declinedHomes: partial.declinedHomes ?? base4.declinedHomes,
4862
+ homesGrandfathered: partial.homesGrandfathered ?? base4.homesGrandfathered,
4863
4863
  enabled
4864
4864
  };
4865
4865
  }
4866
- function mergePrivacy(base3, partial) {
4866
+ function mergePrivacy(base4, partial) {
4867
4867
  if (!partial)
4868
- return base3;
4869
- return { ...base3, ...partial };
4868
+ return base4;
4869
+ return { ...base4, ...partial };
4870
4870
  }
4871
- function mergeSync(base3, partial) {
4871
+ function mergeSync(base4, partial) {
4872
4872
  if (!partial)
4873
- return base3;
4873
+ return base4;
4874
4874
  return {
4875
- ...base3,
4875
+ ...base4,
4876
4876
  ...partial,
4877
- upload: { ...base3.upload, ...partial.upload ?? {} }
4877
+ upload: { ...base4.upload, ...partial.upload ?? {} }
4878
4878
  };
4879
4879
  }
4880
- function mergeTeam(base3, partial) {
4880
+ function mergeTeam(base4, partial) {
4881
4881
  if (!partial)
4882
- return base3;
4882
+ return base4;
4883
4883
  return {
4884
- ...base3,
4884
+ ...base4,
4885
4885
  ...partial,
4886
- publishAllowed: { ...base3.publishAllowed, ...partial.publishAllowed ?? {} },
4887
- vault: { ...base3.vault, ...partial.vault ?? {} }
4886
+ publishAllowed: { ...base4.publishAllowed, ...partial.publishAllowed ?? {} },
4887
+ vault: { ...base4.vault, ...partial.vault ?? {} }
4888
4888
  };
4889
4889
  }
4890
4890
  function settingsFilePath() {
@@ -5002,15 +5002,15 @@ function loadSettings() {
5002
5002
  }
5003
5003
  try {
5004
5004
  const parsed = JSON.parse(readFileSync(path, "utf-8"));
5005
- const base3 = freshDefaults();
5005
+ const base4 = freshDefaults();
5006
5006
  const result = {
5007
5007
  v: SCHEMA_VERSION,
5008
- embedding: { ...base3.embedding, ...parsed.embedding ?? {} },
5009
- summary: { ...base3.summary, ...parsed.summary ?? {} },
5010
- sources: mergeSources(base3.sources, parsed.sources),
5011
- privacy: mergePrivacy(base3.privacy, parsed.privacy),
5012
- sync: mergeSync(base3.sync, parsed.sync),
5013
- team: mergeTeam(base3.team, parsed.team)
5008
+ embedding: { ...base4.embedding, ...parsed.embedding ?? {} },
5009
+ summary: { ...base4.summary, ...parsed.summary ?? {} },
5010
+ sources: mergeSources(base4.sources, parsed.sources),
5011
+ privacy: mergePrivacy(base4.privacy, parsed.privacy),
5012
+ sync: mergeSync(base4.sync, parsed.sync),
5013
+ team: mergeTeam(base4.team, parsed.team)
5014
5014
  };
5015
5015
  if (mtimeMs >= 0)
5016
5016
  _settingsCache = { mtimeMs, size, value: structuredClone(result) };
@@ -5216,10 +5216,10 @@ function legacyAutoSyncedHomes() {
5216
5216
  { base: join3(home, ".local", "share", "opencode"), marker: "opencode.db" },
5217
5217
  { base: join3(home, ".cursor"), marker: "chats" }
5218
5218
  ];
5219
- for (const { base: base3, marker } of bases) {
5220
- add(base3, marker);
5221
- const parent = dirname3(base3);
5222
- const leaf = base3.slice(parent.length + 1);
5219
+ for (const { base: base4, marker } of bases) {
5220
+ add(base4, marker);
5221
+ const parent = dirname3(base4);
5222
+ const leaf = base4.slice(parent.length + 1);
5223
5223
  try {
5224
5224
  for (const e of readdirSync2(parent, { withFileTypes: true })) {
5225
5225
  if (!e.isDirectory())
@@ -5417,17 +5417,17 @@ function cursorHomeDir() {
5417
5417
  function cursorIdeHomeDir() {
5418
5418
  return process.env.CHAT_RECALL_CURSOR_IDE_HOME || sources().cursorIdeHome || (process.platform === "darwin" ? join4(homedir3(), "Library", "Application Support", "Cursor") : join4(homedir3(), ".config", "Cursor"));
5419
5419
  }
5420
- function siblingHomes(base3, overridden, suffix) {
5420
+ function siblingHomes(base4, overridden, suffix) {
5421
5421
  const roots = [];
5422
5422
  const add = (home) => {
5423
5423
  const root = suffix ? join4(home, suffix) : home;
5424
5424
  if (existsSync4(root) && !roots.includes(root))
5425
5425
  roots.push(root);
5426
5426
  };
5427
- add(base3);
5427
+ add(base4);
5428
5428
  if (!overridden) {
5429
- const parent = dirname4(base3);
5430
- const leaf = basename(base3);
5429
+ const parent = dirname4(base4);
5430
+ const leaf = basename(base4);
5431
5431
  try {
5432
5432
  for (const entry of readdirSync3(parent, { withFileTypes: true })) {
5433
5433
  if (!entry.isDirectory())
@@ -5937,9 +5937,9 @@ async function parseSessionFile(sessionPath, maxMessages = 50) {
5937
5937
  content.metadata.durationMs += obj.durationMs;
5938
5938
  }
5939
5939
  if (msgType === "file-history-snapshot") {
5940
- const snapshot = obj.snapshot;
5941
- if (snapshot && typeof snapshot === "object") {
5942
- const backups = snapshot.trackedFileBackups;
5940
+ const snapshot2 = obj.snapshot;
5941
+ if (snapshot2 && typeof snapshot2 === "object") {
5942
+ const backups = snapshot2.trackedFileBackups;
5943
5943
  if (backups && typeof backups === "object") {
5944
5944
  for (const filePath2 of Object.keys(backups)) {
5945
5945
  filesModified.add(filePath2);
@@ -10956,12 +10956,14 @@ function lineKey(line) {
10956
10956
  try {
10957
10957
  const o = JSON.parse(line);
10958
10958
  if (typeof o?.uuid === "string" && o.uuid)
10959
- return { key: `u:${o.uuid}`, singleton: false };
10960
- if (typeof o?.type === "string" && SINGLETON_META.has(o.type))
10961
- return { key: `m:${o.type}`, singleton: true };
10959
+ return { key: `u:${o.uuid}`, meta: false, json: true };
10960
+ return { key: `h:${sha1(line)}`, meta: typeof o?.type === "string" && STATE_META.has(o.type), json: true };
10962
10961
  } catch {
10963
10962
  }
10964
- return { key: `h:${sha1(line)}`, singleton: false };
10963
+ return { key: `h:${sha1(line)}`, meta: false, json: false };
10964
+ }
10965
+ function isHalfWritten(line, currentLines) {
10966
+ return currentLines.some((c) => c.length > line.length && c.startsWith(line));
10965
10967
  }
10966
10968
  function mergeLineText(shadowText, currentText) {
10967
10969
  const shadowLines = shadowText.split("\n").filter((l) => l.trim());
@@ -10969,27 +10971,24 @@ function mergeLineText(shadowText, currentText) {
10969
10971
  const currentKeys = /* @__PURE__ */ new Set();
10970
10972
  for (const l of currentLines)
10971
10973
  currentKeys.add(lineKey(l).key);
10972
- const shadowKeys = /* @__PURE__ */ new Set();
10973
- for (const l of shadowLines)
10974
- shadowKeys.add(lineKey(l).key);
10975
- let recovered = 0;
10976
- for (const k of shadowKeys)
10977
- if (!currentKeys.has(k))
10978
- recovered++;
10979
- if (recovered === 0) {
10980
- return { text: currentText.endsWith("\n") ? currentText : currentText + "\n", recovered: 0, totalRecords: currentKeys.size };
10981
- }
10982
- const out = [];
10983
- const emitted = /* @__PURE__ */ new Set();
10974
+ const kept = [];
10975
+ const keptKeys = /* @__PURE__ */ new Set();
10976
+ const counted = /* @__PURE__ */ new Set();
10984
10977
  for (const l of shadowLines) {
10985
- const { key: key2, singleton } = lineKey(l);
10986
- if (singleton && currentKeys.has(key2))
10987
- continue;
10988
- if (emitted.has(key2))
10978
+ const { key: key2, meta, json } = lineKey(l);
10979
+ if (!json && isHalfWritten(l, currentLines))
10989
10980
  continue;
10990
- out.push(l);
10991
- emitted.add(key2);
10981
+ kept.push(l);
10982
+ keptKeys.add(key2);
10983
+ if (!meta && !currentKeys.has(key2))
10984
+ counted.add(key2);
10985
+ }
10986
+ const recovered = counted.size;
10987
+ if (recovered === 0) {
10988
+ return { text: currentText.endsWith("\n") ? currentText : currentText + "\n", recovered: 0, totalRecords: currentKeys.size };
10992
10989
  }
10990
+ const out = [...kept];
10991
+ const emitted = keptKeys;
10993
10992
  for (const l of currentLines) {
10994
10993
  const { key: key2 } = lineKey(l);
10995
10994
  if (emitted.has(key2))
@@ -11174,14 +11173,14 @@ function shadowSizeOnDisk(tool, rawId) {
11174
11173
  return 0;
11175
11174
  }
11176
11175
  }
11177
- var WHOLE_FILE_TOOLS, SINGLETON_META, lastLiveFingerprint;
11176
+ var WHOLE_FILE_TOOLS, STATE_META, lastLiveFingerprint;
11178
11177
  var init_shadow = __esm({
11179
11178
  "../engine/dist/transcript/shadow.js"() {
11180
11179
  "use strict";
11181
11180
  init_paths();
11182
11181
  init_raw();
11183
11182
  WHOLE_FILE_TOOLS = /* @__PURE__ */ new Set(["cursor"]);
11184
- SINGLETON_META = /* @__PURE__ */ new Set(["mode", "permission-mode", "ai-title", "last-prompt", "pr-link", "summary"]);
11183
+ STATE_META = /* @__PURE__ */ new Set(["mode", "permission-mode", "ai-title", "last-prompt", "pr-link", "summary"]);
11185
11184
  lastLiveFingerprint = /* @__PURE__ */ new Map();
11186
11185
  }
11187
11186
  });
@@ -12777,8 +12776,8 @@ function _clearServerRulePack() {
12777
12776
  serverPack = null;
12778
12777
  }
12779
12778
  function activeRules() {
12780
- const base3 = settingsView().rules;
12781
- return serverPack && serverPack.rules.length > 0 ? [...base3, ...serverPack.rules] : base3;
12779
+ const base4 = settingsView().rules;
12780
+ return serverPack && serverPack.rules.length > 0 ? [...base4, ...serverPack.rules] : base4;
12782
12781
  }
12783
12782
  function isRedactionEnabled() {
12784
12783
  const env = isEnvRedactionRequested();
@@ -18536,7 +18535,7 @@ var init_extractor_version = __esm({
18536
18535
  });
18537
18536
 
18538
18537
  // src/sync-ledger.ts
18539
- import { readFileSync as readFileSync29, writeFileSync as writeFileSync5, renameSync as renameSync4, mkdirSync as mkdirSync6 } from "node:fs";
18538
+ import { readFileSync as readFileSync29, writeFileSync as writeFileSync5, renameSync as renameSync4, mkdirSync as mkdirSync6, statSync as statSync35 } from "node:fs";
18540
18539
  import { join as join38, dirname as dirname15 } from "node:path";
18541
18540
  function toRow(entry) {
18542
18541
  if (entry === void 0) return void 0;
@@ -18545,32 +18544,94 @@ function toRow(entry) {
18545
18544
  function ledgerFilePath() {
18546
18545
  return ledgerPath();
18547
18546
  }
18548
- function load() {
18549
- if (cache3) return cache3;
18547
+ function stampOf(path) {
18548
+ try {
18549
+ const st = statSync35(path);
18550
+ return `${st.mtimeMs}:${st.size}`;
18551
+ } catch {
18552
+ return null;
18553
+ }
18554
+ }
18555
+ function readDisk(path) {
18550
18556
  try {
18551
- const parsed = JSON.parse(readFileSync29(ledgerPath(), "utf-8"));
18552
- cache3 = parsed && typeof parsed === "object" ? parsed : {};
18557
+ const parsed = JSON.parse(readFileSync29(path, "utf-8"));
18558
+ return parsed && typeof parsed === "object" ? parsed : {};
18553
18559
  } catch {
18554
- cache3 = {};
18560
+ return {};
18555
18561
  }
18562
+ }
18563
+ function snapshot(data) {
18564
+ const out = /* @__PURE__ */ new Map();
18565
+ for (const [server, rows] of Object.entries(data)) {
18566
+ for (const [id, entry] of Object.entries(rows)) out.set(rowKey(server, id), JSON.stringify(entry));
18567
+ }
18568
+ return out;
18569
+ }
18570
+ function mergeOnto(disk) {
18571
+ const out = {};
18572
+ const put = (server, id, entry) => {
18573
+ (out[server] ??= {})[id] = entry;
18574
+ };
18575
+ const mine = cache3 ?? {};
18576
+ for (const [server, rows] of Object.entries(disk)) {
18577
+ for (const [id, entry] of Object.entries(rows)) {
18578
+ const k = rowKey(server, id);
18579
+ const own = mine[server]?.[id];
18580
+ const was = base.get(k);
18581
+ if (own === void 0) {
18582
+ if (was === void 0) put(server, id, entry);
18583
+ } else {
18584
+ put(server, id, JSON.stringify(own) === was ? entry : own);
18585
+ }
18586
+ }
18587
+ }
18588
+ for (const [server, rows] of Object.entries(mine)) {
18589
+ for (const [id, entry] of Object.entries(rows)) {
18590
+ if (disk[server]?.[id] !== void 0) continue;
18591
+ if (JSON.stringify(entry) !== base.get(rowKey(server, id))) put(server, id, entry);
18592
+ }
18593
+ }
18594
+ return out;
18595
+ }
18596
+ function load() {
18597
+ const path = ledgerPath();
18598
+ const stamp = stampOf(path);
18599
+ if (cache3 && stamp === diskStamp) return cache3;
18600
+ const disk = readDisk(path);
18601
+ const merged = cache3 ? mergeOnto(disk) : disk;
18602
+ if (cache3) {
18603
+ for (const server of Object.keys(cache3)) if (!(server in merged)) delete cache3[server];
18604
+ for (const [server, rows] of Object.entries(merged)) {
18605
+ const target = cache3[server] ?? (cache3[server] = {});
18606
+ for (const id of Object.keys(target)) if (!(id in rows)) delete target[id];
18607
+ Object.assign(target, rows);
18608
+ }
18609
+ } else {
18610
+ cache3 = merged;
18611
+ }
18612
+ base = snapshot(disk);
18613
+ diskStamp = stamp;
18556
18614
  return cache3;
18557
18615
  }
18558
- function persistNow(data) {
18616
+ function persistNow() {
18559
18617
  const path = ledgerPath();
18560
18618
  mkdirSync6(dirname15(path), { recursive: true });
18561
- const tmp = `${path}.tmp`;
18562
- writeFileSync5(tmp, JSON.stringify(data));
18619
+ load();
18620
+ const tmp = `${path}.tmp-${process.pid}`;
18621
+ writeFileSync5(tmp, JSON.stringify(cache3 ?? {}));
18563
18622
  renameSync4(tmp, path);
18623
+ base = snapshot(cache3 ?? {});
18624
+ diskStamp = stampOf(path);
18564
18625
  pendingWrite = false;
18565
18626
  }
18566
- function persist(data) {
18627
+ function persist(_data) {
18567
18628
  pendingWrite = true;
18568
18629
  if (flushTimer) return;
18569
18630
  flushTimer = setTimeout(() => {
18570
18631
  flushTimer = null;
18571
18632
  if (pendingWrite) {
18572
18633
  try {
18573
- persistNow(data);
18634
+ persistNow();
18574
18635
  } catch {
18575
18636
  }
18576
18637
  }
@@ -18604,7 +18665,7 @@ function pruneLedgerTargets(configuredServers) {
18604
18665
  }
18605
18666
  const rows = names.reduce((n, s) => n + Object.keys(orphans[s]).length, 0);
18606
18667
  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.`);
18607
- persistNow(data);
18668
+ persistNow();
18608
18669
  return names.length;
18609
18670
  }
18610
18671
  function flushLedger() {
@@ -18613,7 +18674,7 @@ function flushLedger() {
18613
18674
  flushTimer = null;
18614
18675
  }
18615
18676
  if (!pendingWrite || !cache3) return;
18616
- persistNow(cache3);
18677
+ persistNow();
18617
18678
  }
18618
18679
  function loadItemVersionsAll() {
18619
18680
  if (itemVersionsCache) return itemVersionsCache;
@@ -18689,13 +18750,13 @@ function markSynced(server, rows) {
18689
18750
  const o = (cursorFromCaller ? r.offset : void 0) ?? prevOS.o ?? 0;
18690
18751
  const s = (cursorFromCaller ? r.size : void 0) ?? prevOS.s ?? 0;
18691
18752
  const ev = extractorVersionForId(r.id);
18692
- const base3 = prevF ? { m: Math.floor(r.mtime), v: ev, f: prevF } : { m: Math.floor(r.mtime), v: ev };
18753
+ const base4 = prevF ? { m: Math.floor(r.mtime), v: ev, f: prevF } : { m: Math.floor(r.mtime), v: ev };
18693
18754
  if (o > 0 || s > 0) {
18694
- base3.o = o;
18695
- base3.s = s;
18755
+ base4.o = o;
18756
+ base4.s = s;
18696
18757
  }
18697
- if (r.hash !== void 0) base3.h = r.hash;
18698
- forServer[r.id] = base3;
18758
+ if (r.hash !== void 0) base4.h = r.hash;
18759
+ forServer[r.id] = base4;
18699
18760
  }
18700
18761
  persist(data);
18701
18762
  }
@@ -18770,7 +18831,7 @@ function syncMode(row, mtime, fileSize, extractorVersion, isAppendOnly) {
18770
18831
  if (row.m >= Math.floor(mtime)) return "skip";
18771
18832
  return "full";
18772
18833
  }
18773
- var ledgerPath, cache3, LEDGER_FLUSH_MS, pendingWrite, flushTimer, itemVersionsPath, itemVersionsCache, inventoryPath, unackedCursorAttempts, reconcilePath, reconcileCache;
18834
+ var ledgerPath, cache3, base, diskStamp, rowKey, LEDGER_FLUSH_MS, pendingWrite, flushTimer, itemVersionsPath, itemVersionsCache, inventoryPath, unackedCursorAttempts, reconcilePath, reconcileCache;
18774
18835
  var init_sync_ledger = __esm({
18775
18836
  "src/sync-ledger.ts"() {
18776
18837
  "use strict";
@@ -18778,6 +18839,9 @@ var init_sync_ledger = __esm({
18778
18839
  init_extractor_version();
18779
18840
  ledgerPath = () => join38(getDataDir(), "sync-ledger.json");
18780
18841
  cache3 = null;
18842
+ base = /* @__PURE__ */ new Map();
18843
+ diskStamp = null;
18844
+ rowKey = (server, id) => `${server}\0${id}`;
18781
18845
  LEDGER_FLUSH_MS = 2e3;
18782
18846
  pendingWrite = false;
18783
18847
  flushTimer = null;
@@ -18816,7 +18880,7 @@ var init_sync_fields = __esm({
18816
18880
  });
18817
18881
 
18818
18882
  // ../engine/dist/core/index-lock.js
18819
- import { existsSync as existsSync39, mkdirSync as mkdirSync7, openSync as openSync8, writeFileSync as writeFileSync6, readFileSync as readFileSync30, rmSync as rmSync4, statSync as statSync35, closeSync as closeSync8 } from "fs";
18883
+ import { existsSync as existsSync39, mkdirSync as mkdirSync7, openSync as openSync8, writeFileSync as writeFileSync6, readFileSync as readFileSync30, rmSync as rmSync4, statSync as statSync36, closeSync as closeSync8 } from "fs";
18820
18884
  import { dirname as dirname16, join as join39 } from "path";
18821
18885
  function acquireIndexLock(opts) {
18822
18886
  const lockPath = lockFilePath(opts.file);
@@ -18866,7 +18930,7 @@ function lockFilePath(file = ".compact.lock") {
18866
18930
  }
18867
18931
  function stealStaleLock(lockPath, staleAfterMs) {
18868
18932
  try {
18869
- const s = statSync35(lockPath);
18933
+ const s = statSync36(lockPath);
18870
18934
  const age = Date.now() - s.mtimeMs;
18871
18935
  let payload;
18872
18936
  try {
@@ -18938,7 +19002,7 @@ var init_http = __esm({
18938
19002
  CLI_VERSION = JSON.parse(readFileSync31(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
18939
19003
  } catch {
18940
19004
  try {
18941
- if (true) CLI_VERSION = "0.7.13";
19005
+ if (true) CLI_VERSION = "0.7.15";
18942
19006
  } catch {
18943
19007
  }
18944
19008
  }
@@ -19436,7 +19500,7 @@ var init_telemetry = __esm({
19436
19500
  init_sync_client();
19437
19501
  cliVersion2 = () => {
19438
19502
  try {
19439
- return true ? "0.7.13" : "dev";
19503
+ return true ? "0.7.15" : "dev";
19440
19504
  } catch {
19441
19505
  return "dev";
19442
19506
  }
@@ -19612,11 +19676,11 @@ __export(server_probe_exports, {
19612
19676
  function probeOk(r) {
19613
19677
  return r.kind === "ok" && r.apiVersion >= 2;
19614
19678
  }
19615
- async function probeServer(base3, opts = {}) {
19679
+ async function probeServer(base4, opts = {}) {
19616
19680
  const f = opts.fetchImpl || fetch;
19617
19681
  let res;
19618
19682
  try {
19619
- res = await f(`${base3.replace(/\/+$/, "")}/api/capabilities`, {
19683
+ res = await f(`${base4.replace(/\/+$/, "")}/api/capabilities`, {
19620
19684
  signal: AbortSignal.timeout(opts.timeoutMs ?? 1e4)
19621
19685
  });
19622
19686
  } catch (err) {
@@ -19653,34 +19717,34 @@ async function probeServer(base3, opts = {}) {
19653
19717
  raw: parsed
19654
19718
  };
19655
19719
  }
19656
- function probeAdvice(r, base3) {
19720
+ function probeAdvice(r, base4) {
19657
19721
  switch (r.kind) {
19658
19722
  case "ok":
19659
19723
  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`;
19660
19724
  case "moved":
19661
- return `HTTP ${r.status} \u2014 nothing is served at ${base3}. If the host moved, re-point it: \`chat-recall login <new-server-url>\``;
19725
+ return `HTTP ${r.status} \u2014 nothing is served at ${base4}. If the host moved, re-point it: \`chat-recall login <new-server-url>\``;
19662
19726
  case "unauthorized":
19663
- return `HTTP ${r.status} \u2014 ${base3} rejected the credential. Re-login: \`chat-recall login ` + base3 + "`";
19727
+ return `HTTP ${r.status} \u2014 ${base4} rejected the credential. Re-login: \`chat-recall login ` + base4 + "`";
19664
19728
  case "server_error":
19665
- return `HTTP ${r.status} \u2014 ${base3} is up but failing. Nothing to fix locally; check the server.`;
19729
+ return `HTTP ${r.status} \u2014 ${base4} is up but failing. Nothing to fix locally; check the server.`;
19666
19730
  case "not_api":
19667
- 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`;
19731
+ return `${base4} 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`;
19668
19732
  case "unreachable":
19669
19733
  switch (r.reason) {
19670
19734
  case "dns":
19671
- return `cannot resolve the host in ${base3} (${r.error}) \u2014 check the URL for a typo, and your DNS or VPN`;
19735
+ return `cannot resolve the host in ${base4} (${r.error}) \u2014 check the URL for a typo, and your DNS or VPN`;
19672
19736
  case "refused":
19673
- return `${base3} resolves but refused the connection (${r.error}) \u2014 the server is not running, or the port is wrong`;
19737
+ return `${base4} resolves but refused the connection (${r.error}) \u2014 the server is not running, or the port is wrong`;
19674
19738
  case "tls":
19675
- 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.`;
19739
+ return `the TLS certificate at ${base4} was rejected (${r.error}) \u2014 expired, self-signed, or issued for another host. A corporate proxy that re-signs traffic does this.`;
19676
19740
  case "timeout":
19677
- return `${base3} did not answer in time (${r.error}) \u2014 a firewall or proxy that drops traffic silently looks exactly like this`;
19741
+ return `${base4} did not answer in time (${r.error}) \u2014 a firewall or proxy that drops traffic silently looks exactly like this`;
19678
19742
  case "reset":
19679
- return `the connection to ${base3} was cut (${r.error}) \u2014 often a proxy or a captive portal`;
19743
+ return `the connection to ${base4} was cut (${r.error}) \u2014 often a proxy or a captive portal`;
19680
19744
  case "bad_port":
19681
- 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`;
19745
+ return `${base4} names a port that Node and every browser refuse to open (the WHATWG bad-port list) \u2014 use the server's real port`;
19682
19746
  default:
19683
- return `no HTTP response from ${base3} (${r.error}) \u2014 check the URL, DNS, or that the server is running`;
19747
+ return `no HTTP response from ${base4} (${r.error}) \u2014 check the URL, DNS, or that the server is running`;
19684
19748
  }
19685
19749
  }
19686
19750
  }
@@ -19713,8 +19777,8 @@ function describeCause(err) {
19713
19777
  const code2 = e.code;
19714
19778
  if (typeof code2 === "string" && code2 && !parts.includes(code2)) parts.push(code2);
19715
19779
  }
19716
- const base3 = err instanceof Error ? err.message : String(err);
19717
- return parts.length ? `${base3}: ${parts.join(" \u2192 ")}` : base3;
19780
+ const base4 = err instanceof Error ? err.message : String(err);
19781
+ return parts.length ? `${base4}: ${parts.join(" \u2192 ")}` : base4;
19718
19782
  }
19719
19783
  function describeUnreachable(err) {
19720
19784
  const reason = classifyUnreachable(err);
@@ -19827,7 +19891,7 @@ __export(auto_update_exports, {
19827
19891
  import { execSync as execSync2, execFileSync as execFileSync3 } from "node:child_process";
19828
19892
  import { readFileSync as readFileSync34, existsSync as existsSync41 } from "node:fs";
19829
19893
  import { fileURLToPath as fileURLToPath2 } from "node:url";
19830
- import { writeFileSync as writeFileSync8, mkdtempSync as mkdtempSync3, rmSync as rmSync5, readdirSync as readdirSync30, statSync as statSync36, mkdirSync as mkdirSync9 } from "node:fs";
19894
+ import { writeFileSync as writeFileSync8, mkdtempSync as mkdtempSync3, rmSync as rmSync5, readdirSync as readdirSync30, statSync as statSync37, mkdirSync as mkdirSync9 } from "node:fs";
19831
19895
  import { join as join41, dirname as dirname18, sep as sep2, posix as pathPosix, win32 as pathWin32 } from "node:path";
19832
19896
  import { tmpdir as tmpdir2, homedir as homedir15 } from "node:os";
19833
19897
  import { createHash as createHash8 } from "node:crypto";
@@ -19859,12 +19923,12 @@ function installedVersion() {
19859
19923
  return null;
19860
19924
  }
19861
19925
  }
19862
- function planAutoUpdate(base3, caps, ownVersion3, flag) {
19926
+ function planAutoUpdate(base4, caps, ownVersion3, flag) {
19863
19927
  const rel = caps.cli;
19864
19928
  if (!rel || !rel.version || !rel.sha256) return { update: false, reason: "server advertises no CLI release" };
19865
19929
  if (!isAutoUpdateEnabled(caps.edition, flag)) return { update: false, reason: `auto-update disabled (edition ${caps.edition ?? "?"})` };
19866
19930
  if (compareVersions(rel.version, ownVersion3) <= 0) return { update: false, reason: `already current (own ${ownVersion3} >= server ${rel.version})` };
19867
- 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 };
19931
+ return { update: true, reason: `server ${rel.version} > own ${ownVersion3}`, url: tarballUrl(base4, rel.version), fallbackUrl: tarballUrl(base4), sha256: rel.sha256, from: ownVersion3, to: rel.version };
19868
19932
  }
19869
19933
  function sweepStaleStaging(root = tmpdir2(), now = Date.now()) {
19870
19934
  const MKDTEMP_SUFFIX = /^cr-update-.{6}$/s;
@@ -19880,7 +19944,7 @@ function sweepStaleStaging(root = tmpdir2(), now = Date.now()) {
19880
19944
  if (!MKDTEMP_SUFFIX.test(name)) continue;
19881
19945
  const dir = join41(root, name);
19882
19946
  try {
19883
- const st = statSync36(dir);
19947
+ const st = statSync37(dir);
19884
19948
  if (!st.isDirectory() || now - st.mtimeMs < COLD_MS) continue;
19885
19949
  const inside = readdirSync30(dir);
19886
19950
  if (inside.length > 1 || inside.length === 1 && inside[0] !== "chat-recall.tgz") continue;
@@ -20044,20 +20108,20 @@ function clearUpdateFailures() {
20044
20108
  function stopAutoUpdates() {
20045
20109
  stopRequested = true;
20046
20110
  }
20047
- async function runAutoUpdate(base3, authHeaders, ownVersion3, deps) {
20111
+ async function runAutoUpdate(base4, authHeaders, ownVersion3, deps) {
20048
20112
  let caps;
20049
20113
  try {
20050
- const res = await fetchWithTimeout(`${base3.replace(/\/+$/, "")}/api/capabilities`, { headers: authHeaders });
20114
+ const res = await fetchWithTimeout(`${base4.replace(/\/+$/, "")}/api/capabilities`, { headers: authHeaders });
20051
20115
  if (!res.ok) return { updated: false, reason: `capabilities HTTP ${res.status}` };
20052
20116
  caps = await res.json();
20053
20117
  } catch (e) {
20054
20118
  return { updated: false, reason: `capabilities unreachable: ${e instanceof Error ? e.message : e}` };
20055
20119
  }
20056
20120
  const effectiveOwn = newerOf(ownVersion3, installedVersion());
20057
- const plan = planAutoUpdate(base3, caps, effectiveOwn, process.env.CHAT_RECALL_AUTO_UPDATE);
20121
+ const plan = planAutoUpdate(base4, caps, effectiveOwn, process.env.CHAT_RECALL_AUTO_UPDATE);
20058
20122
  if (!plan.update) {
20059
- if (/disabled|no CLI release/.test(plan.reason) && !reportedStandingSkip.has(base3)) {
20060
- reportedStandingSkip.add(base3);
20123
+ if (/disabled|no CLI release/.test(plan.reason) && !reportedStandingSkip.has(base4)) {
20124
+ reportedStandingSkip.add(base4);
20061
20125
  try {
20062
20126
  const { reportClientEvent: reportClientEvent2 } = await Promise.resolve().then(() => (init_client_events(), client_events_exports));
20063
20127
  reportClientEvent2("auto_update_skipped", { message: `${plan.reason} (server offers ${caps.cli?.version ?? "?"}, this device runs ${effectiveOwn})` });
@@ -20113,7 +20177,7 @@ var init_auto_update = __esm({
20113
20177
  "use strict";
20114
20178
  init_http();
20115
20179
  init_index_lock();
20116
- tarballUrl = (base3, version2) => `${base3.replace(/\/+$/, "")}/install/${version2 ? `chat-recall-${version2}.tgz` : "chat-recall.tgz"}`;
20180
+ tarballUrl = (base4, version2) => `${base4.replace(/\/+$/, "")}/install/${version2 ? `chat-recall-${version2}.tgz` : "chat-recall.tgz"}`;
20117
20181
  GIVE_UP_AFTER = 3;
20118
20182
  reportedStandingSkip = /* @__PURE__ */ new Set();
20119
20183
  STOPPING_REASON = "not installed: this process is shutting down";
@@ -20158,7 +20222,7 @@ __export(sync_client_exports, {
20158
20222
  syncSessions: () => syncSessions
20159
20223
  });
20160
20224
  import { join as join42, dirname as dirname19, basename as basename20 } from "node:path";
20161
- 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";
20225
+ 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";
20162
20226
  import { tmpdir as tmpdir3, hostname as hostname2 } from "node:os";
20163
20227
  import { createHash as createHash9 } from "node:crypto";
20164
20228
  import { fileURLToPath as fileURLToPath3 } from "node:url";
@@ -20221,15 +20285,15 @@ function loadAllCredentials() {
20221
20285
  return [];
20222
20286
  }
20223
20287
  async function fetchTenantSecurityConfig(cred) {
20224
- const base3 = cred.serverUrl.replace(/\/+$/, "");
20225
- const cached = _securityConfigCache.get(base3);
20288
+ const base4 = cred.serverUrl.replace(/\/+$/, "");
20289
+ const cached = _securityConfigCache.get(base4);
20226
20290
  if (cached && Date.now() - cached.fetchedAt < SECURITY_CONFIG_TTL_MS) return cached.config;
20227
20291
  const headers = { "content-type": "application/json" };
20228
20292
  if (cred.token) headers.authorization = `Bearer ${cred.token}`;
20229
20293
  try {
20230
20294
  const [rulesRes, settingsRes] = await Promise.all([
20231
- fetchWithTimeout(`${base3}/api/secrets/rules`, { headers }),
20232
- fetchWithTimeout(`${base3}/api/teams/security-config`, { headers }).catch(() => null)
20295
+ fetchWithTimeout(`${base4}/api/secrets/rules`, { headers }),
20296
+ fetchWithTimeout(`${base4}/api/teams/security-config`, { headers }).catch(() => null)
20233
20297
  ]);
20234
20298
  let tenantRules = [];
20235
20299
  let rulePackVersion = null;
@@ -20254,18 +20318,18 @@ async function fetchTenantSecurityConfig(cred) {
20254
20318
  const body2 = await settingsRes.json().catch(() => ({}));
20255
20319
  if (typeof body2.verifySecrets === "boolean") verifySecrets = body2.verifySecrets;
20256
20320
  if (typeof body2.telemetry === "boolean") {
20257
- setTelemetryEligible(base3, body2.telemetry);
20321
+ setTelemetryEligible(base4, body2.telemetry);
20258
20322
  try {
20259
20323
  const prior = readCollectorHealth()?.telemetryEligible ?? {};
20260
20324
  updateCollectorHealth({
20261
- telemetryEligible: { ...prior, [base3]: { allowed: body2.telemetry, at: Date.now() } }
20325
+ telemetryEligible: { ...prior, [base4]: { allowed: body2.telemetry, at: Date.now() } }
20262
20326
  });
20263
20327
  } catch {
20264
20328
  }
20265
20329
  }
20266
20330
  }
20267
20331
  const config2 = { tenantRules, verifySecrets, rulePackVersion };
20268
- _securityConfigCache.set(base3, { fetchedAt: Date.now(), config: config2 });
20332
+ _securityConfigCache.set(base4, { fetchedAt: Date.now(), config: config2 });
20269
20333
  return config2;
20270
20334
  } catch {
20271
20335
  return { tenantRules: [], verifySecrets: true, rulePackVersion: null };
@@ -20284,18 +20348,18 @@ function readPersistedSyncConfigs() {
20284
20348
  return {};
20285
20349
  }
20286
20350
  }
20287
- function persistSyncConfig(base3, config2) {
20351
+ function persistSyncConfig(base4, config2) {
20288
20352
  try {
20289
20353
  const all = readPersistedSyncConfigs();
20290
- all[base3] = { fetchedAt: Date.now(), config: config2 };
20354
+ all[base4] = { fetchedAt: Date.now(), config: config2 };
20291
20355
  mkdirSync10(dirname19(syncConfigCachePath()), { recursive: true });
20292
20356
  writeFileSync9(syncConfigCachePath(), JSON.stringify(all, null, 2));
20293
20357
  } catch {
20294
20358
  }
20295
20359
  }
20296
20360
  async function fetchTenantSyncConfig(cred) {
20297
- const base3 = cred.serverUrl.replace(/\/+$/, "");
20298
- const cached = _syncConfigCache.get(base3);
20361
+ const base4 = cred.serverUrl.replace(/\/+$/, "");
20362
+ const cached = _syncConfigCache.get(base4);
20299
20363
  if (cached && Date.now() - cached.fetchedAt < SECURITY_CONFIG_TTL_MS) return cached.config;
20300
20364
  const headers = { "content-type": "application/json" };
20301
20365
  if (cred.token) headers.authorization = `Bearer ${cred.token}`;
@@ -20303,7 +20367,7 @@ async function fetchTenantSyncConfig(cred) {
20303
20367
  try {
20304
20368
  const sources3 = discoverSessionSources();
20305
20369
  if (sources3.length > 0) {
20306
- await fetchWithTimeout(`${base3}/api/sync-config/sources`, {
20370
+ await fetchWithTimeout(`${base4}/api/sync-config/sources`, {
20307
20371
  method: "POST",
20308
20372
  headers,
20309
20373
  body: JSON.stringify({ device: deviceLabel(), sources: sources3 })
@@ -20311,12 +20375,12 @@ async function fetchTenantSyncConfig(cred) {
20311
20375
  }
20312
20376
  } catch {
20313
20377
  }
20314
- const res = await fetchWithTimeout(`${base3}/api/sync-config`, { headers });
20378
+ const res = await fetchWithTimeout(`${base4}/api/sync-config`, { headers });
20315
20379
  if (res.status === 404) {
20316
- _syncConfigCache.set(base3, { fetchedAt: Date.now(), config: EMPTY_SYNC_CONFIG });
20380
+ _syncConfigCache.set(base4, { fetchedAt: Date.now(), config: EMPTY_SYNC_CONFIG });
20317
20381
  return EMPTY_SYNC_CONFIG;
20318
20382
  }
20319
- if (!res.ok) return lastKnownSyncConfig(base3, `HTTP ${res.status}`);
20383
+ if (!res.ok) return lastKnownSyncConfig(base4, `HTTP ${res.status}`);
20320
20384
  const body2 = await res.json().catch(() => ({}));
20321
20385
  const config2 = {
20322
20386
  excludeTools: Array.isArray(body2.excludeTools) ? body2.excludeTools.filter((t) => typeof t === "string") : [],
@@ -20353,22 +20417,22 @@ async function fetchTenantSyncConfig(cred) {
20353
20417
  if (decided > 0) console.error(`[sync] applied ${decided} folder decision(s) from the dashboard`);
20354
20418
  } catch {
20355
20419
  }
20356
- _syncConfigCache.set(base3, { fetchedAt: Date.now(), config: config2 });
20357
- persistSyncConfig(base3, config2);
20420
+ _syncConfigCache.set(base4, { fetchedAt: Date.now(), config: config2 });
20421
+ persistSyncConfig(base4, config2);
20358
20422
  return config2;
20359
20423
  } catch (err) {
20360
20424
  if (isSyncRulesRefusal(err)) throw err;
20361
- return lastKnownSyncConfig(base3, err instanceof Error ? err.message : "request failed");
20425
+ return lastKnownSyncConfig(base4, err instanceof Error ? err.message : "request failed");
20362
20426
  }
20363
20427
  }
20364
- function lastKnownSyncConfig(base3, reason) {
20365
- const remembered = _syncConfigCache.get(base3) ?? readPersistedSyncConfigs()[base3];
20428
+ function lastKnownSyncConfig(base4, reason) {
20429
+ const remembered = _syncConfigCache.get(base4) ?? readPersistedSyncConfigs()[base4];
20366
20430
  if (remembered) {
20367
20431
  console.error(`[sync] could not read server-side sync rules (${reason}) \u2014 applying the last known set from ${new Date(remembered.fetchedAt).toISOString()}`);
20368
20432
  return remembered.config;
20369
20433
  }
20370
20434
  const refusal = new Error(
20371
- `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.`
20435
+ `Cannot read the server-side sync rules from ${base4} (${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.`
20372
20436
  );
20373
20437
  refusal[SYNC_RULES_REFUSAL] = true;
20374
20438
  throw refusal;
@@ -20489,25 +20553,25 @@ async function syncSessions(opts = {}) {
20489
20553
  ${errors.join("\n ")}`);
20490
20554
  return { ...agg, perTarget };
20491
20555
  }
20492
- async function postFieldBatch(base3, token, rows) {
20556
+ async function postFieldBatch(base4, token, rows) {
20493
20557
  const headers = { "content-type": "application/json" };
20494
20558
  if (token) headers.authorization = `Bearer ${token}`;
20495
20559
  const sleep2 = (ms) => new Promise((r) => setTimeout(r, ms));
20496
20560
  for (let attempt = 0; ; attempt++) {
20497
- const res = await fetchWithTimeout(`${base3}/api/sync`, { method: "POST", headers, body: JSON.stringify({ fields: rows }) }, 6e4);
20561
+ const res = await fetchWithTimeout(`${base4}/api/sync`, { method: "POST", headers, body: JSON.stringify({ fields: rows }) }, 6e4);
20498
20562
  if (res.ok) return;
20499
20563
  const retryable = res.status === 429 || res.status >= 500;
20500
- if (!retryable || attempt >= 5) throw new Error(`${base3}: fields batch HTTP ${res.status} ${await res.text().catch(() => "")}`);
20564
+ if (!retryable || attempt >= 5) throw new Error(`${base4}: fields batch HTTP ${res.status} ${await res.text().catch(() => "")}`);
20501
20565
  const ra = Number(res.headers.get("retry-after")) || 0;
20502
20566
  await sleep2(ra > 0 ? ra * 1e3 : [500, 1500, 4e3, 8e3, 15e3][Math.min(attempt, 4)]);
20503
20567
  }
20504
20568
  }
20505
20569
  async function reconcileFieldsForTarget(cred, fullRefs, opts = {}) {
20506
- const base3 = cred.serverUrl.replace(/\/+$/, "");
20507
- const ledger = getSyncedRows(base3);
20570
+ const base4 = cred.serverUrl.replace(/\/+$/, "");
20571
+ const ledger = getSyncedRows(base4);
20508
20572
  let pushed = 0, absent = 0, scanned = 0;
20509
20573
  for (const field of SYNC_FIELDS) {
20510
- const needFull = !!opts.force || fieldNeedsFullPass(base3, field);
20574
+ const needFull = !!opts.force || fieldNeedsFullPass(base4, field);
20511
20575
  const candidates2 = needFull ? fullRefs() : opts.convRefs ?? fullRefs();
20512
20576
  const send = [];
20513
20577
  const mtimeById = /* @__PURE__ */ new Map();
@@ -20523,15 +20587,15 @@ async function reconcileFieldsForTarget(cred, fullRefs, opts = {}) {
20523
20587
  }
20524
20588
  for (let i = 0; i < send.length; i += 200) {
20525
20589
  const chunk = send.slice(i, i + 200);
20526
- await postFieldBatch(base3, cred.token, chunk);
20527
- markFieldCoverage(base3, field, chunk.map((r) => ({ id: r.session_id, present: true, mtime: mtimeById.get(r.session_id) ?? 0 })));
20590
+ await postFieldBatch(base4, cred.token, chunk);
20591
+ markFieldCoverage(base4, field, chunk.map((r) => ({ id: r.session_id, present: true, mtime: mtimeById.get(r.session_id) ?? 0 })));
20528
20592
  pushed += chunk.length;
20529
20593
  }
20530
20594
  if (absentIds.length) {
20531
- markFieldCoverage(base3, field, absentIds.map((id) => ({ id, present: false, mtime: mtimeById.get(id) ?? 0 })));
20595
+ markFieldCoverage(base4, field, absentIds.map((id) => ({ id, present: false, mtime: mtimeById.get(id) ?? 0 })));
20532
20596
  absent += absentIds.length;
20533
20597
  }
20534
- if (needFull) markFieldFullPassDone(base3, field);
20598
+ if (needFull) markFieldFullPassDone(base4, field);
20535
20599
  }
20536
20600
  return { pushed, absent, scanned };
20537
20601
  }
@@ -20569,7 +20633,7 @@ function reapStaleScanDirs(dir = tmpdir3(), maxAgeMs = 6 * 36e5, now = Date.now(
20569
20633
  if (!name.startsWith("cr-batchscan-")) continue;
20570
20634
  const p = join42(dir, name);
20571
20635
  try {
20572
- if (now - statSync37(p).mtimeMs < maxAgeMs) continue;
20636
+ if (now - statSync38(p).mtimeMs < maxAgeMs) continue;
20573
20637
  rmSync6(p, { recursive: true, force: true });
20574
20638
  reaped++;
20575
20639
  } catch {
@@ -20648,25 +20712,25 @@ function serverIngestConcurrency(serverUrl) {
20648
20712
  return advertisedIngestConc.get(serverUrl.replace(/\/$/, "")) ?? null;
20649
20713
  }
20650
20714
  async function verifyServerApi(serverUrl, minApi) {
20651
- const base3 = serverUrl.replace(/\/$/, "");
20652
- const seen = capsOk.get(base3);
20715
+ const base4 = serverUrl.replace(/\/$/, "");
20716
+ const seen = capsOk.get(base4);
20653
20717
  if (seen !== void 0 && Date.now() - seen < CAPS_TTL_MS) return true;
20654
20718
  const { probeServer: probeServer2, probeAdvice: probeAdvice2 } = await Promise.resolve().then(() => (init_server_probe(), server_probe_exports));
20655
- const probe = await probeServer2(base3, {
20719
+ const probe = await probeServer2(base4, {
20656
20720
  fetchImpl: ((url, init) => fetchWithTimeout(String(url), init ?? {}))
20657
20721
  });
20658
- if (probe.kind !== "ok") throw new Error(probeAdvice2(probe, base3));
20722
+ if (probe.kind !== "ok") throw new Error(probeAdvice2(probe, base4));
20659
20723
  const caps = probe.raw;
20660
20724
  if ((caps.apiVersion ?? 0) < minApi) {
20661
20725
  throw new Error(`server too old: apiVersion ${caps.apiVersion ?? "none"} < required ${minApi} \u2014 update the server image before syncing`);
20662
20726
  }
20663
20727
  const adv = caps.limits?.ingestConcurrencyPerTenant;
20664
20728
  if (typeof adv === "number" && Number.isFinite(adv) && adv >= 1) {
20665
- advertisedIngestConc.set(base3, Math.floor(adv));
20729
+ advertisedIngestConc.set(base4, Math.floor(adv));
20666
20730
  }
20667
- if (caps.limits?.acceptsGzipBody === true) advertisedGzipBody.add(base3);
20668
- else advertisedGzipBody.delete(base3);
20669
- capsOk.set(base3, Date.now());
20731
+ if (caps.limits?.acceptsGzipBody === true) advertisedGzipBody.add(base4);
20732
+ else advertisedGzipBody.delete(base4);
20733
+ capsOk.set(base4, Date.now());
20670
20734
  return true;
20671
20735
  }
20672
20736
  async function syncToTarget(cred, opts = {}) {
@@ -20731,7 +20795,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20731
20795
  const ac = new AbortController();
20732
20796
  const timer = setTimeout(() => ac.abort(new Error(`upload timed out after ${UPLOAD_TIMEOUT_MS}ms`)), UPLOAD_TIMEOUT_MS);
20733
20797
  try {
20734
- const res = await fetch(`${base3}/api/sync`, {
20798
+ const res = await fetch(`${base4}/api/sync`, {
20735
20799
  method: "POST",
20736
20800
  // No token ⇒ no auth header: a no-auth local server (AUTH_PROVIDER=none)
20737
20801
  // accepts it as the single 'default' tenant.
@@ -20747,26 +20811,26 @@ async function syncToTargetInScope(cred, opts = {}) {
20747
20811
  acceptedUploads.set(cred.serverUrl, (acceptedUploads.get(cred.serverUrl) ?? 0) + 1);
20748
20812
  const body3 = await res.json().catch(() => ({}));
20749
20813
  if (typeof body3.telemetry === "boolean") {
20750
- setTelemetryEligible(base3, body3.telemetry);
20814
+ setTelemetryEligible(base4, body3.telemetry);
20751
20815
  try {
20752
20816
  const prior = readCollectorHealth()?.telemetryEligible ?? {};
20753
20817
  updateCollectorHealth({
20754
- telemetryEligible: { ...prior, [base3]: { allowed: body3.telemetry, at: Date.now() } }
20818
+ telemetryEligible: { ...prior, [base4]: { allowed: body3.telemetry, at: Date.now() } }
20755
20819
  });
20756
20820
  } catch {
20757
20821
  }
20758
20822
  }
20759
20823
  const adv = body3.limits?.ingestConcurrencyPerTenant;
20760
20824
  if (typeof adv === "number" && Number.isFinite(adv) && adv >= 1) {
20761
- setServerIngestConcurrency(base3, Math.floor(adv));
20825
+ setServerIngestConcurrency(base4, Math.floor(adv));
20762
20826
  }
20763
20827
  if (body3.cli && body3.cli.version) {
20764
20828
  const { planAutoUpdate: planAutoUpdate2, runAutoUpdate: runAutoUpdate2, sweepStaleStaging: sweepStaleStaging2 } = await Promise.resolve().then(() => (init_auto_update(), auto_update_exports));
20765
20829
  const authHeaders = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
20766
- const plan = planAutoUpdate2(base3, { cli: body3.cli }, ownVersion, process.env.CHAT_RECALL_AUTO_UPDATE);
20830
+ const plan = planAutoUpdate2(base4, { cli: body3.cli }, ownVersion, process.env.CHAT_RECALL_AUTO_UPDATE);
20767
20831
  sweepStaleStaging2();
20768
20832
  if (plan.update) {
20769
- void runAutoUpdate2(base3, authHeaders, ownVersion).catch(() => {
20833
+ void runAutoUpdate2(base4, authHeaders, ownVersion).catch(() => {
20770
20834
  });
20771
20835
  }
20772
20836
  }
@@ -20775,7 +20839,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20775
20839
  const retryable = res.status === 429 || res.status >= 500;
20776
20840
  const text = await res.text().catch(() => "");
20777
20841
  if (res.status === 401 || res.status === 403) {
20778
- throw classedError("auth", `server rejected this machine's device token (HTTP ${res.status} \u2014 revoked?). Reconnect with: chat-recall login ${base3}`);
20842
+ throw classedError("auth", `server rejected this machine's device token (HTTP ${res.status} \u2014 revoked?). Reconnect with: chat-recall login ${base4}`);
20779
20843
  }
20780
20844
  if (res.status === 402) {
20781
20845
  let detail = text;
@@ -20796,7 +20860,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20796
20860
  const retryAfterS = Number(res.headers.get("retry-after"));
20797
20861
  const waitMs = res.status === 429 && retryAfterS > 0 ? retryAfterS * 1e3 : RETRY_DELAYS_MS[attempt];
20798
20862
  const why = res.status === 524 ? ` \u2014 the proxy cut the request at its time limit; the batch is too big for one request` : "";
20799
- console.error(`[sync] HTTP ${res.status} from ${base3}${why} \u2014 backing off ${Math.round(waitMs / 1e3)}s (attempt ${attempt + 1})`);
20863
+ console.error(`[sync] HTTP ${res.status} from ${base4}${why} \u2014 backing off ${Math.round(waitMs / 1e3)}s (attempt ${attempt + 1})`);
20800
20864
  await sleep2(waitMs);
20801
20865
  continue;
20802
20866
  } catch (err) {
@@ -20864,11 +20928,11 @@ async function syncToTargetInScope(cred, opts = {}) {
20864
20928
  }
20865
20929
  };
20866
20930
  };
20867
- const base3 = cred.serverUrl.replace(/\/$/, "");
20868
- const ledger = opts.useLedger ? getSyncedRows(base3) : null;
20931
+ const base4 = cred.serverUrl.replace(/\/$/, "");
20932
+ const ledger = opts.useLedger ? getSyncedRows(base4) : null;
20869
20933
  const convBatch = makeBatcher("conversations", 25, false, (rows) => {
20870
20934
  try {
20871
- markSynced(base3, rows.map((r) => {
20935
+ markSynced(base4, rows.map((r) => {
20872
20936
  const off = typeof r.from_offset === "number" ? r.from_offset : 0;
20873
20937
  const hash = shippedHash.get(r.session_id);
20874
20938
  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 };
@@ -20883,7 +20947,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20883
20947
  const ac = new AbortController();
20884
20948
  const timer = setTimeout(() => ac.abort(new Error(`upload timed out after ${UPLOAD_TIMEOUT_MS}ms`)), UPLOAD_TIMEOUT_MS);
20885
20949
  try {
20886
- const res = await fetch(`${base3}/api/sync`, {
20950
+ const res = await fetch(`${base4}/api/sync`, {
20887
20951
  method: "POST",
20888
20952
  headers,
20889
20953
  body: JSON.stringify({ conversations: convs }),
@@ -20894,10 +20958,10 @@ async function syncToTargetInScope(cred, opts = {}) {
20894
20958
  if (body2.cli && body2.cli.version) {
20895
20959
  const { planAutoUpdate: planAutoUpdate2, runAutoUpdate: runAutoUpdate2, sweepStaleStaging: sweepStaleStaging2 } = await Promise.resolve().then(() => (init_auto_update(), auto_update_exports));
20896
20960
  const authHeaders = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
20897
- const plan = planAutoUpdate2(base3, { cli: body2.cli }, ownVersion, process.env.CHAT_RECALL_AUTO_UPDATE);
20961
+ const plan = planAutoUpdate2(base4, { cli: body2.cli }, ownVersion, process.env.CHAT_RECALL_AUTO_UPDATE);
20898
20962
  sweepStaleStaging2();
20899
20963
  if (plan.update) {
20900
- void runAutoUpdate2(base3, authHeaders, ownVersion).catch(() => {
20964
+ void runAutoUpdate2(base4, authHeaders, ownVersion).catch(() => {
20901
20965
  });
20902
20966
  }
20903
20967
  }
@@ -20905,7 +20969,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20905
20969
  const acked = convs.filter((c) => !fullNeeded.has(c.session_id));
20906
20970
  if (acked.length > 0) {
20907
20971
  try {
20908
- markSynced(base3, acked.map((c) => ({
20972
+ markSynced(base4, acked.map((c) => ({
20909
20973
  id: c.session_id,
20910
20974
  mtime: c.mtime,
20911
20975
  offset: c.from_offset,
@@ -20929,7 +20993,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20929
20993
  const ac = new AbortController();
20930
20994
  const timer = setTimeout(() => ac.abort(new Error(`upload timed out after ${UPLOAD_TIMEOUT_MS}ms`)), UPLOAD_TIMEOUT_MS);
20931
20995
  try {
20932
- const res = await fetch(`${base3}/api/sync`, {
20996
+ const res = await fetch(`${base4}/api/sync`, {
20933
20997
  method: "POST",
20934
20998
  headers,
20935
20999
  body: JSON.stringify({ conversations: [conv] }),
@@ -20942,11 +21006,11 @@ async function syncToTargetInScope(cred, opts = {}) {
20942
21006
  const mtime = conv.mtime;
20943
21007
  try {
20944
21008
  if (!guarded) {
20945
- markSynced(base3, [{ id, mtime, offset: conv.from_offset, size: conv.from_offset, acked: true }]);
21009
+ markSynced(base4, [{ id, mtime, offset: conv.from_offset, size: conv.from_offset, acked: true }]);
20946
21010
  } else if (typeof guarded.o === "number" && guarded.o > 0 && guarded.o <= fileSize) {
20947
- markSynced(base3, [{ id, mtime, offset: guarded.o, size: guarded.o, acked: true }]);
21011
+ markSynced(base4, [{ id, mtime, offset: guarded.o, size: guarded.o, acked: true }]);
20948
21012
  } else {
20949
- markSynced(base3, [{ id, mtime }]);
21013
+ markSynced(base4, [{ id, mtime }]);
20950
21014
  }
20951
21015
  } catch {
20952
21016
  }
@@ -21012,7 +21076,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21012
21076
  const m = process.memoryUsage();
21013
21077
  console.error(`[sync-trace] ${msg} \xB7 heap=${(m.heapUsed / 1048576).toFixed(0)}MB rss=${(m.rss / 1048576).toFixed(0)}MB`);
21014
21078
  } : null;
21015
- trace?.(`walk start: ${slice.length} ref(s) \u2192 ${base3}`);
21079
+ trace?.(`walk start: ${slice.length} ref(s) \u2192 ${base4}`);
21016
21080
  if (upload.sessionMeta) {
21017
21081
  try {
21018
21082
  await reconcileFieldsForTarget(
@@ -21027,7 +21091,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21027
21091
  { convRefs: slice }
21028
21092
  );
21029
21093
  } catch (e) {
21030
- console.error(`[sync] field reconcile (${base3}): ${e instanceof Error ? e.message : e}`);
21094
+ console.error(`[sync] field reconcile (${base4}): ${e instanceof Error ? e.message : e}`);
21031
21095
  }
21032
21096
  }
21033
21097
  trace?.("field reconcile done");
@@ -21069,7 +21133,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21069
21133
  }
21070
21134
  trace?.("conversation walk start");
21071
21135
  const walkStartedAt = Date.now();
21072
- const firstWalk = (ledger ?? getSyncedRows(base3)).size === 0;
21136
+ const firstWalk = (ledger ?? getSyncedRows(base4)).size === 0;
21073
21137
  reportWalkProgress({ done: 0, total: slice.length, startedAt: walkStartedAt, complete: false, first: firstWalk });
21074
21138
  walkProgressForUpload = { done: 0, total: slice.length, complete: false };
21075
21139
  let traceN = 0;
@@ -21109,7 +21173,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21109
21173
  continue;
21110
21174
  } else {
21111
21175
  try {
21112
- markSynced(base3, [{ id: ref.prefixedId, mtime: ref.mtime }]);
21176
+ markSynced(base4, [{ id: ref.prefixedId, mtime: ref.mtime }]);
21113
21177
  } catch {
21114
21178
  }
21115
21179
  skipped++;
@@ -21132,7 +21196,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21132
21196
  const off = getBackendForId(ref.prefixedId)?.fileSize?.(ref.rawId) ?? 0;
21133
21197
  const priorCursor = ackRow?.s ?? 0;
21134
21198
  const safeToAck = off > 0 && off <= priorCursor;
21135
- 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 }]);
21199
+ markSynced(base4, [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 }]);
21136
21200
  } catch {
21137
21201
  }
21138
21202
  }
@@ -21142,7 +21206,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21142
21206
  if (!built) {
21143
21207
  if (ledger) {
21144
21208
  try {
21145
- markSynced(base3, [{ id: ref.prefixedId, mtime: ref.mtime }]);
21209
+ markSynced(base4, [{ id: ref.prefixedId, mtime: ref.mtime }]);
21146
21210
  } catch {
21147
21211
  }
21148
21212
  }
@@ -21199,7 +21263,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21199
21263
  walked++;
21200
21264
  if (walked % 250 === 0) console.error(`[sync] ${walked}/${slice.length} sessions\u2026`);
21201
21265
  }
21202
- const itemVersions = loadItemVersions(base3);
21266
+ const itemVersions = loadItemVersions(base4);
21203
21267
  const seenTools = /* @__PURE__ */ new Set();
21204
21268
  const seenItemKeys = /* @__PURE__ */ new Map();
21205
21269
  const registry = buildSourceRegistry();
@@ -21293,7 +21357,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21293
21357
  await appendFlush();
21294
21358
  for (const id of appendResults.fullResyncNeeded) {
21295
21359
  try {
21296
- markFullResync(base3, id);
21360
+ markFullResync(base4, id);
21297
21361
  } catch {
21298
21362
  }
21299
21363
  }
@@ -21306,7 +21370,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21306
21370
  await findingsBatch.drain();
21307
21371
  await drainInflight();
21308
21372
  {
21309
- const sentHashes = loadInventoryHashes(base3);
21373
+ const sentHashes = loadInventoryHashes(base4);
21310
21374
  const entries = [];
21311
21375
  const hashes = {};
21312
21376
  for (const [sourceType, ids] of inventory) {
@@ -21320,7 +21384,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21320
21384
  if (entries.length > 0) {
21321
21385
  try {
21322
21386
  await post({ inventory: entries });
21323
- saveInventoryHashes(base3, hashes);
21387
+ saveInventoryHashes(base4, hashes);
21324
21388
  } catch (err) {
21325
21389
  console.error(`[sync] toolkit inventory not sent (it is retried next sync): ${err instanceof Error ? err.message : err}`);
21326
21390
  }
@@ -21331,7 +21395,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21331
21395
  const rec = {};
21332
21396
  for (const t of seenTools) rec[t] = extractorVersionForTool(t);
21333
21397
  for (const [k, v] of seenItemKeys) rec[k] = v;
21334
- saveItemVersions(base3, rec);
21398
+ saveItemVersions(base4, rec);
21335
21399
  } catch {
21336
21400
  }
21337
21401
  }
@@ -21344,9 +21408,9 @@ async function syncToTargetInScope(cred, opts = {}) {
21344
21408
  }
21345
21409
  if (tombstones.length > 0) {
21346
21410
  await post({ tombstones });
21347
- const data = getLedgerData(base3);
21411
+ const data = getLedgerData(base4);
21348
21412
  for (const t of tombstones) delete data[t.session_id];
21349
- persistLedgerData(base3, data);
21413
+ persistLedgerData(base4, data);
21350
21414
  }
21351
21415
  }
21352
21416
  if (opts.prune) await post({ prune_empty_sessions: true });
@@ -21817,7 +21881,7 @@ var init_sync_client = __esm({
21817
21881
  ownVersion = JSON.parse(readFileSync35(join42(dir, "../package.json"), "utf-8")).version || ownVersion;
21818
21882
  } catch {
21819
21883
  try {
21820
- if (true) ownVersion = "0.7.13";
21884
+ if (true) ownVersion = "0.7.15";
21821
21885
  } catch {
21822
21886
  }
21823
21887
  }
@@ -21911,9 +21975,9 @@ async function refreshUpdateCheck(force = false) {
21911
21975
  const { loadAllCredentials: loadAllCredentials2 } = await Promise.resolve().then(() => (init_sync_client(), sync_client_exports));
21912
21976
  for (const cred of loadAllCredentials2()) {
21913
21977
  if (!cred.serverUrl) continue;
21914
- const base3 = cred.serverUrl.replace(/\/+$/, "");
21978
+ const base4 = cred.serverUrl.replace(/\/+$/, "");
21915
21979
  try {
21916
- const res = await fetchWithTimeout(`${base3}/api/capabilities`, {
21980
+ const res = await fetchWithTimeout(`${base4}/api/capabilities`, {
21917
21981
  headers: cred.token ? { authorization: `Bearer ${cred.token}` } : {}
21918
21982
  }, 5e3);
21919
21983
  if (!res.ok) continue;
@@ -21968,11 +22032,11 @@ var init_update_notice = __esm({
21968
22032
  });
21969
22033
 
21970
22034
  // ../engine/dist/core/which.js
21971
- import { existsSync as existsSync42, statSync as statSync38, accessSync, constants } from "node:fs";
22035
+ import { existsSync as existsSync42, statSync as statSync39, accessSync, constants } from "node:fs";
21972
22036
  import { join as join44, isAbsolute as isAbsolute2, delimiter as delimiter2, sep as sep3 } from "node:path";
21973
22037
  function executable(p) {
21974
22038
  try {
21975
- if (!statSync38(p).isFile())
22039
+ if (!statSync39(p).isFile())
21976
22040
  return false;
21977
22041
  } catch {
21978
22042
  return false;
@@ -22301,7 +22365,7 @@ __export(companions_exports, {
22301
22365
  uninstallCodeindex: () => uninstallCodeindex,
22302
22366
  unregisterCodeindexMcp: () => unregisterCodeindexMcp
22303
22367
  });
22304
- import { existsSync as existsSync45, mkdirSync as mkdirSync13, statSync as statSync39, chmodSync as chmodSync4, unlinkSync as unlinkSync3, renameSync as renameSync5, createWriteStream, readFileSync as readFileSync38, writeFileSync as writeFileSync13 } from "node:fs";
22368
+ import { existsSync as existsSync45, mkdirSync as mkdirSync13, statSync as statSync40, chmodSync as chmodSync4, unlinkSync as unlinkSync3, renameSync as renameSync5, createWriteStream, readFileSync as readFileSync38, writeFileSync as writeFileSync13 } from "node:fs";
22305
22369
  import { homedir as homedir17 } from "node:os";
22306
22370
  import { join as join47 } from "node:path";
22307
22371
  import { execSync as execSync3 } from "node:child_process";
@@ -22352,7 +22416,7 @@ function checkCodeindexStatus() {
22352
22416
  status.installed = true;
22353
22417
  status.path = foundPath;
22354
22418
  try {
22355
- status.size = statSync39(foundPath).size;
22419
+ status.size = statSync40(foundPath).size;
22356
22420
  } catch {
22357
22421
  }
22358
22422
  try {
@@ -22502,7 +22566,7 @@ __export(install_skills_exports, {
22502
22566
  skillsSourceDir: () => skillsSourceDir,
22503
22567
  uninstallSkills: () => uninstallSkills
22504
22568
  });
22505
- import { readdirSync as readdirSync32, existsSync as existsSync46, mkdirSync as mkdirSync14, rmSync as rmSync7, cpSync, writeFileSync as writeFileSync14, readFileSync as readFileSync39, statSync as statSync40, realpathSync as realpathSync4 } from "fs";
22569
+ import { readdirSync as readdirSync32, existsSync as existsSync46, mkdirSync as mkdirSync14, rmSync as rmSync7, cpSync, writeFileSync as writeFileSync14, readFileSync as readFileSync39, statSync as statSync41, realpathSync as realpathSync4 } from "fs";
22506
22570
  import { createHash as createHash11 } from "crypto";
22507
22571
  import { join as join48, basename as basename21 } from "path";
22508
22572
  function skillsSourceDir() {
@@ -22721,10 +22785,10 @@ function parseAgentText(content, format, fallbackName) {
22721
22785
  return { name: fm.name || fallbackName, description: fm.description || "", tools: fm.tools, body: body2.trim() };
22722
22786
  }
22723
22787
  function readCommand(filePath, format) {
22724
- return parseCommandText(readFileSync40(filePath, "utf-8"), format, base(filePath));
22788
+ return parseCommandText(readFileSync40(filePath, "utf-8"), format, base2(filePath));
22725
22789
  }
22726
22790
  function readAgent(filePath, format) {
22727
- return parseAgentText(readFileSync40(filePath, "utf-8"), format, base(filePath));
22791
+ return parseAgentText(readFileSync40(filePath, "utf-8"), format, base2(filePath));
22728
22792
  }
22729
22793
  function readInstructions(filePath, name) {
22730
22794
  const content = readFileSync40(filePath, "utf-8");
@@ -22824,7 +22888,7 @@ function emit(type, art, toTool, projectPath) {
22824
22888
  content: stringifyFrontmatter({ name: art.name, description: art.description, ...art.tools ? { tools: art.tools } : {} }, art.body)
22825
22889
  };
22826
22890
  }
22827
- function base(filePath) {
22891
+ function base2(filePath) {
22828
22892
  return basename22(filePath).replace(/\.(md|toml)$/, "");
22829
22893
  }
22830
22894
  var init_artifact_codec = __esm({
@@ -23309,11 +23373,11 @@ __export(toolkit_pull_exports, {
23309
23373
  platformRefusal: () => platformRefusal,
23310
23374
  portableCommand: () => portableCommand
23311
23375
  });
23312
- import { existsSync as existsSync48, mkdirSync as mkdirSync16, statSync as statSync41, writeFileSync as writeFileSync16 } from "node:fs";
23376
+ import { existsSync as existsSync48, mkdirSync as mkdirSync16, statSync as statSync42, writeFileSync as writeFileSync16 } from "node:fs";
23313
23377
  import { dirname as dirname23, join as join51, basename as basename24, isAbsolute as isAbsolute3 } from "node:path";
23314
23378
  function isExecutableFile(p) {
23315
23379
  try {
23316
- return statSync41(p).isFile();
23380
+ return statSync42(p).isFile();
23317
23381
  } catch {
23318
23382
  return false;
23319
23383
  }
@@ -23327,9 +23391,9 @@ function portableCommand(cmd) {
23327
23391
  }
23328
23392
  if (isExecutableFile(cmd))
23329
23393
  return { command: cmd, rewritten: false };
23330
- const base3 = basename24(cmd);
23331
- if (onPath(base3))
23332
- return { command: base3, rewritten: true };
23394
+ const base4 = basename24(cmd);
23395
+ if (onPath(base4))
23396
+ return { command: base4, rewritten: true };
23333
23397
  return { missing: cmd };
23334
23398
  }
23335
23399
  function entryFromSpec(spec) {
@@ -24163,8 +24227,8 @@ import { homedir as homedir20 } from "os";
24163
24227
  import { join as join53 } from "path";
24164
24228
  function opencodeConfigDir() {
24165
24229
  const xdg = process.env.XDG_CONFIG_HOME;
24166
- const base3 = xdg && xdg.trim() ? xdg : join53(homedir20(), ".config");
24167
- return join53(base3, "opencode");
24230
+ const base4 = xdg && xdg.trim() ? xdg : join53(homedir20(), ".config");
24231
+ return join53(base4, "opencode");
24168
24232
  }
24169
24233
  function opencodePluginDir() {
24170
24234
  return join53(opencodeConfigDir(), "plugins");
@@ -24751,17 +24815,17 @@ async function collectCode(opts) {
24751
24815
  return r;
24752
24816
  };
24753
24817
  log6(`indexing ${ws} + analyses \u2026`);
24754
- const base3 = await runMcp(bin, ws, [
24818
+ const base4 = await runMcp(bin, ws, [
24755
24819
  call(1, "index_workspace", { path: ws }),
24756
24820
  call(2, "status"),
24757
24821
  call(3, "get_tree"),
24758
24822
  ...ANALYSES.map((a, i) => call(10 + i, "analyze", { analysis: a }))
24759
24823
  ]);
24760
- const st = parseJson(base3, 2, {});
24761
- const tree = parseJson(base3, 3, []);
24824
+ const st = parseJson(base4, 2, {});
24825
+ const tree = parseJson(base4, 3, []);
24762
24826
  const A = {};
24763
24827
  ANALYSES.forEach((a, i) => {
24764
- A[a] = parseJson(base3, 10 + i, {});
24828
+ A[a] = parseJson(base4, 10 + i, {});
24765
24829
  });
24766
24830
  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;
24767
24831
  if (tree.length === 0) {
@@ -25590,7 +25654,7 @@ __export(project_tasks_exports, {
25590
25654
  pushProjectTaskStatuses: () => pushProjectTaskStatuses,
25591
25655
  renderTeamTasksMd: () => renderTeamTasksMd
25592
25656
  });
25593
- import { existsSync as existsSync51, readFileSync as readFileSync44, writeFileSync as writeFileSync18, mkdirSync as mkdirSync18, statSync as statSync42 } from "node:fs";
25657
+ import { existsSync as existsSync51, readFileSync as readFileSync44, writeFileSync as writeFileSync18, mkdirSync as mkdirSync18, statSync as statSync43 } from "node:fs";
25594
25658
  import { join as join55, dirname as dirname25 } from "node:path";
25595
25659
  import { homedir as homedir21 } from "node:os";
25596
25660
  function isTeamTaskStatus(v) {
@@ -25661,14 +25725,14 @@ function writeLedger(l) {
25661
25725
  } catch {
25662
25726
  }
25663
25727
  }
25664
- async function pushProjectTaskStatuses(base3, authHeaders, opts = {}) {
25728
+ async function pushProjectTaskStatuses(base4, authHeaders, opts = {}) {
25665
25729
  const out = { files: 0, pushedTasks: 0 };
25666
25730
  const ledger = readLedger();
25667
25731
  let ledgerDirty = false;
25668
25732
  for (const fk of FILE_KINDS) {
25669
25733
  let projects;
25670
25734
  try {
25671
- const res = await fetchWithTimeout(`${base3}${fk.trackedPath}`, { headers: authHeaders });
25735
+ const res = await fetchWithTimeout(`${base4}${fk.trackedPath}`, { headers: authHeaders });
25672
25736
  if (!res.ok) continue;
25673
25737
  projects = (await res.json()).projects || [];
25674
25738
  } catch {
@@ -25679,7 +25743,7 @@ async function pushProjectTaskStatuses(base3, authHeaders, opts = {}) {
25679
25743
  if (!existsSync51(file)) continue;
25680
25744
  let mtime;
25681
25745
  try {
25682
- mtime = statSync42(file).mtimeMs;
25746
+ mtime = statSync43(file).mtimeMs;
25683
25747
  } catch {
25684
25748
  continue;
25685
25749
  }
@@ -25696,7 +25760,7 @@ async function pushProjectTaskStatuses(base3, authHeaders, opts = {}) {
25696
25760
  continue;
25697
25761
  }
25698
25762
  try {
25699
- const res = await fetchWithTimeout(`${base3}${fk.statusPath}`, {
25763
+ const res = await fetchWithTimeout(`${base4}${fk.statusPath}`, {
25700
25764
  method: "POST",
25701
25765
  headers: { "content-type": "application/json", ...authHeaders },
25702
25766
  body: JSON.stringify({ project, items: changed.map((t) => ({ id: t.id, status: t.intent })) })
@@ -25822,16 +25886,16 @@ ${block}`);
25822
25886
  return { status: "error", result: JSON.stringify({ error: e instanceof Error ? e.message : "failed" }) };
25823
25887
  }
25824
25888
  }
25825
- async function runPull(base3, opts) {
25889
+ async function runPull(base4, opts) {
25826
25890
  const { executePull: executePull2 } = await Promise.resolve().then(() => (init_toolkit_pull(), toolkit_pull_exports));
25827
25891
  const { hostname: hostname3 } = await import("node:os");
25828
- const creds = loadAllCredentials().find((c) => c.serverUrl.replace(/\/+$/, "") === base3.replace(/\/+$/, ""));
25892
+ const creds = loadAllCredentials().find((c) => c.serverUrl.replace(/\/+$/, "") === base4.replace(/\/+$/, ""));
25829
25893
  const headers = creds?.token ? { authorization: `Bearer ${creds.token}` } : {};
25830
25894
  const wanted = opts.types?.length ? opts.types : ["mcp", "skill", "command", "agent", "instructions"];
25831
25895
  const rows = [];
25832
25896
  for (const type of wanted) {
25833
25897
  try {
25834
- const res = await fetchWithTimeout(`${base3}/api/toolkit/browse/${type}?limit=1000`, { headers });
25898
+ const res = await fetchWithTimeout(`${base4}/api/toolkit/browse/${type}?limit=1000`, { headers });
25835
25899
  if (!res.ok) continue;
25836
25900
  const body2 = await res.json();
25837
25901
  for (const it of body2.items || []) rows.push(it);
@@ -25900,20 +25964,20 @@ async function runIntent(intent, ctx) {
25900
25964
  async function drainSyncIntents(opts = {}) {
25901
25965
  const out = { processed: 0, done: 0, errored: 0 };
25902
25966
  for (const cred of loadAllCredentials()) {
25903
- const base3 = cred.serverUrl.replace(/\/+$/, "");
25967
+ const base4 = cred.serverUrl.replace(/\/+$/, "");
25904
25968
  const authHeaders = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
25905
25969
  let pending;
25906
25970
  try {
25907
- const res = await fetchWithTimeout(`${base3}/api/sync-intents/pending`, { headers: authHeaders });
25971
+ const res = await fetchWithTimeout(`${base4}/api/sync-intents/pending`, { headers: authHeaders });
25908
25972
  if (!res.ok) continue;
25909
25973
  const data = await res.json();
25910
25974
  pending = data.intents || [];
25911
25975
  if (data.cli && data.cli.version) {
25912
25976
  const { planAutoUpdate: planAutoUpdate2, runAutoUpdate: runAutoUpdate2, sweepStaleStaging: sweepStaleStaging2 } = await Promise.resolve().then(() => (init_auto_update(), auto_update_exports));
25913
- const plan = planAutoUpdate2(base3, { cli: data.cli }, ownVersion2, process.env.CHAT_RECALL_AUTO_UPDATE);
25977
+ const plan = planAutoUpdate2(base4, { cli: data.cli }, ownVersion2, process.env.CHAT_RECALL_AUTO_UPDATE);
25914
25978
  sweepStaleStaging2();
25915
25979
  if (plan.update) {
25916
- void runAutoUpdate2(base3, authHeaders, ownVersion2).catch(() => {
25980
+ void runAutoUpdate2(base4, authHeaders, ownVersion2).catch(() => {
25917
25981
  });
25918
25982
  }
25919
25983
  }
@@ -25921,7 +25985,7 @@ async function drainSyncIntents(opts = {}) {
25921
25985
  continue;
25922
25986
  }
25923
25987
  for (const intent of pending) {
25924
- const { status, result } = await runIntent(intent, { base: base3 });
25988
+ const { status, result } = await runIntent(intent, { base: base4 });
25925
25989
  out.processed++;
25926
25990
  if (status === "done") out.done++;
25927
25991
  else out.errored++;
@@ -25930,7 +25994,7 @@ async function drainSyncIntents(opts = {}) {
25930
25994
  console.error(`[sync-intent] ${label}: ${status}`);
25931
25995
  }
25932
25996
  try {
25933
- await fetchWithTimeout(`${base3}/api/sync-intents/${intent.id}/ack`, {
25997
+ await fetchWithTimeout(`${base4}/api/sync-intents/${intent.id}/ack`, {
25934
25998
  method: "POST",
25935
25999
  headers: { "content-type": "application/json", ...authHeaders },
25936
26000
  body: JSON.stringify({ status, result })
@@ -25939,7 +26003,7 @@ async function drainSyncIntents(opts = {}) {
25939
26003
  }
25940
26004
  }
25941
26005
  try {
25942
- await pushProjectTaskStatuses(base3, authHeaders, { verbose: opts.verbose });
26006
+ await pushProjectTaskStatuses(base4, authHeaders, { verbose: opts.verbose });
25943
26007
  } catch {
25944
26008
  }
25945
26009
  }
@@ -25979,7 +26043,7 @@ var init_intent_drain = __esm({
25979
26043
  ownVersion2 = JSON.parse(readFileSync45(join56(dir, "../package.json"), "utf-8")).version || ownVersion2;
25980
26044
  } catch {
25981
26045
  try {
25982
- if (true) ownVersion2 = "0.7.13";
26046
+ if (true) ownVersion2 = "0.7.15";
25983
26047
  } catch {
25984
26048
  }
25985
26049
  }
@@ -26180,7 +26244,7 @@ var team_merge_exports = {};
26180
26244
  __export(team_merge_exports, {
26181
26245
  mergePullResult: () => mergePullResult
26182
26246
  });
26183
- import { existsSync as existsSync53, mkdirSync as mkdirSync20, readFileSync as readFileSync46, rmSync as rmSync8, writeFileSync as writeFileSync20, statSync as statSync43 } from "fs";
26247
+ import { existsSync as existsSync53, mkdirSync as mkdirSync20, readFileSync as readFileSync46, rmSync as rmSync8, writeFileSync as writeFileSync20, statSync as statSync44 } from "fs";
26184
26248
  import { dirname as dirname27, join as join57 } from "path";
26185
26249
  import { createHash as createHash14 } from "crypto";
26186
26250
  function installPathFor(art, tool) {
@@ -26317,7 +26381,7 @@ function readFileIfExists(path) {
26317
26381
  try {
26318
26382
  if (!existsSync53(path))
26319
26383
  return null;
26320
- const s = statSync43(path);
26384
+ const s = statSync44(path);
26321
26385
  if (!s.isFile())
26322
26386
  return null;
26323
26387
  return readFileSync46(path);
@@ -26401,7 +26465,7 @@ var init_vault_crypto = __esm({
26401
26465
  });
26402
26466
 
26403
26467
  // ../engine/dist/core/vault-source.js
26404
- import { existsSync as existsSync54, readdirSync as readdirSync33, statSync as statSync44 } from "fs";
26468
+ import { existsSync as existsSync54, readdirSync as readdirSync33, statSync as statSync45 } from "fs";
26405
26469
  import { extname, join as join58 } from "path";
26406
26470
  function* walkVaultSources() {
26407
26471
  const t = loadSettings().team.vault;
@@ -26417,7 +26481,7 @@ function* walkVaultSources() {
26417
26481
  }
26418
26482
  function safeStat(path) {
26419
26483
  try {
26420
- const s = statSync44(path);
26484
+ const s = statSync45(path);
26421
26485
  if (!s.isFile())
26422
26486
  return null;
26423
26487
  return { mtimeMs: s.mtimeMs, size: s.size };
@@ -26502,8 +26566,8 @@ function* walkCodex() {
26502
26566
  const s = safeStat(path);
26503
26567
  if (!s)
26504
26568
  continue;
26505
- const base3 = e.name.replace(/\.jsonl$/, "");
26506
- yield { sessionId: `codex_${base3}`, tool: "codex", path, mtimeMs: s.mtimeMs, sizeBytes: s.size };
26569
+ const base4 = e.name.replace(/\.jsonl$/, "");
26570
+ yield { sessionId: `codex_${base4}`, tool: "codex", path, mtimeMs: s.mtimeMs, sizeBytes: s.size };
26507
26571
  }
26508
26572
  }
26509
26573
  }
@@ -26520,7 +26584,7 @@ function* walkAgy() {
26520
26584
  for (const rawId of sessionDirs) {
26521
26585
  const sessionPath = join58(brainDir, rawId);
26522
26586
  try {
26523
- if (!statSync44(sessionPath).isDirectory())
26587
+ if (!statSync45(sessionPath).isDirectory())
26524
26588
  continue;
26525
26589
  } catch {
26526
26590
  continue;
@@ -26645,11 +26709,11 @@ function vaultEnable(passphrase, opts = {}) {
26645
26709
  }
26646
26710
  async function vaultEnableWithRemote(passphrase, remote, opts = {}) {
26647
26711
  const doFetch = opts.fetchImpl ?? fetch;
26648
- const base3 = remote.baseUrl.replace(/\/+$/, "");
26712
+ const base4 = remote.baseUrl.replace(/\/+$/, "");
26649
26713
  const headers = { authorization: `Bearer ${remote.token}`, "content-type": "application/json" };
26650
26714
  let published = { saltHex: null, keyId: null };
26651
26715
  try {
26652
- const r = await doFetch(`${base3}/api/vault/salt`, { headers });
26716
+ const r = await doFetch(`${base4}/api/vault/salt`, { headers });
26653
26717
  if (r.ok)
26654
26718
  published = await r.json();
26655
26719
  } catch {
@@ -26663,7 +26727,7 @@ async function vaultEnableWithRemote(passphrase, remote, opts = {}) {
26663
26727
  }
26664
26728
  const result = vaultEnable(passphrase);
26665
26729
  try {
26666
- const r = await doFetch(`${base3}/api/vault/salt`, {
26730
+ const r = await doFetch(`${base4}/api/vault/salt`, {
26667
26731
  method: "POST",
26668
26732
  headers,
26669
26733
  body: JSON.stringify({ saltHex: result.saltHex, keyId: result.keyId })
@@ -26756,8 +26820,8 @@ async function vaultSync(passphrase) {
26756
26820
  return report;
26757
26821
  }
26758
26822
  function importedPathFor(tool, sessionId) {
26759
- const base3 = sessionId.replace(/^gemini_/, "").replace(/^codex_/, "").replace(/^agy_/, "").replace(/^cursor_/, "").replace(/^opencode_/, "");
26760
- return join59(IMPORTED_ROOT(), tool, `${base3}.jsonl`);
26823
+ const base4 = sessionId.replace(/^gemini_/, "").replace(/^codex_/, "").replace(/^agy_/, "").replace(/^cursor_/, "").replace(/^opencode_/, "");
26824
+ return join59(IMPORTED_ROOT(), tool, `${base4}.jsonl`);
26761
26825
  }
26762
26826
  async function vaultRestore(passphrase, opts = {}) {
26763
26827
  const ctx = context2();
@@ -27158,8 +27222,8 @@ var init_decision_guard = __esm({
27158
27222
  isManifest = (p) => {
27159
27223
  if (!p)
27160
27224
  return false;
27161
- const base3 = p.split(/[\\/]/).pop()?.toLowerCase() ?? "";
27162
- return MANIFESTS.includes(base3);
27225
+ const base4 = p.split(/[\\/]/).pop()?.toLowerCase() ?? "";
27226
+ return MANIFESTS.includes(base4);
27163
27227
  };
27164
27228
  }
27165
27229
  });
@@ -27757,8 +27821,8 @@ async function deviceLogin(opts, onPrompt) {
27757
27821
  throw new Error("device-auth timed out \u2014 the code expired before approval.");
27758
27822
  }
27759
27823
  async function betterAuthDeviceLogin(serverUrl, onPrompt) {
27760
- const base3 = serverUrl.replace(/\/+$/, "");
27761
- const startRes = await fetch(`${base3}/api/auth/device/code`, {
27824
+ const base4 = serverUrl.replace(/\/+$/, "");
27825
+ const startRes = await fetch(`${base4}/api/auth/device/code`, {
27762
27826
  method: "POST",
27763
27827
  headers: { "content-type": "application/json" },
27764
27828
  body: JSON.stringify({ client_id: BETTER_AUTH_CLI_CLIENT_ID })
@@ -27766,7 +27830,7 @@ async function betterAuthDeviceLogin(serverUrl, onPrompt) {
27766
27830
  if (!startRes.ok) {
27767
27831
  throw new Error(`device-auth init failed: HTTP ${startRes.status} ${await startRes.text().catch(() => "")}`);
27768
27832
  }
27769
- const start = await readDeviceCode(startRes, base3);
27833
+ const start = await readDeviceCode(startRes, base4);
27770
27834
  onPrompt({
27771
27835
  url: start.verification_uri_complete || start.verification_uri,
27772
27836
  userCode: start.user_code,
@@ -27776,7 +27840,7 @@ async function betterAuthDeviceLogin(serverUrl, onPrompt) {
27776
27840
  let interval = (start.interval ?? 5) * 1e3;
27777
27841
  while (Date.now() < deadline) {
27778
27842
  await sleep(interval);
27779
- const res = await fetch(`${base3}/api/auth/device/token`, {
27843
+ const res = await fetch(`${base4}/api/auth/device/token`, {
27780
27844
  method: "POST",
27781
27845
  headers: { "content-type": "application/json" },
27782
27846
  body: JSON.stringify({
@@ -27878,7 +27942,7 @@ async function selectSessions(target, opts, fetchImpl = fetch) {
27878
27942
  const qs = new URLSearchParams({ limit: String(PAGE), offset: String(offset) });
27879
27943
  if (opts.project) qs.set("project", opts.project);
27880
27944
  if (opts.tool) qs.set("tool", opts.tool);
27881
- const res = await fetchImpl(`${base2(target.serverUrl)}/api/conversations/recent?${qs}`, {
27945
+ const res = await fetchImpl(`${base3(target.serverUrl)}/api/conversations/recent?${qs}`, {
27882
27946
  headers: { authorization: `Bearer ${target.token}` }
27883
27947
  });
27884
27948
  if (!res.ok) throw new Error(`list failed: HTTP ${res.status}`);
@@ -27907,7 +27971,7 @@ async function bulkDelete(ids, opts = {}) {
27907
27971
  try {
27908
27972
  for (let i = 0; i < unique.length; i += BATCH) {
27909
27973
  const slice = unique.slice(i, i + BATCH);
27910
- const res = await fetchImpl(`${base2(t.serverUrl)}/api/sync`, {
27974
+ const res = await fetchImpl(`${base3(t.serverUrl)}/api/sync`, {
27911
27975
  method: "POST",
27912
27976
  headers: { "content-type": "application/json", authorization: `Bearer ${t.token}` },
27913
27977
  body: JSON.stringify({
@@ -27943,7 +28007,7 @@ async function bulkDelete(ids, opts = {}) {
27943
28007
  return out;
27944
28008
  }
27945
28009
  async function listTombstones(target, limit = 500, fetchImpl = fetch) {
27946
- const res = await fetchImpl(`${base2(target.serverUrl)}/api/data/tombstones?limit=${limit}`, {
28010
+ const res = await fetchImpl(`${base3(target.serverUrl)}/api/data/tombstones?limit=${limit}`, {
27947
28011
  headers: { authorization: `Bearer ${target.token}` }
27948
28012
  });
27949
28013
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
@@ -27960,7 +28024,7 @@ async function restoreSessions(ids, opts = {}) {
27960
28024
  try {
27961
28025
  let restored = 0, notDeleted = 0;
27962
28026
  for (let i = 0; i < unique.length; i += BATCH) {
27963
- const res = await fetchImpl(`${base2(t.serverUrl)}/api/data/restore`, {
28027
+ const res = await fetchImpl(`${base3(t.serverUrl)}/api/data/restore`, {
27964
28028
  method: "POST",
27965
28029
  headers: { "content-type": "application/json", authorization: `Bearer ${t.token}` },
27966
28030
  body: JSON.stringify({ session_ids: unique.slice(i, i + BATCH) })
@@ -27983,7 +28047,7 @@ function needsConfirmation(opts) {
27983
28047
  const enumeratedByCaller = opts.argvIds > 0 && !opts.project && !opts.stdin;
27984
28048
  return !enumeratedByCaller;
27985
28049
  }
27986
- var PAGE, BATCH, base2;
28050
+ var PAGE, BATCH, base3;
27987
28051
  var init_bulk_delete = __esm({
27988
28052
  "src/bulk-delete.ts"() {
27989
28053
  "use strict";
@@ -27991,7 +28055,7 @@ var init_bulk_delete = __esm({
27991
28055
  init_sync_ledger();
27992
28056
  PAGE = 200;
27993
28057
  BATCH = 250;
27994
- base2 = (url) => url.replace(/\/+$/, "");
28058
+ base3 = (url) => url.replace(/\/+$/, "");
27995
28059
  }
27996
28060
  });
27997
28061
 
@@ -28356,13 +28420,13 @@ function requireTarget() {
28356
28420
  }
28357
28421
  return t;
28358
28422
  }
28359
- async function readJsonBody(res, base3, what) {
28423
+ async function readJsonBody(res, base4, what) {
28360
28424
  const text = await res.text().catch(() => "");
28361
28425
  try {
28362
28426
  return JSON.parse(text);
28363
28427
  } catch {
28364
28428
  throw new Error(
28365
- `${base3} answered ${res.status} with something that is not JSON (${JSON.stringify(text.trim().slice(0, 60))}) for ${what} \u2014 a proxy, a captive portal or a host that no longer serves the chat-recall API`
28429
+ `${base4} answered ${res.status} with something that is not JSON (${JSON.stringify(text.trim().slice(0, 60))}) for ${what} \u2014 a proxy, a captive portal or a host that no longer serves the chat-recall API`
28366
28430
  );
28367
28431
  }
28368
28432
  }
@@ -29168,9 +29232,9 @@ program.command("feedback").argument("<message...>", "what you want to say \u201
29168
29232
  return;
29169
29233
  }
29170
29234
  const target = firstTarget();
29171
- const base3 = target?.base || (process.env.CHAT_RECALL_SERVER || "https://chatrecall.dev").replace(/\/+$/, "");
29235
+ const base4 = target?.base || (process.env.CHAT_RECALL_SERVER || "https://chatrecall.dev").replace(/\/+$/, "");
29172
29236
  try {
29173
- const res = await fetch(`${base3}/api/contact/feedback`, {
29237
+ const res = await fetch(`${base4}/api/contact/feedback`, {
29174
29238
  method: "POST",
29175
29239
  headers: {
29176
29240
  "content-type": "application/json",
@@ -29197,14 +29261,14 @@ program.command("feedback").argument("<message...>", "what you want to say \u201
29197
29261
  console.log(chalk2.dim(" Add --email <address> next time if you want a reply."));
29198
29262
  }
29199
29263
  } catch (err) {
29200
- console.error(chalk2.red(`Could not reach ${base3}.`));
29264
+ console.error(chalk2.red(`Could not reach ${base4}.`));
29201
29265
  console.error(chalk2.dim(" Your message, so it is not lost:"));
29202
29266
  console.error(chalk2.dim(` ${message}`));
29203
29267
  process.exitCode = 1;
29204
29268
  }
29205
29269
  });
29206
29270
  program.command("doctor").description("Quick health check across login, server, credentials, hooks, MCP server, and codeindex").option("--purge-local", "Remove the legacy local index (cache.db + vector/KG files) left by pre-thin-collector versions \u2014 storage is server-side now. Requires login; keeps credentials, sync ledger, identity, and the audit log.").action(async (opts) => {
29207
- const { existsSync: existsSync58, readFileSync: readFileSync50, statSync: statSync45 } = await import("fs");
29271
+ const { existsSync: existsSync58, readFileSync: readFileSync50, statSync: statSync46 } = await import("fs");
29208
29272
  const { execSync: execSync6 } = await import("child_process");
29209
29273
  const rows = [];
29210
29274
  const note = (ok, label, detail) => rows.push({ ok, label, detail });
@@ -29272,7 +29336,7 @@ program.command("doctor").description("Quick health check across login, server,
29272
29336
  note(false, "Credentials file", `missing \u2014 run \`chat-recall login <server-url>\``);
29273
29337
  } else {
29274
29338
  try {
29275
- const mode = statSync45(credFile).mode & 511;
29339
+ const mode = statSync46(credFile).mode & 511;
29276
29340
  const isWin = process.platform === "win32";
29277
29341
  const safe = isWin || (mode & 63) === 0;
29278
29342
  note(safe, "Credentials file", isWin ? `${credFile} (Windows ACL \u2014 POSIX mode does not apply)` : `${credFile} (mode ${mode.toString(8).padStart(3, "0")}${safe ? "" : " \u2014 should be 600"})`);
@@ -29802,13 +29866,13 @@ sources2.command("decline <path>").description("Keep a folder out of sync (e.g.
29802
29866
  }
29803
29867
  const { fetchWithTimeout: fetchWithTimeout2 } = await Promise.resolve().then(() => (init_http(), http_exports));
29804
29868
  for (const t of targets) {
29805
- const base3 = t.serverUrl.replace(/\/+$/, "");
29869
+ const base4 = t.serverUrl.replace(/\/+$/, "");
29806
29870
  const headers = {};
29807
29871
  if (t.token) headers.authorization = `Bearer ${t.token}`;
29808
29872
  let deleted = 0, missing = 0, failed = 0;
29809
29873
  for (const id of ids) {
29810
29874
  try {
29811
- const res = await fetchWithTimeout2(`${base3}/api/conversations/${encodeURIComponent(id)}`, { method: "DELETE", headers }, 3e4);
29875
+ const res = await fetchWithTimeout2(`${base4}/api/conversations/${encodeURIComponent(id)}`, { method: "DELETE", headers }, 3e4);
29812
29876
  if (res.ok) deleted++;
29813
29877
  else if (res.status === 404) missing++;
29814
29878
  else failed++;
@@ -29816,7 +29880,7 @@ sources2.command("decline <path>").description("Keep a folder out of sync (e.g.
29816
29880
  failed++;
29817
29881
  }
29818
29882
  }
29819
- const line = ` ${base3}: deleted ${deleted}` + (missing ? `, ${missing} were not there` : "") + (failed ? chalk2.red(`, ${failed} FAILED`) : "");
29883
+ const line = ` ${base4}: deleted ${deleted}` + (missing ? `, ${missing} were not there` : "") + (failed ? chalk2.red(`, ${failed} FAILED`) : "");
29820
29884
  console.log(failed ? chalk2.yellow(line) : chalk2.green(line));
29821
29885
  if (failed) process.exitCode = 1;
29822
29886
  }
@@ -30598,7 +30662,7 @@ program.command("task-hook").description("Move a board card when a prompt or a c
30598
30662
  }
30599
30663
  });
30600
30664
  program.command("install-hooks").description("Install Claude Code hooks (Stop + PreCompact + UserPromptSubmit + SessionEnd + SessionStart) into every Claude profile").option("--uninstall", "Remove hooks instead of installing them").option("--no-resume-hint", "Don't install the UserPromptSubmit resume-hint hook").option("--no-escalate", "Don't install the SessionEnd learnings-escalation hook").option("--no-wakeup", "Don't install the SessionStart wake-up hook").option("--no-guard", "Don't install the PreToolUse decision guard").option("--no-task-board", "Don't install the hooks that claim and close board cards").action(async (opts) => {
30601
- const { mkdirSync: mkdirSync23, copyFileSync: copyFileSync4, chmodSync: chmodSync5, existsSync: existsSync58, readFileSync: readFileSync50, writeFileSync: writeFileSync24, statSync: statSync45, unlinkSync: unlinkSync4 } = await import("fs");
30665
+ const { mkdirSync: mkdirSync23, copyFileSync: copyFileSync4, chmodSync: chmodSync5, existsSync: existsSync58, readFileSync: readFileSync50, writeFileSync: writeFileSync24, statSync: statSync46, unlinkSync: unlinkSync4 } = await import("fs");
30602
30666
  const { fileURLToPath: fileURLToPath6 } = await import("url");
30603
30667
  const { boardHookEntries: boardHookEntries2, isBoardHookEntry: isBoardHookEntry2, registerBoardHooks: registerBoardHooks2, resolveCliEntry: resolveCliEntry2 } = await Promise.resolve().then(() => (init_board_hooks(), board_hooks_exports));
30604
30668
  const here = fileURLToPath6(new URL(".", import.meta.url));
@@ -30813,18 +30877,18 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
30813
30877
  writeFileSync24(hooksJson, JSON.stringify(config2, null, 2) + "\n");
30814
30878
  }
30815
30879
  if (installGuard) await addGuardToOtherTools(installedGuardHook);
30816
- const saveSz = statSync45(installedSaveHook).size;
30880
+ const saveSz = statSync46(installedSaveHook).size;
30817
30881
  console.log(chalk2.green(`\u2713 Installed chat-recall save hook (${saveSz} bytes)`));
30818
30882
  if (installResume) {
30819
- const resumeSz = statSync45(installedResumeHook).size;
30883
+ const resumeSz = statSync46(installedResumeHook).size;
30820
30884
  console.log(chalk2.green(`\u2713 Installed chat-recall resume-hint hook (${resumeSz} bytes)`));
30821
30885
  }
30822
30886
  if (installEscalate) {
30823
- const escalateSz = statSync45(installedEscalateHook).size;
30887
+ const escalateSz = statSync46(installedEscalateHook).size;
30824
30888
  console.log(chalk2.green(`\u2713 Installed chat-recall learnings-escalation hook (${escalateSz} bytes)`));
30825
30889
  }
30826
30890
  if (installGuard) {
30827
- const guardSz = statSync45(installedGuardHook).size;
30891
+ const guardSz = statSync46(installedGuardHook).size;
30828
30892
  console.log(chalk2.green(`\u2713 Installed chat-recall decision guard (${guardSz} bytes)`));
30829
30893
  }
30830
30894
  if (installTaskBoard) {
@@ -30832,7 +30896,7 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
30832
30896
  console.log(chalk2.dim(" A prompt naming a card id claims it; a commit message naming one closes it."));
30833
30897
  }
30834
30898
  if (installWakeup) {
30835
- const wakeupSz = statSync45(installedWakeupHook).size;
30899
+ const wakeupSz = statSync46(installedWakeupHook).size;
30836
30900
  console.log(chalk2.green(`\u2713 Installed chat-recall wake-up hook (${wakeupSz} bytes)`));
30837
30901
  for (const f of wakeupSkipped) {
30838
30902
  console.log(chalk2.dim(` (SessionStart already wired in ${f} \u2014 left as is, not duplicated)`));
@@ -30949,10 +31013,10 @@ program.command("service <action>").description("Manage the per-user background
30949
31013
  });
30950
31014
  async function runLogin(serverUrl, opts) {
30951
31015
  const { saveCredentials: saveCredentials2, loadAllCredentials: loadAllCredentials2 } = await Promise.resolve().then(() => (init_sync_client(), sync_client_exports));
30952
- const base3 = serverUrl.replace(/\/+$/, "");
31016
+ const base4 = serverUrl.replace(/\/+$/, "");
30953
31017
  const verifyToken = async (token) => {
30954
31018
  try {
30955
- const res = await fetch(`${base3}/api/status`, {
31019
+ const res = await fetch(`${base4}/api/status`, {
30956
31020
  headers: token ? { authorization: `Bearer ${token}` } : {},
30957
31021
  signal: AbortSignal.timeout(1e4)
30958
31022
  });
@@ -30968,36 +31032,36 @@ async function runLogin(serverUrl, opts) {
30968
31032
  return failLogin(opts, 'the token contains non-ASCII characters \u2014 this looks like a masked/truncated copy (e.g. "ct_12345678\u2026")');
30969
31033
  }
30970
31034
  const { probeServer: identifyServer, probeOk: identified, probeAdvice: identifyAdvice } = await Promise.resolve().then(() => (init_server_probe(), server_probe_exports));
30971
- const who = await identifyServer(base3, { timeoutMs: 1e4 });
30972
- if (!identified(who)) return failLogin(opts, identifyAdvice(who, base3));
31035
+ const who = await identifyServer(base4, { timeoutMs: 1e4 });
31036
+ if (!identified(who)) return failLogin(opts, identifyAdvice(who, base4));
30973
31037
  const check = await verifyToken(token);
30974
31038
  if (!check.ok) {
30975
31039
  if (check.status === 401 || check.status === 403) {
30976
31040
  console.error(chalk2.dim("Tokens are shown once \u2014 mint a fresh one (Account \u2192 Connect your machine) and copy the whole line."));
30977
- return failLogin(opts, `${base3} rejected the token (HTTP ${check.status})`);
31041
+ return failLogin(opts, `${base4} rejected the token (HTTP ${check.status})`);
30978
31042
  }
30979
31043
  if (check.status !== void 0 && check.status >= 500) {
30980
- return failLogin(opts, `${base3} answered HTTP ${check.status} \u2014 the server is up but failing. The token was never checked. Nothing to fix locally.`);
31044
+ return failLogin(opts, `${base4} answered HTTP ${check.status} \u2014 the server is up but failing. The token was never checked. Nothing to fix locally.`);
30981
31045
  }
30982
31046
  if (check.status === 404 || check.status === 410) {
30983
- return failLogin(opts, `${base3} does not serve the chat-recall API (HTTP ${check.status}). If the server moved, log in to its new URL.`);
31047
+ return failLogin(opts, `${base4} does not serve the chat-recall API (HTTP ${check.status}). If the server moved, log in to its new URL.`);
30984
31048
  }
30985
- return failLogin(opts, `could not verify the token against ${base3}: ${check.error || `HTTP ${check.status}`}`);
31049
+ return failLogin(opts, `could not verify the token against ${base4}: ${check.error || `HTTP ${check.status}`}`);
30986
31050
  }
30987
31051
  saveCredentials2({ serverUrl, token });
30988
31052
  console.log(chalk2.green("\u2713 Logged in.") + chalk2.dim(` server: ${serverUrl} (token verified)`));
30989
31053
  return;
30990
31054
  }
30991
- const existing = loadAllCredentials2().find((t) => t.serverUrl.replace(/\/+$/, "") === base3);
31055
+ const existing = loadAllCredentials2().find((t) => t.serverUrl.replace(/\/+$/, "") === base4);
30992
31056
  if (existing && (await verifyToken(existing.token)).ok) {
30993
31057
  console.log(chalk2.green("\u2713 Already connected.") + chalk2.dim(` server: ${serverUrl} (existing token verified)`));
30994
31058
  return;
30995
31059
  }
30996
31060
  try {
30997
31061
  const { probeServer: probeServer2, probeOk: probeOk2 } = await Promise.resolve().then(() => (init_server_probe(), server_probe_exports));
30998
- const identified = await probeServer2(base3, { timeoutMs: 8e3 });
31062
+ const identified = await probeServer2(base4, { timeoutMs: 8e3 });
30999
31063
  if (probeOk2(identified)) {
31000
- const probe = await fetch(`${base3}/api/status`, { signal: AbortSignal.timeout(8e3) });
31064
+ const probe = await fetch(`${base4}/api/status`, { signal: AbortSignal.timeout(8e3) });
31001
31065
  if (probe.status === 200) {
31002
31066
  saveCredentials2({ serverUrl, token: "" });
31003
31067
  console.log(chalk2.green("\u2713 Logged in.") + chalk2.dim(` ${serverUrl} (local server \u2014 no auth, no token needed)`));
@@ -31018,16 +31082,16 @@ async function runLogin(serverUrl, opts) {
31018
31082
  if (!issuer) {
31019
31083
  const { probeServer: probeServer2, probeOk: probeOk2, probeAdvice: probeAdvice2 } = await Promise.resolve().then(() => (init_server_probe(), server_probe_exports));
31020
31084
  for (let attempt = 1; attempt <= 3 && !authProvider; attempt++) {
31021
- const probe = await probeServer2(base3, { timeoutMs: 15e3 });
31085
+ const probe = await probeServer2(base4, { timeoutMs: 15e3 });
31022
31086
  if (probeOk2(probe)) {
31023
31087
  const caps = probe.raw;
31024
31088
  authProvider = caps?.authProvider;
31025
31089
  if (caps?.oidcIssuer) issuer = caps.oidcIssuer;
31026
31090
  capsError = null;
31027
31091
  } else if (probe.kind === "moved" || probe.kind === "not_api") {
31028
- return failLogin(opts, probeAdvice2(probe, base3));
31092
+ return failLogin(opts, probeAdvice2(probe, base4));
31029
31093
  } else {
31030
- capsError = probeAdvice2(probe, base3);
31094
+ capsError = probeAdvice2(probe, base4);
31031
31095
  }
31032
31096
  if (!authProvider && attempt < 3) await new Promise((r) => setTimeout(r, attempt * 1e3));
31033
31097
  }
@@ -31036,7 +31100,7 @@ async function runLogin(serverUrl, opts) {
31036
31100
  authProvider = "better-auth";
31037
31101
  if (capsError) {
31038
31102
  console.log(` ${chalk2.yellow("Could not read the server's capabilities")} (${capsError}) \u2014 assuming the standard sign-in flow.`);
31039
- void Promise.resolve().then(() => (init_install_report(), install_report_exports)).then(({ reportInstallFailure: reportInstallFailure2 }) => reportInstallFailure2(base3, {
31103
+ void Promise.resolve().then(() => (init_install_report(), install_report_exports)).then(({ reportInstallFailure: reportInstallFailure2 }) => reportInstallFailure2(base4, {
31040
31104
  step: "cli_login_probe",
31041
31105
  reason: capsError?.slice(0, 40) ?? null,
31042
31106
  message: capsError
@@ -31058,20 +31122,20 @@ async function runLogin(serverUrl, opts) {
31058
31122
  console.log(chalk2.dim(` If the page asks for a code: ${chalk2.bold(p.userCode)}`));
31059
31123
  console.log(chalk2.dim("Then come back here \u2014 this finishes on its own. Waiting\u2026"));
31060
31124
  };
31061
- const tokens = authProvider === "better-auth" ? await betterAuthDeviceLogin2(base3, onPrompt) : await deviceLogin2({ issuer, clientId: opts.clientId }, onPrompt);
31125
+ const tokens = authProvider === "better-auth" ? await betterAuthDeviceLogin2(base4, onPrompt) : await deviceLogin2({ issuer, clientId: opts.clientId }, onPrompt);
31062
31126
  const authHdr = { authorization: `Bearer ${tokens.accessToken}`, "content-type": "application/json" };
31063
- const meRes = await fetch(`${base3}/api/me`, { headers: authHdr });
31064
- if (!meRes.ok) throw new Error(`${base3}/api/me: HTTP ${meRes.status} ${await meRes.text().catch(() => "")}`);
31065
- const me = await readJsonBody(meRes, base3, "GET /api/me");
31127
+ const meRes = await fetch(`${base4}/api/me`, { headers: authHdr });
31128
+ if (!meRes.ok) throw new Error(`${base4}/api/me: HTTP ${meRes.status} ${await meRes.text().catch(() => "")}`);
31129
+ const me = await readJsonBody(meRes, base4, "GET /api/me");
31066
31130
  const teams = me.teams || [];
31067
31131
  let slug = opts.team;
31068
31132
  if (!slug) {
31069
31133
  if (teams.length === 1) slug = teams[0].team_slug;
31070
31134
  else if (teams.length === 0) {
31071
31135
  const name = me.user?.email?.split("@")[0]?.replace(/[^a-z0-9]/gi, "") || "workspace";
31072
- const created = await fetch(`${base3}/api/teams`, { method: "POST", headers: authHdr, body: JSON.stringify({ name }) });
31136
+ const created = await fetch(`${base4}/api/teams`, { method: "POST", headers: authHdr, body: JSON.stringify({ name }) });
31073
31137
  if (!created.ok) throw new Error(`workspace create failed: HTTP ${created.status} ${await created.text().catch(() => "")}`);
31074
- slug = (await readJsonBody(created, base3, "POST /api/teams")).slug;
31138
+ slug = (await readJsonBody(created, base4, "POST /api/teams")).slug;
31075
31139
  console.log(chalk2.dim(`Created workspace "${name}" (${slug}) \u2014 you're its owner.`));
31076
31140
  } else {
31077
31141
  teams.forEach((t) => console.error(` ${t.team_slug} ${chalk2.dim(t.name)}`));
@@ -31079,13 +31143,13 @@ async function runLogin(serverUrl, opts) {
31079
31143
  }
31080
31144
  }
31081
31145
  const deviceId = opts.deviceId || (await import("node:os")).hostname();
31082
- const mint = await fetch(`${base3}/api/teams/${encodeURIComponent(slug)}/tokens`, {
31146
+ const mint = await fetch(`${base4}/api/teams/${encodeURIComponent(slug)}/tokens`, {
31083
31147
  method: "POST",
31084
31148
  headers: authHdr,
31085
31149
  body: JSON.stringify({ device_id: deviceId })
31086
31150
  });
31087
31151
  if (!mint.ok) throw new Error(`token mint failed: HTTP ${mint.status} ${await mint.text().catch(() => "")}`);
31088
- const { token } = await readJsonBody(mint, base3, "POST /api/teams/:slug/tokens");
31152
+ const { token } = await readJsonBody(mint, base4, "POST /api/teams/:slug/tokens");
31089
31153
  saveCredentials2({ serverUrl, token });
31090
31154
  console.log(chalk2.green(`\u2713 Logged in to ${chalk2.bold(slug)}`) + chalk2.dim(` (device: ${deviceId}) server: ${serverUrl}`));
31091
31155
  if (!opts.fromInit) {
@@ -31562,16 +31626,16 @@ program.command("update").description("Update this CLI now from the server you s
31562
31626
  }
31563
31627
  let installFailed = false;
31564
31628
  for (const cred of targets) {
31565
- const base3 = cred.serverUrl.replace(/\/+$/, "");
31629
+ const base4 = cred.serverUrl.replace(/\/+$/, "");
31566
31630
  const headers = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
31567
- const r = await runAutoUpdate2(base3, headers, cliVersion3());
31631
+ const r = await runAutoUpdate2(base4, headers, cliVersion3());
31568
31632
  if (r.updated) {
31569
- console.log(chalk2.green(`\u2713 ${r.reason}`) + chalk2.dim(` (${base3})`));
31633
+ console.log(chalk2.green(`\u2713 ${r.reason}`) + chalk2.dim(` (${base4})`));
31570
31634
  continue;
31571
31635
  }
31572
31636
  const benign = /already current|no CLI release|disabled/.test(r.reason);
31573
31637
  if (/install failed|download failed|checksum/.test(r.reason)) installFailed = true;
31574
- console.log((benign ? chalk2.dim("\u2022 ") : chalk2.red("\u2717 ")) + r.reason + chalk2.dim(` (${base3})`));
31638
+ console.log((benign ? chalk2.dim("\u2022 ") : chalk2.red("\u2717 ")) + r.reason + chalk2.dim(` (${base4})`));
31575
31639
  }
31576
31640
  const check = await refreshUpdateCheck2(true);
31577
31641
  if (installFailed) {