chat-recall 0.7.17 → 0.7.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/cli.js +1402 -538
- package/dist/cli.js.map +1 -1
- package/dist/mcp-relay.js +136 -40
- package/dist/mcp-relay.js.map +1 -1
- package/dist/mcp.js +1160 -290
- package/dist/mcp.js.map +1 -1
- package/dist/raw-archive-parts.d.ts +46 -0
- package/dist/raw-archive-parts.d.ts.map +1 -0
- package/dist/raw-archive-parts.js +175 -0
- package/dist/raw-archive-parts.js.map +1 -0
- package/dist/relay-lifecycle.d.ts +23 -0
- package/dist/relay-lifecycle.d.ts.map +1 -1
- package/dist/relay-lifecycle.js +173 -0
- package/dist/relay-lifecycle.js.map +1 -1
- package/dist/repair.d.ts.map +1 -1
- package/dist/repair.js +15 -7
- package/dist/repair.js.map +1 -1
- package/dist/scan-worker.js +617 -31
- package/dist/sync-client.d.ts +8 -0
- package/dist/sync-client.d.ts.map +1 -1
- package/dist/sync-client.js +107 -12
- package/dist/sync-client.js.map +1 -1
- package/dist/sync-ledger.d.ts +37 -1
- package/dist/sync-ledger.d.ts.map +1 -1
- package/dist/sync-ledger.js +50 -1
- package/dist/sync-ledger.js.map +1 -1
- package/dist/watch.js +1221 -348
- package/package.json +1 -1
package/dist/mcp.js
CHANGED
|
@@ -2034,7 +2034,7 @@ var require_thread_stream = __commonJS({
|
|
|
2034
2034
|
var { version: version2 } = require_package();
|
|
2035
2035
|
var { EventEmitter } = __require("events");
|
|
2036
2036
|
var { Worker: Worker2 } = __require("worker_threads");
|
|
2037
|
-
var { join:
|
|
2037
|
+
var { join: join54 } = __require("path");
|
|
2038
2038
|
var { pathToFileURL } = __require("url");
|
|
2039
2039
|
var { wait } = require_wait();
|
|
2040
2040
|
var {
|
|
@@ -2077,7 +2077,7 @@ var require_thread_stream = __commonJS({
|
|
|
2077
2077
|
function createWorker(stream, opts) {
|
|
2078
2078
|
const { filename, workerData } = opts;
|
|
2079
2079
|
const bundlerOverrides = "__bundlerPathsOverrides" in globalThis ? globalThis.__bundlerPathsOverrides : {};
|
|
2080
|
-
const toExecute = bundlerOverrides["thread-stream-worker"] ||
|
|
2080
|
+
const toExecute = bundlerOverrides["thread-stream-worker"] || join54(__dirname, "lib", "worker.js");
|
|
2081
2081
|
const worker = new Worker2(toExecute, {
|
|
2082
2082
|
...opts.workerOpts,
|
|
2083
2083
|
trackUnmanagedFds: false,
|
|
@@ -2480,7 +2480,7 @@ var require_transport = __commonJS({
|
|
|
2480
2480
|
"use strict";
|
|
2481
2481
|
var { createRequire: createRequire3 } = __require("module");
|
|
2482
2482
|
var getCallers = require_caller();
|
|
2483
|
-
var { join:
|
|
2483
|
+
var { join: join54, isAbsolute: isAbsolute3, sep: sep4 } = __require("node:path");
|
|
2484
2484
|
var sleep = require_atomic_sleep();
|
|
2485
2485
|
var onExit = require_on_exit_leak_free();
|
|
2486
2486
|
var ThreadStream = require_thread_stream();
|
|
@@ -2543,7 +2543,7 @@ var require_transport = __commonJS({
|
|
|
2543
2543
|
throw new Error("only one of target or targets can be specified");
|
|
2544
2544
|
}
|
|
2545
2545
|
if (targets) {
|
|
2546
|
-
target = bundlerOverrides["pino-worker"] ||
|
|
2546
|
+
target = bundlerOverrides["pino-worker"] || join54(__dirname, "worker.js");
|
|
2547
2547
|
options.targets = targets.filter((dest) => dest.target).map((dest) => {
|
|
2548
2548
|
return {
|
|
2549
2549
|
...dest,
|
|
@@ -2561,7 +2561,7 @@ var require_transport = __commonJS({
|
|
|
2561
2561
|
});
|
|
2562
2562
|
});
|
|
2563
2563
|
} else if (pipeline) {
|
|
2564
|
-
target = bundlerOverrides["pino-worker"] ||
|
|
2564
|
+
target = bundlerOverrides["pino-worker"] || join54(__dirname, "worker.js");
|
|
2565
2565
|
options.pipelines = [pipeline.map((dest) => {
|
|
2566
2566
|
return {
|
|
2567
2567
|
...dest,
|
|
@@ -2583,7 +2583,7 @@ var require_transport = __commonJS({
|
|
|
2583
2583
|
return origin;
|
|
2584
2584
|
}
|
|
2585
2585
|
if (origin === "pino/file") {
|
|
2586
|
-
return
|
|
2586
|
+
return join54(__dirname, "..", "file.js");
|
|
2587
2587
|
}
|
|
2588
2588
|
let fixTarget2;
|
|
2589
2589
|
for (const filePath of callers) {
|
|
@@ -3572,7 +3572,7 @@ var require_safe_stable_stringify = __commonJS({
|
|
|
3572
3572
|
return circularValue;
|
|
3573
3573
|
}
|
|
3574
3574
|
let res = "";
|
|
3575
|
-
let
|
|
3575
|
+
let join54 = ",";
|
|
3576
3576
|
const originalIndentation = indentation;
|
|
3577
3577
|
if (Array.isArray(value)) {
|
|
3578
3578
|
if (value.length === 0) {
|
|
@@ -3586,7 +3586,7 @@ var require_safe_stable_stringify = __commonJS({
|
|
|
3586
3586
|
indentation += spacer;
|
|
3587
3587
|
res += `
|
|
3588
3588
|
${indentation}`;
|
|
3589
|
-
|
|
3589
|
+
join54 = `,
|
|
3590
3590
|
${indentation}`;
|
|
3591
3591
|
}
|
|
3592
3592
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
@@ -3594,13 +3594,13 @@ ${indentation}`;
|
|
|
3594
3594
|
for (; i < maximumValuesToStringify - 1; i++) {
|
|
3595
3595
|
const tmp2 = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
|
|
3596
3596
|
res += tmp2 !== void 0 ? tmp2 : "null";
|
|
3597
|
-
res +=
|
|
3597
|
+
res += join54;
|
|
3598
3598
|
}
|
|
3599
3599
|
const tmp = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
|
|
3600
3600
|
res += tmp !== void 0 ? tmp : "null";
|
|
3601
3601
|
if (value.length - 1 > maximumBreadth) {
|
|
3602
3602
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
3603
|
-
res += `${
|
|
3603
|
+
res += `${join54}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
3604
3604
|
}
|
|
3605
3605
|
if (spacer !== "") {
|
|
3606
3606
|
res += `
|
|
@@ -3621,7 +3621,7 @@ ${originalIndentation}`;
|
|
|
3621
3621
|
let separator = "";
|
|
3622
3622
|
if (spacer !== "") {
|
|
3623
3623
|
indentation += spacer;
|
|
3624
|
-
|
|
3624
|
+
join54 = `,
|
|
3625
3625
|
${indentation}`;
|
|
3626
3626
|
whitespace = " ";
|
|
3627
3627
|
}
|
|
@@ -3635,13 +3635,13 @@ ${indentation}`;
|
|
|
3635
3635
|
const tmp = stringifyFnReplacer(key3, value, stack, replacer, spacer, indentation);
|
|
3636
3636
|
if (tmp !== void 0) {
|
|
3637
3637
|
res += `${separator}${strEscape(key3)}:${whitespace}${tmp}`;
|
|
3638
|
-
separator =
|
|
3638
|
+
separator = join54;
|
|
3639
3639
|
}
|
|
3640
3640
|
}
|
|
3641
3641
|
if (keyLength > maximumBreadth) {
|
|
3642
3642
|
const removedKeys = keyLength - maximumBreadth;
|
|
3643
3643
|
res += `${separator}"...":${whitespace}"${getItemCount(removedKeys)} not stringified"`;
|
|
3644
|
-
separator =
|
|
3644
|
+
separator = join54;
|
|
3645
3645
|
}
|
|
3646
3646
|
if (spacer !== "" && separator.length > 1) {
|
|
3647
3647
|
res = `
|
|
@@ -3682,7 +3682,7 @@ ${originalIndentation}`;
|
|
|
3682
3682
|
}
|
|
3683
3683
|
const originalIndentation = indentation;
|
|
3684
3684
|
let res = "";
|
|
3685
|
-
let
|
|
3685
|
+
let join54 = ",";
|
|
3686
3686
|
if (Array.isArray(value)) {
|
|
3687
3687
|
if (value.length === 0) {
|
|
3688
3688
|
return "[]";
|
|
@@ -3695,7 +3695,7 @@ ${originalIndentation}`;
|
|
|
3695
3695
|
indentation += spacer;
|
|
3696
3696
|
res += `
|
|
3697
3697
|
${indentation}`;
|
|
3698
|
-
|
|
3698
|
+
join54 = `,
|
|
3699
3699
|
${indentation}`;
|
|
3700
3700
|
}
|
|
3701
3701
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
@@ -3703,13 +3703,13 @@ ${indentation}`;
|
|
|
3703
3703
|
for (; i < maximumValuesToStringify - 1; i++) {
|
|
3704
3704
|
const tmp2 = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
|
|
3705
3705
|
res += tmp2 !== void 0 ? tmp2 : "null";
|
|
3706
|
-
res +=
|
|
3706
|
+
res += join54;
|
|
3707
3707
|
}
|
|
3708
3708
|
const tmp = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
|
|
3709
3709
|
res += tmp !== void 0 ? tmp : "null";
|
|
3710
3710
|
if (value.length - 1 > maximumBreadth) {
|
|
3711
3711
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
3712
|
-
res += `${
|
|
3712
|
+
res += `${join54}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
3713
3713
|
}
|
|
3714
3714
|
if (spacer !== "") {
|
|
3715
3715
|
res += `
|
|
@@ -3722,7 +3722,7 @@ ${originalIndentation}`;
|
|
|
3722
3722
|
let whitespace = "";
|
|
3723
3723
|
if (spacer !== "") {
|
|
3724
3724
|
indentation += spacer;
|
|
3725
|
-
|
|
3725
|
+
join54 = `,
|
|
3726
3726
|
${indentation}`;
|
|
3727
3727
|
whitespace = " ";
|
|
3728
3728
|
}
|
|
@@ -3731,7 +3731,7 @@ ${indentation}`;
|
|
|
3731
3731
|
const tmp = stringifyArrayReplacer(key3, value[key3], stack, replacer, spacer, indentation);
|
|
3732
3732
|
if (tmp !== void 0) {
|
|
3733
3733
|
res += `${separator}${strEscape(key3)}:${whitespace}${tmp}`;
|
|
3734
|
-
separator =
|
|
3734
|
+
separator = join54;
|
|
3735
3735
|
}
|
|
3736
3736
|
}
|
|
3737
3737
|
if (spacer !== "" && separator.length > 1) {
|
|
@@ -3789,20 +3789,20 @@ ${originalIndentation}`;
|
|
|
3789
3789
|
indentation += spacer;
|
|
3790
3790
|
let res2 = `
|
|
3791
3791
|
${indentation}`;
|
|
3792
|
-
const
|
|
3792
|
+
const join55 = `,
|
|
3793
3793
|
${indentation}`;
|
|
3794
3794
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
3795
3795
|
let i = 0;
|
|
3796
3796
|
for (; i < maximumValuesToStringify - 1; i++) {
|
|
3797
3797
|
const tmp2 = stringifyIndent(String(i), value[i], stack, spacer, indentation);
|
|
3798
3798
|
res2 += tmp2 !== void 0 ? tmp2 : "null";
|
|
3799
|
-
res2 +=
|
|
3799
|
+
res2 += join55;
|
|
3800
3800
|
}
|
|
3801
3801
|
const tmp = stringifyIndent(String(i), value[i], stack, spacer, indentation);
|
|
3802
3802
|
res2 += tmp !== void 0 ? tmp : "null";
|
|
3803
3803
|
if (value.length - 1 > maximumBreadth) {
|
|
3804
3804
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
3805
|
-
res2 += `${
|
|
3805
|
+
res2 += `${join55}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
3806
3806
|
}
|
|
3807
3807
|
res2 += `
|
|
3808
3808
|
${originalIndentation}`;
|
|
@@ -3818,16 +3818,16 @@ ${originalIndentation}`;
|
|
|
3818
3818
|
return '"[Object]"';
|
|
3819
3819
|
}
|
|
3820
3820
|
indentation += spacer;
|
|
3821
|
-
const
|
|
3821
|
+
const join54 = `,
|
|
3822
3822
|
${indentation}`;
|
|
3823
3823
|
let res = "";
|
|
3824
3824
|
let separator = "";
|
|
3825
3825
|
let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth);
|
|
3826
3826
|
if (isTypedArrayWithEntries(value)) {
|
|
3827
|
-
res += stringifyTypedArray(value,
|
|
3827
|
+
res += stringifyTypedArray(value, join54, maximumBreadth);
|
|
3828
3828
|
keys = keys.slice(value.length);
|
|
3829
3829
|
maximumPropertiesToStringify -= value.length;
|
|
3830
|
-
separator =
|
|
3830
|
+
separator = join54;
|
|
3831
3831
|
}
|
|
3832
3832
|
if (deterministic) {
|
|
3833
3833
|
keys = sort(keys, comparator);
|
|
@@ -3838,13 +3838,13 @@ ${indentation}`;
|
|
|
3838
3838
|
const tmp = stringifyIndent(key3, value[key3], stack, spacer, indentation);
|
|
3839
3839
|
if (tmp !== void 0) {
|
|
3840
3840
|
res += `${separator}${strEscape(key3)}: ${tmp}`;
|
|
3841
|
-
separator =
|
|
3841
|
+
separator = join54;
|
|
3842
3842
|
}
|
|
3843
3843
|
}
|
|
3844
3844
|
if (keyLength > maximumBreadth) {
|
|
3845
3845
|
const removedKeys = keyLength - maximumBreadth;
|
|
3846
3846
|
res += `${separator}"...": "${getItemCount(removedKeys)} not stringified"`;
|
|
3847
|
-
separator =
|
|
3847
|
+
separator = join54;
|
|
3848
3848
|
}
|
|
3849
3849
|
if (separator !== "") {
|
|
3850
3850
|
res = `
|
|
@@ -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 };
|
|
@@ -11680,6 +12264,7 @@ var init_from_events = __esm({
|
|
|
11680
12264
|
// ../engine/dist/transcript/raw.js
|
|
11681
12265
|
var raw_exports = {};
|
|
11682
12266
|
__export(raw_exports, {
|
|
12267
|
+
RAW_PARSE_MAX_BYTES: () => RAW_PARSE_MAX_BYTES,
|
|
11683
12268
|
archiveRawSession: () => archiveRawSession,
|
|
11684
12269
|
buildRawContainer: () => buildRawContainer,
|
|
11685
12270
|
containerSrcHash: () => containerSrcHash,
|
|
@@ -11979,11 +12564,11 @@ async function archiveRawSession(store2, sessionId) {
|
|
|
11979
12564
|
return await store2.putRawSession(sessionId, exp.tool, Math.floor(exp.mtime), gz, size);
|
|
11980
12565
|
}
|
|
11981
12566
|
function detectForkPredecessor(sessionPath) {
|
|
11982
|
-
const { readFileSync:
|
|
11983
|
-
const { dirname: dirname21, join:
|
|
12567
|
+
const { readFileSync: readFileSync45, readdirSync: readdirSync34 } = requireFs();
|
|
12568
|
+
const { dirname: dirname21, join: join54, basename: basename24 } = requirePath();
|
|
11984
12569
|
let text;
|
|
11985
12570
|
try {
|
|
11986
|
-
text =
|
|
12571
|
+
text = readFileSync45(sessionPath, "utf-8");
|
|
11987
12572
|
} catch {
|
|
11988
12573
|
return null;
|
|
11989
12574
|
}
|
|
@@ -12017,7 +12602,7 @@ function detectForkPredecessor(sessionPath) {
|
|
|
12017
12602
|
if (!f.endsWith(".jsonl") || f === self || f === "sessions-index.json")
|
|
12018
12603
|
continue;
|
|
12019
12604
|
try {
|
|
12020
|
-
if (
|
|
12605
|
+
if (readFileSync45(join54(dir, f), "utf-8").includes(`"uuid":"${headParent}"`)) {
|
|
12021
12606
|
return basename24(f, ".jsonl");
|
|
12022
12607
|
}
|
|
12023
12608
|
} catch {
|
|
@@ -12031,7 +12616,7 @@ function requireFs() {
|
|
|
12031
12616
|
function requirePath() {
|
|
12032
12617
|
return pathMod;
|
|
12033
12618
|
}
|
|
12034
|
-
var MARKER_QUOTE;
|
|
12619
|
+
var RAW_PARSE_MAX_BYTES, MARKER_QUOTE;
|
|
12035
12620
|
var init_raw = __esm({
|
|
12036
12621
|
"../engine/dist/transcript/raw.js"() {
|
|
12037
12622
|
"use strict";
|
|
@@ -12039,6 +12624,7 @@ var init_raw = __esm({
|
|
|
12039
12624
|
init_claude2();
|
|
12040
12625
|
init_codex2();
|
|
12041
12626
|
init_from_events();
|
|
12627
|
+
RAW_PARSE_MAX_BYTES = 40 * 1024 * 1024;
|
|
12042
12628
|
MARKER_QUOTE = /\[REDACTED:[A-Za-z0-9_-]+\]"/g;
|
|
12043
12629
|
}
|
|
12044
12630
|
});
|
|
@@ -12046,7 +12632,7 @@ var init_raw = __esm({
|
|
|
12046
12632
|
// ../engine/dist/transcript/shadow.js
|
|
12047
12633
|
import { gzipSync as gzipSync2, gunzipSync as gunzipSync2 } from "zlib";
|
|
12048
12634
|
import { createHash as createHash4 } from "crypto";
|
|
12049
|
-
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";
|
|
12050
12636
|
import { dirname as dirname14, join as join18 } from "path";
|
|
12051
12637
|
function shadowRoot() {
|
|
12052
12638
|
return join18(getDataDir(), "shadow");
|
|
@@ -12057,7 +12643,7 @@ function shadowFileFor(tool, rawId) {
|
|
|
12057
12643
|
}
|
|
12058
12644
|
function readShadowContainer(tool, rawId) {
|
|
12059
12645
|
const path2 = shadowFileFor(tool, rawId);
|
|
12060
|
-
if (!
|
|
12646
|
+
if (!existsSync16(path2))
|
|
12061
12647
|
return null;
|
|
12062
12648
|
try {
|
|
12063
12649
|
const c = JSON.parse(gunzipSync2(readFileSync11(path2)).toString("utf-8"));
|
|
@@ -12259,7 +12845,7 @@ var init_shadow = __esm({
|
|
|
12259
12845
|
});
|
|
12260
12846
|
|
|
12261
12847
|
// ../engine/dist/core/live-session-scan.js
|
|
12262
|
-
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";
|
|
12263
12849
|
import { join as join19, basename as basename12 } from "path";
|
|
12264
12850
|
function detectTool(sessionId) {
|
|
12265
12851
|
return getBackendForId(sessionId)?.id ?? "claude";
|
|
@@ -12316,7 +12902,7 @@ function sessionFileIndex() {
|
|
|
12316
12902
|
return p;
|
|
12317
12903
|
};
|
|
12318
12904
|
for (const root of roots) {
|
|
12319
|
-
if (seenRoots.has(root) || !
|
|
12905
|
+
if (seenRoots.has(root) || !existsSync17(root))
|
|
12320
12906
|
continue;
|
|
12321
12907
|
seenRoots.add(root);
|
|
12322
12908
|
dirs.set(root, dirMtime(root));
|
|
@@ -12442,7 +13028,7 @@ function resolveSessionContentPaths(sessionFile) {
|
|
|
12442
13028
|
if (!hasSubagentsDir(sessionFile))
|
|
12443
13029
|
return [sessionFile];
|
|
12444
13030
|
const subDir = join19(sessionFile.slice(0, -6), "subagents");
|
|
12445
|
-
if (!
|
|
13031
|
+
if (!existsSync17(subDir))
|
|
12446
13032
|
return [sessionFile];
|
|
12447
13033
|
const subPaths = readdirSync13(subDir).filter((f) => f.endsWith(".jsonl")).sort().map((f) => join19(subDir, f));
|
|
12448
13034
|
return [sessionFile, ...subPaths];
|
|
@@ -12459,7 +13045,7 @@ function findCodexSessionFile(sessionId) {
|
|
|
12459
13045
|
return null;
|
|
12460
13046
|
}
|
|
12461
13047
|
function findCodexSessionFileIn(root, sessionId) {
|
|
12462
|
-
if (!
|
|
13048
|
+
if (!existsSync17(root))
|
|
12463
13049
|
return null;
|
|
12464
13050
|
for (const year of readdirSync13(root, { withFileTypes: true })) {
|
|
12465
13051
|
if (!year.isDirectory())
|
|
@@ -12552,10 +13138,10 @@ var init_types = __esm({
|
|
|
12552
13138
|
|
|
12553
13139
|
// ../engine/dist/transcript/opencode.js
|
|
12554
13140
|
async function parseOpenCodeSubagents(parentSessionId) {
|
|
12555
|
-
const { existsSync:
|
|
13141
|
+
const { existsSync: existsSync49 } = await import("fs");
|
|
12556
13142
|
const { opencodeBackend: opencodeBackend2 } = await Promise.resolve().then(() => (init_opencode(), opencode_exports));
|
|
12557
13143
|
const dbPath = opencodeBackend2.dbPath();
|
|
12558
|
-
if (!
|
|
13144
|
+
if (!existsSync49(dbPath))
|
|
12559
13145
|
return [];
|
|
12560
13146
|
const realParent = parentSessionId.replace("opencode_", "");
|
|
12561
13147
|
const db = openSqliteReadonlyOrThrow(dbPath);
|
|
@@ -12596,10 +13182,10 @@ async function parseOpenCodeSubagents(parentSessionId) {
|
|
|
12596
13182
|
}
|
|
12597
13183
|
}
|
|
12598
13184
|
async function parseOpenCodeTranscript(sessionId) {
|
|
12599
|
-
const { existsSync:
|
|
13185
|
+
const { existsSync: existsSync49 } = await import("fs");
|
|
12600
13186
|
const { opencodeBackend: opencodeBackend2 } = await Promise.resolve().then(() => (init_opencode(), opencode_exports));
|
|
12601
13187
|
const dbPath = opencodeBackend2.dbPath();
|
|
12602
|
-
if (!
|
|
13188
|
+
if (!existsSync49(dbPath))
|
|
12603
13189
|
return [];
|
|
12604
13190
|
const realId = sessionId.replace("opencode_", "");
|
|
12605
13191
|
const db = openSqliteReadonlyOrThrow(dbPath);
|
|
@@ -12873,7 +13459,7 @@ var init_credentials_env = __esm({
|
|
|
12873
13459
|
});
|
|
12874
13460
|
|
|
12875
13461
|
// ../engine/dist/core/which.js
|
|
12876
|
-
import { existsSync as
|
|
13462
|
+
import { existsSync as existsSync19, statSync as statSync17, accessSync as accessSync2, constants as constants2 } from "node:fs";
|
|
12877
13463
|
import { join as join21, isAbsolute as isAbsolute2, delimiter as delimiter2, sep as sep2 } from "node:path";
|
|
12878
13464
|
function executable(p) {
|
|
12879
13465
|
try {
|
|
@@ -12914,7 +13500,7 @@ function resolveOnPath(name) {
|
|
|
12914
13500
|
continue;
|
|
12915
13501
|
for (const c of candidates(name)) {
|
|
12916
13502
|
const full = join21(dir, c);
|
|
12917
|
-
if (
|
|
13503
|
+
if (existsSync19(full) && executable(full))
|
|
12918
13504
|
return full;
|
|
12919
13505
|
}
|
|
12920
13506
|
}
|
|
@@ -13078,7 +13664,7 @@ var init_code_intel = __esm({
|
|
|
13078
13664
|
});
|
|
13079
13665
|
|
|
13080
13666
|
// ../engine/dist/core/companions.js
|
|
13081
|
-
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";
|
|
13082
13668
|
import { homedir as homedir5 } from "node:os";
|
|
13083
13669
|
import { join as join23 } from "node:path";
|
|
13084
13670
|
import { execSync as execSync2 } from "node:child_process";
|
|
@@ -13201,7 +13787,7 @@ Refusing to install. The release may have been re-uploaded, or something is serv
|
|
|
13201
13787
|
renameSync3(tmpPath, CODEINDEX_BIN_PATH);
|
|
13202
13788
|
} catch (err) {
|
|
13203
13789
|
try {
|
|
13204
|
-
if (
|
|
13790
|
+
if (existsSync20(tmpPath))
|
|
13205
13791
|
unlinkSync(tmpPath);
|
|
13206
13792
|
} catch {
|
|
13207
13793
|
}
|
|
@@ -13638,7 +14224,7 @@ var init_secret_redactor = __esm({
|
|
|
13638
14224
|
|
|
13639
14225
|
// ../engine/dist/core/detector-install.js
|
|
13640
14226
|
import { createHash as createHash7 } from "crypto";
|
|
13641
|
-
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";
|
|
13642
14228
|
import { join as join24 } from "path";
|
|
13643
14229
|
function managedDetectorPath(name) {
|
|
13644
14230
|
return join24(getDetectorBinDir(), name + exeSuffix());
|
|
@@ -13678,7 +14264,7 @@ function resolveDetector(name) {
|
|
|
13678
14264
|
const dir = configuredDir();
|
|
13679
14265
|
if (dir) {
|
|
13680
14266
|
const p2 = join24(dir, name + exeSuffix());
|
|
13681
|
-
if (
|
|
14267
|
+
if (existsSync21(p2))
|
|
13682
14268
|
return { path: p2, version: "operator-supplied", source: "configured" };
|
|
13683
14269
|
return { error: "not-installed" };
|
|
13684
14270
|
}
|
|
@@ -13686,7 +14272,7 @@ function resolveDetector(name) {
|
|
|
13686
14272
|
if (!spec.assets[platformKey()])
|
|
13687
14273
|
return { error: "unsupported-platform" };
|
|
13688
14274
|
const p = managedDetectorPath(name);
|
|
13689
|
-
if (!
|
|
14275
|
+
if (!existsSync21(p))
|
|
13690
14276
|
return { error: "not-installed" };
|
|
13691
14277
|
const receipt = readReceipt(name);
|
|
13692
14278
|
if (!receipt)
|
|
@@ -13742,7 +14328,7 @@ var init_detector_install = __esm({
|
|
|
13742
14328
|
|
|
13743
14329
|
// ../engine/dist/core/secret-scanner.js
|
|
13744
14330
|
import { spawnSync } from "child_process";
|
|
13745
|
-
import { existsSync as
|
|
14331
|
+
import { existsSync as existsSync22, unlinkSync as unlinkSync2, readFileSync as readFileSync16, mkdtempSync as mkdtempSync2, rmSync as rmSync3 } from "fs";
|
|
13746
14332
|
import { tmpdir as tmpdir2 } from "os";
|
|
13747
14333
|
import { join as join25 } from "path";
|
|
13748
14334
|
function mask(s) {
|
|
@@ -13908,7 +14494,7 @@ function runTrufflehogDir(binary, dir, opts = {}) {
|
|
|
13908
14494
|
return out;
|
|
13909
14495
|
}
|
|
13910
14496
|
function scanDirForSecrets(dir, opts = {}) {
|
|
13911
|
-
if (!
|
|
14497
|
+
if (!existsSync22(dir))
|
|
13912
14498
|
return [];
|
|
13913
14499
|
const gitleaks = whichDetector("gitleaks");
|
|
13914
14500
|
const trufflehog = whichDetector("trufflehog");
|
|
@@ -13945,7 +14531,7 @@ function scanTenantRules(text, tenantRules) {
|
|
|
13945
14531
|
return out;
|
|
13946
14532
|
}
|
|
13947
14533
|
function scanFileForSecrets(filePath, opts = {}) {
|
|
13948
|
-
if (!
|
|
14534
|
+
if (!existsSync22(filePath))
|
|
13949
14535
|
return [];
|
|
13950
14536
|
const gitleaks = whichDetector("gitleaks");
|
|
13951
14537
|
const trufflehog = whichDetector("trufflehog");
|
|
@@ -15024,7 +15610,7 @@ var init_collector = __esm({
|
|
|
15024
15610
|
|
|
15025
15611
|
// ../engine/dist/core/source-discovery.js
|
|
15026
15612
|
import { createHash as createHash8 } from "crypto";
|
|
15027
|
-
import { existsSync as
|
|
15613
|
+
import { existsSync as existsSync24, readdirSync as readdirSync14, statSync as statSync22 } from "fs";
|
|
15028
15614
|
import { join as join28 } from "path";
|
|
15029
15615
|
function sourceId(path2) {
|
|
15030
15616
|
return "src_" + createHash8("sha256").update(path2).digest("hex").slice(0, 12);
|
|
@@ -15083,7 +15669,7 @@ function countTranscripts(root, tool) {
|
|
|
15083
15669
|
walk(root, 0);
|
|
15084
15670
|
return { sessions, newestMtime };
|
|
15085
15671
|
}
|
|
15086
|
-
function
|
|
15672
|
+
function countDbSessions(dbPath) {
|
|
15087
15673
|
try {
|
|
15088
15674
|
const st = statSync22(dbPath);
|
|
15089
15675
|
return { sessions: 0, newestMtime: st.mtimeMs };
|
|
@@ -15101,18 +15687,24 @@ function discoverSessionSources() {
|
|
|
15101
15687
|
];
|
|
15102
15688
|
for (const [tool, dirs] of dirTools) {
|
|
15103
15689
|
for (const [i, path2] of dirs.entries()) {
|
|
15104
|
-
if (!
|
|
15690
|
+
if (!existsSync24(path2))
|
|
15105
15691
|
continue;
|
|
15106
15692
|
const { sessions, newestMtime } = countTranscripts(path2, tool);
|
|
15107
15693
|
out.push({ id: sourceId(path2), tool, path: path2, sessions, newestMtime, isPrimary: i === 0 });
|
|
15108
15694
|
}
|
|
15109
15695
|
}
|
|
15110
15696
|
for (const [i, path2] of opencodeDbPaths({ includeExcluded: true }).entries()) {
|
|
15111
|
-
if (!
|
|
15697
|
+
if (!existsSync24(path2))
|
|
15112
15698
|
continue;
|
|
15113
|
-
const { sessions, newestMtime } =
|
|
15699
|
+
const { sessions, newestMtime } = countDbSessions(path2);
|
|
15114
15700
|
out.push({ id: sourceId(path2), tool: "opencode", path: path2, sessions, newestMtime, isPrimary: i === 0 });
|
|
15115
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
|
+
}
|
|
15116
15708
|
return out;
|
|
15117
15709
|
}
|
|
15118
15710
|
var excludedIds, SOURCE_ID_RE, MAX_DEPTH;
|
|
@@ -15128,7 +15720,7 @@ var init_source_discovery = __esm({
|
|
|
15128
15720
|
|
|
15129
15721
|
// ../engine/dist/core/home-discovery.js
|
|
15130
15722
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
15131
|
-
import { existsSync as
|
|
15723
|
+
import { existsSync as existsSync25, readdirSync as readdirSync15, readFileSync as readFileSync19, realpathSync as realpathSync3, statSync as statSync23 } from "fs";
|
|
15132
15724
|
import { homedir as homedir7, platform as osPlatform } from "os";
|
|
15133
15725
|
import { join as join29 } from "path";
|
|
15134
15726
|
function candidateRoots(plat = osPlatform(), env = process.env) {
|
|
@@ -15149,10 +15741,10 @@ function candidateRoots(plat = osPlatform(), env = process.env) {
|
|
|
15149
15741
|
add(env.XDG_CONFIG_HOME || join29(home, ".config"));
|
|
15150
15742
|
add(env.XDG_DATA_HOME || join29(home, ".local", "share"));
|
|
15151
15743
|
}
|
|
15152
|
-
return roots.filter((r) =>
|
|
15744
|
+
return roots.filter((r) => existsSync25(r));
|
|
15153
15745
|
}
|
|
15154
15746
|
function identifyHome(dir) {
|
|
15155
|
-
const has = (...parts) =>
|
|
15747
|
+
const has = (...parts) => existsSync25(join29(dir, ...parts));
|
|
15156
15748
|
if (has("projects") && dirHasTranscript(join29(dir, "projects"), (f) => f.endsWith(".jsonl"), 2))
|
|
15157
15749
|
return "claude";
|
|
15158
15750
|
if (has("sessions") && dirHasTranscript(join29(dir, "sessions"), (f) => f.startsWith("rollout-") && f.endsWith(".jsonl"), 4))
|
|
@@ -15163,6 +15755,8 @@ function identifyHome(dir) {
|
|
|
15163
15755
|
return "cursor";
|
|
15164
15756
|
if (has("opencode.db"))
|
|
15165
15757
|
return "opencode";
|
|
15758
|
+
if (has("state.db") && has("SOUL.md"))
|
|
15759
|
+
return "hermes";
|
|
15166
15760
|
return null;
|
|
15167
15761
|
}
|
|
15168
15762
|
function dirHasTranscript(root, match, depth) {
|
|
@@ -15190,7 +15784,8 @@ function countSessions(dir, tool) {
|
|
|
15190
15784
|
codex: { sub: "sessions", depth: 4, match: (f) => f.startsWith("rollout-") && f.endsWith(".jsonl") },
|
|
15191
15785
|
agy: { sub: "brain", depth: 4, match: (f) => f.endsWith(".jsonl") },
|
|
15192
15786
|
cursor: { sub: "chats", depth: 3, match: (f) => f === "store.db" },
|
|
15193
|
-
opencode: { sub: "", depth: 0, match: () => false }
|
|
15787
|
+
opencode: { sub: "", depth: 0, match: () => false },
|
|
15788
|
+
hermes: { sub: "", depth: 0, match: () => false }
|
|
15194
15789
|
};
|
|
15195
15790
|
const s = spec[tool];
|
|
15196
15791
|
if (!s.sub)
|
|
@@ -15233,6 +15828,8 @@ function declaredHomes(env = process.env, plat = osPlatform()) {
|
|
|
15233
15828
|
add(env.CHAT_RECALL_AGY_HOME);
|
|
15234
15829
|
add(env.CHAT_RECALL_CURSOR_HOME);
|
|
15235
15830
|
add(env.CHAT_RECALL_CURSOR_IDE_HOME);
|
|
15831
|
+
add(env.CHAT_RECALL_HERMES_HOME);
|
|
15832
|
+
add(env.HERMES_HOME);
|
|
15236
15833
|
for (const d of (env.CLAUDE_DIRS || "").split(","))
|
|
15237
15834
|
add(d);
|
|
15238
15835
|
if (plat === "win32") {
|
|
@@ -15332,6 +15929,15 @@ function discoverHomes(opts = {}) {
|
|
|
15332
15929
|
if (prior && !(via === "declared" && prior.via !== "declared"))
|
|
15333
15930
|
return;
|
|
15334
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
|
+
}
|
|
15335
15941
|
};
|
|
15336
15942
|
for (const d of declaredHomes(env, plat))
|
|
15337
15943
|
consider(d, "declared");
|
|
@@ -15999,7 +16605,7 @@ var init_source_policy = __esm({
|
|
|
15999
16605
|
init_project_path_match();
|
|
16000
16606
|
init_settings();
|
|
16001
16607
|
cache2 = null;
|
|
16002
|
-
TOOLS = ["claude", "opencode", "codex", "agy", "cursor"];
|
|
16608
|
+
TOOLS = ["claude", "opencode", "codex", "agy", "cursor", "hermes"];
|
|
16003
16609
|
}
|
|
16004
16610
|
});
|
|
16005
16611
|
|
|
@@ -16094,7 +16700,7 @@ var init_source_registry = __esm({
|
|
|
16094
16700
|
});
|
|
16095
16701
|
|
|
16096
16702
|
// ../engine/dist/core/utils.js
|
|
16097
|
-
import { existsSync as
|
|
16703
|
+
import { existsSync as existsSync26, readdirSync as readdirSync16 } from "fs";
|
|
16098
16704
|
import { homedir as homedir8 } from "os";
|
|
16099
16705
|
import { join as join30 } from "path";
|
|
16100
16706
|
function splitByHeaders(markdown) {
|
|
@@ -16130,7 +16736,7 @@ function getClaudeDirs() {
|
|
|
16130
16736
|
const dirs = [];
|
|
16131
16737
|
const seen = /* @__PURE__ */ new Set();
|
|
16132
16738
|
const add = (dir) => {
|
|
16133
|
-
if (!seen.has(dir) &&
|
|
16739
|
+
if (!seen.has(dir) && existsSync26(dir)) {
|
|
16134
16740
|
seen.add(dir);
|
|
16135
16741
|
dirs.push(dir);
|
|
16136
16742
|
}
|
|
@@ -16149,7 +16755,7 @@ function getClaudeDirs() {
|
|
|
16149
16755
|
for (const entry of entries) {
|
|
16150
16756
|
if (entry.isDirectory() && entry.name.startsWith(".claude-") && entry.name !== ".claude-code") {
|
|
16151
16757
|
const candidate = join30(home, entry.name);
|
|
16152
|
-
if (
|
|
16758
|
+
if (existsSync26(join30(candidate, "projects"))) {
|
|
16153
16759
|
add(candidate);
|
|
16154
16760
|
}
|
|
16155
16761
|
}
|
|
@@ -16162,7 +16768,7 @@ function discoverSubdirs(subdir) {
|
|
|
16162
16768
|
const result = [];
|
|
16163
16769
|
for (const claudeDir of getClaudeDirs()) {
|
|
16164
16770
|
const path2 = join30(claudeDir, subdir);
|
|
16165
|
-
if (
|
|
16771
|
+
if (existsSync26(path2)) {
|
|
16166
16772
|
result.push(path2);
|
|
16167
16773
|
}
|
|
16168
16774
|
}
|
|
@@ -16175,7 +16781,7 @@ var init_utils = __esm({
|
|
|
16175
16781
|
});
|
|
16176
16782
|
|
|
16177
16783
|
// ../engine/dist/parsers/plan-source.js
|
|
16178
|
-
import { existsSync as
|
|
16784
|
+
import { existsSync as existsSync27, readdirSync as readdirSync17, readFileSync as readFileSync20, statSync as statSync25 } from "fs";
|
|
16179
16785
|
import { homedir as homedir9 } from "os";
|
|
16180
16786
|
import { join as join31, basename as basename14 } from "path";
|
|
16181
16787
|
function parseFrontmatter(content) {
|
|
@@ -16233,7 +16839,7 @@ var init_plan_source = __esm({
|
|
|
16233
16839
|
return this._knownProjectDirs;
|
|
16234
16840
|
const projectsDir = claudeBackend.projectsDir();
|
|
16235
16841
|
this._knownProjectDirs = [];
|
|
16236
|
-
if (!
|
|
16842
|
+
if (!existsSync27(projectsDir))
|
|
16237
16843
|
return this._knownProjectDirs;
|
|
16238
16844
|
try {
|
|
16239
16845
|
const entries = readdirSync17(projectsDir, { withFileTypes: true });
|
|
@@ -16241,7 +16847,7 @@ var init_plan_source = __esm({
|
|
|
16241
16847
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
16242
16848
|
continue;
|
|
16243
16849
|
const projectPath = resolveProjectDirName(entry.name);
|
|
16244
|
-
if (
|
|
16850
|
+
if (existsSync27(projectPath)) {
|
|
16245
16851
|
this._knownProjectDirs.push(projectPath);
|
|
16246
16852
|
}
|
|
16247
16853
|
}
|
|
@@ -16265,7 +16871,7 @@ var init_plan_source = __esm({
|
|
|
16265
16871
|
async *discoverClaudePlans() {
|
|
16266
16872
|
const seenClaude = /* @__PURE__ */ new Set();
|
|
16267
16873
|
for (const plansDir of this.plansDirs) {
|
|
16268
|
-
if (!
|
|
16874
|
+
if (!existsSync27(plansDir))
|
|
16269
16875
|
continue;
|
|
16270
16876
|
const files = readdirSync17(plansDir).filter((f) => f.endsWith(".md"));
|
|
16271
16877
|
for (const file of files) {
|
|
@@ -16307,7 +16913,7 @@ var init_plan_source = __esm({
|
|
|
16307
16913
|
}
|
|
16308
16914
|
async *discoverOpenCodePlans() {
|
|
16309
16915
|
const plansDir = opencodeBackend.plansDir();
|
|
16310
|
-
if (!
|
|
16916
|
+
if (!existsSync27(plansDir))
|
|
16311
16917
|
return;
|
|
16312
16918
|
let files;
|
|
16313
16919
|
try {
|
|
@@ -16394,7 +17000,7 @@ var init_plan_source = __esm({
|
|
|
16394
17000
|
return "";
|
|
16395
17001
|
}
|
|
16396
17002
|
async parse(item) {
|
|
16397
|
-
if (!
|
|
17003
|
+
if (!existsSync27(item.filePath))
|
|
16398
17004
|
return [];
|
|
16399
17005
|
const content = readFileSync20(item.filePath, "utf-8");
|
|
16400
17006
|
const chunks = [];
|
|
@@ -16435,7 +17041,7 @@ var init_plan_source = __esm({
|
|
|
16435
17041
|
const projPath = join31(root, proj);
|
|
16436
17042
|
for (const sessionEntry of safeReaddir(projPath)) {
|
|
16437
17043
|
const subDir = join31(projPath, sessionEntry, "subagents");
|
|
16438
|
-
if (!
|
|
17044
|
+
if (!existsSync27(subDir))
|
|
16439
17045
|
continue;
|
|
16440
17046
|
for (const f of safeReaddir(subDir)) {
|
|
16441
17047
|
const m = f.match(/^agent-([a-z0-9_-]+)\.jsonl$/i);
|
|
@@ -16510,7 +17116,7 @@ var init_plan_source = __esm({
|
|
|
16510
17116
|
}
|
|
16511
17117
|
async *discoverAgyPlans() {
|
|
16512
17118
|
const brainDir = join31(agyBackend.homeDir(), "brain");
|
|
16513
|
-
if (!
|
|
17119
|
+
if (!existsSync27(brainDir))
|
|
16514
17120
|
return;
|
|
16515
17121
|
let sessionDirs;
|
|
16516
17122
|
try {
|
|
@@ -16565,7 +17171,7 @@ var init_plan_source = __esm({
|
|
|
16565
17171
|
});
|
|
16566
17172
|
|
|
16567
17173
|
// ../engine/dist/parsers/task-source.js
|
|
16568
|
-
import { existsSync as
|
|
17174
|
+
import { existsSync as existsSync28, readdirSync as readdirSync18, readFileSync as readFileSync21, statSync as statSync26 } from "fs";
|
|
16569
17175
|
import { join as join32 } from "path";
|
|
16570
17176
|
var MAX_CHUNK_CHARS2, TaskSource;
|
|
16571
17177
|
var init_task_source = __esm({
|
|
@@ -16595,7 +17201,7 @@ var init_task_source = __esm({
|
|
|
16595
17201
|
}
|
|
16596
17202
|
async *discoverClaudeTodos() {
|
|
16597
17203
|
const todosDir = claudeBackend.todosDir();
|
|
16598
|
-
if (!
|
|
17204
|
+
if (!existsSync28(todosDir))
|
|
16599
17205
|
return;
|
|
16600
17206
|
let files;
|
|
16601
17207
|
try {
|
|
@@ -16646,7 +17252,7 @@ var init_task_source = __esm({
|
|
|
16646
17252
|
}
|
|
16647
17253
|
}
|
|
16648
17254
|
async *discoverInDir(tasksDir) {
|
|
16649
|
-
if (!
|
|
17255
|
+
if (!existsSync28(tasksDir))
|
|
16650
17256
|
return;
|
|
16651
17257
|
const entries = readdirSync18(tasksDir, { withFileTypes: true });
|
|
16652
17258
|
for (const entry of entries) {
|
|
@@ -16688,7 +17294,7 @@ var init_task_source = __esm({
|
|
|
16688
17294
|
return this.parseAgentTodo(item);
|
|
16689
17295
|
}
|
|
16690
17296
|
const taskDir = item.filePath;
|
|
16691
|
-
if (!
|
|
17297
|
+
if (!existsSync28(taskDir))
|
|
16692
17298
|
return [];
|
|
16693
17299
|
const taskFiles = readdirSync18(taskDir).filter((f) => f.endsWith(".json"));
|
|
16694
17300
|
const tasks = this.readTasks(taskDir, taskFiles);
|
|
@@ -16749,7 +17355,7 @@ ${task.description}`.slice(0, MAX_CHUNK_CHARS2);
|
|
|
16749
17355
|
}];
|
|
16750
17356
|
}
|
|
16751
17357
|
async parseAgentTodo(item) {
|
|
16752
|
-
if (!
|
|
17358
|
+
if (!existsSync28(item.filePath))
|
|
16753
17359
|
return [];
|
|
16754
17360
|
let parsed;
|
|
16755
17361
|
try {
|
|
@@ -16801,7 +17407,7 @@ ${task.description}`.slice(0, MAX_CHUNK_CHARS2);
|
|
|
16801
17407
|
});
|
|
16802
17408
|
|
|
16803
17409
|
// ../engine/dist/parsers/claude-md-source.js
|
|
16804
|
-
import { existsSync as
|
|
17410
|
+
import { existsSync as existsSync29, readFileSync as readFileSync22, readdirSync as readdirSync19, statSync as statSync27 } from "fs";
|
|
16805
17411
|
import { homedir as homedir10 } from "os";
|
|
16806
17412
|
import { join as join33, basename as basename15, dirname as dirname16 } from "path";
|
|
16807
17413
|
import { createHash as createHash9 } from "crypto";
|
|
@@ -16809,13 +17415,13 @@ function discoverProjectDirs(claudeDir) {
|
|
|
16809
17415
|
const dirs = [];
|
|
16810
17416
|
const seen = /* @__PURE__ */ new Set();
|
|
16811
17417
|
const addProject = (path2) => {
|
|
16812
|
-
if (!seen.has(path2) &&
|
|
17418
|
+
if (!seen.has(path2) && existsSync29(path2)) {
|
|
16813
17419
|
seen.add(path2);
|
|
16814
17420
|
dirs.push(path2);
|
|
16815
17421
|
}
|
|
16816
17422
|
};
|
|
16817
17423
|
const scanProjectsDir = (projectsDir) => {
|
|
16818
|
-
if (!
|
|
17424
|
+
if (!existsSync29(projectsDir))
|
|
16819
17425
|
return;
|
|
16820
17426
|
try {
|
|
16821
17427
|
const entries = readdirSync19(projectsDir, { withFileTypes: true });
|
|
@@ -16843,7 +17449,7 @@ function discoverProjectDirs(claudeDir) {
|
|
|
16843
17449
|
} catch {
|
|
16844
17450
|
}
|
|
16845
17451
|
const gemProjects = agyBackend.sharedProjectsJson();
|
|
16846
|
-
if (
|
|
17452
|
+
if (existsSync29(gemProjects)) {
|
|
16847
17453
|
try {
|
|
16848
17454
|
const data = JSON.parse(readFileSync22(gemProjects, "utf-8"));
|
|
16849
17455
|
for (const path2 of Object.keys(data.projects || {}))
|
|
@@ -16852,7 +17458,7 @@ function discoverProjectDirs(claudeDir) {
|
|
|
16852
17458
|
}
|
|
16853
17459
|
}
|
|
16854
17460
|
const ocDb = opencodeBackend.dbPath();
|
|
16855
|
-
if (
|
|
17461
|
+
if (existsSync29(ocDb)) {
|
|
16856
17462
|
try {
|
|
16857
17463
|
const db = openSqliteReadonlyOrThrow(ocDb);
|
|
16858
17464
|
try {
|
|
@@ -16903,7 +17509,7 @@ var init_claude_md_source = __esm({
|
|
|
16903
17509
|
for (const note of NOTE_FILES) {
|
|
16904
17510
|
const p = join33(homedir10(), note.filename);
|
|
16905
17511
|
const key2 = seenKey(p, note.tool);
|
|
16906
|
-
if (
|
|
17512
|
+
if (existsSync29(p) && !seen.has(key2)) {
|
|
16907
17513
|
seen.add(key2);
|
|
16908
17514
|
const item = this.fileToItem(p, note.filename, note.tool);
|
|
16909
17515
|
if (item)
|
|
@@ -16915,7 +17521,7 @@ var init_claude_md_source = __esm({
|
|
|
16915
17521
|
for (const note of NOTE_FILES) {
|
|
16916
17522
|
const p = join33(projectDir, note.filename);
|
|
16917
17523
|
const key2 = seenKey(p, note.tool);
|
|
16918
|
-
if (
|
|
17524
|
+
if (existsSync29(p) && !seen.has(key2)) {
|
|
16919
17525
|
seen.add(key2);
|
|
16920
17526
|
const item = this.fileToItem(p, note.filename, note.tool);
|
|
16921
17527
|
if (item)
|
|
@@ -16924,12 +17530,12 @@ var init_claude_md_source = __esm({
|
|
|
16924
17530
|
}
|
|
16925
17531
|
}
|
|
16926
17532
|
for (const searchDir of this.searchDirs) {
|
|
16927
|
-
if (!
|
|
17533
|
+
if (!existsSync29(searchDir))
|
|
16928
17534
|
continue;
|
|
16929
17535
|
for (const note of NOTE_FILES) {
|
|
16930
17536
|
const directPath = join33(searchDir, note.filename);
|
|
16931
17537
|
const key2 = seenKey(directPath, note.tool);
|
|
16932
|
-
if (
|
|
17538
|
+
if (existsSync29(directPath) && !seen.has(key2)) {
|
|
16933
17539
|
seen.add(key2);
|
|
16934
17540
|
const item = this.fileToItem(directPath, note.filename, note.tool);
|
|
16935
17541
|
if (item)
|
|
@@ -16944,7 +17550,7 @@ var init_claude_md_source = __esm({
|
|
|
16944
17550
|
for (const note of NOTE_FILES) {
|
|
16945
17551
|
const p = join33(searchDir, entry.name, note.filename);
|
|
16946
17552
|
const key2 = seenKey(p, note.tool);
|
|
16947
|
-
if (
|
|
17553
|
+
if (existsSync29(p) && !seen.has(key2)) {
|
|
16948
17554
|
seen.add(key2);
|
|
16949
17555
|
const item = this.fileToItem(p, note.filename, note.tool);
|
|
16950
17556
|
if (item)
|
|
@@ -16958,7 +17564,7 @@ var init_claude_md_source = __esm({
|
|
|
16958
17564
|
}
|
|
16959
17565
|
}
|
|
16960
17566
|
async parse(item) {
|
|
16961
|
-
if (!
|
|
17567
|
+
if (!existsSync29(item.filePath))
|
|
16962
17568
|
return [];
|
|
16963
17569
|
const content = readFileSync22(item.filePath, "utf-8");
|
|
16964
17570
|
const chunks = [];
|
|
@@ -17027,7 +17633,7 @@ var init_claude_md_source = __esm({
|
|
|
17027
17633
|
});
|
|
17028
17634
|
|
|
17029
17635
|
// ../engine/dist/parsers/agent-memory-source.js
|
|
17030
|
-
import { existsSync as
|
|
17636
|
+
import { existsSync as existsSync30, readFileSync as readFileSync23, readdirSync as readdirSync20, statSync as statSync28 } from "fs";
|
|
17031
17637
|
import { homedir as homedir11 } from "os";
|
|
17032
17638
|
import { join as join34, basename as basename16 } from "path";
|
|
17033
17639
|
function parseFrontmatter2(content) {
|
|
@@ -17061,7 +17667,7 @@ function discoverMemoryDirs() {
|
|
|
17061
17667
|
const out = [];
|
|
17062
17668
|
const seen = /* @__PURE__ */ new Set();
|
|
17063
17669
|
const add = (memoryDir, projectHash) => {
|
|
17064
|
-
if (!seen.has(memoryDir) &&
|
|
17670
|
+
if (!seen.has(memoryDir) && existsSync30(memoryDir)) {
|
|
17065
17671
|
seen.add(memoryDir);
|
|
17066
17672
|
out.push({ memoryDir, projectHash });
|
|
17067
17673
|
}
|
|
@@ -17077,7 +17683,7 @@ function discoverMemoryDirs() {
|
|
|
17077
17683
|
} catch {
|
|
17078
17684
|
}
|
|
17079
17685
|
for (const projectsDir of claudeRoots) {
|
|
17080
|
-
if (!
|
|
17686
|
+
if (!existsSync30(projectsDir))
|
|
17081
17687
|
continue;
|
|
17082
17688
|
try {
|
|
17083
17689
|
for (const entry of readdirSync20(projectsDir, { withFileTypes: true })) {
|
|
@@ -17126,7 +17732,7 @@ var init_agent_memory_source = __esm({
|
|
|
17126
17732
|
}
|
|
17127
17733
|
}
|
|
17128
17734
|
async parse(item) {
|
|
17129
|
-
if (!
|
|
17735
|
+
if (!existsSync30(item.filePath))
|
|
17130
17736
|
return [];
|
|
17131
17737
|
const content = readFileSync23(item.filePath, "utf-8");
|
|
17132
17738
|
const { body: body2 } = parseFrontmatter2(content);
|
|
@@ -17212,7 +17818,7 @@ var init_agent_memory_source = __esm({
|
|
|
17212
17818
|
});
|
|
17213
17819
|
|
|
17214
17820
|
// ../engine/dist/parsers/history-source.js
|
|
17215
|
-
import { existsSync as
|
|
17821
|
+
import { existsSync as existsSync31, readdirSync as readdirSync21, statSync as statSync29 } from "fs";
|
|
17216
17822
|
import { createReadStream as createReadStream3 } from "fs";
|
|
17217
17823
|
import { createInterface as createInterface2 } from "readline";
|
|
17218
17824
|
import { homedir as homedir12 } from "os";
|
|
@@ -17234,7 +17840,7 @@ var init_history_source = __esm({
|
|
|
17234
17840
|
const home = homedir12();
|
|
17235
17841
|
const paths = [];
|
|
17236
17842
|
const tryAdd = (p) => {
|
|
17237
|
-
if (
|
|
17843
|
+
if (existsSync31(p) && !paths.includes(p))
|
|
17238
17844
|
paths.push(p);
|
|
17239
17845
|
};
|
|
17240
17846
|
tryAdd(claudeBackend.historyFile());
|
|
@@ -17252,7 +17858,7 @@ var init_history_source = __esm({
|
|
|
17252
17858
|
async *discover() {
|
|
17253
17859
|
if (!isSourceEnabled("claude", "history"))
|
|
17254
17860
|
return;
|
|
17255
|
-
const historyPath = this.historyPaths.find((p) =>
|
|
17861
|
+
const historyPath = this.historyPaths.find((p) => existsSync31(p));
|
|
17256
17862
|
if (!historyPath)
|
|
17257
17863
|
return;
|
|
17258
17864
|
const stat3 = statSync29(historyPath);
|
|
@@ -17348,7 +17954,7 @@ var init_history_source = __esm({
|
|
|
17348
17954
|
async groupByProject() {
|
|
17349
17955
|
const groups = /* @__PURE__ */ new Map();
|
|
17350
17956
|
for (const historyPath of this.historyPaths) {
|
|
17351
|
-
if (!
|
|
17957
|
+
if (!existsSync31(historyPath))
|
|
17352
17958
|
continue;
|
|
17353
17959
|
const rl = createInterface2({
|
|
17354
17960
|
input: createReadStream3(historyPath),
|
|
@@ -17396,7 +18002,7 @@ var init_history_source = __esm({
|
|
|
17396
18002
|
});
|
|
17397
18003
|
|
|
17398
18004
|
// ../engine/dist/parsers/paste-source.js
|
|
17399
|
-
import { existsSync as
|
|
18005
|
+
import { existsSync as existsSync32, readdirSync as readdirSync22, readFileSync as readFileSync24, statSync as statSync30 } from "fs";
|
|
17400
18006
|
import { homedir as homedir13 } from "os";
|
|
17401
18007
|
import { join as join36, basename as basename17 } from "path";
|
|
17402
18008
|
var MAX_CHUNK_CHARS6, MAX_FILE_SIZE, PasteSource;
|
|
@@ -17417,7 +18023,7 @@ var init_paste_source = __esm({
|
|
|
17417
18023
|
const home = homedir13();
|
|
17418
18024
|
const dirs = [];
|
|
17419
18025
|
const tryAdd = (p) => {
|
|
17420
|
-
if (
|
|
18026
|
+
if (existsSync32(p) && !dirs.includes(p))
|
|
17421
18027
|
dirs.push(p);
|
|
17422
18028
|
};
|
|
17423
18029
|
tryAdd(claudeBackend.pasteCacheDir());
|
|
@@ -17437,7 +18043,7 @@ var init_paste_source = __esm({
|
|
|
17437
18043
|
return;
|
|
17438
18044
|
const seen = /* @__PURE__ */ new Set();
|
|
17439
18045
|
for (const cacheDir of this.cacheDirs) {
|
|
17440
|
-
if (!
|
|
18046
|
+
if (!existsSync32(cacheDir))
|
|
17441
18047
|
continue;
|
|
17442
18048
|
const files = readdirSync22(cacheDir).filter((f) => f.endsWith(".txt"));
|
|
17443
18049
|
for (const file of files) {
|
|
@@ -17471,7 +18077,7 @@ var init_paste_source = __esm({
|
|
|
17471
18077
|
}
|
|
17472
18078
|
}
|
|
17473
18079
|
async parse(item) {
|
|
17474
|
-
if (!
|
|
18080
|
+
if (!existsSync32(item.filePath))
|
|
17475
18081
|
return [];
|
|
17476
18082
|
const content = readFileSync24(item.filePath, "utf-8");
|
|
17477
18083
|
if (content.trim().length < 20)
|
|
@@ -17496,7 +18102,7 @@ var init_paste_source = __esm({
|
|
|
17496
18102
|
});
|
|
17497
18103
|
|
|
17498
18104
|
// ../engine/dist/parsers/antigravity-brain-source.js
|
|
17499
|
-
import { existsSync as
|
|
18105
|
+
import { existsSync as existsSync33, readdirSync as readdirSync23, readFileSync as readFileSync25, statSync as statSync31 } from "fs";
|
|
17500
18106
|
import { join as join37 } from "path";
|
|
17501
18107
|
var MAX_CHUNK_CHARS7, AntigravityBrainSource;
|
|
17502
18108
|
var init_antigravity_brain_source = __esm({
|
|
@@ -17515,7 +18121,7 @@ var init_antigravity_brain_source = __esm({
|
|
|
17515
18121
|
async *discover() {
|
|
17516
18122
|
if (!isSourceEnabled("agy", "brain"))
|
|
17517
18123
|
return;
|
|
17518
|
-
if (!
|
|
18124
|
+
if (!existsSync33(this.brainDir))
|
|
17519
18125
|
return;
|
|
17520
18126
|
const sessions = readdirSync23(this.brainDir, { withFileTypes: true });
|
|
17521
18127
|
for (const entry of sessions) {
|
|
@@ -17534,7 +18140,7 @@ var init_antigravity_brain_source = __esm({
|
|
|
17534
18140
|
const heading = content.split("\n").find((l) => l.startsWith("#"))?.replace(/^#+\s*/, "").trim() || file;
|
|
17535
18141
|
const metaPath = `${filePath}.metadata.json`;
|
|
17536
18142
|
let metaSummary = "";
|
|
17537
|
-
if (
|
|
18143
|
+
if (existsSync33(metaPath)) {
|
|
17538
18144
|
try {
|
|
17539
18145
|
const meta = JSON.parse(readFileSync25(metaPath, "utf-8"));
|
|
17540
18146
|
metaSummary = meta.summary || "";
|
|
@@ -17565,7 +18171,7 @@ var init_antigravity_brain_source = __esm({
|
|
|
17565
18171
|
}
|
|
17566
18172
|
}
|
|
17567
18173
|
async parse(item) {
|
|
17568
|
-
if (!
|
|
18174
|
+
if (!existsSync33(item.filePath))
|
|
17569
18175
|
return [];
|
|
17570
18176
|
const content = readFileSync25(item.filePath, "utf-8");
|
|
17571
18177
|
const chunks = [];
|
|
@@ -17608,7 +18214,7 @@ var init_antigravity_brain_source = __esm({
|
|
|
17608
18214
|
});
|
|
17609
18215
|
|
|
17610
18216
|
// ../engine/dist/parsers/opencode-source.js
|
|
17611
|
-
import { existsSync as
|
|
18217
|
+
import { existsSync as existsSync34 } from "fs";
|
|
17612
18218
|
var MAX_CHUNK_CHARS8, OpenCodeSource;
|
|
17613
18219
|
var init_opencode_source = __esm({
|
|
17614
18220
|
"../engine/dist/parsers/opencode-source.js"() {
|
|
@@ -17626,7 +18232,7 @@ var init_opencode_source = __esm({
|
|
|
17626
18232
|
async *discover() {
|
|
17627
18233
|
if (!isSourceEnabled("opencode", "sessions"))
|
|
17628
18234
|
return;
|
|
17629
|
-
if (!
|
|
18235
|
+
if (!existsSync34(this.dbPath))
|
|
17630
18236
|
return;
|
|
17631
18237
|
let db;
|
|
17632
18238
|
try {
|
|
@@ -17724,7 +18330,7 @@ var init_opencode_source = __esm({
|
|
|
17724
18330
|
}
|
|
17725
18331
|
}
|
|
17726
18332
|
async parse(item) {
|
|
17727
|
-
if (!
|
|
18333
|
+
if (!existsSync34(this.dbPath))
|
|
17728
18334
|
return [];
|
|
17729
18335
|
const sessionId = item.id.replace("opencode_", "");
|
|
17730
18336
|
const db = openSqliteReadonlyOrThrow(this.dbPath);
|
|
@@ -17796,7 +18402,7 @@ var init_opencode_source = __esm({
|
|
|
17796
18402
|
});
|
|
17797
18403
|
|
|
17798
18404
|
// ../engine/dist/parsers/opencode-todo-source.js
|
|
17799
|
-
import { existsSync as
|
|
18405
|
+
import { existsSync as existsSync35 } from "fs";
|
|
17800
18406
|
var OpenCodeTodoSource;
|
|
17801
18407
|
var init_opencode_todo_source = __esm({
|
|
17802
18408
|
"../engine/dist/parsers/opencode-todo-source.js"() {
|
|
@@ -17813,7 +18419,7 @@ var init_opencode_todo_source = __esm({
|
|
|
17813
18419
|
async *discover() {
|
|
17814
18420
|
if (!isSourceEnabled("opencode", "todos"))
|
|
17815
18421
|
return;
|
|
17816
|
-
if (!
|
|
18422
|
+
if (!existsSync35(this.dbPath))
|
|
17817
18423
|
return;
|
|
17818
18424
|
let db;
|
|
17819
18425
|
try {
|
|
@@ -17862,7 +18468,7 @@ var init_opencode_todo_source = __esm({
|
|
|
17862
18468
|
}
|
|
17863
18469
|
}
|
|
17864
18470
|
async parse(item) {
|
|
17865
|
-
if (!
|
|
18471
|
+
if (!existsSync35(this.dbPath))
|
|
17866
18472
|
return [];
|
|
17867
18473
|
const sessionId = item.extra?.sessionId || item.id.replace(`${opencodeBackend.idPrefix}todo_`, "");
|
|
17868
18474
|
const db = openSqliteReadonlyOrThrow(this.dbPath);
|
|
@@ -17910,7 +18516,7 @@ var init_opencode_todo_source = __esm({
|
|
|
17910
18516
|
});
|
|
17911
18517
|
|
|
17912
18518
|
// ../engine/dist/parsers/codex-session-source.js
|
|
17913
|
-
import { existsSync as
|
|
18519
|
+
import { existsSync as existsSync36, readdirSync as readdirSync24, readFileSync as readFileSync26, statSync as statSync32 } from "fs";
|
|
17914
18520
|
import { join as join38, basename as basename18 } from "path";
|
|
17915
18521
|
function getCodexSessionsDir() {
|
|
17916
18522
|
return codexBackend.sessionsDir();
|
|
@@ -17967,7 +18573,7 @@ var init_codex_session_source = __esm({
|
|
|
17967
18573
|
async *discover() {
|
|
17968
18574
|
if (!isSourceEnabled("codex", "sessions"))
|
|
17969
18575
|
return;
|
|
17970
|
-
if (!
|
|
18576
|
+
if (!existsSync36(this.sessionsDir))
|
|
17971
18577
|
return;
|
|
17972
18578
|
const jsonlFiles = this.collectJsonlFiles(this.sessionsDir);
|
|
17973
18579
|
for (const filePath of jsonlFiles) {
|
|
@@ -18026,7 +18632,7 @@ var init_codex_session_source = __esm({
|
|
|
18026
18632
|
}
|
|
18027
18633
|
}
|
|
18028
18634
|
async parse(item) {
|
|
18029
|
-
if (!
|
|
18635
|
+
if (!existsSync36(item.filePath))
|
|
18030
18636
|
return [];
|
|
18031
18637
|
const events = readJsonlLines(item.filePath);
|
|
18032
18638
|
const chunks = [];
|
|
@@ -18129,7 +18735,7 @@ var init_codex_session_source = __esm({
|
|
|
18129
18735
|
}
|
|
18130
18736
|
collectJsonlFiles(dir) {
|
|
18131
18737
|
const results = [];
|
|
18132
|
-
if (!
|
|
18738
|
+
if (!existsSync36(dir))
|
|
18133
18739
|
return results;
|
|
18134
18740
|
for (const entry of readdirSync24(dir, { withFileTypes: true })) {
|
|
18135
18741
|
const fullPath = join38(dir, entry.name);
|
|
@@ -18146,7 +18752,7 @@ var init_codex_session_source = __esm({
|
|
|
18146
18752
|
});
|
|
18147
18753
|
|
|
18148
18754
|
// ../engine/dist/parsers/diary-source.js
|
|
18149
|
-
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";
|
|
18150
18756
|
import { join as join39, basename as basename19 } from "path";
|
|
18151
18757
|
var MAX_CHUNK_CHARS10, DiarySource;
|
|
18152
18758
|
var init_diary_source = __esm({
|
|
@@ -18162,7 +18768,7 @@ var init_diary_source = __esm({
|
|
|
18162
18768
|
}
|
|
18163
18769
|
/** Discover all diary entries across all agents. */
|
|
18164
18770
|
async *discover() {
|
|
18165
|
-
if (!
|
|
18771
|
+
if (!existsSync37(this.diaryDir))
|
|
18166
18772
|
return;
|
|
18167
18773
|
const agents = readdirSync25(this.diaryDir, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
18168
18774
|
for (const agentDir of agents) {
|
|
@@ -18197,7 +18803,7 @@ var init_diary_source = __esm({
|
|
|
18197
18803
|
}
|
|
18198
18804
|
}
|
|
18199
18805
|
async parse(item) {
|
|
18200
|
-
if (!
|
|
18806
|
+
if (!existsSync37(item.filePath))
|
|
18201
18807
|
return [];
|
|
18202
18808
|
const raw = readFileSync27(item.filePath, "utf-8");
|
|
18203
18809
|
const entry = JSON.parse(raw);
|
|
@@ -18237,7 +18843,7 @@ var init_diary_source = __esm({
|
|
|
18237
18843
|
static write(entry, diaryDir) {
|
|
18238
18844
|
const dir = diaryDir || getDiaryDir();
|
|
18239
18845
|
const agentDir = join39(dir, entry.agent.toLowerCase().replace(/[^a-z0-9_-]/g, "_"));
|
|
18240
|
-
if (!
|
|
18846
|
+
if (!existsSync37(agentDir)) {
|
|
18241
18847
|
mkdirSync9(agentDir, { recursive: true });
|
|
18242
18848
|
}
|
|
18243
18849
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
@@ -18256,7 +18862,7 @@ var init_diary_source = __esm({
|
|
|
18256
18862
|
static read(agentName, lastN = 10, diaryDir) {
|
|
18257
18863
|
const dir = diaryDir || getDiaryDir();
|
|
18258
18864
|
const agentDir = join39(dir, agentName.toLowerCase().replace(/[^a-z0-9_-]/g, "_"));
|
|
18259
|
-
if (!
|
|
18865
|
+
if (!existsSync37(agentDir))
|
|
18260
18866
|
return [];
|
|
18261
18867
|
const files = readdirSync25(agentDir).filter((f) => f.endsWith(".json")).sort().reverse().slice(0, lastN);
|
|
18262
18868
|
const entries = [];
|
|
@@ -18307,7 +18913,7 @@ var init_redact_inline = __esm({
|
|
|
18307
18913
|
});
|
|
18308
18914
|
|
|
18309
18915
|
// ../engine/dist/parsers/skills-source.js
|
|
18310
|
-
import { existsSync as
|
|
18916
|
+
import { existsSync as existsSync38, readdirSync as readdirSync26, readFileSync as readFileSync28, statSync as statSync34 } from "fs";
|
|
18311
18917
|
import { homedir as homedir14 } from "os";
|
|
18312
18918
|
import { join as join40 } from "path";
|
|
18313
18919
|
function rebuildBody(content) {
|
|
@@ -18347,7 +18953,7 @@ function resolveRoots() {
|
|
|
18347
18953
|
all.push({ path: join40(cursorHomeDir(), "skills"), tool: "cursor" });
|
|
18348
18954
|
all.push({ path: join40(cursorHomeDir(), "skills-cursor"), tool: "cursor", readonly: true });
|
|
18349
18955
|
}
|
|
18350
|
-
return all.filter((r) =>
|
|
18956
|
+
return all.filter((r) => existsSync38(r.path));
|
|
18351
18957
|
}
|
|
18352
18958
|
function parseFrontmatter3(text) {
|
|
18353
18959
|
const m = text.match(/^---\n([\s\S]*?)\n---/);
|
|
@@ -18389,7 +18995,7 @@ var init_skills_source = __esm({
|
|
|
18389
18995
|
return;
|
|
18390
18996
|
for (const { name: pluginName, dir } of codexBackend.installedPluginDirs()) {
|
|
18391
18997
|
const skillsDir = join40(dir, "skills");
|
|
18392
|
-
if (!
|
|
18998
|
+
if (!existsSync38(skillsDir))
|
|
18393
18999
|
continue;
|
|
18394
19000
|
yield* this.fromSkillRoot({ path: skillsDir, tool: "codex" }, pluginName);
|
|
18395
19001
|
}
|
|
@@ -18414,7 +19020,7 @@ var init_skills_source = __esm({
|
|
|
18414
19020
|
if (!st.isDirectory())
|
|
18415
19021
|
continue;
|
|
18416
19022
|
const skillMd = join40(skillDir, "SKILL.md");
|
|
18417
|
-
if (!
|
|
19023
|
+
if (!existsSync38(skillMd))
|
|
18418
19024
|
continue;
|
|
18419
19025
|
let content;
|
|
18420
19026
|
try {
|
|
@@ -18479,7 +19085,7 @@ var init_skills_source = __esm({
|
|
|
18479
19085
|
}
|
|
18480
19086
|
}
|
|
18481
19087
|
async parse(item) {
|
|
18482
|
-
if (!
|
|
19088
|
+
if (!existsSync38(item.filePath))
|
|
18483
19089
|
return [];
|
|
18484
19090
|
const content = readFileSync28(item.filePath, "utf-8");
|
|
18485
19091
|
if (!content.trim())
|
|
@@ -18504,11 +19110,11 @@ var init_skills_source = __esm({
|
|
|
18504
19110
|
});
|
|
18505
19111
|
|
|
18506
19112
|
// ../engine/dist/parsers/mcps-source.js
|
|
18507
|
-
import { existsSync as
|
|
19113
|
+
import { existsSync as existsSync39, readFileSync as readFileSync29, statSync as statSync35 } from "fs";
|
|
18508
19114
|
import { homedir as homedir15 } from "os";
|
|
18509
19115
|
import { join as join41 } from "path";
|
|
18510
19116
|
function readJson(path2) {
|
|
18511
|
-
if (!
|
|
19117
|
+
if (!existsSync39(path2))
|
|
18512
19118
|
return null;
|
|
18513
19119
|
try {
|
|
18514
19120
|
const raw = readFileSync29(path2, "utf-8");
|
|
@@ -18671,7 +19277,7 @@ var init_mcps_source = __esm({
|
|
|
18671
19277
|
}
|
|
18672
19278
|
}
|
|
18673
19279
|
async *fromCodexToml(path2) {
|
|
18674
|
-
if (!
|
|
19280
|
+
if (!existsSync39(path2))
|
|
18675
19281
|
return;
|
|
18676
19282
|
let content;
|
|
18677
19283
|
try {
|
|
@@ -18827,7 +19433,7 @@ var init_toolkit_format = __esm({
|
|
|
18827
19433
|
});
|
|
18828
19434
|
|
|
18829
19435
|
// ../engine/dist/parsers/slash-commands-source.js
|
|
18830
|
-
import { existsSync as
|
|
19436
|
+
import { existsSync as existsSync40, readdirSync as readdirSync27, readFileSync as readFileSync30, statSync as statSync36 } from "fs";
|
|
18831
19437
|
import { join as join42, basename as basename20 } from "path";
|
|
18832
19438
|
function rebuildBody2(content) {
|
|
18833
19439
|
const { text, redacted } = redactInlineSecrets(content);
|
|
@@ -18880,14 +19486,14 @@ var init_slash_commands_source = __esm({
|
|
|
18880
19486
|
if (isSourceEnabled("claude", "commands")) {
|
|
18881
19487
|
roots.push({ path: claudeBackend.commandsDir(), tool: "claude", scope: "user", projectPath: "", format: "md" });
|
|
18882
19488
|
const projectsRoot = claudeBackend.projectsDir();
|
|
18883
|
-
if (
|
|
19489
|
+
if (existsSync40(projectsRoot)) {
|
|
18884
19490
|
try {
|
|
18885
19491
|
for (const entry of readdirSync27(projectsRoot, { withFileTypes: true })) {
|
|
18886
19492
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
18887
19493
|
continue;
|
|
18888
19494
|
const projectPath = resolveProjectDirName(entry.name);
|
|
18889
19495
|
const cmdDir = join42(projectPath, ".claude", "commands");
|
|
18890
|
-
if (
|
|
19496
|
+
if (existsSync40(cmdDir))
|
|
18891
19497
|
roots.push({ path: cmdDir, tool: "claude", scope: "project", projectPath, format: "md" });
|
|
18892
19498
|
}
|
|
18893
19499
|
} catch {
|
|
@@ -18949,7 +19555,7 @@ var init_slash_commands_source = __esm({
|
|
|
18949
19555
|
}
|
|
18950
19556
|
}
|
|
18951
19557
|
async parse(item) {
|
|
18952
|
-
if (!
|
|
19558
|
+
if (!existsSync40(item.filePath))
|
|
18953
19559
|
return [];
|
|
18954
19560
|
const content = readFileSync30(item.filePath, "utf-8");
|
|
18955
19561
|
if (!content.trim())
|
|
@@ -18974,7 +19580,7 @@ var init_slash_commands_source = __esm({
|
|
|
18974
19580
|
});
|
|
18975
19581
|
|
|
18976
19582
|
// ../engine/dist/parsers/subagents-source.js
|
|
18977
|
-
import { existsSync as
|
|
19583
|
+
import { existsSync as existsSync41, readdirSync as readdirSync28, readFileSync as readFileSync31, statSync as statSync37 } from "fs";
|
|
18978
19584
|
import { join as join43, basename as basename21 } from "path";
|
|
18979
19585
|
function rebuildBody3(content) {
|
|
18980
19586
|
const { text, redacted } = redactInlineSecrets(content);
|
|
@@ -19029,14 +19635,14 @@ var init_subagents_source = __esm({
|
|
|
19029
19635
|
if (isSourceEnabled("claude", "agents")) {
|
|
19030
19636
|
roots.push({ path: claudeBackend.agentsDir(), tool: "claude", scope: "user", projectPath: "", format: "md" });
|
|
19031
19637
|
const projectsRoot = claudeBackend.projectsDir();
|
|
19032
|
-
if (
|
|
19638
|
+
if (existsSync41(projectsRoot)) {
|
|
19033
19639
|
try {
|
|
19034
19640
|
for (const entry of readdirSync28(projectsRoot, { withFileTypes: true })) {
|
|
19035
19641
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
19036
19642
|
continue;
|
|
19037
19643
|
const projectPath = resolveProjectDirName(entry.name);
|
|
19038
19644
|
const agentDir = join43(projectPath, ".claude", "agents");
|
|
19039
|
-
if (
|
|
19645
|
+
if (existsSync41(agentDir))
|
|
19040
19646
|
roots.push({ path: agentDir, tool: "claude", scope: "project", projectPath, format: "md" });
|
|
19041
19647
|
}
|
|
19042
19648
|
} catch {
|
|
@@ -19099,7 +19705,7 @@ var init_subagents_source = __esm({
|
|
|
19099
19705
|
}
|
|
19100
19706
|
}
|
|
19101
19707
|
async parse(item) {
|
|
19102
|
-
if (!
|
|
19708
|
+
if (!existsSync41(item.filePath))
|
|
19103
19709
|
return [];
|
|
19104
19710
|
const content = readFileSync31(item.filePath, "utf-8");
|
|
19105
19711
|
if (!content.trim())
|
|
@@ -19124,10 +19730,10 @@ var init_subagents_source = __esm({
|
|
|
19124
19730
|
});
|
|
19125
19731
|
|
|
19126
19732
|
// ../engine/dist/parsers/hooks-source.js
|
|
19127
|
-
import { existsSync as
|
|
19733
|
+
import { existsSync as existsSync42, readFileSync as readFileSync32, readdirSync as readdirSync29, statSync as statSync38 } from "fs";
|
|
19128
19734
|
import { join as join44 } from "path";
|
|
19129
19735
|
function readJson2(path2) {
|
|
19130
|
-
if (!
|
|
19736
|
+
if (!existsSync42(path2))
|
|
19131
19737
|
return null;
|
|
19132
19738
|
try {
|
|
19133
19739
|
return JSON.parse(readFileSync32(path2, "utf-8"));
|
|
@@ -19149,14 +19755,14 @@ var init_hooks_source = __esm({
|
|
|
19149
19755
|
return;
|
|
19150
19756
|
yield* this.fromSettings(claudeBackend.settingsFile(), "user", "");
|
|
19151
19757
|
const projectsRoot = claudeBackend.projectsDir();
|
|
19152
|
-
if (
|
|
19758
|
+
if (existsSync42(projectsRoot)) {
|
|
19153
19759
|
try {
|
|
19154
19760
|
for (const entry of readdirSync29(projectsRoot, { withFileTypes: true })) {
|
|
19155
19761
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
19156
19762
|
continue;
|
|
19157
19763
|
const projectPath = resolveProjectDirName(entry.name);
|
|
19158
19764
|
const settingsPath2 = join44(projectPath, ".claude", "settings.json");
|
|
19159
|
-
if (
|
|
19765
|
+
if (existsSync42(settingsPath2)) {
|
|
19160
19766
|
yield* this.fromSettings(settingsPath2, "project", projectPath);
|
|
19161
19767
|
}
|
|
19162
19768
|
}
|
|
@@ -19247,11 +19853,11 @@ var init_hooks_source = __esm({
|
|
|
19247
19853
|
});
|
|
19248
19854
|
|
|
19249
19855
|
// ../engine/dist/parsers/plugins-source.js
|
|
19250
|
-
import { existsSync as
|
|
19856
|
+
import { existsSync as existsSync43, readFileSync as readFileSync33, readdirSync as readdirSync30, statSync as statSync39 } from "fs";
|
|
19251
19857
|
import { homedir as homedir16 } from "os";
|
|
19252
19858
|
import { join as join45 } from "path";
|
|
19253
19859
|
function readJson3(path2) {
|
|
19254
|
-
if (!
|
|
19860
|
+
if (!existsSync43(path2))
|
|
19255
19861
|
return null;
|
|
19256
19862
|
try {
|
|
19257
19863
|
return JSON.parse(readFileSync33(path2, "utf-8"));
|
|
@@ -19306,7 +19912,7 @@ var init_plugins_source = __esm({
|
|
|
19306
19912
|
}
|
|
19307
19913
|
}
|
|
19308
19914
|
const gemRoot = agyBackend.sharedExtensionsDir();
|
|
19309
|
-
if (isSourceEnabled("agy", "extensions") &&
|
|
19915
|
+
if (isSourceEnabled("agy", "extensions") && existsSync43(gemRoot)) {
|
|
19310
19916
|
let entries;
|
|
19311
19917
|
try {
|
|
19312
19918
|
entries = readdirSync30(gemRoot);
|
|
@@ -19482,6 +20088,8 @@ function toolOfId(id) {
|
|
|
19482
20088
|
return "codex";
|
|
19483
20089
|
if (id.startsWith("cursor_"))
|
|
19484
20090
|
return "cursor";
|
|
20091
|
+
if (id.startsWith("hermes_"))
|
|
20092
|
+
return "hermes";
|
|
19485
20093
|
return "claude";
|
|
19486
20094
|
}
|
|
19487
20095
|
function extractorVersionForTool(tool) {
|
|
@@ -19734,6 +20342,13 @@ function markSynced(server, rows) {
|
|
|
19734
20342
|
base2.s = s;
|
|
19735
20343
|
}
|
|
19736
20344
|
if (r.hash !== void 0) base2.h = r.hash;
|
|
20345
|
+
const completesChunked = cursorFromCaller && r.chunkFinal === true && prev?.k === 1;
|
|
20346
|
+
if (cursorFromCaller && (r.full || completesChunked) && o > 0) base2.F = o;
|
|
20347
|
+
else if (prev?.F !== void 0) base2.F = prev.F;
|
|
20348
|
+
if (cursorFromCaller && r.chunkedHead) base2.k = 1;
|
|
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;
|
|
19737
20352
|
forServer[r.id] = base2;
|
|
19738
20353
|
}
|
|
19739
20354
|
persist(data);
|
|
@@ -19790,6 +20405,14 @@ function markFieldFullPassDone(server, field) {
|
|
|
19790
20405
|
delete st.force[field.name];
|
|
19791
20406
|
persistReconcile(data);
|
|
19792
20407
|
}
|
|
20408
|
+
function forgetFullCoverage(server, sessionId) {
|
|
20409
|
+
const data = load();
|
|
20410
|
+
const row = data[server]?.[sessionId];
|
|
20411
|
+
if (!row || typeof row !== "object") return;
|
|
20412
|
+
delete row.F;
|
|
20413
|
+
delete row.h;
|
|
20414
|
+
persist(data);
|
|
20415
|
+
}
|
|
19793
20416
|
function markFullResync(server, sessionId) {
|
|
19794
20417
|
const data = load();
|
|
19795
20418
|
const forServer = data[server];
|
|
@@ -19798,7 +20421,11 @@ function markFullResync(server, sessionId) {
|
|
|
19798
20421
|
delete forServer[sessionId];
|
|
19799
20422
|
persist(data);
|
|
19800
20423
|
}
|
|
19801
|
-
function
|
|
20424
|
+
function fullCoveredOffset(row) {
|
|
20425
|
+
if (row.F !== void 0) return row.F;
|
|
20426
|
+
return row.h ? row.s ?? 0 : 0;
|
|
20427
|
+
}
|
|
20428
|
+
function syncMode(row, mtime, fileSize, extractorVersion, isAppendOnly, nowMs = Date.now()) {
|
|
19802
20429
|
if (!row) return "full";
|
|
19803
20430
|
if (row.v < extractorVersion) return "full";
|
|
19804
20431
|
const offset = row.o ?? 0;
|
|
@@ -19806,10 +20433,13 @@ function syncMode(row, mtime, fileSize, extractorVersion, isAppendOnly) {
|
|
|
19806
20433
|
if (process.env.CHAT_RECALL_TAIL_APPEND !== "0" && isAppendOnly && fileSize > 0 && offset > 0 && fileSize > (row.s ?? 0)) {
|
|
19807
20434
|
return "append";
|
|
19808
20435
|
}
|
|
20436
|
+
if (isAppendOnly && offset > 0 && fileSize > 0 && fileSize === (row.s ?? 0) && !row.k && fullCoveredOffset(row) < offset && nowMs - Math.floor(mtime) >= SETTLE_QUIET_MS) {
|
|
20437
|
+
return "full";
|
|
20438
|
+
}
|
|
19809
20439
|
if (row.m >= Math.floor(mtime)) return "skip";
|
|
19810
20440
|
return "full";
|
|
19811
20441
|
}
|
|
19812
|
-
var ledgerPath, cache3, base, diskStamp, rowKey, LEDGER_FLUSH_MS, pendingWrite, flushTimer, itemVersionsPath, itemVersionsCache, inventoryPath, unackedCursorAttempts, reconcilePath, reconcileCache;
|
|
20442
|
+
var ledgerPath, cache3, base, diskStamp, rowKey, LEDGER_FLUSH_MS, pendingWrite, flushTimer, itemVersionsPath, itemVersionsCache, inventoryPath, unackedCursorAttempts, reconcilePath, reconcileCache, SETTLE_QUIET_MS;
|
|
19813
20443
|
var init_sync_ledger = __esm({
|
|
19814
20444
|
"src/sync-ledger.ts"() {
|
|
19815
20445
|
"use strict";
|
|
@@ -19829,6 +20459,7 @@ var init_sync_ledger = __esm({
|
|
|
19829
20459
|
unackedCursorAttempts = 0;
|
|
19830
20460
|
reconcilePath = () => join46(getDataDir(), "sync-field-reconcile.json");
|
|
19831
20461
|
reconcileCache = null;
|
|
20462
|
+
SETTLE_QUIET_MS = 2 * 60 * 60 * 1e3;
|
|
19832
20463
|
}
|
|
19833
20464
|
});
|
|
19834
20465
|
|
|
@@ -19858,12 +20489,12 @@ var init_sync_fields = __esm({
|
|
|
19858
20489
|
});
|
|
19859
20490
|
|
|
19860
20491
|
// ../engine/dist/core/index-lock.js
|
|
19861
|
-
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";
|
|
19862
20493
|
import { dirname as dirname18, join as join47 } from "path";
|
|
19863
20494
|
function acquireIndexLock(opts) {
|
|
19864
20495
|
const lockPath = lockFilePath(opts.file);
|
|
19865
20496
|
mkdirSync11(dirname18(lockPath), { recursive: true });
|
|
19866
|
-
if (
|
|
20497
|
+
if (existsSync44(lockPath)) {
|
|
19867
20498
|
if (!stealStaleLock(lockPath, opts.staleAfterMs ?? 10 * 6e4)) {
|
|
19868
20499
|
return null;
|
|
19869
20500
|
}
|
|
@@ -19974,7 +20605,7 @@ var init_http = __esm({
|
|
|
19974
20605
|
CLI_VERSION = JSON.parse(readFileSync36(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
|
|
19975
20606
|
} catch {
|
|
19976
20607
|
try {
|
|
19977
|
-
if (true) CLI_VERSION = "0.7.
|
|
20608
|
+
if (true) CLI_VERSION = "0.7.19";
|
|
19978
20609
|
} catch {
|
|
19979
20610
|
}
|
|
19980
20611
|
}
|
|
@@ -20071,7 +20702,7 @@ var init_derived = __esm({
|
|
|
20071
20702
|
|
|
20072
20703
|
// src/scan-pool.ts
|
|
20073
20704
|
import { Worker } from "node:worker_threads";
|
|
20074
|
-
import { existsSync as
|
|
20705
|
+
import { existsSync as existsSync45 } from "node:fs";
|
|
20075
20706
|
import { fileURLToPath } from "node:url";
|
|
20076
20707
|
import { cpus } from "node:os";
|
|
20077
20708
|
function poolSize() {
|
|
@@ -20086,7 +20717,7 @@ function workerScript() {
|
|
|
20086
20717
|
for (const rel of ["./scan-worker.js", "../dist/scan-worker.js"]) {
|
|
20087
20718
|
try {
|
|
20088
20719
|
const p = fileURLToPath(new URL(rel, import.meta.url));
|
|
20089
|
-
if (
|
|
20720
|
+
if (existsSync45(p)) return p;
|
|
20090
20721
|
} catch {
|
|
20091
20722
|
}
|
|
20092
20723
|
}
|
|
@@ -20472,7 +21103,7 @@ var init_telemetry = __esm({
|
|
|
20472
21103
|
init_sync_client();
|
|
20473
21104
|
cliVersion2 = () => {
|
|
20474
21105
|
try {
|
|
20475
|
-
return true ? "0.7.
|
|
21106
|
+
return true ? "0.7.19" : "dev";
|
|
20476
21107
|
} catch {
|
|
20477
21108
|
return "dev";
|
|
20478
21109
|
}
|
|
@@ -20482,6 +21113,150 @@ var init_telemetry = __esm({
|
|
|
20482
21113
|
}
|
|
20483
21114
|
});
|
|
20484
21115
|
|
|
21116
|
+
// src/raw-archive-parts.ts
|
|
21117
|
+
import { createReadStream as createReadStream4, createWriteStream as createWriteStream2, openSync as openSync10, readSync as readSync8, closeSync as closeSync10, rmSync as rmSync5, statSync as statSync42 } from "node:fs";
|
|
21118
|
+
import { tmpdir as tmpdir3 } from "node:os";
|
|
21119
|
+
import { join as join48 } from "node:path";
|
|
21120
|
+
import { randomBytes } from "node:crypto";
|
|
21121
|
+
import { createGzip } from "node:zlib";
|
|
21122
|
+
import { once } from "node:events";
|
|
21123
|
+
import { readFileSync as readFileSync37 } from "node:fs";
|
|
21124
|
+
async function* fileLines(path2) {
|
|
21125
|
+
let rest = "";
|
|
21126
|
+
const decoder = new TextDecoder("utf-8");
|
|
21127
|
+
for await (const chunk of createReadStream4(path2, { highWaterMark: 1024 * 1024 })) {
|
|
21128
|
+
rest += decoder.decode(chunk, { stream: true });
|
|
21129
|
+
let nl = rest.indexOf("\n");
|
|
21130
|
+
while (nl >= 0) {
|
|
21131
|
+
yield rest.slice(0, nl + 1);
|
|
21132
|
+
rest = rest.slice(nl + 1);
|
|
21133
|
+
nl = rest.indexOf("\n");
|
|
21134
|
+
}
|
|
21135
|
+
}
|
|
21136
|
+
rest += decoder.decode();
|
|
21137
|
+
if (rest) yield rest;
|
|
21138
|
+
}
|
|
21139
|
+
function* textLines(text) {
|
|
21140
|
+
let at = 0;
|
|
21141
|
+
while (at < text.length) {
|
|
21142
|
+
const nl = text.indexOf("\n", at);
|
|
21143
|
+
const end = nl < 0 ? text.length : nl + 1;
|
|
21144
|
+
yield text.slice(at, end);
|
|
21145
|
+
at = end;
|
|
21146
|
+
}
|
|
21147
|
+
}
|
|
21148
|
+
async function writeArchiveFile(source, meta, redact, dir = tmpdir3()) {
|
|
21149
|
+
const path2 = join48(dir, `cr-archive-${randomBytes(8).toString("hex")}.json.gz`);
|
|
21150
|
+
const gzip = createGzip({ level: 6 });
|
|
21151
|
+
const out = createWriteStream2(path2, { mode: 384 });
|
|
21152
|
+
const done = once(out, "finish");
|
|
21153
|
+
gzip.pipe(out);
|
|
21154
|
+
let size = 0;
|
|
21155
|
+
const write = async (s) => {
|
|
21156
|
+
size += Buffer.byteLength(s);
|
|
21157
|
+
if (!gzip.write(s)) await once(gzip, "drain");
|
|
21158
|
+
};
|
|
21159
|
+
try {
|
|
21160
|
+
await write(`{"v":1,"tool":${JSON.stringify(meta.tool)},"mtime":${Math.floor(meta.mtime)},"files":[`);
|
|
21161
|
+
for (const [i, f] of source.files.entries()) {
|
|
21162
|
+
await write(`${i ? "," : ""}{"name":${JSON.stringify(f.name)},"text":"`);
|
|
21163
|
+
const whole = () => source.kind === "memory" ? f.text : readFileSync37(f.path, "utf-8");
|
|
21164
|
+
if (!f.name.endsWith(".jsonl")) {
|
|
21165
|
+
await write(escapeJson(redact(whole())));
|
|
21166
|
+
} else {
|
|
21167
|
+
const lines = source.kind === "memory" ? textLines(f.text) : fileLines(f.path);
|
|
21168
|
+
for await (const line of lines) {
|
|
21169
|
+
const nl = line.endsWith("\n");
|
|
21170
|
+
const body2 = nl ? line.slice(0, -1) : line;
|
|
21171
|
+
await write(escapeJson((body2 ? redactJsonLine(body2, redact) : body2) + (nl ? "\n" : "")));
|
|
21172
|
+
}
|
|
21173
|
+
}
|
|
21174
|
+
await write('"}');
|
|
21175
|
+
}
|
|
21176
|
+
await write("]}");
|
|
21177
|
+
gzip.end();
|
|
21178
|
+
await done;
|
|
21179
|
+
} catch (err) {
|
|
21180
|
+
gzip.destroy();
|
|
21181
|
+
out.destroy();
|
|
21182
|
+
rmSync5(path2, { force: true });
|
|
21183
|
+
throw err;
|
|
21184
|
+
}
|
|
21185
|
+
return { path: path2, gzSize: statSync42(path2).size, size };
|
|
21186
|
+
}
|
|
21187
|
+
async function putPart(url, body2) {
|
|
21188
|
+
let last;
|
|
21189
|
+
for (let attempt = 1; attempt <= PART_ATTEMPTS; attempt++) {
|
|
21190
|
+
const ac = new AbortController();
|
|
21191
|
+
const timer = setTimeout(() => ac.abort(), PART_TIMEOUT_MS);
|
|
21192
|
+
try {
|
|
21193
|
+
const r = await fetch(url, { method: "PUT", body: body2, signal: ac.signal });
|
|
21194
|
+
const etag = r.headers.get("etag");
|
|
21195
|
+
if (r.ok && etag) return etag;
|
|
21196
|
+
last = new Error(`part PUT answered ${r.status}`);
|
|
21197
|
+
if (r.status === 403 || r.status === 404) break;
|
|
21198
|
+
} catch (err) {
|
|
21199
|
+
last = err;
|
|
21200
|
+
} finally {
|
|
21201
|
+
clearTimeout(timer);
|
|
21202
|
+
}
|
|
21203
|
+
}
|
|
21204
|
+
throw last instanceof Error ? last : new Error(String(last));
|
|
21205
|
+
}
|
|
21206
|
+
async function uploadArchiveFile(base2, token, args) {
|
|
21207
|
+
const headers = { "content-type": "application/json" };
|
|
21208
|
+
if (token) headers.authorization = `Bearer ${token}`;
|
|
21209
|
+
const post = async (path2, body2) => {
|
|
21210
|
+
const r = await fetch(`${base2}/api/sync/raw-upload/${path2}`, { method: "POST", headers, body: JSON.stringify(body2) });
|
|
21211
|
+
const json = await r.json().catch(() => ({}));
|
|
21212
|
+
return { status: r.status, json };
|
|
21213
|
+
};
|
|
21214
|
+
const start = await post("start", {
|
|
21215
|
+
session_id: args.sessionId,
|
|
21216
|
+
tool: args.tool,
|
|
21217
|
+
mtime: Math.floor(args.mtime),
|
|
21218
|
+
size: args.file.size,
|
|
21219
|
+
gz_size: args.file.gzSize,
|
|
21220
|
+
project_id: args.projectId,
|
|
21221
|
+
project_path: args.projectPath
|
|
21222
|
+
});
|
|
21223
|
+
if (start.status === 501 || start.status === 404) return "unsupported";
|
|
21224
|
+
if (start.status !== 200) throw new Error(`raw upload start answered ${start.status}: ${start.json.error ?? ""}`);
|
|
21225
|
+
if (start.json.result === "unchanged" || start.json.result === "shrink-protected") return start.json.result;
|
|
21226
|
+
const urls = start.json.urls;
|
|
21227
|
+
const partBytes = Number(start.json.part_bytes);
|
|
21228
|
+
const parts = [];
|
|
21229
|
+
const fd = openSync10(args.file.path, "r");
|
|
21230
|
+
try {
|
|
21231
|
+
for (const [i, url] of urls.entries()) {
|
|
21232
|
+
const len = Math.min(partBytes, args.file.gzSize - i * partBytes);
|
|
21233
|
+
const buf = Buffer.allocUnsafe(len);
|
|
21234
|
+
let got = 0;
|
|
21235
|
+
while (got < len) {
|
|
21236
|
+
const n = readSync8(fd, buf, got, len - got, i * partBytes + got);
|
|
21237
|
+
if (n <= 0) break;
|
|
21238
|
+
got += n;
|
|
21239
|
+
}
|
|
21240
|
+
parts.push({ part_number: i + 1, etag: await putPart(url, buf.subarray(0, got)) });
|
|
21241
|
+
}
|
|
21242
|
+
} finally {
|
|
21243
|
+
closeSync10(fd);
|
|
21244
|
+
}
|
|
21245
|
+
const done = await post("complete", { session_id: args.sessionId, upload_id: start.json.upload_id, parts });
|
|
21246
|
+
if (done.status !== 200) throw new Error(`raw upload complete answered ${done.status}: ${done.json.error ?? ""}`);
|
|
21247
|
+
return done.json.result;
|
|
21248
|
+
}
|
|
21249
|
+
var escapeJson, PART_TIMEOUT_MS, PART_ATTEMPTS;
|
|
21250
|
+
var init_raw_archive_parts = __esm({
|
|
21251
|
+
"src/raw-archive-parts.ts"() {
|
|
21252
|
+
"use strict";
|
|
21253
|
+
init_transcript();
|
|
21254
|
+
escapeJson = (s) => JSON.stringify(s).slice(1, -1);
|
|
21255
|
+
PART_TIMEOUT_MS = 12e4;
|
|
21256
|
+
PART_ATTEMPTS = 3;
|
|
21257
|
+
}
|
|
21258
|
+
});
|
|
21259
|
+
|
|
20485
21260
|
// src/server-probe.ts
|
|
20486
21261
|
var server_probe_exports = {};
|
|
20487
21262
|
__export(server_probe_exports, {
|
|
@@ -20643,11 +21418,11 @@ __export(auto_update_exports, {
|
|
|
20643
21418
|
tarballUrl: () => tarballUrl
|
|
20644
21419
|
});
|
|
20645
21420
|
import { execSync as execSync4, execFileSync as execFileSync3 } from "node:child_process";
|
|
20646
|
-
import { readFileSync as
|
|
21421
|
+
import { readFileSync as readFileSync38, existsSync as existsSync46 } from "node:fs";
|
|
20647
21422
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
20648
|
-
import { writeFileSync as writeFileSync9, mkdtempSync as mkdtempSync3, rmSync as
|
|
20649
|
-
import { join as
|
|
20650
|
-
import { tmpdir as
|
|
21423
|
+
import { writeFileSync as writeFileSync9, mkdtempSync as mkdtempSync3, rmSync as rmSync6, readdirSync as readdirSync31, statSync as statSync43, mkdirSync as mkdirSync12 } from "node:fs";
|
|
21424
|
+
import { join as join49, dirname as dirname19, sep as sep3, posix as pathPosix, win32 as pathWin32 } from "node:path";
|
|
21425
|
+
import { tmpdir as tmpdir4, homedir as homedir17 } from "node:os";
|
|
20651
21426
|
import { createHash as createHash10 } from "node:crypto";
|
|
20652
21427
|
function compareVersions(a, b) {
|
|
20653
21428
|
const pa = String(a).split("-")[0].split(".").map((n) => parseInt(n, 10) || 0);
|
|
@@ -20671,7 +21446,7 @@ function newerOf(a, b) {
|
|
|
20671
21446
|
function installedVersion() {
|
|
20672
21447
|
try {
|
|
20673
21448
|
const here = dirname19(fileURLToPath2(import.meta.url));
|
|
20674
|
-
const raw =
|
|
21449
|
+
const raw = readFileSync38(join49(here, "..", "package.json"), "utf-8");
|
|
20675
21450
|
return JSON.parse(raw).version || null;
|
|
20676
21451
|
} catch {
|
|
20677
21452
|
return null;
|
|
@@ -20684,7 +21459,7 @@ function planAutoUpdate(base2, caps, ownVersion2, flag) {
|
|
|
20684
21459
|
if (compareVersions(rel.version, ownVersion2) <= 0) return { update: false, reason: `already current (own ${ownVersion2} >= server ${rel.version})` };
|
|
20685
21460
|
return { update: true, reason: `server ${rel.version} > own ${ownVersion2}`, url: tarballUrl(base2, rel.version), fallbackUrl: tarballUrl(base2), sha256: rel.sha256, from: ownVersion2, to: rel.version };
|
|
20686
21461
|
}
|
|
20687
|
-
function sweepStaleStaging(root =
|
|
21462
|
+
function sweepStaleStaging(root = tmpdir4(), now = Date.now()) {
|
|
20688
21463
|
const MKDTEMP_SUFFIX = /^cr-update-.{6}$/s;
|
|
20689
21464
|
const COLD_MS = 60 * 60 * 1e3;
|
|
20690
21465
|
let removed = 0;
|
|
@@ -20696,13 +21471,13 @@ function sweepStaleStaging(root = tmpdir3(), now = Date.now()) {
|
|
|
20696
21471
|
}
|
|
20697
21472
|
for (const name of entries) {
|
|
20698
21473
|
if (!MKDTEMP_SUFFIX.test(name)) continue;
|
|
20699
|
-
const dir =
|
|
21474
|
+
const dir = join49(root, name);
|
|
20700
21475
|
try {
|
|
20701
|
-
const st =
|
|
21476
|
+
const st = statSync43(dir);
|
|
20702
21477
|
if (!st.isDirectory() || now - st.mtimeMs < COLD_MS) continue;
|
|
20703
21478
|
const inside = readdirSync31(dir);
|
|
20704
21479
|
if (inside.length > 1 || inside.length === 1 && inside[0] !== "chat-recall.tgz") continue;
|
|
20705
|
-
|
|
21480
|
+
rmSync6(dir, { recursive: true, force: true });
|
|
20706
21481
|
removed++;
|
|
20707
21482
|
} catch {
|
|
20708
21483
|
}
|
|
@@ -20725,14 +21500,14 @@ async function executeAutoUpdate(plan, deps) {
|
|
|
20725
21500
|
}
|
|
20726
21501
|
const got = createHash10("sha256").update(buf).digest("hex");
|
|
20727
21502
|
if (got !== plan.sha256) return { updated: false, reason: `checksum mismatch (expected ${plan.sha256.slice(0, 12)}\u2026, got ${got.slice(0, 12)}\u2026) \u2014 NOT installing` };
|
|
20728
|
-
const dir = mkdtempSync3(
|
|
21503
|
+
const dir = mkdtempSync3(join49(tmpdir4(), "cr-update-"));
|
|
20729
21504
|
const discardStaging = () => {
|
|
20730
21505
|
try {
|
|
20731
|
-
|
|
21506
|
+
rmSync6(dir, { recursive: true, force: true });
|
|
20732
21507
|
} catch {
|
|
20733
21508
|
}
|
|
20734
21509
|
};
|
|
20735
|
-
const tgz =
|
|
21510
|
+
const tgz = join49(dir, "chat-recall.tgz");
|
|
20736
21511
|
writeFileSync9(tgz, buf);
|
|
20737
21512
|
if (deps.stopping?.()) {
|
|
20738
21513
|
discardStaging();
|
|
@@ -20804,7 +21579,7 @@ function resolveNpm(loc) {
|
|
|
20804
21579
|
}
|
|
20805
21580
|
function realInstall(tgz) {
|
|
20806
21581
|
const prefix = runningPrefix();
|
|
20807
|
-
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 });
|
|
20808
21583
|
if (prefix) {
|
|
20809
21584
|
npmInstall(npm, ["install", "-g", "--prefix", prefix, tgz]);
|
|
20810
21585
|
return;
|
|
@@ -20812,7 +21587,7 @@ function realInstall(tgz) {
|
|
|
20812
21587
|
try {
|
|
20813
21588
|
npmInstall(npm, ["install", "-g", tgz]);
|
|
20814
21589
|
} catch {
|
|
20815
|
-
npmInstall(npm, ["install", "-g", "--prefix",
|
|
21590
|
+
npmInstall(npm, ["install", "-g", "--prefix", join49(homedir17(), ".local"), tgz]);
|
|
20816
21591
|
}
|
|
20817
21592
|
}
|
|
20818
21593
|
function acquireUpdateLock() {
|
|
@@ -20829,12 +21604,12 @@ function realRestart(platform2) {
|
|
|
20829
21604
|
if (c) execSync4(c.cmd, { stdio: "ignore", ...c.shell ? { shell: c.shell } : {} });
|
|
20830
21605
|
}
|
|
20831
21606
|
function updateStatePath() {
|
|
20832
|
-
const dir = process.env.CHAT_RECALL_DATA_DIR ||
|
|
20833
|
-
return
|
|
21607
|
+
const dir = process.env.CHAT_RECALL_DATA_DIR || join49(homedir17(), ".chat-recall");
|
|
21608
|
+
return join49(dir, "auto-update-state.json");
|
|
20834
21609
|
}
|
|
20835
21610
|
function readUpdateState() {
|
|
20836
21611
|
try {
|
|
20837
|
-
return JSON.parse(
|
|
21612
|
+
return JSON.parse(readFileSync38(updateStatePath(), "utf8"));
|
|
20838
21613
|
} catch {
|
|
20839
21614
|
return {};
|
|
20840
21615
|
}
|
|
@@ -20975,9 +21750,9 @@ __export(sync_client_exports, {
|
|
|
20975
21750
|
syncIncremental: () => syncIncremental,
|
|
20976
21751
|
syncSessions: () => syncSessions
|
|
20977
21752
|
});
|
|
20978
|
-
import { join as
|
|
20979
|
-
import { readFileSync as
|
|
20980
|
-
import { tmpdir as
|
|
21753
|
+
import { join as join50, dirname as dirname20, basename as basename22 } from "node:path";
|
|
21754
|
+
import { readFileSync as readFileSync39, writeFileSync as writeFileSync10, mkdirSync as mkdirSync13, mkdtempSync as mkdtempSync4, rmSync as rmSync7, chmodSync as chmodSync6, unlinkSync as unlinkSync3, readdirSync as readdirSync32, statSync as statSync44 } from "node:fs";
|
|
21755
|
+
import { tmpdir as tmpdir5, hostname as hostname2 } from "node:os";
|
|
20981
21756
|
import { createHash as createHash11 } from "node:crypto";
|
|
20982
21757
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
20983
21758
|
import { gzipSync as gzipSync3 } from "zlib";
|
|
@@ -21031,7 +21806,7 @@ function loadAllCredentials() {
|
|
|
21031
21806
|
const fromEnv = envCredentials();
|
|
21032
21807
|
if (fromEnv) return [{ serverUrl: fromEnv.serverUrl, token: fromEnv.token }];
|
|
21033
21808
|
try {
|
|
21034
|
-
const parsed = JSON.parse(
|
|
21809
|
+
const parsed = JSON.parse(readFileSync39(credPath(), "utf-8"));
|
|
21035
21810
|
if (Array.isArray(parsed?.targets)) return parsed.targets.filter((t) => t?.serverUrl).map((t) => ({ serverUrl: t.serverUrl, token: t.token || "" }));
|
|
21036
21811
|
if (parsed?.serverUrl) return [{ serverUrl: parsed.serverUrl, token: parsed.token || "" }];
|
|
21037
21812
|
} catch {
|
|
@@ -21093,11 +21868,11 @@ function _resetTenantSecurityConfigCache() {
|
|
|
21093
21868
|
_securityConfigCache.clear();
|
|
21094
21869
|
}
|
|
21095
21870
|
function syncConfigCachePath() {
|
|
21096
|
-
return
|
|
21871
|
+
return join50(getDataDir(), "sync-config-cache.json");
|
|
21097
21872
|
}
|
|
21098
21873
|
function readPersistedSyncConfigs() {
|
|
21099
21874
|
try {
|
|
21100
|
-
return JSON.parse(
|
|
21875
|
+
return JSON.parse(readFileSync39(syncConfigCachePath(), "utf-8"));
|
|
21101
21876
|
} catch {
|
|
21102
21877
|
return {};
|
|
21103
21878
|
}
|
|
@@ -21375,7 +22150,7 @@ async function reconcileFields(opts = {}) {
|
|
|
21375
22150
|
}
|
|
21376
22151
|
return { sessions: fullRefs().length, scanned, pushed, absent, perTarget };
|
|
21377
22152
|
}
|
|
21378
|
-
function reapStaleScanDirs(dir =
|
|
22153
|
+
function reapStaleScanDirs(dir = tmpdir5(), maxAgeMs = 6 * 36e5, now = Date.now()) {
|
|
21379
22154
|
let reaped = 0;
|
|
21380
22155
|
let names;
|
|
21381
22156
|
try {
|
|
@@ -21385,10 +22160,10 @@ function reapStaleScanDirs(dir = tmpdir4(), maxAgeMs = 6 * 36e5, now = Date.now(
|
|
|
21385
22160
|
}
|
|
21386
22161
|
for (const name of names) {
|
|
21387
22162
|
if (!name.startsWith("cr-batchscan-")) continue;
|
|
21388
|
-
const p =
|
|
22163
|
+
const p = join50(dir, name);
|
|
21389
22164
|
try {
|
|
21390
|
-
if (now -
|
|
21391
|
-
|
|
22165
|
+
if (now - statSync44(p).mtimeMs < maxAgeMs) continue;
|
|
22166
|
+
rmSync7(p, { recursive: true, force: true });
|
|
21392
22167
|
reaped++;
|
|
21393
22168
|
} catch {
|
|
21394
22169
|
}
|
|
@@ -21402,7 +22177,7 @@ function batchScanExternal(items, opts = {}) {
|
|
|
21402
22177
|
let scanned = 0, slices = 0, scanMs = 0;
|
|
21403
22178
|
if (items.length === 0) return { findings, scanned, slices, scanMs };
|
|
21404
22179
|
reapStaleScanDirs();
|
|
21405
|
-
let scanDir = mkdtempSync4(
|
|
22180
|
+
let scanDir = mkdtempSync4(join50(tmpdir5(), "cr-batchscan-"));
|
|
21406
22181
|
let safeToId = /* @__PURE__ */ new Map();
|
|
21407
22182
|
let bytesInDir = 0;
|
|
21408
22183
|
const flushSlice = () => {
|
|
@@ -21420,7 +22195,7 @@ function batchScanExternal(items, opts = {}) {
|
|
|
21420
22195
|
slices++;
|
|
21421
22196
|
}
|
|
21422
22197
|
try {
|
|
21423
|
-
|
|
22198
|
+
rmSync7(scanDir, { recursive: true, force: true });
|
|
21424
22199
|
} catch {
|
|
21425
22200
|
}
|
|
21426
22201
|
safeToId = /* @__PURE__ */ new Map();
|
|
@@ -21433,19 +22208,19 @@ function batchScanExternal(items, opts = {}) {
|
|
|
21433
22208
|
if (raw === null) continue;
|
|
21434
22209
|
const safe = item.id.replace(/[^A-Za-z0-9_-]/g, "");
|
|
21435
22210
|
safeToId.set(safe, item.id);
|
|
21436
|
-
writeFileSync10(
|
|
22211
|
+
writeFileSync10(join50(scanDir, `${safe}.txt`), raw);
|
|
21437
22212
|
bytesInDir += Buffer.byteLength(raw);
|
|
21438
22213
|
} catch {
|
|
21439
22214
|
}
|
|
21440
22215
|
if (bytesInDir >= maxBytes) {
|
|
21441
22216
|
flushSlice();
|
|
21442
|
-
scanDir = mkdtempSync4(
|
|
22217
|
+
scanDir = mkdtempSync4(join50(tmpdir5(), "cr-batchscan-"));
|
|
21443
22218
|
}
|
|
21444
22219
|
}
|
|
21445
22220
|
flushSlice();
|
|
21446
22221
|
} finally {
|
|
21447
22222
|
try {
|
|
21448
|
-
|
|
22223
|
+
rmSync7(scanDir, { recursive: true, force: true });
|
|
21449
22224
|
} catch {
|
|
21450
22225
|
}
|
|
21451
22226
|
}
|
|
@@ -21657,6 +22432,11 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21657
22432
|
};
|
|
21658
22433
|
const localSessionIds = /* @__PURE__ */ new Set();
|
|
21659
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
|
+
};
|
|
21660
22440
|
const makeBatcher = (field, maxItems, flatten = false, onFlush, barrier) => {
|
|
21661
22441
|
let batch = [];
|
|
21662
22442
|
let batchBytes = 0;
|
|
@@ -21689,12 +22469,13 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21689
22469
|
markSynced(base2, rows.map((r) => {
|
|
21690
22470
|
const off = typeof r.from_offset === "number" ? r.from_offset : 0;
|
|
21691
22471
|
const hash = shippedHash.get(r.session_id);
|
|
21692
|
-
return off > 0 ? { id: r.session_id, mtime: r.mtime, offset: off, size: off, hash, acked: true } : { id: r.session_id, mtime: r.mtime, hash };
|
|
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 };
|
|
21693
22473
|
}));
|
|
21694
22474
|
} catch {
|
|
21695
22475
|
}
|
|
21696
22476
|
});
|
|
21697
22477
|
const appendResults = { uploaded: 0, fullResyncNeeded: /* @__PURE__ */ new Set() };
|
|
22478
|
+
const pendingArchives = [];
|
|
21698
22479
|
const postAppend = async (convs) => {
|
|
21699
22480
|
const headers = { "content-type": "application/json" };
|
|
21700
22481
|
if (cred.token) headers.authorization = `Bearer ${cred.token}`;
|
|
@@ -21729,8 +22510,11 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21729
22510
|
offset: c.from_offset,
|
|
21730
22511
|
size: c.from_offset,
|
|
21731
22512
|
// size = new offset (file grew to here)
|
|
21732
|
-
acked: true
|
|
22513
|
+
acked: true,
|
|
21733
22514
|
// server merged this tail
|
|
22515
|
+
chunkFinal: c.final === true,
|
|
22516
|
+
// completes a chunked full sync
|
|
22517
|
+
...layoutOf(c.session_id)
|
|
21734
22518
|
})));
|
|
21735
22519
|
} catch {
|
|
21736
22520
|
}
|
|
@@ -21762,9 +22546,9 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21762
22546
|
const mtime = conv.mtime;
|
|
21763
22547
|
try {
|
|
21764
22548
|
if (staged || !guarded) {
|
|
21765
|
-
markSynced(base2, [{ id, mtime, offset: conv.from_offset, size: conv.from_offset, acked: true }]);
|
|
22549
|
+
markSynced(base2, [{ id, mtime, offset: conv.from_offset, size: conv.from_offset, acked: true, chunkedHead: true, ...layoutOf(id) }]);
|
|
21766
22550
|
} else if (typeof guarded.o === "number" && guarded.o > 0 && guarded.o <= fileSize) {
|
|
21767
|
-
markSynced(base2, [{ id, mtime, offset: guarded.o, size: guarded.o, acked: true }]);
|
|
22551
|
+
markSynced(base2, [{ id, mtime, offset: guarded.o, size: guarded.o, acked: true, chunkedHead: true, ...layoutOf(id) }]);
|
|
21768
22552
|
} else {
|
|
21769
22553
|
markSynced(base2, [{ id, mtime }]);
|
|
21770
22554
|
}
|
|
@@ -21859,8 +22643,8 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21859
22643
|
if (!ledger) return ref.mtime >= (opts.sinceMs ?? 0) ? "full" : "skip";
|
|
21860
22644
|
const ack = ledger.get(ref.prefixedId);
|
|
21861
22645
|
const backend = backendFor(ref);
|
|
21862
|
-
const
|
|
21863
|
-
const isAO = !!backend?.isAppendOnly?.() &&
|
|
22646
|
+
const sameLayout = (ack?.L ?? "") === (backend?.sourceLayout?.(ref.prefixedId) ?? "");
|
|
22647
|
+
const isAO = !!backend?.isAppendOnly?.() && sameLayout;
|
|
21864
22648
|
const size = isAO ? backend?.fileSize?.(ref.prefixedId) ?? 0 : 0;
|
|
21865
22649
|
return syncMode(ack, ref.mtime, size, extractorVersionForTool(ref.toolId), isAO);
|
|
21866
22650
|
};
|
|
@@ -21907,6 +22691,9 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21907
22691
|
skipped++;
|
|
21908
22692
|
continue;
|
|
21909
22693
|
}
|
|
22694
|
+
const layout = backendFor(ref)?.sourceLayout?.(ref.prefixedId) ?? "";
|
|
22695
|
+
if (layout) shippedLayout.set(ref.prefixedId, layout);
|
|
22696
|
+
else shippedLayout.delete(ref.prefixedId);
|
|
21910
22697
|
trace?.(`build (${mode}) ${ref.prefixedId} \xB7 ${(sessionFileBytes(ref) / 1048576).toFixed(1)}MB`);
|
|
21911
22698
|
let promotedForFindings = false;
|
|
21912
22699
|
if (mode === "append" && ledger) {
|
|
@@ -21952,7 +22739,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21952
22739
|
const off = getBackendForId(ref.prefixedId)?.fileSize?.(ref.rawId) ?? 0;
|
|
21953
22740
|
const priorCursor = ackRow?.s ?? 0;
|
|
21954
22741
|
const safeToAck = off > 0 && off <= priorCursor;
|
|
21955
|
-
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 }]);
|
|
21956
22743
|
} catch {
|
|
21957
22744
|
}
|
|
21958
22745
|
}
|
|
@@ -21973,6 +22760,14 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21973
22760
|
if (built.srcHash) shippedHash.set(ref.prefixedId, built.srcHash);
|
|
21974
22761
|
if (built.conv.chunked) await postChunkedHead(built.conv, sessionFileBytes(ref));
|
|
21975
22762
|
else await convBatch.add(built.conv);
|
|
22763
|
+
if (built.archive) {
|
|
22764
|
+
pendingArchives.push({
|
|
22765
|
+
id: ref.prefixedId,
|
|
22766
|
+
...built.archive,
|
|
22767
|
+
projectId: built.conv.project_id,
|
|
22768
|
+
projectPath: built.conv.project_path
|
|
22769
|
+
});
|
|
22770
|
+
}
|
|
21976
22771
|
if (built.findings.length > 0) await findingsBatch.add(built.findings);
|
|
21977
22772
|
if (upload.sessionMeta) {
|
|
21978
22773
|
await accumulateKg(extractEntities(built.kgText, { projectPath: built.projectPath, sourceType: "session", sessionId: ref.prefixedId, validFrom: ref.mtime ? new Date(ref.mtime).toISOString().slice(0, 10) : void 0 }), ref.prefixedId);
|
|
@@ -22125,6 +22920,30 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
22125
22920
|
await kgTripleBatch.drain();
|
|
22126
22921
|
await findingsBatch.drain();
|
|
22127
22922
|
await drainInflight();
|
|
22923
|
+
let archivesUnsupported = false;
|
|
22924
|
+
for (const a of pendingArchives) {
|
|
22925
|
+
try {
|
|
22926
|
+
if (!archivesUnsupported) {
|
|
22927
|
+
const r = await uploadArchiveFile(base2, cred.token, {
|
|
22928
|
+
sessionId: a.id,
|
|
22929
|
+
tool: a.tool,
|
|
22930
|
+
mtime: a.mtime,
|
|
22931
|
+
projectId: a.projectId,
|
|
22932
|
+
projectPath: a.projectPath,
|
|
22933
|
+
file: a.file
|
|
22934
|
+
});
|
|
22935
|
+
if (r === "unsupported") archivesUnsupported = true;
|
|
22936
|
+
}
|
|
22937
|
+
} catch (err) {
|
|
22938
|
+
console.error(`[sync] raw archive for ${a.id} not uploaded (tried again when the session is next quiet): ${err instanceof Error ? err.message : err}`);
|
|
22939
|
+
try {
|
|
22940
|
+
forgetFullCoverage(base2, a.id);
|
|
22941
|
+
} catch {
|
|
22942
|
+
}
|
|
22943
|
+
} finally {
|
|
22944
|
+
rmSync7(a.file.path, { force: true });
|
|
22945
|
+
}
|
|
22946
|
+
}
|
|
22128
22947
|
{
|
|
22129
22948
|
const sentHashes = loadInventoryHashes(base2);
|
|
22130
22949
|
const entries = [];
|
|
@@ -22230,6 +23049,7 @@ async function buildConversationSync(ref, mtime, opts = {}) {
|
|
|
22230
23049
|
let includeRaw = opts.includeRaw !== false;
|
|
22231
23050
|
let includeMeta = opts.includeMeta !== false;
|
|
22232
23051
|
let srcHash;
|
|
23052
|
+
const wantRaw = opts.includeRaw !== false;
|
|
22233
23053
|
const oversized = sessionBuildBytes(ref) > FULL_BUILD_MAX_BYTES;
|
|
22234
23054
|
let headOffsetEnd = 0;
|
|
22235
23055
|
let oversizedFindings = null;
|
|
@@ -22398,7 +23218,7 @@ async function buildConversationSync(ref, mtime, opts = {}) {
|
|
|
22398
23218
|
} else if (opts.scanSecrets) {
|
|
22399
23219
|
let tmp = null;
|
|
22400
23220
|
try {
|
|
22401
|
-
tmp =
|
|
23221
|
+
tmp = join50(tmpdir5(), `cr-scan-${ref.prefixedId.replace(/[^A-Za-z0-9_-]/g, "")}-${mtime}.txt`);
|
|
22402
23222
|
writeFileSync10(tmp, rawText);
|
|
22403
23223
|
for (const f of scanFileForSecrets(tmp, { verifyOnly: opts.verifySecrets, tenantRules: opts.tenantRules })) {
|
|
22404
23224
|
const verifiedAt = f.verified ? (/* @__PURE__ */ new Date()).toISOString() : null;
|
|
@@ -22450,6 +23270,25 @@ async function buildConversationSync(ref, mtime, opts = {}) {
|
|
|
22450
23270
|
}
|
|
22451
23271
|
const envTexts = envelope.messages.filter((m) => m.content?.trim());
|
|
22452
23272
|
const redactedText = envTexts.map((m) => m.content).join("\n");
|
|
23273
|
+
let archive;
|
|
23274
|
+
if (wantRaw && !raw_b64) {
|
|
23275
|
+
try {
|
|
23276
|
+
const redact = (t) => redactSecrets(t, { force: true, count });
|
|
23277
|
+
let source = null;
|
|
23278
|
+
let archiveMtime = Math.floor(ref.mtime) || 0;
|
|
23279
|
+
let archiveTool = ref.toolId;
|
|
23280
|
+
if (container) {
|
|
23281
|
+
source = { kind: "memory", files: container.files };
|
|
23282
|
+
archiveMtime = container.mtime;
|
|
23283
|
+
archiveTool = container.tool;
|
|
23284
|
+
} else if (oversized) {
|
|
23285
|
+
source = diskArchiveSource(ref);
|
|
23286
|
+
}
|
|
23287
|
+
if (source) archive = { file: await writeArchiveFile(source, { tool: archiveTool, mtime: archiveMtime }, redact), tool: archiveTool, mtime: archiveMtime };
|
|
23288
|
+
} catch (err) {
|
|
23289
|
+
console.error(`[sync] raw archive for ${ref.prefixedId} not written: ${err instanceof Error ? err.message : err}`);
|
|
23290
|
+
}
|
|
23291
|
+
}
|
|
22453
23292
|
return {
|
|
22454
23293
|
conv: {
|
|
22455
23294
|
session_id: ref.prefixedId,
|
|
@@ -22481,7 +23320,17 @@ async function buildConversationSync(ref, mtime, opts = {}) {
|
|
|
22481
23320
|
redactions: count.redactions,
|
|
22482
23321
|
findings,
|
|
22483
23322
|
scanMs,
|
|
22484
|
-
srcHash
|
|
23323
|
+
srcHash,
|
|
23324
|
+
archive
|
|
23325
|
+
};
|
|
23326
|
+
}
|
|
23327
|
+
function diskArchiveSource(ref) {
|
|
23328
|
+
if (ref.toolId !== "claude") return null;
|
|
23329
|
+
const groups = resolveSessionContentGroups(ref.rawId);
|
|
23330
|
+
if (groups.length === 0 || groups.some((g) => g.paths.length !== 1)) return null;
|
|
23331
|
+
return {
|
|
23332
|
+
kind: "disk",
|
|
23333
|
+
files: groups.map((g) => ({ name: g.name === "main" ? `${ref.rawId}.jsonl` : g.name, path: g.paths[0] }))
|
|
22485
23334
|
};
|
|
22486
23335
|
}
|
|
22487
23336
|
function parseTailMessages(tool, text) {
|
|
@@ -22637,14 +23486,15 @@ var init_sync_client = __esm({
|
|
|
22637
23486
|
init_telemetry();
|
|
22638
23487
|
init_collector_health();
|
|
22639
23488
|
init_live_session_scan();
|
|
23489
|
+
init_raw_archive_parts();
|
|
22640
23490
|
init_backends();
|
|
22641
23491
|
ownVersion = "0.0.0";
|
|
22642
23492
|
try {
|
|
22643
23493
|
const dir = dirname20(fileURLToPath3(import.meta.url));
|
|
22644
|
-
ownVersion = JSON.parse(
|
|
23494
|
+
ownVersion = JSON.parse(readFileSync39(join50(dir, "../package.json"), "utf-8")).version || ownVersion;
|
|
22645
23495
|
} catch {
|
|
22646
23496
|
try {
|
|
22647
|
-
if (true) ownVersion = "0.7.
|
|
23497
|
+
if (true) ownVersion = "0.7.19";
|
|
22648
23498
|
} catch {
|
|
22649
23499
|
}
|
|
22650
23500
|
}
|
|
@@ -22656,7 +23506,7 @@ var init_sync_client = __esm({
|
|
|
22656
23506
|
]);
|
|
22657
23507
|
walkProgressForUpload = null;
|
|
22658
23508
|
lastServerPackSpec = null;
|
|
22659
|
-
credPath = () =>
|
|
23509
|
+
credPath = () => join50(getDataDir(), "credentials.json");
|
|
22660
23510
|
_securityConfigCache = /* @__PURE__ */ new Map();
|
|
22661
23511
|
SECURITY_CONFIG_TTL_MS = 5 * 60 * 1e3;
|
|
22662
23512
|
_syncConfigCache = /* @__PURE__ */ new Map();
|
|
@@ -22685,7 +23535,7 @@ __export(client_events_exports, {
|
|
|
22685
23535
|
isTelemetryEnabled: () => isTelemetryEnabled,
|
|
22686
23536
|
reportClientEvent: () => reportClientEvent2
|
|
22687
23537
|
});
|
|
22688
|
-
import { readFileSync as
|
|
23538
|
+
import { readFileSync as readFileSync40 } from "node:fs";
|
|
22689
23539
|
function scrub(msg) {
|
|
22690
23540
|
if (!msg) return "";
|
|
22691
23541
|
const noHome = msg.replace(/\/(?:home|Users)\/[^/\s]+/g, "~");
|
|
@@ -22738,7 +23588,7 @@ var init_client_events = __esm({
|
|
|
22738
23588
|
init_secret_redactor();
|
|
22739
23589
|
CLI_VERSION2 = "0.0.0";
|
|
22740
23590
|
try {
|
|
22741
|
-
CLI_VERSION2 = JSON.parse(
|
|
23591
|
+
CLI_VERSION2 = JSON.parse(readFileSync40(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION2;
|
|
22742
23592
|
} catch {
|
|
22743
23593
|
}
|
|
22744
23594
|
}
|
|
@@ -22752,15 +23602,15 @@ __export(update_notice_exports, {
|
|
|
22752
23602
|
refreshUpdateCheck: () => refreshUpdateCheck,
|
|
22753
23603
|
updateNotice: () => updateNotice2
|
|
22754
23604
|
});
|
|
22755
|
-
import { readFileSync as
|
|
22756
|
-
import { join as
|
|
23605
|
+
import { readFileSync as readFileSync41, writeFileSync as writeFileSync11 } from "node:fs";
|
|
23606
|
+
import { join as join51 } from "node:path";
|
|
22757
23607
|
function newestKnown(c) {
|
|
22758
23608
|
const npm = c.npmVersion ?? "0.0.0";
|
|
22759
23609
|
return compareVersions(npm, c.serverVersion) > 0 ? { version: npm, source: "npm" } : { version: c.serverVersion, source: "server" };
|
|
22760
23610
|
}
|
|
22761
23611
|
function readCheck() {
|
|
22762
23612
|
try {
|
|
22763
|
-
const c = JSON.parse(
|
|
23613
|
+
const c = JSON.parse(readFileSync41(checkPath(), "utf-8"));
|
|
22764
23614
|
return c && typeof c.serverVersion === "string" ? c : null;
|
|
22765
23615
|
} catch {
|
|
22766
23616
|
return null;
|
|
@@ -22854,7 +23704,7 @@ var init_update_notice = __esm({
|
|
|
22854
23704
|
init_http();
|
|
22855
23705
|
CHECK_TTL_MS = 6 * 3600 * 1e3;
|
|
22856
23706
|
NPM_LATEST_URL = "https://registry.npmjs.org/chat-recall";
|
|
22857
|
-
checkPath = () =>
|
|
23707
|
+
checkPath = () => join51(getDataDir(), "update-check.json");
|
|
22858
23708
|
printed = false;
|
|
22859
23709
|
}
|
|
22860
23710
|
});
|
|
@@ -22926,15 +23776,15 @@ __export(service_installer_exports, {
|
|
|
22926
23776
|
uninstallService: () => uninstallService
|
|
22927
23777
|
});
|
|
22928
23778
|
import { execSync as execSync5 } from "child_process";
|
|
22929
|
-
import { existsSync as
|
|
23779
|
+
import { existsSync as existsSync47, mkdirSync as mkdirSync14, readFileSync as readFileSync42, rmSync as rmSync8, writeFileSync as writeFileSync12 } from "fs";
|
|
22930
23780
|
import { homedir as homedir18 } from "os";
|
|
22931
|
-
import { join as
|
|
23781
|
+
import { join as join52 } from "path";
|
|
22932
23782
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
22933
23783
|
function resolveDaemonPaths() {
|
|
22934
23784
|
const watchJs = fileURLToPath4(new URL("./watch.js", import.meta.url));
|
|
22935
23785
|
const node = process.execPath;
|
|
22936
|
-
const dataDir =
|
|
22937
|
-
const logFile =
|
|
23786
|
+
const dataDir = join52(homedir18(), ".chat-recall");
|
|
23787
|
+
const logFile = join52(dataDir, "watch.log");
|
|
22938
23788
|
return { watchJs, node, logFile, dataDir };
|
|
22939
23789
|
}
|
|
22940
23790
|
function tryCmd(cmd) {
|
|
@@ -22961,12 +23811,12 @@ function refreshServiceDefinition() {
|
|
|
22961
23811
|
if (process.platform !== "linux") return false;
|
|
22962
23812
|
try {
|
|
22963
23813
|
const { watchJs, node, logFile } = resolveDaemonPaths();
|
|
22964
|
-
const unitPath =
|
|
22965
|
-
if (!
|
|
22966
|
-
const current =
|
|
23814
|
+
const unitPath = join52(homedir18(), ".config", "systemd", "user", "chat-recall-watch.service");
|
|
23815
|
+
if (!existsSync47(unitPath)) return false;
|
|
23816
|
+
const current = readFileSync42(unitPath, "utf8");
|
|
22967
23817
|
if (!current.includes(watchJs)) return false;
|
|
22968
23818
|
const wanted = renderSystemdUnit(watchJs, node, logFile);
|
|
22969
|
-
if (
|
|
23819
|
+
if (readFileSync42(unitPath, "utf8") === wanted) return false;
|
|
22970
23820
|
writeFileSync12(unitPath, wanted);
|
|
22971
23821
|
execSync5("systemctl --user daemon-reload", { stdio: "ignore" });
|
|
22972
23822
|
return true;
|
|
@@ -22992,8 +23842,8 @@ function installService() {
|
|
|
22992
23842
|
);
|
|
22993
23843
|
}
|
|
22994
23844
|
function installSystemd(watchJs, node, logFile) {
|
|
22995
|
-
const unitDir =
|
|
22996
|
-
const unitPath =
|
|
23845
|
+
const unitDir = join52(homedir18(), ".config", "systemd", "user");
|
|
23846
|
+
const unitPath = join52(unitDir, "chat-recall-watch.service");
|
|
22997
23847
|
const unit = renderSystemdUnit(watchJs, node, logFile);
|
|
22998
23848
|
mkdirSync14(unitDir, { recursive: true });
|
|
22999
23849
|
writeFileSync12(unitPath, unit);
|
|
@@ -23072,8 +23922,8 @@ function renderSystemdUnit(watchJs, node, logFile) {
|
|
|
23072
23922
|
}
|
|
23073
23923
|
function installLaunchd(watchJs, node, logFile) {
|
|
23074
23924
|
const label = "com.chat-recall.watch";
|
|
23075
|
-
const plistDir =
|
|
23076
|
-
const plistPath =
|
|
23925
|
+
const plistDir = join52(homedir18(), "Library", "LaunchAgents");
|
|
23926
|
+
const plistPath = join52(plistDir, `${label}.plist`);
|
|
23077
23927
|
const plist = renderLaunchdPlist(watchJs, node, logFile, label);
|
|
23078
23928
|
mkdirSync14(plistDir, { recursive: true });
|
|
23079
23929
|
writeFileSync12(plistPath, plist);
|
|
@@ -23129,9 +23979,9 @@ function uninstallService() {
|
|
|
23129
23979
|
removed = true;
|
|
23130
23980
|
} catch {
|
|
23131
23981
|
}
|
|
23132
|
-
const unitPath =
|
|
23133
|
-
if (
|
|
23134
|
-
|
|
23982
|
+
const unitPath = join52(homedir18(), ".config", "systemd", "user", "chat-recall-watch.service");
|
|
23983
|
+
if (existsSync47(unitPath)) {
|
|
23984
|
+
rmSync8(unitPath, { force: true });
|
|
23135
23985
|
removed = true;
|
|
23136
23986
|
}
|
|
23137
23987
|
try {
|
|
@@ -23141,14 +23991,14 @@ function uninstallService() {
|
|
|
23141
23991
|
return removed;
|
|
23142
23992
|
}
|
|
23143
23993
|
if (process.platform === "darwin") {
|
|
23144
|
-
const plistPath =
|
|
23994
|
+
const plistPath = join52(homedir18(), "Library", "LaunchAgents", "com.chat-recall.watch.plist");
|
|
23145
23995
|
try {
|
|
23146
23996
|
execSync5(`launchctl unload "${plistPath}" 2>/dev/null`, { stdio: "ignore" });
|
|
23147
23997
|
} catch {
|
|
23148
23998
|
}
|
|
23149
23999
|
let removed = false;
|
|
23150
|
-
if (
|
|
23151
|
-
|
|
24000
|
+
if (existsSync47(plistPath)) {
|
|
24001
|
+
rmSync8(plistPath, { force: true });
|
|
23152
24002
|
removed = true;
|
|
23153
24003
|
}
|
|
23154
24004
|
return removed;
|
|
@@ -23194,15 +24044,15 @@ __export(install_skills_exports, {
|
|
|
23194
24044
|
skillsSourceDir: () => skillsSourceDir,
|
|
23195
24045
|
uninstallSkills: () => uninstallSkills
|
|
23196
24046
|
});
|
|
23197
|
-
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";
|
|
23198
24048
|
import { createHash as createHash12 } from "crypto";
|
|
23199
|
-
import { join as
|
|
24049
|
+
import { join as join53, basename as basename23 } from "path";
|
|
23200
24050
|
function skillsSourceDir() {
|
|
23201
|
-
return
|
|
24051
|
+
return join53(import.meta.dirname, "..", "skills");
|
|
23202
24052
|
}
|
|
23203
24053
|
function version() {
|
|
23204
24054
|
try {
|
|
23205
|
-
return JSON.parse(
|
|
24055
|
+
return JSON.parse(readFileSync43(new URL("../package.json", import.meta.url), "utf-8")).version || "0.0.0";
|
|
23206
24056
|
} catch {
|
|
23207
24057
|
return "0.0.0";
|
|
23208
24058
|
}
|
|
@@ -23211,9 +24061,9 @@ function skillsFingerprint() {
|
|
|
23211
24061
|
const src = skillsSourceDir();
|
|
23212
24062
|
const h = createHash12("sha256");
|
|
23213
24063
|
for (const name of bundledSkillNames()) {
|
|
23214
|
-
for (const rel of filesUnder(
|
|
24064
|
+
for (const rel of filesUnder(join53(src, name)).sort()) {
|
|
23215
24065
|
h.update(name + "/" + rel);
|
|
23216
|
-
h.update(
|
|
24066
|
+
h.update(readFileSync43(join53(src, name, rel)));
|
|
23217
24067
|
}
|
|
23218
24068
|
}
|
|
23219
24069
|
return h.digest("hex").slice(0, 12);
|
|
@@ -23223,7 +24073,7 @@ function filesUnder(dir, prefix = "") {
|
|
|
23223
24073
|
for (const e of readdirSync33(dir, { withFileTypes: true })) {
|
|
23224
24074
|
if (e.name === MARKER) continue;
|
|
23225
24075
|
const rel = prefix ? `${prefix}/${e.name}` : e.name;
|
|
23226
|
-
if (e.isDirectory()) out.push(...filesUnder(
|
|
24076
|
+
if (e.isDirectory()) out.push(...filesUnder(join53(dir, e.name), rel));
|
|
23227
24077
|
else out.push(rel);
|
|
23228
24078
|
}
|
|
23229
24079
|
return out;
|
|
@@ -23233,8 +24083,8 @@ function skillStamp() {
|
|
|
23233
24083
|
}
|
|
23234
24084
|
function bundledSkillNames() {
|
|
23235
24085
|
const src = skillsSourceDir();
|
|
23236
|
-
if (!
|
|
23237
|
-
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();
|
|
23238
24088
|
}
|
|
23239
24089
|
function realPathOrSelf(p) {
|
|
23240
24090
|
try {
|
|
@@ -23247,7 +24097,7 @@ function claudeSkillTargets() {
|
|
|
23247
24097
|
const targets = [];
|
|
23248
24098
|
const seen = /* @__PURE__ */ new Set();
|
|
23249
24099
|
for (const home of claudeHomeDirs()) {
|
|
23250
|
-
const dir =
|
|
24100
|
+
const dir = join53(home, "skills");
|
|
23251
24101
|
const key2 = realPathOrSelf(dir);
|
|
23252
24102
|
if (seen.has(key2)) continue;
|
|
23253
24103
|
seen.add(key2);
|
|
@@ -23258,7 +24108,7 @@ function claudeSkillTargets() {
|
|
|
23258
24108
|
dir,
|
|
23259
24109
|
// Judge each profile on ITS OWN transcripts, not the primary's: a home
|
|
23260
24110
|
// with no projects/ is a directory someone made, not a Claude install.
|
|
23261
|
-
available:
|
|
24111
|
+
available: existsSync48(join53(home, "projects"))
|
|
23262
24112
|
});
|
|
23263
24113
|
}
|
|
23264
24114
|
if (targets.length === 0) {
|
|
@@ -23273,16 +24123,16 @@ function skillTargets() {
|
|
|
23273
24123
|
// both produces "skill conflict" duplicate warnings. Every tool we support
|
|
23274
24124
|
// has its own dir, so per-tool coverage is complete.
|
|
23275
24125
|
...claudeSkillTargets(),
|
|
23276
|
-
{ id: "agy", label: "Antigravity", dir:
|
|
24126
|
+
{ id: "agy", label: "Antigravity", dir: join53(agyBackend.homeDir(), "skills"), available: agyBackend.isAvailable() },
|
|
23277
24127
|
{ id: "codex", label: "Codex", dir: codexBackend.skillsDir(), available: codexBackend.isAvailable() },
|
|
23278
24128
|
{ id: "opencode", label: "OpenCode", dir: opencodeBackend.skillsDir(), available: opencodeBackend.isAvailable() },
|
|
23279
24129
|
// Cursor DOES have its own dir (~/.cursor/skills). `skills-cursor` next to
|
|
23280
24130
|
// it is Cursor's bundled set — read-only, never an install target.
|
|
23281
|
-
{ id: "cursor", label: "Cursor", dir:
|
|
24131
|
+
{ id: "cursor", label: "Cursor", dir: join53(cursorHomeDir(), "skills"), available: cursorBackend.isAvailable() }
|
|
23282
24132
|
];
|
|
23283
24133
|
}
|
|
23284
24134
|
function isManaged(dir) {
|
|
23285
|
-
return
|
|
24135
|
+
return existsSync48(join53(dir, MARKER));
|
|
23286
24136
|
}
|
|
23287
24137
|
function installSkills(opts = {}) {
|
|
23288
24138
|
const onlyAvailable = opts.onlyAvailable ?? true;
|
|
@@ -23299,15 +24149,15 @@ function installSkills(opts = {}) {
|
|
|
23299
24149
|
continue;
|
|
23300
24150
|
}
|
|
23301
24151
|
for (const name of names) {
|
|
23302
|
-
const dest =
|
|
23303
|
-
if (
|
|
24152
|
+
const dest = join53(t.dir, name);
|
|
24153
|
+
if (existsSync48(dest) && !isManaged(dest)) {
|
|
23304
24154
|
skippedUserOwned.push(name);
|
|
23305
24155
|
continue;
|
|
23306
24156
|
}
|
|
23307
24157
|
mkdirSync15(t.dir, { recursive: true });
|
|
23308
|
-
|
|
23309
|
-
cpSync(
|
|
23310
|
-
writeFileSync13(
|
|
24158
|
+
rmSync9(dest, { recursive: true, force: true });
|
|
24159
|
+
cpSync(join53(src, name), dest, { recursive: true });
|
|
24160
|
+
writeFileSync13(join53(dest, MARKER), `${stamp}
|
|
23311
24161
|
`);
|
|
23312
24162
|
installed.push(name);
|
|
23313
24163
|
}
|
|
@@ -23320,15 +24170,15 @@ function uninstallSkills() {
|
|
|
23320
24170
|
const perTarget = [];
|
|
23321
24171
|
for (const t of skillTargets()) {
|
|
23322
24172
|
const removed = [];
|
|
23323
|
-
if (!
|
|
24173
|
+
if (!existsSync48(t.dir)) {
|
|
23324
24174
|
perTarget.push({ id: t.id, label: t.label, removed });
|
|
23325
24175
|
continue;
|
|
23326
24176
|
}
|
|
23327
24177
|
for (const entry of readdirSync33(t.dir, { withFileTypes: true })) {
|
|
23328
24178
|
if (!entry.isDirectory()) continue;
|
|
23329
|
-
const dir =
|
|
24179
|
+
const dir = join53(t.dir, entry.name);
|
|
23330
24180
|
if (isManaged(dir) && (names.has(entry.name) || entry.name.startsWith("chat-recall"))) {
|
|
23331
|
-
|
|
24181
|
+
rmSync9(dir, { recursive: true, force: true });
|
|
23332
24182
|
removed.push(entry.name);
|
|
23333
24183
|
}
|
|
23334
24184
|
}
|
|
@@ -23343,10 +24193,10 @@ function skillsNeedRefresh() {
|
|
|
23343
24193
|
for (const t of skillTargets()) {
|
|
23344
24194
|
if (!t.available) continue;
|
|
23345
24195
|
for (const name of names) {
|
|
23346
|
-
const marker =
|
|
23347
|
-
if (!
|
|
24196
|
+
const marker = join53(t.dir, name, MARKER);
|
|
24197
|
+
if (!existsSync48(marker)) return true;
|
|
23348
24198
|
try {
|
|
23349
|
-
if (
|
|
24199
|
+
if (readFileSync43(marker, "utf-8").trim() !== cur) return true;
|
|
23350
24200
|
} catch {
|
|
23351
24201
|
return true;
|
|
23352
24202
|
}
|
|
@@ -23361,11 +24211,11 @@ function skillStatus() {
|
|
|
23361
24211
|
let installed = 0;
|
|
23362
24212
|
let ver = null;
|
|
23363
24213
|
for (const name of names) {
|
|
23364
|
-
const marker =
|
|
23365
|
-
if (
|
|
24214
|
+
const marker = join53(t.dir, name, MARKER);
|
|
24215
|
+
if (existsSync48(marker)) {
|
|
23366
24216
|
installed++;
|
|
23367
24217
|
try {
|
|
23368
|
-
ver =
|
|
24218
|
+
ver = readFileSync43(marker, "utf-8").trim();
|
|
23369
24219
|
} catch {
|
|
23370
24220
|
}
|
|
23371
24221
|
}
|
|
@@ -23622,6 +24472,7 @@ var SESSION_ID_PREFIXES = {
|
|
|
23622
24472
|
opencode: "opencode_",
|
|
23623
24473
|
agy: "agy_",
|
|
23624
24474
|
cursor: "cursor_",
|
|
24475
|
+
hermes: "hermes_",
|
|
23625
24476
|
gemini: "gemini_"
|
|
23626
24477
|
};
|
|
23627
24478
|
function toolOfSessionId(sessionId) {
|
|
@@ -23650,6 +24501,8 @@ function resumeCommandFor(sessionId, tool) {
|
|
|
23650
24501
|
// available answer for either.
|
|
23651
24502
|
case "cursor":
|
|
23652
24503
|
return `cursor-agent --resume ${raw("cursor_")}`;
|
|
24504
|
+
case "hermes":
|
|
24505
|
+
return `hermes --resume ${raw("hermes_")}`;
|
|
23653
24506
|
// Gemini's `--resume` takes an index or "latest", never a session id.
|
|
23654
24507
|
default:
|
|
23655
24508
|
return null;
|
|
@@ -24639,7 +25492,7 @@ function isMultiTenant() {
|
|
|
24639
25492
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
24640
25493
|
import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ListPromptsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
24641
25494
|
import { z } from "zod";
|
|
24642
|
-
import { existsSync as
|
|
25495
|
+
import { existsSync as existsSync23, readFileSync as readFileSync18, statSync as statSync21 } from "fs";
|
|
24643
25496
|
import { join as join27 } from "path";
|
|
24644
25497
|
|
|
24645
25498
|
// ../engine/dist/core/context.js
|
|
@@ -24787,7 +25640,7 @@ function sanitizeQuery(query) {
|
|
|
24787
25640
|
|
|
24788
25641
|
// ../engine/dist/core/write-ahead-log.js
|
|
24789
25642
|
init_paths();
|
|
24790
|
-
import { existsSync as
|
|
25643
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync5, appendFileSync, openSync as openSync8, closeSync as closeSync8, chmodSync as chmodSync3 } from "fs";
|
|
24791
25644
|
import { join as join20 } from "path";
|
|
24792
25645
|
var REDACT_KEYS = /* @__PURE__ */ new Set([
|
|
24793
25646
|
"content",
|
|
@@ -24804,7 +25657,7 @@ var WriteAheadLog = class {
|
|
|
24804
25657
|
walPath;
|
|
24805
25658
|
constructor(walDir) {
|
|
24806
25659
|
const dir = walDir || getWalDir();
|
|
24807
|
-
if (!
|
|
25660
|
+
if (!existsSync18(dir)) {
|
|
24808
25661
|
mkdirSync5(dir, { recursive: true });
|
|
24809
25662
|
try {
|
|
24810
25663
|
chmodSync3(dir, 448);
|
|
@@ -24812,7 +25665,7 @@ var WriteAheadLog = class {
|
|
|
24812
25665
|
}
|
|
24813
25666
|
}
|
|
24814
25667
|
this.walPath = join20(dir, "write_log.jsonl");
|
|
24815
|
-
if (!
|
|
25668
|
+
if (!existsSync18(this.walPath)) {
|
|
24816
25669
|
const fd = openSync8(this.walPath, "w", 384);
|
|
24817
25670
|
closeSync8(fd);
|
|
24818
25671
|
}
|
|
@@ -25173,7 +26026,7 @@ var RecallEditsTimelineSchema = z.object({
|
|
|
25173
26026
|
pattern: z.string().optional().describe("Optional substring filter on file path"),
|
|
25174
26027
|
project_filter: z.string().optional().describe("Filter by project name (matched against the encoded project directory name)"),
|
|
25175
26028
|
include_reads: z.boolean().optional().default(false).describe("Include read-type tool calls in addition to write/edit ones"),
|
|
25176
|
-
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."),
|
|
25177
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."),
|
|
25178
26031
|
view: z.enum(["timeline", "summary"]).optional().default("timeline").describe("timeline = the chronological edit rows; summary = an aggregated rollup over the same window"),
|
|
25179
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).')
|
|
@@ -25885,7 +26738,7 @@ aggregate per session instead \u2014 "which sessions edited auth.rs in the last
|
|
|
25885
26738
|
include_reads: { type: "boolean", default: false, description: "Include Read tool_uses too" },
|
|
25886
26739
|
tools: {
|
|
25887
26740
|
type: "array",
|
|
25888
|
-
items: { type: "string", enum: ["claude", "opencode", "codex", "agy", "cursor"] },
|
|
26741
|
+
items: { type: "string", enum: ["claude", "opencode", "codex", "agy", "cursor", "hermes"] },
|
|
25889
26742
|
description: "Restrict to specific AI tools. Default: every tool this machine has."
|
|
25890
26743
|
},
|
|
25891
26744
|
group_by_repo: { type: "boolean", default: false, description: "Group results by detected git repo root." },
|
|
@@ -27846,7 +28699,7 @@ _Edits stayed local or window was off \u2014 try increasing buffer_minutes._` }]
|
|
|
27846
28699
|
}
|
|
27847
28700
|
case "recall_project_context": {
|
|
27848
28701
|
const params = RecallProjectContextSchema.parse(args);
|
|
27849
|
-
const target =
|
|
28702
|
+
const target = existsSync23(params.project_path) && statSync21(params.project_path).isDirectory() ? resolveProjectId(params.project_path).id : params.project_path;
|
|
27850
28703
|
const dossier = await remoteGetQS(`/api/projects/${encodeURIComponent(target)}/dossier`, { sessions: params.limit, tasks: params.tasks, plans: params.plans });
|
|
27851
28704
|
return { content: [{ type: "text", text: dossier.markdown }] };
|
|
27852
28705
|
}
|
|
@@ -28806,7 +29659,7 @@ Subject: ${params.subject}`;
|
|
|
28806
29659
|
const start = resolve2(p.path ?? process.cwd());
|
|
28807
29660
|
let root = start;
|
|
28808
29661
|
for (let dir = start, last = ""; dir && dir !== last; last = dir, dir = resolve2(dir, "..")) {
|
|
28809
|
-
if (
|
|
29662
|
+
if (existsSync23(join27(dir, ".git"))) {
|
|
28810
29663
|
root = dir;
|
|
28811
29664
|
break;
|
|
28812
29665
|
}
|
|
@@ -28963,7 +29816,7 @@ ${row.value}`
|
|
|
28963
29816
|
let identity = params.identity ?? "AI coding assistant";
|
|
28964
29817
|
if (!params.identity && !isMultiTenant()) {
|
|
28965
29818
|
const idFile = getIdentityFilePath();
|
|
28966
|
-
if (
|
|
29819
|
+
if (existsSync23(idFile)) {
|
|
28967
29820
|
try {
|
|
28968
29821
|
identity = readFileSync18(idFile, "utf-8").trim() || identity;
|
|
28969
29822
|
} catch {
|
|
@@ -29460,9 +30313,9 @@ function openBrowser(url) {
|
|
|
29460
30313
|
// src/mcp.ts
|
|
29461
30314
|
init_client_events();
|
|
29462
30315
|
init_update_notice();
|
|
29463
|
-
import { readFileSync as
|
|
30316
|
+
import { readFileSync as readFileSync44 } from "node:fs";
|
|
29464
30317
|
setServerVersion(JSON.parse(
|
|
29465
|
-
|
|
30318
|
+
readFileSync44(new URL("../package.json", import.meta.url), "utf-8")
|
|
29466
30319
|
).version);
|
|
29467
30320
|
setEventReporter(reportClientEvent2);
|
|
29468
30321
|
setIndexRunner(runIndexChild2);
|
|
@@ -29579,9 +30432,9 @@ var SYNC_TICK_MS = 3 * 6e4;
|
|
|
29579
30432
|
function startBackgroundSync() {
|
|
29580
30433
|
const tick = async (scope) => {
|
|
29581
30434
|
try {
|
|
29582
|
-
const { installedVersion:
|
|
30435
|
+
const { installedVersion: installedVersion3 } = await Promise.resolve().then(() => (init_auto_update(), auto_update_exports));
|
|
29583
30436
|
const { installedIsNewer: installedIsNewer2, runInstalledSync: runInstalledSync2 } = await Promise.resolve().then(() => (init_sync_delegate(), sync_delegate_exports));
|
|
29584
|
-
const installed =
|
|
30437
|
+
const installed = installedVersion3();
|
|
29585
30438
|
if (installedIsNewer2(RELAY_VERSION, installed)) {
|
|
29586
30439
|
const code = await runInstalledSync2(fileURLToPath5(new URL("./cli.js", import.meta.url)));
|
|
29587
30440
|
if (code !== 0) console.error(`[mcp] sync by the installed CLI ${installed} ended with ${code ?? "no exit code"}`);
|
|
@@ -29635,7 +30488,7 @@ function installCrashGuards() {
|
|
|
29635
30488
|
reportClientEvent2("mcp_crash", { message: err.stack || err.message });
|
|
29636
30489
|
});
|
|
29637
30490
|
}
|
|
29638
|
-
var RELAY_VERSION = true ? "0.7.
|
|
30491
|
+
var RELAY_VERSION = true ? "0.7.19" : "0.0.0";
|
|
29639
30492
|
function daemonIdleSecs() {
|
|
29640
30493
|
const raw = process.env.CHAT_RECALL_DAEMON_IDLE_SECS;
|
|
29641
30494
|
if (raw === void 0) return 900;
|
|
@@ -29731,8 +30584,25 @@ async function runDaemon() {
|
|
|
29731
30584
|
};
|
|
29732
30585
|
process.on("SIGTERM", shutdown);
|
|
29733
30586
|
process.on("SIGINT", shutdown);
|
|
30587
|
+
const upgradeTimer = setInterval(() => {
|
|
30588
|
+
const installed = installedVersion2();
|
|
30589
|
+
if (installed && RELAY_VERSION !== "0.0.0" && installed !== RELAY_VERSION) {
|
|
30590
|
+
console.error(`[mcp] v${installed} is installed; daemon v${RELAY_VERSION} is leaving`);
|
|
30591
|
+
clearInterval(upgradeTimer);
|
|
30592
|
+
shutdown();
|
|
30593
|
+
}
|
|
30594
|
+
}, 3e4);
|
|
30595
|
+
upgradeTimer.unref();
|
|
29734
30596
|
return true;
|
|
29735
30597
|
}
|
|
30598
|
+
function installedVersion2() {
|
|
30599
|
+
try {
|
|
30600
|
+
const pkg = JSON.parse(readFileSync44(new URL("../package.json", import.meta.url), "utf-8"));
|
|
30601
|
+
return typeof pkg.version === "string" ? pkg.version : null;
|
|
30602
|
+
} catch {
|
|
30603
|
+
return null;
|
|
30604
|
+
}
|
|
30605
|
+
}
|
|
29736
30606
|
async function main() {
|
|
29737
30607
|
installCrashGuards();
|
|
29738
30608
|
if (process.argv.includes("--daemon")) {
|