chat-recall 0.7.18 → 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/mcp.js CHANGED
@@ -5023,6 +5023,8 @@ function declaredOrigin(value) {
5023
5023
  function userRecordOrigin(obj, text) {
5024
5024
  if (obj.isSidechain === true)
5025
5025
  return "subagent";
5026
+ if (obj.isCompactSummary === true)
5027
+ return "compact-summary";
5026
5028
  const declared = declaredOrigin(obj.origin);
5027
5029
  if (declared && declared !== "human")
5028
5030
  return declared;
@@ -5206,6 +5208,7 @@ function defaultSourcesEnabled() {
5206
5208
  commands: true
5207
5209
  },
5208
5210
  cursor: { sessions: true, skills: true, agents: true, commands: true },
5211
+ hermes: { sessions: true },
5209
5212
  shared: { skills: true },
5210
5213
  common: { mcps: true, agentMd: true }
5211
5214
  };
@@ -5282,6 +5285,7 @@ function mergeSources(base2, partial) {
5282
5285
  codex: { ...base2.enabled.codex, ...partial.enabled?.codex ?? {} },
5283
5286
  agy: { ...base2.enabled.agy, ...inherited, ...partial.enabled?.agy ?? {} },
5284
5287
  cursor: { ...base2.enabled.cursor, ...partial.enabled?.cursor ?? {} },
5288
+ hermes: { ...base2.enabled.hermes, ...partial.enabled?.hermes ?? {} },
5285
5289
  shared: { ...base2.enabled.shared, ...partial.enabled?.shared ?? {} },
5286
5290
  common: { ...base2.enabled.common, ...partial.enabled?.common ?? {} }
5287
5291
  };
@@ -5293,6 +5297,7 @@ function mergeSources(base2, partial) {
5293
5297
  agyHome: partial.agyHome ?? base2.agyHome,
5294
5298
  cursorHome: partial.cursorHome ?? base2.cursorHome,
5295
5299
  cursorIdeHome: partial.cursorIdeHome ?? base2.cursorIdeHome,
5300
+ hermesHome: partial.hermesHome ?? base2.hermesHome,
5296
5301
  extraClaudeHomes: partial.extraClaudeHomes ?? base2.extraClaudeHomes,
5297
5302
  approvedHomes: partial.approvedHomes ?? base2.approvedHomes,
5298
5303
  declinedHomes: partial.declinedHomes ?? base2.declinedHomes,
@@ -5689,6 +5694,13 @@ function grandfatherLegacyHomes() {
5689
5694
  }
5690
5695
  return { seeded };
5691
5696
  }
5697
+ function defaultHermesHome() {
5698
+ if (process.platform === "win32") {
5699
+ const local = process.env.LOCALAPPDATA?.trim() || join6(homedir2(), "AppData", "Local");
5700
+ return join6(local, "hermes");
5701
+ }
5702
+ return join6(homedir2(), ".hermes");
5703
+ }
5692
5704
  function primaryHomes() {
5693
5705
  const home = homedir2();
5694
5706
  const env = process.env;
@@ -5705,7 +5717,8 @@ function primaryHomes() {
5705
5717
  env.CHAT_RECALL_CODEX_HOME || s?.codexHome || join6(home, ".codex"),
5706
5718
  env.CHAT_RECALL_AGY_HOME || s?.agyHome || join6(home, ".gemini", "antigravity-cli"),
5707
5719
  env.CHAT_RECALL_CURSOR_HOME || s?.cursorHome || join6(home, ".cursor"),
5708
- dirOf(opencodeDb)
5720
+ dirOf(opencodeDb),
5721
+ env.CHAT_RECALL_HERMES_HOME || s?.hermesHome || env.HERMES_HOME?.trim() || defaultHermesHome()
5709
5722
  ];
5710
5723
  return candidates2.map(normalizeHomePath);
5711
5724
  }
@@ -5815,6 +5828,9 @@ function geminiHomeDir() {
5815
5828
  function opencodeDbPath() {
5816
5829
  return process.env.CHAT_RECALL_OPENCODE_DB || sources().opencodeDbPath || join7(homedir3(), ".local", "share", "opencode", "opencode.db");
5817
5830
  }
5831
+ function hermesHomeDir() {
5832
+ return process.env.CHAT_RECALL_HERMES_HOME || sources().hermesHome || process.env.HERMES_HOME?.trim() || defaultHermesHome();
5833
+ }
5818
5834
  function codexHomeDir() {
5819
5835
  return process.env.CHAT_RECALL_CODEX_HOME || sources().codexHome || join7(homedir3(), ".codex");
5820
5836
  }
@@ -5916,6 +5932,22 @@ function opencodeDbPaths(opts = {}) {
5916
5932
  dbs.push(primary);
5917
5933
  return applyExclusions(dbs, opts.includeExcluded);
5918
5934
  }
5935
+ function hermesDbPaths(opts = {}) {
5936
+ const root = hermesHomeDir();
5937
+ const dbs = [join7(root, "state.db")];
5938
+ try {
5939
+ const profiles = join7(root, "profiles");
5940
+ for (const entry of readdirSync5(profiles, { withFileTypes: true })) {
5941
+ if (!entry.isDirectory())
5942
+ continue;
5943
+ const p = join7(profiles, entry.name, "state.db");
5944
+ if (existsSync5(p))
5945
+ dbs.push(p);
5946
+ }
5947
+ } catch {
5948
+ }
5949
+ return applyExclusions(dbs, opts.includeExcluded);
5950
+ }
5919
5951
  function extraClaudeHomeDirs() {
5920
5952
  const extras = sources().extraClaudeHomes ?? [];
5921
5953
  const primary = claudeHomeDir();
@@ -7212,6 +7244,71 @@ function readTailFromOffset(path2, offset, maxBytes = TAIL_READ_MAX_BYTES) {
7212
7244
  }
7213
7245
  }
7214
7246
  }
7247
+ function readSourcesFromOffset(paths, offset, maxBytes = TAIL_READ_MAX_BYTES) {
7248
+ let start = 0;
7249
+ let linesBefore = 0;
7250
+ for (let i = 0; i < paths.length; i++) {
7251
+ const path2 = paths[i];
7252
+ let size = 0;
7253
+ try {
7254
+ size = statSync6(path2).size;
7255
+ } catch {
7256
+ size = 0;
7257
+ }
7258
+ const last = i === paths.length - 1;
7259
+ if (!last && offset >= start + size) {
7260
+ const lines = linesBeforeOffset(path2, size);
7261
+ if (lines === void 0)
7262
+ return { text: "", newOffset: offset };
7263
+ linesBefore += lines + (size > 0 && !endsWithNewline(path2, size) ? 1 : 0);
7264
+ start += size;
7265
+ continue;
7266
+ }
7267
+ const local = offset - start;
7268
+ const read = readTailFromOffset(path2, local, maxBytes);
7269
+ const shift = (r) => ({
7270
+ ...r,
7271
+ newOffset: start + r.newOffset,
7272
+ ...r.baseLine !== void 0 ? { baseLine: linesBefore + r.baseLine } : {}
7273
+ });
7274
+ if (last || read.newOffset > local || local >= size)
7275
+ return shift(read);
7276
+ if (size - local > maxBytes)
7277
+ return { text: "", newOffset: start + size, skippedBytes: size - local };
7278
+ let fd = null;
7279
+ try {
7280
+ fd = openSync(path2, "r");
7281
+ const text = readAt(fd, local, size - local).toString("utf-8");
7282
+ return shift({ text, newOffset: size, baseLine: linesBeforeOffset(path2, local) });
7283
+ } catch {
7284
+ return { text: "", newOffset: offset };
7285
+ } finally {
7286
+ if (fd !== null) {
7287
+ try {
7288
+ closeSync(fd);
7289
+ } catch {
7290
+ }
7291
+ }
7292
+ }
7293
+ }
7294
+ return { text: "", newOffset: offset };
7295
+ }
7296
+ function endsWithNewline(path2, size) {
7297
+ let fd = null;
7298
+ try {
7299
+ fd = openSync(path2, "r");
7300
+ return readAt(fd, size - 1, 1)[0] === 10;
7301
+ } catch {
7302
+ return true;
7303
+ } finally {
7304
+ if (fd !== null) {
7305
+ try {
7306
+ closeSync(fd);
7307
+ } catch {
7308
+ }
7309
+ }
7310
+ }
7311
+ }
7215
7312
  function findNewline(fd, from, size) {
7216
7313
  const block = Buffer.allocUnsafe(SKIP_SCAN_BYTES);
7217
7314
  let pos = from;
@@ -9690,6 +9787,473 @@ var init_cursor = __esm({
9690
9787
  }
9691
9788
  });
9692
9789
 
9790
+ // ../engine/dist/core/backends/hermes.js
9791
+ import { existsSync as existsSync12 } from "fs";
9792
+ function firstUserPrompt(db, sessionId) {
9793
+ try {
9794
+ const row = db.prepare(`
9795
+ SELECT substr(content, 1, 400) AS text FROM messages
9796
+ WHERE session_id = ? AND role = 'user' AND active = 1 AND _compressed_summary = 0
9797
+ AND (display_kind IS NULL OR display_kind = 'steer')
9798
+ AND length(trim(content)) > 0
9799
+ ORDER BY id LIMIT 1
9800
+ `).get(sessionId);
9801
+ return row?.text ? flatString(row.text.slice(0, 200)) : "";
9802
+ } catch {
9803
+ return "";
9804
+ }
9805
+ }
9806
+ function messageRowsToEvents(rows) {
9807
+ const events = [];
9808
+ let line = 0;
9809
+ for (const r of rows) {
9810
+ line++;
9811
+ if (r.active === 0)
9812
+ continue;
9813
+ if (r.display_kind === "failed_turn" || r.display_kind === "hidden")
9814
+ continue;
9815
+ const ts = Math.round((r.timestamp || 0) * 1e3);
9816
+ const tsIso = ts ? new Date(ts).toISOString() : void 0;
9817
+ const text = (r.content ?? "").trim();
9818
+ if (r._compressed_summary === 1) {
9819
+ if (text)
9820
+ events.push({ kind: "summary", ts, tsIso, line, text });
9821
+ continue;
9822
+ }
9823
+ if (r.role === "user") {
9824
+ if (!text)
9825
+ continue;
9826
+ events.push({
9827
+ kind: "user",
9828
+ ts,
9829
+ tsIso,
9830
+ line,
9831
+ text,
9832
+ ...r.display_kind === "process_complete" ? { origin: "task-notification" } : {}
9833
+ });
9834
+ continue;
9835
+ }
9836
+ if (r.role === "assistant") {
9837
+ if (text)
9838
+ events.push({ kind: "assistant_text", ts, tsIso, line, text });
9839
+ for (const call2 of parseToolCalls(r.tool_calls)) {
9840
+ const toolName = call2.function?.name ?? "";
9841
+ const toolInput = parseArguments(call2.function?.arguments);
9842
+ const command = toolName === "terminal" && typeof toolInput?.command === "string" ? toolInput.command : void 0;
9843
+ events.push({
9844
+ kind: "tool_use",
9845
+ ts,
9846
+ tsIso,
9847
+ line,
9848
+ toolName,
9849
+ toolUseId: call2.id || call2.call_id || `${r.id}:${toolName}`,
9850
+ toolInput,
9851
+ ...command ? { command } : {}
9852
+ });
9853
+ }
9854
+ continue;
9855
+ }
9856
+ if (r.role === "tool") {
9857
+ const body2 = r.content ?? "";
9858
+ const { exitCode, isError } = toolResultStatus(body2);
9859
+ events.push({
9860
+ kind: "tool_result",
9861
+ ts,
9862
+ tsIso,
9863
+ line,
9864
+ toolUseId: r.tool_call_id ?? void 0,
9865
+ toolName: r.tool_name ?? void 0,
9866
+ resultBody: body2,
9867
+ resultIsError: isError,
9868
+ ...exitCode !== void 0 ? { resultExitCode: exitCode } : {},
9869
+ resultBytes: Buffer.byteLength(body2)
9870
+ });
9871
+ }
9872
+ }
9873
+ return events;
9874
+ }
9875
+ function parseToolCalls(json) {
9876
+ if (!json)
9877
+ return [];
9878
+ try {
9879
+ const calls = JSON.parse(json);
9880
+ return Array.isArray(calls) ? calls : [];
9881
+ } catch {
9882
+ return [];
9883
+ }
9884
+ }
9885
+ function parseArguments(args) {
9886
+ if (typeof args !== "string")
9887
+ return args ?? {};
9888
+ try {
9889
+ return JSON.parse(args);
9890
+ } catch {
9891
+ return { raw: args };
9892
+ }
9893
+ }
9894
+ function toolResultStatus(body2) {
9895
+ if (!body2.startsWith("{"))
9896
+ return { isError: false };
9897
+ try {
9898
+ const r = JSON.parse(body2);
9899
+ const exitCode = typeof r.exit_code === "number" ? r.exit_code : void 0;
9900
+ const hasError = r.error !== void 0 && r.error !== null && r.error !== "";
9901
+ return { exitCode, isError: hasError || exitCode !== void 0 && exitCode !== 0 };
9902
+ } catch {
9903
+ return { isError: false };
9904
+ }
9905
+ }
9906
+ var PREFIX5, MESSAGE_COLUMNS, ARCHIVED_SESSION_COLUMNS, SESSION_MTIME_SQL, HermesBackend, hermesBackend;
9907
+ var init_hermes = __esm({
9908
+ "../engine/dist/core/backends/hermes.js"() {
9909
+ "use strict";
9910
+ init_sqlite_reader();
9911
+ init_tool_paths();
9912
+ init_session_outcome();
9913
+ init_session_git();
9914
+ init_generic_engine();
9915
+ init_flat_string();
9916
+ PREFIX5 = "hermes_";
9917
+ MESSAGE_COLUMNS = "id, role, content, tool_calls, tool_call_id, tool_name, timestamp, display_kind, active, _compressed_summary";
9918
+ ARCHIVED_SESSION_COLUMNS = [
9919
+ "id",
9920
+ "source",
9921
+ "title",
9922
+ "model",
9923
+ "cwd",
9924
+ "git_branch",
9925
+ "git_repo_root",
9926
+ "parent_session_id",
9927
+ "started_at",
9928
+ "ended_at",
9929
+ "end_reason",
9930
+ "message_count",
9931
+ "tool_call_count",
9932
+ "input_tokens",
9933
+ "output_tokens",
9934
+ "cache_read_tokens",
9935
+ "cache_write_tokens",
9936
+ "reasoning_tokens",
9937
+ "estimated_cost_usd",
9938
+ "actual_cost_usd"
9939
+ ];
9940
+ SESSION_MTIME_SQL = `MAX(
9941
+ s.started_at,
9942
+ COALESCE(s.ended_at, 0),
9943
+ COALESCE(s.last_activity_at, 0),
9944
+ COALESCE((SELECT MAX(m.timestamp) FROM messages m WHERE m.session_id = s.id), 0)
9945
+ )`;
9946
+ HermesBackend = class {
9947
+ id = "hermes";
9948
+ idPrefix = PREFIX5;
9949
+ displayName = "Hermes";
9950
+ homeDir() {
9951
+ return hermesHomeDir();
9952
+ }
9953
+ /** Every Hermes database on this machine, the root profile first. */
9954
+ dbPaths() {
9955
+ return hermesDbPaths();
9956
+ }
9957
+ isAvailable() {
9958
+ return this.dbPaths().some((p) => existsSync12(p));
9959
+ }
9960
+ /** The database that holds this session. A session id is unique within a
9961
+ * database, and each named profile has its own. */
9962
+ dbPathFor(rawId) {
9963
+ const cached = this._dbForSession.get(rawId);
9964
+ if (cached)
9965
+ return cached;
9966
+ for (const path2 of this.dbPaths()) {
9967
+ const db = openSqliteReadonly(path2);
9968
+ if (!db)
9969
+ continue;
9970
+ try {
9971
+ if (db.prepare("SELECT 1 AS ok FROM sessions WHERE id = ?").get(rawId)) {
9972
+ this._dbForSession.set(rawId, path2);
9973
+ return path2;
9974
+ }
9975
+ } catch {
9976
+ } finally {
9977
+ db.close();
9978
+ }
9979
+ }
9980
+ return null;
9981
+ }
9982
+ _dbForSession = /* @__PURE__ */ new Map();
9983
+ /** Tests, and anything that adds a profile mid-process. */
9984
+ _clearDbRouting() {
9985
+ this._dbForSession.clear();
9986
+ }
9987
+ // ── ID handling ────────────────────────────────────────────────
9988
+ matchesId(id) {
9989
+ return id.startsWith(PREFIX5);
9990
+ }
9991
+ toRawId(id) {
9992
+ return id.startsWith(PREFIX5) ? id.slice(PREFIX5.length) : id;
9993
+ }
9994
+ toPrefixedId(rawId) {
9995
+ return rawId.startsWith(PREFIX5) ? rawId : PREFIX5 + rawId;
9996
+ }
9997
+ // ── Location ───────────────────────────────────────────────────
9998
+ findSession(id) {
9999
+ const rawId = this.toRawId(id);
10000
+ const path2 = this.dbPathFor(rawId);
10001
+ if (!path2)
10002
+ return null;
10003
+ const db = openSqliteReadonly(path2);
10004
+ if (!db)
10005
+ return null;
10006
+ try {
10007
+ const row = db.prepare(`
10008
+ SELECT s.cwd, s.git_repo_root, ${SESSION_MTIME_SQL} AS mtime
10009
+ FROM sessions s WHERE s.id = ?
10010
+ `).get(rawId);
10011
+ if (!row)
10012
+ return null;
10013
+ return {
10014
+ path: path2,
10015
+ format: "sqlite",
10016
+ projectDir: "",
10017
+ projectPath: row.git_repo_root || row.cwd || "",
10018
+ mtime: Math.round((row.mtime || 0) * 1e3)
10019
+ };
10020
+ } catch {
10021
+ return null;
10022
+ } finally {
10023
+ db.close();
10024
+ }
10025
+ }
10026
+ listSessions(opts = {}) {
10027
+ const byId = /* @__PURE__ */ new Map();
10028
+ for (const dbPath of this.dbPaths()) {
10029
+ if (!existsSync12(dbPath))
10030
+ continue;
10031
+ for (const ref of this.listSessionsInDb(dbPath, opts)) {
10032
+ const prior = byId.get(ref.rawId);
10033
+ if (!prior || ref.mtime > prior.mtime)
10034
+ byId.set(ref.rawId, ref);
10035
+ }
10036
+ }
10037
+ const all = [...byId.values()].sort((a, b) => b.mtime - a.mtime);
10038
+ return opts.limit ? all.slice(0, opts.limit) : all;
10039
+ }
10040
+ listSessionsInDb(dbPath, opts) {
10041
+ const cutoffSec = (opts.sinceMs ?? 0) / 1e3;
10042
+ const filter = opts.projectFilter?.toLowerCase();
10043
+ const db = openSqliteReadonly(dbPath);
10044
+ if (!db)
10045
+ return [];
10046
+ try {
10047
+ const rows = db.prepare(`
10048
+ SELECT * FROM (
10049
+ SELECT s.id, s.cwd, s.git_repo_root, s.started_at, s.message_count,
10050
+ ${SESSION_MTIME_SQL} AS mtime
10051
+ FROM sessions s
10052
+ ) WHERE mtime >= ? ORDER BY mtime DESC
10053
+ `).all(cutoffSec);
10054
+ const out = [];
10055
+ for (const row of rows) {
10056
+ const projectPath = row.git_repo_root || row.cwd || "";
10057
+ if (filter && !projectPath.toLowerCase().includes(filter))
10058
+ continue;
10059
+ const mtime = Math.round(row.mtime * 1e3);
10060
+ this._dbForSession.set(row.id, dbPath);
10061
+ out.push({
10062
+ toolId: "hermes",
10063
+ rawId: row.id,
10064
+ prefixedId: this.toPrefixedId(row.id),
10065
+ projectPath,
10066
+ projectDir: "",
10067
+ fullPath: dbPath,
10068
+ created: new Date(Math.round(row.started_at * 1e3)).toISOString(),
10069
+ modified: new Date(mtime).toISOString(),
10070
+ mtime,
10071
+ firstPrompt: opts.previews === false ? "" : firstUserPrompt(db, row.id),
10072
+ messageCount: opts.previews === false ? 0 : row.message_count ?? 0
10073
+ });
10074
+ if (opts.limit && out.length >= opts.limit)
10075
+ break;
10076
+ }
10077
+ return out;
10078
+ } catch {
10079
+ return [];
10080
+ } finally {
10081
+ db.close();
10082
+ }
10083
+ }
10084
+ /** Hermes writes a title for each session (a model-written one, or the
10085
+ * first prompt for a one-shot run). */
10086
+ getNativeTitle(rawId) {
10087
+ const path2 = this.dbPathFor(this.toRawId(rawId));
10088
+ if (!path2)
10089
+ return null;
10090
+ const db = openSqliteReadonly(path2);
10091
+ if (!db)
10092
+ return null;
10093
+ try {
10094
+ const row = db.prepare("SELECT title FROM sessions WHERE id = ?").get(this.toRawId(rawId));
10095
+ const t = row?.title?.trim();
10096
+ return t ? t.slice(0, 200) : null;
10097
+ } catch {
10098
+ return null;
10099
+ } finally {
10100
+ db.close();
10101
+ }
10102
+ }
10103
+ // ── Generic-engine inputs ───────────────────────────────────────
10104
+ fileToolMap = {
10105
+ write_file: "write",
10106
+ patch: "edit",
10107
+ read_file: "read"
10108
+ };
10109
+ /**
10110
+ * `write_file` carries `{ path, content }`. `patch` carries
10111
+ * `{ mode: 'replace', path, old_string, new_string }`; its other mode,
10112
+ * `patch`, is a multi-file V4A patch with no single before and after.
10113
+ */
10114
+ extractEditDelta(toolName, input) {
10115
+ if (input == null || typeof input !== "object")
10116
+ return null;
10117
+ const inp = input;
10118
+ if (toolName === "write_file") {
10119
+ return { before: "", after: typeof inp.content === "string" ? inp.content : null };
10120
+ }
10121
+ if (toolName === "patch" && (inp.mode === void 0 || inp.mode === "replace")) {
10122
+ const before = typeof inp.old_string === "string" ? inp.old_string : null;
10123
+ const after = typeof inp.new_string === "string" ? inp.new_string : null;
10124
+ if (before === null && after === null)
10125
+ return null;
10126
+ return { before, after };
10127
+ }
10128
+ return null;
10129
+ }
10130
+ readEvents(rawId) {
10131
+ const id = this.toRawId(rawId);
10132
+ const path2 = this.dbPathFor(id);
10133
+ if (!path2)
10134
+ return [];
10135
+ const db = openSqliteReadonly(path2);
10136
+ if (!db)
10137
+ return [];
10138
+ try {
10139
+ const rows = db.prepare(`SELECT ${MESSAGE_COLUMNS} FROM messages WHERE session_id = ? ORDER BY id`).all(id);
10140
+ return messageRowsToEvents(rows);
10141
+ } catch {
10142
+ return [];
10143
+ } finally {
10144
+ db.close();
10145
+ }
10146
+ }
10147
+ /**
10148
+ * Events from the dump `exportRawSession` writes, for a session rebuilt from
10149
+ * the server's archive. The archive joins the lines of every dump it got, so
10150
+ * a row that changed (a rewind sets `active` to 0) is there more than once.
10151
+ * The last copy of each row id is the newest.
10152
+ */
10153
+ readEventsFromText(text) {
10154
+ const rows = /* @__PURE__ */ new Map();
10155
+ for (const line of text.split("\n")) {
10156
+ if (!line.trim())
10157
+ continue;
10158
+ try {
10159
+ const rec = JSON.parse(line);
10160
+ if (rec.kind === "message" && rec.row) {
10161
+ rows.delete(rec.row.id);
10162
+ rows.set(rec.row.id, rec.row);
10163
+ }
10164
+ } catch {
10165
+ }
10166
+ }
10167
+ return messageRowsToEvents([...rows.values()].sort((a, b) => a.id - b.id));
10168
+ }
10169
+ // ── Per-session operations — all delegate to the generic engine ─
10170
+ extractTurns(id, opts = {}) {
10171
+ return extractTurnsFromEvents(this.toPrefixedId(id), this.readEvents(id), opts);
10172
+ }
10173
+ liveScanEdits(id) {
10174
+ const located = this.findSession(id);
10175
+ if (!located) {
10176
+ return { found: false, projectPath: "", projectDir: "", edits: [], fileMtime: 0, tool: "hermes" };
10177
+ }
10178
+ return liveScanEditsFromEvents(this.readEvents(id), this.fileToolMap, {
10179
+ sessionId: this.toPrefixedId(id),
10180
+ tool: "hermes",
10181
+ projectPath: located.projectPath,
10182
+ projectDir: located.projectDir,
10183
+ fileMtime: located.mtime,
10184
+ found: true
10185
+ });
10186
+ }
10187
+ replay(id) {
10188
+ const located = this.findSession(id);
10189
+ if (!located) {
10190
+ return { sessionId: this.toPrefixedId(id), found: false, projectPath: "", files: [], totalLinesAdded: 0, totalLinesRemoved: 0 };
10191
+ }
10192
+ return replayFromEvents(this.toPrefixedId(id), this.readEvents(id), this.fileToolMap, this.extractEditDelta.bind(this), {
10193
+ projectPath: located.projectPath,
10194
+ found: true
10195
+ });
10196
+ }
10197
+ computeOutcome(id, opts) {
10198
+ return computeOutcome(this.toPrefixedId(id), opts);
10199
+ }
10200
+ /** File edits since `sinceMs` across the sessions active since then. */
10201
+ collectRecentEdits(opts) {
10202
+ const refs = this.listSessions({ sinceMs: opts.sinceMs, projectFilter: opts.projectFilter, previews: false });
10203
+ const edits = [];
10204
+ for (const ref of opts.limitSessions ? refs.slice(0, opts.limitSessions) : refs) {
10205
+ for (const e of this.liveScanEdits(ref.rawId).edits) {
10206
+ if (e.ts >= opts.sinceMs)
10207
+ edits.push(e);
10208
+ }
10209
+ }
10210
+ return edits.sort((a, b) => b.ts - a.ts);
10211
+ }
10212
+ getCommits(id, files, startMs, endMs, bufferMinutes) {
10213
+ return getSessionCommits(this.toPrefixedId(id), files, startMs, endMs, bufferMinutes);
10214
+ }
10215
+ /**
10216
+ * The session row and its messages as JSONL, one row per line in id order.
10217
+ * Hermes rewrites and compacts its database, so the archive keeps the rows
10218
+ * as they were synced.
10219
+ */
10220
+ exportRawSession(id) {
10221
+ const rawId = this.toRawId(id);
10222
+ const path2 = this.dbPathFor(rawId);
10223
+ if (!path2)
10224
+ return null;
10225
+ const db = openSqliteReadonly(path2);
10226
+ if (!db)
10227
+ return null;
10228
+ try {
10229
+ const have = new Set(db.prepare(`SELECT name FROM pragma_table_info('sessions')`).all().map((c) => c.name));
10230
+ const cols = ARCHIVED_SESSION_COLUMNS.filter((c) => have.has(c)).map((c) => `s.${c}`);
10231
+ const session = db.prepare(`
10232
+ SELECT ${[...cols, `${SESSION_MTIME_SQL} AS mtime`].join(", ")}
10233
+ FROM sessions s WHERE s.id = ?
10234
+ `).get(rawId);
10235
+ if (!session)
10236
+ return null;
10237
+ const rows = db.prepare(`SELECT ${MESSAGE_COLUMNS} FROM messages WHERE session_id = ? ORDER BY id`).all(rawId);
10238
+ const lines = [JSON.stringify({ kind: "session", row: session })];
10239
+ for (const r of rows)
10240
+ lines.push(JSON.stringify({ kind: "message", row: r }));
10241
+ return {
10242
+ tool: "hermes",
10243
+ mtime: Math.round(Number(session.mtime || 0) * 1e3),
10244
+ files: [{ name: `${rawId}.dump.jsonl`, bytes: Buffer.from(lines.join("\n") + "\n", "utf-8") }]
10245
+ };
10246
+ } catch {
10247
+ return null;
10248
+ } finally {
10249
+ db.close();
10250
+ }
10251
+ }
10252
+ };
10253
+ hermesBackend = new HermesBackend();
10254
+ }
10255
+ });
10256
+
9693
10257
  // ../engine/dist/core/backends/index.js
9694
10258
  function bootstrapBackends() {
9695
10259
  registerBackend(claudeBackend);
@@ -9697,6 +10261,7 @@ function bootstrapBackends() {
9697
10261
  registerBackend(codexBackend);
9698
10262
  registerBackend(agyBackend);
9699
10263
  registerBackend(cursorBackend);
10264
+ registerBackend(hermesBackend);
9700
10265
  }
9701
10266
  var init_backends = __esm({
9702
10267
  "../engine/dist/core/backends/index.js"() {
@@ -9707,6 +10272,7 @@ var init_backends = __esm({
9707
10272
  init_codex();
9708
10273
  init_agy();
9709
10274
  init_cursor();
10275
+ init_hermes();
9710
10276
  init_tool_backend();
9711
10277
  _setRegistryBootstrapper(bootstrapBackends);
9712
10278
  }
@@ -9919,7 +10485,7 @@ var init_session_outcome = __esm({
9919
10485
  });
9920
10486
 
9921
10487
  // ../engine/dist/core/first-prompt.js
9922
- import { createReadStream, existsSync as existsSync12, openSync as openSync3, readSync as readSync3, closeSync as closeSync3 } from "fs";
10488
+ import { createReadStream, existsSync as existsSync13, openSync as openSync3, readSync as readSync3, closeSync as closeSync3 } from "fs";
9923
10489
  import { StringDecoder } from "string_decoder";
9924
10490
  function stripBanners(s) {
9925
10491
  let out = s;
@@ -10088,7 +10654,7 @@ var init_project_dir_name = __esm({
10088
10654
  });
10089
10655
 
10090
10656
  // ../engine/dist/core/backends/claude.js
10091
- import { existsSync as existsSync13, readdirSync as readdirSync11, readFileSync as readFileSync9, statSync as statSync12, openSync as openSync4, readSync as readSync4, closeSync as closeSync4 } from "fs";
10657
+ import { existsSync as existsSync14, readdirSync as readdirSync11, readFileSync as readFileSync9, statSync as statSync12, openSync as openSync4, readSync as readSync4, closeSync as closeSync4 } from "fs";
10092
10658
  import { join as join14, basename as basename8 } from "path";
10093
10659
  function stripReminders(text) {
10094
10660
  return text.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g, "").trim();
@@ -10158,7 +10724,7 @@ var init_claude = __esm({
10158
10724
  return join14(this.homeDir(), "history.jsonl");
10159
10725
  }
10160
10726
  isAvailable() {
10161
- return existsSync13(this.projectsDir());
10727
+ return existsSync14(this.projectsDir());
10162
10728
  }
10163
10729
  // ── ID handling ────────────────────────────────────────────────
10164
10730
  /**
@@ -10264,7 +10830,7 @@ var init_claude = __esm({
10264
10830
  prior.modified = ref.modified;
10265
10831
  }
10266
10832
  };
10267
- if (!existsSync13(root))
10833
+ if (!existsSync14(root))
10268
10834
  return;
10269
10835
  for (const proj of readdirSync11(root, { withFileTypes: true })) {
10270
10836
  if (!proj.isDirectory())
@@ -10275,12 +10841,12 @@ var init_claude = __esm({
10275
10841
  const projectPath = resolveProjectDirName(proj.name);
10276
10842
  const indexPath = join14(projPath, "sessions-index.json");
10277
10843
  const indexed = /* @__PURE__ */ new Set();
10278
- if (existsSync13(indexPath)) {
10844
+ if (existsSync14(indexPath)) {
10279
10845
  try {
10280
10846
  const indexData = JSON.parse(readFileSync9(indexPath, "utf-8"));
10281
10847
  const entries = indexData.entries || [];
10282
10848
  for (const entry of entries) {
10283
- if (!entry.fullPath || !existsSync13(entry.fullPath))
10849
+ if (!entry.fullPath || !existsSync14(entry.fullPath))
10284
10850
  continue;
10285
10851
  indexed.add(entry.sessionId);
10286
10852
  add({
@@ -10605,7 +11171,7 @@ var init_claude = __esm({
10605
11171
  collectRecentEdits(opts) {
10606
11172
  const candidates2 = [];
10607
11173
  for (const root of claudeProjectDirs()) {
10608
- if (!existsSync13(root))
11174
+ if (!existsSync14(root))
10609
11175
  continue;
10610
11176
  for (const projEntry of readdirSync11(root, { withFileTypes: true })) {
10611
11177
  if (!projEntry.isDirectory())
@@ -10627,7 +11193,7 @@ var init_claude = __esm({
10627
11193
  const st = statSync12(fp);
10628
11194
  let mtime = st.mtimeMs;
10629
11195
  const subDir = join14(projPath, f.slice(0, -6), "subagents");
10630
- if (existsSync13(subDir)) {
11196
+ if (existsSync14(subDir)) {
10631
11197
  for (const sub of readdirSync11(subDir)) {
10632
11198
  try {
10633
11199
  const subSt = statSync12(join14(subDir, sub));
@@ -10704,27 +11270,45 @@ var init_claude = __esm({
10704
11270
  /**
10705
11271
  * True when this session exists in MORE THAN ONE home.
10706
11272
  *
10707
- * Such a session cannot be tail-appended: `fileSize()` is the SUM across
10708
- * copies while a byte offset addresses ONE file, so the two disagree by
10709
- * construction and the "tail" is either empty or the wrong bytes. The caller
10710
- * uses this to force a FULL sync, which ships the unioned container and is
10711
- * correct regardless of how the halves are arranged.
10712
- *
10713
11273
  * Measured on ec05f266: ~/.claude 1715 records, ~/.claude-work 205 records,
10714
- * zero overlap. An offset-based append against a 5846662-byte "size" that no
10715
- * single file has could only ever ship nonsense.
11274
+ * zero overlap. `fileSize()` is the sum across the copies, and
11275
+ * `readFromOffset()` reads them joined end to end, primary first.
10716
11276
  */
10717
11277
  spansMultipleSources(prefixedId) {
10718
11278
  return findSessionFiles(this.toRawId(prefixedId)).length > 1;
10719
11279
  }
11280
+ /**
11281
+ * The copies before the last one, each with its size. Claude Code writes to
11282
+ * the home of the profile that runs the session, so the live copy can grow,
11283
+ * appear, vanish or merge back into the primary. Each of those moves bytes
11284
+ * under an offset into the joined copies; this key changes with all of them.
11285
+ */
11286
+ sourceLayout(prefixedId) {
11287
+ const copies = findSessionFiles(this.toRawId(prefixedId));
11288
+ if (copies.length < 2)
11289
+ return "";
11290
+ return copies.slice(0, -1).map((c) => {
11291
+ let size = -1;
11292
+ try {
11293
+ size = statSync12(c.path).size;
11294
+ } catch {
11295
+ }
11296
+ return `${c.path}:${size}`;
11297
+ }).join("|");
11298
+ }
11299
+ /**
11300
+ * Session 8de13d0a had 31 MB in ~/.claude and 2 MB in ~/.claude-work. Over
11301
+ * the 24 MB build ceiling a sync ships the transcript in chunks read here,
11302
+ * and this returned no text for a session in two homes. Each sync shipped
11303
+ * nothing, and the server stayed three hours behind.
11304
+ */
10720
11305
  async readFromOffset(prefixedId, offset, maxBytes) {
10721
- const rawId = this.toRawId(prefixedId);
10722
- const copies = findSessionFiles(rawId);
11306
+ const copies = findSessionFiles(this.toRawId(prefixedId));
10723
11307
  if (copies.length === 0)
10724
11308
  return { text: "", newOffset: offset };
10725
- if (copies.length > 1)
10726
- return { text: "", newOffset: offset };
10727
- return readTailFromOffset(copies[0].path, offset, maxBytes);
11309
+ if (copies.length === 1)
11310
+ return readTailFromOffset(copies[0].path, offset, maxBytes);
11311
+ return readSourcesFromOffset(copies.map((c) => c.path), offset, maxBytes);
10728
11312
  }
10729
11313
  };
10730
11314
  claudeBackend = new ClaudeBackend();
@@ -10902,7 +11486,7 @@ var init_model_pricing = __esm({
10902
11486
  });
10903
11487
 
10904
11488
  // ../engine/dist/parsers/session.js
10905
- import { createReadStream as createReadStream2, existsSync as existsSync14, readdirSync as readdirSync12, readFileSync as readFileSync10, statSync as statSync13, openSync as openSync5, readSync as readSync5, closeSync as closeSync5 } from "fs";
11489
+ import { createReadStream as createReadStream2, existsSync as existsSync15, readdirSync as readdirSync12, readFileSync as readFileSync10, statSync as statSync13, openSync as openSync5, readSync as readSync5, closeSync as closeSync5 } from "fs";
10906
11490
  import { createInterface } from "readline";
10907
11491
  import { join as join15, basename as basename9 } from "path";
10908
11492
  function removeCodeBlocks(text) {
@@ -10951,17 +11535,17 @@ function isValuableToolResult(content, toolName = "") {
10951
11535
  }
10952
11536
  function hasSubagentsDir(sessionPath) {
10953
11537
  const dir = sessionPath.slice(0, -6);
10954
- return existsSync14(join15(dir, "subagents"));
11538
+ return existsSync15(join15(dir, "subagents"));
10955
11539
  }
10956
11540
  function getSubagentPaths(sessionPath) {
10957
11541
  const subagentsDir = join15(sessionPath.slice(0, -6), "subagents");
10958
- if (!existsSync14(subagentsDir))
11542
+ if (!existsSync15(subagentsDir))
10959
11543
  return [];
10960
11544
  return readdirSync12(subagentsDir).filter((f) => f.endsWith(".jsonl")).sort().map((f) => join15(subagentsDir, f));
10961
11545
  }
10962
11546
  function readCwdFromJsonl(sessionPath) {
10963
11547
  try {
10964
- if (!existsSync14(sessionPath))
11548
+ if (!existsSync15(sessionPath))
10965
11549
  return "";
10966
11550
  let text;
10967
11551
  const fd = openSync5(sessionPath, "r");
@@ -11018,7 +11602,7 @@ async function parseSessionFile(sessionPath, maxMessages = 50) {
11018
11602
  };
11019
11603
  const modelsUsed = /* @__PURE__ */ new Set();
11020
11604
  const filesModified = /* @__PURE__ */ new Set();
11021
- if (!existsSync14(sessionPath)) {
11605
+ if (!existsSync15(sessionPath)) {
11022
11606
  return content;
11023
11607
  }
11024
11608
  const filesToParse = hasSubagentsDir(sessionPath) ? [sessionPath, ...getSubagentPaths(sessionPath)] : [sessionPath];
@@ -11637,7 +12221,7 @@ function canonicalEventsToMessages(events) {
11637
12221
  switch (e.kind) {
11638
12222
  case "user":
11639
12223
  cur = null;
11640
- messages.push({ line: e.line, role: "user", content: e.text ?? "", timestamp: e.tsIso });
12224
+ messages.push({ line: e.line, role: "user", content: e.text ?? "", timestamp: e.tsIso, ...e.origin ? { origin: e.origin } : {} });
11641
12225
  break;
11642
12226
  case "assistant_text":
11643
12227
  cur = { line: e.line, role: "assistant", content: e.text ?? "", timestamp: e.tsIso };
@@ -12048,7 +12632,7 @@ var init_raw = __esm({
12048
12632
  // ../engine/dist/transcript/shadow.js
12049
12633
  import { gzipSync as gzipSync2, gunzipSync as gunzipSync2 } from "zlib";
12050
12634
  import { createHash as createHash4 } from "crypto";
12051
- import { existsSync as existsSync15, mkdirSync as mkdirSync4, readFileSync as readFileSync11, writeFileSync as writeFileSync2, renameSync as renameSync2, statSync as statSync14, openSync as openSync6, readSync as readSync6, closeSync as closeSync6 } from "fs";
12635
+ import { existsSync as existsSync16, mkdirSync as mkdirSync4, readFileSync as readFileSync11, writeFileSync as writeFileSync2, renameSync as renameSync2, statSync as statSync14, openSync as openSync6, readSync as readSync6, closeSync as closeSync6 } from "fs";
12052
12636
  import { dirname as dirname14, join as join18 } from "path";
12053
12637
  function shadowRoot() {
12054
12638
  return join18(getDataDir(), "shadow");
@@ -12059,7 +12643,7 @@ function shadowFileFor(tool, rawId) {
12059
12643
  }
12060
12644
  function readShadowContainer(tool, rawId) {
12061
12645
  const path2 = shadowFileFor(tool, rawId);
12062
- if (!existsSync15(path2))
12646
+ if (!existsSync16(path2))
12063
12647
  return null;
12064
12648
  try {
12065
12649
  const c = JSON.parse(gunzipSync2(readFileSync11(path2)).toString("utf-8"));
@@ -12261,7 +12845,7 @@ var init_shadow = __esm({
12261
12845
  });
12262
12846
 
12263
12847
  // ../engine/dist/core/live-session-scan.js
12264
- import { existsSync as existsSync16, readdirSync as readdirSync13, readFileSync as readFileSync12, statSync as statSync15, openSync as openSync7, readSync as readSync7, closeSync as closeSync7 } from "fs";
12848
+ import { existsSync as existsSync17, readdirSync as readdirSync13, readFileSync as readFileSync12, statSync as statSync15, openSync as openSync7, readSync as readSync7, closeSync as closeSync7 } from "fs";
12265
12849
  import { join as join19, basename as basename12 } from "path";
12266
12850
  function detectTool(sessionId) {
12267
12851
  return getBackendForId(sessionId)?.id ?? "claude";
@@ -12318,7 +12902,7 @@ function sessionFileIndex() {
12318
12902
  return p;
12319
12903
  };
12320
12904
  for (const root of roots) {
12321
- if (seenRoots.has(root) || !existsSync16(root))
12905
+ if (seenRoots.has(root) || !existsSync17(root))
12322
12906
  continue;
12323
12907
  seenRoots.add(root);
12324
12908
  dirs.set(root, dirMtime(root));
@@ -12444,7 +13028,7 @@ function resolveSessionContentPaths(sessionFile) {
12444
13028
  if (!hasSubagentsDir(sessionFile))
12445
13029
  return [sessionFile];
12446
13030
  const subDir = join19(sessionFile.slice(0, -6), "subagents");
12447
- if (!existsSync16(subDir))
13031
+ if (!existsSync17(subDir))
12448
13032
  return [sessionFile];
12449
13033
  const subPaths = readdirSync13(subDir).filter((f) => f.endsWith(".jsonl")).sort().map((f) => join19(subDir, f));
12450
13034
  return [sessionFile, ...subPaths];
@@ -12461,7 +13045,7 @@ function findCodexSessionFile(sessionId) {
12461
13045
  return null;
12462
13046
  }
12463
13047
  function findCodexSessionFileIn(root, sessionId) {
12464
- if (!existsSync16(root))
13048
+ if (!existsSync17(root))
12465
13049
  return null;
12466
13050
  for (const year of readdirSync13(root, { withFileTypes: true })) {
12467
13051
  if (!year.isDirectory())
@@ -12554,10 +13138,10 @@ var init_types = __esm({
12554
13138
 
12555
13139
  // ../engine/dist/transcript/opencode.js
12556
13140
  async function parseOpenCodeSubagents(parentSessionId) {
12557
- const { existsSync: existsSync48 } = await import("fs");
13141
+ const { existsSync: existsSync49 } = await import("fs");
12558
13142
  const { opencodeBackend: opencodeBackend2 } = await Promise.resolve().then(() => (init_opencode(), opencode_exports));
12559
13143
  const dbPath = opencodeBackend2.dbPath();
12560
- if (!existsSync48(dbPath))
13144
+ if (!existsSync49(dbPath))
12561
13145
  return [];
12562
13146
  const realParent = parentSessionId.replace("opencode_", "");
12563
13147
  const db = openSqliteReadonlyOrThrow(dbPath);
@@ -12598,10 +13182,10 @@ async function parseOpenCodeSubagents(parentSessionId) {
12598
13182
  }
12599
13183
  }
12600
13184
  async function parseOpenCodeTranscript(sessionId) {
12601
- const { existsSync: existsSync48 } = await import("fs");
13185
+ const { existsSync: existsSync49 } = await import("fs");
12602
13186
  const { opencodeBackend: opencodeBackend2 } = await Promise.resolve().then(() => (init_opencode(), opencode_exports));
12603
13187
  const dbPath = opencodeBackend2.dbPath();
12604
- if (!existsSync48(dbPath))
13188
+ if (!existsSync49(dbPath))
12605
13189
  return [];
12606
13190
  const realId = sessionId.replace("opencode_", "");
12607
13191
  const db = openSqliteReadonlyOrThrow(dbPath);
@@ -12875,7 +13459,7 @@ var init_credentials_env = __esm({
12875
13459
  });
12876
13460
 
12877
13461
  // ../engine/dist/core/which.js
12878
- import { existsSync as existsSync18, statSync as statSync17, accessSync as accessSync2, constants as constants2 } from "node:fs";
13462
+ import { existsSync as existsSync19, statSync as statSync17, accessSync as accessSync2, constants as constants2 } from "node:fs";
12879
13463
  import { join as join21, isAbsolute as isAbsolute2, delimiter as delimiter2, sep as sep2 } from "node:path";
12880
13464
  function executable(p) {
12881
13465
  try {
@@ -12916,7 +13500,7 @@ function resolveOnPath(name) {
12916
13500
  continue;
12917
13501
  for (const c of candidates(name)) {
12918
13502
  const full = join21(dir, c);
12919
- if (existsSync18(full) && executable(full))
13503
+ if (existsSync19(full) && executable(full))
12920
13504
  return full;
12921
13505
  }
12922
13506
  }
@@ -13080,7 +13664,7 @@ var init_code_intel = __esm({
13080
13664
  });
13081
13665
 
13082
13666
  // ../engine/dist/core/companions.js
13083
- import { existsSync as existsSync19, mkdirSync as mkdirSync7, statSync as statSync18, chmodSync as chmodSync4, unlinkSync, renameSync as renameSync3, createWriteStream, readFileSync as readFileSync14, writeFileSync as writeFileSync4 } from "node:fs";
13667
+ import { existsSync as existsSync20, mkdirSync as mkdirSync7, statSync as statSync18, chmodSync as chmodSync4, unlinkSync, renameSync as renameSync3, createWriteStream, readFileSync as readFileSync14, writeFileSync as writeFileSync4 } from "node:fs";
13084
13668
  import { homedir as homedir5 } from "node:os";
13085
13669
  import { join as join23 } from "node:path";
13086
13670
  import { execSync as execSync2 } from "node:child_process";
@@ -13203,7 +13787,7 @@ Refusing to install. The release may have been re-uploaded, or something is serv
13203
13787
  renameSync3(tmpPath, CODEINDEX_BIN_PATH);
13204
13788
  } catch (err) {
13205
13789
  try {
13206
- if (existsSync19(tmpPath))
13790
+ if (existsSync20(tmpPath))
13207
13791
  unlinkSync(tmpPath);
13208
13792
  } catch {
13209
13793
  }
@@ -13640,7 +14224,7 @@ var init_secret_redactor = __esm({
13640
14224
 
13641
14225
  // ../engine/dist/core/detector-install.js
13642
14226
  import { createHash as createHash7 } from "crypto";
13643
- import { existsSync as existsSync20, mkdirSync as mkdirSync8, mkdtempSync, chmodSync as chmodSync5, renameSync as renameSync4, rmSync as rmSync2, writeFileSync as writeFileSync5, readFileSync as readFileSync15, statSync as statSync20, copyFileSync as copyFileSync2 } from "fs";
14227
+ import { existsSync as existsSync21, mkdirSync as mkdirSync8, mkdtempSync, chmodSync as chmodSync5, renameSync as renameSync4, rmSync as rmSync2, writeFileSync as writeFileSync5, readFileSync as readFileSync15, statSync as statSync20, copyFileSync as copyFileSync2 } from "fs";
13644
14228
  import { join as join24 } from "path";
13645
14229
  function managedDetectorPath(name) {
13646
14230
  return join24(getDetectorBinDir(), name + exeSuffix());
@@ -13680,7 +14264,7 @@ function resolveDetector(name) {
13680
14264
  const dir = configuredDir();
13681
14265
  if (dir) {
13682
14266
  const p2 = join24(dir, name + exeSuffix());
13683
- if (existsSync20(p2))
14267
+ if (existsSync21(p2))
13684
14268
  return { path: p2, version: "operator-supplied", source: "configured" };
13685
14269
  return { error: "not-installed" };
13686
14270
  }
@@ -13688,7 +14272,7 @@ function resolveDetector(name) {
13688
14272
  if (!spec.assets[platformKey()])
13689
14273
  return { error: "unsupported-platform" };
13690
14274
  const p = managedDetectorPath(name);
13691
- if (!existsSync20(p))
14275
+ if (!existsSync21(p))
13692
14276
  return { error: "not-installed" };
13693
14277
  const receipt = readReceipt(name);
13694
14278
  if (!receipt)
@@ -13744,7 +14328,7 @@ var init_detector_install = __esm({
13744
14328
 
13745
14329
  // ../engine/dist/core/secret-scanner.js
13746
14330
  import { spawnSync } from "child_process";
13747
- import { existsSync as existsSync21, unlinkSync as unlinkSync2, readFileSync as readFileSync16, mkdtempSync as mkdtempSync2, rmSync as rmSync3 } from "fs";
14331
+ import { existsSync as existsSync22, unlinkSync as unlinkSync2, readFileSync as readFileSync16, mkdtempSync as mkdtempSync2, rmSync as rmSync3 } from "fs";
13748
14332
  import { tmpdir as tmpdir2 } from "os";
13749
14333
  import { join as join25 } from "path";
13750
14334
  function mask(s) {
@@ -13910,7 +14494,7 @@ function runTrufflehogDir(binary, dir, opts = {}) {
13910
14494
  return out;
13911
14495
  }
13912
14496
  function scanDirForSecrets(dir, opts = {}) {
13913
- if (!existsSync21(dir))
14497
+ if (!existsSync22(dir))
13914
14498
  return [];
13915
14499
  const gitleaks = whichDetector("gitleaks");
13916
14500
  const trufflehog = whichDetector("trufflehog");
@@ -13947,7 +14531,7 @@ function scanTenantRules(text, tenantRules) {
13947
14531
  return out;
13948
14532
  }
13949
14533
  function scanFileForSecrets(filePath, opts = {}) {
13950
- if (!existsSync21(filePath))
14534
+ if (!existsSync22(filePath))
13951
14535
  return [];
13952
14536
  const gitleaks = whichDetector("gitleaks");
13953
14537
  const trufflehog = whichDetector("trufflehog");
@@ -15026,7 +15610,7 @@ var init_collector = __esm({
15026
15610
 
15027
15611
  // ../engine/dist/core/source-discovery.js
15028
15612
  import { createHash as createHash8 } from "crypto";
15029
- import { existsSync as existsSync23, readdirSync as readdirSync14, statSync as statSync22 } from "fs";
15613
+ import { existsSync as existsSync24, readdirSync as readdirSync14, statSync as statSync22 } from "fs";
15030
15614
  import { join as join28 } from "path";
15031
15615
  function sourceId(path2) {
15032
15616
  return "src_" + createHash8("sha256").update(path2).digest("hex").slice(0, 12);
@@ -15085,7 +15669,7 @@ function countTranscripts(root, tool) {
15085
15669
  walk(root, 0);
15086
15670
  return { sessions, newestMtime };
15087
15671
  }
15088
- function countOpencodeSessions(dbPath) {
15672
+ function countDbSessions(dbPath) {
15089
15673
  try {
15090
15674
  const st = statSync22(dbPath);
15091
15675
  return { sessions: 0, newestMtime: st.mtimeMs };
@@ -15103,18 +15687,24 @@ function discoverSessionSources() {
15103
15687
  ];
15104
15688
  for (const [tool, dirs] of dirTools) {
15105
15689
  for (const [i, path2] of dirs.entries()) {
15106
- if (!existsSync23(path2))
15690
+ if (!existsSync24(path2))
15107
15691
  continue;
15108
15692
  const { sessions, newestMtime } = countTranscripts(path2, tool);
15109
15693
  out.push({ id: sourceId(path2), tool, path: path2, sessions, newestMtime, isPrimary: i === 0 });
15110
15694
  }
15111
15695
  }
15112
15696
  for (const [i, path2] of opencodeDbPaths({ includeExcluded: true }).entries()) {
15113
- if (!existsSync23(path2))
15697
+ if (!existsSync24(path2))
15114
15698
  continue;
15115
- const { sessions, newestMtime } = countOpencodeSessions(path2);
15699
+ const { sessions, newestMtime } = countDbSessions(path2);
15116
15700
  out.push({ id: sourceId(path2), tool: "opencode", path: path2, sessions, newestMtime, isPrimary: i === 0 });
15117
15701
  }
15702
+ for (const [i, path2] of hermesDbPaths({ includeExcluded: true }).entries()) {
15703
+ if (!existsSync24(path2))
15704
+ continue;
15705
+ const { sessions, newestMtime } = countDbSessions(path2);
15706
+ out.push({ id: sourceId(path2), tool: "hermes", path: path2, sessions, newestMtime, isPrimary: i === 0 });
15707
+ }
15118
15708
  return out;
15119
15709
  }
15120
15710
  var excludedIds, SOURCE_ID_RE, MAX_DEPTH;
@@ -15130,7 +15720,7 @@ var init_source_discovery = __esm({
15130
15720
 
15131
15721
  // ../engine/dist/core/home-discovery.js
15132
15722
  import { execFileSync as execFileSync2 } from "child_process";
15133
- import { existsSync as existsSync24, readdirSync as readdirSync15, readFileSync as readFileSync19, realpathSync as realpathSync3, statSync as statSync23 } from "fs";
15723
+ import { existsSync as existsSync25, readdirSync as readdirSync15, readFileSync as readFileSync19, realpathSync as realpathSync3, statSync as statSync23 } from "fs";
15134
15724
  import { homedir as homedir7, platform as osPlatform } from "os";
15135
15725
  import { join as join29 } from "path";
15136
15726
  function candidateRoots(plat = osPlatform(), env = process.env) {
@@ -15151,10 +15741,10 @@ function candidateRoots(plat = osPlatform(), env = process.env) {
15151
15741
  add(env.XDG_CONFIG_HOME || join29(home, ".config"));
15152
15742
  add(env.XDG_DATA_HOME || join29(home, ".local", "share"));
15153
15743
  }
15154
- return roots.filter((r) => existsSync24(r));
15744
+ return roots.filter((r) => existsSync25(r));
15155
15745
  }
15156
15746
  function identifyHome(dir) {
15157
- const has = (...parts) => existsSync24(join29(dir, ...parts));
15747
+ const has = (...parts) => existsSync25(join29(dir, ...parts));
15158
15748
  if (has("projects") && dirHasTranscript(join29(dir, "projects"), (f) => f.endsWith(".jsonl"), 2))
15159
15749
  return "claude";
15160
15750
  if (has("sessions") && dirHasTranscript(join29(dir, "sessions"), (f) => f.startsWith("rollout-") && f.endsWith(".jsonl"), 4))
@@ -15165,6 +15755,8 @@ function identifyHome(dir) {
15165
15755
  return "cursor";
15166
15756
  if (has("opencode.db"))
15167
15757
  return "opencode";
15758
+ if (has("state.db") && has("SOUL.md"))
15759
+ return "hermes";
15168
15760
  return null;
15169
15761
  }
15170
15762
  function dirHasTranscript(root, match, depth) {
@@ -15192,7 +15784,8 @@ function countSessions(dir, tool) {
15192
15784
  codex: { sub: "sessions", depth: 4, match: (f) => f.startsWith("rollout-") && f.endsWith(".jsonl") },
15193
15785
  agy: { sub: "brain", depth: 4, match: (f) => f.endsWith(".jsonl") },
15194
15786
  cursor: { sub: "chats", depth: 3, match: (f) => f === "store.db" },
15195
- opencode: { sub: "", depth: 0, match: () => false }
15787
+ opencode: { sub: "", depth: 0, match: () => false },
15788
+ hermes: { sub: "", depth: 0, match: () => false }
15196
15789
  };
15197
15790
  const s = spec[tool];
15198
15791
  if (!s.sub)
@@ -15235,6 +15828,8 @@ function declaredHomes(env = process.env, plat = osPlatform()) {
15235
15828
  add(env.CHAT_RECALL_AGY_HOME);
15236
15829
  add(env.CHAT_RECALL_CURSOR_HOME);
15237
15830
  add(env.CHAT_RECALL_CURSOR_IDE_HOME);
15831
+ add(env.CHAT_RECALL_HERMES_HOME);
15832
+ add(env.HERMES_HOME);
15238
15833
  for (const d of (env.CLAUDE_DIRS || "").split(","))
15239
15834
  add(d);
15240
15835
  if (plat === "win32") {
@@ -15334,6 +15929,15 @@ function discoverHomes(opts = {}) {
15334
15929
  if (prior && !(via === "declared" && prior.via !== "declared"))
15335
15930
  return;
15336
15931
  found.set(real, { tool, path: real, via, sessions: countSessions(real, tool) });
15932
+ if (tool === "hermes") {
15933
+ try {
15934
+ for (const e of readdirSync15(join29(real, "profiles"), { withFileTypes: true })) {
15935
+ if (e.isDirectory())
15936
+ consider(join29(real, "profiles", e.name), via);
15937
+ }
15938
+ } catch {
15939
+ }
15940
+ }
15337
15941
  };
15338
15942
  for (const d of declaredHomes(env, plat))
15339
15943
  consider(d, "declared");
@@ -16001,7 +16605,7 @@ var init_source_policy = __esm({
16001
16605
  init_project_path_match();
16002
16606
  init_settings();
16003
16607
  cache2 = null;
16004
- TOOLS = ["claude", "opencode", "codex", "agy", "cursor"];
16608
+ TOOLS = ["claude", "opencode", "codex", "agy", "cursor", "hermes"];
16005
16609
  }
16006
16610
  });
16007
16611
 
@@ -16096,7 +16700,7 @@ var init_source_registry = __esm({
16096
16700
  });
16097
16701
 
16098
16702
  // ../engine/dist/core/utils.js
16099
- import { existsSync as existsSync25, readdirSync as readdirSync16 } from "fs";
16703
+ import { existsSync as existsSync26, readdirSync as readdirSync16 } from "fs";
16100
16704
  import { homedir as homedir8 } from "os";
16101
16705
  import { join as join30 } from "path";
16102
16706
  function splitByHeaders(markdown) {
@@ -16132,7 +16736,7 @@ function getClaudeDirs() {
16132
16736
  const dirs = [];
16133
16737
  const seen = /* @__PURE__ */ new Set();
16134
16738
  const add = (dir) => {
16135
- if (!seen.has(dir) && existsSync25(dir)) {
16739
+ if (!seen.has(dir) && existsSync26(dir)) {
16136
16740
  seen.add(dir);
16137
16741
  dirs.push(dir);
16138
16742
  }
@@ -16151,7 +16755,7 @@ function getClaudeDirs() {
16151
16755
  for (const entry of entries) {
16152
16756
  if (entry.isDirectory() && entry.name.startsWith(".claude-") && entry.name !== ".claude-code") {
16153
16757
  const candidate = join30(home, entry.name);
16154
- if (existsSync25(join30(candidate, "projects"))) {
16758
+ if (existsSync26(join30(candidate, "projects"))) {
16155
16759
  add(candidate);
16156
16760
  }
16157
16761
  }
@@ -16164,7 +16768,7 @@ function discoverSubdirs(subdir) {
16164
16768
  const result = [];
16165
16769
  for (const claudeDir of getClaudeDirs()) {
16166
16770
  const path2 = join30(claudeDir, subdir);
16167
- if (existsSync25(path2)) {
16771
+ if (existsSync26(path2)) {
16168
16772
  result.push(path2);
16169
16773
  }
16170
16774
  }
@@ -16177,7 +16781,7 @@ var init_utils = __esm({
16177
16781
  });
16178
16782
 
16179
16783
  // ../engine/dist/parsers/plan-source.js
16180
- import { existsSync as existsSync26, readdirSync as readdirSync17, readFileSync as readFileSync20, statSync as statSync25 } from "fs";
16784
+ import { existsSync as existsSync27, readdirSync as readdirSync17, readFileSync as readFileSync20, statSync as statSync25 } from "fs";
16181
16785
  import { homedir as homedir9 } from "os";
16182
16786
  import { join as join31, basename as basename14 } from "path";
16183
16787
  function parseFrontmatter(content) {
@@ -16235,7 +16839,7 @@ var init_plan_source = __esm({
16235
16839
  return this._knownProjectDirs;
16236
16840
  const projectsDir = claudeBackend.projectsDir();
16237
16841
  this._knownProjectDirs = [];
16238
- if (!existsSync26(projectsDir))
16842
+ if (!existsSync27(projectsDir))
16239
16843
  return this._knownProjectDirs;
16240
16844
  try {
16241
16845
  const entries = readdirSync17(projectsDir, { withFileTypes: true });
@@ -16243,7 +16847,7 @@ var init_plan_source = __esm({
16243
16847
  if (!entry.isDirectory() || entry.name.startsWith("."))
16244
16848
  continue;
16245
16849
  const projectPath = resolveProjectDirName(entry.name);
16246
- if (existsSync26(projectPath)) {
16850
+ if (existsSync27(projectPath)) {
16247
16851
  this._knownProjectDirs.push(projectPath);
16248
16852
  }
16249
16853
  }
@@ -16267,7 +16871,7 @@ var init_plan_source = __esm({
16267
16871
  async *discoverClaudePlans() {
16268
16872
  const seenClaude = /* @__PURE__ */ new Set();
16269
16873
  for (const plansDir of this.plansDirs) {
16270
- if (!existsSync26(plansDir))
16874
+ if (!existsSync27(plansDir))
16271
16875
  continue;
16272
16876
  const files = readdirSync17(plansDir).filter((f) => f.endsWith(".md"));
16273
16877
  for (const file of files) {
@@ -16309,7 +16913,7 @@ var init_plan_source = __esm({
16309
16913
  }
16310
16914
  async *discoverOpenCodePlans() {
16311
16915
  const plansDir = opencodeBackend.plansDir();
16312
- if (!existsSync26(plansDir))
16916
+ if (!existsSync27(plansDir))
16313
16917
  return;
16314
16918
  let files;
16315
16919
  try {
@@ -16396,7 +17000,7 @@ var init_plan_source = __esm({
16396
17000
  return "";
16397
17001
  }
16398
17002
  async parse(item) {
16399
- if (!existsSync26(item.filePath))
17003
+ if (!existsSync27(item.filePath))
16400
17004
  return [];
16401
17005
  const content = readFileSync20(item.filePath, "utf-8");
16402
17006
  const chunks = [];
@@ -16437,7 +17041,7 @@ var init_plan_source = __esm({
16437
17041
  const projPath = join31(root, proj);
16438
17042
  for (const sessionEntry of safeReaddir(projPath)) {
16439
17043
  const subDir = join31(projPath, sessionEntry, "subagents");
16440
- if (!existsSync26(subDir))
17044
+ if (!existsSync27(subDir))
16441
17045
  continue;
16442
17046
  for (const f of safeReaddir(subDir)) {
16443
17047
  const m = f.match(/^agent-([a-z0-9_-]+)\.jsonl$/i);
@@ -16512,7 +17116,7 @@ var init_plan_source = __esm({
16512
17116
  }
16513
17117
  async *discoverAgyPlans() {
16514
17118
  const brainDir = join31(agyBackend.homeDir(), "brain");
16515
- if (!existsSync26(brainDir))
17119
+ if (!existsSync27(brainDir))
16516
17120
  return;
16517
17121
  let sessionDirs;
16518
17122
  try {
@@ -16567,7 +17171,7 @@ var init_plan_source = __esm({
16567
17171
  });
16568
17172
 
16569
17173
  // ../engine/dist/parsers/task-source.js
16570
- import { existsSync as existsSync27, readdirSync as readdirSync18, readFileSync as readFileSync21, statSync as statSync26 } from "fs";
17174
+ import { existsSync as existsSync28, readdirSync as readdirSync18, readFileSync as readFileSync21, statSync as statSync26 } from "fs";
16571
17175
  import { join as join32 } from "path";
16572
17176
  var MAX_CHUNK_CHARS2, TaskSource;
16573
17177
  var init_task_source = __esm({
@@ -16597,7 +17201,7 @@ var init_task_source = __esm({
16597
17201
  }
16598
17202
  async *discoverClaudeTodos() {
16599
17203
  const todosDir = claudeBackend.todosDir();
16600
- if (!existsSync27(todosDir))
17204
+ if (!existsSync28(todosDir))
16601
17205
  return;
16602
17206
  let files;
16603
17207
  try {
@@ -16648,7 +17252,7 @@ var init_task_source = __esm({
16648
17252
  }
16649
17253
  }
16650
17254
  async *discoverInDir(tasksDir) {
16651
- if (!existsSync27(tasksDir))
17255
+ if (!existsSync28(tasksDir))
16652
17256
  return;
16653
17257
  const entries = readdirSync18(tasksDir, { withFileTypes: true });
16654
17258
  for (const entry of entries) {
@@ -16690,7 +17294,7 @@ var init_task_source = __esm({
16690
17294
  return this.parseAgentTodo(item);
16691
17295
  }
16692
17296
  const taskDir = item.filePath;
16693
- if (!existsSync27(taskDir))
17297
+ if (!existsSync28(taskDir))
16694
17298
  return [];
16695
17299
  const taskFiles = readdirSync18(taskDir).filter((f) => f.endsWith(".json"));
16696
17300
  const tasks = this.readTasks(taskDir, taskFiles);
@@ -16751,7 +17355,7 @@ ${task.description}`.slice(0, MAX_CHUNK_CHARS2);
16751
17355
  }];
16752
17356
  }
16753
17357
  async parseAgentTodo(item) {
16754
- if (!existsSync27(item.filePath))
17358
+ if (!existsSync28(item.filePath))
16755
17359
  return [];
16756
17360
  let parsed;
16757
17361
  try {
@@ -16803,7 +17407,7 @@ ${task.description}`.slice(0, MAX_CHUNK_CHARS2);
16803
17407
  });
16804
17408
 
16805
17409
  // ../engine/dist/parsers/claude-md-source.js
16806
- import { existsSync as existsSync28, readFileSync as readFileSync22, readdirSync as readdirSync19, statSync as statSync27 } from "fs";
17410
+ import { existsSync as existsSync29, readFileSync as readFileSync22, readdirSync as readdirSync19, statSync as statSync27 } from "fs";
16807
17411
  import { homedir as homedir10 } from "os";
16808
17412
  import { join as join33, basename as basename15, dirname as dirname16 } from "path";
16809
17413
  import { createHash as createHash9 } from "crypto";
@@ -16811,13 +17415,13 @@ function discoverProjectDirs(claudeDir) {
16811
17415
  const dirs = [];
16812
17416
  const seen = /* @__PURE__ */ new Set();
16813
17417
  const addProject = (path2) => {
16814
- if (!seen.has(path2) && existsSync28(path2)) {
17418
+ if (!seen.has(path2) && existsSync29(path2)) {
16815
17419
  seen.add(path2);
16816
17420
  dirs.push(path2);
16817
17421
  }
16818
17422
  };
16819
17423
  const scanProjectsDir = (projectsDir) => {
16820
- if (!existsSync28(projectsDir))
17424
+ if (!existsSync29(projectsDir))
16821
17425
  return;
16822
17426
  try {
16823
17427
  const entries = readdirSync19(projectsDir, { withFileTypes: true });
@@ -16845,7 +17449,7 @@ function discoverProjectDirs(claudeDir) {
16845
17449
  } catch {
16846
17450
  }
16847
17451
  const gemProjects = agyBackend.sharedProjectsJson();
16848
- if (existsSync28(gemProjects)) {
17452
+ if (existsSync29(gemProjects)) {
16849
17453
  try {
16850
17454
  const data = JSON.parse(readFileSync22(gemProjects, "utf-8"));
16851
17455
  for (const path2 of Object.keys(data.projects || {}))
@@ -16854,7 +17458,7 @@ function discoverProjectDirs(claudeDir) {
16854
17458
  }
16855
17459
  }
16856
17460
  const ocDb = opencodeBackend.dbPath();
16857
- if (existsSync28(ocDb)) {
17461
+ if (existsSync29(ocDb)) {
16858
17462
  try {
16859
17463
  const db = openSqliteReadonlyOrThrow(ocDb);
16860
17464
  try {
@@ -16905,7 +17509,7 @@ var init_claude_md_source = __esm({
16905
17509
  for (const note of NOTE_FILES) {
16906
17510
  const p = join33(homedir10(), note.filename);
16907
17511
  const key2 = seenKey(p, note.tool);
16908
- if (existsSync28(p) && !seen.has(key2)) {
17512
+ if (existsSync29(p) && !seen.has(key2)) {
16909
17513
  seen.add(key2);
16910
17514
  const item = this.fileToItem(p, note.filename, note.tool);
16911
17515
  if (item)
@@ -16917,7 +17521,7 @@ var init_claude_md_source = __esm({
16917
17521
  for (const note of NOTE_FILES) {
16918
17522
  const p = join33(projectDir, note.filename);
16919
17523
  const key2 = seenKey(p, note.tool);
16920
- if (existsSync28(p) && !seen.has(key2)) {
17524
+ if (existsSync29(p) && !seen.has(key2)) {
16921
17525
  seen.add(key2);
16922
17526
  const item = this.fileToItem(p, note.filename, note.tool);
16923
17527
  if (item)
@@ -16926,12 +17530,12 @@ var init_claude_md_source = __esm({
16926
17530
  }
16927
17531
  }
16928
17532
  for (const searchDir of this.searchDirs) {
16929
- if (!existsSync28(searchDir))
17533
+ if (!existsSync29(searchDir))
16930
17534
  continue;
16931
17535
  for (const note of NOTE_FILES) {
16932
17536
  const directPath = join33(searchDir, note.filename);
16933
17537
  const key2 = seenKey(directPath, note.tool);
16934
- if (existsSync28(directPath) && !seen.has(key2)) {
17538
+ if (existsSync29(directPath) && !seen.has(key2)) {
16935
17539
  seen.add(key2);
16936
17540
  const item = this.fileToItem(directPath, note.filename, note.tool);
16937
17541
  if (item)
@@ -16946,7 +17550,7 @@ var init_claude_md_source = __esm({
16946
17550
  for (const note of NOTE_FILES) {
16947
17551
  const p = join33(searchDir, entry.name, note.filename);
16948
17552
  const key2 = seenKey(p, note.tool);
16949
- if (existsSync28(p) && !seen.has(key2)) {
17553
+ if (existsSync29(p) && !seen.has(key2)) {
16950
17554
  seen.add(key2);
16951
17555
  const item = this.fileToItem(p, note.filename, note.tool);
16952
17556
  if (item)
@@ -16960,7 +17564,7 @@ var init_claude_md_source = __esm({
16960
17564
  }
16961
17565
  }
16962
17566
  async parse(item) {
16963
- if (!existsSync28(item.filePath))
17567
+ if (!existsSync29(item.filePath))
16964
17568
  return [];
16965
17569
  const content = readFileSync22(item.filePath, "utf-8");
16966
17570
  const chunks = [];
@@ -17029,7 +17633,7 @@ var init_claude_md_source = __esm({
17029
17633
  });
17030
17634
 
17031
17635
  // ../engine/dist/parsers/agent-memory-source.js
17032
- import { existsSync as existsSync29, readFileSync as readFileSync23, readdirSync as readdirSync20, statSync as statSync28 } from "fs";
17636
+ import { existsSync as existsSync30, readFileSync as readFileSync23, readdirSync as readdirSync20, statSync as statSync28 } from "fs";
17033
17637
  import { homedir as homedir11 } from "os";
17034
17638
  import { join as join34, basename as basename16 } from "path";
17035
17639
  function parseFrontmatter2(content) {
@@ -17063,7 +17667,7 @@ function discoverMemoryDirs() {
17063
17667
  const out = [];
17064
17668
  const seen = /* @__PURE__ */ new Set();
17065
17669
  const add = (memoryDir, projectHash) => {
17066
- if (!seen.has(memoryDir) && existsSync29(memoryDir)) {
17670
+ if (!seen.has(memoryDir) && existsSync30(memoryDir)) {
17067
17671
  seen.add(memoryDir);
17068
17672
  out.push({ memoryDir, projectHash });
17069
17673
  }
@@ -17079,7 +17683,7 @@ function discoverMemoryDirs() {
17079
17683
  } catch {
17080
17684
  }
17081
17685
  for (const projectsDir of claudeRoots) {
17082
- if (!existsSync29(projectsDir))
17686
+ if (!existsSync30(projectsDir))
17083
17687
  continue;
17084
17688
  try {
17085
17689
  for (const entry of readdirSync20(projectsDir, { withFileTypes: true })) {
@@ -17128,7 +17732,7 @@ var init_agent_memory_source = __esm({
17128
17732
  }
17129
17733
  }
17130
17734
  async parse(item) {
17131
- if (!existsSync29(item.filePath))
17735
+ if (!existsSync30(item.filePath))
17132
17736
  return [];
17133
17737
  const content = readFileSync23(item.filePath, "utf-8");
17134
17738
  const { body: body2 } = parseFrontmatter2(content);
@@ -17214,7 +17818,7 @@ var init_agent_memory_source = __esm({
17214
17818
  });
17215
17819
 
17216
17820
  // ../engine/dist/parsers/history-source.js
17217
- import { existsSync as existsSync30, readdirSync as readdirSync21, statSync as statSync29 } from "fs";
17821
+ import { existsSync as existsSync31, readdirSync as readdirSync21, statSync as statSync29 } from "fs";
17218
17822
  import { createReadStream as createReadStream3 } from "fs";
17219
17823
  import { createInterface as createInterface2 } from "readline";
17220
17824
  import { homedir as homedir12 } from "os";
@@ -17236,7 +17840,7 @@ var init_history_source = __esm({
17236
17840
  const home = homedir12();
17237
17841
  const paths = [];
17238
17842
  const tryAdd = (p) => {
17239
- if (existsSync30(p) && !paths.includes(p))
17843
+ if (existsSync31(p) && !paths.includes(p))
17240
17844
  paths.push(p);
17241
17845
  };
17242
17846
  tryAdd(claudeBackend.historyFile());
@@ -17254,7 +17858,7 @@ var init_history_source = __esm({
17254
17858
  async *discover() {
17255
17859
  if (!isSourceEnabled("claude", "history"))
17256
17860
  return;
17257
- const historyPath = this.historyPaths.find((p) => existsSync30(p));
17861
+ const historyPath = this.historyPaths.find((p) => existsSync31(p));
17258
17862
  if (!historyPath)
17259
17863
  return;
17260
17864
  const stat3 = statSync29(historyPath);
@@ -17350,7 +17954,7 @@ var init_history_source = __esm({
17350
17954
  async groupByProject() {
17351
17955
  const groups = /* @__PURE__ */ new Map();
17352
17956
  for (const historyPath of this.historyPaths) {
17353
- if (!existsSync30(historyPath))
17957
+ if (!existsSync31(historyPath))
17354
17958
  continue;
17355
17959
  const rl = createInterface2({
17356
17960
  input: createReadStream3(historyPath),
@@ -17398,7 +18002,7 @@ var init_history_source = __esm({
17398
18002
  });
17399
18003
 
17400
18004
  // ../engine/dist/parsers/paste-source.js
17401
- import { existsSync as existsSync31, readdirSync as readdirSync22, readFileSync as readFileSync24, statSync as statSync30 } from "fs";
18005
+ import { existsSync as existsSync32, readdirSync as readdirSync22, readFileSync as readFileSync24, statSync as statSync30 } from "fs";
17402
18006
  import { homedir as homedir13 } from "os";
17403
18007
  import { join as join36, basename as basename17 } from "path";
17404
18008
  var MAX_CHUNK_CHARS6, MAX_FILE_SIZE, PasteSource;
@@ -17419,7 +18023,7 @@ var init_paste_source = __esm({
17419
18023
  const home = homedir13();
17420
18024
  const dirs = [];
17421
18025
  const tryAdd = (p) => {
17422
- if (existsSync31(p) && !dirs.includes(p))
18026
+ if (existsSync32(p) && !dirs.includes(p))
17423
18027
  dirs.push(p);
17424
18028
  };
17425
18029
  tryAdd(claudeBackend.pasteCacheDir());
@@ -17439,7 +18043,7 @@ var init_paste_source = __esm({
17439
18043
  return;
17440
18044
  const seen = /* @__PURE__ */ new Set();
17441
18045
  for (const cacheDir of this.cacheDirs) {
17442
- if (!existsSync31(cacheDir))
18046
+ if (!existsSync32(cacheDir))
17443
18047
  continue;
17444
18048
  const files = readdirSync22(cacheDir).filter((f) => f.endsWith(".txt"));
17445
18049
  for (const file of files) {
@@ -17473,7 +18077,7 @@ var init_paste_source = __esm({
17473
18077
  }
17474
18078
  }
17475
18079
  async parse(item) {
17476
- if (!existsSync31(item.filePath))
18080
+ if (!existsSync32(item.filePath))
17477
18081
  return [];
17478
18082
  const content = readFileSync24(item.filePath, "utf-8");
17479
18083
  if (content.trim().length < 20)
@@ -17498,7 +18102,7 @@ var init_paste_source = __esm({
17498
18102
  });
17499
18103
 
17500
18104
  // ../engine/dist/parsers/antigravity-brain-source.js
17501
- import { existsSync as existsSync32, readdirSync as readdirSync23, readFileSync as readFileSync25, statSync as statSync31 } from "fs";
18105
+ import { existsSync as existsSync33, readdirSync as readdirSync23, readFileSync as readFileSync25, statSync as statSync31 } from "fs";
17502
18106
  import { join as join37 } from "path";
17503
18107
  var MAX_CHUNK_CHARS7, AntigravityBrainSource;
17504
18108
  var init_antigravity_brain_source = __esm({
@@ -17517,7 +18121,7 @@ var init_antigravity_brain_source = __esm({
17517
18121
  async *discover() {
17518
18122
  if (!isSourceEnabled("agy", "brain"))
17519
18123
  return;
17520
- if (!existsSync32(this.brainDir))
18124
+ if (!existsSync33(this.brainDir))
17521
18125
  return;
17522
18126
  const sessions = readdirSync23(this.brainDir, { withFileTypes: true });
17523
18127
  for (const entry of sessions) {
@@ -17536,7 +18140,7 @@ var init_antigravity_brain_source = __esm({
17536
18140
  const heading = content.split("\n").find((l) => l.startsWith("#"))?.replace(/^#+\s*/, "").trim() || file;
17537
18141
  const metaPath = `${filePath}.metadata.json`;
17538
18142
  let metaSummary = "";
17539
- if (existsSync32(metaPath)) {
18143
+ if (existsSync33(metaPath)) {
17540
18144
  try {
17541
18145
  const meta = JSON.parse(readFileSync25(metaPath, "utf-8"));
17542
18146
  metaSummary = meta.summary || "";
@@ -17567,7 +18171,7 @@ var init_antigravity_brain_source = __esm({
17567
18171
  }
17568
18172
  }
17569
18173
  async parse(item) {
17570
- if (!existsSync32(item.filePath))
18174
+ if (!existsSync33(item.filePath))
17571
18175
  return [];
17572
18176
  const content = readFileSync25(item.filePath, "utf-8");
17573
18177
  const chunks = [];
@@ -17610,7 +18214,7 @@ var init_antigravity_brain_source = __esm({
17610
18214
  });
17611
18215
 
17612
18216
  // ../engine/dist/parsers/opencode-source.js
17613
- import { existsSync as existsSync33 } from "fs";
18217
+ import { existsSync as existsSync34 } from "fs";
17614
18218
  var MAX_CHUNK_CHARS8, OpenCodeSource;
17615
18219
  var init_opencode_source = __esm({
17616
18220
  "../engine/dist/parsers/opencode-source.js"() {
@@ -17628,7 +18232,7 @@ var init_opencode_source = __esm({
17628
18232
  async *discover() {
17629
18233
  if (!isSourceEnabled("opencode", "sessions"))
17630
18234
  return;
17631
- if (!existsSync33(this.dbPath))
18235
+ if (!existsSync34(this.dbPath))
17632
18236
  return;
17633
18237
  let db;
17634
18238
  try {
@@ -17726,7 +18330,7 @@ var init_opencode_source = __esm({
17726
18330
  }
17727
18331
  }
17728
18332
  async parse(item) {
17729
- if (!existsSync33(this.dbPath))
18333
+ if (!existsSync34(this.dbPath))
17730
18334
  return [];
17731
18335
  const sessionId = item.id.replace("opencode_", "");
17732
18336
  const db = openSqliteReadonlyOrThrow(this.dbPath);
@@ -17798,7 +18402,7 @@ var init_opencode_source = __esm({
17798
18402
  });
17799
18403
 
17800
18404
  // ../engine/dist/parsers/opencode-todo-source.js
17801
- import { existsSync as existsSync34 } from "fs";
18405
+ import { existsSync as existsSync35 } from "fs";
17802
18406
  var OpenCodeTodoSource;
17803
18407
  var init_opencode_todo_source = __esm({
17804
18408
  "../engine/dist/parsers/opencode-todo-source.js"() {
@@ -17815,7 +18419,7 @@ var init_opencode_todo_source = __esm({
17815
18419
  async *discover() {
17816
18420
  if (!isSourceEnabled("opencode", "todos"))
17817
18421
  return;
17818
- if (!existsSync34(this.dbPath))
18422
+ if (!existsSync35(this.dbPath))
17819
18423
  return;
17820
18424
  let db;
17821
18425
  try {
@@ -17864,7 +18468,7 @@ var init_opencode_todo_source = __esm({
17864
18468
  }
17865
18469
  }
17866
18470
  async parse(item) {
17867
- if (!existsSync34(this.dbPath))
18471
+ if (!existsSync35(this.dbPath))
17868
18472
  return [];
17869
18473
  const sessionId = item.extra?.sessionId || item.id.replace(`${opencodeBackend.idPrefix}todo_`, "");
17870
18474
  const db = openSqliteReadonlyOrThrow(this.dbPath);
@@ -17912,7 +18516,7 @@ var init_opencode_todo_source = __esm({
17912
18516
  });
17913
18517
 
17914
18518
  // ../engine/dist/parsers/codex-session-source.js
17915
- import { existsSync as existsSync35, readdirSync as readdirSync24, readFileSync as readFileSync26, statSync as statSync32 } from "fs";
18519
+ import { existsSync as existsSync36, readdirSync as readdirSync24, readFileSync as readFileSync26, statSync as statSync32 } from "fs";
17916
18520
  import { join as join38, basename as basename18 } from "path";
17917
18521
  function getCodexSessionsDir() {
17918
18522
  return codexBackend.sessionsDir();
@@ -17969,7 +18573,7 @@ var init_codex_session_source = __esm({
17969
18573
  async *discover() {
17970
18574
  if (!isSourceEnabled("codex", "sessions"))
17971
18575
  return;
17972
- if (!existsSync35(this.sessionsDir))
18576
+ if (!existsSync36(this.sessionsDir))
17973
18577
  return;
17974
18578
  const jsonlFiles = this.collectJsonlFiles(this.sessionsDir);
17975
18579
  for (const filePath of jsonlFiles) {
@@ -18028,7 +18632,7 @@ var init_codex_session_source = __esm({
18028
18632
  }
18029
18633
  }
18030
18634
  async parse(item) {
18031
- if (!existsSync35(item.filePath))
18635
+ if (!existsSync36(item.filePath))
18032
18636
  return [];
18033
18637
  const events = readJsonlLines(item.filePath);
18034
18638
  const chunks = [];
@@ -18131,7 +18735,7 @@ var init_codex_session_source = __esm({
18131
18735
  }
18132
18736
  collectJsonlFiles(dir) {
18133
18737
  const results = [];
18134
- if (!existsSync35(dir))
18738
+ if (!existsSync36(dir))
18135
18739
  return results;
18136
18740
  for (const entry of readdirSync24(dir, { withFileTypes: true })) {
18137
18741
  const fullPath = join38(dir, entry.name);
@@ -18148,7 +18752,7 @@ var init_codex_session_source = __esm({
18148
18752
  });
18149
18753
 
18150
18754
  // ../engine/dist/parsers/diary-source.js
18151
- import { existsSync as existsSync36, mkdirSync as mkdirSync9, readdirSync as readdirSync25, readFileSync as readFileSync27, writeFileSync as writeFileSync6, statSync as statSync33 } from "fs";
18755
+ import { existsSync as existsSync37, mkdirSync as mkdirSync9, readdirSync as readdirSync25, readFileSync as readFileSync27, writeFileSync as writeFileSync6, statSync as statSync33 } from "fs";
18152
18756
  import { join as join39, basename as basename19 } from "path";
18153
18757
  var MAX_CHUNK_CHARS10, DiarySource;
18154
18758
  var init_diary_source = __esm({
@@ -18164,7 +18768,7 @@ var init_diary_source = __esm({
18164
18768
  }
18165
18769
  /** Discover all diary entries across all agents. */
18166
18770
  async *discover() {
18167
- if (!existsSync36(this.diaryDir))
18771
+ if (!existsSync37(this.diaryDir))
18168
18772
  return;
18169
18773
  const agents = readdirSync25(this.diaryDir, { withFileTypes: true }).filter((d) => d.isDirectory());
18170
18774
  for (const agentDir of agents) {
@@ -18199,7 +18803,7 @@ var init_diary_source = __esm({
18199
18803
  }
18200
18804
  }
18201
18805
  async parse(item) {
18202
- if (!existsSync36(item.filePath))
18806
+ if (!existsSync37(item.filePath))
18203
18807
  return [];
18204
18808
  const raw = readFileSync27(item.filePath, "utf-8");
18205
18809
  const entry = JSON.parse(raw);
@@ -18239,7 +18843,7 @@ var init_diary_source = __esm({
18239
18843
  static write(entry, diaryDir) {
18240
18844
  const dir = diaryDir || getDiaryDir();
18241
18845
  const agentDir = join39(dir, entry.agent.toLowerCase().replace(/[^a-z0-9_-]/g, "_"));
18242
- if (!existsSync36(agentDir)) {
18846
+ if (!existsSync37(agentDir)) {
18243
18847
  mkdirSync9(agentDir, { recursive: true });
18244
18848
  }
18245
18849
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
@@ -18258,7 +18862,7 @@ var init_diary_source = __esm({
18258
18862
  static read(agentName, lastN = 10, diaryDir) {
18259
18863
  const dir = diaryDir || getDiaryDir();
18260
18864
  const agentDir = join39(dir, agentName.toLowerCase().replace(/[^a-z0-9_-]/g, "_"));
18261
- if (!existsSync36(agentDir))
18865
+ if (!existsSync37(agentDir))
18262
18866
  return [];
18263
18867
  const files = readdirSync25(agentDir).filter((f) => f.endsWith(".json")).sort().reverse().slice(0, lastN);
18264
18868
  const entries = [];
@@ -18309,7 +18913,7 @@ var init_redact_inline = __esm({
18309
18913
  });
18310
18914
 
18311
18915
  // ../engine/dist/parsers/skills-source.js
18312
- import { existsSync as existsSync37, readdirSync as readdirSync26, readFileSync as readFileSync28, statSync as statSync34 } from "fs";
18916
+ import { existsSync as existsSync38, readdirSync as readdirSync26, readFileSync as readFileSync28, statSync as statSync34 } from "fs";
18313
18917
  import { homedir as homedir14 } from "os";
18314
18918
  import { join as join40 } from "path";
18315
18919
  function rebuildBody(content) {
@@ -18349,7 +18953,7 @@ function resolveRoots() {
18349
18953
  all.push({ path: join40(cursorHomeDir(), "skills"), tool: "cursor" });
18350
18954
  all.push({ path: join40(cursorHomeDir(), "skills-cursor"), tool: "cursor", readonly: true });
18351
18955
  }
18352
- return all.filter((r) => existsSync37(r.path));
18956
+ return all.filter((r) => existsSync38(r.path));
18353
18957
  }
18354
18958
  function parseFrontmatter3(text) {
18355
18959
  const m = text.match(/^---\n([\s\S]*?)\n---/);
@@ -18391,7 +18995,7 @@ var init_skills_source = __esm({
18391
18995
  return;
18392
18996
  for (const { name: pluginName, dir } of codexBackend.installedPluginDirs()) {
18393
18997
  const skillsDir = join40(dir, "skills");
18394
- if (!existsSync37(skillsDir))
18998
+ if (!existsSync38(skillsDir))
18395
18999
  continue;
18396
19000
  yield* this.fromSkillRoot({ path: skillsDir, tool: "codex" }, pluginName);
18397
19001
  }
@@ -18416,7 +19020,7 @@ var init_skills_source = __esm({
18416
19020
  if (!st.isDirectory())
18417
19021
  continue;
18418
19022
  const skillMd = join40(skillDir, "SKILL.md");
18419
- if (!existsSync37(skillMd))
19023
+ if (!existsSync38(skillMd))
18420
19024
  continue;
18421
19025
  let content;
18422
19026
  try {
@@ -18481,7 +19085,7 @@ var init_skills_source = __esm({
18481
19085
  }
18482
19086
  }
18483
19087
  async parse(item) {
18484
- if (!existsSync37(item.filePath))
19088
+ if (!existsSync38(item.filePath))
18485
19089
  return [];
18486
19090
  const content = readFileSync28(item.filePath, "utf-8");
18487
19091
  if (!content.trim())
@@ -18506,11 +19110,11 @@ var init_skills_source = __esm({
18506
19110
  });
18507
19111
 
18508
19112
  // ../engine/dist/parsers/mcps-source.js
18509
- import { existsSync as existsSync38, readFileSync as readFileSync29, statSync as statSync35 } from "fs";
19113
+ import { existsSync as existsSync39, readFileSync as readFileSync29, statSync as statSync35 } from "fs";
18510
19114
  import { homedir as homedir15 } from "os";
18511
19115
  import { join as join41 } from "path";
18512
19116
  function readJson(path2) {
18513
- if (!existsSync38(path2))
19117
+ if (!existsSync39(path2))
18514
19118
  return null;
18515
19119
  try {
18516
19120
  const raw = readFileSync29(path2, "utf-8");
@@ -18673,7 +19277,7 @@ var init_mcps_source = __esm({
18673
19277
  }
18674
19278
  }
18675
19279
  async *fromCodexToml(path2) {
18676
- if (!existsSync38(path2))
19280
+ if (!existsSync39(path2))
18677
19281
  return;
18678
19282
  let content;
18679
19283
  try {
@@ -18829,7 +19433,7 @@ var init_toolkit_format = __esm({
18829
19433
  });
18830
19434
 
18831
19435
  // ../engine/dist/parsers/slash-commands-source.js
18832
- import { existsSync as existsSync39, readdirSync as readdirSync27, readFileSync as readFileSync30, statSync as statSync36 } from "fs";
19436
+ import { existsSync as existsSync40, readdirSync as readdirSync27, readFileSync as readFileSync30, statSync as statSync36 } from "fs";
18833
19437
  import { join as join42, basename as basename20 } from "path";
18834
19438
  function rebuildBody2(content) {
18835
19439
  const { text, redacted } = redactInlineSecrets(content);
@@ -18882,14 +19486,14 @@ var init_slash_commands_source = __esm({
18882
19486
  if (isSourceEnabled("claude", "commands")) {
18883
19487
  roots.push({ path: claudeBackend.commandsDir(), tool: "claude", scope: "user", projectPath: "", format: "md" });
18884
19488
  const projectsRoot = claudeBackend.projectsDir();
18885
- if (existsSync39(projectsRoot)) {
19489
+ if (existsSync40(projectsRoot)) {
18886
19490
  try {
18887
19491
  for (const entry of readdirSync27(projectsRoot, { withFileTypes: true })) {
18888
19492
  if (!entry.isDirectory() || entry.name.startsWith("."))
18889
19493
  continue;
18890
19494
  const projectPath = resolveProjectDirName(entry.name);
18891
19495
  const cmdDir = join42(projectPath, ".claude", "commands");
18892
- if (existsSync39(cmdDir))
19496
+ if (existsSync40(cmdDir))
18893
19497
  roots.push({ path: cmdDir, tool: "claude", scope: "project", projectPath, format: "md" });
18894
19498
  }
18895
19499
  } catch {
@@ -18951,7 +19555,7 @@ var init_slash_commands_source = __esm({
18951
19555
  }
18952
19556
  }
18953
19557
  async parse(item) {
18954
- if (!existsSync39(item.filePath))
19558
+ if (!existsSync40(item.filePath))
18955
19559
  return [];
18956
19560
  const content = readFileSync30(item.filePath, "utf-8");
18957
19561
  if (!content.trim())
@@ -18976,7 +19580,7 @@ var init_slash_commands_source = __esm({
18976
19580
  });
18977
19581
 
18978
19582
  // ../engine/dist/parsers/subagents-source.js
18979
- import { existsSync as existsSync40, readdirSync as readdirSync28, readFileSync as readFileSync31, statSync as statSync37 } from "fs";
19583
+ import { existsSync as existsSync41, readdirSync as readdirSync28, readFileSync as readFileSync31, statSync as statSync37 } from "fs";
18980
19584
  import { join as join43, basename as basename21 } from "path";
18981
19585
  function rebuildBody3(content) {
18982
19586
  const { text, redacted } = redactInlineSecrets(content);
@@ -19031,14 +19635,14 @@ var init_subagents_source = __esm({
19031
19635
  if (isSourceEnabled("claude", "agents")) {
19032
19636
  roots.push({ path: claudeBackend.agentsDir(), tool: "claude", scope: "user", projectPath: "", format: "md" });
19033
19637
  const projectsRoot = claudeBackend.projectsDir();
19034
- if (existsSync40(projectsRoot)) {
19638
+ if (existsSync41(projectsRoot)) {
19035
19639
  try {
19036
19640
  for (const entry of readdirSync28(projectsRoot, { withFileTypes: true })) {
19037
19641
  if (!entry.isDirectory() || entry.name.startsWith("."))
19038
19642
  continue;
19039
19643
  const projectPath = resolveProjectDirName(entry.name);
19040
19644
  const agentDir = join43(projectPath, ".claude", "agents");
19041
- if (existsSync40(agentDir))
19645
+ if (existsSync41(agentDir))
19042
19646
  roots.push({ path: agentDir, tool: "claude", scope: "project", projectPath, format: "md" });
19043
19647
  }
19044
19648
  } catch {
@@ -19101,7 +19705,7 @@ var init_subagents_source = __esm({
19101
19705
  }
19102
19706
  }
19103
19707
  async parse(item) {
19104
- if (!existsSync40(item.filePath))
19708
+ if (!existsSync41(item.filePath))
19105
19709
  return [];
19106
19710
  const content = readFileSync31(item.filePath, "utf-8");
19107
19711
  if (!content.trim())
@@ -19126,10 +19730,10 @@ var init_subagents_source = __esm({
19126
19730
  });
19127
19731
 
19128
19732
  // ../engine/dist/parsers/hooks-source.js
19129
- import { existsSync as existsSync41, readFileSync as readFileSync32, readdirSync as readdirSync29, statSync as statSync38 } from "fs";
19733
+ import { existsSync as existsSync42, readFileSync as readFileSync32, readdirSync as readdirSync29, statSync as statSync38 } from "fs";
19130
19734
  import { join as join44 } from "path";
19131
19735
  function readJson2(path2) {
19132
- if (!existsSync41(path2))
19736
+ if (!existsSync42(path2))
19133
19737
  return null;
19134
19738
  try {
19135
19739
  return JSON.parse(readFileSync32(path2, "utf-8"));
@@ -19151,14 +19755,14 @@ var init_hooks_source = __esm({
19151
19755
  return;
19152
19756
  yield* this.fromSettings(claudeBackend.settingsFile(), "user", "");
19153
19757
  const projectsRoot = claudeBackend.projectsDir();
19154
- if (existsSync41(projectsRoot)) {
19758
+ if (existsSync42(projectsRoot)) {
19155
19759
  try {
19156
19760
  for (const entry of readdirSync29(projectsRoot, { withFileTypes: true })) {
19157
19761
  if (!entry.isDirectory() || entry.name.startsWith("."))
19158
19762
  continue;
19159
19763
  const projectPath = resolveProjectDirName(entry.name);
19160
19764
  const settingsPath2 = join44(projectPath, ".claude", "settings.json");
19161
- if (existsSync41(settingsPath2)) {
19765
+ if (existsSync42(settingsPath2)) {
19162
19766
  yield* this.fromSettings(settingsPath2, "project", projectPath);
19163
19767
  }
19164
19768
  }
@@ -19249,11 +19853,11 @@ var init_hooks_source = __esm({
19249
19853
  });
19250
19854
 
19251
19855
  // ../engine/dist/parsers/plugins-source.js
19252
- import { existsSync as existsSync42, readFileSync as readFileSync33, readdirSync as readdirSync30, statSync as statSync39 } from "fs";
19856
+ import { existsSync as existsSync43, readFileSync as readFileSync33, readdirSync as readdirSync30, statSync as statSync39 } from "fs";
19253
19857
  import { homedir as homedir16 } from "os";
19254
19858
  import { join as join45 } from "path";
19255
19859
  function readJson3(path2) {
19256
- if (!existsSync42(path2))
19860
+ if (!existsSync43(path2))
19257
19861
  return null;
19258
19862
  try {
19259
19863
  return JSON.parse(readFileSync33(path2, "utf-8"));
@@ -19308,7 +19912,7 @@ var init_plugins_source = __esm({
19308
19912
  }
19309
19913
  }
19310
19914
  const gemRoot = agyBackend.sharedExtensionsDir();
19311
- if (isSourceEnabled("agy", "extensions") && existsSync42(gemRoot)) {
19915
+ if (isSourceEnabled("agy", "extensions") && existsSync43(gemRoot)) {
19312
19916
  let entries;
19313
19917
  try {
19314
19918
  entries = readdirSync30(gemRoot);
@@ -19484,6 +20088,8 @@ function toolOfId(id) {
19484
20088
  return "codex";
19485
20089
  if (id.startsWith("cursor_"))
19486
20090
  return "cursor";
20091
+ if (id.startsWith("hermes_"))
20092
+ return "hermes";
19487
20093
  return "claude";
19488
20094
  }
19489
20095
  function extractorVersionForTool(tool) {
@@ -19741,6 +20347,8 @@ function markSynced(server, rows) {
19741
20347
  else if (prev?.F !== void 0) base2.F = prev.F;
19742
20348
  if (cursorFromCaller && r.chunkedHead) base2.k = 1;
19743
20349
  else if (prev?.k && !completesChunked && !(cursorFromCaller && r.full)) base2.k = 1;
20350
+ const layout = cursorFromCaller ? r.layout : prev?.L;
20351
+ if (layout) base2.L = layout;
19744
20352
  forServer[r.id] = base2;
19745
20353
  }
19746
20354
  persist(data);
@@ -19881,12 +20489,12 @@ var init_sync_fields = __esm({
19881
20489
  });
19882
20490
 
19883
20491
  // ../engine/dist/core/index-lock.js
19884
- import { existsSync as existsSync43, mkdirSync as mkdirSync11, openSync as openSync9, writeFileSync as writeFileSync8, readFileSync as readFileSync35, rmSync as rmSync4, statSync as statSync41, closeSync as closeSync9 } from "fs";
20492
+ import { existsSync as existsSync44, mkdirSync as mkdirSync11, openSync as openSync9, writeFileSync as writeFileSync8, readFileSync as readFileSync35, rmSync as rmSync4, statSync as statSync41, closeSync as closeSync9 } from "fs";
19885
20493
  import { dirname as dirname18, join as join47 } from "path";
19886
20494
  function acquireIndexLock(opts) {
19887
20495
  const lockPath = lockFilePath(opts.file);
19888
20496
  mkdirSync11(dirname18(lockPath), { recursive: true });
19889
- if (existsSync43(lockPath)) {
20497
+ if (existsSync44(lockPath)) {
19890
20498
  if (!stealStaleLock(lockPath, opts.staleAfterMs ?? 10 * 6e4)) {
19891
20499
  return null;
19892
20500
  }
@@ -19997,7 +20605,7 @@ var init_http = __esm({
19997
20605
  CLI_VERSION = JSON.parse(readFileSync36(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
19998
20606
  } catch {
19999
20607
  try {
20000
- if (true) CLI_VERSION = "0.7.18";
20608
+ if (true) CLI_VERSION = "0.7.19";
20001
20609
  } catch {
20002
20610
  }
20003
20611
  }
@@ -20094,7 +20702,7 @@ var init_derived = __esm({
20094
20702
 
20095
20703
  // src/scan-pool.ts
20096
20704
  import { Worker } from "node:worker_threads";
20097
- import { existsSync as existsSync44 } from "node:fs";
20705
+ import { existsSync as existsSync45 } from "node:fs";
20098
20706
  import { fileURLToPath } from "node:url";
20099
20707
  import { cpus } from "node:os";
20100
20708
  function poolSize() {
@@ -20109,7 +20717,7 @@ function workerScript() {
20109
20717
  for (const rel of ["./scan-worker.js", "../dist/scan-worker.js"]) {
20110
20718
  try {
20111
20719
  const p = fileURLToPath(new URL(rel, import.meta.url));
20112
- if (existsSync44(p)) return p;
20720
+ if (existsSync45(p)) return p;
20113
20721
  } catch {
20114
20722
  }
20115
20723
  }
@@ -20495,7 +21103,7 @@ var init_telemetry = __esm({
20495
21103
  init_sync_client();
20496
21104
  cliVersion2 = () => {
20497
21105
  try {
20498
- return true ? "0.7.18" : "dev";
21106
+ return true ? "0.7.19" : "dev";
20499
21107
  } catch {
20500
21108
  return "dev";
20501
21109
  }
@@ -20810,7 +21418,7 @@ __export(auto_update_exports, {
20810
21418
  tarballUrl: () => tarballUrl
20811
21419
  });
20812
21420
  import { execSync as execSync4, execFileSync as execFileSync3 } from "node:child_process";
20813
- import { readFileSync as readFileSync38, existsSync as existsSync45 } from "node:fs";
21421
+ import { readFileSync as readFileSync38, existsSync as existsSync46 } from "node:fs";
20814
21422
  import { fileURLToPath as fileURLToPath2 } from "node:url";
20815
21423
  import { writeFileSync as writeFileSync9, mkdtempSync as mkdtempSync3, rmSync as rmSync6, readdirSync as readdirSync31, statSync as statSync43, mkdirSync as mkdirSync12 } from "node:fs";
20816
21424
  import { join as join49, dirname as dirname19, sep as sep3, posix as pathPosix, win32 as pathWin32 } from "node:path";
@@ -20971,7 +21579,7 @@ function resolveNpm(loc) {
20971
21579
  }
20972
21580
  function realInstall(tgz) {
20973
21581
  const prefix = runningPrefix();
20974
- const npm = resolveNpm({ execPath: process.execPath, prefix, platform: process.platform, env: process.env, exists: existsSync45 });
21582
+ const npm = resolveNpm({ execPath: process.execPath, prefix, platform: process.platform, env: process.env, exists: existsSync46 });
20975
21583
  if (prefix) {
20976
21584
  npmInstall(npm, ["install", "-g", "--prefix", prefix, tgz]);
20977
21585
  return;
@@ -21824,6 +22432,11 @@ async function syncToTargetInScope(cred, opts = {}) {
21824
22432
  };
21825
22433
  const localSessionIds = /* @__PURE__ */ new Set();
21826
22434
  const shippedHash = /* @__PURE__ */ new Map();
22435
+ const shippedLayout = /* @__PURE__ */ new Map();
22436
+ const layoutOf = (id) => {
22437
+ const layout = shippedLayout.get(id);
22438
+ return layout ? { layout } : {};
22439
+ };
21827
22440
  const makeBatcher = (field, maxItems, flatten = false, onFlush, barrier) => {
21828
22441
  let batch = [];
21829
22442
  let batchBytes = 0;
@@ -21856,7 +22469,7 @@ async function syncToTargetInScope(cred, opts = {}) {
21856
22469
  markSynced(base2, rows.map((r) => {
21857
22470
  const off = typeof r.from_offset === "number" ? r.from_offset : 0;
21858
22471
  const hash = shippedHash.get(r.session_id);
21859
- return off > 0 ? { id: r.session_id, mtime: r.mtime, offset: off, size: off, hash, acked: true, full: true } : { id: r.session_id, mtime: r.mtime, hash };
22472
+ 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 };
21860
22473
  }));
21861
22474
  } catch {
21862
22475
  }
@@ -21899,8 +22512,9 @@ async function syncToTargetInScope(cred, opts = {}) {
21899
22512
  // size = new offset (file grew to here)
21900
22513
  acked: true,
21901
22514
  // server merged this tail
21902
- chunkFinal: c.final === true
22515
+ chunkFinal: c.final === true,
21903
22516
  // completes a chunked full sync
22517
+ ...layoutOf(c.session_id)
21904
22518
  })));
21905
22519
  } catch {
21906
22520
  }
@@ -21932,9 +22546,9 @@ async function syncToTargetInScope(cred, opts = {}) {
21932
22546
  const mtime = conv.mtime;
21933
22547
  try {
21934
22548
  if (staged || !guarded) {
21935
- markSynced(base2, [{ id, mtime, offset: conv.from_offset, size: conv.from_offset, acked: true, chunkedHead: true }]);
22549
+ markSynced(base2, [{ id, mtime, offset: conv.from_offset, size: conv.from_offset, acked: true, chunkedHead: true, ...layoutOf(id) }]);
21936
22550
  } else if (typeof guarded.o === "number" && guarded.o > 0 && guarded.o <= fileSize) {
21937
- markSynced(base2, [{ id, mtime, offset: guarded.o, size: guarded.o, acked: true, chunkedHead: true }]);
22551
+ markSynced(base2, [{ id, mtime, offset: guarded.o, size: guarded.o, acked: true, chunkedHead: true, ...layoutOf(id) }]);
21938
22552
  } else {
21939
22553
  markSynced(base2, [{ id, mtime }]);
21940
22554
  }
@@ -22029,8 +22643,8 @@ async function syncToTargetInScope(cred, opts = {}) {
22029
22643
  if (!ledger) return ref.mtime >= (opts.sinceMs ?? 0) ? "full" : "skip";
22030
22644
  const ack = ledger.get(ref.prefixedId);
22031
22645
  const backend = backendFor(ref);
22032
- const split = !!backend?.spansMultipleSources?.(ref.prefixedId);
22033
- const isAO = !!backend?.isAppendOnly?.() && !split;
22646
+ const sameLayout = (ack?.L ?? "") === (backend?.sourceLayout?.(ref.prefixedId) ?? "");
22647
+ const isAO = !!backend?.isAppendOnly?.() && sameLayout;
22034
22648
  const size = isAO ? backend?.fileSize?.(ref.prefixedId) ?? 0 : 0;
22035
22649
  return syncMode(ack, ref.mtime, size, extractorVersionForTool(ref.toolId), isAO);
22036
22650
  };
@@ -22077,6 +22691,9 @@ async function syncToTargetInScope(cred, opts = {}) {
22077
22691
  skipped++;
22078
22692
  continue;
22079
22693
  }
22694
+ const layout = backendFor(ref)?.sourceLayout?.(ref.prefixedId) ?? "";
22695
+ if (layout) shippedLayout.set(ref.prefixedId, layout);
22696
+ else shippedLayout.delete(ref.prefixedId);
22080
22697
  trace?.(`build (${mode}) ${ref.prefixedId} \xB7 ${(sessionFileBytes(ref) / 1048576).toFixed(1)}MB`);
22081
22698
  let promotedForFindings = false;
22082
22699
  if (mode === "append" && ledger) {
@@ -22122,7 +22739,7 @@ async function syncToTargetInScope(cred, opts = {}) {
22122
22739
  const off = getBackendForId(ref.prefixedId)?.fileSize?.(ref.rawId) ?? 0;
22123
22740
  const priorCursor = ackRow?.s ?? 0;
22124
22741
  const safeToAck = off > 0 && off <= priorCursor;
22125
- markSynced(base2, [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 }]);
22742
+ markSynced(base2, [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 }]);
22126
22743
  } catch {
22127
22744
  }
22128
22745
  }
@@ -22877,7 +23494,7 @@ var init_sync_client = __esm({
22877
23494
  ownVersion = JSON.parse(readFileSync39(join50(dir, "../package.json"), "utf-8")).version || ownVersion;
22878
23495
  } catch {
22879
23496
  try {
22880
- if (true) ownVersion = "0.7.18";
23497
+ if (true) ownVersion = "0.7.19";
22881
23498
  } catch {
22882
23499
  }
22883
23500
  }
@@ -23159,7 +23776,7 @@ __export(service_installer_exports, {
23159
23776
  uninstallService: () => uninstallService
23160
23777
  });
23161
23778
  import { execSync as execSync5 } from "child_process";
23162
- import { existsSync as existsSync46, mkdirSync as mkdirSync14, readFileSync as readFileSync42, rmSync as rmSync8, writeFileSync as writeFileSync12 } from "fs";
23779
+ import { existsSync as existsSync47, mkdirSync as mkdirSync14, readFileSync as readFileSync42, rmSync as rmSync8, writeFileSync as writeFileSync12 } from "fs";
23163
23780
  import { homedir as homedir18 } from "os";
23164
23781
  import { join as join52 } from "path";
23165
23782
  import { fileURLToPath as fileURLToPath4 } from "url";
@@ -23195,7 +23812,7 @@ function refreshServiceDefinition() {
23195
23812
  try {
23196
23813
  const { watchJs, node, logFile } = resolveDaemonPaths();
23197
23814
  const unitPath = join52(homedir18(), ".config", "systemd", "user", "chat-recall-watch.service");
23198
- if (!existsSync46(unitPath)) return false;
23815
+ if (!existsSync47(unitPath)) return false;
23199
23816
  const current = readFileSync42(unitPath, "utf8");
23200
23817
  if (!current.includes(watchJs)) return false;
23201
23818
  const wanted = renderSystemdUnit(watchJs, node, logFile);
@@ -23363,7 +23980,7 @@ function uninstallService() {
23363
23980
  } catch {
23364
23981
  }
23365
23982
  const unitPath = join52(homedir18(), ".config", "systemd", "user", "chat-recall-watch.service");
23366
- if (existsSync46(unitPath)) {
23983
+ if (existsSync47(unitPath)) {
23367
23984
  rmSync8(unitPath, { force: true });
23368
23985
  removed = true;
23369
23986
  }
@@ -23380,7 +23997,7 @@ function uninstallService() {
23380
23997
  } catch {
23381
23998
  }
23382
23999
  let removed = false;
23383
- if (existsSync46(plistPath)) {
24000
+ if (existsSync47(plistPath)) {
23384
24001
  rmSync8(plistPath, { force: true });
23385
24002
  removed = true;
23386
24003
  }
@@ -23427,7 +24044,7 @@ __export(install_skills_exports, {
23427
24044
  skillsSourceDir: () => skillsSourceDir,
23428
24045
  uninstallSkills: () => uninstallSkills
23429
24046
  });
23430
- import { readdirSync as readdirSync33, existsSync as existsSync47, mkdirSync as mkdirSync15, rmSync as rmSync9, cpSync, writeFileSync as writeFileSync13, readFileSync as readFileSync43, statSync as statSync45, realpathSync as realpathSync4 } from "fs";
24047
+ import { readdirSync as readdirSync33, existsSync as existsSync48, mkdirSync as mkdirSync15, rmSync as rmSync9, cpSync, writeFileSync as writeFileSync13, readFileSync as readFileSync43, statSync as statSync45, realpathSync as realpathSync4 } from "fs";
23431
24048
  import { createHash as createHash12 } from "crypto";
23432
24049
  import { join as join53, basename as basename23 } from "path";
23433
24050
  function skillsSourceDir() {
@@ -23466,8 +24083,8 @@ function skillStamp() {
23466
24083
  }
23467
24084
  function bundledSkillNames() {
23468
24085
  const src = skillsSourceDir();
23469
- if (!existsSync47(src)) return [];
23470
- return readdirSync33(src, { withFileTypes: true }).filter((e) => e.isDirectory() && existsSync47(join53(src, e.name, "SKILL.md"))).map((e) => e.name).sort();
24086
+ if (!existsSync48(src)) return [];
24087
+ return readdirSync33(src, { withFileTypes: true }).filter((e) => e.isDirectory() && existsSync48(join53(src, e.name, "SKILL.md"))).map((e) => e.name).sort();
23471
24088
  }
23472
24089
  function realPathOrSelf(p) {
23473
24090
  try {
@@ -23491,7 +24108,7 @@ function claudeSkillTargets() {
23491
24108
  dir,
23492
24109
  // Judge each profile on ITS OWN transcripts, not the primary's: a home
23493
24110
  // with no projects/ is a directory someone made, not a Claude install.
23494
- available: existsSync47(join53(home, "projects"))
24111
+ available: existsSync48(join53(home, "projects"))
23495
24112
  });
23496
24113
  }
23497
24114
  if (targets.length === 0) {
@@ -23515,7 +24132,7 @@ function skillTargets() {
23515
24132
  ];
23516
24133
  }
23517
24134
  function isManaged(dir) {
23518
- return existsSync47(join53(dir, MARKER));
24135
+ return existsSync48(join53(dir, MARKER));
23519
24136
  }
23520
24137
  function installSkills(opts = {}) {
23521
24138
  const onlyAvailable = opts.onlyAvailable ?? true;
@@ -23533,7 +24150,7 @@ function installSkills(opts = {}) {
23533
24150
  }
23534
24151
  for (const name of names) {
23535
24152
  const dest = join53(t.dir, name);
23536
- if (existsSync47(dest) && !isManaged(dest)) {
24153
+ if (existsSync48(dest) && !isManaged(dest)) {
23537
24154
  skippedUserOwned.push(name);
23538
24155
  continue;
23539
24156
  }
@@ -23553,7 +24170,7 @@ function uninstallSkills() {
23553
24170
  const perTarget = [];
23554
24171
  for (const t of skillTargets()) {
23555
24172
  const removed = [];
23556
- if (!existsSync47(t.dir)) {
24173
+ if (!existsSync48(t.dir)) {
23557
24174
  perTarget.push({ id: t.id, label: t.label, removed });
23558
24175
  continue;
23559
24176
  }
@@ -23577,7 +24194,7 @@ function skillsNeedRefresh() {
23577
24194
  if (!t.available) continue;
23578
24195
  for (const name of names) {
23579
24196
  const marker = join53(t.dir, name, MARKER);
23580
- if (!existsSync47(marker)) return true;
24197
+ if (!existsSync48(marker)) return true;
23581
24198
  try {
23582
24199
  if (readFileSync43(marker, "utf-8").trim() !== cur) return true;
23583
24200
  } catch {
@@ -23595,7 +24212,7 @@ function skillStatus() {
23595
24212
  let ver = null;
23596
24213
  for (const name of names) {
23597
24214
  const marker = join53(t.dir, name, MARKER);
23598
- if (existsSync47(marker)) {
24215
+ if (existsSync48(marker)) {
23599
24216
  installed++;
23600
24217
  try {
23601
24218
  ver = readFileSync43(marker, "utf-8").trim();
@@ -23855,6 +24472,7 @@ var SESSION_ID_PREFIXES = {
23855
24472
  opencode: "opencode_",
23856
24473
  agy: "agy_",
23857
24474
  cursor: "cursor_",
24475
+ hermes: "hermes_",
23858
24476
  gemini: "gemini_"
23859
24477
  };
23860
24478
  function toolOfSessionId(sessionId) {
@@ -23883,6 +24501,8 @@ function resumeCommandFor(sessionId, tool) {
23883
24501
  // available answer for either.
23884
24502
  case "cursor":
23885
24503
  return `cursor-agent --resume ${raw("cursor_")}`;
24504
+ case "hermes":
24505
+ return `hermes --resume ${raw("hermes_")}`;
23886
24506
  // Gemini's `--resume` takes an index or "latest", never a session id.
23887
24507
  default:
23888
24508
  return null;
@@ -24872,7 +25492,7 @@ function isMultiTenant() {
24872
25492
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
24873
25493
  import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ListPromptsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
24874
25494
  import { z } from "zod";
24875
- import { existsSync as existsSync22, readFileSync as readFileSync18, statSync as statSync21 } from "fs";
25495
+ import { existsSync as existsSync23, readFileSync as readFileSync18, statSync as statSync21 } from "fs";
24876
25496
  import { join as join27 } from "path";
24877
25497
 
24878
25498
  // ../engine/dist/core/context.js
@@ -25020,7 +25640,7 @@ function sanitizeQuery(query) {
25020
25640
 
25021
25641
  // ../engine/dist/core/write-ahead-log.js
25022
25642
  init_paths();
25023
- import { existsSync as existsSync17, mkdirSync as mkdirSync5, appendFileSync, openSync as openSync8, closeSync as closeSync8, chmodSync as chmodSync3 } from "fs";
25643
+ import { existsSync as existsSync18, mkdirSync as mkdirSync5, appendFileSync, openSync as openSync8, closeSync as closeSync8, chmodSync as chmodSync3 } from "fs";
25024
25644
  import { join as join20 } from "path";
25025
25645
  var REDACT_KEYS = /* @__PURE__ */ new Set([
25026
25646
  "content",
@@ -25037,7 +25657,7 @@ var WriteAheadLog = class {
25037
25657
  walPath;
25038
25658
  constructor(walDir) {
25039
25659
  const dir = walDir || getWalDir();
25040
- if (!existsSync17(dir)) {
25660
+ if (!existsSync18(dir)) {
25041
25661
  mkdirSync5(dir, { recursive: true });
25042
25662
  try {
25043
25663
  chmodSync3(dir, 448);
@@ -25045,7 +25665,7 @@ var WriteAheadLog = class {
25045
25665
  }
25046
25666
  }
25047
25667
  this.walPath = join20(dir, "write_log.jsonl");
25048
- if (!existsSync17(this.walPath)) {
25668
+ if (!existsSync18(this.walPath)) {
25049
25669
  const fd = openSync8(this.walPath, "w", 384);
25050
25670
  closeSync8(fd);
25051
25671
  }
@@ -25406,7 +26026,7 @@ var RecallEditsTimelineSchema = z.object({
25406
26026
  pattern: z.string().optional().describe("Optional substring filter on file path"),
25407
26027
  project_filter: z.string().optional().describe("Filter by project name (matched against the encoded project directory name)"),
25408
26028
  include_reads: z.boolean().optional().default(false).describe("Include read-type tool calls in addition to write/edit ones"),
25409
- tools: z.array(z.enum(["claude", "opencode", "codex", "agy", "cursor"])).optional().describe("Restrict to a subset of AI tools. Default: every tool this machine has."),
26029
+ tools: z.array(z.enum(["claude", "opencode", "codex", "agy", "cursor", "hermes"])).optional().describe("Restrict to a subset of AI tools. Default: every tool this machine has."),
25410
26030
  group_by_repo: z.boolean().optional().default(false).describe("Group output by detected git repo root instead of returning a flat list. Useful when a single session touched multiple repos."),
25411
26031
  view: z.enum(["timeline", "summary"]).optional().default("timeline").describe("timeline = the chronological edit rows; summary = an aggregated rollup over the same window"),
25412
26032
  group_by: z.enum(["session"]).optional().describe('"session" = aggregate edits per session instead of a flat timeline \u2014 answers "which sessions touched files matching X?" (pass `pattern` + a wide `since_hours`, e.g. 720 for 30 days).')
@@ -26118,7 +26738,7 @@ aggregate per session instead \u2014 "which sessions edited auth.rs in the last
26118
26738
  include_reads: { type: "boolean", default: false, description: "Include Read tool_uses too" },
26119
26739
  tools: {
26120
26740
  type: "array",
26121
- items: { type: "string", enum: ["claude", "opencode", "codex", "agy", "cursor"] },
26741
+ items: { type: "string", enum: ["claude", "opencode", "codex", "agy", "cursor", "hermes"] },
26122
26742
  description: "Restrict to specific AI tools. Default: every tool this machine has."
26123
26743
  },
26124
26744
  group_by_repo: { type: "boolean", default: false, description: "Group results by detected git repo root." },
@@ -28079,7 +28699,7 @@ _Edits stayed local or window was off \u2014 try increasing buffer_minutes._` }]
28079
28699
  }
28080
28700
  case "recall_project_context": {
28081
28701
  const params = RecallProjectContextSchema.parse(args);
28082
- const target = existsSync22(params.project_path) && statSync21(params.project_path).isDirectory() ? resolveProjectId(params.project_path).id : params.project_path;
28702
+ const target = existsSync23(params.project_path) && statSync21(params.project_path).isDirectory() ? resolveProjectId(params.project_path).id : params.project_path;
28083
28703
  const dossier = await remoteGetQS(`/api/projects/${encodeURIComponent(target)}/dossier`, { sessions: params.limit, tasks: params.tasks, plans: params.plans });
28084
28704
  return { content: [{ type: "text", text: dossier.markdown }] };
28085
28705
  }
@@ -29039,7 +29659,7 @@ Subject: ${params.subject}`;
29039
29659
  const start = resolve2(p.path ?? process.cwd());
29040
29660
  let root = start;
29041
29661
  for (let dir = start, last = ""; dir && dir !== last; last = dir, dir = resolve2(dir, "..")) {
29042
- if (existsSync22(join27(dir, ".git"))) {
29662
+ if (existsSync23(join27(dir, ".git"))) {
29043
29663
  root = dir;
29044
29664
  break;
29045
29665
  }
@@ -29196,7 +29816,7 @@ ${row.value}`
29196
29816
  let identity = params.identity ?? "AI coding assistant";
29197
29817
  if (!params.identity && !isMultiTenant()) {
29198
29818
  const idFile = getIdentityFilePath();
29199
- if (existsSync22(idFile)) {
29819
+ if (existsSync23(idFile)) {
29200
29820
  try {
29201
29821
  identity = readFileSync18(idFile, "utf-8").trim() || identity;
29202
29822
  } catch {
@@ -29868,7 +30488,7 @@ function installCrashGuards() {
29868
30488
  reportClientEvent2("mcp_crash", { message: err.stack || err.message });
29869
30489
  });
29870
30490
  }
29871
- var RELAY_VERSION = true ? "0.7.18" : "0.0.0";
30491
+ var RELAY_VERSION = true ? "0.7.19" : "0.0.0";
29872
30492
  function daemonIdleSecs() {
29873
30493
  const raw = process.env.CHAT_RECALL_DAEMON_IDLE_SECS;
29874
30494
  if (raw === void 0) return 900;