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/watch.js CHANGED
@@ -2233,7 +2233,7 @@ var require_thread_stream = __commonJS({
2233
2233
  var { version } = require_package();
2234
2234
  var { EventEmitter } = __require("events");
2235
2235
  var { Worker: Worker2 } = __require("worker_threads");
2236
- var { join: join55 } = __require("path");
2236
+ var { join: join56 } = __require("path");
2237
2237
  var { pathToFileURL } = __require("url");
2238
2238
  var { wait } = require_wait();
2239
2239
  var {
@@ -2276,7 +2276,7 @@ var require_thread_stream = __commonJS({
2276
2276
  function createWorker(stream, opts) {
2277
2277
  const { filename, workerData } = opts;
2278
2278
  const bundlerOverrides = "__bundlerPathsOverrides" in globalThis ? globalThis.__bundlerPathsOverrides : {};
2279
- const toExecute = bundlerOverrides["thread-stream-worker"] || join55(__dirname, "lib", "worker.js");
2279
+ const toExecute = bundlerOverrides["thread-stream-worker"] || join56(__dirname, "lib", "worker.js");
2280
2280
  const worker = new Worker2(toExecute, {
2281
2281
  ...opts.workerOpts,
2282
2282
  trackUnmanagedFds: false,
@@ -2679,7 +2679,7 @@ var require_transport = __commonJS({
2679
2679
  "use strict";
2680
2680
  var { createRequire: createRequire3 } = __require("module");
2681
2681
  var getCallers = require_caller();
2682
- var { join: join55, isAbsolute: isAbsolute4, sep: sep5 } = __require("node:path");
2682
+ var { join: join56, isAbsolute: isAbsolute4, sep: sep5 } = __require("node:path");
2683
2683
  var sleep = require_atomic_sleep();
2684
2684
  var onExit = require_on_exit_leak_free();
2685
2685
  var ThreadStream = require_thread_stream();
@@ -2742,7 +2742,7 @@ var require_transport = __commonJS({
2742
2742
  throw new Error("only one of target or targets can be specified");
2743
2743
  }
2744
2744
  if (targets) {
2745
- target = bundlerOverrides["pino-worker"] || join55(__dirname, "worker.js");
2745
+ target = bundlerOverrides["pino-worker"] || join56(__dirname, "worker.js");
2746
2746
  options.targets = targets.filter((dest) => dest.target).map((dest) => {
2747
2747
  return {
2748
2748
  ...dest,
@@ -2760,7 +2760,7 @@ var require_transport = __commonJS({
2760
2760
  });
2761
2761
  });
2762
2762
  } else if (pipeline) {
2763
- target = bundlerOverrides["pino-worker"] || join55(__dirname, "worker.js");
2763
+ target = bundlerOverrides["pino-worker"] || join56(__dirname, "worker.js");
2764
2764
  options.pipelines = [pipeline.map((dest) => {
2765
2765
  return {
2766
2766
  ...dest,
@@ -2782,7 +2782,7 @@ var require_transport = __commonJS({
2782
2782
  return origin;
2783
2783
  }
2784
2784
  if (origin === "pino/file") {
2785
- return join55(__dirname, "..", "file.js");
2785
+ return join56(__dirname, "..", "file.js");
2786
2786
  }
2787
2787
  let fixTarget2;
2788
2788
  for (const filePath of callers) {
@@ -3771,7 +3771,7 @@ var require_safe_stable_stringify = __commonJS({
3771
3771
  return circularValue;
3772
3772
  }
3773
3773
  let res = "";
3774
- let join55 = ",";
3774
+ let join56 = ",";
3775
3775
  const originalIndentation = indentation;
3776
3776
  if (Array.isArray(value)) {
3777
3777
  if (value.length === 0) {
@@ -3785,7 +3785,7 @@ var require_safe_stable_stringify = __commonJS({
3785
3785
  indentation += spacer;
3786
3786
  res += `
3787
3787
  ${indentation}`;
3788
- join55 = `,
3788
+ join56 = `,
3789
3789
  ${indentation}`;
3790
3790
  }
3791
3791
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
@@ -3793,13 +3793,13 @@ ${indentation}`;
3793
3793
  for (; i < maximumValuesToStringify - 1; i++) {
3794
3794
  const tmp2 = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
3795
3795
  res += tmp2 !== void 0 ? tmp2 : "null";
3796
- res += join55;
3796
+ res += join56;
3797
3797
  }
3798
3798
  const tmp = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
3799
3799
  res += tmp !== void 0 ? tmp : "null";
3800
3800
  if (value.length - 1 > maximumBreadth) {
3801
3801
  const removedKeys = value.length - maximumBreadth - 1;
3802
- res += `${join55}"... ${getItemCount(removedKeys)} not stringified"`;
3802
+ res += `${join56}"... ${getItemCount(removedKeys)} not stringified"`;
3803
3803
  }
3804
3804
  if (spacer !== "") {
3805
3805
  res += `
@@ -3820,7 +3820,7 @@ ${originalIndentation}`;
3820
3820
  let separator = "";
3821
3821
  if (spacer !== "") {
3822
3822
  indentation += spacer;
3823
- join55 = `,
3823
+ join56 = `,
3824
3824
  ${indentation}`;
3825
3825
  whitespace = " ";
3826
3826
  }
@@ -3834,13 +3834,13 @@ ${indentation}`;
3834
3834
  const tmp = stringifyFnReplacer(key3, value, stack, replacer, spacer, indentation);
3835
3835
  if (tmp !== void 0) {
3836
3836
  res += `${separator}${strEscape(key3)}:${whitespace}${tmp}`;
3837
- separator = join55;
3837
+ separator = join56;
3838
3838
  }
3839
3839
  }
3840
3840
  if (keyLength > maximumBreadth) {
3841
3841
  const removedKeys = keyLength - maximumBreadth;
3842
3842
  res += `${separator}"...":${whitespace}"${getItemCount(removedKeys)} not stringified"`;
3843
- separator = join55;
3843
+ separator = join56;
3844
3844
  }
3845
3845
  if (spacer !== "" && separator.length > 1) {
3846
3846
  res = `
@@ -3881,7 +3881,7 @@ ${originalIndentation}`;
3881
3881
  }
3882
3882
  const originalIndentation = indentation;
3883
3883
  let res = "";
3884
- let join55 = ",";
3884
+ let join56 = ",";
3885
3885
  if (Array.isArray(value)) {
3886
3886
  if (value.length === 0) {
3887
3887
  return "[]";
@@ -3894,7 +3894,7 @@ ${originalIndentation}`;
3894
3894
  indentation += spacer;
3895
3895
  res += `
3896
3896
  ${indentation}`;
3897
- join55 = `,
3897
+ join56 = `,
3898
3898
  ${indentation}`;
3899
3899
  }
3900
3900
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
@@ -3902,13 +3902,13 @@ ${indentation}`;
3902
3902
  for (; i < maximumValuesToStringify - 1; i++) {
3903
3903
  const tmp2 = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
3904
3904
  res += tmp2 !== void 0 ? tmp2 : "null";
3905
- res += join55;
3905
+ res += join56;
3906
3906
  }
3907
3907
  const tmp = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
3908
3908
  res += tmp !== void 0 ? tmp : "null";
3909
3909
  if (value.length - 1 > maximumBreadth) {
3910
3910
  const removedKeys = value.length - maximumBreadth - 1;
3911
- res += `${join55}"... ${getItemCount(removedKeys)} not stringified"`;
3911
+ res += `${join56}"... ${getItemCount(removedKeys)} not stringified"`;
3912
3912
  }
3913
3913
  if (spacer !== "") {
3914
3914
  res += `
@@ -3921,7 +3921,7 @@ ${originalIndentation}`;
3921
3921
  let whitespace = "";
3922
3922
  if (spacer !== "") {
3923
3923
  indentation += spacer;
3924
- join55 = `,
3924
+ join56 = `,
3925
3925
  ${indentation}`;
3926
3926
  whitespace = " ";
3927
3927
  }
@@ -3930,7 +3930,7 @@ ${indentation}`;
3930
3930
  const tmp = stringifyArrayReplacer(key3, value[key3], stack, replacer, spacer, indentation);
3931
3931
  if (tmp !== void 0) {
3932
3932
  res += `${separator}${strEscape(key3)}:${whitespace}${tmp}`;
3933
- separator = join55;
3933
+ separator = join56;
3934
3934
  }
3935
3935
  }
3936
3936
  if (spacer !== "" && separator.length > 1) {
@@ -3988,20 +3988,20 @@ ${originalIndentation}`;
3988
3988
  indentation += spacer;
3989
3989
  let res2 = `
3990
3990
  ${indentation}`;
3991
- const join56 = `,
3991
+ const join57 = `,
3992
3992
  ${indentation}`;
3993
3993
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
3994
3994
  let i = 0;
3995
3995
  for (; i < maximumValuesToStringify - 1; i++) {
3996
3996
  const tmp2 = stringifyIndent(String(i), value[i], stack, spacer, indentation);
3997
3997
  res2 += tmp2 !== void 0 ? tmp2 : "null";
3998
- res2 += join56;
3998
+ res2 += join57;
3999
3999
  }
4000
4000
  const tmp = stringifyIndent(String(i), value[i], stack, spacer, indentation);
4001
4001
  res2 += tmp !== void 0 ? tmp : "null";
4002
4002
  if (value.length - 1 > maximumBreadth) {
4003
4003
  const removedKeys = value.length - maximumBreadth - 1;
4004
- res2 += `${join56}"... ${getItemCount(removedKeys)} not stringified"`;
4004
+ res2 += `${join57}"... ${getItemCount(removedKeys)} not stringified"`;
4005
4005
  }
4006
4006
  res2 += `
4007
4007
  ${originalIndentation}`;
@@ -4017,16 +4017,16 @@ ${originalIndentation}`;
4017
4017
  return '"[Object]"';
4018
4018
  }
4019
4019
  indentation += spacer;
4020
- const join55 = `,
4020
+ const join56 = `,
4021
4021
  ${indentation}`;
4022
4022
  let res = "";
4023
4023
  let separator = "";
4024
4024
  let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth);
4025
4025
  if (isTypedArrayWithEntries(value)) {
4026
- res += stringifyTypedArray(value, join55, maximumBreadth);
4026
+ res += stringifyTypedArray(value, join56, maximumBreadth);
4027
4027
  keys = keys.slice(value.length);
4028
4028
  maximumPropertiesToStringify -= value.length;
4029
- separator = join55;
4029
+ separator = join56;
4030
4030
  }
4031
4031
  if (deterministic) {
4032
4032
  keys = sort(keys, comparator);
@@ -4037,13 +4037,13 @@ ${indentation}`;
4037
4037
  const tmp = stringifyIndent(key3, value[key3], stack, spacer, indentation);
4038
4038
  if (tmp !== void 0) {
4039
4039
  res += `${separator}${strEscape(key3)}: ${tmp}`;
4040
- separator = join55;
4040
+ separator = join56;
4041
4041
  }
4042
4042
  }
4043
4043
  if (keyLength > maximumBreadth) {
4044
4044
  const removedKeys = keyLength - maximumBreadth;
4045
4045
  res += `${separator}"...": "${getItemCount(removedKeys)} not stringified"`;
4046
- separator = join55;
4046
+ separator = join56;
4047
4047
  }
4048
4048
  if (separator !== "") {
4049
4049
  res = `
@@ -6448,6 +6448,7 @@ var init_from_events = __esm({
6448
6448
  // ../engine/dist/transcript/raw.js
6449
6449
  var raw_exports = {};
6450
6450
  __export(raw_exports, {
6451
+ RAW_PARSE_MAX_BYTES: () => RAW_PARSE_MAX_BYTES,
6451
6452
  archiveRawSession: () => archiveRawSession,
6452
6453
  buildRawContainer: () => buildRawContainer,
6453
6454
  containerSrcHash: () => containerSrcHash,
@@ -6747,11 +6748,11 @@ async function archiveRawSession(store, sessionId) {
6747
6748
  return await store.putRawSession(sessionId, exp.tool, Math.floor(exp.mtime), gz, size);
6748
6749
  }
6749
6750
  function detectForkPredecessor(sessionPath) {
6750
- const { readFileSync: readFileSync46, readdirSync: readdirSync33 } = requireFs();
6751
- const { dirname: dirname26, join: join55, basename: basename26 } = requirePath();
6751
+ const { readFileSync: readFileSync47, readdirSync: readdirSync33 } = requireFs();
6752
+ const { dirname: dirname26, join: join56, basename: basename26 } = requirePath();
6752
6753
  let text;
6753
6754
  try {
6754
- text = readFileSync46(sessionPath, "utf-8");
6755
+ text = readFileSync47(sessionPath, "utf-8");
6755
6756
  } catch {
6756
6757
  return null;
6757
6758
  }
@@ -6785,7 +6786,7 @@ function detectForkPredecessor(sessionPath) {
6785
6786
  if (!f.endsWith(".jsonl") || f === self || f === "sessions-index.json")
6786
6787
  continue;
6787
6788
  try {
6788
- if (readFileSync46(join55(dir, f), "utf-8").includes(`"uuid":"${headParent}"`)) {
6789
+ if (readFileSync47(join56(dir, f), "utf-8").includes(`"uuid":"${headParent}"`)) {
6789
6790
  return basename26(f, ".jsonl");
6790
6791
  }
6791
6792
  } catch {
@@ -6799,7 +6800,7 @@ function requireFs() {
6799
6800
  function requirePath() {
6800
6801
  return pathMod;
6801
6802
  }
6802
- var MARKER_QUOTE;
6803
+ var RAW_PARSE_MAX_BYTES, MARKER_QUOTE;
6803
6804
  var init_raw = __esm({
6804
6805
  "../engine/dist/transcript/raw.js"() {
6805
6806
  "use strict";
@@ -6807,6 +6808,7 @@ var init_raw = __esm({
6807
6808
  init_claude();
6808
6809
  init_codex();
6809
6810
  init_from_events();
6811
+ RAW_PARSE_MAX_BYTES = 40 * 1024 * 1024;
6810
6812
  MARKER_QUOTE = /\[REDACTED:[A-Za-z0-9_-]+\]"/g;
6811
6813
  }
6812
6814
  });
@@ -13525,6 +13527,7 @@ var init_opencode2 = __esm({
13525
13527
  // ../engine/dist/transcript/index.js
13526
13528
  var transcript_exports = {};
13527
13529
  __export(transcript_exports, {
13530
+ RAW_PARSE_MAX_BYTES: () => RAW_PARSE_MAX_BYTES,
13528
13531
  TRANSCRIPT_VERSION: () => TRANSCRIPT_VERSION,
13529
13532
  archiveRawSession: () => archiveRawSession,
13530
13533
  buildRawContainer: () => buildRawContainer,
@@ -18104,12 +18107,15 @@ var init_extractor_version = __esm({
18104
18107
  // src/sync-ledger.ts
18105
18108
  var sync_ledger_exports = {};
18106
18109
  __export(sync_ledger_exports, {
18110
+ SETTLE_QUIET_MS: () => SETTLE_QUIET_MS,
18107
18111
  _resetLedgerCacheForTests: () => _resetLedgerCacheForTests,
18108
18112
  _resetUnackedCursorCount: () => _resetUnackedCursorCount,
18109
18113
  fieldNeedsFullPass: () => fieldNeedsFullPass,
18110
18114
  fieldNeedsScan: () => fieldNeedsScan,
18111
18115
  flushLedger: () => flushLedger,
18112
18116
  forceFieldRescan: () => forceFieldRescan,
18117
+ forgetFullCoverage: () => forgetFullCoverage,
18118
+ fullCoveredOffset: () => fullCoveredOffset,
18113
18119
  getLedgerData: () => getLedgerData,
18114
18120
  getSyncedMtimes: () => getSyncedMtimes,
18115
18121
  getSyncedRows: () => getSyncedRows,
@@ -18361,6 +18367,11 @@ function markSynced(server, rows) {
18361
18367
  base3.s = s;
18362
18368
  }
18363
18369
  if (r.hash !== void 0) base3.h = r.hash;
18370
+ const completesChunked = cursorFromCaller && r.chunkFinal === true && prev?.k === 1;
18371
+ if (cursorFromCaller && (r.full || completesChunked) && o > 0) base3.F = o;
18372
+ else if (prev?.F !== void 0) base3.F = prev.F;
18373
+ if (cursorFromCaller && r.chunkedHead) base3.k = 1;
18374
+ else if (prev?.k && !completesChunked && !(cursorFromCaller && r.full)) base3.k = 1;
18364
18375
  forServer[r.id] = base3;
18365
18376
  }
18366
18377
  persist(data);
@@ -18434,6 +18445,14 @@ function _resetLedgerCacheForTests() {
18434
18445
  diskStamp = null;
18435
18446
  reconcileCache = null;
18436
18447
  }
18448
+ function forgetFullCoverage(server, sessionId) {
18449
+ const data = load();
18450
+ const row = data[server]?.[sessionId];
18451
+ if (!row || typeof row !== "object") return;
18452
+ delete row.F;
18453
+ delete row.h;
18454
+ persist(data);
18455
+ }
18437
18456
  function markFullResync(server, sessionId) {
18438
18457
  const data = load();
18439
18458
  const forServer = data[server];
@@ -18442,7 +18461,11 @@ function markFullResync(server, sessionId) {
18442
18461
  delete forServer[sessionId];
18443
18462
  persist(data);
18444
18463
  }
18445
- function syncMode(row, mtime, fileSize, extractorVersion, isAppendOnly) {
18464
+ function fullCoveredOffset(row) {
18465
+ if (row.F !== void 0) return row.F;
18466
+ return row.h ? row.s ?? 0 : 0;
18467
+ }
18468
+ function syncMode(row, mtime, fileSize, extractorVersion, isAppendOnly, nowMs = Date.now()) {
18446
18469
  if (!row) return "full";
18447
18470
  if (row.v < extractorVersion) return "full";
18448
18471
  const offset = row.o ?? 0;
@@ -18450,10 +18473,13 @@ function syncMode(row, mtime, fileSize, extractorVersion, isAppendOnly) {
18450
18473
  if (process.env.CHAT_RECALL_TAIL_APPEND !== "0" && isAppendOnly && fileSize > 0 && offset > 0 && fileSize > (row.s ?? 0)) {
18451
18474
  return "append";
18452
18475
  }
18476
+ if (isAppendOnly && offset > 0 && fileSize > 0 && fileSize === (row.s ?? 0) && !row.k && fullCoveredOffset(row) < offset && nowMs - Math.floor(mtime) >= SETTLE_QUIET_MS) {
18477
+ return "full";
18478
+ }
18453
18479
  if (row.m >= Math.floor(mtime)) return "skip";
18454
18480
  return "full";
18455
18481
  }
18456
- var ledgerPath, cache3, base, diskStamp, rowKey, LEDGER_FLUSH_MS, pendingWrite, flushTimer, itemVersionsPath, itemVersionsCache, inventoryPath, unackedCursorAttempts, reconcilePath, reconcileCache;
18482
+ var ledgerPath, cache3, base, diskStamp, rowKey, LEDGER_FLUSH_MS, pendingWrite, flushTimer, itemVersionsPath, itemVersionsCache, inventoryPath, unackedCursorAttempts, reconcilePath, reconcileCache, SETTLE_QUIET_MS;
18457
18483
  var init_sync_ledger = __esm({
18458
18484
  "src/sync-ledger.ts"() {
18459
18485
  "use strict";
@@ -18473,6 +18499,7 @@ var init_sync_ledger = __esm({
18473
18499
  unackedCursorAttempts = 0;
18474
18500
  reconcilePath = () => join39(getDataDir(), "sync-field-reconcile.json");
18475
18501
  reconcileCache = null;
18502
+ SETTLE_QUIET_MS = 2 * 60 * 60 * 1e3;
18476
18503
  }
18477
18504
  });
18478
18505
 
@@ -18615,7 +18642,7 @@ var init_http = __esm({
18615
18642
  CLI_VERSION = JSON.parse(readFileSync32(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
18616
18643
  } catch {
18617
18644
  try {
18618
- if (true) CLI_VERSION = "0.7.17";
18645
+ if (true) CLI_VERSION = "0.7.18";
18619
18646
  } catch {
18620
18647
  }
18621
18648
  }
@@ -19109,7 +19136,7 @@ var init_telemetry = __esm({
19109
19136
  init_sync_client();
19110
19137
  cliVersion = () => {
19111
19138
  try {
19112
- return true ? "0.7.17" : "dev";
19139
+ return true ? "0.7.18" : "dev";
19113
19140
  } catch {
19114
19141
  return "dev";
19115
19142
  }
@@ -19119,6 +19146,150 @@ var init_telemetry = __esm({
19119
19146
  }
19120
19147
  });
19121
19148
 
19149
+ // src/raw-archive-parts.ts
19150
+ import { createReadStream as createReadStream4, createWriteStream, openSync as openSync9, readSync as readSync8, closeSync as closeSync9, rmSync as rmSync5, statSync as statSync37 } from "node:fs";
19151
+ import { tmpdir as tmpdir2 } from "node:os";
19152
+ import { join as join41 } from "node:path";
19153
+ import { randomBytes } from "node:crypto";
19154
+ import { createGzip } from "node:zlib";
19155
+ import { once } from "node:events";
19156
+ import { readFileSync as readFileSync33 } from "node:fs";
19157
+ async function* fileLines(path) {
19158
+ let rest = "";
19159
+ const decoder = new TextDecoder("utf-8");
19160
+ for await (const chunk of createReadStream4(path, { highWaterMark: 1024 * 1024 })) {
19161
+ rest += decoder.decode(chunk, { stream: true });
19162
+ let nl = rest.indexOf("\n");
19163
+ while (nl >= 0) {
19164
+ yield rest.slice(0, nl + 1);
19165
+ rest = rest.slice(nl + 1);
19166
+ nl = rest.indexOf("\n");
19167
+ }
19168
+ }
19169
+ rest += decoder.decode();
19170
+ if (rest) yield rest;
19171
+ }
19172
+ function* textLines(text) {
19173
+ let at = 0;
19174
+ while (at < text.length) {
19175
+ const nl = text.indexOf("\n", at);
19176
+ const end = nl < 0 ? text.length : nl + 1;
19177
+ yield text.slice(at, end);
19178
+ at = end;
19179
+ }
19180
+ }
19181
+ async function writeArchiveFile(source, meta, redact, dir = tmpdir2()) {
19182
+ const path = join41(dir, `cr-archive-${randomBytes(8).toString("hex")}.json.gz`);
19183
+ const gzip = createGzip({ level: 6 });
19184
+ const out = createWriteStream(path, { mode: 384 });
19185
+ const done = once(out, "finish");
19186
+ gzip.pipe(out);
19187
+ let size = 0;
19188
+ const write = async (s) => {
19189
+ size += Buffer.byteLength(s);
19190
+ if (!gzip.write(s)) await once(gzip, "drain");
19191
+ };
19192
+ try {
19193
+ await write(`{"v":1,"tool":${JSON.stringify(meta.tool)},"mtime":${Math.floor(meta.mtime)},"files":[`);
19194
+ for (const [i, f] of source.files.entries()) {
19195
+ await write(`${i ? "," : ""}{"name":${JSON.stringify(f.name)},"text":"`);
19196
+ const whole = () => source.kind === "memory" ? f.text : readFileSync33(f.path, "utf-8");
19197
+ if (!f.name.endsWith(".jsonl")) {
19198
+ await write(escapeJson(redact(whole())));
19199
+ } else {
19200
+ const lines = source.kind === "memory" ? textLines(f.text) : fileLines(f.path);
19201
+ for await (const line of lines) {
19202
+ const nl = line.endsWith("\n");
19203
+ const body = nl ? line.slice(0, -1) : line;
19204
+ await write(escapeJson((body ? redactJsonLine(body, redact) : body) + (nl ? "\n" : "")));
19205
+ }
19206
+ }
19207
+ await write('"}');
19208
+ }
19209
+ await write("]}");
19210
+ gzip.end();
19211
+ await done;
19212
+ } catch (err) {
19213
+ gzip.destroy();
19214
+ out.destroy();
19215
+ rmSync5(path, { force: true });
19216
+ throw err;
19217
+ }
19218
+ return { path, gzSize: statSync37(path).size, size };
19219
+ }
19220
+ async function putPart(url, body) {
19221
+ let last;
19222
+ for (let attempt = 1; attempt <= PART_ATTEMPTS; attempt++) {
19223
+ const ac = new AbortController();
19224
+ const timer = setTimeout(() => ac.abort(), PART_TIMEOUT_MS);
19225
+ try {
19226
+ const r = await fetch(url, { method: "PUT", body, signal: ac.signal });
19227
+ const etag = r.headers.get("etag");
19228
+ if (r.ok && etag) return etag;
19229
+ last = new Error(`part PUT answered ${r.status}`);
19230
+ if (r.status === 403 || r.status === 404) break;
19231
+ } catch (err) {
19232
+ last = err;
19233
+ } finally {
19234
+ clearTimeout(timer);
19235
+ }
19236
+ }
19237
+ throw last instanceof Error ? last : new Error(String(last));
19238
+ }
19239
+ async function uploadArchiveFile(base3, token, args) {
19240
+ const headers = { "content-type": "application/json" };
19241
+ if (token) headers.authorization = `Bearer ${token}`;
19242
+ const post = async (path, body) => {
19243
+ const r = await fetch(`${base3}/api/sync/raw-upload/${path}`, { method: "POST", headers, body: JSON.stringify(body) });
19244
+ const json = await r.json().catch(() => ({}));
19245
+ return { status: r.status, json };
19246
+ };
19247
+ const start = await post("start", {
19248
+ session_id: args.sessionId,
19249
+ tool: args.tool,
19250
+ mtime: Math.floor(args.mtime),
19251
+ size: args.file.size,
19252
+ gz_size: args.file.gzSize,
19253
+ project_id: args.projectId,
19254
+ project_path: args.projectPath
19255
+ });
19256
+ if (start.status === 501 || start.status === 404) return "unsupported";
19257
+ if (start.status !== 200) throw new Error(`raw upload start answered ${start.status}: ${start.json.error ?? ""}`);
19258
+ if (start.json.result === "unchanged" || start.json.result === "shrink-protected") return start.json.result;
19259
+ const urls = start.json.urls;
19260
+ const partBytes = Number(start.json.part_bytes);
19261
+ const parts = [];
19262
+ const fd = openSync9(args.file.path, "r");
19263
+ try {
19264
+ for (const [i, url] of urls.entries()) {
19265
+ const len = Math.min(partBytes, args.file.gzSize - i * partBytes);
19266
+ const buf = Buffer.allocUnsafe(len);
19267
+ let got = 0;
19268
+ while (got < len) {
19269
+ const n = readSync8(fd, buf, got, len - got, i * partBytes + got);
19270
+ if (n <= 0) break;
19271
+ got += n;
19272
+ }
19273
+ parts.push({ part_number: i + 1, etag: await putPart(url, buf.subarray(0, got)) });
19274
+ }
19275
+ } finally {
19276
+ closeSync9(fd);
19277
+ }
19278
+ const done = await post("complete", { session_id: args.sessionId, upload_id: start.json.upload_id, parts });
19279
+ if (done.status !== 200) throw new Error(`raw upload complete answered ${done.status}: ${done.json.error ?? ""}`);
19280
+ return done.json.result;
19281
+ }
19282
+ var escapeJson, PART_TIMEOUT_MS, PART_ATTEMPTS;
19283
+ var init_raw_archive_parts = __esm({
19284
+ "src/raw-archive-parts.ts"() {
19285
+ "use strict";
19286
+ init_transcript();
19287
+ escapeJson = (s) => JSON.stringify(s).slice(1, -1);
19288
+ PART_TIMEOUT_MS = 12e4;
19289
+ PART_ATTEMPTS = 3;
19290
+ }
19291
+ });
19292
+
19122
19293
  // src/server-probe.ts
19123
19294
  var server_probe_exports = {};
19124
19295
  __export(server_probe_exports, {
@@ -19262,7 +19433,7 @@ __export(client_events_exports, {
19262
19433
  isTelemetryEnabled: () => isTelemetryEnabled,
19263
19434
  reportClientEvent: () => reportClientEvent
19264
19435
  });
19265
- import { readFileSync as readFileSync33 } from "node:fs";
19436
+ import { readFileSync as readFileSync34 } from "node:fs";
19266
19437
  function scrub(msg) {
19267
19438
  if (!msg) return "";
19268
19439
  const noHome = msg.replace(/\/(?:home|Users)\/[^/\s]+/g, "~");
@@ -19315,7 +19486,7 @@ var init_client_events = __esm({
19315
19486
  init_secret_redactor();
19316
19487
  CLI_VERSION2 = "0.0.0";
19317
19488
  try {
19318
- CLI_VERSION2 = JSON.parse(readFileSync33(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION2;
19489
+ CLI_VERSION2 = JSON.parse(readFileSync34(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION2;
19319
19490
  } catch {
19320
19491
  }
19321
19492
  }
@@ -19345,11 +19516,11 @@ __export(auto_update_exports, {
19345
19516
  tarballUrl: () => tarballUrl
19346
19517
  });
19347
19518
  import { execSync as execSync2, execFileSync as execFileSync3 } from "node:child_process";
19348
- import { readFileSync as readFileSync34, existsSync as existsSync41 } from "node:fs";
19519
+ import { readFileSync as readFileSync35, existsSync as existsSync41 } from "node:fs";
19349
19520
  import { fileURLToPath as fileURLToPath2 } from "node:url";
19350
- import { writeFileSync as writeFileSync8, mkdtempSync as mkdtempSync3, rmSync as rmSync5, readdirSync as readdirSync30, statSync as statSync37, mkdirSync as mkdirSync9 } from "node:fs";
19351
- import { join as join41, dirname as dirname18, sep as sep2, posix as pathPosix, win32 as pathWin32 } from "node:path";
19352
- import { tmpdir as tmpdir2, homedir as homedir15 } from "node:os";
19521
+ import { writeFileSync as writeFileSync8, mkdtempSync as mkdtempSync3, rmSync as rmSync6, readdirSync as readdirSync30, statSync as statSync38, mkdirSync as mkdirSync9 } from "node:fs";
19522
+ import { join as join42, dirname as dirname18, sep as sep2, posix as pathPosix, win32 as pathWin32 } from "node:path";
19523
+ import { tmpdir as tmpdir3, homedir as homedir15 } from "node:os";
19353
19524
  import { createHash as createHash7 } from "node:crypto";
19354
19525
  function compareVersions(a, b) {
19355
19526
  const pa = String(a).split("-")[0].split(".").map((n) => parseInt(n, 10) || 0);
@@ -19373,7 +19544,7 @@ function newerOf(a, b) {
19373
19544
  function installedVersion() {
19374
19545
  try {
19375
19546
  const here = dirname18(fileURLToPath2(import.meta.url));
19376
- const raw = readFileSync34(join41(here, "..", "package.json"), "utf-8");
19547
+ const raw = readFileSync35(join42(here, "..", "package.json"), "utf-8");
19377
19548
  return JSON.parse(raw).version || null;
19378
19549
  } catch {
19379
19550
  return null;
@@ -19386,7 +19557,7 @@ function planAutoUpdate(base3, caps, ownVersion3, flag) {
19386
19557
  if (compareVersions(rel.version, ownVersion3) <= 0) return { update: false, reason: `already current (own ${ownVersion3} >= server ${rel.version})` };
19387
19558
  return { update: true, reason: `server ${rel.version} > own ${ownVersion3}`, url: tarballUrl(base3, rel.version), fallbackUrl: tarballUrl(base3), sha256: rel.sha256, from: ownVersion3, to: rel.version };
19388
19559
  }
19389
- function sweepStaleStaging(root = tmpdir2(), now = Date.now()) {
19560
+ function sweepStaleStaging(root = tmpdir3(), now = Date.now()) {
19390
19561
  const MKDTEMP_SUFFIX = /^cr-update-.{6}$/s;
19391
19562
  const COLD_MS = 60 * 60 * 1e3;
19392
19563
  let removed = 0;
@@ -19398,13 +19569,13 @@ function sweepStaleStaging(root = tmpdir2(), now = Date.now()) {
19398
19569
  }
19399
19570
  for (const name of entries) {
19400
19571
  if (!MKDTEMP_SUFFIX.test(name)) continue;
19401
- const dir = join41(root, name);
19572
+ const dir = join42(root, name);
19402
19573
  try {
19403
- const st = statSync37(dir);
19574
+ const st = statSync38(dir);
19404
19575
  if (!st.isDirectory() || now - st.mtimeMs < COLD_MS) continue;
19405
19576
  const inside = readdirSync30(dir);
19406
19577
  if (inside.length > 1 || inside.length === 1 && inside[0] !== "chat-recall.tgz") continue;
19407
- rmSync5(dir, { recursive: true, force: true });
19578
+ rmSync6(dir, { recursive: true, force: true });
19408
19579
  removed++;
19409
19580
  } catch {
19410
19581
  }
@@ -19427,14 +19598,14 @@ async function executeAutoUpdate(plan, deps) {
19427
19598
  }
19428
19599
  const got = createHash7("sha256").update(buf).digest("hex");
19429
19600
  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` };
19430
- const dir = mkdtempSync3(join41(tmpdir2(), "cr-update-"));
19601
+ const dir = mkdtempSync3(join42(tmpdir3(), "cr-update-"));
19431
19602
  const discardStaging = () => {
19432
19603
  try {
19433
- rmSync5(dir, { recursive: true, force: true });
19604
+ rmSync6(dir, { recursive: true, force: true });
19434
19605
  } catch {
19435
19606
  }
19436
19607
  };
19437
- const tgz = join41(dir, "chat-recall.tgz");
19608
+ const tgz = join42(dir, "chat-recall.tgz");
19438
19609
  writeFileSync8(tgz, buf);
19439
19610
  if (deps.stopping?.()) {
19440
19611
  discardStaging();
@@ -19514,7 +19685,7 @@ function realInstall(tgz) {
19514
19685
  try {
19515
19686
  npmInstall(npm, ["install", "-g", tgz]);
19516
19687
  } catch {
19517
- npmInstall(npm, ["install", "-g", "--prefix", join41(homedir15(), ".local"), tgz]);
19688
+ npmInstall(npm, ["install", "-g", "--prefix", join42(homedir15(), ".local"), tgz]);
19518
19689
  }
19519
19690
  }
19520
19691
  function acquireUpdateLock() {
@@ -19531,12 +19702,12 @@ function realRestart(platform2) {
19531
19702
  if (c) execSync2(c.cmd, { stdio: "ignore", ...c.shell ? { shell: c.shell } : {} });
19532
19703
  }
19533
19704
  function updateStatePath() {
19534
- const dir = process.env.CHAT_RECALL_DATA_DIR || join41(homedir15(), ".chat-recall");
19535
- return join41(dir, "auto-update-state.json");
19705
+ const dir = process.env.CHAT_RECALL_DATA_DIR || join42(homedir15(), ".chat-recall");
19706
+ return join42(dir, "auto-update-state.json");
19536
19707
  }
19537
19708
  function readUpdateState() {
19538
19709
  try {
19539
- return JSON.parse(readFileSync34(updateStatePath(), "utf8"));
19710
+ return JSON.parse(readFileSync35(updateStatePath(), "utf8"));
19540
19711
  } catch {
19541
19712
  return {};
19542
19713
  }
@@ -19643,9 +19814,9 @@ var init_auto_update = __esm({
19643
19814
  });
19644
19815
 
19645
19816
  // src/sync-client.ts
19646
- import { join as join42, dirname as dirname19, basename as basename20 } from "node:path";
19647
- 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";
19648
- import { tmpdir as tmpdir3, hostname as hostname2 } from "node:os";
19817
+ import { join as join43, dirname as dirname19, basename as basename20 } from "node:path";
19818
+ 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";
19819
+ import { tmpdir as tmpdir4, hostname as hostname2 } from "node:os";
19649
19820
  import { createHash as createHash8 } from "node:crypto";
19650
19821
  import { fileURLToPath as fileURLToPath3 } from "node:url";
19651
19822
  import { gzipSync as gzipSync3 } from "zlib";
@@ -19681,7 +19852,7 @@ function loadAllCredentials() {
19681
19852
  const fromEnv = envCredentials();
19682
19853
  if (fromEnv) return [{ serverUrl: fromEnv.serverUrl, token: fromEnv.token }];
19683
19854
  try {
19684
- const parsed = JSON.parse(readFileSync35(credPath(), "utf-8"));
19855
+ const parsed = JSON.parse(readFileSync36(credPath(), "utf-8"));
19685
19856
  if (Array.isArray(parsed?.targets)) return parsed.targets.filter((t) => t?.serverUrl).map((t) => ({ serverUrl: t.serverUrl, token: t.token || "" }));
19686
19857
  if (parsed?.serverUrl) return [{ serverUrl: parsed.serverUrl, token: parsed.token || "" }];
19687
19858
  } catch {
@@ -19740,11 +19911,11 @@ async function fetchTenantSecurityConfig(cred) {
19740
19911
  }
19741
19912
  }
19742
19913
  function syncConfigCachePath() {
19743
- return join42(getDataDir(), "sync-config-cache.json");
19914
+ return join43(getDataDir(), "sync-config-cache.json");
19744
19915
  }
19745
19916
  function readPersistedSyncConfigs() {
19746
19917
  try {
19747
- return JSON.parse(readFileSync35(syncConfigCachePath(), "utf-8"));
19918
+ return JSON.parse(readFileSync36(syncConfigCachePath(), "utf-8"));
19748
19919
  } catch {
19749
19920
  return {};
19750
19921
  }
@@ -19987,7 +20158,7 @@ async function reconcileFieldsForTarget(cred, fullRefs, opts = {}) {
19987
20158
  }
19988
20159
  return { pushed, absent, scanned };
19989
20160
  }
19990
- function reapStaleScanDirs(dir = tmpdir3(), maxAgeMs = 6 * 36e5, now = Date.now()) {
20161
+ function reapStaleScanDirs(dir = tmpdir4(), maxAgeMs = 6 * 36e5, now = Date.now()) {
19991
20162
  let reaped = 0;
19992
20163
  let names;
19993
20164
  try {
@@ -19997,10 +20168,10 @@ function reapStaleScanDirs(dir = tmpdir3(), maxAgeMs = 6 * 36e5, now = Date.now(
19997
20168
  }
19998
20169
  for (const name of names) {
19999
20170
  if (!name.startsWith("cr-batchscan-")) continue;
20000
- const p = join42(dir, name);
20171
+ const p = join43(dir, name);
20001
20172
  try {
20002
- if (now - statSync38(p).mtimeMs < maxAgeMs) continue;
20003
- rmSync6(p, { recursive: true, force: true });
20173
+ if (now - statSync39(p).mtimeMs < maxAgeMs) continue;
20174
+ rmSync7(p, { recursive: true, force: true });
20004
20175
  reaped++;
20005
20176
  } catch {
20006
20177
  }
@@ -20014,7 +20185,7 @@ function batchScanExternal(items, opts = {}) {
20014
20185
  let scanned = 0, slices = 0, scanMs = 0;
20015
20186
  if (items.length === 0) return { findings, scanned, slices, scanMs };
20016
20187
  reapStaleScanDirs();
20017
- let scanDir = mkdtempSync4(join42(tmpdir3(), "cr-batchscan-"));
20188
+ let scanDir = mkdtempSync4(join43(tmpdir4(), "cr-batchscan-"));
20018
20189
  let safeToId = /* @__PURE__ */ new Map();
20019
20190
  let bytesInDir = 0;
20020
20191
  const flushSlice = () => {
@@ -20032,7 +20203,7 @@ function batchScanExternal(items, opts = {}) {
20032
20203
  slices++;
20033
20204
  }
20034
20205
  try {
20035
- rmSync6(scanDir, { recursive: true, force: true });
20206
+ rmSync7(scanDir, { recursive: true, force: true });
20036
20207
  } catch {
20037
20208
  }
20038
20209
  safeToId = /* @__PURE__ */ new Map();
@@ -20045,19 +20216,19 @@ function batchScanExternal(items, opts = {}) {
20045
20216
  if (raw === null) continue;
20046
20217
  const safe = item.id.replace(/[^A-Za-z0-9_-]/g, "");
20047
20218
  safeToId.set(safe, item.id);
20048
- writeFileSync9(join42(scanDir, `${safe}.txt`), raw);
20219
+ writeFileSync9(join43(scanDir, `${safe}.txt`), raw);
20049
20220
  bytesInDir += Buffer.byteLength(raw);
20050
20221
  } catch {
20051
20222
  }
20052
20223
  if (bytesInDir >= maxBytes) {
20053
20224
  flushSlice();
20054
- scanDir = mkdtempSync4(join42(tmpdir3(), "cr-batchscan-"));
20225
+ scanDir = mkdtempSync4(join43(tmpdir4(), "cr-batchscan-"));
20055
20226
  }
20056
20227
  }
20057
20228
  flushSlice();
20058
20229
  } finally {
20059
20230
  try {
20060
- rmSync6(scanDir, { recursive: true, force: true });
20231
+ rmSync7(scanDir, { recursive: true, force: true });
20061
20232
  } catch {
20062
20233
  }
20063
20234
  }
@@ -20296,12 +20467,13 @@ async function syncToTargetInScope(cred, opts = {}) {
20296
20467
  markSynced(base3, rows.map((r) => {
20297
20468
  const off = typeof r.from_offset === "number" ? r.from_offset : 0;
20298
20469
  const hash = shippedHash.get(r.session_id);
20299
- 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 };
20470
+ 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 };
20300
20471
  }));
20301
20472
  } catch {
20302
20473
  }
20303
20474
  });
20304
20475
  const appendResults = { uploaded: 0, fullResyncNeeded: /* @__PURE__ */ new Set() };
20476
+ const pendingArchives = [];
20305
20477
  const postAppend = async (convs) => {
20306
20478
  const headers = { "content-type": "application/json" };
20307
20479
  if (cred.token) headers.authorization = `Bearer ${cred.token}`;
@@ -20336,8 +20508,10 @@ async function syncToTargetInScope(cred, opts = {}) {
20336
20508
  offset: c.from_offset,
20337
20509
  size: c.from_offset,
20338
20510
  // size = new offset (file grew to here)
20339
- acked: true
20511
+ acked: true,
20340
20512
  // server merged this tail
20513
+ chunkFinal: c.final === true
20514
+ // completes a chunked full sync
20341
20515
  })));
20342
20516
  } catch {
20343
20517
  }
@@ -20369,9 +20543,9 @@ async function syncToTargetInScope(cred, opts = {}) {
20369
20543
  const mtime = conv.mtime;
20370
20544
  try {
20371
20545
  if (staged || !guarded) {
20372
- markSynced(base3, [{ id, mtime, offset: conv.from_offset, size: conv.from_offset, acked: true }]);
20546
+ markSynced(base3, [{ id, mtime, offset: conv.from_offset, size: conv.from_offset, acked: true, chunkedHead: true }]);
20373
20547
  } else if (typeof guarded.o === "number" && guarded.o > 0 && guarded.o <= fileSize) {
20374
- markSynced(base3, [{ id, mtime, offset: guarded.o, size: guarded.o, acked: true }]);
20548
+ markSynced(base3, [{ id, mtime, offset: guarded.o, size: guarded.o, acked: true, chunkedHead: true }]);
20375
20549
  } else {
20376
20550
  markSynced(base3, [{ id, mtime }]);
20377
20551
  }
@@ -20580,6 +20754,14 @@ async function syncToTargetInScope(cred, opts = {}) {
20580
20754
  if (built.srcHash) shippedHash.set(ref.prefixedId, built.srcHash);
20581
20755
  if (built.conv.chunked) await postChunkedHead(built.conv, sessionFileBytes(ref));
20582
20756
  else await convBatch.add(built.conv);
20757
+ if (built.archive) {
20758
+ pendingArchives.push({
20759
+ id: ref.prefixedId,
20760
+ ...built.archive,
20761
+ projectId: built.conv.project_id,
20762
+ projectPath: built.conv.project_path
20763
+ });
20764
+ }
20583
20765
  if (built.findings.length > 0) await findingsBatch.add(built.findings);
20584
20766
  if (upload.sessionMeta) {
20585
20767
  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);
@@ -20732,6 +20914,30 @@ async function syncToTargetInScope(cred, opts = {}) {
20732
20914
  await kgTripleBatch.drain();
20733
20915
  await findingsBatch.drain();
20734
20916
  await drainInflight();
20917
+ let archivesUnsupported = false;
20918
+ for (const a of pendingArchives) {
20919
+ try {
20920
+ if (!archivesUnsupported) {
20921
+ const r = await uploadArchiveFile(base3, cred.token, {
20922
+ sessionId: a.id,
20923
+ tool: a.tool,
20924
+ mtime: a.mtime,
20925
+ projectId: a.projectId,
20926
+ projectPath: a.projectPath,
20927
+ file: a.file
20928
+ });
20929
+ if (r === "unsupported") archivesUnsupported = true;
20930
+ }
20931
+ } catch (err) {
20932
+ console.error(`[sync] raw archive for ${a.id} not uploaded (tried again when the session is next quiet): ${err instanceof Error ? err.message : err}`);
20933
+ try {
20934
+ forgetFullCoverage(base3, a.id);
20935
+ } catch {
20936
+ }
20937
+ } finally {
20938
+ rmSync7(a.file.path, { force: true });
20939
+ }
20940
+ }
20735
20941
  {
20736
20942
  const sentHashes = loadInventoryHashes(base3);
20737
20943
  const entries = [];
@@ -20837,6 +21043,7 @@ async function buildConversationSync(ref, mtime, opts = {}) {
20837
21043
  let includeRaw = opts.includeRaw !== false;
20838
21044
  let includeMeta = opts.includeMeta !== false;
20839
21045
  let srcHash;
21046
+ const wantRaw = opts.includeRaw !== false;
20840
21047
  const oversized = sessionBuildBytes(ref) > FULL_BUILD_MAX_BYTES;
20841
21048
  let headOffsetEnd = 0;
20842
21049
  let oversizedFindings = null;
@@ -21005,7 +21212,7 @@ async function buildConversationSync(ref, mtime, opts = {}) {
21005
21212
  } else if (opts.scanSecrets) {
21006
21213
  let tmp = null;
21007
21214
  try {
21008
- tmp = join42(tmpdir3(), `cr-scan-${ref.prefixedId.replace(/[^A-Za-z0-9_-]/g, "")}-${mtime}.txt`);
21215
+ tmp = join43(tmpdir4(), `cr-scan-${ref.prefixedId.replace(/[^A-Za-z0-9_-]/g, "")}-${mtime}.txt`);
21009
21216
  writeFileSync9(tmp, rawText);
21010
21217
  for (const f of scanFileForSecrets(tmp, { verifyOnly: opts.verifySecrets, tenantRules: opts.tenantRules })) {
21011
21218
  const verifiedAt = f.verified ? (/* @__PURE__ */ new Date()).toISOString() : null;
@@ -21057,6 +21264,25 @@ async function buildConversationSync(ref, mtime, opts = {}) {
21057
21264
  }
21058
21265
  const envTexts = envelope.messages.filter((m) => m.content?.trim());
21059
21266
  const redactedText = envTexts.map((m) => m.content).join("\n");
21267
+ let archive;
21268
+ if (wantRaw && !raw_b64) {
21269
+ try {
21270
+ const redact = (t) => redactSecrets(t, { force: true, count });
21271
+ let source = null;
21272
+ let archiveMtime = Math.floor(ref.mtime) || 0;
21273
+ let archiveTool = ref.toolId;
21274
+ if (container) {
21275
+ source = { kind: "memory", files: container.files };
21276
+ archiveMtime = container.mtime;
21277
+ archiveTool = container.tool;
21278
+ } else if (oversized) {
21279
+ source = diskArchiveSource(ref);
21280
+ }
21281
+ if (source) archive = { file: await writeArchiveFile(source, { tool: archiveTool, mtime: archiveMtime }, redact), tool: archiveTool, mtime: archiveMtime };
21282
+ } catch (err) {
21283
+ console.error(`[sync] raw archive for ${ref.prefixedId} not written: ${err instanceof Error ? err.message : err}`);
21284
+ }
21285
+ }
21060
21286
  return {
21061
21287
  conv: {
21062
21288
  session_id: ref.prefixedId,
@@ -21088,7 +21314,17 @@ async function buildConversationSync(ref, mtime, opts = {}) {
21088
21314
  redactions: count.redactions,
21089
21315
  findings,
21090
21316
  scanMs,
21091
- srcHash
21317
+ srcHash,
21318
+ archive
21319
+ };
21320
+ }
21321
+ function diskArchiveSource(ref) {
21322
+ if (ref.toolId !== "claude") return null;
21323
+ const groups = resolveSessionContentGroups(ref.rawId);
21324
+ if (groups.length === 0 || groups.some((g) => g.paths.length !== 1)) return null;
21325
+ return {
21326
+ kind: "disk",
21327
+ files: groups.map((g) => ({ name: g.name === "main" ? `${ref.rawId}.jsonl` : g.name, path: g.paths[0] }))
21092
21328
  };
21093
21329
  }
21094
21330
  function parseTailMessages(tool, text) {
@@ -21244,14 +21480,15 @@ var init_sync_client = __esm({
21244
21480
  init_telemetry();
21245
21481
  init_collector_health();
21246
21482
  init_live_session_scan();
21483
+ init_raw_archive_parts();
21247
21484
  init_backends();
21248
21485
  ownVersion = "0.0.0";
21249
21486
  try {
21250
21487
  const dir = dirname19(fileURLToPath3(import.meta.url));
21251
- ownVersion = JSON.parse(readFileSync35(join42(dir, "../package.json"), "utf-8")).version || ownVersion;
21488
+ ownVersion = JSON.parse(readFileSync36(join43(dir, "../package.json"), "utf-8")).version || ownVersion;
21252
21489
  } catch {
21253
21490
  try {
21254
- if (true) ownVersion = "0.7.17";
21491
+ if (true) ownVersion = "0.7.18";
21255
21492
  } catch {
21256
21493
  }
21257
21494
  }
@@ -21263,7 +21500,7 @@ var init_sync_client = __esm({
21263
21500
  ]);
21264
21501
  walkProgressForUpload = null;
21265
21502
  lastServerPackSpec = null;
21266
- credPath = () => join42(getDataDir(), "credentials.json");
21503
+ credPath = () => join43(getDataDir(), "credentials.json");
21267
21504
  _securityConfigCache = /* @__PURE__ */ new Map();
21268
21505
  SECURITY_CONFIG_TTL_MS = 5 * 60 * 1e3;
21269
21506
  _syncConfigCache = /* @__PURE__ */ new Map();
@@ -21286,8 +21523,8 @@ var init_sync_client = __esm({
21286
21523
  });
21287
21524
 
21288
21525
  // ../engine/dist/core/artifact-codec.js
21289
- import { readFileSync as readFileSync36 } from "fs";
21290
- import { basename as basename21, join as join43 } from "path";
21526
+ import { readFileSync as readFileSync37 } from "fs";
21527
+ import { basename as basename21, join as join44 } from "path";
21291
21528
  import { homedir as homedir16 } from "os";
21292
21529
  function parseCommandText(content, format, fallbackName) {
21293
21530
  if (format === "toml") {
@@ -21310,41 +21547,41 @@ function parseAgentText(content, format, fallbackName) {
21310
21547
  return { name: fm.name || fallbackName, description: fm.description || "", tools: fm.tools, body: body.trim() };
21311
21548
  }
21312
21549
  function readCommand(filePath, format) {
21313
- return parseCommandText(readFileSync36(filePath, "utf-8"), format, base2(filePath));
21550
+ return parseCommandText(readFileSync37(filePath, "utf-8"), format, base2(filePath));
21314
21551
  }
21315
21552
  function readAgent(filePath, format) {
21316
- return parseAgentText(readFileSync36(filePath, "utf-8"), format, base2(filePath));
21553
+ return parseAgentText(readFileSync37(filePath, "utf-8"), format, base2(filePath));
21317
21554
  }
21318
21555
  function readInstructions(filePath, name) {
21319
- const content = readFileSync36(filePath, "utf-8");
21556
+ const content = readFileSync37(filePath, "utf-8");
21320
21557
  return { name, description: "", body: content };
21321
21558
  }
21322
21559
  function commandPath(tool, name) {
21323
21560
  switch (tool) {
21324
21561
  case "claude":
21325
- return join43(claudeBackend.commandsDir(), `${name}.md`);
21562
+ return join44(claudeBackend.commandsDir(), `${name}.md`);
21326
21563
  case "agy":
21327
- return join43(join43(agyBackend.homeDir(), "commands"), `${name}.toml`);
21564
+ return join44(join44(agyBackend.homeDir(), "commands"), `${name}.toml`);
21328
21565
  case "opencode":
21329
- return join43(opencodeBackend.commandsDir(), `${name}.md`);
21566
+ return join44(opencodeBackend.commandsDir(), `${name}.md`);
21330
21567
  case "codex":
21331
- return join43(codexBackend.promptsDir(), `${name}.md`);
21568
+ return join44(codexBackend.promptsDir(), `${name}.md`);
21332
21569
  case "cursor":
21333
- return join43(cursorHomeDir(), "commands", `${name}.md`);
21570
+ return join44(cursorHomeDir(), "commands", `${name}.md`);
21334
21571
  }
21335
21572
  }
21336
21573
  function agentPath(tool, name) {
21337
21574
  switch (tool) {
21338
21575
  case "claude":
21339
- return join43(claudeBackend.agentsDir(), `${name}.md`);
21576
+ return join44(claudeBackend.agentsDir(), `${name}.md`);
21340
21577
  case "agy":
21341
- return join43(join43(agyBackend.homeDir(), "agents"), `${name}.md`);
21578
+ return join44(join44(agyBackend.homeDir(), "agents"), `${name}.md`);
21342
21579
  case "opencode":
21343
- return join43(opencodeBackend.agentsDir(), `${name}.md`);
21580
+ return join44(opencodeBackend.agentsDir(), `${name}.md`);
21344
21581
  case "codex":
21345
- return join43(codexBackend.agentsDir(), `${name}.toml`);
21582
+ return join44(codexBackend.agentsDir(), `${name}.toml`);
21346
21583
  case "cursor":
21347
- return join43(cursorHomeDir(), "agents", `${name}.md`);
21584
+ return join44(cursorHomeDir(), "agents", `${name}.md`);
21348
21585
  }
21349
21586
  }
21350
21587
  function instructionsFilename(tool) {
@@ -21369,21 +21606,21 @@ function instructionsFilename(tool) {
21369
21606
  function instructionsPath(tool, projectPath) {
21370
21607
  const file = instructionsFilename(tool);
21371
21608
  if (projectPath)
21372
- return join43(projectPath, file);
21609
+ return join44(projectPath, file);
21373
21610
  switch (tool) {
21374
21611
  case "claude":
21375
- return join43(claudeBackend.homeDir(), file);
21612
+ return join44(claudeBackend.homeDir(), file);
21376
21613
  case "agy":
21377
- return join43(agyBackend.homeDir(), file);
21614
+ return join44(agyBackend.homeDir(), file);
21378
21615
  case "codex":
21379
- return join43(codexBackend.homeDir(), file);
21616
+ return join44(codexBackend.homeDir(), file);
21380
21617
  case "opencode":
21381
- return join43(homedir16(), ".config", "opencode", file);
21618
+ return join44(homedir16(), ".config", "opencode", file);
21382
21619
  // Cursor has no single user-scope instructions FILE — user-level guidance
21383
21620
  // is User Rules plus ~/.cursor/rules/*.mdc. AGENTS.md at the home root is
21384
21621
  // the closest equivalent and is what a mirror can actually write.
21385
21622
  case "cursor":
21386
- return join43(cursorHomeDir(), file);
21623
+ return join44(cursorHomeDir(), file);
21387
21624
  }
21388
21625
  }
21389
21626
  function emit(type, art, toTool, projectPath) {
@@ -21429,8 +21666,8 @@ var init_artifact_codec = __esm({
21429
21666
  });
21430
21667
 
21431
21668
  // ../engine/dist/core/toolkit-sync.js
21432
- import { existsSync as existsSync42, mkdirSync as mkdirSync11, readFileSync as readFileSync37, writeFileSync as writeFileSync10, cpSync } from "fs";
21433
- import { dirname as dirname20, join as join44, basename as basename22 } from "path";
21669
+ import { existsSync as existsSync42, mkdirSync as mkdirSync11, readFileSync as readFileSync38, writeFileSync as writeFileSync10, cpSync } from "fs";
21670
+ import { dirname as dirname20, join as join45, basename as basename22 } from "path";
21434
21671
  import { homedir as homedir17 } from "os";
21435
21672
  function rowFromMemoryItem(type, item) {
21436
21673
  const extra = item.extra || {};
@@ -21451,14 +21688,14 @@ function skillsDirFor(tool) {
21451
21688
  case "claude":
21452
21689
  return claudeBackend.skillsDir();
21453
21690
  case "agy":
21454
- return join44(agyBackend.homeDir(), "skills");
21691
+ return join45(agyBackend.homeDir(), "skills");
21455
21692
  case "opencode":
21456
21693
  return opencodeBackend.skillsDir();
21457
21694
  case "codex":
21458
21695
  return codexBackend.skillsDir();
21459
21696
  // user skills, NOT .system
21460
21697
  case "cursor":
21461
- return join44(cursorHomeDir(), "skills");
21698
+ return join45(cursorHomeDir(), "skills");
21462
21699
  }
21463
21700
  }
21464
21701
  function copySkill(row, toTool) {
@@ -21466,7 +21703,7 @@ function copySkill(row, toTool) {
21466
21703
  if (!existsSync42(skillDir))
21467
21704
  return { ok: false, status: 404, error: `Source dir missing: ${skillDir}` };
21468
21705
  const name = row.extra.skillName || basename22(skillDir);
21469
- const targetDir = join44(skillsDirFor(toTool), name);
21706
+ const targetDir = join45(skillsDirFor(toTool), name);
21470
21707
  if (existsSync42(targetDir))
21471
21708
  return { ok: false, status: 409, error: `Already exists: ${targetDir}` };
21472
21709
  try {
@@ -21481,20 +21718,20 @@ function readMcpEntry(tool, name) {
21481
21718
  const home = homedir17();
21482
21719
  const tries = [];
21483
21720
  if (tool === "claude") {
21484
- tries.push({ path: join44(home, ".mcp.json"), key: "mcpServers" });
21485
- tries.push({ path: join44(home, ".claude.json"), key: "mcpServers" });
21721
+ tries.push({ path: join45(home, ".mcp.json"), key: "mcpServers" });
21722
+ tries.push({ path: join45(home, ".claude.json"), key: "mcpServers" });
21486
21723
  } else if (tool === "gemini") {
21487
- tries.push({ path: join44(home, ".gemini", "settings.json"), key: "mcpServers" });
21724
+ tries.push({ path: join45(home, ".gemini", "settings.json"), key: "mcpServers" });
21488
21725
  } else if (tool === "agy") {
21489
- tries.push({ path: join44(home, ".gemini", "config", "mcp_config.json"), key: "mcpServers" });
21726
+ tries.push({ path: join45(home, ".gemini", "config", "mcp_config.json"), key: "mcpServers" });
21490
21727
  } else if (tool === "cursor") {
21491
- tries.push({ path: join44(cursorHomeDir(), "mcp.json"), key: "mcpServers" });
21728
+ tries.push({ path: join45(cursorHomeDir(), "mcp.json"), key: "mcpServers" });
21492
21729
  } else if (tool === "opencode") {
21493
- tries.push({ path: join44(home, ".config", "opencode", "opencode.json"), key: "mcp" });
21494
- tries.push({ path: join44(home, ".config", "opencode", "config.json"), key: "mcp" });
21495
- tries.push({ path: join44(home, ".opencode", "config.json"), key: "mcp" });
21730
+ tries.push({ path: join45(home, ".config", "opencode", "opencode.json"), key: "mcp" });
21731
+ tries.push({ path: join45(home, ".config", "opencode", "config.json"), key: "mcp" });
21732
+ tries.push({ path: join45(home, ".opencode", "config.json"), key: "mcp" });
21496
21733
  } else if (tool === "codex") {
21497
- const entry = readCodexMcpEntry(join44(home, ".codex", "config.toml"), name);
21734
+ const entry = readCodexMcpEntry(join45(home, ".codex", "config.toml"), name);
21498
21735
  if (entry)
21499
21736
  return entry;
21500
21737
  }
@@ -21502,7 +21739,7 @@ function readMcpEntry(tool, name) {
21502
21739
  if (!existsSync42(t.path))
21503
21740
  continue;
21504
21741
  try {
21505
- const cfg = JSON.parse(readFileSync37(t.path, "utf-8"));
21742
+ const cfg = JSON.parse(readFileSync38(t.path, "utf-8"));
21506
21743
  const block = cfg[t.key] || {};
21507
21744
  if (block[name])
21508
21745
  return block[name];
@@ -21516,7 +21753,7 @@ function readCodexMcpEntry(path, target) {
21516
21753
  return null;
21517
21754
  let content;
21518
21755
  try {
21519
- content = readFileSync37(path, "utf-8");
21756
+ content = readFileSync38(path, "utf-8");
21520
21757
  } catch {
21521
21758
  return null;
21522
21759
  }
@@ -21567,7 +21804,7 @@ function readCodexMcpEntry(path, target) {
21567
21804
  function writeCodexMcpEntry(path, name, entry) {
21568
21805
  let content = "";
21569
21806
  if (existsSync42(path))
21570
- content = readFileSync37(path, "utf-8");
21807
+ content = readFileSync38(path, "utf-8");
21571
21808
  const header = `[mcp_servers.${name}]`;
21572
21809
  if (content.includes(header))
21573
21810
  return false;
@@ -21603,7 +21840,7 @@ function writeCodexMcpEntry(path, name, entry) {
21603
21840
  function writeMcpEntry(toTool, name, entry) {
21604
21841
  const home = homedir17();
21605
21842
  if (toTool === "codex") {
21606
- const path2 = join44(home, ".codex", "config.toml");
21843
+ const path2 = join45(home, ".codex", "config.toml");
21607
21844
  if (!writeCodexMcpEntry(path2, name, entry))
21608
21845
  return { ok: false, status: 409, error: `MCP "${name}" already exists in ${path2}.` };
21609
21846
  return { ok: true, targetPath: path2 };
@@ -21611,22 +21848,22 @@ function writeMcpEntry(toTool, name, entry) {
21611
21848
  let path;
21612
21849
  let key2;
21613
21850
  if (toTool === "claude") {
21614
- path = join44(home, ".mcp.json");
21851
+ path = join45(home, ".mcp.json");
21615
21852
  key2 = "mcpServers";
21616
21853
  } else if (toTool === "agy") {
21617
- path = join44(home, ".gemini", "config", "mcp_config.json");
21854
+ path = join45(home, ".gemini", "config", "mcp_config.json");
21618
21855
  key2 = "mcpServers";
21619
21856
  } else if (toTool === "cursor") {
21620
- path = join44(cursorHomeDir(), "mcp.json");
21857
+ path = join45(cursorHomeDir(), "mcp.json");
21621
21858
  key2 = "mcpServers";
21622
21859
  } else {
21623
- path = join44(home, ".config", "opencode", "opencode.json");
21860
+ path = join45(home, ".config", "opencode", "opencode.json");
21624
21861
  key2 = "mcp";
21625
21862
  }
21626
21863
  let cfg = {};
21627
21864
  if (existsSync42(path)) {
21628
21865
  try {
21629
- cfg = JSON.parse(readFileSync37(path, "utf-8"));
21866
+ cfg = JSON.parse(readFileSync38(path, "utf-8"));
21630
21867
  } catch {
21631
21868
  return { ok: false, status: 500, error: `Target config is malformed: ${path}` };
21632
21869
  }
@@ -21851,11 +22088,11 @@ var init_toolkit_sync = __esm({
21851
22088
  });
21852
22089
 
21853
22090
  // ../engine/dist/core/which.js
21854
- import { existsSync as existsSync44, statSync as statSync40, accessSync, constants } from "node:fs";
21855
- import { join as join46, isAbsolute as isAbsolute2, delimiter as delimiter2, sep as sep3 } from "node:path";
22091
+ import { existsSync as existsSync44, statSync as statSync41, accessSync, constants } from "node:fs";
22092
+ import { join as join47, isAbsolute as isAbsolute2, delimiter as delimiter2, sep as sep3 } from "node:path";
21856
22093
  function executable(p) {
21857
22094
  try {
21858
- if (!statSync40(p).isFile())
22095
+ if (!statSync41(p).isFile())
21859
22096
  return false;
21860
22097
  } catch {
21861
22098
  return false;
@@ -21891,7 +22128,7 @@ function resolveOnPath(name) {
21891
22128
  if (!dir)
21892
22129
  continue;
21893
22130
  for (const c of candidates(name)) {
21894
- const full = join46(dir, c);
22131
+ const full = join47(dir, c);
21895
22132
  if (existsSync44(full) && executable(full))
21896
22133
  return full;
21897
22134
  }
@@ -21918,11 +22155,11 @@ __export(toolkit_pull_exports, {
21918
22155
  platformRefusal: () => platformRefusal,
21919
22156
  portableCommand: () => portableCommand
21920
22157
  });
21921
- import { existsSync as existsSync45, mkdirSync as mkdirSync13, statSync as statSync41, writeFileSync as writeFileSync12 } from "node:fs";
21922
- import { dirname as dirname22, join as join47, basename as basename23, isAbsolute as isAbsolute3 } from "node:path";
22158
+ import { existsSync as existsSync45, mkdirSync as mkdirSync13, statSync as statSync42, writeFileSync as writeFileSync12 } from "node:fs";
22159
+ import { dirname as dirname22, join as join48, basename as basename23, isAbsolute as isAbsolute3 } from "node:path";
21923
22160
  function isExecutableFile(p) {
21924
22161
  try {
21925
- return statSync41(p).isFile();
22162
+ return statSync42(p).isFile();
21926
22163
  } catch {
21927
22164
  return false;
21928
22165
  }
@@ -22089,8 +22326,8 @@ function executePull(rows, opts = {}) {
22089
22326
  const outcomes = [];
22090
22327
  for (const { name, body, truncated, redacted, tools } of skills) {
22091
22328
  for (const tool of tools) {
22092
- const dir = join47(skillsDirFor(tool), name);
22093
- const file = join47(dir, "SKILL.md");
22329
+ const dir = join48(skillsDirFor(tool), name);
22330
+ const file = join48(dir, "SKILL.md");
22094
22331
  if (existsSync45(file)) {
22095
22332
  outcomes.push({ type: "skill", name, tool, status: "present" });
22096
22333
  continue;
@@ -22423,11 +22660,16 @@ async function repairAll(opts = {}) {
22423
22660
  scanned++;
22424
22661
  if (opts.verbose && scanned % 50 === 0) log6(`checked ${scanned}/${ids.length}\u2026`);
22425
22662
  const arch = await fetchJson(`${primary.url}/api/conversations/${id}/raw-archive?count=1`, primary.token);
22426
- const archiveMsgs = typeof arch?.messages === "number" ? arch.messages : 0;
22427
- if (archiveMsgs < minMessages) continue;
22428
- const meta = await fetchJson(`${primary.url}/api/conversations/${id}/metadata`, primary.token);
22429
- const current = typeof meta?.messageCount === "number" ? meta.messageCount : 0;
22430
- if (archiveMsgs <= current) continue;
22663
+ const counted = arch && arch.messages !== null;
22664
+ if (counted) {
22665
+ const archiveMsgs = typeof arch?.messages === "number" ? arch.messages : 0;
22666
+ if (archiveMsgs < minMessages) continue;
22667
+ const meta = await fetchJson(`${primary.url}/api/conversations/${id}/metadata`, primary.token);
22668
+ const current = typeof meta?.messageCount === "number" ? meta.messageCount : 0;
22669
+ if (archiveMsgs <= current) continue;
22670
+ } else if (!arch) {
22671
+ continue;
22672
+ }
22431
22673
  const r = await repairSession(id, { dryRun: !opts.apply, verbose: opts.verbose, server: opts.server });
22432
22674
  if (r.status === "already-full") continue;
22433
22675
  candidates2.push(r);
@@ -22455,8 +22697,8 @@ __export(shadow_prune_exports, {
22455
22697
  DEFAULT_MAX_TOTAL_BYTES: () => DEFAULT_MAX_TOTAL_BYTES,
22456
22698
  pruneShadow: () => pruneShadow
22457
22699
  });
22458
- import { readdirSync as readdirSync32, statSync as statSync44, unlinkSync as unlinkSync3 } from "fs";
22459
- import { join as join50 } from "path";
22700
+ import { readdirSync as readdirSync32, statSync as statSync45, unlinkSync as unlinkSync3 } from "fs";
22701
+ import { join as join51 } from "path";
22460
22702
  function listShadows(isFullyAcked) {
22461
22703
  const out = [];
22462
22704
  const root = shadowRoot();
@@ -22467,7 +22709,7 @@ function listShadows(isFullyAcked) {
22467
22709
  return out;
22468
22710
  }
22469
22711
  for (const tool of tools) {
22470
- const dir = join50(root, tool);
22712
+ const dir = join51(root, tool);
22471
22713
  let names;
22472
22714
  try {
22473
22715
  names = readdirSync32(dir);
@@ -22477,10 +22719,10 @@ function listShadows(isFullyAcked) {
22477
22719
  for (const name of names) {
22478
22720
  if (!name.endsWith(".gz"))
22479
22721
  continue;
22480
- const path = join50(dir, name);
22722
+ const path = join51(dir, name);
22481
22723
  let st;
22482
22724
  try {
22483
- st = statSync44(path);
22725
+ st = statSync45(path);
22484
22726
  } catch {
22485
22727
  continue;
22486
22728
  }
@@ -22595,9 +22837,9 @@ var init_code_intel = __esm({
22595
22837
  });
22596
22838
 
22597
22839
  // ../engine/dist/core/companions.js
22598
- import { existsSync as existsSync48, mkdirSync as mkdirSync16, statSync as statSync45, chmodSync as chmodSync4, unlinkSync as unlinkSync4, renameSync as renameSync5, createWriteStream, readFileSync as readFileSync42, writeFileSync as writeFileSync15 } from "node:fs";
22840
+ import { existsSync as existsSync48, mkdirSync as mkdirSync16, statSync as statSync46, chmodSync as chmodSync4, unlinkSync as unlinkSync4, renameSync as renameSync5, createWriteStream as createWriteStream2, readFileSync as readFileSync43, writeFileSync as writeFileSync15 } from "node:fs";
22599
22841
  import { homedir as homedir19 } from "node:os";
22600
- import { join as join51 } from "node:path";
22842
+ import { join as join52 } from "node:path";
22601
22843
  import { execSync as execSync3 } from "node:child_process";
22602
22844
  import { createHash as createHash13 } from "node:crypto";
22603
22845
  function expectedCodeindexSha256(artifact) {
@@ -22646,7 +22888,7 @@ function checkCodeindexStatus() {
22646
22888
  status.installed = true;
22647
22889
  status.path = foundPath;
22648
22890
  try {
22649
- status.size = statSync45(foundPath).size;
22891
+ status.size = statSync46(foundPath).size;
22650
22892
  } catch {
22651
22893
  }
22652
22894
  try {
@@ -22672,7 +22914,7 @@ async function downloadArtifact(artifact, dest) {
22672
22914
  throw new Error(`Download failed: ${res.status} ${res.statusText}`);
22673
22915
  if (!res.body)
22674
22916
  throw new Error("Download returned empty body");
22675
- const file = createWriteStream(dest);
22917
+ const file = createWriteStream2(dest);
22676
22918
  await new Promise((resolve3, reject) => {
22677
22919
  const reader = res.body.getReader();
22678
22920
  const pump = async () => {
@@ -22707,7 +22949,7 @@ async function installCodeindex(opts = {}) {
22707
22949
  if (!expected) {
22708
22950
  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.`);
22709
22951
  }
22710
- const actual = createHash13("sha256").update(readFileSync42(tmpPath)).digest("hex");
22952
+ const actual = createHash13("sha256").update(readFileSync43(tmpPath)).digest("hex");
22711
22953
  if (actual !== expected) {
22712
22954
  throw new Error(`Checksum mismatch for ${status.artifactName}.
22713
22955
  expected ${expected}
@@ -22741,9 +22983,9 @@ var init_companions = __esm({
22741
22983
  "x86_64-windows": "a96fc8c8949bb399a44cc0615b12e458460a529c69f01e8829cc39a20f45ab29",
22742
22984
  "aarch64-windows": "42620d56272cd9ba9d785569d8d754d6b4a3e80f36f28db3e0c483fd600ed117"
22743
22985
  };
22744
- CODEINDEX_INSTALL_DIR = join51(homedir19(), ".local", "bin");
22986
+ CODEINDEX_INSTALL_DIR = join52(homedir19(), ".local", "bin");
22745
22987
  CODEINDEX_BIN_NAME = process.platform === "win32" ? "codeindex.exe" : "codeindex";
22746
- CODEINDEX_BIN_PATH = join51(CODEINDEX_INSTALL_DIR, CODEINDEX_BIN_NAME);
22988
+ CODEINDEX_BIN_PATH = join52(CODEINDEX_INSTALL_DIR, CODEINDEX_BIN_NAME);
22747
22989
  }
22748
22990
  });
22749
22991
 
@@ -22858,8 +23100,8 @@ __export(collector_exports, {
22858
23100
  });
22859
23101
  import { spawn as spawn2 } from "node:child_process";
22860
23102
  import { execSync as execSync4 } from "node:child_process";
22861
- import { readFileSync as readFileSync43 } from "node:fs";
22862
- import { join as join52, basename as basename24 } from "node:path";
23103
+ import { readFileSync as readFileSync44 } from "node:fs";
23104
+ import { join as join53, basename as basename24 } from "node:path";
22863
23105
  async function resolveCodeindexBin(autoInstall = true) {
22864
23106
  let st = checkCodeindexStatus();
22865
23107
  if (!st.installed && autoInstall)
@@ -23041,7 +23283,7 @@ async function collectCode(opts) {
23041
23283
  }
23042
23284
  const complexity = (r) => {
23043
23285
  try {
23044
- const txt = readFileSync43(join52(ws, r), "utf8");
23286
+ const txt = readFileSync44(join53(ws, r), "utf8");
23045
23287
  if (txt.length > 2e6)
23046
23288
  return 1;
23047
23289
  const m = txt.match(CF_RE);
@@ -23805,15 +24047,15 @@ __export(service_installer_exports, {
23805
24047
  uninstallService: () => uninstallService
23806
24048
  });
23807
24049
  import { execSync as execSync5 } from "child_process";
23808
- import { existsSync as existsSync49, mkdirSync as mkdirSync17, readFileSync as readFileSync44, rmSync as rmSync7, writeFileSync as writeFileSync16 } from "fs";
24050
+ import { existsSync as existsSync49, mkdirSync as mkdirSync17, readFileSync as readFileSync45, rmSync as rmSync8, writeFileSync as writeFileSync16 } from "fs";
23809
24051
  import { homedir as homedir20 } from "os";
23810
- import { join as join53 } from "path";
24052
+ import { join as join54 } from "path";
23811
24053
  import { fileURLToPath as fileURLToPath5 } from "url";
23812
24054
  function resolveDaemonPaths() {
23813
24055
  const watchJs = fileURLToPath5(new URL("./watch.js", import.meta.url));
23814
24056
  const node = process.execPath;
23815
- const dataDir = join53(homedir20(), ".chat-recall");
23816
- const logFile = join53(dataDir, "watch.log");
24057
+ const dataDir = join54(homedir20(), ".chat-recall");
24058
+ const logFile = join54(dataDir, "watch.log");
23817
24059
  return { watchJs, node, logFile, dataDir };
23818
24060
  }
23819
24061
  function tryCmd(cmd) {
@@ -23840,12 +24082,12 @@ function refreshServiceDefinition() {
23840
24082
  if (process.platform !== "linux") return false;
23841
24083
  try {
23842
24084
  const { watchJs, node, logFile } = resolveDaemonPaths();
23843
- const unitPath = join53(homedir20(), ".config", "systemd", "user", "chat-recall-watch.service");
24085
+ const unitPath = join54(homedir20(), ".config", "systemd", "user", "chat-recall-watch.service");
23844
24086
  if (!existsSync49(unitPath)) return false;
23845
- const current = readFileSync44(unitPath, "utf8");
24087
+ const current = readFileSync45(unitPath, "utf8");
23846
24088
  if (!current.includes(watchJs)) return false;
23847
24089
  const wanted = renderSystemdUnit(watchJs, node, logFile);
23848
- if (readFileSync44(unitPath, "utf8") === wanted) return false;
24090
+ if (readFileSync45(unitPath, "utf8") === wanted) return false;
23849
24091
  writeFileSync16(unitPath, wanted);
23850
24092
  execSync5("systemctl --user daemon-reload", { stdio: "ignore" });
23851
24093
  return true;
@@ -23871,8 +24113,8 @@ function installService() {
23871
24113
  );
23872
24114
  }
23873
24115
  function installSystemd(watchJs, node, logFile) {
23874
- const unitDir = join53(homedir20(), ".config", "systemd", "user");
23875
- const unitPath = join53(unitDir, "chat-recall-watch.service");
24116
+ const unitDir = join54(homedir20(), ".config", "systemd", "user");
24117
+ const unitPath = join54(unitDir, "chat-recall-watch.service");
23876
24118
  const unit = renderSystemdUnit(watchJs, node, logFile);
23877
24119
  mkdirSync17(unitDir, { recursive: true });
23878
24120
  writeFileSync16(unitPath, unit);
@@ -23951,8 +24193,8 @@ function renderSystemdUnit(watchJs, node, logFile) {
23951
24193
  }
23952
24194
  function installLaunchd(watchJs, node, logFile) {
23953
24195
  const label = "com.chat-recall.watch";
23954
- const plistDir = join53(homedir20(), "Library", "LaunchAgents");
23955
- const plistPath = join53(plistDir, `${label}.plist`);
24196
+ const plistDir = join54(homedir20(), "Library", "LaunchAgents");
24197
+ const plistPath = join54(plistDir, `${label}.plist`);
23956
24198
  const plist = renderLaunchdPlist(watchJs, node, logFile, label);
23957
24199
  mkdirSync17(plistDir, { recursive: true });
23958
24200
  writeFileSync16(plistPath, plist);
@@ -24008,9 +24250,9 @@ function uninstallService() {
24008
24250
  removed = true;
24009
24251
  } catch {
24010
24252
  }
24011
- const unitPath = join53(homedir20(), ".config", "systemd", "user", "chat-recall-watch.service");
24253
+ const unitPath = join54(homedir20(), ".config", "systemd", "user", "chat-recall-watch.service");
24012
24254
  if (existsSync49(unitPath)) {
24013
- rmSync7(unitPath, { force: true });
24255
+ rmSync8(unitPath, { force: true });
24014
24256
  removed = true;
24015
24257
  }
24016
24258
  try {
@@ -24020,14 +24262,14 @@ function uninstallService() {
24020
24262
  return removed;
24021
24263
  }
24022
24264
  if (process.platform === "darwin") {
24023
- const plistPath = join53(homedir20(), "Library", "LaunchAgents", "com.chat-recall.watch.plist");
24265
+ const plistPath = join54(homedir20(), "Library", "LaunchAgents", "com.chat-recall.watch.plist");
24024
24266
  try {
24025
24267
  execSync5(`launchctl unload "${plistPath}" 2>/dev/null`, { stdio: "ignore" });
24026
24268
  } catch {
24027
24269
  }
24028
24270
  let removed = false;
24029
24271
  if (existsSync49(plistPath)) {
24030
- rmSync7(plistPath, { force: true });
24272
+ rmSync8(plistPath, { force: true });
24031
24273
  removed = true;
24032
24274
  }
24033
24275
  return removed;
@@ -24071,7 +24313,7 @@ init_settings();
24071
24313
  init_sync_client();
24072
24314
  init_http();
24073
24315
  import chokidar from "chokidar";
24074
- import { dirname as dirname25, basename as basename25, join as join54, resolve as resolve2, sep as sep4 } from "path";
24316
+ import { dirname as dirname25, basename as basename25, join as join55, resolve as resolve2, sep as sep4 } from "path";
24075
24317
  import { homedir as homedir21 } from "os";
24076
24318
 
24077
24319
  // src/intent-drain.ts
@@ -24084,13 +24326,13 @@ init_codex2();
24084
24326
  init_cursor();
24085
24327
  init_opencode();
24086
24328
  init_agy();
24087
- import { existsSync as existsSync46, readFileSync as readFileSync39, writeFileSync as writeFileSync13, appendFileSync, mkdirSync as mkdirSync14 } from "node:fs";
24088
- import { join as join48 } from "node:path";
24329
+ import { existsSync as existsSync46, readFileSync as readFileSync40, writeFileSync as writeFileSync13, appendFileSync, mkdirSync as mkdirSync14 } from "node:fs";
24330
+ import { join as join49 } from "node:path";
24089
24331
 
24090
24332
  // src/project-tasks.ts
24091
24333
  init_http();
24092
- import { existsSync as existsSync43, readFileSync as readFileSync38, writeFileSync as writeFileSync11, mkdirSync as mkdirSync12, statSync as statSync39 } from "node:fs";
24093
- import { join as join45, dirname as dirname21 } from "node:path";
24334
+ import { existsSync as existsSync43, readFileSync as readFileSync39, writeFileSync as writeFileSync11, mkdirSync as mkdirSync12, statSync as statSync40 } from "node:fs";
24335
+ import { join as join46, dirname as dirname21 } from "node:path";
24094
24336
  import { homedir as homedir18 } from "node:os";
24095
24337
 
24096
24338
  // ../engine/dist/core/secret-task-status.js
@@ -24159,11 +24401,11 @@ function parseTaskFile(content) {
24159
24401
  return out;
24160
24402
  }
24161
24403
  function ledgerPath2() {
24162
- return join45(homedir18(), ".chat-recall", "project-tasks-ledger.json");
24404
+ return join46(homedir18(), ".chat-recall", "project-tasks-ledger.json");
24163
24405
  }
24164
24406
  function readLedger() {
24165
24407
  try {
24166
- return JSON.parse(readFileSync38(ledgerPath2(), "utf8"));
24408
+ return JSON.parse(readFileSync39(ledgerPath2(), "utf8"));
24167
24409
  } catch {
24168
24410
  return {};
24169
24411
  }
@@ -24196,18 +24438,18 @@ async function pushProjectTaskStatuses(base3, authHeaders, opts = {}) {
24196
24438
  continue;
24197
24439
  }
24198
24440
  for (const project of projects) {
24199
- const file = join45(project, fk.filename);
24441
+ const file = join46(project, fk.filename);
24200
24442
  if (!existsSync43(file)) continue;
24201
24443
  let mtime;
24202
24444
  try {
24203
- mtime = statSync39(file).mtimeMs;
24445
+ mtime = statSync40(file).mtimeMs;
24204
24446
  } catch {
24205
24447
  continue;
24206
24448
  }
24207
24449
  if (ledger[file] === mtime) continue;
24208
24450
  let changed;
24209
24451
  try {
24210
- changed = parseTaskFile(readFileSync38(file, "utf8")).filter((t) => t.kind === fk.kind);
24452
+ changed = parseTaskFile(readFileSync39(file, "utf8")).filter((t) => t.kind === fk.kind);
24211
24453
  } catch {
24212
24454
  continue;
24213
24455
  }
@@ -24258,16 +24500,16 @@ function instructionTargets(rootPath, isGlobal) {
24258
24500
  const tools = installed.length ? installed : [INSTRUCTION_TOOLS[0]];
24259
24501
  if (isGlobal) return [...new Set(tools.map((t) => instructionsPath(t.id)))];
24260
24502
  if (!rootPath) return [];
24261
- const present = INSTRUCTION_FILENAMES.map((f) => join48(rootPath, f)).filter((p) => existsSync46(p));
24503
+ const present = INSTRUCTION_FILENAMES.map((f) => join49(rootPath, f)).filter((p) => existsSync46(p));
24262
24504
  if (present.length) return present;
24263
- return [...new Set(tools.map((t) => join48(rootPath, instructionsFilename(t.id))))];
24505
+ return [...new Set(tools.map((t) => join49(rootPath, instructionsFilename(t.id))))];
24264
24506
  }
24265
24507
  function applyCodeRecommendation(intent) {
24266
24508
  try {
24267
24509
  const meta = JSON.parse(intent.name || "{}");
24268
24510
  if (intent.artifact_type === "write_tasks_file") {
24269
24511
  if (!meta.rootPath || !meta.content) return { status: "error", result: JSON.stringify({ error: "missing rootPath or content" }) };
24270
- const file = join48(meta.rootPath, meta.filename || "CODE_TASKS.md");
24512
+ const file = join49(meta.rootPath, meta.filename || "CODE_TASKS.md");
24271
24513
  writeFileSync13(file, meta.content);
24272
24514
  return { status: "done", result: JSON.stringify({ wrote: file }) };
24273
24515
  }
@@ -24286,7 +24528,7 @@ function applyCodeRecommendation(intent) {
24286
24528
  mkdirSync14(dir, { recursive: true });
24287
24529
  } catch {
24288
24530
  }
24289
- const existing = existsSync46(file) ? readFileSync39(file, "utf8") : "";
24531
+ const existing = existsSync46(file) ? readFileSync40(file, "utf8") : "";
24290
24532
  if (existing.includes(text)) {
24291
24533
  skipped.push(file);
24292
24534
  continue;
@@ -24385,10 +24627,10 @@ async function runIntent(intent, ctx) {
24385
24627
  var ownVersion2 = "0.0.0";
24386
24628
  try {
24387
24629
  const dir = dirname23(fileURLToPath4(import.meta.url));
24388
- ownVersion2 = JSON.parse(readFileSync39(join48(dir, "../package.json"), "utf-8")).version || ownVersion2;
24630
+ ownVersion2 = JSON.parse(readFileSync40(join49(dir, "../package.json"), "utf-8")).version || ownVersion2;
24389
24631
  } catch {
24390
24632
  try {
24391
- if (true) ownVersion2 = "0.7.17";
24633
+ if (true) ownVersion2 = "0.7.18";
24392
24634
  } catch {
24393
24635
  }
24394
24636
  }
@@ -24453,14 +24695,14 @@ init_auto_update();
24453
24695
 
24454
24696
  // src/code-index-cursor.ts
24455
24697
  init_paths();
24456
- import { readFileSync as readFileSync40, writeFileSync as writeFileSync14, mkdirSync as mkdirSync15, statSync as statSync42 } from "fs";
24698
+ import { readFileSync as readFileSync41, writeFileSync as writeFileSync14, mkdirSync as mkdirSync15, statSync as statSync43 } from "fs";
24457
24699
  import { execFileSync as execFileSync4 } from "child_process";
24458
24700
  import { createHash as createHash10 } from "crypto";
24459
- import { join as join49, dirname as dirname24 } from "path";
24460
- var cursorPath = () => join49(getDataDir(), "code-index-cursor.json");
24701
+ import { join as join50, dirname as dirname24 } from "path";
24702
+ var cursorPath = () => join50(getDataDir(), "code-index-cursor.json");
24461
24703
  function readCursor() {
24462
24704
  try {
24463
- const raw = JSON.parse(readFileSync40(cursorPath(), "utf-8"));
24705
+ const raw = JSON.parse(readFileSync41(cursorPath(), "utf-8"));
24464
24706
  if (raw && typeof raw === "object" && !Array.isArray(raw)) {
24465
24707
  const out = {};
24466
24708
  for (const [k, v] of Object.entries(raw)) {
@@ -24504,7 +24746,7 @@ function workspaceFingerprint(workspace, collectorVersion) {
24504
24746
  const rel = entry.slice(3);
24505
24747
  let stamp2 = "gone";
24506
24748
  try {
24507
- const s = statSync42(join49(workspace, rel));
24749
+ const s = statSync43(join50(workspace, rel));
24508
24750
  stamp2 = `${s.size}:${Math.floor(s.mtimeMs)}`;
24509
24751
  } catch {
24510
24752
  }
@@ -24640,13 +24882,13 @@ init_telemetry();
24640
24882
 
24641
24883
  // src/self-restart.ts
24642
24884
  import { spawn } from "child_process";
24643
- import { readFileSync as readFileSync41 } from "fs";
24885
+ import { readFileSync as readFileSync42 } from "fs";
24644
24886
  import { createHash as createHash11 } from "crypto";
24645
24887
  var EXIT_CODE_CODE_CHANGED = 75;
24646
24888
  function codeFingerprint(entry = process.argv[1]) {
24647
24889
  if (!entry) return null;
24648
24890
  try {
24649
- const buf = readFileSync41(entry);
24891
+ const buf = readFileSync42(entry);
24650
24892
  return {
24651
24893
  path: entry,
24652
24894
  size: buf.byteLength,
@@ -24713,11 +24955,11 @@ function checkSelfRestart(opts) {
24713
24955
  }
24714
24956
 
24715
24957
  // src/log-rotate.ts
24716
- import { statSync as statSync43, copyFileSync as copyFileSync3, truncateSync } from "fs";
24958
+ import { statSync as statSync44, copyFileSync as copyFileSync3, truncateSync } from "fs";
24717
24959
  var LOG_MAX_BYTES = 32 * 1024 * 1024;
24718
24960
  function rotateLogIfLarge(logPath, maxBytes = LOG_MAX_BYTES) {
24719
24961
  try {
24720
- const size = statSync43(logPath).size;
24962
+ const size = statSync44(logPath).size;
24721
24963
  if (size < maxBytes) return { rotated: false, sizeBefore: 0 };
24722
24964
  copyFileSync3(logPath, `${logPath}.1`);
24723
24965
  truncateSync(logPath, 0);
@@ -24772,8 +25014,8 @@ async function runCollectorMigration(opts) {
24772
25014
  // auto-indexer/indexer.ts
24773
25015
  init_sync_ledger();
24774
25016
  init_collector_health();
24775
- import { existsSync as existsSync50, readFileSync as readFileSync45, statSync as statSync46 } from "fs";
24776
- var CLI_VERSION3 = true ? "0.7.17" : "0.0.0";
25017
+ import { existsSync as existsSync50, readFileSync as readFileSync46, statSync as statSync47 } from "fs";
25018
+ var CLI_VERSION3 = true ? "0.7.18" : "0.0.0";
24777
25019
  var DEBOUNCE_MS = 5e3;
24778
25020
  var PLANS_DIR = claudeBackend.plansDir();
24779
25021
  var TASKS_DIR = claudeBackend.tasksDir();
@@ -24782,8 +25024,8 @@ var DIARY_DIR = getDiaryDir();
24782
25024
  var CODEX_SESSIONS_DIR = codexBackend.sessionsDir();
24783
25025
  var OPENCODE_DB_PATH = opencodeBackend.dbPath();
24784
25026
  var OPENCODE_DB_DIR = dirname25(OPENCODE_DB_PATH);
24785
- var CURRENT_RESUME_PATH = join54(claudeBackend.homeDir(), "current-resume");
24786
- var LAST_CLEANUP_PATH = join54(claudeBackend.homeDir(), ".last-cleanup");
25027
+ var CURRENT_RESUME_PATH = join55(claudeBackend.homeDir(), "current-resume");
25028
+ var LAST_CLEANUP_PATH = join55(claudeBackend.homeDir(), ".last-cleanup");
24787
25029
  var debounceTimer = null;
24788
25030
  var ticks = new TickQueue({
24789
25031
  onError: (kind, err) => daemonLog.error(`${kind} tick failed: ${err instanceof Error ? err.message : err}`)
@@ -24832,7 +25074,7 @@ var lastResumeAt = /* @__PURE__ */ new Map();
24832
25074
  var RESUME_REARM_MS = 6e4;
24833
25075
  async function onResumeSignal(path) {
24834
25076
  try {
24835
- const txt = readFileSync45(path, "utf-8");
25077
+ const txt = readFileSync46(path, "utf-8");
24836
25078
  const m = /--resume\s+([0-9a-fA-F-]{36})/.exec(txt);
24837
25079
  if (!m) return;
24838
25080
  const id = m[1];
@@ -24878,7 +25120,7 @@ var CLAUDE_SESSION_ROOTS = claudeProjectDirs();
24878
25120
  var sessionWatcher = watchWithFallback("sessions", CLAUDE_SESSION_ROOTS.map((root) => `${root}/**/*.jsonl`), {
24879
25121
  ignored: (p, stats) => {
24880
25122
  if (/agent-/.test(p) || /^\./.test(basename25(p))) return true;
24881
- const st = stats ?? statSync46(p, { throwIfNoEntry: false });
25123
+ const st = stats ?? statSync47(p, { throwIfNoEntry: false });
24882
25124
  if (!st || st.isDirectory()) return false;
24883
25125
  return st.mtimeMs < Date.now() - WATCH_WINDOW_MS;
24884
25126
  },
@@ -25020,7 +25262,7 @@ if (BOOT_CODE) {
25020
25262
  daemonLog.info(`running bundle ${BOOT_CODE.path} (${BOOT_CODE.size} bytes)`);
25021
25263
  }
25022
25264
  {
25023
- const r = rotateLogIfLarge(join54(getDataDir(), "watch.log"));
25265
+ const r = rotateLogIfLarge(join55(getDataDir(), "watch.log"));
25024
25266
  if (r.rotated) {
25025
25267
  daemonLog.info(`rotated watch.log at ${(r.sizeBefore / 1048576).toFixed(0)}MB \u2192 watch.log.1 (copy+truncate; the path is preserved)`);
25026
25268
  }
@@ -25206,7 +25448,7 @@ function isCodeWorkspace(p) {
25206
25448
  }
25207
25449
  return WORKSPACE_MARKERS.some((m) => {
25208
25450
  try {
25209
- return existsSync50(join54(p, m));
25451
+ return existsSync50(join55(p, m));
25210
25452
  } catch {
25211
25453
  return false;
25212
25454
  }