chat-recall 0.7.0 → 0.7.1

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
@@ -8093,7 +8093,7 @@ var init_opencode = __esm({
8093
8093
 
8094
8094
  // ../engine/dist/core/backends/tail-read.js
8095
8095
  import { openSync as openSync2, readSync as readSync2, closeSync as closeSync2, statSync as statSync4 } from "node:fs";
8096
- function readTailFromOffset(path, offset) {
8096
+ function readTailFromOffset(path, offset, maxBytes = TAIL_READ_MAX_BYTES) {
8097
8097
  let size = 0;
8098
8098
  try {
8099
8099
  size = statSync4(path).size;
@@ -8102,7 +8102,7 @@ function readTailFromOffset(path, offset) {
8102
8102
  }
8103
8103
  if (size <= offset)
8104
8104
  return { text: "", newOffset: offset };
8105
- const len = Math.min(size - offset, 16 * 1024 * 1024);
8105
+ const len = Math.min(size - offset, Math.max(1, maxBytes));
8106
8106
  const buf = Buffer.allocUnsafe(len);
8107
8107
  let fd = null;
8108
8108
  try {
@@ -8118,11 +8118,16 @@ function readTailFromOffset(path, offset) {
8118
8118
  return { text: "", newOffset: offset };
8119
8119
  const slice = got < len ? buf.subarray(0, got) : buf;
8120
8120
  const lastNl = slice.lastIndexOf(10);
8121
- if (lastNl < 0) {
8122
- return { text: "", newOffset: offset };
8121
+ if (lastNl >= 0) {
8122
+ const text = slice.subarray(0, lastNl + 1).toString("utf-8");
8123
+ return { text, newOffset: offset + lastNl + 1 };
8123
8124
  }
8124
- const text = slice.subarray(0, lastNl + 1).toString("utf-8");
8125
- return { text, newOffset: offset + lastNl + 1 };
8125
+ if (offset + got >= size)
8126
+ return { text: "", newOffset: offset };
8127
+ const end = findNewline(fd, offset + got, size);
8128
+ if (end < 0)
8129
+ return { text: "", newOffset: offset };
8130
+ return { text: "", newOffset: end + 1, skippedBytes: end + 1 - offset };
8126
8131
  } catch {
8127
8132
  return { text: "", newOffset: offset };
8128
8133
  } finally {
@@ -8134,9 +8139,26 @@ function readTailFromOffset(path, offset) {
8134
8139
  }
8135
8140
  }
8136
8141
  }
8142
+ function findNewline(fd, from, size) {
8143
+ const block = Buffer.allocUnsafe(SKIP_SCAN_BYTES);
8144
+ let pos = from;
8145
+ while (pos < size) {
8146
+ const n = readSync2(fd, block, 0, Math.min(SKIP_SCAN_BYTES, size - pos), pos);
8147
+ if (n <= 0)
8148
+ return -1;
8149
+ const i = block.subarray(0, n).indexOf(10);
8150
+ if (i >= 0)
8151
+ return pos + i;
8152
+ pos += n;
8153
+ }
8154
+ return -1;
8155
+ }
8156
+ var TAIL_READ_MAX_BYTES, SKIP_SCAN_BYTES;
8137
8157
  var init_tail_read = __esm({
8138
8158
  "../engine/dist/core/backends/tail-read.js"() {
8139
8159
  "use strict";
8160
+ TAIL_READ_MAX_BYTES = 16 * 1024 * 1024;
8161
+ SKIP_SCAN_BYTES = 1024 * 1024;
8140
8162
  }
8141
8163
  });
8142
8164
 
@@ -8843,11 +8865,11 @@ var init_codex2 = __esm({
8843
8865
  return 0;
8844
8866
  }
8845
8867
  }
8846
- async readFromOffset(prefixedId, offset) {
8868
+ async readFromOffset(prefixedId, offset, maxBytes) {
8847
8869
  const loc = this.findSession(prefixedId);
8848
8870
  if (!loc)
8849
8871
  return { text: "", newOffset: offset };
8850
- return readTailFromOffset(loc.path, offset);
8872
+ return readTailFromOffset(loc.path, offset, maxBytes);
8851
8873
  }
8852
8874
  };
8853
8875
  codexBackend = new CodexBackend();
@@ -9408,11 +9430,11 @@ var init_agy = __esm({
9408
9430
  return 0;
9409
9431
  }
9410
9432
  }
9411
- async readFromOffset(prefixedId, offset) {
9433
+ async readFromOffset(prefixedId, offset, maxBytes) {
9412
9434
  const loc = this.findSession(prefixedId);
9413
9435
  if (!loc)
9414
9436
  return { text: "", newOffset: offset };
9415
- return readTailFromOffset(loc.path, offset);
9437
+ return readTailFromOffset(loc.path, offset, maxBytes);
9416
9438
  }
9417
9439
  };
9418
9440
  agyBackend = new AgyBackend();
@@ -10608,7 +10630,7 @@ var init_backends = __esm({
10608
10630
  // ../engine/dist/transcript/shadow.js
10609
10631
  import { gzipSync as gzipSync2, gunzipSync as gunzipSync2 } from "zlib";
10610
10632
  import { createHash as createHash2 } from "crypto";
10611
- import { existsSync as existsSync12, mkdirSync as mkdirSync3, readFileSync as readFileSync8, writeFileSync as writeFileSync2, renameSync as renameSync2, statSync as statSync10 } from "fs";
10633
+ import { existsSync as existsSync12, mkdirSync as mkdirSync3, readFileSync as readFileSync8, writeFileSync as writeFileSync2, renameSync as renameSync2, statSync as statSync10, openSync as openSync4, readSync as readSync4, closeSync as closeSync4 } from "fs";
10612
10634
  import { dirname as dirname12, join as join14 } from "path";
10613
10635
  function shadowRoot() {
10614
10636
  return join14(getDataDir(), "shadow");
@@ -10832,6 +10854,29 @@ function seedShadow(sessionId, container) {
10832
10854
  }
10833
10855
  return fullest;
10834
10856
  }
10857
+ function shadowUncompressedBytes(tool, rawId) {
10858
+ const path = shadowFileFor(tool, rawId);
10859
+ let fd = null;
10860
+ try {
10861
+ const size = statSync10(path).size;
10862
+ if (size < 18)
10863
+ return 0;
10864
+ fd = openSync4(path, "r");
10865
+ const tail = Buffer.alloc(4);
10866
+ if (readSync4(fd, tail, 0, 4, size - 4) !== 4)
10867
+ return 0;
10868
+ return tail.readUInt32LE(0);
10869
+ } catch {
10870
+ return 0;
10871
+ } finally {
10872
+ if (fd !== null) {
10873
+ try {
10874
+ closeSync4(fd);
10875
+ } catch {
10876
+ }
10877
+ }
10878
+ }
10879
+ }
10835
10880
  function shadowSizeOnDisk(tool, rawId) {
10836
10881
  try {
10837
10882
  return statSync10(shadowFileFor(tool, rawId)).size;
@@ -10852,7 +10897,7 @@ var init_shadow = __esm({
10852
10897
  });
10853
10898
 
10854
10899
  // ../engine/dist/core/live-session-scan.js
10855
- import { existsSync as existsSync13, readdirSync as readdirSync10, readFileSync as readFileSync9, statSync as statSync11, openSync as openSync4, readSync as readSync4, closeSync as closeSync4 } from "fs";
10900
+ import { existsSync as existsSync13, readdirSync as readdirSync10, readFileSync as readFileSync9, statSync as statSync11, openSync as openSync5, readSync as readSync5, closeSync as closeSync5 } from "fs";
10856
10901
  import { join as join15, basename as basename9 } from "path";
10857
10902
  function detectTool(sessionId) {
10858
10903
  return getBackendForId(sessionId)?.id ?? "claude";
@@ -10879,6 +10924,15 @@ function sessionFileIndex() {
10879
10924
  return indexCache;
10880
10925
  const byId = /* @__PURE__ */ new Map();
10881
10926
  const seenRoots = /* @__PURE__ */ new Set();
10927
+ const projectPaths = /* @__PURE__ */ new Map();
10928
+ const projectPathOf = (dirName) => {
10929
+ let p = projectPaths.get(dirName);
10930
+ if (p === void 0) {
10931
+ p = resolveProjectDirName(dirName);
10932
+ projectPaths.set(dirName, p);
10933
+ }
10934
+ return p;
10935
+ };
10882
10936
  for (const root of claudeProjectDirs()) {
10883
10937
  if (seenRoots.has(root) || !existsSync13(root))
10884
10938
  continue;
@@ -10906,7 +10960,7 @@ function sessionFileIndex() {
10906
10960
  const located = {
10907
10961
  path: join15(dir, name),
10908
10962
  projectDir: entry.name,
10909
- projectPath: resolveProjectDirName(entry.name)
10963
+ projectPath: projectPathOf(entry.name)
10910
10964
  };
10911
10965
  const prior = byId.get(id);
10912
10966
  if (prior)
@@ -11096,7 +11150,7 @@ var init_live_session_scan = __esm({
11096
11150
  });
11097
11151
 
11098
11152
  // ../engine/dist/core/first-prompt.js
11099
- import { createReadStream as createReadStream2, existsSync as existsSync14, openSync as openSync5, readSync as readSync5, closeSync as closeSync5 } from "fs";
11153
+ import { createReadStream as createReadStream2, existsSync as existsSync14, openSync as openSync6, readSync as readSync6, closeSync as closeSync6 } from "fs";
11100
11154
  import { StringDecoder } from "string_decoder";
11101
11155
  function stripBanners2(s) {
11102
11156
  let out = s;
@@ -11150,7 +11204,7 @@ function extractFirstUserPromptSync(filePath, options = {}) {
11150
11204
  const maxBytes = options.maxBytes ?? 4 * 1024 * 1024;
11151
11205
  let fd;
11152
11206
  try {
11153
- fd = openSync5(filePath, "r");
11207
+ fd = openSync6(filePath, "r");
11154
11208
  } catch {
11155
11209
  return "";
11156
11210
  }
@@ -11162,7 +11216,7 @@ function extractFirstUserPromptSync(filePath, options = {}) {
11162
11216
  let pos = 0;
11163
11217
  let lineNo = 0;
11164
11218
  for (; ; ) {
11165
- const n = readSync5(fd, buf, 0, CHUNK, pos);
11219
+ const n = readSync6(fd, buf, 0, CHUNK, pos);
11166
11220
  if (n <= 0)
11167
11221
  break;
11168
11222
  pos += n;
@@ -11188,7 +11242,7 @@ function extractFirstUserPromptSync(filePath, options = {}) {
11188
11242
  return "";
11189
11243
  } finally {
11190
11244
  try {
11191
- closeSync5(fd);
11245
+ closeSync6(fd);
11192
11246
  } catch {
11193
11247
  }
11194
11248
  }
@@ -11207,7 +11261,7 @@ var init_first_prompt = __esm({
11207
11261
  });
11208
11262
 
11209
11263
  // ../engine/dist/core/backends/claude.js
11210
- import { existsSync as existsSync15, readdirSync as readdirSync11, readFileSync as readFileSync10, statSync as statSync12, openSync as openSync6, readSync as readSync6, closeSync as closeSync6 } from "fs";
11264
+ import { existsSync as existsSync15, readdirSync as readdirSync11, readFileSync as readFileSync10, statSync as statSync12, openSync as openSync7, readSync as readSync7, closeSync as closeSync7 } from "fs";
11211
11265
  import { join as join16, basename as basename10 } from "path";
11212
11266
  function stripReminders(text) {
11213
11267
  return text.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g, "").trim();
@@ -11304,13 +11358,13 @@ var init_claude2 = __esm({
11304
11358
  return null;
11305
11359
  let head;
11306
11360
  try {
11307
- const fd = openSync6(located.path, "r");
11361
+ const fd = openSync7(located.path, "r");
11308
11362
  try {
11309
11363
  const buf = Buffer.alloc(65536);
11310
- const n = readSync6(fd, buf, 0, buf.length, 0);
11364
+ const n = readSync7(fd, buf, 0, buf.length, 0);
11311
11365
  head = buf.toString("utf-8", 0, n);
11312
11366
  } finally {
11313
- closeSync6(fd);
11367
+ closeSync7(fd);
11314
11368
  }
11315
11369
  } catch {
11316
11370
  return null;
@@ -11782,14 +11836,14 @@ var init_claude2 = __esm({
11782
11836
  spansMultipleSources(prefixedId) {
11783
11837
  return findSessionFiles(this.toRawId(prefixedId)).length > 1;
11784
11838
  }
11785
- async readFromOffset(prefixedId, offset) {
11839
+ async readFromOffset(prefixedId, offset, maxBytes) {
11786
11840
  const rawId = this.toRawId(prefixedId);
11787
11841
  const copies = findSessionFiles(rawId);
11788
11842
  if (copies.length === 0)
11789
11843
  return { text: "", newOffset: offset };
11790
11844
  if (copies.length > 1)
11791
11845
  return { text: "", newOffset: offset };
11792
- return readTailFromOffset(copies[0].path, offset);
11846
+ return readTailFromOffset(copies[0].path, offset, maxBytes);
11793
11847
  }
11794
11848
  };
11795
11849
  claudeBackend = new ClaudeBackend();
@@ -13742,10 +13796,10 @@ var init_types = __esm({
13742
13796
 
13743
13797
  // ../engine/dist/transcript/opencode.js
13744
13798
  async function parseOpenCodeSubagents(parentSessionId) {
13745
- const { existsSync: existsSync57 } = await import("fs");
13799
+ const { existsSync: existsSync58 } = await import("fs");
13746
13800
  const { opencodeBackend: opencodeBackend2 } = await Promise.resolve().then(() => (init_opencode(), opencode_exports));
13747
13801
  const dbPath = opencodeBackend2.dbPath();
13748
- if (!existsSync57(dbPath))
13802
+ if (!existsSync58(dbPath))
13749
13803
  return [];
13750
13804
  const realParent = parentSessionId.replace("opencode_", "");
13751
13805
  const db = openSqliteReadonlyOrThrow(dbPath);
@@ -13786,10 +13840,10 @@ async function parseOpenCodeSubagents(parentSessionId) {
13786
13840
  }
13787
13841
  }
13788
13842
  async function parseOpenCodeTranscript(sessionId) {
13789
- const { existsSync: existsSync57 } = await import("fs");
13843
+ const { existsSync: existsSync58 } = await import("fs");
13790
13844
  const { opencodeBackend: opencodeBackend2 } = await Promise.resolve().then(() => (init_opencode(), opencode_exports));
13791
13845
  const dbPath = opencodeBackend2.dbPath();
13792
- if (!existsSync57(dbPath))
13846
+ if (!existsSync58(dbPath))
13793
13847
  return [];
13794
13848
  const realId = sessionId.replace("opencode_", "");
13795
13849
  const db = openSqliteReadonlyOrThrow(dbPath);
@@ -13866,6 +13920,7 @@ __export(transcript_exports, {
13866
13920
  shadowFileFor: () => shadowFileFor,
13867
13921
  shadowRoot: () => shadowRoot,
13868
13922
  shadowSizeOnDisk: () => shadowSizeOnDisk,
13923
+ shadowUncompressedBytes: () => shadowUncompressedBytes,
13869
13924
  snapshotShadow: () => snapshotShadow,
13870
13925
  trimTranscriptForSync: () => trimTranscriptForSync,
13871
13926
  updateShadow: () => updateShadow,
@@ -18335,7 +18390,7 @@ var init_sync_fields = __esm({
18335
18390
  });
18336
18391
 
18337
18392
  // ../engine/dist/core/index-lock.js
18338
- import { existsSync as existsSync39, mkdirSync as mkdirSync7, openSync as openSync7, writeFileSync as writeFileSync6, readFileSync as readFileSync30, rmSync as rmSync4, statSync as statSync35, closeSync as closeSync7 } from "fs";
18393
+ 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";
18339
18394
  import { dirname as dirname16, join as join39 } from "path";
18340
18395
  function acquireIndexLock(opts) {
18341
18396
  const lockPath = lockFilePath();
@@ -18347,7 +18402,7 @@ function acquireIndexLock(opts) {
18347
18402
  }
18348
18403
  let fd;
18349
18404
  try {
18350
- fd = openSync7(lockPath, "wx", 384);
18405
+ fd = openSync8(lockPath, "wx", 384);
18351
18406
  } catch (err) {
18352
18407
  if (err.code === "EEXIST")
18353
18408
  return null;
@@ -18357,7 +18412,7 @@ function acquireIndexLock(opts) {
18357
18412
  try {
18358
18413
  writeFileSync6(fd, JSON.stringify(holder));
18359
18414
  } finally {
18360
- closeSync7(fd);
18415
+ closeSync8(fd);
18361
18416
  }
18362
18417
  let released = false;
18363
18418
  return {
@@ -18457,7 +18512,7 @@ var init_http = __esm({
18457
18512
  CLI_VERSION = JSON.parse(readFileSync31(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
18458
18513
  } catch {
18459
18514
  try {
18460
- if (true) CLI_VERSION = "0.7.0";
18515
+ if (true) CLI_VERSION = "0.7.1";
18461
18516
  } catch {
18462
18517
  }
18463
18518
  }
@@ -18956,7 +19011,7 @@ var init_telemetry = __esm({
18956
19011
  init_sync_client();
18957
19012
  cliVersion2 = () => {
18958
19013
  try {
18959
- return true ? "0.7.0" : "dev";
19014
+ return true ? "0.7.1" : "dev";
18960
19015
  } catch {
18961
19016
  return "dev";
18962
19017
  }
@@ -19312,16 +19367,17 @@ __export(auto_update_exports, {
19312
19367
  noteUpdateFailure: () => noteUpdateFailure,
19313
19368
  planAutoUpdate: () => planAutoUpdate,
19314
19369
  readUpdateState: () => readUpdateState,
19370
+ resolveNpm: () => resolveNpm,
19315
19371
  runAutoUpdate: () => runAutoUpdate,
19316
19372
  runningPrefix: () => runningPrefix,
19317
19373
  sweepStaleStaging: () => sweepStaleStaging,
19318
19374
  tarballUrl: () => tarballUrl
19319
19375
  });
19320
- import { execSync as execSync2 } from "node:child_process";
19321
- import { readFileSync as readFileSync34 } from "node:fs";
19376
+ import { execSync as execSync2, execFileSync as execFileSync3 } from "node:child_process";
19377
+ import { readFileSync as readFileSync34, existsSync as existsSync41 } from "node:fs";
19322
19378
  import { fileURLToPath as fileURLToPath2 } from "node:url";
19323
19379
  import { writeFileSync as writeFileSync8, mkdtempSync as mkdtempSync3, rmSync as rmSync5, readdirSync as readdirSync31, statSync as statSync36, mkdirSync as mkdirSync9 } from "node:fs";
19324
- import { join as join41, dirname as dirname18, sep as sep2 } from "node:path";
19380
+ import { join as join41, dirname as dirname18, sep as sep2, posix as pathPosix, win32 as pathWin32 } from "node:path";
19325
19381
  import { tmpdir as tmpdir2, homedir as homedir15 } from "node:os";
19326
19382
  import { createHash as createHash8 } from "node:crypto";
19327
19383
  function compareVersions(a, b) {
@@ -19436,25 +19492,46 @@ function runningPrefix(moduleUrl = import.meta.url) {
19436
19492
  const beforeNodeModules = here.slice(0, at);
19437
19493
  return beforeNodeModules.endsWith(`${sep2}lib`) ? beforeNodeModules.slice(0, -4) : beforeNodeModules;
19438
19494
  }
19439
- function npmInstall(cmd) {
19495
+ function npmInstall(npm, args) {
19440
19496
  try {
19441
- execSync2(cmd, { stdio: ["ignore", "ignore", "pipe"] });
19497
+ const opts = { stdio: ["ignore", "ignore", "pipe"], env: npm.env };
19498
+ if (npm.shell) execSync2([npm.file, ...npm.args, ...args].map((a) => `"${a}"`).join(" "), opts);
19499
+ else execFileSync3(npm.file, [...npm.args, ...args], opts);
19442
19500
  } catch (e) {
19443
19501
  const err = e;
19444
19502
  const detail = String(err.stderr ?? "").trim().split("\n").filter((l) => l.trim() && !/^npm (notice|warn)\b/i.test(l)).slice(-4).join(" | ").slice(0, 400);
19445
19503
  throw new Error(detail ? `${err.message ?? "install failed"} \u2014 ${detail}` : err.message ?? "install failed");
19446
19504
  }
19447
19505
  }
19506
+ function resolveNpm(loc) {
19507
+ const win = loc.platform === "win32";
19508
+ const p = win ? pathWin32 : pathPosix;
19509
+ const nodeDir = p.dirname(loc.execPath);
19510
+ const cliUnder = (root) => win ? p.join(root, "node_modules", "npm", "bin", "npm-cli.js") : p.join(root, "lib", "node_modules", "npm", "bin", "npm-cli.js");
19511
+ const candidates2 = [
19512
+ cliUnder(win ? nodeDir : p.join(nodeDir, "..")),
19513
+ ...loc.prefix ? [cliUnder(loc.prefix)] : []
19514
+ ];
19515
+ const pathKey = Object.keys(loc.env).find((k) => k.toUpperCase() === "PATH") ?? "PATH";
19516
+ const binDirs = [nodeDir, ...loc.prefix ? [win ? loc.prefix : p.join(loc.prefix, "bin")] : []];
19517
+ const delimiter3 = win ? ";" : ":";
19518
+ const current = loc.env[pathKey] ?? "";
19519
+ const env = { ...loc.env, [pathKey]: [...binDirs, ...current ? [current] : []].join(delimiter3) };
19520
+ const cli = candidates2.find((c) => loc.exists(c));
19521
+ if (cli) return { file: loc.execPath, args: [cli], env, shell: false };
19522
+ return { file: "npm", args: [], env, shell: true };
19523
+ }
19448
19524
  function realInstall(tgz) {
19449
19525
  const prefix = runningPrefix();
19526
+ const npm = resolveNpm({ execPath: process.execPath, prefix, platform: process.platform, env: process.env, exists: existsSync41 });
19450
19527
  if (prefix) {
19451
- npmInstall(`npm install -g --prefix "${prefix}" "${tgz}"`);
19528
+ npmInstall(npm, ["install", "-g", "--prefix", prefix, tgz]);
19452
19529
  return;
19453
19530
  }
19454
19531
  try {
19455
- npmInstall(`npm install -g "${tgz}"`);
19532
+ npmInstall(npm, ["install", "-g", tgz]);
19456
19533
  } catch {
19457
- npmInstall(`npm install -g --prefix "${process.env.HOME}/.local" "${tgz}"`);
19534
+ npmInstall(npm, ["install", "-g", "--prefix", join41(homedir15(), ".local"), tgz]);
19458
19535
  }
19459
19536
  }
19460
19537
  function realRestart(platform2) {
@@ -19555,7 +19632,9 @@ var init_auto_update = __esm({
19555
19632
  var sync_client_exports = {};
19556
19633
  __export(sync_client_exports, {
19557
19634
  BATCH_SCAN_MAX_BYTES: () => BATCH_SCAN_MAX_BYTES,
19635
+ DERIVED_MAX_BYTES: () => DERIVED_MAX_BYTES,
19558
19636
  FULL_BUILD_MAX_BYTES: () => FULL_BUILD_MAX_BYTES,
19637
+ SYNC_CHUNK_BYTES: () => SYNC_CHUNK_BYTES,
19559
19638
  _acceptedUploads: () => _acceptedUploads,
19560
19639
  _fetchTenantSyncConfigForTests: () => _fetchTenantSyncConfigForTests,
19561
19640
  _resetCapsCacheForTests: () => _resetCapsCacheForTests,
@@ -19574,8 +19653,10 @@ __export(sync_client_exports, {
19574
19653
  reconcileFields: () => reconcileFields,
19575
19654
  removeCredentials: () => removeCredentials,
19576
19655
  saveCredentials: () => saveCredentials,
19656
+ scanTranscriptFindingsChunked: () => scanTranscriptFindingsChunked,
19577
19657
  serverAcceptsGzipBody: () => serverAcceptsGzipBody,
19578
19658
  serverIngestConcurrency: () => serverIngestConcurrency,
19659
+ sessionBuildBytes: () => sessionBuildBytes,
19579
19660
  sessionFileBytes: () => sessionFileBytes,
19580
19661
  setServerIngestConcurrency: () => setServerIngestConcurrency,
19581
19662
  syncIncremental: () => syncIncremental,
@@ -20347,16 +20428,53 @@ async function syncToTargetInScope(cred, opts = {}) {
20347
20428
  clearTimeout(timer);
20348
20429
  }
20349
20430
  };
20431
+ const postChunkedHead = async (conv, fileSize) => {
20432
+ const headers = { "content-type": "application/json" };
20433
+ if (cred.token) headers.authorization = `Bearer ${cred.token}`;
20434
+ const ac = new AbortController();
20435
+ const timer = setTimeout(() => ac.abort(new Error(`upload timed out after ${UPLOAD_TIMEOUT_MS}ms`)), UPLOAD_TIMEOUT_MS);
20436
+ try {
20437
+ const res = await fetch(`${base3}/api/sync`, {
20438
+ method: "POST",
20439
+ headers,
20440
+ body: JSON.stringify({ conversations: [conv] }),
20441
+ signal: ac.signal
20442
+ });
20443
+ if (!res.ok) throw new Error(`chunked head sync failed: HTTP ${res.status} ${await res.text().catch(() => "")}`);
20444
+ const body = await res.json().catch(() => ({}));
20445
+ const id = conv.session_id;
20446
+ const guarded = (body.shrink_guarded ?? []).find((g) => g.session_id === id);
20447
+ const mtime = conv.mtime;
20448
+ try {
20449
+ if (!guarded) {
20450
+ markSynced(base3, [{ id, mtime, offset: conv.from_offset, size: conv.from_offset, acked: true }]);
20451
+ } else if (typeof guarded.o === "number" && guarded.o > 0 && guarded.o <= fileSize) {
20452
+ markSynced(base3, [{ id, mtime, offset: guarded.o, size: guarded.o, acked: true }]);
20453
+ } else {
20454
+ markSynced(base3, [{ id, mtime }]);
20455
+ }
20456
+ } catch {
20457
+ }
20458
+ appendResults.uploaded++;
20459
+ } finally {
20460
+ clearTimeout(timer);
20461
+ }
20462
+ };
20350
20463
  let appendBatch = [];
20464
+ let appendBatchBytes = 0;
20351
20465
  const APPEND_BATCH_SIZE = 50;
20466
+ const APPEND_BATCH_MAX_BYTES = SYNC_CHUNK_BYTES;
20352
20467
  const appendFlush = async () => {
20353
20468
  if (appendBatch.length === 0) return;
20354
20469
  const batch = appendBatch;
20355
20470
  appendBatch = [];
20471
+ appendBatchBytes = 0;
20356
20472
  await postAppend(batch);
20357
20473
  };
20358
- const appendAdd = async (conv) => {
20474
+ const appendAdd = async (conv, bytes = 0) => {
20475
+ if (appendBatch.length > 0 && appendBatchBytes + bytes > APPEND_BATCH_MAX_BYTES) await appendFlush();
20359
20476
  appendBatch.push(conv);
20477
+ appendBatchBytes += bytes;
20360
20478
  if (appendBatch.length >= APPEND_BATCH_SIZE) await appendFlush();
20361
20479
  };
20362
20480
  const itemsBatch = makeBatcher("items", 100);
@@ -20435,7 +20553,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20435
20553
  let externalFindings = null;
20436
20554
  if (scanSecrets) {
20437
20555
  externalFindings = /* @__PURE__ */ new Map();
20438
- const toScan = slice.filter((ref) => modeOf(ref) === "full" && sessionFileBytes(ref) <= FULL_BUILD_MAX_BYTES);
20556
+ const toScan = slice.filter((ref) => modeOf(ref) === "full" && sessionBuildBytes(ref) <= FULL_BUILD_MAX_BYTES);
20439
20557
  trace?.(`batch secret scan start: ${toScan.length} session(s), \u2264${(BATCH_SCAN_MAX_BYTES / 1048576).toFixed(0)}MB per slice`);
20440
20558
  const batch = batchScanExternal(
20441
20559
  toScan.map((ref) => ({
@@ -20479,11 +20597,17 @@ async function syncToTargetInScope(cred, opts = {}) {
20479
20597
  const ack = ledger.get(ref.prefixedId);
20480
20598
  try {
20481
20599
  const tail = await buildConversationTail(ref, ack.o ?? 0, { mapPath, tenantRules });
20482
- if (tail && tail.findings.length > 0) {
20600
+ const chunked = sessionBuildBytes(ref) > FULL_BUILD_MAX_BYTES;
20601
+ if (tail && tail.findings.length > 0 && !chunked) {
20483
20602
  promotedForFindings = true;
20484
20603
  } else if (tail) {
20485
20604
  redactions += tail.redactions;
20486
- await appendAdd(tail.conv);
20605
+ await appendAdd(tail.conv, tail.bytes);
20606
+ if (tail.findings.length > 0) {
20607
+ await appendFlush();
20608
+ const all = await scanTranscriptFindingsChunked(ref, tenantRules);
20609
+ if (all.length > 0) await findingsBatch.add(all);
20610
+ }
20487
20611
  walked++;
20488
20612
  if (walked % 250 === 0) console.error(`[sync] ${walked}/${slice.length} sessions\u2026`);
20489
20613
  continue;
@@ -20531,12 +20655,13 @@ async function syncToTargetInScope(cred, opts = {}) {
20531
20655
  }
20532
20656
  redactions += built.redactions;
20533
20657
  if (built.srcHash) shippedHash.set(ref.prefixedId, built.srcHash);
20534
- await convBatch.add(built.conv);
20658
+ if (built.conv.chunked) await postChunkedHead(built.conv, sessionFileBytes(ref));
20659
+ else await convBatch.add(built.conv);
20535
20660
  if (built.findings.length > 0) await findingsBatch.add(built.findings);
20536
20661
  if (upload.sessionMeta) {
20537
20662
  await accumulateKg(extractEntities(built.kgText, { projectPath: built.projectPath, sourceType: "session", sessionId: ref.prefixedId, validFrom: ref.mtime ? new Date(ref.mtime).toISOString().slice(0, 10) : void 0 }), ref.prefixedId);
20538
20663
  }
20539
- if (upload.sessionMeta && sessionFileBytes(ref) <= FULL_BUILD_MAX_BYTES) {
20664
+ if (upload.sessionMeta && sessionFileBytes(ref) <= DERIVED_MAX_BYTES) {
20540
20665
  try {
20541
20666
  const count = { redactions: 0 };
20542
20667
  const offloaded = await scanPool().runDerived({
@@ -20716,35 +20841,70 @@ async function syncToTargetInScope(cred, opts = {}) {
20716
20841
  scanMs: Math.round(scanMs)
20717
20842
  };
20718
20843
  }
20844
+ async function scanTranscriptFindingsChunked(ref, tenantRules) {
20845
+ const backend = getBackendForId(ref.prefixedId);
20846
+ const findings = [];
20847
+ if (!backend?.readFromOffset) return findings;
20848
+ let offset = 0;
20849
+ let lineBase = 0;
20850
+ for (; ; ) {
20851
+ const chunk = await backend.readFromOffset(ref.prefixedId, offset, SYNC_CHUNK_BYTES);
20852
+ if (chunk.newOffset <= offset) break;
20853
+ offset = chunk.newOffset;
20854
+ if (chunk.skippedBytes) {
20855
+ lineBase += 1;
20856
+ continue;
20857
+ }
20858
+ try {
20859
+ for (const f of scanTextForFindings(chunk.text)) {
20860
+ findings.push({ session_id: ref.prefixedId, detector: "builtin", rule: f.rule, line: lineBase + f.line, preview: f.preview });
20861
+ }
20862
+ if (tenantRules && tenantRules.length > 0) {
20863
+ for (const f of scanTenantRules(chunk.text, tenantRules)) {
20864
+ findings.push({ session_id: ref.prefixedId, detector: f.detector, rule: f.rule, line: lineBase + f.line, preview: f.preview });
20865
+ }
20866
+ }
20867
+ } catch {
20868
+ }
20869
+ for (let i = chunk.text.indexOf("\n"); i >= 0; i = chunk.text.indexOf("\n", i + 1)) lineBase++;
20870
+ }
20871
+ return dropFuzzyFindings(findings, (f) => ({ detector: f.detector, rule: f.rule }));
20872
+ }
20719
20873
  function sessionFileBytes(ref) {
20720
20874
  const backend = getBackendForId(ref.prefixedId);
20721
20875
  if (!backend?.isAppendOnly?.()) return 0;
20722
20876
  return backend.fileSize?.(ref.prefixedId) ?? 0;
20723
20877
  }
20878
+ function sessionBuildBytes(ref) {
20879
+ const main = sessionFileBytes(ref);
20880
+ if (main === 0) return 0;
20881
+ return Math.max(main, shadowUncompressedBytes(ref.toolId, ref.rawId));
20882
+ }
20724
20883
  async function buildConversationSync(ref, mtime, opts = {}) {
20725
20884
  const mapPath = opts.mapPath ?? ((p) => p);
20726
20885
  let includeRaw = opts.includeRaw !== false;
20727
20886
  let includeMeta = opts.includeMeta !== false;
20728
20887
  let srcHash;
20729
- const fileBytes = sessionFileBytes(ref);
20730
- const oversized = fileBytes > FULL_BUILD_MAX_BYTES;
20731
- let tailText = "";
20732
- let tailOffsetEnd = 0;
20888
+ const oversized = sessionBuildBytes(ref) > FULL_BUILD_MAX_BYTES;
20889
+ let headOffsetEnd = 0;
20890
+ let oversizedFindings = null;
20733
20891
  let transcript = null;
20734
20892
  let fullestContainer = null;
20735
20893
  if (oversized) {
20736
20894
  const backend = getBackendForId(ref.prefixedId);
20737
20895
  if (!backend?.readFromOffset) return null;
20738
20896
  try {
20739
- const tail = await backend.readFromOffset(ref.prefixedId, fileBytes - FULL_BUILD_TAIL_BYTES);
20740
- tailText = tail.text;
20741
- tailOffsetEnd = tail.newOffset;
20742
- const messages = parseTailMessages(ref.toolId, tailText);
20897
+ let head = await backend.readFromOffset(ref.prefixedId, 0, SYNC_CHUNK_BYTES);
20898
+ for (let hops = 0; head.skippedBytes && hops < 8; hops++) {
20899
+ head = await backend.readFromOffset(ref.prefixedId, head.newOffset, SYNC_CHUNK_BYTES);
20900
+ }
20901
+ headOffsetEnd = head.newOffset;
20902
+ const messages = parseTailMessages(ref.toolId, head.text);
20743
20903
  if (messages.length > 0) transcript = { messages, subagents: [] };
20744
20904
  } catch {
20745
20905
  }
20746
20906
  includeRaw = false;
20747
- includeMeta = false;
20907
+ oversizedFindings = await scanTranscriptFindingsChunked(ref, opts.tenantRules);
20748
20908
  } else {
20749
20909
  try {
20750
20910
  const backend = getBackendForId(ref.prefixedId) ?? getBackend("claude");
@@ -20805,7 +20965,6 @@ async function buildConversationSync(ref, mtime, opts = {}) {
20805
20965
  );
20806
20966
  let projectPath = ref.projectPath;
20807
20967
  const meta = { messageCount: textMessages.length };
20808
- if (oversized) meta.truncated = true;
20809
20968
  if (textMessages.filter((m) => m.role === "user").length <= 1) meta.oneShot = true;
20810
20969
  try {
20811
20970
  const cwd = ref.fullPath ? readCwdFromJsonl(ref.fullPath) : "";
@@ -20919,21 +21078,7 @@ async function buildConversationSync(ref, mtime, opts = {}) {
20919
21078
  }
20920
21079
  scanMs = performance.now() - t0;
20921
21080
  }
20922
- if (oversized && tailText) {
20923
- const t0 = performance.now();
20924
- try {
20925
- for (const f of scanTextForFindings(tailText)) {
20926
- findings.push({ session_id: ref.prefixedId, detector: "builtin", rule: f.rule, line: f.line, preview: f.preview });
20927
- }
20928
- if (opts.tenantRules && opts.tenantRules.length > 0) {
20929
- for (const f of scanTenantRules(tailText, opts.tenantRules)) {
20930
- findings.push({ session_id: ref.prefixedId, detector: f.detector, rule: f.rule, line: f.line, preview: f.preview });
20931
- }
20932
- }
20933
- } catch {
20934
- }
20935
- scanMs = performance.now() - t0;
20936
- }
21081
+ if (oversizedFindings) findings.push(...oversizedFindings);
20937
21082
  const keptFindings = dropFuzzyFindings(findings, (f) => ({ detector: f.detector, rule: f.rule }));
20938
21083
  findings.length = 0;
20939
21084
  findings.push(...keptFindings);
@@ -20979,7 +21124,10 @@ async function buildConversationSync(ref, mtime, opts = {}) {
20979
21124
  // (convBatch onFlush uses this, not a recomputed size) so the next
20980
21125
  // append's base_offset matches exactly — no spurious continuity misses on
20981
21126
  // an actively-growing session. undefined for non-append-only backends.
20982
- from_offset: oversized ? tailOffsetEnd : getBackendForId(ref.prefixedId)?.fileSize?.(ref.rawId),
21127
+ from_offset: oversized ? headOffsetEnd : getBackendForId(ref.prefixedId)?.fileSize?.(ref.rawId),
21128
+ // The head of a chunked session. The server reports back when its shrink
21129
+ // guard keeps a fuller stored copy, so the client appends from there.
21130
+ ...oversized ? { chunked: true } : {},
20983
21131
  meta,
20984
21132
  mtime
20985
21133
  },
@@ -21001,12 +21149,30 @@ async function buildConversationTail(ref, fromOffset, opts = {}) {
21001
21149
  const backend = getBackendForId(ref.prefixedId);
21002
21150
  if (!backend?.readFromOffset) return null;
21003
21151
  const mapPath = opts.mapPath ?? ((p) => p);
21004
- const { text: tailText, newOffset } = await backend.readFromOffset(ref.prefixedId, fromOffset);
21005
- if (!tailText.trim()) return null;
21006
- const messages = parseTailMessages(ref.toolId, tailText);
21007
- if (messages.length === 0) return null;
21152
+ const { text: tailText, newOffset, skippedBytes } = await backend.readFromOffset(ref.prefixedId, fromOffset, SYNC_CHUNK_BYTES);
21153
+ if (newOffset <= fromOffset) return null;
21154
+ const messages = skippedBytes ? [] : parseTailMessages(ref.toolId, tailText);
21008
21155
  const textMessages = messages.filter((m) => m.role !== "summary" && m.content?.trim());
21009
- if (textMessages.length === 0 && !messages.some((m) => m.toolCalls?.length)) return null;
21156
+ const hasContent = textMessages.length > 0 || messages.some((m) => m.toolCalls?.length);
21157
+ if (!hasContent) {
21158
+ return {
21159
+ conv: {
21160
+ session_id: ref.prefixedId,
21161
+ tool: ref.toolId,
21162
+ project_path: mapPath(ref.projectPath),
21163
+ append: true,
21164
+ base_offset: fromOffset,
21165
+ from_offset: newOffset,
21166
+ redacted_text: "",
21167
+ envelope: { v: TRANSCRIPT_VERSION, messages: [], subagents: [] },
21168
+ mtime: Math.floor(ref.mtime) || 0
21169
+ },
21170
+ redactions: 0,
21171
+ newOffset,
21172
+ findings: [],
21173
+ bytes: 0
21174
+ };
21175
+ }
21010
21176
  const firstUser = textMessages.find((m) => m.role === "user");
21011
21177
  if (isInternalToolPrompt(firstUser?.content)) return null;
21012
21178
  const count = { redactions: 0 };
@@ -21049,7 +21215,8 @@ async function buildConversationTail(ref, fromOffset, opts = {}) {
21049
21215
  },
21050
21216
  redactions: count.redactions,
21051
21217
  newOffset,
21052
- findings
21218
+ findings,
21219
+ bytes: Buffer.byteLength(tailText)
21053
21220
  };
21054
21221
  }
21055
21222
  function isSyncSkip(r) {
@@ -21079,7 +21246,7 @@ async function syncIncremental(opts = {}) {
21079
21246
  lock.release();
21080
21247
  }
21081
21248
  }
21082
- var ownVersion, ERROR_CLASS, STANDING_FAILURE, walkProgressForUpload, lastServerPackSpec, credPath, _securityConfigCache, SECURITY_CONFIG_TTL_MS, _syncConfigCache, EMPTY_SYNC_CONFIG, _fetchTenantSyncConfigForTests, SYNC_RULES_REFUSAL, hashPath, acceptedUploads, MAX_DERIVED_ROW_BYTES, isLocalHost, CAPS_TTL_MS, capsOk, advertisedIngestConc, advertisedGzipBody, FULL_BUILD_MAX_BYTES, FULL_BUILD_TAIL_BYTES, BATCH_SCAN_MAX_BYTES;
21249
+ var ownVersion, ERROR_CLASS, STANDING_FAILURE, walkProgressForUpload, lastServerPackSpec, credPath, _securityConfigCache, SECURITY_CONFIG_TTL_MS, _syncConfigCache, EMPTY_SYNC_CONFIG, _fetchTenantSyncConfigForTests, SYNC_RULES_REFUSAL, hashPath, acceptedUploads, MAX_DERIVED_ROW_BYTES, isLocalHost, CAPS_TTL_MS, capsOk, advertisedIngestConc, advertisedGzipBody, FULL_BUILD_MAX_BYTES, DERIVED_MAX_BYTES, SYNC_CHUNK_BYTES, BATCH_SCAN_MAX_BYTES;
21083
21250
  var init_sync_client = __esm({
21084
21251
  "src/sync-client.ts"() {
21085
21252
  "use strict";
@@ -21124,7 +21291,7 @@ var init_sync_client = __esm({
21124
21291
  ownVersion = JSON.parse(readFileSync35(join42(dir, "../package.json"), "utf-8")).version || ownVersion;
21125
21292
  } catch {
21126
21293
  try {
21127
- if (true) ownVersion = "0.7.0";
21294
+ if (true) ownVersion = "0.7.1";
21128
21295
  } catch {
21129
21296
  }
21130
21297
  }
@@ -21151,8 +21318,9 @@ var init_sync_client = __esm({
21151
21318
  capsOk = /* @__PURE__ */ new Map();
21152
21319
  advertisedIngestConc = /* @__PURE__ */ new Map();
21153
21320
  advertisedGzipBody = /* @__PURE__ */ new Set();
21154
- FULL_BUILD_MAX_BYTES = Math.max(8, parseInt(process.env.CHAT_RECALL_FULL_BUILD_MAX_MB || "64", 10)) * 1024 * 1024;
21155
- FULL_BUILD_TAIL_BYTES = 16 * 1024 * 1024;
21321
+ FULL_BUILD_MAX_BYTES = Math.max(8, parseInt(process.env.CHAT_RECALL_FULL_BUILD_MAX_MB || "24", 10)) * 1024 * 1024;
21322
+ DERIVED_MAX_BYTES = Math.max(8, parseInt(process.env.CHAT_RECALL_DERIVED_MAX_MB || "64", 10)) * 1024 * 1024;
21323
+ SYNC_CHUNK_BYTES = 8 * 1024 * 1024;
21156
21324
  BATCH_SCAN_MAX_BYTES = Math.max(1, parseInt(process.env.CHAT_RECALL_BATCHSCAN_MAX_MB || "64", 10)) * 1024 * 1024;
21157
21325
  }
21158
21326
  });
@@ -21273,7 +21441,7 @@ var init_update_notice = __esm({
21273
21441
  });
21274
21442
 
21275
21443
  // ../engine/dist/core/which.js
21276
- import { existsSync as existsSync41, statSync as statSync38, accessSync, constants } from "node:fs";
21444
+ import { existsSync as existsSync42, statSync as statSync38, accessSync, constants } from "node:fs";
21277
21445
  import { join as join44, isAbsolute as isAbsolute2, delimiter as delimiter2, sep as sep3 } from "node:path";
21278
21446
  function executable(p) {
21279
21447
  try {
@@ -21314,7 +21482,7 @@ function resolveOnPath(name) {
21314
21482
  continue;
21315
21483
  for (const c of candidates(name)) {
21316
21484
  const full = join44(dir, c);
21317
- if (existsSync41(full) && executable(full))
21485
+ if (existsSync42(full) && executable(full))
21318
21486
  return full;
21319
21487
  }
21320
21488
  }
@@ -21377,7 +21545,7 @@ __export(mcp_clients_exports, {
21377
21545
  inspectMcpClients: () => inspectMcpClients,
21378
21546
  registerMcpEverywhere: () => registerMcpEverywhere
21379
21547
  });
21380
- import { existsSync as existsSync43, mkdirSync as mkdirSync12, readFileSync as readFileSync37, writeFileSync as writeFileSync12 } from "fs";
21548
+ import { existsSync as existsSync44, mkdirSync as mkdirSync12, readFileSync as readFileSync37, writeFileSync as writeFileSync12 } from "fs";
21381
21549
  import { homedir as homedir16 } from "os";
21382
21550
  import { dirname as dirname21, join as join46 } from "path";
21383
21551
  function envHome(varName, fallback) {
@@ -21396,7 +21564,7 @@ function readJsonObject(path) {
21396
21564
  }
21397
21565
  function registerMcpServersJson(target, path, spec) {
21398
21566
  let cfg = {};
21399
- if (existsSync43(path)) {
21567
+ if (existsSync44(path)) {
21400
21568
  try {
21401
21569
  cfg = readJsonObject(path);
21402
21570
  } catch (err) {
@@ -21425,7 +21593,7 @@ function registerOpencodeJson(path, spec) {
21425
21593
  const id = "opencode";
21426
21594
  const label = "OpenCode";
21427
21595
  let cfg = {};
21428
- if (existsSync43(path)) {
21596
+ if (existsSync44(path)) {
21429
21597
  try {
21430
21598
  cfg = readJsonObject(path);
21431
21599
  } catch (err) {
@@ -21464,7 +21632,7 @@ function registerCodexToml(path, spec) {
21464
21632
  const id = "codex";
21465
21633
  const label = "Codex";
21466
21634
  const block = codexBlock(spec);
21467
- const prev = existsSync43(path) ? readFileSync37(path, "utf-8") : "";
21635
+ const prev = existsSync44(path) ? readFileSync37(path, "utf-8") : "";
21468
21636
  const lines = prev.length ? prev.split("\n") : [];
21469
21637
  const start = lines.findIndex((l) => l.trim() === CODEX_HEADER);
21470
21638
  if (start === -1) {
@@ -21505,7 +21673,7 @@ function inspectMcpClients(opts = {}) {
21505
21673
  return MCP_CLIENTS.map((c) => {
21506
21674
  const path = c.configPath(home);
21507
21675
  let registered = false;
21508
- if (existsSync43(path)) {
21676
+ if (existsSync44(path)) {
21509
21677
  try {
21510
21678
  const raw = readFileSync37(path, "utf-8");
21511
21679
  registered = c.id === "codex" ? raw.includes(CODEX_HEADER) : !!(JSON.parse(raw).mcpServers?.[MCP_SERVER_NAME] ?? JSON.parse(raw).mcp?.[MCP_SERVER_NAME]);
@@ -21542,7 +21710,7 @@ var init_mcp_clients = __esm({
21542
21710
  configPath: (home) => join46(envHome("CHAT_RECALL_CODEX_HOME", join46(home, ".codex")), "config.toml"),
21543
21711
  isPresent(home) {
21544
21712
  const p = this.configPath(home);
21545
- return existsSync43(p) || existsSync43(dirname21(p));
21713
+ return existsSync44(p) || existsSync44(dirname21(p));
21546
21714
  },
21547
21715
  register(spec, home) {
21548
21716
  return registerCodexToml(this.configPath(home), spec);
@@ -21555,7 +21723,7 @@ var init_mcp_clients = __esm({
21555
21723
  configPath: (home) => join46(envHome("XDG_CONFIG_HOME", join46(home, ".config")), "opencode", "opencode.json"),
21556
21724
  isPresent(home) {
21557
21725
  const p = this.configPath(home);
21558
- return existsSync43(p) || existsSync43(dirname21(p));
21726
+ return existsSync44(p) || existsSync44(dirname21(p));
21559
21727
  },
21560
21728
  register(spec, home) {
21561
21729
  return registerOpencodeJson(this.configPath(home), spec);
@@ -21569,7 +21737,7 @@ var init_mcp_clients = __esm({
21569
21737
  bin: "agy",
21570
21738
  configPath: (home) => join46(home, ".gemini", "config", "mcp_config.json"),
21571
21739
  isPresent(home) {
21572
- return existsSync43(join46(home, ".gemini", "antigravity-cli")) || existsSync43(this.configPath(home));
21740
+ return existsSync44(join46(home, ".gemini", "antigravity-cli")) || existsSync44(this.configPath(home));
21573
21741
  },
21574
21742
  register(spec, home) {
21575
21743
  return registerMcpServersJson(this, this.configPath(home), spec);
@@ -21582,7 +21750,7 @@ var init_mcp_clients = __esm({
21582
21750
  configPath: (home) => join46(home, ".cursor", "mcp.json"),
21583
21751
  isPresent(home) {
21584
21752
  const p = this.configPath(home);
21585
- return existsSync43(p) || existsSync43(dirname21(p));
21753
+ return existsSync44(p) || existsSync44(dirname21(p));
21586
21754
  },
21587
21755
  register(spec, home) {
21588
21756
  return registerMcpServersJson(this, this.configPath(home), spec);
@@ -21606,7 +21774,7 @@ __export(companions_exports, {
21606
21774
  uninstallCodeindex: () => uninstallCodeindex,
21607
21775
  unregisterCodeindexMcp: () => unregisterCodeindexMcp
21608
21776
  });
21609
- import { existsSync as existsSync44, 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";
21777
+ 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";
21610
21778
  import { homedir as homedir17 } from "node:os";
21611
21779
  import { join as join47 } from "node:path";
21612
21780
  import { execSync as execSync3 } from "node:child_process";
@@ -21729,7 +21897,7 @@ Refusing to install. The release may have been re-uploaded, or something is serv
21729
21897
  renameSync5(tmpPath, CODEINDEX_BIN_PATH);
21730
21898
  } catch (err) {
21731
21899
  try {
21732
- if (existsSync44(tmpPath))
21900
+ if (existsSync45(tmpPath))
21733
21901
  unlinkSync3(tmpPath);
21734
21902
  } catch {
21735
21903
  }
@@ -21738,7 +21906,7 @@ Refusing to install. The release may have been re-uploaded, or something is serv
21738
21906
  return checkCodeindexStatus();
21739
21907
  }
21740
21908
  function uninstallCodeindex() {
21741
- if (existsSync44(CODEINDEX_BIN_PATH)) {
21909
+ if (existsSync45(CODEINDEX_BIN_PATH)) {
21742
21910
  unlinkSync3(CODEINDEX_BIN_PATH);
21743
21911
  return { removed: true, path: CODEINDEX_BIN_PATH };
21744
21912
  }
@@ -21746,7 +21914,7 @@ function uninstallCodeindex() {
21746
21914
  }
21747
21915
  function registerCodeindexMcp(mcpJsonPath, binaryPath) {
21748
21916
  let cfg = {};
21749
- if (existsSync44(mcpJsonPath)) {
21917
+ if (existsSync45(mcpJsonPath)) {
21750
21918
  try {
21751
21919
  cfg = JSON.parse(readFileSync38(mcpJsonPath, "utf-8"));
21752
21920
  } catch {
@@ -21761,7 +21929,7 @@ function registerCodeindexMcp(mcpJsonPath, binaryPath) {
21761
21929
  return { added: true };
21762
21930
  }
21763
21931
  function unregisterCodeindexMcp(mcpJsonPath) {
21764
- if (!existsSync44(mcpJsonPath))
21932
+ if (!existsSync45(mcpJsonPath))
21765
21933
  return { removed: false };
21766
21934
  let cfg;
21767
21935
  try {
@@ -21807,7 +21975,7 @@ __export(install_skills_exports, {
21807
21975
  skillsSourceDir: () => skillsSourceDir,
21808
21976
  uninstallSkills: () => uninstallSkills
21809
21977
  });
21810
- import { readdirSync as readdirSync33, existsSync as existsSync45, mkdirSync as mkdirSync14, rmSync as rmSync7, cpSync, writeFileSync as writeFileSync14, readFileSync as readFileSync39, statSync as statSync40, realpathSync as realpathSync4 } from "fs";
21978
+ import { readdirSync as readdirSync33, existsSync as existsSync46, mkdirSync as mkdirSync14, rmSync as rmSync7, cpSync, writeFileSync as writeFileSync14, readFileSync as readFileSync39, statSync as statSync40, realpathSync as realpathSync4 } from "fs";
21811
21979
  import { createHash as createHash11 } from "crypto";
21812
21980
  import { join as join48, basename as basename21 } from "path";
21813
21981
  function skillsSourceDir() {
@@ -21846,8 +22014,8 @@ function skillStamp() {
21846
22014
  }
21847
22015
  function bundledSkillNames() {
21848
22016
  const src = skillsSourceDir();
21849
- if (!existsSync45(src)) return [];
21850
- return readdirSync33(src, { withFileTypes: true }).filter((e) => e.isDirectory() && existsSync45(join48(src, e.name, "SKILL.md"))).map((e) => e.name).sort();
22017
+ if (!existsSync46(src)) return [];
22018
+ return readdirSync33(src, { withFileTypes: true }).filter((e) => e.isDirectory() && existsSync46(join48(src, e.name, "SKILL.md"))).map((e) => e.name).sort();
21851
22019
  }
21852
22020
  function realPathOrSelf(p) {
21853
22021
  try {
@@ -21871,7 +22039,7 @@ function claudeSkillTargets() {
21871
22039
  dir,
21872
22040
  // Judge each profile on ITS OWN transcripts, not the primary's: a home
21873
22041
  // with no projects/ is a directory someone made, not a Claude install.
21874
- available: existsSync45(join48(home, "projects"))
22042
+ available: existsSync46(join48(home, "projects"))
21875
22043
  });
21876
22044
  }
21877
22045
  if (targets.length === 0) {
@@ -21895,7 +22063,7 @@ function skillTargets() {
21895
22063
  ];
21896
22064
  }
21897
22065
  function isManaged(dir) {
21898
- return existsSync45(join48(dir, MARKER));
22066
+ return existsSync46(join48(dir, MARKER));
21899
22067
  }
21900
22068
  function installSkills(opts = {}) {
21901
22069
  const onlyAvailable = opts.onlyAvailable ?? true;
@@ -21913,7 +22081,7 @@ function installSkills(opts = {}) {
21913
22081
  }
21914
22082
  for (const name of names) {
21915
22083
  const dest = join48(t.dir, name);
21916
- if (existsSync45(dest) && !isManaged(dest)) {
22084
+ if (existsSync46(dest) && !isManaged(dest)) {
21917
22085
  skippedUserOwned.push(name);
21918
22086
  continue;
21919
22087
  }
@@ -21933,7 +22101,7 @@ function uninstallSkills() {
21933
22101
  const perTarget = [];
21934
22102
  for (const t of skillTargets()) {
21935
22103
  const removed = [];
21936
- if (!existsSync45(t.dir)) {
22104
+ if (!existsSync46(t.dir)) {
21937
22105
  perTarget.push({ id: t.id, label: t.label, removed });
21938
22106
  continue;
21939
22107
  }
@@ -21957,7 +22125,7 @@ function skillsNeedRefresh() {
21957
22125
  if (!t.available) continue;
21958
22126
  for (const name of names) {
21959
22127
  const marker = join48(t.dir, name, MARKER);
21960
- if (!existsSync45(marker)) return true;
22128
+ if (!existsSync46(marker)) return true;
21961
22129
  try {
21962
22130
  if (readFileSync39(marker, "utf-8").trim() !== cur) return true;
21963
22131
  } catch {
@@ -21975,7 +22143,7 @@ function skillStatus() {
21975
22143
  let ver = null;
21976
22144
  for (const name of names) {
21977
22145
  const marker = join48(t.dir, name, MARKER);
21978
- if (existsSync45(marker)) {
22146
+ if (existsSync46(marker)) {
21979
22147
  installed++;
21980
22148
  try {
21981
22149
  ver = readFileSync39(marker, "utf-8").trim();
@@ -22163,7 +22331,7 @@ __export(toolkit_sync_exports, {
22163
22331
  supportedTargetsFor: () => supportedTargetsFor,
22164
22332
  writeMcpEntry: () => writeMcpEntry
22165
22333
  });
22166
- import { existsSync as existsSync46, mkdirSync as mkdirSync15, readFileSync as readFileSync41, writeFileSync as writeFileSync15, cpSync as cpSync2 } from "fs";
22334
+ import { existsSync as existsSync47, mkdirSync as mkdirSync15, readFileSync as readFileSync41, writeFileSync as writeFileSync15, cpSync as cpSync2 } from "fs";
22167
22335
  import { dirname as dirname22, join as join50, basename as basename23 } from "path";
22168
22336
  import { homedir as homedir19 } from "os";
22169
22337
  function supportedTargetsFor(type) {
@@ -22218,11 +22386,11 @@ function skillsDirFor(tool) {
22218
22386
  }
22219
22387
  function copySkill(row, toTool) {
22220
22388
  const skillDir = row.extra.skillDir || dirname22(row.filePath);
22221
- if (!existsSync46(skillDir))
22389
+ if (!existsSync47(skillDir))
22222
22390
  return { ok: false, status: 404, error: `Source dir missing: ${skillDir}` };
22223
22391
  const name = row.extra.skillName || basename23(skillDir);
22224
22392
  const targetDir = join50(skillsDirFor(toTool), name);
22225
- if (existsSync46(targetDir))
22393
+ if (existsSync47(targetDir))
22226
22394
  return { ok: false, status: 409, error: `Already exists: ${targetDir}` };
22227
22395
  try {
22228
22396
  mkdirSync15(dirname22(targetDir), { recursive: true });
@@ -22254,7 +22422,7 @@ function readMcpEntry(tool, name) {
22254
22422
  return entry;
22255
22423
  }
22256
22424
  for (const t of tries) {
22257
- if (!existsSync46(t.path))
22425
+ if (!existsSync47(t.path))
22258
22426
  continue;
22259
22427
  try {
22260
22428
  const cfg = JSON.parse(readFileSync41(t.path, "utf-8"));
@@ -22267,7 +22435,7 @@ function readMcpEntry(tool, name) {
22267
22435
  return null;
22268
22436
  }
22269
22437
  function readCodexMcpEntry(path, target) {
22270
- if (!existsSync46(path))
22438
+ if (!existsSync47(path))
22271
22439
  return null;
22272
22440
  let content;
22273
22441
  try {
@@ -22321,7 +22489,7 @@ function readCodexMcpEntry(path, target) {
22321
22489
  }
22322
22490
  function writeCodexMcpEntry(path, name, entry) {
22323
22491
  let content = "";
22324
- if (existsSync46(path))
22492
+ if (existsSync47(path))
22325
22493
  content = readFileSync41(path, "utf-8");
22326
22494
  const header = `[mcp_servers.${name}]`;
22327
22495
  if (content.includes(header))
@@ -22379,7 +22547,7 @@ function writeMcpEntry(toTool, name, entry) {
22379
22547
  key2 = "mcp";
22380
22548
  }
22381
22549
  let cfg = {};
22382
- if (existsSync46(path)) {
22550
+ if (existsSync47(path)) {
22383
22551
  try {
22384
22552
  cfg = JSON.parse(readFileSync41(path, "utf-8"));
22385
22553
  } catch {
@@ -22443,7 +22611,7 @@ function copyCommandOrAgent(type, row, toTool) {
22443
22611
  return { ok: false, status: 404, error: `Source unreadable: ${e instanceof Error ? e.message : "failed"}` };
22444
22612
  }
22445
22613
  const out = emit(type, art, toTool);
22446
- if (existsSync46(out.path))
22614
+ if (existsSync47(out.path))
22447
22615
  return { ok: false, status: 409, error: `Already exists: ${out.path}` };
22448
22616
  try {
22449
22617
  mkdirSync15(dirname22(out.path), { recursive: true });
@@ -22463,7 +22631,7 @@ function copyInstructions(row, toTool) {
22463
22631
  return { ok: false, status: 404, error: `Source unreadable: ${e instanceof Error ? e.message : "failed"}` };
22464
22632
  }
22465
22633
  const out = emit("instructions", art, toTool, row.projectPath || void 0);
22466
- if (existsSync46(out.path))
22634
+ if (existsSync47(out.path))
22467
22635
  return { ok: false, status: 409, error: `Already exists: ${out.path}` };
22468
22636
  try {
22469
22637
  mkdirSync15(dirname22(out.path), { recursive: true });
@@ -22613,7 +22781,7 @@ __export(toolkit_pull_exports, {
22613
22781
  planPull: () => planPull,
22614
22782
  portableCommand: () => portableCommand
22615
22783
  });
22616
- import { existsSync as existsSync47, mkdirSync as mkdirSync16, statSync as statSync41, writeFileSync as writeFileSync16 } from "node:fs";
22784
+ import { existsSync as existsSync48, mkdirSync as mkdirSync16, statSync as statSync41, writeFileSync as writeFileSync16 } from "node:fs";
22617
22785
  import { dirname as dirname23, join as join51, basename as basename24, isAbsolute as isAbsolute3 } from "node:path";
22618
22786
  function isExecutableFile(p) {
22619
22787
  try {
@@ -22766,7 +22934,7 @@ function executePull(rows, opts = {}) {
22766
22934
  for (const tool of tools) {
22767
22935
  const dir = join51(skillsDirFor(tool), name);
22768
22936
  const file = join51(dir, "SKILL.md");
22769
- if (existsSync47(file)) {
22937
+ if (existsSync48(file)) {
22770
22938
  outcomes.push({ type: "skill", name, tool, status: "present" });
22771
22939
  continue;
22772
22940
  }
@@ -22811,7 +22979,7 @@ function executePull(rows, opts = {}) {
22811
22979
  outcomes.push({ type, name, tool, status: "failed", reason: e instanceof Error ? e.message : "emit failed" });
22812
22980
  continue;
22813
22981
  }
22814
- if (existsSync47(out.path)) {
22982
+ if (existsSync48(out.path)) {
22815
22983
  outcomes.push({ type, name, tool, status: "present" });
22816
22984
  continue;
22817
22985
  }
@@ -22969,7 +23137,7 @@ __export(board_hooks_exports, {
22969
23137
  removeBoardHooks: () => removeBoardHooks,
22970
23138
  resolveCliEntry: () => resolveCliEntry
22971
23139
  });
22972
- import { existsSync as existsSync48, mkdirSync as mkdirSync17, readFileSync as readFileSync42, writeFileSync as writeFileSync17 } from "node:fs";
23140
+ import { existsSync as existsSync49, mkdirSync as mkdirSync17, readFileSync as readFileSync42, writeFileSync as writeFileSync17 } from "node:fs";
22973
23141
  import { dirname as dirname24, join as join52 } from "node:path";
22974
23142
  function boardHookCommand(execPath, cliEntry, mode) {
22975
23143
  return `"${execPath}" "${cliEntry}" task-hook --${mode}`;
@@ -23009,7 +23177,7 @@ function removeBoardHooks(config2) {
23009
23177
  return removed;
23010
23178
  }
23011
23179
  function readConfig(file) {
23012
- if (!existsSync48(file)) return { hooks: {} };
23180
+ if (!existsSync49(file)) return { hooks: {} };
23013
23181
  try {
23014
23182
  const parsed = JSON.parse(readFileSync42(file, "utf-8"));
23015
23183
  if (!parsed.hooks || typeof parsed.hooks !== "object") parsed.hooks = {};
@@ -23021,7 +23189,7 @@ function readConfig(file) {
23021
23189
  function registerBoardHooks(files, execPath, cliEntry) {
23022
23190
  const written = [];
23023
23191
  for (const file of files) {
23024
- if (existsSync48(file)) {
23192
+ if (existsSync49(file)) {
23025
23193
  try {
23026
23194
  JSON.parse(readFileSync42(file, "utf-8"));
23027
23195
  } catch {
@@ -23041,7 +23209,7 @@ function registerBoardHooks(files, execPath, cliEntry) {
23041
23209
  }
23042
23210
  function resolveCliEntry(distDir) {
23043
23211
  const bundled = join52(distDir, "cli.js");
23044
- return existsSync48(bundled) ? bundled : join52(distDir, "cli.ts");
23212
+ return existsSync49(bundled) ? bundled : join52(distDir, "cli.ts");
23045
23213
  }
23046
23214
  var BOARD_HOOKS;
23047
23215
  var init_board_hooks = __esm({
@@ -23144,6 +23312,9 @@ async function repairSession(id, opts = {}) {
23144
23312
  note: "archive count is a lower bound; the rebuild also unions the on-disk tail"
23145
23313
  };
23146
23314
  }
23315
+ if (!opts.force && endpoints.every((ep) => (currentOnServer.get(ep.url) ?? 0) >= fullest.messages)) {
23316
+ return { sessionId: id, status: "already-full", fullestMessages: fullest.messages, fullestSource: fullest.source, pushed: [] };
23317
+ }
23147
23318
  seedShadow(rawId, fullest.container);
23148
23319
  const located = backend.findSession(rawId);
23149
23320
  const projectPath = located?.projectPath || cwdFromContainer(fullest.container);
@@ -23186,7 +23357,7 @@ async function repairSession(id, opts = {}) {
23186
23357
  try {
23187
23358
  const res = await fetchWithTimeout(`${ep.url}/api/sync`, { method: "POST", headers, body: JSON.stringify({ conversations: [built.conv] }) }, 6e4);
23188
23359
  if (!res.ok) {
23189
- pushed.push({ server: ep.url, before, after: before });
23360
+ pushed.push({ server: ep.url, before, after: before, error: `HTTP ${res.status}` });
23190
23361
  log6(`push to ${ep.url} FAILED: HTTP ${res.status}`);
23191
23362
  continue;
23192
23363
  }
@@ -23195,10 +23366,21 @@ async function repairSession(id, opts = {}) {
23195
23366
  pushed.push({ server: ep.url, before, after: afterN });
23196
23367
  log6(`pushed to ${ep.url}: ${before} \u2192 ${afterN} msg(s)`);
23197
23368
  } catch (e) {
23198
- pushed.push({ server: ep.url, before, after: before });
23199
- log6(`push to ${ep.url} errored: ${e instanceof Error ? e.message : e}`);
23369
+ const error = e instanceof Error ? e.message : String(e);
23370
+ pushed.push({ server: ep.url, before, after: before, error });
23371
+ log6(`push to ${ep.url} errored: ${error}`);
23200
23372
  }
23201
23373
  }
23374
+ if (pushed.every((p) => p.error)) {
23375
+ return {
23376
+ sessionId: id,
23377
+ status: "error",
23378
+ fullestMessages: builtCount,
23379
+ fullestSource: fullest.source,
23380
+ pushed,
23381
+ note: `every push failed: ${pushed.map((p) => `${p.server}: ${p.error}`).join("; ")}`
23382
+ };
23383
+ }
23202
23384
  return { sessionId: id, status: "repaired", fullestMessages: builtCount, fullestSource: fullest.source, pushed };
23203
23385
  }
23204
23386
  async function repairSessions(ids, opts = {}) {
@@ -23693,11 +23875,11 @@ var verify_repair_exports = {};
23693
23875
  __export(verify_repair_exports, {
23694
23876
  forceFullResync: () => forceFullResync
23695
23877
  });
23696
- import { copyFileSync as copyFileSync3, existsSync as existsSync49 } from "fs";
23878
+ import { copyFileSync as copyFileSync3, existsSync as existsSync50 } from "fs";
23697
23879
  function forceFullResync(server, sessionIds) {
23698
23880
  if (sessionIds.length === 0) return 0;
23699
23881
  const path = ledgerFilePath();
23700
- if (existsSync49(path)) {
23882
+ if (existsSync50(path)) {
23701
23883
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "").replace(/-/g, "");
23702
23884
  try {
23703
23885
  copyFileSync3(path, `${path}.bak-${stamp}`);
@@ -24851,7 +25033,7 @@ __export(project_tasks_exports, {
24851
25033
  pushProjectTaskStatuses: () => pushProjectTaskStatuses,
24852
25034
  renderTeamTasksMd: () => renderTeamTasksMd
24853
25035
  });
24854
- import { existsSync as existsSync50, readFileSync as readFileSync44, writeFileSync as writeFileSync18, mkdirSync as mkdirSync18, statSync as statSync42 } from "node:fs";
25036
+ import { existsSync as existsSync51, readFileSync as readFileSync44, writeFileSync as writeFileSync18, mkdirSync as mkdirSync18, statSync as statSync42 } from "node:fs";
24855
25037
  import { join as join55, dirname as dirname25 } from "node:path";
24856
25038
  import { homedir as homedir21 } from "node:os";
24857
25039
  function isTeamTaskStatus(v) {
@@ -24937,7 +25119,7 @@ async function pushProjectTaskStatuses(base3, authHeaders, opts = {}) {
24937
25119
  }
24938
25120
  for (const project of projects) {
24939
25121
  const file = join55(project, fk.filename);
24940
- if (!existsSync50(file)) continue;
25122
+ if (!existsSync51(file)) continue;
24941
25123
  let mtime;
24942
25124
  try {
24943
25125
  mtime = statSync42(file).mtimeMs;
@@ -25019,7 +25201,7 @@ __export(intent_drain_exports, {
25019
25201
  drainSyncIntents: () => drainSyncIntents,
25020
25202
  instructionTargets: () => instructionTargets
25021
25203
  });
25022
- import { existsSync as existsSync51, readFileSync as readFileSync45, writeFileSync as writeFileSync19, appendFileSync, mkdirSync as mkdirSync19 } from "node:fs";
25204
+ import { existsSync as existsSync52, readFileSync as readFileSync45, writeFileSync as writeFileSync19, appendFileSync, mkdirSync as mkdirSync19 } from "node:fs";
25023
25205
  import { join as join56 } from "node:path";
25024
25206
  import { fileURLToPath as fileURLToPath4 } from "node:url";
25025
25207
  import { dirname as dirname26 } from "node:path";
@@ -25034,7 +25216,7 @@ function instructionTargets(rootPath, isGlobal) {
25034
25216
  const tools = installed.length ? installed : [INSTRUCTION_TOOLS[0]];
25035
25217
  if (isGlobal) return [...new Set(tools.map((t) => instructionsPath(t.id)))];
25036
25218
  if (!rootPath) return [];
25037
- const present = INSTRUCTION_FILENAMES.map((f) => join56(rootPath, f)).filter((p) => existsSync51(p));
25219
+ const present = INSTRUCTION_FILENAMES.map((f) => join56(rootPath, f)).filter((p) => existsSync52(p));
25038
25220
  if (present.length) return present;
25039
25221
  return [...new Set(tools.map((t) => join56(rootPath, instructionsFilename(t.id))))];
25040
25222
  }
@@ -25062,7 +25244,7 @@ function applyCodeRecommendation(intent) {
25062
25244
  mkdirSync19(dir, { recursive: true });
25063
25245
  } catch {
25064
25246
  }
25065
- const existing = existsSync51(file) ? readFileSync45(file, "utf8") : "";
25247
+ const existing = existsSync52(file) ? readFileSync45(file, "utf8") : "";
25066
25248
  if (existing.includes(text)) {
25067
25249
  skipped.push(file);
25068
25250
  continue;
@@ -25240,7 +25422,7 @@ var init_intent_drain = __esm({
25240
25422
  ownVersion2 = JSON.parse(readFileSync45(join56(dir, "../package.json"), "utf-8")).version || ownVersion2;
25241
25423
  } catch {
25242
25424
  try {
25243
- if (true) ownVersion2 = "0.7.0";
25425
+ if (true) ownVersion2 = "0.7.1";
25244
25426
  } catch {
25245
25427
  }
25246
25428
  }
@@ -25441,7 +25623,7 @@ var team_merge_exports = {};
25441
25623
  __export(team_merge_exports, {
25442
25624
  mergePullResult: () => mergePullResult
25443
25625
  });
25444
- import { existsSync as existsSync52, mkdirSync as mkdirSync20, readFileSync as readFileSync46, rmSync as rmSync8, writeFileSync as writeFileSync20, statSync as statSync43 } from "fs";
25626
+ import { existsSync as existsSync53, mkdirSync as mkdirSync20, readFileSync as readFileSync46, rmSync as rmSync8, writeFileSync as writeFileSync20, statSync as statSync43 } from "fs";
25445
25627
  import { dirname as dirname27, join as join57 } from "path";
25446
25628
  import { createHash as createHash14 } from "crypto";
25447
25629
  function installPathFor(art, tool) {
@@ -25558,7 +25740,7 @@ async function mergePullResult(opts) {
25558
25740
  if (!path)
25559
25741
  continue;
25560
25742
  try {
25561
- if (existsSync52(path))
25743
+ if (existsSync53(path))
25562
25744
  rmSync8(path, { force: true });
25563
25745
  await teamInstallsForget(id, row.tool);
25564
25746
  report.removed.push({ artifactId: id, path });
@@ -25576,7 +25758,7 @@ async function mergePullResult(opts) {
25576
25758
  }
25577
25759
  function readFileIfExists(path) {
25578
25760
  try {
25579
- if (!existsSync52(path))
25761
+ if (!existsSync53(path))
25580
25762
  return null;
25581
25763
  const s = statSync43(path);
25582
25764
  if (!s.isFile())
@@ -25662,7 +25844,7 @@ var init_vault_crypto = __esm({
25662
25844
  });
25663
25845
 
25664
25846
  // ../engine/dist/core/vault-source.js
25665
- import { existsSync as existsSync53, readdirSync as readdirSync34, statSync as statSync44 } from "fs";
25847
+ import { existsSync as existsSync54, readdirSync as readdirSync34, statSync as statSync44 } from "fs";
25666
25848
  import { extname, join as join58 } from "path";
25667
25849
  function* walkVaultSources() {
25668
25850
  const t = loadSettings().team.vault;
@@ -25688,7 +25870,7 @@ function safeStat(path) {
25688
25870
  }
25689
25871
  function* walkClaude() {
25690
25872
  const root = claudeBackend.projectsDir();
25691
- if (!existsSync53(root))
25873
+ if (!existsSync54(root))
25692
25874
  return;
25693
25875
  let projectDirs = [];
25694
25876
  try {
@@ -25741,7 +25923,7 @@ function* walkCursor() {
25741
25923
  }
25742
25924
  function* walkCodex() {
25743
25925
  const sessionsRoot = join58(codexBackend.homeDir(), "sessions");
25744
- if (!existsSync53(sessionsRoot))
25926
+ if (!existsSync54(sessionsRoot))
25745
25927
  return;
25746
25928
  const stack = [sessionsRoot];
25747
25929
  while (stack.length) {
@@ -25770,7 +25952,7 @@ function* walkCodex() {
25770
25952
  }
25771
25953
  function* walkAgy() {
25772
25954
  const brainDir = join58(agyBackend.homeDir(), "brain");
25773
- if (!existsSync53(brainDir))
25955
+ if (!existsSync54(brainDir))
25774
25956
  return;
25775
25957
  let sessionDirs = [];
25776
25958
  try {
@@ -25787,10 +25969,10 @@ function* walkAgy() {
25787
25969
  continue;
25788
25970
  }
25789
25971
  let filePath = join58(sessionPath, ".system_generated", "logs", "transcript.jsonl");
25790
- if (!existsSync53(filePath)) {
25972
+ if (!existsSync54(filePath)) {
25791
25973
  filePath = join58(sessionPath, ".system_generated", "logs", "transcript_full.jsonl");
25792
25974
  }
25793
- if (!existsSync53(filePath))
25975
+ if (!existsSync54(filePath))
25794
25976
  continue;
25795
25977
  const s = safeStat(filePath);
25796
25978
  if (!s)
@@ -25826,7 +26008,7 @@ __export(vault_client_exports, {
25826
26008
  vaultStatus: () => vaultStatus,
25827
26009
  vaultSync: () => vaultSync
25828
26010
  });
25829
- import { mkdirSync as mkdirSync21, readFileSync as readFileSync47, writeFileSync as writeFileSync21, existsSync as existsSync54 } from "fs";
26011
+ import { mkdirSync as mkdirSync21, readFileSync as readFileSync47, writeFileSync as writeFileSync21, existsSync as existsSync55 } from "fs";
25830
26012
  import { dirname as dirname28, join as join59 } from "path";
25831
26013
  function context2() {
25832
26014
  const s = loadSettings().team;
@@ -26039,7 +26221,7 @@ async function vaultRestore(passphrase, opts = {}) {
26039
26221
  }
26040
26222
  try {
26041
26223
  const path = importedPathFor(blob.tool, blob.sessionId);
26042
- if (existsSync54(path)) {
26224
+ if (existsSync55(path)) {
26043
26225
  const localStat = await import("fs").then((m) => m.statSync(path));
26044
26226
  if (Math.abs(localStat.mtimeMs - blob.mtimeSourceMs) < 1) {
26045
26227
  report.skipped.push({ sessionId: blob.sessionId, tool: blob.tool, reason: "unchanged" });
@@ -26122,7 +26304,7 @@ __export(keyring_exports, {
26122
26304
  psQuote: () => psQuote,
26123
26305
  shQuote: () => shQuote
26124
26306
  });
26125
- import { execFileSync as execFileSync3 } from "node:child_process";
26307
+ import { execFileSync as execFileSync4 } from "node:child_process";
26126
26308
  function probeKeyring(r = realRunner) {
26127
26309
  if (r.platform === "darwin") {
26128
26310
  try {
@@ -26234,7 +26416,7 @@ var init_keyring = __esm({
26234
26416
  ACCOUNT = "vault-passphrase";
26235
26417
  realRunner = {
26236
26418
  run(file, args, input) {
26237
- return execFileSync3(file, args, {
26419
+ return execFileSync4(file, args, {
26238
26420
  input,
26239
26421
  encoding: "utf-8",
26240
26422
  stdio: input === void 0 ? ["ignore", "pipe", "pipe"] : ["pipe", "pipe", "pipe"]
@@ -26669,7 +26851,7 @@ __export(service_installer_exports, {
26669
26851
  uninstallService: () => uninstallService
26670
26852
  });
26671
26853
  import { execSync as execSync5 } from "child_process";
26672
- import { existsSync as existsSync55, mkdirSync as mkdirSync22, readFileSync as readFileSync48, rmSync as rmSync9, writeFileSync as writeFileSync22 } from "fs";
26854
+ import { existsSync as existsSync56, mkdirSync as mkdirSync22, readFileSync as readFileSync48, rmSync as rmSync9, writeFileSync as writeFileSync22 } from "fs";
26673
26855
  import { homedir as homedir22 } from "os";
26674
26856
  import { join as join60 } from "path";
26675
26857
  import { fileURLToPath as fileURLToPath5 } from "url";
@@ -26696,7 +26878,7 @@ function isServiceRunning() {
26696
26878
  return /com\.chat-recall\.watch/.test(tryCmd("launchctl list 2>/dev/null"));
26697
26879
  }
26698
26880
  if (process.platform === "linux") {
26699
- return /active/.test(tryCmd("systemctl --user is-active chat-recall-watch.service 2>/dev/null"));
26881
+ return /^active$/m.test(tryCmd("systemctl --user is-active chat-recall-watch.service 2>/dev/null"));
26700
26882
  }
26701
26883
  return false;
26702
26884
  }
@@ -26705,7 +26887,7 @@ function refreshServiceDefinition() {
26705
26887
  try {
26706
26888
  const { watchJs, node, logFile } = resolveDaemonPaths();
26707
26889
  const unitPath = join60(homedir22(), ".config", "systemd", "user", "chat-recall-watch.service");
26708
- if (!existsSync55(unitPath)) return false;
26890
+ if (!existsSync56(unitPath)) return false;
26709
26891
  const current = readFileSync48(unitPath, "utf8");
26710
26892
  if (!current.includes(watchJs)) return false;
26711
26893
  const wanted = renderSystemdUnit(watchJs, node, logFile);
@@ -26772,7 +26954,12 @@ function renderSystemdUnit(watchJs, node, logFile) {
26772
26954
  // sawtooth. 1536MB keeps GC honest (768 OOMed on the largest subagent-fanout session) with plenty of headroom for the
26773
26955
  // largest transcripts.
26774
26956
  `ExecStart=${node} --max-old-space-size=1536 ${watchJs}`,
26775
- "Restart=on-failure",
26957
+ // ALWAYS: the collector never ends its own work, so any exit systemd did
26958
+ // not ask for is a fault. Under on-failure a clean exit left it dead: on
26959
+ // 2026-09-16 the unit went "inactive (dead) … status=0/SUCCESS" and stayed
26960
+ // down for 8 days, so nothing synced and the auto-update tick, which runs
26961
+ // inside the daemon, never ran. `systemctl stop` still stops it.
26962
+ "Restart=always",
26776
26963
  "RestartSec=10",
26777
26964
  "Nice=10",
26778
26965
  // NEVER STOP RETRYING. systemd's default start limiter gives up after a
@@ -26868,7 +27055,7 @@ function uninstallService() {
26868
27055
  } catch {
26869
27056
  }
26870
27057
  const unitPath = join60(homedir22(), ".config", "systemd", "user", "chat-recall-watch.service");
26871
- if (existsSync55(unitPath)) {
27058
+ if (existsSync56(unitPath)) {
26872
27059
  rmSync9(unitPath, { force: true });
26873
27060
  removed = true;
26874
27061
  }
@@ -26885,7 +27072,7 @@ function uninstallService() {
26885
27072
  } catch {
26886
27073
  }
26887
27074
  let removed = false;
26888
- if (existsSync55(plistPath)) {
27075
+ if (existsSync56(plistPath)) {
26889
27076
  rmSync9(plistPath, { force: true });
26890
27077
  removed = true;
26891
27078
  }
@@ -27298,7 +27485,7 @@ init_project_resolver();
27298
27485
  import { config } from "dotenv";
27299
27486
  import { Command } from "commander";
27300
27487
  import chalk2 from "chalk";
27301
- import { existsSync as existsSync56, readFileSync as readFileSync49, writeFileSync as writeFileSync23, realpathSync as realpathSync5 } from "fs";
27488
+ import { existsSync as existsSync57, readFileSync as readFileSync49, writeFileSync as writeFileSync23, realpathSync as realpathSync5 } from "fs";
27302
27489
  import { homedir as homedir23 } from "os";
27303
27490
  import { join as join61, resolve as resolve2, dirname as dirname29, basename as basename27 } from "path";
27304
27491
 
@@ -27407,7 +27594,7 @@ function renderEnvNeeds(needs, installedCount) {
27407
27594
 
27408
27595
  // src/star-nudge.ts
27409
27596
  init_paths();
27410
- import { existsSync as existsSync42, mkdirSync as mkdirSync11, writeFileSync as writeFileSync11 } from "node:fs";
27597
+ import { existsSync as existsSync43, mkdirSync as mkdirSync11, writeFileSync as writeFileSync11 } from "node:fs";
27411
27598
  import { dirname as dirname20, join as join45 } from "node:path";
27412
27599
  var REPO = "https://github.com/munhq/chat-recall";
27413
27600
  function markerPath() {
@@ -27423,7 +27610,7 @@ function shouldAskForStar(resultCount) {
27423
27610
  if (suppressed()) return false;
27424
27611
  if (!process.stderr.isTTY) return false;
27425
27612
  try {
27426
- return !existsSync42(markerPath());
27613
+ return !existsSync43(markerPath());
27427
27614
  } catch {
27428
27615
  return false;
27429
27616
  }
@@ -27464,7 +27651,7 @@ function claudeHookConfigFiles() {
27464
27651
  const out = [];
27465
27652
  const seen = /* @__PURE__ */ new Set();
27466
27653
  for (const home of claudeHomeDirs()) {
27467
- if (!existsSync56(join61(home, "projects"))) continue;
27654
+ if (!existsSync57(join61(home, "projects"))) continue;
27468
27655
  const file = join61(home, "hooks.json");
27469
27656
  let key2;
27470
27657
  try {
@@ -28250,7 +28437,7 @@ memory.command("wake-up").description("Generate wake-up context (high-importance
28250
28437
  try {
28251
28438
  const identityFile = getIdentityFilePath();
28252
28439
  let identity = "AI coding assistant";
28253
- if (existsSync56(identityFile)) {
28440
+ if (existsSync57(identityFile)) {
28254
28441
  identity = readFileSync49(identityFile, "utf-8").trim();
28255
28442
  }
28256
28443
  const lines = [
@@ -28351,7 +28538,7 @@ program.command("feedback").argument("<message...>", "what you want to say \u201
28351
28538
  }
28352
28539
  });
28353
28540
  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) => {
28354
- const { existsSync: existsSync57, readFileSync: readFileSync50, statSync: statSync45 } = await import("fs");
28541
+ const { existsSync: existsSync58, readFileSync: readFileSync50, statSync: statSync45 } = await import("fs");
28355
28542
  const { execSync: execSync6 } = await import("child_process");
28356
28543
  const rows = [];
28357
28544
  const note = (ok, label, detail) => rows.push({ ok, label, detail });
@@ -28415,7 +28602,7 @@ program.command("doctor").description("Quick health check across login, server,
28415
28602
  }
28416
28603
  }
28417
28604
  const credFile = join61(getDataDir(), "credentials.json");
28418
- if (!existsSync57(credFile)) {
28605
+ if (!existsSync58(credFile)) {
28419
28606
  note(false, "Credentials file", `missing \u2014 run \`chat-recall login <server-url>\``);
28420
28607
  } else {
28421
28608
  try {
@@ -28430,13 +28617,13 @@ program.command("doctor").description("Quick health check across login, server,
28430
28617
  for (const hooksJson of claudeHookConfigFiles()) {
28431
28618
  const profile = basename27(dirname29(hooksJson));
28432
28619
  const label = `Claude hooks (${profile})`;
28433
- if (!existsSync57(hooksJson)) {
28620
+ if (!existsSync58(hooksJson)) {
28434
28621
  note(false, label, `no ${hooksJson} \u2014 run \`chat-recall install-hooks\``);
28435
28622
  continue;
28436
28623
  }
28437
28624
  try {
28438
28625
  const readHooks = (file) => {
28439
- if (!existsSync57(file)) return {};
28626
+ if (!existsSync58(file)) return {};
28440
28627
  try {
28441
28628
  return JSON.parse(readFileSync50(file, "utf-8")).hooks || {};
28442
28629
  } catch {
@@ -28479,9 +28666,9 @@ program.command("doctor").description("Quick health check across login, server,
28479
28666
  try {
28480
28667
  const reg = await Promise.resolve().then(() => (init_guard_registration(), guard_registration_exports));
28481
28668
  for (const target2 of reg.guardTargets()) {
28482
- if (!existsSync57(target2.homeDir)) continue;
28669
+ if (!existsSync58(target2.homeDir)) continue;
28483
28670
  const label = `Decision guard \u2014 ${target2.label}`;
28484
- if (!existsSync57(target2.configPath)) {
28671
+ if (!existsSync58(target2.configPath)) {
28485
28672
  note(false, label, `not registered \u2014 run \`chat-recall install-hooks\``);
28486
28673
  continue;
28487
28674
  }
@@ -28506,7 +28693,7 @@ program.command("doctor").description("Quick health check across login, server,
28506
28693
  const want = bundledSkillNames2().length;
28507
28694
  for (const t of skillTargets2()) {
28508
28695
  if (!t.available) continue;
28509
- const have = want === 0 ? 0 : bundledSkillNames2().filter((n) => existsSync57(join61(t.dir, n, ".chat-recall-managed"))).length;
28696
+ const have = want === 0 ? 0 : bundledSkillNames2().filter((n) => existsSync58(join61(t.dir, n, ".chat-recall-managed"))).length;
28510
28697
  note(
28511
28698
  have === want,
28512
28699
  `Skills \u2014 ${t.label}`,
@@ -28576,7 +28763,7 @@ program.command("doctor").description("Quick health check across login, server,
28576
28763
  } else if (process.platform === "darwin") {
28577
28764
  watchRunning = /com\.chat-recall\.watch/.test(tryCmd2("launchctl list 2>/dev/null"));
28578
28765
  } else {
28579
- watchRunning = /active/.test(tryCmd2("systemctl --user is-active chat-recall-watch.service 2>/dev/null"));
28766
+ watchRunning = /^active$/m.test(tryCmd2("systemctl --user is-active chat-recall-watch.service 2>/dev/null"));
28580
28767
  }
28581
28768
  note(watchRunning, "Watch daemon", watchRunning ? "running" : "not running (run `chat-recall watch --install-service` to keep collection running)");
28582
28769
  const dataDir = getDataDir();
@@ -28588,7 +28775,7 @@ program.command("doctor").description("Quick health check across login, server,
28588
28775
  join61(dataDir, "index", "knowledge_graph.db"),
28589
28776
  join61(dataDir, "index", "metadata.db")
28590
28777
  ];
28591
- const legacyPresent = legacyPaths.filter((p) => existsSync57(p));
28778
+ const legacyPresent = legacyPaths.filter((p) => existsSync58(p));
28592
28779
  if (opts.purgeLocal) {
28593
28780
  if (!target) {
28594
28781
  note(false, "Purge legacy index", "refused \u2014 log in and `chat-recall sync` first, so your history is on the server before removing local copies");
@@ -29232,10 +29419,10 @@ tasks.command("pull [dir]").description("Write TEAM_TASKS.md for your tasks in t
29232
29419
  try {
29233
29420
  const { resolveProjectId: resolveProjectId2 } = await Promise.resolve().then(() => (init_project_resolver(), project_resolver_exports));
29234
29421
  const { renderTeamTasksMd: renderTeamTasksMd2, parseTeamTasksFile: parseTeamTasksFile2 } = await Promise.resolve().then(() => (init_project_tasks(), project_tasks_exports));
29235
- const { writeFileSync: writeFileSync24, readFileSync: readFileSync50, existsSync: existsSync57 } = await import("node:fs");
29422
+ const { writeFileSync: writeFileSync24, readFileSync: readFileSync50, existsSync: existsSync58 } = await import("node:fs");
29236
29423
  const { join: join62 } = await import("node:path");
29237
29424
  const file = join62(cwd, "TEAM_TASKS.md");
29238
- if (!opts.force && existsSync57(file) && parseTeamTasksFile2(readFileSync50(file, "utf8")).length > 0) {
29425
+ if (!opts.force && existsSync58(file) && parseTeamTasksFile2(readFileSync50(file, "utf8")).length > 0) {
29239
29426
  console.error(chalk2.red("TEAM_TASKS.md has unpushed edits."), "Run", chalk2.bold("chat-recall tasks push"), "first, or", chalk2.bold("tasks pull --force"), "to discard.");
29240
29427
  process.exit(1);
29241
29428
  }
@@ -29254,10 +29441,10 @@ tasks.command("push [dir]").description("Push TEAM_TASKS.md status edits back to
29254
29441
  const cwd = dir || process.cwd();
29255
29442
  try {
29256
29443
  const { parseTeamTasksFile: parseTeamTasksFile2 } = await Promise.resolve().then(() => (init_project_tasks(), project_tasks_exports));
29257
- const { readFileSync: readFileSync50, existsSync: existsSync57 } = await import("node:fs");
29444
+ const { readFileSync: readFileSync50, existsSync: existsSync58 } = await import("node:fs");
29258
29445
  const { join: join62 } = await import("node:path");
29259
29446
  const file = join62(cwd, "TEAM_TASKS.md");
29260
- if (!existsSync57(file)) {
29447
+ if (!existsSync58(file)) {
29261
29448
  console.error(chalk2.red("no TEAM_TASKS.md here \u2014"), "run", chalk2.bold("chat-recall tasks pull"), "first");
29262
29449
  process.exit(1);
29263
29450
  }
@@ -29699,10 +29886,10 @@ program.command("task-hook").description("Move a board card when a prompt or a c
29699
29886
  return;
29700
29887
  }
29701
29888
  if (!opts.close) return;
29702
- const { execFileSync: execFileSync4 } = await import("node:child_process");
29889
+ const { execFileSync: execFileSync5 } = await import("node:child_process");
29703
29890
  const git2 = (args) => {
29704
29891
  try {
29705
- return execFileSync4("git", args, {
29892
+ return execFileSync5("git", args, {
29706
29893
  cwd,
29707
29894
  encoding: "utf8",
29708
29895
  timeout: 5e3,
@@ -29744,7 +29931,7 @@ program.command("task-hook").description("Move a board card when a prompt or a c
29744
29931
  }
29745
29932
  });
29746
29933
  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) => {
29747
- const { mkdirSync: mkdirSync23, copyFileSync: copyFileSync4, chmodSync: chmodSync5, existsSync: existsSync57, readFileSync: readFileSync50, writeFileSync: writeFileSync24, statSync: statSync45, unlinkSync: unlinkSync4 } = await import("fs");
29934
+ const { mkdirSync: mkdirSync23, copyFileSync: copyFileSync4, chmodSync: chmodSync5, existsSync: existsSync58, readFileSync: readFileSync50, writeFileSync: writeFileSync24, statSync: statSync45, unlinkSync: unlinkSync4 } = await import("fs");
29748
29935
  const { fileURLToPath: fileURLToPath6 } = await import("url");
29749
29936
  const { boardHookEntries: boardHookEntries2, isBoardHookEntry: isBoardHookEntry2, registerBoardHooks: registerBoardHooks2, resolveCliEntry: resolveCliEntry2 } = await Promise.resolve().then(() => (init_board_hooks(), board_hooks_exports));
29750
29937
  const here = fileURLToPath6(new URL(".", import.meta.url));
@@ -29757,7 +29944,7 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
29757
29944
  // freshly added script is only at the root until that build runs.
29758
29945
  join61(here, "..", "..", "..", "hooks", name)
29759
29946
  ];
29760
- return candidates2.find((p) => existsSync57(p));
29947
+ return candidates2.find((p) => existsSync58(p));
29761
29948
  };
29762
29949
  const sourceSaveHook = findHook("chat_recall_save_hook.sh");
29763
29950
  const sourceGuardHook = findHook("chat_recall_guard_hook.sh");
@@ -29776,7 +29963,7 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
29776
29963
  const installedWakeupHook = join61(hooksDir, "chat_recall_wakeup_hook.sh");
29777
29964
  const wakeupWiredInSettings = (home) => {
29778
29965
  const settings2 = join61(home, "settings.json");
29779
- if (!existsSync57(settings2)) return false;
29966
+ if (!existsSync58(settings2)) return false;
29780
29967
  try {
29781
29968
  const cfg = JSON.parse(readFileSync50(settings2, "utf-8"));
29782
29969
  const arr = Array.isArray(cfg.hooks?.SessionStart) ? cfg.hooks.SessionStart : [];
@@ -29787,7 +29974,7 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
29787
29974
  };
29788
29975
  const hookConfigFiles = claudeHookConfigFiles();
29789
29976
  const readHookConfig = (file) => {
29790
- if (!existsSync57(file)) return { hooks: {} };
29977
+ if (!existsSync58(file)) return { hooks: {} };
29791
29978
  try {
29792
29979
  const c = JSON.parse(readFileSync50(file, "utf-8"));
29793
29980
  if (!c.hooks || typeof c.hooks !== "object") c.hooks = {};
@@ -29804,7 +29991,7 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
29804
29991
  };
29805
29992
  const HOOK_EVENTS = ["Stop", "PreCompact", "UserPromptSubmit", "SessionEnd", "SessionStart", "PreToolUse"];
29806
29993
  const readJson4 = (file) => {
29807
- if (!existsSync57(file)) return {};
29994
+ if (!existsSync58(file)) return {};
29808
29995
  try {
29809
29996
  return JSON.parse(readFileSync50(file, "utf-8"));
29810
29997
  } catch {
@@ -29815,7 +30002,7 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
29815
30002
  const reg = await Promise.resolve().then(() => (init_guard_registration(), guard_registration_exports));
29816
30003
  const notes = [];
29817
30004
  for (const target of reg.guardTargets()) {
29818
- if (!existsSync57(target.homeDir)) continue;
30005
+ if (!existsSync58(target.homeDir)) continue;
29819
30006
  const wrapper = join61(hooksDir, reg.guardWrapperName(target.tool));
29820
30007
  writeFileSync24(wrapper, reg.guardWrapperSource(target.tool, hookPath));
29821
30008
  chmodSync5(wrapper, 493);
@@ -29836,7 +30023,7 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
29836
30023
  const reg = await Promise.resolve().then(() => (init_guard_registration(), guard_registration_exports));
29837
30024
  let removed = 0;
29838
30025
  for (const target of reg.guardTargets()) {
29839
- if (!existsSync57(target.configPath)) continue;
30026
+ if (!existsSync58(target.configPath)) continue;
29840
30027
  if (target.tool === "opencode") {
29841
30028
  const body = readFileSync50(target.configPath, "utf-8");
29842
30029
  if (!body.includes("chat-recall install-hooks")) continue;
@@ -29864,7 +30051,7 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
29864
30051
  if (filtered.length) config2.hooks[event] = filtered;
29865
30052
  else delete config2.hooks[event];
29866
30053
  }
29867
- if (removed === 0 && !existsSync57(hooksJson)) continue;
30054
+ if (removed === 0 && !existsSync58(hooksJson)) continue;
29868
30055
  writeFileSync24(hooksJson, JSON.stringify(config2, null, 2) + "\n");
29869
30056
  total += removed;
29870
30057
  console.log(chalk2.green(`\u2713 Removed ${removed} chat-recall hook entr${removed === 1 ? "y" : "ies"} from ${hooksJson}`));
@@ -30737,8 +30924,8 @@ npm has ${version2}; the server you sync to still serves ${check.serverVersion}.
30737
30924
  console.log(chalk2.dim(`
30738
30925
  Installing ${version2} from npm\u2026`));
30739
30926
  try {
30740
- const { execFileSync: execFileSync4 } = await import("node:child_process");
30741
- execFileSync4("npm", ["install", "-g", `chat-recall@${version2}`], { stdio: "inherit" });
30927
+ const { execFileSync: execFileSync5 } = await import("node:child_process");
30928
+ execFileSync5("npm", ["install", "-g", `chat-recall@${version2}`], { stdio: "inherit" });
30742
30929
  const { installedVersion: installedVersion2 } = await Promise.resolve().then(() => (init_auto_update(), auto_update_exports));
30743
30930
  const landed = installedVersion2();
30744
30931
  if (landed && compareVersions2(landed, version2) >= 0) {