chat-recall 0.7.17 → 0.7.19

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
@@ -152,6 +152,8 @@ function declaredOrigin(value) {
152
152
  function userRecordOrigin(obj, text) {
153
153
  if (obj.isSidechain === true)
154
154
  return "subagent";
155
+ if (obj.isCompactSummary === true)
156
+ return "compact-summary";
155
157
  const declared = declaredOrigin(obj.origin);
156
158
  if (declared && declared !== "human")
157
159
  return declared;
@@ -2233,7 +2235,7 @@ var require_thread_stream = __commonJS({
2233
2235
  var { version } = require_package();
2234
2236
  var { EventEmitter } = __require("events");
2235
2237
  var { Worker: Worker2 } = __require("worker_threads");
2236
- var { join: join55 } = __require("path");
2238
+ var { join: join56 } = __require("path");
2237
2239
  var { pathToFileURL } = __require("url");
2238
2240
  var { wait } = require_wait();
2239
2241
  var {
@@ -2276,7 +2278,7 @@ var require_thread_stream = __commonJS({
2276
2278
  function createWorker(stream, opts) {
2277
2279
  const { filename, workerData } = opts;
2278
2280
  const bundlerOverrides = "__bundlerPathsOverrides" in globalThis ? globalThis.__bundlerPathsOverrides : {};
2279
- const toExecute = bundlerOverrides["thread-stream-worker"] || join55(__dirname, "lib", "worker.js");
2281
+ const toExecute = bundlerOverrides["thread-stream-worker"] || join56(__dirname, "lib", "worker.js");
2280
2282
  const worker = new Worker2(toExecute, {
2281
2283
  ...opts.workerOpts,
2282
2284
  trackUnmanagedFds: false,
@@ -2679,7 +2681,7 @@ var require_transport = __commonJS({
2679
2681
  "use strict";
2680
2682
  var { createRequire: createRequire3 } = __require("module");
2681
2683
  var getCallers = require_caller();
2682
- var { join: join55, isAbsolute: isAbsolute4, sep: sep5 } = __require("node:path");
2684
+ var { join: join56, isAbsolute: isAbsolute4, sep: sep5 } = __require("node:path");
2683
2685
  var sleep = require_atomic_sleep();
2684
2686
  var onExit = require_on_exit_leak_free();
2685
2687
  var ThreadStream = require_thread_stream();
@@ -2742,7 +2744,7 @@ var require_transport = __commonJS({
2742
2744
  throw new Error("only one of target or targets can be specified");
2743
2745
  }
2744
2746
  if (targets) {
2745
- target = bundlerOverrides["pino-worker"] || join55(__dirname, "worker.js");
2747
+ target = bundlerOverrides["pino-worker"] || join56(__dirname, "worker.js");
2746
2748
  options.targets = targets.filter((dest) => dest.target).map((dest) => {
2747
2749
  return {
2748
2750
  ...dest,
@@ -2760,7 +2762,7 @@ var require_transport = __commonJS({
2760
2762
  });
2761
2763
  });
2762
2764
  } else if (pipeline) {
2763
- target = bundlerOverrides["pino-worker"] || join55(__dirname, "worker.js");
2765
+ target = bundlerOverrides["pino-worker"] || join56(__dirname, "worker.js");
2764
2766
  options.pipelines = [pipeline.map((dest) => {
2765
2767
  return {
2766
2768
  ...dest,
@@ -2782,7 +2784,7 @@ var require_transport = __commonJS({
2782
2784
  return origin;
2783
2785
  }
2784
2786
  if (origin === "pino/file") {
2785
- return join55(__dirname, "..", "file.js");
2787
+ return join56(__dirname, "..", "file.js");
2786
2788
  }
2787
2789
  let fixTarget2;
2788
2790
  for (const filePath of callers) {
@@ -3771,7 +3773,7 @@ var require_safe_stable_stringify = __commonJS({
3771
3773
  return circularValue;
3772
3774
  }
3773
3775
  let res = "";
3774
- let join55 = ",";
3776
+ let join56 = ",";
3775
3777
  const originalIndentation = indentation;
3776
3778
  if (Array.isArray(value)) {
3777
3779
  if (value.length === 0) {
@@ -3785,7 +3787,7 @@ var require_safe_stable_stringify = __commonJS({
3785
3787
  indentation += spacer;
3786
3788
  res += `
3787
3789
  ${indentation}`;
3788
- join55 = `,
3790
+ join56 = `,
3789
3791
  ${indentation}`;
3790
3792
  }
3791
3793
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
@@ -3793,13 +3795,13 @@ ${indentation}`;
3793
3795
  for (; i < maximumValuesToStringify - 1; i++) {
3794
3796
  const tmp2 = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
3795
3797
  res += tmp2 !== void 0 ? tmp2 : "null";
3796
- res += join55;
3798
+ res += join56;
3797
3799
  }
3798
3800
  const tmp = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
3799
3801
  res += tmp !== void 0 ? tmp : "null";
3800
3802
  if (value.length - 1 > maximumBreadth) {
3801
3803
  const removedKeys = value.length - maximumBreadth - 1;
3802
- res += `${join55}"... ${getItemCount(removedKeys)} not stringified"`;
3804
+ res += `${join56}"... ${getItemCount(removedKeys)} not stringified"`;
3803
3805
  }
3804
3806
  if (spacer !== "") {
3805
3807
  res += `
@@ -3820,7 +3822,7 @@ ${originalIndentation}`;
3820
3822
  let separator = "";
3821
3823
  if (spacer !== "") {
3822
3824
  indentation += spacer;
3823
- join55 = `,
3825
+ join56 = `,
3824
3826
  ${indentation}`;
3825
3827
  whitespace = " ";
3826
3828
  }
@@ -3834,13 +3836,13 @@ ${indentation}`;
3834
3836
  const tmp = stringifyFnReplacer(key3, value, stack, replacer, spacer, indentation);
3835
3837
  if (tmp !== void 0) {
3836
3838
  res += `${separator}${strEscape(key3)}:${whitespace}${tmp}`;
3837
- separator = join55;
3839
+ separator = join56;
3838
3840
  }
3839
3841
  }
3840
3842
  if (keyLength > maximumBreadth) {
3841
3843
  const removedKeys = keyLength - maximumBreadth;
3842
3844
  res += `${separator}"...":${whitespace}"${getItemCount(removedKeys)} not stringified"`;
3843
- separator = join55;
3845
+ separator = join56;
3844
3846
  }
3845
3847
  if (spacer !== "" && separator.length > 1) {
3846
3848
  res = `
@@ -3881,7 +3883,7 @@ ${originalIndentation}`;
3881
3883
  }
3882
3884
  const originalIndentation = indentation;
3883
3885
  let res = "";
3884
- let join55 = ",";
3886
+ let join56 = ",";
3885
3887
  if (Array.isArray(value)) {
3886
3888
  if (value.length === 0) {
3887
3889
  return "[]";
@@ -3894,7 +3896,7 @@ ${originalIndentation}`;
3894
3896
  indentation += spacer;
3895
3897
  res += `
3896
3898
  ${indentation}`;
3897
- join55 = `,
3899
+ join56 = `,
3898
3900
  ${indentation}`;
3899
3901
  }
3900
3902
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
@@ -3902,13 +3904,13 @@ ${indentation}`;
3902
3904
  for (; i < maximumValuesToStringify - 1; i++) {
3903
3905
  const tmp2 = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
3904
3906
  res += tmp2 !== void 0 ? tmp2 : "null";
3905
- res += join55;
3907
+ res += join56;
3906
3908
  }
3907
3909
  const tmp = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
3908
3910
  res += tmp !== void 0 ? tmp : "null";
3909
3911
  if (value.length - 1 > maximumBreadth) {
3910
3912
  const removedKeys = value.length - maximumBreadth - 1;
3911
- res += `${join55}"... ${getItemCount(removedKeys)} not stringified"`;
3913
+ res += `${join56}"... ${getItemCount(removedKeys)} not stringified"`;
3912
3914
  }
3913
3915
  if (spacer !== "") {
3914
3916
  res += `
@@ -3921,7 +3923,7 @@ ${originalIndentation}`;
3921
3923
  let whitespace = "";
3922
3924
  if (spacer !== "") {
3923
3925
  indentation += spacer;
3924
- join55 = `,
3926
+ join56 = `,
3925
3927
  ${indentation}`;
3926
3928
  whitespace = " ";
3927
3929
  }
@@ -3930,7 +3932,7 @@ ${indentation}`;
3930
3932
  const tmp = stringifyArrayReplacer(key3, value[key3], stack, replacer, spacer, indentation);
3931
3933
  if (tmp !== void 0) {
3932
3934
  res += `${separator}${strEscape(key3)}:${whitespace}${tmp}`;
3933
- separator = join55;
3935
+ separator = join56;
3934
3936
  }
3935
3937
  }
3936
3938
  if (spacer !== "" && separator.length > 1) {
@@ -3988,20 +3990,20 @@ ${originalIndentation}`;
3988
3990
  indentation += spacer;
3989
3991
  let res2 = `
3990
3992
  ${indentation}`;
3991
- const join56 = `,
3993
+ const join57 = `,
3992
3994
  ${indentation}`;
3993
3995
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
3994
3996
  let i = 0;
3995
3997
  for (; i < maximumValuesToStringify - 1; i++) {
3996
3998
  const tmp2 = stringifyIndent(String(i), value[i], stack, spacer, indentation);
3997
3999
  res2 += tmp2 !== void 0 ? tmp2 : "null";
3998
- res2 += join56;
4000
+ res2 += join57;
3999
4001
  }
4000
4002
  const tmp = stringifyIndent(String(i), value[i], stack, spacer, indentation);
4001
4003
  res2 += tmp !== void 0 ? tmp : "null";
4002
4004
  if (value.length - 1 > maximumBreadth) {
4003
4005
  const removedKeys = value.length - maximumBreadth - 1;
4004
- res2 += `${join56}"... ${getItemCount(removedKeys)} not stringified"`;
4006
+ res2 += `${join57}"... ${getItemCount(removedKeys)} not stringified"`;
4005
4007
  }
4006
4008
  res2 += `
4007
4009
  ${originalIndentation}`;
@@ -4017,16 +4019,16 @@ ${originalIndentation}`;
4017
4019
  return '"[Object]"';
4018
4020
  }
4019
4021
  indentation += spacer;
4020
- const join55 = `,
4022
+ const join56 = `,
4021
4023
  ${indentation}`;
4022
4024
  let res = "";
4023
4025
  let separator = "";
4024
4026
  let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth);
4025
4027
  if (isTypedArrayWithEntries(value)) {
4026
- res += stringifyTypedArray(value, join55, maximumBreadth);
4028
+ res += stringifyTypedArray(value, join56, maximumBreadth);
4027
4029
  keys = keys.slice(value.length);
4028
4030
  maximumPropertiesToStringify -= value.length;
4029
- separator = join55;
4031
+ separator = join56;
4030
4032
  }
4031
4033
  if (deterministic) {
4032
4034
  keys = sort(keys, comparator);
@@ -4037,13 +4039,13 @@ ${indentation}`;
4037
4039
  const tmp = stringifyIndent(key3, value[key3], stack, spacer, indentation);
4038
4040
  if (tmp !== void 0) {
4039
4041
  res += `${separator}${strEscape(key3)}: ${tmp}`;
4040
- separator = join55;
4042
+ separator = join56;
4041
4043
  }
4042
4044
  }
4043
4045
  if (keyLength > maximumBreadth) {
4044
4046
  const removedKeys = keyLength - maximumBreadth;
4045
4047
  res += `${separator}"...": "${getItemCount(removedKeys)} not stringified"`;
4046
- separator = join55;
4048
+ separator = join56;
4047
4049
  }
4048
4050
  if (separator !== "") {
4049
4051
  res = `
@@ -4816,6 +4818,7 @@ function defaultSourcesEnabled() {
4816
4818
  commands: true
4817
4819
  },
4818
4820
  cursor: { sessions: true, skills: true, agents: true, commands: true },
4821
+ hermes: { sessions: true },
4819
4822
  shared: { skills: true },
4820
4823
  common: { mcps: true, agentMd: true }
4821
4824
  };
@@ -4892,6 +4895,7 @@ function mergeSources(base3, partial) {
4892
4895
  codex: { ...base3.enabled.codex, ...partial.enabled?.codex ?? {} },
4893
4896
  agy: { ...base3.enabled.agy, ...inherited, ...partial.enabled?.agy ?? {} },
4894
4897
  cursor: { ...base3.enabled.cursor, ...partial.enabled?.cursor ?? {} },
4898
+ hermes: { ...base3.enabled.hermes, ...partial.enabled?.hermes ?? {} },
4895
4899
  shared: { ...base3.enabled.shared, ...partial.enabled?.shared ?? {} },
4896
4900
  common: { ...base3.enabled.common, ...partial.enabled?.common ?? {} }
4897
4901
  };
@@ -4903,6 +4907,7 @@ function mergeSources(base3, partial) {
4903
4907
  agyHome: partial.agyHome ?? base3.agyHome,
4904
4908
  cursorHome: partial.cursorHome ?? base3.cursorHome,
4905
4909
  cursorIdeHome: partial.cursorIdeHome ?? base3.cursorIdeHome,
4910
+ hermesHome: partial.hermesHome ?? base3.hermesHome,
4906
4911
  extraClaudeHomes: partial.extraClaudeHomes ?? base3.extraClaudeHomes,
4907
4912
  approvedHomes: partial.approvedHomes ?? base3.approvedHomes,
4908
4913
  declinedHomes: partial.declinedHomes ?? base3.declinedHomes,
@@ -5200,6 +5205,13 @@ function grandfatherLegacyHomes() {
5200
5205
  }
5201
5206
  return { seeded };
5202
5207
  }
5208
+ function defaultHermesHome() {
5209
+ if (process.platform === "win32") {
5210
+ const local = process.env.LOCALAPPDATA?.trim() || join3(homedir2(), "AppData", "Local");
5211
+ return join3(local, "hermes");
5212
+ }
5213
+ return join3(homedir2(), ".hermes");
5214
+ }
5203
5215
  function primaryHomes() {
5204
5216
  const home = homedir2();
5205
5217
  const env = process.env;
@@ -5216,7 +5228,8 @@ function primaryHomes() {
5216
5228
  env.CHAT_RECALL_CODEX_HOME || s?.codexHome || join3(home, ".codex"),
5217
5229
  env.CHAT_RECALL_AGY_HOME || s?.agyHome || join3(home, ".gemini", "antigravity-cli"),
5218
5230
  env.CHAT_RECALL_CURSOR_HOME || s?.cursorHome || join3(home, ".cursor"),
5219
- dirOf(opencodeDb)
5231
+ dirOf(opencodeDb),
5232
+ env.CHAT_RECALL_HERMES_HOME || s?.hermesHome || env.HERMES_HOME?.trim() || defaultHermesHome()
5220
5233
  ];
5221
5234
  return candidates2.map(normalizeHomePath);
5222
5235
  }
@@ -5326,6 +5339,9 @@ function geminiHomeDir() {
5326
5339
  function opencodeDbPath() {
5327
5340
  return process.env.CHAT_RECALL_OPENCODE_DB || sources().opencodeDbPath || join4(homedir3(), ".local", "share", "opencode", "opencode.db");
5328
5341
  }
5342
+ function hermesHomeDir() {
5343
+ return process.env.CHAT_RECALL_HERMES_HOME || sources().hermesHome || process.env.HERMES_HOME?.trim() || defaultHermesHome();
5344
+ }
5329
5345
  function codexHomeDir() {
5330
5346
  return process.env.CHAT_RECALL_CODEX_HOME || sources().codexHome || join4(homedir3(), ".codex");
5331
5347
  }
@@ -5427,6 +5443,22 @@ function opencodeDbPaths(opts = {}) {
5427
5443
  dbs.push(primary);
5428
5444
  return applyExclusions(dbs, opts.includeExcluded);
5429
5445
  }
5446
+ function hermesDbPaths(opts = {}) {
5447
+ const root = hermesHomeDir();
5448
+ const dbs = [join4(root, "state.db")];
5449
+ try {
5450
+ const profiles = join4(root, "profiles");
5451
+ for (const entry of readdirSync3(profiles, { withFileTypes: true })) {
5452
+ if (!entry.isDirectory())
5453
+ continue;
5454
+ const p = join4(profiles, entry.name, "state.db");
5455
+ if (existsSync4(p))
5456
+ dbs.push(p);
5457
+ }
5458
+ } catch {
5459
+ }
5460
+ return applyExclusions(dbs, opts.includeExcluded);
5461
+ }
5430
5462
  var sources, _sourceExclusionFilter;
5431
5463
  var init_tool_paths = __esm({
5432
5464
  "../engine/dist/core/tool-paths.js"() {
@@ -6405,7 +6437,7 @@ function canonicalEventsToMessages(events) {
6405
6437
  switch (e.kind) {
6406
6438
  case "user":
6407
6439
  cur = null;
6408
- messages.push({ line: e.line, role: "user", content: e.text ?? "", timestamp: e.tsIso });
6440
+ messages.push({ line: e.line, role: "user", content: e.text ?? "", timestamp: e.tsIso, ...e.origin ? { origin: e.origin } : {} });
6409
6441
  break;
6410
6442
  case "assistant_text":
6411
6443
  cur = { line: e.line, role: "assistant", content: e.text ?? "", timestamp: e.tsIso };
@@ -6448,6 +6480,7 @@ var init_from_events = __esm({
6448
6480
  // ../engine/dist/transcript/raw.js
6449
6481
  var raw_exports = {};
6450
6482
  __export(raw_exports, {
6483
+ RAW_PARSE_MAX_BYTES: () => RAW_PARSE_MAX_BYTES,
6451
6484
  archiveRawSession: () => archiveRawSession,
6452
6485
  buildRawContainer: () => buildRawContainer,
6453
6486
  containerSrcHash: () => containerSrcHash,
@@ -6747,11 +6780,11 @@ async function archiveRawSession(store, sessionId) {
6747
6780
  return await store.putRawSession(sessionId, exp.tool, Math.floor(exp.mtime), gz, size);
6748
6781
  }
6749
6782
  function detectForkPredecessor(sessionPath) {
6750
- const { readFileSync: readFileSync46, readdirSync: readdirSync33 } = requireFs();
6751
- const { dirname: dirname26, join: join55, basename: basename26 } = requirePath();
6783
+ const { readFileSync: readFileSync47, readdirSync: readdirSync33 } = requireFs();
6784
+ const { dirname: dirname26, join: join56, basename: basename26 } = requirePath();
6752
6785
  let text;
6753
6786
  try {
6754
- text = readFileSync46(sessionPath, "utf-8");
6787
+ text = readFileSync47(sessionPath, "utf-8");
6755
6788
  } catch {
6756
6789
  return null;
6757
6790
  }
@@ -6785,7 +6818,7 @@ function detectForkPredecessor(sessionPath) {
6785
6818
  if (!f.endsWith(".jsonl") || f === self || f === "sessions-index.json")
6786
6819
  continue;
6787
6820
  try {
6788
- if (readFileSync46(join55(dir, f), "utf-8").includes(`"uuid":"${headParent}"`)) {
6821
+ if (readFileSync47(join56(dir, f), "utf-8").includes(`"uuid":"${headParent}"`)) {
6789
6822
  return basename26(f, ".jsonl");
6790
6823
  }
6791
6824
  } catch {
@@ -6799,7 +6832,7 @@ function requireFs() {
6799
6832
  function requirePath() {
6800
6833
  return pathMod;
6801
6834
  }
6802
- var MARKER_QUOTE;
6835
+ var RAW_PARSE_MAX_BYTES, MARKER_QUOTE;
6803
6836
  var init_raw = __esm({
6804
6837
  "../engine/dist/transcript/raw.js"() {
6805
6838
  "use strict";
@@ -6807,6 +6840,7 @@ var init_raw = __esm({
6807
6840
  init_claude();
6808
6841
  init_codex();
6809
6842
  init_from_events();
6843
+ RAW_PARSE_MAX_BYTES = 40 * 1024 * 1024;
6810
6844
  MARKER_QUOTE = /\[REDACTED:[A-Za-z0-9_-]+\]"/g;
6811
6845
  }
6812
6846
  });
@@ -8080,6 +8114,71 @@ function readTailFromOffset(path, offset, maxBytes = TAIL_READ_MAX_BYTES) {
8080
8114
  }
8081
8115
  }
8082
8116
  }
8117
+ function readSourcesFromOffset(paths, offset, maxBytes = TAIL_READ_MAX_BYTES) {
8118
+ let start = 0;
8119
+ let linesBefore = 0;
8120
+ for (let i = 0; i < paths.length; i++) {
8121
+ const path = paths[i];
8122
+ let size = 0;
8123
+ try {
8124
+ size = statSync6(path).size;
8125
+ } catch {
8126
+ size = 0;
8127
+ }
8128
+ const last = i === paths.length - 1;
8129
+ if (!last && offset >= start + size) {
8130
+ const lines = linesBeforeOffset(path, size);
8131
+ if (lines === void 0)
8132
+ return { text: "", newOffset: offset };
8133
+ linesBefore += lines + (size > 0 && !endsWithNewline(path, size) ? 1 : 0);
8134
+ start += size;
8135
+ continue;
8136
+ }
8137
+ const local = offset - start;
8138
+ const read = readTailFromOffset(path, local, maxBytes);
8139
+ const shift = (r) => ({
8140
+ ...r,
8141
+ newOffset: start + r.newOffset,
8142
+ ...r.baseLine !== void 0 ? { baseLine: linesBefore + r.baseLine } : {}
8143
+ });
8144
+ if (last || read.newOffset > local || local >= size)
8145
+ return shift(read);
8146
+ if (size - local > maxBytes)
8147
+ return { text: "", newOffset: start + size, skippedBytes: size - local };
8148
+ let fd = null;
8149
+ try {
8150
+ fd = openSync5(path, "r");
8151
+ const text = readAt(fd, local, size - local).toString("utf-8");
8152
+ return shift({ text, newOffset: size, baseLine: linesBeforeOffset(path, local) });
8153
+ } catch {
8154
+ return { text: "", newOffset: offset };
8155
+ } finally {
8156
+ if (fd !== null) {
8157
+ try {
8158
+ closeSync5(fd);
8159
+ } catch {
8160
+ }
8161
+ }
8162
+ }
8163
+ }
8164
+ return { text: "", newOffset: offset };
8165
+ }
8166
+ function endsWithNewline(path, size) {
8167
+ let fd = null;
8168
+ try {
8169
+ fd = openSync5(path, "r");
8170
+ return readAt(fd, size - 1, 1)[0] === 10;
8171
+ } catch {
8172
+ return true;
8173
+ } finally {
8174
+ if (fd !== null) {
8175
+ try {
8176
+ closeSync5(fd);
8177
+ } catch {
8178
+ }
8179
+ }
8180
+ }
8181
+ }
8083
8182
  function findNewline(fd, from, size) {
8084
8183
  const block = Buffer.allocUnsafe(SKIP_SCAN_BYTES);
8085
8184
  let pos = from;
@@ -8996,27 +9095,45 @@ var init_claude2 = __esm({
8996
9095
  /**
8997
9096
  * True when this session exists in MORE THAN ONE home.
8998
9097
  *
8999
- * Such a session cannot be tail-appended: `fileSize()` is the SUM across
9000
- * copies while a byte offset addresses ONE file, so the two disagree by
9001
- * construction and the "tail" is either empty or the wrong bytes. The caller
9002
- * uses this to force a FULL sync, which ships the unioned container and is
9003
- * correct regardless of how the halves are arranged.
9004
- *
9005
9098
  * Measured on ec05f266: ~/.claude 1715 records, ~/.claude-work 205 records,
9006
- * zero overlap. An offset-based append against a 5846662-byte "size" that no
9007
- * single file has could only ever ship nonsense.
9099
+ * zero overlap. `fileSize()` is the sum across the copies, and
9100
+ * `readFromOffset()` reads them joined end to end, primary first.
9008
9101
  */
9009
9102
  spansMultipleSources(prefixedId) {
9010
9103
  return findSessionFiles(this.toRawId(prefixedId)).length > 1;
9011
9104
  }
9105
+ /**
9106
+ * The copies before the last one, each with its size. Claude Code writes to
9107
+ * the home of the profile that runs the session, so the live copy can grow,
9108
+ * appear, vanish or merge back into the primary. Each of those moves bytes
9109
+ * under an offset into the joined copies; this key changes with all of them.
9110
+ */
9111
+ sourceLayout(prefixedId) {
9112
+ const copies = findSessionFiles(this.toRawId(prefixedId));
9113
+ if (copies.length < 2)
9114
+ return "";
9115
+ return copies.slice(0, -1).map((c) => {
9116
+ let size = -1;
9117
+ try {
9118
+ size = statSync7(c.path).size;
9119
+ } catch {
9120
+ }
9121
+ return `${c.path}:${size}`;
9122
+ }).join("|");
9123
+ }
9124
+ /**
9125
+ * Session 8de13d0a had 31 MB in ~/.claude and 2 MB in ~/.claude-work. Over
9126
+ * the 24 MB build ceiling a sync ships the transcript in chunks read here,
9127
+ * and this returned no text for a session in two homes. Each sync shipped
9128
+ * nothing, and the server stayed three hours behind.
9129
+ */
9012
9130
  async readFromOffset(prefixedId, offset, maxBytes) {
9013
- const rawId = this.toRawId(prefixedId);
9014
- const copies = findSessionFiles(rawId);
9131
+ const copies = findSessionFiles(this.toRawId(prefixedId));
9015
9132
  if (copies.length === 0)
9016
9133
  return { text: "", newOffset: offset };
9017
- if (copies.length > 1)
9018
- return { text: "", newOffset: offset };
9019
- return readTailFromOffset(copies[0].path, offset, maxBytes);
9134
+ if (copies.length === 1)
9135
+ return readTailFromOffset(copies[0].path, offset, maxBytes);
9136
+ return readSourcesFromOffset(copies.map((c) => c.path), offset, maxBytes);
9020
9137
  }
9021
9138
  };
9022
9139
  claudeBackend = new ClaudeBackend();
@@ -12075,6 +12192,473 @@ var init_cursor = __esm({
12075
12192
  }
12076
12193
  });
12077
12194
 
12195
+ // ../engine/dist/core/backends/hermes.js
12196
+ import { existsSync as existsSync16 } from "fs";
12197
+ function firstUserPrompt(db, sessionId) {
12198
+ try {
12199
+ const row = db.prepare(`
12200
+ SELECT substr(content, 1, 400) AS text FROM messages
12201
+ WHERE session_id = ? AND role = 'user' AND active = 1 AND _compressed_summary = 0
12202
+ AND (display_kind IS NULL OR display_kind = 'steer')
12203
+ AND length(trim(content)) > 0
12204
+ ORDER BY id LIMIT 1
12205
+ `).get(sessionId);
12206
+ return row?.text ? flatString(row.text.slice(0, 200)) : "";
12207
+ } catch {
12208
+ return "";
12209
+ }
12210
+ }
12211
+ function messageRowsToEvents(rows) {
12212
+ const events = [];
12213
+ let line = 0;
12214
+ for (const r of rows) {
12215
+ line++;
12216
+ if (r.active === 0)
12217
+ continue;
12218
+ if (r.display_kind === "failed_turn" || r.display_kind === "hidden")
12219
+ continue;
12220
+ const ts = Math.round((r.timestamp || 0) * 1e3);
12221
+ const tsIso = ts ? new Date(ts).toISOString() : void 0;
12222
+ const text = (r.content ?? "").trim();
12223
+ if (r._compressed_summary === 1) {
12224
+ if (text)
12225
+ events.push({ kind: "summary", ts, tsIso, line, text });
12226
+ continue;
12227
+ }
12228
+ if (r.role === "user") {
12229
+ if (!text)
12230
+ continue;
12231
+ events.push({
12232
+ kind: "user",
12233
+ ts,
12234
+ tsIso,
12235
+ line,
12236
+ text,
12237
+ ...r.display_kind === "process_complete" ? { origin: "task-notification" } : {}
12238
+ });
12239
+ continue;
12240
+ }
12241
+ if (r.role === "assistant") {
12242
+ if (text)
12243
+ events.push({ kind: "assistant_text", ts, tsIso, line, text });
12244
+ for (const call2 of parseToolCalls(r.tool_calls)) {
12245
+ const toolName = call2.function?.name ?? "";
12246
+ const toolInput = parseArguments(call2.function?.arguments);
12247
+ const command = toolName === "terminal" && typeof toolInput?.command === "string" ? toolInput.command : void 0;
12248
+ events.push({
12249
+ kind: "tool_use",
12250
+ ts,
12251
+ tsIso,
12252
+ line,
12253
+ toolName,
12254
+ toolUseId: call2.id || call2.call_id || `${r.id}:${toolName}`,
12255
+ toolInput,
12256
+ ...command ? { command } : {}
12257
+ });
12258
+ }
12259
+ continue;
12260
+ }
12261
+ if (r.role === "tool") {
12262
+ const body = r.content ?? "";
12263
+ const { exitCode, isError } = toolResultStatus(body);
12264
+ events.push({
12265
+ kind: "tool_result",
12266
+ ts,
12267
+ tsIso,
12268
+ line,
12269
+ toolUseId: r.tool_call_id ?? void 0,
12270
+ toolName: r.tool_name ?? void 0,
12271
+ resultBody: body,
12272
+ resultIsError: isError,
12273
+ ...exitCode !== void 0 ? { resultExitCode: exitCode } : {},
12274
+ resultBytes: Buffer.byteLength(body)
12275
+ });
12276
+ }
12277
+ }
12278
+ return events;
12279
+ }
12280
+ function parseToolCalls(json) {
12281
+ if (!json)
12282
+ return [];
12283
+ try {
12284
+ const calls = JSON.parse(json);
12285
+ return Array.isArray(calls) ? calls : [];
12286
+ } catch {
12287
+ return [];
12288
+ }
12289
+ }
12290
+ function parseArguments(args) {
12291
+ if (typeof args !== "string")
12292
+ return args ?? {};
12293
+ try {
12294
+ return JSON.parse(args);
12295
+ } catch {
12296
+ return { raw: args };
12297
+ }
12298
+ }
12299
+ function toolResultStatus(body) {
12300
+ if (!body.startsWith("{"))
12301
+ return { isError: false };
12302
+ try {
12303
+ const r = JSON.parse(body);
12304
+ const exitCode = typeof r.exit_code === "number" ? r.exit_code : void 0;
12305
+ const hasError = r.error !== void 0 && r.error !== null && r.error !== "";
12306
+ return { exitCode, isError: hasError || exitCode !== void 0 && exitCode !== 0 };
12307
+ } catch {
12308
+ return { isError: false };
12309
+ }
12310
+ }
12311
+ var PREFIX5, MESSAGE_COLUMNS, ARCHIVED_SESSION_COLUMNS, SESSION_MTIME_SQL, HermesBackend, hermesBackend;
12312
+ var init_hermes = __esm({
12313
+ "../engine/dist/core/backends/hermes.js"() {
12314
+ "use strict";
12315
+ init_sqlite_reader();
12316
+ init_tool_paths();
12317
+ init_session_outcome();
12318
+ init_session_git();
12319
+ init_generic_engine();
12320
+ init_flat_string();
12321
+ PREFIX5 = "hermes_";
12322
+ MESSAGE_COLUMNS = "id, role, content, tool_calls, tool_call_id, tool_name, timestamp, display_kind, active, _compressed_summary";
12323
+ ARCHIVED_SESSION_COLUMNS = [
12324
+ "id",
12325
+ "source",
12326
+ "title",
12327
+ "model",
12328
+ "cwd",
12329
+ "git_branch",
12330
+ "git_repo_root",
12331
+ "parent_session_id",
12332
+ "started_at",
12333
+ "ended_at",
12334
+ "end_reason",
12335
+ "message_count",
12336
+ "tool_call_count",
12337
+ "input_tokens",
12338
+ "output_tokens",
12339
+ "cache_read_tokens",
12340
+ "cache_write_tokens",
12341
+ "reasoning_tokens",
12342
+ "estimated_cost_usd",
12343
+ "actual_cost_usd"
12344
+ ];
12345
+ SESSION_MTIME_SQL = `MAX(
12346
+ s.started_at,
12347
+ COALESCE(s.ended_at, 0),
12348
+ COALESCE(s.last_activity_at, 0),
12349
+ COALESCE((SELECT MAX(m.timestamp) FROM messages m WHERE m.session_id = s.id), 0)
12350
+ )`;
12351
+ HermesBackend = class {
12352
+ id = "hermes";
12353
+ idPrefix = PREFIX5;
12354
+ displayName = "Hermes";
12355
+ homeDir() {
12356
+ return hermesHomeDir();
12357
+ }
12358
+ /** Every Hermes database on this machine, the root profile first. */
12359
+ dbPaths() {
12360
+ return hermesDbPaths();
12361
+ }
12362
+ isAvailable() {
12363
+ return this.dbPaths().some((p) => existsSync16(p));
12364
+ }
12365
+ /** The database that holds this session. A session id is unique within a
12366
+ * database, and each named profile has its own. */
12367
+ dbPathFor(rawId) {
12368
+ const cached = this._dbForSession.get(rawId);
12369
+ if (cached)
12370
+ return cached;
12371
+ for (const path of this.dbPaths()) {
12372
+ const db = openSqliteReadonly(path);
12373
+ if (!db)
12374
+ continue;
12375
+ try {
12376
+ if (db.prepare("SELECT 1 AS ok FROM sessions WHERE id = ?").get(rawId)) {
12377
+ this._dbForSession.set(rawId, path);
12378
+ return path;
12379
+ }
12380
+ } catch {
12381
+ } finally {
12382
+ db.close();
12383
+ }
12384
+ }
12385
+ return null;
12386
+ }
12387
+ _dbForSession = /* @__PURE__ */ new Map();
12388
+ /** Tests, and anything that adds a profile mid-process. */
12389
+ _clearDbRouting() {
12390
+ this._dbForSession.clear();
12391
+ }
12392
+ // ── ID handling ────────────────────────────────────────────────
12393
+ matchesId(id) {
12394
+ return id.startsWith(PREFIX5);
12395
+ }
12396
+ toRawId(id) {
12397
+ return id.startsWith(PREFIX5) ? id.slice(PREFIX5.length) : id;
12398
+ }
12399
+ toPrefixedId(rawId) {
12400
+ return rawId.startsWith(PREFIX5) ? rawId : PREFIX5 + rawId;
12401
+ }
12402
+ // ── Location ───────────────────────────────────────────────────
12403
+ findSession(id) {
12404
+ const rawId = this.toRawId(id);
12405
+ const path = this.dbPathFor(rawId);
12406
+ if (!path)
12407
+ return null;
12408
+ const db = openSqliteReadonly(path);
12409
+ if (!db)
12410
+ return null;
12411
+ try {
12412
+ const row = db.prepare(`
12413
+ SELECT s.cwd, s.git_repo_root, ${SESSION_MTIME_SQL} AS mtime
12414
+ FROM sessions s WHERE s.id = ?
12415
+ `).get(rawId);
12416
+ if (!row)
12417
+ return null;
12418
+ return {
12419
+ path,
12420
+ format: "sqlite",
12421
+ projectDir: "",
12422
+ projectPath: row.git_repo_root || row.cwd || "",
12423
+ mtime: Math.round((row.mtime || 0) * 1e3)
12424
+ };
12425
+ } catch {
12426
+ return null;
12427
+ } finally {
12428
+ db.close();
12429
+ }
12430
+ }
12431
+ listSessions(opts = {}) {
12432
+ const byId = /* @__PURE__ */ new Map();
12433
+ for (const dbPath of this.dbPaths()) {
12434
+ if (!existsSync16(dbPath))
12435
+ continue;
12436
+ for (const ref of this.listSessionsInDb(dbPath, opts)) {
12437
+ const prior = byId.get(ref.rawId);
12438
+ if (!prior || ref.mtime > prior.mtime)
12439
+ byId.set(ref.rawId, ref);
12440
+ }
12441
+ }
12442
+ const all = [...byId.values()].sort((a, b) => b.mtime - a.mtime);
12443
+ return opts.limit ? all.slice(0, opts.limit) : all;
12444
+ }
12445
+ listSessionsInDb(dbPath, opts) {
12446
+ const cutoffSec = (opts.sinceMs ?? 0) / 1e3;
12447
+ const filter = opts.projectFilter?.toLowerCase();
12448
+ const db = openSqliteReadonly(dbPath);
12449
+ if (!db)
12450
+ return [];
12451
+ try {
12452
+ const rows = db.prepare(`
12453
+ SELECT * FROM (
12454
+ SELECT s.id, s.cwd, s.git_repo_root, s.started_at, s.message_count,
12455
+ ${SESSION_MTIME_SQL} AS mtime
12456
+ FROM sessions s
12457
+ ) WHERE mtime >= ? ORDER BY mtime DESC
12458
+ `).all(cutoffSec);
12459
+ const out = [];
12460
+ for (const row of rows) {
12461
+ const projectPath = row.git_repo_root || row.cwd || "";
12462
+ if (filter && !projectPath.toLowerCase().includes(filter))
12463
+ continue;
12464
+ const mtime = Math.round(row.mtime * 1e3);
12465
+ this._dbForSession.set(row.id, dbPath);
12466
+ out.push({
12467
+ toolId: "hermes",
12468
+ rawId: row.id,
12469
+ prefixedId: this.toPrefixedId(row.id),
12470
+ projectPath,
12471
+ projectDir: "",
12472
+ fullPath: dbPath,
12473
+ created: new Date(Math.round(row.started_at * 1e3)).toISOString(),
12474
+ modified: new Date(mtime).toISOString(),
12475
+ mtime,
12476
+ firstPrompt: opts.previews === false ? "" : firstUserPrompt(db, row.id),
12477
+ messageCount: opts.previews === false ? 0 : row.message_count ?? 0
12478
+ });
12479
+ if (opts.limit && out.length >= opts.limit)
12480
+ break;
12481
+ }
12482
+ return out;
12483
+ } catch {
12484
+ return [];
12485
+ } finally {
12486
+ db.close();
12487
+ }
12488
+ }
12489
+ /** Hermes writes a title for each session (a model-written one, or the
12490
+ * first prompt for a one-shot run). */
12491
+ getNativeTitle(rawId) {
12492
+ const path = this.dbPathFor(this.toRawId(rawId));
12493
+ if (!path)
12494
+ return null;
12495
+ const db = openSqliteReadonly(path);
12496
+ if (!db)
12497
+ return null;
12498
+ try {
12499
+ const row = db.prepare("SELECT title FROM sessions WHERE id = ?").get(this.toRawId(rawId));
12500
+ const t = row?.title?.trim();
12501
+ return t ? t.slice(0, 200) : null;
12502
+ } catch {
12503
+ return null;
12504
+ } finally {
12505
+ db.close();
12506
+ }
12507
+ }
12508
+ // ── Generic-engine inputs ───────────────────────────────────────
12509
+ fileToolMap = {
12510
+ write_file: "write",
12511
+ patch: "edit",
12512
+ read_file: "read"
12513
+ };
12514
+ /**
12515
+ * `write_file` carries `{ path, content }`. `patch` carries
12516
+ * `{ mode: 'replace', path, old_string, new_string }`; its other mode,
12517
+ * `patch`, is a multi-file V4A patch with no single before and after.
12518
+ */
12519
+ extractEditDelta(toolName, input) {
12520
+ if (input == null || typeof input !== "object")
12521
+ return null;
12522
+ const inp = input;
12523
+ if (toolName === "write_file") {
12524
+ return { before: "", after: typeof inp.content === "string" ? inp.content : null };
12525
+ }
12526
+ if (toolName === "patch" && (inp.mode === void 0 || inp.mode === "replace")) {
12527
+ const before = typeof inp.old_string === "string" ? inp.old_string : null;
12528
+ const after = typeof inp.new_string === "string" ? inp.new_string : null;
12529
+ if (before === null && after === null)
12530
+ return null;
12531
+ return { before, after };
12532
+ }
12533
+ return null;
12534
+ }
12535
+ readEvents(rawId) {
12536
+ const id = this.toRawId(rawId);
12537
+ const path = this.dbPathFor(id);
12538
+ if (!path)
12539
+ return [];
12540
+ const db = openSqliteReadonly(path);
12541
+ if (!db)
12542
+ return [];
12543
+ try {
12544
+ const rows = db.prepare(`SELECT ${MESSAGE_COLUMNS} FROM messages WHERE session_id = ? ORDER BY id`).all(id);
12545
+ return messageRowsToEvents(rows);
12546
+ } catch {
12547
+ return [];
12548
+ } finally {
12549
+ db.close();
12550
+ }
12551
+ }
12552
+ /**
12553
+ * Events from the dump `exportRawSession` writes, for a session rebuilt from
12554
+ * the server's archive. The archive joins the lines of every dump it got, so
12555
+ * a row that changed (a rewind sets `active` to 0) is there more than once.
12556
+ * The last copy of each row id is the newest.
12557
+ */
12558
+ readEventsFromText(text) {
12559
+ const rows = /* @__PURE__ */ new Map();
12560
+ for (const line of text.split("\n")) {
12561
+ if (!line.trim())
12562
+ continue;
12563
+ try {
12564
+ const rec = JSON.parse(line);
12565
+ if (rec.kind === "message" && rec.row) {
12566
+ rows.delete(rec.row.id);
12567
+ rows.set(rec.row.id, rec.row);
12568
+ }
12569
+ } catch {
12570
+ }
12571
+ }
12572
+ return messageRowsToEvents([...rows.values()].sort((a, b) => a.id - b.id));
12573
+ }
12574
+ // ── Per-session operations — all delegate to the generic engine ─
12575
+ extractTurns(id, opts = {}) {
12576
+ return extractTurnsFromEvents(this.toPrefixedId(id), this.readEvents(id), opts);
12577
+ }
12578
+ liveScanEdits(id) {
12579
+ const located = this.findSession(id);
12580
+ if (!located) {
12581
+ return { found: false, projectPath: "", projectDir: "", edits: [], fileMtime: 0, tool: "hermes" };
12582
+ }
12583
+ return liveScanEditsFromEvents(this.readEvents(id), this.fileToolMap, {
12584
+ sessionId: this.toPrefixedId(id),
12585
+ tool: "hermes",
12586
+ projectPath: located.projectPath,
12587
+ projectDir: located.projectDir,
12588
+ fileMtime: located.mtime,
12589
+ found: true
12590
+ });
12591
+ }
12592
+ replay(id) {
12593
+ const located = this.findSession(id);
12594
+ if (!located) {
12595
+ return { sessionId: this.toPrefixedId(id), found: false, projectPath: "", files: [], totalLinesAdded: 0, totalLinesRemoved: 0 };
12596
+ }
12597
+ return replayFromEvents(this.toPrefixedId(id), this.readEvents(id), this.fileToolMap, this.extractEditDelta.bind(this), {
12598
+ projectPath: located.projectPath,
12599
+ found: true
12600
+ });
12601
+ }
12602
+ computeOutcome(id, opts) {
12603
+ return computeOutcome(this.toPrefixedId(id), opts);
12604
+ }
12605
+ /** File edits since `sinceMs` across the sessions active since then. */
12606
+ collectRecentEdits(opts) {
12607
+ const refs = this.listSessions({ sinceMs: opts.sinceMs, projectFilter: opts.projectFilter, previews: false });
12608
+ const edits = [];
12609
+ for (const ref of opts.limitSessions ? refs.slice(0, opts.limitSessions) : refs) {
12610
+ for (const e of this.liveScanEdits(ref.rawId).edits) {
12611
+ if (e.ts >= opts.sinceMs)
12612
+ edits.push(e);
12613
+ }
12614
+ }
12615
+ return edits.sort((a, b) => b.ts - a.ts);
12616
+ }
12617
+ getCommits(id, files, startMs, endMs, bufferMinutes) {
12618
+ return getSessionCommits(this.toPrefixedId(id), files, startMs, endMs, bufferMinutes);
12619
+ }
12620
+ /**
12621
+ * The session row and its messages as JSONL, one row per line in id order.
12622
+ * Hermes rewrites and compacts its database, so the archive keeps the rows
12623
+ * as they were synced.
12624
+ */
12625
+ exportRawSession(id) {
12626
+ const rawId = this.toRawId(id);
12627
+ const path = this.dbPathFor(rawId);
12628
+ if (!path)
12629
+ return null;
12630
+ const db = openSqliteReadonly(path);
12631
+ if (!db)
12632
+ return null;
12633
+ try {
12634
+ const have = new Set(db.prepare(`SELECT name FROM pragma_table_info('sessions')`).all().map((c) => c.name));
12635
+ const cols = ARCHIVED_SESSION_COLUMNS.filter((c) => have.has(c)).map((c) => `s.${c}`);
12636
+ const session = db.prepare(`
12637
+ SELECT ${[...cols, `${SESSION_MTIME_SQL} AS mtime`].join(", ")}
12638
+ FROM sessions s WHERE s.id = ?
12639
+ `).get(rawId);
12640
+ if (!session)
12641
+ return null;
12642
+ const rows = db.prepare(`SELECT ${MESSAGE_COLUMNS} FROM messages WHERE session_id = ? ORDER BY id`).all(rawId);
12643
+ const lines = [JSON.stringify({ kind: "session", row: session })];
12644
+ for (const r of rows)
12645
+ lines.push(JSON.stringify({ kind: "message", row: r }));
12646
+ return {
12647
+ tool: "hermes",
12648
+ mtime: Math.round(Number(session.mtime || 0) * 1e3),
12649
+ files: [{ name: `${rawId}.dump.jsonl`, bytes: Buffer.from(lines.join("\n") + "\n", "utf-8") }]
12650
+ };
12651
+ } catch {
12652
+ return null;
12653
+ } finally {
12654
+ db.close();
12655
+ }
12656
+ }
12657
+ };
12658
+ hermesBackend = new HermesBackend();
12659
+ }
12660
+ });
12661
+
12078
12662
  // ../engine/dist/core/backends/index.js
12079
12663
  var backends_exports = {};
12080
12664
  __export(backends_exports, {
@@ -12082,6 +12666,7 @@ __export(backends_exports, {
12082
12666
  ClaudeBackend: () => ClaudeBackend,
12083
12667
  CodexBackend: () => CodexBackend,
12084
12668
  CursorBackend: () => CursorBackend,
12669
+ HermesBackend: () => HermesBackend,
12085
12670
  OpencodeBackend: () => OpencodeBackend,
12086
12671
  agyBackend: () => agyBackend,
12087
12672
  bootstrapBackends: () => bootstrapBackends,
@@ -12090,6 +12675,7 @@ __export(backends_exports, {
12090
12675
  cursorBackend: () => cursorBackend,
12091
12676
  getBackend: () => getBackend,
12092
12677
  getBackendForId: () => getBackendForId,
12678
+ hermesBackend: () => hermesBackend,
12093
12679
  listAllBackends: () => listAllBackends,
12094
12680
  listAvailableBackends: () => listAvailableBackends,
12095
12681
  opencodeBackend: () => opencodeBackend,
@@ -12102,6 +12688,7 @@ function bootstrapBackends() {
12102
12688
  registerBackend(codexBackend);
12103
12689
  registerBackend(agyBackend);
12104
12690
  registerBackend(cursorBackend);
12691
+ registerBackend(hermesBackend);
12105
12692
  }
12106
12693
  var init_backends = __esm({
12107
12694
  "../engine/dist/core/backends/index.js"() {
@@ -12112,6 +12699,7 @@ var init_backends = __esm({
12112
12699
  init_codex2();
12113
12700
  init_agy();
12114
12701
  init_cursor();
12702
+ init_hermes();
12115
12703
  init_tool_backend();
12116
12704
  _setRegistryBootstrapper(bootstrapBackends);
12117
12705
  }
@@ -12628,7 +13216,7 @@ var init_secret_redactor = __esm({
12628
13216
 
12629
13217
  // ../engine/dist/core/source-discovery.js
12630
13218
  import { createHash as createHash3 } from "crypto";
12631
- import { existsSync as existsSync16, readdirSync as readdirSync12, statSync as statSync14 } from "fs";
13219
+ import { existsSync as existsSync17, readdirSync as readdirSync12, statSync as statSync14 } from "fs";
12632
13220
  import { join as join18 } from "path";
12633
13221
  function sourceId(path) {
12634
13222
  return "src_" + createHash3("sha256").update(path).digest("hex").slice(0, 12);
@@ -12687,7 +13275,7 @@ function countTranscripts(root, tool) {
12687
13275
  walk(root, 0);
12688
13276
  return { sessions, newestMtime };
12689
13277
  }
12690
- function countOpencodeSessions(dbPath) {
13278
+ function countDbSessions(dbPath) {
12691
13279
  try {
12692
13280
  const st = statSync14(dbPath);
12693
13281
  return { sessions: 0, newestMtime: st.mtimeMs };
@@ -12705,18 +13293,24 @@ function discoverSessionSources() {
12705
13293
  ];
12706
13294
  for (const [tool, dirs] of dirTools) {
12707
13295
  for (const [i, path] of dirs.entries()) {
12708
- if (!existsSync16(path))
13296
+ if (!existsSync17(path))
12709
13297
  continue;
12710
13298
  const { sessions, newestMtime } = countTranscripts(path, tool);
12711
13299
  out.push({ id: sourceId(path), tool, path, sessions, newestMtime, isPrimary: i === 0 });
12712
13300
  }
12713
13301
  }
12714
13302
  for (const [i, path] of opencodeDbPaths({ includeExcluded: true }).entries()) {
12715
- if (!existsSync16(path))
13303
+ if (!existsSync17(path))
12716
13304
  continue;
12717
- const { sessions, newestMtime } = countOpencodeSessions(path);
13305
+ const { sessions, newestMtime } = countDbSessions(path);
12718
13306
  out.push({ id: sourceId(path), tool: "opencode", path, sessions, newestMtime, isPrimary: i === 0 });
12719
13307
  }
13308
+ for (const [i, path] of hermesDbPaths({ includeExcluded: true }).entries()) {
13309
+ if (!existsSync17(path))
13310
+ continue;
13311
+ const { sessions, newestMtime } = countDbSessions(path);
13312
+ out.push({ id: sourceId(path), tool: "hermes", path, sessions, newestMtime, isPrimary: i === 0 });
13313
+ }
12720
13314
  return out;
12721
13315
  }
12722
13316
  var excludedIds, SOURCE_ID_RE, MAX_DEPTH;
@@ -12732,7 +13326,7 @@ var init_source_discovery = __esm({
12732
13326
 
12733
13327
  // ../engine/dist/core/home-discovery.js
12734
13328
  import { execFileSync as execFileSync2 } from "child_process";
12735
- import { existsSync as existsSync17, readdirSync as readdirSync13, readFileSync as readFileSync12, realpathSync as realpathSync2, statSync as statSync15 } from "fs";
13329
+ import { existsSync as existsSync18, readdirSync as readdirSync13, readFileSync as readFileSync12, realpathSync as realpathSync2, statSync as statSync15 } from "fs";
12736
13330
  import { homedir as homedir5, platform as osPlatform } from "os";
12737
13331
  import { join as join19 } from "path";
12738
13332
  function candidateRoots(plat = osPlatform(), env = process.env) {
@@ -12753,10 +13347,10 @@ function candidateRoots(plat = osPlatform(), env = process.env) {
12753
13347
  add(env.XDG_CONFIG_HOME || join19(home, ".config"));
12754
13348
  add(env.XDG_DATA_HOME || join19(home, ".local", "share"));
12755
13349
  }
12756
- return roots.filter((r) => existsSync17(r));
13350
+ return roots.filter((r) => existsSync18(r));
12757
13351
  }
12758
13352
  function identifyHome(dir) {
12759
- const has = (...parts) => existsSync17(join19(dir, ...parts));
13353
+ const has = (...parts) => existsSync18(join19(dir, ...parts));
12760
13354
  if (has("projects") && dirHasTranscript(join19(dir, "projects"), (f) => f.endsWith(".jsonl"), 2))
12761
13355
  return "claude";
12762
13356
  if (has("sessions") && dirHasTranscript(join19(dir, "sessions"), (f) => f.startsWith("rollout-") && f.endsWith(".jsonl"), 4))
@@ -12767,6 +13361,8 @@ function identifyHome(dir) {
12767
13361
  return "cursor";
12768
13362
  if (has("opencode.db"))
12769
13363
  return "opencode";
13364
+ if (has("state.db") && has("SOUL.md"))
13365
+ return "hermes";
12770
13366
  return null;
12771
13367
  }
12772
13368
  function dirHasTranscript(root, match, depth) {
@@ -12794,7 +13390,8 @@ function countSessions(dir, tool) {
12794
13390
  codex: { sub: "sessions", depth: 4, match: (f) => f.startsWith("rollout-") && f.endsWith(".jsonl") },
12795
13391
  agy: { sub: "brain", depth: 4, match: (f) => f.endsWith(".jsonl") },
12796
13392
  cursor: { sub: "chats", depth: 3, match: (f) => f === "store.db" },
12797
- opencode: { sub: "", depth: 0, match: () => false }
13393
+ opencode: { sub: "", depth: 0, match: () => false },
13394
+ hermes: { sub: "", depth: 0, match: () => false }
12798
13395
  };
12799
13396
  const s = spec[tool];
12800
13397
  if (!s.sub)
@@ -12837,6 +13434,8 @@ function declaredHomes(env = process.env, plat = osPlatform()) {
12837
13434
  add(env.CHAT_RECALL_AGY_HOME);
12838
13435
  add(env.CHAT_RECALL_CURSOR_HOME);
12839
13436
  add(env.CHAT_RECALL_CURSOR_IDE_HOME);
13437
+ add(env.CHAT_RECALL_HERMES_HOME);
13438
+ add(env.HERMES_HOME);
12840
13439
  for (const d of (env.CLAUDE_DIRS || "").split(","))
12841
13440
  add(d);
12842
13441
  if (plat === "win32") {
@@ -12936,6 +13535,15 @@ function discoverHomes(opts = {}) {
12936
13535
  if (prior && !(via === "declared" && prior.via !== "declared"))
12937
13536
  return;
12938
13537
  found.set(real, { tool, path: real, via, sessions: countSessions(real, tool) });
13538
+ if (tool === "hermes") {
13539
+ try {
13540
+ for (const e of readdirSync13(join19(real, "profiles"), { withFileTypes: true })) {
13541
+ if (e.isDirectory())
13542
+ consider(join19(real, "profiles", e.name), via);
13543
+ }
13544
+ } catch {
13545
+ }
13546
+ }
12939
13547
  };
12940
13548
  for (const d of declaredHomes(env, plat))
12941
13549
  consider(d, "declared");
@@ -13002,7 +13610,7 @@ var init_home_discovery = __esm({
13002
13610
 
13003
13611
  // ../engine/dist/core/detector-install.js
13004
13612
  import { createHash as createHash4 } from "crypto";
13005
- import { existsSync as existsSync18, mkdirSync as mkdirSync5, mkdtempSync, chmodSync as chmodSync2, renameSync as renameSync3, rmSync as rmSync2, writeFileSync as writeFileSync4, readFileSync as readFileSync13, statSync as statSync16, copyFileSync as copyFileSync2 } from "fs";
13613
+ import { existsSync as existsSync19, mkdirSync as mkdirSync5, mkdtempSync, chmodSync as chmodSync2, renameSync as renameSync3, rmSync as rmSync2, writeFileSync as writeFileSync4, readFileSync as readFileSync13, statSync as statSync16, copyFileSync as copyFileSync2 } from "fs";
13006
13614
  import { join as join20 } from "path";
13007
13615
  function managedDetectorPath(name) {
13008
13616
  return join20(getDetectorBinDir(), name + exeSuffix());
@@ -13042,7 +13650,7 @@ function resolveDetector(name) {
13042
13650
  const dir = configuredDir();
13043
13651
  if (dir) {
13044
13652
  const p2 = join20(dir, name + exeSuffix());
13045
- if (existsSync18(p2))
13653
+ if (existsSync19(p2))
13046
13654
  return { path: p2, version: "operator-supplied", source: "configured" };
13047
13655
  return { error: "not-installed" };
13048
13656
  }
@@ -13050,7 +13658,7 @@ function resolveDetector(name) {
13050
13658
  if (!spec.assets[platformKey()])
13051
13659
  return { error: "unsupported-platform" };
13052
13660
  const p = managedDetectorPath(name);
13053
- if (!existsSync18(p))
13661
+ if (!existsSync19(p))
13054
13662
  return { error: "not-installed" };
13055
13663
  const receipt = readReceipt(name);
13056
13664
  if (!receipt)
@@ -13106,7 +13714,7 @@ var init_detector_install = __esm({
13106
13714
 
13107
13715
  // ../engine/dist/core/secret-scanner.js
13108
13716
  import { spawnSync } from "child_process";
13109
- import { existsSync as existsSync19, unlinkSync, readFileSync as readFileSync14, mkdtempSync as mkdtempSync2, rmSync as rmSync3 } from "fs";
13717
+ import { existsSync as existsSync20, unlinkSync, readFileSync as readFileSync14, mkdtempSync as mkdtempSync2, rmSync as rmSync3 } from "fs";
13110
13718
  import { tmpdir } from "os";
13111
13719
  import { join as join21 } from "path";
13112
13720
  function mask(s) {
@@ -13272,7 +13880,7 @@ function runTrufflehogDir(binary, dir, opts = {}) {
13272
13880
  return out;
13273
13881
  }
13274
13882
  function scanDirForSecrets(dir, opts = {}) {
13275
- if (!existsSync19(dir))
13883
+ if (!existsSync20(dir))
13276
13884
  return [];
13277
13885
  const gitleaks = whichDetector("gitleaks");
13278
13886
  const trufflehog = whichDetector("trufflehog");
@@ -13309,7 +13917,7 @@ function scanTenantRules(text, tenantRules) {
13309
13917
  return out;
13310
13918
  }
13311
13919
  function scanFileForSecrets(filePath, opts = {}) {
13312
- if (!existsSync19(filePath))
13920
+ if (!existsSync20(filePath))
13313
13921
  return [];
13314
13922
  const gitleaks = whichDetector("gitleaks");
13315
13923
  const trufflehog = whichDetector("trufflehog");
@@ -13426,10 +14034,10 @@ var init_types = __esm({
13426
14034
 
13427
14035
  // ../engine/dist/transcript/opencode.js
13428
14036
  async function parseOpenCodeSubagents(parentSessionId) {
13429
- const { existsSync: existsSync51 } = await import("fs");
14037
+ const { existsSync: existsSync52 } = await import("fs");
13430
14038
  const { opencodeBackend: opencodeBackend2 } = await Promise.resolve().then(() => (init_opencode(), opencode_exports));
13431
14039
  const dbPath = opencodeBackend2.dbPath();
13432
- if (!existsSync51(dbPath))
14040
+ if (!existsSync52(dbPath))
13433
14041
  return [];
13434
14042
  const realParent = parentSessionId.replace("opencode_", "");
13435
14043
  const db = openSqliteReadonlyOrThrow(dbPath);
@@ -13470,10 +14078,10 @@ async function parseOpenCodeSubagents(parentSessionId) {
13470
14078
  }
13471
14079
  }
13472
14080
  async function parseOpenCodeTranscript(sessionId) {
13473
- const { existsSync: existsSync51 } = await import("fs");
14081
+ const { existsSync: existsSync52 } = await import("fs");
13474
14082
  const { opencodeBackend: opencodeBackend2 } = await Promise.resolve().then(() => (init_opencode(), opencode_exports));
13475
14083
  const dbPath = opencodeBackend2.dbPath();
13476
- if (!existsSync51(dbPath))
14084
+ if (!existsSync52(dbPath))
13477
14085
  return [];
13478
14086
  const realId = sessionId.replace("opencode_", "");
13479
14087
  const db = openSqliteReadonlyOrThrow(dbPath);
@@ -13525,6 +14133,7 @@ var init_opencode2 = __esm({
13525
14133
  // ../engine/dist/transcript/index.js
13526
14134
  var transcript_exports = {};
13527
14135
  __export(transcript_exports, {
14136
+ RAW_PARSE_MAX_BYTES: () => RAW_PARSE_MAX_BYTES,
13528
14137
  TRANSCRIPT_VERSION: () => TRANSCRIPT_VERSION,
13529
14138
  archiveRawSession: () => archiveRawSession,
13530
14139
  buildRawContainer: () => buildRawContainer,
@@ -13703,7 +14312,7 @@ var init_transcript = __esm({
13703
14312
  // ../engine/dist/core/project-resolver.js
13704
14313
  import { execSync } from "child_process";
13705
14314
  import { createHash as createHash5 } from "crypto";
13706
- import { existsSync as existsSync20, readFileSync as readFileSync15, realpathSync as realpathSync3, readdirSync as readdirSync14, statSync as statSync18 } from "fs";
14315
+ import { existsSync as existsSync21, readFileSync as readFileSync15, realpathSync as realpathSync3, readdirSync as readdirSync14, statSync as statSync18 } from "fs";
13707
14316
  import { basename as basename11, dirname as dirname14, isAbsolute, join as join22, resolve, sep } from "path";
13708
14317
  function getProjectsConfigPath() {
13709
14318
  return join22(getDataDir(), "projects.json");
@@ -13713,7 +14322,7 @@ function loadProjectsConfig() {
13713
14322
  return cachedConfig.cfg;
13714
14323
  }
13715
14324
  const path = getProjectsConfigPath();
13716
- if (!existsSync20(path)) {
14325
+ if (!existsSync21(path)) {
13717
14326
  cachedConfig = { mtime: 0, cfg: {} };
13718
14327
  return cachedConfig.cfg;
13719
14328
  }
@@ -13853,7 +14462,7 @@ function findGitToplevel(realPath) {
13853
14462
  let cur = realPath;
13854
14463
  let last = "";
13855
14464
  while (cur && cur !== last) {
13856
- if (existsSync20(join22(cur, ".git")))
14465
+ if (existsSync21(join22(cur, ".git")))
13857
14466
  return cur;
13858
14467
  last = cur;
13859
14468
  cur = dirname14(cur);
@@ -13920,7 +14529,7 @@ function resolveAutoWorkspace(realPath, minRepos) {
13920
14529
  let last = "";
13921
14530
  let depth = 0;
13922
14531
  while (cur && cur !== last && depth < AUTO_WORKSPACE_MAX_DEPTH) {
13923
- if (!existsSync20(join22(cur, ".git"))) {
14532
+ if (!existsSync21(join22(cur, ".git"))) {
13924
14533
  const cached = workspaceCache.get(cur);
13925
14534
  let qualifies;
13926
14535
  if (cached === void 0) {
@@ -13956,7 +14565,7 @@ function countGitChildren(dir) {
13956
14565
  const st = statSync18(child);
13957
14566
  if (!st.isDirectory())
13958
14567
  continue;
13959
- if (existsSync20(join22(child, ".git")))
14568
+ if (existsSync21(join22(child, ".git")))
13960
14569
  count++;
13961
14570
  } catch {
13962
14571
  }
@@ -14569,7 +15178,7 @@ var init_source_policy = __esm({
14569
15178
  init_project_path_match();
14570
15179
  init_settings();
14571
15180
  cache2 = null;
14572
- TOOLS = ["claude", "opencode", "codex", "agy", "cursor"];
15181
+ TOOLS = ["claude", "opencode", "codex", "agy", "cursor", "hermes"];
14573
15182
  }
14574
15183
  });
14575
15184
 
@@ -14664,7 +15273,7 @@ var init_source_registry = __esm({
14664
15273
  });
14665
15274
 
14666
15275
  // ../engine/dist/core/utils.js
14667
- import { existsSync as existsSync21, readdirSync as readdirSync15 } from "fs";
15276
+ import { existsSync as existsSync22, readdirSync as readdirSync15 } from "fs";
14668
15277
  import { homedir as homedir6 } from "os";
14669
15278
  import { join as join23 } from "path";
14670
15279
  function splitByHeaders(markdown) {
@@ -14700,7 +15309,7 @@ function getClaudeDirs() {
14700
15309
  const dirs = [];
14701
15310
  const seen = /* @__PURE__ */ new Set();
14702
15311
  const add = (dir) => {
14703
- if (!seen.has(dir) && existsSync21(dir)) {
15312
+ if (!seen.has(dir) && existsSync22(dir)) {
14704
15313
  seen.add(dir);
14705
15314
  dirs.push(dir);
14706
15315
  }
@@ -14719,7 +15328,7 @@ function getClaudeDirs() {
14719
15328
  for (const entry of entries) {
14720
15329
  if (entry.isDirectory() && entry.name.startsWith(".claude-") && entry.name !== ".claude-code") {
14721
15330
  const candidate = join23(home, entry.name);
14722
- if (existsSync21(join23(candidate, "projects"))) {
15331
+ if (existsSync22(join23(candidate, "projects"))) {
14723
15332
  add(candidate);
14724
15333
  }
14725
15334
  }
@@ -14732,7 +15341,7 @@ function discoverSubdirs(subdir) {
14732
15341
  const result = [];
14733
15342
  for (const claudeDir of getClaudeDirs()) {
14734
15343
  const path = join23(claudeDir, subdir);
14735
- if (existsSync21(path)) {
15344
+ if (existsSync22(path)) {
14736
15345
  result.push(path);
14737
15346
  }
14738
15347
  }
@@ -14745,7 +15354,7 @@ var init_utils = __esm({
14745
15354
  });
14746
15355
 
14747
15356
  // ../engine/dist/parsers/plan-source.js
14748
- import { existsSync as existsSync22, readdirSync as readdirSync16, readFileSync as readFileSync16, statSync as statSync20 } from "fs";
15357
+ import { existsSync as existsSync23, readdirSync as readdirSync16, readFileSync as readFileSync16, statSync as statSync20 } from "fs";
14749
15358
  import { homedir as homedir7 } from "os";
14750
15359
  import { join as join24, basename as basename12 } from "path";
14751
15360
  function parseFrontmatter(content) {
@@ -14803,7 +15412,7 @@ var init_plan_source = __esm({
14803
15412
  return this._knownProjectDirs;
14804
15413
  const projectsDir = claudeBackend.projectsDir();
14805
15414
  this._knownProjectDirs = [];
14806
- if (!existsSync22(projectsDir))
15415
+ if (!existsSync23(projectsDir))
14807
15416
  return this._knownProjectDirs;
14808
15417
  try {
14809
15418
  const entries = readdirSync16(projectsDir, { withFileTypes: true });
@@ -14811,7 +15420,7 @@ var init_plan_source = __esm({
14811
15420
  if (!entry.isDirectory() || entry.name.startsWith("."))
14812
15421
  continue;
14813
15422
  const projectPath = resolveProjectDirName(entry.name);
14814
- if (existsSync22(projectPath)) {
15423
+ if (existsSync23(projectPath)) {
14815
15424
  this._knownProjectDirs.push(projectPath);
14816
15425
  }
14817
15426
  }
@@ -14835,7 +15444,7 @@ var init_plan_source = __esm({
14835
15444
  async *discoverClaudePlans() {
14836
15445
  const seenClaude = /* @__PURE__ */ new Set();
14837
15446
  for (const plansDir of this.plansDirs) {
14838
- if (!existsSync22(plansDir))
15447
+ if (!existsSync23(plansDir))
14839
15448
  continue;
14840
15449
  const files = readdirSync16(plansDir).filter((f) => f.endsWith(".md"));
14841
15450
  for (const file of files) {
@@ -14877,7 +15486,7 @@ var init_plan_source = __esm({
14877
15486
  }
14878
15487
  async *discoverOpenCodePlans() {
14879
15488
  const plansDir = opencodeBackend.plansDir();
14880
- if (!existsSync22(plansDir))
15489
+ if (!existsSync23(plansDir))
14881
15490
  return;
14882
15491
  let files;
14883
15492
  try {
@@ -14964,7 +15573,7 @@ var init_plan_source = __esm({
14964
15573
  return "";
14965
15574
  }
14966
15575
  async parse(item) {
14967
- if (!existsSync22(item.filePath))
15576
+ if (!existsSync23(item.filePath))
14968
15577
  return [];
14969
15578
  const content = readFileSync16(item.filePath, "utf-8");
14970
15579
  const chunks = [];
@@ -15005,7 +15614,7 @@ var init_plan_source = __esm({
15005
15614
  const projPath = join24(root, proj);
15006
15615
  for (const sessionEntry of safeReaddir(projPath)) {
15007
15616
  const subDir = join24(projPath, sessionEntry, "subagents");
15008
- if (!existsSync22(subDir))
15617
+ if (!existsSync23(subDir))
15009
15618
  continue;
15010
15619
  for (const f of safeReaddir(subDir)) {
15011
15620
  const m = f.match(/^agent-([a-z0-9_-]+)\.jsonl$/i);
@@ -15080,7 +15689,7 @@ var init_plan_source = __esm({
15080
15689
  }
15081
15690
  async *discoverAgyPlans() {
15082
15691
  const brainDir = join24(agyBackend.homeDir(), "brain");
15083
- if (!existsSync22(brainDir))
15692
+ if (!existsSync23(brainDir))
15084
15693
  return;
15085
15694
  let sessionDirs;
15086
15695
  try {
@@ -15135,7 +15744,7 @@ var init_plan_source = __esm({
15135
15744
  });
15136
15745
 
15137
15746
  // ../engine/dist/parsers/task-source.js
15138
- import { existsSync as existsSync23, readdirSync as readdirSync17, readFileSync as readFileSync17, statSync as statSync21 } from "fs";
15747
+ import { existsSync as existsSync24, readdirSync as readdirSync17, readFileSync as readFileSync17, statSync as statSync21 } from "fs";
15139
15748
  import { join as join25 } from "path";
15140
15749
  var MAX_CHUNK_CHARS2, TaskSource;
15141
15750
  var init_task_source = __esm({
@@ -15165,7 +15774,7 @@ var init_task_source = __esm({
15165
15774
  }
15166
15775
  async *discoverClaudeTodos() {
15167
15776
  const todosDir = claudeBackend.todosDir();
15168
- if (!existsSync23(todosDir))
15777
+ if (!existsSync24(todosDir))
15169
15778
  return;
15170
15779
  let files;
15171
15780
  try {
@@ -15216,7 +15825,7 @@ var init_task_source = __esm({
15216
15825
  }
15217
15826
  }
15218
15827
  async *discoverInDir(tasksDir) {
15219
- if (!existsSync23(tasksDir))
15828
+ if (!existsSync24(tasksDir))
15220
15829
  return;
15221
15830
  const entries = readdirSync17(tasksDir, { withFileTypes: true });
15222
15831
  for (const entry of entries) {
@@ -15258,7 +15867,7 @@ var init_task_source = __esm({
15258
15867
  return this.parseAgentTodo(item);
15259
15868
  }
15260
15869
  const taskDir = item.filePath;
15261
- if (!existsSync23(taskDir))
15870
+ if (!existsSync24(taskDir))
15262
15871
  return [];
15263
15872
  const taskFiles = readdirSync17(taskDir).filter((f) => f.endsWith(".json"));
15264
15873
  const tasks = this.readTasks(taskDir, taskFiles);
@@ -15319,7 +15928,7 @@ ${task.description}`.slice(0, MAX_CHUNK_CHARS2);
15319
15928
  }];
15320
15929
  }
15321
15930
  async parseAgentTodo(item) {
15322
- if (!existsSync23(item.filePath))
15931
+ if (!existsSync24(item.filePath))
15323
15932
  return [];
15324
15933
  let parsed;
15325
15934
  try {
@@ -15371,7 +15980,7 @@ ${task.description}`.slice(0, MAX_CHUNK_CHARS2);
15371
15980
  });
15372
15981
 
15373
15982
  // ../engine/dist/parsers/claude-md-source.js
15374
- import { existsSync as existsSync24, readFileSync as readFileSync18, readdirSync as readdirSync18, statSync as statSync22 } from "fs";
15983
+ import { existsSync as existsSync25, readFileSync as readFileSync18, readdirSync as readdirSync18, statSync as statSync22 } from "fs";
15375
15984
  import { homedir as homedir8 } from "os";
15376
15985
  import { join as join26, basename as basename13, dirname as dirname15 } from "path";
15377
15986
  import { createHash as createHash6 } from "crypto";
@@ -15379,13 +15988,13 @@ function discoverProjectDirs(claudeDir) {
15379
15988
  const dirs = [];
15380
15989
  const seen = /* @__PURE__ */ new Set();
15381
15990
  const addProject = (path) => {
15382
- if (!seen.has(path) && existsSync24(path)) {
15991
+ if (!seen.has(path) && existsSync25(path)) {
15383
15992
  seen.add(path);
15384
15993
  dirs.push(path);
15385
15994
  }
15386
15995
  };
15387
15996
  const scanProjectsDir = (projectsDir) => {
15388
- if (!existsSync24(projectsDir))
15997
+ if (!existsSync25(projectsDir))
15389
15998
  return;
15390
15999
  try {
15391
16000
  const entries = readdirSync18(projectsDir, { withFileTypes: true });
@@ -15413,7 +16022,7 @@ function discoverProjectDirs(claudeDir) {
15413
16022
  } catch {
15414
16023
  }
15415
16024
  const gemProjects = agyBackend.sharedProjectsJson();
15416
- if (existsSync24(gemProjects)) {
16025
+ if (existsSync25(gemProjects)) {
15417
16026
  try {
15418
16027
  const data = JSON.parse(readFileSync18(gemProjects, "utf-8"));
15419
16028
  for (const path of Object.keys(data.projects || {}))
@@ -15422,7 +16031,7 @@ function discoverProjectDirs(claudeDir) {
15422
16031
  }
15423
16032
  }
15424
16033
  const ocDb = opencodeBackend.dbPath();
15425
- if (existsSync24(ocDb)) {
16034
+ if (existsSync25(ocDb)) {
15426
16035
  try {
15427
16036
  const db = openSqliteReadonlyOrThrow(ocDb);
15428
16037
  try {
@@ -15473,7 +16082,7 @@ var init_claude_md_source = __esm({
15473
16082
  for (const note of NOTE_FILES) {
15474
16083
  const p = join26(homedir8(), note.filename);
15475
16084
  const key2 = seenKey(p, note.tool);
15476
- if (existsSync24(p) && !seen.has(key2)) {
16085
+ if (existsSync25(p) && !seen.has(key2)) {
15477
16086
  seen.add(key2);
15478
16087
  const item = this.fileToItem(p, note.filename, note.tool);
15479
16088
  if (item)
@@ -15485,7 +16094,7 @@ var init_claude_md_source = __esm({
15485
16094
  for (const note of NOTE_FILES) {
15486
16095
  const p = join26(projectDir, note.filename);
15487
16096
  const key2 = seenKey(p, note.tool);
15488
- if (existsSync24(p) && !seen.has(key2)) {
16097
+ if (existsSync25(p) && !seen.has(key2)) {
15489
16098
  seen.add(key2);
15490
16099
  const item = this.fileToItem(p, note.filename, note.tool);
15491
16100
  if (item)
@@ -15494,12 +16103,12 @@ var init_claude_md_source = __esm({
15494
16103
  }
15495
16104
  }
15496
16105
  for (const searchDir of this.searchDirs) {
15497
- if (!existsSync24(searchDir))
16106
+ if (!existsSync25(searchDir))
15498
16107
  continue;
15499
16108
  for (const note of NOTE_FILES) {
15500
16109
  const directPath = join26(searchDir, note.filename);
15501
16110
  const key2 = seenKey(directPath, note.tool);
15502
- if (existsSync24(directPath) && !seen.has(key2)) {
16111
+ if (existsSync25(directPath) && !seen.has(key2)) {
15503
16112
  seen.add(key2);
15504
16113
  const item = this.fileToItem(directPath, note.filename, note.tool);
15505
16114
  if (item)
@@ -15514,7 +16123,7 @@ var init_claude_md_source = __esm({
15514
16123
  for (const note of NOTE_FILES) {
15515
16124
  const p = join26(searchDir, entry.name, note.filename);
15516
16125
  const key2 = seenKey(p, note.tool);
15517
- if (existsSync24(p) && !seen.has(key2)) {
16126
+ if (existsSync25(p) && !seen.has(key2)) {
15518
16127
  seen.add(key2);
15519
16128
  const item = this.fileToItem(p, note.filename, note.tool);
15520
16129
  if (item)
@@ -15528,7 +16137,7 @@ var init_claude_md_source = __esm({
15528
16137
  }
15529
16138
  }
15530
16139
  async parse(item) {
15531
- if (!existsSync24(item.filePath))
16140
+ if (!existsSync25(item.filePath))
15532
16141
  return [];
15533
16142
  const content = readFileSync18(item.filePath, "utf-8");
15534
16143
  const chunks = [];
@@ -15597,7 +16206,7 @@ var init_claude_md_source = __esm({
15597
16206
  });
15598
16207
 
15599
16208
  // ../engine/dist/parsers/agent-memory-source.js
15600
- import { existsSync as existsSync25, readFileSync as readFileSync19, readdirSync as readdirSync19, statSync as statSync23 } from "fs";
16209
+ import { existsSync as existsSync26, readFileSync as readFileSync19, readdirSync as readdirSync19, statSync as statSync23 } from "fs";
15601
16210
  import { homedir as homedir9 } from "os";
15602
16211
  import { join as join27, basename as basename14 } from "path";
15603
16212
  function parseFrontmatter2(content) {
@@ -15631,7 +16240,7 @@ function discoverMemoryDirs() {
15631
16240
  const out = [];
15632
16241
  const seen = /* @__PURE__ */ new Set();
15633
16242
  const add = (memoryDir, projectHash) => {
15634
- if (!seen.has(memoryDir) && existsSync25(memoryDir)) {
16243
+ if (!seen.has(memoryDir) && existsSync26(memoryDir)) {
15635
16244
  seen.add(memoryDir);
15636
16245
  out.push({ memoryDir, projectHash });
15637
16246
  }
@@ -15647,7 +16256,7 @@ function discoverMemoryDirs() {
15647
16256
  } catch {
15648
16257
  }
15649
16258
  for (const projectsDir of claudeRoots) {
15650
- if (!existsSync25(projectsDir))
16259
+ if (!existsSync26(projectsDir))
15651
16260
  continue;
15652
16261
  try {
15653
16262
  for (const entry of readdirSync19(projectsDir, { withFileTypes: true })) {
@@ -15696,7 +16305,7 @@ var init_agent_memory_source = __esm({
15696
16305
  }
15697
16306
  }
15698
16307
  async parse(item) {
15699
- if (!existsSync25(item.filePath))
16308
+ if (!existsSync26(item.filePath))
15700
16309
  return [];
15701
16310
  const content = readFileSync19(item.filePath, "utf-8");
15702
16311
  const { body } = parseFrontmatter2(content);
@@ -15782,7 +16391,7 @@ var init_agent_memory_source = __esm({
15782
16391
  });
15783
16392
 
15784
16393
  // ../engine/dist/parsers/history-source.js
15785
- import { existsSync as existsSync26, readdirSync as readdirSync20, statSync as statSync24 } from "fs";
16394
+ import { existsSync as existsSync27, readdirSync as readdirSync20, statSync as statSync24 } from "fs";
15786
16395
  import { createReadStream as createReadStream3 } from "fs";
15787
16396
  import { createInterface as createInterface2 } from "readline";
15788
16397
  import { homedir as homedir10 } from "os";
@@ -15804,7 +16413,7 @@ var init_history_source = __esm({
15804
16413
  const home = homedir10();
15805
16414
  const paths = [];
15806
16415
  const tryAdd = (p) => {
15807
- if (existsSync26(p) && !paths.includes(p))
16416
+ if (existsSync27(p) && !paths.includes(p))
15808
16417
  paths.push(p);
15809
16418
  };
15810
16419
  tryAdd(claudeBackend.historyFile());
@@ -15822,7 +16431,7 @@ var init_history_source = __esm({
15822
16431
  async *discover() {
15823
16432
  if (!isSourceEnabled("claude", "history"))
15824
16433
  return;
15825
- const historyPath = this.historyPaths.find((p) => existsSync26(p));
16434
+ const historyPath = this.historyPaths.find((p) => existsSync27(p));
15826
16435
  if (!historyPath)
15827
16436
  return;
15828
16437
  const stat3 = statSync24(historyPath);
@@ -15918,7 +16527,7 @@ var init_history_source = __esm({
15918
16527
  async groupByProject() {
15919
16528
  const groups = /* @__PURE__ */ new Map();
15920
16529
  for (const historyPath of this.historyPaths) {
15921
- if (!existsSync26(historyPath))
16530
+ if (!existsSync27(historyPath))
15922
16531
  continue;
15923
16532
  const rl = createInterface2({
15924
16533
  input: createReadStream3(historyPath),
@@ -15966,7 +16575,7 @@ var init_history_source = __esm({
15966
16575
  });
15967
16576
 
15968
16577
  // ../engine/dist/parsers/paste-source.js
15969
- import { existsSync as existsSync27, readdirSync as readdirSync21, readFileSync as readFileSync20, statSync as statSync25 } from "fs";
16578
+ import { existsSync as existsSync28, readdirSync as readdirSync21, readFileSync as readFileSync20, statSync as statSync25 } from "fs";
15970
16579
  import { homedir as homedir11 } from "os";
15971
16580
  import { join as join29, basename as basename15 } from "path";
15972
16581
  var MAX_CHUNK_CHARS6, MAX_FILE_SIZE, PasteSource;
@@ -15987,7 +16596,7 @@ var init_paste_source = __esm({
15987
16596
  const home = homedir11();
15988
16597
  const dirs = [];
15989
16598
  const tryAdd = (p) => {
15990
- if (existsSync27(p) && !dirs.includes(p))
16599
+ if (existsSync28(p) && !dirs.includes(p))
15991
16600
  dirs.push(p);
15992
16601
  };
15993
16602
  tryAdd(claudeBackend.pasteCacheDir());
@@ -16007,7 +16616,7 @@ var init_paste_source = __esm({
16007
16616
  return;
16008
16617
  const seen = /* @__PURE__ */ new Set();
16009
16618
  for (const cacheDir of this.cacheDirs) {
16010
- if (!existsSync27(cacheDir))
16619
+ if (!existsSync28(cacheDir))
16011
16620
  continue;
16012
16621
  const files = readdirSync21(cacheDir).filter((f) => f.endsWith(".txt"));
16013
16622
  for (const file of files) {
@@ -16041,7 +16650,7 @@ var init_paste_source = __esm({
16041
16650
  }
16042
16651
  }
16043
16652
  async parse(item) {
16044
- if (!existsSync27(item.filePath))
16653
+ if (!existsSync28(item.filePath))
16045
16654
  return [];
16046
16655
  const content = readFileSync20(item.filePath, "utf-8");
16047
16656
  if (content.trim().length < 20)
@@ -16066,7 +16675,7 @@ var init_paste_source = __esm({
16066
16675
  });
16067
16676
 
16068
16677
  // ../engine/dist/parsers/antigravity-brain-source.js
16069
- import { existsSync as existsSync28, readdirSync as readdirSync22, readFileSync as readFileSync21, statSync as statSync26 } from "fs";
16678
+ import { existsSync as existsSync29, readdirSync as readdirSync22, readFileSync as readFileSync21, statSync as statSync26 } from "fs";
16070
16679
  import { join as join30 } from "path";
16071
16680
  var MAX_CHUNK_CHARS7, AntigravityBrainSource;
16072
16681
  var init_antigravity_brain_source = __esm({
@@ -16085,7 +16694,7 @@ var init_antigravity_brain_source = __esm({
16085
16694
  async *discover() {
16086
16695
  if (!isSourceEnabled("agy", "brain"))
16087
16696
  return;
16088
- if (!existsSync28(this.brainDir))
16697
+ if (!existsSync29(this.brainDir))
16089
16698
  return;
16090
16699
  const sessions = readdirSync22(this.brainDir, { withFileTypes: true });
16091
16700
  for (const entry of sessions) {
@@ -16104,7 +16713,7 @@ var init_antigravity_brain_source = __esm({
16104
16713
  const heading = content.split("\n").find((l) => l.startsWith("#"))?.replace(/^#+\s*/, "").trim() || file;
16105
16714
  const metaPath = `${filePath}.metadata.json`;
16106
16715
  let metaSummary = "";
16107
- if (existsSync28(metaPath)) {
16716
+ if (existsSync29(metaPath)) {
16108
16717
  try {
16109
16718
  const meta = JSON.parse(readFileSync21(metaPath, "utf-8"));
16110
16719
  metaSummary = meta.summary || "";
@@ -16135,7 +16744,7 @@ var init_antigravity_brain_source = __esm({
16135
16744
  }
16136
16745
  }
16137
16746
  async parse(item) {
16138
- if (!existsSync28(item.filePath))
16747
+ if (!existsSync29(item.filePath))
16139
16748
  return [];
16140
16749
  const content = readFileSync21(item.filePath, "utf-8");
16141
16750
  const chunks = [];
@@ -16178,7 +16787,7 @@ var init_antigravity_brain_source = __esm({
16178
16787
  });
16179
16788
 
16180
16789
  // ../engine/dist/parsers/opencode-source.js
16181
- import { existsSync as existsSync29 } from "fs";
16790
+ import { existsSync as existsSync30 } from "fs";
16182
16791
  var MAX_CHUNK_CHARS8, OpenCodeSource;
16183
16792
  var init_opencode_source = __esm({
16184
16793
  "../engine/dist/parsers/opencode-source.js"() {
@@ -16196,7 +16805,7 @@ var init_opencode_source = __esm({
16196
16805
  async *discover() {
16197
16806
  if (!isSourceEnabled("opencode", "sessions"))
16198
16807
  return;
16199
- if (!existsSync29(this.dbPath))
16808
+ if (!existsSync30(this.dbPath))
16200
16809
  return;
16201
16810
  let db;
16202
16811
  try {
@@ -16294,7 +16903,7 @@ var init_opencode_source = __esm({
16294
16903
  }
16295
16904
  }
16296
16905
  async parse(item) {
16297
- if (!existsSync29(this.dbPath))
16906
+ if (!existsSync30(this.dbPath))
16298
16907
  return [];
16299
16908
  const sessionId = item.id.replace("opencode_", "");
16300
16909
  const db = openSqliteReadonlyOrThrow(this.dbPath);
@@ -16366,7 +16975,7 @@ var init_opencode_source = __esm({
16366
16975
  });
16367
16976
 
16368
16977
  // ../engine/dist/parsers/opencode-todo-source.js
16369
- import { existsSync as existsSync30 } from "fs";
16978
+ import { existsSync as existsSync31 } from "fs";
16370
16979
  var OpenCodeTodoSource;
16371
16980
  var init_opencode_todo_source = __esm({
16372
16981
  "../engine/dist/parsers/opencode-todo-source.js"() {
@@ -16383,7 +16992,7 @@ var init_opencode_todo_source = __esm({
16383
16992
  async *discover() {
16384
16993
  if (!isSourceEnabled("opencode", "todos"))
16385
16994
  return;
16386
- if (!existsSync30(this.dbPath))
16995
+ if (!existsSync31(this.dbPath))
16387
16996
  return;
16388
16997
  let db;
16389
16998
  try {
@@ -16432,7 +17041,7 @@ var init_opencode_todo_source = __esm({
16432
17041
  }
16433
17042
  }
16434
17043
  async parse(item) {
16435
- if (!existsSync30(this.dbPath))
17044
+ if (!existsSync31(this.dbPath))
16436
17045
  return [];
16437
17046
  const sessionId = item.extra?.sessionId || item.id.replace(`${opencodeBackend.idPrefix}todo_`, "");
16438
17047
  const db = openSqliteReadonlyOrThrow(this.dbPath);
@@ -16480,7 +17089,7 @@ var init_opencode_todo_source = __esm({
16480
17089
  });
16481
17090
 
16482
17091
  // ../engine/dist/parsers/codex-session-source.js
16483
- import { existsSync as existsSync31, readdirSync as readdirSync23, readFileSync as readFileSync22, statSync as statSync27 } from "fs";
17092
+ import { existsSync as existsSync32, readdirSync as readdirSync23, readFileSync as readFileSync22, statSync as statSync27 } from "fs";
16484
17093
  import { join as join31, basename as basename16 } from "path";
16485
17094
  function getCodexSessionsDir() {
16486
17095
  return codexBackend.sessionsDir();
@@ -16537,7 +17146,7 @@ var init_codex_session_source = __esm({
16537
17146
  async *discover() {
16538
17147
  if (!isSourceEnabled("codex", "sessions"))
16539
17148
  return;
16540
- if (!existsSync31(this.sessionsDir))
17149
+ if (!existsSync32(this.sessionsDir))
16541
17150
  return;
16542
17151
  const jsonlFiles = this.collectJsonlFiles(this.sessionsDir);
16543
17152
  for (const filePath of jsonlFiles) {
@@ -16596,7 +17205,7 @@ var init_codex_session_source = __esm({
16596
17205
  }
16597
17206
  }
16598
17207
  async parse(item) {
16599
- if (!existsSync31(item.filePath))
17208
+ if (!existsSync32(item.filePath))
16600
17209
  return [];
16601
17210
  const events = readJsonlLines(item.filePath);
16602
17211
  const chunks = [];
@@ -16699,7 +17308,7 @@ var init_codex_session_source = __esm({
16699
17308
  }
16700
17309
  collectJsonlFiles(dir) {
16701
17310
  const results = [];
16702
- if (!existsSync31(dir))
17311
+ if (!existsSync32(dir))
16703
17312
  return results;
16704
17313
  for (const entry of readdirSync23(dir, { withFileTypes: true })) {
16705
17314
  const fullPath = join31(dir, entry.name);
@@ -16716,7 +17325,7 @@ var init_codex_session_source = __esm({
16716
17325
  });
16717
17326
 
16718
17327
  // ../engine/dist/parsers/diary-source.js
16719
- import { existsSync as existsSync32, mkdirSync as mkdirSync6, readdirSync as readdirSync24, readFileSync as readFileSync23, writeFileSync as writeFileSync5, statSync as statSync28 } from "fs";
17328
+ import { existsSync as existsSync33, mkdirSync as mkdirSync6, readdirSync as readdirSync24, readFileSync as readFileSync23, writeFileSync as writeFileSync5, statSync as statSync28 } from "fs";
16720
17329
  import { join as join32, basename as basename17 } from "path";
16721
17330
  var MAX_CHUNK_CHARS10, DiarySource;
16722
17331
  var init_diary_source = __esm({
@@ -16732,7 +17341,7 @@ var init_diary_source = __esm({
16732
17341
  }
16733
17342
  /** Discover all diary entries across all agents. */
16734
17343
  async *discover() {
16735
- if (!existsSync32(this.diaryDir))
17344
+ if (!existsSync33(this.diaryDir))
16736
17345
  return;
16737
17346
  const agents = readdirSync24(this.diaryDir, { withFileTypes: true }).filter((d) => d.isDirectory());
16738
17347
  for (const agentDir of agents) {
@@ -16767,7 +17376,7 @@ var init_diary_source = __esm({
16767
17376
  }
16768
17377
  }
16769
17378
  async parse(item) {
16770
- if (!existsSync32(item.filePath))
17379
+ if (!existsSync33(item.filePath))
16771
17380
  return [];
16772
17381
  const raw = readFileSync23(item.filePath, "utf-8");
16773
17382
  const entry = JSON.parse(raw);
@@ -16807,7 +17416,7 @@ var init_diary_source = __esm({
16807
17416
  static write(entry, diaryDir) {
16808
17417
  const dir = diaryDir || getDiaryDir();
16809
17418
  const agentDir = join32(dir, entry.agent.toLowerCase().replace(/[^a-z0-9_-]/g, "_"));
16810
- if (!existsSync32(agentDir)) {
17419
+ if (!existsSync33(agentDir)) {
16811
17420
  mkdirSync6(agentDir, { recursive: true });
16812
17421
  }
16813
17422
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
@@ -16826,7 +17435,7 @@ var init_diary_source = __esm({
16826
17435
  static read(agentName, lastN = 10, diaryDir) {
16827
17436
  const dir = diaryDir || getDiaryDir();
16828
17437
  const agentDir = join32(dir, agentName.toLowerCase().replace(/[^a-z0-9_-]/g, "_"));
16829
- if (!existsSync32(agentDir))
17438
+ if (!existsSync33(agentDir))
16830
17439
  return [];
16831
17440
  const files = readdirSync24(agentDir).filter((f) => f.endsWith(".json")).sort().reverse().slice(0, lastN);
16832
17441
  const entries = [];
@@ -16877,7 +17486,7 @@ var init_redact_inline = __esm({
16877
17486
  });
16878
17487
 
16879
17488
  // ../engine/dist/parsers/skills-source.js
16880
- import { existsSync as existsSync33, readdirSync as readdirSync25, readFileSync as readFileSync24, statSync as statSync29 } from "fs";
17489
+ import { existsSync as existsSync34, readdirSync as readdirSync25, readFileSync as readFileSync24, statSync as statSync29 } from "fs";
16881
17490
  import { homedir as homedir12 } from "os";
16882
17491
  import { join as join33 } from "path";
16883
17492
  function rebuildBody(content) {
@@ -16917,7 +17526,7 @@ function resolveRoots() {
16917
17526
  all.push({ path: join33(cursorHomeDir(), "skills"), tool: "cursor" });
16918
17527
  all.push({ path: join33(cursorHomeDir(), "skills-cursor"), tool: "cursor", readonly: true });
16919
17528
  }
16920
- return all.filter((r) => existsSync33(r.path));
17529
+ return all.filter((r) => existsSync34(r.path));
16921
17530
  }
16922
17531
  function parseFrontmatter3(text) {
16923
17532
  const m = text.match(/^---\n([\s\S]*?)\n---/);
@@ -16959,7 +17568,7 @@ var init_skills_source = __esm({
16959
17568
  return;
16960
17569
  for (const { name: pluginName, dir } of codexBackend.installedPluginDirs()) {
16961
17570
  const skillsDir = join33(dir, "skills");
16962
- if (!existsSync33(skillsDir))
17571
+ if (!existsSync34(skillsDir))
16963
17572
  continue;
16964
17573
  yield* this.fromSkillRoot({ path: skillsDir, tool: "codex" }, pluginName);
16965
17574
  }
@@ -16984,7 +17593,7 @@ var init_skills_source = __esm({
16984
17593
  if (!st.isDirectory())
16985
17594
  continue;
16986
17595
  const skillMd = join33(skillDir, "SKILL.md");
16987
- if (!existsSync33(skillMd))
17596
+ if (!existsSync34(skillMd))
16988
17597
  continue;
16989
17598
  let content;
16990
17599
  try {
@@ -17049,7 +17658,7 @@ var init_skills_source = __esm({
17049
17658
  }
17050
17659
  }
17051
17660
  async parse(item) {
17052
- if (!existsSync33(item.filePath))
17661
+ if (!existsSync34(item.filePath))
17053
17662
  return [];
17054
17663
  const content = readFileSync24(item.filePath, "utf-8");
17055
17664
  if (!content.trim())
@@ -17074,11 +17683,11 @@ var init_skills_source = __esm({
17074
17683
  });
17075
17684
 
17076
17685
  // ../engine/dist/parsers/mcps-source.js
17077
- import { existsSync as existsSync34, readFileSync as readFileSync25, statSync as statSync30 } from "fs";
17686
+ import { existsSync as existsSync35, readFileSync as readFileSync25, statSync as statSync30 } from "fs";
17078
17687
  import { homedir as homedir13 } from "os";
17079
17688
  import { join as join34 } from "path";
17080
17689
  function readJson(path) {
17081
- if (!existsSync34(path))
17690
+ if (!existsSync35(path))
17082
17691
  return null;
17083
17692
  try {
17084
17693
  const raw = readFileSync25(path, "utf-8");
@@ -17241,7 +17850,7 @@ var init_mcps_source = __esm({
17241
17850
  }
17242
17851
  }
17243
17852
  async *fromCodexToml(path) {
17244
- if (!existsSync34(path))
17853
+ if (!existsSync35(path))
17245
17854
  return;
17246
17855
  let content;
17247
17856
  try {
@@ -17414,7 +18023,7 @@ var init_toolkit_format = __esm({
17414
18023
  });
17415
18024
 
17416
18025
  // ../engine/dist/parsers/slash-commands-source.js
17417
- import { existsSync as existsSync35, readdirSync as readdirSync26, readFileSync as readFileSync26, statSync as statSync31 } from "fs";
18026
+ import { existsSync as existsSync36, readdirSync as readdirSync26, readFileSync as readFileSync26, statSync as statSync31 } from "fs";
17418
18027
  import { join as join35, basename as basename18 } from "path";
17419
18028
  function rebuildBody2(content) {
17420
18029
  const { text, redacted } = redactInlineSecrets(content);
@@ -17467,14 +18076,14 @@ var init_slash_commands_source = __esm({
17467
18076
  if (isSourceEnabled("claude", "commands")) {
17468
18077
  roots.push({ path: claudeBackend.commandsDir(), tool: "claude", scope: "user", projectPath: "", format: "md" });
17469
18078
  const projectsRoot = claudeBackend.projectsDir();
17470
- if (existsSync35(projectsRoot)) {
18079
+ if (existsSync36(projectsRoot)) {
17471
18080
  try {
17472
18081
  for (const entry of readdirSync26(projectsRoot, { withFileTypes: true })) {
17473
18082
  if (!entry.isDirectory() || entry.name.startsWith("."))
17474
18083
  continue;
17475
18084
  const projectPath = resolveProjectDirName(entry.name);
17476
18085
  const cmdDir = join35(projectPath, ".claude", "commands");
17477
- if (existsSync35(cmdDir))
18086
+ if (existsSync36(cmdDir))
17478
18087
  roots.push({ path: cmdDir, tool: "claude", scope: "project", projectPath, format: "md" });
17479
18088
  }
17480
18089
  } catch {
@@ -17536,7 +18145,7 @@ var init_slash_commands_source = __esm({
17536
18145
  }
17537
18146
  }
17538
18147
  async parse(item) {
17539
- if (!existsSync35(item.filePath))
18148
+ if (!existsSync36(item.filePath))
17540
18149
  return [];
17541
18150
  const content = readFileSync26(item.filePath, "utf-8");
17542
18151
  if (!content.trim())
@@ -17561,7 +18170,7 @@ var init_slash_commands_source = __esm({
17561
18170
  });
17562
18171
 
17563
18172
  // ../engine/dist/parsers/subagents-source.js
17564
- import { existsSync as existsSync36, readdirSync as readdirSync27, readFileSync as readFileSync27, statSync as statSync32 } from "fs";
18173
+ import { existsSync as existsSync37, readdirSync as readdirSync27, readFileSync as readFileSync27, statSync as statSync32 } from "fs";
17565
18174
  import { join as join36, basename as basename19 } from "path";
17566
18175
  function rebuildBody3(content) {
17567
18176
  const { text, redacted } = redactInlineSecrets(content);
@@ -17616,14 +18225,14 @@ var init_subagents_source = __esm({
17616
18225
  if (isSourceEnabled("claude", "agents")) {
17617
18226
  roots.push({ path: claudeBackend.agentsDir(), tool: "claude", scope: "user", projectPath: "", format: "md" });
17618
18227
  const projectsRoot = claudeBackend.projectsDir();
17619
- if (existsSync36(projectsRoot)) {
18228
+ if (existsSync37(projectsRoot)) {
17620
18229
  try {
17621
18230
  for (const entry of readdirSync27(projectsRoot, { withFileTypes: true })) {
17622
18231
  if (!entry.isDirectory() || entry.name.startsWith("."))
17623
18232
  continue;
17624
18233
  const projectPath = resolveProjectDirName(entry.name);
17625
18234
  const agentDir = join36(projectPath, ".claude", "agents");
17626
- if (existsSync36(agentDir))
18235
+ if (existsSync37(agentDir))
17627
18236
  roots.push({ path: agentDir, tool: "claude", scope: "project", projectPath, format: "md" });
17628
18237
  }
17629
18238
  } catch {
@@ -17686,7 +18295,7 @@ var init_subagents_source = __esm({
17686
18295
  }
17687
18296
  }
17688
18297
  async parse(item) {
17689
- if (!existsSync36(item.filePath))
18298
+ if (!existsSync37(item.filePath))
17690
18299
  return [];
17691
18300
  const content = readFileSync27(item.filePath, "utf-8");
17692
18301
  if (!content.trim())
@@ -17711,10 +18320,10 @@ var init_subagents_source = __esm({
17711
18320
  });
17712
18321
 
17713
18322
  // ../engine/dist/parsers/hooks-source.js
17714
- import { existsSync as existsSync37, readFileSync as readFileSync28, readdirSync as readdirSync28, statSync as statSync33 } from "fs";
18323
+ import { existsSync as existsSync38, readFileSync as readFileSync28, readdirSync as readdirSync28, statSync as statSync33 } from "fs";
17715
18324
  import { join as join37 } from "path";
17716
18325
  function readJson2(path) {
17717
- if (!existsSync37(path))
18326
+ if (!existsSync38(path))
17718
18327
  return null;
17719
18328
  try {
17720
18329
  return JSON.parse(readFileSync28(path, "utf-8"));
@@ -17736,14 +18345,14 @@ var init_hooks_source = __esm({
17736
18345
  return;
17737
18346
  yield* this.fromSettings(claudeBackend.settingsFile(), "user", "");
17738
18347
  const projectsRoot = claudeBackend.projectsDir();
17739
- if (existsSync37(projectsRoot)) {
18348
+ if (existsSync38(projectsRoot)) {
17740
18349
  try {
17741
18350
  for (const entry of readdirSync28(projectsRoot, { withFileTypes: true })) {
17742
18351
  if (!entry.isDirectory() || entry.name.startsWith("."))
17743
18352
  continue;
17744
18353
  const projectPath = resolveProjectDirName(entry.name);
17745
18354
  const settingsPath2 = join37(projectPath, ".claude", "settings.json");
17746
- if (existsSync37(settingsPath2)) {
18355
+ if (existsSync38(settingsPath2)) {
17747
18356
  yield* this.fromSettings(settingsPath2, "project", projectPath);
17748
18357
  }
17749
18358
  }
@@ -17834,11 +18443,11 @@ var init_hooks_source = __esm({
17834
18443
  });
17835
18444
 
17836
18445
  // ../engine/dist/parsers/plugins-source.js
17837
- import { existsSync as existsSync38, readFileSync as readFileSync29, readdirSync as readdirSync29, statSync as statSync34 } from "fs";
18446
+ import { existsSync as existsSync39, readFileSync as readFileSync29, readdirSync as readdirSync29, statSync as statSync34 } from "fs";
17838
18447
  import { homedir as homedir14 } from "os";
17839
18448
  import { join as join38 } from "path";
17840
18449
  function readJson3(path) {
17841
- if (!existsSync38(path))
18450
+ if (!existsSync39(path))
17842
18451
  return null;
17843
18452
  try {
17844
18453
  return JSON.parse(readFileSync29(path, "utf-8"));
@@ -17893,7 +18502,7 @@ var init_plugins_source = __esm({
17893
18502
  }
17894
18503
  }
17895
18504
  const gemRoot = agyBackend.sharedExtensionsDir();
17896
- if (isSourceEnabled("agy", "extensions") && existsSync38(gemRoot)) {
18505
+ if (isSourceEnabled("agy", "extensions") && existsSync39(gemRoot)) {
17897
18506
  let entries;
17898
18507
  try {
17899
18508
  entries = readdirSync29(gemRoot);
@@ -18069,6 +18678,8 @@ function toolOfId(id) {
18069
18678
  return "codex";
18070
18679
  if (id.startsWith("cursor_"))
18071
18680
  return "cursor";
18681
+ if (id.startsWith("hermes_"))
18682
+ return "hermes";
18072
18683
  return "claude";
18073
18684
  }
18074
18685
  function extractorVersionForTool(tool) {
@@ -18104,12 +18715,15 @@ var init_extractor_version = __esm({
18104
18715
  // src/sync-ledger.ts
18105
18716
  var sync_ledger_exports = {};
18106
18717
  __export(sync_ledger_exports, {
18718
+ SETTLE_QUIET_MS: () => SETTLE_QUIET_MS,
18107
18719
  _resetLedgerCacheForTests: () => _resetLedgerCacheForTests,
18108
18720
  _resetUnackedCursorCount: () => _resetUnackedCursorCount,
18109
18721
  fieldNeedsFullPass: () => fieldNeedsFullPass,
18110
18722
  fieldNeedsScan: () => fieldNeedsScan,
18111
18723
  flushLedger: () => flushLedger,
18112
18724
  forceFieldRescan: () => forceFieldRescan,
18725
+ forgetFullCoverage: () => forgetFullCoverage,
18726
+ fullCoveredOffset: () => fullCoveredOffset,
18113
18727
  getLedgerData: () => getLedgerData,
18114
18728
  getSyncedMtimes: () => getSyncedMtimes,
18115
18729
  getSyncedRows: () => getSyncedRows,
@@ -18361,6 +18975,13 @@ function markSynced(server, rows) {
18361
18975
  base3.s = s;
18362
18976
  }
18363
18977
  if (r.hash !== void 0) base3.h = r.hash;
18978
+ const completesChunked = cursorFromCaller && r.chunkFinal === true && prev?.k === 1;
18979
+ if (cursorFromCaller && (r.full || completesChunked) && o > 0) base3.F = o;
18980
+ else if (prev?.F !== void 0) base3.F = prev.F;
18981
+ if (cursorFromCaller && r.chunkedHead) base3.k = 1;
18982
+ else if (prev?.k && !completesChunked && !(cursorFromCaller && r.full)) base3.k = 1;
18983
+ const layout = cursorFromCaller ? r.layout : prev?.L;
18984
+ if (layout) base3.L = layout;
18364
18985
  forServer[r.id] = base3;
18365
18986
  }
18366
18987
  persist(data);
@@ -18434,6 +19055,14 @@ function _resetLedgerCacheForTests() {
18434
19055
  diskStamp = null;
18435
19056
  reconcileCache = null;
18436
19057
  }
19058
+ function forgetFullCoverage(server, sessionId) {
19059
+ const data = load();
19060
+ const row = data[server]?.[sessionId];
19061
+ if (!row || typeof row !== "object") return;
19062
+ delete row.F;
19063
+ delete row.h;
19064
+ persist(data);
19065
+ }
18437
19066
  function markFullResync(server, sessionId) {
18438
19067
  const data = load();
18439
19068
  const forServer = data[server];
@@ -18442,7 +19071,11 @@ function markFullResync(server, sessionId) {
18442
19071
  delete forServer[sessionId];
18443
19072
  persist(data);
18444
19073
  }
18445
- function syncMode(row, mtime, fileSize, extractorVersion, isAppendOnly) {
19074
+ function fullCoveredOffset(row) {
19075
+ if (row.F !== void 0) return row.F;
19076
+ return row.h ? row.s ?? 0 : 0;
19077
+ }
19078
+ function syncMode(row, mtime, fileSize, extractorVersion, isAppendOnly, nowMs = Date.now()) {
18446
19079
  if (!row) return "full";
18447
19080
  if (row.v < extractorVersion) return "full";
18448
19081
  const offset = row.o ?? 0;
@@ -18450,10 +19083,13 @@ function syncMode(row, mtime, fileSize, extractorVersion, isAppendOnly) {
18450
19083
  if (process.env.CHAT_RECALL_TAIL_APPEND !== "0" && isAppendOnly && fileSize > 0 && offset > 0 && fileSize > (row.s ?? 0)) {
18451
19084
  return "append";
18452
19085
  }
19086
+ if (isAppendOnly && offset > 0 && fileSize > 0 && fileSize === (row.s ?? 0) && !row.k && fullCoveredOffset(row) < offset && nowMs - Math.floor(mtime) >= SETTLE_QUIET_MS) {
19087
+ return "full";
19088
+ }
18453
19089
  if (row.m >= Math.floor(mtime)) return "skip";
18454
19090
  return "full";
18455
19091
  }
18456
- var ledgerPath, cache3, base, diskStamp, rowKey, LEDGER_FLUSH_MS, pendingWrite, flushTimer, itemVersionsPath, itemVersionsCache, inventoryPath, unackedCursorAttempts, reconcilePath, reconcileCache;
19092
+ var ledgerPath, cache3, base, diskStamp, rowKey, LEDGER_FLUSH_MS, pendingWrite, flushTimer, itemVersionsPath, itemVersionsCache, inventoryPath, unackedCursorAttempts, reconcilePath, reconcileCache, SETTLE_QUIET_MS;
18457
19093
  var init_sync_ledger = __esm({
18458
19094
  "src/sync-ledger.ts"() {
18459
19095
  "use strict";
@@ -18473,6 +19109,7 @@ var init_sync_ledger = __esm({
18473
19109
  unackedCursorAttempts = 0;
18474
19110
  reconcilePath = () => join39(getDataDir(), "sync-field-reconcile.json");
18475
19111
  reconcileCache = null;
19112
+ SETTLE_QUIET_MS = 2 * 60 * 60 * 1e3;
18476
19113
  }
18477
19114
  });
18478
19115
 
@@ -18502,12 +19139,12 @@ var init_sync_fields = __esm({
18502
19139
  });
18503
19140
 
18504
19141
  // ../engine/dist/core/index-lock.js
18505
- import { existsSync as existsSync39, mkdirSync as mkdirSync8, openSync as openSync8, writeFileSync as writeFileSync7, readFileSync as readFileSync31, rmSync as rmSync4, statSync as statSync36, closeSync as closeSync8 } from "fs";
19142
+ import { existsSync as existsSync40, mkdirSync as mkdirSync8, openSync as openSync8, writeFileSync as writeFileSync7, readFileSync as readFileSync31, rmSync as rmSync4, statSync as statSync36, closeSync as closeSync8 } from "fs";
18506
19143
  import { dirname as dirname17, join as join40 } from "path";
18507
19144
  function acquireIndexLock(opts) {
18508
19145
  const lockPath = lockFilePath(opts.file);
18509
19146
  mkdirSync8(dirname17(lockPath), { recursive: true });
18510
- if (existsSync39(lockPath)) {
19147
+ if (existsSync40(lockPath)) {
18511
19148
  if (!stealStaleLock(lockPath, opts.staleAfterMs ?? 10 * 6e4)) {
18512
19149
  return null;
18513
19150
  }
@@ -18615,7 +19252,7 @@ var init_http = __esm({
18615
19252
  CLI_VERSION = JSON.parse(readFileSync32(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
18616
19253
  } catch {
18617
19254
  try {
18618
- if (true) CLI_VERSION = "0.7.17";
19255
+ if (true) CLI_VERSION = "0.7.19";
18619
19256
  } catch {
18620
19257
  }
18621
19258
  }
@@ -18712,7 +19349,7 @@ var init_derived = __esm({
18712
19349
 
18713
19350
  // src/scan-pool.ts
18714
19351
  import { Worker } from "node:worker_threads";
18715
- import { existsSync as existsSync40 } from "node:fs";
19352
+ import { existsSync as existsSync41 } from "node:fs";
18716
19353
  import { fileURLToPath } from "node:url";
18717
19354
  import { cpus } from "node:os";
18718
19355
  function poolSize() {
@@ -18727,7 +19364,7 @@ function workerScript() {
18727
19364
  for (const rel of ["./scan-worker.js", "../dist/scan-worker.js"]) {
18728
19365
  try {
18729
19366
  const p = fileURLToPath(new URL(rel, import.meta.url));
18730
- if (existsSync40(p)) return p;
19367
+ if (existsSync41(p)) return p;
18731
19368
  } catch {
18732
19369
  }
18733
19370
  }
@@ -19109,7 +19746,7 @@ var init_telemetry = __esm({
19109
19746
  init_sync_client();
19110
19747
  cliVersion = () => {
19111
19748
  try {
19112
- return true ? "0.7.17" : "dev";
19749
+ return true ? "0.7.19" : "dev";
19113
19750
  } catch {
19114
19751
  return "dev";
19115
19752
  }
@@ -19119,6 +19756,150 @@ var init_telemetry = __esm({
19119
19756
  }
19120
19757
  });
19121
19758
 
19759
+ // src/raw-archive-parts.ts
19760
+ import { createReadStream as createReadStream4, createWriteStream, openSync as openSync9, readSync as readSync8, closeSync as closeSync9, rmSync as rmSync5, statSync as statSync37 } from "node:fs";
19761
+ import { tmpdir as tmpdir2 } from "node:os";
19762
+ import { join as join41 } from "node:path";
19763
+ import { randomBytes } from "node:crypto";
19764
+ import { createGzip } from "node:zlib";
19765
+ import { once } from "node:events";
19766
+ import { readFileSync as readFileSync33 } from "node:fs";
19767
+ async function* fileLines(path) {
19768
+ let rest = "";
19769
+ const decoder = new TextDecoder("utf-8");
19770
+ for await (const chunk of createReadStream4(path, { highWaterMark: 1024 * 1024 })) {
19771
+ rest += decoder.decode(chunk, { stream: true });
19772
+ let nl = rest.indexOf("\n");
19773
+ while (nl >= 0) {
19774
+ yield rest.slice(0, nl + 1);
19775
+ rest = rest.slice(nl + 1);
19776
+ nl = rest.indexOf("\n");
19777
+ }
19778
+ }
19779
+ rest += decoder.decode();
19780
+ if (rest) yield rest;
19781
+ }
19782
+ function* textLines(text) {
19783
+ let at = 0;
19784
+ while (at < text.length) {
19785
+ const nl = text.indexOf("\n", at);
19786
+ const end = nl < 0 ? text.length : nl + 1;
19787
+ yield text.slice(at, end);
19788
+ at = end;
19789
+ }
19790
+ }
19791
+ async function writeArchiveFile(source, meta, redact, dir = tmpdir2()) {
19792
+ const path = join41(dir, `cr-archive-${randomBytes(8).toString("hex")}.json.gz`);
19793
+ const gzip = createGzip({ level: 6 });
19794
+ const out = createWriteStream(path, { mode: 384 });
19795
+ const done = once(out, "finish");
19796
+ gzip.pipe(out);
19797
+ let size = 0;
19798
+ const write = async (s) => {
19799
+ size += Buffer.byteLength(s);
19800
+ if (!gzip.write(s)) await once(gzip, "drain");
19801
+ };
19802
+ try {
19803
+ await write(`{"v":1,"tool":${JSON.stringify(meta.tool)},"mtime":${Math.floor(meta.mtime)},"files":[`);
19804
+ for (const [i, f] of source.files.entries()) {
19805
+ await write(`${i ? "," : ""}{"name":${JSON.stringify(f.name)},"text":"`);
19806
+ const whole = () => source.kind === "memory" ? f.text : readFileSync33(f.path, "utf-8");
19807
+ if (!f.name.endsWith(".jsonl")) {
19808
+ await write(escapeJson(redact(whole())));
19809
+ } else {
19810
+ const lines = source.kind === "memory" ? textLines(f.text) : fileLines(f.path);
19811
+ for await (const line of lines) {
19812
+ const nl = line.endsWith("\n");
19813
+ const body = nl ? line.slice(0, -1) : line;
19814
+ await write(escapeJson((body ? redactJsonLine(body, redact) : body) + (nl ? "\n" : "")));
19815
+ }
19816
+ }
19817
+ await write('"}');
19818
+ }
19819
+ await write("]}");
19820
+ gzip.end();
19821
+ await done;
19822
+ } catch (err) {
19823
+ gzip.destroy();
19824
+ out.destroy();
19825
+ rmSync5(path, { force: true });
19826
+ throw err;
19827
+ }
19828
+ return { path, gzSize: statSync37(path).size, size };
19829
+ }
19830
+ async function putPart(url, body) {
19831
+ let last;
19832
+ for (let attempt = 1; attempt <= PART_ATTEMPTS; attempt++) {
19833
+ const ac = new AbortController();
19834
+ const timer = setTimeout(() => ac.abort(), PART_TIMEOUT_MS);
19835
+ try {
19836
+ const r = await fetch(url, { method: "PUT", body, signal: ac.signal });
19837
+ const etag = r.headers.get("etag");
19838
+ if (r.ok && etag) return etag;
19839
+ last = new Error(`part PUT answered ${r.status}`);
19840
+ if (r.status === 403 || r.status === 404) break;
19841
+ } catch (err) {
19842
+ last = err;
19843
+ } finally {
19844
+ clearTimeout(timer);
19845
+ }
19846
+ }
19847
+ throw last instanceof Error ? last : new Error(String(last));
19848
+ }
19849
+ async function uploadArchiveFile(base3, token, args) {
19850
+ const headers = { "content-type": "application/json" };
19851
+ if (token) headers.authorization = `Bearer ${token}`;
19852
+ const post = async (path, body) => {
19853
+ const r = await fetch(`${base3}/api/sync/raw-upload/${path}`, { method: "POST", headers, body: JSON.stringify(body) });
19854
+ const json = await r.json().catch(() => ({}));
19855
+ return { status: r.status, json };
19856
+ };
19857
+ const start = await post("start", {
19858
+ session_id: args.sessionId,
19859
+ tool: args.tool,
19860
+ mtime: Math.floor(args.mtime),
19861
+ size: args.file.size,
19862
+ gz_size: args.file.gzSize,
19863
+ project_id: args.projectId,
19864
+ project_path: args.projectPath
19865
+ });
19866
+ if (start.status === 501 || start.status === 404) return "unsupported";
19867
+ if (start.status !== 200) throw new Error(`raw upload start answered ${start.status}: ${start.json.error ?? ""}`);
19868
+ if (start.json.result === "unchanged" || start.json.result === "shrink-protected") return start.json.result;
19869
+ const urls = start.json.urls;
19870
+ const partBytes = Number(start.json.part_bytes);
19871
+ const parts = [];
19872
+ const fd = openSync9(args.file.path, "r");
19873
+ try {
19874
+ for (const [i, url] of urls.entries()) {
19875
+ const len = Math.min(partBytes, args.file.gzSize - i * partBytes);
19876
+ const buf = Buffer.allocUnsafe(len);
19877
+ let got = 0;
19878
+ while (got < len) {
19879
+ const n = readSync8(fd, buf, got, len - got, i * partBytes + got);
19880
+ if (n <= 0) break;
19881
+ got += n;
19882
+ }
19883
+ parts.push({ part_number: i + 1, etag: await putPart(url, buf.subarray(0, got)) });
19884
+ }
19885
+ } finally {
19886
+ closeSync9(fd);
19887
+ }
19888
+ const done = await post("complete", { session_id: args.sessionId, upload_id: start.json.upload_id, parts });
19889
+ if (done.status !== 200) throw new Error(`raw upload complete answered ${done.status}: ${done.json.error ?? ""}`);
19890
+ return done.json.result;
19891
+ }
19892
+ var escapeJson, PART_TIMEOUT_MS, PART_ATTEMPTS;
19893
+ var init_raw_archive_parts = __esm({
19894
+ "src/raw-archive-parts.ts"() {
19895
+ "use strict";
19896
+ init_transcript();
19897
+ escapeJson = (s) => JSON.stringify(s).slice(1, -1);
19898
+ PART_TIMEOUT_MS = 12e4;
19899
+ PART_ATTEMPTS = 3;
19900
+ }
19901
+ });
19902
+
19122
19903
  // src/server-probe.ts
19123
19904
  var server_probe_exports = {};
19124
19905
  __export(server_probe_exports, {
@@ -19262,7 +20043,7 @@ __export(client_events_exports, {
19262
20043
  isTelemetryEnabled: () => isTelemetryEnabled,
19263
20044
  reportClientEvent: () => reportClientEvent
19264
20045
  });
19265
- import { readFileSync as readFileSync33 } from "node:fs";
20046
+ import { readFileSync as readFileSync34 } from "node:fs";
19266
20047
  function scrub(msg) {
19267
20048
  if (!msg) return "";
19268
20049
  const noHome = msg.replace(/\/(?:home|Users)\/[^/\s]+/g, "~");
@@ -19315,7 +20096,7 @@ var init_client_events = __esm({
19315
20096
  init_secret_redactor();
19316
20097
  CLI_VERSION2 = "0.0.0";
19317
20098
  try {
19318
- CLI_VERSION2 = JSON.parse(readFileSync33(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION2;
20099
+ CLI_VERSION2 = JSON.parse(readFileSync34(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION2;
19319
20100
  } catch {
19320
20101
  }
19321
20102
  }
@@ -19345,11 +20126,11 @@ __export(auto_update_exports, {
19345
20126
  tarballUrl: () => tarballUrl
19346
20127
  });
19347
20128
  import { execSync as execSync2, execFileSync as execFileSync3 } from "node:child_process";
19348
- import { readFileSync as readFileSync34, existsSync as existsSync41 } from "node:fs";
20129
+ import { readFileSync as readFileSync35, existsSync as existsSync42 } from "node:fs";
19349
20130
  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";
20131
+ import { writeFileSync as writeFileSync8, mkdtempSync as mkdtempSync3, rmSync as rmSync6, readdirSync as readdirSync30, statSync as statSync38, mkdirSync as mkdirSync9 } from "node:fs";
20132
+ import { join as join42, dirname as dirname18, sep as sep2, posix as pathPosix, win32 as pathWin32 } from "node:path";
20133
+ import { tmpdir as tmpdir3, homedir as homedir15 } from "node:os";
19353
20134
  import { createHash as createHash7 } from "node:crypto";
19354
20135
  function compareVersions(a, b) {
19355
20136
  const pa = String(a).split("-")[0].split(".").map((n) => parseInt(n, 10) || 0);
@@ -19373,7 +20154,7 @@ function newerOf(a, b) {
19373
20154
  function installedVersion() {
19374
20155
  try {
19375
20156
  const here = dirname18(fileURLToPath2(import.meta.url));
19376
- const raw = readFileSync34(join41(here, "..", "package.json"), "utf-8");
20157
+ const raw = readFileSync35(join42(here, "..", "package.json"), "utf-8");
19377
20158
  return JSON.parse(raw).version || null;
19378
20159
  } catch {
19379
20160
  return null;
@@ -19386,7 +20167,7 @@ function planAutoUpdate(base3, caps, ownVersion3, flag) {
19386
20167
  if (compareVersions(rel.version, ownVersion3) <= 0) return { update: false, reason: `already current (own ${ownVersion3} >= server ${rel.version})` };
19387
20168
  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
20169
  }
19389
- function sweepStaleStaging(root = tmpdir2(), now = Date.now()) {
20170
+ function sweepStaleStaging(root = tmpdir3(), now = Date.now()) {
19390
20171
  const MKDTEMP_SUFFIX = /^cr-update-.{6}$/s;
19391
20172
  const COLD_MS = 60 * 60 * 1e3;
19392
20173
  let removed = 0;
@@ -19398,13 +20179,13 @@ function sweepStaleStaging(root = tmpdir2(), now = Date.now()) {
19398
20179
  }
19399
20180
  for (const name of entries) {
19400
20181
  if (!MKDTEMP_SUFFIX.test(name)) continue;
19401
- const dir = join41(root, name);
20182
+ const dir = join42(root, name);
19402
20183
  try {
19403
- const st = statSync37(dir);
20184
+ const st = statSync38(dir);
19404
20185
  if (!st.isDirectory() || now - st.mtimeMs < COLD_MS) continue;
19405
20186
  const inside = readdirSync30(dir);
19406
20187
  if (inside.length > 1 || inside.length === 1 && inside[0] !== "chat-recall.tgz") continue;
19407
- rmSync5(dir, { recursive: true, force: true });
20188
+ rmSync6(dir, { recursive: true, force: true });
19408
20189
  removed++;
19409
20190
  } catch {
19410
20191
  }
@@ -19427,14 +20208,14 @@ async function executeAutoUpdate(plan, deps) {
19427
20208
  }
19428
20209
  const got = createHash7("sha256").update(buf).digest("hex");
19429
20210
  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-"));
20211
+ const dir = mkdtempSync3(join42(tmpdir3(), "cr-update-"));
19431
20212
  const discardStaging = () => {
19432
20213
  try {
19433
- rmSync5(dir, { recursive: true, force: true });
20214
+ rmSync6(dir, { recursive: true, force: true });
19434
20215
  } catch {
19435
20216
  }
19436
20217
  };
19437
- const tgz = join41(dir, "chat-recall.tgz");
20218
+ const tgz = join42(dir, "chat-recall.tgz");
19438
20219
  writeFileSync8(tgz, buf);
19439
20220
  if (deps.stopping?.()) {
19440
20221
  discardStaging();
@@ -19506,7 +20287,7 @@ function resolveNpm(loc) {
19506
20287
  }
19507
20288
  function realInstall(tgz) {
19508
20289
  const prefix = runningPrefix();
19509
- const npm = resolveNpm({ execPath: process.execPath, prefix, platform: process.platform, env: process.env, exists: existsSync41 });
20290
+ const npm = resolveNpm({ execPath: process.execPath, prefix, platform: process.platform, env: process.env, exists: existsSync42 });
19510
20291
  if (prefix) {
19511
20292
  npmInstall(npm, ["install", "-g", "--prefix", prefix, tgz]);
19512
20293
  return;
@@ -19514,7 +20295,7 @@ function realInstall(tgz) {
19514
20295
  try {
19515
20296
  npmInstall(npm, ["install", "-g", tgz]);
19516
20297
  } catch {
19517
- npmInstall(npm, ["install", "-g", "--prefix", join41(homedir15(), ".local"), tgz]);
20298
+ npmInstall(npm, ["install", "-g", "--prefix", join42(homedir15(), ".local"), tgz]);
19518
20299
  }
19519
20300
  }
19520
20301
  function acquireUpdateLock() {
@@ -19531,12 +20312,12 @@ function realRestart(platform2) {
19531
20312
  if (c) execSync2(c.cmd, { stdio: "ignore", ...c.shell ? { shell: c.shell } : {} });
19532
20313
  }
19533
20314
  function updateStatePath() {
19534
- const dir = process.env.CHAT_RECALL_DATA_DIR || join41(homedir15(), ".chat-recall");
19535
- return join41(dir, "auto-update-state.json");
20315
+ const dir = process.env.CHAT_RECALL_DATA_DIR || join42(homedir15(), ".chat-recall");
20316
+ return join42(dir, "auto-update-state.json");
19536
20317
  }
19537
20318
  function readUpdateState() {
19538
20319
  try {
19539
- return JSON.parse(readFileSync34(updateStatePath(), "utf8"));
20320
+ return JSON.parse(readFileSync35(updateStatePath(), "utf8"));
19540
20321
  } catch {
19541
20322
  return {};
19542
20323
  }
@@ -19643,9 +20424,9 @@ var init_auto_update = __esm({
19643
20424
  });
19644
20425
 
19645
20426
  // 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";
20427
+ import { join as join43, dirname as dirname19, basename as basename20 } from "node:path";
20428
+ 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";
20429
+ import { tmpdir as tmpdir4, hostname as hostname2 } from "node:os";
19649
20430
  import { createHash as createHash8 } from "node:crypto";
19650
20431
  import { fileURLToPath as fileURLToPath3 } from "node:url";
19651
20432
  import { gzipSync as gzipSync3 } from "zlib";
@@ -19681,7 +20462,7 @@ function loadAllCredentials() {
19681
20462
  const fromEnv = envCredentials();
19682
20463
  if (fromEnv) return [{ serverUrl: fromEnv.serverUrl, token: fromEnv.token }];
19683
20464
  try {
19684
- const parsed = JSON.parse(readFileSync35(credPath(), "utf-8"));
20465
+ const parsed = JSON.parse(readFileSync36(credPath(), "utf-8"));
19685
20466
  if (Array.isArray(parsed?.targets)) return parsed.targets.filter((t) => t?.serverUrl).map((t) => ({ serverUrl: t.serverUrl, token: t.token || "" }));
19686
20467
  if (parsed?.serverUrl) return [{ serverUrl: parsed.serverUrl, token: parsed.token || "" }];
19687
20468
  } catch {
@@ -19740,11 +20521,11 @@ async function fetchTenantSecurityConfig(cred) {
19740
20521
  }
19741
20522
  }
19742
20523
  function syncConfigCachePath() {
19743
- return join42(getDataDir(), "sync-config-cache.json");
20524
+ return join43(getDataDir(), "sync-config-cache.json");
19744
20525
  }
19745
20526
  function readPersistedSyncConfigs() {
19746
20527
  try {
19747
- return JSON.parse(readFileSync35(syncConfigCachePath(), "utf-8"));
20528
+ return JSON.parse(readFileSync36(syncConfigCachePath(), "utf-8"));
19748
20529
  } catch {
19749
20530
  return {};
19750
20531
  }
@@ -19987,7 +20768,7 @@ async function reconcileFieldsForTarget(cred, fullRefs, opts = {}) {
19987
20768
  }
19988
20769
  return { pushed, absent, scanned };
19989
20770
  }
19990
- function reapStaleScanDirs(dir = tmpdir3(), maxAgeMs = 6 * 36e5, now = Date.now()) {
20771
+ function reapStaleScanDirs(dir = tmpdir4(), maxAgeMs = 6 * 36e5, now = Date.now()) {
19991
20772
  let reaped = 0;
19992
20773
  let names;
19993
20774
  try {
@@ -19997,10 +20778,10 @@ function reapStaleScanDirs(dir = tmpdir3(), maxAgeMs = 6 * 36e5, now = Date.now(
19997
20778
  }
19998
20779
  for (const name of names) {
19999
20780
  if (!name.startsWith("cr-batchscan-")) continue;
20000
- const p = join42(dir, name);
20781
+ const p = join43(dir, name);
20001
20782
  try {
20002
- if (now - statSync38(p).mtimeMs < maxAgeMs) continue;
20003
- rmSync6(p, { recursive: true, force: true });
20783
+ if (now - statSync39(p).mtimeMs < maxAgeMs) continue;
20784
+ rmSync7(p, { recursive: true, force: true });
20004
20785
  reaped++;
20005
20786
  } catch {
20006
20787
  }
@@ -20014,7 +20795,7 @@ function batchScanExternal(items, opts = {}) {
20014
20795
  let scanned = 0, slices = 0, scanMs = 0;
20015
20796
  if (items.length === 0) return { findings, scanned, slices, scanMs };
20016
20797
  reapStaleScanDirs();
20017
- let scanDir = mkdtempSync4(join42(tmpdir3(), "cr-batchscan-"));
20798
+ let scanDir = mkdtempSync4(join43(tmpdir4(), "cr-batchscan-"));
20018
20799
  let safeToId = /* @__PURE__ */ new Map();
20019
20800
  let bytesInDir = 0;
20020
20801
  const flushSlice = () => {
@@ -20032,7 +20813,7 @@ function batchScanExternal(items, opts = {}) {
20032
20813
  slices++;
20033
20814
  }
20034
20815
  try {
20035
- rmSync6(scanDir, { recursive: true, force: true });
20816
+ rmSync7(scanDir, { recursive: true, force: true });
20036
20817
  } catch {
20037
20818
  }
20038
20819
  safeToId = /* @__PURE__ */ new Map();
@@ -20045,19 +20826,19 @@ function batchScanExternal(items, opts = {}) {
20045
20826
  if (raw === null) continue;
20046
20827
  const safe = item.id.replace(/[^A-Za-z0-9_-]/g, "");
20047
20828
  safeToId.set(safe, item.id);
20048
- writeFileSync9(join42(scanDir, `${safe}.txt`), raw);
20829
+ writeFileSync9(join43(scanDir, `${safe}.txt`), raw);
20049
20830
  bytesInDir += Buffer.byteLength(raw);
20050
20831
  } catch {
20051
20832
  }
20052
20833
  if (bytesInDir >= maxBytes) {
20053
20834
  flushSlice();
20054
- scanDir = mkdtempSync4(join42(tmpdir3(), "cr-batchscan-"));
20835
+ scanDir = mkdtempSync4(join43(tmpdir4(), "cr-batchscan-"));
20055
20836
  }
20056
20837
  }
20057
20838
  flushSlice();
20058
20839
  } finally {
20059
20840
  try {
20060
- rmSync6(scanDir, { recursive: true, force: true });
20841
+ rmSync7(scanDir, { recursive: true, force: true });
20061
20842
  } catch {
20062
20843
  }
20063
20844
  }
@@ -20264,6 +21045,11 @@ async function syncToTargetInScope(cred, opts = {}) {
20264
21045
  };
20265
21046
  const localSessionIds = /* @__PURE__ */ new Set();
20266
21047
  const shippedHash = /* @__PURE__ */ new Map();
21048
+ const shippedLayout = /* @__PURE__ */ new Map();
21049
+ const layoutOf = (id) => {
21050
+ const layout = shippedLayout.get(id);
21051
+ return layout ? { layout } : {};
21052
+ };
20267
21053
  const makeBatcher = (field, maxItems, flatten = false, onFlush, barrier) => {
20268
21054
  let batch = [];
20269
21055
  let batchBytes = 0;
@@ -20296,12 +21082,13 @@ async function syncToTargetInScope(cred, opts = {}) {
20296
21082
  markSynced(base3, rows.map((r) => {
20297
21083
  const off = typeof r.from_offset === "number" ? r.from_offset : 0;
20298
21084
  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 };
21085
+ return off > 0 ? { id: r.session_id, mtime: r.mtime, offset: off, size: off, hash, acked: true, full: true, ...layoutOf(r.session_id) } : { id: r.session_id, mtime: r.mtime, hash };
20300
21086
  }));
20301
21087
  } catch {
20302
21088
  }
20303
21089
  });
20304
21090
  const appendResults = { uploaded: 0, fullResyncNeeded: /* @__PURE__ */ new Set() };
21091
+ const pendingArchives = [];
20305
21092
  const postAppend = async (convs) => {
20306
21093
  const headers = { "content-type": "application/json" };
20307
21094
  if (cred.token) headers.authorization = `Bearer ${cred.token}`;
@@ -20336,8 +21123,11 @@ async function syncToTargetInScope(cred, opts = {}) {
20336
21123
  offset: c.from_offset,
20337
21124
  size: c.from_offset,
20338
21125
  // size = new offset (file grew to here)
20339
- acked: true
21126
+ acked: true,
20340
21127
  // server merged this tail
21128
+ chunkFinal: c.final === true,
21129
+ // completes a chunked full sync
21130
+ ...layoutOf(c.session_id)
20341
21131
  })));
20342
21132
  } catch {
20343
21133
  }
@@ -20369,9 +21159,9 @@ async function syncToTargetInScope(cred, opts = {}) {
20369
21159
  const mtime = conv.mtime;
20370
21160
  try {
20371
21161
  if (staged || !guarded) {
20372
- markSynced(base3, [{ id, mtime, offset: conv.from_offset, size: conv.from_offset, acked: true }]);
21162
+ markSynced(base3, [{ id, mtime, offset: conv.from_offset, size: conv.from_offset, acked: true, chunkedHead: true, ...layoutOf(id) }]);
20373
21163
  } 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 }]);
21164
+ markSynced(base3, [{ id, mtime, offset: guarded.o, size: guarded.o, acked: true, chunkedHead: true, ...layoutOf(id) }]);
20375
21165
  } else {
20376
21166
  markSynced(base3, [{ id, mtime }]);
20377
21167
  }
@@ -20466,8 +21256,8 @@ async function syncToTargetInScope(cred, opts = {}) {
20466
21256
  if (!ledger) return ref.mtime >= (opts.sinceMs ?? 0) ? "full" : "skip";
20467
21257
  const ack = ledger.get(ref.prefixedId);
20468
21258
  const backend = backendFor(ref);
20469
- const split = !!backend?.spansMultipleSources?.(ref.prefixedId);
20470
- const isAO = !!backend?.isAppendOnly?.() && !split;
21259
+ const sameLayout = (ack?.L ?? "") === (backend?.sourceLayout?.(ref.prefixedId) ?? "");
21260
+ const isAO = !!backend?.isAppendOnly?.() && sameLayout;
20471
21261
  const size = isAO ? backend?.fileSize?.(ref.prefixedId) ?? 0 : 0;
20472
21262
  return syncMode(ack, ref.mtime, size, extractorVersionForTool(ref.toolId), isAO);
20473
21263
  };
@@ -20514,6 +21304,9 @@ async function syncToTargetInScope(cred, opts = {}) {
20514
21304
  skipped++;
20515
21305
  continue;
20516
21306
  }
21307
+ const layout = backendFor(ref)?.sourceLayout?.(ref.prefixedId) ?? "";
21308
+ if (layout) shippedLayout.set(ref.prefixedId, layout);
21309
+ else shippedLayout.delete(ref.prefixedId);
20517
21310
  trace?.(`build (${mode}) ${ref.prefixedId} \xB7 ${(sessionFileBytes(ref) / 1048576).toFixed(1)}MB`);
20518
21311
  let promotedForFindings = false;
20519
21312
  if (mode === "append" && ledger) {
@@ -20559,7 +21352,7 @@ async function syncToTargetInScope(cred, opts = {}) {
20559
21352
  const off = getBackendForId(ref.prefixedId)?.fileSize?.(ref.rawId) ?? 0;
20560
21353
  const priorCursor = ackRow?.s ?? 0;
20561
21354
  const safeToAck = off > 0 && off <= priorCursor;
20562
- markSynced(base3, [safeToAck ? { id: ref.prefixedId, mtime: ref.mtime, offset: off, size: off, hash: built.srcHash, acked: true } : { id: ref.prefixedId, mtime: ref.mtime, hash: built.srcHash }]);
21355
+ markSynced(base3, [safeToAck ? { id: ref.prefixedId, mtime: ref.mtime, offset: off, size: off, hash: built.srcHash, acked: true, ...layoutOf(ref.prefixedId) } : { id: ref.prefixedId, mtime: ref.mtime, hash: built.srcHash }]);
20563
21356
  } catch {
20564
21357
  }
20565
21358
  }
@@ -20580,6 +21373,14 @@ async function syncToTargetInScope(cred, opts = {}) {
20580
21373
  if (built.srcHash) shippedHash.set(ref.prefixedId, built.srcHash);
20581
21374
  if (built.conv.chunked) await postChunkedHead(built.conv, sessionFileBytes(ref));
20582
21375
  else await convBatch.add(built.conv);
21376
+ if (built.archive) {
21377
+ pendingArchives.push({
21378
+ id: ref.prefixedId,
21379
+ ...built.archive,
21380
+ projectId: built.conv.project_id,
21381
+ projectPath: built.conv.project_path
21382
+ });
21383
+ }
20583
21384
  if (built.findings.length > 0) await findingsBatch.add(built.findings);
20584
21385
  if (upload.sessionMeta) {
20585
21386
  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 +21533,30 @@ async function syncToTargetInScope(cred, opts = {}) {
20732
21533
  await kgTripleBatch.drain();
20733
21534
  await findingsBatch.drain();
20734
21535
  await drainInflight();
21536
+ let archivesUnsupported = false;
21537
+ for (const a of pendingArchives) {
21538
+ try {
21539
+ if (!archivesUnsupported) {
21540
+ const r = await uploadArchiveFile(base3, cred.token, {
21541
+ sessionId: a.id,
21542
+ tool: a.tool,
21543
+ mtime: a.mtime,
21544
+ projectId: a.projectId,
21545
+ projectPath: a.projectPath,
21546
+ file: a.file
21547
+ });
21548
+ if (r === "unsupported") archivesUnsupported = true;
21549
+ }
21550
+ } catch (err) {
21551
+ console.error(`[sync] raw archive for ${a.id} not uploaded (tried again when the session is next quiet): ${err instanceof Error ? err.message : err}`);
21552
+ try {
21553
+ forgetFullCoverage(base3, a.id);
21554
+ } catch {
21555
+ }
21556
+ } finally {
21557
+ rmSync7(a.file.path, { force: true });
21558
+ }
21559
+ }
20735
21560
  {
20736
21561
  const sentHashes = loadInventoryHashes(base3);
20737
21562
  const entries = [];
@@ -20837,6 +21662,7 @@ async function buildConversationSync(ref, mtime, opts = {}) {
20837
21662
  let includeRaw = opts.includeRaw !== false;
20838
21663
  let includeMeta = opts.includeMeta !== false;
20839
21664
  let srcHash;
21665
+ const wantRaw = opts.includeRaw !== false;
20840
21666
  const oversized = sessionBuildBytes(ref) > FULL_BUILD_MAX_BYTES;
20841
21667
  let headOffsetEnd = 0;
20842
21668
  let oversizedFindings = null;
@@ -21005,7 +21831,7 @@ async function buildConversationSync(ref, mtime, opts = {}) {
21005
21831
  } else if (opts.scanSecrets) {
21006
21832
  let tmp = null;
21007
21833
  try {
21008
- tmp = join42(tmpdir3(), `cr-scan-${ref.prefixedId.replace(/[^A-Za-z0-9_-]/g, "")}-${mtime}.txt`);
21834
+ tmp = join43(tmpdir4(), `cr-scan-${ref.prefixedId.replace(/[^A-Za-z0-9_-]/g, "")}-${mtime}.txt`);
21009
21835
  writeFileSync9(tmp, rawText);
21010
21836
  for (const f of scanFileForSecrets(tmp, { verifyOnly: opts.verifySecrets, tenantRules: opts.tenantRules })) {
21011
21837
  const verifiedAt = f.verified ? (/* @__PURE__ */ new Date()).toISOString() : null;
@@ -21057,6 +21883,25 @@ async function buildConversationSync(ref, mtime, opts = {}) {
21057
21883
  }
21058
21884
  const envTexts = envelope.messages.filter((m) => m.content?.trim());
21059
21885
  const redactedText = envTexts.map((m) => m.content).join("\n");
21886
+ let archive;
21887
+ if (wantRaw && !raw_b64) {
21888
+ try {
21889
+ const redact = (t) => redactSecrets(t, { force: true, count });
21890
+ let source = null;
21891
+ let archiveMtime = Math.floor(ref.mtime) || 0;
21892
+ let archiveTool = ref.toolId;
21893
+ if (container) {
21894
+ source = { kind: "memory", files: container.files };
21895
+ archiveMtime = container.mtime;
21896
+ archiveTool = container.tool;
21897
+ } else if (oversized) {
21898
+ source = diskArchiveSource(ref);
21899
+ }
21900
+ if (source) archive = { file: await writeArchiveFile(source, { tool: archiveTool, mtime: archiveMtime }, redact), tool: archiveTool, mtime: archiveMtime };
21901
+ } catch (err) {
21902
+ console.error(`[sync] raw archive for ${ref.prefixedId} not written: ${err instanceof Error ? err.message : err}`);
21903
+ }
21904
+ }
21060
21905
  return {
21061
21906
  conv: {
21062
21907
  session_id: ref.prefixedId,
@@ -21088,7 +21933,17 @@ async function buildConversationSync(ref, mtime, opts = {}) {
21088
21933
  redactions: count.redactions,
21089
21934
  findings,
21090
21935
  scanMs,
21091
- srcHash
21936
+ srcHash,
21937
+ archive
21938
+ };
21939
+ }
21940
+ function diskArchiveSource(ref) {
21941
+ if (ref.toolId !== "claude") return null;
21942
+ const groups = resolveSessionContentGroups(ref.rawId);
21943
+ if (groups.length === 0 || groups.some((g) => g.paths.length !== 1)) return null;
21944
+ return {
21945
+ kind: "disk",
21946
+ files: groups.map((g) => ({ name: g.name === "main" ? `${ref.rawId}.jsonl` : g.name, path: g.paths[0] }))
21092
21947
  };
21093
21948
  }
21094
21949
  function parseTailMessages(tool, text) {
@@ -21244,14 +22099,15 @@ var init_sync_client = __esm({
21244
22099
  init_telemetry();
21245
22100
  init_collector_health();
21246
22101
  init_live_session_scan();
22102
+ init_raw_archive_parts();
21247
22103
  init_backends();
21248
22104
  ownVersion = "0.0.0";
21249
22105
  try {
21250
22106
  const dir = dirname19(fileURLToPath3(import.meta.url));
21251
- ownVersion = JSON.parse(readFileSync35(join42(dir, "../package.json"), "utf-8")).version || ownVersion;
22107
+ ownVersion = JSON.parse(readFileSync36(join43(dir, "../package.json"), "utf-8")).version || ownVersion;
21252
22108
  } catch {
21253
22109
  try {
21254
- if (true) ownVersion = "0.7.17";
22110
+ if (true) ownVersion = "0.7.19";
21255
22111
  } catch {
21256
22112
  }
21257
22113
  }
@@ -21263,7 +22119,7 @@ var init_sync_client = __esm({
21263
22119
  ]);
21264
22120
  walkProgressForUpload = null;
21265
22121
  lastServerPackSpec = null;
21266
- credPath = () => join42(getDataDir(), "credentials.json");
22122
+ credPath = () => join43(getDataDir(), "credentials.json");
21267
22123
  _securityConfigCache = /* @__PURE__ */ new Map();
21268
22124
  SECURITY_CONFIG_TTL_MS = 5 * 60 * 1e3;
21269
22125
  _syncConfigCache = /* @__PURE__ */ new Map();
@@ -21286,8 +22142,8 @@ var init_sync_client = __esm({
21286
22142
  });
21287
22143
 
21288
22144
  // ../engine/dist/core/artifact-codec.js
21289
- import { readFileSync as readFileSync36 } from "fs";
21290
- import { basename as basename21, join as join43 } from "path";
22145
+ import { readFileSync as readFileSync37 } from "fs";
22146
+ import { basename as basename21, join as join44 } from "path";
21291
22147
  import { homedir as homedir16 } from "os";
21292
22148
  function parseCommandText(content, format, fallbackName) {
21293
22149
  if (format === "toml") {
@@ -21310,41 +22166,41 @@ function parseAgentText(content, format, fallbackName) {
21310
22166
  return { name: fm.name || fallbackName, description: fm.description || "", tools: fm.tools, body: body.trim() };
21311
22167
  }
21312
22168
  function readCommand(filePath, format) {
21313
- return parseCommandText(readFileSync36(filePath, "utf-8"), format, base2(filePath));
22169
+ return parseCommandText(readFileSync37(filePath, "utf-8"), format, base2(filePath));
21314
22170
  }
21315
22171
  function readAgent(filePath, format) {
21316
- return parseAgentText(readFileSync36(filePath, "utf-8"), format, base2(filePath));
22172
+ return parseAgentText(readFileSync37(filePath, "utf-8"), format, base2(filePath));
21317
22173
  }
21318
22174
  function readInstructions(filePath, name) {
21319
- const content = readFileSync36(filePath, "utf-8");
22175
+ const content = readFileSync37(filePath, "utf-8");
21320
22176
  return { name, description: "", body: content };
21321
22177
  }
21322
22178
  function commandPath(tool, name) {
21323
22179
  switch (tool) {
21324
22180
  case "claude":
21325
- return join43(claudeBackend.commandsDir(), `${name}.md`);
22181
+ return join44(claudeBackend.commandsDir(), `${name}.md`);
21326
22182
  case "agy":
21327
- return join43(join43(agyBackend.homeDir(), "commands"), `${name}.toml`);
22183
+ return join44(join44(agyBackend.homeDir(), "commands"), `${name}.toml`);
21328
22184
  case "opencode":
21329
- return join43(opencodeBackend.commandsDir(), `${name}.md`);
22185
+ return join44(opencodeBackend.commandsDir(), `${name}.md`);
21330
22186
  case "codex":
21331
- return join43(codexBackend.promptsDir(), `${name}.md`);
22187
+ return join44(codexBackend.promptsDir(), `${name}.md`);
21332
22188
  case "cursor":
21333
- return join43(cursorHomeDir(), "commands", `${name}.md`);
22189
+ return join44(cursorHomeDir(), "commands", `${name}.md`);
21334
22190
  }
21335
22191
  }
21336
22192
  function agentPath(tool, name) {
21337
22193
  switch (tool) {
21338
22194
  case "claude":
21339
- return join43(claudeBackend.agentsDir(), `${name}.md`);
22195
+ return join44(claudeBackend.agentsDir(), `${name}.md`);
21340
22196
  case "agy":
21341
- return join43(join43(agyBackend.homeDir(), "agents"), `${name}.md`);
22197
+ return join44(join44(agyBackend.homeDir(), "agents"), `${name}.md`);
21342
22198
  case "opencode":
21343
- return join43(opencodeBackend.agentsDir(), `${name}.md`);
22199
+ return join44(opencodeBackend.agentsDir(), `${name}.md`);
21344
22200
  case "codex":
21345
- return join43(codexBackend.agentsDir(), `${name}.toml`);
22201
+ return join44(codexBackend.agentsDir(), `${name}.toml`);
21346
22202
  case "cursor":
21347
- return join43(cursorHomeDir(), "agents", `${name}.md`);
22203
+ return join44(cursorHomeDir(), "agents", `${name}.md`);
21348
22204
  }
21349
22205
  }
21350
22206
  function instructionsFilename(tool) {
@@ -21369,21 +22225,21 @@ function instructionsFilename(tool) {
21369
22225
  function instructionsPath(tool, projectPath) {
21370
22226
  const file = instructionsFilename(tool);
21371
22227
  if (projectPath)
21372
- return join43(projectPath, file);
22228
+ return join44(projectPath, file);
21373
22229
  switch (tool) {
21374
22230
  case "claude":
21375
- return join43(claudeBackend.homeDir(), file);
22231
+ return join44(claudeBackend.homeDir(), file);
21376
22232
  case "agy":
21377
- return join43(agyBackend.homeDir(), file);
22233
+ return join44(agyBackend.homeDir(), file);
21378
22234
  case "codex":
21379
- return join43(codexBackend.homeDir(), file);
22235
+ return join44(codexBackend.homeDir(), file);
21380
22236
  case "opencode":
21381
- return join43(homedir16(), ".config", "opencode", file);
22237
+ return join44(homedir16(), ".config", "opencode", file);
21382
22238
  // Cursor has no single user-scope instructions FILE — user-level guidance
21383
22239
  // is User Rules plus ~/.cursor/rules/*.mdc. AGENTS.md at the home root is
21384
22240
  // the closest equivalent and is what a mirror can actually write.
21385
22241
  case "cursor":
21386
- return join43(cursorHomeDir(), file);
22242
+ return join44(cursorHomeDir(), file);
21387
22243
  }
21388
22244
  }
21389
22245
  function emit(type, art, toTool, projectPath) {
@@ -21429,8 +22285,8 @@ var init_artifact_codec = __esm({
21429
22285
  });
21430
22286
 
21431
22287
  // ../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";
22288
+ import { existsSync as existsSync43, mkdirSync as mkdirSync11, readFileSync as readFileSync38, writeFileSync as writeFileSync10, cpSync } from "fs";
22289
+ import { dirname as dirname20, join as join45, basename as basename22 } from "path";
21434
22290
  import { homedir as homedir17 } from "os";
21435
22291
  function rowFromMemoryItem(type, item) {
21436
22292
  const extra = item.extra || {};
@@ -21451,23 +22307,23 @@ function skillsDirFor(tool) {
21451
22307
  case "claude":
21452
22308
  return claudeBackend.skillsDir();
21453
22309
  case "agy":
21454
- return join44(agyBackend.homeDir(), "skills");
22310
+ return join45(agyBackend.homeDir(), "skills");
21455
22311
  case "opencode":
21456
22312
  return opencodeBackend.skillsDir();
21457
22313
  case "codex":
21458
22314
  return codexBackend.skillsDir();
21459
22315
  // user skills, NOT .system
21460
22316
  case "cursor":
21461
- return join44(cursorHomeDir(), "skills");
22317
+ return join45(cursorHomeDir(), "skills");
21462
22318
  }
21463
22319
  }
21464
22320
  function copySkill(row, toTool) {
21465
22321
  const skillDir = row.extra.skillDir || dirname20(row.filePath);
21466
- if (!existsSync42(skillDir))
22322
+ if (!existsSync43(skillDir))
21467
22323
  return { ok: false, status: 404, error: `Source dir missing: ${skillDir}` };
21468
22324
  const name = row.extra.skillName || basename22(skillDir);
21469
- const targetDir = join44(skillsDirFor(toTool), name);
21470
- if (existsSync42(targetDir))
22325
+ const targetDir = join45(skillsDirFor(toTool), name);
22326
+ if (existsSync43(targetDir))
21471
22327
  return { ok: false, status: 409, error: `Already exists: ${targetDir}` };
21472
22328
  try {
21473
22329
  mkdirSync11(dirname20(targetDir), { recursive: true });
@@ -21481,28 +22337,28 @@ function readMcpEntry(tool, name) {
21481
22337
  const home = homedir17();
21482
22338
  const tries = [];
21483
22339
  if (tool === "claude") {
21484
- tries.push({ path: join44(home, ".mcp.json"), key: "mcpServers" });
21485
- tries.push({ path: join44(home, ".claude.json"), key: "mcpServers" });
22340
+ tries.push({ path: join45(home, ".mcp.json"), key: "mcpServers" });
22341
+ tries.push({ path: join45(home, ".claude.json"), key: "mcpServers" });
21486
22342
  } else if (tool === "gemini") {
21487
- tries.push({ path: join44(home, ".gemini", "settings.json"), key: "mcpServers" });
22343
+ tries.push({ path: join45(home, ".gemini", "settings.json"), key: "mcpServers" });
21488
22344
  } else if (tool === "agy") {
21489
- tries.push({ path: join44(home, ".gemini", "config", "mcp_config.json"), key: "mcpServers" });
22345
+ tries.push({ path: join45(home, ".gemini", "config", "mcp_config.json"), key: "mcpServers" });
21490
22346
  } else if (tool === "cursor") {
21491
- tries.push({ path: join44(cursorHomeDir(), "mcp.json"), key: "mcpServers" });
22347
+ tries.push({ path: join45(cursorHomeDir(), "mcp.json"), key: "mcpServers" });
21492
22348
  } 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" });
22349
+ tries.push({ path: join45(home, ".config", "opencode", "opencode.json"), key: "mcp" });
22350
+ tries.push({ path: join45(home, ".config", "opencode", "config.json"), key: "mcp" });
22351
+ tries.push({ path: join45(home, ".opencode", "config.json"), key: "mcp" });
21496
22352
  } else if (tool === "codex") {
21497
- const entry = readCodexMcpEntry(join44(home, ".codex", "config.toml"), name);
22353
+ const entry = readCodexMcpEntry(join45(home, ".codex", "config.toml"), name);
21498
22354
  if (entry)
21499
22355
  return entry;
21500
22356
  }
21501
22357
  for (const t of tries) {
21502
- if (!existsSync42(t.path))
22358
+ if (!existsSync43(t.path))
21503
22359
  continue;
21504
22360
  try {
21505
- const cfg = JSON.parse(readFileSync37(t.path, "utf-8"));
22361
+ const cfg = JSON.parse(readFileSync38(t.path, "utf-8"));
21506
22362
  const block = cfg[t.key] || {};
21507
22363
  if (block[name])
21508
22364
  return block[name];
@@ -21512,11 +22368,11 @@ function readMcpEntry(tool, name) {
21512
22368
  return null;
21513
22369
  }
21514
22370
  function readCodexMcpEntry(path, target) {
21515
- if (!existsSync42(path))
22371
+ if (!existsSync43(path))
21516
22372
  return null;
21517
22373
  let content;
21518
22374
  try {
21519
- content = readFileSync37(path, "utf-8");
22375
+ content = readFileSync38(path, "utf-8");
21520
22376
  } catch {
21521
22377
  return null;
21522
22378
  }
@@ -21566,8 +22422,8 @@ function readCodexMcpEntry(path, target) {
21566
22422
  }
21567
22423
  function writeCodexMcpEntry(path, name, entry) {
21568
22424
  let content = "";
21569
- if (existsSync42(path))
21570
- content = readFileSync37(path, "utf-8");
22425
+ if (existsSync43(path))
22426
+ content = readFileSync38(path, "utf-8");
21571
22427
  const header = `[mcp_servers.${name}]`;
21572
22428
  if (content.includes(header))
21573
22429
  return false;
@@ -21603,7 +22459,7 @@ function writeCodexMcpEntry(path, name, entry) {
21603
22459
  function writeMcpEntry(toTool, name, entry) {
21604
22460
  const home = homedir17();
21605
22461
  if (toTool === "codex") {
21606
- const path2 = join44(home, ".codex", "config.toml");
22462
+ const path2 = join45(home, ".codex", "config.toml");
21607
22463
  if (!writeCodexMcpEntry(path2, name, entry))
21608
22464
  return { ok: false, status: 409, error: `MCP "${name}" already exists in ${path2}.` };
21609
22465
  return { ok: true, targetPath: path2 };
@@ -21611,22 +22467,22 @@ function writeMcpEntry(toTool, name, entry) {
21611
22467
  let path;
21612
22468
  let key2;
21613
22469
  if (toTool === "claude") {
21614
- path = join44(home, ".mcp.json");
22470
+ path = join45(home, ".mcp.json");
21615
22471
  key2 = "mcpServers";
21616
22472
  } else if (toTool === "agy") {
21617
- path = join44(home, ".gemini", "config", "mcp_config.json");
22473
+ path = join45(home, ".gemini", "config", "mcp_config.json");
21618
22474
  key2 = "mcpServers";
21619
22475
  } else if (toTool === "cursor") {
21620
- path = join44(cursorHomeDir(), "mcp.json");
22476
+ path = join45(cursorHomeDir(), "mcp.json");
21621
22477
  key2 = "mcpServers";
21622
22478
  } else {
21623
- path = join44(home, ".config", "opencode", "opencode.json");
22479
+ path = join45(home, ".config", "opencode", "opencode.json");
21624
22480
  key2 = "mcp";
21625
22481
  }
21626
22482
  let cfg = {};
21627
- if (existsSync42(path)) {
22483
+ if (existsSync43(path)) {
21628
22484
  try {
21629
- cfg = JSON.parse(readFileSync37(path, "utf-8"));
22485
+ cfg = JSON.parse(readFileSync38(path, "utf-8"));
21630
22486
  } catch {
21631
22487
  return { ok: false, status: 500, error: `Target config is malformed: ${path}` };
21632
22488
  }
@@ -21688,7 +22544,7 @@ function copyCommandOrAgent(type, row, toTool) {
21688
22544
  return { ok: false, status: 404, error: `Source unreadable: ${e instanceof Error ? e.message : "failed"}` };
21689
22545
  }
21690
22546
  const out = emit(type, art, toTool);
21691
- if (existsSync42(out.path))
22547
+ if (existsSync43(out.path))
21692
22548
  return { ok: false, status: 409, error: `Already exists: ${out.path}` };
21693
22549
  try {
21694
22550
  mkdirSync11(dirname20(out.path), { recursive: true });
@@ -21708,7 +22564,7 @@ function copyInstructions(row, toTool) {
21708
22564
  return { ok: false, status: 404, error: `Source unreadable: ${e instanceof Error ? e.message : "failed"}` };
21709
22565
  }
21710
22566
  const out = emit("instructions", art, toTool, row.projectPath || void 0);
21711
- if (existsSync42(out.path))
22567
+ if (existsSync43(out.path))
21712
22568
  return { ok: false, status: 409, error: `Already exists: ${out.path}` };
21713
22569
  try {
21714
22570
  mkdirSync11(dirname20(out.path), { recursive: true });
@@ -21851,11 +22707,11 @@ var init_toolkit_sync = __esm({
21851
22707
  });
21852
22708
 
21853
22709
  // ../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";
22710
+ import { existsSync as existsSync45, statSync as statSync41, accessSync, constants } from "node:fs";
22711
+ import { join as join47, isAbsolute as isAbsolute2, delimiter as delimiter2, sep as sep3 } from "node:path";
21856
22712
  function executable(p) {
21857
22713
  try {
21858
- if (!statSync40(p).isFile())
22714
+ if (!statSync41(p).isFile())
21859
22715
  return false;
21860
22716
  } catch {
21861
22717
  return false;
@@ -21891,8 +22747,8 @@ function resolveOnPath(name) {
21891
22747
  if (!dir)
21892
22748
  continue;
21893
22749
  for (const c of candidates(name)) {
21894
- const full = join46(dir, c);
21895
- if (existsSync44(full) && executable(full))
22750
+ const full = join47(dir, c);
22751
+ if (existsSync45(full) && executable(full))
21896
22752
  return full;
21897
22753
  }
21898
22754
  }
@@ -21918,11 +22774,11 @@ __export(toolkit_pull_exports, {
21918
22774
  platformRefusal: () => platformRefusal,
21919
22775
  portableCommand: () => portableCommand
21920
22776
  });
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";
22777
+ import { existsSync as existsSync46, mkdirSync as mkdirSync13, statSync as statSync42, writeFileSync as writeFileSync12 } from "node:fs";
22778
+ import { dirname as dirname22, join as join48, basename as basename23, isAbsolute as isAbsolute3 } from "node:path";
21923
22779
  function isExecutableFile(p) {
21924
22780
  try {
21925
- return statSync41(p).isFile();
22781
+ return statSync42(p).isFile();
21926
22782
  } catch {
21927
22783
  return false;
21928
22784
  }
@@ -22089,9 +22945,9 @@ function executePull(rows, opts = {}) {
22089
22945
  const outcomes = [];
22090
22946
  for (const { name, body, truncated, redacted, tools } of skills) {
22091
22947
  for (const tool of tools) {
22092
- const dir = join47(skillsDirFor(tool), name);
22093
- const file = join47(dir, "SKILL.md");
22094
- if (existsSync45(file)) {
22948
+ const dir = join48(skillsDirFor(tool), name);
22949
+ const file = join48(dir, "SKILL.md");
22950
+ if (existsSync46(file)) {
22095
22951
  outcomes.push({ type: "skill", name, tool, status: "present" });
22096
22952
  continue;
22097
22953
  }
@@ -22136,7 +22992,7 @@ function executePull(rows, opts = {}) {
22136
22992
  outcomes.push({ type, name, tool, status: "failed", reason: e instanceof Error ? e.message : "emit failed" });
22137
22993
  continue;
22138
22994
  }
22139
- if (existsSync45(out.path)) {
22995
+ if (existsSync46(out.path)) {
22140
22996
  outcomes.push({ type, name, tool, status: "present" });
22141
22997
  continue;
22142
22998
  }
@@ -22423,11 +23279,16 @@ async function repairAll(opts = {}) {
22423
23279
  scanned++;
22424
23280
  if (opts.verbose && scanned % 50 === 0) log6(`checked ${scanned}/${ids.length}\u2026`);
22425
23281
  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;
23282
+ const counted = arch && arch.messages !== null;
23283
+ if (counted) {
23284
+ const archiveMsgs = typeof arch?.messages === "number" ? arch.messages : 0;
23285
+ if (archiveMsgs < minMessages) continue;
23286
+ const meta = await fetchJson(`${primary.url}/api/conversations/${id}/metadata`, primary.token);
23287
+ const current = typeof meta?.messageCount === "number" ? meta.messageCount : 0;
23288
+ if (archiveMsgs <= current) continue;
23289
+ } else if (!arch) {
23290
+ continue;
23291
+ }
22431
23292
  const r = await repairSession(id, { dryRun: !opts.apply, verbose: opts.verbose, server: opts.server });
22432
23293
  if (r.status === "already-full") continue;
22433
23294
  candidates2.push(r);
@@ -22455,8 +23316,8 @@ __export(shadow_prune_exports, {
22455
23316
  DEFAULT_MAX_TOTAL_BYTES: () => DEFAULT_MAX_TOTAL_BYTES,
22456
23317
  pruneShadow: () => pruneShadow
22457
23318
  });
22458
- import { readdirSync as readdirSync32, statSync as statSync44, unlinkSync as unlinkSync3 } from "fs";
22459
- import { join as join50 } from "path";
23319
+ import { readdirSync as readdirSync32, statSync as statSync45, unlinkSync as unlinkSync3 } from "fs";
23320
+ import { join as join51 } from "path";
22460
23321
  function listShadows(isFullyAcked) {
22461
23322
  const out = [];
22462
23323
  const root = shadowRoot();
@@ -22467,7 +23328,7 @@ function listShadows(isFullyAcked) {
22467
23328
  return out;
22468
23329
  }
22469
23330
  for (const tool of tools) {
22470
- const dir = join50(root, tool);
23331
+ const dir = join51(root, tool);
22471
23332
  let names;
22472
23333
  try {
22473
23334
  names = readdirSync32(dir);
@@ -22477,10 +23338,10 @@ function listShadows(isFullyAcked) {
22477
23338
  for (const name of names) {
22478
23339
  if (!name.endsWith(".gz"))
22479
23340
  continue;
22480
- const path = join50(dir, name);
23341
+ const path = join51(dir, name);
22481
23342
  let st;
22482
23343
  try {
22483
- st = statSync44(path);
23344
+ st = statSync45(path);
22484
23345
  } catch {
22485
23346
  continue;
22486
23347
  }
@@ -22595,9 +23456,9 @@ var init_code_intel = __esm({
22595
23456
  });
22596
23457
 
22597
23458
  // ../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";
23459
+ import { existsSync as existsSync49, 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
23460
  import { homedir as homedir19 } from "node:os";
22600
- import { join as join51 } from "node:path";
23461
+ import { join as join52 } from "node:path";
22601
23462
  import { execSync as execSync3 } from "node:child_process";
22602
23463
  import { createHash as createHash13 } from "node:crypto";
22603
23464
  function expectedCodeindexSha256(artifact) {
@@ -22646,7 +23507,7 @@ function checkCodeindexStatus() {
22646
23507
  status.installed = true;
22647
23508
  status.path = foundPath;
22648
23509
  try {
22649
- status.size = statSync45(foundPath).size;
23510
+ status.size = statSync46(foundPath).size;
22650
23511
  } catch {
22651
23512
  }
22652
23513
  try {
@@ -22672,7 +23533,7 @@ async function downloadArtifact(artifact, dest) {
22672
23533
  throw new Error(`Download failed: ${res.status} ${res.statusText}`);
22673
23534
  if (!res.body)
22674
23535
  throw new Error("Download returned empty body");
22675
- const file = createWriteStream(dest);
23536
+ const file = createWriteStream2(dest);
22676
23537
  await new Promise((resolve3, reject) => {
22677
23538
  const reader = res.body.getReader();
22678
23539
  const pump = async () => {
@@ -22707,7 +23568,7 @@ async function installCodeindex(opts = {}) {
22707
23568
  if (!expected) {
22708
23569
  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
23570
  }
22710
- const actual = createHash13("sha256").update(readFileSync42(tmpPath)).digest("hex");
23571
+ const actual = createHash13("sha256").update(readFileSync43(tmpPath)).digest("hex");
22711
23572
  if (actual !== expected) {
22712
23573
  throw new Error(`Checksum mismatch for ${status.artifactName}.
22713
23574
  expected ${expected}
@@ -22718,7 +23579,7 @@ Refusing to install. The release may have been re-uploaded, or something is serv
22718
23579
  renameSync5(tmpPath, CODEINDEX_BIN_PATH);
22719
23580
  } catch (err) {
22720
23581
  try {
22721
- if (existsSync48(tmpPath))
23582
+ if (existsSync49(tmpPath))
22722
23583
  unlinkSync4(tmpPath);
22723
23584
  } catch {
22724
23585
  }
@@ -22741,9 +23602,9 @@ var init_companions = __esm({
22741
23602
  "x86_64-windows": "a96fc8c8949bb399a44cc0615b12e458460a529c69f01e8829cc39a20f45ab29",
22742
23603
  "aarch64-windows": "42620d56272cd9ba9d785569d8d754d6b4a3e80f36f28db3e0c483fd600ed117"
22743
23604
  };
22744
- CODEINDEX_INSTALL_DIR = join51(homedir19(), ".local", "bin");
23605
+ CODEINDEX_INSTALL_DIR = join52(homedir19(), ".local", "bin");
22745
23606
  CODEINDEX_BIN_NAME = process.platform === "win32" ? "codeindex.exe" : "codeindex";
22746
- CODEINDEX_BIN_PATH = join51(CODEINDEX_INSTALL_DIR, CODEINDEX_BIN_NAME);
23607
+ CODEINDEX_BIN_PATH = join52(CODEINDEX_INSTALL_DIR, CODEINDEX_BIN_NAME);
22747
23608
  }
22748
23609
  });
22749
23610
 
@@ -22858,8 +23719,8 @@ __export(collector_exports, {
22858
23719
  });
22859
23720
  import { spawn as spawn2 } from "node:child_process";
22860
23721
  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";
23722
+ import { readFileSync as readFileSync44 } from "node:fs";
23723
+ import { join as join53, basename as basename24 } from "node:path";
22863
23724
  async function resolveCodeindexBin(autoInstall = true) {
22864
23725
  let st = checkCodeindexStatus();
22865
23726
  if (!st.installed && autoInstall)
@@ -23041,7 +23902,7 @@ async function collectCode(opts) {
23041
23902
  }
23042
23903
  const complexity = (r) => {
23043
23904
  try {
23044
- const txt = readFileSync43(join52(ws, r), "utf8");
23905
+ const txt = readFileSync44(join53(ws, r), "utf8");
23045
23906
  if (txt.length > 2e6)
23046
23907
  return 1;
23047
23908
  const m = txt.match(CF_RE);
@@ -23805,15 +24666,15 @@ __export(service_installer_exports, {
23805
24666
  uninstallService: () => uninstallService
23806
24667
  });
23807
24668
  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";
24669
+ import { existsSync as existsSync50, mkdirSync as mkdirSync17, readFileSync as readFileSync45, rmSync as rmSync8, writeFileSync as writeFileSync16 } from "fs";
23809
24670
  import { homedir as homedir20 } from "os";
23810
- import { join as join53 } from "path";
24671
+ import { join as join54 } from "path";
23811
24672
  import { fileURLToPath as fileURLToPath5 } from "url";
23812
24673
  function resolveDaemonPaths() {
23813
24674
  const watchJs = fileURLToPath5(new URL("./watch.js", import.meta.url));
23814
24675
  const node = process.execPath;
23815
- const dataDir = join53(homedir20(), ".chat-recall");
23816
- const logFile = join53(dataDir, "watch.log");
24676
+ const dataDir = join54(homedir20(), ".chat-recall");
24677
+ const logFile = join54(dataDir, "watch.log");
23817
24678
  return { watchJs, node, logFile, dataDir };
23818
24679
  }
23819
24680
  function tryCmd(cmd) {
@@ -23840,12 +24701,12 @@ function refreshServiceDefinition() {
23840
24701
  if (process.platform !== "linux") return false;
23841
24702
  try {
23842
24703
  const { watchJs, node, logFile } = resolveDaemonPaths();
23843
- const unitPath = join53(homedir20(), ".config", "systemd", "user", "chat-recall-watch.service");
23844
- if (!existsSync49(unitPath)) return false;
23845
- const current = readFileSync44(unitPath, "utf8");
24704
+ const unitPath = join54(homedir20(), ".config", "systemd", "user", "chat-recall-watch.service");
24705
+ if (!existsSync50(unitPath)) return false;
24706
+ const current = readFileSync45(unitPath, "utf8");
23846
24707
  if (!current.includes(watchJs)) return false;
23847
24708
  const wanted = renderSystemdUnit(watchJs, node, logFile);
23848
- if (readFileSync44(unitPath, "utf8") === wanted) return false;
24709
+ if (readFileSync45(unitPath, "utf8") === wanted) return false;
23849
24710
  writeFileSync16(unitPath, wanted);
23850
24711
  execSync5("systemctl --user daemon-reload", { stdio: "ignore" });
23851
24712
  return true;
@@ -23871,8 +24732,8 @@ function installService() {
23871
24732
  );
23872
24733
  }
23873
24734
  function installSystemd(watchJs, node, logFile) {
23874
- const unitDir = join53(homedir20(), ".config", "systemd", "user");
23875
- const unitPath = join53(unitDir, "chat-recall-watch.service");
24735
+ const unitDir = join54(homedir20(), ".config", "systemd", "user");
24736
+ const unitPath = join54(unitDir, "chat-recall-watch.service");
23876
24737
  const unit = renderSystemdUnit(watchJs, node, logFile);
23877
24738
  mkdirSync17(unitDir, { recursive: true });
23878
24739
  writeFileSync16(unitPath, unit);
@@ -23951,8 +24812,8 @@ function renderSystemdUnit(watchJs, node, logFile) {
23951
24812
  }
23952
24813
  function installLaunchd(watchJs, node, logFile) {
23953
24814
  const label = "com.chat-recall.watch";
23954
- const plistDir = join53(homedir20(), "Library", "LaunchAgents");
23955
- const plistPath = join53(plistDir, `${label}.plist`);
24815
+ const plistDir = join54(homedir20(), "Library", "LaunchAgents");
24816
+ const plistPath = join54(plistDir, `${label}.plist`);
23956
24817
  const plist = renderLaunchdPlist(watchJs, node, logFile, label);
23957
24818
  mkdirSync17(plistDir, { recursive: true });
23958
24819
  writeFileSync16(plistPath, plist);
@@ -24008,9 +24869,9 @@ function uninstallService() {
24008
24869
  removed = true;
24009
24870
  } catch {
24010
24871
  }
24011
- const unitPath = join53(homedir20(), ".config", "systemd", "user", "chat-recall-watch.service");
24012
- if (existsSync49(unitPath)) {
24013
- rmSync7(unitPath, { force: true });
24872
+ const unitPath = join54(homedir20(), ".config", "systemd", "user", "chat-recall-watch.service");
24873
+ if (existsSync50(unitPath)) {
24874
+ rmSync8(unitPath, { force: true });
24014
24875
  removed = true;
24015
24876
  }
24016
24877
  try {
@@ -24020,14 +24881,14 @@ function uninstallService() {
24020
24881
  return removed;
24021
24882
  }
24022
24883
  if (process.platform === "darwin") {
24023
- const plistPath = join53(homedir20(), "Library", "LaunchAgents", "com.chat-recall.watch.plist");
24884
+ const plistPath = join54(homedir20(), "Library", "LaunchAgents", "com.chat-recall.watch.plist");
24024
24885
  try {
24025
24886
  execSync5(`launchctl unload "${plistPath}" 2>/dev/null`, { stdio: "ignore" });
24026
24887
  } catch {
24027
24888
  }
24028
24889
  let removed = false;
24029
- if (existsSync49(plistPath)) {
24030
- rmSync7(plistPath, { force: true });
24890
+ if (existsSync50(plistPath)) {
24891
+ rmSync8(plistPath, { force: true });
24031
24892
  removed = true;
24032
24893
  }
24033
24894
  return removed;
@@ -24071,7 +24932,7 @@ init_settings();
24071
24932
  init_sync_client();
24072
24933
  init_http();
24073
24934
  import chokidar from "chokidar";
24074
- import { dirname as dirname25, basename as basename25, join as join54, resolve as resolve2, sep as sep4 } from "path";
24935
+ import { dirname as dirname25, basename as basename25, join as join55, resolve as resolve2, sep as sep4 } from "path";
24075
24936
  import { homedir as homedir21 } from "os";
24076
24937
 
24077
24938
  // src/intent-drain.ts
@@ -24084,13 +24945,13 @@ init_codex2();
24084
24945
  init_cursor();
24085
24946
  init_opencode();
24086
24947
  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";
24948
+ import { existsSync as existsSync47, readFileSync as readFileSync40, writeFileSync as writeFileSync13, appendFileSync, mkdirSync as mkdirSync14 } from "node:fs";
24949
+ import { join as join49 } from "node:path";
24089
24950
 
24090
24951
  // src/project-tasks.ts
24091
24952
  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";
24953
+ import { existsSync as existsSync44, readFileSync as readFileSync39, writeFileSync as writeFileSync11, mkdirSync as mkdirSync12, statSync as statSync40 } from "node:fs";
24954
+ import { join as join46, dirname as dirname21 } from "node:path";
24094
24955
  import { homedir as homedir18 } from "node:os";
24095
24956
 
24096
24957
  // ../engine/dist/core/secret-task-status.js
@@ -24159,11 +25020,11 @@ function parseTaskFile(content) {
24159
25020
  return out;
24160
25021
  }
24161
25022
  function ledgerPath2() {
24162
- return join45(homedir18(), ".chat-recall", "project-tasks-ledger.json");
25023
+ return join46(homedir18(), ".chat-recall", "project-tasks-ledger.json");
24163
25024
  }
24164
25025
  function readLedger() {
24165
25026
  try {
24166
- return JSON.parse(readFileSync38(ledgerPath2(), "utf8"));
25027
+ return JSON.parse(readFileSync39(ledgerPath2(), "utf8"));
24167
25028
  } catch {
24168
25029
  return {};
24169
25030
  }
@@ -24196,18 +25057,18 @@ async function pushProjectTaskStatuses(base3, authHeaders, opts = {}) {
24196
25057
  continue;
24197
25058
  }
24198
25059
  for (const project of projects) {
24199
- const file = join45(project, fk.filename);
24200
- if (!existsSync43(file)) continue;
25060
+ const file = join46(project, fk.filename);
25061
+ if (!existsSync44(file)) continue;
24201
25062
  let mtime;
24202
25063
  try {
24203
- mtime = statSync39(file).mtimeMs;
25064
+ mtime = statSync40(file).mtimeMs;
24204
25065
  } catch {
24205
25066
  continue;
24206
25067
  }
24207
25068
  if (ledger[file] === mtime) continue;
24208
25069
  let changed;
24209
25070
  try {
24210
- changed = parseTaskFile(readFileSync38(file, "utf8")).filter((t) => t.kind === fk.kind);
25071
+ changed = parseTaskFile(readFileSync39(file, "utf8")).filter((t) => t.kind === fk.kind);
24211
25072
  } catch {
24212
25073
  continue;
24213
25074
  }
@@ -24258,16 +25119,16 @@ function instructionTargets(rootPath, isGlobal) {
24258
25119
  const tools = installed.length ? installed : [INSTRUCTION_TOOLS[0]];
24259
25120
  if (isGlobal) return [...new Set(tools.map((t) => instructionsPath(t.id)))];
24260
25121
  if (!rootPath) return [];
24261
- const present = INSTRUCTION_FILENAMES.map((f) => join48(rootPath, f)).filter((p) => existsSync46(p));
25122
+ const present = INSTRUCTION_FILENAMES.map((f) => join49(rootPath, f)).filter((p) => existsSync47(p));
24262
25123
  if (present.length) return present;
24263
- return [...new Set(tools.map((t) => join48(rootPath, instructionsFilename(t.id))))];
25124
+ return [...new Set(tools.map((t) => join49(rootPath, instructionsFilename(t.id))))];
24264
25125
  }
24265
25126
  function applyCodeRecommendation(intent) {
24266
25127
  try {
24267
25128
  const meta = JSON.parse(intent.name || "{}");
24268
25129
  if (intent.artifact_type === "write_tasks_file") {
24269
25130
  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");
25131
+ const file = join49(meta.rootPath, meta.filename || "CODE_TASKS.md");
24271
25132
  writeFileSync13(file, meta.content);
24272
25133
  return { status: "done", result: JSON.stringify({ wrote: file }) };
24273
25134
  }
@@ -24286,7 +25147,7 @@ function applyCodeRecommendation(intent) {
24286
25147
  mkdirSync14(dir, { recursive: true });
24287
25148
  } catch {
24288
25149
  }
24289
- const existing = existsSync46(file) ? readFileSync39(file, "utf8") : "";
25150
+ const existing = existsSync47(file) ? readFileSync40(file, "utf8") : "";
24290
25151
  if (existing.includes(text)) {
24291
25152
  skipped.push(file);
24292
25153
  continue;
@@ -24385,10 +25246,10 @@ async function runIntent(intent, ctx) {
24385
25246
  var ownVersion2 = "0.0.0";
24386
25247
  try {
24387
25248
  const dir = dirname23(fileURLToPath4(import.meta.url));
24388
- ownVersion2 = JSON.parse(readFileSync39(join48(dir, "../package.json"), "utf-8")).version || ownVersion2;
25249
+ ownVersion2 = JSON.parse(readFileSync40(join49(dir, "../package.json"), "utf-8")).version || ownVersion2;
24389
25250
  } catch {
24390
25251
  try {
24391
- if (true) ownVersion2 = "0.7.17";
25252
+ if (true) ownVersion2 = "0.7.19";
24392
25253
  } catch {
24393
25254
  }
24394
25255
  }
@@ -24453,14 +25314,14 @@ init_auto_update();
24453
25314
 
24454
25315
  // src/code-index-cursor.ts
24455
25316
  init_paths();
24456
- import { readFileSync as readFileSync40, writeFileSync as writeFileSync14, mkdirSync as mkdirSync15, statSync as statSync42 } from "fs";
25317
+ import { readFileSync as readFileSync41, writeFileSync as writeFileSync14, mkdirSync as mkdirSync15, statSync as statSync43 } from "fs";
24457
25318
  import { execFileSync as execFileSync4 } from "child_process";
24458
25319
  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");
25320
+ import { join as join50, dirname as dirname24 } from "path";
25321
+ var cursorPath = () => join50(getDataDir(), "code-index-cursor.json");
24461
25322
  function readCursor() {
24462
25323
  try {
24463
- const raw = JSON.parse(readFileSync40(cursorPath(), "utf-8"));
25324
+ const raw = JSON.parse(readFileSync41(cursorPath(), "utf-8"));
24464
25325
  if (raw && typeof raw === "object" && !Array.isArray(raw)) {
24465
25326
  const out = {};
24466
25327
  for (const [k, v] of Object.entries(raw)) {
@@ -24504,7 +25365,7 @@ function workspaceFingerprint(workspace, collectorVersion) {
24504
25365
  const rel = entry.slice(3);
24505
25366
  let stamp2 = "gone";
24506
25367
  try {
24507
- const s = statSync42(join49(workspace, rel));
25368
+ const s = statSync43(join50(workspace, rel));
24508
25369
  stamp2 = `${s.size}:${Math.floor(s.mtimeMs)}`;
24509
25370
  } catch {
24510
25371
  }
@@ -24640,13 +25501,13 @@ init_telemetry();
24640
25501
 
24641
25502
  // src/self-restart.ts
24642
25503
  import { spawn } from "child_process";
24643
- import { readFileSync as readFileSync41 } from "fs";
25504
+ import { readFileSync as readFileSync42 } from "fs";
24644
25505
  import { createHash as createHash11 } from "crypto";
24645
25506
  var EXIT_CODE_CODE_CHANGED = 75;
24646
25507
  function codeFingerprint(entry = process.argv[1]) {
24647
25508
  if (!entry) return null;
24648
25509
  try {
24649
- const buf = readFileSync41(entry);
25510
+ const buf = readFileSync42(entry);
24650
25511
  return {
24651
25512
  path: entry,
24652
25513
  size: buf.byteLength,
@@ -24713,11 +25574,11 @@ function checkSelfRestart(opts) {
24713
25574
  }
24714
25575
 
24715
25576
  // src/log-rotate.ts
24716
- import { statSync as statSync43, copyFileSync as copyFileSync3, truncateSync } from "fs";
25577
+ import { statSync as statSync44, copyFileSync as copyFileSync3, truncateSync } from "fs";
24717
25578
  var LOG_MAX_BYTES = 32 * 1024 * 1024;
24718
25579
  function rotateLogIfLarge(logPath, maxBytes = LOG_MAX_BYTES) {
24719
25580
  try {
24720
- const size = statSync43(logPath).size;
25581
+ const size = statSync44(logPath).size;
24721
25582
  if (size < maxBytes) return { rotated: false, sizeBefore: 0 };
24722
25583
  copyFileSync3(logPath, `${logPath}.1`);
24723
25584
  truncateSync(logPath, 0);
@@ -24729,8 +25590,8 @@ function rotateLogIfLarge(logPath, maxBytes = LOG_MAX_BYTES) {
24729
25590
 
24730
25591
  // src/collector-migrate.ts
24731
25592
  init_http();
24732
- import { existsSync as existsSync47 } from "node:fs";
24733
- function selectProjectsToReindex(projects, current, existsFn = existsSync47) {
25593
+ import { existsSync as existsSync48 } from "node:fs";
25594
+ function selectProjectsToReindex(projects, current, existsFn = existsSync48) {
24734
25595
  const reindex = [];
24735
25596
  const missing = [];
24736
25597
  for (const p of projects) {
@@ -24772,8 +25633,8 @@ async function runCollectorMigration(opts) {
24772
25633
  // auto-indexer/indexer.ts
24773
25634
  init_sync_ledger();
24774
25635
  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";
25636
+ import { existsSync as existsSync51, readFileSync as readFileSync46, statSync as statSync47 } from "fs";
25637
+ var CLI_VERSION3 = true ? "0.7.19" : "0.0.0";
24777
25638
  var DEBOUNCE_MS = 5e3;
24778
25639
  var PLANS_DIR = claudeBackend.plansDir();
24779
25640
  var TASKS_DIR = claudeBackend.tasksDir();
@@ -24782,8 +25643,8 @@ var DIARY_DIR = getDiaryDir();
24782
25643
  var CODEX_SESSIONS_DIR = codexBackend.sessionsDir();
24783
25644
  var OPENCODE_DB_PATH = opencodeBackend.dbPath();
24784
25645
  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");
25646
+ var CURRENT_RESUME_PATH = join55(claudeBackend.homeDir(), "current-resume");
25647
+ var LAST_CLEANUP_PATH = join55(claudeBackend.homeDir(), ".last-cleanup");
24787
25648
  var debounceTimer = null;
24788
25649
  var ticks = new TickQueue({
24789
25650
  onError: (kind, err) => daemonLog.error(`${kind} tick failed: ${err instanceof Error ? err.message : err}`)
@@ -24832,7 +25693,7 @@ var lastResumeAt = /* @__PURE__ */ new Map();
24832
25693
  var RESUME_REARM_MS = 6e4;
24833
25694
  async function onResumeSignal(path) {
24834
25695
  try {
24835
- const txt = readFileSync45(path, "utf-8");
25696
+ const txt = readFileSync46(path, "utf-8");
24836
25697
  const m = /--resume\s+([0-9a-fA-F-]{36})/.exec(txt);
24837
25698
  if (!m) return;
24838
25699
  const id = m[1];
@@ -24878,7 +25739,7 @@ var CLAUDE_SESSION_ROOTS = claudeProjectDirs();
24878
25739
  var sessionWatcher = watchWithFallback("sessions", CLAUDE_SESSION_ROOTS.map((root) => `${root}/**/*.jsonl`), {
24879
25740
  ignored: (p, stats) => {
24880
25741
  if (/agent-/.test(p) || /^\./.test(basename25(p))) return true;
24881
- const st = stats ?? statSync46(p, { throwIfNoEntry: false });
25742
+ const st = stats ?? statSync47(p, { throwIfNoEntry: false });
24882
25743
  if (!st || st.isDirectory()) return false;
24883
25744
  return st.mtimeMs < Date.now() - WATCH_WINDOW_MS;
24884
25745
  },
@@ -24925,6 +25786,16 @@ var opencodeWatcher = chokidar.watch(
24925
25786
  ...POLL(1e4)
24926
25787
  }
24927
25788
  );
25789
+ var HERMES_DB_PATHS = hermesBackend.dbPaths();
25790
+ var hermesWatcher = chokidar.watch(
25791
+ HERMES_DB_PATHS.flatMap((p) => [p, `${p}-wal`]),
25792
+ {
25793
+ persistent: true,
25794
+ ignoreInitial: true,
25795
+ awaitWriteFinish: { stabilityThreshold: 2500, pollInterval: 500 },
25796
+ ...POLL(1e4)
25797
+ }
25798
+ );
24928
25799
  var agentMemoryWatcher = chokidar.watch(CLAUDE_SESSION_ROOTS.map((root) => `${root}/*/memory/*.md`), {
24929
25800
  persistent: true,
24930
25801
  ignoreInitial: true,
@@ -24945,6 +25816,7 @@ var watchers = {
24945
25816
  diary: diaryWatcher,
24946
25817
  codex: codexWatcher,
24947
25818
  opencode: opencodeWatcher,
25819
+ hermes: hermesWatcher,
24948
25820
  agentMemory: agentMemoryWatcher,
24949
25821
  cleanup: cleanupWatcher
24950
25822
  };
@@ -24980,6 +25852,7 @@ daemonLog.info(` Watching history: ${HISTORY_PATH}`);
24980
25852
  daemonLog.info(` Watching diary: ${DIARY_DIR}`);
24981
25853
  daemonLog.info(` Watching codex: ${CODEX_SESSIONS_DIR}`);
24982
25854
  daemonLog.info(` Watching opencode: ${OPENCODE_DB_DIR}`);
25855
+ daemonLog.info(` Watching hermes: ${HERMES_DB_PATHS.join(", ")}`);
24983
25856
  daemonLog.info(` Watching agent memory: ${CLAUDE_SESSION_ROOTS.map((root) => `${root}/*/memory/`).join(", ")}`);
24984
25857
  daemonLog.info(` Resume-guard: ${CURRENT_RESUME_PATH}`);
24985
25858
  daemonLog.info(` Debounce: ${DEBOUNCE_MS}ms \xB7 ships via syncIncremental() to the configured server`);
@@ -25020,7 +25893,7 @@ if (BOOT_CODE) {
25020
25893
  daemonLog.info(`running bundle ${BOOT_CODE.path} (${BOOT_CODE.size} bytes)`);
25021
25894
  }
25022
25895
  {
25023
- const r = rotateLogIfLarge(join54(getDataDir(), "watch.log"));
25896
+ const r = rotateLogIfLarge(join55(getDataDir(), "watch.log"));
25024
25897
  if (r.rotated) {
25025
25898
  daemonLog.info(`rotated watch.log at ${(r.sizeBefore / 1048576).toFixed(0)}MB \u2192 watch.log.1 (copy+truncate; the path is preserved)`);
25026
25899
  }
@@ -25174,7 +26047,7 @@ function discoverWorkspaces() {
25174
26047
  const isExcluded = (p) => excluded.some((x) => p.includes(x));
25175
26048
  const candidates2 = [...newest.entries()].filter(([p]) => !isExcluded(p)).filter(([p]) => !isPersonalPath(p, includeProjects)).filter(([p]) => {
25176
26049
  try {
25177
- return existsSync50(p);
26050
+ return existsSync51(p);
25178
26051
  } catch {
25179
26052
  return false;
25180
26053
  }
@@ -25206,7 +26079,7 @@ function isCodeWorkspace(p) {
25206
26079
  }
25207
26080
  return WORKSPACE_MARKERS.some((m) => {
25208
26081
  try {
25209
- return existsSync50(join54(p, m));
26082
+ return existsSync51(join55(p, m));
25210
26083
  } catch {
25211
26084
  return false;
25212
26085
  }