chat-recall 0.7.17 → 0.7.18

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
@@ -2034,7 +2034,7 @@ var require_thread_stream = __commonJS({
2034
2034
  var { version: version2 } = require_package();
2035
2035
  var { EventEmitter } = __require("events");
2036
2036
  var { Worker: Worker2 } = __require("worker_threads");
2037
- var { join: join62 } = __require("path");
2037
+ var { join: join63 } = __require("path");
2038
2038
  var { pathToFileURL } = __require("url");
2039
2039
  var { wait } = require_wait();
2040
2040
  var {
@@ -2077,7 +2077,7 @@ var require_thread_stream = __commonJS({
2077
2077
  function createWorker(stream, opts) {
2078
2078
  const { filename, workerData } = opts;
2079
2079
  const bundlerOverrides = "__bundlerPathsOverrides" in globalThis ? globalThis.__bundlerPathsOverrides : {};
2080
- const toExecute = bundlerOverrides["thread-stream-worker"] || join62(__dirname, "lib", "worker.js");
2080
+ const toExecute = bundlerOverrides["thread-stream-worker"] || join63(__dirname, "lib", "worker.js");
2081
2081
  const worker = new Worker2(toExecute, {
2082
2082
  ...opts.workerOpts,
2083
2083
  trackUnmanagedFds: false,
@@ -2480,7 +2480,7 @@ var require_transport = __commonJS({
2480
2480
  "use strict";
2481
2481
  var { createRequire: createRequire3 } = __require("module");
2482
2482
  var getCallers = require_caller();
2483
- var { join: join62, isAbsolute: isAbsolute4, sep: sep4 } = __require("node:path");
2483
+ var { join: join63, isAbsolute: isAbsolute4, sep: sep4 } = __require("node:path");
2484
2484
  var sleep2 = require_atomic_sleep();
2485
2485
  var onExit = require_on_exit_leak_free();
2486
2486
  var ThreadStream = require_thread_stream();
@@ -2543,7 +2543,7 @@ var require_transport = __commonJS({
2543
2543
  throw new Error("only one of target or targets can be specified");
2544
2544
  }
2545
2545
  if (targets) {
2546
- target = bundlerOverrides["pino-worker"] || join62(__dirname, "worker.js");
2546
+ target = bundlerOverrides["pino-worker"] || join63(__dirname, "worker.js");
2547
2547
  options.targets = targets.filter((dest) => dest.target).map((dest) => {
2548
2548
  return {
2549
2549
  ...dest,
@@ -2561,7 +2561,7 @@ var require_transport = __commonJS({
2561
2561
  });
2562
2562
  });
2563
2563
  } else if (pipeline) {
2564
- target = bundlerOverrides["pino-worker"] || join62(__dirname, "worker.js");
2564
+ target = bundlerOverrides["pino-worker"] || join63(__dirname, "worker.js");
2565
2565
  options.pipelines = [pipeline.map((dest) => {
2566
2566
  return {
2567
2567
  ...dest,
@@ -2583,7 +2583,7 @@ var require_transport = __commonJS({
2583
2583
  return origin;
2584
2584
  }
2585
2585
  if (origin === "pino/file") {
2586
- return join62(__dirname, "..", "file.js");
2586
+ return join63(__dirname, "..", "file.js");
2587
2587
  }
2588
2588
  let fixTarget2;
2589
2589
  for (const filePath of callers) {
@@ -3572,7 +3572,7 @@ var require_safe_stable_stringify = __commonJS({
3572
3572
  return circularValue;
3573
3573
  }
3574
3574
  let res = "";
3575
- let join62 = ",";
3575
+ let join63 = ",";
3576
3576
  const originalIndentation = indentation;
3577
3577
  if (Array.isArray(value)) {
3578
3578
  if (value.length === 0) {
@@ -3586,7 +3586,7 @@ var require_safe_stable_stringify = __commonJS({
3586
3586
  indentation += spacer;
3587
3587
  res += `
3588
3588
  ${indentation}`;
3589
- join62 = `,
3589
+ join63 = `,
3590
3590
  ${indentation}`;
3591
3591
  }
3592
3592
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
@@ -3594,13 +3594,13 @@ ${indentation}`;
3594
3594
  for (; i < maximumValuesToStringify - 1; i++) {
3595
3595
  const tmp2 = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
3596
3596
  res += tmp2 !== void 0 ? tmp2 : "null";
3597
- res += join62;
3597
+ res += join63;
3598
3598
  }
3599
3599
  const tmp = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
3600
3600
  res += tmp !== void 0 ? tmp : "null";
3601
3601
  if (value.length - 1 > maximumBreadth) {
3602
3602
  const removedKeys = value.length - maximumBreadth - 1;
3603
- res += `${join62}"... ${getItemCount(removedKeys)} not stringified"`;
3603
+ res += `${join63}"... ${getItemCount(removedKeys)} not stringified"`;
3604
3604
  }
3605
3605
  if (spacer !== "") {
3606
3606
  res += `
@@ -3621,7 +3621,7 @@ ${originalIndentation}`;
3621
3621
  let separator = "";
3622
3622
  if (spacer !== "") {
3623
3623
  indentation += spacer;
3624
- join62 = `,
3624
+ join63 = `,
3625
3625
  ${indentation}`;
3626
3626
  whitespace = " ";
3627
3627
  }
@@ -3635,13 +3635,13 @@ ${indentation}`;
3635
3635
  const tmp = stringifyFnReplacer(key3, value, stack, replacer, spacer, indentation);
3636
3636
  if (tmp !== void 0) {
3637
3637
  res += `${separator}${strEscape(key3)}:${whitespace}${tmp}`;
3638
- separator = join62;
3638
+ separator = join63;
3639
3639
  }
3640
3640
  }
3641
3641
  if (keyLength > maximumBreadth) {
3642
3642
  const removedKeys = keyLength - maximumBreadth;
3643
3643
  res += `${separator}"...":${whitespace}"${getItemCount(removedKeys)} not stringified"`;
3644
- separator = join62;
3644
+ separator = join63;
3645
3645
  }
3646
3646
  if (spacer !== "" && separator.length > 1) {
3647
3647
  res = `
@@ -3682,7 +3682,7 @@ ${originalIndentation}`;
3682
3682
  }
3683
3683
  const originalIndentation = indentation;
3684
3684
  let res = "";
3685
- let join62 = ",";
3685
+ let join63 = ",";
3686
3686
  if (Array.isArray(value)) {
3687
3687
  if (value.length === 0) {
3688
3688
  return "[]";
@@ -3695,7 +3695,7 @@ ${originalIndentation}`;
3695
3695
  indentation += spacer;
3696
3696
  res += `
3697
3697
  ${indentation}`;
3698
- join62 = `,
3698
+ join63 = `,
3699
3699
  ${indentation}`;
3700
3700
  }
3701
3701
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
@@ -3703,13 +3703,13 @@ ${indentation}`;
3703
3703
  for (; i < maximumValuesToStringify - 1; i++) {
3704
3704
  const tmp2 = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
3705
3705
  res += tmp2 !== void 0 ? tmp2 : "null";
3706
- res += join62;
3706
+ res += join63;
3707
3707
  }
3708
3708
  const tmp = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
3709
3709
  res += tmp !== void 0 ? tmp : "null";
3710
3710
  if (value.length - 1 > maximumBreadth) {
3711
3711
  const removedKeys = value.length - maximumBreadth - 1;
3712
- res += `${join62}"... ${getItemCount(removedKeys)} not stringified"`;
3712
+ res += `${join63}"... ${getItemCount(removedKeys)} not stringified"`;
3713
3713
  }
3714
3714
  if (spacer !== "") {
3715
3715
  res += `
@@ -3722,7 +3722,7 @@ ${originalIndentation}`;
3722
3722
  let whitespace = "";
3723
3723
  if (spacer !== "") {
3724
3724
  indentation += spacer;
3725
- join62 = `,
3725
+ join63 = `,
3726
3726
  ${indentation}`;
3727
3727
  whitespace = " ";
3728
3728
  }
@@ -3731,7 +3731,7 @@ ${indentation}`;
3731
3731
  const tmp = stringifyArrayReplacer(key3, value[key3], stack, replacer, spacer, indentation);
3732
3732
  if (tmp !== void 0) {
3733
3733
  res += `${separator}${strEscape(key3)}:${whitespace}${tmp}`;
3734
- separator = join62;
3734
+ separator = join63;
3735
3735
  }
3736
3736
  }
3737
3737
  if (spacer !== "" && separator.length > 1) {
@@ -3789,20 +3789,20 @@ ${originalIndentation}`;
3789
3789
  indentation += spacer;
3790
3790
  let res2 = `
3791
3791
  ${indentation}`;
3792
- const join63 = `,
3792
+ const join64 = `,
3793
3793
  ${indentation}`;
3794
3794
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
3795
3795
  let i = 0;
3796
3796
  for (; i < maximumValuesToStringify - 1; i++) {
3797
3797
  const tmp2 = stringifyIndent(String(i), value[i], stack, spacer, indentation);
3798
3798
  res2 += tmp2 !== void 0 ? tmp2 : "null";
3799
- res2 += join63;
3799
+ res2 += join64;
3800
3800
  }
3801
3801
  const tmp = stringifyIndent(String(i), value[i], stack, spacer, indentation);
3802
3802
  res2 += tmp !== void 0 ? tmp : "null";
3803
3803
  if (value.length - 1 > maximumBreadth) {
3804
3804
  const removedKeys = value.length - maximumBreadth - 1;
3805
- res2 += `${join63}"... ${getItemCount(removedKeys)} not stringified"`;
3805
+ res2 += `${join64}"... ${getItemCount(removedKeys)} not stringified"`;
3806
3806
  }
3807
3807
  res2 += `
3808
3808
  ${originalIndentation}`;
@@ -3818,16 +3818,16 @@ ${originalIndentation}`;
3818
3818
  return '"[Object]"';
3819
3819
  }
3820
3820
  indentation += spacer;
3821
- const join62 = `,
3821
+ const join63 = `,
3822
3822
  ${indentation}`;
3823
3823
  let res = "";
3824
3824
  let separator = "";
3825
3825
  let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth);
3826
3826
  if (isTypedArrayWithEntries(value)) {
3827
- res += stringifyTypedArray(value, join62, maximumBreadth);
3827
+ res += stringifyTypedArray(value, join63, maximumBreadth);
3828
3828
  keys = keys.slice(value.length);
3829
3829
  maximumPropertiesToStringify -= value.length;
3830
- separator = join62;
3830
+ separator = join63;
3831
3831
  }
3832
3832
  if (deterministic) {
3833
3833
  keys = sort(keys, comparator);
@@ -3838,13 +3838,13 @@ ${indentation}`;
3838
3838
  const tmp = stringifyIndent(key3, value[key3], stack, spacer, indentation);
3839
3839
  if (tmp !== void 0) {
3840
3840
  res += `${separator}${strEscape(key3)}: ${tmp}`;
3841
- separator = join62;
3841
+ separator = join63;
3842
3842
  }
3843
3843
  }
3844
3844
  if (keyLength > maximumBreadth) {
3845
3845
  const removedKeys = keyLength - maximumBreadth;
3846
3846
  res += `${separator}"...": "${getItemCount(removedKeys)} not stringified"`;
3847
- separator = join62;
3847
+ separator = join63;
3848
3848
  }
3849
3849
  if (separator !== "") {
3850
3850
  res = `
@@ -6617,6 +6617,7 @@ var init_from_events = __esm({
6617
6617
  // ../engine/dist/transcript/raw.js
6618
6618
  var raw_exports = {};
6619
6619
  __export(raw_exports, {
6620
+ RAW_PARSE_MAX_BYTES: () => RAW_PARSE_MAX_BYTES,
6620
6621
  archiveRawSession: () => archiveRawSession,
6621
6622
  buildRawContainer: () => buildRawContainer,
6622
6623
  containerSrcHash: () => containerSrcHash,
@@ -6916,11 +6917,11 @@ async function archiveRawSession(store, sessionId) {
6916
6917
  return await store.putRawSession(sessionId, exp.tool, Math.floor(exp.mtime), gz, size);
6917
6918
  }
6918
6919
  function detectForkPredecessor(sessionPath) {
6919
- const { readFileSync: readFileSync50, readdirSync: readdirSync34 } = requireFs();
6920
- const { dirname: dirname30, join: join62, basename: basename28 } = requirePath();
6920
+ const { readFileSync: readFileSync51, readdirSync: readdirSync34 } = requireFs();
6921
+ const { dirname: dirname30, join: join63, basename: basename28 } = requirePath();
6921
6922
  let text;
6922
6923
  try {
6923
- text = readFileSync50(sessionPath, "utf-8");
6924
+ text = readFileSync51(sessionPath, "utf-8");
6924
6925
  } catch {
6925
6926
  return null;
6926
6927
  }
@@ -6954,7 +6955,7 @@ function detectForkPredecessor(sessionPath) {
6954
6955
  if (!f.endsWith(".jsonl") || f === self || f === "sessions-index.json")
6955
6956
  continue;
6956
6957
  try {
6957
- if (readFileSync50(join62(dir, f), "utf-8").includes(`"uuid":"${headParent}"`)) {
6958
+ if (readFileSync51(join63(dir, f), "utf-8").includes(`"uuid":"${headParent}"`)) {
6958
6959
  return basename28(f, ".jsonl");
6959
6960
  }
6960
6961
  } catch {
@@ -6968,7 +6969,7 @@ function requireFs() {
6968
6969
  function requirePath() {
6969
6970
  return pathMod;
6970
6971
  }
6971
- var MARKER_QUOTE;
6972
+ var RAW_PARSE_MAX_BYTES, MARKER_QUOTE;
6972
6973
  var init_raw = __esm({
6973
6974
  "../engine/dist/transcript/raw.js"() {
6974
6975
  "use strict";
@@ -6976,6 +6977,7 @@ var init_raw = __esm({
6976
6977
  init_claude();
6977
6978
  init_codex();
6978
6979
  init_from_events();
6980
+ RAW_PARSE_MAX_BYTES = 40 * 1024 * 1024;
6979
6981
  MARKER_QUOTE = /\[REDACTED:[A-Za-z0-9_-]+\]"/g;
6980
6982
  }
6981
6983
  });
@@ -14360,6 +14362,7 @@ var init_opencode2 = __esm({
14360
14362
  // ../engine/dist/transcript/index.js
14361
14363
  var transcript_exports = {};
14362
14364
  __export(transcript_exports, {
14365
+ RAW_PARSE_MAX_BYTES: () => RAW_PARSE_MAX_BYTES,
14363
14366
  TRANSCRIPT_VERSION: () => TRANSCRIPT_VERSION,
14364
14367
  archiveRawSession: () => archiveRawSession,
14365
14368
  buildRawContainer: () => buildRawContainer,
@@ -18820,6 +18823,11 @@ function markSynced(server, rows) {
18820
18823
  base4.s = s;
18821
18824
  }
18822
18825
  if (r.hash !== void 0) base4.h = r.hash;
18826
+ const completesChunked = cursorFromCaller && r.chunkFinal === true && prev?.k === 1;
18827
+ if (cursorFromCaller && (r.full || completesChunked) && o > 0) base4.F = o;
18828
+ else if (prev?.F !== void 0) base4.F = prev.F;
18829
+ if (cursorFromCaller && r.chunkedHead) base4.k = 1;
18830
+ else if (prev?.k && !completesChunked && !(cursorFromCaller && r.full)) base4.k = 1;
18823
18831
  forServer[r.id] = base4;
18824
18832
  }
18825
18833
  persist(data);
@@ -18876,6 +18884,14 @@ function markFieldFullPassDone(server, field) {
18876
18884
  delete st.force[field.name];
18877
18885
  persistReconcile(data);
18878
18886
  }
18887
+ function forgetFullCoverage(server, sessionId) {
18888
+ const data = load();
18889
+ const row = data[server]?.[sessionId];
18890
+ if (!row || typeof row !== "object") return;
18891
+ delete row.F;
18892
+ delete row.h;
18893
+ persist(data);
18894
+ }
18879
18895
  function markFullResync(server, sessionId) {
18880
18896
  const data = load();
18881
18897
  const forServer = data[server];
@@ -18884,7 +18900,11 @@ function markFullResync(server, sessionId) {
18884
18900
  delete forServer[sessionId];
18885
18901
  persist(data);
18886
18902
  }
18887
- function syncMode(row, mtime, fileSize, extractorVersion, isAppendOnly) {
18903
+ function fullCoveredOffset(row) {
18904
+ if (row.F !== void 0) return row.F;
18905
+ return row.h ? row.s ?? 0 : 0;
18906
+ }
18907
+ function syncMode(row, mtime, fileSize, extractorVersion, isAppendOnly, nowMs = Date.now()) {
18888
18908
  if (!row) return "full";
18889
18909
  if (row.v < extractorVersion) return "full";
18890
18910
  const offset = row.o ?? 0;
@@ -18892,10 +18912,13 @@ function syncMode(row, mtime, fileSize, extractorVersion, isAppendOnly) {
18892
18912
  if (process.env.CHAT_RECALL_TAIL_APPEND !== "0" && isAppendOnly && fileSize > 0 && offset > 0 && fileSize > (row.s ?? 0)) {
18893
18913
  return "append";
18894
18914
  }
18915
+ if (isAppendOnly && offset > 0 && fileSize > 0 && fileSize === (row.s ?? 0) && !row.k && fullCoveredOffset(row) < offset && nowMs - Math.floor(mtime) >= SETTLE_QUIET_MS) {
18916
+ return "full";
18917
+ }
18895
18918
  if (row.m >= Math.floor(mtime)) return "skip";
18896
18919
  return "full";
18897
18920
  }
18898
- var ledgerPath, cache3, base, diskStamp, rowKey, LEDGER_FLUSH_MS, pendingWrite, flushTimer, itemVersionsPath, itemVersionsCache, inventoryPath, unackedCursorAttempts, reconcilePath, reconcileCache;
18921
+ var ledgerPath, cache3, base, diskStamp, rowKey, LEDGER_FLUSH_MS, pendingWrite, flushTimer, itemVersionsPath, itemVersionsCache, inventoryPath, unackedCursorAttempts, reconcilePath, reconcileCache, SETTLE_QUIET_MS;
18899
18922
  var init_sync_ledger = __esm({
18900
18923
  "src/sync-ledger.ts"() {
18901
18924
  "use strict";
@@ -18915,6 +18938,7 @@ var init_sync_ledger = __esm({
18915
18938
  unackedCursorAttempts = 0;
18916
18939
  reconcilePath = () => join38(getDataDir(), "sync-field-reconcile.json");
18917
18940
  reconcileCache = null;
18941
+ SETTLE_QUIET_MS = 2 * 60 * 60 * 1e3;
18918
18942
  }
18919
18943
  });
18920
18944
 
@@ -19066,7 +19090,7 @@ var init_http = __esm({
19066
19090
  CLI_VERSION = JSON.parse(readFileSync31(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
19067
19091
  } catch {
19068
19092
  try {
19069
- if (true) CLI_VERSION = "0.7.17";
19093
+ if (true) CLI_VERSION = "0.7.18";
19070
19094
  } catch {
19071
19095
  }
19072
19096
  }
@@ -19564,7 +19588,7 @@ var init_telemetry = __esm({
19564
19588
  init_sync_client();
19565
19589
  cliVersion2 = () => {
19566
19590
  try {
19567
- return true ? "0.7.17" : "dev";
19591
+ return true ? "0.7.18" : "dev";
19568
19592
  } catch {
19569
19593
  return "dev";
19570
19594
  }
@@ -19727,6 +19751,150 @@ var init_collector_health = __esm({
19727
19751
  }
19728
19752
  });
19729
19753
 
19754
+ // src/raw-archive-parts.ts
19755
+ import { createReadStream as createReadStream4, createWriteStream, openSync as openSync9, readSync as readSync8, closeSync as closeSync9, rmSync as rmSync5, statSync as statSync37 } from "node:fs";
19756
+ import { tmpdir as tmpdir2 } from "node:os";
19757
+ import { join as join41 } from "node:path";
19758
+ import { randomBytes } from "node:crypto";
19759
+ import { createGzip } from "node:zlib";
19760
+ import { once } from "node:events";
19761
+ import { readFileSync as readFileSync33 } from "node:fs";
19762
+ async function* fileLines(path) {
19763
+ let rest = "";
19764
+ const decoder = new TextDecoder("utf-8");
19765
+ for await (const chunk of createReadStream4(path, { highWaterMark: 1024 * 1024 })) {
19766
+ rest += decoder.decode(chunk, { stream: true });
19767
+ let nl = rest.indexOf("\n");
19768
+ while (nl >= 0) {
19769
+ yield rest.slice(0, nl + 1);
19770
+ rest = rest.slice(nl + 1);
19771
+ nl = rest.indexOf("\n");
19772
+ }
19773
+ }
19774
+ rest += decoder.decode();
19775
+ if (rest) yield rest;
19776
+ }
19777
+ function* textLines(text) {
19778
+ let at = 0;
19779
+ while (at < text.length) {
19780
+ const nl = text.indexOf("\n", at);
19781
+ const end = nl < 0 ? text.length : nl + 1;
19782
+ yield text.slice(at, end);
19783
+ at = end;
19784
+ }
19785
+ }
19786
+ async function writeArchiveFile(source, meta, redact, dir = tmpdir2()) {
19787
+ const path = join41(dir, `cr-archive-${randomBytes(8).toString("hex")}.json.gz`);
19788
+ const gzip = createGzip({ level: 6 });
19789
+ const out = createWriteStream(path, { mode: 384 });
19790
+ const done = once(out, "finish");
19791
+ gzip.pipe(out);
19792
+ let size = 0;
19793
+ const write = async (s) => {
19794
+ size += Buffer.byteLength(s);
19795
+ if (!gzip.write(s)) await once(gzip, "drain");
19796
+ };
19797
+ try {
19798
+ await write(`{"v":1,"tool":${JSON.stringify(meta.tool)},"mtime":${Math.floor(meta.mtime)},"files":[`);
19799
+ for (const [i, f] of source.files.entries()) {
19800
+ await write(`${i ? "," : ""}{"name":${JSON.stringify(f.name)},"text":"`);
19801
+ const whole = () => source.kind === "memory" ? f.text : readFileSync33(f.path, "utf-8");
19802
+ if (!f.name.endsWith(".jsonl")) {
19803
+ await write(escapeJson(redact(whole())));
19804
+ } else {
19805
+ const lines = source.kind === "memory" ? textLines(f.text) : fileLines(f.path);
19806
+ for await (const line of lines) {
19807
+ const nl = line.endsWith("\n");
19808
+ const body2 = nl ? line.slice(0, -1) : line;
19809
+ await write(escapeJson((body2 ? redactJsonLine(body2, redact) : body2) + (nl ? "\n" : "")));
19810
+ }
19811
+ }
19812
+ await write('"}');
19813
+ }
19814
+ await write("]}");
19815
+ gzip.end();
19816
+ await done;
19817
+ } catch (err) {
19818
+ gzip.destroy();
19819
+ out.destroy();
19820
+ rmSync5(path, { force: true });
19821
+ throw err;
19822
+ }
19823
+ return { path, gzSize: statSync37(path).size, size };
19824
+ }
19825
+ async function putPart(url, body2) {
19826
+ let last;
19827
+ for (let attempt = 1; attempt <= PART_ATTEMPTS; attempt++) {
19828
+ const ac = new AbortController();
19829
+ const timer = setTimeout(() => ac.abort(), PART_TIMEOUT_MS);
19830
+ try {
19831
+ const r = await fetch(url, { method: "PUT", body: body2, signal: ac.signal });
19832
+ const etag = r.headers.get("etag");
19833
+ if (r.ok && etag) return etag;
19834
+ last = new Error(`part PUT answered ${r.status}`);
19835
+ if (r.status === 403 || r.status === 404) break;
19836
+ } catch (err) {
19837
+ last = err;
19838
+ } finally {
19839
+ clearTimeout(timer);
19840
+ }
19841
+ }
19842
+ throw last instanceof Error ? last : new Error(String(last));
19843
+ }
19844
+ async function uploadArchiveFile(base4, token, args) {
19845
+ const headers = { "content-type": "application/json" };
19846
+ if (token) headers.authorization = `Bearer ${token}`;
19847
+ const post = async (path, body2) => {
19848
+ const r = await fetch(`${base4}/api/sync/raw-upload/${path}`, { method: "POST", headers, body: JSON.stringify(body2) });
19849
+ const json = await r.json().catch(() => ({}));
19850
+ return { status: r.status, json };
19851
+ };
19852
+ const start = await post("start", {
19853
+ session_id: args.sessionId,
19854
+ tool: args.tool,
19855
+ mtime: Math.floor(args.mtime),
19856
+ size: args.file.size,
19857
+ gz_size: args.file.gzSize,
19858
+ project_id: args.projectId,
19859
+ project_path: args.projectPath
19860
+ });
19861
+ if (start.status === 501 || start.status === 404) return "unsupported";
19862
+ if (start.status !== 200) throw new Error(`raw upload start answered ${start.status}: ${start.json.error ?? ""}`);
19863
+ if (start.json.result === "unchanged" || start.json.result === "shrink-protected") return start.json.result;
19864
+ const urls = start.json.urls;
19865
+ const partBytes = Number(start.json.part_bytes);
19866
+ const parts = [];
19867
+ const fd = openSync9(args.file.path, "r");
19868
+ try {
19869
+ for (const [i, url] of urls.entries()) {
19870
+ const len = Math.min(partBytes, args.file.gzSize - i * partBytes);
19871
+ const buf = Buffer.allocUnsafe(len);
19872
+ let got = 0;
19873
+ while (got < len) {
19874
+ const n = readSync8(fd, buf, got, len - got, i * partBytes + got);
19875
+ if (n <= 0) break;
19876
+ got += n;
19877
+ }
19878
+ parts.push({ part_number: i + 1, etag: await putPart(url, buf.subarray(0, got)) });
19879
+ }
19880
+ } finally {
19881
+ closeSync9(fd);
19882
+ }
19883
+ const done = await post("complete", { session_id: args.sessionId, upload_id: start.json.upload_id, parts });
19884
+ if (done.status !== 200) throw new Error(`raw upload complete answered ${done.status}: ${done.json.error ?? ""}`);
19885
+ return done.json.result;
19886
+ }
19887
+ var escapeJson, PART_TIMEOUT_MS, PART_ATTEMPTS;
19888
+ var init_raw_archive_parts = __esm({
19889
+ "src/raw-archive-parts.ts"() {
19890
+ "use strict";
19891
+ init_transcript();
19892
+ escapeJson = (s) => JSON.stringify(s).slice(1, -1);
19893
+ PART_TIMEOUT_MS = 12e4;
19894
+ PART_ATTEMPTS = 3;
19895
+ }
19896
+ });
19897
+
19730
19898
  // src/server-probe.ts
19731
19899
  var server_probe_exports = {};
19732
19900
  __export(server_probe_exports, {
@@ -19870,7 +20038,7 @@ __export(client_events_exports, {
19870
20038
  isTelemetryEnabled: () => isTelemetryEnabled,
19871
20039
  reportClientEvent: () => reportClientEvent
19872
20040
  });
19873
- import { readFileSync as readFileSync33 } from "node:fs";
20041
+ import { readFileSync as readFileSync34 } from "node:fs";
19874
20042
  function scrub(msg) {
19875
20043
  if (!msg) return "";
19876
20044
  const noHome = msg.replace(/\/(?:home|Users)\/[^/\s]+/g, "~");
@@ -19923,7 +20091,7 @@ var init_client_events = __esm({
19923
20091
  init_secret_redactor();
19924
20092
  CLI_VERSION2 = "0.0.0";
19925
20093
  try {
19926
- CLI_VERSION2 = JSON.parse(readFileSync33(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION2;
20094
+ CLI_VERSION2 = JSON.parse(readFileSync34(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION2;
19927
20095
  } catch {
19928
20096
  }
19929
20097
  }
@@ -19953,11 +20121,11 @@ __export(auto_update_exports, {
19953
20121
  tarballUrl: () => tarballUrl
19954
20122
  });
19955
20123
  import { execSync as execSync2, execFileSync as execFileSync3 } from "node:child_process";
19956
- import { readFileSync as readFileSync34, existsSync as existsSync41 } from "node:fs";
20124
+ import { readFileSync as readFileSync35, existsSync as existsSync41 } from "node:fs";
19957
20125
  import { fileURLToPath as fileURLToPath2 } from "node:url";
19958
- import { writeFileSync as writeFileSync8, mkdtempSync as mkdtempSync3, rmSync as rmSync5, readdirSync as readdirSync30, statSync as statSync37, mkdirSync as mkdirSync9 } from "node:fs";
19959
- import { join as join41, dirname as dirname18, sep as sep2, posix as pathPosix, win32 as pathWin32 } from "node:path";
19960
- import { tmpdir as tmpdir2, homedir as homedir15 } from "node:os";
20126
+ import { writeFileSync as writeFileSync8, mkdtempSync as mkdtempSync3, rmSync as rmSync6, readdirSync as readdirSync30, statSync as statSync38, mkdirSync as mkdirSync9 } from "node:fs";
20127
+ import { join as join42, dirname as dirname18, sep as sep2, posix as pathPosix, win32 as pathWin32 } from "node:path";
20128
+ import { tmpdir as tmpdir3, homedir as homedir15 } from "node:os";
19961
20129
  import { createHash as createHash8 } from "node:crypto";
19962
20130
  function compareVersions(a, b) {
19963
20131
  const pa = String(a).split("-")[0].split(".").map((n) => parseInt(n, 10) || 0);
@@ -19981,7 +20149,7 @@ function newerOf(a, b) {
19981
20149
  function installedVersion() {
19982
20150
  try {
19983
20151
  const here = dirname18(fileURLToPath2(import.meta.url));
19984
- const raw = readFileSync34(join41(here, "..", "package.json"), "utf-8");
20152
+ const raw = readFileSync35(join42(here, "..", "package.json"), "utf-8");
19985
20153
  return JSON.parse(raw).version || null;
19986
20154
  } catch {
19987
20155
  return null;
@@ -19994,7 +20162,7 @@ function planAutoUpdate(base4, caps, ownVersion3, flag) {
19994
20162
  if (compareVersions(rel.version, ownVersion3) <= 0) return { update: false, reason: `already current (own ${ownVersion3} >= server ${rel.version})` };
19995
20163
  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 };
19996
20164
  }
19997
- function sweepStaleStaging(root = tmpdir2(), now = Date.now()) {
20165
+ function sweepStaleStaging(root = tmpdir3(), now = Date.now()) {
19998
20166
  const MKDTEMP_SUFFIX = /^cr-update-.{6}$/s;
19999
20167
  const COLD_MS = 60 * 60 * 1e3;
20000
20168
  let removed = 0;
@@ -20006,13 +20174,13 @@ function sweepStaleStaging(root = tmpdir2(), now = Date.now()) {
20006
20174
  }
20007
20175
  for (const name of entries) {
20008
20176
  if (!MKDTEMP_SUFFIX.test(name)) continue;
20009
- const dir = join41(root, name);
20177
+ const dir = join42(root, name);
20010
20178
  try {
20011
- const st = statSync37(dir);
20179
+ const st = statSync38(dir);
20012
20180
  if (!st.isDirectory() || now - st.mtimeMs < COLD_MS) continue;
20013
20181
  const inside = readdirSync30(dir);
20014
20182
  if (inside.length > 1 || inside.length === 1 && inside[0] !== "chat-recall.tgz") continue;
20015
- rmSync5(dir, { recursive: true, force: true });
20183
+ rmSync6(dir, { recursive: true, force: true });
20016
20184
  removed++;
20017
20185
  } catch {
20018
20186
  }
@@ -20035,14 +20203,14 @@ async function executeAutoUpdate(plan, deps) {
20035
20203
  }
20036
20204
  const got = createHash8("sha256").update(buf).digest("hex");
20037
20205
  if (got !== plan.sha256) return { updated: false, reason: `checksum mismatch (expected ${plan.sha256.slice(0, 12)}\u2026, got ${got.slice(0, 12)}\u2026) \u2014 NOT installing` };
20038
- const dir = mkdtempSync3(join41(tmpdir2(), "cr-update-"));
20206
+ const dir = mkdtempSync3(join42(tmpdir3(), "cr-update-"));
20039
20207
  const discardStaging = () => {
20040
20208
  try {
20041
- rmSync5(dir, { recursive: true, force: true });
20209
+ rmSync6(dir, { recursive: true, force: true });
20042
20210
  } catch {
20043
20211
  }
20044
20212
  };
20045
- const tgz = join41(dir, "chat-recall.tgz");
20213
+ const tgz = join42(dir, "chat-recall.tgz");
20046
20214
  writeFileSync8(tgz, buf);
20047
20215
  if (deps.stopping?.()) {
20048
20216
  discardStaging();
@@ -20122,7 +20290,7 @@ function realInstall(tgz) {
20122
20290
  try {
20123
20291
  npmInstall(npm, ["install", "-g", tgz]);
20124
20292
  } catch {
20125
- npmInstall(npm, ["install", "-g", "--prefix", join41(homedir15(), ".local"), tgz]);
20293
+ npmInstall(npm, ["install", "-g", "--prefix", join42(homedir15(), ".local"), tgz]);
20126
20294
  }
20127
20295
  }
20128
20296
  function acquireUpdateLock() {
@@ -20139,12 +20307,12 @@ function realRestart(platform2) {
20139
20307
  if (c) execSync2(c.cmd, { stdio: "ignore", ...c.shell ? { shell: c.shell } : {} });
20140
20308
  }
20141
20309
  function updateStatePath() {
20142
- const dir = process.env.CHAT_RECALL_DATA_DIR || join41(homedir15(), ".chat-recall");
20143
- return join41(dir, "auto-update-state.json");
20310
+ const dir = process.env.CHAT_RECALL_DATA_DIR || join42(homedir15(), ".chat-recall");
20311
+ return join42(dir, "auto-update-state.json");
20144
20312
  }
20145
20313
  function readUpdateState() {
20146
20314
  try {
20147
- return JSON.parse(readFileSync34(updateStatePath(), "utf8"));
20315
+ return JSON.parse(readFileSync35(updateStatePath(), "utf8"));
20148
20316
  } catch {
20149
20317
  return {};
20150
20318
  }
@@ -20285,9 +20453,9 @@ __export(sync_client_exports, {
20285
20453
  syncIncremental: () => syncIncremental,
20286
20454
  syncSessions: () => syncSessions
20287
20455
  });
20288
- import { join as join42, dirname as dirname19, basename as basename20 } from "node:path";
20289
- 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";
20290
- import { tmpdir as tmpdir3, hostname as hostname2 } from "node:os";
20456
+ import { join as join43, dirname as dirname19, basename as basename20 } from "node:path";
20457
+ import { readFileSync as readFileSync36, writeFileSync as writeFileSync9, mkdirSync as mkdirSync10, mkdtempSync as mkdtempSync4, rmSync as rmSync7, chmodSync as chmodSync3, unlinkSync as unlinkSync2, readdirSync as readdirSync31, statSync as statSync39 } from "node:fs";
20458
+ import { tmpdir as tmpdir4, hostname as hostname2 } from "node:os";
20291
20459
  import { createHash as createHash9 } from "node:crypto";
20292
20460
  import { fileURLToPath as fileURLToPath3 } from "node:url";
20293
20461
  import { gzipSync as gzipSync3 } from "zlib";
@@ -20341,7 +20509,7 @@ function loadAllCredentials() {
20341
20509
  const fromEnv = envCredentials();
20342
20510
  if (fromEnv) return [{ serverUrl: fromEnv.serverUrl, token: fromEnv.token }];
20343
20511
  try {
20344
- const parsed = JSON.parse(readFileSync35(credPath(), "utf-8"));
20512
+ const parsed = JSON.parse(readFileSync36(credPath(), "utf-8"));
20345
20513
  if (Array.isArray(parsed?.targets)) return parsed.targets.filter((t) => t?.serverUrl).map((t) => ({ serverUrl: t.serverUrl, token: t.token || "" }));
20346
20514
  if (parsed?.serverUrl) return [{ serverUrl: parsed.serverUrl, token: parsed.token || "" }];
20347
20515
  } catch {
@@ -20403,11 +20571,11 @@ function _resetTenantSecurityConfigCache() {
20403
20571
  _securityConfigCache.clear();
20404
20572
  }
20405
20573
  function syncConfigCachePath() {
20406
- return join42(getDataDir(), "sync-config-cache.json");
20574
+ return join43(getDataDir(), "sync-config-cache.json");
20407
20575
  }
20408
20576
  function readPersistedSyncConfigs() {
20409
20577
  try {
20410
- return JSON.parse(readFileSync35(syncConfigCachePath(), "utf-8"));
20578
+ return JSON.parse(readFileSync36(syncConfigCachePath(), "utf-8"));
20411
20579
  } catch {
20412
20580
  return {};
20413
20581
  }
@@ -20685,7 +20853,7 @@ async function reconcileFields(opts = {}) {
20685
20853
  }
20686
20854
  return { sessions: fullRefs().length, scanned, pushed, absent, perTarget };
20687
20855
  }
20688
- function reapStaleScanDirs(dir = tmpdir3(), maxAgeMs = 6 * 36e5, now = Date.now()) {
20856
+ function reapStaleScanDirs(dir = tmpdir4(), maxAgeMs = 6 * 36e5, now = Date.now()) {
20689
20857
  let reaped = 0;
20690
20858
  let names;
20691
20859
  try {
@@ -20695,10 +20863,10 @@ function reapStaleScanDirs(dir = tmpdir3(), maxAgeMs = 6 * 36e5, now = Date.now(
20695
20863
  }
20696
20864
  for (const name of names) {
20697
20865
  if (!name.startsWith("cr-batchscan-")) continue;
20698
- const p = join42(dir, name);
20866
+ const p = join43(dir, name);
20699
20867
  try {
20700
- if (now - statSync38(p).mtimeMs < maxAgeMs) continue;
20701
- rmSync6(p, { recursive: true, force: true });
20868
+ if (now - statSync39(p).mtimeMs < maxAgeMs) continue;
20869
+ rmSync7(p, { recursive: true, force: true });
20702
20870
  reaped++;
20703
20871
  } catch {
20704
20872
  }
@@ -20712,7 +20880,7 @@ function batchScanExternal(items, opts = {}) {
20712
20880
  let scanned = 0, slices = 0, scanMs = 0;
20713
20881
  if (items.length === 0) return { findings, scanned, slices, scanMs };
20714
20882
  reapStaleScanDirs();
20715
- let scanDir = mkdtempSync4(join42(tmpdir3(), "cr-batchscan-"));
20883
+ let scanDir = mkdtempSync4(join43(tmpdir4(), "cr-batchscan-"));
20716
20884
  let safeToId = /* @__PURE__ */ new Map();
20717
20885
  let bytesInDir = 0;
20718
20886
  const flushSlice = () => {
@@ -20730,7 +20898,7 @@ function batchScanExternal(items, opts = {}) {
20730
20898
  slices++;
20731
20899
  }
20732
20900
  try {
20733
- rmSync6(scanDir, { recursive: true, force: true });
20901
+ rmSync7(scanDir, { recursive: true, force: true });
20734
20902
  } catch {
20735
20903
  }
20736
20904
  safeToId = /* @__PURE__ */ new Map();
@@ -20743,19 +20911,19 @@ function batchScanExternal(items, opts = {}) {
20743
20911
  if (raw === null) continue;
20744
20912
  const safe = item.id.replace(/[^A-Za-z0-9_-]/g, "");
20745
20913
  safeToId.set(safe, item.id);
20746
- writeFileSync9(join42(scanDir, `${safe}.txt`), raw);
20914
+ writeFileSync9(join43(scanDir, `${safe}.txt`), raw);
20747
20915
  bytesInDir += Buffer.byteLength(raw);
20748
20916
  } catch {
20749
20917
  }
20750
20918
  if (bytesInDir >= maxBytes) {
20751
20919
  flushSlice();
20752
- scanDir = mkdtempSync4(join42(tmpdir3(), "cr-batchscan-"));
20920
+ scanDir = mkdtempSync4(join43(tmpdir4(), "cr-batchscan-"));
20753
20921
  }
20754
20922
  }
20755
20923
  flushSlice();
20756
20924
  } finally {
20757
20925
  try {
20758
- rmSync6(scanDir, { recursive: true, force: true });
20926
+ rmSync7(scanDir, { recursive: true, force: true });
20759
20927
  } catch {
20760
20928
  }
20761
20929
  }
@@ -20999,12 +21167,13 @@ async function syncToTargetInScope(cred, opts = {}) {
20999
21167
  markSynced(base4, rows.map((r) => {
21000
21168
  const off = typeof r.from_offset === "number" ? r.from_offset : 0;
21001
21169
  const hash = shippedHash.get(r.session_id);
21002
- 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 };
21170
+ return off > 0 ? { id: r.session_id, mtime: r.mtime, offset: off, size: off, hash, acked: true, full: true } : { id: r.session_id, mtime: r.mtime, hash };
21003
21171
  }));
21004
21172
  } catch {
21005
21173
  }
21006
21174
  });
21007
21175
  const appendResults = { uploaded: 0, fullResyncNeeded: /* @__PURE__ */ new Set() };
21176
+ const pendingArchives = [];
21008
21177
  const postAppend = async (convs) => {
21009
21178
  const headers = { "content-type": "application/json" };
21010
21179
  if (cred.token) headers.authorization = `Bearer ${cred.token}`;
@@ -21039,8 +21208,10 @@ async function syncToTargetInScope(cred, opts = {}) {
21039
21208
  offset: c.from_offset,
21040
21209
  size: c.from_offset,
21041
21210
  // size = new offset (file grew to here)
21042
- acked: true
21211
+ acked: true,
21043
21212
  // server merged this tail
21213
+ chunkFinal: c.final === true
21214
+ // completes a chunked full sync
21044
21215
  })));
21045
21216
  } catch {
21046
21217
  }
@@ -21072,9 +21243,9 @@ async function syncToTargetInScope(cred, opts = {}) {
21072
21243
  const mtime = conv.mtime;
21073
21244
  try {
21074
21245
  if (staged || !guarded) {
21075
- markSynced(base4, [{ id, mtime, offset: conv.from_offset, size: conv.from_offset, acked: true }]);
21246
+ markSynced(base4, [{ id, mtime, offset: conv.from_offset, size: conv.from_offset, acked: true, chunkedHead: true }]);
21076
21247
  } else if (typeof guarded.o === "number" && guarded.o > 0 && guarded.o <= fileSize) {
21077
- markSynced(base4, [{ id, mtime, offset: guarded.o, size: guarded.o, acked: true }]);
21248
+ markSynced(base4, [{ id, mtime, offset: guarded.o, size: guarded.o, acked: true, chunkedHead: true }]);
21078
21249
  } else {
21079
21250
  markSynced(base4, [{ id, mtime }]);
21080
21251
  }
@@ -21283,6 +21454,14 @@ async function syncToTargetInScope(cred, opts = {}) {
21283
21454
  if (built.srcHash) shippedHash.set(ref.prefixedId, built.srcHash);
21284
21455
  if (built.conv.chunked) await postChunkedHead(built.conv, sessionFileBytes(ref));
21285
21456
  else await convBatch.add(built.conv);
21457
+ if (built.archive) {
21458
+ pendingArchives.push({
21459
+ id: ref.prefixedId,
21460
+ ...built.archive,
21461
+ projectId: built.conv.project_id,
21462
+ projectPath: built.conv.project_path
21463
+ });
21464
+ }
21286
21465
  if (built.findings.length > 0) await findingsBatch.add(built.findings);
21287
21466
  if (upload.sessionMeta) {
21288
21467
  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);
@@ -21435,6 +21614,30 @@ async function syncToTargetInScope(cred, opts = {}) {
21435
21614
  await kgTripleBatch.drain();
21436
21615
  await findingsBatch.drain();
21437
21616
  await drainInflight();
21617
+ let archivesUnsupported = false;
21618
+ for (const a of pendingArchives) {
21619
+ try {
21620
+ if (!archivesUnsupported) {
21621
+ const r = await uploadArchiveFile(base4, cred.token, {
21622
+ sessionId: a.id,
21623
+ tool: a.tool,
21624
+ mtime: a.mtime,
21625
+ projectId: a.projectId,
21626
+ projectPath: a.projectPath,
21627
+ file: a.file
21628
+ });
21629
+ if (r === "unsupported") archivesUnsupported = true;
21630
+ }
21631
+ } catch (err) {
21632
+ console.error(`[sync] raw archive for ${a.id} not uploaded (tried again when the session is next quiet): ${err instanceof Error ? err.message : err}`);
21633
+ try {
21634
+ forgetFullCoverage(base4, a.id);
21635
+ } catch {
21636
+ }
21637
+ } finally {
21638
+ rmSync7(a.file.path, { force: true });
21639
+ }
21640
+ }
21438
21641
  {
21439
21642
  const sentHashes = loadInventoryHashes(base4);
21440
21643
  const entries = [];
@@ -21540,6 +21743,7 @@ async function buildConversationSync(ref, mtime, opts = {}) {
21540
21743
  let includeRaw = opts.includeRaw !== false;
21541
21744
  let includeMeta = opts.includeMeta !== false;
21542
21745
  let srcHash;
21746
+ const wantRaw = opts.includeRaw !== false;
21543
21747
  const oversized = sessionBuildBytes(ref) > FULL_BUILD_MAX_BYTES;
21544
21748
  let headOffsetEnd = 0;
21545
21749
  let oversizedFindings = null;
@@ -21708,7 +21912,7 @@ async function buildConversationSync(ref, mtime, opts = {}) {
21708
21912
  } else if (opts.scanSecrets) {
21709
21913
  let tmp = null;
21710
21914
  try {
21711
- tmp = join42(tmpdir3(), `cr-scan-${ref.prefixedId.replace(/[^A-Za-z0-9_-]/g, "")}-${mtime}.txt`);
21915
+ tmp = join43(tmpdir4(), `cr-scan-${ref.prefixedId.replace(/[^A-Za-z0-9_-]/g, "")}-${mtime}.txt`);
21712
21916
  writeFileSync9(tmp, rawText);
21713
21917
  for (const f of scanFileForSecrets(tmp, { verifyOnly: opts.verifySecrets, tenantRules: opts.tenantRules })) {
21714
21918
  const verifiedAt = f.verified ? (/* @__PURE__ */ new Date()).toISOString() : null;
@@ -21760,6 +21964,25 @@ async function buildConversationSync(ref, mtime, opts = {}) {
21760
21964
  }
21761
21965
  const envTexts = envelope.messages.filter((m) => m.content?.trim());
21762
21966
  const redactedText = envTexts.map((m) => m.content).join("\n");
21967
+ let archive;
21968
+ if (wantRaw && !raw_b64) {
21969
+ try {
21970
+ const redact = (t) => redactSecrets(t, { force: true, count });
21971
+ let source = null;
21972
+ let archiveMtime = Math.floor(ref.mtime) || 0;
21973
+ let archiveTool = ref.toolId;
21974
+ if (container) {
21975
+ source = { kind: "memory", files: container.files };
21976
+ archiveMtime = container.mtime;
21977
+ archiveTool = container.tool;
21978
+ } else if (oversized) {
21979
+ source = diskArchiveSource(ref);
21980
+ }
21981
+ if (source) archive = { file: await writeArchiveFile(source, { tool: archiveTool, mtime: archiveMtime }, redact), tool: archiveTool, mtime: archiveMtime };
21982
+ } catch (err) {
21983
+ console.error(`[sync] raw archive for ${ref.prefixedId} not written: ${err instanceof Error ? err.message : err}`);
21984
+ }
21985
+ }
21763
21986
  return {
21764
21987
  conv: {
21765
21988
  session_id: ref.prefixedId,
@@ -21791,7 +22014,17 @@ async function buildConversationSync(ref, mtime, opts = {}) {
21791
22014
  redactions: count.redactions,
21792
22015
  findings,
21793
22016
  scanMs,
21794
- srcHash
22017
+ srcHash,
22018
+ archive
22019
+ };
22020
+ }
22021
+ function diskArchiveSource(ref) {
22022
+ if (ref.toolId !== "claude") return null;
22023
+ const groups = resolveSessionContentGroups(ref.rawId);
22024
+ if (groups.length === 0 || groups.some((g) => g.paths.length !== 1)) return null;
22025
+ return {
22026
+ kind: "disk",
22027
+ files: groups.map((g) => ({ name: g.name === "main" ? `${ref.rawId}.jsonl` : g.name, path: g.paths[0] }))
21795
22028
  };
21796
22029
  }
21797
22030
  function parseTailMessages(tool, text) {
@@ -21947,14 +22180,15 @@ var init_sync_client = __esm({
21947
22180
  init_telemetry();
21948
22181
  init_collector_health();
21949
22182
  init_live_session_scan();
22183
+ init_raw_archive_parts();
21950
22184
  init_backends();
21951
22185
  ownVersion = "0.0.0";
21952
22186
  try {
21953
22187
  const dir = dirname19(fileURLToPath3(import.meta.url));
21954
- ownVersion = JSON.parse(readFileSync35(join42(dir, "../package.json"), "utf-8")).version || ownVersion;
22188
+ ownVersion = JSON.parse(readFileSync36(join43(dir, "../package.json"), "utf-8")).version || ownVersion;
21955
22189
  } catch {
21956
22190
  try {
21957
- if (true) ownVersion = "0.7.17";
22191
+ if (true) ownVersion = "0.7.18";
21958
22192
  } catch {
21959
22193
  }
21960
22194
  }
@@ -21966,7 +22200,7 @@ var init_sync_client = __esm({
21966
22200
  ]);
21967
22201
  walkProgressForUpload = null;
21968
22202
  lastServerPackSpec = null;
21969
- credPath = () => join42(getDataDir(), "credentials.json");
22203
+ credPath = () => join43(getDataDir(), "credentials.json");
21970
22204
  _securityConfigCache = /* @__PURE__ */ new Map();
21971
22205
  SECURITY_CONFIG_TTL_MS = 5 * 60 * 1e3;
21972
22206
  _syncConfigCache = /* @__PURE__ */ new Map();
@@ -21997,15 +22231,15 @@ __export(update_notice_exports, {
21997
22231
  refreshUpdateCheck: () => refreshUpdateCheck,
21998
22232
  updateNotice: () => updateNotice
21999
22233
  });
22000
- import { readFileSync as readFileSync36, writeFileSync as writeFileSync10 } from "node:fs";
22001
- import { join as join43 } from "node:path";
22234
+ import { readFileSync as readFileSync37, writeFileSync as writeFileSync10 } from "node:fs";
22235
+ import { join as join44 } from "node:path";
22002
22236
  function newestKnown(c) {
22003
22237
  const npm = c.npmVersion ?? "0.0.0";
22004
22238
  return compareVersions(npm, c.serverVersion) > 0 ? { version: npm, source: "npm" } : { version: c.serverVersion, source: "server" };
22005
22239
  }
22006
22240
  function readCheck() {
22007
22241
  try {
22008
- const c = JSON.parse(readFileSync36(checkPath(), "utf-8"));
22242
+ const c = JSON.parse(readFileSync37(checkPath(), "utf-8"));
22009
22243
  return c && typeof c.serverVersion === "string" ? c : null;
22010
22244
  } catch {
22011
22245
  return null;
@@ -22099,17 +22333,17 @@ var init_update_notice = __esm({
22099
22333
  init_http();
22100
22334
  CHECK_TTL_MS = 6 * 3600 * 1e3;
22101
22335
  NPM_LATEST_URL = "https://registry.npmjs.org/chat-recall";
22102
- checkPath = () => join43(getDataDir(), "update-check.json");
22336
+ checkPath = () => join44(getDataDir(), "update-check.json");
22103
22337
  printed = false;
22104
22338
  }
22105
22339
  });
22106
22340
 
22107
22341
  // ../engine/dist/core/which.js
22108
- import { existsSync as existsSync42, statSync as statSync39, accessSync, constants } from "node:fs";
22109
- import { join as join44, isAbsolute as isAbsolute2, delimiter as delimiter2, sep as sep3 } from "node:path";
22342
+ import { existsSync as existsSync42, statSync as statSync40, accessSync, constants } from "node:fs";
22343
+ import { join as join45, isAbsolute as isAbsolute2, delimiter as delimiter2, sep as sep3 } from "node:path";
22110
22344
  function executable(p) {
22111
22345
  try {
22112
- if (!statSync39(p).isFile())
22346
+ if (!statSync40(p).isFile())
22113
22347
  return false;
22114
22348
  } catch {
22115
22349
  return false;
@@ -22145,7 +22379,7 @@ function resolveOnPath(name) {
22145
22379
  if (!dir)
22146
22380
  continue;
22147
22381
  for (const c of candidates(name)) {
22148
- const full = join44(dir, c);
22382
+ const full = join45(dir, c);
22149
22383
  if (existsSync42(full) && executable(full))
22150
22384
  return full;
22151
22385
  }
@@ -22209,9 +22443,9 @@ __export(mcp_clients_exports, {
22209
22443
  inspectMcpClients: () => inspectMcpClients,
22210
22444
  registerMcpEverywhere: () => registerMcpEverywhere
22211
22445
  });
22212
- import { existsSync as existsSync44, mkdirSync as mkdirSync12, readFileSync as readFileSync37, writeFileSync as writeFileSync12 } from "fs";
22446
+ import { existsSync as existsSync44, mkdirSync as mkdirSync12, readFileSync as readFileSync38, writeFileSync as writeFileSync12 } from "fs";
22213
22447
  import { homedir as homedir16 } from "os";
22214
- import { dirname as dirname21, join as join46 } from "path";
22448
+ import { dirname as dirname21, join as join47 } from "path";
22215
22449
  function envHome(varName, fallback) {
22216
22450
  const v = process.env[varName];
22217
22451
  return v && v.trim() ? v.trim() : fallback;
@@ -22221,7 +22455,7 @@ function writeFileMkdir(path, body2) {
22221
22455
  writeFileSync12(path, body2);
22222
22456
  }
22223
22457
  function readJsonObject(path) {
22224
- const raw = readFileSync37(path, "utf-8");
22458
+ const raw = readFileSync38(path, "utf-8");
22225
22459
  if (raw.trim() === "")
22226
22460
  return {};
22227
22461
  return JSON.parse(raw);
@@ -22296,7 +22530,7 @@ function registerCodexToml(path, spec) {
22296
22530
  const id = "codex";
22297
22531
  const label = "Codex";
22298
22532
  const block = codexBlock(spec);
22299
- const prev = existsSync44(path) ? readFileSync37(path, "utf-8") : "";
22533
+ const prev = existsSync44(path) ? readFileSync38(path, "utf-8") : "";
22300
22534
  const lines = prev.length ? prev.split("\n") : [];
22301
22535
  const start = lines.findIndex((l) => l.trim() === CODEX_HEADER);
22302
22536
  if (start === -1) {
@@ -22339,7 +22573,7 @@ function inspectMcpClients(opts = {}) {
22339
22573
  let registered = false;
22340
22574
  if (existsSync44(path)) {
22341
22575
  try {
22342
- const raw = readFileSync37(path, "utf-8");
22576
+ const raw = readFileSync38(path, "utf-8");
22343
22577
  registered = c.id === "codex" ? raw.includes(CODEX_HEADER) : !!(JSON.parse(raw).mcpServers?.[MCP_SERVER_NAME] ?? JSON.parse(raw).mcp?.[MCP_SERVER_NAME]);
22344
22578
  } catch {
22345
22579
  registered = false;
@@ -22359,7 +22593,7 @@ var init_mcp_clients = __esm({
22359
22593
  id: "claude",
22360
22594
  label: "Claude Code",
22361
22595
  bin: "claude",
22362
- configPath: (home) => join46(home, ".mcp.json"),
22596
+ configPath: (home) => join47(home, ".mcp.json"),
22363
22597
  // Claude Code is the reference client and `init`'s historical target, so we
22364
22598
  // always write it — a fresh machine has no ~/.claude yet on first install.
22365
22599
  isPresent: () => true,
@@ -22371,7 +22605,7 @@ var init_mcp_clients = __esm({
22371
22605
  id: "codex",
22372
22606
  label: "Codex",
22373
22607
  bin: "codex",
22374
- configPath: (home) => join46(envHome("CHAT_RECALL_CODEX_HOME", join46(home, ".codex")), "config.toml"),
22608
+ configPath: (home) => join47(envHome("CHAT_RECALL_CODEX_HOME", join47(home, ".codex")), "config.toml"),
22375
22609
  isPresent(home) {
22376
22610
  const p = this.configPath(home);
22377
22611
  return existsSync44(p) || existsSync44(dirname21(p));
@@ -22384,7 +22618,7 @@ var init_mcp_clients = __esm({
22384
22618
  id: "opencode",
22385
22619
  label: "OpenCode",
22386
22620
  bin: "opencode",
22387
- configPath: (home) => join46(envHome("XDG_CONFIG_HOME", join46(home, ".config")), "opencode", "opencode.json"),
22621
+ configPath: (home) => join47(envHome("XDG_CONFIG_HOME", join47(home, ".config")), "opencode", "opencode.json"),
22388
22622
  isPresent(home) {
22389
22623
  const p = this.configPath(home);
22390
22624
  return existsSync44(p) || existsSync44(dirname21(p));
@@ -22399,9 +22633,9 @@ var init_mcp_clients = __esm({
22399
22633
  id: "agy",
22400
22634
  label: "Antigravity",
22401
22635
  bin: "agy",
22402
- configPath: (home) => join46(home, ".gemini", "config", "mcp_config.json"),
22636
+ configPath: (home) => join47(home, ".gemini", "config", "mcp_config.json"),
22403
22637
  isPresent(home) {
22404
- return existsSync44(join46(home, ".gemini", "antigravity-cli")) || existsSync44(this.configPath(home));
22638
+ return existsSync44(join47(home, ".gemini", "antigravity-cli")) || existsSync44(this.configPath(home));
22405
22639
  },
22406
22640
  register(spec, home) {
22407
22641
  return registerMcpServersJson(this, this.configPath(home), spec);
@@ -22411,7 +22645,7 @@ var init_mcp_clients = __esm({
22411
22645
  id: "cursor",
22412
22646
  label: "Cursor",
22413
22647
  bin: "cursor",
22414
- configPath: (home) => join46(home, ".cursor", "mcp.json"),
22648
+ configPath: (home) => join47(home, ".cursor", "mcp.json"),
22415
22649
  isPresent(home) {
22416
22650
  const p = this.configPath(home);
22417
22651
  return existsSync44(p) || existsSync44(dirname21(p));
@@ -22438,9 +22672,9 @@ __export(companions_exports, {
22438
22672
  uninstallCodeindex: () => uninstallCodeindex,
22439
22673
  unregisterCodeindexMcp: () => unregisterCodeindexMcp
22440
22674
  });
22441
- 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";
22675
+ import { existsSync as existsSync45, mkdirSync as mkdirSync13, statSync as statSync41, chmodSync as chmodSync4, unlinkSync as unlinkSync3, renameSync as renameSync5, createWriteStream as createWriteStream2, readFileSync as readFileSync39, writeFileSync as writeFileSync13 } from "node:fs";
22442
22676
  import { homedir as homedir17 } from "node:os";
22443
- import { join as join47 } from "node:path";
22677
+ import { join as join48 } from "node:path";
22444
22678
  import { execSync as execSync3 } from "node:child_process";
22445
22679
  import { createHash as createHash10 } from "node:crypto";
22446
22680
  function expectedCodeindexSha256(artifact) {
@@ -22489,7 +22723,7 @@ function checkCodeindexStatus() {
22489
22723
  status.installed = true;
22490
22724
  status.path = foundPath;
22491
22725
  try {
22492
- status.size = statSync40(foundPath).size;
22726
+ status.size = statSync41(foundPath).size;
22493
22727
  } catch {
22494
22728
  }
22495
22729
  try {
@@ -22515,7 +22749,7 @@ async function downloadArtifact(artifact, dest) {
22515
22749
  throw new Error(`Download failed: ${res.status} ${res.statusText}`);
22516
22750
  if (!res.body)
22517
22751
  throw new Error("Download returned empty body");
22518
- const file = createWriteStream(dest);
22752
+ const file = createWriteStream2(dest);
22519
22753
  await new Promise((resolve3, reject) => {
22520
22754
  const reader = res.body.getReader();
22521
22755
  const pump = async () => {
@@ -22550,7 +22784,7 @@ async function installCodeindex(opts = {}) {
22550
22784
  if (!expected) {
22551
22785
  throw new Error(`No pinned checksum for ${status.artifactName} \u2014 refusing to install an unverified binary. Add its sha256 to CODEINDEX_SHA256 in companions.ts.`);
22552
22786
  }
22553
- const actual = createHash10("sha256").update(readFileSync38(tmpPath)).digest("hex");
22787
+ const actual = createHash10("sha256").update(readFileSync39(tmpPath)).digest("hex");
22554
22788
  if (actual !== expected) {
22555
22789
  throw new Error(`Checksum mismatch for ${status.artifactName}.
22556
22790
  expected ${expected}
@@ -22580,7 +22814,7 @@ function registerCodeindexMcp(mcpJsonPath, binaryPath) {
22580
22814
  let cfg = {};
22581
22815
  if (existsSync45(mcpJsonPath)) {
22582
22816
  try {
22583
- cfg = JSON.parse(readFileSync38(mcpJsonPath, "utf-8"));
22817
+ cfg = JSON.parse(readFileSync39(mcpJsonPath, "utf-8"));
22584
22818
  } catch {
22585
22819
  cfg = {};
22586
22820
  }
@@ -22597,7 +22831,7 @@ function unregisterCodeindexMcp(mcpJsonPath) {
22597
22831
  return { removed: false };
22598
22832
  let cfg;
22599
22833
  try {
22600
- cfg = JSON.parse(readFileSync38(mcpJsonPath, "utf-8"));
22834
+ cfg = JSON.parse(readFileSync39(mcpJsonPath, "utf-8"));
22601
22835
  } catch {
22602
22836
  return { removed: false };
22603
22837
  }
@@ -22622,9 +22856,9 @@ var init_companions = __esm({
22622
22856
  "x86_64-windows": "a96fc8c8949bb399a44cc0615b12e458460a529c69f01e8829cc39a20f45ab29",
22623
22857
  "aarch64-windows": "42620d56272cd9ba9d785569d8d754d6b4a3e80f36f28db3e0c483fd600ed117"
22624
22858
  };
22625
- CODEINDEX_INSTALL_DIR = join47(homedir17(), ".local", "bin");
22859
+ CODEINDEX_INSTALL_DIR = join48(homedir17(), ".local", "bin");
22626
22860
  CODEINDEX_BIN_NAME = process.platform === "win32" ? "codeindex.exe" : "codeindex";
22627
- CODEINDEX_BIN_PATH = join47(CODEINDEX_INSTALL_DIR, CODEINDEX_BIN_NAME);
22861
+ CODEINDEX_BIN_PATH = join48(CODEINDEX_INSTALL_DIR, CODEINDEX_BIN_NAME);
22628
22862
  }
22629
22863
  });
22630
22864
 
@@ -22639,15 +22873,15 @@ __export(install_skills_exports, {
22639
22873
  skillsSourceDir: () => skillsSourceDir,
22640
22874
  uninstallSkills: () => uninstallSkills
22641
22875
  });
22642
- 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";
22876
+ import { readdirSync as readdirSync32, existsSync as existsSync46, mkdirSync as mkdirSync14, rmSync as rmSync8, cpSync, writeFileSync as writeFileSync14, readFileSync as readFileSync40, statSync as statSync42, realpathSync as realpathSync4 } from "fs";
22643
22877
  import { createHash as createHash11 } from "crypto";
22644
- import { join as join48, basename as basename21 } from "path";
22878
+ import { join as join49, basename as basename21 } from "path";
22645
22879
  function skillsSourceDir() {
22646
- return join48(import.meta.dirname, "..", "skills");
22880
+ return join49(import.meta.dirname, "..", "skills");
22647
22881
  }
22648
22882
  function version() {
22649
22883
  try {
22650
- return JSON.parse(readFileSync39(new URL("../package.json", import.meta.url), "utf-8")).version || "0.0.0";
22884
+ return JSON.parse(readFileSync40(new URL("../package.json", import.meta.url), "utf-8")).version || "0.0.0";
22651
22885
  } catch {
22652
22886
  return "0.0.0";
22653
22887
  }
@@ -22656,9 +22890,9 @@ function skillsFingerprint() {
22656
22890
  const src = skillsSourceDir();
22657
22891
  const h = createHash11("sha256");
22658
22892
  for (const name of bundledSkillNames()) {
22659
- for (const rel of filesUnder(join48(src, name)).sort()) {
22893
+ for (const rel of filesUnder(join49(src, name)).sort()) {
22660
22894
  h.update(name + "/" + rel);
22661
- h.update(readFileSync39(join48(src, name, rel)));
22895
+ h.update(readFileSync40(join49(src, name, rel)));
22662
22896
  }
22663
22897
  }
22664
22898
  return h.digest("hex").slice(0, 12);
@@ -22668,7 +22902,7 @@ function filesUnder(dir, prefix = "") {
22668
22902
  for (const e of readdirSync32(dir, { withFileTypes: true })) {
22669
22903
  if (e.name === MARKER) continue;
22670
22904
  const rel = prefix ? `${prefix}/${e.name}` : e.name;
22671
- if (e.isDirectory()) out.push(...filesUnder(join48(dir, e.name), rel));
22905
+ if (e.isDirectory()) out.push(...filesUnder(join49(dir, e.name), rel));
22672
22906
  else out.push(rel);
22673
22907
  }
22674
22908
  return out;
@@ -22679,7 +22913,7 @@ function skillStamp() {
22679
22913
  function bundledSkillNames() {
22680
22914
  const src = skillsSourceDir();
22681
22915
  if (!existsSync46(src)) return [];
22682
- return readdirSync32(src, { withFileTypes: true }).filter((e) => e.isDirectory() && existsSync46(join48(src, e.name, "SKILL.md"))).map((e) => e.name).sort();
22916
+ return readdirSync32(src, { withFileTypes: true }).filter((e) => e.isDirectory() && existsSync46(join49(src, e.name, "SKILL.md"))).map((e) => e.name).sort();
22683
22917
  }
22684
22918
  function realPathOrSelf(p) {
22685
22919
  try {
@@ -22692,7 +22926,7 @@ function claudeSkillTargets() {
22692
22926
  const targets = [];
22693
22927
  const seen = /* @__PURE__ */ new Set();
22694
22928
  for (const home of claudeHomeDirs()) {
22695
- const dir = join48(home, "skills");
22929
+ const dir = join49(home, "skills");
22696
22930
  const key2 = realPathOrSelf(dir);
22697
22931
  if (seen.has(key2)) continue;
22698
22932
  seen.add(key2);
@@ -22703,7 +22937,7 @@ function claudeSkillTargets() {
22703
22937
  dir,
22704
22938
  // Judge each profile on ITS OWN transcripts, not the primary's: a home
22705
22939
  // with no projects/ is a directory someone made, not a Claude install.
22706
- available: existsSync46(join48(home, "projects"))
22940
+ available: existsSync46(join49(home, "projects"))
22707
22941
  });
22708
22942
  }
22709
22943
  if (targets.length === 0) {
@@ -22718,16 +22952,16 @@ function skillTargets() {
22718
22952
  // both produces "skill conflict" duplicate warnings. Every tool we support
22719
22953
  // has its own dir, so per-tool coverage is complete.
22720
22954
  ...claudeSkillTargets(),
22721
- { id: "agy", label: "Antigravity", dir: join48(agyBackend.homeDir(), "skills"), available: agyBackend.isAvailable() },
22955
+ { id: "agy", label: "Antigravity", dir: join49(agyBackend.homeDir(), "skills"), available: agyBackend.isAvailable() },
22722
22956
  { id: "codex", label: "Codex", dir: codexBackend.skillsDir(), available: codexBackend.isAvailable() },
22723
22957
  { id: "opencode", label: "OpenCode", dir: opencodeBackend.skillsDir(), available: opencodeBackend.isAvailable() },
22724
22958
  // Cursor DOES have its own dir (~/.cursor/skills). `skills-cursor` next to
22725
22959
  // it is Cursor's bundled set — read-only, never an install target.
22726
- { id: "cursor", label: "Cursor", dir: join48(cursorHomeDir(), "skills"), available: cursorBackend.isAvailable() }
22960
+ { id: "cursor", label: "Cursor", dir: join49(cursorHomeDir(), "skills"), available: cursorBackend.isAvailable() }
22727
22961
  ];
22728
22962
  }
22729
22963
  function isManaged(dir) {
22730
- return existsSync46(join48(dir, MARKER));
22964
+ return existsSync46(join49(dir, MARKER));
22731
22965
  }
22732
22966
  function installSkills(opts = {}) {
22733
22967
  const onlyAvailable = opts.onlyAvailable ?? true;
@@ -22744,15 +22978,15 @@ function installSkills(opts = {}) {
22744
22978
  continue;
22745
22979
  }
22746
22980
  for (const name of names) {
22747
- const dest = join48(t.dir, name);
22981
+ const dest = join49(t.dir, name);
22748
22982
  if (existsSync46(dest) && !isManaged(dest)) {
22749
22983
  skippedUserOwned.push(name);
22750
22984
  continue;
22751
22985
  }
22752
22986
  mkdirSync14(t.dir, { recursive: true });
22753
- rmSync7(dest, { recursive: true, force: true });
22754
- cpSync(join48(src, name), dest, { recursive: true });
22755
- writeFileSync14(join48(dest, MARKER), `${stamp}
22987
+ rmSync8(dest, { recursive: true, force: true });
22988
+ cpSync(join49(src, name), dest, { recursive: true });
22989
+ writeFileSync14(join49(dest, MARKER), `${stamp}
22756
22990
  `);
22757
22991
  installed.push(name);
22758
22992
  }
@@ -22771,9 +23005,9 @@ function uninstallSkills() {
22771
23005
  }
22772
23006
  for (const entry of readdirSync32(t.dir, { withFileTypes: true })) {
22773
23007
  if (!entry.isDirectory()) continue;
22774
- const dir = join48(t.dir, entry.name);
23008
+ const dir = join49(t.dir, entry.name);
22775
23009
  if (isManaged(dir) && (names.has(entry.name) || entry.name.startsWith("chat-recall"))) {
22776
- rmSync7(dir, { recursive: true, force: true });
23010
+ rmSync8(dir, { recursive: true, force: true });
22777
23011
  removed.push(entry.name);
22778
23012
  }
22779
23013
  }
@@ -22788,10 +23022,10 @@ function skillsNeedRefresh() {
22788
23022
  for (const t of skillTargets()) {
22789
23023
  if (!t.available) continue;
22790
23024
  for (const name of names) {
22791
- const marker = join48(t.dir, name, MARKER);
23025
+ const marker = join49(t.dir, name, MARKER);
22792
23026
  if (!existsSync46(marker)) return true;
22793
23027
  try {
22794
- if (readFileSync39(marker, "utf-8").trim() !== cur) return true;
23028
+ if (readFileSync40(marker, "utf-8").trim() !== cur) return true;
22795
23029
  } catch {
22796
23030
  return true;
22797
23031
  }
@@ -22806,11 +23040,11 @@ function skillStatus() {
22806
23040
  let installed = 0;
22807
23041
  let ver = null;
22808
23042
  for (const name of names) {
22809
- const marker = join48(t.dir, name, MARKER);
23043
+ const marker = join49(t.dir, name, MARKER);
22810
23044
  if (existsSync46(marker)) {
22811
23045
  installed++;
22812
23046
  try {
22813
- ver = readFileSync39(marker, "utf-8").trim();
23047
+ ver = readFileSync40(marker, "utf-8").trim();
22814
23048
  } catch {
22815
23049
  }
22816
23050
  }
@@ -22834,8 +23068,8 @@ var init_install_skills = __esm({
22834
23068
  });
22835
23069
 
22836
23070
  // ../engine/dist/core/artifact-codec.js
22837
- import { readFileSync as readFileSync40 } from "fs";
22838
- import { basename as basename22, join as join49 } from "path";
23071
+ import { readFileSync as readFileSync41 } from "fs";
23072
+ import { basename as basename22, join as join50 } from "path";
22839
23073
  import { homedir as homedir18 } from "os";
22840
23074
  function parseCommandText(content, format, fallbackName) {
22841
23075
  if (format === "toml") {
@@ -22858,41 +23092,41 @@ function parseAgentText(content, format, fallbackName) {
22858
23092
  return { name: fm.name || fallbackName, description: fm.description || "", tools: fm.tools, body: body2.trim() };
22859
23093
  }
22860
23094
  function readCommand(filePath, format) {
22861
- return parseCommandText(readFileSync40(filePath, "utf-8"), format, base2(filePath));
23095
+ return parseCommandText(readFileSync41(filePath, "utf-8"), format, base2(filePath));
22862
23096
  }
22863
23097
  function readAgent(filePath, format) {
22864
- return parseAgentText(readFileSync40(filePath, "utf-8"), format, base2(filePath));
23098
+ return parseAgentText(readFileSync41(filePath, "utf-8"), format, base2(filePath));
22865
23099
  }
22866
23100
  function readInstructions(filePath, name) {
22867
- const content = readFileSync40(filePath, "utf-8");
23101
+ const content = readFileSync41(filePath, "utf-8");
22868
23102
  return { name, description: "", body: content };
22869
23103
  }
22870
23104
  function commandPath(tool, name) {
22871
23105
  switch (tool) {
22872
23106
  case "claude":
22873
- return join49(claudeBackend.commandsDir(), `${name}.md`);
23107
+ return join50(claudeBackend.commandsDir(), `${name}.md`);
22874
23108
  case "agy":
22875
- return join49(join49(agyBackend.homeDir(), "commands"), `${name}.toml`);
23109
+ return join50(join50(agyBackend.homeDir(), "commands"), `${name}.toml`);
22876
23110
  case "opencode":
22877
- return join49(opencodeBackend.commandsDir(), `${name}.md`);
23111
+ return join50(opencodeBackend.commandsDir(), `${name}.md`);
22878
23112
  case "codex":
22879
- return join49(codexBackend.promptsDir(), `${name}.md`);
23113
+ return join50(codexBackend.promptsDir(), `${name}.md`);
22880
23114
  case "cursor":
22881
- return join49(cursorHomeDir(), "commands", `${name}.md`);
23115
+ return join50(cursorHomeDir(), "commands", `${name}.md`);
22882
23116
  }
22883
23117
  }
22884
23118
  function agentPath(tool, name) {
22885
23119
  switch (tool) {
22886
23120
  case "claude":
22887
- return join49(claudeBackend.agentsDir(), `${name}.md`);
23121
+ return join50(claudeBackend.agentsDir(), `${name}.md`);
22888
23122
  case "agy":
22889
- return join49(join49(agyBackend.homeDir(), "agents"), `${name}.md`);
23123
+ return join50(join50(agyBackend.homeDir(), "agents"), `${name}.md`);
22890
23124
  case "opencode":
22891
- return join49(opencodeBackend.agentsDir(), `${name}.md`);
23125
+ return join50(opencodeBackend.agentsDir(), `${name}.md`);
22892
23126
  case "codex":
22893
- return join49(codexBackend.agentsDir(), `${name}.toml`);
23127
+ return join50(codexBackend.agentsDir(), `${name}.toml`);
22894
23128
  case "cursor":
22895
- return join49(cursorHomeDir(), "agents", `${name}.md`);
23129
+ return join50(cursorHomeDir(), "agents", `${name}.md`);
22896
23130
  }
22897
23131
  }
22898
23132
  function instructionsFilename(tool) {
@@ -22917,21 +23151,21 @@ function instructionsFilename(tool) {
22917
23151
  function instructionsPath(tool, projectPath) {
22918
23152
  const file = instructionsFilename(tool);
22919
23153
  if (projectPath)
22920
- return join49(projectPath, file);
23154
+ return join50(projectPath, file);
22921
23155
  switch (tool) {
22922
23156
  case "claude":
22923
- return join49(claudeBackend.homeDir(), file);
23157
+ return join50(claudeBackend.homeDir(), file);
22924
23158
  case "agy":
22925
- return join49(agyBackend.homeDir(), file);
23159
+ return join50(agyBackend.homeDir(), file);
22926
23160
  case "codex":
22927
- return join49(codexBackend.homeDir(), file);
23161
+ return join50(codexBackend.homeDir(), file);
22928
23162
  case "opencode":
22929
- return join49(homedir18(), ".config", "opencode", file);
23163
+ return join50(homedir18(), ".config", "opencode", file);
22930
23164
  // Cursor has no single user-scope instructions FILE — user-level guidance
22931
23165
  // is User Rules plus ~/.cursor/rules/*.mdc. AGENTS.md at the home root is
22932
23166
  // the closest equivalent and is what a mirror can actually write.
22933
23167
  case "cursor":
22934
- return join49(cursorHomeDir(), file);
23168
+ return join50(cursorHomeDir(), file);
22935
23169
  }
22936
23170
  }
22937
23171
  function emit(type, art, toTool, projectPath) {
@@ -22995,8 +23229,8 @@ __export(toolkit_sync_exports, {
22995
23229
  supportedTargetsFor: () => supportedTargetsFor,
22996
23230
  writeMcpEntry: () => writeMcpEntry
22997
23231
  });
22998
- import { existsSync as existsSync47, mkdirSync as mkdirSync15, readFileSync as readFileSync41, writeFileSync as writeFileSync15, cpSync as cpSync2 } from "fs";
22999
- import { dirname as dirname22, join as join50, basename as basename23 } from "path";
23232
+ import { existsSync as existsSync47, mkdirSync as mkdirSync15, readFileSync as readFileSync42, writeFileSync as writeFileSync15, cpSync as cpSync2 } from "fs";
23233
+ import { dirname as dirname22, join as join51, basename as basename23 } from "path";
23000
23234
  import { homedir as homedir19 } from "os";
23001
23235
  function supportedTargetsFor(type) {
23002
23236
  return SUPPORTED_TARGETS[type];
@@ -23038,14 +23272,14 @@ function skillsDirFor(tool) {
23038
23272
  case "claude":
23039
23273
  return claudeBackend.skillsDir();
23040
23274
  case "agy":
23041
- return join50(agyBackend.homeDir(), "skills");
23275
+ return join51(agyBackend.homeDir(), "skills");
23042
23276
  case "opencode":
23043
23277
  return opencodeBackend.skillsDir();
23044
23278
  case "codex":
23045
23279
  return codexBackend.skillsDir();
23046
23280
  // user skills, NOT .system
23047
23281
  case "cursor":
23048
- return join50(cursorHomeDir(), "skills");
23282
+ return join51(cursorHomeDir(), "skills");
23049
23283
  }
23050
23284
  }
23051
23285
  function copySkill(row, toTool) {
@@ -23053,7 +23287,7 @@ function copySkill(row, toTool) {
23053
23287
  if (!existsSync47(skillDir))
23054
23288
  return { ok: false, status: 404, error: `Source dir missing: ${skillDir}` };
23055
23289
  const name = row.extra.skillName || basename23(skillDir);
23056
- const targetDir = join50(skillsDirFor(toTool), name);
23290
+ const targetDir = join51(skillsDirFor(toTool), name);
23057
23291
  if (existsSync47(targetDir))
23058
23292
  return { ok: false, status: 409, error: `Already exists: ${targetDir}` };
23059
23293
  try {
@@ -23068,20 +23302,20 @@ function readMcpEntry(tool, name) {
23068
23302
  const home = homedir19();
23069
23303
  const tries = [];
23070
23304
  if (tool === "claude") {
23071
- tries.push({ path: join50(home, ".mcp.json"), key: "mcpServers" });
23072
- tries.push({ path: join50(home, ".claude.json"), key: "mcpServers" });
23305
+ tries.push({ path: join51(home, ".mcp.json"), key: "mcpServers" });
23306
+ tries.push({ path: join51(home, ".claude.json"), key: "mcpServers" });
23073
23307
  } else if (tool === "gemini") {
23074
- tries.push({ path: join50(home, ".gemini", "settings.json"), key: "mcpServers" });
23308
+ tries.push({ path: join51(home, ".gemini", "settings.json"), key: "mcpServers" });
23075
23309
  } else if (tool === "agy") {
23076
- tries.push({ path: join50(home, ".gemini", "config", "mcp_config.json"), key: "mcpServers" });
23310
+ tries.push({ path: join51(home, ".gemini", "config", "mcp_config.json"), key: "mcpServers" });
23077
23311
  } else if (tool === "cursor") {
23078
- tries.push({ path: join50(cursorHomeDir(), "mcp.json"), key: "mcpServers" });
23312
+ tries.push({ path: join51(cursorHomeDir(), "mcp.json"), key: "mcpServers" });
23079
23313
  } else if (tool === "opencode") {
23080
- tries.push({ path: join50(home, ".config", "opencode", "opencode.json"), key: "mcp" });
23081
- tries.push({ path: join50(home, ".config", "opencode", "config.json"), key: "mcp" });
23082
- tries.push({ path: join50(home, ".opencode", "config.json"), key: "mcp" });
23314
+ tries.push({ path: join51(home, ".config", "opencode", "opencode.json"), key: "mcp" });
23315
+ tries.push({ path: join51(home, ".config", "opencode", "config.json"), key: "mcp" });
23316
+ tries.push({ path: join51(home, ".opencode", "config.json"), key: "mcp" });
23083
23317
  } else if (tool === "codex") {
23084
- const entry = readCodexMcpEntry(join50(home, ".codex", "config.toml"), name);
23318
+ const entry = readCodexMcpEntry(join51(home, ".codex", "config.toml"), name);
23085
23319
  if (entry)
23086
23320
  return entry;
23087
23321
  }
@@ -23089,7 +23323,7 @@ function readMcpEntry(tool, name) {
23089
23323
  if (!existsSync47(t.path))
23090
23324
  continue;
23091
23325
  try {
23092
- const cfg = JSON.parse(readFileSync41(t.path, "utf-8"));
23326
+ const cfg = JSON.parse(readFileSync42(t.path, "utf-8"));
23093
23327
  const block = cfg[t.key] || {};
23094
23328
  if (block[name])
23095
23329
  return block[name];
@@ -23103,7 +23337,7 @@ function readCodexMcpEntry(path, target) {
23103
23337
  return null;
23104
23338
  let content;
23105
23339
  try {
23106
- content = readFileSync41(path, "utf-8");
23340
+ content = readFileSync42(path, "utf-8");
23107
23341
  } catch {
23108
23342
  return null;
23109
23343
  }
@@ -23154,7 +23388,7 @@ function readCodexMcpEntry(path, target) {
23154
23388
  function writeCodexMcpEntry(path, name, entry) {
23155
23389
  let content = "";
23156
23390
  if (existsSync47(path))
23157
- content = readFileSync41(path, "utf-8");
23391
+ content = readFileSync42(path, "utf-8");
23158
23392
  const header = `[mcp_servers.${name}]`;
23159
23393
  if (content.includes(header))
23160
23394
  return false;
@@ -23190,7 +23424,7 @@ function writeCodexMcpEntry(path, name, entry) {
23190
23424
  function writeMcpEntry(toTool, name, entry) {
23191
23425
  const home = homedir19();
23192
23426
  if (toTool === "codex") {
23193
- const path2 = join50(home, ".codex", "config.toml");
23427
+ const path2 = join51(home, ".codex", "config.toml");
23194
23428
  if (!writeCodexMcpEntry(path2, name, entry))
23195
23429
  return { ok: false, status: 409, error: `MCP "${name}" already exists in ${path2}.` };
23196
23430
  return { ok: true, targetPath: path2 };
@@ -23198,22 +23432,22 @@ function writeMcpEntry(toTool, name, entry) {
23198
23432
  let path;
23199
23433
  let key2;
23200
23434
  if (toTool === "claude") {
23201
- path = join50(home, ".mcp.json");
23435
+ path = join51(home, ".mcp.json");
23202
23436
  key2 = "mcpServers";
23203
23437
  } else if (toTool === "agy") {
23204
- path = join50(home, ".gemini", "config", "mcp_config.json");
23438
+ path = join51(home, ".gemini", "config", "mcp_config.json");
23205
23439
  key2 = "mcpServers";
23206
23440
  } else if (toTool === "cursor") {
23207
- path = join50(cursorHomeDir(), "mcp.json");
23441
+ path = join51(cursorHomeDir(), "mcp.json");
23208
23442
  key2 = "mcpServers";
23209
23443
  } else {
23210
- path = join50(home, ".config", "opencode", "opencode.json");
23444
+ path = join51(home, ".config", "opencode", "opencode.json");
23211
23445
  key2 = "mcp";
23212
23446
  }
23213
23447
  let cfg = {};
23214
23448
  if (existsSync47(path)) {
23215
23449
  try {
23216
- cfg = JSON.parse(readFileSync41(path, "utf-8"));
23450
+ cfg = JSON.parse(readFileSync42(path, "utf-8"));
23217
23451
  } catch {
23218
23452
  return { ok: false, status: 500, error: `Target config is malformed: ${path}` };
23219
23453
  }
@@ -23446,11 +23680,11 @@ __export(toolkit_pull_exports, {
23446
23680
  platformRefusal: () => platformRefusal,
23447
23681
  portableCommand: () => portableCommand
23448
23682
  });
23449
- import { existsSync as existsSync48, mkdirSync as mkdirSync16, statSync as statSync42, writeFileSync as writeFileSync16 } from "node:fs";
23450
- import { dirname as dirname23, join as join51, basename as basename24, isAbsolute as isAbsolute3 } from "node:path";
23683
+ import { existsSync as existsSync48, mkdirSync as mkdirSync16, statSync as statSync43, writeFileSync as writeFileSync16 } from "node:fs";
23684
+ import { dirname as dirname23, join as join52, basename as basename24, isAbsolute as isAbsolute3 } from "node:path";
23451
23685
  function isExecutableFile(p) {
23452
23686
  try {
23453
- return statSync42(p).isFile();
23687
+ return statSync43(p).isFile();
23454
23688
  } catch {
23455
23689
  return false;
23456
23690
  }
@@ -23617,8 +23851,8 @@ function executePull(rows, opts = {}) {
23617
23851
  const outcomes = [];
23618
23852
  for (const { name, body: body2, truncated, redacted, tools } of skills) {
23619
23853
  for (const tool of tools) {
23620
- const dir = join51(skillsDirFor(tool), name);
23621
- const file = join51(dir, "SKILL.md");
23854
+ const dir = join52(skillsDirFor(tool), name);
23855
+ const file = join52(dir, "SKILL.md");
23622
23856
  if (existsSync48(file)) {
23623
23857
  outcomes.push({ type: "skill", name, tool, status: "present" });
23624
23858
  continue;
@@ -23827,8 +24061,8 @@ __export(board_hooks_exports, {
23827
24061
  removeBoardHooks: () => removeBoardHooks,
23828
24062
  resolveCliEntry: () => resolveCliEntry
23829
24063
  });
23830
- import { existsSync as existsSync49, mkdirSync as mkdirSync17, readFileSync as readFileSync42, writeFileSync as writeFileSync17 } from "node:fs";
23831
- import { dirname as dirname24, join as join52 } from "node:path";
24064
+ import { existsSync as existsSync49, mkdirSync as mkdirSync17, readFileSync as readFileSync43, writeFileSync as writeFileSync17 } from "node:fs";
24065
+ import { dirname as dirname24, join as join53 } from "node:path";
23832
24066
  function boardHookCommand(execPath, cliEntry, mode) {
23833
24067
  return `"${execPath}" "${cliEntry}" task-hook --${mode}`;
23834
24068
  }
@@ -23869,7 +24103,7 @@ function removeBoardHooks(config2) {
23869
24103
  function readConfig(file) {
23870
24104
  if (!existsSync49(file)) return { hooks: {} };
23871
24105
  try {
23872
- const parsed = JSON.parse(readFileSync42(file, "utf-8"));
24106
+ const parsed = JSON.parse(readFileSync43(file, "utf-8"));
23873
24107
  if (!parsed.hooks || typeof parsed.hooks !== "object") parsed.hooks = {};
23874
24108
  return parsed;
23875
24109
  } catch {
@@ -23881,7 +24115,7 @@ function registerBoardHooks(files, execPath, cliEntry) {
23881
24115
  for (const file of files) {
23882
24116
  if (existsSync49(file)) {
23883
24117
  try {
23884
- JSON.parse(readFileSync42(file, "utf-8"));
24118
+ JSON.parse(readFileSync43(file, "utf-8"));
23885
24119
  } catch {
23886
24120
  continue;
23887
24121
  }
@@ -23898,8 +24132,8 @@ function registerBoardHooks(files, execPath, cliEntry) {
23898
24132
  return written;
23899
24133
  }
23900
24134
  function resolveCliEntry(distDir) {
23901
- const bundled = join52(distDir, "cli.js");
23902
- return existsSync49(bundled) ? bundled : join52(distDir, "cli.ts");
24135
+ const bundled = join53(distDir, "cli.js");
24136
+ return existsSync49(bundled) ? bundled : join53(distDir, "cli.ts");
23903
24137
  }
23904
24138
  var BOARD_HOOKS;
23905
24139
  var init_board_hooks = __esm({
@@ -24108,11 +24342,16 @@ async function repairAll(opts = {}) {
24108
24342
  scanned++;
24109
24343
  if (opts.verbose && scanned % 50 === 0) log6(`checked ${scanned}/${ids.length}\u2026`);
24110
24344
  const arch = await fetchJson(`${primary.url}/api/conversations/${id}/raw-archive?count=1`, primary.token);
24111
- const archiveMsgs = typeof arch?.messages === "number" ? arch.messages : 0;
24112
- if (archiveMsgs < minMessages) continue;
24113
- const meta = await fetchJson(`${primary.url}/api/conversations/${id}/metadata`, primary.token);
24114
- const current = typeof meta?.messageCount === "number" ? meta.messageCount : 0;
24115
- if (archiveMsgs <= current) continue;
24345
+ const counted = arch && arch.messages !== null;
24346
+ if (counted) {
24347
+ const archiveMsgs = typeof arch?.messages === "number" ? arch.messages : 0;
24348
+ if (archiveMsgs < minMessages) continue;
24349
+ const meta = await fetchJson(`${primary.url}/api/conversations/${id}/metadata`, primary.token);
24350
+ const current = typeof meta?.messageCount === "number" ? meta.messageCount : 0;
24351
+ if (archiveMsgs <= current) continue;
24352
+ } else if (!arch) {
24353
+ continue;
24354
+ }
24116
24355
  const r = await repairSession(id, { dryRun: !opts.apply, verbose: opts.verbose, server: opts.server });
24117
24356
  if (r.status === "already-full") continue;
24118
24357
  candidates2.push(r);
@@ -24297,21 +24536,21 @@ __export(guard_registration_exports, {
24297
24536
  unregisterGuard: () => unregisterGuard
24298
24537
  });
24299
24538
  import { homedir as homedir20 } from "os";
24300
- import { join as join53 } from "path";
24539
+ import { join as join54 } from "path";
24301
24540
  function opencodeConfigDir() {
24302
24541
  const xdg = process.env.XDG_CONFIG_HOME;
24303
- const base4 = xdg && xdg.trim() ? xdg : join53(homedir20(), ".config");
24304
- return join53(base4, "opencode");
24542
+ const base4 = xdg && xdg.trim() ? xdg : join54(homedir20(), ".config");
24543
+ return join54(base4, "opencode");
24305
24544
  }
24306
24545
  function opencodePluginDir() {
24307
- return join53(opencodeConfigDir(), "plugins");
24546
+ return join54(opencodeConfigDir(), "plugins");
24308
24547
  }
24309
24548
  function guardTargets() {
24310
24549
  return [
24311
24550
  {
24312
24551
  tool: "codex",
24313
24552
  label: "Codex",
24314
- configPath: join53(codexBackend.homeDir(), "hooks.json"),
24553
+ configPath: join54(codexBackend.homeDir(), "hooks.json"),
24315
24554
  homeDir: codexBackend.homeDir(),
24316
24555
  // Codex will not run a hook until a person has reviewed it, and the
24317
24556
  // approval is bound to the hook's hash. There is no way to grant it from
@@ -24324,20 +24563,20 @@ function guardTargets() {
24324
24563
  {
24325
24564
  tool: "agy",
24326
24565
  label: "Antigravity",
24327
- configPath: join53(agyBackend.homeDir(), "hooks.json"),
24566
+ configPath: join54(agyBackend.homeDir(), "hooks.json"),
24328
24567
  homeDir: agyBackend.homeDir()
24329
24568
  },
24330
24569
  {
24331
24570
  tool: "cursor",
24332
24571
  label: "Cursor",
24333
- configPath: join53(cursorBackend.homeDir(), "hooks.json"),
24572
+ configPath: join54(cursorBackend.homeDir(), "hooks.json"),
24334
24573
  homeDir: cursorBackend.homeDir(),
24335
24574
  note: "Cursor checks a shell command before it runs and a file edit after it is written."
24336
24575
  },
24337
24576
  {
24338
24577
  tool: "opencode",
24339
24578
  label: "OpenCode",
24340
- configPath: join53(opencodePluginDir(), "chat-recall-guard.js"),
24579
+ configPath: join54(opencodePluginDir(), "chat-recall-guard.js"),
24341
24580
  homeDir: opencodeConfigDir(),
24342
24581
  note: "OpenCode plugin hooks do not fire for subagent tool calls, so a delegating agent bypasses this."
24343
24582
  }
@@ -24760,8 +24999,8 @@ __export(collector_exports, {
24760
24999
  });
24761
25000
  import { spawn as spawn3 } from "node:child_process";
24762
25001
  import { execSync as execSync4 } from "node:child_process";
24763
- import { readFileSync as readFileSync43 } from "node:fs";
24764
- import { join as join54, basename as basename26 } from "node:path";
25002
+ import { readFileSync as readFileSync44 } from "node:fs";
25003
+ import { join as join55, basename as basename26 } from "node:path";
24765
25004
  async function resolveCodeindexBin(autoInstall = true) {
24766
25005
  let st = checkCodeindexStatus();
24767
25006
  if (!st.installed && autoInstall)
@@ -24943,7 +25182,7 @@ async function collectCode(opts) {
24943
25182
  }
24944
25183
  const complexity = (r) => {
24945
25184
  try {
24946
- const txt = readFileSync43(join54(ws, r), "utf8");
25185
+ const txt = readFileSync44(join55(ws, r), "utf8");
24947
25186
  if (txt.length > 2e6)
24948
25187
  return 1;
24949
25188
  const m = txt.match(CF_RE);
@@ -25727,8 +25966,8 @@ __export(project_tasks_exports, {
25727
25966
  pushProjectTaskStatuses: () => pushProjectTaskStatuses,
25728
25967
  renderTeamTasksMd: () => renderTeamTasksMd
25729
25968
  });
25730
- import { existsSync as existsSync51, readFileSync as readFileSync44, writeFileSync as writeFileSync18, mkdirSync as mkdirSync18, statSync as statSync43 } from "node:fs";
25731
- import { join as join55, dirname as dirname25 } from "node:path";
25969
+ import { existsSync as existsSync51, readFileSync as readFileSync45, writeFileSync as writeFileSync18, mkdirSync as mkdirSync18, statSync as statSync44 } from "node:fs";
25970
+ import { join as join56, dirname as dirname25 } from "node:path";
25732
25971
  import { homedir as homedir21 } from "node:os";
25733
25972
  function isTeamTaskStatus(v) {
25734
25973
  return !!v && TEAM_STATUSES.has(v);
@@ -25779,11 +26018,11 @@ function parseTaskFile(content) {
25779
26018
  return out;
25780
26019
  }
25781
26020
  function ledgerPath2() {
25782
- return join55(homedir21(), ".chat-recall", "project-tasks-ledger.json");
26021
+ return join56(homedir21(), ".chat-recall", "project-tasks-ledger.json");
25783
26022
  }
25784
26023
  function readLedger() {
25785
26024
  try {
25786
- return JSON.parse(readFileSync44(ledgerPath2(), "utf8"));
26025
+ return JSON.parse(readFileSync45(ledgerPath2(), "utf8"));
25787
26026
  } catch {
25788
26027
  return {};
25789
26028
  }
@@ -25812,18 +26051,18 @@ async function pushProjectTaskStatuses(base4, authHeaders, opts = {}) {
25812
26051
  continue;
25813
26052
  }
25814
26053
  for (const project of projects) {
25815
- const file = join55(project, fk.filename);
26054
+ const file = join56(project, fk.filename);
25816
26055
  if (!existsSync51(file)) continue;
25817
26056
  let mtime;
25818
26057
  try {
25819
- mtime = statSync43(file).mtimeMs;
26058
+ mtime = statSync44(file).mtimeMs;
25820
26059
  } catch {
25821
26060
  continue;
25822
26061
  }
25823
26062
  if (ledger[file] === mtime) continue;
25824
26063
  let changed;
25825
26064
  try {
25826
- changed = parseTaskFile(readFileSync44(file, "utf8")).filter((t) => t.kind === fk.kind);
26065
+ changed = parseTaskFile(readFileSync45(file, "utf8")).filter((t) => t.kind === fk.kind);
25827
26066
  } catch {
25828
26067
  continue;
25829
26068
  }
@@ -25895,8 +26134,8 @@ __export(intent_drain_exports, {
25895
26134
  drainSyncIntents: () => drainSyncIntents,
25896
26135
  instructionTargets: () => instructionTargets
25897
26136
  });
25898
- import { existsSync as existsSync52, readFileSync as readFileSync45, writeFileSync as writeFileSync19, appendFileSync, mkdirSync as mkdirSync19 } from "node:fs";
25899
- import { join as join56 } from "node:path";
26137
+ import { existsSync as existsSync52, readFileSync as readFileSync46, writeFileSync as writeFileSync19, appendFileSync, mkdirSync as mkdirSync19 } from "node:fs";
26138
+ import { join as join57 } from "node:path";
25900
26139
  import { fileURLToPath as fileURLToPath4 } from "node:url";
25901
26140
  import { dirname as dirname26 } from "node:path";
25902
26141
  function instructionTargets(rootPath, isGlobal) {
@@ -25910,16 +26149,16 @@ function instructionTargets(rootPath, isGlobal) {
25910
26149
  const tools = installed.length ? installed : [INSTRUCTION_TOOLS[0]];
25911
26150
  if (isGlobal) return [...new Set(tools.map((t) => instructionsPath(t.id)))];
25912
26151
  if (!rootPath) return [];
25913
- const present = INSTRUCTION_FILENAMES.map((f) => join56(rootPath, f)).filter((p) => existsSync52(p));
26152
+ const present = INSTRUCTION_FILENAMES.map((f) => join57(rootPath, f)).filter((p) => existsSync52(p));
25914
26153
  if (present.length) return present;
25915
- return [...new Set(tools.map((t) => join56(rootPath, instructionsFilename(t.id))))];
26154
+ return [...new Set(tools.map((t) => join57(rootPath, instructionsFilename(t.id))))];
25916
26155
  }
25917
26156
  function applyCodeRecommendation(intent) {
25918
26157
  try {
25919
26158
  const meta = JSON.parse(intent.name || "{}");
25920
26159
  if (intent.artifact_type === "write_tasks_file") {
25921
26160
  if (!meta.rootPath || !meta.content) return { status: "error", result: JSON.stringify({ error: "missing rootPath or content" }) };
25922
- const file = join56(meta.rootPath, meta.filename || "CODE_TASKS.md");
26161
+ const file = join57(meta.rootPath, meta.filename || "CODE_TASKS.md");
25923
26162
  writeFileSync19(file, meta.content);
25924
26163
  return { status: "done", result: JSON.stringify({ wrote: file }) };
25925
26164
  }
@@ -25938,7 +26177,7 @@ function applyCodeRecommendation(intent) {
25938
26177
  mkdirSync19(dir, { recursive: true });
25939
26178
  } catch {
25940
26179
  }
25941
- const existing = existsSync52(file) ? readFileSync45(file, "utf8") : "";
26180
+ const existing = existsSync52(file) ? readFileSync46(file, "utf8") : "";
25942
26181
  if (existing.includes(text)) {
25943
26182
  skipped.push(file);
25944
26183
  continue;
@@ -26113,10 +26352,10 @@ var init_intent_drain = __esm({
26113
26352
  ownVersion2 = "0.0.0";
26114
26353
  try {
26115
26354
  const dir = dirname26(fileURLToPath4(import.meta.url));
26116
- ownVersion2 = JSON.parse(readFileSync45(join56(dir, "../package.json"), "utf-8")).version || ownVersion2;
26355
+ ownVersion2 = JSON.parse(readFileSync46(join57(dir, "../package.json"), "utf-8")).version || ownVersion2;
26117
26356
  } catch {
26118
26357
  try {
26119
- if (true) ownVersion2 = "0.7.17";
26358
+ if (true) ownVersion2 = "0.7.18";
26120
26359
  } catch {
26121
26360
  }
26122
26361
  }
@@ -26317,48 +26556,48 @@ var team_merge_exports = {};
26317
26556
  __export(team_merge_exports, {
26318
26557
  mergePullResult: () => mergePullResult
26319
26558
  });
26320
- import { existsSync as existsSync53, mkdirSync as mkdirSync20, readFileSync as readFileSync46, rmSync as rmSync8, writeFileSync as writeFileSync20, statSync as statSync44 } from "fs";
26321
- import { dirname as dirname27, join as join57 } from "path";
26559
+ import { existsSync as existsSync53, mkdirSync as mkdirSync20, readFileSync as readFileSync47, rmSync as rmSync9, writeFileSync as writeFileSync20, statSync as statSync45 } from "fs";
26560
+ import { dirname as dirname27, join as join58 } from "path";
26322
26561
  import { createHash as createHash14 } from "crypto";
26323
26562
  function installPathFor(art, tool) {
26324
26563
  switch (art.type) {
26325
26564
  case "skill":
26326
26565
  switch (tool) {
26327
26566
  case "claude":
26328
- return join57(claudeBackend.skillsDir(), art.name, "SKILL.md");
26567
+ return join58(claudeBackend.skillsDir(), art.name, "SKILL.md");
26329
26568
  // Antigravity's OWN skills dir. It used to resolve to the shared
26330
26569
  // ~/.gemini/skills while toolkit-sync installed to
26331
26570
  // ~/.gemini/antigravity-cli/skills, so a team skill landed in one place
26332
26571
  // and a synced skill in the other.
26333
26572
  case "agy":
26334
- return join57(agyBackend.homeDir(), "skills", art.name, "SKILL.md");
26573
+ return join58(agyBackend.homeDir(), "skills", art.name, "SKILL.md");
26335
26574
  case "opencode":
26336
- return join57(opencodeBackend.skillsDir(), art.name, "SKILL.md");
26575
+ return join58(opencodeBackend.skillsDir(), art.name, "SKILL.md");
26337
26576
  // User skills go to ~/.codex/skills (NOT .system, which is OpenAI's bundle).
26338
26577
  case "codex":
26339
- return join57(codexBackend.skillsDir(), art.name, "SKILL.md");
26578
+ return join58(codexBackend.skillsDir(), art.name, "SKILL.md");
26340
26579
  case "cursor":
26341
- return join57(cursorHomeDir(), "skills", art.name, "SKILL.md");
26580
+ return join58(cursorHomeDir(), "skills", art.name, "SKILL.md");
26342
26581
  }
26343
26582
  break;
26344
26583
  case "agent":
26345
26584
  if (tool === "claude")
26346
- return join57(claudeBackend.agentsDir(), `${art.name}.md`);
26585
+ return join58(claudeBackend.agentsDir(), `${art.name}.md`);
26347
26586
  return null;
26348
26587
  case "command":
26349
26588
  if (tool === "claude")
26350
- return join57(claudeBackend.commandsDir(), `${art.name}.md`);
26589
+ return join58(claudeBackend.commandsDir(), `${art.name}.md`);
26351
26590
  return null;
26352
26591
  case "hook":
26353
26592
  if (tool === "claude")
26354
- return join57(claudeBackend.homeDir(), "chat-recall-hooks", `${art.name}.json`);
26593
+ return join58(claudeBackend.homeDir(), "chat-recall-hooks", `${art.name}.json`);
26355
26594
  return null;
26356
26595
  case "plan":
26357
26596
  switch (tool) {
26358
26597
  case "claude":
26359
- return join57(claudeBackend.plansDir(), `${art.name}.md`);
26598
+ return join58(claudeBackend.plansDir(), `${art.name}.md`);
26360
26599
  case "opencode":
26361
- return join57(opencodeBackend.plansDir(), `${art.name}.md`);
26600
+ return join58(opencodeBackend.plansDir(), `${art.name}.md`);
26362
26601
  case "agy":
26363
26602
  return null;
26364
26603
  // Antigravity plans live per-session
@@ -26369,11 +26608,11 @@ function installPathFor(art, tool) {
26369
26608
  }
26370
26609
  break;
26371
26610
  case "instructions":
26372
- return join57(getDataDir(), "team-instructions", tool, `${art.name}.md`);
26611
+ return join58(getDataDir(), "team-instructions", tool, `${art.name}.md`);
26373
26612
  case "mcp":
26374
- return join57(getDataDir(), "team-mcps", `${art.name}.json`);
26613
+ return join58(getDataDir(), "team-mcps", `${art.name}.json`);
26375
26614
  case "plugin":
26376
- return join57(getDataDir(), "team-plugins", tool, art.name, "manifest.json");
26615
+ return join58(getDataDir(), "team-plugins", tool, art.name, "manifest.json");
26377
26616
  }
26378
26617
  return null;
26379
26618
  }
@@ -26435,7 +26674,7 @@ async function mergePullResult(opts) {
26435
26674
  continue;
26436
26675
  try {
26437
26676
  if (existsSync53(path))
26438
- rmSync8(path, { force: true });
26677
+ rmSync9(path, { force: true });
26439
26678
  await teamInstallsForget(id, row.tool);
26440
26679
  report.removed.push({ artifactId: id, path });
26441
26680
  } catch (err) {
@@ -26454,10 +26693,10 @@ function readFileIfExists(path) {
26454
26693
  try {
26455
26694
  if (!existsSync53(path))
26456
26695
  return null;
26457
- const s = statSync44(path);
26696
+ const s = statSync45(path);
26458
26697
  if (!s.isFile())
26459
26698
  return null;
26460
- return readFileSync46(path);
26699
+ return readFileSync47(path);
26461
26700
  } catch {
26462
26701
  return null;
26463
26702
  }
@@ -26538,8 +26777,8 @@ var init_vault_crypto = __esm({
26538
26777
  });
26539
26778
 
26540
26779
  // ../engine/dist/core/vault-source.js
26541
- import { existsSync as existsSync54, readdirSync as readdirSync33, statSync as statSync45 } from "fs";
26542
- import { extname, join as join58 } from "path";
26780
+ import { existsSync as existsSync54, readdirSync as readdirSync33, statSync as statSync46 } from "fs";
26781
+ import { extname, join as join59 } from "path";
26543
26782
  function* walkVaultSources() {
26544
26783
  const t = loadSettings().team.vault;
26545
26784
  const include2 = new Set(t.syncTools);
@@ -26554,7 +26793,7 @@ function* walkVaultSources() {
26554
26793
  }
26555
26794
  function safeStat(path) {
26556
26795
  try {
26557
- const s = statSync45(path);
26796
+ const s = statSync46(path);
26558
26797
  if (!s.isFile())
26559
26798
  return null;
26560
26799
  return { mtimeMs: s.mtimeMs, size: s.size };
@@ -26576,7 +26815,7 @@ function* walkClaude() {
26576
26815
  if (proj.startsWith("."))
26577
26816
  continue;
26578
26817
  const projectPath = resolveProjectDirName(proj);
26579
- const projDir = join58(root, proj);
26818
+ const projDir = join59(root, proj);
26580
26819
  let entries = [];
26581
26820
  try {
26582
26821
  entries = readdirSync33(projDir);
@@ -26586,7 +26825,7 @@ function* walkClaude() {
26586
26825
  for (const f of entries) {
26587
26826
  if (extname(f) !== ".jsonl")
26588
26827
  continue;
26589
- const path = join58(projDir, f);
26828
+ const path = join59(projDir, f);
26590
26829
  const s = safeStat(path);
26591
26830
  if (!s)
26592
26831
  continue;
@@ -26616,7 +26855,7 @@ function* walkCursor() {
26616
26855
  }
26617
26856
  }
26618
26857
  function* walkCodex() {
26619
- const sessionsRoot = join58(codexBackend.homeDir(), "sessions");
26858
+ const sessionsRoot = join59(codexBackend.homeDir(), "sessions");
26620
26859
  if (!existsSync54(sessionsRoot))
26621
26860
  return;
26622
26861
  const stack = [sessionsRoot];
@@ -26629,7 +26868,7 @@ function* walkCodex() {
26629
26868
  continue;
26630
26869
  }
26631
26870
  for (const e of entries) {
26632
- const path = join58(dir, e.name);
26871
+ const path = join59(dir, e.name);
26633
26872
  if (e.isDirectory()) {
26634
26873
  stack.push(path);
26635
26874
  continue;
@@ -26645,7 +26884,7 @@ function* walkCodex() {
26645
26884
  }
26646
26885
  }
26647
26886
  function* walkAgy() {
26648
- const brainDir = join58(agyBackend.homeDir(), "brain");
26887
+ const brainDir = join59(agyBackend.homeDir(), "brain");
26649
26888
  if (!existsSync54(brainDir))
26650
26889
  return;
26651
26890
  let sessionDirs = [];
@@ -26655,16 +26894,16 @@ function* walkAgy() {
26655
26894
  return;
26656
26895
  }
26657
26896
  for (const rawId of sessionDirs) {
26658
- const sessionPath = join58(brainDir, rawId);
26897
+ const sessionPath = join59(brainDir, rawId);
26659
26898
  try {
26660
- if (!statSync45(sessionPath).isDirectory())
26899
+ if (!statSync46(sessionPath).isDirectory())
26661
26900
  continue;
26662
26901
  } catch {
26663
26902
  continue;
26664
26903
  }
26665
- let filePath = join58(sessionPath, ".system_generated", "logs", "transcript.jsonl");
26904
+ let filePath = join59(sessionPath, ".system_generated", "logs", "transcript.jsonl");
26666
26905
  if (!existsSync54(filePath)) {
26667
- filePath = join58(sessionPath, ".system_generated", "logs", "transcript_full.jsonl");
26906
+ filePath = join59(sessionPath, ".system_generated", "logs", "transcript_full.jsonl");
26668
26907
  }
26669
26908
  if (!existsSync54(filePath))
26670
26909
  continue;
@@ -26702,8 +26941,8 @@ __export(vault_client_exports, {
26702
26941
  vaultStatus: () => vaultStatus,
26703
26942
  vaultSync: () => vaultSync
26704
26943
  });
26705
- import { mkdirSync as mkdirSync21, readFileSync as readFileSync47, writeFileSync as writeFileSync21, existsSync as existsSync55 } from "fs";
26706
- import { dirname as dirname28, join as join59 } from "path";
26944
+ import { mkdirSync as mkdirSync21, readFileSync as readFileSync48, writeFileSync as writeFileSync21, existsSync as existsSync55 } from "fs";
26945
+ import { dirname as dirname28, join as join60 } from "path";
26707
26946
  function context2() {
26708
26947
  const s = loadSettings().team;
26709
26948
  if (!s.enabled)
@@ -26842,7 +27081,7 @@ async function vaultSync(passphrase) {
26842
27081
  continue;
26843
27082
  }
26844
27083
  try {
26845
- const plaintext = readFileSync47(src.path);
27084
+ const plaintext = readFileSync48(src.path);
26846
27085
  const sourceSha = sha256Hex(plaintext);
26847
27086
  const priorSha = uploaded.get(uploadKey(src.sessionId, src.tool));
26848
27087
  if (priorSha === sourceSha) {
@@ -26894,7 +27133,7 @@ async function vaultSync(passphrase) {
26894
27133
  }
26895
27134
  function importedPathFor(tool, sessionId) {
26896
27135
  const base4 = sessionId.replace(/^gemini_/, "").replace(/^codex_/, "").replace(/^agy_/, "").replace(/^cursor_/, "").replace(/^opencode_/, "");
26897
- return join59(IMPORTED_ROOT(), tool, `${base4}.jsonl`);
27136
+ return join60(IMPORTED_ROOT(), tool, `${base4}.jsonl`);
26898
27137
  }
26899
27138
  async function vaultRestore(passphrase, opts = {}) {
26900
27139
  const ctx = context2();
@@ -26983,7 +27222,7 @@ var init_vault_client = __esm({
26983
27222
  uploadKey = (sessionId, tool) => `${sessionId}\0${tool}`;
26984
27223
  VaultPassphraseMismatchError = class extends Error {
26985
27224
  };
26986
- IMPORTED_ROOT = () => join59(getDataDir(), "imported");
27225
+ IMPORTED_ROOT = () => join60(getDataDir(), "imported");
26987
27226
  }
26988
27227
  });
26989
27228
 
@@ -27545,15 +27784,15 @@ __export(service_installer_exports, {
27545
27784
  uninstallService: () => uninstallService
27546
27785
  });
27547
27786
  import { execSync as execSync5 } from "child_process";
27548
- import { existsSync as existsSync56, mkdirSync as mkdirSync22, readFileSync as readFileSync48, rmSync as rmSync9, writeFileSync as writeFileSync22 } from "fs";
27787
+ import { existsSync as existsSync56, mkdirSync as mkdirSync22, readFileSync as readFileSync49, rmSync as rmSync10, writeFileSync as writeFileSync22 } from "fs";
27549
27788
  import { homedir as homedir22 } from "os";
27550
- import { join as join60 } from "path";
27789
+ import { join as join61 } from "path";
27551
27790
  import { fileURLToPath as fileURLToPath5 } from "url";
27552
27791
  function resolveDaemonPaths() {
27553
27792
  const watchJs = fileURLToPath5(new URL("./watch.js", import.meta.url));
27554
27793
  const node = process.execPath;
27555
- const dataDir = join60(homedir22(), ".chat-recall");
27556
- const logFile = join60(dataDir, "watch.log");
27794
+ const dataDir = join61(homedir22(), ".chat-recall");
27795
+ const logFile = join61(dataDir, "watch.log");
27557
27796
  return { watchJs, node, logFile, dataDir };
27558
27797
  }
27559
27798
  function tryCmd(cmd) {
@@ -27580,12 +27819,12 @@ function refreshServiceDefinition() {
27580
27819
  if (process.platform !== "linux") return false;
27581
27820
  try {
27582
27821
  const { watchJs, node, logFile } = resolveDaemonPaths();
27583
- const unitPath = join60(homedir22(), ".config", "systemd", "user", "chat-recall-watch.service");
27822
+ const unitPath = join61(homedir22(), ".config", "systemd", "user", "chat-recall-watch.service");
27584
27823
  if (!existsSync56(unitPath)) return false;
27585
- const current = readFileSync48(unitPath, "utf8");
27824
+ const current = readFileSync49(unitPath, "utf8");
27586
27825
  if (!current.includes(watchJs)) return false;
27587
27826
  const wanted = renderSystemdUnit(watchJs, node, logFile);
27588
- if (readFileSync48(unitPath, "utf8") === wanted) return false;
27827
+ if (readFileSync49(unitPath, "utf8") === wanted) return false;
27589
27828
  writeFileSync22(unitPath, wanted);
27590
27829
  execSync5("systemctl --user daemon-reload", { stdio: "ignore" });
27591
27830
  return true;
@@ -27611,8 +27850,8 @@ function installService() {
27611
27850
  );
27612
27851
  }
27613
27852
  function installSystemd(watchJs, node, logFile) {
27614
- const unitDir = join60(homedir22(), ".config", "systemd", "user");
27615
- const unitPath = join60(unitDir, "chat-recall-watch.service");
27853
+ const unitDir = join61(homedir22(), ".config", "systemd", "user");
27854
+ const unitPath = join61(unitDir, "chat-recall-watch.service");
27616
27855
  const unit = renderSystemdUnit(watchJs, node, logFile);
27617
27856
  mkdirSync22(unitDir, { recursive: true });
27618
27857
  writeFileSync22(unitPath, unit);
@@ -27691,8 +27930,8 @@ function renderSystemdUnit(watchJs, node, logFile) {
27691
27930
  }
27692
27931
  function installLaunchd(watchJs, node, logFile) {
27693
27932
  const label = "com.chat-recall.watch";
27694
- const plistDir = join60(homedir22(), "Library", "LaunchAgents");
27695
- const plistPath = join60(plistDir, `${label}.plist`);
27933
+ const plistDir = join61(homedir22(), "Library", "LaunchAgents");
27934
+ const plistPath = join61(plistDir, `${label}.plist`);
27696
27935
  const plist = renderLaunchdPlist(watchJs, node, logFile, label);
27697
27936
  mkdirSync22(plistDir, { recursive: true });
27698
27937
  writeFileSync22(plistPath, plist);
@@ -27748,9 +27987,9 @@ function uninstallService() {
27748
27987
  removed = true;
27749
27988
  } catch {
27750
27989
  }
27751
- const unitPath = join60(homedir22(), ".config", "systemd", "user", "chat-recall-watch.service");
27990
+ const unitPath = join61(homedir22(), ".config", "systemd", "user", "chat-recall-watch.service");
27752
27991
  if (existsSync56(unitPath)) {
27753
- rmSync9(unitPath, { force: true });
27992
+ rmSync10(unitPath, { force: true });
27754
27993
  removed = true;
27755
27994
  }
27756
27995
  try {
@@ -27760,14 +27999,14 @@ function uninstallService() {
27760
27999
  return removed;
27761
28000
  }
27762
28001
  if (process.platform === "darwin") {
27763
- const plistPath = join60(homedir22(), "Library", "LaunchAgents", "com.chat-recall.watch.plist");
28002
+ const plistPath = join61(homedir22(), "Library", "LaunchAgents", "com.chat-recall.watch.plist");
27764
28003
  try {
27765
28004
  execSync5(`launchctl unload "${plistPath}" 2>/dev/null`, { stdio: "ignore" });
27766
28005
  } catch {
27767
28006
  }
27768
28007
  let removed = false;
27769
28008
  if (existsSync56(plistPath)) {
27770
- rmSync9(plistPath, { force: true });
28009
+ rmSync10(plistPath, { force: true });
27771
28010
  removed = true;
27772
28011
  }
27773
28012
  return removed;
@@ -27811,7 +28050,7 @@ __export(device_auth_exports, {
27811
28050
  betterAuthDeviceLogin: () => betterAuthDeviceLogin,
27812
28051
  deviceLogin: () => deviceLogin
27813
28052
  });
27814
- import { createHash as createHash15, randomBytes } from "node:crypto";
28053
+ import { createHash as createHash15, randomBytes as randomBytes2 } from "node:crypto";
27815
28054
  async function readDeviceCode(res, where) {
27816
28055
  const text = await res.text().catch(() => "");
27817
28056
  let parsed;
@@ -27839,7 +28078,7 @@ async function deviceLogin(opts, onPrompt) {
27839
28078
  }
27840
28079
  const clientId = opts.clientId || DEFAULT_CLIENT_ID;
27841
28080
  const scope = opts.scope || "openid email profile";
27842
- const codeVerifier = b64url(randomBytes(32));
28081
+ const codeVerifier = b64url(randomBytes2(32));
27843
28082
  const codeChallenge = b64url(createHash15("sha256").update(codeVerifier).digest());
27844
28083
  const startRes = await fetch(`${issuer}/protocol/openid-connect/auth/device`, {
27845
28084
  method: "POST",
@@ -28289,9 +28528,9 @@ init_project_resolver();
28289
28528
  import { config } from "dotenv";
28290
28529
  import { Command } from "commander";
28291
28530
  import chalk2 from "chalk";
28292
- import { existsSync as existsSync57, readFileSync as readFileSync49, writeFileSync as writeFileSync23, realpathSync as realpathSync5 } from "fs";
28531
+ import { existsSync as existsSync57, readFileSync as readFileSync50, writeFileSync as writeFileSync23, realpathSync as realpathSync5 } from "fs";
28293
28532
  import { homedir as homedir23 } from "os";
28294
- import { join as join61, resolve as resolve2, dirname as dirname29, basename as basename27 } from "path";
28533
+ import { join as join62, resolve as resolve2, dirname as dirname29, basename as basename27 } from "path";
28295
28534
 
28296
28535
  // ../engine/dist/core/score-tier.js
28297
28536
  var STRONG_RATIO = 0.85;
@@ -28399,10 +28638,10 @@ function renderEnvNeeds(needs, installedCount) {
28399
28638
  // src/star-nudge.ts
28400
28639
  init_paths();
28401
28640
  import { existsSync as existsSync43, mkdirSync as mkdirSync11, writeFileSync as writeFileSync11 } from "node:fs";
28402
- import { dirname as dirname20, join as join45 } from "node:path";
28641
+ import { dirname as dirname20, join as join46 } from "node:path";
28403
28642
  var REPO = "https://github.com/munhq/chat-recall";
28404
28643
  function markerPath() {
28405
- return join45(getDataDir(), ".star-asked");
28644
+ return join46(getDataDir(), ".star-asked");
28406
28645
  }
28407
28646
  function suppressed() {
28408
28647
  const env = process.env;
@@ -28455,8 +28694,8 @@ function claudeHookConfigFiles() {
28455
28694
  const out = [];
28456
28695
  const seen = /* @__PURE__ */ new Set();
28457
28696
  for (const home of claudeHomeDirs()) {
28458
- if (!existsSync57(join61(home, "projects"))) continue;
28459
- const file = join61(home, "hooks.json");
28697
+ if (!existsSync57(join62(home, "projects"))) continue;
28698
+ const file = join62(home, "hooks.json");
28460
28699
  let key2;
28461
28700
  try {
28462
28701
  key2 = realpathSync5(file);
@@ -28551,13 +28790,13 @@ async function serverDelete(path, body2) {
28551
28790
  }
28552
28791
  var pkgEngines = (() => {
28553
28792
  try {
28554
- return JSON.parse(readFileSync49(new URL("../package.json", import.meta.url), "utf-8")).engines?.node ?? "";
28793
+ return JSON.parse(readFileSync50(new URL("../package.json", import.meta.url), "utf-8")).engines?.node ?? "";
28555
28794
  } catch {
28556
28795
  return "";
28557
28796
  }
28558
28797
  })();
28559
28798
  var pkgVersion = JSON.parse(
28560
- readFileSync49(new URL("../package.json", import.meta.url), "utf-8")
28799
+ readFileSync50(new URL("../package.json", import.meta.url), "utf-8")
28561
28800
  ).version;
28562
28801
  var DEFAULT_SERVER = (process.env.CHAT_RECALL_DEFAULT_SERVER || "https://chatrecall.dev").replace(/\/+$/, "");
28563
28802
  var DEFAULT_ALLOW = [
@@ -28731,10 +28970,10 @@ program.command("init").description("Set up chat-recall: connect to your server,
28731
28970
  } else if (target) {
28732
28971
  }
28733
28972
  if (!options.skipMcp) {
28734
- const projectRoot = join61(import.meta.dirname, "..");
28973
+ const projectRoot = join62(import.meta.dirname, "..");
28735
28974
  let mcpBinOnPath = false;
28736
28975
  mcpBinOnPath = isOnPath("chat-recall-mcp");
28737
- const launch = mcpBinOnPath ? { command: "chat-recall-mcp" } : { command: "node", args: [join61(projectRoot, "dist", "mcp-relay.js")] };
28976
+ const launch = mcpBinOnPath ? { command: "chat-recall-mcp" } : { command: "node", args: [join62(projectRoot, "dist", "mcp-relay.js")] };
28738
28977
  const MCP_ENV = { NODE_OPTIONS: "--max-old-space-size=1024" };
28739
28978
  const { registerMcpEverywhere: registerMcpEverywhere2 } = await Promise.resolve().then(() => (init_mcp_clients(), mcp_clients_exports));
28740
28979
  const MCP_CLIENT_FOR_BIN = {
@@ -28774,7 +29013,7 @@ program.command("init").description("Set up chat-recall: connect to your server,
28774
29013
  const detected = checkCodeindexStatus2();
28775
29014
  if (detected.installed && !forceInstall) {
28776
29015
  if (!options.skipMcp) {
28777
- const mcpJsonPath = join61(homedir23(), ".mcp.json");
29016
+ const mcpJsonPath = join62(homedir23(), ".mcp.json");
28778
29017
  const reg = registerCodeindexMcp2(mcpJsonPath, detected.path);
28779
29018
  }
28780
29019
  } else if (forceInstall) {
@@ -28783,7 +29022,7 @@ program.command("init").description("Set up chat-recall: connect to your server,
28783
29022
  if (result.installed) {
28784
29023
  const sizeMb = result.size ? `${(result.size / 1024 / 1024).toFixed(1)} MB` : "?";
28785
29024
  if (!options.skipMcp) {
28786
- const mcpJsonPath = join61(homedir23(), ".mcp.json");
29025
+ const mcpJsonPath = join62(homedir23(), ".mcp.json");
28787
29026
  const reg = registerCodeindexMcp2(mcpJsonPath, CODEINDEX_BIN_PATH2);
28788
29027
  }
28789
29028
  } else if (!result.prebuiltAvailable) {
@@ -29241,7 +29480,7 @@ memory.command("wake-up").description("Generate wake-up context (high-importance
29241
29480
  const identityFile = getIdentityFilePath();
29242
29481
  let identity = "AI coding assistant";
29243
29482
  if (existsSync57(identityFile)) {
29244
- identity = readFileSync49(identityFile, "utf-8").trim();
29483
+ identity = readFileSync50(identityFile, "utf-8").trim();
29245
29484
  }
29246
29485
  const lines = [
29247
29486
  chalk2.bold("# Wake-Up Context"),
@@ -29341,7 +29580,7 @@ program.command("feedback").argument("<message...>", "what you want to say \u201
29341
29580
  }
29342
29581
  });
29343
29582
  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) => {
29344
- const { existsSync: existsSync58, readFileSync: readFileSync50, statSync: statSync46 } = await import("fs");
29583
+ const { existsSync: existsSync58, readFileSync: readFileSync51, statSync: statSync47 } = await import("fs");
29345
29584
  const { execSync: execSync6 } = await import("child_process");
29346
29585
  const rows = [];
29347
29586
  const note = (ok, label, detail) => rows.push({ ok, label, detail });
@@ -29404,12 +29643,12 @@ program.command("doctor").description("Quick health check across login, server,
29404
29643
  }
29405
29644
  }
29406
29645
  }
29407
- const credFile = join61(getDataDir(), "credentials.json");
29646
+ const credFile = join62(getDataDir(), "credentials.json");
29408
29647
  if (!existsSync58(credFile)) {
29409
29648
  note(false, "Credentials file", `missing \u2014 run \`chat-recall login <server-url>\``);
29410
29649
  } else {
29411
29650
  try {
29412
- const mode = statSync46(credFile).mode & 511;
29651
+ const mode = statSync47(credFile).mode & 511;
29413
29652
  const isWin = process.platform === "win32";
29414
29653
  const safe = isWin || (mode & 63) === 0;
29415
29654
  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"})`);
@@ -29428,13 +29667,13 @@ program.command("doctor").description("Quick health check across login, server,
29428
29667
  const readHooks = (file) => {
29429
29668
  if (!existsSync58(file)) return {};
29430
29669
  try {
29431
- return JSON.parse(readFileSync50(file, "utf-8")).hooks || {};
29670
+ return JSON.parse(readFileSync51(file, "utf-8")).hooks || {};
29432
29671
  } catch {
29433
29672
  return {};
29434
29673
  }
29435
29674
  };
29436
29675
  const cfg = readHooks(hooksJson);
29437
- const settings2 = readHooks(join61(dirname29(hooksJson), "settings.json"));
29676
+ const settings2 = readHooks(join62(dirname29(hooksJson), "settings.json"));
29438
29677
  const all = ["SessionStart", "UserPromptSubmit", "Stop", "PreCompact", "SessionEnd"];
29439
29678
  const hits = [];
29440
29679
  for (const ev of all) {
@@ -29481,7 +29720,7 @@ program.command("doctor").description("Quick health check across login, server,
29481
29720
  }
29482
29721
  let registered = false;
29483
29722
  try {
29484
- const cfg = JSON.parse(readFileSync50(target2.configPath, "utf-8"));
29723
+ const cfg = JSON.parse(readFileSync51(target2.configPath, "utf-8"));
29485
29724
  registered = JSON.stringify(cfg).includes("chat_recall_guard");
29486
29725
  } catch {
29487
29726
  }
@@ -29496,7 +29735,7 @@ program.command("doctor").description("Quick health check across login, server,
29496
29735
  const want = bundledSkillNames2().length;
29497
29736
  for (const t of skillTargets2()) {
29498
29737
  if (!t.available) continue;
29499
- const have = want === 0 ? 0 : bundledSkillNames2().filter((n) => existsSync58(join61(t.dir, n, ".chat-recall-managed"))).length;
29738
+ const have = want === 0 ? 0 : bundledSkillNames2().filter((n) => existsSync58(join62(t.dir, n, ".chat-recall-managed"))).length;
29500
29739
  note(
29501
29740
  have === want,
29502
29741
  `Skills \u2014 ${t.label}`,
@@ -29571,12 +29810,12 @@ program.command("doctor").description("Quick health check across login, server,
29571
29810
  note(watchRunning, "Watch daemon", watchRunning ? "running" : "not running (run `chat-recall watch --install-service` to keep collection running)");
29572
29811
  const dataDir = getDataDir();
29573
29812
  const legacyPaths = [
29574
- join61(dataDir, "cache.db"),
29575
- join61(dataDir, "cache.db-wal"),
29576
- join61(dataDir, "cache.db-shm"),
29577
- join61(dataDir, "index", "lancedb"),
29578
- join61(dataDir, "index", "knowledge_graph.db"),
29579
- join61(dataDir, "index", "metadata.db")
29813
+ join62(dataDir, "cache.db"),
29814
+ join62(dataDir, "cache.db-wal"),
29815
+ join62(dataDir, "cache.db-shm"),
29816
+ join62(dataDir, "index", "lancedb"),
29817
+ join62(dataDir, "index", "knowledge_graph.db"),
29818
+ join62(dataDir, "index", "metadata.db")
29580
29819
  ];
29581
29820
  const legacyPresent = legacyPaths.filter((p) => existsSync58(p));
29582
29821
  if (opts.purgeLocal) {
@@ -29585,11 +29824,11 @@ program.command("doctor").description("Quick health check across login, server,
29585
29824
  } else if (legacyPresent.length === 0) {
29586
29825
  note(true, "Purge legacy index", "nothing to remove");
29587
29826
  } else {
29588
- const { rmSync: rmSync10 } = await import("fs");
29827
+ const { rmSync: rmSync11 } = await import("fs");
29589
29828
  let removed = 0;
29590
29829
  for (const p of legacyPresent) {
29591
29830
  try {
29592
- rmSync10(p, { recursive: true, force: true });
29831
+ rmSync11(p, { recursive: true, force: true });
29593
29832
  removed++;
29594
29833
  } catch {
29595
29834
  }
@@ -29649,7 +29888,7 @@ companions.command("install").description("Install codeindex (downloads from mun
29649
29888
  if (result.installed) {
29650
29889
  const sizeMb = result.size ? `${(result.size / 1024 / 1024).toFixed(1)} MB` : "?";
29651
29890
  console.log(chalk2.green(`\u2713 codeindex installed (${sizeMb}) \u2192 ${result.path}`));
29652
- const mcpJsonPath = join61(homedir23(), ".mcp.json");
29891
+ const mcpJsonPath = join62(homedir23(), ".mcp.json");
29653
29892
  const reg = registerCodeindexMcp2(mcpJsonPath, CODEINDEX_BIN_PATH2);
29654
29893
  if (reg.added) console.log(chalk2.dim(` Registered as MCP server in ${mcpJsonPath}`));
29655
29894
  else console.log(chalk2.dim(` Already registered as MCP server`));
@@ -29671,7 +29910,7 @@ companions.command("uninstall").description("Remove the codeindex binary chat-re
29671
29910
  const r = uninstallCodeindex2();
29672
29911
  if (r.removed) console.log(chalk2.green(`\u2713 Removed ${r.path}`));
29673
29912
  else console.log(chalk2.dim(` Nothing to remove at ${r.path}`));
29674
- const mcpJsonPath = join61(homedir23(), ".mcp.json");
29913
+ const mcpJsonPath = join62(homedir23(), ".mcp.json");
29675
29914
  const u = unregisterCodeindexMcp2(mcpJsonPath);
29676
29915
  if (u.removed) console.log(chalk2.dim(` Unregistered MCP server from ${mcpJsonPath}`));
29677
29916
  });
@@ -30223,10 +30462,10 @@ tasks.command("pull [dir]").description("Write TEAM_TASKS.md for your tasks in t
30223
30462
  try {
30224
30463
  const { resolveProjectId: resolveProjectId2 } = await Promise.resolve().then(() => (init_project_resolver(), project_resolver_exports));
30225
30464
  const { renderTeamTasksMd: renderTeamTasksMd2, parseTeamTasksFile: parseTeamTasksFile2 } = await Promise.resolve().then(() => (init_project_tasks(), project_tasks_exports));
30226
- const { writeFileSync: writeFileSync24, readFileSync: readFileSync50, existsSync: existsSync58 } = await import("node:fs");
30227
- const { join: join62 } = await import("node:path");
30228
- const file = join62(cwd, "TEAM_TASKS.md");
30229
- if (!opts.force && existsSync58(file) && parseTeamTasksFile2(readFileSync50(file, "utf8")).length > 0) {
30465
+ const { writeFileSync: writeFileSync24, readFileSync: readFileSync51, existsSync: existsSync58 } = await import("node:fs");
30466
+ const { join: join63 } = await import("node:path");
30467
+ const file = join63(cwd, "TEAM_TASKS.md");
30468
+ if (!opts.force && existsSync58(file) && parseTeamTasksFile2(readFileSync51(file, "utf8")).length > 0) {
30230
30469
  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.");
30231
30470
  process.exit(1);
30232
30471
  }
@@ -30245,14 +30484,14 @@ tasks.command("push [dir]").description("Push TEAM_TASKS.md status edits back to
30245
30484
  const cwd = dir || process.cwd();
30246
30485
  try {
30247
30486
  const { parseTeamTasksFile: parseTeamTasksFile2 } = await Promise.resolve().then(() => (init_project_tasks(), project_tasks_exports));
30248
- const { readFileSync: readFileSync50, existsSync: existsSync58 } = await import("node:fs");
30249
- const { join: join62 } = await import("node:path");
30250
- const file = join62(cwd, "TEAM_TASKS.md");
30487
+ const { readFileSync: readFileSync51, existsSync: existsSync58 } = await import("node:fs");
30488
+ const { join: join63 } = await import("node:path");
30489
+ const file = join63(cwd, "TEAM_TASKS.md");
30251
30490
  if (!existsSync58(file)) {
30252
30491
  console.error(chalk2.red("no TEAM_TASKS.md here \u2014"), "run", chalk2.bold("chat-recall tasks pull"), "first");
30253
30492
  process.exit(1);
30254
30493
  }
30255
- const edits = parseTeamTasksFile2(readFileSync50(file, "utf8"));
30494
+ const edits = parseTeamTasksFile2(readFileSync51(file, "utf8"));
30256
30495
  let n = 0;
30257
30496
  for (const e of edits) {
30258
30497
  await serverPatch(`/api/tasks/${encodeURIComponent(e.id)}`, { status: e.intent });
@@ -30358,8 +30597,8 @@ team.command("publish <type> <name> <file>").description("Publish a local file a
30358
30597
  console.error(chalk2.red(`Invalid tool: ${opts.tool}. Must be one of: ${validTools.join(", ")}`));
30359
30598
  process.exit(1);
30360
30599
  }
30361
- const { readFileSync: readFileSync50 } = await import("fs");
30362
- const body2 = readFileSync50(file);
30600
+ const { readFileSync: readFileSync51 } = await import("fs");
30601
+ const body2 = readFileSync51(file);
30363
30602
  const { teamPublish: teamPublish2 } = await Promise.resolve().then(() => (init_team_client(), team_client_exports));
30364
30603
  const a = await teamPublish2({
30365
30604
  type,
@@ -30735,18 +30974,18 @@ program.command("task-hook").description("Move a board card when a prompt or a c
30735
30974
  }
30736
30975
  });
30737
30976
  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) => {
30738
- const { mkdirSync: mkdirSync23, copyFileSync: copyFileSync4, chmodSync: chmodSync5, existsSync: existsSync58, readFileSync: readFileSync50, writeFileSync: writeFileSync24, statSync: statSync46, unlinkSync: unlinkSync4 } = await import("fs");
30977
+ const { mkdirSync: mkdirSync23, copyFileSync: copyFileSync4, chmodSync: chmodSync5, existsSync: existsSync58, readFileSync: readFileSync51, writeFileSync: writeFileSync24, statSync: statSync47, unlinkSync: unlinkSync4 } = await import("fs");
30739
30978
  const { fileURLToPath: fileURLToPath6 } = await import("url");
30740
30979
  const { boardHookEntries: boardHookEntries2, isBoardHookEntry: isBoardHookEntry2, registerBoardHooks: registerBoardHooks2, resolveCliEntry: resolveCliEntry2 } = await Promise.resolve().then(() => (init_board_hooks(), board_hooks_exports));
30741
30980
  const here = fileURLToPath6(new URL(".", import.meta.url));
30742
30981
  const findHook = (name) => {
30743
30982
  const candidates2 = [
30744
- join61(here, "..", "hooks", name),
30745
- join61(here, "..", "..", "hooks", name),
30983
+ join62(here, "..", "hooks", name),
30984
+ join62(here, "..", "..", "hooks", name),
30746
30985
  // The monorepo root, for a run straight from the checkout. The copy
30747
30986
  // under packages/cli/hooks is written by the package build, so a
30748
30987
  // freshly added script is only at the root until that build runs.
30749
- join61(here, "..", "..", "..", "hooks", name)
30988
+ join62(here, "..", "..", "..", "hooks", name)
30750
30989
  ];
30751
30990
  return candidates2.find((p) => existsSync58(p));
30752
30991
  };
@@ -30760,16 +30999,16 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
30760
30999
  process.exit(1);
30761
31000
  }
30762
31001
  const hooksDir = getHooksDir();
30763
- const installedSaveHook = join61(hooksDir, "chat_recall_save_hook.sh");
30764
- const installedGuardHook = join61(hooksDir, "chat_recall_guard_hook.sh");
30765
- const installedResumeHook = join61(hooksDir, "chat_recall_resume_hook.sh");
30766
- const installedEscalateHook = join61(hooksDir, "chat_recall_escalate_hook.sh");
30767
- const installedWakeupHook = join61(hooksDir, "chat_recall_wakeup_hook.sh");
31002
+ const installedSaveHook = join62(hooksDir, "chat_recall_save_hook.sh");
31003
+ const installedGuardHook = join62(hooksDir, "chat_recall_guard_hook.sh");
31004
+ const installedResumeHook = join62(hooksDir, "chat_recall_resume_hook.sh");
31005
+ const installedEscalateHook = join62(hooksDir, "chat_recall_escalate_hook.sh");
31006
+ const installedWakeupHook = join62(hooksDir, "chat_recall_wakeup_hook.sh");
30768
31007
  const wakeupWiredInSettings = (home) => {
30769
- const settings2 = join61(home, "settings.json");
31008
+ const settings2 = join62(home, "settings.json");
30770
31009
  if (!existsSync58(settings2)) return false;
30771
31010
  try {
30772
- const cfg = JSON.parse(readFileSync50(settings2, "utf-8"));
31011
+ const cfg = JSON.parse(readFileSync51(settings2, "utf-8"));
30773
31012
  const arr = Array.isArray(cfg.hooks?.SessionStart) ? cfg.hooks.SessionStart : [];
30774
31013
  return arr.some((h) => (h?.hooks?.[0]?.command || "").includes("chat_recall_wakeup_hook"));
30775
31014
  } catch {
@@ -30780,7 +31019,7 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
30780
31019
  const readHookConfig = (file) => {
30781
31020
  if (!existsSync58(file)) return { hooks: {} };
30782
31021
  try {
30783
- const c = JSON.parse(readFileSync50(file, "utf-8"));
31022
+ const c = JSON.parse(readFileSync51(file, "utf-8"));
30784
31023
  if (!c.hooks || typeof c.hooks !== "object") c.hooks = {};
30785
31024
  return c;
30786
31025
  } catch (err) {
@@ -30797,7 +31036,7 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
30797
31036
  const readJson4 = (file) => {
30798
31037
  if (!existsSync58(file)) return {};
30799
31038
  try {
30800
- return JSON.parse(readFileSync50(file, "utf-8"));
31039
+ return JSON.parse(readFileSync51(file, "utf-8"));
30801
31040
  } catch {
30802
31041
  return {};
30803
31042
  }
@@ -30807,7 +31046,7 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
30807
31046
  const notes = [];
30808
31047
  for (const target of reg.guardTargets()) {
30809
31048
  if (!existsSync58(target.homeDir)) continue;
30810
- const wrapper = join61(hooksDir, reg.guardWrapperName(target.tool));
31049
+ const wrapper = join62(hooksDir, reg.guardWrapperName(target.tool));
30811
31050
  writeFileSync24(wrapper, reg.guardWrapperSource(target.tool, hookPath));
30812
31051
  chmodSync5(wrapper, 493);
30813
31052
  mkdirSync23(dirname29(target.configPath), { recursive: true });
@@ -30829,7 +31068,7 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
30829
31068
  for (const target of reg.guardTargets()) {
30830
31069
  if (!existsSync58(target.configPath)) continue;
30831
31070
  if (target.tool === "opencode") {
30832
- const body2 = readFileSync50(target.configPath, "utf-8");
31071
+ const body2 = readFileSync51(target.configPath, "utf-8");
30833
31072
  if (!body2.includes("chat-recall install-hooks")) continue;
30834
31073
  unlinkSync4(target.configPath);
30835
31074
  removed += 1;
@@ -30937,7 +31176,7 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
30937
31176
  const config2 = readHookConfig(hooksJson);
30938
31177
  const home = dirname29(hooksJson);
30939
31178
  const alreadyWired = wakeupWiredInSettings(home);
30940
- if (alreadyWired) wakeupSkipped.push(join61(home, "settings.json"));
31179
+ if (alreadyWired) wakeupSkipped.push(join62(home, "settings.json"));
30941
31180
  const perProfile = installWakeup && !alreadyWired ? [...events, ["SessionStart", wakeupEntry]] : events;
30942
31181
  for (const event of HOOK_EVENTS) {
30943
31182
  const arr = Array.isArray(config2.hooks[event]) ? config2.hooks[event] : [];
@@ -30950,18 +31189,18 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
30950
31189
  writeFileSync24(hooksJson, JSON.stringify(config2, null, 2) + "\n");
30951
31190
  }
30952
31191
  if (installGuard) await addGuardToOtherTools(installedGuardHook);
30953
- const saveSz = statSync46(installedSaveHook).size;
31192
+ const saveSz = statSync47(installedSaveHook).size;
30954
31193
  console.log(chalk2.green(`\u2713 Installed chat-recall save hook (${saveSz} bytes)`));
30955
31194
  if (installResume) {
30956
- const resumeSz = statSync46(installedResumeHook).size;
31195
+ const resumeSz = statSync47(installedResumeHook).size;
30957
31196
  console.log(chalk2.green(`\u2713 Installed chat-recall resume-hint hook (${resumeSz} bytes)`));
30958
31197
  }
30959
31198
  if (installEscalate) {
30960
- const escalateSz = statSync46(installedEscalateHook).size;
31199
+ const escalateSz = statSync47(installedEscalateHook).size;
30961
31200
  console.log(chalk2.green(`\u2713 Installed chat-recall learnings-escalation hook (${escalateSz} bytes)`));
30962
31201
  }
30963
31202
  if (installGuard) {
30964
- const guardSz = statSync46(installedGuardHook).size;
31203
+ const guardSz = statSync47(installedGuardHook).size;
30965
31204
  console.log(chalk2.green(`\u2713 Installed chat-recall decision guard (${guardSz} bytes)`));
30966
31205
  }
30967
31206
  if (installTaskBoard) {
@@ -30969,7 +31208,7 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
30969
31208
  console.log(chalk2.dim(" A prompt naming a card id claims it; a commit message naming one closes it."));
30970
31209
  }
30971
31210
  if (installWakeup) {
30972
- const wakeupSz = statSync46(installedWakeupHook).size;
31211
+ const wakeupSz = statSync47(installedWakeupHook).size;
30973
31212
  console.log(chalk2.green(`\u2713 Installed chat-recall wake-up hook (${wakeupSz} bytes)`));
30974
31213
  for (const f of wakeupSkipped) {
30975
31214
  console.log(chalk2.dim(` (SessionStart already wired in ${f} \u2014 left as is, not duplicated)`));