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/README.md +2 -2
- package/dist/cli.js +873 -248
- package/dist/cli.js.map +1 -1
- package/dist/mcp-relay.js +1 -1
- package/dist/mcp.js +799 -179
- package/dist/scan-worker.js +615 -31
- package/dist/sync-client.d.ts.map +1 -1
- package/dist/sync-client.js +24 -10
- package/dist/sync-client.js.map +1 -1
- package/dist/sync-ledger.d.ts +6 -0
- package/dist/sync-ledger.d.ts.map +1 -1
- package/dist/sync-ledger.js +3 -0
- package/dist/sync-ledger.js.map +1 -1
- package/dist/watch.js +801 -170
- package/package.json +1 -1
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
|
|
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
|
|
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
|
|
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 (!
|
|
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 (
|
|
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 || !
|
|
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 (!
|
|
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 (
|
|
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.
|
|
10715
|
-
*
|
|
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
|
|
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
|
|
10726
|
-
return
|
|
10727
|
-
return
|
|
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
|
|
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
|
|
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 (!
|
|
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 (!
|
|
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 (!
|
|
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
|
|
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 (!
|
|
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
|
|
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) || !
|
|
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 (!
|
|
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 (!
|
|
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:
|
|
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 (!
|
|
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:
|
|
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 (!
|
|
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
|
|
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 (
|
|
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
|
|
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 (
|
|
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
|
|
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 (
|
|
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 (!
|
|
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
|
|
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 (!
|
|
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 (!
|
|
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
|
|
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
|
|
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 (!
|
|
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 (!
|
|
15697
|
+
if (!existsSync24(path2))
|
|
15114
15698
|
continue;
|
|
15115
|
-
const { sessions, newestMtime } =
|
|
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
|
|
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) =>
|
|
15744
|
+
return roots.filter((r) => existsSync25(r));
|
|
15155
15745
|
}
|
|
15156
15746
|
function identifyHome(dir) {
|
|
15157
|
-
const has = (...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
|
|
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) &&
|
|
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 (
|
|
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 (
|
|
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
|
|
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 (!
|
|
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 (
|
|
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 (!
|
|
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 (!
|
|
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 (!
|
|
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 (!
|
|
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 (!
|
|
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
|
|
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 (!
|
|
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 (!
|
|
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 (!
|
|
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 (!
|
|
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
|
|
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) &&
|
|
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 (!
|
|
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 (
|
|
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 (
|
|
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 (
|
|
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 (
|
|
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 (!
|
|
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 (
|
|
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 (
|
|
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 (!
|
|
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
|
|
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) &&
|
|
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 (!
|
|
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 (!
|
|
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
|
|
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 (
|
|
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) =>
|
|
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 (!
|
|
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
|
|
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 (
|
|
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 (!
|
|
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 (!
|
|
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
|
|
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 (!
|
|
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 (
|
|
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 (!
|
|
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
|
|
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 (!
|
|
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 (!
|
|
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
|
|
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 (!
|
|
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 (!
|
|
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
|
|
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 (!
|
|
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 (!
|
|
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 (!
|
|
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
|
|
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 (!
|
|
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 (!
|
|
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 (!
|
|
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 (!
|
|
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
|
|
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) =>
|
|
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 (!
|
|
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 (!
|
|
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 (!
|
|
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
|
|
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 (!
|
|
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 (!
|
|
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
|
|
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 (
|
|
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 (
|
|
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 (!
|
|
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
|
|
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 (
|
|
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 (
|
|
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 (!
|
|
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
|
|
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 (!
|
|
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 (
|
|
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 (
|
|
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
|
|
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 (!
|
|
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") &&
|
|
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
|
|
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 (
|
|
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.
|
|
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
|
|
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 (
|
|
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.
|
|
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
|
|
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:
|
|
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
|
|
22033
|
-
const isAO = !!backend?.isAppendOnly?.() &&
|
|
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.
|
|
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
|
|
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 (!
|
|
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 (
|
|
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 (
|
|
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
|
|
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 (!
|
|
23470
|
-
return readdirSync33(src, { withFileTypes: true }).filter((e) => e.isDirectory() &&
|
|
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:
|
|
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
|
|
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 (
|
|
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 (!
|
|
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 (!
|
|
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 (
|
|
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
|
|
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
|
|
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 (!
|
|
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 (!
|
|
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 =
|
|
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 (
|
|
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 (
|
|
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.
|
|
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;
|