chat-recall 0.7.14 → 0.7.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/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);
@@ -12776,8 +12776,8 @@ function _clearServerRulePack() {
12776
12776
  serverPack = null;
12777
12777
  }
12778
12778
  function activeRules() {
12779
- const base3 = settingsView().rules;
12780
- 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;
12781
12781
  }
12782
12782
  function isRedactionEnabled() {
12783
12783
  const env = isEnvRedactionRequested();
@@ -18535,7 +18535,7 @@ var init_extractor_version = __esm({
18535
18535
  });
18536
18536
 
18537
18537
  // src/sync-ledger.ts
18538
- 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";
18539
18539
  import { join as join38, dirname as dirname15 } from "node:path";
18540
18540
  function toRow(entry) {
18541
18541
  if (entry === void 0) return void 0;
@@ -18544,32 +18544,94 @@ function toRow(entry) {
18544
18544
  function ledgerFilePath() {
18545
18545
  return ledgerPath();
18546
18546
  }
18547
- function load() {
18548
- if (cache3) return cache3;
18547
+ function stampOf(path) {
18549
18548
  try {
18550
- const parsed = JSON.parse(readFileSync29(ledgerPath(), "utf-8"));
18551
- cache3 = parsed && typeof parsed === "object" ? parsed : {};
18549
+ const st = statSync35(path);
18550
+ return `${st.mtimeMs}:${st.size}`;
18552
18551
  } catch {
18553
- cache3 = {};
18552
+ return null;
18554
18553
  }
18554
+ }
18555
+ function readDisk(path) {
18556
+ try {
18557
+ const parsed = JSON.parse(readFileSync29(path, "utf-8"));
18558
+ return parsed && typeof parsed === "object" ? parsed : {};
18559
+ } catch {
18560
+ return {};
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;
18555
18614
  return cache3;
18556
18615
  }
18557
- function persistNow(data) {
18616
+ function persistNow() {
18558
18617
  const path = ledgerPath();
18559
18618
  mkdirSync6(dirname15(path), { recursive: true });
18560
- const tmp = `${path}.tmp`;
18561
- writeFileSync5(tmp, JSON.stringify(data));
18619
+ load();
18620
+ const tmp = `${path}.tmp-${process.pid}`;
18621
+ writeFileSync5(tmp, JSON.stringify(cache3 ?? {}));
18562
18622
  renameSync4(tmp, path);
18623
+ base = snapshot(cache3 ?? {});
18624
+ diskStamp = stampOf(path);
18563
18625
  pendingWrite = false;
18564
18626
  }
18565
- function persist(data) {
18627
+ function persist(_data) {
18566
18628
  pendingWrite = true;
18567
18629
  if (flushTimer) return;
18568
18630
  flushTimer = setTimeout(() => {
18569
18631
  flushTimer = null;
18570
18632
  if (pendingWrite) {
18571
18633
  try {
18572
- persistNow(data);
18634
+ persistNow();
18573
18635
  } catch {
18574
18636
  }
18575
18637
  }
@@ -18603,7 +18665,7 @@ function pruneLedgerTargets(configuredServers) {
18603
18665
  }
18604
18666
  const rows = names.reduce((n, s) => n + Object.keys(orphans[s]).length, 0);
18605
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.`);
18606
- persistNow(data);
18668
+ persistNow();
18607
18669
  return names.length;
18608
18670
  }
18609
18671
  function flushLedger() {
@@ -18612,7 +18674,7 @@ function flushLedger() {
18612
18674
  flushTimer = null;
18613
18675
  }
18614
18676
  if (!pendingWrite || !cache3) return;
18615
- persistNow(cache3);
18677
+ persistNow();
18616
18678
  }
18617
18679
  function loadItemVersionsAll() {
18618
18680
  if (itemVersionsCache) return itemVersionsCache;
@@ -18688,13 +18750,13 @@ function markSynced(server, rows) {
18688
18750
  const o = (cursorFromCaller ? r.offset : void 0) ?? prevOS.o ?? 0;
18689
18751
  const s = (cursorFromCaller ? r.size : void 0) ?? prevOS.s ?? 0;
18690
18752
  const ev = extractorVersionForId(r.id);
18691
- 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 };
18692
18754
  if (o > 0 || s > 0) {
18693
- base3.o = o;
18694
- base3.s = s;
18755
+ base4.o = o;
18756
+ base4.s = s;
18695
18757
  }
18696
- if (r.hash !== void 0) base3.h = r.hash;
18697
- forServer[r.id] = base3;
18758
+ if (r.hash !== void 0) base4.h = r.hash;
18759
+ forServer[r.id] = base4;
18698
18760
  }
18699
18761
  persist(data);
18700
18762
  }
@@ -18769,7 +18831,7 @@ function syncMode(row, mtime, fileSize, extractorVersion, isAppendOnly) {
18769
18831
  if (row.m >= Math.floor(mtime)) return "skip";
18770
18832
  return "full";
18771
18833
  }
18772
- 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;
18773
18835
  var init_sync_ledger = __esm({
18774
18836
  "src/sync-ledger.ts"() {
18775
18837
  "use strict";
@@ -18777,6 +18839,9 @@ var init_sync_ledger = __esm({
18777
18839
  init_extractor_version();
18778
18840
  ledgerPath = () => join38(getDataDir(), "sync-ledger.json");
18779
18841
  cache3 = null;
18842
+ base = /* @__PURE__ */ new Map();
18843
+ diskStamp = null;
18844
+ rowKey = (server, id) => `${server}\0${id}`;
18780
18845
  LEDGER_FLUSH_MS = 2e3;
18781
18846
  pendingWrite = false;
18782
18847
  flushTimer = null;
@@ -18815,7 +18880,7 @@ var init_sync_fields = __esm({
18815
18880
  });
18816
18881
 
18817
18882
  // ../engine/dist/core/index-lock.js
18818
- 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";
18819
18884
  import { dirname as dirname16, join as join39 } from "path";
18820
18885
  function acquireIndexLock(opts) {
18821
18886
  const lockPath = lockFilePath(opts.file);
@@ -18865,7 +18930,7 @@ function lockFilePath(file = ".compact.lock") {
18865
18930
  }
18866
18931
  function stealStaleLock(lockPath, staleAfterMs) {
18867
18932
  try {
18868
- const s = statSync35(lockPath);
18933
+ const s = statSync36(lockPath);
18869
18934
  const age = Date.now() - s.mtimeMs;
18870
18935
  let payload;
18871
18936
  try {
@@ -18937,7 +19002,7 @@ var init_http = __esm({
18937
19002
  CLI_VERSION = JSON.parse(readFileSync31(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
18938
19003
  } catch {
18939
19004
  try {
18940
- if (true) CLI_VERSION = "0.7.14";
19005
+ if (true) CLI_VERSION = "0.7.15";
18941
19006
  } catch {
18942
19007
  }
18943
19008
  }
@@ -19435,7 +19500,7 @@ var init_telemetry = __esm({
19435
19500
  init_sync_client();
19436
19501
  cliVersion2 = () => {
19437
19502
  try {
19438
- return true ? "0.7.14" : "dev";
19503
+ return true ? "0.7.15" : "dev";
19439
19504
  } catch {
19440
19505
  return "dev";
19441
19506
  }
@@ -19611,11 +19676,11 @@ __export(server_probe_exports, {
19611
19676
  function probeOk(r) {
19612
19677
  return r.kind === "ok" && r.apiVersion >= 2;
19613
19678
  }
19614
- async function probeServer(base3, opts = {}) {
19679
+ async function probeServer(base4, opts = {}) {
19615
19680
  const f = opts.fetchImpl || fetch;
19616
19681
  let res;
19617
19682
  try {
19618
- res = await f(`${base3.replace(/\/+$/, "")}/api/capabilities`, {
19683
+ res = await f(`${base4.replace(/\/+$/, "")}/api/capabilities`, {
19619
19684
  signal: AbortSignal.timeout(opts.timeoutMs ?? 1e4)
19620
19685
  });
19621
19686
  } catch (err) {
@@ -19652,34 +19717,34 @@ async function probeServer(base3, opts = {}) {
19652
19717
  raw: parsed
19653
19718
  };
19654
19719
  }
19655
- function probeAdvice(r, base3) {
19720
+ function probeAdvice(r, base4) {
19656
19721
  switch (r.kind) {
19657
19722
  case "ok":
19658
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`;
19659
19724
  case "moved":
19660
- 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>\``;
19661
19726
  case "unauthorized":
19662
- 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 + "`";
19663
19728
  case "server_error":
19664
- 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.`;
19665
19730
  case "not_api":
19666
- 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`;
19667
19732
  case "unreachable":
19668
19733
  switch (r.reason) {
19669
19734
  case "dns":
19670
- 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`;
19671
19736
  case "refused":
19672
- 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`;
19673
19738
  case "tls":
19674
- 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.`;
19675
19740
  case "timeout":
19676
- 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`;
19677
19742
  case "reset":
19678
- 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`;
19679
19744
  case "bad_port":
19680
- 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`;
19681
19746
  default:
19682
- 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`;
19683
19748
  }
19684
19749
  }
19685
19750
  }
@@ -19712,8 +19777,8 @@ function describeCause(err) {
19712
19777
  const code2 = e.code;
19713
19778
  if (typeof code2 === "string" && code2 && !parts.includes(code2)) parts.push(code2);
19714
19779
  }
19715
- const base3 = err instanceof Error ? err.message : String(err);
19716
- 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;
19717
19782
  }
19718
19783
  function describeUnreachable(err) {
19719
19784
  const reason = classifyUnreachable(err);
@@ -19826,7 +19891,7 @@ __export(auto_update_exports, {
19826
19891
  import { execSync as execSync2, execFileSync as execFileSync3 } from "node:child_process";
19827
19892
  import { readFileSync as readFileSync34, existsSync as existsSync41 } from "node:fs";
19828
19893
  import { fileURLToPath as fileURLToPath2 } from "node:url";
19829
- 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";
19830
19895
  import { join as join41, dirname as dirname18, sep as sep2, posix as pathPosix, win32 as pathWin32 } from "node:path";
19831
19896
  import { tmpdir as tmpdir2, homedir as homedir15 } from "node:os";
19832
19897
  import { createHash as createHash8 } from "node:crypto";
@@ -19858,12 +19923,12 @@ function installedVersion() {
19858
19923
  return null;
19859
19924
  }
19860
19925
  }
19861
- function planAutoUpdate(base3, caps, ownVersion3, flag) {
19926
+ function planAutoUpdate(base4, caps, ownVersion3, flag) {
19862
19927
  const rel = caps.cli;
19863
19928
  if (!rel || !rel.version || !rel.sha256) return { update: false, reason: "server advertises no CLI release" };
19864
19929
  if (!isAutoUpdateEnabled(caps.edition, flag)) return { update: false, reason: `auto-update disabled (edition ${caps.edition ?? "?"})` };
19865
19930
  if (compareVersions(rel.version, ownVersion3) <= 0) return { update: false, reason: `already current (own ${ownVersion3} >= server ${rel.version})` };
19866
- 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 };
19867
19932
  }
19868
19933
  function sweepStaleStaging(root = tmpdir2(), now = Date.now()) {
19869
19934
  const MKDTEMP_SUFFIX = /^cr-update-.{6}$/s;
@@ -19879,7 +19944,7 @@ function sweepStaleStaging(root = tmpdir2(), now = Date.now()) {
19879
19944
  if (!MKDTEMP_SUFFIX.test(name)) continue;
19880
19945
  const dir = join41(root, name);
19881
19946
  try {
19882
- const st = statSync36(dir);
19947
+ const st = statSync37(dir);
19883
19948
  if (!st.isDirectory() || now - st.mtimeMs < COLD_MS) continue;
19884
19949
  const inside = readdirSync30(dir);
19885
19950
  if (inside.length > 1 || inside.length === 1 && inside[0] !== "chat-recall.tgz") continue;
@@ -20043,20 +20108,20 @@ function clearUpdateFailures() {
20043
20108
  function stopAutoUpdates() {
20044
20109
  stopRequested = true;
20045
20110
  }
20046
- async function runAutoUpdate(base3, authHeaders, ownVersion3, deps) {
20111
+ async function runAutoUpdate(base4, authHeaders, ownVersion3, deps) {
20047
20112
  let caps;
20048
20113
  try {
20049
- const res = await fetchWithTimeout(`${base3.replace(/\/+$/, "")}/api/capabilities`, { headers: authHeaders });
20114
+ const res = await fetchWithTimeout(`${base4.replace(/\/+$/, "")}/api/capabilities`, { headers: authHeaders });
20050
20115
  if (!res.ok) return { updated: false, reason: `capabilities HTTP ${res.status}` };
20051
20116
  caps = await res.json();
20052
20117
  } catch (e) {
20053
20118
  return { updated: false, reason: `capabilities unreachable: ${e instanceof Error ? e.message : e}` };
20054
20119
  }
20055
20120
  const effectiveOwn = newerOf(ownVersion3, installedVersion());
20056
- 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);
20057
20122
  if (!plan.update) {
20058
- if (/disabled|no CLI release/.test(plan.reason) && !reportedStandingSkip.has(base3)) {
20059
- reportedStandingSkip.add(base3);
20123
+ if (/disabled|no CLI release/.test(plan.reason) && !reportedStandingSkip.has(base4)) {
20124
+ reportedStandingSkip.add(base4);
20060
20125
  try {
20061
20126
  const { reportClientEvent: reportClientEvent2 } = await Promise.resolve().then(() => (init_client_events(), client_events_exports));
20062
20127
  reportClientEvent2("auto_update_skipped", { message: `${plan.reason} (server offers ${caps.cli?.version ?? "?"}, this device runs ${effectiveOwn})` });
@@ -20112,7 +20177,7 @@ var init_auto_update = __esm({
20112
20177
  "use strict";
20113
20178
  init_http();
20114
20179
  init_index_lock();
20115
- 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"}`;
20116
20181
  GIVE_UP_AFTER = 3;
20117
20182
  reportedStandingSkip = /* @__PURE__ */ new Set();
20118
20183
  STOPPING_REASON = "not installed: this process is shutting down";
@@ -20157,7 +20222,7 @@ __export(sync_client_exports, {
20157
20222
  syncSessions: () => syncSessions
20158
20223
  });
20159
20224
  import { join as join42, dirname as dirname19, basename as basename20 } from "node:path";
20160
- 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";
20161
20226
  import { tmpdir as tmpdir3, hostname as hostname2 } from "node:os";
20162
20227
  import { createHash as createHash9 } from "node:crypto";
20163
20228
  import { fileURLToPath as fileURLToPath3 } from "node:url";
@@ -20220,15 +20285,15 @@ function loadAllCredentials() {
20220
20285
  return [];
20221
20286
  }
20222
20287
  async function fetchTenantSecurityConfig(cred) {
20223
- const base3 = cred.serverUrl.replace(/\/+$/, "");
20224
- const cached = _securityConfigCache.get(base3);
20288
+ const base4 = cred.serverUrl.replace(/\/+$/, "");
20289
+ const cached = _securityConfigCache.get(base4);
20225
20290
  if (cached && Date.now() - cached.fetchedAt < SECURITY_CONFIG_TTL_MS) return cached.config;
20226
20291
  const headers = { "content-type": "application/json" };
20227
20292
  if (cred.token) headers.authorization = `Bearer ${cred.token}`;
20228
20293
  try {
20229
20294
  const [rulesRes, settingsRes] = await Promise.all([
20230
- fetchWithTimeout(`${base3}/api/secrets/rules`, { headers }),
20231
- 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)
20232
20297
  ]);
20233
20298
  let tenantRules = [];
20234
20299
  let rulePackVersion = null;
@@ -20253,18 +20318,18 @@ async function fetchTenantSecurityConfig(cred) {
20253
20318
  const body2 = await settingsRes.json().catch(() => ({}));
20254
20319
  if (typeof body2.verifySecrets === "boolean") verifySecrets = body2.verifySecrets;
20255
20320
  if (typeof body2.telemetry === "boolean") {
20256
- setTelemetryEligible(base3, body2.telemetry);
20321
+ setTelemetryEligible(base4, body2.telemetry);
20257
20322
  try {
20258
20323
  const prior = readCollectorHealth()?.telemetryEligible ?? {};
20259
20324
  updateCollectorHealth({
20260
- telemetryEligible: { ...prior, [base3]: { allowed: body2.telemetry, at: Date.now() } }
20325
+ telemetryEligible: { ...prior, [base4]: { allowed: body2.telemetry, at: Date.now() } }
20261
20326
  });
20262
20327
  } catch {
20263
20328
  }
20264
20329
  }
20265
20330
  }
20266
20331
  const config2 = { tenantRules, verifySecrets, rulePackVersion };
20267
- _securityConfigCache.set(base3, { fetchedAt: Date.now(), config: config2 });
20332
+ _securityConfigCache.set(base4, { fetchedAt: Date.now(), config: config2 });
20268
20333
  return config2;
20269
20334
  } catch {
20270
20335
  return { tenantRules: [], verifySecrets: true, rulePackVersion: null };
@@ -20283,18 +20348,18 @@ function readPersistedSyncConfigs() {
20283
20348
  return {};
20284
20349
  }
20285
20350
  }
20286
- function persistSyncConfig(base3, config2) {
20351
+ function persistSyncConfig(base4, config2) {
20287
20352
  try {
20288
20353
  const all = readPersistedSyncConfigs();
20289
- all[base3] = { fetchedAt: Date.now(), config: config2 };
20354
+ all[base4] = { fetchedAt: Date.now(), config: config2 };
20290
20355
  mkdirSync10(dirname19(syncConfigCachePath()), { recursive: true });
20291
20356
  writeFileSync9(syncConfigCachePath(), JSON.stringify(all, null, 2));
20292
20357
  } catch {
20293
20358
  }
20294
20359
  }
20295
20360
  async function fetchTenantSyncConfig(cred) {
20296
- const base3 = cred.serverUrl.replace(/\/+$/, "");
20297
- const cached = _syncConfigCache.get(base3);
20361
+ const base4 = cred.serverUrl.replace(/\/+$/, "");
20362
+ const cached = _syncConfigCache.get(base4);
20298
20363
  if (cached && Date.now() - cached.fetchedAt < SECURITY_CONFIG_TTL_MS) return cached.config;
20299
20364
  const headers = { "content-type": "application/json" };
20300
20365
  if (cred.token) headers.authorization = `Bearer ${cred.token}`;
@@ -20302,7 +20367,7 @@ async function fetchTenantSyncConfig(cred) {
20302
20367
  try {
20303
20368
  const sources3 = discoverSessionSources();
20304
20369
  if (sources3.length > 0) {
20305
- await fetchWithTimeout(`${base3}/api/sync-config/sources`, {
20370
+ await fetchWithTimeout(`${base4}/api/sync-config/sources`, {
20306
20371
  method: "POST",
20307
20372
  headers,
20308
20373
  body: JSON.stringify({ device: deviceLabel(), sources: sources3 })
@@ -20310,12 +20375,12 @@ async function fetchTenantSyncConfig(cred) {
20310
20375
  }
20311
20376
  } catch {
20312
20377
  }
20313
- const res = await fetchWithTimeout(`${base3}/api/sync-config`, { headers });
20378
+ const res = await fetchWithTimeout(`${base4}/api/sync-config`, { headers });
20314
20379
  if (res.status === 404) {
20315
- _syncConfigCache.set(base3, { fetchedAt: Date.now(), config: EMPTY_SYNC_CONFIG });
20380
+ _syncConfigCache.set(base4, { fetchedAt: Date.now(), config: EMPTY_SYNC_CONFIG });
20316
20381
  return EMPTY_SYNC_CONFIG;
20317
20382
  }
20318
- if (!res.ok) return lastKnownSyncConfig(base3, `HTTP ${res.status}`);
20383
+ if (!res.ok) return lastKnownSyncConfig(base4, `HTTP ${res.status}`);
20319
20384
  const body2 = await res.json().catch(() => ({}));
20320
20385
  const config2 = {
20321
20386
  excludeTools: Array.isArray(body2.excludeTools) ? body2.excludeTools.filter((t) => typeof t === "string") : [],
@@ -20352,22 +20417,22 @@ async function fetchTenantSyncConfig(cred) {
20352
20417
  if (decided > 0) console.error(`[sync] applied ${decided} folder decision(s) from the dashboard`);
20353
20418
  } catch {
20354
20419
  }
20355
- _syncConfigCache.set(base3, { fetchedAt: Date.now(), config: config2 });
20356
- persistSyncConfig(base3, config2);
20420
+ _syncConfigCache.set(base4, { fetchedAt: Date.now(), config: config2 });
20421
+ persistSyncConfig(base4, config2);
20357
20422
  return config2;
20358
20423
  } catch (err) {
20359
20424
  if (isSyncRulesRefusal(err)) throw err;
20360
- return lastKnownSyncConfig(base3, err instanceof Error ? err.message : "request failed");
20425
+ return lastKnownSyncConfig(base4, err instanceof Error ? err.message : "request failed");
20361
20426
  }
20362
20427
  }
20363
- function lastKnownSyncConfig(base3, reason) {
20364
- const remembered = _syncConfigCache.get(base3) ?? readPersistedSyncConfigs()[base3];
20428
+ function lastKnownSyncConfig(base4, reason) {
20429
+ const remembered = _syncConfigCache.get(base4) ?? readPersistedSyncConfigs()[base4];
20365
20430
  if (remembered) {
20366
20431
  console.error(`[sync] could not read server-side sync rules (${reason}) \u2014 applying the last known set from ${new Date(remembered.fetchedAt).toISOString()}`);
20367
20432
  return remembered.config;
20368
20433
  }
20369
20434
  const refusal = new Error(
20370
- `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.`
20371
20436
  );
20372
20437
  refusal[SYNC_RULES_REFUSAL] = true;
20373
20438
  throw refusal;
@@ -20488,25 +20553,25 @@ async function syncSessions(opts = {}) {
20488
20553
  ${errors.join("\n ")}`);
20489
20554
  return { ...agg, perTarget };
20490
20555
  }
20491
- async function postFieldBatch(base3, token, rows) {
20556
+ async function postFieldBatch(base4, token, rows) {
20492
20557
  const headers = { "content-type": "application/json" };
20493
20558
  if (token) headers.authorization = `Bearer ${token}`;
20494
20559
  const sleep2 = (ms) => new Promise((r) => setTimeout(r, ms));
20495
20560
  for (let attempt = 0; ; attempt++) {
20496
- 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);
20497
20562
  if (res.ok) return;
20498
20563
  const retryable = res.status === 429 || res.status >= 500;
20499
- 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(() => "")}`);
20500
20565
  const ra = Number(res.headers.get("retry-after")) || 0;
20501
20566
  await sleep2(ra > 0 ? ra * 1e3 : [500, 1500, 4e3, 8e3, 15e3][Math.min(attempt, 4)]);
20502
20567
  }
20503
20568
  }
20504
20569
  async function reconcileFieldsForTarget(cred, fullRefs, opts = {}) {
20505
- const base3 = cred.serverUrl.replace(/\/+$/, "");
20506
- const ledger = getSyncedRows(base3);
20570
+ const base4 = cred.serverUrl.replace(/\/+$/, "");
20571
+ const ledger = getSyncedRows(base4);
20507
20572
  let pushed = 0, absent = 0, scanned = 0;
20508
20573
  for (const field of SYNC_FIELDS) {
20509
- const needFull = !!opts.force || fieldNeedsFullPass(base3, field);
20574
+ const needFull = !!opts.force || fieldNeedsFullPass(base4, field);
20510
20575
  const candidates2 = needFull ? fullRefs() : opts.convRefs ?? fullRefs();
20511
20576
  const send = [];
20512
20577
  const mtimeById = /* @__PURE__ */ new Map();
@@ -20522,15 +20587,15 @@ async function reconcileFieldsForTarget(cred, fullRefs, opts = {}) {
20522
20587
  }
20523
20588
  for (let i = 0; i < send.length; i += 200) {
20524
20589
  const chunk = send.slice(i, i + 200);
20525
- await postFieldBatch(base3, cred.token, chunk);
20526
- 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 })));
20527
20592
  pushed += chunk.length;
20528
20593
  }
20529
20594
  if (absentIds.length) {
20530
- 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 })));
20531
20596
  absent += absentIds.length;
20532
20597
  }
20533
- if (needFull) markFieldFullPassDone(base3, field);
20598
+ if (needFull) markFieldFullPassDone(base4, field);
20534
20599
  }
20535
20600
  return { pushed, absent, scanned };
20536
20601
  }
@@ -20568,7 +20633,7 @@ function reapStaleScanDirs(dir = tmpdir3(), maxAgeMs = 6 * 36e5, now = Date.now(
20568
20633
  if (!name.startsWith("cr-batchscan-")) continue;
20569
20634
  const p = join42(dir, name);
20570
20635
  try {
20571
- if (now - statSync37(p).mtimeMs < maxAgeMs) continue;
20636
+ if (now - statSync38(p).mtimeMs < maxAgeMs) continue;
20572
20637
  rmSync6(p, { recursive: true, force: true });
20573
20638
  reaped++;
20574
20639
  } catch {
@@ -20647,25 +20712,25 @@ function serverIngestConcurrency(serverUrl) {
20647
20712
  return advertisedIngestConc.get(serverUrl.replace(/\/$/, "")) ?? null;
20648
20713
  }
20649
20714
  async function verifyServerApi(serverUrl, minApi) {
20650
- const base3 = serverUrl.replace(/\/$/, "");
20651
- const seen = capsOk.get(base3);
20715
+ const base4 = serverUrl.replace(/\/$/, "");
20716
+ const seen = capsOk.get(base4);
20652
20717
  if (seen !== void 0 && Date.now() - seen < CAPS_TTL_MS) return true;
20653
20718
  const { probeServer: probeServer2, probeAdvice: probeAdvice2 } = await Promise.resolve().then(() => (init_server_probe(), server_probe_exports));
20654
- const probe = await probeServer2(base3, {
20719
+ const probe = await probeServer2(base4, {
20655
20720
  fetchImpl: ((url, init) => fetchWithTimeout(String(url), init ?? {}))
20656
20721
  });
20657
- if (probe.kind !== "ok") throw new Error(probeAdvice2(probe, base3));
20722
+ if (probe.kind !== "ok") throw new Error(probeAdvice2(probe, base4));
20658
20723
  const caps = probe.raw;
20659
20724
  if ((caps.apiVersion ?? 0) < minApi) {
20660
20725
  throw new Error(`server too old: apiVersion ${caps.apiVersion ?? "none"} < required ${minApi} \u2014 update the server image before syncing`);
20661
20726
  }
20662
20727
  const adv = caps.limits?.ingestConcurrencyPerTenant;
20663
20728
  if (typeof adv === "number" && Number.isFinite(adv) && adv >= 1) {
20664
- advertisedIngestConc.set(base3, Math.floor(adv));
20729
+ advertisedIngestConc.set(base4, Math.floor(adv));
20665
20730
  }
20666
- if (caps.limits?.acceptsGzipBody === true) advertisedGzipBody.add(base3);
20667
- else advertisedGzipBody.delete(base3);
20668
- 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());
20669
20734
  return true;
20670
20735
  }
20671
20736
  async function syncToTarget(cred, opts = {}) {
@@ -20730,7 +20795,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20730
20795
  const ac = new AbortController();
20731
20796
  const timer = setTimeout(() => ac.abort(new Error(`upload timed out after ${UPLOAD_TIMEOUT_MS}ms`)), UPLOAD_TIMEOUT_MS);
20732
20797
  try {
20733
- const res = await fetch(`${base3}/api/sync`, {
20798
+ const res = await fetch(`${base4}/api/sync`, {
20734
20799
  method: "POST",
20735
20800
  // No token ⇒ no auth header: a no-auth local server (AUTH_PROVIDER=none)
20736
20801
  // accepts it as the single 'default' tenant.
@@ -20746,26 +20811,26 @@ async function syncToTargetInScope(cred, opts = {}) {
20746
20811
  acceptedUploads.set(cred.serverUrl, (acceptedUploads.get(cred.serverUrl) ?? 0) + 1);
20747
20812
  const body3 = await res.json().catch(() => ({}));
20748
20813
  if (typeof body3.telemetry === "boolean") {
20749
- setTelemetryEligible(base3, body3.telemetry);
20814
+ setTelemetryEligible(base4, body3.telemetry);
20750
20815
  try {
20751
20816
  const prior = readCollectorHealth()?.telemetryEligible ?? {};
20752
20817
  updateCollectorHealth({
20753
- telemetryEligible: { ...prior, [base3]: { allowed: body3.telemetry, at: Date.now() } }
20818
+ telemetryEligible: { ...prior, [base4]: { allowed: body3.telemetry, at: Date.now() } }
20754
20819
  });
20755
20820
  } catch {
20756
20821
  }
20757
20822
  }
20758
20823
  const adv = body3.limits?.ingestConcurrencyPerTenant;
20759
20824
  if (typeof adv === "number" && Number.isFinite(adv) && adv >= 1) {
20760
- setServerIngestConcurrency(base3, Math.floor(adv));
20825
+ setServerIngestConcurrency(base4, Math.floor(adv));
20761
20826
  }
20762
20827
  if (body3.cli && body3.cli.version) {
20763
20828
  const { planAutoUpdate: planAutoUpdate2, runAutoUpdate: runAutoUpdate2, sweepStaleStaging: sweepStaleStaging2 } = await Promise.resolve().then(() => (init_auto_update(), auto_update_exports));
20764
20829
  const authHeaders = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
20765
- 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);
20766
20831
  sweepStaleStaging2();
20767
20832
  if (plan.update) {
20768
- void runAutoUpdate2(base3, authHeaders, ownVersion).catch(() => {
20833
+ void runAutoUpdate2(base4, authHeaders, ownVersion).catch(() => {
20769
20834
  });
20770
20835
  }
20771
20836
  }
@@ -20774,7 +20839,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20774
20839
  const retryable = res.status === 429 || res.status >= 500;
20775
20840
  const text = await res.text().catch(() => "");
20776
20841
  if (res.status === 401 || res.status === 403) {
20777
- 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}`);
20778
20843
  }
20779
20844
  if (res.status === 402) {
20780
20845
  let detail = text;
@@ -20795,7 +20860,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20795
20860
  const retryAfterS = Number(res.headers.get("retry-after"));
20796
20861
  const waitMs = res.status === 429 && retryAfterS > 0 ? retryAfterS * 1e3 : RETRY_DELAYS_MS[attempt];
20797
20862
  const why = res.status === 524 ? ` \u2014 the proxy cut the request at its time limit; the batch is too big for one request` : "";
20798
- 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})`);
20799
20864
  await sleep2(waitMs);
20800
20865
  continue;
20801
20866
  } catch (err) {
@@ -20863,11 +20928,11 @@ async function syncToTargetInScope(cred, opts = {}) {
20863
20928
  }
20864
20929
  };
20865
20930
  };
20866
- const base3 = cred.serverUrl.replace(/\/$/, "");
20867
- const ledger = opts.useLedger ? getSyncedRows(base3) : null;
20931
+ const base4 = cred.serverUrl.replace(/\/$/, "");
20932
+ const ledger = opts.useLedger ? getSyncedRows(base4) : null;
20868
20933
  const convBatch = makeBatcher("conversations", 25, false, (rows) => {
20869
20934
  try {
20870
- markSynced(base3, rows.map((r) => {
20935
+ markSynced(base4, rows.map((r) => {
20871
20936
  const off = typeof r.from_offset === "number" ? r.from_offset : 0;
20872
20937
  const hash = shippedHash.get(r.session_id);
20873
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 };
@@ -20882,7 +20947,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20882
20947
  const ac = new AbortController();
20883
20948
  const timer = setTimeout(() => ac.abort(new Error(`upload timed out after ${UPLOAD_TIMEOUT_MS}ms`)), UPLOAD_TIMEOUT_MS);
20884
20949
  try {
20885
- const res = await fetch(`${base3}/api/sync`, {
20950
+ const res = await fetch(`${base4}/api/sync`, {
20886
20951
  method: "POST",
20887
20952
  headers,
20888
20953
  body: JSON.stringify({ conversations: convs }),
@@ -20893,10 +20958,10 @@ async function syncToTargetInScope(cred, opts = {}) {
20893
20958
  if (body2.cli && body2.cli.version) {
20894
20959
  const { planAutoUpdate: planAutoUpdate2, runAutoUpdate: runAutoUpdate2, sweepStaleStaging: sweepStaleStaging2 } = await Promise.resolve().then(() => (init_auto_update(), auto_update_exports));
20895
20960
  const authHeaders = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
20896
- 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);
20897
20962
  sweepStaleStaging2();
20898
20963
  if (plan.update) {
20899
- void runAutoUpdate2(base3, authHeaders, ownVersion).catch(() => {
20964
+ void runAutoUpdate2(base4, authHeaders, ownVersion).catch(() => {
20900
20965
  });
20901
20966
  }
20902
20967
  }
@@ -20904,7 +20969,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20904
20969
  const acked = convs.filter((c) => !fullNeeded.has(c.session_id));
20905
20970
  if (acked.length > 0) {
20906
20971
  try {
20907
- markSynced(base3, acked.map((c) => ({
20972
+ markSynced(base4, acked.map((c) => ({
20908
20973
  id: c.session_id,
20909
20974
  mtime: c.mtime,
20910
20975
  offset: c.from_offset,
@@ -20928,7 +20993,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20928
20993
  const ac = new AbortController();
20929
20994
  const timer = setTimeout(() => ac.abort(new Error(`upload timed out after ${UPLOAD_TIMEOUT_MS}ms`)), UPLOAD_TIMEOUT_MS);
20930
20995
  try {
20931
- const res = await fetch(`${base3}/api/sync`, {
20996
+ const res = await fetch(`${base4}/api/sync`, {
20932
20997
  method: "POST",
20933
20998
  headers,
20934
20999
  body: JSON.stringify({ conversations: [conv] }),
@@ -20941,11 +21006,11 @@ async function syncToTargetInScope(cred, opts = {}) {
20941
21006
  const mtime = conv.mtime;
20942
21007
  try {
20943
21008
  if (!guarded) {
20944
- 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 }]);
20945
21010
  } else if (typeof guarded.o === "number" && guarded.o > 0 && guarded.o <= fileSize) {
20946
- 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 }]);
20947
21012
  } else {
20948
- markSynced(base3, [{ id, mtime }]);
21013
+ markSynced(base4, [{ id, mtime }]);
20949
21014
  }
20950
21015
  } catch {
20951
21016
  }
@@ -21011,7 +21076,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21011
21076
  const m = process.memoryUsage();
21012
21077
  console.error(`[sync-trace] ${msg} \xB7 heap=${(m.heapUsed / 1048576).toFixed(0)}MB rss=${(m.rss / 1048576).toFixed(0)}MB`);
21013
21078
  } : null;
21014
- trace?.(`walk start: ${slice.length} ref(s) \u2192 ${base3}`);
21079
+ trace?.(`walk start: ${slice.length} ref(s) \u2192 ${base4}`);
21015
21080
  if (upload.sessionMeta) {
21016
21081
  try {
21017
21082
  await reconcileFieldsForTarget(
@@ -21026,7 +21091,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21026
21091
  { convRefs: slice }
21027
21092
  );
21028
21093
  } catch (e) {
21029
- 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}`);
21030
21095
  }
21031
21096
  }
21032
21097
  trace?.("field reconcile done");
@@ -21068,7 +21133,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21068
21133
  }
21069
21134
  trace?.("conversation walk start");
21070
21135
  const walkStartedAt = Date.now();
21071
- const firstWalk = (ledger ?? getSyncedRows(base3)).size === 0;
21136
+ const firstWalk = (ledger ?? getSyncedRows(base4)).size === 0;
21072
21137
  reportWalkProgress({ done: 0, total: slice.length, startedAt: walkStartedAt, complete: false, first: firstWalk });
21073
21138
  walkProgressForUpload = { done: 0, total: slice.length, complete: false };
21074
21139
  let traceN = 0;
@@ -21108,7 +21173,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21108
21173
  continue;
21109
21174
  } else {
21110
21175
  try {
21111
- markSynced(base3, [{ id: ref.prefixedId, mtime: ref.mtime }]);
21176
+ markSynced(base4, [{ id: ref.prefixedId, mtime: ref.mtime }]);
21112
21177
  } catch {
21113
21178
  }
21114
21179
  skipped++;
@@ -21131,7 +21196,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21131
21196
  const off = getBackendForId(ref.prefixedId)?.fileSize?.(ref.rawId) ?? 0;
21132
21197
  const priorCursor = ackRow?.s ?? 0;
21133
21198
  const safeToAck = off > 0 && off <= priorCursor;
21134
- 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 }]);
21135
21200
  } catch {
21136
21201
  }
21137
21202
  }
@@ -21141,7 +21206,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21141
21206
  if (!built) {
21142
21207
  if (ledger) {
21143
21208
  try {
21144
- markSynced(base3, [{ id: ref.prefixedId, mtime: ref.mtime }]);
21209
+ markSynced(base4, [{ id: ref.prefixedId, mtime: ref.mtime }]);
21145
21210
  } catch {
21146
21211
  }
21147
21212
  }
@@ -21198,7 +21263,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21198
21263
  walked++;
21199
21264
  if (walked % 250 === 0) console.error(`[sync] ${walked}/${slice.length} sessions\u2026`);
21200
21265
  }
21201
- const itemVersions = loadItemVersions(base3);
21266
+ const itemVersions = loadItemVersions(base4);
21202
21267
  const seenTools = /* @__PURE__ */ new Set();
21203
21268
  const seenItemKeys = /* @__PURE__ */ new Map();
21204
21269
  const registry = buildSourceRegistry();
@@ -21292,7 +21357,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21292
21357
  await appendFlush();
21293
21358
  for (const id of appendResults.fullResyncNeeded) {
21294
21359
  try {
21295
- markFullResync(base3, id);
21360
+ markFullResync(base4, id);
21296
21361
  } catch {
21297
21362
  }
21298
21363
  }
@@ -21305,7 +21370,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21305
21370
  await findingsBatch.drain();
21306
21371
  await drainInflight();
21307
21372
  {
21308
- const sentHashes = loadInventoryHashes(base3);
21373
+ const sentHashes = loadInventoryHashes(base4);
21309
21374
  const entries = [];
21310
21375
  const hashes = {};
21311
21376
  for (const [sourceType, ids] of inventory) {
@@ -21319,7 +21384,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21319
21384
  if (entries.length > 0) {
21320
21385
  try {
21321
21386
  await post({ inventory: entries });
21322
- saveInventoryHashes(base3, hashes);
21387
+ saveInventoryHashes(base4, hashes);
21323
21388
  } catch (err) {
21324
21389
  console.error(`[sync] toolkit inventory not sent (it is retried next sync): ${err instanceof Error ? err.message : err}`);
21325
21390
  }
@@ -21330,7 +21395,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21330
21395
  const rec = {};
21331
21396
  for (const t of seenTools) rec[t] = extractorVersionForTool(t);
21332
21397
  for (const [k, v] of seenItemKeys) rec[k] = v;
21333
- saveItemVersions(base3, rec);
21398
+ saveItemVersions(base4, rec);
21334
21399
  } catch {
21335
21400
  }
21336
21401
  }
@@ -21343,9 +21408,9 @@ async function syncToTargetInScope(cred, opts = {}) {
21343
21408
  }
21344
21409
  if (tombstones.length > 0) {
21345
21410
  await post({ tombstones });
21346
- const data = getLedgerData(base3);
21411
+ const data = getLedgerData(base4);
21347
21412
  for (const t of tombstones) delete data[t.session_id];
21348
- persistLedgerData(base3, data);
21413
+ persistLedgerData(base4, data);
21349
21414
  }
21350
21415
  }
21351
21416
  if (opts.prune) await post({ prune_empty_sessions: true });
@@ -21816,7 +21881,7 @@ var init_sync_client = __esm({
21816
21881
  ownVersion = JSON.parse(readFileSync35(join42(dir, "../package.json"), "utf-8")).version || ownVersion;
21817
21882
  } catch {
21818
21883
  try {
21819
- if (true) ownVersion = "0.7.14";
21884
+ if (true) ownVersion = "0.7.15";
21820
21885
  } catch {
21821
21886
  }
21822
21887
  }
@@ -21910,9 +21975,9 @@ async function refreshUpdateCheck(force = false) {
21910
21975
  const { loadAllCredentials: loadAllCredentials2 } = await Promise.resolve().then(() => (init_sync_client(), sync_client_exports));
21911
21976
  for (const cred of loadAllCredentials2()) {
21912
21977
  if (!cred.serverUrl) continue;
21913
- const base3 = cred.serverUrl.replace(/\/+$/, "");
21978
+ const base4 = cred.serverUrl.replace(/\/+$/, "");
21914
21979
  try {
21915
- const res = await fetchWithTimeout(`${base3}/api/capabilities`, {
21980
+ const res = await fetchWithTimeout(`${base4}/api/capabilities`, {
21916
21981
  headers: cred.token ? { authorization: `Bearer ${cred.token}` } : {}
21917
21982
  }, 5e3);
21918
21983
  if (!res.ok) continue;
@@ -21967,11 +22032,11 @@ var init_update_notice = __esm({
21967
22032
  });
21968
22033
 
21969
22034
  // ../engine/dist/core/which.js
21970
- 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";
21971
22036
  import { join as join44, isAbsolute as isAbsolute2, delimiter as delimiter2, sep as sep3 } from "node:path";
21972
22037
  function executable(p) {
21973
22038
  try {
21974
- if (!statSync38(p).isFile())
22039
+ if (!statSync39(p).isFile())
21975
22040
  return false;
21976
22041
  } catch {
21977
22042
  return false;
@@ -22300,7 +22365,7 @@ __export(companions_exports, {
22300
22365
  uninstallCodeindex: () => uninstallCodeindex,
22301
22366
  unregisterCodeindexMcp: () => unregisterCodeindexMcp
22302
22367
  });
22303
- 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";
22304
22369
  import { homedir as homedir17 } from "node:os";
22305
22370
  import { join as join47 } from "node:path";
22306
22371
  import { execSync as execSync3 } from "node:child_process";
@@ -22351,7 +22416,7 @@ function checkCodeindexStatus() {
22351
22416
  status.installed = true;
22352
22417
  status.path = foundPath;
22353
22418
  try {
22354
- status.size = statSync39(foundPath).size;
22419
+ status.size = statSync40(foundPath).size;
22355
22420
  } catch {
22356
22421
  }
22357
22422
  try {
@@ -22501,7 +22566,7 @@ __export(install_skills_exports, {
22501
22566
  skillsSourceDir: () => skillsSourceDir,
22502
22567
  uninstallSkills: () => uninstallSkills
22503
22568
  });
22504
- 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";
22505
22570
  import { createHash as createHash11 } from "crypto";
22506
22571
  import { join as join48, basename as basename21 } from "path";
22507
22572
  function skillsSourceDir() {
@@ -22720,10 +22785,10 @@ function parseAgentText(content, format, fallbackName) {
22720
22785
  return { name: fm.name || fallbackName, description: fm.description || "", tools: fm.tools, body: body2.trim() };
22721
22786
  }
22722
22787
  function readCommand(filePath, format) {
22723
- return parseCommandText(readFileSync40(filePath, "utf-8"), format, base(filePath));
22788
+ return parseCommandText(readFileSync40(filePath, "utf-8"), format, base2(filePath));
22724
22789
  }
22725
22790
  function readAgent(filePath, format) {
22726
- return parseAgentText(readFileSync40(filePath, "utf-8"), format, base(filePath));
22791
+ return parseAgentText(readFileSync40(filePath, "utf-8"), format, base2(filePath));
22727
22792
  }
22728
22793
  function readInstructions(filePath, name) {
22729
22794
  const content = readFileSync40(filePath, "utf-8");
@@ -22823,7 +22888,7 @@ function emit(type, art, toTool, projectPath) {
22823
22888
  content: stringifyFrontmatter({ name: art.name, description: art.description, ...art.tools ? { tools: art.tools } : {} }, art.body)
22824
22889
  };
22825
22890
  }
22826
- function base(filePath) {
22891
+ function base2(filePath) {
22827
22892
  return basename22(filePath).replace(/\.(md|toml)$/, "");
22828
22893
  }
22829
22894
  var init_artifact_codec = __esm({
@@ -23308,11 +23373,11 @@ __export(toolkit_pull_exports, {
23308
23373
  platformRefusal: () => platformRefusal,
23309
23374
  portableCommand: () => portableCommand
23310
23375
  });
23311
- 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";
23312
23377
  import { dirname as dirname23, join as join51, basename as basename24, isAbsolute as isAbsolute3 } from "node:path";
23313
23378
  function isExecutableFile(p) {
23314
23379
  try {
23315
- return statSync41(p).isFile();
23380
+ return statSync42(p).isFile();
23316
23381
  } catch {
23317
23382
  return false;
23318
23383
  }
@@ -23326,9 +23391,9 @@ function portableCommand(cmd) {
23326
23391
  }
23327
23392
  if (isExecutableFile(cmd))
23328
23393
  return { command: cmd, rewritten: false };
23329
- const base3 = basename24(cmd);
23330
- if (onPath(base3))
23331
- return { command: base3, rewritten: true };
23394
+ const base4 = basename24(cmd);
23395
+ if (onPath(base4))
23396
+ return { command: base4, rewritten: true };
23332
23397
  return { missing: cmd };
23333
23398
  }
23334
23399
  function entryFromSpec(spec) {
@@ -24162,8 +24227,8 @@ import { homedir as homedir20 } from "os";
24162
24227
  import { join as join53 } from "path";
24163
24228
  function opencodeConfigDir() {
24164
24229
  const xdg = process.env.XDG_CONFIG_HOME;
24165
- const base3 = xdg && xdg.trim() ? xdg : join53(homedir20(), ".config");
24166
- return join53(base3, "opencode");
24230
+ const base4 = xdg && xdg.trim() ? xdg : join53(homedir20(), ".config");
24231
+ return join53(base4, "opencode");
24167
24232
  }
24168
24233
  function opencodePluginDir() {
24169
24234
  return join53(opencodeConfigDir(), "plugins");
@@ -24750,17 +24815,17 @@ async function collectCode(opts) {
24750
24815
  return r;
24751
24816
  };
24752
24817
  log6(`indexing ${ws} + analyses \u2026`);
24753
- const base3 = await runMcp(bin, ws, [
24818
+ const base4 = await runMcp(bin, ws, [
24754
24819
  call(1, "index_workspace", { path: ws }),
24755
24820
  call(2, "status"),
24756
24821
  call(3, "get_tree"),
24757
24822
  ...ANALYSES.map((a, i) => call(10 + i, "analyze", { analysis: a }))
24758
24823
  ]);
24759
- const st = parseJson(base3, 2, {});
24760
- const tree = parseJson(base3, 3, []);
24824
+ const st = parseJson(base4, 2, {});
24825
+ const tree = parseJson(base4, 3, []);
24761
24826
  const A = {};
24762
24827
  ANALYSES.forEach((a, i) => {
24763
- A[a] = parseJson(base3, 10 + i, {});
24828
+ A[a] = parseJson(base4, 10 + i, {});
24764
24829
  });
24765
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;
24766
24831
  if (tree.length === 0) {
@@ -25589,7 +25654,7 @@ __export(project_tasks_exports, {
25589
25654
  pushProjectTaskStatuses: () => pushProjectTaskStatuses,
25590
25655
  renderTeamTasksMd: () => renderTeamTasksMd
25591
25656
  });
25592
- 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";
25593
25658
  import { join as join55, dirname as dirname25 } from "node:path";
25594
25659
  import { homedir as homedir21 } from "node:os";
25595
25660
  function isTeamTaskStatus(v) {
@@ -25660,14 +25725,14 @@ function writeLedger(l) {
25660
25725
  } catch {
25661
25726
  }
25662
25727
  }
25663
- async function pushProjectTaskStatuses(base3, authHeaders, opts = {}) {
25728
+ async function pushProjectTaskStatuses(base4, authHeaders, opts = {}) {
25664
25729
  const out = { files: 0, pushedTasks: 0 };
25665
25730
  const ledger = readLedger();
25666
25731
  let ledgerDirty = false;
25667
25732
  for (const fk of FILE_KINDS) {
25668
25733
  let projects;
25669
25734
  try {
25670
- const res = await fetchWithTimeout(`${base3}${fk.trackedPath}`, { headers: authHeaders });
25735
+ const res = await fetchWithTimeout(`${base4}${fk.trackedPath}`, { headers: authHeaders });
25671
25736
  if (!res.ok) continue;
25672
25737
  projects = (await res.json()).projects || [];
25673
25738
  } catch {
@@ -25678,7 +25743,7 @@ async function pushProjectTaskStatuses(base3, authHeaders, opts = {}) {
25678
25743
  if (!existsSync51(file)) continue;
25679
25744
  let mtime;
25680
25745
  try {
25681
- mtime = statSync42(file).mtimeMs;
25746
+ mtime = statSync43(file).mtimeMs;
25682
25747
  } catch {
25683
25748
  continue;
25684
25749
  }
@@ -25695,7 +25760,7 @@ async function pushProjectTaskStatuses(base3, authHeaders, opts = {}) {
25695
25760
  continue;
25696
25761
  }
25697
25762
  try {
25698
- const res = await fetchWithTimeout(`${base3}${fk.statusPath}`, {
25763
+ const res = await fetchWithTimeout(`${base4}${fk.statusPath}`, {
25699
25764
  method: "POST",
25700
25765
  headers: { "content-type": "application/json", ...authHeaders },
25701
25766
  body: JSON.stringify({ project, items: changed.map((t) => ({ id: t.id, status: t.intent })) })
@@ -25821,16 +25886,16 @@ ${block}`);
25821
25886
  return { status: "error", result: JSON.stringify({ error: e instanceof Error ? e.message : "failed" }) };
25822
25887
  }
25823
25888
  }
25824
- async function runPull(base3, opts) {
25889
+ async function runPull(base4, opts) {
25825
25890
  const { executePull: executePull2 } = await Promise.resolve().then(() => (init_toolkit_pull(), toolkit_pull_exports));
25826
25891
  const { hostname: hostname3 } = await import("node:os");
25827
- const creds = loadAllCredentials().find((c) => c.serverUrl.replace(/\/+$/, "") === base3.replace(/\/+$/, ""));
25892
+ const creds = loadAllCredentials().find((c) => c.serverUrl.replace(/\/+$/, "") === base4.replace(/\/+$/, ""));
25828
25893
  const headers = creds?.token ? { authorization: `Bearer ${creds.token}` } : {};
25829
25894
  const wanted = opts.types?.length ? opts.types : ["mcp", "skill", "command", "agent", "instructions"];
25830
25895
  const rows = [];
25831
25896
  for (const type of wanted) {
25832
25897
  try {
25833
- 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 });
25834
25899
  if (!res.ok) continue;
25835
25900
  const body2 = await res.json();
25836
25901
  for (const it of body2.items || []) rows.push(it);
@@ -25899,20 +25964,20 @@ async function runIntent(intent, ctx) {
25899
25964
  async function drainSyncIntents(opts = {}) {
25900
25965
  const out = { processed: 0, done: 0, errored: 0 };
25901
25966
  for (const cred of loadAllCredentials()) {
25902
- const base3 = cred.serverUrl.replace(/\/+$/, "");
25967
+ const base4 = cred.serverUrl.replace(/\/+$/, "");
25903
25968
  const authHeaders = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
25904
25969
  let pending;
25905
25970
  try {
25906
- const res = await fetchWithTimeout(`${base3}/api/sync-intents/pending`, { headers: authHeaders });
25971
+ const res = await fetchWithTimeout(`${base4}/api/sync-intents/pending`, { headers: authHeaders });
25907
25972
  if (!res.ok) continue;
25908
25973
  const data = await res.json();
25909
25974
  pending = data.intents || [];
25910
25975
  if (data.cli && data.cli.version) {
25911
25976
  const { planAutoUpdate: planAutoUpdate2, runAutoUpdate: runAutoUpdate2, sweepStaleStaging: sweepStaleStaging2 } = await Promise.resolve().then(() => (init_auto_update(), auto_update_exports));
25912
- 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);
25913
25978
  sweepStaleStaging2();
25914
25979
  if (plan.update) {
25915
- void runAutoUpdate2(base3, authHeaders, ownVersion2).catch(() => {
25980
+ void runAutoUpdate2(base4, authHeaders, ownVersion2).catch(() => {
25916
25981
  });
25917
25982
  }
25918
25983
  }
@@ -25920,7 +25985,7 @@ async function drainSyncIntents(opts = {}) {
25920
25985
  continue;
25921
25986
  }
25922
25987
  for (const intent of pending) {
25923
- const { status, result } = await runIntent(intent, { base: base3 });
25988
+ const { status, result } = await runIntent(intent, { base: base4 });
25924
25989
  out.processed++;
25925
25990
  if (status === "done") out.done++;
25926
25991
  else out.errored++;
@@ -25929,7 +25994,7 @@ async function drainSyncIntents(opts = {}) {
25929
25994
  console.error(`[sync-intent] ${label}: ${status}`);
25930
25995
  }
25931
25996
  try {
25932
- await fetchWithTimeout(`${base3}/api/sync-intents/${intent.id}/ack`, {
25997
+ await fetchWithTimeout(`${base4}/api/sync-intents/${intent.id}/ack`, {
25933
25998
  method: "POST",
25934
25999
  headers: { "content-type": "application/json", ...authHeaders },
25935
26000
  body: JSON.stringify({ status, result })
@@ -25938,7 +26003,7 @@ async function drainSyncIntents(opts = {}) {
25938
26003
  }
25939
26004
  }
25940
26005
  try {
25941
- await pushProjectTaskStatuses(base3, authHeaders, { verbose: opts.verbose });
26006
+ await pushProjectTaskStatuses(base4, authHeaders, { verbose: opts.verbose });
25942
26007
  } catch {
25943
26008
  }
25944
26009
  }
@@ -25978,7 +26043,7 @@ var init_intent_drain = __esm({
25978
26043
  ownVersion2 = JSON.parse(readFileSync45(join56(dir, "../package.json"), "utf-8")).version || ownVersion2;
25979
26044
  } catch {
25980
26045
  try {
25981
- if (true) ownVersion2 = "0.7.14";
26046
+ if (true) ownVersion2 = "0.7.15";
25982
26047
  } catch {
25983
26048
  }
25984
26049
  }
@@ -26179,7 +26244,7 @@ var team_merge_exports = {};
26179
26244
  __export(team_merge_exports, {
26180
26245
  mergePullResult: () => mergePullResult
26181
26246
  });
26182
- 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";
26183
26248
  import { dirname as dirname27, join as join57 } from "path";
26184
26249
  import { createHash as createHash14 } from "crypto";
26185
26250
  function installPathFor(art, tool) {
@@ -26316,7 +26381,7 @@ function readFileIfExists(path) {
26316
26381
  try {
26317
26382
  if (!existsSync53(path))
26318
26383
  return null;
26319
- const s = statSync43(path);
26384
+ const s = statSync44(path);
26320
26385
  if (!s.isFile())
26321
26386
  return null;
26322
26387
  return readFileSync46(path);
@@ -26400,7 +26465,7 @@ var init_vault_crypto = __esm({
26400
26465
  });
26401
26466
 
26402
26467
  // ../engine/dist/core/vault-source.js
26403
- 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";
26404
26469
  import { extname, join as join58 } from "path";
26405
26470
  function* walkVaultSources() {
26406
26471
  const t = loadSettings().team.vault;
@@ -26416,7 +26481,7 @@ function* walkVaultSources() {
26416
26481
  }
26417
26482
  function safeStat(path) {
26418
26483
  try {
26419
- const s = statSync44(path);
26484
+ const s = statSync45(path);
26420
26485
  if (!s.isFile())
26421
26486
  return null;
26422
26487
  return { mtimeMs: s.mtimeMs, size: s.size };
@@ -26501,8 +26566,8 @@ function* walkCodex() {
26501
26566
  const s = safeStat(path);
26502
26567
  if (!s)
26503
26568
  continue;
26504
- const base3 = e.name.replace(/\.jsonl$/, "");
26505
- 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 };
26506
26571
  }
26507
26572
  }
26508
26573
  }
@@ -26519,7 +26584,7 @@ function* walkAgy() {
26519
26584
  for (const rawId of sessionDirs) {
26520
26585
  const sessionPath = join58(brainDir, rawId);
26521
26586
  try {
26522
- if (!statSync44(sessionPath).isDirectory())
26587
+ if (!statSync45(sessionPath).isDirectory())
26523
26588
  continue;
26524
26589
  } catch {
26525
26590
  continue;
@@ -26644,11 +26709,11 @@ function vaultEnable(passphrase, opts = {}) {
26644
26709
  }
26645
26710
  async function vaultEnableWithRemote(passphrase, remote, opts = {}) {
26646
26711
  const doFetch = opts.fetchImpl ?? fetch;
26647
- const base3 = remote.baseUrl.replace(/\/+$/, "");
26712
+ const base4 = remote.baseUrl.replace(/\/+$/, "");
26648
26713
  const headers = { authorization: `Bearer ${remote.token}`, "content-type": "application/json" };
26649
26714
  let published = { saltHex: null, keyId: null };
26650
26715
  try {
26651
- const r = await doFetch(`${base3}/api/vault/salt`, { headers });
26716
+ const r = await doFetch(`${base4}/api/vault/salt`, { headers });
26652
26717
  if (r.ok)
26653
26718
  published = await r.json();
26654
26719
  } catch {
@@ -26662,7 +26727,7 @@ async function vaultEnableWithRemote(passphrase, remote, opts = {}) {
26662
26727
  }
26663
26728
  const result = vaultEnable(passphrase);
26664
26729
  try {
26665
- const r = await doFetch(`${base3}/api/vault/salt`, {
26730
+ const r = await doFetch(`${base4}/api/vault/salt`, {
26666
26731
  method: "POST",
26667
26732
  headers,
26668
26733
  body: JSON.stringify({ saltHex: result.saltHex, keyId: result.keyId })
@@ -26755,8 +26820,8 @@ async function vaultSync(passphrase) {
26755
26820
  return report;
26756
26821
  }
26757
26822
  function importedPathFor(tool, sessionId) {
26758
- const base3 = sessionId.replace(/^gemini_/, "").replace(/^codex_/, "").replace(/^agy_/, "").replace(/^cursor_/, "").replace(/^opencode_/, "");
26759
- 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`);
26760
26825
  }
26761
26826
  async function vaultRestore(passphrase, opts = {}) {
26762
26827
  const ctx = context2();
@@ -27157,8 +27222,8 @@ var init_decision_guard = __esm({
27157
27222
  isManifest = (p) => {
27158
27223
  if (!p)
27159
27224
  return false;
27160
- const base3 = p.split(/[\\/]/).pop()?.toLowerCase() ?? "";
27161
- return MANIFESTS.includes(base3);
27225
+ const base4 = p.split(/[\\/]/).pop()?.toLowerCase() ?? "";
27226
+ return MANIFESTS.includes(base4);
27162
27227
  };
27163
27228
  }
27164
27229
  });
@@ -27756,8 +27821,8 @@ async function deviceLogin(opts, onPrompt) {
27756
27821
  throw new Error("device-auth timed out \u2014 the code expired before approval.");
27757
27822
  }
27758
27823
  async function betterAuthDeviceLogin(serverUrl, onPrompt) {
27759
- const base3 = serverUrl.replace(/\/+$/, "");
27760
- const startRes = await fetch(`${base3}/api/auth/device/code`, {
27824
+ const base4 = serverUrl.replace(/\/+$/, "");
27825
+ const startRes = await fetch(`${base4}/api/auth/device/code`, {
27761
27826
  method: "POST",
27762
27827
  headers: { "content-type": "application/json" },
27763
27828
  body: JSON.stringify({ client_id: BETTER_AUTH_CLI_CLIENT_ID })
@@ -27765,7 +27830,7 @@ async function betterAuthDeviceLogin(serverUrl, onPrompt) {
27765
27830
  if (!startRes.ok) {
27766
27831
  throw new Error(`device-auth init failed: HTTP ${startRes.status} ${await startRes.text().catch(() => "")}`);
27767
27832
  }
27768
- const start = await readDeviceCode(startRes, base3);
27833
+ const start = await readDeviceCode(startRes, base4);
27769
27834
  onPrompt({
27770
27835
  url: start.verification_uri_complete || start.verification_uri,
27771
27836
  userCode: start.user_code,
@@ -27775,7 +27840,7 @@ async function betterAuthDeviceLogin(serverUrl, onPrompt) {
27775
27840
  let interval = (start.interval ?? 5) * 1e3;
27776
27841
  while (Date.now() < deadline) {
27777
27842
  await sleep(interval);
27778
- const res = await fetch(`${base3}/api/auth/device/token`, {
27843
+ const res = await fetch(`${base4}/api/auth/device/token`, {
27779
27844
  method: "POST",
27780
27845
  headers: { "content-type": "application/json" },
27781
27846
  body: JSON.stringify({
@@ -27877,7 +27942,7 @@ async function selectSessions(target, opts, fetchImpl = fetch) {
27877
27942
  const qs = new URLSearchParams({ limit: String(PAGE), offset: String(offset) });
27878
27943
  if (opts.project) qs.set("project", opts.project);
27879
27944
  if (opts.tool) qs.set("tool", opts.tool);
27880
- const res = await fetchImpl(`${base2(target.serverUrl)}/api/conversations/recent?${qs}`, {
27945
+ const res = await fetchImpl(`${base3(target.serverUrl)}/api/conversations/recent?${qs}`, {
27881
27946
  headers: { authorization: `Bearer ${target.token}` }
27882
27947
  });
27883
27948
  if (!res.ok) throw new Error(`list failed: HTTP ${res.status}`);
@@ -27906,7 +27971,7 @@ async function bulkDelete(ids, opts = {}) {
27906
27971
  try {
27907
27972
  for (let i = 0; i < unique.length; i += BATCH) {
27908
27973
  const slice = unique.slice(i, i + BATCH);
27909
- const res = await fetchImpl(`${base2(t.serverUrl)}/api/sync`, {
27974
+ const res = await fetchImpl(`${base3(t.serverUrl)}/api/sync`, {
27910
27975
  method: "POST",
27911
27976
  headers: { "content-type": "application/json", authorization: `Bearer ${t.token}` },
27912
27977
  body: JSON.stringify({
@@ -27942,7 +28007,7 @@ async function bulkDelete(ids, opts = {}) {
27942
28007
  return out;
27943
28008
  }
27944
28009
  async function listTombstones(target, limit = 500, fetchImpl = fetch) {
27945
- 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}`, {
27946
28011
  headers: { authorization: `Bearer ${target.token}` }
27947
28012
  });
27948
28013
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
@@ -27959,7 +28024,7 @@ async function restoreSessions(ids, opts = {}) {
27959
28024
  try {
27960
28025
  let restored = 0, notDeleted = 0;
27961
28026
  for (let i = 0; i < unique.length; i += BATCH) {
27962
- const res = await fetchImpl(`${base2(t.serverUrl)}/api/data/restore`, {
28027
+ const res = await fetchImpl(`${base3(t.serverUrl)}/api/data/restore`, {
27963
28028
  method: "POST",
27964
28029
  headers: { "content-type": "application/json", authorization: `Bearer ${t.token}` },
27965
28030
  body: JSON.stringify({ session_ids: unique.slice(i, i + BATCH) })
@@ -27982,7 +28047,7 @@ function needsConfirmation(opts) {
27982
28047
  const enumeratedByCaller = opts.argvIds > 0 && !opts.project && !opts.stdin;
27983
28048
  return !enumeratedByCaller;
27984
28049
  }
27985
- var PAGE, BATCH, base2;
28050
+ var PAGE, BATCH, base3;
27986
28051
  var init_bulk_delete = __esm({
27987
28052
  "src/bulk-delete.ts"() {
27988
28053
  "use strict";
@@ -27990,7 +28055,7 @@ var init_bulk_delete = __esm({
27990
28055
  init_sync_ledger();
27991
28056
  PAGE = 200;
27992
28057
  BATCH = 250;
27993
- base2 = (url) => url.replace(/\/+$/, "");
28058
+ base3 = (url) => url.replace(/\/+$/, "");
27994
28059
  }
27995
28060
  });
27996
28061
 
@@ -28355,13 +28420,13 @@ function requireTarget() {
28355
28420
  }
28356
28421
  return t;
28357
28422
  }
28358
- async function readJsonBody(res, base3, what) {
28423
+ async function readJsonBody(res, base4, what) {
28359
28424
  const text = await res.text().catch(() => "");
28360
28425
  try {
28361
28426
  return JSON.parse(text);
28362
28427
  } catch {
28363
28428
  throw new Error(
28364
- `${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`
28365
28430
  );
28366
28431
  }
28367
28432
  }
@@ -29167,9 +29232,9 @@ program.command("feedback").argument("<message...>", "what you want to say \u201
29167
29232
  return;
29168
29233
  }
29169
29234
  const target = firstTarget();
29170
- 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(/\/+$/, "");
29171
29236
  try {
29172
- const res = await fetch(`${base3}/api/contact/feedback`, {
29237
+ const res = await fetch(`${base4}/api/contact/feedback`, {
29173
29238
  method: "POST",
29174
29239
  headers: {
29175
29240
  "content-type": "application/json",
@@ -29196,14 +29261,14 @@ program.command("feedback").argument("<message...>", "what you want to say \u201
29196
29261
  console.log(chalk2.dim(" Add --email <address> next time if you want a reply."));
29197
29262
  }
29198
29263
  } catch (err) {
29199
- console.error(chalk2.red(`Could not reach ${base3}.`));
29264
+ console.error(chalk2.red(`Could not reach ${base4}.`));
29200
29265
  console.error(chalk2.dim(" Your message, so it is not lost:"));
29201
29266
  console.error(chalk2.dim(` ${message}`));
29202
29267
  process.exitCode = 1;
29203
29268
  }
29204
29269
  });
29205
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) => {
29206
- const { existsSync: existsSync58, readFileSync: readFileSync50, statSync: statSync45 } = await import("fs");
29271
+ const { existsSync: existsSync58, readFileSync: readFileSync50, statSync: statSync46 } = await import("fs");
29207
29272
  const { execSync: execSync6 } = await import("child_process");
29208
29273
  const rows = [];
29209
29274
  const note = (ok, label, detail) => rows.push({ ok, label, detail });
@@ -29271,7 +29336,7 @@ program.command("doctor").description("Quick health check across login, server,
29271
29336
  note(false, "Credentials file", `missing \u2014 run \`chat-recall login <server-url>\``);
29272
29337
  } else {
29273
29338
  try {
29274
- const mode = statSync45(credFile).mode & 511;
29339
+ const mode = statSync46(credFile).mode & 511;
29275
29340
  const isWin = process.platform === "win32";
29276
29341
  const safe = isWin || (mode & 63) === 0;
29277
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"})`);
@@ -29801,13 +29866,13 @@ sources2.command("decline <path>").description("Keep a folder out of sync (e.g.
29801
29866
  }
29802
29867
  const { fetchWithTimeout: fetchWithTimeout2 } = await Promise.resolve().then(() => (init_http(), http_exports));
29803
29868
  for (const t of targets) {
29804
- const base3 = t.serverUrl.replace(/\/+$/, "");
29869
+ const base4 = t.serverUrl.replace(/\/+$/, "");
29805
29870
  const headers = {};
29806
29871
  if (t.token) headers.authorization = `Bearer ${t.token}`;
29807
29872
  let deleted = 0, missing = 0, failed = 0;
29808
29873
  for (const id of ids) {
29809
29874
  try {
29810
- 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);
29811
29876
  if (res.ok) deleted++;
29812
29877
  else if (res.status === 404) missing++;
29813
29878
  else failed++;
@@ -29815,7 +29880,7 @@ sources2.command("decline <path>").description("Keep a folder out of sync (e.g.
29815
29880
  failed++;
29816
29881
  }
29817
29882
  }
29818
- 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`) : "");
29819
29884
  console.log(failed ? chalk2.yellow(line) : chalk2.green(line));
29820
29885
  if (failed) process.exitCode = 1;
29821
29886
  }
@@ -30597,7 +30662,7 @@ program.command("task-hook").description("Move a board card when a prompt or a c
30597
30662
  }
30598
30663
  });
30599
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) => {
30600
- 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");
30601
30666
  const { fileURLToPath: fileURLToPath6 } = await import("url");
30602
30667
  const { boardHookEntries: boardHookEntries2, isBoardHookEntry: isBoardHookEntry2, registerBoardHooks: registerBoardHooks2, resolveCliEntry: resolveCliEntry2 } = await Promise.resolve().then(() => (init_board_hooks(), board_hooks_exports));
30603
30668
  const here = fileURLToPath6(new URL(".", import.meta.url));
@@ -30812,18 +30877,18 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
30812
30877
  writeFileSync24(hooksJson, JSON.stringify(config2, null, 2) + "\n");
30813
30878
  }
30814
30879
  if (installGuard) await addGuardToOtherTools(installedGuardHook);
30815
- const saveSz = statSync45(installedSaveHook).size;
30880
+ const saveSz = statSync46(installedSaveHook).size;
30816
30881
  console.log(chalk2.green(`\u2713 Installed chat-recall save hook (${saveSz} bytes)`));
30817
30882
  if (installResume) {
30818
- const resumeSz = statSync45(installedResumeHook).size;
30883
+ const resumeSz = statSync46(installedResumeHook).size;
30819
30884
  console.log(chalk2.green(`\u2713 Installed chat-recall resume-hint hook (${resumeSz} bytes)`));
30820
30885
  }
30821
30886
  if (installEscalate) {
30822
- const escalateSz = statSync45(installedEscalateHook).size;
30887
+ const escalateSz = statSync46(installedEscalateHook).size;
30823
30888
  console.log(chalk2.green(`\u2713 Installed chat-recall learnings-escalation hook (${escalateSz} bytes)`));
30824
30889
  }
30825
30890
  if (installGuard) {
30826
- const guardSz = statSync45(installedGuardHook).size;
30891
+ const guardSz = statSync46(installedGuardHook).size;
30827
30892
  console.log(chalk2.green(`\u2713 Installed chat-recall decision guard (${guardSz} bytes)`));
30828
30893
  }
30829
30894
  if (installTaskBoard) {
@@ -30831,7 +30896,7 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
30831
30896
  console.log(chalk2.dim(" A prompt naming a card id claims it; a commit message naming one closes it."));
30832
30897
  }
30833
30898
  if (installWakeup) {
30834
- const wakeupSz = statSync45(installedWakeupHook).size;
30899
+ const wakeupSz = statSync46(installedWakeupHook).size;
30835
30900
  console.log(chalk2.green(`\u2713 Installed chat-recall wake-up hook (${wakeupSz} bytes)`));
30836
30901
  for (const f of wakeupSkipped) {
30837
30902
  console.log(chalk2.dim(` (SessionStart already wired in ${f} \u2014 left as is, not duplicated)`));
@@ -30948,10 +31013,10 @@ program.command("service <action>").description("Manage the per-user background
30948
31013
  });
30949
31014
  async function runLogin(serverUrl, opts) {
30950
31015
  const { saveCredentials: saveCredentials2, loadAllCredentials: loadAllCredentials2 } = await Promise.resolve().then(() => (init_sync_client(), sync_client_exports));
30951
- const base3 = serverUrl.replace(/\/+$/, "");
31016
+ const base4 = serverUrl.replace(/\/+$/, "");
30952
31017
  const verifyToken = async (token) => {
30953
31018
  try {
30954
- const res = await fetch(`${base3}/api/status`, {
31019
+ const res = await fetch(`${base4}/api/status`, {
30955
31020
  headers: token ? { authorization: `Bearer ${token}` } : {},
30956
31021
  signal: AbortSignal.timeout(1e4)
30957
31022
  });
@@ -30967,36 +31032,36 @@ async function runLogin(serverUrl, opts) {
30967
31032
  return failLogin(opts, 'the token contains non-ASCII characters \u2014 this looks like a masked/truncated copy (e.g. "ct_12345678\u2026")');
30968
31033
  }
30969
31034
  const { probeServer: identifyServer, probeOk: identified, probeAdvice: identifyAdvice } = await Promise.resolve().then(() => (init_server_probe(), server_probe_exports));
30970
- const who = await identifyServer(base3, { timeoutMs: 1e4 });
30971
- 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));
30972
31037
  const check = await verifyToken(token);
30973
31038
  if (!check.ok) {
30974
31039
  if (check.status === 401 || check.status === 403) {
30975
31040
  console.error(chalk2.dim("Tokens are shown once \u2014 mint a fresh one (Account \u2192 Connect your machine) and copy the whole line."));
30976
- return failLogin(opts, `${base3} rejected the token (HTTP ${check.status})`);
31041
+ return failLogin(opts, `${base4} rejected the token (HTTP ${check.status})`);
30977
31042
  }
30978
31043
  if (check.status !== void 0 && check.status >= 500) {
30979
- 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.`);
30980
31045
  }
30981
31046
  if (check.status === 404 || check.status === 410) {
30982
- 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.`);
30983
31048
  }
30984
- 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}`}`);
30985
31050
  }
30986
31051
  saveCredentials2({ serverUrl, token });
30987
31052
  console.log(chalk2.green("\u2713 Logged in.") + chalk2.dim(` server: ${serverUrl} (token verified)`));
30988
31053
  return;
30989
31054
  }
30990
- const existing = loadAllCredentials2().find((t) => t.serverUrl.replace(/\/+$/, "") === base3);
31055
+ const existing = loadAllCredentials2().find((t) => t.serverUrl.replace(/\/+$/, "") === base4);
30991
31056
  if (existing && (await verifyToken(existing.token)).ok) {
30992
31057
  console.log(chalk2.green("\u2713 Already connected.") + chalk2.dim(` server: ${serverUrl} (existing token verified)`));
30993
31058
  return;
30994
31059
  }
30995
31060
  try {
30996
31061
  const { probeServer: probeServer2, probeOk: probeOk2 } = await Promise.resolve().then(() => (init_server_probe(), server_probe_exports));
30997
- const identified = await probeServer2(base3, { timeoutMs: 8e3 });
31062
+ const identified = await probeServer2(base4, { timeoutMs: 8e3 });
30998
31063
  if (probeOk2(identified)) {
30999
- const probe = await fetch(`${base3}/api/status`, { signal: AbortSignal.timeout(8e3) });
31064
+ const probe = await fetch(`${base4}/api/status`, { signal: AbortSignal.timeout(8e3) });
31000
31065
  if (probe.status === 200) {
31001
31066
  saveCredentials2({ serverUrl, token: "" });
31002
31067
  console.log(chalk2.green("\u2713 Logged in.") + chalk2.dim(` ${serverUrl} (local server \u2014 no auth, no token needed)`));
@@ -31017,16 +31082,16 @@ async function runLogin(serverUrl, opts) {
31017
31082
  if (!issuer) {
31018
31083
  const { probeServer: probeServer2, probeOk: probeOk2, probeAdvice: probeAdvice2 } = await Promise.resolve().then(() => (init_server_probe(), server_probe_exports));
31019
31084
  for (let attempt = 1; attempt <= 3 && !authProvider; attempt++) {
31020
- const probe = await probeServer2(base3, { timeoutMs: 15e3 });
31085
+ const probe = await probeServer2(base4, { timeoutMs: 15e3 });
31021
31086
  if (probeOk2(probe)) {
31022
31087
  const caps = probe.raw;
31023
31088
  authProvider = caps?.authProvider;
31024
31089
  if (caps?.oidcIssuer) issuer = caps.oidcIssuer;
31025
31090
  capsError = null;
31026
31091
  } else if (probe.kind === "moved" || probe.kind === "not_api") {
31027
- return failLogin(opts, probeAdvice2(probe, base3));
31092
+ return failLogin(opts, probeAdvice2(probe, base4));
31028
31093
  } else {
31029
- capsError = probeAdvice2(probe, base3);
31094
+ capsError = probeAdvice2(probe, base4);
31030
31095
  }
31031
31096
  if (!authProvider && attempt < 3) await new Promise((r) => setTimeout(r, attempt * 1e3));
31032
31097
  }
@@ -31035,7 +31100,7 @@ async function runLogin(serverUrl, opts) {
31035
31100
  authProvider = "better-auth";
31036
31101
  if (capsError) {
31037
31102
  console.log(` ${chalk2.yellow("Could not read the server's capabilities")} (${capsError}) \u2014 assuming the standard sign-in flow.`);
31038
- 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, {
31039
31104
  step: "cli_login_probe",
31040
31105
  reason: capsError?.slice(0, 40) ?? null,
31041
31106
  message: capsError
@@ -31057,20 +31122,20 @@ async function runLogin(serverUrl, opts) {
31057
31122
  console.log(chalk2.dim(` If the page asks for a code: ${chalk2.bold(p.userCode)}`));
31058
31123
  console.log(chalk2.dim("Then come back here \u2014 this finishes on its own. Waiting\u2026"));
31059
31124
  };
31060
- 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);
31061
31126
  const authHdr = { authorization: `Bearer ${tokens.accessToken}`, "content-type": "application/json" };
31062
- const meRes = await fetch(`${base3}/api/me`, { headers: authHdr });
31063
- if (!meRes.ok) throw new Error(`${base3}/api/me: HTTP ${meRes.status} ${await meRes.text().catch(() => "")}`);
31064
- 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");
31065
31130
  const teams = me.teams || [];
31066
31131
  let slug = opts.team;
31067
31132
  if (!slug) {
31068
31133
  if (teams.length === 1) slug = teams[0].team_slug;
31069
31134
  else if (teams.length === 0) {
31070
31135
  const name = me.user?.email?.split("@")[0]?.replace(/[^a-z0-9]/gi, "") || "workspace";
31071
- 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 }) });
31072
31137
  if (!created.ok) throw new Error(`workspace create failed: HTTP ${created.status} ${await created.text().catch(() => "")}`);
31073
- slug = (await readJsonBody(created, base3, "POST /api/teams")).slug;
31138
+ slug = (await readJsonBody(created, base4, "POST /api/teams")).slug;
31074
31139
  console.log(chalk2.dim(`Created workspace "${name}" (${slug}) \u2014 you're its owner.`));
31075
31140
  } else {
31076
31141
  teams.forEach((t) => console.error(` ${t.team_slug} ${chalk2.dim(t.name)}`));
@@ -31078,13 +31143,13 @@ async function runLogin(serverUrl, opts) {
31078
31143
  }
31079
31144
  }
31080
31145
  const deviceId = opts.deviceId || (await import("node:os")).hostname();
31081
- const mint = await fetch(`${base3}/api/teams/${encodeURIComponent(slug)}/tokens`, {
31146
+ const mint = await fetch(`${base4}/api/teams/${encodeURIComponent(slug)}/tokens`, {
31082
31147
  method: "POST",
31083
31148
  headers: authHdr,
31084
31149
  body: JSON.stringify({ device_id: deviceId })
31085
31150
  });
31086
31151
  if (!mint.ok) throw new Error(`token mint failed: HTTP ${mint.status} ${await mint.text().catch(() => "")}`);
31087
- const { token } = await readJsonBody(mint, base3, "POST /api/teams/:slug/tokens");
31152
+ const { token } = await readJsonBody(mint, base4, "POST /api/teams/:slug/tokens");
31088
31153
  saveCredentials2({ serverUrl, token });
31089
31154
  console.log(chalk2.green(`\u2713 Logged in to ${chalk2.bold(slug)}`) + chalk2.dim(` (device: ${deviceId}) server: ${serverUrl}`));
31090
31155
  if (!opts.fromInit) {
@@ -31561,16 +31626,16 @@ program.command("update").description("Update this CLI now from the server you s
31561
31626
  }
31562
31627
  let installFailed = false;
31563
31628
  for (const cred of targets) {
31564
- const base3 = cred.serverUrl.replace(/\/+$/, "");
31629
+ const base4 = cred.serverUrl.replace(/\/+$/, "");
31565
31630
  const headers = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
31566
- const r = await runAutoUpdate2(base3, headers, cliVersion3());
31631
+ const r = await runAutoUpdate2(base4, headers, cliVersion3());
31567
31632
  if (r.updated) {
31568
- console.log(chalk2.green(`\u2713 ${r.reason}`) + chalk2.dim(` (${base3})`));
31633
+ console.log(chalk2.green(`\u2713 ${r.reason}`) + chalk2.dim(` (${base4})`));
31569
31634
  continue;
31570
31635
  }
31571
31636
  const benign = /already current|no CLI release|disabled/.test(r.reason);
31572
31637
  if (/install failed|download failed|checksum/.test(r.reason)) installFailed = true;
31573
- 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})`));
31574
31639
  }
31575
31640
  const check = await refreshUpdateCheck2(true);
31576
31641
  if (installFailed) {