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/cli.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: join63 } = __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"] || join63(__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: join63, isAbsolute: isAbsolute4, sep: sep4 } = __require("node:path");
|
|
2484
2484
|
var sleep2 = 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"] || join63(__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"] || join63(__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 join63(__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 join63 = ",";
|
|
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
|
+
join63 = `,
|
|
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 += join63;
|
|
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 += `${join63}"... ${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
|
+
join63 = `,
|
|
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 = join63;
|
|
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 = join63;
|
|
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 join63 = ",";
|
|
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
|
+
join63 = `,
|
|
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 += join63;
|
|
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 += `${join63}"... ${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
|
+
join63 = `,
|
|
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 = join63;
|
|
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 join64 = `,
|
|
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 += join64;
|
|
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 += `${join64}"... ${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 join63 = `,
|
|
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, join63, maximumBreadth);
|
|
3828
3828
|
keys = keys.slice(value.length);
|
|
3829
3829
|
maximumPropertiesToStringify -= value.length;
|
|
3830
|
-
separator =
|
|
3830
|
+
separator = join63;
|
|
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 = join63;
|
|
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 = join63;
|
|
3848
3848
|
}
|
|
3849
3849
|
if (separator !== "") {
|
|
3850
3850
|
res = `
|
|
@@ -4586,6 +4586,8 @@ function declaredOrigin(value) {
|
|
|
4586
4586
|
function userRecordOrigin(obj, text) {
|
|
4587
4587
|
if (obj.isSidechain === true)
|
|
4588
4588
|
return "subagent";
|
|
4589
|
+
if (obj.isCompactSummary === true)
|
|
4590
|
+
return "compact-summary";
|
|
4589
4591
|
const declared = declaredOrigin(obj.origin);
|
|
4590
4592
|
if (declared && declared !== "human")
|
|
4591
4593
|
return declared;
|
|
@@ -4769,6 +4771,7 @@ function defaultSourcesEnabled() {
|
|
|
4769
4771
|
commands: true
|
|
4770
4772
|
},
|
|
4771
4773
|
cursor: { sessions: true, skills: true, agents: true, commands: true },
|
|
4774
|
+
hermes: { sessions: true },
|
|
4772
4775
|
shared: { skills: true },
|
|
4773
4776
|
common: { mcps: true, agentMd: true }
|
|
4774
4777
|
};
|
|
@@ -4845,6 +4848,7 @@ function mergeSources(base4, partial) {
|
|
|
4845
4848
|
codex: { ...base4.enabled.codex, ...partial.enabled?.codex ?? {} },
|
|
4846
4849
|
agy: { ...base4.enabled.agy, ...inherited, ...partial.enabled?.agy ?? {} },
|
|
4847
4850
|
cursor: { ...base4.enabled.cursor, ...partial.enabled?.cursor ?? {} },
|
|
4851
|
+
hermes: { ...base4.enabled.hermes, ...partial.enabled?.hermes ?? {} },
|
|
4848
4852
|
shared: { ...base4.enabled.shared, ...partial.enabled?.shared ?? {} },
|
|
4849
4853
|
common: { ...base4.enabled.common, ...partial.enabled?.common ?? {} }
|
|
4850
4854
|
};
|
|
@@ -4856,6 +4860,7 @@ function mergeSources(base4, partial) {
|
|
|
4856
4860
|
agyHome: partial.agyHome ?? base4.agyHome,
|
|
4857
4861
|
cursorHome: partial.cursorHome ?? base4.cursorHome,
|
|
4858
4862
|
cursorIdeHome: partial.cursorIdeHome ?? base4.cursorIdeHome,
|
|
4863
|
+
hermesHome: partial.hermesHome ?? base4.hermesHome,
|
|
4859
4864
|
extraClaudeHomes: partial.extraClaudeHomes ?? base4.extraClaudeHomes,
|
|
4860
4865
|
approvedHomes: partial.approvedHomes ?? base4.approvedHomes,
|
|
4861
4866
|
declinedHomes: partial.declinedHomes ?? base4.declinedHomes,
|
|
@@ -5180,6 +5185,7 @@ var home_approval_exports = {};
|
|
|
5180
5185
|
__export(home_approval_exports, {
|
|
5181
5186
|
approveHome: () => approveHome,
|
|
5182
5187
|
declineHome: () => declineHome,
|
|
5188
|
+
defaultHermesHome: () => defaultHermesHome,
|
|
5183
5189
|
grandfatherLegacyHomes: () => grandfatherLegacyHomes,
|
|
5184
5190
|
homeDecision: () => homeDecision,
|
|
5185
5191
|
isHomeSynced: () => isHomeSynced,
|
|
@@ -5262,6 +5268,13 @@ function grandfatherLegacyHomes() {
|
|
|
5262
5268
|
}
|
|
5263
5269
|
return { seeded };
|
|
5264
5270
|
}
|
|
5271
|
+
function defaultHermesHome() {
|
|
5272
|
+
if (process.platform === "win32") {
|
|
5273
|
+
const local = process.env.LOCALAPPDATA?.trim() || join3(homedir2(), "AppData", "Local");
|
|
5274
|
+
return join3(local, "hermes");
|
|
5275
|
+
}
|
|
5276
|
+
return join3(homedir2(), ".hermes");
|
|
5277
|
+
}
|
|
5265
5278
|
function primaryHomes() {
|
|
5266
5279
|
const home = homedir2();
|
|
5267
5280
|
const env = process.env;
|
|
@@ -5278,7 +5291,8 @@ function primaryHomes() {
|
|
|
5278
5291
|
env.CHAT_RECALL_CODEX_HOME || s?.codexHome || join3(home, ".codex"),
|
|
5279
5292
|
env.CHAT_RECALL_AGY_HOME || s?.agyHome || join3(home, ".gemini", "antigravity-cli"),
|
|
5280
5293
|
env.CHAT_RECALL_CURSOR_HOME || s?.cursorHome || join3(home, ".cursor"),
|
|
5281
|
-
dirOf(opencodeDb)
|
|
5294
|
+
dirOf(opencodeDb),
|
|
5295
|
+
env.CHAT_RECALL_HERMES_HOME || s?.hermesHome || env.HERMES_HOME?.trim() || defaultHermesHome()
|
|
5282
5296
|
];
|
|
5283
5297
|
return candidates2.map(normalizeHomePath);
|
|
5284
5298
|
}
|
|
@@ -5405,6 +5419,9 @@ function geminiHomeDir() {
|
|
|
5405
5419
|
function opencodeDbPath() {
|
|
5406
5420
|
return process.env.CHAT_RECALL_OPENCODE_DB || sources().opencodeDbPath || join4(homedir3(), ".local", "share", "opencode", "opencode.db");
|
|
5407
5421
|
}
|
|
5422
|
+
function hermesHomeDir() {
|
|
5423
|
+
return process.env.CHAT_RECALL_HERMES_HOME || sources().hermesHome || process.env.HERMES_HOME?.trim() || defaultHermesHome();
|
|
5424
|
+
}
|
|
5408
5425
|
function codexHomeDir() {
|
|
5409
5426
|
return process.env.CHAT_RECALL_CODEX_HOME || sources().codexHome || join4(homedir3(), ".codex");
|
|
5410
5427
|
}
|
|
@@ -5506,6 +5523,22 @@ function opencodeDbPaths(opts = {}) {
|
|
|
5506
5523
|
dbs.push(primary);
|
|
5507
5524
|
return applyExclusions(dbs, opts.includeExcluded);
|
|
5508
5525
|
}
|
|
5526
|
+
function hermesDbPaths(opts = {}) {
|
|
5527
|
+
const root = hermesHomeDir();
|
|
5528
|
+
const dbs = [join4(root, "state.db")];
|
|
5529
|
+
try {
|
|
5530
|
+
const profiles = join4(root, "profiles");
|
|
5531
|
+
for (const entry of readdirSync3(profiles, { withFileTypes: true })) {
|
|
5532
|
+
if (!entry.isDirectory())
|
|
5533
|
+
continue;
|
|
5534
|
+
const p = join4(profiles, entry.name, "state.db");
|
|
5535
|
+
if (existsSync4(p))
|
|
5536
|
+
dbs.push(p);
|
|
5537
|
+
}
|
|
5538
|
+
} catch {
|
|
5539
|
+
}
|
|
5540
|
+
return applyExclusions(dbs, opts.includeExcluded);
|
|
5541
|
+
}
|
|
5509
5542
|
function extraClaudeHomeDirs() {
|
|
5510
5543
|
const extras = sources().extraClaudeHomes ?? [];
|
|
5511
5544
|
const primary = claudeHomeDir();
|
|
@@ -6574,7 +6607,7 @@ function canonicalEventsToMessages(events) {
|
|
|
6574
6607
|
switch (e.kind) {
|
|
6575
6608
|
case "user":
|
|
6576
6609
|
cur = null;
|
|
6577
|
-
messages.push({ line: e.line, role: "user", content: e.text ?? "", timestamp: e.tsIso });
|
|
6610
|
+
messages.push({ line: e.line, role: "user", content: e.text ?? "", timestamp: e.tsIso, ...e.origin ? { origin: e.origin } : {} });
|
|
6578
6611
|
break;
|
|
6579
6612
|
case "assistant_text":
|
|
6580
6613
|
cur = { line: e.line, role: "assistant", content: e.text ?? "", timestamp: e.tsIso };
|
|
@@ -6617,6 +6650,7 @@ var init_from_events = __esm({
|
|
|
6617
6650
|
// ../engine/dist/transcript/raw.js
|
|
6618
6651
|
var raw_exports = {};
|
|
6619
6652
|
__export(raw_exports, {
|
|
6653
|
+
RAW_PARSE_MAX_BYTES: () => RAW_PARSE_MAX_BYTES,
|
|
6620
6654
|
archiveRawSession: () => archiveRawSession,
|
|
6621
6655
|
buildRawContainer: () => buildRawContainer,
|
|
6622
6656
|
containerSrcHash: () => containerSrcHash,
|
|
@@ -6916,11 +6950,11 @@ async function archiveRawSession(store, sessionId) {
|
|
|
6916
6950
|
return await store.putRawSession(sessionId, exp.tool, Math.floor(exp.mtime), gz, size);
|
|
6917
6951
|
}
|
|
6918
6952
|
function detectForkPredecessor(sessionPath) {
|
|
6919
|
-
const { readFileSync:
|
|
6920
|
-
const { dirname: dirname30, join:
|
|
6953
|
+
const { readFileSync: readFileSync51, readdirSync: readdirSync34 } = requireFs();
|
|
6954
|
+
const { dirname: dirname30, join: join63, basename: basename28 } = requirePath();
|
|
6921
6955
|
let text;
|
|
6922
6956
|
try {
|
|
6923
|
-
text =
|
|
6957
|
+
text = readFileSync51(sessionPath, "utf-8");
|
|
6924
6958
|
} catch {
|
|
6925
6959
|
return null;
|
|
6926
6960
|
}
|
|
@@ -6954,7 +6988,7 @@ function detectForkPredecessor(sessionPath) {
|
|
|
6954
6988
|
if (!f.endsWith(".jsonl") || f === self || f === "sessions-index.json")
|
|
6955
6989
|
continue;
|
|
6956
6990
|
try {
|
|
6957
|
-
if (
|
|
6991
|
+
if (readFileSync51(join63(dir, f), "utf-8").includes(`"uuid":"${headParent}"`)) {
|
|
6958
6992
|
return basename28(f, ".jsonl");
|
|
6959
6993
|
}
|
|
6960
6994
|
} catch {
|
|
@@ -6968,7 +7002,7 @@ function requireFs() {
|
|
|
6968
7002
|
function requirePath() {
|
|
6969
7003
|
return pathMod;
|
|
6970
7004
|
}
|
|
6971
|
-
var MARKER_QUOTE;
|
|
7005
|
+
var RAW_PARSE_MAX_BYTES, MARKER_QUOTE;
|
|
6972
7006
|
var init_raw = __esm({
|
|
6973
7007
|
"../engine/dist/transcript/raw.js"() {
|
|
6974
7008
|
"use strict";
|
|
@@ -6976,6 +7010,7 @@ var init_raw = __esm({
|
|
|
6976
7010
|
init_claude();
|
|
6977
7011
|
init_codex();
|
|
6978
7012
|
init_from_events();
|
|
7013
|
+
RAW_PARSE_MAX_BYTES = 40 * 1024 * 1024;
|
|
6979
7014
|
MARKER_QUOTE = /\[REDACTED:[A-Za-z0-9_-]+\]"/g;
|
|
6980
7015
|
}
|
|
6981
7016
|
});
|
|
@@ -8457,6 +8492,71 @@ function readTailFromOffset(path, offset, maxBytes = TAIL_READ_MAX_BYTES) {
|
|
|
8457
8492
|
}
|
|
8458
8493
|
}
|
|
8459
8494
|
}
|
|
8495
|
+
function readSourcesFromOffset(paths, offset, maxBytes = TAIL_READ_MAX_BYTES) {
|
|
8496
|
+
let start = 0;
|
|
8497
|
+
let linesBefore = 0;
|
|
8498
|
+
for (let i = 0; i < paths.length; i++) {
|
|
8499
|
+
const path = paths[i];
|
|
8500
|
+
let size = 0;
|
|
8501
|
+
try {
|
|
8502
|
+
size = statSync4(path).size;
|
|
8503
|
+
} catch {
|
|
8504
|
+
size = 0;
|
|
8505
|
+
}
|
|
8506
|
+
const last = i === paths.length - 1;
|
|
8507
|
+
if (!last && offset >= start + size) {
|
|
8508
|
+
const lines = linesBeforeOffset(path, size);
|
|
8509
|
+
if (lines === void 0)
|
|
8510
|
+
return { text: "", newOffset: offset };
|
|
8511
|
+
linesBefore += lines + (size > 0 && !endsWithNewline(path, size) ? 1 : 0);
|
|
8512
|
+
start += size;
|
|
8513
|
+
continue;
|
|
8514
|
+
}
|
|
8515
|
+
const local = offset - start;
|
|
8516
|
+
const read = readTailFromOffset(path, local, maxBytes);
|
|
8517
|
+
const shift = (r) => ({
|
|
8518
|
+
...r,
|
|
8519
|
+
newOffset: start + r.newOffset,
|
|
8520
|
+
...r.baseLine !== void 0 ? { baseLine: linesBefore + r.baseLine } : {}
|
|
8521
|
+
});
|
|
8522
|
+
if (last || read.newOffset > local || local >= size)
|
|
8523
|
+
return shift(read);
|
|
8524
|
+
if (size - local > maxBytes)
|
|
8525
|
+
return { text: "", newOffset: start + size, skippedBytes: size - local };
|
|
8526
|
+
let fd = null;
|
|
8527
|
+
try {
|
|
8528
|
+
fd = openSync2(path, "r");
|
|
8529
|
+
const text = readAt(fd, local, size - local).toString("utf-8");
|
|
8530
|
+
return shift({ text, newOffset: size, baseLine: linesBeforeOffset(path, local) });
|
|
8531
|
+
} catch {
|
|
8532
|
+
return { text: "", newOffset: offset };
|
|
8533
|
+
} finally {
|
|
8534
|
+
if (fd !== null) {
|
|
8535
|
+
try {
|
|
8536
|
+
closeSync2(fd);
|
|
8537
|
+
} catch {
|
|
8538
|
+
}
|
|
8539
|
+
}
|
|
8540
|
+
}
|
|
8541
|
+
}
|
|
8542
|
+
return { text: "", newOffset: offset };
|
|
8543
|
+
}
|
|
8544
|
+
function endsWithNewline(path, size) {
|
|
8545
|
+
let fd = null;
|
|
8546
|
+
try {
|
|
8547
|
+
fd = openSync2(path, "r");
|
|
8548
|
+
return readAt(fd, size - 1, 1)[0] === 10;
|
|
8549
|
+
} catch {
|
|
8550
|
+
return true;
|
|
8551
|
+
} finally {
|
|
8552
|
+
if (fd !== null) {
|
|
8553
|
+
try {
|
|
8554
|
+
closeSync2(fd);
|
|
8555
|
+
} catch {
|
|
8556
|
+
}
|
|
8557
|
+
}
|
|
8558
|
+
}
|
|
8559
|
+
}
|
|
8460
8560
|
function findNewline(fd, from, size) {
|
|
8461
8561
|
const block = Buffer.allocUnsafe(SKIP_SCAN_BYTES);
|
|
8462
8562
|
let pos = from;
|
|
@@ -10935,6 +11035,473 @@ var init_cursor = __esm({
|
|
|
10935
11035
|
}
|
|
10936
11036
|
});
|
|
10937
11037
|
|
|
11038
|
+
// ../engine/dist/core/backends/hermes.js
|
|
11039
|
+
import { existsSync as existsSync12 } from "fs";
|
|
11040
|
+
function firstUserPrompt(db, sessionId) {
|
|
11041
|
+
try {
|
|
11042
|
+
const row = db.prepare(`
|
|
11043
|
+
SELECT substr(content, 1, 400) AS text FROM messages
|
|
11044
|
+
WHERE session_id = ? AND role = 'user' AND active = 1 AND _compressed_summary = 0
|
|
11045
|
+
AND (display_kind IS NULL OR display_kind = 'steer')
|
|
11046
|
+
AND length(trim(content)) > 0
|
|
11047
|
+
ORDER BY id LIMIT 1
|
|
11048
|
+
`).get(sessionId);
|
|
11049
|
+
return row?.text ? flatString(row.text.slice(0, 200)) : "";
|
|
11050
|
+
} catch {
|
|
11051
|
+
return "";
|
|
11052
|
+
}
|
|
11053
|
+
}
|
|
11054
|
+
function messageRowsToEvents(rows) {
|
|
11055
|
+
const events = [];
|
|
11056
|
+
let line = 0;
|
|
11057
|
+
for (const r of rows) {
|
|
11058
|
+
line++;
|
|
11059
|
+
if (r.active === 0)
|
|
11060
|
+
continue;
|
|
11061
|
+
if (r.display_kind === "failed_turn" || r.display_kind === "hidden")
|
|
11062
|
+
continue;
|
|
11063
|
+
const ts = Math.round((r.timestamp || 0) * 1e3);
|
|
11064
|
+
const tsIso = ts ? new Date(ts).toISOString() : void 0;
|
|
11065
|
+
const text = (r.content ?? "").trim();
|
|
11066
|
+
if (r._compressed_summary === 1) {
|
|
11067
|
+
if (text)
|
|
11068
|
+
events.push({ kind: "summary", ts, tsIso, line, text });
|
|
11069
|
+
continue;
|
|
11070
|
+
}
|
|
11071
|
+
if (r.role === "user") {
|
|
11072
|
+
if (!text)
|
|
11073
|
+
continue;
|
|
11074
|
+
events.push({
|
|
11075
|
+
kind: "user",
|
|
11076
|
+
ts,
|
|
11077
|
+
tsIso,
|
|
11078
|
+
line,
|
|
11079
|
+
text,
|
|
11080
|
+
...r.display_kind === "process_complete" ? { origin: "task-notification" } : {}
|
|
11081
|
+
});
|
|
11082
|
+
continue;
|
|
11083
|
+
}
|
|
11084
|
+
if (r.role === "assistant") {
|
|
11085
|
+
if (text)
|
|
11086
|
+
events.push({ kind: "assistant_text", ts, tsIso, line, text });
|
|
11087
|
+
for (const call2 of parseToolCalls(r.tool_calls)) {
|
|
11088
|
+
const toolName = call2.function?.name ?? "";
|
|
11089
|
+
const toolInput = parseArguments(call2.function?.arguments);
|
|
11090
|
+
const command = toolName === "terminal" && typeof toolInput?.command === "string" ? toolInput.command : void 0;
|
|
11091
|
+
events.push({
|
|
11092
|
+
kind: "tool_use",
|
|
11093
|
+
ts,
|
|
11094
|
+
tsIso,
|
|
11095
|
+
line,
|
|
11096
|
+
toolName,
|
|
11097
|
+
toolUseId: call2.id || call2.call_id || `${r.id}:${toolName}`,
|
|
11098
|
+
toolInput,
|
|
11099
|
+
...command ? { command } : {}
|
|
11100
|
+
});
|
|
11101
|
+
}
|
|
11102
|
+
continue;
|
|
11103
|
+
}
|
|
11104
|
+
if (r.role === "tool") {
|
|
11105
|
+
const body2 = r.content ?? "";
|
|
11106
|
+
const { exitCode, isError } = toolResultStatus(body2);
|
|
11107
|
+
events.push({
|
|
11108
|
+
kind: "tool_result",
|
|
11109
|
+
ts,
|
|
11110
|
+
tsIso,
|
|
11111
|
+
line,
|
|
11112
|
+
toolUseId: r.tool_call_id ?? void 0,
|
|
11113
|
+
toolName: r.tool_name ?? void 0,
|
|
11114
|
+
resultBody: body2,
|
|
11115
|
+
resultIsError: isError,
|
|
11116
|
+
...exitCode !== void 0 ? { resultExitCode: exitCode } : {},
|
|
11117
|
+
resultBytes: Buffer.byteLength(body2)
|
|
11118
|
+
});
|
|
11119
|
+
}
|
|
11120
|
+
}
|
|
11121
|
+
return events;
|
|
11122
|
+
}
|
|
11123
|
+
function parseToolCalls(json) {
|
|
11124
|
+
if (!json)
|
|
11125
|
+
return [];
|
|
11126
|
+
try {
|
|
11127
|
+
const calls = JSON.parse(json);
|
|
11128
|
+
return Array.isArray(calls) ? calls : [];
|
|
11129
|
+
} catch {
|
|
11130
|
+
return [];
|
|
11131
|
+
}
|
|
11132
|
+
}
|
|
11133
|
+
function parseArguments(args) {
|
|
11134
|
+
if (typeof args !== "string")
|
|
11135
|
+
return args ?? {};
|
|
11136
|
+
try {
|
|
11137
|
+
return JSON.parse(args);
|
|
11138
|
+
} catch {
|
|
11139
|
+
return { raw: args };
|
|
11140
|
+
}
|
|
11141
|
+
}
|
|
11142
|
+
function toolResultStatus(body2) {
|
|
11143
|
+
if (!body2.startsWith("{"))
|
|
11144
|
+
return { isError: false };
|
|
11145
|
+
try {
|
|
11146
|
+
const r = JSON.parse(body2);
|
|
11147
|
+
const exitCode = typeof r.exit_code === "number" ? r.exit_code : void 0;
|
|
11148
|
+
const hasError = r.error !== void 0 && r.error !== null && r.error !== "";
|
|
11149
|
+
return { exitCode, isError: hasError || exitCode !== void 0 && exitCode !== 0 };
|
|
11150
|
+
} catch {
|
|
11151
|
+
return { isError: false };
|
|
11152
|
+
}
|
|
11153
|
+
}
|
|
11154
|
+
var PREFIX5, MESSAGE_COLUMNS, ARCHIVED_SESSION_COLUMNS, SESSION_MTIME_SQL, HermesBackend, hermesBackend;
|
|
11155
|
+
var init_hermes = __esm({
|
|
11156
|
+
"../engine/dist/core/backends/hermes.js"() {
|
|
11157
|
+
"use strict";
|
|
11158
|
+
init_sqlite_reader();
|
|
11159
|
+
init_tool_paths();
|
|
11160
|
+
init_session_outcome();
|
|
11161
|
+
init_session_git();
|
|
11162
|
+
init_generic_engine();
|
|
11163
|
+
init_flat_string();
|
|
11164
|
+
PREFIX5 = "hermes_";
|
|
11165
|
+
MESSAGE_COLUMNS = "id, role, content, tool_calls, tool_call_id, tool_name, timestamp, display_kind, active, _compressed_summary";
|
|
11166
|
+
ARCHIVED_SESSION_COLUMNS = [
|
|
11167
|
+
"id",
|
|
11168
|
+
"source",
|
|
11169
|
+
"title",
|
|
11170
|
+
"model",
|
|
11171
|
+
"cwd",
|
|
11172
|
+
"git_branch",
|
|
11173
|
+
"git_repo_root",
|
|
11174
|
+
"parent_session_id",
|
|
11175
|
+
"started_at",
|
|
11176
|
+
"ended_at",
|
|
11177
|
+
"end_reason",
|
|
11178
|
+
"message_count",
|
|
11179
|
+
"tool_call_count",
|
|
11180
|
+
"input_tokens",
|
|
11181
|
+
"output_tokens",
|
|
11182
|
+
"cache_read_tokens",
|
|
11183
|
+
"cache_write_tokens",
|
|
11184
|
+
"reasoning_tokens",
|
|
11185
|
+
"estimated_cost_usd",
|
|
11186
|
+
"actual_cost_usd"
|
|
11187
|
+
];
|
|
11188
|
+
SESSION_MTIME_SQL = `MAX(
|
|
11189
|
+
s.started_at,
|
|
11190
|
+
COALESCE(s.ended_at, 0),
|
|
11191
|
+
COALESCE(s.last_activity_at, 0),
|
|
11192
|
+
COALESCE((SELECT MAX(m.timestamp) FROM messages m WHERE m.session_id = s.id), 0)
|
|
11193
|
+
)`;
|
|
11194
|
+
HermesBackend = class {
|
|
11195
|
+
id = "hermes";
|
|
11196
|
+
idPrefix = PREFIX5;
|
|
11197
|
+
displayName = "Hermes";
|
|
11198
|
+
homeDir() {
|
|
11199
|
+
return hermesHomeDir();
|
|
11200
|
+
}
|
|
11201
|
+
/** Every Hermes database on this machine, the root profile first. */
|
|
11202
|
+
dbPaths() {
|
|
11203
|
+
return hermesDbPaths();
|
|
11204
|
+
}
|
|
11205
|
+
isAvailable() {
|
|
11206
|
+
return this.dbPaths().some((p) => existsSync12(p));
|
|
11207
|
+
}
|
|
11208
|
+
/** The database that holds this session. A session id is unique within a
|
|
11209
|
+
* database, and each named profile has its own. */
|
|
11210
|
+
dbPathFor(rawId) {
|
|
11211
|
+
const cached = this._dbForSession.get(rawId);
|
|
11212
|
+
if (cached)
|
|
11213
|
+
return cached;
|
|
11214
|
+
for (const path of this.dbPaths()) {
|
|
11215
|
+
const db = openSqliteReadonly(path);
|
|
11216
|
+
if (!db)
|
|
11217
|
+
continue;
|
|
11218
|
+
try {
|
|
11219
|
+
if (db.prepare("SELECT 1 AS ok FROM sessions WHERE id = ?").get(rawId)) {
|
|
11220
|
+
this._dbForSession.set(rawId, path);
|
|
11221
|
+
return path;
|
|
11222
|
+
}
|
|
11223
|
+
} catch {
|
|
11224
|
+
} finally {
|
|
11225
|
+
db.close();
|
|
11226
|
+
}
|
|
11227
|
+
}
|
|
11228
|
+
return null;
|
|
11229
|
+
}
|
|
11230
|
+
_dbForSession = /* @__PURE__ */ new Map();
|
|
11231
|
+
/** Tests, and anything that adds a profile mid-process. */
|
|
11232
|
+
_clearDbRouting() {
|
|
11233
|
+
this._dbForSession.clear();
|
|
11234
|
+
}
|
|
11235
|
+
// ── ID handling ────────────────────────────────────────────────
|
|
11236
|
+
matchesId(id) {
|
|
11237
|
+
return id.startsWith(PREFIX5);
|
|
11238
|
+
}
|
|
11239
|
+
toRawId(id) {
|
|
11240
|
+
return id.startsWith(PREFIX5) ? id.slice(PREFIX5.length) : id;
|
|
11241
|
+
}
|
|
11242
|
+
toPrefixedId(rawId) {
|
|
11243
|
+
return rawId.startsWith(PREFIX5) ? rawId : PREFIX5 + rawId;
|
|
11244
|
+
}
|
|
11245
|
+
// ── Location ───────────────────────────────────────────────────
|
|
11246
|
+
findSession(id) {
|
|
11247
|
+
const rawId = this.toRawId(id);
|
|
11248
|
+
const path = this.dbPathFor(rawId);
|
|
11249
|
+
if (!path)
|
|
11250
|
+
return null;
|
|
11251
|
+
const db = openSqliteReadonly(path);
|
|
11252
|
+
if (!db)
|
|
11253
|
+
return null;
|
|
11254
|
+
try {
|
|
11255
|
+
const row = db.prepare(`
|
|
11256
|
+
SELECT s.cwd, s.git_repo_root, ${SESSION_MTIME_SQL} AS mtime
|
|
11257
|
+
FROM sessions s WHERE s.id = ?
|
|
11258
|
+
`).get(rawId);
|
|
11259
|
+
if (!row)
|
|
11260
|
+
return null;
|
|
11261
|
+
return {
|
|
11262
|
+
path,
|
|
11263
|
+
format: "sqlite",
|
|
11264
|
+
projectDir: "",
|
|
11265
|
+
projectPath: row.git_repo_root || row.cwd || "",
|
|
11266
|
+
mtime: Math.round((row.mtime || 0) * 1e3)
|
|
11267
|
+
};
|
|
11268
|
+
} catch {
|
|
11269
|
+
return null;
|
|
11270
|
+
} finally {
|
|
11271
|
+
db.close();
|
|
11272
|
+
}
|
|
11273
|
+
}
|
|
11274
|
+
listSessions(opts = {}) {
|
|
11275
|
+
const byId = /* @__PURE__ */ new Map();
|
|
11276
|
+
for (const dbPath of this.dbPaths()) {
|
|
11277
|
+
if (!existsSync12(dbPath))
|
|
11278
|
+
continue;
|
|
11279
|
+
for (const ref of this.listSessionsInDb(dbPath, opts)) {
|
|
11280
|
+
const prior = byId.get(ref.rawId);
|
|
11281
|
+
if (!prior || ref.mtime > prior.mtime)
|
|
11282
|
+
byId.set(ref.rawId, ref);
|
|
11283
|
+
}
|
|
11284
|
+
}
|
|
11285
|
+
const all = [...byId.values()].sort((a, b) => b.mtime - a.mtime);
|
|
11286
|
+
return opts.limit ? all.slice(0, opts.limit) : all;
|
|
11287
|
+
}
|
|
11288
|
+
listSessionsInDb(dbPath, opts) {
|
|
11289
|
+
const cutoffSec = (opts.sinceMs ?? 0) / 1e3;
|
|
11290
|
+
const filter = opts.projectFilter?.toLowerCase();
|
|
11291
|
+
const db = openSqliteReadonly(dbPath);
|
|
11292
|
+
if (!db)
|
|
11293
|
+
return [];
|
|
11294
|
+
try {
|
|
11295
|
+
const rows = db.prepare(`
|
|
11296
|
+
SELECT * FROM (
|
|
11297
|
+
SELECT s.id, s.cwd, s.git_repo_root, s.started_at, s.message_count,
|
|
11298
|
+
${SESSION_MTIME_SQL} AS mtime
|
|
11299
|
+
FROM sessions s
|
|
11300
|
+
) WHERE mtime >= ? ORDER BY mtime DESC
|
|
11301
|
+
`).all(cutoffSec);
|
|
11302
|
+
const out = [];
|
|
11303
|
+
for (const row of rows) {
|
|
11304
|
+
const projectPath = row.git_repo_root || row.cwd || "";
|
|
11305
|
+
if (filter && !projectPath.toLowerCase().includes(filter))
|
|
11306
|
+
continue;
|
|
11307
|
+
const mtime = Math.round(row.mtime * 1e3);
|
|
11308
|
+
this._dbForSession.set(row.id, dbPath);
|
|
11309
|
+
out.push({
|
|
11310
|
+
toolId: "hermes",
|
|
11311
|
+
rawId: row.id,
|
|
11312
|
+
prefixedId: this.toPrefixedId(row.id),
|
|
11313
|
+
projectPath,
|
|
11314
|
+
projectDir: "",
|
|
11315
|
+
fullPath: dbPath,
|
|
11316
|
+
created: new Date(Math.round(row.started_at * 1e3)).toISOString(),
|
|
11317
|
+
modified: new Date(mtime).toISOString(),
|
|
11318
|
+
mtime,
|
|
11319
|
+
firstPrompt: opts.previews === false ? "" : firstUserPrompt(db, row.id),
|
|
11320
|
+
messageCount: opts.previews === false ? 0 : row.message_count ?? 0
|
|
11321
|
+
});
|
|
11322
|
+
if (opts.limit && out.length >= opts.limit)
|
|
11323
|
+
break;
|
|
11324
|
+
}
|
|
11325
|
+
return out;
|
|
11326
|
+
} catch {
|
|
11327
|
+
return [];
|
|
11328
|
+
} finally {
|
|
11329
|
+
db.close();
|
|
11330
|
+
}
|
|
11331
|
+
}
|
|
11332
|
+
/** Hermes writes a title for each session (a model-written one, or the
|
|
11333
|
+
* first prompt for a one-shot run). */
|
|
11334
|
+
getNativeTitle(rawId) {
|
|
11335
|
+
const path = this.dbPathFor(this.toRawId(rawId));
|
|
11336
|
+
if (!path)
|
|
11337
|
+
return null;
|
|
11338
|
+
const db = openSqliteReadonly(path);
|
|
11339
|
+
if (!db)
|
|
11340
|
+
return null;
|
|
11341
|
+
try {
|
|
11342
|
+
const row = db.prepare("SELECT title FROM sessions WHERE id = ?").get(this.toRawId(rawId));
|
|
11343
|
+
const t = row?.title?.trim();
|
|
11344
|
+
return t ? t.slice(0, 200) : null;
|
|
11345
|
+
} catch {
|
|
11346
|
+
return null;
|
|
11347
|
+
} finally {
|
|
11348
|
+
db.close();
|
|
11349
|
+
}
|
|
11350
|
+
}
|
|
11351
|
+
// ── Generic-engine inputs ───────────────────────────────────────
|
|
11352
|
+
fileToolMap = {
|
|
11353
|
+
write_file: "write",
|
|
11354
|
+
patch: "edit",
|
|
11355
|
+
read_file: "read"
|
|
11356
|
+
};
|
|
11357
|
+
/**
|
|
11358
|
+
* `write_file` carries `{ path, content }`. `patch` carries
|
|
11359
|
+
* `{ mode: 'replace', path, old_string, new_string }`; its other mode,
|
|
11360
|
+
* `patch`, is a multi-file V4A patch with no single before and after.
|
|
11361
|
+
*/
|
|
11362
|
+
extractEditDelta(toolName, input) {
|
|
11363
|
+
if (input == null || typeof input !== "object")
|
|
11364
|
+
return null;
|
|
11365
|
+
const inp = input;
|
|
11366
|
+
if (toolName === "write_file") {
|
|
11367
|
+
return { before: "", after: typeof inp.content === "string" ? inp.content : null };
|
|
11368
|
+
}
|
|
11369
|
+
if (toolName === "patch" && (inp.mode === void 0 || inp.mode === "replace")) {
|
|
11370
|
+
const before = typeof inp.old_string === "string" ? inp.old_string : null;
|
|
11371
|
+
const after = typeof inp.new_string === "string" ? inp.new_string : null;
|
|
11372
|
+
if (before === null && after === null)
|
|
11373
|
+
return null;
|
|
11374
|
+
return { before, after };
|
|
11375
|
+
}
|
|
11376
|
+
return null;
|
|
11377
|
+
}
|
|
11378
|
+
readEvents(rawId) {
|
|
11379
|
+
const id = this.toRawId(rawId);
|
|
11380
|
+
const path = this.dbPathFor(id);
|
|
11381
|
+
if (!path)
|
|
11382
|
+
return [];
|
|
11383
|
+
const db = openSqliteReadonly(path);
|
|
11384
|
+
if (!db)
|
|
11385
|
+
return [];
|
|
11386
|
+
try {
|
|
11387
|
+
const rows = db.prepare(`SELECT ${MESSAGE_COLUMNS} FROM messages WHERE session_id = ? ORDER BY id`).all(id);
|
|
11388
|
+
return messageRowsToEvents(rows);
|
|
11389
|
+
} catch {
|
|
11390
|
+
return [];
|
|
11391
|
+
} finally {
|
|
11392
|
+
db.close();
|
|
11393
|
+
}
|
|
11394
|
+
}
|
|
11395
|
+
/**
|
|
11396
|
+
* Events from the dump `exportRawSession` writes, for a session rebuilt from
|
|
11397
|
+
* the server's archive. The archive joins the lines of every dump it got, so
|
|
11398
|
+
* a row that changed (a rewind sets `active` to 0) is there more than once.
|
|
11399
|
+
* The last copy of each row id is the newest.
|
|
11400
|
+
*/
|
|
11401
|
+
readEventsFromText(text) {
|
|
11402
|
+
const rows = /* @__PURE__ */ new Map();
|
|
11403
|
+
for (const line of text.split("\n")) {
|
|
11404
|
+
if (!line.trim())
|
|
11405
|
+
continue;
|
|
11406
|
+
try {
|
|
11407
|
+
const rec = JSON.parse(line);
|
|
11408
|
+
if (rec.kind === "message" && rec.row) {
|
|
11409
|
+
rows.delete(rec.row.id);
|
|
11410
|
+
rows.set(rec.row.id, rec.row);
|
|
11411
|
+
}
|
|
11412
|
+
} catch {
|
|
11413
|
+
}
|
|
11414
|
+
}
|
|
11415
|
+
return messageRowsToEvents([...rows.values()].sort((a, b) => a.id - b.id));
|
|
11416
|
+
}
|
|
11417
|
+
// ── Per-session operations — all delegate to the generic engine ─
|
|
11418
|
+
extractTurns(id, opts = {}) {
|
|
11419
|
+
return extractTurnsFromEvents(this.toPrefixedId(id), this.readEvents(id), opts);
|
|
11420
|
+
}
|
|
11421
|
+
liveScanEdits(id) {
|
|
11422
|
+
const located = this.findSession(id);
|
|
11423
|
+
if (!located) {
|
|
11424
|
+
return { found: false, projectPath: "", projectDir: "", edits: [], fileMtime: 0, tool: "hermes" };
|
|
11425
|
+
}
|
|
11426
|
+
return liveScanEditsFromEvents(this.readEvents(id), this.fileToolMap, {
|
|
11427
|
+
sessionId: this.toPrefixedId(id),
|
|
11428
|
+
tool: "hermes",
|
|
11429
|
+
projectPath: located.projectPath,
|
|
11430
|
+
projectDir: located.projectDir,
|
|
11431
|
+
fileMtime: located.mtime,
|
|
11432
|
+
found: true
|
|
11433
|
+
});
|
|
11434
|
+
}
|
|
11435
|
+
replay(id) {
|
|
11436
|
+
const located = this.findSession(id);
|
|
11437
|
+
if (!located) {
|
|
11438
|
+
return { sessionId: this.toPrefixedId(id), found: false, projectPath: "", files: [], totalLinesAdded: 0, totalLinesRemoved: 0 };
|
|
11439
|
+
}
|
|
11440
|
+
return replayFromEvents(this.toPrefixedId(id), this.readEvents(id), this.fileToolMap, this.extractEditDelta.bind(this), {
|
|
11441
|
+
projectPath: located.projectPath,
|
|
11442
|
+
found: true
|
|
11443
|
+
});
|
|
11444
|
+
}
|
|
11445
|
+
computeOutcome(id, opts) {
|
|
11446
|
+
return computeOutcome(this.toPrefixedId(id), opts);
|
|
11447
|
+
}
|
|
11448
|
+
/** File edits since `sinceMs` across the sessions active since then. */
|
|
11449
|
+
collectRecentEdits(opts) {
|
|
11450
|
+
const refs = this.listSessions({ sinceMs: opts.sinceMs, projectFilter: opts.projectFilter, previews: false });
|
|
11451
|
+
const edits = [];
|
|
11452
|
+
for (const ref of opts.limitSessions ? refs.slice(0, opts.limitSessions) : refs) {
|
|
11453
|
+
for (const e of this.liveScanEdits(ref.rawId).edits) {
|
|
11454
|
+
if (e.ts >= opts.sinceMs)
|
|
11455
|
+
edits.push(e);
|
|
11456
|
+
}
|
|
11457
|
+
}
|
|
11458
|
+
return edits.sort((a, b) => b.ts - a.ts);
|
|
11459
|
+
}
|
|
11460
|
+
getCommits(id, files, startMs, endMs, bufferMinutes) {
|
|
11461
|
+
return getSessionCommits(this.toPrefixedId(id), files, startMs, endMs, bufferMinutes);
|
|
11462
|
+
}
|
|
11463
|
+
/**
|
|
11464
|
+
* The session row and its messages as JSONL, one row per line in id order.
|
|
11465
|
+
* Hermes rewrites and compacts its database, so the archive keeps the rows
|
|
11466
|
+
* as they were synced.
|
|
11467
|
+
*/
|
|
11468
|
+
exportRawSession(id) {
|
|
11469
|
+
const rawId = this.toRawId(id);
|
|
11470
|
+
const path = this.dbPathFor(rawId);
|
|
11471
|
+
if (!path)
|
|
11472
|
+
return null;
|
|
11473
|
+
const db = openSqliteReadonly(path);
|
|
11474
|
+
if (!db)
|
|
11475
|
+
return null;
|
|
11476
|
+
try {
|
|
11477
|
+
const have = new Set(db.prepare(`SELECT name FROM pragma_table_info('sessions')`).all().map((c) => c.name));
|
|
11478
|
+
const cols = ARCHIVED_SESSION_COLUMNS.filter((c) => have.has(c)).map((c) => `s.${c}`);
|
|
11479
|
+
const session = db.prepare(`
|
|
11480
|
+
SELECT ${[...cols, `${SESSION_MTIME_SQL} AS mtime`].join(", ")}
|
|
11481
|
+
FROM sessions s WHERE s.id = ?
|
|
11482
|
+
`).get(rawId);
|
|
11483
|
+
if (!session)
|
|
11484
|
+
return null;
|
|
11485
|
+
const rows = db.prepare(`SELECT ${MESSAGE_COLUMNS} FROM messages WHERE session_id = ? ORDER BY id`).all(rawId);
|
|
11486
|
+
const lines = [JSON.stringify({ kind: "session", row: session })];
|
|
11487
|
+
for (const r of rows)
|
|
11488
|
+
lines.push(JSON.stringify({ kind: "message", row: r }));
|
|
11489
|
+
return {
|
|
11490
|
+
tool: "hermes",
|
|
11491
|
+
mtime: Math.round(Number(session.mtime || 0) * 1e3),
|
|
11492
|
+
files: [{ name: `${rawId}.dump.jsonl`, bytes: Buffer.from(lines.join("\n") + "\n", "utf-8") }]
|
|
11493
|
+
};
|
|
11494
|
+
} catch {
|
|
11495
|
+
return null;
|
|
11496
|
+
} finally {
|
|
11497
|
+
db.close();
|
|
11498
|
+
}
|
|
11499
|
+
}
|
|
11500
|
+
};
|
|
11501
|
+
hermesBackend = new HermesBackend();
|
|
11502
|
+
}
|
|
11503
|
+
});
|
|
11504
|
+
|
|
10938
11505
|
// ../engine/dist/core/backends/index.js
|
|
10939
11506
|
var backends_exports = {};
|
|
10940
11507
|
__export(backends_exports, {
|
|
@@ -10942,6 +11509,7 @@ __export(backends_exports, {
|
|
|
10942
11509
|
ClaudeBackend: () => ClaudeBackend,
|
|
10943
11510
|
CodexBackend: () => CodexBackend,
|
|
10944
11511
|
CursorBackend: () => CursorBackend,
|
|
11512
|
+
HermesBackend: () => HermesBackend,
|
|
10945
11513
|
OpencodeBackend: () => OpencodeBackend,
|
|
10946
11514
|
agyBackend: () => agyBackend,
|
|
10947
11515
|
bootstrapBackends: () => bootstrapBackends,
|
|
@@ -10950,6 +11518,7 @@ __export(backends_exports, {
|
|
|
10950
11518
|
cursorBackend: () => cursorBackend,
|
|
10951
11519
|
getBackend: () => getBackend,
|
|
10952
11520
|
getBackendForId: () => getBackendForId,
|
|
11521
|
+
hermesBackend: () => hermesBackend,
|
|
10953
11522
|
listAllBackends: () => listAllBackends,
|
|
10954
11523
|
listAvailableBackends: () => listAvailableBackends,
|
|
10955
11524
|
opencodeBackend: () => opencodeBackend,
|
|
@@ -10962,6 +11531,7 @@ function bootstrapBackends() {
|
|
|
10962
11531
|
registerBackend(codexBackend);
|
|
10963
11532
|
registerBackend(agyBackend);
|
|
10964
11533
|
registerBackend(cursorBackend);
|
|
11534
|
+
registerBackend(hermesBackend);
|
|
10965
11535
|
}
|
|
10966
11536
|
var init_backends = __esm({
|
|
10967
11537
|
"../engine/dist/core/backends/index.js"() {
|
|
@@ -10972,6 +11542,7 @@ var init_backends = __esm({
|
|
|
10972
11542
|
init_codex2();
|
|
10973
11543
|
init_agy();
|
|
10974
11544
|
init_cursor();
|
|
11545
|
+
init_hermes();
|
|
10975
11546
|
init_tool_backend();
|
|
10976
11547
|
_setRegistryBootstrapper(bootstrapBackends);
|
|
10977
11548
|
}
|
|
@@ -10980,7 +11551,7 @@ var init_backends = __esm({
|
|
|
10980
11551
|
// ../engine/dist/transcript/shadow.js
|
|
10981
11552
|
import { gzipSync as gzipSync2, gunzipSync as gunzipSync2 } from "zlib";
|
|
10982
11553
|
import { createHash as createHash2 } from "crypto";
|
|
10983
|
-
import { existsSync as
|
|
11554
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync3, readFileSync as readFileSync8, writeFileSync as writeFileSync2, renameSync as renameSync2, statSync as statSync10, openSync as openSync4, readSync as readSync4, closeSync as closeSync4 } from "fs";
|
|
10984
11555
|
import { dirname as dirname12, join as join14 } from "path";
|
|
10985
11556
|
function shadowRoot() {
|
|
10986
11557
|
return join14(getDataDir(), "shadow");
|
|
@@ -10991,7 +11562,7 @@ function shadowFileFor(tool, rawId) {
|
|
|
10991
11562
|
}
|
|
10992
11563
|
function readShadowContainer(tool, rawId) {
|
|
10993
11564
|
const path = shadowFileFor(tool, rawId);
|
|
10994
|
-
if (!
|
|
11565
|
+
if (!existsSync13(path))
|
|
10995
11566
|
return null;
|
|
10996
11567
|
try {
|
|
10997
11568
|
const c = JSON.parse(gunzipSync2(readFileSync8(path)).toString("utf-8"));
|
|
@@ -11249,7 +11820,7 @@ var init_shadow = __esm({
|
|
|
11249
11820
|
});
|
|
11250
11821
|
|
|
11251
11822
|
// ../engine/dist/core/live-session-scan.js
|
|
11252
|
-
import { existsSync as
|
|
11823
|
+
import { existsSync as existsSync14, readdirSync as readdirSync10, readFileSync as readFileSync9, statSync as statSync11, openSync as openSync5, readSync as readSync5, closeSync as closeSync5 } from "fs";
|
|
11253
11824
|
import { join as join15, basename as basename9 } from "path";
|
|
11254
11825
|
function detectTool(sessionId) {
|
|
11255
11826
|
return getBackendForId(sessionId)?.id ?? "claude";
|
|
@@ -11306,7 +11877,7 @@ function sessionFileIndex() {
|
|
|
11306
11877
|
return p;
|
|
11307
11878
|
};
|
|
11308
11879
|
for (const root of roots) {
|
|
11309
|
-
if (seenRoots.has(root) || !
|
|
11880
|
+
if (seenRoots.has(root) || !existsSync14(root))
|
|
11310
11881
|
continue;
|
|
11311
11882
|
seenRoots.add(root);
|
|
11312
11883
|
dirs.set(root, dirMtime(root));
|
|
@@ -11432,7 +12003,7 @@ function resolveSessionContentPaths(sessionFile) {
|
|
|
11432
12003
|
if (!hasSubagentsDir(sessionFile))
|
|
11433
12004
|
return [sessionFile];
|
|
11434
12005
|
const subDir = join15(sessionFile.slice(0, -6), "subagents");
|
|
11435
|
-
if (!
|
|
12006
|
+
if (!existsSync14(subDir))
|
|
11436
12007
|
return [sessionFile];
|
|
11437
12008
|
const subPaths = readdirSync10(subDir).filter((f) => f.endsWith(".jsonl")).sort().map((f) => join15(subDir, f));
|
|
11438
12009
|
return [sessionFile, ...subPaths];
|
|
@@ -11449,7 +12020,7 @@ function findCodexSessionFile(sessionId) {
|
|
|
11449
12020
|
return null;
|
|
11450
12021
|
}
|
|
11451
12022
|
function findCodexSessionFileIn(root, sessionId) {
|
|
11452
|
-
if (!
|
|
12023
|
+
if (!existsSync14(root))
|
|
11453
12024
|
return null;
|
|
11454
12025
|
for (const year of readdirSync10(root, { withFileTypes: true })) {
|
|
11455
12026
|
if (!year.isDirectory())
|
|
@@ -11532,7 +12103,7 @@ var init_live_session_scan = __esm({
|
|
|
11532
12103
|
});
|
|
11533
12104
|
|
|
11534
12105
|
// ../engine/dist/core/first-prompt.js
|
|
11535
|
-
import { createReadStream as createReadStream2, existsSync as
|
|
12106
|
+
import { createReadStream as createReadStream2, existsSync as existsSync15, openSync as openSync6, readSync as readSync6, closeSync as closeSync6 } from "fs";
|
|
11536
12107
|
import { StringDecoder } from "string_decoder";
|
|
11537
12108
|
function stripBanners2(s) {
|
|
11538
12109
|
let out = s;
|
|
@@ -11643,7 +12214,7 @@ var init_first_prompt = __esm({
|
|
|
11643
12214
|
});
|
|
11644
12215
|
|
|
11645
12216
|
// ../engine/dist/core/backends/claude.js
|
|
11646
|
-
import { existsSync as
|
|
12217
|
+
import { existsSync as existsSync16, readdirSync as readdirSync11, readFileSync as readFileSync10, statSync as statSync12, openSync as openSync7, readSync as readSync7, closeSync as closeSync7 } from "fs";
|
|
11647
12218
|
import { join as join16, basename as basename10 } from "path";
|
|
11648
12219
|
function stripReminders(text) {
|
|
11649
12220
|
return text.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g, "").trim();
|
|
@@ -11713,7 +12284,7 @@ var init_claude2 = __esm({
|
|
|
11713
12284
|
return join16(this.homeDir(), "history.jsonl");
|
|
11714
12285
|
}
|
|
11715
12286
|
isAvailable() {
|
|
11716
|
-
return
|
|
12287
|
+
return existsSync16(this.projectsDir());
|
|
11717
12288
|
}
|
|
11718
12289
|
// ── ID handling ────────────────────────────────────────────────
|
|
11719
12290
|
/**
|
|
@@ -11819,7 +12390,7 @@ var init_claude2 = __esm({
|
|
|
11819
12390
|
prior.modified = ref.modified;
|
|
11820
12391
|
}
|
|
11821
12392
|
};
|
|
11822
|
-
if (!
|
|
12393
|
+
if (!existsSync16(root))
|
|
11823
12394
|
return;
|
|
11824
12395
|
for (const proj of readdirSync11(root, { withFileTypes: true })) {
|
|
11825
12396
|
if (!proj.isDirectory())
|
|
@@ -11830,12 +12401,12 @@ var init_claude2 = __esm({
|
|
|
11830
12401
|
const projectPath = resolveProjectDirName(proj.name);
|
|
11831
12402
|
const indexPath = join16(projPath, "sessions-index.json");
|
|
11832
12403
|
const indexed = /* @__PURE__ */ new Set();
|
|
11833
|
-
if (
|
|
12404
|
+
if (existsSync16(indexPath)) {
|
|
11834
12405
|
try {
|
|
11835
12406
|
const indexData = JSON.parse(readFileSync10(indexPath, "utf-8"));
|
|
11836
12407
|
const entries = indexData.entries || [];
|
|
11837
12408
|
for (const entry of entries) {
|
|
11838
|
-
if (!entry.fullPath || !
|
|
12409
|
+
if (!entry.fullPath || !existsSync16(entry.fullPath))
|
|
11839
12410
|
continue;
|
|
11840
12411
|
indexed.add(entry.sessionId);
|
|
11841
12412
|
add({
|
|
@@ -12160,7 +12731,7 @@ var init_claude2 = __esm({
|
|
|
12160
12731
|
collectRecentEdits(opts) {
|
|
12161
12732
|
const candidates2 = [];
|
|
12162
12733
|
for (const root of claudeProjectDirs()) {
|
|
12163
|
-
if (!
|
|
12734
|
+
if (!existsSync16(root))
|
|
12164
12735
|
continue;
|
|
12165
12736
|
for (const projEntry of readdirSync11(root, { withFileTypes: true })) {
|
|
12166
12737
|
if (!projEntry.isDirectory())
|
|
@@ -12182,7 +12753,7 @@ var init_claude2 = __esm({
|
|
|
12182
12753
|
const st = statSync12(fp);
|
|
12183
12754
|
let mtime = st.mtimeMs;
|
|
12184
12755
|
const subDir = join16(projPath, f.slice(0, -6), "subagents");
|
|
12185
|
-
if (
|
|
12756
|
+
if (existsSync16(subDir)) {
|
|
12186
12757
|
for (const sub of readdirSync11(subDir)) {
|
|
12187
12758
|
try {
|
|
12188
12759
|
const subSt = statSync12(join16(subDir, sub));
|
|
@@ -12259,27 +12830,45 @@ var init_claude2 = __esm({
|
|
|
12259
12830
|
/**
|
|
12260
12831
|
* True when this session exists in MORE THAN ONE home.
|
|
12261
12832
|
*
|
|
12262
|
-
* Such a session cannot be tail-appended: `fileSize()` is the SUM across
|
|
12263
|
-
* copies while a byte offset addresses ONE file, so the two disagree by
|
|
12264
|
-
* construction and the "tail" is either empty or the wrong bytes. The caller
|
|
12265
|
-
* uses this to force a FULL sync, which ships the unioned container and is
|
|
12266
|
-
* correct regardless of how the halves are arranged.
|
|
12267
|
-
*
|
|
12268
12833
|
* Measured on ec05f266: ~/.claude 1715 records, ~/.claude-work 205 records,
|
|
12269
|
-
* zero overlap.
|
|
12270
|
-
*
|
|
12834
|
+
* zero overlap. `fileSize()` is the sum across the copies, and
|
|
12835
|
+
* `readFromOffset()` reads them joined end to end, primary first.
|
|
12271
12836
|
*/
|
|
12272
12837
|
spansMultipleSources(prefixedId) {
|
|
12273
12838
|
return findSessionFiles(this.toRawId(prefixedId)).length > 1;
|
|
12274
12839
|
}
|
|
12840
|
+
/**
|
|
12841
|
+
* The copies before the last one, each with its size. Claude Code writes to
|
|
12842
|
+
* the home of the profile that runs the session, so the live copy can grow,
|
|
12843
|
+
* appear, vanish or merge back into the primary. Each of those moves bytes
|
|
12844
|
+
* under an offset into the joined copies; this key changes with all of them.
|
|
12845
|
+
*/
|
|
12846
|
+
sourceLayout(prefixedId) {
|
|
12847
|
+
const copies = findSessionFiles(this.toRawId(prefixedId));
|
|
12848
|
+
if (copies.length < 2)
|
|
12849
|
+
return "";
|
|
12850
|
+
return copies.slice(0, -1).map((c) => {
|
|
12851
|
+
let size = -1;
|
|
12852
|
+
try {
|
|
12853
|
+
size = statSync12(c.path).size;
|
|
12854
|
+
} catch {
|
|
12855
|
+
}
|
|
12856
|
+
return `${c.path}:${size}`;
|
|
12857
|
+
}).join("|");
|
|
12858
|
+
}
|
|
12859
|
+
/**
|
|
12860
|
+
* Session 8de13d0a had 31 MB in ~/.claude and 2 MB in ~/.claude-work. Over
|
|
12861
|
+
* the 24 MB build ceiling a sync ships the transcript in chunks read here,
|
|
12862
|
+
* and this returned no text for a session in two homes. Each sync shipped
|
|
12863
|
+
* nothing, and the server stayed three hours behind.
|
|
12864
|
+
*/
|
|
12275
12865
|
async readFromOffset(prefixedId, offset, maxBytes) {
|
|
12276
|
-
const
|
|
12277
|
-
const copies = findSessionFiles(rawId);
|
|
12866
|
+
const copies = findSessionFiles(this.toRawId(prefixedId));
|
|
12278
12867
|
if (copies.length === 0)
|
|
12279
12868
|
return { text: "", newOffset: offset };
|
|
12280
|
-
if (copies.length
|
|
12281
|
-
return
|
|
12282
|
-
return
|
|
12869
|
+
if (copies.length === 1)
|
|
12870
|
+
return readTailFromOffset(copies[0].path, offset, maxBytes);
|
|
12871
|
+
return readSourcesFromOffset(copies.map((c) => c.path), offset, maxBytes);
|
|
12283
12872
|
}
|
|
12284
12873
|
};
|
|
12285
12874
|
claudeBackend = new ClaudeBackend();
|
|
@@ -12300,7 +12889,7 @@ __export(project_resolver_exports, {
|
|
|
12300
12889
|
});
|
|
12301
12890
|
import { execSync } from "child_process";
|
|
12302
12891
|
import { createHash as createHash3 } from "crypto";
|
|
12303
|
-
import { existsSync as
|
|
12892
|
+
import { existsSync as existsSync17, readFileSync as readFileSync11, realpathSync as realpathSync2, readdirSync as readdirSync12, statSync as statSync13 } from "fs";
|
|
12304
12893
|
import { basename as basename11, dirname as dirname13, isAbsolute, join as join17, resolve, sep } from "path";
|
|
12305
12894
|
function getProjectsConfigPath() {
|
|
12306
12895
|
return join17(getDataDir(), "projects.json");
|
|
@@ -12310,7 +12899,7 @@ function loadProjectsConfig() {
|
|
|
12310
12899
|
return cachedConfig.cfg;
|
|
12311
12900
|
}
|
|
12312
12901
|
const path = getProjectsConfigPath();
|
|
12313
|
-
if (!
|
|
12902
|
+
if (!existsSync17(path)) {
|
|
12314
12903
|
cachedConfig = { mtime: 0, cfg: {} };
|
|
12315
12904
|
return cachedConfig.cfg;
|
|
12316
12905
|
}
|
|
@@ -12484,7 +13073,7 @@ function findGitToplevel(realPath) {
|
|
|
12484
13073
|
let cur = realPath;
|
|
12485
13074
|
let last = "";
|
|
12486
13075
|
while (cur && cur !== last) {
|
|
12487
|
-
if (
|
|
13076
|
+
if (existsSync17(join17(cur, ".git")))
|
|
12488
13077
|
return cur;
|
|
12489
13078
|
last = cur;
|
|
12490
13079
|
cur = dirname13(cur);
|
|
@@ -12551,7 +13140,7 @@ function resolveAutoWorkspace(realPath, minRepos) {
|
|
|
12551
13140
|
let last = "";
|
|
12552
13141
|
let depth = 0;
|
|
12553
13142
|
while (cur && cur !== last && depth < AUTO_WORKSPACE_MAX_DEPTH) {
|
|
12554
|
-
if (!
|
|
13143
|
+
if (!existsSync17(join17(cur, ".git"))) {
|
|
12555
13144
|
const cached = workspaceCache.get(cur);
|
|
12556
13145
|
let qualifies;
|
|
12557
13146
|
if (cached === void 0) {
|
|
@@ -12587,7 +13176,7 @@ function countGitChildren(dir) {
|
|
|
12587
13176
|
const st = statSync13(child);
|
|
12588
13177
|
if (!st.isDirectory())
|
|
12589
13178
|
continue;
|
|
12590
|
-
if (
|
|
13179
|
+
if (existsSync17(join17(child, ".git")))
|
|
12591
13180
|
count++;
|
|
12592
13181
|
} catch {
|
|
12593
13182
|
}
|
|
@@ -13177,7 +13766,7 @@ var init_secret_redactor = __esm({
|
|
|
13177
13766
|
|
|
13178
13767
|
// ../engine/dist/core/source-discovery.js
|
|
13179
13768
|
import { createHash as createHash5 } from "crypto";
|
|
13180
|
-
import { existsSync as
|
|
13769
|
+
import { existsSync as existsSync18, readdirSync as readdirSync13, statSync as statSync15 } from "fs";
|
|
13181
13770
|
import { join as join18 } from "path";
|
|
13182
13771
|
function sourceId(path) {
|
|
13183
13772
|
return "src_" + createHash5("sha256").update(path).digest("hex").slice(0, 12);
|
|
@@ -13236,7 +13825,7 @@ function countTranscripts(root, tool) {
|
|
|
13236
13825
|
walk(root, 0);
|
|
13237
13826
|
return { sessions, newestMtime };
|
|
13238
13827
|
}
|
|
13239
|
-
function
|
|
13828
|
+
function countDbSessions(dbPath) {
|
|
13240
13829
|
try {
|
|
13241
13830
|
const st = statSync15(dbPath);
|
|
13242
13831
|
return { sessions: 0, newestMtime: st.mtimeMs };
|
|
@@ -13254,18 +13843,24 @@ function discoverSessionSources() {
|
|
|
13254
13843
|
];
|
|
13255
13844
|
for (const [tool, dirs] of dirTools) {
|
|
13256
13845
|
for (const [i, path] of dirs.entries()) {
|
|
13257
|
-
if (!
|
|
13846
|
+
if (!existsSync18(path))
|
|
13258
13847
|
continue;
|
|
13259
13848
|
const { sessions, newestMtime } = countTranscripts(path, tool);
|
|
13260
13849
|
out.push({ id: sourceId(path), tool, path, sessions, newestMtime, isPrimary: i === 0 });
|
|
13261
13850
|
}
|
|
13262
13851
|
}
|
|
13263
13852
|
for (const [i, path] of opencodeDbPaths({ includeExcluded: true }).entries()) {
|
|
13264
|
-
if (!
|
|
13853
|
+
if (!existsSync18(path))
|
|
13265
13854
|
continue;
|
|
13266
|
-
const { sessions, newestMtime } =
|
|
13855
|
+
const { sessions, newestMtime } = countDbSessions(path);
|
|
13267
13856
|
out.push({ id: sourceId(path), tool: "opencode", path, sessions, newestMtime, isPrimary: i === 0 });
|
|
13268
13857
|
}
|
|
13858
|
+
for (const [i, path] of hermesDbPaths({ includeExcluded: true }).entries()) {
|
|
13859
|
+
if (!existsSync18(path))
|
|
13860
|
+
continue;
|
|
13861
|
+
const { sessions, newestMtime } = countDbSessions(path);
|
|
13862
|
+
out.push({ id: sourceId(path), tool: "hermes", path, sessions, newestMtime, isPrimary: i === 0 });
|
|
13863
|
+
}
|
|
13269
13864
|
return out;
|
|
13270
13865
|
}
|
|
13271
13866
|
var excludedIds, SOURCE_ID_RE, MAX_DEPTH;
|
|
@@ -13290,7 +13885,7 @@ __export(home_discovery_exports, {
|
|
|
13290
13885
|
sessionIdsInHome: () => sessionIdsInHome
|
|
13291
13886
|
});
|
|
13292
13887
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
13293
|
-
import { existsSync as
|
|
13888
|
+
import { existsSync as existsSync19, readdirSync as readdirSync14, readFileSync as readFileSync12, realpathSync as realpathSync3, statSync as statSync16 } from "fs";
|
|
13294
13889
|
import { homedir as homedir5, platform as osPlatform } from "os";
|
|
13295
13890
|
import { join as join19 } from "path";
|
|
13296
13891
|
function candidateRoots(plat = osPlatform(), env = process.env) {
|
|
@@ -13311,10 +13906,10 @@ function candidateRoots(plat = osPlatform(), env = process.env) {
|
|
|
13311
13906
|
add(env.XDG_CONFIG_HOME || join19(home, ".config"));
|
|
13312
13907
|
add(env.XDG_DATA_HOME || join19(home, ".local", "share"));
|
|
13313
13908
|
}
|
|
13314
|
-
return roots.filter((r) =>
|
|
13909
|
+
return roots.filter((r) => existsSync19(r));
|
|
13315
13910
|
}
|
|
13316
13911
|
function identifyHome(dir) {
|
|
13317
|
-
const has = (...parts) =>
|
|
13912
|
+
const has = (...parts) => existsSync19(join19(dir, ...parts));
|
|
13318
13913
|
if (has("projects") && dirHasTranscript(join19(dir, "projects"), (f) => f.endsWith(".jsonl"), 2))
|
|
13319
13914
|
return "claude";
|
|
13320
13915
|
if (has("sessions") && dirHasTranscript(join19(dir, "sessions"), (f) => f.startsWith("rollout-") && f.endsWith(".jsonl"), 4))
|
|
@@ -13325,6 +13920,8 @@ function identifyHome(dir) {
|
|
|
13325
13920
|
return "cursor";
|
|
13326
13921
|
if (has("opencode.db"))
|
|
13327
13922
|
return "opencode";
|
|
13923
|
+
if (has("state.db") && has("SOUL.md"))
|
|
13924
|
+
return "hermes";
|
|
13328
13925
|
return null;
|
|
13329
13926
|
}
|
|
13330
13927
|
function dirHasTranscript(root, match, depth) {
|
|
@@ -13352,7 +13949,8 @@ function countSessions(dir, tool) {
|
|
|
13352
13949
|
codex: { sub: "sessions", depth: 4, match: (f) => f.startsWith("rollout-") && f.endsWith(".jsonl") },
|
|
13353
13950
|
agy: { sub: "brain", depth: 4, match: (f) => f.endsWith(".jsonl") },
|
|
13354
13951
|
cursor: { sub: "chats", depth: 3, match: (f) => f === "store.db" },
|
|
13355
|
-
opencode: { sub: "", depth: 0, match: () => false }
|
|
13952
|
+
opencode: { sub: "", depth: 0, match: () => false },
|
|
13953
|
+
hermes: { sub: "", depth: 0, match: () => false }
|
|
13356
13954
|
};
|
|
13357
13955
|
const s = spec[tool];
|
|
13358
13956
|
if (!s.sub)
|
|
@@ -13402,7 +14000,9 @@ function sessionIdsInHome(dir, tool) {
|
|
|
13402
14000
|
// id is the DIRECTORY name
|
|
13403
14001
|
cursor: { sub: "chats", depth: 2, idOf: () => null },
|
|
13404
14002
|
// id is the DIRECTORY name
|
|
13405
|
-
opencode: { sub: "", depth: 0, idOf: () => null }
|
|
14003
|
+
opencode: { sub: "", depth: 0, idOf: () => null },
|
|
14004
|
+
// rows, not files
|
|
14005
|
+
hermes: { sub: "", depth: 0, idOf: () => null }
|
|
13406
14006
|
// rows, not files
|
|
13407
14007
|
};
|
|
13408
14008
|
const s = spec[tool];
|
|
@@ -13475,6 +14075,8 @@ function declaredHomes(env = process.env, plat = osPlatform()) {
|
|
|
13475
14075
|
add(env.CHAT_RECALL_AGY_HOME);
|
|
13476
14076
|
add(env.CHAT_RECALL_CURSOR_HOME);
|
|
13477
14077
|
add(env.CHAT_RECALL_CURSOR_IDE_HOME);
|
|
14078
|
+
add(env.CHAT_RECALL_HERMES_HOME);
|
|
14079
|
+
add(env.HERMES_HOME);
|
|
13478
14080
|
for (const d of (env.CLAUDE_DIRS || "").split(","))
|
|
13479
14081
|
add(d);
|
|
13480
14082
|
if (plat === "win32") {
|
|
@@ -13574,6 +14176,15 @@ function discoverHomes(opts = {}) {
|
|
|
13574
14176
|
if (prior && !(via === "declared" && prior.via !== "declared"))
|
|
13575
14177
|
return;
|
|
13576
14178
|
found.set(real, { tool, path: real, via, sessions: countSessions(real, tool) });
|
|
14179
|
+
if (tool === "hermes") {
|
|
14180
|
+
try {
|
|
14181
|
+
for (const e of readdirSync14(join19(real, "profiles"), { withFileTypes: true })) {
|
|
14182
|
+
if (e.isDirectory())
|
|
14183
|
+
consider(join19(real, "profiles", e.name), via);
|
|
14184
|
+
}
|
|
14185
|
+
} catch {
|
|
14186
|
+
}
|
|
14187
|
+
}
|
|
13577
14188
|
};
|
|
13578
14189
|
for (const d of declaredHomes(env, plat))
|
|
13579
14190
|
consider(d, "declared");
|
|
@@ -13653,7 +14264,7 @@ __export(detector_install_exports, {
|
|
|
13653
14264
|
});
|
|
13654
14265
|
import { spawnSync } from "child_process";
|
|
13655
14266
|
import { createHash as createHash6 } from "crypto";
|
|
13656
|
-
import { existsSync as
|
|
14267
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync4, mkdtempSync, chmodSync as chmodSync2, renameSync as renameSync3, rmSync as rmSync2, writeFileSync as writeFileSync3, readFileSync as readFileSync13, statSync as statSync17, copyFileSync as copyFileSync2 } from "fs";
|
|
13657
14268
|
import { join as join20 } from "path";
|
|
13658
14269
|
function managedDetectorPath(name) {
|
|
13659
14270
|
return join20(getDetectorBinDir(), name + exeSuffix());
|
|
@@ -13696,7 +14307,7 @@ function resolveDetector(name) {
|
|
|
13696
14307
|
const dir = configuredDir();
|
|
13697
14308
|
if (dir) {
|
|
13698
14309
|
const p2 = join20(dir, name + exeSuffix());
|
|
13699
|
-
if (
|
|
14310
|
+
if (existsSync20(p2))
|
|
13700
14311
|
return { path: p2, version: "operator-supplied", source: "configured" };
|
|
13701
14312
|
return { error: "not-installed" };
|
|
13702
14313
|
}
|
|
@@ -13704,7 +14315,7 @@ function resolveDetector(name) {
|
|
|
13704
14315
|
if (!spec.assets[platformKey()])
|
|
13705
14316
|
return { error: "unsupported-platform" };
|
|
13706
14317
|
const p = managedDetectorPath(name);
|
|
13707
|
-
if (!
|
|
14318
|
+
if (!existsSync20(p))
|
|
13708
14319
|
return { error: "not-installed" };
|
|
13709
14320
|
const receipt = readReceipt(name);
|
|
13710
14321
|
if (!receipt)
|
|
@@ -13724,7 +14335,7 @@ function downloadUrl(spec, asset) {
|
|
|
13724
14335
|
}
|
|
13725
14336
|
function extractMember(archive, member, destDir) {
|
|
13726
14337
|
const r = spawnSync("tar", ["-xf", archive, "-C", destDir, member], { encoding: "utf-8", timeout: 12e4 });
|
|
13727
|
-
if (r.status === 0 &&
|
|
14338
|
+
if (r.status === 0 && existsSync20(join20(destDir, member)))
|
|
13728
14339
|
return true;
|
|
13729
14340
|
log4.error({ status: r.status, stderr: (r.stderr || "").slice(0, 400), archive, member }, "extract failed");
|
|
13730
14341
|
return false;
|
|
@@ -13793,7 +14404,7 @@ function removeDetector(name) {
|
|
|
13793
14404
|
let removed = false;
|
|
13794
14405
|
for (const p of [managedDetectorPath(name), receiptPath(name)]) {
|
|
13795
14406
|
try {
|
|
13796
|
-
if (
|
|
14407
|
+
if (existsSync20(p)) {
|
|
13797
14408
|
rmSync2(p, { force: true });
|
|
13798
14409
|
removed = true;
|
|
13799
14410
|
}
|
|
@@ -13819,7 +14430,7 @@ function detectorStatus() {
|
|
|
13819
14430
|
}
|
|
13820
14431
|
function ensureDetectorBinDir() {
|
|
13821
14432
|
const d = getDetectorBinDir();
|
|
13822
|
-
if (!
|
|
14433
|
+
if (!existsSync20(d))
|
|
13823
14434
|
mkdirSync4(d, { recursive: true, mode: 493 });
|
|
13824
14435
|
return d;
|
|
13825
14436
|
}
|
|
@@ -13877,7 +14488,7 @@ __export(secret_scanner_exports, {
|
|
|
13877
14488
|
scanTenantRules: () => scanTenantRules
|
|
13878
14489
|
});
|
|
13879
14490
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
13880
|
-
import { existsSync as
|
|
14491
|
+
import { existsSync as existsSync21, unlinkSync, readFileSync as readFileSync14, mkdtempSync as mkdtempSync2, rmSync as rmSync3 } from "fs";
|
|
13881
14492
|
import { tmpdir } from "os";
|
|
13882
14493
|
import { join as join21 } from "path";
|
|
13883
14494
|
function mask(s) {
|
|
@@ -14046,7 +14657,7 @@ function runTrufflehogDir(binary, dir, opts = {}) {
|
|
|
14046
14657
|
return out;
|
|
14047
14658
|
}
|
|
14048
14659
|
function scanDirForSecrets(dir, opts = {}) {
|
|
14049
|
-
if (!
|
|
14660
|
+
if (!existsSync21(dir))
|
|
14050
14661
|
return [];
|
|
14051
14662
|
const gitleaks = whichDetector("gitleaks");
|
|
14052
14663
|
const trufflehog = whichDetector("trufflehog");
|
|
@@ -14083,7 +14694,7 @@ function scanTenantRules(text, tenantRules) {
|
|
|
14083
14694
|
return out;
|
|
14084
14695
|
}
|
|
14085
14696
|
function scanFileForSecrets(filePath, opts = {}) {
|
|
14086
|
-
if (!
|
|
14697
|
+
if (!existsSync21(filePath))
|
|
14087
14698
|
return [];
|
|
14088
14699
|
const gitleaks = whichDetector("gitleaks");
|
|
14089
14700
|
const trufflehog = whichDetector("trufflehog");
|
|
@@ -14105,7 +14716,7 @@ function scanFileForSecrets(filePath, opts = {}) {
|
|
|
14105
14716
|
}
|
|
14106
14717
|
async function scanSessionForSecrets(opts) {
|
|
14107
14718
|
const result = { sessionId: opts.sessionId, byDetector: {}, total: 0, ran: false };
|
|
14108
|
-
if (!
|
|
14719
|
+
if (!existsSync21(opts.filePath))
|
|
14109
14720
|
return result;
|
|
14110
14721
|
const gitleaks = whichDetector("gitleaks");
|
|
14111
14722
|
const trufflehog = whichDetector("trufflehog");
|
|
@@ -14261,10 +14872,10 @@ var init_types = __esm({
|
|
|
14261
14872
|
|
|
14262
14873
|
// ../engine/dist/transcript/opencode.js
|
|
14263
14874
|
async function parseOpenCodeSubagents(parentSessionId) {
|
|
14264
|
-
const { existsSync:
|
|
14875
|
+
const { existsSync: existsSync59 } = await import("fs");
|
|
14265
14876
|
const { opencodeBackend: opencodeBackend2 } = await Promise.resolve().then(() => (init_opencode(), opencode_exports));
|
|
14266
14877
|
const dbPath = opencodeBackend2.dbPath();
|
|
14267
|
-
if (!
|
|
14878
|
+
if (!existsSync59(dbPath))
|
|
14268
14879
|
return [];
|
|
14269
14880
|
const realParent = parentSessionId.replace("opencode_", "");
|
|
14270
14881
|
const db = openSqliteReadonlyOrThrow(dbPath);
|
|
@@ -14305,10 +14916,10 @@ async function parseOpenCodeSubagents(parentSessionId) {
|
|
|
14305
14916
|
}
|
|
14306
14917
|
}
|
|
14307
14918
|
async function parseOpenCodeTranscript(sessionId) {
|
|
14308
|
-
const { existsSync:
|
|
14919
|
+
const { existsSync: existsSync59 } = await import("fs");
|
|
14309
14920
|
const { opencodeBackend: opencodeBackend2 } = await Promise.resolve().then(() => (init_opencode(), opencode_exports));
|
|
14310
14921
|
const dbPath = opencodeBackend2.dbPath();
|
|
14311
|
-
if (!
|
|
14922
|
+
if (!existsSync59(dbPath))
|
|
14312
14923
|
return [];
|
|
14313
14924
|
const realId = sessionId.replace("opencode_", "");
|
|
14314
14925
|
const db = openSqliteReadonlyOrThrow(dbPath);
|
|
@@ -14360,6 +14971,7 @@ var init_opencode2 = __esm({
|
|
|
14360
14971
|
// ../engine/dist/transcript/index.js
|
|
14361
14972
|
var transcript_exports = {};
|
|
14362
14973
|
__export(transcript_exports, {
|
|
14974
|
+
RAW_PARSE_MAX_BYTES: () => RAW_PARSE_MAX_BYTES,
|
|
14363
14975
|
TRANSCRIPT_VERSION: () => TRANSCRIPT_VERSION,
|
|
14364
14976
|
archiveRawSession: () => archiveRawSession,
|
|
14365
14977
|
buildRawContainer: () => buildRawContainer,
|
|
@@ -15065,7 +15677,7 @@ var init_source_policy = __esm({
|
|
|
15065
15677
|
init_project_path_match();
|
|
15066
15678
|
init_settings();
|
|
15067
15679
|
cache2 = null;
|
|
15068
|
-
TOOLS = ["claude", "opencode", "codex", "agy", "cursor"];
|
|
15680
|
+
TOOLS = ["claude", "opencode", "codex", "agy", "cursor", "hermes"];
|
|
15069
15681
|
}
|
|
15070
15682
|
});
|
|
15071
15683
|
|
|
@@ -15160,7 +15772,7 @@ var init_source_registry = __esm({
|
|
|
15160
15772
|
});
|
|
15161
15773
|
|
|
15162
15774
|
// ../engine/dist/core/utils.js
|
|
15163
|
-
import { existsSync as
|
|
15775
|
+
import { existsSync as existsSync22, readdirSync as readdirSync15 } from "fs";
|
|
15164
15776
|
import { homedir as homedir6 } from "os";
|
|
15165
15777
|
import { join as join22 } from "path";
|
|
15166
15778
|
function splitByHeaders(markdown) {
|
|
@@ -15196,7 +15808,7 @@ function getClaudeDirs() {
|
|
|
15196
15808
|
const dirs = [];
|
|
15197
15809
|
const seen = /* @__PURE__ */ new Set();
|
|
15198
15810
|
const add = (dir) => {
|
|
15199
|
-
if (!seen.has(dir) &&
|
|
15811
|
+
if (!seen.has(dir) && existsSync22(dir)) {
|
|
15200
15812
|
seen.add(dir);
|
|
15201
15813
|
dirs.push(dir);
|
|
15202
15814
|
}
|
|
@@ -15215,7 +15827,7 @@ function getClaudeDirs() {
|
|
|
15215
15827
|
for (const entry of entries) {
|
|
15216
15828
|
if (entry.isDirectory() && entry.name.startsWith(".claude-") && entry.name !== ".claude-code") {
|
|
15217
15829
|
const candidate = join22(home, entry.name);
|
|
15218
|
-
if (
|
|
15830
|
+
if (existsSync22(join22(candidate, "projects"))) {
|
|
15219
15831
|
add(candidate);
|
|
15220
15832
|
}
|
|
15221
15833
|
}
|
|
@@ -15228,7 +15840,7 @@ function discoverSubdirs(subdir) {
|
|
|
15228
15840
|
const result = [];
|
|
15229
15841
|
for (const claudeDir of getClaudeDirs()) {
|
|
15230
15842
|
const path = join22(claudeDir, subdir);
|
|
15231
|
-
if (
|
|
15843
|
+
if (existsSync22(path)) {
|
|
15232
15844
|
result.push(path);
|
|
15233
15845
|
}
|
|
15234
15846
|
}
|
|
@@ -15241,7 +15853,7 @@ var init_utils = __esm({
|
|
|
15241
15853
|
});
|
|
15242
15854
|
|
|
15243
15855
|
// ../engine/dist/parsers/plan-source.js
|
|
15244
|
-
import { existsSync as
|
|
15856
|
+
import { existsSync as existsSync23, readdirSync as readdirSync16, readFileSync as readFileSync15, statSync as statSync20 } from "fs";
|
|
15245
15857
|
import { homedir as homedir7 } from "os";
|
|
15246
15858
|
import { join as join23, basename as basename12 } from "path";
|
|
15247
15859
|
function parseFrontmatter(content) {
|
|
@@ -15299,7 +15911,7 @@ var init_plan_source = __esm({
|
|
|
15299
15911
|
return this._knownProjectDirs;
|
|
15300
15912
|
const projectsDir = claudeBackend.projectsDir();
|
|
15301
15913
|
this._knownProjectDirs = [];
|
|
15302
|
-
if (!
|
|
15914
|
+
if (!existsSync23(projectsDir))
|
|
15303
15915
|
return this._knownProjectDirs;
|
|
15304
15916
|
try {
|
|
15305
15917
|
const entries = readdirSync16(projectsDir, { withFileTypes: true });
|
|
@@ -15307,7 +15919,7 @@ var init_plan_source = __esm({
|
|
|
15307
15919
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
15308
15920
|
continue;
|
|
15309
15921
|
const projectPath = resolveProjectDirName(entry.name);
|
|
15310
|
-
if (
|
|
15922
|
+
if (existsSync23(projectPath)) {
|
|
15311
15923
|
this._knownProjectDirs.push(projectPath);
|
|
15312
15924
|
}
|
|
15313
15925
|
}
|
|
@@ -15331,7 +15943,7 @@ var init_plan_source = __esm({
|
|
|
15331
15943
|
async *discoverClaudePlans() {
|
|
15332
15944
|
const seenClaude = /* @__PURE__ */ new Set();
|
|
15333
15945
|
for (const plansDir of this.plansDirs) {
|
|
15334
|
-
if (!
|
|
15946
|
+
if (!existsSync23(plansDir))
|
|
15335
15947
|
continue;
|
|
15336
15948
|
const files = readdirSync16(plansDir).filter((f) => f.endsWith(".md"));
|
|
15337
15949
|
for (const file of files) {
|
|
@@ -15373,7 +15985,7 @@ var init_plan_source = __esm({
|
|
|
15373
15985
|
}
|
|
15374
15986
|
async *discoverOpenCodePlans() {
|
|
15375
15987
|
const plansDir = opencodeBackend.plansDir();
|
|
15376
|
-
if (!
|
|
15988
|
+
if (!existsSync23(plansDir))
|
|
15377
15989
|
return;
|
|
15378
15990
|
let files;
|
|
15379
15991
|
try {
|
|
@@ -15460,7 +16072,7 @@ var init_plan_source = __esm({
|
|
|
15460
16072
|
return "";
|
|
15461
16073
|
}
|
|
15462
16074
|
async parse(item) {
|
|
15463
|
-
if (!
|
|
16075
|
+
if (!existsSync23(item.filePath))
|
|
15464
16076
|
return [];
|
|
15465
16077
|
const content = readFileSync15(item.filePath, "utf-8");
|
|
15466
16078
|
const chunks = [];
|
|
@@ -15501,7 +16113,7 @@ var init_plan_source = __esm({
|
|
|
15501
16113
|
const projPath = join23(root, proj);
|
|
15502
16114
|
for (const sessionEntry of safeReaddir(projPath)) {
|
|
15503
16115
|
const subDir = join23(projPath, sessionEntry, "subagents");
|
|
15504
|
-
if (!
|
|
16116
|
+
if (!existsSync23(subDir))
|
|
15505
16117
|
continue;
|
|
15506
16118
|
for (const f of safeReaddir(subDir)) {
|
|
15507
16119
|
const m = f.match(/^agent-([a-z0-9_-]+)\.jsonl$/i);
|
|
@@ -15576,7 +16188,7 @@ var init_plan_source = __esm({
|
|
|
15576
16188
|
}
|
|
15577
16189
|
async *discoverAgyPlans() {
|
|
15578
16190
|
const brainDir = join23(agyBackend.homeDir(), "brain");
|
|
15579
|
-
if (!
|
|
16191
|
+
if (!existsSync23(brainDir))
|
|
15580
16192
|
return;
|
|
15581
16193
|
let sessionDirs;
|
|
15582
16194
|
try {
|
|
@@ -15631,7 +16243,7 @@ var init_plan_source = __esm({
|
|
|
15631
16243
|
});
|
|
15632
16244
|
|
|
15633
16245
|
// ../engine/dist/parsers/task-source.js
|
|
15634
|
-
import { existsSync as
|
|
16246
|
+
import { existsSync as existsSync24, readdirSync as readdirSync17, readFileSync as readFileSync16, statSync as statSync21 } from "fs";
|
|
15635
16247
|
import { join as join24 } from "path";
|
|
15636
16248
|
var MAX_CHUNK_CHARS2, TaskSource;
|
|
15637
16249
|
var init_task_source = __esm({
|
|
@@ -15661,7 +16273,7 @@ var init_task_source = __esm({
|
|
|
15661
16273
|
}
|
|
15662
16274
|
async *discoverClaudeTodos() {
|
|
15663
16275
|
const todosDir = claudeBackend.todosDir();
|
|
15664
|
-
if (!
|
|
16276
|
+
if (!existsSync24(todosDir))
|
|
15665
16277
|
return;
|
|
15666
16278
|
let files;
|
|
15667
16279
|
try {
|
|
@@ -15712,7 +16324,7 @@ var init_task_source = __esm({
|
|
|
15712
16324
|
}
|
|
15713
16325
|
}
|
|
15714
16326
|
async *discoverInDir(tasksDir) {
|
|
15715
|
-
if (!
|
|
16327
|
+
if (!existsSync24(tasksDir))
|
|
15716
16328
|
return;
|
|
15717
16329
|
const entries = readdirSync17(tasksDir, { withFileTypes: true });
|
|
15718
16330
|
for (const entry of entries) {
|
|
@@ -15754,7 +16366,7 @@ var init_task_source = __esm({
|
|
|
15754
16366
|
return this.parseAgentTodo(item);
|
|
15755
16367
|
}
|
|
15756
16368
|
const taskDir = item.filePath;
|
|
15757
|
-
if (!
|
|
16369
|
+
if (!existsSync24(taskDir))
|
|
15758
16370
|
return [];
|
|
15759
16371
|
const taskFiles = readdirSync17(taskDir).filter((f) => f.endsWith(".json"));
|
|
15760
16372
|
const tasks2 = this.readTasks(taskDir, taskFiles);
|
|
@@ -15815,7 +16427,7 @@ ${task.description}`.slice(0, MAX_CHUNK_CHARS2);
|
|
|
15815
16427
|
}];
|
|
15816
16428
|
}
|
|
15817
16429
|
async parseAgentTodo(item) {
|
|
15818
|
-
if (!
|
|
16430
|
+
if (!existsSync24(item.filePath))
|
|
15819
16431
|
return [];
|
|
15820
16432
|
let parsed;
|
|
15821
16433
|
try {
|
|
@@ -15867,7 +16479,7 @@ ${task.description}`.slice(0, MAX_CHUNK_CHARS2);
|
|
|
15867
16479
|
});
|
|
15868
16480
|
|
|
15869
16481
|
// ../engine/dist/parsers/claude-md-source.js
|
|
15870
|
-
import { existsSync as
|
|
16482
|
+
import { existsSync as existsSync25, readFileSync as readFileSync17, readdirSync as readdirSync18, statSync as statSync22 } from "fs";
|
|
15871
16483
|
import { homedir as homedir8 } from "os";
|
|
15872
16484
|
import { join as join25, basename as basename13, dirname as dirname14 } from "path";
|
|
15873
16485
|
import { createHash as createHash7 } from "crypto";
|
|
@@ -15875,13 +16487,13 @@ function discoverProjectDirs(claudeDir) {
|
|
|
15875
16487
|
const dirs = [];
|
|
15876
16488
|
const seen = /* @__PURE__ */ new Set();
|
|
15877
16489
|
const addProject = (path) => {
|
|
15878
|
-
if (!seen.has(path) &&
|
|
16490
|
+
if (!seen.has(path) && existsSync25(path)) {
|
|
15879
16491
|
seen.add(path);
|
|
15880
16492
|
dirs.push(path);
|
|
15881
16493
|
}
|
|
15882
16494
|
};
|
|
15883
16495
|
const scanProjectsDir = (projectsDir) => {
|
|
15884
|
-
if (!
|
|
16496
|
+
if (!existsSync25(projectsDir))
|
|
15885
16497
|
return;
|
|
15886
16498
|
try {
|
|
15887
16499
|
const entries = readdirSync18(projectsDir, { withFileTypes: true });
|
|
@@ -15909,7 +16521,7 @@ function discoverProjectDirs(claudeDir) {
|
|
|
15909
16521
|
} catch {
|
|
15910
16522
|
}
|
|
15911
16523
|
const gemProjects = agyBackend.sharedProjectsJson();
|
|
15912
|
-
if (
|
|
16524
|
+
if (existsSync25(gemProjects)) {
|
|
15913
16525
|
try {
|
|
15914
16526
|
const data = JSON.parse(readFileSync17(gemProjects, "utf-8"));
|
|
15915
16527
|
for (const path of Object.keys(data.projects || {}))
|
|
@@ -15918,7 +16530,7 @@ function discoverProjectDirs(claudeDir) {
|
|
|
15918
16530
|
}
|
|
15919
16531
|
}
|
|
15920
16532
|
const ocDb = opencodeBackend.dbPath();
|
|
15921
|
-
if (
|
|
16533
|
+
if (existsSync25(ocDb)) {
|
|
15922
16534
|
try {
|
|
15923
16535
|
const db = openSqliteReadonlyOrThrow(ocDb);
|
|
15924
16536
|
try {
|
|
@@ -15969,7 +16581,7 @@ var init_claude_md_source = __esm({
|
|
|
15969
16581
|
for (const note of NOTE_FILES) {
|
|
15970
16582
|
const p = join25(homedir8(), note.filename);
|
|
15971
16583
|
const key2 = seenKey(p, note.tool);
|
|
15972
|
-
if (
|
|
16584
|
+
if (existsSync25(p) && !seen.has(key2)) {
|
|
15973
16585
|
seen.add(key2);
|
|
15974
16586
|
const item = this.fileToItem(p, note.filename, note.tool);
|
|
15975
16587
|
if (item)
|
|
@@ -15981,7 +16593,7 @@ var init_claude_md_source = __esm({
|
|
|
15981
16593
|
for (const note of NOTE_FILES) {
|
|
15982
16594
|
const p = join25(projectDir, note.filename);
|
|
15983
16595
|
const key2 = seenKey(p, note.tool);
|
|
15984
|
-
if (
|
|
16596
|
+
if (existsSync25(p) && !seen.has(key2)) {
|
|
15985
16597
|
seen.add(key2);
|
|
15986
16598
|
const item = this.fileToItem(p, note.filename, note.tool);
|
|
15987
16599
|
if (item)
|
|
@@ -15990,12 +16602,12 @@ var init_claude_md_source = __esm({
|
|
|
15990
16602
|
}
|
|
15991
16603
|
}
|
|
15992
16604
|
for (const searchDir of this.searchDirs) {
|
|
15993
|
-
if (!
|
|
16605
|
+
if (!existsSync25(searchDir))
|
|
15994
16606
|
continue;
|
|
15995
16607
|
for (const note of NOTE_FILES) {
|
|
15996
16608
|
const directPath = join25(searchDir, note.filename);
|
|
15997
16609
|
const key2 = seenKey(directPath, note.tool);
|
|
15998
|
-
if (
|
|
16610
|
+
if (existsSync25(directPath) && !seen.has(key2)) {
|
|
15999
16611
|
seen.add(key2);
|
|
16000
16612
|
const item = this.fileToItem(directPath, note.filename, note.tool);
|
|
16001
16613
|
if (item)
|
|
@@ -16010,7 +16622,7 @@ var init_claude_md_source = __esm({
|
|
|
16010
16622
|
for (const note of NOTE_FILES) {
|
|
16011
16623
|
const p = join25(searchDir, entry.name, note.filename);
|
|
16012
16624
|
const key2 = seenKey(p, note.tool);
|
|
16013
|
-
if (
|
|
16625
|
+
if (existsSync25(p) && !seen.has(key2)) {
|
|
16014
16626
|
seen.add(key2);
|
|
16015
16627
|
const item = this.fileToItem(p, note.filename, note.tool);
|
|
16016
16628
|
if (item)
|
|
@@ -16024,7 +16636,7 @@ var init_claude_md_source = __esm({
|
|
|
16024
16636
|
}
|
|
16025
16637
|
}
|
|
16026
16638
|
async parse(item) {
|
|
16027
|
-
if (!
|
|
16639
|
+
if (!existsSync25(item.filePath))
|
|
16028
16640
|
return [];
|
|
16029
16641
|
const content = readFileSync17(item.filePath, "utf-8");
|
|
16030
16642
|
const chunks = [];
|
|
@@ -16093,7 +16705,7 @@ var init_claude_md_source = __esm({
|
|
|
16093
16705
|
});
|
|
16094
16706
|
|
|
16095
16707
|
// ../engine/dist/parsers/agent-memory-source.js
|
|
16096
|
-
import { existsSync as
|
|
16708
|
+
import { existsSync as existsSync26, readFileSync as readFileSync18, readdirSync as readdirSync19, statSync as statSync23 } from "fs";
|
|
16097
16709
|
import { homedir as homedir9 } from "os";
|
|
16098
16710
|
import { join as join26, basename as basename14 } from "path";
|
|
16099
16711
|
function parseFrontmatter2(content) {
|
|
@@ -16127,7 +16739,7 @@ function discoverMemoryDirs() {
|
|
|
16127
16739
|
const out = [];
|
|
16128
16740
|
const seen = /* @__PURE__ */ new Set();
|
|
16129
16741
|
const add = (memoryDir, projectHash) => {
|
|
16130
|
-
if (!seen.has(memoryDir) &&
|
|
16742
|
+
if (!seen.has(memoryDir) && existsSync26(memoryDir)) {
|
|
16131
16743
|
seen.add(memoryDir);
|
|
16132
16744
|
out.push({ memoryDir, projectHash });
|
|
16133
16745
|
}
|
|
@@ -16143,7 +16755,7 @@ function discoverMemoryDirs() {
|
|
|
16143
16755
|
} catch {
|
|
16144
16756
|
}
|
|
16145
16757
|
for (const projectsDir of claudeRoots) {
|
|
16146
|
-
if (!
|
|
16758
|
+
if (!existsSync26(projectsDir))
|
|
16147
16759
|
continue;
|
|
16148
16760
|
try {
|
|
16149
16761
|
for (const entry of readdirSync19(projectsDir, { withFileTypes: true })) {
|
|
@@ -16192,7 +16804,7 @@ var init_agent_memory_source = __esm({
|
|
|
16192
16804
|
}
|
|
16193
16805
|
}
|
|
16194
16806
|
async parse(item) {
|
|
16195
|
-
if (!
|
|
16807
|
+
if (!existsSync26(item.filePath))
|
|
16196
16808
|
return [];
|
|
16197
16809
|
const content = readFileSync18(item.filePath, "utf-8");
|
|
16198
16810
|
const { body: body2 } = parseFrontmatter2(content);
|
|
@@ -16278,7 +16890,7 @@ var init_agent_memory_source = __esm({
|
|
|
16278
16890
|
});
|
|
16279
16891
|
|
|
16280
16892
|
// ../engine/dist/parsers/history-source.js
|
|
16281
|
-
import { existsSync as
|
|
16893
|
+
import { existsSync as existsSync27, readdirSync as readdirSync20, statSync as statSync24 } from "fs";
|
|
16282
16894
|
import { createReadStream as createReadStream3 } from "fs";
|
|
16283
16895
|
import { createInterface as createInterface2 } from "readline";
|
|
16284
16896
|
import { homedir as homedir10 } from "os";
|
|
@@ -16300,7 +16912,7 @@ var init_history_source = __esm({
|
|
|
16300
16912
|
const home = homedir10();
|
|
16301
16913
|
const paths = [];
|
|
16302
16914
|
const tryAdd = (p) => {
|
|
16303
|
-
if (
|
|
16915
|
+
if (existsSync27(p) && !paths.includes(p))
|
|
16304
16916
|
paths.push(p);
|
|
16305
16917
|
};
|
|
16306
16918
|
tryAdd(claudeBackend.historyFile());
|
|
@@ -16318,7 +16930,7 @@ var init_history_source = __esm({
|
|
|
16318
16930
|
async *discover() {
|
|
16319
16931
|
if (!isSourceEnabled("claude", "history"))
|
|
16320
16932
|
return;
|
|
16321
|
-
const historyPath = this.historyPaths.find((p) =>
|
|
16933
|
+
const historyPath = this.historyPaths.find((p) => existsSync27(p));
|
|
16322
16934
|
if (!historyPath)
|
|
16323
16935
|
return;
|
|
16324
16936
|
const stat3 = statSync24(historyPath);
|
|
@@ -16414,7 +17026,7 @@ var init_history_source = __esm({
|
|
|
16414
17026
|
async groupByProject() {
|
|
16415
17027
|
const groups = /* @__PURE__ */ new Map();
|
|
16416
17028
|
for (const historyPath of this.historyPaths) {
|
|
16417
|
-
if (!
|
|
17029
|
+
if (!existsSync27(historyPath))
|
|
16418
17030
|
continue;
|
|
16419
17031
|
const rl = createInterface2({
|
|
16420
17032
|
input: createReadStream3(historyPath),
|
|
@@ -16462,7 +17074,7 @@ var init_history_source = __esm({
|
|
|
16462
17074
|
});
|
|
16463
17075
|
|
|
16464
17076
|
// ../engine/dist/parsers/paste-source.js
|
|
16465
|
-
import { existsSync as
|
|
17077
|
+
import { existsSync as existsSync28, readdirSync as readdirSync21, readFileSync as readFileSync19, statSync as statSync25 } from "fs";
|
|
16466
17078
|
import { homedir as homedir11 } from "os";
|
|
16467
17079
|
import { join as join28, basename as basename15 } from "path";
|
|
16468
17080
|
var MAX_CHUNK_CHARS6, MAX_FILE_SIZE, PasteSource;
|
|
@@ -16483,7 +17095,7 @@ var init_paste_source = __esm({
|
|
|
16483
17095
|
const home = homedir11();
|
|
16484
17096
|
const dirs = [];
|
|
16485
17097
|
const tryAdd = (p) => {
|
|
16486
|
-
if (
|
|
17098
|
+
if (existsSync28(p) && !dirs.includes(p))
|
|
16487
17099
|
dirs.push(p);
|
|
16488
17100
|
};
|
|
16489
17101
|
tryAdd(claudeBackend.pasteCacheDir());
|
|
@@ -16503,7 +17115,7 @@ var init_paste_source = __esm({
|
|
|
16503
17115
|
return;
|
|
16504
17116
|
const seen = /* @__PURE__ */ new Set();
|
|
16505
17117
|
for (const cacheDir of this.cacheDirs) {
|
|
16506
|
-
if (!
|
|
17118
|
+
if (!existsSync28(cacheDir))
|
|
16507
17119
|
continue;
|
|
16508
17120
|
const files = readdirSync21(cacheDir).filter((f) => f.endsWith(".txt"));
|
|
16509
17121
|
for (const file of files) {
|
|
@@ -16537,7 +17149,7 @@ var init_paste_source = __esm({
|
|
|
16537
17149
|
}
|
|
16538
17150
|
}
|
|
16539
17151
|
async parse(item) {
|
|
16540
|
-
if (!
|
|
17152
|
+
if (!existsSync28(item.filePath))
|
|
16541
17153
|
return [];
|
|
16542
17154
|
const content = readFileSync19(item.filePath, "utf-8");
|
|
16543
17155
|
if (content.trim().length < 20)
|
|
@@ -16562,7 +17174,7 @@ var init_paste_source = __esm({
|
|
|
16562
17174
|
});
|
|
16563
17175
|
|
|
16564
17176
|
// ../engine/dist/parsers/antigravity-brain-source.js
|
|
16565
|
-
import { existsSync as
|
|
17177
|
+
import { existsSync as existsSync29, readdirSync as readdirSync22, readFileSync as readFileSync20, statSync as statSync26 } from "fs";
|
|
16566
17178
|
import { join as join29 } from "path";
|
|
16567
17179
|
var MAX_CHUNK_CHARS7, AntigravityBrainSource;
|
|
16568
17180
|
var init_antigravity_brain_source = __esm({
|
|
@@ -16581,7 +17193,7 @@ var init_antigravity_brain_source = __esm({
|
|
|
16581
17193
|
async *discover() {
|
|
16582
17194
|
if (!isSourceEnabled("agy", "brain"))
|
|
16583
17195
|
return;
|
|
16584
|
-
if (!
|
|
17196
|
+
if (!existsSync29(this.brainDir))
|
|
16585
17197
|
return;
|
|
16586
17198
|
const sessions = readdirSync22(this.brainDir, { withFileTypes: true });
|
|
16587
17199
|
for (const entry of sessions) {
|
|
@@ -16600,7 +17212,7 @@ var init_antigravity_brain_source = __esm({
|
|
|
16600
17212
|
const heading = content.split("\n").find((l) => l.startsWith("#"))?.replace(/^#+\s*/, "").trim() || file;
|
|
16601
17213
|
const metaPath = `${filePath}.metadata.json`;
|
|
16602
17214
|
let metaSummary = "";
|
|
16603
|
-
if (
|
|
17215
|
+
if (existsSync29(metaPath)) {
|
|
16604
17216
|
try {
|
|
16605
17217
|
const meta = JSON.parse(readFileSync20(metaPath, "utf-8"));
|
|
16606
17218
|
metaSummary = meta.summary || "";
|
|
@@ -16631,7 +17243,7 @@ var init_antigravity_brain_source = __esm({
|
|
|
16631
17243
|
}
|
|
16632
17244
|
}
|
|
16633
17245
|
async parse(item) {
|
|
16634
|
-
if (!
|
|
17246
|
+
if (!existsSync29(item.filePath))
|
|
16635
17247
|
return [];
|
|
16636
17248
|
const content = readFileSync20(item.filePath, "utf-8");
|
|
16637
17249
|
const chunks = [];
|
|
@@ -16674,7 +17286,7 @@ var init_antigravity_brain_source = __esm({
|
|
|
16674
17286
|
});
|
|
16675
17287
|
|
|
16676
17288
|
// ../engine/dist/parsers/opencode-source.js
|
|
16677
|
-
import { existsSync as
|
|
17289
|
+
import { existsSync as existsSync30 } from "fs";
|
|
16678
17290
|
var MAX_CHUNK_CHARS8, OpenCodeSource;
|
|
16679
17291
|
var init_opencode_source = __esm({
|
|
16680
17292
|
"../engine/dist/parsers/opencode-source.js"() {
|
|
@@ -16692,7 +17304,7 @@ var init_opencode_source = __esm({
|
|
|
16692
17304
|
async *discover() {
|
|
16693
17305
|
if (!isSourceEnabled("opencode", "sessions"))
|
|
16694
17306
|
return;
|
|
16695
|
-
if (!
|
|
17307
|
+
if (!existsSync30(this.dbPath))
|
|
16696
17308
|
return;
|
|
16697
17309
|
let db;
|
|
16698
17310
|
try {
|
|
@@ -16790,7 +17402,7 @@ var init_opencode_source = __esm({
|
|
|
16790
17402
|
}
|
|
16791
17403
|
}
|
|
16792
17404
|
async parse(item) {
|
|
16793
|
-
if (!
|
|
17405
|
+
if (!existsSync30(this.dbPath))
|
|
16794
17406
|
return [];
|
|
16795
17407
|
const sessionId = item.id.replace("opencode_", "");
|
|
16796
17408
|
const db = openSqliteReadonlyOrThrow(this.dbPath);
|
|
@@ -16862,7 +17474,7 @@ var init_opencode_source = __esm({
|
|
|
16862
17474
|
});
|
|
16863
17475
|
|
|
16864
17476
|
// ../engine/dist/parsers/opencode-todo-source.js
|
|
16865
|
-
import { existsSync as
|
|
17477
|
+
import { existsSync as existsSync31 } from "fs";
|
|
16866
17478
|
var OpenCodeTodoSource;
|
|
16867
17479
|
var init_opencode_todo_source = __esm({
|
|
16868
17480
|
"../engine/dist/parsers/opencode-todo-source.js"() {
|
|
@@ -16879,7 +17491,7 @@ var init_opencode_todo_source = __esm({
|
|
|
16879
17491
|
async *discover() {
|
|
16880
17492
|
if (!isSourceEnabled("opencode", "todos"))
|
|
16881
17493
|
return;
|
|
16882
|
-
if (!
|
|
17494
|
+
if (!existsSync31(this.dbPath))
|
|
16883
17495
|
return;
|
|
16884
17496
|
let db;
|
|
16885
17497
|
try {
|
|
@@ -16928,7 +17540,7 @@ var init_opencode_todo_source = __esm({
|
|
|
16928
17540
|
}
|
|
16929
17541
|
}
|
|
16930
17542
|
async parse(item) {
|
|
16931
|
-
if (!
|
|
17543
|
+
if (!existsSync31(this.dbPath))
|
|
16932
17544
|
return [];
|
|
16933
17545
|
const sessionId = item.extra?.sessionId || item.id.replace(`${opencodeBackend.idPrefix}todo_`, "");
|
|
16934
17546
|
const db = openSqliteReadonlyOrThrow(this.dbPath);
|
|
@@ -16976,7 +17588,7 @@ var init_opencode_todo_source = __esm({
|
|
|
16976
17588
|
});
|
|
16977
17589
|
|
|
16978
17590
|
// ../engine/dist/parsers/codex-session-source.js
|
|
16979
|
-
import { existsSync as
|
|
17591
|
+
import { existsSync as existsSync32, readdirSync as readdirSync23, readFileSync as readFileSync21, statSync as statSync27 } from "fs";
|
|
16980
17592
|
import { join as join30, basename as basename16 } from "path";
|
|
16981
17593
|
function getCodexSessionsDir() {
|
|
16982
17594
|
return codexBackend.sessionsDir();
|
|
@@ -17033,7 +17645,7 @@ var init_codex_session_source = __esm({
|
|
|
17033
17645
|
async *discover() {
|
|
17034
17646
|
if (!isSourceEnabled("codex", "sessions"))
|
|
17035
17647
|
return;
|
|
17036
|
-
if (!
|
|
17648
|
+
if (!existsSync32(this.sessionsDir))
|
|
17037
17649
|
return;
|
|
17038
17650
|
const jsonlFiles = this.collectJsonlFiles(this.sessionsDir);
|
|
17039
17651
|
for (const filePath of jsonlFiles) {
|
|
@@ -17092,7 +17704,7 @@ var init_codex_session_source = __esm({
|
|
|
17092
17704
|
}
|
|
17093
17705
|
}
|
|
17094
17706
|
async parse(item) {
|
|
17095
|
-
if (!
|
|
17707
|
+
if (!existsSync32(item.filePath))
|
|
17096
17708
|
return [];
|
|
17097
17709
|
const events = readJsonlLines(item.filePath);
|
|
17098
17710
|
const chunks = [];
|
|
@@ -17195,7 +17807,7 @@ var init_codex_session_source = __esm({
|
|
|
17195
17807
|
}
|
|
17196
17808
|
collectJsonlFiles(dir) {
|
|
17197
17809
|
const results = [];
|
|
17198
|
-
if (!
|
|
17810
|
+
if (!existsSync32(dir))
|
|
17199
17811
|
return results;
|
|
17200
17812
|
for (const entry of readdirSync23(dir, { withFileTypes: true })) {
|
|
17201
17813
|
const fullPath = join30(dir, entry.name);
|
|
@@ -17212,7 +17824,7 @@ var init_codex_session_source = __esm({
|
|
|
17212
17824
|
});
|
|
17213
17825
|
|
|
17214
17826
|
// ../engine/dist/parsers/diary-source.js
|
|
17215
|
-
import { existsSync as
|
|
17827
|
+
import { existsSync as existsSync33, mkdirSync as mkdirSync5, readdirSync as readdirSync24, readFileSync as readFileSync22, writeFileSync as writeFileSync4, statSync as statSync28 } from "fs";
|
|
17216
17828
|
import { join as join31, basename as basename17 } from "path";
|
|
17217
17829
|
var MAX_CHUNK_CHARS10, DiarySource;
|
|
17218
17830
|
var init_diary_source = __esm({
|
|
@@ -17228,7 +17840,7 @@ var init_diary_source = __esm({
|
|
|
17228
17840
|
}
|
|
17229
17841
|
/** Discover all diary entries across all agents. */
|
|
17230
17842
|
async *discover() {
|
|
17231
|
-
if (!
|
|
17843
|
+
if (!existsSync33(this.diaryDir))
|
|
17232
17844
|
return;
|
|
17233
17845
|
const agents = readdirSync24(this.diaryDir, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
17234
17846
|
for (const agentDir of agents) {
|
|
@@ -17263,7 +17875,7 @@ var init_diary_source = __esm({
|
|
|
17263
17875
|
}
|
|
17264
17876
|
}
|
|
17265
17877
|
async parse(item) {
|
|
17266
|
-
if (!
|
|
17878
|
+
if (!existsSync33(item.filePath))
|
|
17267
17879
|
return [];
|
|
17268
17880
|
const raw = readFileSync22(item.filePath, "utf-8");
|
|
17269
17881
|
const entry = JSON.parse(raw);
|
|
@@ -17303,7 +17915,7 @@ var init_diary_source = __esm({
|
|
|
17303
17915
|
static write(entry, diaryDir) {
|
|
17304
17916
|
const dir = diaryDir || getDiaryDir();
|
|
17305
17917
|
const agentDir = join31(dir, entry.agent.toLowerCase().replace(/[^a-z0-9_-]/g, "_"));
|
|
17306
|
-
if (!
|
|
17918
|
+
if (!existsSync33(agentDir)) {
|
|
17307
17919
|
mkdirSync5(agentDir, { recursive: true });
|
|
17308
17920
|
}
|
|
17309
17921
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
@@ -17322,7 +17934,7 @@ var init_diary_source = __esm({
|
|
|
17322
17934
|
static read(agentName, lastN = 10, diaryDir) {
|
|
17323
17935
|
const dir = diaryDir || getDiaryDir();
|
|
17324
17936
|
const agentDir = join31(dir, agentName.toLowerCase().replace(/[^a-z0-9_-]/g, "_"));
|
|
17325
|
-
if (!
|
|
17937
|
+
if (!existsSync33(agentDir))
|
|
17326
17938
|
return [];
|
|
17327
17939
|
const files = readdirSync24(agentDir).filter((f) => f.endsWith(".json")).sort().reverse().slice(0, lastN);
|
|
17328
17940
|
const entries = [];
|
|
@@ -17373,7 +17985,7 @@ var init_redact_inline = __esm({
|
|
|
17373
17985
|
});
|
|
17374
17986
|
|
|
17375
17987
|
// ../engine/dist/parsers/skills-source.js
|
|
17376
|
-
import { existsSync as
|
|
17988
|
+
import { existsSync as existsSync34, readdirSync as readdirSync25, readFileSync as readFileSync23, statSync as statSync29 } from "fs";
|
|
17377
17989
|
import { homedir as homedir12 } from "os";
|
|
17378
17990
|
import { join as join32 } from "path";
|
|
17379
17991
|
function rebuildBody(content) {
|
|
@@ -17413,7 +18025,7 @@ function resolveRoots() {
|
|
|
17413
18025
|
all.push({ path: join32(cursorHomeDir(), "skills"), tool: "cursor" });
|
|
17414
18026
|
all.push({ path: join32(cursorHomeDir(), "skills-cursor"), tool: "cursor", readonly: true });
|
|
17415
18027
|
}
|
|
17416
|
-
return all.filter((r) =>
|
|
18028
|
+
return all.filter((r) => existsSync34(r.path));
|
|
17417
18029
|
}
|
|
17418
18030
|
function parseFrontmatter3(text) {
|
|
17419
18031
|
const m = text.match(/^---\n([\s\S]*?)\n---/);
|
|
@@ -17455,7 +18067,7 @@ var init_skills_source = __esm({
|
|
|
17455
18067
|
return;
|
|
17456
18068
|
for (const { name: pluginName, dir } of codexBackend.installedPluginDirs()) {
|
|
17457
18069
|
const skillsDir = join32(dir, "skills");
|
|
17458
|
-
if (!
|
|
18070
|
+
if (!existsSync34(skillsDir))
|
|
17459
18071
|
continue;
|
|
17460
18072
|
yield* this.fromSkillRoot({ path: skillsDir, tool: "codex" }, pluginName);
|
|
17461
18073
|
}
|
|
@@ -17480,7 +18092,7 @@ var init_skills_source = __esm({
|
|
|
17480
18092
|
if (!st.isDirectory())
|
|
17481
18093
|
continue;
|
|
17482
18094
|
const skillMd = join32(skillDir, "SKILL.md");
|
|
17483
|
-
if (!
|
|
18095
|
+
if (!existsSync34(skillMd))
|
|
17484
18096
|
continue;
|
|
17485
18097
|
let content;
|
|
17486
18098
|
try {
|
|
@@ -17545,7 +18157,7 @@ var init_skills_source = __esm({
|
|
|
17545
18157
|
}
|
|
17546
18158
|
}
|
|
17547
18159
|
async parse(item) {
|
|
17548
|
-
if (!
|
|
18160
|
+
if (!existsSync34(item.filePath))
|
|
17549
18161
|
return [];
|
|
17550
18162
|
const content = readFileSync23(item.filePath, "utf-8");
|
|
17551
18163
|
if (!content.trim())
|
|
@@ -17570,11 +18182,11 @@ var init_skills_source = __esm({
|
|
|
17570
18182
|
});
|
|
17571
18183
|
|
|
17572
18184
|
// ../engine/dist/parsers/mcps-source.js
|
|
17573
|
-
import { existsSync as
|
|
18185
|
+
import { existsSync as existsSync35, readFileSync as readFileSync24, statSync as statSync30 } from "fs";
|
|
17574
18186
|
import { homedir as homedir13 } from "os";
|
|
17575
18187
|
import { join as join33 } from "path";
|
|
17576
18188
|
function readJson(path) {
|
|
17577
|
-
if (!
|
|
18189
|
+
if (!existsSync35(path))
|
|
17578
18190
|
return null;
|
|
17579
18191
|
try {
|
|
17580
18192
|
const raw = readFileSync24(path, "utf-8");
|
|
@@ -17737,7 +18349,7 @@ var init_mcps_source = __esm({
|
|
|
17737
18349
|
}
|
|
17738
18350
|
}
|
|
17739
18351
|
async *fromCodexToml(path) {
|
|
17740
|
-
if (!
|
|
18352
|
+
if (!existsSync35(path))
|
|
17741
18353
|
return;
|
|
17742
18354
|
let content;
|
|
17743
18355
|
try {
|
|
@@ -17910,7 +18522,7 @@ var init_toolkit_format = __esm({
|
|
|
17910
18522
|
});
|
|
17911
18523
|
|
|
17912
18524
|
// ../engine/dist/parsers/slash-commands-source.js
|
|
17913
|
-
import { existsSync as
|
|
18525
|
+
import { existsSync as existsSync36, readdirSync as readdirSync26, readFileSync as readFileSync25, statSync as statSync31 } from "fs";
|
|
17914
18526
|
import { join as join34, basename as basename18 } from "path";
|
|
17915
18527
|
function rebuildBody2(content) {
|
|
17916
18528
|
const { text, redacted } = redactInlineSecrets(content);
|
|
@@ -17963,14 +18575,14 @@ var init_slash_commands_source = __esm({
|
|
|
17963
18575
|
if (isSourceEnabled("claude", "commands")) {
|
|
17964
18576
|
roots.push({ path: claudeBackend.commandsDir(), tool: "claude", scope: "user", projectPath: "", format: "md" });
|
|
17965
18577
|
const projectsRoot = claudeBackend.projectsDir();
|
|
17966
|
-
if (
|
|
18578
|
+
if (existsSync36(projectsRoot)) {
|
|
17967
18579
|
try {
|
|
17968
18580
|
for (const entry of readdirSync26(projectsRoot, { withFileTypes: true })) {
|
|
17969
18581
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
17970
18582
|
continue;
|
|
17971
18583
|
const projectPath = resolveProjectDirName(entry.name);
|
|
17972
18584
|
const cmdDir = join34(projectPath, ".claude", "commands");
|
|
17973
|
-
if (
|
|
18585
|
+
if (existsSync36(cmdDir))
|
|
17974
18586
|
roots.push({ path: cmdDir, tool: "claude", scope: "project", projectPath, format: "md" });
|
|
17975
18587
|
}
|
|
17976
18588
|
} catch {
|
|
@@ -18032,7 +18644,7 @@ var init_slash_commands_source = __esm({
|
|
|
18032
18644
|
}
|
|
18033
18645
|
}
|
|
18034
18646
|
async parse(item) {
|
|
18035
|
-
if (!
|
|
18647
|
+
if (!existsSync36(item.filePath))
|
|
18036
18648
|
return [];
|
|
18037
18649
|
const content = readFileSync25(item.filePath, "utf-8");
|
|
18038
18650
|
if (!content.trim())
|
|
@@ -18057,7 +18669,7 @@ var init_slash_commands_source = __esm({
|
|
|
18057
18669
|
});
|
|
18058
18670
|
|
|
18059
18671
|
// ../engine/dist/parsers/subagents-source.js
|
|
18060
|
-
import { existsSync as
|
|
18672
|
+
import { existsSync as existsSync37, readdirSync as readdirSync27, readFileSync as readFileSync26, statSync as statSync32 } from "fs";
|
|
18061
18673
|
import { join as join35, basename as basename19 } from "path";
|
|
18062
18674
|
function rebuildBody3(content) {
|
|
18063
18675
|
const { text, redacted } = redactInlineSecrets(content);
|
|
@@ -18112,14 +18724,14 @@ var init_subagents_source = __esm({
|
|
|
18112
18724
|
if (isSourceEnabled("claude", "agents")) {
|
|
18113
18725
|
roots.push({ path: claudeBackend.agentsDir(), tool: "claude", scope: "user", projectPath: "", format: "md" });
|
|
18114
18726
|
const projectsRoot = claudeBackend.projectsDir();
|
|
18115
|
-
if (
|
|
18727
|
+
if (existsSync37(projectsRoot)) {
|
|
18116
18728
|
try {
|
|
18117
18729
|
for (const entry of readdirSync27(projectsRoot, { withFileTypes: true })) {
|
|
18118
18730
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
18119
18731
|
continue;
|
|
18120
18732
|
const projectPath = resolveProjectDirName(entry.name);
|
|
18121
18733
|
const agentDir = join35(projectPath, ".claude", "agents");
|
|
18122
|
-
if (
|
|
18734
|
+
if (existsSync37(agentDir))
|
|
18123
18735
|
roots.push({ path: agentDir, tool: "claude", scope: "project", projectPath, format: "md" });
|
|
18124
18736
|
}
|
|
18125
18737
|
} catch {
|
|
@@ -18182,7 +18794,7 @@ var init_subagents_source = __esm({
|
|
|
18182
18794
|
}
|
|
18183
18795
|
}
|
|
18184
18796
|
async parse(item) {
|
|
18185
|
-
if (!
|
|
18797
|
+
if (!existsSync37(item.filePath))
|
|
18186
18798
|
return [];
|
|
18187
18799
|
const content = readFileSync26(item.filePath, "utf-8");
|
|
18188
18800
|
if (!content.trim())
|
|
@@ -18207,10 +18819,10 @@ var init_subagents_source = __esm({
|
|
|
18207
18819
|
});
|
|
18208
18820
|
|
|
18209
18821
|
// ../engine/dist/parsers/hooks-source.js
|
|
18210
|
-
import { existsSync as
|
|
18822
|
+
import { existsSync as existsSync38, readFileSync as readFileSync27, readdirSync as readdirSync28, statSync as statSync33 } from "fs";
|
|
18211
18823
|
import { join as join36 } from "path";
|
|
18212
18824
|
function readJson2(path) {
|
|
18213
|
-
if (!
|
|
18825
|
+
if (!existsSync38(path))
|
|
18214
18826
|
return null;
|
|
18215
18827
|
try {
|
|
18216
18828
|
return JSON.parse(readFileSync27(path, "utf-8"));
|
|
@@ -18232,14 +18844,14 @@ var init_hooks_source = __esm({
|
|
|
18232
18844
|
return;
|
|
18233
18845
|
yield* this.fromSettings(claudeBackend.settingsFile(), "user", "");
|
|
18234
18846
|
const projectsRoot = claudeBackend.projectsDir();
|
|
18235
|
-
if (
|
|
18847
|
+
if (existsSync38(projectsRoot)) {
|
|
18236
18848
|
try {
|
|
18237
18849
|
for (const entry of readdirSync28(projectsRoot, { withFileTypes: true })) {
|
|
18238
18850
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
18239
18851
|
continue;
|
|
18240
18852
|
const projectPath = resolveProjectDirName(entry.name);
|
|
18241
18853
|
const settingsPath2 = join36(projectPath, ".claude", "settings.json");
|
|
18242
|
-
if (
|
|
18854
|
+
if (existsSync38(settingsPath2)) {
|
|
18243
18855
|
yield* this.fromSettings(settingsPath2, "project", projectPath);
|
|
18244
18856
|
}
|
|
18245
18857
|
}
|
|
@@ -18330,11 +18942,11 @@ var init_hooks_source = __esm({
|
|
|
18330
18942
|
});
|
|
18331
18943
|
|
|
18332
18944
|
// ../engine/dist/parsers/plugins-source.js
|
|
18333
|
-
import { existsSync as
|
|
18945
|
+
import { existsSync as existsSync39, readFileSync as readFileSync28, readdirSync as readdirSync29, statSync as statSync34 } from "fs";
|
|
18334
18946
|
import { homedir as homedir14 } from "os";
|
|
18335
18947
|
import { join as join37 } from "path";
|
|
18336
18948
|
function readJson3(path) {
|
|
18337
|
-
if (!
|
|
18949
|
+
if (!existsSync39(path))
|
|
18338
18950
|
return null;
|
|
18339
18951
|
try {
|
|
18340
18952
|
return JSON.parse(readFileSync28(path, "utf-8"));
|
|
@@ -18389,7 +19001,7 @@ var init_plugins_source = __esm({
|
|
|
18389
19001
|
}
|
|
18390
19002
|
}
|
|
18391
19003
|
const gemRoot = agyBackend.sharedExtensionsDir();
|
|
18392
|
-
if (isSourceEnabled("agy", "extensions") &&
|
|
19004
|
+
if (isSourceEnabled("agy", "extensions") && existsSync39(gemRoot)) {
|
|
18393
19005
|
let entries;
|
|
18394
19006
|
try {
|
|
18395
19007
|
entries = readdirSync29(gemRoot);
|
|
@@ -18565,6 +19177,8 @@ function toolOfId(id) {
|
|
|
18565
19177
|
return "codex";
|
|
18566
19178
|
if (id.startsWith("cursor_"))
|
|
18567
19179
|
return "cursor";
|
|
19180
|
+
if (id.startsWith("hermes_"))
|
|
19181
|
+
return "hermes";
|
|
18568
19182
|
return "claude";
|
|
18569
19183
|
}
|
|
18570
19184
|
function extractorVersionForTool(tool) {
|
|
@@ -18820,6 +19434,13 @@ function markSynced(server, rows) {
|
|
|
18820
19434
|
base4.s = s;
|
|
18821
19435
|
}
|
|
18822
19436
|
if (r.hash !== void 0) base4.h = r.hash;
|
|
19437
|
+
const completesChunked = cursorFromCaller && r.chunkFinal === true && prev?.k === 1;
|
|
19438
|
+
if (cursorFromCaller && (r.full || completesChunked) && o > 0) base4.F = o;
|
|
19439
|
+
else if (prev?.F !== void 0) base4.F = prev.F;
|
|
19440
|
+
if (cursorFromCaller && r.chunkedHead) base4.k = 1;
|
|
19441
|
+
else if (prev?.k && !completesChunked && !(cursorFromCaller && r.full)) base4.k = 1;
|
|
19442
|
+
const layout = cursorFromCaller ? r.layout : prev?.L;
|
|
19443
|
+
if (layout) base4.L = layout;
|
|
18823
19444
|
forServer[r.id] = base4;
|
|
18824
19445
|
}
|
|
18825
19446
|
persist(data);
|
|
@@ -18876,6 +19497,14 @@ function markFieldFullPassDone(server, field) {
|
|
|
18876
19497
|
delete st.force[field.name];
|
|
18877
19498
|
persistReconcile(data);
|
|
18878
19499
|
}
|
|
19500
|
+
function forgetFullCoverage(server, sessionId) {
|
|
19501
|
+
const data = load();
|
|
19502
|
+
const row = data[server]?.[sessionId];
|
|
19503
|
+
if (!row || typeof row !== "object") return;
|
|
19504
|
+
delete row.F;
|
|
19505
|
+
delete row.h;
|
|
19506
|
+
persist(data);
|
|
19507
|
+
}
|
|
18879
19508
|
function markFullResync(server, sessionId) {
|
|
18880
19509
|
const data = load();
|
|
18881
19510
|
const forServer = data[server];
|
|
@@ -18884,7 +19513,11 @@ function markFullResync(server, sessionId) {
|
|
|
18884
19513
|
delete forServer[sessionId];
|
|
18885
19514
|
persist(data);
|
|
18886
19515
|
}
|
|
18887
|
-
function
|
|
19516
|
+
function fullCoveredOffset(row) {
|
|
19517
|
+
if (row.F !== void 0) return row.F;
|
|
19518
|
+
return row.h ? row.s ?? 0 : 0;
|
|
19519
|
+
}
|
|
19520
|
+
function syncMode(row, mtime, fileSize, extractorVersion, isAppendOnly, nowMs = Date.now()) {
|
|
18888
19521
|
if (!row) return "full";
|
|
18889
19522
|
if (row.v < extractorVersion) return "full";
|
|
18890
19523
|
const offset = row.o ?? 0;
|
|
@@ -18892,10 +19525,13 @@ function syncMode(row, mtime, fileSize, extractorVersion, isAppendOnly) {
|
|
|
18892
19525
|
if (process.env.CHAT_RECALL_TAIL_APPEND !== "0" && isAppendOnly && fileSize > 0 && offset > 0 && fileSize > (row.s ?? 0)) {
|
|
18893
19526
|
return "append";
|
|
18894
19527
|
}
|
|
19528
|
+
if (isAppendOnly && offset > 0 && fileSize > 0 && fileSize === (row.s ?? 0) && !row.k && fullCoveredOffset(row) < offset && nowMs - Math.floor(mtime) >= SETTLE_QUIET_MS) {
|
|
19529
|
+
return "full";
|
|
19530
|
+
}
|
|
18895
19531
|
if (row.m >= Math.floor(mtime)) return "skip";
|
|
18896
19532
|
return "full";
|
|
18897
19533
|
}
|
|
18898
|
-
var ledgerPath, cache3, base, diskStamp, rowKey, LEDGER_FLUSH_MS, pendingWrite, flushTimer, itemVersionsPath, itemVersionsCache, inventoryPath, unackedCursorAttempts, reconcilePath, reconcileCache;
|
|
19534
|
+
var ledgerPath, cache3, base, diskStamp, rowKey, LEDGER_FLUSH_MS, pendingWrite, flushTimer, itemVersionsPath, itemVersionsCache, inventoryPath, unackedCursorAttempts, reconcilePath, reconcileCache, SETTLE_QUIET_MS;
|
|
18899
19535
|
var init_sync_ledger = __esm({
|
|
18900
19536
|
"src/sync-ledger.ts"() {
|
|
18901
19537
|
"use strict";
|
|
@@ -18915,6 +19551,7 @@ var init_sync_ledger = __esm({
|
|
|
18915
19551
|
unackedCursorAttempts = 0;
|
|
18916
19552
|
reconcilePath = () => join38(getDataDir(), "sync-field-reconcile.json");
|
|
18917
19553
|
reconcileCache = null;
|
|
19554
|
+
SETTLE_QUIET_MS = 2 * 60 * 60 * 1e3;
|
|
18918
19555
|
}
|
|
18919
19556
|
});
|
|
18920
19557
|
|
|
@@ -18944,12 +19581,12 @@ var init_sync_fields = __esm({
|
|
|
18944
19581
|
});
|
|
18945
19582
|
|
|
18946
19583
|
// ../engine/dist/core/index-lock.js
|
|
18947
|
-
import { existsSync as
|
|
19584
|
+
import { existsSync as existsSync40, mkdirSync as mkdirSync7, openSync as openSync8, writeFileSync as writeFileSync6, readFileSync as readFileSync30, rmSync as rmSync4, statSync as statSync36, closeSync as closeSync8 } from "fs";
|
|
18948
19585
|
import { dirname as dirname16, join as join39 } from "path";
|
|
18949
19586
|
function acquireIndexLock(opts) {
|
|
18950
19587
|
const lockPath = lockFilePath(opts.file);
|
|
18951
19588
|
mkdirSync7(dirname16(lockPath), { recursive: true });
|
|
18952
|
-
if (
|
|
19589
|
+
if (existsSync40(lockPath)) {
|
|
18953
19590
|
if (!stealStaleLock(lockPath, opts.staleAfterMs ?? 10 * 6e4)) {
|
|
18954
19591
|
return null;
|
|
18955
19592
|
}
|
|
@@ -19066,7 +19703,7 @@ var init_http = __esm({
|
|
|
19066
19703
|
CLI_VERSION = JSON.parse(readFileSync31(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
|
|
19067
19704
|
} catch {
|
|
19068
19705
|
try {
|
|
19069
|
-
if (true) CLI_VERSION = "0.7.
|
|
19706
|
+
if (true) CLI_VERSION = "0.7.19";
|
|
19070
19707
|
} catch {
|
|
19071
19708
|
}
|
|
19072
19709
|
}
|
|
@@ -19163,7 +19800,7 @@ var init_derived = __esm({
|
|
|
19163
19800
|
|
|
19164
19801
|
// src/scan-pool.ts
|
|
19165
19802
|
import { Worker } from "node:worker_threads";
|
|
19166
|
-
import { existsSync as
|
|
19803
|
+
import { existsSync as existsSync41 } from "node:fs";
|
|
19167
19804
|
import { fileURLToPath } from "node:url";
|
|
19168
19805
|
import { cpus } from "node:os";
|
|
19169
19806
|
function poolSize() {
|
|
@@ -19178,7 +19815,7 @@ function workerScript() {
|
|
|
19178
19815
|
for (const rel of ["./scan-worker.js", "../dist/scan-worker.js"]) {
|
|
19179
19816
|
try {
|
|
19180
19817
|
const p = fileURLToPath(new URL(rel, import.meta.url));
|
|
19181
|
-
if (
|
|
19818
|
+
if (existsSync41(p)) return p;
|
|
19182
19819
|
} catch {
|
|
19183
19820
|
}
|
|
19184
19821
|
}
|
|
@@ -19564,7 +20201,7 @@ var init_telemetry = __esm({
|
|
|
19564
20201
|
init_sync_client();
|
|
19565
20202
|
cliVersion2 = () => {
|
|
19566
20203
|
try {
|
|
19567
|
-
return true ? "0.7.
|
|
20204
|
+
return true ? "0.7.19" : "dev";
|
|
19568
20205
|
} catch {
|
|
19569
20206
|
return "dev";
|
|
19570
20207
|
}
|
|
@@ -19727,6 +20364,150 @@ var init_collector_health = __esm({
|
|
|
19727
20364
|
}
|
|
19728
20365
|
});
|
|
19729
20366
|
|
|
20367
|
+
// src/raw-archive-parts.ts
|
|
20368
|
+
import { createReadStream as createReadStream4, createWriteStream, openSync as openSync9, readSync as readSync8, closeSync as closeSync9, rmSync as rmSync5, statSync as statSync37 } from "node:fs";
|
|
20369
|
+
import { tmpdir as tmpdir2 } from "node:os";
|
|
20370
|
+
import { join as join41 } from "node:path";
|
|
20371
|
+
import { randomBytes } from "node:crypto";
|
|
20372
|
+
import { createGzip } from "node:zlib";
|
|
20373
|
+
import { once } from "node:events";
|
|
20374
|
+
import { readFileSync as readFileSync33 } from "node:fs";
|
|
20375
|
+
async function* fileLines(path) {
|
|
20376
|
+
let rest = "";
|
|
20377
|
+
const decoder = new TextDecoder("utf-8");
|
|
20378
|
+
for await (const chunk of createReadStream4(path, { highWaterMark: 1024 * 1024 })) {
|
|
20379
|
+
rest += decoder.decode(chunk, { stream: true });
|
|
20380
|
+
let nl = rest.indexOf("\n");
|
|
20381
|
+
while (nl >= 0) {
|
|
20382
|
+
yield rest.slice(0, nl + 1);
|
|
20383
|
+
rest = rest.slice(nl + 1);
|
|
20384
|
+
nl = rest.indexOf("\n");
|
|
20385
|
+
}
|
|
20386
|
+
}
|
|
20387
|
+
rest += decoder.decode();
|
|
20388
|
+
if (rest) yield rest;
|
|
20389
|
+
}
|
|
20390
|
+
function* textLines(text) {
|
|
20391
|
+
let at = 0;
|
|
20392
|
+
while (at < text.length) {
|
|
20393
|
+
const nl = text.indexOf("\n", at);
|
|
20394
|
+
const end = nl < 0 ? text.length : nl + 1;
|
|
20395
|
+
yield text.slice(at, end);
|
|
20396
|
+
at = end;
|
|
20397
|
+
}
|
|
20398
|
+
}
|
|
20399
|
+
async function writeArchiveFile(source, meta, redact, dir = tmpdir2()) {
|
|
20400
|
+
const path = join41(dir, `cr-archive-${randomBytes(8).toString("hex")}.json.gz`);
|
|
20401
|
+
const gzip = createGzip({ level: 6 });
|
|
20402
|
+
const out = createWriteStream(path, { mode: 384 });
|
|
20403
|
+
const done = once(out, "finish");
|
|
20404
|
+
gzip.pipe(out);
|
|
20405
|
+
let size = 0;
|
|
20406
|
+
const write = async (s) => {
|
|
20407
|
+
size += Buffer.byteLength(s);
|
|
20408
|
+
if (!gzip.write(s)) await once(gzip, "drain");
|
|
20409
|
+
};
|
|
20410
|
+
try {
|
|
20411
|
+
await write(`{"v":1,"tool":${JSON.stringify(meta.tool)},"mtime":${Math.floor(meta.mtime)},"files":[`);
|
|
20412
|
+
for (const [i, f] of source.files.entries()) {
|
|
20413
|
+
await write(`${i ? "," : ""}{"name":${JSON.stringify(f.name)},"text":"`);
|
|
20414
|
+
const whole = () => source.kind === "memory" ? f.text : readFileSync33(f.path, "utf-8");
|
|
20415
|
+
if (!f.name.endsWith(".jsonl")) {
|
|
20416
|
+
await write(escapeJson(redact(whole())));
|
|
20417
|
+
} else {
|
|
20418
|
+
const lines = source.kind === "memory" ? textLines(f.text) : fileLines(f.path);
|
|
20419
|
+
for await (const line of lines) {
|
|
20420
|
+
const nl = line.endsWith("\n");
|
|
20421
|
+
const body2 = nl ? line.slice(0, -1) : line;
|
|
20422
|
+
await write(escapeJson((body2 ? redactJsonLine(body2, redact) : body2) + (nl ? "\n" : "")));
|
|
20423
|
+
}
|
|
20424
|
+
}
|
|
20425
|
+
await write('"}');
|
|
20426
|
+
}
|
|
20427
|
+
await write("]}");
|
|
20428
|
+
gzip.end();
|
|
20429
|
+
await done;
|
|
20430
|
+
} catch (err) {
|
|
20431
|
+
gzip.destroy();
|
|
20432
|
+
out.destroy();
|
|
20433
|
+
rmSync5(path, { force: true });
|
|
20434
|
+
throw err;
|
|
20435
|
+
}
|
|
20436
|
+
return { path, gzSize: statSync37(path).size, size };
|
|
20437
|
+
}
|
|
20438
|
+
async function putPart(url, body2) {
|
|
20439
|
+
let last;
|
|
20440
|
+
for (let attempt = 1; attempt <= PART_ATTEMPTS; attempt++) {
|
|
20441
|
+
const ac = new AbortController();
|
|
20442
|
+
const timer = setTimeout(() => ac.abort(), PART_TIMEOUT_MS);
|
|
20443
|
+
try {
|
|
20444
|
+
const r = await fetch(url, { method: "PUT", body: body2, signal: ac.signal });
|
|
20445
|
+
const etag = r.headers.get("etag");
|
|
20446
|
+
if (r.ok && etag) return etag;
|
|
20447
|
+
last = new Error(`part PUT answered ${r.status}`);
|
|
20448
|
+
if (r.status === 403 || r.status === 404) break;
|
|
20449
|
+
} catch (err) {
|
|
20450
|
+
last = err;
|
|
20451
|
+
} finally {
|
|
20452
|
+
clearTimeout(timer);
|
|
20453
|
+
}
|
|
20454
|
+
}
|
|
20455
|
+
throw last instanceof Error ? last : new Error(String(last));
|
|
20456
|
+
}
|
|
20457
|
+
async function uploadArchiveFile(base4, token, args) {
|
|
20458
|
+
const headers = { "content-type": "application/json" };
|
|
20459
|
+
if (token) headers.authorization = `Bearer ${token}`;
|
|
20460
|
+
const post = async (path, body2) => {
|
|
20461
|
+
const r = await fetch(`${base4}/api/sync/raw-upload/${path}`, { method: "POST", headers, body: JSON.stringify(body2) });
|
|
20462
|
+
const json = await r.json().catch(() => ({}));
|
|
20463
|
+
return { status: r.status, json };
|
|
20464
|
+
};
|
|
20465
|
+
const start = await post("start", {
|
|
20466
|
+
session_id: args.sessionId,
|
|
20467
|
+
tool: args.tool,
|
|
20468
|
+
mtime: Math.floor(args.mtime),
|
|
20469
|
+
size: args.file.size,
|
|
20470
|
+
gz_size: args.file.gzSize,
|
|
20471
|
+
project_id: args.projectId,
|
|
20472
|
+
project_path: args.projectPath
|
|
20473
|
+
});
|
|
20474
|
+
if (start.status === 501 || start.status === 404) return "unsupported";
|
|
20475
|
+
if (start.status !== 200) throw new Error(`raw upload start answered ${start.status}: ${start.json.error ?? ""}`);
|
|
20476
|
+
if (start.json.result === "unchanged" || start.json.result === "shrink-protected") return start.json.result;
|
|
20477
|
+
const urls = start.json.urls;
|
|
20478
|
+
const partBytes = Number(start.json.part_bytes);
|
|
20479
|
+
const parts = [];
|
|
20480
|
+
const fd = openSync9(args.file.path, "r");
|
|
20481
|
+
try {
|
|
20482
|
+
for (const [i, url] of urls.entries()) {
|
|
20483
|
+
const len = Math.min(partBytes, args.file.gzSize - i * partBytes);
|
|
20484
|
+
const buf = Buffer.allocUnsafe(len);
|
|
20485
|
+
let got = 0;
|
|
20486
|
+
while (got < len) {
|
|
20487
|
+
const n = readSync8(fd, buf, got, len - got, i * partBytes + got);
|
|
20488
|
+
if (n <= 0) break;
|
|
20489
|
+
got += n;
|
|
20490
|
+
}
|
|
20491
|
+
parts.push({ part_number: i + 1, etag: await putPart(url, buf.subarray(0, got)) });
|
|
20492
|
+
}
|
|
20493
|
+
} finally {
|
|
20494
|
+
closeSync9(fd);
|
|
20495
|
+
}
|
|
20496
|
+
const done = await post("complete", { session_id: args.sessionId, upload_id: start.json.upload_id, parts });
|
|
20497
|
+
if (done.status !== 200) throw new Error(`raw upload complete answered ${done.status}: ${done.json.error ?? ""}`);
|
|
20498
|
+
return done.json.result;
|
|
20499
|
+
}
|
|
20500
|
+
var escapeJson, PART_TIMEOUT_MS, PART_ATTEMPTS;
|
|
20501
|
+
var init_raw_archive_parts = __esm({
|
|
20502
|
+
"src/raw-archive-parts.ts"() {
|
|
20503
|
+
"use strict";
|
|
20504
|
+
init_transcript();
|
|
20505
|
+
escapeJson = (s) => JSON.stringify(s).slice(1, -1);
|
|
20506
|
+
PART_TIMEOUT_MS = 12e4;
|
|
20507
|
+
PART_ATTEMPTS = 3;
|
|
20508
|
+
}
|
|
20509
|
+
});
|
|
20510
|
+
|
|
19730
20511
|
// src/server-probe.ts
|
|
19731
20512
|
var server_probe_exports = {};
|
|
19732
20513
|
__export(server_probe_exports, {
|
|
@@ -19870,7 +20651,7 @@ __export(client_events_exports, {
|
|
|
19870
20651
|
isTelemetryEnabled: () => isTelemetryEnabled,
|
|
19871
20652
|
reportClientEvent: () => reportClientEvent
|
|
19872
20653
|
});
|
|
19873
|
-
import { readFileSync as
|
|
20654
|
+
import { readFileSync as readFileSync34 } from "node:fs";
|
|
19874
20655
|
function scrub(msg) {
|
|
19875
20656
|
if (!msg) return "";
|
|
19876
20657
|
const noHome = msg.replace(/\/(?:home|Users)\/[^/\s]+/g, "~");
|
|
@@ -19923,7 +20704,7 @@ var init_client_events = __esm({
|
|
|
19923
20704
|
init_secret_redactor();
|
|
19924
20705
|
CLI_VERSION2 = "0.0.0";
|
|
19925
20706
|
try {
|
|
19926
|
-
CLI_VERSION2 = JSON.parse(
|
|
20707
|
+
CLI_VERSION2 = JSON.parse(readFileSync34(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION2;
|
|
19927
20708
|
} catch {
|
|
19928
20709
|
}
|
|
19929
20710
|
}
|
|
@@ -19953,11 +20734,11 @@ __export(auto_update_exports, {
|
|
|
19953
20734
|
tarballUrl: () => tarballUrl
|
|
19954
20735
|
});
|
|
19955
20736
|
import { execSync as execSync2, execFileSync as execFileSync3 } from "node:child_process";
|
|
19956
|
-
import { readFileSync as
|
|
20737
|
+
import { readFileSync as readFileSync35, existsSync as existsSync42 } from "node:fs";
|
|
19957
20738
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
19958
|
-
import { writeFileSync as writeFileSync8, mkdtempSync as mkdtempSync3, rmSync as
|
|
19959
|
-
import { join as
|
|
19960
|
-
import { tmpdir as
|
|
20739
|
+
import { writeFileSync as writeFileSync8, mkdtempSync as mkdtempSync3, rmSync as rmSync6, readdirSync as readdirSync30, statSync as statSync38, mkdirSync as mkdirSync9 } from "node:fs";
|
|
20740
|
+
import { join as join42, dirname as dirname18, sep as sep2, posix as pathPosix, win32 as pathWin32 } from "node:path";
|
|
20741
|
+
import { tmpdir as tmpdir3, homedir as homedir15 } from "node:os";
|
|
19961
20742
|
import { createHash as createHash8 } from "node:crypto";
|
|
19962
20743
|
function compareVersions(a, b) {
|
|
19963
20744
|
const pa = String(a).split("-")[0].split(".").map((n) => parseInt(n, 10) || 0);
|
|
@@ -19981,7 +20762,7 @@ function newerOf(a, b) {
|
|
|
19981
20762
|
function installedVersion() {
|
|
19982
20763
|
try {
|
|
19983
20764
|
const here = dirname18(fileURLToPath2(import.meta.url));
|
|
19984
|
-
const raw =
|
|
20765
|
+
const raw = readFileSync35(join42(here, "..", "package.json"), "utf-8");
|
|
19985
20766
|
return JSON.parse(raw).version || null;
|
|
19986
20767
|
} catch {
|
|
19987
20768
|
return null;
|
|
@@ -19994,7 +20775,7 @@ function planAutoUpdate(base4, caps, ownVersion3, flag) {
|
|
|
19994
20775
|
if (compareVersions(rel.version, ownVersion3) <= 0) return { update: false, reason: `already current (own ${ownVersion3} >= server ${rel.version})` };
|
|
19995
20776
|
return { update: true, reason: `server ${rel.version} > own ${ownVersion3}`, url: tarballUrl(base4, rel.version), fallbackUrl: tarballUrl(base4), sha256: rel.sha256, from: ownVersion3, to: rel.version };
|
|
19996
20777
|
}
|
|
19997
|
-
function sweepStaleStaging(root =
|
|
20778
|
+
function sweepStaleStaging(root = tmpdir3(), now = Date.now()) {
|
|
19998
20779
|
const MKDTEMP_SUFFIX = /^cr-update-.{6}$/s;
|
|
19999
20780
|
const COLD_MS = 60 * 60 * 1e3;
|
|
20000
20781
|
let removed = 0;
|
|
@@ -20006,13 +20787,13 @@ function sweepStaleStaging(root = tmpdir2(), now = Date.now()) {
|
|
|
20006
20787
|
}
|
|
20007
20788
|
for (const name of entries) {
|
|
20008
20789
|
if (!MKDTEMP_SUFFIX.test(name)) continue;
|
|
20009
|
-
const dir =
|
|
20790
|
+
const dir = join42(root, name);
|
|
20010
20791
|
try {
|
|
20011
|
-
const st =
|
|
20792
|
+
const st = statSync38(dir);
|
|
20012
20793
|
if (!st.isDirectory() || now - st.mtimeMs < COLD_MS) continue;
|
|
20013
20794
|
const inside = readdirSync30(dir);
|
|
20014
20795
|
if (inside.length > 1 || inside.length === 1 && inside[0] !== "chat-recall.tgz") continue;
|
|
20015
|
-
|
|
20796
|
+
rmSync6(dir, { recursive: true, force: true });
|
|
20016
20797
|
removed++;
|
|
20017
20798
|
} catch {
|
|
20018
20799
|
}
|
|
@@ -20035,14 +20816,14 @@ async function executeAutoUpdate(plan, deps) {
|
|
|
20035
20816
|
}
|
|
20036
20817
|
const got = createHash8("sha256").update(buf).digest("hex");
|
|
20037
20818
|
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` };
|
|
20038
|
-
const dir = mkdtempSync3(
|
|
20819
|
+
const dir = mkdtempSync3(join42(tmpdir3(), "cr-update-"));
|
|
20039
20820
|
const discardStaging = () => {
|
|
20040
20821
|
try {
|
|
20041
|
-
|
|
20822
|
+
rmSync6(dir, { recursive: true, force: true });
|
|
20042
20823
|
} catch {
|
|
20043
20824
|
}
|
|
20044
20825
|
};
|
|
20045
|
-
const tgz =
|
|
20826
|
+
const tgz = join42(dir, "chat-recall.tgz");
|
|
20046
20827
|
writeFileSync8(tgz, buf);
|
|
20047
20828
|
if (deps.stopping?.()) {
|
|
20048
20829
|
discardStaging();
|
|
@@ -20114,7 +20895,7 @@ function resolveNpm(loc) {
|
|
|
20114
20895
|
}
|
|
20115
20896
|
function realInstall(tgz) {
|
|
20116
20897
|
const prefix = runningPrefix();
|
|
20117
|
-
const npm = resolveNpm({ execPath: process.execPath, prefix, platform: process.platform, env: process.env, exists:
|
|
20898
|
+
const npm = resolveNpm({ execPath: process.execPath, prefix, platform: process.platform, env: process.env, exists: existsSync42 });
|
|
20118
20899
|
if (prefix) {
|
|
20119
20900
|
npmInstall(npm, ["install", "-g", "--prefix", prefix, tgz]);
|
|
20120
20901
|
return;
|
|
@@ -20122,7 +20903,7 @@ function realInstall(tgz) {
|
|
|
20122
20903
|
try {
|
|
20123
20904
|
npmInstall(npm, ["install", "-g", tgz]);
|
|
20124
20905
|
} catch {
|
|
20125
|
-
npmInstall(npm, ["install", "-g", "--prefix",
|
|
20906
|
+
npmInstall(npm, ["install", "-g", "--prefix", join42(homedir15(), ".local"), tgz]);
|
|
20126
20907
|
}
|
|
20127
20908
|
}
|
|
20128
20909
|
function acquireUpdateLock() {
|
|
@@ -20139,12 +20920,12 @@ function realRestart(platform2) {
|
|
|
20139
20920
|
if (c) execSync2(c.cmd, { stdio: "ignore", ...c.shell ? { shell: c.shell } : {} });
|
|
20140
20921
|
}
|
|
20141
20922
|
function updateStatePath() {
|
|
20142
|
-
const dir = process.env.CHAT_RECALL_DATA_DIR ||
|
|
20143
|
-
return
|
|
20923
|
+
const dir = process.env.CHAT_RECALL_DATA_DIR || join42(homedir15(), ".chat-recall");
|
|
20924
|
+
return join42(dir, "auto-update-state.json");
|
|
20144
20925
|
}
|
|
20145
20926
|
function readUpdateState() {
|
|
20146
20927
|
try {
|
|
20147
|
-
return JSON.parse(
|
|
20928
|
+
return JSON.parse(readFileSync35(updateStatePath(), "utf8"));
|
|
20148
20929
|
} catch {
|
|
20149
20930
|
return {};
|
|
20150
20931
|
}
|
|
@@ -20285,9 +21066,9 @@ __export(sync_client_exports, {
|
|
|
20285
21066
|
syncIncremental: () => syncIncremental,
|
|
20286
21067
|
syncSessions: () => syncSessions
|
|
20287
21068
|
});
|
|
20288
|
-
import { join as
|
|
20289
|
-
import { readFileSync as
|
|
20290
|
-
import { tmpdir as
|
|
21069
|
+
import { join as join43, dirname as dirname19, basename as basename20 } from "node:path";
|
|
21070
|
+
import { readFileSync as readFileSync36, writeFileSync as writeFileSync9, mkdirSync as mkdirSync10, mkdtempSync as mkdtempSync4, rmSync as rmSync7, chmodSync as chmodSync3, unlinkSync as unlinkSync2, readdirSync as readdirSync31, statSync as statSync39 } from "node:fs";
|
|
21071
|
+
import { tmpdir as tmpdir4, hostname as hostname2 } from "node:os";
|
|
20291
21072
|
import { createHash as createHash9 } from "node:crypto";
|
|
20292
21073
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
20293
21074
|
import { gzipSync as gzipSync3 } from "zlib";
|
|
@@ -20341,7 +21122,7 @@ function loadAllCredentials() {
|
|
|
20341
21122
|
const fromEnv = envCredentials();
|
|
20342
21123
|
if (fromEnv) return [{ serverUrl: fromEnv.serverUrl, token: fromEnv.token }];
|
|
20343
21124
|
try {
|
|
20344
|
-
const parsed = JSON.parse(
|
|
21125
|
+
const parsed = JSON.parse(readFileSync36(credPath(), "utf-8"));
|
|
20345
21126
|
if (Array.isArray(parsed?.targets)) return parsed.targets.filter((t) => t?.serverUrl).map((t) => ({ serverUrl: t.serverUrl, token: t.token || "" }));
|
|
20346
21127
|
if (parsed?.serverUrl) return [{ serverUrl: parsed.serverUrl, token: parsed.token || "" }];
|
|
20347
21128
|
} catch {
|
|
@@ -20403,11 +21184,11 @@ function _resetTenantSecurityConfigCache() {
|
|
|
20403
21184
|
_securityConfigCache.clear();
|
|
20404
21185
|
}
|
|
20405
21186
|
function syncConfigCachePath() {
|
|
20406
|
-
return
|
|
21187
|
+
return join43(getDataDir(), "sync-config-cache.json");
|
|
20407
21188
|
}
|
|
20408
21189
|
function readPersistedSyncConfigs() {
|
|
20409
21190
|
try {
|
|
20410
|
-
return JSON.parse(
|
|
21191
|
+
return JSON.parse(readFileSync36(syncConfigCachePath(), "utf-8"));
|
|
20411
21192
|
} catch {
|
|
20412
21193
|
return {};
|
|
20413
21194
|
}
|
|
@@ -20685,7 +21466,7 @@ async function reconcileFields(opts = {}) {
|
|
|
20685
21466
|
}
|
|
20686
21467
|
return { sessions: fullRefs().length, scanned, pushed, absent, perTarget };
|
|
20687
21468
|
}
|
|
20688
|
-
function reapStaleScanDirs(dir =
|
|
21469
|
+
function reapStaleScanDirs(dir = tmpdir4(), maxAgeMs = 6 * 36e5, now = Date.now()) {
|
|
20689
21470
|
let reaped = 0;
|
|
20690
21471
|
let names;
|
|
20691
21472
|
try {
|
|
@@ -20695,10 +21476,10 @@ function reapStaleScanDirs(dir = tmpdir3(), maxAgeMs = 6 * 36e5, now = Date.now(
|
|
|
20695
21476
|
}
|
|
20696
21477
|
for (const name of names) {
|
|
20697
21478
|
if (!name.startsWith("cr-batchscan-")) continue;
|
|
20698
|
-
const p =
|
|
21479
|
+
const p = join43(dir, name);
|
|
20699
21480
|
try {
|
|
20700
|
-
if (now -
|
|
20701
|
-
|
|
21481
|
+
if (now - statSync39(p).mtimeMs < maxAgeMs) continue;
|
|
21482
|
+
rmSync7(p, { recursive: true, force: true });
|
|
20702
21483
|
reaped++;
|
|
20703
21484
|
} catch {
|
|
20704
21485
|
}
|
|
@@ -20712,7 +21493,7 @@ function batchScanExternal(items, opts = {}) {
|
|
|
20712
21493
|
let scanned = 0, slices = 0, scanMs = 0;
|
|
20713
21494
|
if (items.length === 0) return { findings, scanned, slices, scanMs };
|
|
20714
21495
|
reapStaleScanDirs();
|
|
20715
|
-
let scanDir = mkdtempSync4(
|
|
21496
|
+
let scanDir = mkdtempSync4(join43(tmpdir4(), "cr-batchscan-"));
|
|
20716
21497
|
let safeToId = /* @__PURE__ */ new Map();
|
|
20717
21498
|
let bytesInDir = 0;
|
|
20718
21499
|
const flushSlice = () => {
|
|
@@ -20730,7 +21511,7 @@ function batchScanExternal(items, opts = {}) {
|
|
|
20730
21511
|
slices++;
|
|
20731
21512
|
}
|
|
20732
21513
|
try {
|
|
20733
|
-
|
|
21514
|
+
rmSync7(scanDir, { recursive: true, force: true });
|
|
20734
21515
|
} catch {
|
|
20735
21516
|
}
|
|
20736
21517
|
safeToId = /* @__PURE__ */ new Map();
|
|
@@ -20743,19 +21524,19 @@ function batchScanExternal(items, opts = {}) {
|
|
|
20743
21524
|
if (raw === null) continue;
|
|
20744
21525
|
const safe = item.id.replace(/[^A-Za-z0-9_-]/g, "");
|
|
20745
21526
|
safeToId.set(safe, item.id);
|
|
20746
|
-
writeFileSync9(
|
|
21527
|
+
writeFileSync9(join43(scanDir, `${safe}.txt`), raw);
|
|
20747
21528
|
bytesInDir += Buffer.byteLength(raw);
|
|
20748
21529
|
} catch {
|
|
20749
21530
|
}
|
|
20750
21531
|
if (bytesInDir >= maxBytes) {
|
|
20751
21532
|
flushSlice();
|
|
20752
|
-
scanDir = mkdtempSync4(
|
|
21533
|
+
scanDir = mkdtempSync4(join43(tmpdir4(), "cr-batchscan-"));
|
|
20753
21534
|
}
|
|
20754
21535
|
}
|
|
20755
21536
|
flushSlice();
|
|
20756
21537
|
} finally {
|
|
20757
21538
|
try {
|
|
20758
|
-
|
|
21539
|
+
rmSync7(scanDir, { recursive: true, force: true });
|
|
20759
21540
|
} catch {
|
|
20760
21541
|
}
|
|
20761
21542
|
}
|
|
@@ -20967,6 +21748,11 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
20967
21748
|
};
|
|
20968
21749
|
const localSessionIds = /* @__PURE__ */ new Set();
|
|
20969
21750
|
const shippedHash = /* @__PURE__ */ new Map();
|
|
21751
|
+
const shippedLayout = /* @__PURE__ */ new Map();
|
|
21752
|
+
const layoutOf = (id) => {
|
|
21753
|
+
const layout = shippedLayout.get(id);
|
|
21754
|
+
return layout ? { layout } : {};
|
|
21755
|
+
};
|
|
20970
21756
|
const makeBatcher = (field, maxItems, flatten = false, onFlush, barrier) => {
|
|
20971
21757
|
let batch = [];
|
|
20972
21758
|
let batchBytes = 0;
|
|
@@ -20999,12 +21785,13 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
20999
21785
|
markSynced(base4, rows.map((r) => {
|
|
21000
21786
|
const off = typeof r.from_offset === "number" ? r.from_offset : 0;
|
|
21001
21787
|
const hash = shippedHash.get(r.session_id);
|
|
21002
|
-
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 };
|
|
21788
|
+
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 };
|
|
21003
21789
|
}));
|
|
21004
21790
|
} catch {
|
|
21005
21791
|
}
|
|
21006
21792
|
});
|
|
21007
21793
|
const appendResults = { uploaded: 0, fullResyncNeeded: /* @__PURE__ */ new Set() };
|
|
21794
|
+
const pendingArchives = [];
|
|
21008
21795
|
const postAppend = async (convs) => {
|
|
21009
21796
|
const headers = { "content-type": "application/json" };
|
|
21010
21797
|
if (cred.token) headers.authorization = `Bearer ${cred.token}`;
|
|
@@ -21039,8 +21826,11 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21039
21826
|
offset: c.from_offset,
|
|
21040
21827
|
size: c.from_offset,
|
|
21041
21828
|
// size = new offset (file grew to here)
|
|
21042
|
-
acked: true
|
|
21829
|
+
acked: true,
|
|
21043
21830
|
// server merged this tail
|
|
21831
|
+
chunkFinal: c.final === true,
|
|
21832
|
+
// completes a chunked full sync
|
|
21833
|
+
...layoutOf(c.session_id)
|
|
21044
21834
|
})));
|
|
21045
21835
|
} catch {
|
|
21046
21836
|
}
|
|
@@ -21072,9 +21862,9 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21072
21862
|
const mtime = conv.mtime;
|
|
21073
21863
|
try {
|
|
21074
21864
|
if (staged || !guarded) {
|
|
21075
|
-
markSynced(base4, [{ id, mtime, offset: conv.from_offset, size: conv.from_offset, acked: true }]);
|
|
21865
|
+
markSynced(base4, [{ id, mtime, offset: conv.from_offset, size: conv.from_offset, acked: true, chunkedHead: true, ...layoutOf(id) }]);
|
|
21076
21866
|
} else if (typeof guarded.o === "number" && guarded.o > 0 && guarded.o <= fileSize) {
|
|
21077
|
-
markSynced(base4, [{ id, mtime, offset: guarded.o, size: guarded.o, acked: true }]);
|
|
21867
|
+
markSynced(base4, [{ id, mtime, offset: guarded.o, size: guarded.o, acked: true, chunkedHead: true, ...layoutOf(id) }]);
|
|
21078
21868
|
} else {
|
|
21079
21869
|
markSynced(base4, [{ id, mtime }]);
|
|
21080
21870
|
}
|
|
@@ -21169,8 +21959,8 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21169
21959
|
if (!ledger) return ref.mtime >= (opts.sinceMs ?? 0) ? "full" : "skip";
|
|
21170
21960
|
const ack = ledger.get(ref.prefixedId);
|
|
21171
21961
|
const backend = backendFor(ref);
|
|
21172
|
-
const
|
|
21173
|
-
const isAO = !!backend?.isAppendOnly?.() &&
|
|
21962
|
+
const sameLayout = (ack?.L ?? "") === (backend?.sourceLayout?.(ref.prefixedId) ?? "");
|
|
21963
|
+
const isAO = !!backend?.isAppendOnly?.() && sameLayout;
|
|
21174
21964
|
const size = isAO ? backend?.fileSize?.(ref.prefixedId) ?? 0 : 0;
|
|
21175
21965
|
return syncMode(ack, ref.mtime, size, extractorVersionForTool(ref.toolId), isAO);
|
|
21176
21966
|
};
|
|
@@ -21217,6 +22007,9 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21217
22007
|
skipped++;
|
|
21218
22008
|
continue;
|
|
21219
22009
|
}
|
|
22010
|
+
const layout = backendFor(ref)?.sourceLayout?.(ref.prefixedId) ?? "";
|
|
22011
|
+
if (layout) shippedLayout.set(ref.prefixedId, layout);
|
|
22012
|
+
else shippedLayout.delete(ref.prefixedId);
|
|
21220
22013
|
trace?.(`build (${mode}) ${ref.prefixedId} \xB7 ${(sessionFileBytes(ref) / 1048576).toFixed(1)}MB`);
|
|
21221
22014
|
let promotedForFindings = false;
|
|
21222
22015
|
if (mode === "append" && ledger) {
|
|
@@ -21262,7 +22055,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21262
22055
|
const off = getBackendForId(ref.prefixedId)?.fileSize?.(ref.rawId) ?? 0;
|
|
21263
22056
|
const priorCursor = ackRow?.s ?? 0;
|
|
21264
22057
|
const safeToAck = off > 0 && off <= priorCursor;
|
|
21265
|
-
markSynced(base4, [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 }]);
|
|
22058
|
+
markSynced(base4, [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 }]);
|
|
21266
22059
|
} catch {
|
|
21267
22060
|
}
|
|
21268
22061
|
}
|
|
@@ -21283,6 +22076,14 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21283
22076
|
if (built.srcHash) shippedHash.set(ref.prefixedId, built.srcHash);
|
|
21284
22077
|
if (built.conv.chunked) await postChunkedHead(built.conv, sessionFileBytes(ref));
|
|
21285
22078
|
else await convBatch.add(built.conv);
|
|
22079
|
+
if (built.archive) {
|
|
22080
|
+
pendingArchives.push({
|
|
22081
|
+
id: ref.prefixedId,
|
|
22082
|
+
...built.archive,
|
|
22083
|
+
projectId: built.conv.project_id,
|
|
22084
|
+
projectPath: built.conv.project_path
|
|
22085
|
+
});
|
|
22086
|
+
}
|
|
21286
22087
|
if (built.findings.length > 0) await findingsBatch.add(built.findings);
|
|
21287
22088
|
if (upload.sessionMeta) {
|
|
21288
22089
|
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);
|
|
@@ -21435,6 +22236,30 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21435
22236
|
await kgTripleBatch.drain();
|
|
21436
22237
|
await findingsBatch.drain();
|
|
21437
22238
|
await drainInflight();
|
|
22239
|
+
let archivesUnsupported = false;
|
|
22240
|
+
for (const a of pendingArchives) {
|
|
22241
|
+
try {
|
|
22242
|
+
if (!archivesUnsupported) {
|
|
22243
|
+
const r = await uploadArchiveFile(base4, cred.token, {
|
|
22244
|
+
sessionId: a.id,
|
|
22245
|
+
tool: a.tool,
|
|
22246
|
+
mtime: a.mtime,
|
|
22247
|
+
projectId: a.projectId,
|
|
22248
|
+
projectPath: a.projectPath,
|
|
22249
|
+
file: a.file
|
|
22250
|
+
});
|
|
22251
|
+
if (r === "unsupported") archivesUnsupported = true;
|
|
22252
|
+
}
|
|
22253
|
+
} catch (err) {
|
|
22254
|
+
console.error(`[sync] raw archive for ${a.id} not uploaded (tried again when the session is next quiet): ${err instanceof Error ? err.message : err}`);
|
|
22255
|
+
try {
|
|
22256
|
+
forgetFullCoverage(base4, a.id);
|
|
22257
|
+
} catch {
|
|
22258
|
+
}
|
|
22259
|
+
} finally {
|
|
22260
|
+
rmSync7(a.file.path, { force: true });
|
|
22261
|
+
}
|
|
22262
|
+
}
|
|
21438
22263
|
{
|
|
21439
22264
|
const sentHashes = loadInventoryHashes(base4);
|
|
21440
22265
|
const entries = [];
|
|
@@ -21540,6 +22365,7 @@ async function buildConversationSync(ref, mtime, opts = {}) {
|
|
|
21540
22365
|
let includeRaw = opts.includeRaw !== false;
|
|
21541
22366
|
let includeMeta = opts.includeMeta !== false;
|
|
21542
22367
|
let srcHash;
|
|
22368
|
+
const wantRaw = opts.includeRaw !== false;
|
|
21543
22369
|
const oversized = sessionBuildBytes(ref) > FULL_BUILD_MAX_BYTES;
|
|
21544
22370
|
let headOffsetEnd = 0;
|
|
21545
22371
|
let oversizedFindings = null;
|
|
@@ -21708,7 +22534,7 @@ async function buildConversationSync(ref, mtime, opts = {}) {
|
|
|
21708
22534
|
} else if (opts.scanSecrets) {
|
|
21709
22535
|
let tmp = null;
|
|
21710
22536
|
try {
|
|
21711
|
-
tmp =
|
|
22537
|
+
tmp = join43(tmpdir4(), `cr-scan-${ref.prefixedId.replace(/[^A-Za-z0-9_-]/g, "")}-${mtime}.txt`);
|
|
21712
22538
|
writeFileSync9(tmp, rawText);
|
|
21713
22539
|
for (const f of scanFileForSecrets(tmp, { verifyOnly: opts.verifySecrets, tenantRules: opts.tenantRules })) {
|
|
21714
22540
|
const verifiedAt = f.verified ? (/* @__PURE__ */ new Date()).toISOString() : null;
|
|
@@ -21760,6 +22586,25 @@ async function buildConversationSync(ref, mtime, opts = {}) {
|
|
|
21760
22586
|
}
|
|
21761
22587
|
const envTexts = envelope.messages.filter((m) => m.content?.trim());
|
|
21762
22588
|
const redactedText = envTexts.map((m) => m.content).join("\n");
|
|
22589
|
+
let archive;
|
|
22590
|
+
if (wantRaw && !raw_b64) {
|
|
22591
|
+
try {
|
|
22592
|
+
const redact = (t) => redactSecrets(t, { force: true, count });
|
|
22593
|
+
let source = null;
|
|
22594
|
+
let archiveMtime = Math.floor(ref.mtime) || 0;
|
|
22595
|
+
let archiveTool = ref.toolId;
|
|
22596
|
+
if (container) {
|
|
22597
|
+
source = { kind: "memory", files: container.files };
|
|
22598
|
+
archiveMtime = container.mtime;
|
|
22599
|
+
archiveTool = container.tool;
|
|
22600
|
+
} else if (oversized) {
|
|
22601
|
+
source = diskArchiveSource(ref);
|
|
22602
|
+
}
|
|
22603
|
+
if (source) archive = { file: await writeArchiveFile(source, { tool: archiveTool, mtime: archiveMtime }, redact), tool: archiveTool, mtime: archiveMtime };
|
|
22604
|
+
} catch (err) {
|
|
22605
|
+
console.error(`[sync] raw archive for ${ref.prefixedId} not written: ${err instanceof Error ? err.message : err}`);
|
|
22606
|
+
}
|
|
22607
|
+
}
|
|
21763
22608
|
return {
|
|
21764
22609
|
conv: {
|
|
21765
22610
|
session_id: ref.prefixedId,
|
|
@@ -21791,7 +22636,17 @@ async function buildConversationSync(ref, mtime, opts = {}) {
|
|
|
21791
22636
|
redactions: count.redactions,
|
|
21792
22637
|
findings,
|
|
21793
22638
|
scanMs,
|
|
21794
|
-
srcHash
|
|
22639
|
+
srcHash,
|
|
22640
|
+
archive
|
|
22641
|
+
};
|
|
22642
|
+
}
|
|
22643
|
+
function diskArchiveSource(ref) {
|
|
22644
|
+
if (ref.toolId !== "claude") return null;
|
|
22645
|
+
const groups = resolveSessionContentGroups(ref.rawId);
|
|
22646
|
+
if (groups.length === 0 || groups.some((g) => g.paths.length !== 1)) return null;
|
|
22647
|
+
return {
|
|
22648
|
+
kind: "disk",
|
|
22649
|
+
files: groups.map((g) => ({ name: g.name === "main" ? `${ref.rawId}.jsonl` : g.name, path: g.paths[0] }))
|
|
21795
22650
|
};
|
|
21796
22651
|
}
|
|
21797
22652
|
function parseTailMessages(tool, text) {
|
|
@@ -21947,14 +22802,15 @@ var init_sync_client = __esm({
|
|
|
21947
22802
|
init_telemetry();
|
|
21948
22803
|
init_collector_health();
|
|
21949
22804
|
init_live_session_scan();
|
|
22805
|
+
init_raw_archive_parts();
|
|
21950
22806
|
init_backends();
|
|
21951
22807
|
ownVersion = "0.0.0";
|
|
21952
22808
|
try {
|
|
21953
22809
|
const dir = dirname19(fileURLToPath3(import.meta.url));
|
|
21954
|
-
ownVersion = JSON.parse(
|
|
22810
|
+
ownVersion = JSON.parse(readFileSync36(join43(dir, "../package.json"), "utf-8")).version || ownVersion;
|
|
21955
22811
|
} catch {
|
|
21956
22812
|
try {
|
|
21957
|
-
if (true) ownVersion = "0.7.
|
|
22813
|
+
if (true) ownVersion = "0.7.19";
|
|
21958
22814
|
} catch {
|
|
21959
22815
|
}
|
|
21960
22816
|
}
|
|
@@ -21966,7 +22822,7 @@ var init_sync_client = __esm({
|
|
|
21966
22822
|
]);
|
|
21967
22823
|
walkProgressForUpload = null;
|
|
21968
22824
|
lastServerPackSpec = null;
|
|
21969
|
-
credPath = () =>
|
|
22825
|
+
credPath = () => join43(getDataDir(), "credentials.json");
|
|
21970
22826
|
_securityConfigCache = /* @__PURE__ */ new Map();
|
|
21971
22827
|
SECURITY_CONFIG_TTL_MS = 5 * 60 * 1e3;
|
|
21972
22828
|
_syncConfigCache = /* @__PURE__ */ new Map();
|
|
@@ -21997,15 +22853,15 @@ __export(update_notice_exports, {
|
|
|
21997
22853
|
refreshUpdateCheck: () => refreshUpdateCheck,
|
|
21998
22854
|
updateNotice: () => updateNotice
|
|
21999
22855
|
});
|
|
22000
|
-
import { readFileSync as
|
|
22001
|
-
import { join as
|
|
22856
|
+
import { readFileSync as readFileSync37, writeFileSync as writeFileSync10 } from "node:fs";
|
|
22857
|
+
import { join as join44 } from "node:path";
|
|
22002
22858
|
function newestKnown(c) {
|
|
22003
22859
|
const npm = c.npmVersion ?? "0.0.0";
|
|
22004
22860
|
return compareVersions(npm, c.serverVersion) > 0 ? { version: npm, source: "npm" } : { version: c.serverVersion, source: "server" };
|
|
22005
22861
|
}
|
|
22006
22862
|
function readCheck() {
|
|
22007
22863
|
try {
|
|
22008
|
-
const c = JSON.parse(
|
|
22864
|
+
const c = JSON.parse(readFileSync37(checkPath(), "utf-8"));
|
|
22009
22865
|
return c && typeof c.serverVersion === "string" ? c : null;
|
|
22010
22866
|
} catch {
|
|
22011
22867
|
return null;
|
|
@@ -22099,17 +22955,17 @@ var init_update_notice = __esm({
|
|
|
22099
22955
|
init_http();
|
|
22100
22956
|
CHECK_TTL_MS = 6 * 3600 * 1e3;
|
|
22101
22957
|
NPM_LATEST_URL = "https://registry.npmjs.org/chat-recall";
|
|
22102
|
-
checkPath = () =>
|
|
22958
|
+
checkPath = () => join44(getDataDir(), "update-check.json");
|
|
22103
22959
|
printed = false;
|
|
22104
22960
|
}
|
|
22105
22961
|
});
|
|
22106
22962
|
|
|
22107
22963
|
// ../engine/dist/core/which.js
|
|
22108
|
-
import { existsSync as
|
|
22109
|
-
import { join as
|
|
22964
|
+
import { existsSync as existsSync43, statSync as statSync40, accessSync, constants } from "node:fs";
|
|
22965
|
+
import { join as join45, isAbsolute as isAbsolute2, delimiter as delimiter2, sep as sep3 } from "node:path";
|
|
22110
22966
|
function executable(p) {
|
|
22111
22967
|
try {
|
|
22112
|
-
if (!
|
|
22968
|
+
if (!statSync40(p).isFile())
|
|
22113
22969
|
return false;
|
|
22114
22970
|
} catch {
|
|
22115
22971
|
return false;
|
|
@@ -22145,8 +23001,8 @@ function resolveOnPath(name) {
|
|
|
22145
23001
|
if (!dir)
|
|
22146
23002
|
continue;
|
|
22147
23003
|
for (const c of candidates(name)) {
|
|
22148
|
-
const full =
|
|
22149
|
-
if (
|
|
23004
|
+
const full = join45(dir, c);
|
|
23005
|
+
if (existsSync43(full) && executable(full))
|
|
22150
23006
|
return full;
|
|
22151
23007
|
}
|
|
22152
23008
|
}
|
|
@@ -22209,9 +23065,9 @@ __export(mcp_clients_exports, {
|
|
|
22209
23065
|
inspectMcpClients: () => inspectMcpClients,
|
|
22210
23066
|
registerMcpEverywhere: () => registerMcpEverywhere
|
|
22211
23067
|
});
|
|
22212
|
-
import { existsSync as
|
|
23068
|
+
import { existsSync as existsSync45, mkdirSync as mkdirSync12, readFileSync as readFileSync38, writeFileSync as writeFileSync12 } from "fs";
|
|
22213
23069
|
import { homedir as homedir16 } from "os";
|
|
22214
|
-
import { dirname as dirname21, join as
|
|
23070
|
+
import { dirname as dirname21, join as join47 } from "path";
|
|
22215
23071
|
function envHome(varName, fallback) {
|
|
22216
23072
|
const v = process.env[varName];
|
|
22217
23073
|
return v && v.trim() ? v.trim() : fallback;
|
|
@@ -22221,14 +23077,14 @@ function writeFileMkdir(path, body2) {
|
|
|
22221
23077
|
writeFileSync12(path, body2);
|
|
22222
23078
|
}
|
|
22223
23079
|
function readJsonObject(path) {
|
|
22224
|
-
const raw =
|
|
23080
|
+
const raw = readFileSync38(path, "utf-8");
|
|
22225
23081
|
if (raw.trim() === "")
|
|
22226
23082
|
return {};
|
|
22227
23083
|
return JSON.parse(raw);
|
|
22228
23084
|
}
|
|
22229
23085
|
function registerMcpServersJson(target, path, spec) {
|
|
22230
23086
|
let cfg = {};
|
|
22231
|
-
if (
|
|
23087
|
+
if (existsSync45(path)) {
|
|
22232
23088
|
try {
|
|
22233
23089
|
cfg = readJsonObject(path);
|
|
22234
23090
|
} catch (err) {
|
|
@@ -22257,7 +23113,7 @@ function registerOpencodeJson(path, spec) {
|
|
|
22257
23113
|
const id = "opencode";
|
|
22258
23114
|
const label = "OpenCode";
|
|
22259
23115
|
let cfg = {};
|
|
22260
|
-
if (
|
|
23116
|
+
if (existsSync45(path)) {
|
|
22261
23117
|
try {
|
|
22262
23118
|
cfg = readJsonObject(path);
|
|
22263
23119
|
} catch (err) {
|
|
@@ -22296,7 +23152,7 @@ function registerCodexToml(path, spec) {
|
|
|
22296
23152
|
const id = "codex";
|
|
22297
23153
|
const label = "Codex";
|
|
22298
23154
|
const block = codexBlock(spec);
|
|
22299
|
-
const prev =
|
|
23155
|
+
const prev = existsSync45(path) ? readFileSync38(path, "utf-8") : "";
|
|
22300
23156
|
const lines = prev.length ? prev.split("\n") : [];
|
|
22301
23157
|
const start = lines.findIndex((l) => l.trim() === CODEX_HEADER);
|
|
22302
23158
|
if (start === -1) {
|
|
@@ -22337,9 +23193,9 @@ function inspectMcpClients(opts = {}) {
|
|
|
22337
23193
|
return MCP_CLIENTS.map((c) => {
|
|
22338
23194
|
const path = c.configPath(home);
|
|
22339
23195
|
let registered = false;
|
|
22340
|
-
if (
|
|
23196
|
+
if (existsSync45(path)) {
|
|
22341
23197
|
try {
|
|
22342
|
-
const raw =
|
|
23198
|
+
const raw = readFileSync38(path, "utf-8");
|
|
22343
23199
|
registered = c.id === "codex" ? raw.includes(CODEX_HEADER) : !!(JSON.parse(raw).mcpServers?.[MCP_SERVER_NAME] ?? JSON.parse(raw).mcp?.[MCP_SERVER_NAME]);
|
|
22344
23200
|
} catch {
|
|
22345
23201
|
registered = false;
|
|
@@ -22359,7 +23215,7 @@ var init_mcp_clients = __esm({
|
|
|
22359
23215
|
id: "claude",
|
|
22360
23216
|
label: "Claude Code",
|
|
22361
23217
|
bin: "claude",
|
|
22362
|
-
configPath: (home) =>
|
|
23218
|
+
configPath: (home) => join47(home, ".mcp.json"),
|
|
22363
23219
|
// Claude Code is the reference client and `init`'s historical target, so we
|
|
22364
23220
|
// always write it — a fresh machine has no ~/.claude yet on first install.
|
|
22365
23221
|
isPresent: () => true,
|
|
@@ -22371,10 +23227,10 @@ var init_mcp_clients = __esm({
|
|
|
22371
23227
|
id: "codex",
|
|
22372
23228
|
label: "Codex",
|
|
22373
23229
|
bin: "codex",
|
|
22374
|
-
configPath: (home) =>
|
|
23230
|
+
configPath: (home) => join47(envHome("CHAT_RECALL_CODEX_HOME", join47(home, ".codex")), "config.toml"),
|
|
22375
23231
|
isPresent(home) {
|
|
22376
23232
|
const p = this.configPath(home);
|
|
22377
|
-
return
|
|
23233
|
+
return existsSync45(p) || existsSync45(dirname21(p));
|
|
22378
23234
|
},
|
|
22379
23235
|
register(spec, home) {
|
|
22380
23236
|
return registerCodexToml(this.configPath(home), spec);
|
|
@@ -22384,10 +23240,10 @@ var init_mcp_clients = __esm({
|
|
|
22384
23240
|
id: "opencode",
|
|
22385
23241
|
label: "OpenCode",
|
|
22386
23242
|
bin: "opencode",
|
|
22387
|
-
configPath: (home) =>
|
|
23243
|
+
configPath: (home) => join47(envHome("XDG_CONFIG_HOME", join47(home, ".config")), "opencode", "opencode.json"),
|
|
22388
23244
|
isPresent(home) {
|
|
22389
23245
|
const p = this.configPath(home);
|
|
22390
|
-
return
|
|
23246
|
+
return existsSync45(p) || existsSync45(dirname21(p));
|
|
22391
23247
|
},
|
|
22392
23248
|
register(spec, home) {
|
|
22393
23249
|
return registerOpencodeJson(this.configPath(home), spec);
|
|
@@ -22399,9 +23255,9 @@ var init_mcp_clients = __esm({
|
|
|
22399
23255
|
id: "agy",
|
|
22400
23256
|
label: "Antigravity",
|
|
22401
23257
|
bin: "agy",
|
|
22402
|
-
configPath: (home) =>
|
|
23258
|
+
configPath: (home) => join47(home, ".gemini", "config", "mcp_config.json"),
|
|
22403
23259
|
isPresent(home) {
|
|
22404
|
-
return
|
|
23260
|
+
return existsSync45(join47(home, ".gemini", "antigravity-cli")) || existsSync45(this.configPath(home));
|
|
22405
23261
|
},
|
|
22406
23262
|
register(spec, home) {
|
|
22407
23263
|
return registerMcpServersJson(this, this.configPath(home), spec);
|
|
@@ -22411,10 +23267,10 @@ var init_mcp_clients = __esm({
|
|
|
22411
23267
|
id: "cursor",
|
|
22412
23268
|
label: "Cursor",
|
|
22413
23269
|
bin: "cursor",
|
|
22414
|
-
configPath: (home) =>
|
|
23270
|
+
configPath: (home) => join47(home, ".cursor", "mcp.json"),
|
|
22415
23271
|
isPresent(home) {
|
|
22416
23272
|
const p = this.configPath(home);
|
|
22417
|
-
return
|
|
23273
|
+
return existsSync45(p) || existsSync45(dirname21(p));
|
|
22418
23274
|
},
|
|
22419
23275
|
register(spec, home) {
|
|
22420
23276
|
return registerMcpServersJson(this, this.configPath(home), spec);
|
|
@@ -22438,9 +23294,9 @@ __export(companions_exports, {
|
|
|
22438
23294
|
uninstallCodeindex: () => uninstallCodeindex,
|
|
22439
23295
|
unregisterCodeindexMcp: () => unregisterCodeindexMcp
|
|
22440
23296
|
});
|
|
22441
|
-
import { existsSync as
|
|
23297
|
+
import { existsSync as existsSync46, mkdirSync as mkdirSync13, statSync as statSync41, chmodSync as chmodSync4, unlinkSync as unlinkSync3, renameSync as renameSync5, createWriteStream as createWriteStream2, readFileSync as readFileSync39, writeFileSync as writeFileSync13 } from "node:fs";
|
|
22442
23298
|
import { homedir as homedir17 } from "node:os";
|
|
22443
|
-
import { join as
|
|
23299
|
+
import { join as join48 } from "node:path";
|
|
22444
23300
|
import { execSync as execSync3 } from "node:child_process";
|
|
22445
23301
|
import { createHash as createHash10 } from "node:crypto";
|
|
22446
23302
|
function expectedCodeindexSha256(artifact) {
|
|
@@ -22489,7 +23345,7 @@ function checkCodeindexStatus() {
|
|
|
22489
23345
|
status.installed = true;
|
|
22490
23346
|
status.path = foundPath;
|
|
22491
23347
|
try {
|
|
22492
|
-
status.size =
|
|
23348
|
+
status.size = statSync41(foundPath).size;
|
|
22493
23349
|
} catch {
|
|
22494
23350
|
}
|
|
22495
23351
|
try {
|
|
@@ -22515,7 +23371,7 @@ async function downloadArtifact(artifact, dest) {
|
|
|
22515
23371
|
throw new Error(`Download failed: ${res.status} ${res.statusText}`);
|
|
22516
23372
|
if (!res.body)
|
|
22517
23373
|
throw new Error("Download returned empty body");
|
|
22518
|
-
const file =
|
|
23374
|
+
const file = createWriteStream2(dest);
|
|
22519
23375
|
await new Promise((resolve3, reject) => {
|
|
22520
23376
|
const reader = res.body.getReader();
|
|
22521
23377
|
const pump = async () => {
|
|
@@ -22550,7 +23406,7 @@ async function installCodeindex(opts = {}) {
|
|
|
22550
23406
|
if (!expected) {
|
|
22551
23407
|
throw new Error(`No pinned checksum for ${status.artifactName} \u2014 refusing to install an unverified binary. Add its sha256 to CODEINDEX_SHA256 in companions.ts.`);
|
|
22552
23408
|
}
|
|
22553
|
-
const actual = createHash10("sha256").update(
|
|
23409
|
+
const actual = createHash10("sha256").update(readFileSync39(tmpPath)).digest("hex");
|
|
22554
23410
|
if (actual !== expected) {
|
|
22555
23411
|
throw new Error(`Checksum mismatch for ${status.artifactName}.
|
|
22556
23412
|
expected ${expected}
|
|
@@ -22561,7 +23417,7 @@ Refusing to install. The release may have been re-uploaded, or something is serv
|
|
|
22561
23417
|
renameSync5(tmpPath, CODEINDEX_BIN_PATH);
|
|
22562
23418
|
} catch (err) {
|
|
22563
23419
|
try {
|
|
22564
|
-
if (
|
|
23420
|
+
if (existsSync46(tmpPath))
|
|
22565
23421
|
unlinkSync3(tmpPath);
|
|
22566
23422
|
} catch {
|
|
22567
23423
|
}
|
|
@@ -22570,7 +23426,7 @@ Refusing to install. The release may have been re-uploaded, or something is serv
|
|
|
22570
23426
|
return checkCodeindexStatus();
|
|
22571
23427
|
}
|
|
22572
23428
|
function uninstallCodeindex() {
|
|
22573
|
-
if (
|
|
23429
|
+
if (existsSync46(CODEINDEX_BIN_PATH)) {
|
|
22574
23430
|
unlinkSync3(CODEINDEX_BIN_PATH);
|
|
22575
23431
|
return { removed: true, path: CODEINDEX_BIN_PATH };
|
|
22576
23432
|
}
|
|
@@ -22578,9 +23434,9 @@ function uninstallCodeindex() {
|
|
|
22578
23434
|
}
|
|
22579
23435
|
function registerCodeindexMcp(mcpJsonPath, binaryPath) {
|
|
22580
23436
|
let cfg = {};
|
|
22581
|
-
if (
|
|
23437
|
+
if (existsSync46(mcpJsonPath)) {
|
|
22582
23438
|
try {
|
|
22583
|
-
cfg = JSON.parse(
|
|
23439
|
+
cfg = JSON.parse(readFileSync39(mcpJsonPath, "utf-8"));
|
|
22584
23440
|
} catch {
|
|
22585
23441
|
cfg = {};
|
|
22586
23442
|
}
|
|
@@ -22593,11 +23449,11 @@ function registerCodeindexMcp(mcpJsonPath, binaryPath) {
|
|
|
22593
23449
|
return { added: true };
|
|
22594
23450
|
}
|
|
22595
23451
|
function unregisterCodeindexMcp(mcpJsonPath) {
|
|
22596
|
-
if (!
|
|
23452
|
+
if (!existsSync46(mcpJsonPath))
|
|
22597
23453
|
return { removed: false };
|
|
22598
23454
|
let cfg;
|
|
22599
23455
|
try {
|
|
22600
|
-
cfg = JSON.parse(
|
|
23456
|
+
cfg = JSON.parse(readFileSync39(mcpJsonPath, "utf-8"));
|
|
22601
23457
|
} catch {
|
|
22602
23458
|
return { removed: false };
|
|
22603
23459
|
}
|
|
@@ -22622,9 +23478,9 @@ var init_companions = __esm({
|
|
|
22622
23478
|
"x86_64-windows": "a96fc8c8949bb399a44cc0615b12e458460a529c69f01e8829cc39a20f45ab29",
|
|
22623
23479
|
"aarch64-windows": "42620d56272cd9ba9d785569d8d754d6b4a3e80f36f28db3e0c483fd600ed117"
|
|
22624
23480
|
};
|
|
22625
|
-
CODEINDEX_INSTALL_DIR =
|
|
23481
|
+
CODEINDEX_INSTALL_DIR = join48(homedir17(), ".local", "bin");
|
|
22626
23482
|
CODEINDEX_BIN_NAME = process.platform === "win32" ? "codeindex.exe" : "codeindex";
|
|
22627
|
-
CODEINDEX_BIN_PATH =
|
|
23483
|
+
CODEINDEX_BIN_PATH = join48(CODEINDEX_INSTALL_DIR, CODEINDEX_BIN_NAME);
|
|
22628
23484
|
}
|
|
22629
23485
|
});
|
|
22630
23486
|
|
|
@@ -22639,15 +23495,15 @@ __export(install_skills_exports, {
|
|
|
22639
23495
|
skillsSourceDir: () => skillsSourceDir,
|
|
22640
23496
|
uninstallSkills: () => uninstallSkills
|
|
22641
23497
|
});
|
|
22642
|
-
import { readdirSync as readdirSync32, existsSync as
|
|
23498
|
+
import { readdirSync as readdirSync32, existsSync as existsSync47, mkdirSync as mkdirSync14, rmSync as rmSync8, cpSync, writeFileSync as writeFileSync14, readFileSync as readFileSync40, statSync as statSync42, realpathSync as realpathSync4 } from "fs";
|
|
22643
23499
|
import { createHash as createHash11 } from "crypto";
|
|
22644
|
-
import { join as
|
|
23500
|
+
import { join as join49, basename as basename21 } from "path";
|
|
22645
23501
|
function skillsSourceDir() {
|
|
22646
|
-
return
|
|
23502
|
+
return join49(import.meta.dirname, "..", "skills");
|
|
22647
23503
|
}
|
|
22648
23504
|
function version() {
|
|
22649
23505
|
try {
|
|
22650
|
-
return JSON.parse(
|
|
23506
|
+
return JSON.parse(readFileSync40(new URL("../package.json", import.meta.url), "utf-8")).version || "0.0.0";
|
|
22651
23507
|
} catch {
|
|
22652
23508
|
return "0.0.0";
|
|
22653
23509
|
}
|
|
@@ -22656,9 +23512,9 @@ function skillsFingerprint() {
|
|
|
22656
23512
|
const src = skillsSourceDir();
|
|
22657
23513
|
const h = createHash11("sha256");
|
|
22658
23514
|
for (const name of bundledSkillNames()) {
|
|
22659
|
-
for (const rel of filesUnder(
|
|
23515
|
+
for (const rel of filesUnder(join49(src, name)).sort()) {
|
|
22660
23516
|
h.update(name + "/" + rel);
|
|
22661
|
-
h.update(
|
|
23517
|
+
h.update(readFileSync40(join49(src, name, rel)));
|
|
22662
23518
|
}
|
|
22663
23519
|
}
|
|
22664
23520
|
return h.digest("hex").slice(0, 12);
|
|
@@ -22668,7 +23524,7 @@ function filesUnder(dir, prefix = "") {
|
|
|
22668
23524
|
for (const e of readdirSync32(dir, { withFileTypes: true })) {
|
|
22669
23525
|
if (e.name === MARKER) continue;
|
|
22670
23526
|
const rel = prefix ? `${prefix}/${e.name}` : e.name;
|
|
22671
|
-
if (e.isDirectory()) out.push(...filesUnder(
|
|
23527
|
+
if (e.isDirectory()) out.push(...filesUnder(join49(dir, e.name), rel));
|
|
22672
23528
|
else out.push(rel);
|
|
22673
23529
|
}
|
|
22674
23530
|
return out;
|
|
@@ -22678,8 +23534,8 @@ function skillStamp() {
|
|
|
22678
23534
|
}
|
|
22679
23535
|
function bundledSkillNames() {
|
|
22680
23536
|
const src = skillsSourceDir();
|
|
22681
|
-
if (!
|
|
22682
|
-
return readdirSync32(src, { withFileTypes: true }).filter((e) => e.isDirectory() &&
|
|
23537
|
+
if (!existsSync47(src)) return [];
|
|
23538
|
+
return readdirSync32(src, { withFileTypes: true }).filter((e) => e.isDirectory() && existsSync47(join49(src, e.name, "SKILL.md"))).map((e) => e.name).sort();
|
|
22683
23539
|
}
|
|
22684
23540
|
function realPathOrSelf(p) {
|
|
22685
23541
|
try {
|
|
@@ -22692,7 +23548,7 @@ function claudeSkillTargets() {
|
|
|
22692
23548
|
const targets = [];
|
|
22693
23549
|
const seen = /* @__PURE__ */ new Set();
|
|
22694
23550
|
for (const home of claudeHomeDirs()) {
|
|
22695
|
-
const dir =
|
|
23551
|
+
const dir = join49(home, "skills");
|
|
22696
23552
|
const key2 = realPathOrSelf(dir);
|
|
22697
23553
|
if (seen.has(key2)) continue;
|
|
22698
23554
|
seen.add(key2);
|
|
@@ -22703,7 +23559,7 @@ function claudeSkillTargets() {
|
|
|
22703
23559
|
dir,
|
|
22704
23560
|
// Judge each profile on ITS OWN transcripts, not the primary's: a home
|
|
22705
23561
|
// with no projects/ is a directory someone made, not a Claude install.
|
|
22706
|
-
available:
|
|
23562
|
+
available: existsSync47(join49(home, "projects"))
|
|
22707
23563
|
});
|
|
22708
23564
|
}
|
|
22709
23565
|
if (targets.length === 0) {
|
|
@@ -22718,16 +23574,16 @@ function skillTargets() {
|
|
|
22718
23574
|
// both produces "skill conflict" duplicate warnings. Every tool we support
|
|
22719
23575
|
// has its own dir, so per-tool coverage is complete.
|
|
22720
23576
|
...claudeSkillTargets(),
|
|
22721
|
-
{ id: "agy", label: "Antigravity", dir:
|
|
23577
|
+
{ id: "agy", label: "Antigravity", dir: join49(agyBackend.homeDir(), "skills"), available: agyBackend.isAvailable() },
|
|
22722
23578
|
{ id: "codex", label: "Codex", dir: codexBackend.skillsDir(), available: codexBackend.isAvailable() },
|
|
22723
23579
|
{ id: "opencode", label: "OpenCode", dir: opencodeBackend.skillsDir(), available: opencodeBackend.isAvailable() },
|
|
22724
23580
|
// Cursor DOES have its own dir (~/.cursor/skills). `skills-cursor` next to
|
|
22725
23581
|
// it is Cursor's bundled set — read-only, never an install target.
|
|
22726
|
-
{ id: "cursor", label: "Cursor", dir:
|
|
23582
|
+
{ id: "cursor", label: "Cursor", dir: join49(cursorHomeDir(), "skills"), available: cursorBackend.isAvailable() }
|
|
22727
23583
|
];
|
|
22728
23584
|
}
|
|
22729
23585
|
function isManaged(dir) {
|
|
22730
|
-
return
|
|
23586
|
+
return existsSync47(join49(dir, MARKER));
|
|
22731
23587
|
}
|
|
22732
23588
|
function installSkills(opts = {}) {
|
|
22733
23589
|
const onlyAvailable = opts.onlyAvailable ?? true;
|
|
@@ -22744,15 +23600,15 @@ function installSkills(opts = {}) {
|
|
|
22744
23600
|
continue;
|
|
22745
23601
|
}
|
|
22746
23602
|
for (const name of names) {
|
|
22747
|
-
const dest =
|
|
22748
|
-
if (
|
|
23603
|
+
const dest = join49(t.dir, name);
|
|
23604
|
+
if (existsSync47(dest) && !isManaged(dest)) {
|
|
22749
23605
|
skippedUserOwned.push(name);
|
|
22750
23606
|
continue;
|
|
22751
23607
|
}
|
|
22752
23608
|
mkdirSync14(t.dir, { recursive: true });
|
|
22753
|
-
|
|
22754
|
-
cpSync(
|
|
22755
|
-
writeFileSync14(
|
|
23609
|
+
rmSync8(dest, { recursive: true, force: true });
|
|
23610
|
+
cpSync(join49(src, name), dest, { recursive: true });
|
|
23611
|
+
writeFileSync14(join49(dest, MARKER), `${stamp}
|
|
22756
23612
|
`);
|
|
22757
23613
|
installed.push(name);
|
|
22758
23614
|
}
|
|
@@ -22765,15 +23621,15 @@ function uninstallSkills() {
|
|
|
22765
23621
|
const perTarget = [];
|
|
22766
23622
|
for (const t of skillTargets()) {
|
|
22767
23623
|
const removed = [];
|
|
22768
|
-
if (!
|
|
23624
|
+
if (!existsSync47(t.dir)) {
|
|
22769
23625
|
perTarget.push({ id: t.id, label: t.label, removed });
|
|
22770
23626
|
continue;
|
|
22771
23627
|
}
|
|
22772
23628
|
for (const entry of readdirSync32(t.dir, { withFileTypes: true })) {
|
|
22773
23629
|
if (!entry.isDirectory()) continue;
|
|
22774
|
-
const dir =
|
|
23630
|
+
const dir = join49(t.dir, entry.name);
|
|
22775
23631
|
if (isManaged(dir) && (names.has(entry.name) || entry.name.startsWith("chat-recall"))) {
|
|
22776
|
-
|
|
23632
|
+
rmSync8(dir, { recursive: true, force: true });
|
|
22777
23633
|
removed.push(entry.name);
|
|
22778
23634
|
}
|
|
22779
23635
|
}
|
|
@@ -22788,10 +23644,10 @@ function skillsNeedRefresh() {
|
|
|
22788
23644
|
for (const t of skillTargets()) {
|
|
22789
23645
|
if (!t.available) continue;
|
|
22790
23646
|
for (const name of names) {
|
|
22791
|
-
const marker =
|
|
22792
|
-
if (!
|
|
23647
|
+
const marker = join49(t.dir, name, MARKER);
|
|
23648
|
+
if (!existsSync47(marker)) return true;
|
|
22793
23649
|
try {
|
|
22794
|
-
if (
|
|
23650
|
+
if (readFileSync40(marker, "utf-8").trim() !== cur) return true;
|
|
22795
23651
|
} catch {
|
|
22796
23652
|
return true;
|
|
22797
23653
|
}
|
|
@@ -22806,11 +23662,11 @@ function skillStatus() {
|
|
|
22806
23662
|
let installed = 0;
|
|
22807
23663
|
let ver = null;
|
|
22808
23664
|
for (const name of names) {
|
|
22809
|
-
const marker =
|
|
22810
|
-
if (
|
|
23665
|
+
const marker = join49(t.dir, name, MARKER);
|
|
23666
|
+
if (existsSync47(marker)) {
|
|
22811
23667
|
installed++;
|
|
22812
23668
|
try {
|
|
22813
|
-
ver =
|
|
23669
|
+
ver = readFileSync40(marker, "utf-8").trim();
|
|
22814
23670
|
} catch {
|
|
22815
23671
|
}
|
|
22816
23672
|
}
|
|
@@ -22834,8 +23690,8 @@ var init_install_skills = __esm({
|
|
|
22834
23690
|
});
|
|
22835
23691
|
|
|
22836
23692
|
// ../engine/dist/core/artifact-codec.js
|
|
22837
|
-
import { readFileSync as
|
|
22838
|
-
import { basename as basename22, join as
|
|
23693
|
+
import { readFileSync as readFileSync41 } from "fs";
|
|
23694
|
+
import { basename as basename22, join as join50 } from "path";
|
|
22839
23695
|
import { homedir as homedir18 } from "os";
|
|
22840
23696
|
function parseCommandText(content, format, fallbackName) {
|
|
22841
23697
|
if (format === "toml") {
|
|
@@ -22858,41 +23714,41 @@ function parseAgentText(content, format, fallbackName) {
|
|
|
22858
23714
|
return { name: fm.name || fallbackName, description: fm.description || "", tools: fm.tools, body: body2.trim() };
|
|
22859
23715
|
}
|
|
22860
23716
|
function readCommand(filePath, format) {
|
|
22861
|
-
return parseCommandText(
|
|
23717
|
+
return parseCommandText(readFileSync41(filePath, "utf-8"), format, base2(filePath));
|
|
22862
23718
|
}
|
|
22863
23719
|
function readAgent(filePath, format) {
|
|
22864
|
-
return parseAgentText(
|
|
23720
|
+
return parseAgentText(readFileSync41(filePath, "utf-8"), format, base2(filePath));
|
|
22865
23721
|
}
|
|
22866
23722
|
function readInstructions(filePath, name) {
|
|
22867
|
-
const content =
|
|
23723
|
+
const content = readFileSync41(filePath, "utf-8");
|
|
22868
23724
|
return { name, description: "", body: content };
|
|
22869
23725
|
}
|
|
22870
23726
|
function commandPath(tool, name) {
|
|
22871
23727
|
switch (tool) {
|
|
22872
23728
|
case "claude":
|
|
22873
|
-
return
|
|
23729
|
+
return join50(claudeBackend.commandsDir(), `${name}.md`);
|
|
22874
23730
|
case "agy":
|
|
22875
|
-
return
|
|
23731
|
+
return join50(join50(agyBackend.homeDir(), "commands"), `${name}.toml`);
|
|
22876
23732
|
case "opencode":
|
|
22877
|
-
return
|
|
23733
|
+
return join50(opencodeBackend.commandsDir(), `${name}.md`);
|
|
22878
23734
|
case "codex":
|
|
22879
|
-
return
|
|
23735
|
+
return join50(codexBackend.promptsDir(), `${name}.md`);
|
|
22880
23736
|
case "cursor":
|
|
22881
|
-
return
|
|
23737
|
+
return join50(cursorHomeDir(), "commands", `${name}.md`);
|
|
22882
23738
|
}
|
|
22883
23739
|
}
|
|
22884
23740
|
function agentPath(tool, name) {
|
|
22885
23741
|
switch (tool) {
|
|
22886
23742
|
case "claude":
|
|
22887
|
-
return
|
|
23743
|
+
return join50(claudeBackend.agentsDir(), `${name}.md`);
|
|
22888
23744
|
case "agy":
|
|
22889
|
-
return
|
|
23745
|
+
return join50(join50(agyBackend.homeDir(), "agents"), `${name}.md`);
|
|
22890
23746
|
case "opencode":
|
|
22891
|
-
return
|
|
23747
|
+
return join50(opencodeBackend.agentsDir(), `${name}.md`);
|
|
22892
23748
|
case "codex":
|
|
22893
|
-
return
|
|
23749
|
+
return join50(codexBackend.agentsDir(), `${name}.toml`);
|
|
22894
23750
|
case "cursor":
|
|
22895
|
-
return
|
|
23751
|
+
return join50(cursorHomeDir(), "agents", `${name}.md`);
|
|
22896
23752
|
}
|
|
22897
23753
|
}
|
|
22898
23754
|
function instructionsFilename(tool) {
|
|
@@ -22917,21 +23773,21 @@ function instructionsFilename(tool) {
|
|
|
22917
23773
|
function instructionsPath(tool, projectPath) {
|
|
22918
23774
|
const file = instructionsFilename(tool);
|
|
22919
23775
|
if (projectPath)
|
|
22920
|
-
return
|
|
23776
|
+
return join50(projectPath, file);
|
|
22921
23777
|
switch (tool) {
|
|
22922
23778
|
case "claude":
|
|
22923
|
-
return
|
|
23779
|
+
return join50(claudeBackend.homeDir(), file);
|
|
22924
23780
|
case "agy":
|
|
22925
|
-
return
|
|
23781
|
+
return join50(agyBackend.homeDir(), file);
|
|
22926
23782
|
case "codex":
|
|
22927
|
-
return
|
|
23783
|
+
return join50(codexBackend.homeDir(), file);
|
|
22928
23784
|
case "opencode":
|
|
22929
|
-
return
|
|
23785
|
+
return join50(homedir18(), ".config", "opencode", file);
|
|
22930
23786
|
// Cursor has no single user-scope instructions FILE — user-level guidance
|
|
22931
23787
|
// is User Rules plus ~/.cursor/rules/*.mdc. AGENTS.md at the home root is
|
|
22932
23788
|
// the closest equivalent and is what a mirror can actually write.
|
|
22933
23789
|
case "cursor":
|
|
22934
|
-
return
|
|
23790
|
+
return join50(cursorHomeDir(), file);
|
|
22935
23791
|
}
|
|
22936
23792
|
}
|
|
22937
23793
|
function emit(type, art, toTool, projectPath) {
|
|
@@ -22995,8 +23851,8 @@ __export(toolkit_sync_exports, {
|
|
|
22995
23851
|
supportedTargetsFor: () => supportedTargetsFor,
|
|
22996
23852
|
writeMcpEntry: () => writeMcpEntry
|
|
22997
23853
|
});
|
|
22998
|
-
import { existsSync as
|
|
22999
|
-
import { dirname as dirname22, join as
|
|
23854
|
+
import { existsSync as existsSync48, mkdirSync as mkdirSync15, readFileSync as readFileSync42, writeFileSync as writeFileSync15, cpSync as cpSync2 } from "fs";
|
|
23855
|
+
import { dirname as dirname22, join as join51, basename as basename23 } from "path";
|
|
23000
23856
|
import { homedir as homedir19 } from "os";
|
|
23001
23857
|
function supportedTargetsFor(type) {
|
|
23002
23858
|
return SUPPORTED_TARGETS[type];
|
|
@@ -23038,23 +23894,23 @@ function skillsDirFor(tool) {
|
|
|
23038
23894
|
case "claude":
|
|
23039
23895
|
return claudeBackend.skillsDir();
|
|
23040
23896
|
case "agy":
|
|
23041
|
-
return
|
|
23897
|
+
return join51(agyBackend.homeDir(), "skills");
|
|
23042
23898
|
case "opencode":
|
|
23043
23899
|
return opencodeBackend.skillsDir();
|
|
23044
23900
|
case "codex":
|
|
23045
23901
|
return codexBackend.skillsDir();
|
|
23046
23902
|
// user skills, NOT .system
|
|
23047
23903
|
case "cursor":
|
|
23048
|
-
return
|
|
23904
|
+
return join51(cursorHomeDir(), "skills");
|
|
23049
23905
|
}
|
|
23050
23906
|
}
|
|
23051
23907
|
function copySkill(row, toTool) {
|
|
23052
23908
|
const skillDir = row.extra.skillDir || dirname22(row.filePath);
|
|
23053
|
-
if (!
|
|
23909
|
+
if (!existsSync48(skillDir))
|
|
23054
23910
|
return { ok: false, status: 404, error: `Source dir missing: ${skillDir}` };
|
|
23055
23911
|
const name = row.extra.skillName || basename23(skillDir);
|
|
23056
|
-
const targetDir =
|
|
23057
|
-
if (
|
|
23912
|
+
const targetDir = join51(skillsDirFor(toTool), name);
|
|
23913
|
+
if (existsSync48(targetDir))
|
|
23058
23914
|
return { ok: false, status: 409, error: `Already exists: ${targetDir}` };
|
|
23059
23915
|
try {
|
|
23060
23916
|
mkdirSync15(dirname22(targetDir), { recursive: true });
|
|
@@ -23068,28 +23924,28 @@ function readMcpEntry(tool, name) {
|
|
|
23068
23924
|
const home = homedir19();
|
|
23069
23925
|
const tries = [];
|
|
23070
23926
|
if (tool === "claude") {
|
|
23071
|
-
tries.push({ path:
|
|
23072
|
-
tries.push({ path:
|
|
23927
|
+
tries.push({ path: join51(home, ".mcp.json"), key: "mcpServers" });
|
|
23928
|
+
tries.push({ path: join51(home, ".claude.json"), key: "mcpServers" });
|
|
23073
23929
|
} else if (tool === "gemini") {
|
|
23074
|
-
tries.push({ path:
|
|
23930
|
+
tries.push({ path: join51(home, ".gemini", "settings.json"), key: "mcpServers" });
|
|
23075
23931
|
} else if (tool === "agy") {
|
|
23076
|
-
tries.push({ path:
|
|
23932
|
+
tries.push({ path: join51(home, ".gemini", "config", "mcp_config.json"), key: "mcpServers" });
|
|
23077
23933
|
} else if (tool === "cursor") {
|
|
23078
|
-
tries.push({ path:
|
|
23934
|
+
tries.push({ path: join51(cursorHomeDir(), "mcp.json"), key: "mcpServers" });
|
|
23079
23935
|
} else if (tool === "opencode") {
|
|
23080
|
-
tries.push({ path:
|
|
23081
|
-
tries.push({ path:
|
|
23082
|
-
tries.push({ path:
|
|
23936
|
+
tries.push({ path: join51(home, ".config", "opencode", "opencode.json"), key: "mcp" });
|
|
23937
|
+
tries.push({ path: join51(home, ".config", "opencode", "config.json"), key: "mcp" });
|
|
23938
|
+
tries.push({ path: join51(home, ".opencode", "config.json"), key: "mcp" });
|
|
23083
23939
|
} else if (tool === "codex") {
|
|
23084
|
-
const entry = readCodexMcpEntry(
|
|
23940
|
+
const entry = readCodexMcpEntry(join51(home, ".codex", "config.toml"), name);
|
|
23085
23941
|
if (entry)
|
|
23086
23942
|
return entry;
|
|
23087
23943
|
}
|
|
23088
23944
|
for (const t of tries) {
|
|
23089
|
-
if (!
|
|
23945
|
+
if (!existsSync48(t.path))
|
|
23090
23946
|
continue;
|
|
23091
23947
|
try {
|
|
23092
|
-
const cfg = JSON.parse(
|
|
23948
|
+
const cfg = JSON.parse(readFileSync42(t.path, "utf-8"));
|
|
23093
23949
|
const block = cfg[t.key] || {};
|
|
23094
23950
|
if (block[name])
|
|
23095
23951
|
return block[name];
|
|
@@ -23099,11 +23955,11 @@ function readMcpEntry(tool, name) {
|
|
|
23099
23955
|
return null;
|
|
23100
23956
|
}
|
|
23101
23957
|
function readCodexMcpEntry(path, target) {
|
|
23102
|
-
if (!
|
|
23958
|
+
if (!existsSync48(path))
|
|
23103
23959
|
return null;
|
|
23104
23960
|
let content;
|
|
23105
23961
|
try {
|
|
23106
|
-
content =
|
|
23962
|
+
content = readFileSync42(path, "utf-8");
|
|
23107
23963
|
} catch {
|
|
23108
23964
|
return null;
|
|
23109
23965
|
}
|
|
@@ -23153,8 +24009,8 @@ function readCodexMcpEntry(path, target) {
|
|
|
23153
24009
|
}
|
|
23154
24010
|
function writeCodexMcpEntry(path, name, entry) {
|
|
23155
24011
|
let content = "";
|
|
23156
|
-
if (
|
|
23157
|
-
content =
|
|
24012
|
+
if (existsSync48(path))
|
|
24013
|
+
content = readFileSync42(path, "utf-8");
|
|
23158
24014
|
const header = `[mcp_servers.${name}]`;
|
|
23159
24015
|
if (content.includes(header))
|
|
23160
24016
|
return false;
|
|
@@ -23190,7 +24046,7 @@ function writeCodexMcpEntry(path, name, entry) {
|
|
|
23190
24046
|
function writeMcpEntry(toTool, name, entry) {
|
|
23191
24047
|
const home = homedir19();
|
|
23192
24048
|
if (toTool === "codex") {
|
|
23193
|
-
const path2 =
|
|
24049
|
+
const path2 = join51(home, ".codex", "config.toml");
|
|
23194
24050
|
if (!writeCodexMcpEntry(path2, name, entry))
|
|
23195
24051
|
return { ok: false, status: 409, error: `MCP "${name}" already exists in ${path2}.` };
|
|
23196
24052
|
return { ok: true, targetPath: path2 };
|
|
@@ -23198,22 +24054,22 @@ function writeMcpEntry(toTool, name, entry) {
|
|
|
23198
24054
|
let path;
|
|
23199
24055
|
let key2;
|
|
23200
24056
|
if (toTool === "claude") {
|
|
23201
|
-
path =
|
|
24057
|
+
path = join51(home, ".mcp.json");
|
|
23202
24058
|
key2 = "mcpServers";
|
|
23203
24059
|
} else if (toTool === "agy") {
|
|
23204
|
-
path =
|
|
24060
|
+
path = join51(home, ".gemini", "config", "mcp_config.json");
|
|
23205
24061
|
key2 = "mcpServers";
|
|
23206
24062
|
} else if (toTool === "cursor") {
|
|
23207
|
-
path =
|
|
24063
|
+
path = join51(cursorHomeDir(), "mcp.json");
|
|
23208
24064
|
key2 = "mcpServers";
|
|
23209
24065
|
} else {
|
|
23210
|
-
path =
|
|
24066
|
+
path = join51(home, ".config", "opencode", "opencode.json");
|
|
23211
24067
|
key2 = "mcp";
|
|
23212
24068
|
}
|
|
23213
24069
|
let cfg = {};
|
|
23214
|
-
if (
|
|
24070
|
+
if (existsSync48(path)) {
|
|
23215
24071
|
try {
|
|
23216
|
-
cfg = JSON.parse(
|
|
24072
|
+
cfg = JSON.parse(readFileSync42(path, "utf-8"));
|
|
23217
24073
|
} catch {
|
|
23218
24074
|
return { ok: false, status: 500, error: `Target config is malformed: ${path}` };
|
|
23219
24075
|
}
|
|
@@ -23275,7 +24131,7 @@ function copyCommandOrAgent(type, row, toTool) {
|
|
|
23275
24131
|
return { ok: false, status: 404, error: `Source unreadable: ${e instanceof Error ? e.message : "failed"}` };
|
|
23276
24132
|
}
|
|
23277
24133
|
const out = emit(type, art, toTool);
|
|
23278
|
-
if (
|
|
24134
|
+
if (existsSync48(out.path))
|
|
23279
24135
|
return { ok: false, status: 409, error: `Already exists: ${out.path}` };
|
|
23280
24136
|
try {
|
|
23281
24137
|
mkdirSync15(dirname22(out.path), { recursive: true });
|
|
@@ -23295,7 +24151,7 @@ function copyInstructions(row, toTool) {
|
|
|
23295
24151
|
return { ok: false, status: 404, error: `Source unreadable: ${e instanceof Error ? e.message : "failed"}` };
|
|
23296
24152
|
}
|
|
23297
24153
|
const out = emit("instructions", art, toTool, row.projectPath || void 0);
|
|
23298
|
-
if (
|
|
24154
|
+
if (existsSync48(out.path))
|
|
23299
24155
|
return { ok: false, status: 409, error: `Already exists: ${out.path}` };
|
|
23300
24156
|
try {
|
|
23301
24157
|
mkdirSync15(dirname22(out.path), { recursive: true });
|
|
@@ -23446,11 +24302,11 @@ __export(toolkit_pull_exports, {
|
|
|
23446
24302
|
platformRefusal: () => platformRefusal,
|
|
23447
24303
|
portableCommand: () => portableCommand
|
|
23448
24304
|
});
|
|
23449
|
-
import { existsSync as
|
|
23450
|
-
import { dirname as dirname23, join as
|
|
24305
|
+
import { existsSync as existsSync49, mkdirSync as mkdirSync16, statSync as statSync43, writeFileSync as writeFileSync16 } from "node:fs";
|
|
24306
|
+
import { dirname as dirname23, join as join52, basename as basename24, isAbsolute as isAbsolute3 } from "node:path";
|
|
23451
24307
|
function isExecutableFile(p) {
|
|
23452
24308
|
try {
|
|
23453
|
-
return
|
|
24309
|
+
return statSync43(p).isFile();
|
|
23454
24310
|
} catch {
|
|
23455
24311
|
return false;
|
|
23456
24312
|
}
|
|
@@ -23617,9 +24473,9 @@ function executePull(rows, opts = {}) {
|
|
|
23617
24473
|
const outcomes = [];
|
|
23618
24474
|
for (const { name, body: body2, truncated, redacted, tools } of skills) {
|
|
23619
24475
|
for (const tool of tools) {
|
|
23620
|
-
const dir =
|
|
23621
|
-
const file =
|
|
23622
|
-
if (
|
|
24476
|
+
const dir = join52(skillsDirFor(tool), name);
|
|
24477
|
+
const file = join52(dir, "SKILL.md");
|
|
24478
|
+
if (existsSync49(file)) {
|
|
23623
24479
|
outcomes.push({ type: "skill", name, tool, status: "present" });
|
|
23624
24480
|
continue;
|
|
23625
24481
|
}
|
|
@@ -23664,7 +24520,7 @@ function executePull(rows, opts = {}) {
|
|
|
23664
24520
|
outcomes.push({ type, name, tool, status: "failed", reason: e instanceof Error ? e.message : "emit failed" });
|
|
23665
24521
|
continue;
|
|
23666
24522
|
}
|
|
23667
|
-
if (
|
|
24523
|
+
if (existsSync49(out.path)) {
|
|
23668
24524
|
outcomes.push({ type, name, tool, status: "present" });
|
|
23669
24525
|
continue;
|
|
23670
24526
|
}
|
|
@@ -23827,8 +24683,8 @@ __export(board_hooks_exports, {
|
|
|
23827
24683
|
removeBoardHooks: () => removeBoardHooks,
|
|
23828
24684
|
resolveCliEntry: () => resolveCliEntry
|
|
23829
24685
|
});
|
|
23830
|
-
import { existsSync as
|
|
23831
|
-
import { dirname as dirname24, join as
|
|
24686
|
+
import { existsSync as existsSync50, mkdirSync as mkdirSync17, readFileSync as readFileSync43, writeFileSync as writeFileSync17 } from "node:fs";
|
|
24687
|
+
import { dirname as dirname24, join as join53 } from "node:path";
|
|
23832
24688
|
function boardHookCommand(execPath, cliEntry, mode) {
|
|
23833
24689
|
return `"${execPath}" "${cliEntry}" task-hook --${mode}`;
|
|
23834
24690
|
}
|
|
@@ -23867,9 +24723,9 @@ function removeBoardHooks(config2) {
|
|
|
23867
24723
|
return removed;
|
|
23868
24724
|
}
|
|
23869
24725
|
function readConfig(file) {
|
|
23870
|
-
if (!
|
|
24726
|
+
if (!existsSync50(file)) return { hooks: {} };
|
|
23871
24727
|
try {
|
|
23872
|
-
const parsed = JSON.parse(
|
|
24728
|
+
const parsed = JSON.parse(readFileSync43(file, "utf-8"));
|
|
23873
24729
|
if (!parsed.hooks || typeof parsed.hooks !== "object") parsed.hooks = {};
|
|
23874
24730
|
return parsed;
|
|
23875
24731
|
} catch {
|
|
@@ -23879,9 +24735,9 @@ function readConfig(file) {
|
|
|
23879
24735
|
function registerBoardHooks(files, execPath, cliEntry) {
|
|
23880
24736
|
const written = [];
|
|
23881
24737
|
for (const file of files) {
|
|
23882
|
-
if (
|
|
24738
|
+
if (existsSync50(file)) {
|
|
23883
24739
|
try {
|
|
23884
|
-
JSON.parse(
|
|
24740
|
+
JSON.parse(readFileSync43(file, "utf-8"));
|
|
23885
24741
|
} catch {
|
|
23886
24742
|
continue;
|
|
23887
24743
|
}
|
|
@@ -23898,8 +24754,8 @@ function registerBoardHooks(files, execPath, cliEntry) {
|
|
|
23898
24754
|
return written;
|
|
23899
24755
|
}
|
|
23900
24756
|
function resolveCliEntry(distDir) {
|
|
23901
|
-
const bundled =
|
|
23902
|
-
return
|
|
24757
|
+
const bundled = join53(distDir, "cli.js");
|
|
24758
|
+
return existsSync50(bundled) ? bundled : join53(distDir, "cli.ts");
|
|
23903
24759
|
}
|
|
23904
24760
|
var BOARD_HOOKS;
|
|
23905
24761
|
var init_board_hooks = __esm({
|
|
@@ -24108,11 +24964,16 @@ async function repairAll(opts = {}) {
|
|
|
24108
24964
|
scanned++;
|
|
24109
24965
|
if (opts.verbose && scanned % 50 === 0) log6(`checked ${scanned}/${ids.length}\u2026`);
|
|
24110
24966
|
const arch = await fetchJson(`${primary.url}/api/conversations/${id}/raw-archive?count=1`, primary.token);
|
|
24111
|
-
const
|
|
24112
|
-
if (
|
|
24113
|
-
|
|
24114
|
-
|
|
24115
|
-
|
|
24967
|
+
const counted = arch && arch.messages !== null;
|
|
24968
|
+
if (counted) {
|
|
24969
|
+
const archiveMsgs = typeof arch?.messages === "number" ? arch.messages : 0;
|
|
24970
|
+
if (archiveMsgs < minMessages) continue;
|
|
24971
|
+
const meta = await fetchJson(`${primary.url}/api/conversations/${id}/metadata`, primary.token);
|
|
24972
|
+
const current = typeof meta?.messageCount === "number" ? meta.messageCount : 0;
|
|
24973
|
+
if (archiveMsgs <= current) continue;
|
|
24974
|
+
} else if (!arch) {
|
|
24975
|
+
continue;
|
|
24976
|
+
}
|
|
24116
24977
|
const r = await repairSession(id, { dryRun: !opts.apply, verbose: opts.verbose, server: opts.server });
|
|
24117
24978
|
if (r.status === "already-full") continue;
|
|
24118
24979
|
candidates2.push(r);
|
|
@@ -24297,21 +25158,21 @@ __export(guard_registration_exports, {
|
|
|
24297
25158
|
unregisterGuard: () => unregisterGuard
|
|
24298
25159
|
});
|
|
24299
25160
|
import { homedir as homedir20 } from "os";
|
|
24300
|
-
import { join as
|
|
25161
|
+
import { join as join54 } from "path";
|
|
24301
25162
|
function opencodeConfigDir() {
|
|
24302
25163
|
const xdg = process.env.XDG_CONFIG_HOME;
|
|
24303
|
-
const base4 = xdg && xdg.trim() ? xdg :
|
|
24304
|
-
return
|
|
25164
|
+
const base4 = xdg && xdg.trim() ? xdg : join54(homedir20(), ".config");
|
|
25165
|
+
return join54(base4, "opencode");
|
|
24305
25166
|
}
|
|
24306
25167
|
function opencodePluginDir() {
|
|
24307
|
-
return
|
|
25168
|
+
return join54(opencodeConfigDir(), "plugins");
|
|
24308
25169
|
}
|
|
24309
25170
|
function guardTargets() {
|
|
24310
25171
|
return [
|
|
24311
25172
|
{
|
|
24312
25173
|
tool: "codex",
|
|
24313
25174
|
label: "Codex",
|
|
24314
|
-
configPath:
|
|
25175
|
+
configPath: join54(codexBackend.homeDir(), "hooks.json"),
|
|
24315
25176
|
homeDir: codexBackend.homeDir(),
|
|
24316
25177
|
// Codex will not run a hook until a person has reviewed it, and the
|
|
24317
25178
|
// approval is bound to the hook's hash. There is no way to grant it from
|
|
@@ -24324,20 +25185,20 @@ function guardTargets() {
|
|
|
24324
25185
|
{
|
|
24325
25186
|
tool: "agy",
|
|
24326
25187
|
label: "Antigravity",
|
|
24327
|
-
configPath:
|
|
25188
|
+
configPath: join54(agyBackend.homeDir(), "hooks.json"),
|
|
24328
25189
|
homeDir: agyBackend.homeDir()
|
|
24329
25190
|
},
|
|
24330
25191
|
{
|
|
24331
25192
|
tool: "cursor",
|
|
24332
25193
|
label: "Cursor",
|
|
24333
|
-
configPath:
|
|
25194
|
+
configPath: join54(cursorBackend.homeDir(), "hooks.json"),
|
|
24334
25195
|
homeDir: cursorBackend.homeDir(),
|
|
24335
25196
|
note: "Cursor checks a shell command before it runs and a file edit after it is written."
|
|
24336
25197
|
},
|
|
24337
25198
|
{
|
|
24338
25199
|
tool: "opencode",
|
|
24339
25200
|
label: "OpenCode",
|
|
24340
|
-
configPath:
|
|
25201
|
+
configPath: join54(opencodePluginDir(), "chat-recall-guard.js"),
|
|
24341
25202
|
homeDir: opencodeConfigDir(),
|
|
24342
25203
|
note: "OpenCode plugin hooks do not fire for subagent tool calls, so a delegating agent bypasses this."
|
|
24343
25204
|
}
|
|
@@ -24566,11 +25427,11 @@ var verify_repair_exports = {};
|
|
|
24566
25427
|
__export(verify_repair_exports, {
|
|
24567
25428
|
forceFullResync: () => forceFullResync
|
|
24568
25429
|
});
|
|
24569
|
-
import { copyFileSync as copyFileSync3, existsSync as
|
|
25430
|
+
import { copyFileSync as copyFileSync3, existsSync as existsSync51 } from "fs";
|
|
24570
25431
|
function forceFullResync(server, sessionIds) {
|
|
24571
25432
|
if (sessionIds.length === 0) return 0;
|
|
24572
25433
|
const path = ledgerFilePath();
|
|
24573
|
-
if (
|
|
25434
|
+
if (existsSync51(path)) {
|
|
24574
25435
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "").replace(/-/g, "");
|
|
24575
25436
|
try {
|
|
24576
25437
|
copyFileSync3(path, `${path}.bak-${stamp}`);
|
|
@@ -24760,8 +25621,8 @@ __export(collector_exports, {
|
|
|
24760
25621
|
});
|
|
24761
25622
|
import { spawn as spawn3 } from "node:child_process";
|
|
24762
25623
|
import { execSync as execSync4 } from "node:child_process";
|
|
24763
|
-
import { readFileSync as
|
|
24764
|
-
import { join as
|
|
25624
|
+
import { readFileSync as readFileSync44 } from "node:fs";
|
|
25625
|
+
import { join as join55, basename as basename26 } from "node:path";
|
|
24765
25626
|
async function resolveCodeindexBin(autoInstall = true) {
|
|
24766
25627
|
let st = checkCodeindexStatus();
|
|
24767
25628
|
if (!st.installed && autoInstall)
|
|
@@ -24943,7 +25804,7 @@ async function collectCode(opts) {
|
|
|
24943
25804
|
}
|
|
24944
25805
|
const complexity = (r) => {
|
|
24945
25806
|
try {
|
|
24946
|
-
const txt =
|
|
25807
|
+
const txt = readFileSync44(join55(ws, r), "utf8");
|
|
24947
25808
|
if (txt.length > 2e6)
|
|
24948
25809
|
return 1;
|
|
24949
25810
|
const m = txt.match(CF_RE);
|
|
@@ -25727,8 +26588,8 @@ __export(project_tasks_exports, {
|
|
|
25727
26588
|
pushProjectTaskStatuses: () => pushProjectTaskStatuses,
|
|
25728
26589
|
renderTeamTasksMd: () => renderTeamTasksMd
|
|
25729
26590
|
});
|
|
25730
|
-
import { existsSync as
|
|
25731
|
-
import { join as
|
|
26591
|
+
import { existsSync as existsSync52, readFileSync as readFileSync45, writeFileSync as writeFileSync18, mkdirSync as mkdirSync18, statSync as statSync44 } from "node:fs";
|
|
26592
|
+
import { join as join56, dirname as dirname25 } from "node:path";
|
|
25732
26593
|
import { homedir as homedir21 } from "node:os";
|
|
25733
26594
|
function isTeamTaskStatus(v) {
|
|
25734
26595
|
return !!v && TEAM_STATUSES.has(v);
|
|
@@ -25779,11 +26640,11 @@ function parseTaskFile(content) {
|
|
|
25779
26640
|
return out;
|
|
25780
26641
|
}
|
|
25781
26642
|
function ledgerPath2() {
|
|
25782
|
-
return
|
|
26643
|
+
return join56(homedir21(), ".chat-recall", "project-tasks-ledger.json");
|
|
25783
26644
|
}
|
|
25784
26645
|
function readLedger() {
|
|
25785
26646
|
try {
|
|
25786
|
-
return JSON.parse(
|
|
26647
|
+
return JSON.parse(readFileSync45(ledgerPath2(), "utf8"));
|
|
25787
26648
|
} catch {
|
|
25788
26649
|
return {};
|
|
25789
26650
|
}
|
|
@@ -25812,18 +26673,18 @@ async function pushProjectTaskStatuses(base4, authHeaders, opts = {}) {
|
|
|
25812
26673
|
continue;
|
|
25813
26674
|
}
|
|
25814
26675
|
for (const project of projects) {
|
|
25815
|
-
const file =
|
|
25816
|
-
if (!
|
|
26676
|
+
const file = join56(project, fk.filename);
|
|
26677
|
+
if (!existsSync52(file)) continue;
|
|
25817
26678
|
let mtime;
|
|
25818
26679
|
try {
|
|
25819
|
-
mtime =
|
|
26680
|
+
mtime = statSync44(file).mtimeMs;
|
|
25820
26681
|
} catch {
|
|
25821
26682
|
continue;
|
|
25822
26683
|
}
|
|
25823
26684
|
if (ledger[file] === mtime) continue;
|
|
25824
26685
|
let changed;
|
|
25825
26686
|
try {
|
|
25826
|
-
changed = parseTaskFile(
|
|
26687
|
+
changed = parseTaskFile(readFileSync45(file, "utf8")).filter((t) => t.kind === fk.kind);
|
|
25827
26688
|
} catch {
|
|
25828
26689
|
continue;
|
|
25829
26690
|
}
|
|
@@ -25895,8 +26756,8 @@ __export(intent_drain_exports, {
|
|
|
25895
26756
|
drainSyncIntents: () => drainSyncIntents,
|
|
25896
26757
|
instructionTargets: () => instructionTargets
|
|
25897
26758
|
});
|
|
25898
|
-
import { existsSync as
|
|
25899
|
-
import { join as
|
|
26759
|
+
import { existsSync as existsSync53, readFileSync as readFileSync46, writeFileSync as writeFileSync19, appendFileSync, mkdirSync as mkdirSync19 } from "node:fs";
|
|
26760
|
+
import { join as join57 } from "node:path";
|
|
25900
26761
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
25901
26762
|
import { dirname as dirname26 } from "node:path";
|
|
25902
26763
|
function instructionTargets(rootPath, isGlobal) {
|
|
@@ -25910,16 +26771,16 @@ function instructionTargets(rootPath, isGlobal) {
|
|
|
25910
26771
|
const tools = installed.length ? installed : [INSTRUCTION_TOOLS[0]];
|
|
25911
26772
|
if (isGlobal) return [...new Set(tools.map((t) => instructionsPath(t.id)))];
|
|
25912
26773
|
if (!rootPath) return [];
|
|
25913
|
-
const present = INSTRUCTION_FILENAMES.map((f) =>
|
|
26774
|
+
const present = INSTRUCTION_FILENAMES.map((f) => join57(rootPath, f)).filter((p) => existsSync53(p));
|
|
25914
26775
|
if (present.length) return present;
|
|
25915
|
-
return [...new Set(tools.map((t) =>
|
|
26776
|
+
return [...new Set(tools.map((t) => join57(rootPath, instructionsFilename(t.id))))];
|
|
25916
26777
|
}
|
|
25917
26778
|
function applyCodeRecommendation(intent) {
|
|
25918
26779
|
try {
|
|
25919
26780
|
const meta = JSON.parse(intent.name || "{}");
|
|
25920
26781
|
if (intent.artifact_type === "write_tasks_file") {
|
|
25921
26782
|
if (!meta.rootPath || !meta.content) return { status: "error", result: JSON.stringify({ error: "missing rootPath or content" }) };
|
|
25922
|
-
const file =
|
|
26783
|
+
const file = join57(meta.rootPath, meta.filename || "CODE_TASKS.md");
|
|
25923
26784
|
writeFileSync19(file, meta.content);
|
|
25924
26785
|
return { status: "done", result: JSON.stringify({ wrote: file }) };
|
|
25925
26786
|
}
|
|
@@ -25938,7 +26799,7 @@ function applyCodeRecommendation(intent) {
|
|
|
25938
26799
|
mkdirSync19(dir, { recursive: true });
|
|
25939
26800
|
} catch {
|
|
25940
26801
|
}
|
|
25941
|
-
const existing =
|
|
26802
|
+
const existing = existsSync53(file) ? readFileSync46(file, "utf8") : "";
|
|
25942
26803
|
if (existing.includes(text)) {
|
|
25943
26804
|
skipped.push(file);
|
|
25944
26805
|
continue;
|
|
@@ -26113,10 +26974,10 @@ var init_intent_drain = __esm({
|
|
|
26113
26974
|
ownVersion2 = "0.0.0";
|
|
26114
26975
|
try {
|
|
26115
26976
|
const dir = dirname26(fileURLToPath4(import.meta.url));
|
|
26116
|
-
ownVersion2 = JSON.parse(
|
|
26977
|
+
ownVersion2 = JSON.parse(readFileSync46(join57(dir, "../package.json"), "utf-8")).version || ownVersion2;
|
|
26117
26978
|
} catch {
|
|
26118
26979
|
try {
|
|
26119
|
-
if (true) ownVersion2 = "0.7.
|
|
26980
|
+
if (true) ownVersion2 = "0.7.19";
|
|
26120
26981
|
} catch {
|
|
26121
26982
|
}
|
|
26122
26983
|
}
|
|
@@ -26317,48 +27178,48 @@ var team_merge_exports = {};
|
|
|
26317
27178
|
__export(team_merge_exports, {
|
|
26318
27179
|
mergePullResult: () => mergePullResult
|
|
26319
27180
|
});
|
|
26320
|
-
import { existsSync as
|
|
26321
|
-
import { dirname as dirname27, join as
|
|
27181
|
+
import { existsSync as existsSync54, mkdirSync as mkdirSync20, readFileSync as readFileSync47, rmSync as rmSync9, writeFileSync as writeFileSync20, statSync as statSync45 } from "fs";
|
|
27182
|
+
import { dirname as dirname27, join as join58 } from "path";
|
|
26322
27183
|
import { createHash as createHash14 } from "crypto";
|
|
26323
27184
|
function installPathFor(art, tool) {
|
|
26324
27185
|
switch (art.type) {
|
|
26325
27186
|
case "skill":
|
|
26326
27187
|
switch (tool) {
|
|
26327
27188
|
case "claude":
|
|
26328
|
-
return
|
|
27189
|
+
return join58(claudeBackend.skillsDir(), art.name, "SKILL.md");
|
|
26329
27190
|
// Antigravity's OWN skills dir. It used to resolve to the shared
|
|
26330
27191
|
// ~/.gemini/skills while toolkit-sync installed to
|
|
26331
27192
|
// ~/.gemini/antigravity-cli/skills, so a team skill landed in one place
|
|
26332
27193
|
// and a synced skill in the other.
|
|
26333
27194
|
case "agy":
|
|
26334
|
-
return
|
|
27195
|
+
return join58(agyBackend.homeDir(), "skills", art.name, "SKILL.md");
|
|
26335
27196
|
case "opencode":
|
|
26336
|
-
return
|
|
27197
|
+
return join58(opencodeBackend.skillsDir(), art.name, "SKILL.md");
|
|
26337
27198
|
// User skills go to ~/.codex/skills (NOT .system, which is OpenAI's bundle).
|
|
26338
27199
|
case "codex":
|
|
26339
|
-
return
|
|
27200
|
+
return join58(codexBackend.skillsDir(), art.name, "SKILL.md");
|
|
26340
27201
|
case "cursor":
|
|
26341
|
-
return
|
|
27202
|
+
return join58(cursorHomeDir(), "skills", art.name, "SKILL.md");
|
|
26342
27203
|
}
|
|
26343
27204
|
break;
|
|
26344
27205
|
case "agent":
|
|
26345
27206
|
if (tool === "claude")
|
|
26346
|
-
return
|
|
27207
|
+
return join58(claudeBackend.agentsDir(), `${art.name}.md`);
|
|
26347
27208
|
return null;
|
|
26348
27209
|
case "command":
|
|
26349
27210
|
if (tool === "claude")
|
|
26350
|
-
return
|
|
27211
|
+
return join58(claudeBackend.commandsDir(), `${art.name}.md`);
|
|
26351
27212
|
return null;
|
|
26352
27213
|
case "hook":
|
|
26353
27214
|
if (tool === "claude")
|
|
26354
|
-
return
|
|
27215
|
+
return join58(claudeBackend.homeDir(), "chat-recall-hooks", `${art.name}.json`);
|
|
26355
27216
|
return null;
|
|
26356
27217
|
case "plan":
|
|
26357
27218
|
switch (tool) {
|
|
26358
27219
|
case "claude":
|
|
26359
|
-
return
|
|
27220
|
+
return join58(claudeBackend.plansDir(), `${art.name}.md`);
|
|
26360
27221
|
case "opencode":
|
|
26361
|
-
return
|
|
27222
|
+
return join58(opencodeBackend.plansDir(), `${art.name}.md`);
|
|
26362
27223
|
case "agy":
|
|
26363
27224
|
return null;
|
|
26364
27225
|
// Antigravity plans live per-session
|
|
@@ -26369,11 +27230,11 @@ function installPathFor(art, tool) {
|
|
|
26369
27230
|
}
|
|
26370
27231
|
break;
|
|
26371
27232
|
case "instructions":
|
|
26372
|
-
return
|
|
27233
|
+
return join58(getDataDir(), "team-instructions", tool, `${art.name}.md`);
|
|
26373
27234
|
case "mcp":
|
|
26374
|
-
return
|
|
27235
|
+
return join58(getDataDir(), "team-mcps", `${art.name}.json`);
|
|
26375
27236
|
case "plugin":
|
|
26376
|
-
return
|
|
27237
|
+
return join58(getDataDir(), "team-plugins", tool, art.name, "manifest.json");
|
|
26377
27238
|
}
|
|
26378
27239
|
return null;
|
|
26379
27240
|
}
|
|
@@ -26434,8 +27295,8 @@ async function mergePullResult(opts) {
|
|
|
26434
27295
|
if (!path)
|
|
26435
27296
|
continue;
|
|
26436
27297
|
try {
|
|
26437
|
-
if (
|
|
26438
|
-
|
|
27298
|
+
if (existsSync54(path))
|
|
27299
|
+
rmSync9(path, { force: true });
|
|
26439
27300
|
await teamInstallsForget(id, row.tool);
|
|
26440
27301
|
report.removed.push({ artifactId: id, path });
|
|
26441
27302
|
} catch (err) {
|
|
@@ -26452,12 +27313,12 @@ async function mergePullResult(opts) {
|
|
|
26452
27313
|
}
|
|
26453
27314
|
function readFileIfExists(path) {
|
|
26454
27315
|
try {
|
|
26455
|
-
if (!
|
|
27316
|
+
if (!existsSync54(path))
|
|
26456
27317
|
return null;
|
|
26457
|
-
const s =
|
|
27318
|
+
const s = statSync45(path);
|
|
26458
27319
|
if (!s.isFile())
|
|
26459
27320
|
return null;
|
|
26460
|
-
return
|
|
27321
|
+
return readFileSync47(path);
|
|
26461
27322
|
} catch {
|
|
26462
27323
|
return null;
|
|
26463
27324
|
}
|
|
@@ -26538,8 +27399,8 @@ var init_vault_crypto = __esm({
|
|
|
26538
27399
|
});
|
|
26539
27400
|
|
|
26540
27401
|
// ../engine/dist/core/vault-source.js
|
|
26541
|
-
import { existsSync as
|
|
26542
|
-
import { extname, join as
|
|
27402
|
+
import { existsSync as existsSync55, readdirSync as readdirSync33, statSync as statSync46 } from "fs";
|
|
27403
|
+
import { extname, join as join59 } from "path";
|
|
26543
27404
|
function* walkVaultSources() {
|
|
26544
27405
|
const t = loadSettings().team.vault;
|
|
26545
27406
|
const include2 = new Set(t.syncTools);
|
|
@@ -26554,7 +27415,7 @@ function* walkVaultSources() {
|
|
|
26554
27415
|
}
|
|
26555
27416
|
function safeStat(path) {
|
|
26556
27417
|
try {
|
|
26557
|
-
const s =
|
|
27418
|
+
const s = statSync46(path);
|
|
26558
27419
|
if (!s.isFile())
|
|
26559
27420
|
return null;
|
|
26560
27421
|
return { mtimeMs: s.mtimeMs, size: s.size };
|
|
@@ -26564,7 +27425,7 @@ function safeStat(path) {
|
|
|
26564
27425
|
}
|
|
26565
27426
|
function* walkClaude() {
|
|
26566
27427
|
const root = claudeBackend.projectsDir();
|
|
26567
|
-
if (!
|
|
27428
|
+
if (!existsSync55(root))
|
|
26568
27429
|
return;
|
|
26569
27430
|
let projectDirs = [];
|
|
26570
27431
|
try {
|
|
@@ -26576,7 +27437,7 @@ function* walkClaude() {
|
|
|
26576
27437
|
if (proj.startsWith("."))
|
|
26577
27438
|
continue;
|
|
26578
27439
|
const projectPath = resolveProjectDirName(proj);
|
|
26579
|
-
const projDir =
|
|
27440
|
+
const projDir = join59(root, proj);
|
|
26580
27441
|
let entries = [];
|
|
26581
27442
|
try {
|
|
26582
27443
|
entries = readdirSync33(projDir);
|
|
@@ -26586,7 +27447,7 @@ function* walkClaude() {
|
|
|
26586
27447
|
for (const f of entries) {
|
|
26587
27448
|
if (extname(f) !== ".jsonl")
|
|
26588
27449
|
continue;
|
|
26589
|
-
const path =
|
|
27450
|
+
const path = join59(projDir, f);
|
|
26590
27451
|
const s = safeStat(path);
|
|
26591
27452
|
if (!s)
|
|
26592
27453
|
continue;
|
|
@@ -26616,8 +27477,8 @@ function* walkCursor() {
|
|
|
26616
27477
|
}
|
|
26617
27478
|
}
|
|
26618
27479
|
function* walkCodex() {
|
|
26619
|
-
const sessionsRoot =
|
|
26620
|
-
if (!
|
|
27480
|
+
const sessionsRoot = join59(codexBackend.homeDir(), "sessions");
|
|
27481
|
+
if (!existsSync55(sessionsRoot))
|
|
26621
27482
|
return;
|
|
26622
27483
|
const stack = [sessionsRoot];
|
|
26623
27484
|
while (stack.length) {
|
|
@@ -26629,7 +27490,7 @@ function* walkCodex() {
|
|
|
26629
27490
|
continue;
|
|
26630
27491
|
}
|
|
26631
27492
|
for (const e of entries) {
|
|
26632
|
-
const path =
|
|
27493
|
+
const path = join59(dir, e.name);
|
|
26633
27494
|
if (e.isDirectory()) {
|
|
26634
27495
|
stack.push(path);
|
|
26635
27496
|
continue;
|
|
@@ -26645,8 +27506,8 @@ function* walkCodex() {
|
|
|
26645
27506
|
}
|
|
26646
27507
|
}
|
|
26647
27508
|
function* walkAgy() {
|
|
26648
|
-
const brainDir =
|
|
26649
|
-
if (!
|
|
27509
|
+
const brainDir = join59(agyBackend.homeDir(), "brain");
|
|
27510
|
+
if (!existsSync55(brainDir))
|
|
26650
27511
|
return;
|
|
26651
27512
|
let sessionDirs = [];
|
|
26652
27513
|
try {
|
|
@@ -26655,18 +27516,18 @@ function* walkAgy() {
|
|
|
26655
27516
|
return;
|
|
26656
27517
|
}
|
|
26657
27518
|
for (const rawId of sessionDirs) {
|
|
26658
|
-
const sessionPath =
|
|
27519
|
+
const sessionPath = join59(brainDir, rawId);
|
|
26659
27520
|
try {
|
|
26660
|
-
if (!
|
|
27521
|
+
if (!statSync46(sessionPath).isDirectory())
|
|
26661
27522
|
continue;
|
|
26662
27523
|
} catch {
|
|
26663
27524
|
continue;
|
|
26664
27525
|
}
|
|
26665
|
-
let filePath =
|
|
26666
|
-
if (!
|
|
26667
|
-
filePath =
|
|
27526
|
+
let filePath = join59(sessionPath, ".system_generated", "logs", "transcript.jsonl");
|
|
27527
|
+
if (!existsSync55(filePath)) {
|
|
27528
|
+
filePath = join59(sessionPath, ".system_generated", "logs", "transcript_full.jsonl");
|
|
26668
27529
|
}
|
|
26669
|
-
if (!
|
|
27530
|
+
if (!existsSync55(filePath))
|
|
26670
27531
|
continue;
|
|
26671
27532
|
const s = safeStat(filePath);
|
|
26672
27533
|
if (!s)
|
|
@@ -26702,8 +27563,8 @@ __export(vault_client_exports, {
|
|
|
26702
27563
|
vaultStatus: () => vaultStatus,
|
|
26703
27564
|
vaultSync: () => vaultSync
|
|
26704
27565
|
});
|
|
26705
|
-
import { mkdirSync as mkdirSync21, readFileSync as
|
|
26706
|
-
import { dirname as dirname28, join as
|
|
27566
|
+
import { mkdirSync as mkdirSync21, readFileSync as readFileSync48, writeFileSync as writeFileSync21, existsSync as existsSync56 } from "fs";
|
|
27567
|
+
import { dirname as dirname28, join as join60 } from "path";
|
|
26707
27568
|
function context2() {
|
|
26708
27569
|
const s = loadSettings().team;
|
|
26709
27570
|
if (!s.enabled)
|
|
@@ -26842,7 +27703,7 @@ async function vaultSync(passphrase) {
|
|
|
26842
27703
|
continue;
|
|
26843
27704
|
}
|
|
26844
27705
|
try {
|
|
26845
|
-
const plaintext =
|
|
27706
|
+
const plaintext = readFileSync48(src.path);
|
|
26846
27707
|
const sourceSha = sha256Hex(plaintext);
|
|
26847
27708
|
const priorSha = uploaded.get(uploadKey(src.sessionId, src.tool));
|
|
26848
27709
|
if (priorSha === sourceSha) {
|
|
@@ -26894,7 +27755,7 @@ async function vaultSync(passphrase) {
|
|
|
26894
27755
|
}
|
|
26895
27756
|
function importedPathFor(tool, sessionId) {
|
|
26896
27757
|
const base4 = sessionId.replace(/^gemini_/, "").replace(/^codex_/, "").replace(/^agy_/, "").replace(/^cursor_/, "").replace(/^opencode_/, "");
|
|
26897
|
-
return
|
|
27758
|
+
return join60(IMPORTED_ROOT(), tool, `${base4}.jsonl`);
|
|
26898
27759
|
}
|
|
26899
27760
|
async function vaultRestore(passphrase, opts = {}) {
|
|
26900
27761
|
const ctx = context2();
|
|
@@ -26915,7 +27776,7 @@ async function vaultRestore(passphrase, opts = {}) {
|
|
|
26915
27776
|
}
|
|
26916
27777
|
try {
|
|
26917
27778
|
const path = importedPathFor(blob.tool, blob.sessionId);
|
|
26918
|
-
if (
|
|
27779
|
+
if (existsSync56(path)) {
|
|
26919
27780
|
const localStat = await import("fs").then((m) => m.statSync(path));
|
|
26920
27781
|
if (Math.abs(localStat.mtimeMs - blob.mtimeSourceMs) < 1) {
|
|
26921
27782
|
report.skipped.push({ sessionId: blob.sessionId, tool: blob.tool, reason: "unchanged" });
|
|
@@ -26983,7 +27844,7 @@ var init_vault_client = __esm({
|
|
|
26983
27844
|
uploadKey = (sessionId, tool) => `${sessionId}\0${tool}`;
|
|
26984
27845
|
VaultPassphraseMismatchError = class extends Error {
|
|
26985
27846
|
};
|
|
26986
|
-
IMPORTED_ROOT = () =>
|
|
27847
|
+
IMPORTED_ROOT = () => join60(getDataDir(), "imported");
|
|
26987
27848
|
}
|
|
26988
27849
|
});
|
|
26989
27850
|
|
|
@@ -27545,15 +28406,15 @@ __export(service_installer_exports, {
|
|
|
27545
28406
|
uninstallService: () => uninstallService
|
|
27546
28407
|
});
|
|
27547
28408
|
import { execSync as execSync5 } from "child_process";
|
|
27548
|
-
import { existsSync as
|
|
28409
|
+
import { existsSync as existsSync57, mkdirSync as mkdirSync22, readFileSync as readFileSync49, rmSync as rmSync10, writeFileSync as writeFileSync22 } from "fs";
|
|
27549
28410
|
import { homedir as homedir22 } from "os";
|
|
27550
|
-
import { join as
|
|
28411
|
+
import { join as join61 } from "path";
|
|
27551
28412
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
27552
28413
|
function resolveDaemonPaths() {
|
|
27553
28414
|
const watchJs = fileURLToPath5(new URL("./watch.js", import.meta.url));
|
|
27554
28415
|
const node = process.execPath;
|
|
27555
|
-
const dataDir =
|
|
27556
|
-
const logFile =
|
|
28416
|
+
const dataDir = join61(homedir22(), ".chat-recall");
|
|
28417
|
+
const logFile = join61(dataDir, "watch.log");
|
|
27557
28418
|
return { watchJs, node, logFile, dataDir };
|
|
27558
28419
|
}
|
|
27559
28420
|
function tryCmd(cmd) {
|
|
@@ -27580,12 +28441,12 @@ function refreshServiceDefinition() {
|
|
|
27580
28441
|
if (process.platform !== "linux") return false;
|
|
27581
28442
|
try {
|
|
27582
28443
|
const { watchJs, node, logFile } = resolveDaemonPaths();
|
|
27583
|
-
const unitPath =
|
|
27584
|
-
if (!
|
|
27585
|
-
const current =
|
|
28444
|
+
const unitPath = join61(homedir22(), ".config", "systemd", "user", "chat-recall-watch.service");
|
|
28445
|
+
if (!existsSync57(unitPath)) return false;
|
|
28446
|
+
const current = readFileSync49(unitPath, "utf8");
|
|
27586
28447
|
if (!current.includes(watchJs)) return false;
|
|
27587
28448
|
const wanted = renderSystemdUnit(watchJs, node, logFile);
|
|
27588
|
-
if (
|
|
28449
|
+
if (readFileSync49(unitPath, "utf8") === wanted) return false;
|
|
27589
28450
|
writeFileSync22(unitPath, wanted);
|
|
27590
28451
|
execSync5("systemctl --user daemon-reload", { stdio: "ignore" });
|
|
27591
28452
|
return true;
|
|
@@ -27611,8 +28472,8 @@ function installService() {
|
|
|
27611
28472
|
);
|
|
27612
28473
|
}
|
|
27613
28474
|
function installSystemd(watchJs, node, logFile) {
|
|
27614
|
-
const unitDir =
|
|
27615
|
-
const unitPath =
|
|
28475
|
+
const unitDir = join61(homedir22(), ".config", "systemd", "user");
|
|
28476
|
+
const unitPath = join61(unitDir, "chat-recall-watch.service");
|
|
27616
28477
|
const unit = renderSystemdUnit(watchJs, node, logFile);
|
|
27617
28478
|
mkdirSync22(unitDir, { recursive: true });
|
|
27618
28479
|
writeFileSync22(unitPath, unit);
|
|
@@ -27691,8 +28552,8 @@ function renderSystemdUnit(watchJs, node, logFile) {
|
|
|
27691
28552
|
}
|
|
27692
28553
|
function installLaunchd(watchJs, node, logFile) {
|
|
27693
28554
|
const label = "com.chat-recall.watch";
|
|
27694
|
-
const plistDir =
|
|
27695
|
-
const plistPath =
|
|
28555
|
+
const plistDir = join61(homedir22(), "Library", "LaunchAgents");
|
|
28556
|
+
const plistPath = join61(plistDir, `${label}.plist`);
|
|
27696
28557
|
const plist = renderLaunchdPlist(watchJs, node, logFile, label);
|
|
27697
28558
|
mkdirSync22(plistDir, { recursive: true });
|
|
27698
28559
|
writeFileSync22(plistPath, plist);
|
|
@@ -27748,9 +28609,9 @@ function uninstallService() {
|
|
|
27748
28609
|
removed = true;
|
|
27749
28610
|
} catch {
|
|
27750
28611
|
}
|
|
27751
|
-
const unitPath =
|
|
27752
|
-
if (
|
|
27753
|
-
|
|
28612
|
+
const unitPath = join61(homedir22(), ".config", "systemd", "user", "chat-recall-watch.service");
|
|
28613
|
+
if (existsSync57(unitPath)) {
|
|
28614
|
+
rmSync10(unitPath, { force: true });
|
|
27754
28615
|
removed = true;
|
|
27755
28616
|
}
|
|
27756
28617
|
try {
|
|
@@ -27760,14 +28621,14 @@ function uninstallService() {
|
|
|
27760
28621
|
return removed;
|
|
27761
28622
|
}
|
|
27762
28623
|
if (process.platform === "darwin") {
|
|
27763
|
-
const plistPath =
|
|
28624
|
+
const plistPath = join61(homedir22(), "Library", "LaunchAgents", "com.chat-recall.watch.plist");
|
|
27764
28625
|
try {
|
|
27765
28626
|
execSync5(`launchctl unload "${plistPath}" 2>/dev/null`, { stdio: "ignore" });
|
|
27766
28627
|
} catch {
|
|
27767
28628
|
}
|
|
27768
28629
|
let removed = false;
|
|
27769
|
-
if (
|
|
27770
|
-
|
|
28630
|
+
if (existsSync57(plistPath)) {
|
|
28631
|
+
rmSync10(plistPath, { force: true });
|
|
27771
28632
|
removed = true;
|
|
27772
28633
|
}
|
|
27773
28634
|
return removed;
|
|
@@ -27811,7 +28672,7 @@ __export(device_auth_exports, {
|
|
|
27811
28672
|
betterAuthDeviceLogin: () => betterAuthDeviceLogin,
|
|
27812
28673
|
deviceLogin: () => deviceLogin
|
|
27813
28674
|
});
|
|
27814
|
-
import { createHash as createHash15, randomBytes } from "node:crypto";
|
|
28675
|
+
import { createHash as createHash15, randomBytes as randomBytes2 } from "node:crypto";
|
|
27815
28676
|
async function readDeviceCode(res, where) {
|
|
27816
28677
|
const text = await res.text().catch(() => "");
|
|
27817
28678
|
let parsed;
|
|
@@ -27839,7 +28700,7 @@ async function deviceLogin(opts, onPrompt) {
|
|
|
27839
28700
|
}
|
|
27840
28701
|
const clientId = opts.clientId || DEFAULT_CLIENT_ID;
|
|
27841
28702
|
const scope = opts.scope || "openid email profile";
|
|
27842
|
-
const codeVerifier = b64url(
|
|
28703
|
+
const codeVerifier = b64url(randomBytes2(32));
|
|
27843
28704
|
const codeChallenge = b64url(createHash15("sha256").update(codeVerifier).digest());
|
|
27844
28705
|
const startRes = await fetch(`${issuer}/protocol/openid-connect/auth/device`, {
|
|
27845
28706
|
method: "POST",
|
|
@@ -28138,6 +28999,7 @@ var SESSION_ID_PREFIXES = {
|
|
|
28138
28999
|
opencode: "opencode_",
|
|
28139
29000
|
agy: "agy_",
|
|
28140
29001
|
cursor: "cursor_",
|
|
29002
|
+
hermes: "hermes_",
|
|
28141
29003
|
gemini: "gemini_"
|
|
28142
29004
|
};
|
|
28143
29005
|
function toolOfSessionId(sessionId) {
|
|
@@ -28166,6 +29028,8 @@ function resumeCommandFor(sessionId, tool) {
|
|
|
28166
29028
|
// available answer for either.
|
|
28167
29029
|
case "cursor":
|
|
28168
29030
|
return `cursor-agent --resume ${raw("cursor_")}`;
|
|
29031
|
+
case "hermes":
|
|
29032
|
+
return `hermes --resume ${raw("hermes_")}`;
|
|
28169
29033
|
// Gemini's `--resume` takes an index or "latest", never a session id.
|
|
28170
29034
|
default:
|
|
28171
29035
|
return null;
|
|
@@ -28289,9 +29153,9 @@ init_project_resolver();
|
|
|
28289
29153
|
import { config } from "dotenv";
|
|
28290
29154
|
import { Command } from "commander";
|
|
28291
29155
|
import chalk2 from "chalk";
|
|
28292
|
-
import { existsSync as
|
|
29156
|
+
import { existsSync as existsSync58, readFileSync as readFileSync50, writeFileSync as writeFileSync23, realpathSync as realpathSync5 } from "fs";
|
|
28293
29157
|
import { homedir as homedir23 } from "os";
|
|
28294
|
-
import { join as
|
|
29158
|
+
import { join as join62, resolve as resolve2, dirname as dirname29, basename as basename27 } from "path";
|
|
28295
29159
|
|
|
28296
29160
|
// ../engine/dist/core/score-tier.js
|
|
28297
29161
|
var STRONG_RATIO = 0.85;
|
|
@@ -28398,11 +29262,11 @@ function renderEnvNeeds(needs, installedCount) {
|
|
|
28398
29262
|
|
|
28399
29263
|
// src/star-nudge.ts
|
|
28400
29264
|
init_paths();
|
|
28401
|
-
import { existsSync as
|
|
28402
|
-
import { dirname as dirname20, join as
|
|
29265
|
+
import { existsSync as existsSync44, mkdirSync as mkdirSync11, writeFileSync as writeFileSync11 } from "node:fs";
|
|
29266
|
+
import { dirname as dirname20, join as join46 } from "node:path";
|
|
28403
29267
|
var REPO = "https://github.com/munhq/chat-recall";
|
|
28404
29268
|
function markerPath() {
|
|
28405
|
-
return
|
|
29269
|
+
return join46(getDataDir(), ".star-asked");
|
|
28406
29270
|
}
|
|
28407
29271
|
function suppressed() {
|
|
28408
29272
|
const env = process.env;
|
|
@@ -28414,7 +29278,7 @@ function shouldAskForStar(resultCount) {
|
|
|
28414
29278
|
if (suppressed()) return false;
|
|
28415
29279
|
if (!process.stderr.isTTY) return false;
|
|
28416
29280
|
try {
|
|
28417
|
-
return !
|
|
29281
|
+
return !existsSync44(markerPath());
|
|
28418
29282
|
} catch {
|
|
28419
29283
|
return false;
|
|
28420
29284
|
}
|
|
@@ -28455,8 +29319,8 @@ function claudeHookConfigFiles() {
|
|
|
28455
29319
|
const out = [];
|
|
28456
29320
|
const seen = /* @__PURE__ */ new Set();
|
|
28457
29321
|
for (const home of claudeHomeDirs()) {
|
|
28458
|
-
if (!
|
|
28459
|
-
const file =
|
|
29322
|
+
if (!existsSync58(join62(home, "projects"))) continue;
|
|
29323
|
+
const file = join62(home, "hooks.json");
|
|
28460
29324
|
let key2;
|
|
28461
29325
|
try {
|
|
28462
29326
|
key2 = realpathSync5(file);
|
|
@@ -28551,13 +29415,13 @@ async function serverDelete(path, body2) {
|
|
|
28551
29415
|
}
|
|
28552
29416
|
var pkgEngines = (() => {
|
|
28553
29417
|
try {
|
|
28554
|
-
return JSON.parse(
|
|
29418
|
+
return JSON.parse(readFileSync50(new URL("../package.json", import.meta.url), "utf-8")).engines?.node ?? "";
|
|
28555
29419
|
} catch {
|
|
28556
29420
|
return "";
|
|
28557
29421
|
}
|
|
28558
29422
|
})();
|
|
28559
29423
|
var pkgVersion = JSON.parse(
|
|
28560
|
-
|
|
29424
|
+
readFileSync50(new URL("../package.json", import.meta.url), "utf-8")
|
|
28561
29425
|
).version;
|
|
28562
29426
|
var DEFAULT_SERVER = (process.env.CHAT_RECALL_DEFAULT_SERVER || "https://chatrecall.dev").replace(/\/+$/, "");
|
|
28563
29427
|
var DEFAULT_ALLOW = [
|
|
@@ -28731,10 +29595,10 @@ program.command("init").description("Set up chat-recall: connect to your server,
|
|
|
28731
29595
|
} else if (target) {
|
|
28732
29596
|
}
|
|
28733
29597
|
if (!options.skipMcp) {
|
|
28734
|
-
const projectRoot =
|
|
29598
|
+
const projectRoot = join62(import.meta.dirname, "..");
|
|
28735
29599
|
let mcpBinOnPath = false;
|
|
28736
29600
|
mcpBinOnPath = isOnPath("chat-recall-mcp");
|
|
28737
|
-
const launch = mcpBinOnPath ? { command: "chat-recall-mcp" } : { command: "node", args: [
|
|
29601
|
+
const launch = mcpBinOnPath ? { command: "chat-recall-mcp" } : { command: "node", args: [join62(projectRoot, "dist", "mcp-relay.js")] };
|
|
28738
29602
|
const MCP_ENV = { NODE_OPTIONS: "--max-old-space-size=1024" };
|
|
28739
29603
|
const { registerMcpEverywhere: registerMcpEverywhere2 } = await Promise.resolve().then(() => (init_mcp_clients(), mcp_clients_exports));
|
|
28740
29604
|
const MCP_CLIENT_FOR_BIN = {
|
|
@@ -28774,7 +29638,7 @@ program.command("init").description("Set up chat-recall: connect to your server,
|
|
|
28774
29638
|
const detected = checkCodeindexStatus2();
|
|
28775
29639
|
if (detected.installed && !forceInstall) {
|
|
28776
29640
|
if (!options.skipMcp) {
|
|
28777
|
-
const mcpJsonPath =
|
|
29641
|
+
const mcpJsonPath = join62(homedir23(), ".mcp.json");
|
|
28778
29642
|
const reg = registerCodeindexMcp2(mcpJsonPath, detected.path);
|
|
28779
29643
|
}
|
|
28780
29644
|
} else if (forceInstall) {
|
|
@@ -28783,7 +29647,7 @@ program.command("init").description("Set up chat-recall: connect to your server,
|
|
|
28783
29647
|
if (result.installed) {
|
|
28784
29648
|
const sizeMb = result.size ? `${(result.size / 1024 / 1024).toFixed(1)} MB` : "?";
|
|
28785
29649
|
if (!options.skipMcp) {
|
|
28786
|
-
const mcpJsonPath =
|
|
29650
|
+
const mcpJsonPath = join62(homedir23(), ".mcp.json");
|
|
28787
29651
|
const reg = registerCodeindexMcp2(mcpJsonPath, CODEINDEX_BIN_PATH2);
|
|
28788
29652
|
}
|
|
28789
29653
|
} else if (!result.prebuiltAvailable) {
|
|
@@ -29240,8 +30104,8 @@ memory.command("wake-up").description("Generate wake-up context (high-importance
|
|
|
29240
30104
|
try {
|
|
29241
30105
|
const identityFile = getIdentityFilePath();
|
|
29242
30106
|
let identity = "AI coding assistant";
|
|
29243
|
-
if (
|
|
29244
|
-
identity =
|
|
30107
|
+
if (existsSync58(identityFile)) {
|
|
30108
|
+
identity = readFileSync50(identityFile, "utf-8").trim();
|
|
29245
30109
|
}
|
|
29246
30110
|
const lines = [
|
|
29247
30111
|
chalk2.bold("# Wake-Up Context"),
|
|
@@ -29341,7 +30205,7 @@ program.command("feedback").argument("<message...>", "what you want to say \u201
|
|
|
29341
30205
|
}
|
|
29342
30206
|
});
|
|
29343
30207
|
program.command("doctor").description("Quick health check across login, server, credentials, hooks, MCP server, and codeindex").option("--purge-local", "Remove the legacy local index (cache.db + vector/KG files) left by pre-thin-collector versions \u2014 storage is server-side now. Requires login; keeps credentials, sync ledger, identity, and the audit log.").action(async (opts) => {
|
|
29344
|
-
const { existsSync:
|
|
30208
|
+
const { existsSync: existsSync59, readFileSync: readFileSync51, statSync: statSync47 } = await import("fs");
|
|
29345
30209
|
const { execSync: execSync6 } = await import("child_process");
|
|
29346
30210
|
const rows = [];
|
|
29347
30211
|
const note = (ok, label, detail) => rows.push({ ok, label, detail });
|
|
@@ -29404,12 +30268,12 @@ program.command("doctor").description("Quick health check across login, server,
|
|
|
29404
30268
|
}
|
|
29405
30269
|
}
|
|
29406
30270
|
}
|
|
29407
|
-
const credFile =
|
|
29408
|
-
if (!
|
|
30271
|
+
const credFile = join62(getDataDir(), "credentials.json");
|
|
30272
|
+
if (!existsSync59(credFile)) {
|
|
29409
30273
|
note(false, "Credentials file", `missing \u2014 run \`chat-recall login <server-url>\``);
|
|
29410
30274
|
} else {
|
|
29411
30275
|
try {
|
|
29412
|
-
const mode =
|
|
30276
|
+
const mode = statSync47(credFile).mode & 511;
|
|
29413
30277
|
const isWin = process.platform === "win32";
|
|
29414
30278
|
const safe = isWin || (mode & 63) === 0;
|
|
29415
30279
|
note(safe, "Credentials file", isWin ? `${credFile} (Windows ACL \u2014 POSIX mode does not apply)` : `${credFile} (mode ${mode.toString(8).padStart(3, "0")}${safe ? "" : " \u2014 should be 600"})`);
|
|
@@ -29420,21 +30284,21 @@ program.command("doctor").description("Quick health check across login, server,
|
|
|
29420
30284
|
for (const hooksJson of claudeHookConfigFiles()) {
|
|
29421
30285
|
const profile = basename27(dirname29(hooksJson));
|
|
29422
30286
|
const label = `Claude hooks (${profile})`;
|
|
29423
|
-
if (!
|
|
30287
|
+
if (!existsSync59(hooksJson)) {
|
|
29424
30288
|
note(false, label, `no ${hooksJson} \u2014 run \`chat-recall install-hooks\``);
|
|
29425
30289
|
continue;
|
|
29426
30290
|
}
|
|
29427
30291
|
try {
|
|
29428
30292
|
const readHooks = (file) => {
|
|
29429
|
-
if (!
|
|
30293
|
+
if (!existsSync59(file)) return {};
|
|
29430
30294
|
try {
|
|
29431
|
-
return JSON.parse(
|
|
30295
|
+
return JSON.parse(readFileSync51(file, "utf-8")).hooks || {};
|
|
29432
30296
|
} catch {
|
|
29433
30297
|
return {};
|
|
29434
30298
|
}
|
|
29435
30299
|
};
|
|
29436
30300
|
const cfg = readHooks(hooksJson);
|
|
29437
|
-
const settings2 = readHooks(
|
|
30301
|
+
const settings2 = readHooks(join62(dirname29(hooksJson), "settings.json"));
|
|
29438
30302
|
const all = ["SessionStart", "UserPromptSubmit", "Stop", "PreCompact", "SessionEnd"];
|
|
29439
30303
|
const hits = [];
|
|
29440
30304
|
for (const ev of all) {
|
|
@@ -29469,9 +30333,9 @@ program.command("doctor").description("Quick health check across login, server,
|
|
|
29469
30333
|
try {
|
|
29470
30334
|
const reg = await Promise.resolve().then(() => (init_guard_registration(), guard_registration_exports));
|
|
29471
30335
|
for (const target2 of reg.guardTargets()) {
|
|
29472
|
-
if (!
|
|
30336
|
+
if (!existsSync59(target2.homeDir)) continue;
|
|
29473
30337
|
const label = `Decision guard \u2014 ${target2.label}`;
|
|
29474
|
-
if (!
|
|
30338
|
+
if (!existsSync59(target2.configPath)) {
|
|
29475
30339
|
note(false, label, `not registered \u2014 run \`chat-recall install-hooks\``);
|
|
29476
30340
|
continue;
|
|
29477
30341
|
}
|
|
@@ -29481,7 +30345,7 @@ program.command("doctor").description("Quick health check across login, server,
|
|
|
29481
30345
|
}
|
|
29482
30346
|
let registered = false;
|
|
29483
30347
|
try {
|
|
29484
|
-
const cfg = JSON.parse(
|
|
30348
|
+
const cfg = JSON.parse(readFileSync51(target2.configPath, "utf-8"));
|
|
29485
30349
|
registered = JSON.stringify(cfg).includes("chat_recall_guard");
|
|
29486
30350
|
} catch {
|
|
29487
30351
|
}
|
|
@@ -29496,7 +30360,7 @@ program.command("doctor").description("Quick health check across login, server,
|
|
|
29496
30360
|
const want = bundledSkillNames2().length;
|
|
29497
30361
|
for (const t of skillTargets2()) {
|
|
29498
30362
|
if (!t.available) continue;
|
|
29499
|
-
const have = want === 0 ? 0 : bundledSkillNames2().filter((n) =>
|
|
30363
|
+
const have = want === 0 ? 0 : bundledSkillNames2().filter((n) => existsSync59(join62(t.dir, n, ".chat-recall-managed"))).length;
|
|
29500
30364
|
note(
|
|
29501
30365
|
have === want,
|
|
29502
30366
|
`Skills \u2014 ${t.label}`,
|
|
@@ -29571,25 +30435,25 @@ program.command("doctor").description("Quick health check across login, server,
|
|
|
29571
30435
|
note(watchRunning, "Watch daemon", watchRunning ? "running" : "not running (run `chat-recall watch --install-service` to keep collection running)");
|
|
29572
30436
|
const dataDir = getDataDir();
|
|
29573
30437
|
const legacyPaths = [
|
|
29574
|
-
|
|
29575
|
-
|
|
29576
|
-
|
|
29577
|
-
|
|
29578
|
-
|
|
29579
|
-
|
|
30438
|
+
join62(dataDir, "cache.db"),
|
|
30439
|
+
join62(dataDir, "cache.db-wal"),
|
|
30440
|
+
join62(dataDir, "cache.db-shm"),
|
|
30441
|
+
join62(dataDir, "index", "lancedb"),
|
|
30442
|
+
join62(dataDir, "index", "knowledge_graph.db"),
|
|
30443
|
+
join62(dataDir, "index", "metadata.db")
|
|
29580
30444
|
];
|
|
29581
|
-
const legacyPresent = legacyPaths.filter((p) =>
|
|
30445
|
+
const legacyPresent = legacyPaths.filter((p) => existsSync59(p));
|
|
29582
30446
|
if (opts.purgeLocal) {
|
|
29583
30447
|
if (!target) {
|
|
29584
30448
|
note(false, "Purge legacy index", "refused \u2014 log in and `chat-recall sync` first, so your history is on the server before removing local copies");
|
|
29585
30449
|
} else if (legacyPresent.length === 0) {
|
|
29586
30450
|
note(true, "Purge legacy index", "nothing to remove");
|
|
29587
30451
|
} else {
|
|
29588
|
-
const { rmSync:
|
|
30452
|
+
const { rmSync: rmSync11 } = await import("fs");
|
|
29589
30453
|
let removed = 0;
|
|
29590
30454
|
for (const p of legacyPresent) {
|
|
29591
30455
|
try {
|
|
29592
|
-
|
|
30456
|
+
rmSync11(p, { recursive: true, force: true });
|
|
29593
30457
|
removed++;
|
|
29594
30458
|
} catch {
|
|
29595
30459
|
}
|
|
@@ -29649,7 +30513,7 @@ companions.command("install").description("Install codeindex (downloads from mun
|
|
|
29649
30513
|
if (result.installed) {
|
|
29650
30514
|
const sizeMb = result.size ? `${(result.size / 1024 / 1024).toFixed(1)} MB` : "?";
|
|
29651
30515
|
console.log(chalk2.green(`\u2713 codeindex installed (${sizeMb}) \u2192 ${result.path}`));
|
|
29652
|
-
const mcpJsonPath =
|
|
30516
|
+
const mcpJsonPath = join62(homedir23(), ".mcp.json");
|
|
29653
30517
|
const reg = registerCodeindexMcp2(mcpJsonPath, CODEINDEX_BIN_PATH2);
|
|
29654
30518
|
if (reg.added) console.log(chalk2.dim(` Registered as MCP server in ${mcpJsonPath}`));
|
|
29655
30519
|
else console.log(chalk2.dim(` Already registered as MCP server`));
|
|
@@ -29671,7 +30535,7 @@ companions.command("uninstall").description("Remove the codeindex binary chat-re
|
|
|
29671
30535
|
const r = uninstallCodeindex2();
|
|
29672
30536
|
if (r.removed) console.log(chalk2.green(`\u2713 Removed ${r.path}`));
|
|
29673
30537
|
else console.log(chalk2.dim(` Nothing to remove at ${r.path}`));
|
|
29674
|
-
const mcpJsonPath =
|
|
30538
|
+
const mcpJsonPath = join62(homedir23(), ".mcp.json");
|
|
29675
30539
|
const u = unregisterCodeindexMcp2(mcpJsonPath);
|
|
29676
30540
|
if (u.removed) console.log(chalk2.dim(` Unregistered MCP server from ${mcpJsonPath}`));
|
|
29677
30541
|
});
|
|
@@ -30223,10 +31087,10 @@ tasks.command("pull [dir]").description("Write TEAM_TASKS.md for your tasks in t
|
|
|
30223
31087
|
try {
|
|
30224
31088
|
const { resolveProjectId: resolveProjectId2 } = await Promise.resolve().then(() => (init_project_resolver(), project_resolver_exports));
|
|
30225
31089
|
const { renderTeamTasksMd: renderTeamTasksMd2, parseTeamTasksFile: parseTeamTasksFile2 } = await Promise.resolve().then(() => (init_project_tasks(), project_tasks_exports));
|
|
30226
|
-
const { writeFileSync: writeFileSync24, readFileSync:
|
|
30227
|
-
const { join:
|
|
30228
|
-
const file =
|
|
30229
|
-
if (!opts.force &&
|
|
31090
|
+
const { writeFileSync: writeFileSync24, readFileSync: readFileSync51, existsSync: existsSync59 } = await import("node:fs");
|
|
31091
|
+
const { join: join63 } = await import("node:path");
|
|
31092
|
+
const file = join63(cwd, "TEAM_TASKS.md");
|
|
31093
|
+
if (!opts.force && existsSync59(file) && parseTeamTasksFile2(readFileSync51(file, "utf8")).length > 0) {
|
|
30230
31094
|
console.error(chalk2.red("TEAM_TASKS.md has unpushed edits."), "Run", chalk2.bold("chat-recall tasks push"), "first, or", chalk2.bold("tasks pull --force"), "to discard.");
|
|
30231
31095
|
process.exit(1);
|
|
30232
31096
|
}
|
|
@@ -30245,14 +31109,14 @@ tasks.command("push [dir]").description("Push TEAM_TASKS.md status edits back to
|
|
|
30245
31109
|
const cwd = dir || process.cwd();
|
|
30246
31110
|
try {
|
|
30247
31111
|
const { parseTeamTasksFile: parseTeamTasksFile2 } = await Promise.resolve().then(() => (init_project_tasks(), project_tasks_exports));
|
|
30248
|
-
const { readFileSync:
|
|
30249
|
-
const { join:
|
|
30250
|
-
const file =
|
|
30251
|
-
if (!
|
|
31112
|
+
const { readFileSync: readFileSync51, existsSync: existsSync59 } = await import("node:fs");
|
|
31113
|
+
const { join: join63 } = await import("node:path");
|
|
31114
|
+
const file = join63(cwd, "TEAM_TASKS.md");
|
|
31115
|
+
if (!existsSync59(file)) {
|
|
30252
31116
|
console.error(chalk2.red("no TEAM_TASKS.md here \u2014"), "run", chalk2.bold("chat-recall tasks pull"), "first");
|
|
30253
31117
|
process.exit(1);
|
|
30254
31118
|
}
|
|
30255
|
-
const edits = parseTeamTasksFile2(
|
|
31119
|
+
const edits = parseTeamTasksFile2(readFileSync51(file, "utf8"));
|
|
30256
31120
|
let n = 0;
|
|
30257
31121
|
for (const e of edits) {
|
|
30258
31122
|
await serverPatch(`/api/tasks/${encodeURIComponent(e.id)}`, { status: e.intent });
|
|
@@ -30358,8 +31222,8 @@ team.command("publish <type> <name> <file>").description("Publish a local file a
|
|
|
30358
31222
|
console.error(chalk2.red(`Invalid tool: ${opts.tool}. Must be one of: ${validTools.join(", ")}`));
|
|
30359
31223
|
process.exit(1);
|
|
30360
31224
|
}
|
|
30361
|
-
const { readFileSync:
|
|
30362
|
-
const body2 =
|
|
31225
|
+
const { readFileSync: readFileSync51 } = await import("fs");
|
|
31226
|
+
const body2 = readFileSync51(file);
|
|
30363
31227
|
const { teamPublish: teamPublish2 } = await Promise.resolve().then(() => (init_team_client(), team_client_exports));
|
|
30364
31228
|
const a = await teamPublish2({
|
|
30365
31229
|
type,
|
|
@@ -30735,20 +31599,20 @@ program.command("task-hook").description("Move a board card when a prompt or a c
|
|
|
30735
31599
|
}
|
|
30736
31600
|
});
|
|
30737
31601
|
program.command("install-hooks").description("Install Claude Code hooks (Stop + PreCompact + UserPromptSubmit + SessionEnd + SessionStart) into every Claude profile").option("--uninstall", "Remove hooks instead of installing them").option("--no-resume-hint", "Don't install the UserPromptSubmit resume-hint hook").option("--no-escalate", "Don't install the SessionEnd learnings-escalation hook").option("--no-wakeup", "Don't install the SessionStart wake-up hook").option("--no-guard", "Don't install the PreToolUse decision guard").option("--no-task-board", "Don't install the hooks that claim and close board cards").action(async (opts) => {
|
|
30738
|
-
const { mkdirSync: mkdirSync23, copyFileSync: copyFileSync4, chmodSync: chmodSync5, existsSync:
|
|
31602
|
+
const { mkdirSync: mkdirSync23, copyFileSync: copyFileSync4, chmodSync: chmodSync5, existsSync: existsSync59, readFileSync: readFileSync51, writeFileSync: writeFileSync24, statSync: statSync47, unlinkSync: unlinkSync4 } = await import("fs");
|
|
30739
31603
|
const { fileURLToPath: fileURLToPath6 } = await import("url");
|
|
30740
31604
|
const { boardHookEntries: boardHookEntries2, isBoardHookEntry: isBoardHookEntry2, registerBoardHooks: registerBoardHooks2, resolveCliEntry: resolveCliEntry2 } = await Promise.resolve().then(() => (init_board_hooks(), board_hooks_exports));
|
|
30741
31605
|
const here = fileURLToPath6(new URL(".", import.meta.url));
|
|
30742
31606
|
const findHook = (name) => {
|
|
30743
31607
|
const candidates2 = [
|
|
30744
|
-
|
|
30745
|
-
|
|
31608
|
+
join62(here, "..", "hooks", name),
|
|
31609
|
+
join62(here, "..", "..", "hooks", name),
|
|
30746
31610
|
// The monorepo root, for a run straight from the checkout. The copy
|
|
30747
31611
|
// under packages/cli/hooks is written by the package build, so a
|
|
30748
31612
|
// freshly added script is only at the root until that build runs.
|
|
30749
|
-
|
|
31613
|
+
join62(here, "..", "..", "..", "hooks", name)
|
|
30750
31614
|
];
|
|
30751
|
-
return candidates2.find((p) =>
|
|
31615
|
+
return candidates2.find((p) => existsSync59(p));
|
|
30752
31616
|
};
|
|
30753
31617
|
const sourceSaveHook = findHook("chat_recall_save_hook.sh");
|
|
30754
31618
|
const sourceGuardHook = findHook("chat_recall_guard_hook.sh");
|
|
@@ -30760,16 +31624,16 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
|
|
|
30760
31624
|
process.exit(1);
|
|
30761
31625
|
}
|
|
30762
31626
|
const hooksDir = getHooksDir();
|
|
30763
|
-
const installedSaveHook =
|
|
30764
|
-
const installedGuardHook =
|
|
30765
|
-
const installedResumeHook =
|
|
30766
|
-
const installedEscalateHook =
|
|
30767
|
-
const installedWakeupHook =
|
|
31627
|
+
const installedSaveHook = join62(hooksDir, "chat_recall_save_hook.sh");
|
|
31628
|
+
const installedGuardHook = join62(hooksDir, "chat_recall_guard_hook.sh");
|
|
31629
|
+
const installedResumeHook = join62(hooksDir, "chat_recall_resume_hook.sh");
|
|
31630
|
+
const installedEscalateHook = join62(hooksDir, "chat_recall_escalate_hook.sh");
|
|
31631
|
+
const installedWakeupHook = join62(hooksDir, "chat_recall_wakeup_hook.sh");
|
|
30768
31632
|
const wakeupWiredInSettings = (home) => {
|
|
30769
|
-
const settings2 =
|
|
30770
|
-
if (!
|
|
31633
|
+
const settings2 = join62(home, "settings.json");
|
|
31634
|
+
if (!existsSync59(settings2)) return false;
|
|
30771
31635
|
try {
|
|
30772
|
-
const cfg = JSON.parse(
|
|
31636
|
+
const cfg = JSON.parse(readFileSync51(settings2, "utf-8"));
|
|
30773
31637
|
const arr = Array.isArray(cfg.hooks?.SessionStart) ? cfg.hooks.SessionStart : [];
|
|
30774
31638
|
return arr.some((h) => (h?.hooks?.[0]?.command || "").includes("chat_recall_wakeup_hook"));
|
|
30775
31639
|
} catch {
|
|
@@ -30778,9 +31642,9 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
|
|
|
30778
31642
|
};
|
|
30779
31643
|
const hookConfigFiles = claudeHookConfigFiles();
|
|
30780
31644
|
const readHookConfig = (file) => {
|
|
30781
|
-
if (!
|
|
31645
|
+
if (!existsSync59(file)) return { hooks: {} };
|
|
30782
31646
|
try {
|
|
30783
|
-
const c = JSON.parse(
|
|
31647
|
+
const c = JSON.parse(readFileSync51(file, "utf-8"));
|
|
30784
31648
|
if (!c.hooks || typeof c.hooks !== "object") c.hooks = {};
|
|
30785
31649
|
return c;
|
|
30786
31650
|
} catch (err) {
|
|
@@ -30795,9 +31659,9 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
|
|
|
30795
31659
|
};
|
|
30796
31660
|
const HOOK_EVENTS = ["Stop", "PreCompact", "UserPromptSubmit", "SessionEnd", "SessionStart", "PreToolUse"];
|
|
30797
31661
|
const readJson4 = (file) => {
|
|
30798
|
-
if (!
|
|
31662
|
+
if (!existsSync59(file)) return {};
|
|
30799
31663
|
try {
|
|
30800
|
-
return JSON.parse(
|
|
31664
|
+
return JSON.parse(readFileSync51(file, "utf-8"));
|
|
30801
31665
|
} catch {
|
|
30802
31666
|
return {};
|
|
30803
31667
|
}
|
|
@@ -30806,8 +31670,8 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
|
|
|
30806
31670
|
const reg = await Promise.resolve().then(() => (init_guard_registration(), guard_registration_exports));
|
|
30807
31671
|
const notes = [];
|
|
30808
31672
|
for (const target of reg.guardTargets()) {
|
|
30809
|
-
if (!
|
|
30810
|
-
const wrapper =
|
|
31673
|
+
if (!existsSync59(target.homeDir)) continue;
|
|
31674
|
+
const wrapper = join62(hooksDir, reg.guardWrapperName(target.tool));
|
|
30811
31675
|
writeFileSync24(wrapper, reg.guardWrapperSource(target.tool, hookPath));
|
|
30812
31676
|
chmodSync5(wrapper, 493);
|
|
30813
31677
|
mkdirSync23(dirname29(target.configPath), { recursive: true });
|
|
@@ -30827,9 +31691,9 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
|
|
|
30827
31691
|
const reg = await Promise.resolve().then(() => (init_guard_registration(), guard_registration_exports));
|
|
30828
31692
|
let removed = 0;
|
|
30829
31693
|
for (const target of reg.guardTargets()) {
|
|
30830
|
-
if (!
|
|
31694
|
+
if (!existsSync59(target.configPath)) continue;
|
|
30831
31695
|
if (target.tool === "opencode") {
|
|
30832
|
-
const body2 =
|
|
31696
|
+
const body2 = readFileSync51(target.configPath, "utf-8");
|
|
30833
31697
|
if (!body2.includes("chat-recall install-hooks")) continue;
|
|
30834
31698
|
unlinkSync4(target.configPath);
|
|
30835
31699
|
removed += 1;
|
|
@@ -30855,7 +31719,7 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
|
|
|
30855
31719
|
if (filtered.length) config2.hooks[event] = filtered;
|
|
30856
31720
|
else delete config2.hooks[event];
|
|
30857
31721
|
}
|
|
30858
|
-
if (removed === 0 && !
|
|
31722
|
+
if (removed === 0 && !existsSync59(hooksJson)) continue;
|
|
30859
31723
|
writeFileSync24(hooksJson, JSON.stringify(config2, null, 2) + "\n");
|
|
30860
31724
|
total += removed;
|
|
30861
31725
|
console.log(chalk2.green(`\u2713 Removed ${removed} chat-recall hook entr${removed === 1 ? "y" : "ies"} from ${hooksJson}`));
|
|
@@ -30937,7 +31801,7 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
|
|
|
30937
31801
|
const config2 = readHookConfig(hooksJson);
|
|
30938
31802
|
const home = dirname29(hooksJson);
|
|
30939
31803
|
const alreadyWired = wakeupWiredInSettings(home);
|
|
30940
|
-
if (alreadyWired) wakeupSkipped.push(
|
|
31804
|
+
if (alreadyWired) wakeupSkipped.push(join62(home, "settings.json"));
|
|
30941
31805
|
const perProfile = installWakeup && !alreadyWired ? [...events, ["SessionStart", wakeupEntry]] : events;
|
|
30942
31806
|
for (const event of HOOK_EVENTS) {
|
|
30943
31807
|
const arr = Array.isArray(config2.hooks[event]) ? config2.hooks[event] : [];
|
|
@@ -30950,18 +31814,18 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
|
|
|
30950
31814
|
writeFileSync24(hooksJson, JSON.stringify(config2, null, 2) + "\n");
|
|
30951
31815
|
}
|
|
30952
31816
|
if (installGuard) await addGuardToOtherTools(installedGuardHook);
|
|
30953
|
-
const saveSz =
|
|
31817
|
+
const saveSz = statSync47(installedSaveHook).size;
|
|
30954
31818
|
console.log(chalk2.green(`\u2713 Installed chat-recall save hook (${saveSz} bytes)`));
|
|
30955
31819
|
if (installResume) {
|
|
30956
|
-
const resumeSz =
|
|
31820
|
+
const resumeSz = statSync47(installedResumeHook).size;
|
|
30957
31821
|
console.log(chalk2.green(`\u2713 Installed chat-recall resume-hint hook (${resumeSz} bytes)`));
|
|
30958
31822
|
}
|
|
30959
31823
|
if (installEscalate) {
|
|
30960
|
-
const escalateSz =
|
|
31824
|
+
const escalateSz = statSync47(installedEscalateHook).size;
|
|
30961
31825
|
console.log(chalk2.green(`\u2713 Installed chat-recall learnings-escalation hook (${escalateSz} bytes)`));
|
|
30962
31826
|
}
|
|
30963
31827
|
if (installGuard) {
|
|
30964
|
-
const guardSz =
|
|
31828
|
+
const guardSz = statSync47(installedGuardHook).size;
|
|
30965
31829
|
console.log(chalk2.green(`\u2713 Installed chat-recall decision guard (${guardSz} bytes)`));
|
|
30966
31830
|
}
|
|
30967
31831
|
if (installTaskBoard) {
|
|
@@ -30969,7 +31833,7 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
|
|
|
30969
31833
|
console.log(chalk2.dim(" A prompt naming a card id claims it; a commit message naming one closes it."));
|
|
30970
31834
|
}
|
|
30971
31835
|
if (installWakeup) {
|
|
30972
|
-
const wakeupSz =
|
|
31836
|
+
const wakeupSz = statSync47(installedWakeupHook).size;
|
|
30973
31837
|
console.log(chalk2.green(`\u2713 Installed chat-recall wake-up hook (${wakeupSz} bytes)`));
|
|
30974
31838
|
for (const f of wakeupSkipped) {
|
|
30975
31839
|
console.log(chalk2.dim(` (SessionStart already wired in ${f} \u2014 left as is, not duplicated)`));
|
|
@@ -31430,8 +32294,8 @@ exclude.command("project <path>").description("Exclude a project path from synci
|
|
|
31430
32294
|
saveSettings2(s);
|
|
31431
32295
|
console.log(chalk2.green(`\u2713 Excluded ${abs}`) + chalk2.dim(" \u2014 takes effect next sync; already-synced rows stay until deleted."));
|
|
31432
32296
|
});
|
|
31433
|
-
exclude.command("tool <tool>").description("Exclude an AI tool entirely (claude | gemini | codex | opencode | agy | cursor)").action(async (tool) => {
|
|
31434
|
-
const valid = ["claude", "gemini", "codex", "opencode", "agy", "cursor"];
|
|
32297
|
+
exclude.command("tool <tool>").description("Exclude an AI tool entirely (claude | gemini | codex | opencode | agy | cursor | hermes)").action(async (tool) => {
|
|
32298
|
+
const valid = ["claude", "gemini", "codex", "opencode", "agy", "cursor", "hermes"];
|
|
31435
32299
|
if (!valid.includes(tool)) {
|
|
31436
32300
|
console.error(chalk2.red(`Unknown tool '${tool}'.`) + chalk2.dim(` Use one of: ${valid.join(" | ")}`));
|
|
31437
32301
|
process.exit(1);
|