chat-recall 0.5.5 → 0.5.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +1389 -697
- package/dist/cli.js.map +1 -1
- package/dist/mcp-diagnostics.d.ts.map +1 -1
- package/dist/mcp-diagnostics.js +10 -8
- package/dist/mcp-diagnostics.js.map +1 -1
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +1133 -457
- package/dist/mcp.js.map +1 -1
- package/dist/project-tasks.d.ts.map +1 -1
- package/dist/project-tasks.js +12 -7
- package/dist/project-tasks.js.map +1 -1
- package/dist/service-installer.d.ts +1 -1
- package/dist/service-installer.d.ts.map +1 -1
- package/dist/service-installer.js +20 -6
- package/dist/service-installer.js.map +1 -1
- package/dist/sync-client.d.ts +1 -0
- package/dist/sync-client.d.ts.map +1 -1
- package/dist/sync-client.js +162 -93
- package/dist/sync-client.js.map +1 -1
- package/dist/sync-ledger.d.ts +22 -0
- package/dist/sync-ledger.d.ts.map +1 -1
- package/dist/sync-ledger.js +108 -1
- package/dist/sync-ledger.js.map +1 -1
- package/dist/watch.js +989 -445
- package/hooks/chat_recall_escalate_hook.sh +28 -2
- package/hooks/chat_recall_save_hook.sh +17 -11
- package/hooks/chat_recall_wakeup_hook.sh +27 -1
- package/package.json +7 -3
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 } = __require("worker_threads");
|
|
2037
|
-
var { join:
|
|
2037
|
+
var { join: join57 } = __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"] || join57(__dirname, "lib", "worker.js");
|
|
2081
2081
|
const worker = new Worker(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: join57, isAbsolute: isAbsolute3, sep: sep3 } = __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"] || join57(__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"] || join57(__dirname, "worker.js");
|
|
2565
2565
|
options.pipelines = [pipeline.map((dest) => {
|
|
2566
2566
|
return {
|
|
2567
2567
|
...dest,
|
|
@@ -2579,16 +2579,16 @@ var require_transport = __commonJS({
|
|
|
2579
2579
|
return buildStream(fixTarget(target), options, worker, sync);
|
|
2580
2580
|
function fixTarget(origin) {
|
|
2581
2581
|
origin = bundlerOverrides[origin] || origin;
|
|
2582
|
-
if (
|
|
2582
|
+
if (isAbsolute3(origin) || origin.indexOf("file://") === 0) {
|
|
2583
2583
|
return origin;
|
|
2584
2584
|
}
|
|
2585
2585
|
if (origin === "pino/file") {
|
|
2586
|
-
return
|
|
2586
|
+
return join57(__dirname, "..", "file.js");
|
|
2587
2587
|
}
|
|
2588
2588
|
let fixTarget2;
|
|
2589
2589
|
for (const filePath of callers) {
|
|
2590
2590
|
try {
|
|
2591
|
-
const context3 = filePath === "node:repl" ? process.cwd() +
|
|
2591
|
+
const context3 = filePath === "node:repl" ? process.cwd() + sep3 : filePath;
|
|
2592
2592
|
fixTarget2 = createRequire3(context3).resolve(origin);
|
|
2593
2593
|
break;
|
|
2594
2594
|
} catch (err) {
|
|
@@ -3572,7 +3572,7 @@ var require_safe_stable_stringify = __commonJS({
|
|
|
3572
3572
|
return circularValue;
|
|
3573
3573
|
}
|
|
3574
3574
|
let res = "";
|
|
3575
|
-
let
|
|
3575
|
+
let join57 = ",";
|
|
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
|
+
join57 = `,
|
|
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 += join57;
|
|
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 += `${join57}"... ${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
|
+
join57 = `,
|
|
3625
3625
|
${indentation}`;
|
|
3626
3626
|
whitespace = " ";
|
|
3627
3627
|
}
|
|
@@ -3635,13 +3635,13 @@ ${indentation}`;
|
|
|
3635
3635
|
const tmp = stringifyFnReplacer(key2, value, stack, replacer, spacer, indentation);
|
|
3636
3636
|
if (tmp !== void 0) {
|
|
3637
3637
|
res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
|
|
3638
|
-
separator =
|
|
3638
|
+
separator = join57;
|
|
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 = join57;
|
|
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 join57 = ",";
|
|
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
|
+
join57 = `,
|
|
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 += join57;
|
|
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 += `${join57}"... ${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
|
+
join57 = `,
|
|
3726
3726
|
${indentation}`;
|
|
3727
3727
|
whitespace = " ";
|
|
3728
3728
|
}
|
|
@@ -3731,7 +3731,7 @@ ${indentation}`;
|
|
|
3731
3731
|
const tmp = stringifyArrayReplacer(key2, value[key2], stack, replacer, spacer, indentation);
|
|
3732
3732
|
if (tmp !== void 0) {
|
|
3733
3733
|
res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
|
|
3734
|
-
separator =
|
|
3734
|
+
separator = join57;
|
|
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 join58 = `,
|
|
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 += join58;
|
|
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 += `${join58}"... ${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 join57 = `,
|
|
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, join57, maximumBreadth);
|
|
3828
3828
|
keys = keys.slice(value.length);
|
|
3829
3829
|
maximumPropertiesToStringify -= value.length;
|
|
3830
|
-
separator =
|
|
3830
|
+
separator = join57;
|
|
3831
3831
|
}
|
|
3832
3832
|
if (deterministic) {
|
|
3833
3833
|
keys = sort(keys, comparator);
|
|
@@ -3838,13 +3838,13 @@ ${indentation}`;
|
|
|
3838
3838
|
const tmp = stringifyIndent(key2, value[key2], stack, spacer, indentation);
|
|
3839
3839
|
if (tmp !== void 0) {
|
|
3840
3840
|
res += `${separator}${strEscape(key2)}: ${tmp}`;
|
|
3841
|
-
separator =
|
|
3841
|
+
separator = join57;
|
|
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 = join57;
|
|
3848
3848
|
}
|
|
3849
3849
|
if (separator !== "") {
|
|
3850
3850
|
res = `
|
|
@@ -4552,7 +4552,10 @@ var init_paths = __esm({
|
|
|
4552
4552
|
// ../engine/dist/core/settings.js
|
|
4553
4553
|
var settings_exports = {};
|
|
4554
4554
|
__export(settings_exports, {
|
|
4555
|
+
PERSONAL_DIR_NAMES: () => PERSONAL_DIR_NAMES,
|
|
4555
4556
|
PERSONAL_DIR_PATTERNS: () => PERSONAL_DIR_PATTERNS,
|
|
4557
|
+
_resetSecretsCacheForTests: () => _resetSecretsCacheForTests,
|
|
4558
|
+
_resetSettingsCacheForTests: () => _resetSettingsCacheForTests,
|
|
4556
4559
|
_resetSourceSettingsCache: () => _resetSourceSettingsCache,
|
|
4557
4560
|
applySettingsToEnv: () => applySettingsToEnv,
|
|
4558
4561
|
isPersonalPath: () => isPersonalPath,
|
|
@@ -4671,7 +4674,8 @@ function defaultSync() {
|
|
|
4671
4674
|
function isPersonalPath(projectPath, includeProjects = []) {
|
|
4672
4675
|
if (includeProjects.some((inc) => inc && projectPath.includes(inc)))
|
|
4673
4676
|
return false;
|
|
4674
|
-
|
|
4677
|
+
const norm = (projectPath.replace(/\\/g, "/") + "/").toLowerCase();
|
|
4678
|
+
return PERSONAL_DIR_NAMES.some((n) => norm.includes(`/${n.toLowerCase()}/`));
|
|
4675
4679
|
}
|
|
4676
4680
|
function defaultTeam() {
|
|
4677
4681
|
return {
|
|
@@ -4791,11 +4795,24 @@ function _resetSourceSettingsCache() {
|
|
|
4791
4795
|
function secretsPath() {
|
|
4792
4796
|
return join2(getDataDir(), "secrets.env");
|
|
4793
4797
|
}
|
|
4798
|
+
function _resetSecretsCacheForTests() {
|
|
4799
|
+
_secretsCache = null;
|
|
4800
|
+
}
|
|
4794
4801
|
function loadSecrets() {
|
|
4795
4802
|
const out = {};
|
|
4796
4803
|
const p = secretsPath();
|
|
4797
4804
|
if (!existsSync2(p))
|
|
4798
4805
|
return out;
|
|
4806
|
+
let mtimeMs = -1, size = -1;
|
|
4807
|
+
try {
|
|
4808
|
+
const st = statSync2(p);
|
|
4809
|
+
mtimeMs = st.mtimeMs;
|
|
4810
|
+
size = st.size;
|
|
4811
|
+
} catch {
|
|
4812
|
+
}
|
|
4813
|
+
if (_secretsCache && _secretsCache.mtimeMs === mtimeMs && _secretsCache.size === size) {
|
|
4814
|
+
return { ..._secretsCache.value };
|
|
4815
|
+
}
|
|
4799
4816
|
try {
|
|
4800
4817
|
for (const line of readFileSync(p, "utf-8").split("\n")) {
|
|
4801
4818
|
const t = line.trim();
|
|
@@ -4813,9 +4830,12 @@ function loadSecrets() {
|
|
|
4813
4830
|
}
|
|
4814
4831
|
} catch {
|
|
4815
4832
|
}
|
|
4833
|
+
if (mtimeMs >= 0)
|
|
4834
|
+
_secretsCache = { mtimeMs, size, value: { ...out } };
|
|
4816
4835
|
return out;
|
|
4817
4836
|
}
|
|
4818
4837
|
function writeSecrets(secrets) {
|
|
4838
|
+
_secretsCache = null;
|
|
4819
4839
|
const p = secretsPath();
|
|
4820
4840
|
mkdirSync2(dirname2(p), { recursive: true });
|
|
4821
4841
|
const body = "# chat-recall secrets \u2014 NOT committed/synced. Mode 0600.\n" + Object.entries(secrets).filter(([, v]) => v).map(([k, v]) => `${k}=${v}`).join("\n") + "\n";
|
|
@@ -4825,10 +4845,34 @@ function writeSecrets(secrets) {
|
|
|
4825
4845
|
} catch {
|
|
4826
4846
|
}
|
|
4827
4847
|
}
|
|
4848
|
+
function applySecretOverlay(result) {
|
|
4849
|
+
const secrets = loadSecrets();
|
|
4850
|
+
for (const { block, field, env } of SECRET_FIELDS) {
|
|
4851
|
+
const blk = result[block];
|
|
4852
|
+
const value = process.env[env] || secrets[env] || blk[field];
|
|
4853
|
+
if (value)
|
|
4854
|
+
blk[field] = value;
|
|
4855
|
+
}
|
|
4856
|
+
return result;
|
|
4857
|
+
}
|
|
4858
|
+
function _resetSettingsCacheForTests() {
|
|
4859
|
+
_settingsCache = null;
|
|
4860
|
+
}
|
|
4828
4861
|
function loadSettings() {
|
|
4829
4862
|
const path = settingsPath();
|
|
4830
4863
|
if (!existsSync2(path))
|
|
4831
4864
|
return freshDefaults();
|
|
4865
|
+
let mtimeMs = -1, size = -1;
|
|
4866
|
+
try {
|
|
4867
|
+
const st = statSync2(path);
|
|
4868
|
+
mtimeMs = st.mtimeMs;
|
|
4869
|
+
size = st.size;
|
|
4870
|
+
} catch {
|
|
4871
|
+
}
|
|
4872
|
+
if (_settingsCache && _settingsCache.mtimeMs === mtimeMs && _settingsCache.size === size) {
|
|
4873
|
+
const cached = structuredClone(_settingsCache.value);
|
|
4874
|
+
return applySecretOverlay(cached);
|
|
4875
|
+
}
|
|
4832
4876
|
try {
|
|
4833
4877
|
const parsed = JSON.parse(readFileSync(path, "utf-8"));
|
|
4834
4878
|
const base2 = freshDefaults();
|
|
@@ -4841,19 +4885,15 @@ function loadSettings() {
|
|
|
4841
4885
|
sync: mergeSync(base2.sync, parsed.sync),
|
|
4842
4886
|
team: mergeTeam(base2.team, parsed.team)
|
|
4843
4887
|
};
|
|
4844
|
-
|
|
4845
|
-
|
|
4846
|
-
|
|
4847
|
-
const value = process.env[env] || secrets[env] || blk[field];
|
|
4848
|
-
if (value)
|
|
4849
|
-
blk[field] = value;
|
|
4850
|
-
}
|
|
4851
|
-
return result;
|
|
4888
|
+
if (mtimeMs >= 0)
|
|
4889
|
+
_settingsCache = { mtimeMs, size, value: structuredClone(result) };
|
|
4890
|
+
return applySecretOverlay(result);
|
|
4852
4891
|
} catch {
|
|
4853
4892
|
return freshDefaults();
|
|
4854
4893
|
}
|
|
4855
4894
|
}
|
|
4856
4895
|
function saveSettings(settings2) {
|
|
4896
|
+
_settingsCache = null;
|
|
4857
4897
|
const secrets = loadSecrets();
|
|
4858
4898
|
const stripped = {
|
|
4859
4899
|
...settings2,
|
|
@@ -4967,7 +5007,7 @@ function mergeSettings(current, update) {
|
|
|
4967
5007
|
const team2 = mergeTeam(current.team, update.team);
|
|
4968
5008
|
return { v: SCHEMA_VERSION, embedding: e, summary: sm, sources: sources3, privacy, sync, team: team2 };
|
|
4969
5009
|
}
|
|
4970
|
-
var CLI_DETECTION_ORDER, SCHEMA_VERSION, PERSONAL_DIR_PATTERNS, _sourceSettingsCache, SECRET_FIELDS;
|
|
5010
|
+
var CLI_DETECTION_ORDER, SCHEMA_VERSION, PERSONAL_DIR_NAMES, PERSONAL_DIR_PATTERNS, _sourceSettingsCache, SECRET_FIELDS, _secretsCache, _settingsCache;
|
|
4971
5011
|
var init_settings = __esm({
|
|
4972
5012
|
"../engine/dist/core/settings.js"() {
|
|
4973
5013
|
"use strict";
|
|
@@ -4981,17 +5021,18 @@ var init_settings = __esm({
|
|
|
4981
5021
|
{ preset: "aichat", bin: "aichat", cmd: "aichat --no-stream" }
|
|
4982
5022
|
];
|
|
4983
5023
|
SCHEMA_VERSION = 3;
|
|
4984
|
-
|
|
4985
|
-
"
|
|
4986
|
-
"
|
|
4987
|
-
"
|
|
4988
|
-
"
|
|
4989
|
-
"
|
|
4990
|
-
"
|
|
4991
|
-
"
|
|
4992
|
-
"
|
|
4993
|
-
"
|
|
5024
|
+
PERSONAL_DIR_NAMES = [
|
|
5025
|
+
"Pictures",
|
|
5026
|
+
"Music",
|
|
5027
|
+
"Movies",
|
|
5028
|
+
"Videos",
|
|
5029
|
+
"Photos Library",
|
|
5030
|
+
"Documents",
|
|
5031
|
+
"Desktop",
|
|
5032
|
+
"Downloads",
|
|
5033
|
+
"Library"
|
|
4994
5034
|
];
|
|
5035
|
+
PERSONAL_DIR_PATTERNS = PERSONAL_DIR_NAMES.map((n) => `/${n}/`);
|
|
4995
5036
|
_sourceSettingsCache = null;
|
|
4996
5037
|
SECRET_FIELDS = [
|
|
4997
5038
|
{ block: "summary", field: "apiKey", env: "SUMMARY_API_KEY" },
|
|
@@ -5002,6 +5043,8 @@ var init_settings = __esm({
|
|
|
5002
5043
|
{ block: "embedding", field: "ollamaCloudApiKey", env: "OLLAMA_API_KEY" },
|
|
5003
5044
|
{ block: "embedding", field: "openaiCompatApiKey", env: "OPENAI_COMPAT_API_KEY" }
|
|
5004
5045
|
];
|
|
5046
|
+
_secretsCache = null;
|
|
5047
|
+
_settingsCache = null;
|
|
5005
5048
|
}
|
|
5006
5049
|
});
|
|
5007
5050
|
|
|
@@ -5101,14 +5144,14 @@ function primaryHomes() {
|
|
|
5101
5144
|
s = void 0;
|
|
5102
5145
|
}
|
|
5103
5146
|
const opencodeDb = env.CHAT_RECALL_OPENCODE_DB || s?.opencodeDbPath || join3(home, ".local", "share", "opencode", "opencode.db");
|
|
5104
|
-
const
|
|
5147
|
+
const candidates2 = [
|
|
5105
5148
|
env.CHAT_RECALL_CLAUDE_HOME || s?.claudeHome || join3(home, ".claude"),
|
|
5106
5149
|
env.CHAT_RECALL_GEMINI_HOME || s?.geminiHome || join3(home, ".gemini"),
|
|
5107
5150
|
env.CHAT_RECALL_CODEX_HOME || s?.codexHome || join3(home, ".codex"),
|
|
5108
5151
|
env.CHAT_RECALL_AGY_HOME || s?.agyHome || join3(home, ".gemini", "antigravity-cli"),
|
|
5109
5152
|
dirOf(opencodeDb)
|
|
5110
5153
|
];
|
|
5111
|
-
return
|
|
5154
|
+
return candidates2.map(normalizeHomePath);
|
|
5112
5155
|
}
|
|
5113
5156
|
function homeDecision(path) {
|
|
5114
5157
|
const p = normalizeHomePath(path);
|
|
@@ -5522,28 +5565,55 @@ function maskSecret(s) {
|
|
|
5522
5565
|
return "*".repeat(s.length);
|
|
5523
5566
|
return "*".repeat(Math.min(s.length - 4, 60)) + s.slice(-4);
|
|
5524
5567
|
}
|
|
5568
|
+
function globalRegexFor(pattern) {
|
|
5569
|
+
const flags = pattern.flags.includes("g") ? pattern.flags : pattern.flags + "g";
|
|
5570
|
+
const key = pattern.source + "\0" + flags;
|
|
5571
|
+
let re = globalRegexCache.get(key);
|
|
5572
|
+
if (!re) {
|
|
5573
|
+
re = new RegExp(pattern.source, flags);
|
|
5574
|
+
globalRegexCache.set(key, re);
|
|
5575
|
+
}
|
|
5576
|
+
return re;
|
|
5577
|
+
}
|
|
5578
|
+
function makeLineResolver(text) {
|
|
5579
|
+
const starts = [];
|
|
5580
|
+
for (let i = text.indexOf("\n"); i !== -1; i = text.indexOf("\n", i + 1))
|
|
5581
|
+
starts.push(i);
|
|
5582
|
+
return (index) => {
|
|
5583
|
+
let lo = 0, hi = starts.length;
|
|
5584
|
+
while (lo < hi) {
|
|
5585
|
+
const mid = lo + hi >> 1;
|
|
5586
|
+
if (starts[mid] < index)
|
|
5587
|
+
lo = mid + 1;
|
|
5588
|
+
else
|
|
5589
|
+
hi = mid;
|
|
5590
|
+
}
|
|
5591
|
+
return lo + 1;
|
|
5592
|
+
};
|
|
5593
|
+
}
|
|
5525
5594
|
function scanTextForFindings(text, opts = {}) {
|
|
5526
5595
|
if (!text)
|
|
5527
5596
|
return [];
|
|
5528
5597
|
const rules = opts.rules || activeRules();
|
|
5529
5598
|
const findings = [];
|
|
5530
5599
|
const seenSpans = /* @__PURE__ */ new Set();
|
|
5600
|
+
const lineAt = makeLineResolver(text);
|
|
5531
5601
|
for (const r of rules) {
|
|
5532
|
-
const re =
|
|
5602
|
+
const re = globalRegexFor(r.pattern);
|
|
5603
|
+
re.lastIndex = 0;
|
|
5533
5604
|
let m;
|
|
5534
5605
|
while ((m = re.exec(text)) !== null) {
|
|
5535
5606
|
const span = `${m.index}:${m[0].length}`;
|
|
5536
5607
|
if (!seenSpans.has(span)) {
|
|
5537
5608
|
seenSpans.add(span);
|
|
5538
|
-
|
|
5539
|
-
findings.push({ rule: r.label, line, preview: maskSecret(m[0]) });
|
|
5609
|
+
findings.push({ rule: r.label, line: lineAt(m.index), preview: maskSecret(m[0]) });
|
|
5540
5610
|
}
|
|
5541
5611
|
if (re.lastIndex === m.index)
|
|
5542
5612
|
re.lastIndex++;
|
|
5543
5613
|
}
|
|
5544
5614
|
}
|
|
5545
5615
|
for (const { start, end } of findContextualSecrets(text)) {
|
|
5546
|
-
const line =
|
|
5616
|
+
const line = lineAt(start);
|
|
5547
5617
|
findings.push({ rule: "secret-context", line, preview: maskSecret(text.slice(start, end)) });
|
|
5548
5618
|
}
|
|
5549
5619
|
return findings;
|
|
@@ -5596,7 +5666,7 @@ function redactToolResultBody(toolName, body) {
|
|
|
5596
5666
|
return body;
|
|
5597
5667
|
return `[redacted: ${toolName} output, ${body.length} chars]`;
|
|
5598
5668
|
}
|
|
5599
|
-
var DEFAULT_REDACTION_RULES, SECRET_CONTEXT_RE, HIGH_ENTROPY_TOKEN_RE, cache, CANARY, MAX_PACK_RULES, MAX_PATTERN_LEN, serverPack, privacyCache, PATH_REGEX;
|
|
5669
|
+
var DEFAULT_REDACTION_RULES, SECRET_CONTEXT_RE, HIGH_ENTROPY_TOKEN_RE, cache, CANARY, MAX_PACK_RULES, MAX_PATTERN_LEN, serverPack, globalRegexCache, privacyCache, PATH_REGEX;
|
|
5600
5670
|
var init_secret_redactor = __esm({
|
|
5601
5671
|
"../engine/dist/core/secret-redactor.js"() {
|
|
5602
5672
|
"use strict";
|
|
@@ -5734,6 +5804,7 @@ var init_secret_redactor = __esm({
|
|
|
5734
5804
|
MAX_PACK_RULES = 200;
|
|
5735
5805
|
MAX_PATTERN_LEN = 512;
|
|
5736
5806
|
serverPack = null;
|
|
5807
|
+
globalRegexCache = /* @__PURE__ */ new Map();
|
|
5737
5808
|
privacyCache = null;
|
|
5738
5809
|
PATH_REGEX = /(?<![A-Za-z0-9_])(?:\/[^\s'"`<>]+|[A-Za-z]:\\[^\s'"`<>]+)/g;
|
|
5739
5810
|
}
|
|
@@ -6494,8 +6565,8 @@ function decodeDirName(dirName) {
|
|
|
6494
6565
|
}
|
|
6495
6566
|
for (let len = 2; len <= segments.length - i; len++) {
|
|
6496
6567
|
const joinedSegments = segments.slice(i, i + len);
|
|
6497
|
-
for (const
|
|
6498
|
-
const candidate = join5(currentPath, joinedSegments.join(
|
|
6568
|
+
for (const sep3 of ["-", "_", "."]) {
|
|
6569
|
+
const candidate = join5(currentPath, joinedSegments.join(sep3));
|
|
6499
6570
|
if (existsSync5(candidate)) {
|
|
6500
6571
|
currentPath = candidate;
|
|
6501
6572
|
i += len;
|
|
@@ -6865,8 +6936,8 @@ var init_claude = __esm({
|
|
|
6865
6936
|
|
|
6866
6937
|
// ../engine/dist/transcript/gemini.js
|
|
6867
6938
|
async function parseGeminiTranscript(sessionPath) {
|
|
6868
|
-
const { readFileSync:
|
|
6869
|
-
return parseGeminiTranscriptText(
|
|
6939
|
+
const { readFileSync: readFileSync46 } = await import("fs");
|
|
6940
|
+
return parseGeminiTranscriptText(readFileSync46(sessionPath, "utf-8"));
|
|
6870
6941
|
}
|
|
6871
6942
|
function parseGeminiTranscriptText(text) {
|
|
6872
6943
|
let content;
|
|
@@ -7322,11 +7393,11 @@ async function archiveRawSession(store, sessionId) {
|
|
|
7322
7393
|
return await store.putRawSession(sessionId, exp.tool, Math.floor(exp.mtime), gz, size);
|
|
7323
7394
|
}
|
|
7324
7395
|
function detectForkPredecessor(sessionPath) {
|
|
7325
|
-
const { readFileSync:
|
|
7326
|
-
const { dirname:
|
|
7396
|
+
const { readFileSync: readFileSync46, readdirSync: readdirSync33 } = requireFs();
|
|
7397
|
+
const { dirname: dirname25, join: join57, basename: basename28 } = requirePath();
|
|
7327
7398
|
let text;
|
|
7328
7399
|
try {
|
|
7329
|
-
text =
|
|
7400
|
+
text = readFileSync46(sessionPath, "utf-8");
|
|
7330
7401
|
} catch {
|
|
7331
7402
|
return null;
|
|
7332
7403
|
}
|
|
@@ -7348,7 +7419,7 @@ function detectForkPredecessor(sessionPath) {
|
|
|
7348
7419
|
return null;
|
|
7349
7420
|
if (text.includes(`"uuid":"${headParent}"`))
|
|
7350
7421
|
return null;
|
|
7351
|
-
const dir =
|
|
7422
|
+
const dir = dirname25(sessionPath);
|
|
7352
7423
|
const self = basename28(sessionPath);
|
|
7353
7424
|
let entries;
|
|
7354
7425
|
try {
|
|
@@ -7360,7 +7431,7 @@ function detectForkPredecessor(sessionPath) {
|
|
|
7360
7431
|
if (!f.endsWith(".jsonl") || f === self || f === "sessions-index.json")
|
|
7361
7432
|
continue;
|
|
7362
7433
|
try {
|
|
7363
|
-
if (
|
|
7434
|
+
if (readFileSync46(join57(dir, f), "utf-8").includes(`"uuid":"${headParent}"`)) {
|
|
7364
7435
|
return basename28(f, ".jsonl");
|
|
7365
7436
|
}
|
|
7366
7437
|
} catch {
|
|
@@ -8161,6 +8232,20 @@ var init_tail_read = __esm({
|
|
|
8161
8232
|
}
|
|
8162
8233
|
});
|
|
8163
8234
|
|
|
8235
|
+
// ../engine/dist/core/flat-string.js
|
|
8236
|
+
function flatString(s) {
|
|
8237
|
+
if (!s)
|
|
8238
|
+
return "";
|
|
8239
|
+
if (s.length < 13)
|
|
8240
|
+
return s;
|
|
8241
|
+
return Buffer.from(s, "utf8").toString("utf8");
|
|
8242
|
+
}
|
|
8243
|
+
var init_flat_string = __esm({
|
|
8244
|
+
"../engine/dist/core/flat-string.js"() {
|
|
8245
|
+
"use strict";
|
|
8246
|
+
}
|
|
8247
|
+
});
|
|
8248
|
+
|
|
8164
8249
|
// ../engine/dist/core/backends/gemini.js
|
|
8165
8250
|
import { createHash as createHash3 } from "crypto";
|
|
8166
8251
|
import { existsSync as existsSync7, readdirSync as readdirSync5, readFileSync as readFileSync3, statSync as statSync6 } from "fs";
|
|
@@ -8202,6 +8287,7 @@ var init_gemini2 = __esm({
|
|
|
8202
8287
|
init_session_git();
|
|
8203
8288
|
init_generic_engine();
|
|
8204
8289
|
init_tail_read();
|
|
8290
|
+
init_flat_string();
|
|
8205
8291
|
PREFIX = "gemini_";
|
|
8206
8292
|
FULL_PARSE_MAX = 4 * 1024 * 1024;
|
|
8207
8293
|
GeminiBackend = class {
|
|
@@ -8311,7 +8397,7 @@ var init_gemini2 = __esm({
|
|
|
8311
8397
|
sessionId = readSessionId(fullPath, format);
|
|
8312
8398
|
const messages = readGeminiMessages(fullPath, format);
|
|
8313
8399
|
const firstUser = messages.find((m) => m.type === "user");
|
|
8314
|
-
firstPrompt = (typeof firstUser?.text === "string" ? firstUser.text : flatten(firstUser?.content)).slice(0, 200);
|
|
8400
|
+
firstPrompt = flatString((typeof firstUser?.text === "string" ? firstUser.text : flatten(firstUser?.content)).slice(0, 200));
|
|
8315
8401
|
messageCount = messages.length;
|
|
8316
8402
|
} else if (format === "jsonl") {
|
|
8317
8403
|
const lines = readHeadSync(fullPath, 1048576).split("\n");
|
|
@@ -8333,7 +8419,7 @@ var init_gemini2 = __esm({
|
|
|
8333
8419
|
}
|
|
8334
8420
|
if (m?.type !== "user")
|
|
8335
8421
|
continue;
|
|
8336
|
-
firstPrompt = (typeof m.text === "string" ? m.text : flatten(m.content)).slice(0, 200);
|
|
8422
|
+
firstPrompt = flatString((typeof m.text === "string" ? m.text : flatten(m.content)).slice(0, 200));
|
|
8337
8423
|
break;
|
|
8338
8424
|
}
|
|
8339
8425
|
}
|
|
@@ -8509,7 +8595,7 @@ var init_gemini2 = __esm({
|
|
|
8509
8595
|
if (!existsSync7(tmpRoot))
|
|
8510
8596
|
return [];
|
|
8511
8597
|
const projMap = this.loadProjectMap();
|
|
8512
|
-
const
|
|
8598
|
+
const candidates2 = [];
|
|
8513
8599
|
for (const proj of readdirSync5(tmpRoot, { withFileTypes: true })) {
|
|
8514
8600
|
if (!proj.isDirectory())
|
|
8515
8601
|
continue;
|
|
@@ -8540,13 +8626,13 @@ var init_gemini2 = __esm({
|
|
|
8540
8626
|
if (st.mtimeMs < opts.sinceMs)
|
|
8541
8627
|
continue;
|
|
8542
8628
|
const trimLen = isJsonl ? 6 : 5;
|
|
8543
|
-
|
|
8629
|
+
candidates2.push({ rawIdHint: f.slice(0, -trimLen), mtime: st.mtimeMs });
|
|
8544
8630
|
} catch {
|
|
8545
8631
|
}
|
|
8546
8632
|
}
|
|
8547
8633
|
}
|
|
8548
|
-
|
|
8549
|
-
const limited = opts.limitSessions ?
|
|
8634
|
+
candidates2.sort((a, b) => b.mtime - a.mtime);
|
|
8635
|
+
const limited = opts.limitSessions ? candidates2.slice(0, opts.limitSessions) : candidates2;
|
|
8550
8636
|
const edits = [];
|
|
8551
8637
|
for (const c of limited) {
|
|
8552
8638
|
const scan = this.liveScanEdits(c.rawIdHint);
|
|
@@ -8678,6 +8764,7 @@ var init_opencode = __esm({
|
|
|
8678
8764
|
init_session_outcome();
|
|
8679
8765
|
init_session_git();
|
|
8680
8766
|
init_generic_engine();
|
|
8767
|
+
init_flat_string();
|
|
8681
8768
|
PREFIX2 = "opencode_";
|
|
8682
8769
|
OpencodeBackend = class {
|
|
8683
8770
|
id = "opencode";
|
|
@@ -8845,7 +8932,7 @@ var init_opencode = __esm({
|
|
|
8845
8932
|
if (firstUser) {
|
|
8846
8933
|
try {
|
|
8847
8934
|
const parsed = JSON.parse(firstUser.data);
|
|
8848
|
-
firstPrompt = String(parsed?.text || "").slice(0, 200);
|
|
8935
|
+
firstPrompt = flatString(String(parsed?.text || "").slice(0, 200));
|
|
8849
8936
|
} catch {
|
|
8850
8937
|
}
|
|
8851
8938
|
}
|
|
@@ -9336,6 +9423,7 @@ var init_codex2 = __esm({
|
|
|
9336
9423
|
init_session_git();
|
|
9337
9424
|
init_generic_engine();
|
|
9338
9425
|
init_tail_read();
|
|
9426
|
+
init_flat_string();
|
|
9339
9427
|
PREFIX3 = "codex_";
|
|
9340
9428
|
CodexBackend = class {
|
|
9341
9429
|
id = "codex";
|
|
@@ -9448,7 +9536,7 @@ var init_codex2 = __esm({
|
|
|
9448
9536
|
if (ev.type === "event_msg" && ev.payload?.type === "user_message") {
|
|
9449
9537
|
messageCount++;
|
|
9450
9538
|
if (!firstPrompt && ev.payload.message) {
|
|
9451
|
-
firstPrompt = String(ev.payload.message).slice(0, 200);
|
|
9539
|
+
firstPrompt = flatString(String(ev.payload.message).slice(0, 200));
|
|
9452
9540
|
}
|
|
9453
9541
|
} else if (ev.type === "response_item" && ev.payload?.type === "message") {
|
|
9454
9542
|
messageCount++;
|
|
@@ -10021,6 +10109,7 @@ var init_agy = __esm({
|
|
|
10021
10109
|
init_session_outcome();
|
|
10022
10110
|
init_session_git();
|
|
10023
10111
|
init_generic_engine();
|
|
10112
|
+
init_flat_string();
|
|
10024
10113
|
PREFIX4 = "agy_";
|
|
10025
10114
|
AgyBackend = class {
|
|
10026
10115
|
id = "agy";
|
|
@@ -10121,7 +10210,7 @@ var init_agy = __esm({
|
|
|
10121
10210
|
const content = obj.content;
|
|
10122
10211
|
const match = content.match(/<USER_REQUEST>([\s\S]*?)<\/USER_REQUEST>/);
|
|
10123
10212
|
const rawText = match ? match[1].trim() : content.trim();
|
|
10124
|
-
firstPrompt = rawText.slice(0, 200);
|
|
10213
|
+
firstPrompt = flatString(rawText.slice(0, 200));
|
|
10125
10214
|
break;
|
|
10126
10215
|
}
|
|
10127
10216
|
}
|
|
@@ -10355,7 +10444,7 @@ var init_agy = __esm({
|
|
|
10355
10444
|
if (brainRoots.length === 0)
|
|
10356
10445
|
return [];
|
|
10357
10446
|
const brainDir = brainRoots[0];
|
|
10358
|
-
const
|
|
10447
|
+
const candidates2 = [];
|
|
10359
10448
|
let sessionDirs;
|
|
10360
10449
|
try {
|
|
10361
10450
|
sessionDirs = readdirSync7(brainDir);
|
|
@@ -10377,12 +10466,12 @@ var init_agy = __esm({
|
|
|
10377
10466
|
const st = statSync8(filePath);
|
|
10378
10467
|
if (st.mtimeMs < opts.sinceMs)
|
|
10379
10468
|
continue;
|
|
10380
|
-
|
|
10469
|
+
candidates2.push({ rawId, mtime: st.mtimeMs });
|
|
10381
10470
|
} catch {
|
|
10382
10471
|
}
|
|
10383
10472
|
}
|
|
10384
|
-
|
|
10385
|
-
const limited = opts.limitSessions ?
|
|
10473
|
+
candidates2.sort((a, b) => b.mtime - a.mtime);
|
|
10474
|
+
const limited = opts.limitSessions ? candidates2.slice(0, opts.limitSessions) : candidates2;
|
|
10386
10475
|
const edits = [];
|
|
10387
10476
|
for (const c of limited) {
|
|
10388
10477
|
const scan = this.liveScanEdits(c.rawId);
|
|
@@ -10654,18 +10743,43 @@ function updateShadow(sessionId, exp) {
|
|
|
10654
10743
|
path
|
|
10655
10744
|
};
|
|
10656
10745
|
}
|
|
10657
|
-
async function snapshotShadow(sessionId) {
|
|
10746
|
+
async function snapshotShadow(sessionId, opts = {}) {
|
|
10658
10747
|
await Promise.resolve().then(() => (init_backends(), backends_exports));
|
|
10659
10748
|
const { getBackendForId: getBackendForId2, getBackend: getBackend2 } = await Promise.resolve().then(() => (init_tool_backend(), tool_backend_exports));
|
|
10660
10749
|
const backend = getBackendForId2(sessionId) ?? getBackend2("claude");
|
|
10661
10750
|
const rawId = backend.toRawId(sessionId);
|
|
10751
|
+
const fp = liveFingerprint(backend, rawId);
|
|
10752
|
+
if (!opts.force && fp && lastLiveFingerprint.get(rawId) === fp) {
|
|
10753
|
+
return {
|
|
10754
|
+
status: "skipped",
|
|
10755
|
+
sessionId,
|
|
10756
|
+
tool: backend.id,
|
|
10757
|
+
container: null,
|
|
10758
|
+
recovered: 0,
|
|
10759
|
+
path: shadowFileFor(backend.id, rawId)
|
|
10760
|
+
};
|
|
10761
|
+
}
|
|
10662
10762
|
let exp = null;
|
|
10663
10763
|
try {
|
|
10664
10764
|
exp = backend.exportRawSession(rawId);
|
|
10665
10765
|
} catch {
|
|
10666
10766
|
exp = null;
|
|
10667
10767
|
}
|
|
10668
|
-
|
|
10768
|
+
const result = updateShadow(rawId, exp);
|
|
10769
|
+
if (fp && result.status !== "unavailable")
|
|
10770
|
+
lastLiveFingerprint.set(rawId, fp);
|
|
10771
|
+
return result;
|
|
10772
|
+
}
|
|
10773
|
+
function liveFingerprint(backend, rawId) {
|
|
10774
|
+
try {
|
|
10775
|
+
const loc = backend.findSession(rawId);
|
|
10776
|
+
if (!loc?.path)
|
|
10777
|
+
return "";
|
|
10778
|
+
const st = statSync9(loc.path);
|
|
10779
|
+
return `${st.mtimeMs}:${st.size}`;
|
|
10780
|
+
} catch {
|
|
10781
|
+
return "";
|
|
10782
|
+
}
|
|
10669
10783
|
}
|
|
10670
10784
|
function seedShadow(sessionId, container) {
|
|
10671
10785
|
const tool = container.tool;
|
|
@@ -10684,7 +10798,7 @@ function shadowSizeOnDisk(tool, rawId) {
|
|
|
10684
10798
|
return 0;
|
|
10685
10799
|
}
|
|
10686
10800
|
}
|
|
10687
|
-
var WHOLE_FILE_TOOLS, SINGLETON_META;
|
|
10801
|
+
var WHOLE_FILE_TOOLS, SINGLETON_META, lastLiveFingerprint;
|
|
10688
10802
|
var init_shadow = __esm({
|
|
10689
10803
|
"../engine/dist/transcript/shadow.js"() {
|
|
10690
10804
|
"use strict";
|
|
@@ -10692,6 +10806,27 @@ var init_shadow = __esm({
|
|
|
10692
10806
|
init_raw();
|
|
10693
10807
|
WHOLE_FILE_TOOLS = /* @__PURE__ */ new Set(["gemini"]);
|
|
10694
10808
|
SINGLETON_META = /* @__PURE__ */ new Set(["mode", "permission-mode", "ai-title", "last-prompt", "pr-link", "summary"]);
|
|
10809
|
+
lastLiveFingerprint = /* @__PURE__ */ new Map();
|
|
10810
|
+
}
|
|
10811
|
+
});
|
|
10812
|
+
|
|
10813
|
+
// ../engine/dist/core/project-dir-name.js
|
|
10814
|
+
function looksWindowsEncoded(dirName) {
|
|
10815
|
+
return /^[A-Za-z]--/.test(dirName);
|
|
10816
|
+
}
|
|
10817
|
+
function decodeProjectDirName(dirName) {
|
|
10818
|
+
if (!dirName)
|
|
10819
|
+
return "";
|
|
10820
|
+
if (looksWindowsEncoded(dirName)) {
|
|
10821
|
+
const drive = dirName[0].toUpperCase();
|
|
10822
|
+
const rest = dirName.slice(3).replace(/-/g, "\\");
|
|
10823
|
+
return `${drive}:\\${rest}`;
|
|
10824
|
+
}
|
|
10825
|
+
return "/" + dirName.replace(/^-/, "").replace(/-/g, "/");
|
|
10826
|
+
}
|
|
10827
|
+
var init_project_dir_name = __esm({
|
|
10828
|
+
"../engine/dist/core/project-dir-name.js"() {
|
|
10829
|
+
"use strict";
|
|
10695
10830
|
}
|
|
10696
10831
|
});
|
|
10697
10832
|
|
|
@@ -10718,7 +10853,7 @@ function findSessionFile(sessionId) {
|
|
|
10718
10853
|
path: candidate,
|
|
10719
10854
|
projectDir: entry.name,
|
|
10720
10855
|
// Project path is encoded by replacing slashes with dashes.
|
|
10721
|
-
projectPath: entry.name
|
|
10856
|
+
projectPath: decodeProjectDirName(entry.name)
|
|
10722
10857
|
};
|
|
10723
10858
|
}
|
|
10724
10859
|
}
|
|
@@ -10747,7 +10882,7 @@ function findSessionFiles(sessionId) {
|
|
|
10747
10882
|
out.push({
|
|
10748
10883
|
path: candidate,
|
|
10749
10884
|
projectDir: entry.name,
|
|
10750
|
-
projectPath: entry.name
|
|
10885
|
+
projectPath: decodeProjectDirName(entry.name)
|
|
10751
10886
|
});
|
|
10752
10887
|
}
|
|
10753
10888
|
}
|
|
@@ -10771,7 +10906,31 @@ function resolveSessionContentGroups(sessionId) {
|
|
|
10771
10906
|
const names = [...groups.keys()].sort((a, b) => a === "main" ? -1 : b === "main" ? 1 : a.localeCompare(b));
|
|
10772
10907
|
return names.map((name) => ({ name, paths: groups.get(name) }));
|
|
10773
10908
|
}
|
|
10909
|
+
function withSessionReadCache(fn) {
|
|
10910
|
+
readScopeDepth++;
|
|
10911
|
+
try {
|
|
10912
|
+
return fn();
|
|
10913
|
+
} finally {
|
|
10914
|
+
if (--readScopeDepth === 0)
|
|
10915
|
+
readScope = null;
|
|
10916
|
+
}
|
|
10917
|
+
}
|
|
10774
10918
|
function readSessionGroupText(group) {
|
|
10919
|
+
let key = "";
|
|
10920
|
+
if (readScopeDepth > 0) {
|
|
10921
|
+
const parts = [];
|
|
10922
|
+
for (const p of group.paths) {
|
|
10923
|
+
try {
|
|
10924
|
+
const st = statSync10(p);
|
|
10925
|
+
parts.push(`${p}:${st.mtimeMs}:${st.size}`);
|
|
10926
|
+
} catch {
|
|
10927
|
+
parts.push(`${p}:missing`);
|
|
10928
|
+
}
|
|
10929
|
+
}
|
|
10930
|
+
key = parts.join("|");
|
|
10931
|
+
if (readScope && readScope.key === key)
|
|
10932
|
+
return readScope.value;
|
|
10933
|
+
}
|
|
10775
10934
|
let text = "";
|
|
10776
10935
|
let mtime = 0;
|
|
10777
10936
|
for (const p of group.paths) {
|
|
@@ -10787,7 +10946,10 @@ function readSessionGroupText(group) {
|
|
|
10787
10946
|
}
|
|
10788
10947
|
text = text ? mergeLineText(text, raw).text : raw;
|
|
10789
10948
|
}
|
|
10790
|
-
|
|
10949
|
+
const out = { text, mtime };
|
|
10950
|
+
if (readScopeDepth > 0 && key)
|
|
10951
|
+
readScope = { key, value: out };
|
|
10952
|
+
return out;
|
|
10791
10953
|
}
|
|
10792
10954
|
function resolveSessionContentPaths(sessionFile) {
|
|
10793
10955
|
if (!hasSubagentsDir(sessionFile))
|
|
@@ -11010,7 +11172,7 @@ function findCodexSessionFileIn(root, sessionId) {
|
|
|
11010
11172
|
}
|
|
11011
11173
|
return scanDir(root);
|
|
11012
11174
|
}
|
|
11013
|
-
var geminiProjectMapCache, MAX_EVENT_LINE_BYTES;
|
|
11175
|
+
var readScope, readScopeDepth, geminiProjectMapCache, MAX_EVENT_LINE_BYTES;
|
|
11014
11176
|
var init_live_session_scan = __esm({
|
|
11015
11177
|
"../engine/dist/core/live-session-scan.js"() {
|
|
11016
11178
|
"use strict";
|
|
@@ -11019,79 +11181,117 @@ var init_live_session_scan = __esm({
|
|
|
11019
11181
|
init_tool_backend();
|
|
11020
11182
|
init_tool_paths();
|
|
11021
11183
|
init_backends();
|
|
11184
|
+
init_project_dir_name();
|
|
11185
|
+
readScope = null;
|
|
11186
|
+
readScopeDepth = 0;
|
|
11022
11187
|
geminiProjectMapCache = null;
|
|
11023
11188
|
MAX_EVENT_LINE_BYTES = 8 * 1024 * 1024;
|
|
11024
11189
|
}
|
|
11025
11190
|
});
|
|
11026
11191
|
|
|
11027
11192
|
// ../engine/dist/core/first-prompt.js
|
|
11028
|
-
import { createReadStream as createReadStream2, existsSync as existsSync12,
|
|
11193
|
+
import { createReadStream as createReadStream2, existsSync as existsSync12, openSync as openSync5, readSync as readSync5, closeSync as closeSync5 } from "fs";
|
|
11194
|
+
import { StringDecoder } from "string_decoder";
|
|
11029
11195
|
function stripBanners2(s) {
|
|
11030
11196
|
let out = s;
|
|
11031
11197
|
for (const re of BANNERS)
|
|
11032
11198
|
out = out.replace(re, " ");
|
|
11033
11199
|
return out.replace(/[ \t]{2,}/g, " ").trim();
|
|
11034
11200
|
}
|
|
11201
|
+
function promptFromLine(raw, maxLength) {
|
|
11202
|
+
if (!raw.trim())
|
|
11203
|
+
return null;
|
|
11204
|
+
let obj;
|
|
11205
|
+
try {
|
|
11206
|
+
obj = JSON.parse(raw);
|
|
11207
|
+
} catch {
|
|
11208
|
+
return null;
|
|
11209
|
+
}
|
|
11210
|
+
if (obj.type !== "user")
|
|
11211
|
+
return null;
|
|
11212
|
+
if (obj.isSidechain === true)
|
|
11213
|
+
return null;
|
|
11214
|
+
const message = obj.message;
|
|
11215
|
+
if (!message)
|
|
11216
|
+
return null;
|
|
11217
|
+
const content = message.content;
|
|
11218
|
+
let text = "";
|
|
11219
|
+
if (typeof content === "string") {
|
|
11220
|
+
text = content;
|
|
11221
|
+
} else if (Array.isArray(content)) {
|
|
11222
|
+
const parts = [];
|
|
11223
|
+
for (const block of content) {
|
|
11224
|
+
if (block && typeof block === "object" && block.type === "text" && typeof block.text === "string") {
|
|
11225
|
+
parts.push(block.text);
|
|
11226
|
+
}
|
|
11227
|
+
}
|
|
11228
|
+
text = parts.join("\n");
|
|
11229
|
+
}
|
|
11230
|
+
if (!text)
|
|
11231
|
+
return null;
|
|
11232
|
+
if (text.includes("<system-reminder>"))
|
|
11233
|
+
return null;
|
|
11234
|
+
if (text.trim() === "[Request interrupted by user]")
|
|
11235
|
+
return null;
|
|
11236
|
+
const cleaned = stripBanners2(text);
|
|
11237
|
+
if (cleaned.length < 10)
|
|
11238
|
+
return null;
|
|
11239
|
+
return flatString(cleaned.slice(0, maxLength));
|
|
11240
|
+
}
|
|
11035
11241
|
function extractFirstUserPromptSync(filePath, options = {}) {
|
|
11036
11242
|
const maxLines = options.maxLines ?? 500;
|
|
11037
11243
|
const maxLength = options.maxLength ?? 1e3;
|
|
11038
|
-
|
|
11039
|
-
|
|
11040
|
-
let raw;
|
|
11244
|
+
const maxBytes = options.maxBytes ?? 4 * 1024 * 1024;
|
|
11245
|
+
let fd;
|
|
11041
11246
|
try {
|
|
11042
|
-
|
|
11247
|
+
fd = openSync5(filePath, "r");
|
|
11043
11248
|
} catch {
|
|
11044
11249
|
return "";
|
|
11045
11250
|
}
|
|
11046
|
-
|
|
11047
|
-
|
|
11048
|
-
|
|
11049
|
-
const
|
|
11050
|
-
|
|
11051
|
-
|
|
11052
|
-
let
|
|
11251
|
+
try {
|
|
11252
|
+
const CHUNK = 64 * 1024;
|
|
11253
|
+
const buf = Buffer.allocUnsafe(CHUNK);
|
|
11254
|
+
const decoder = new StringDecoder("utf-8");
|
|
11255
|
+
let carry = "";
|
|
11256
|
+
let pos = 0;
|
|
11257
|
+
let lineNo = 0;
|
|
11258
|
+
for (; ; ) {
|
|
11259
|
+
const n = readSync5(fd, buf, 0, CHUNK, pos);
|
|
11260
|
+
if (n <= 0)
|
|
11261
|
+
break;
|
|
11262
|
+
pos += n;
|
|
11263
|
+
carry += decoder.write(buf.subarray(0, n));
|
|
11264
|
+
const parts = carry.split("\n");
|
|
11265
|
+
carry = parts.pop() ?? "";
|
|
11266
|
+
for (const line of parts) {
|
|
11267
|
+
if (++lineNo > maxLines)
|
|
11268
|
+
return "";
|
|
11269
|
+
const found = promptFromLine(line, maxLength);
|
|
11270
|
+
if (found !== null)
|
|
11271
|
+
return found;
|
|
11272
|
+
}
|
|
11273
|
+
if (pos >= maxBytes)
|
|
11274
|
+
return "";
|
|
11275
|
+
}
|
|
11276
|
+
carry += decoder.end();
|
|
11277
|
+
if (carry && lineNo < maxLines) {
|
|
11278
|
+
const found = promptFromLine(carry, maxLength);
|
|
11279
|
+
if (found !== null)
|
|
11280
|
+
return found;
|
|
11281
|
+
}
|
|
11282
|
+
return "";
|
|
11283
|
+
} finally {
|
|
11053
11284
|
try {
|
|
11054
|
-
|
|
11285
|
+
closeSync5(fd);
|
|
11055
11286
|
} catch {
|
|
11056
|
-
continue;
|
|
11057
11287
|
}
|
|
11058
|
-
if (obj.type !== "user")
|
|
11059
|
-
continue;
|
|
11060
|
-
if (obj.isSidechain === true)
|
|
11061
|
-
continue;
|
|
11062
|
-
const message = obj.message;
|
|
11063
|
-
if (!message)
|
|
11064
|
-
continue;
|
|
11065
|
-
const content = message.content;
|
|
11066
|
-
let text = "";
|
|
11067
|
-
if (typeof content === "string") {
|
|
11068
|
-
text = content;
|
|
11069
|
-
} else if (Array.isArray(content)) {
|
|
11070
|
-
const parts = [];
|
|
11071
|
-
for (const block of content) {
|
|
11072
|
-
if (block && typeof block === "object" && block.type === "text" && typeof block.text === "string") {
|
|
11073
|
-
parts.push(block.text);
|
|
11074
|
-
}
|
|
11075
|
-
}
|
|
11076
|
-
text = parts.join("\n");
|
|
11077
|
-
}
|
|
11078
|
-
if (!text)
|
|
11079
|
-
continue;
|
|
11080
|
-
if (text.includes("<system-reminder>"))
|
|
11081
|
-
continue;
|
|
11082
|
-
if (text.trim() === "[Request interrupted by user]")
|
|
11083
|
-
continue;
|
|
11084
|
-
const cleaned = stripBanners2(text);
|
|
11085
|
-
if (cleaned.length < 10)
|
|
11086
|
-
continue;
|
|
11087
|
-
return cleaned.slice(0, maxLength);
|
|
11088
11288
|
}
|
|
11089
|
-
return "";
|
|
11090
11289
|
}
|
|
11091
11290
|
var BANNERS;
|
|
11092
11291
|
var init_first_prompt = __esm({
|
|
11093
11292
|
"../engine/dist/core/first-prompt.js"() {
|
|
11094
11293
|
"use strict";
|
|
11294
|
+
init_flat_string();
|
|
11095
11295
|
BANNERS = [
|
|
11096
11296
|
/MCP issues detected\. ?Run \/mcp list for status\.?/g,
|
|
11097
11297
|
/Context low[^\n]*Run \/compact[^\n]*/g,
|
|
@@ -11101,7 +11301,7 @@ var init_first_prompt = __esm({
|
|
|
11101
11301
|
});
|
|
11102
11302
|
|
|
11103
11303
|
// ../engine/dist/core/backends/claude.js
|
|
11104
|
-
import { existsSync as existsSync13, readdirSync as readdirSync9, readFileSync as
|
|
11304
|
+
import { existsSync as existsSync13, readdirSync as readdirSync9, readFileSync as readFileSync8, statSync as statSync11, openSync as openSync6, readSync as readSync6, closeSync as closeSync6 } from "fs";
|
|
11105
11305
|
import { join as join14, basename as basename11 } from "path";
|
|
11106
11306
|
function stripReminders(text) {
|
|
11107
11307
|
return text.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g, "").trim();
|
|
@@ -11120,6 +11320,7 @@ var init_claude2 = __esm({
|
|
|
11120
11320
|
init_session_git();
|
|
11121
11321
|
init_first_prompt();
|
|
11122
11322
|
init_tail_read();
|
|
11323
|
+
init_project_dir_name();
|
|
11123
11324
|
init_generic_engine();
|
|
11124
11325
|
UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
11125
11326
|
ClaudeBackend = class {
|
|
@@ -11196,13 +11397,13 @@ var init_claude2 = __esm({
|
|
|
11196
11397
|
return null;
|
|
11197
11398
|
let head;
|
|
11198
11399
|
try {
|
|
11199
|
-
const fd =
|
|
11400
|
+
const fd = openSync6(located.path, "r");
|
|
11200
11401
|
try {
|
|
11201
11402
|
const buf = Buffer.alloc(65536);
|
|
11202
|
-
const n =
|
|
11403
|
+
const n = readSync6(fd, buf, 0, buf.length, 0);
|
|
11203
11404
|
head = buf.toString("utf-8", 0, n);
|
|
11204
11405
|
} finally {
|
|
11205
|
-
|
|
11406
|
+
closeSync6(fd);
|
|
11206
11407
|
}
|
|
11207
11408
|
} catch {
|
|
11208
11409
|
return null;
|
|
@@ -11261,11 +11462,11 @@ var init_claude2 = __esm({
|
|
|
11261
11462
|
if (filter && !proj.name.toLowerCase().includes(filter))
|
|
11262
11463
|
continue;
|
|
11263
11464
|
const projPath = join14(root, proj.name);
|
|
11264
|
-
const projectPath = proj.name
|
|
11465
|
+
const projectPath = decodeProjectDirName(proj.name);
|
|
11265
11466
|
const indexPath = join14(projPath, "sessions-index.json");
|
|
11266
11467
|
if (existsSync13(indexPath)) {
|
|
11267
11468
|
try {
|
|
11268
|
-
const indexData = JSON.parse(
|
|
11469
|
+
const indexData = JSON.parse(readFileSync8(indexPath, "utf-8"));
|
|
11269
11470
|
const entries = indexData.entries || [];
|
|
11270
11471
|
for (const entry of entries) {
|
|
11271
11472
|
if (!entry.fullPath || !existsSync13(entry.fullPath))
|
|
@@ -11557,7 +11758,7 @@ var init_claude2 = __esm({
|
|
|
11557
11758
|
* with quiet main + active subagents still surfaces.
|
|
11558
11759
|
*/
|
|
11559
11760
|
collectRecentEdits(opts) {
|
|
11560
|
-
const
|
|
11761
|
+
const candidates2 = [];
|
|
11561
11762
|
for (const root of claudeProjectDirs()) {
|
|
11562
11763
|
if (!existsSync13(root))
|
|
11563
11764
|
continue;
|
|
@@ -11593,14 +11794,14 @@ var init_claude2 = __esm({
|
|
|
11593
11794
|
}
|
|
11594
11795
|
if (mtime < opts.sinceMs)
|
|
11595
11796
|
continue;
|
|
11596
|
-
|
|
11797
|
+
candidates2.push({ rawId: basename11(f, ".jsonl"), mtime });
|
|
11597
11798
|
} catch {
|
|
11598
11799
|
}
|
|
11599
11800
|
}
|
|
11600
11801
|
}
|
|
11601
11802
|
}
|
|
11602
|
-
|
|
11603
|
-
const limited = opts.limitSessions ?
|
|
11803
|
+
candidates2.sort((a, b) => b.mtime - a.mtime);
|
|
11804
|
+
const limited = opts.limitSessions ? candidates2.slice(0, opts.limitSessions) : candidates2;
|
|
11604
11805
|
const edits = [];
|
|
11605
11806
|
for (const c of limited) {
|
|
11606
11807
|
const scan = this.liveScanEdits(c.rawId);
|
|
@@ -11699,7 +11900,7 @@ __export(project_resolver_exports, {
|
|
|
11699
11900
|
});
|
|
11700
11901
|
import { execSync } from "child_process";
|
|
11701
11902
|
import { createHash as createHash6 } from "crypto";
|
|
11702
|
-
import { existsSync as existsSync14, readFileSync as
|
|
11903
|
+
import { existsSync as existsSync14, readFileSync as readFileSync9, realpathSync as realpathSync2, readdirSync as readdirSync10, statSync as statSync12 } from "fs";
|
|
11703
11904
|
import { basename as basename12, dirname as dirname12, isAbsolute, join as join15, resolve, sep } from "path";
|
|
11704
11905
|
function getProjectsConfigPath() {
|
|
11705
11906
|
return join15(getDataDir(), "projects.json");
|
|
@@ -11717,7 +11918,7 @@ function loadProjectsConfig() {
|
|
|
11717
11918
|
if (cachedConfig && cachedConfig.mtime === mtime)
|
|
11718
11919
|
return cachedConfig.cfg;
|
|
11719
11920
|
try {
|
|
11720
|
-
const raw =
|
|
11921
|
+
const raw = readFileSync9(path, "utf-8");
|
|
11721
11922
|
const cfg = JSON.parse(raw);
|
|
11722
11923
|
cachedConfig = { mtime, cfg };
|
|
11723
11924
|
return cfg;
|
|
@@ -11818,8 +12019,8 @@ function resolveBotWorktree(realPath) {
|
|
|
11818
12019
|
};
|
|
11819
12020
|
}
|
|
11820
12021
|
function matchDeclaredProject(realPath, projects) {
|
|
11821
|
-
const
|
|
11822
|
-
for (const proj of
|
|
12022
|
+
const candidates2 = [...projects].sort((a, b) => b.root.length - a.root.length);
|
|
12023
|
+
for (const proj of candidates2) {
|
|
11823
12024
|
const root = safeRealpath(proj.root);
|
|
11824
12025
|
if (!isInside(realPath, root))
|
|
11825
12026
|
continue;
|
|
@@ -12044,6 +12245,24 @@ var init_project_resolver = __esm({
|
|
|
12044
12245
|
}
|
|
12045
12246
|
});
|
|
12046
12247
|
|
|
12248
|
+
// ../engine/dist/core/credentials-env.js
|
|
12249
|
+
function envCredentials(env = process.env) {
|
|
12250
|
+
const token = (env.CHAT_RECALL_TOKEN || "").trim();
|
|
12251
|
+
const server = (env.CHAT_RECALL_SERVER || "").trim();
|
|
12252
|
+
if (!token || !server)
|
|
12253
|
+
return null;
|
|
12254
|
+
if (!/^https?:\/\//i.test(server))
|
|
12255
|
+
return null;
|
|
12256
|
+
return { serverUrl: normalise(server), token };
|
|
12257
|
+
}
|
|
12258
|
+
var normalise;
|
|
12259
|
+
var init_credentials_env = __esm({
|
|
12260
|
+
"../engine/dist/core/credentials-env.js"() {
|
|
12261
|
+
"use strict";
|
|
12262
|
+
normalise = (u) => u.trim().replace(/\/+$/, "");
|
|
12263
|
+
}
|
|
12264
|
+
});
|
|
12265
|
+
|
|
12047
12266
|
// ../engine/dist/core/source-discovery.js
|
|
12048
12267
|
import { createHash as createHash7 } from "crypto";
|
|
12049
12268
|
import { existsSync as existsSync15, readdirSync as readdirSync11, statSync as statSync13 } from "fs";
|
|
@@ -12159,7 +12378,7 @@ __export(home_discovery_exports, {
|
|
|
12159
12378
|
sessionIdsInHome: () => sessionIdsInHome
|
|
12160
12379
|
});
|
|
12161
12380
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
12162
|
-
import { existsSync as existsSync16, readdirSync as readdirSync12, readFileSync as
|
|
12381
|
+
import { existsSync as existsSync16, readdirSync as readdirSync12, readFileSync as readFileSync10, realpathSync as realpathSync3, statSync as statSync14 } from "fs";
|
|
12163
12382
|
import { homedir as homedir5, platform as osPlatform } from "os";
|
|
12164
12383
|
import { join as join17 } from "path";
|
|
12165
12384
|
function candidateRoots(plat = osPlatform(), env = process.env) {
|
|
@@ -12347,7 +12566,7 @@ function declaredHomes(env = process.env, plat = osPlatform()) {
|
|
|
12347
12566
|
for (const rc of rcs) {
|
|
12348
12567
|
let text;
|
|
12349
12568
|
try {
|
|
12350
|
-
text =
|
|
12569
|
+
text = readFileSync10(rc, "utf-8");
|
|
12351
12570
|
} catch {
|
|
12352
12571
|
continue;
|
|
12353
12572
|
}
|
|
@@ -12372,7 +12591,7 @@ function runningToolHomes(plat = osPlatform()) {
|
|
|
12372
12591
|
for (const pid of pids) {
|
|
12373
12592
|
let env;
|
|
12374
12593
|
try {
|
|
12375
|
-
env =
|
|
12594
|
+
env = readFileSync10(`/proc/${pid}/environ`, "utf-8");
|
|
12376
12595
|
} catch {
|
|
12377
12596
|
continue;
|
|
12378
12597
|
}
|
|
@@ -12506,7 +12725,7 @@ __export(detector_install_exports, {
|
|
|
12506
12725
|
});
|
|
12507
12726
|
import { spawnSync } from "child_process";
|
|
12508
12727
|
import { createHash as createHash8 } from "crypto";
|
|
12509
|
-
import { existsSync as existsSync17, mkdirSync as mkdirSync4, mkdtempSync, chmodSync as chmodSync2, renameSync as renameSync3, rmSync as rmSync2, writeFileSync as writeFileSync3, readFileSync as
|
|
12728
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync4, mkdtempSync, chmodSync as chmodSync2, renameSync as renameSync3, rmSync as rmSync2, writeFileSync as writeFileSync3, readFileSync as readFileSync11, statSync as statSync15, copyFileSync as copyFileSync2 } from "fs";
|
|
12510
12729
|
import { join as join18 } from "path";
|
|
12511
12730
|
function managedDetectorPath(name) {
|
|
12512
12731
|
return join18(getDetectorBinDir(), name + exeSuffix());
|
|
@@ -12515,11 +12734,11 @@ function receiptPath(name) {
|
|
|
12515
12734
|
return join18(getDetectorBinDir(), `${name}.receipt.json`);
|
|
12516
12735
|
}
|
|
12517
12736
|
function sha256File(path) {
|
|
12518
|
-
return createHash8("sha256").update(
|
|
12737
|
+
return createHash8("sha256").update(readFileSync11(path)).digest("hex");
|
|
12519
12738
|
}
|
|
12520
12739
|
function readReceipt(name) {
|
|
12521
12740
|
try {
|
|
12522
|
-
return JSON.parse(
|
|
12741
|
+
return JSON.parse(readFileSync11(receiptPath(name), "utf-8"));
|
|
12523
12742
|
} catch {
|
|
12524
12743
|
return null;
|
|
12525
12744
|
}
|
|
@@ -12730,7 +12949,7 @@ __export(secret_scanner_exports, {
|
|
|
12730
12949
|
scanTenantRules: () => scanTenantRules
|
|
12731
12950
|
});
|
|
12732
12951
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
12733
|
-
import { existsSync as existsSync18, unlinkSync, readFileSync as
|
|
12952
|
+
import { existsSync as existsSync18, unlinkSync, readFileSync as readFileSync12, mkdtempSync as mkdtempSync2, rmSync as rmSync3 } from "fs";
|
|
12734
12953
|
import { tmpdir } from "os";
|
|
12735
12954
|
import { join as join19 } from "path";
|
|
12736
12955
|
function mask(s) {
|
|
@@ -12794,7 +13013,7 @@ function runGitleaks(binary, filePath) {
|
|
|
12794
13013
|
return [];
|
|
12795
13014
|
let parsed = [];
|
|
12796
13015
|
try {
|
|
12797
|
-
parsed = JSON.parse(
|
|
13016
|
+
parsed = JSON.parse(readFileSync12(reportPath, "utf-8")) || [];
|
|
12798
13017
|
} catch {
|
|
12799
13018
|
}
|
|
12800
13019
|
try {
|
|
@@ -12858,7 +13077,7 @@ function runGitleaksDir(binary, dir) {
|
|
|
12858
13077
|
}
|
|
12859
13078
|
let parsed = [];
|
|
12860
13079
|
try {
|
|
12861
|
-
parsed = JSON.parse(
|
|
13080
|
+
parsed = JSON.parse(readFileSync12(reportPath, "utf-8")) || [];
|
|
12862
13081
|
} catch {
|
|
12863
13082
|
}
|
|
12864
13083
|
try {
|
|
@@ -12949,7 +13168,7 @@ function scanFileForSecrets(filePath, opts = {}) {
|
|
|
12949
13168
|
out.push({ detector: "trufflehog", ...f });
|
|
12950
13169
|
if (opts.tenantRules && opts.tenantRules.length > 0) {
|
|
12951
13170
|
try {
|
|
12952
|
-
const text =
|
|
13171
|
+
const text = readFileSync12(filePath, "utf-8");
|
|
12953
13172
|
out.push(...scanTenantRules(text, opts.tenantRules));
|
|
12954
13173
|
} catch {
|
|
12955
13174
|
}
|
|
@@ -12977,7 +13196,7 @@ async function scanSessionForSecrets(opts) {
|
|
|
12977
13196
|
try {
|
|
12978
13197
|
const tenantRules = (await opts.store.listSecretRules()).filter((r) => r.enabled).map((r) => ({ name: r.name, regex: r.regex, severity: r.severity }));
|
|
12979
13198
|
if (tenantRules.length > 0) {
|
|
12980
|
-
const text =
|
|
13199
|
+
const text = readFileSync12(opts.filePath, "utf-8");
|
|
12981
13200
|
const lines = text.split("\n");
|
|
12982
13201
|
for (const r of tenantRules) {
|
|
12983
13202
|
let re;
|
|
@@ -13135,10 +13354,10 @@ var init_types = __esm({
|
|
|
13135
13354
|
|
|
13136
13355
|
// ../engine/dist/transcript/opencode.js
|
|
13137
13356
|
async function parseOpenCodeSubagents(parentSessionId) {
|
|
13138
|
-
const { existsSync:
|
|
13357
|
+
const { existsSync: existsSync52 } = await import("fs");
|
|
13139
13358
|
const { opencodeBackend: opencodeBackend2 } = await Promise.resolve().then(() => (init_opencode(), opencode_exports));
|
|
13140
13359
|
const dbPath = opencodeBackend2.dbPath();
|
|
13141
|
-
if (!
|
|
13360
|
+
if (!existsSync52(dbPath))
|
|
13142
13361
|
return [];
|
|
13143
13362
|
const realParent = parentSessionId.replace("opencode_", "");
|
|
13144
13363
|
const db = openSqliteReadonlyOrThrow(dbPath);
|
|
@@ -13179,10 +13398,10 @@ async function parseOpenCodeSubagents(parentSessionId) {
|
|
|
13179
13398
|
}
|
|
13180
13399
|
}
|
|
13181
13400
|
async function parseOpenCodeTranscript(sessionId) {
|
|
13182
|
-
const { existsSync:
|
|
13401
|
+
const { existsSync: existsSync52 } = await import("fs");
|
|
13183
13402
|
const { opencodeBackend: opencodeBackend2 } = await Promise.resolve().then(() => (init_opencode(), opencode_exports));
|
|
13184
13403
|
const dbPath = opencodeBackend2.dbPath();
|
|
13185
|
-
if (!
|
|
13404
|
+
if (!existsSync52(dbPath))
|
|
13186
13405
|
return [];
|
|
13187
13406
|
const realId = sessionId.replace("opencode_", "");
|
|
13188
13407
|
const db = openSqliteReadonlyOrThrow(dbPath);
|
|
@@ -14223,7 +14442,7 @@ var init_utils = __esm({
|
|
|
14223
14442
|
});
|
|
14224
14443
|
|
|
14225
14444
|
// ../engine/dist/parsers/plan-source.js
|
|
14226
|
-
import { existsSync as existsSync20, readdirSync as readdirSync14, readFileSync as
|
|
14445
|
+
import { existsSync as existsSync20, readdirSync as readdirSync14, readFileSync as readFileSync13, statSync as statSync18 } from "fs";
|
|
14227
14446
|
import { homedir as homedir7 } from "os";
|
|
14228
14447
|
import { join as join21, basename as basename13 } from "path";
|
|
14229
14448
|
import { createHash as createHash9 } from "crypto";
|
|
@@ -14265,6 +14484,7 @@ var init_plan_source = __esm({
|
|
|
14265
14484
|
init_claude2();
|
|
14266
14485
|
init_agy();
|
|
14267
14486
|
init_settings();
|
|
14487
|
+
init_project_dir_name();
|
|
14268
14488
|
MAX_CHUNK_CHARS = 2e3;
|
|
14269
14489
|
UUID_RE3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
14270
14490
|
PlanSource = class {
|
|
@@ -14289,7 +14509,7 @@ var init_plan_source = __esm({
|
|
|
14289
14509
|
for (const entry of entries) {
|
|
14290
14510
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
14291
14511
|
continue;
|
|
14292
|
-
const projectPath = entry.name
|
|
14512
|
+
const projectPath = decodeProjectDirName(entry.name);
|
|
14293
14513
|
if (existsSync20(projectPath)) {
|
|
14294
14514
|
this._knownProjectDirs.push(projectPath);
|
|
14295
14515
|
}
|
|
@@ -14327,7 +14547,7 @@ var init_plan_source = __esm({
|
|
|
14327
14547
|
const stat3 = statSync18(filePath);
|
|
14328
14548
|
const planName = basename13(file, ".md");
|
|
14329
14549
|
const isAgentPlan = planName.includes("-agent-");
|
|
14330
|
-
const content =
|
|
14550
|
+
const content = readFileSync13(filePath, "utf-8");
|
|
14331
14551
|
const fm = parseFrontmatter(content);
|
|
14332
14552
|
const body = fm.body;
|
|
14333
14553
|
const firstLine = body.split("\n").find((l) => l.trim())?.replace(/^#+\s*/, "").trim() || planName;
|
|
@@ -14369,7 +14589,7 @@ var init_plan_source = __esm({
|
|
|
14369
14589
|
const filePath = join21(plansDir, file);
|
|
14370
14590
|
try {
|
|
14371
14591
|
const stat3 = statSync18(filePath);
|
|
14372
|
-
const content =
|
|
14592
|
+
const content = readFileSync13(filePath, "utf-8");
|
|
14373
14593
|
const firstLine = content.split("\n").find((l) => l.trim())?.replace(/^#+\s*/, "").trim() || file;
|
|
14374
14594
|
const planName = `${opencodeBackend.idPrefix}plan_${basename13(file, ".md")}`;
|
|
14375
14595
|
const projectPath = this.extractProjectPath(content);
|
|
@@ -14399,7 +14619,7 @@ var init_plan_source = __esm({
|
|
|
14399
14619
|
const projectsPath = geminiBackend.projectsJson();
|
|
14400
14620
|
if (existsSync20(projectsPath)) {
|
|
14401
14621
|
try {
|
|
14402
|
-
const data = JSON.parse(
|
|
14622
|
+
const data = JSON.parse(readFileSync13(projectsPath, "utf-8"));
|
|
14403
14623
|
for (const path of Object.keys(data.projects || {})) {
|
|
14404
14624
|
projMap.set(createHash9("sha256").update(path).digest("hex"), path);
|
|
14405
14625
|
}
|
|
@@ -14435,7 +14655,7 @@ var init_plan_source = __esm({
|
|
|
14435
14655
|
const filePath = join21(plansDir, file);
|
|
14436
14656
|
try {
|
|
14437
14657
|
const stat3 = statSync18(filePath);
|
|
14438
|
-
const content =
|
|
14658
|
+
const content = readFileSync13(filePath, "utf-8");
|
|
14439
14659
|
const firstLine = content.split("\n").find((l) => l.trim())?.replace(/^#+\s*/, "").trim() || file;
|
|
14440
14660
|
const planName = `${geminiBackend.idPrefix}plan_${sess}_${basename13(file, ".md")}`;
|
|
14441
14661
|
yield {
|
|
@@ -14514,7 +14734,7 @@ var init_plan_source = __esm({
|
|
|
14514
14734
|
async parse(item) {
|
|
14515
14735
|
if (!existsSync20(item.filePath))
|
|
14516
14736
|
return [];
|
|
14517
|
-
const content =
|
|
14737
|
+
const content = readFileSync13(item.filePath, "utf-8");
|
|
14518
14738
|
const chunks = [];
|
|
14519
14739
|
const { body } = parseFrontmatter(content);
|
|
14520
14740
|
const sections = splitByHeaders(body);
|
|
@@ -14658,7 +14878,7 @@ var init_plan_source = __esm({
|
|
|
14658
14878
|
const filePath = join21(sessionPath, file);
|
|
14659
14879
|
try {
|
|
14660
14880
|
const stat3 = statSync18(filePath);
|
|
14661
|
-
const content =
|
|
14881
|
+
const content = readFileSync13(filePath, "utf-8");
|
|
14662
14882
|
const firstLine = content.split("\n").find((l) => l.trim())?.replace(/^#+\s*/, "").trim() || file;
|
|
14663
14883
|
const sessionLoc = agyBackend.findSession(rawId);
|
|
14664
14884
|
const projectPath = sessionLoc?.projectPath || this.extractProjectPath(content);
|
|
@@ -14687,7 +14907,7 @@ var init_plan_source = __esm({
|
|
|
14687
14907
|
});
|
|
14688
14908
|
|
|
14689
14909
|
// ../engine/dist/parsers/task-source.js
|
|
14690
|
-
import { existsSync as existsSync21, readdirSync as readdirSync15, readFileSync as
|
|
14910
|
+
import { existsSync as existsSync21, readdirSync as readdirSync15, readFileSync as readFileSync14, statSync as statSync19 } from "fs";
|
|
14691
14911
|
import { join as join22 } from "path";
|
|
14692
14912
|
var MAX_CHUNK_CHARS2, TaskSource;
|
|
14693
14913
|
var init_task_source = __esm({
|
|
@@ -14737,7 +14957,7 @@ var init_task_source = __esm({
|
|
|
14737
14957
|
continue;
|
|
14738
14958
|
let parsed;
|
|
14739
14959
|
try {
|
|
14740
|
-
const raw =
|
|
14960
|
+
const raw = readFileSync14(filePath, "utf-8");
|
|
14741
14961
|
parsed = JSON.parse(raw);
|
|
14742
14962
|
if (!Array.isArray(parsed) || parsed.length === 0)
|
|
14743
14963
|
continue;
|
|
@@ -14875,7 +15095,7 @@ ${task.description}`.slice(0, MAX_CHUNK_CHARS2);
|
|
|
14875
15095
|
return [];
|
|
14876
15096
|
let parsed;
|
|
14877
15097
|
try {
|
|
14878
|
-
parsed = JSON.parse(
|
|
15098
|
+
parsed = JSON.parse(readFileSync14(item.filePath, "utf-8"));
|
|
14879
15099
|
} catch {
|
|
14880
15100
|
return [];
|
|
14881
15101
|
}
|
|
@@ -14907,7 +15127,7 @@ ${task.description}`.slice(0, MAX_CHUNK_CHARS2);
|
|
|
14907
15127
|
});
|
|
14908
15128
|
for (const file of sorted) {
|
|
14909
15129
|
try {
|
|
14910
|
-
const content =
|
|
15130
|
+
const content = readFileSync14(join22(taskDir, file), "utf-8");
|
|
14911
15131
|
const task = JSON.parse(content);
|
|
14912
15132
|
if (task.subject) {
|
|
14913
15133
|
tasks2.push(task);
|
|
@@ -14923,7 +15143,7 @@ ${task.description}`.slice(0, MAX_CHUNK_CHARS2);
|
|
|
14923
15143
|
});
|
|
14924
15144
|
|
|
14925
15145
|
// ../engine/dist/parsers/claude-md-source.js
|
|
14926
|
-
import { existsSync as existsSync22, readFileSync as
|
|
15146
|
+
import { existsSync as existsSync22, readFileSync as readFileSync15, readdirSync as readdirSync16, statSync as statSync20 } from "fs";
|
|
14927
15147
|
import { homedir as homedir8 } from "os";
|
|
14928
15148
|
import { join as join23, basename as basename14, dirname as dirname13 } from "path";
|
|
14929
15149
|
import { createHash as createHash10 } from "crypto";
|
|
@@ -14944,7 +15164,7 @@ function discoverProjectDirs(claudeDir) {
|
|
|
14944
15164
|
for (const entry of entries) {
|
|
14945
15165
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
14946
15166
|
continue;
|
|
14947
|
-
const projectPath = entry.name
|
|
15167
|
+
const projectPath = decodeProjectDirName(entry.name);
|
|
14948
15168
|
addProject(projectPath);
|
|
14949
15169
|
}
|
|
14950
15170
|
} catch {
|
|
@@ -14967,7 +15187,7 @@ function discoverProjectDirs(claudeDir) {
|
|
|
14967
15187
|
const gemProjects = geminiBackend.projectsJson();
|
|
14968
15188
|
if (existsSync22(gemProjects)) {
|
|
14969
15189
|
try {
|
|
14970
|
-
const data = JSON.parse(
|
|
15190
|
+
const data = JSON.parse(readFileSync15(gemProjects, "utf-8"));
|
|
14971
15191
|
for (const path of Object.keys(data.projects || {}))
|
|
14972
15192
|
addProject(path);
|
|
14973
15193
|
} catch {
|
|
@@ -15001,6 +15221,7 @@ var init_claude_md_source = __esm({
|
|
|
15001
15221
|
init_gemini2();
|
|
15002
15222
|
init_settings();
|
|
15003
15223
|
init_opencode();
|
|
15224
|
+
init_project_dir_name();
|
|
15004
15225
|
MAX_CHUNK_CHARS3 = 2e3;
|
|
15005
15226
|
NOTE_FILES = [
|
|
15006
15227
|
{ filename: "CLAUDE.md", tool: "claude" },
|
|
@@ -15081,7 +15302,7 @@ var init_claude_md_source = __esm({
|
|
|
15081
15302
|
async parse(item) {
|
|
15082
15303
|
if (!existsSync22(item.filePath))
|
|
15083
15304
|
return [];
|
|
15084
|
-
const content =
|
|
15305
|
+
const content = readFileSync15(item.filePath, "utf-8");
|
|
15085
15306
|
const chunks = [];
|
|
15086
15307
|
const sections = splitByHeaders(content);
|
|
15087
15308
|
for (let i = 0; i < sections.length; i++) {
|
|
@@ -15123,7 +15344,7 @@ var init_claude_md_source = __esm({
|
|
|
15123
15344
|
const projectDir = dirname13(filePath);
|
|
15124
15345
|
const projectName = basename14(projectDir);
|
|
15125
15346
|
const projectPath = projectDir;
|
|
15126
|
-
const content =
|
|
15347
|
+
const content = readFileSync15(filePath, "utf-8");
|
|
15127
15348
|
const firstLine = content.split("\n").find((l) => l.trim() && !l.startsWith("#"))?.trim()?.slice(0, 200) || `${filename} for ${projectName}`;
|
|
15128
15349
|
const id = tool === "claude" ? projectName : `${projectName}_${tool}`;
|
|
15129
15350
|
return {
|
|
@@ -15148,7 +15369,7 @@ var init_claude_md_source = __esm({
|
|
|
15148
15369
|
});
|
|
15149
15370
|
|
|
15150
15371
|
// ../engine/dist/parsers/agent-memory-source.js
|
|
15151
|
-
import { existsSync as existsSync23, readFileSync as
|
|
15372
|
+
import { existsSync as existsSync23, readFileSync as readFileSync16, readdirSync as readdirSync17, statSync as statSync21 } from "fs";
|
|
15152
15373
|
import { homedir as homedir9 } from "os";
|
|
15153
15374
|
import { join as join24, basename as basename15 } from "path";
|
|
15154
15375
|
function parseFrontmatter2(content) {
|
|
@@ -15176,7 +15397,7 @@ function parseFrontmatter2(content) {
|
|
|
15176
15397
|
return { fm, body };
|
|
15177
15398
|
}
|
|
15178
15399
|
function projectHashToPath(hashDir) {
|
|
15179
|
-
return hashDir
|
|
15400
|
+
return decodeProjectDirName(hashDir);
|
|
15180
15401
|
}
|
|
15181
15402
|
function discoverMemoryDirs() {
|
|
15182
15403
|
const out = [];
|
|
@@ -15218,6 +15439,7 @@ var init_agent_memory_source = __esm({
|
|
|
15218
15439
|
init_utils();
|
|
15219
15440
|
init_claude2();
|
|
15220
15441
|
init_settings();
|
|
15442
|
+
init_project_dir_name();
|
|
15221
15443
|
MAX_CHUNK_CHARS4 = 2e3;
|
|
15222
15444
|
MAX_CHUNKS = 12;
|
|
15223
15445
|
AgentMemorySource = class {
|
|
@@ -15248,7 +15470,7 @@ var init_agent_memory_source = __esm({
|
|
|
15248
15470
|
async parse(item) {
|
|
15249
15471
|
if (!existsSync23(item.filePath))
|
|
15250
15472
|
return [];
|
|
15251
|
-
const content =
|
|
15473
|
+
const content = readFileSync16(item.filePath, "utf-8");
|
|
15252
15474
|
const { body } = parseFrontmatter2(content);
|
|
15253
15475
|
const chunks = [];
|
|
15254
15476
|
const sections = splitByHeaders(body);
|
|
@@ -15301,7 +15523,7 @@ var init_agent_memory_source = __esm({
|
|
|
15301
15523
|
fileToItem(filePath, filename, projectPath, _projectHash) {
|
|
15302
15524
|
try {
|
|
15303
15525
|
const stat3 = statSync21(filePath);
|
|
15304
|
-
const content =
|
|
15526
|
+
const content = readFileSync16(filePath, "utf-8");
|
|
15305
15527
|
const { fm } = parseFrontmatter2(content);
|
|
15306
15528
|
const stem = filename.replace(/\.md$/, "");
|
|
15307
15529
|
const idBase = fm.name || stem;
|
|
@@ -15516,7 +15738,7 @@ var init_history_source = __esm({
|
|
|
15516
15738
|
});
|
|
15517
15739
|
|
|
15518
15740
|
// ../engine/dist/parsers/paste-source.js
|
|
15519
|
-
import { existsSync as existsSync25, readdirSync as readdirSync19, readFileSync as
|
|
15741
|
+
import { existsSync as existsSync25, readdirSync as readdirSync19, readFileSync as readFileSync17, statSync as statSync23 } from "fs";
|
|
15520
15742
|
import { homedir as homedir11 } from "os";
|
|
15521
15743
|
import { join as join26, basename as basename16 } from "path";
|
|
15522
15744
|
var MAX_CHUNK_CHARS6, MAX_FILE_SIZE, PasteSource;
|
|
@@ -15572,7 +15794,7 @@ var init_paste_source = __esm({
|
|
|
15572
15794
|
if (stat3.size < 10)
|
|
15573
15795
|
continue;
|
|
15574
15796
|
const hash = basename16(file, ".txt");
|
|
15575
|
-
const content =
|
|
15797
|
+
const content = readFileSync17(filePath, "utf-8");
|
|
15576
15798
|
const firstLine = content.split("\n").find((l) => l.trim().length > 5)?.trim()?.slice(0, 100) || `Paste ${hash.slice(0, 8)}`;
|
|
15577
15799
|
yield {
|
|
15578
15800
|
id: hash,
|
|
@@ -15593,7 +15815,7 @@ var init_paste_source = __esm({
|
|
|
15593
15815
|
async parse(item) {
|
|
15594
15816
|
if (!existsSync25(item.filePath))
|
|
15595
15817
|
return [];
|
|
15596
|
-
const content =
|
|
15818
|
+
const content = readFileSync17(item.filePath, "utf-8");
|
|
15597
15819
|
if (content.trim().length < 20)
|
|
15598
15820
|
return [];
|
|
15599
15821
|
return [{
|
|
@@ -15616,7 +15838,7 @@ var init_paste_source = __esm({
|
|
|
15616
15838
|
});
|
|
15617
15839
|
|
|
15618
15840
|
// ../engine/dist/parsers/gemini-source.js
|
|
15619
|
-
import { existsSync as existsSync26, readdirSync as readdirSync20, readFileSync as
|
|
15841
|
+
import { existsSync as existsSync26, readdirSync as readdirSync20, readFileSync as readFileSync18, statSync as statSync24 } from "fs";
|
|
15620
15842
|
import { join as join27, basename as basename17 } from "path";
|
|
15621
15843
|
import { createHash as createHash11 } from "crypto";
|
|
15622
15844
|
function loadGeminiProjectMap2() {
|
|
@@ -15625,7 +15847,7 @@ function loadGeminiProjectMap2() {
|
|
|
15625
15847
|
if (!existsSync26(projectsPath))
|
|
15626
15848
|
return map;
|
|
15627
15849
|
try {
|
|
15628
|
-
const data = JSON.parse(
|
|
15850
|
+
const data = JSON.parse(readFileSync18(projectsPath, "utf-8"));
|
|
15629
15851
|
const projects = data.projects || {};
|
|
15630
15852
|
for (const [path] of Object.entries(projects)) {
|
|
15631
15853
|
const hash = createHash11("sha256").update(path).digest("hex");
|
|
@@ -15670,7 +15892,7 @@ var init_gemini_source = __esm({
|
|
|
15670
15892
|
const filePath = join27(chatsDir, file);
|
|
15671
15893
|
try {
|
|
15672
15894
|
const stat3 = statSync24(filePath);
|
|
15673
|
-
const content = JSON.parse(
|
|
15895
|
+
const content = JSON.parse(readFileSync18(filePath, "utf-8"));
|
|
15674
15896
|
const sessionId = content.sessionId || basename17(file, ".json");
|
|
15675
15897
|
if (seen.has(sessionId))
|
|
15676
15898
|
continue;
|
|
@@ -15751,7 +15973,7 @@ var init_gemini_source = __esm({
|
|
|
15751
15973
|
async parse(item) {
|
|
15752
15974
|
if (!existsSync26(item.filePath))
|
|
15753
15975
|
return [];
|
|
15754
|
-
const content = JSON.parse(
|
|
15976
|
+
const content = JSON.parse(readFileSync18(item.filePath, "utf-8"));
|
|
15755
15977
|
const messages = content.messages || [];
|
|
15756
15978
|
const chunks = [];
|
|
15757
15979
|
const getText = (m) => {
|
|
@@ -15799,7 +16021,7 @@ var init_gemini_source = __esm({
|
|
|
15799
16021
|
});
|
|
15800
16022
|
|
|
15801
16023
|
// ../engine/dist/parsers/gemini-brain-source.js
|
|
15802
|
-
import { existsSync as existsSync27, readdirSync as readdirSync21, readFileSync as
|
|
16024
|
+
import { existsSync as existsSync27, readdirSync as readdirSync21, readFileSync as readFileSync19, statSync as statSync25 } from "fs";
|
|
15803
16025
|
import { join as join28 } from "path";
|
|
15804
16026
|
var MAX_CHUNK_CHARS8, GeminiBrainSource;
|
|
15805
16027
|
var init_gemini_brain_source = __esm({
|
|
@@ -15832,14 +16054,14 @@ var init_gemini_brain_source = __esm({
|
|
|
15832
16054
|
const filePath = join28(sessionDir, file);
|
|
15833
16055
|
try {
|
|
15834
16056
|
const stat3 = statSync25(filePath);
|
|
15835
|
-
const content =
|
|
16057
|
+
const content = readFileSync19(filePath, "utf-8");
|
|
15836
16058
|
const firstLine = content.split("\n").find((l) => l.trim() && !l.startsWith("#"))?.trim() || "";
|
|
15837
16059
|
const heading = content.split("\n").find((l) => l.startsWith("#"))?.replace(/^#+\s*/, "").trim() || file;
|
|
15838
16060
|
const metaPath = `${filePath}.metadata.json`;
|
|
15839
16061
|
let metaSummary = "";
|
|
15840
16062
|
if (existsSync27(metaPath)) {
|
|
15841
16063
|
try {
|
|
15842
|
-
const meta = JSON.parse(
|
|
16064
|
+
const meta = JSON.parse(readFileSync19(metaPath, "utf-8"));
|
|
15843
16065
|
metaSummary = meta.summary || "";
|
|
15844
16066
|
} catch {
|
|
15845
16067
|
}
|
|
@@ -15870,7 +16092,7 @@ var init_gemini_brain_source = __esm({
|
|
|
15870
16092
|
async parse(item) {
|
|
15871
16093
|
if (!existsSync27(item.filePath))
|
|
15872
16094
|
return [];
|
|
15873
|
-
const content =
|
|
16095
|
+
const content = readFileSync19(item.filePath, "utf-8");
|
|
15874
16096
|
const chunks = [];
|
|
15875
16097
|
const sections = splitByHeaders(content);
|
|
15876
16098
|
for (let i = 0; i < sections.length; i++) {
|
|
@@ -16213,7 +16435,7 @@ var init_opencode_todo_source = __esm({
|
|
|
16213
16435
|
});
|
|
16214
16436
|
|
|
16215
16437
|
// ../engine/dist/parsers/codex-session-source.js
|
|
16216
|
-
import { existsSync as existsSync30, readdirSync as readdirSync22, readFileSync as
|
|
16438
|
+
import { existsSync as existsSync30, readdirSync as readdirSync22, readFileSync as readFileSync20, statSync as statSync26 } from "fs";
|
|
16217
16439
|
import { join as join29, basename as basename18 } from "path";
|
|
16218
16440
|
function getCodexSessionsDir() {
|
|
16219
16441
|
return codexBackend.sessionsDir();
|
|
@@ -16241,7 +16463,7 @@ function extractReasoningText(event) {
|
|
|
16241
16463
|
return "";
|
|
16242
16464
|
}
|
|
16243
16465
|
function readJsonlLines(filePath) {
|
|
16244
|
-
const text =
|
|
16466
|
+
const text = readFileSync20(filePath, "utf-8");
|
|
16245
16467
|
const lines = text.split("\n");
|
|
16246
16468
|
const events = [];
|
|
16247
16469
|
for (const line of lines) {
|
|
@@ -16276,7 +16498,7 @@ var init_codex_session_source = __esm({
|
|
|
16276
16498
|
for (const filePath of jsonlFiles) {
|
|
16277
16499
|
try {
|
|
16278
16500
|
const stat3 = statSync26(filePath);
|
|
16279
|
-
const lines =
|
|
16501
|
+
const lines = readFileSync20(filePath, "utf-8").split("\n");
|
|
16280
16502
|
const firstLine = lines.find((l) => l.trim());
|
|
16281
16503
|
if (!firstLine)
|
|
16282
16504
|
continue;
|
|
@@ -16449,7 +16671,7 @@ var init_codex_session_source = __esm({
|
|
|
16449
16671
|
});
|
|
16450
16672
|
|
|
16451
16673
|
// ../engine/dist/parsers/diary-source.js
|
|
16452
|
-
import { existsSync as existsSync31, mkdirSync as mkdirSync5, readdirSync as readdirSync23, readFileSync as
|
|
16674
|
+
import { existsSync as existsSync31, mkdirSync as mkdirSync5, readdirSync as readdirSync23, readFileSync as readFileSync21, writeFileSync as writeFileSync4, statSync as statSync27 } from "fs";
|
|
16453
16675
|
import { join as join30, basename as basename19 } from "path";
|
|
16454
16676
|
var MAX_CHUNK_CHARS11, DiarySource;
|
|
16455
16677
|
var init_diary_source = __esm({
|
|
@@ -16475,7 +16697,7 @@ var init_diary_source = __esm({
|
|
|
16475
16697
|
const filePath = join30(agentPath2, file);
|
|
16476
16698
|
try {
|
|
16477
16699
|
const stat3 = statSync27(filePath);
|
|
16478
|
-
const raw =
|
|
16700
|
+
const raw = readFileSync21(filePath, "utf-8");
|
|
16479
16701
|
const entry = JSON.parse(raw);
|
|
16480
16702
|
const entryId = basename19(file, ".json");
|
|
16481
16703
|
const title = `[${entry.agent}] ${entry.topic}: ${entry.content.slice(0, 80)}`;
|
|
@@ -16502,7 +16724,7 @@ var init_diary_source = __esm({
|
|
|
16502
16724
|
async parse(item) {
|
|
16503
16725
|
if (!existsSync31(item.filePath))
|
|
16504
16726
|
return [];
|
|
16505
|
-
const raw =
|
|
16727
|
+
const raw = readFileSync21(item.filePath, "utf-8");
|
|
16506
16728
|
const entry = JSON.parse(raw);
|
|
16507
16729
|
if (!entry.content || entry.content.trim().length < 10)
|
|
16508
16730
|
return [];
|
|
@@ -16565,7 +16787,7 @@ var init_diary_source = __esm({
|
|
|
16565
16787
|
const entries = [];
|
|
16566
16788
|
for (const file of files) {
|
|
16567
16789
|
try {
|
|
16568
|
-
const raw =
|
|
16790
|
+
const raw = readFileSync21(join30(agentDir, file), "utf-8");
|
|
16569
16791
|
entries.push(JSON.parse(raw));
|
|
16570
16792
|
} catch {
|
|
16571
16793
|
continue;
|
|
@@ -16578,7 +16800,7 @@ var init_diary_source = __esm({
|
|
|
16578
16800
|
});
|
|
16579
16801
|
|
|
16580
16802
|
// ../engine/dist/parsers/skills-source.js
|
|
16581
|
-
import { existsSync as existsSync32, readdirSync as readdirSync24, readFileSync as
|
|
16803
|
+
import { existsSync as existsSync32, readdirSync as readdirSync24, readFileSync as readFileSync22, statSync as statSync28 } from "fs";
|
|
16582
16804
|
import { homedir as homedir12 } from "os";
|
|
16583
16805
|
import { join as join31 } from "path";
|
|
16584
16806
|
function resolveRoots() {
|
|
@@ -16671,7 +16893,7 @@ var init_skills_source = __esm({
|
|
|
16671
16893
|
continue;
|
|
16672
16894
|
let content;
|
|
16673
16895
|
try {
|
|
16674
|
-
content =
|
|
16896
|
+
content = readFileSync22(skillMd, "utf-8");
|
|
16675
16897
|
} catch {
|
|
16676
16898
|
continue;
|
|
16677
16899
|
}
|
|
@@ -16731,7 +16953,7 @@ var init_skills_source = __esm({
|
|
|
16731
16953
|
async parse(item) {
|
|
16732
16954
|
if (!existsSync32(item.filePath))
|
|
16733
16955
|
return [];
|
|
16734
|
-
const content =
|
|
16956
|
+
const content = readFileSync22(item.filePath, "utf-8");
|
|
16735
16957
|
if (!content.trim())
|
|
16736
16958
|
return [];
|
|
16737
16959
|
return [{
|
|
@@ -16754,14 +16976,14 @@ var init_skills_source = __esm({
|
|
|
16754
16976
|
});
|
|
16755
16977
|
|
|
16756
16978
|
// ../engine/dist/parsers/mcps-source.js
|
|
16757
|
-
import { existsSync as existsSync33, readdirSync as readdirSync25, readFileSync as
|
|
16979
|
+
import { existsSync as existsSync33, readdirSync as readdirSync25, readFileSync as readFileSync23, statSync as statSync29 } from "fs";
|
|
16758
16980
|
import { homedir as homedir13 } from "os";
|
|
16759
16981
|
import { join as join32 } from "path";
|
|
16760
16982
|
function readJson(path) {
|
|
16761
16983
|
if (!existsSync33(path))
|
|
16762
16984
|
return null;
|
|
16763
16985
|
try {
|
|
16764
|
-
const raw =
|
|
16986
|
+
const raw = readFileSync23(path, "utf-8");
|
|
16765
16987
|
const stripped = path.endsWith(".jsonc") ? raw.replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|[^:])\/\/.*$/gm, "$1").replace(/,(\s*[}\]])/g, "$1") : raw;
|
|
16766
16988
|
return JSON.parse(stripped);
|
|
16767
16989
|
} catch {
|
|
@@ -16874,7 +17096,7 @@ var init_mcps_source = __esm({
|
|
|
16874
17096
|
return;
|
|
16875
17097
|
let content;
|
|
16876
17098
|
try {
|
|
16877
|
-
content =
|
|
17099
|
+
content = readFileSync23(path, "utf-8");
|
|
16878
17100
|
} catch {
|
|
16879
17101
|
return;
|
|
16880
17102
|
}
|
|
@@ -17043,7 +17265,7 @@ var init_toolkit_format = __esm({
|
|
|
17043
17265
|
});
|
|
17044
17266
|
|
|
17045
17267
|
// ../engine/dist/parsers/slash-commands-source.js
|
|
17046
|
-
import { existsSync as existsSync34, readdirSync as readdirSync26, readFileSync as
|
|
17268
|
+
import { existsSync as existsSync34, readdirSync as readdirSync26, readFileSync as readFileSync24, statSync as statSync30 } from "fs";
|
|
17047
17269
|
import { join as join33, basename as basename20 } from "path";
|
|
17048
17270
|
function parseCommand(content, fallbackName, format) {
|
|
17049
17271
|
if (format === "toml") {
|
|
@@ -17071,6 +17293,7 @@ var init_slash_commands_source = __esm({
|
|
|
17071
17293
|
init_codex2();
|
|
17072
17294
|
init_settings();
|
|
17073
17295
|
init_toolkit_format();
|
|
17296
|
+
init_project_dir_name();
|
|
17074
17297
|
MAX_CHUNK_CHARS13 = 2e3;
|
|
17075
17298
|
SlashCommandsSource = class {
|
|
17076
17299
|
sourceType = "command";
|
|
@@ -17084,7 +17307,7 @@ var init_slash_commands_source = __esm({
|
|
|
17084
17307
|
for (const entry of readdirSync26(projectsRoot, { withFileTypes: true })) {
|
|
17085
17308
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
17086
17309
|
continue;
|
|
17087
|
-
const projectPath = entry.name
|
|
17310
|
+
const projectPath = decodeProjectDirName(entry.name);
|
|
17088
17311
|
const cmdDir = join33(projectPath, ".claude", "commands");
|
|
17089
17312
|
if (existsSync34(cmdDir))
|
|
17090
17313
|
roots.push({ path: cmdDir, tool: "claude", scope: "project", projectPath, format: "md" });
|
|
@@ -17117,7 +17340,7 @@ var init_slash_commands_source = __esm({
|
|
|
17117
17340
|
const filePath = join33(root.path, file);
|
|
17118
17341
|
try {
|
|
17119
17342
|
const stat3 = statSync30(filePath);
|
|
17120
|
-
const content =
|
|
17343
|
+
const content = readFileSync24(filePath, "utf-8");
|
|
17121
17344
|
const parsed = parseCommand(content, basename20(file, ext), root.format);
|
|
17122
17345
|
yield {
|
|
17123
17346
|
id: `${root.tool}_cmd_${root.scope}_${parsed.name}`,
|
|
@@ -17143,7 +17366,7 @@ var init_slash_commands_source = __esm({
|
|
|
17143
17366
|
async parse(item) {
|
|
17144
17367
|
if (!existsSync34(item.filePath))
|
|
17145
17368
|
return [];
|
|
17146
|
-
const content =
|
|
17369
|
+
const content = readFileSync24(item.filePath, "utf-8");
|
|
17147
17370
|
if (!content.trim())
|
|
17148
17371
|
return [];
|
|
17149
17372
|
return [{
|
|
@@ -17166,7 +17389,7 @@ var init_slash_commands_source = __esm({
|
|
|
17166
17389
|
});
|
|
17167
17390
|
|
|
17168
17391
|
// ../engine/dist/parsers/subagents-source.js
|
|
17169
|
-
import { existsSync as existsSync35, readdirSync as readdirSync27, readFileSync as
|
|
17392
|
+
import { existsSync as existsSync35, readdirSync as readdirSync27, readFileSync as readFileSync25, statSync as statSync31 } from "fs";
|
|
17170
17393
|
import { join as join34, basename as basename21 } from "path";
|
|
17171
17394
|
function parseAgent(content, fallbackName, format) {
|
|
17172
17395
|
if (format === "toml") {
|
|
@@ -17196,6 +17419,7 @@ var init_subagents_source = __esm({
|
|
|
17196
17419
|
init_codex2();
|
|
17197
17420
|
init_settings();
|
|
17198
17421
|
init_toolkit_format();
|
|
17422
|
+
init_project_dir_name();
|
|
17199
17423
|
MAX_CHUNK_CHARS14 = 2e3;
|
|
17200
17424
|
SubagentsSource = class {
|
|
17201
17425
|
sourceType = "agent";
|
|
@@ -17209,7 +17433,7 @@ var init_subagents_source = __esm({
|
|
|
17209
17433
|
for (const entry of readdirSync27(projectsRoot, { withFileTypes: true })) {
|
|
17210
17434
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
17211
17435
|
continue;
|
|
17212
|
-
const projectPath = entry.name
|
|
17436
|
+
const projectPath = decodeProjectDirName(entry.name);
|
|
17213
17437
|
const agentDir = join34(projectPath, ".claude", "agents");
|
|
17214
17438
|
if (existsSync35(agentDir))
|
|
17215
17439
|
roots.push({ path: agentDir, tool: "claude", scope: "project", projectPath, format: "md" });
|
|
@@ -17242,7 +17466,7 @@ var init_subagents_source = __esm({
|
|
|
17242
17466
|
const filePath = join34(root.path, file);
|
|
17243
17467
|
try {
|
|
17244
17468
|
const stat3 = statSync31(filePath);
|
|
17245
|
-
const content =
|
|
17469
|
+
const content = readFileSync25(filePath, "utf-8");
|
|
17246
17470
|
const parsed = parseAgent(content, basename21(file, ext), root.format);
|
|
17247
17471
|
yield {
|
|
17248
17472
|
id: `${root.tool}_agent_${root.scope}_${parsed.name}`,
|
|
@@ -17269,7 +17493,7 @@ var init_subagents_source = __esm({
|
|
|
17269
17493
|
async parse(item) {
|
|
17270
17494
|
if (!existsSync35(item.filePath))
|
|
17271
17495
|
return [];
|
|
17272
|
-
const content =
|
|
17496
|
+
const content = readFileSync25(item.filePath, "utf-8");
|
|
17273
17497
|
if (!content.trim())
|
|
17274
17498
|
return [];
|
|
17275
17499
|
return [{
|
|
@@ -17292,13 +17516,13 @@ var init_subagents_source = __esm({
|
|
|
17292
17516
|
});
|
|
17293
17517
|
|
|
17294
17518
|
// ../engine/dist/parsers/hooks-source.js
|
|
17295
|
-
import { existsSync as existsSync36, readFileSync as
|
|
17519
|
+
import { existsSync as existsSync36, readFileSync as readFileSync26, readdirSync as readdirSync28, statSync as statSync32 } from "fs";
|
|
17296
17520
|
import { join as join35 } from "path";
|
|
17297
17521
|
function readJson2(path) {
|
|
17298
17522
|
if (!existsSync36(path))
|
|
17299
17523
|
return null;
|
|
17300
17524
|
try {
|
|
17301
|
-
return JSON.parse(
|
|
17525
|
+
return JSON.parse(readFileSync26(path, "utf-8"));
|
|
17302
17526
|
} catch {
|
|
17303
17527
|
return null;
|
|
17304
17528
|
}
|
|
@@ -17309,6 +17533,7 @@ var init_hooks_source = __esm({
|
|
|
17309
17533
|
"use strict";
|
|
17310
17534
|
init_claude2();
|
|
17311
17535
|
init_settings();
|
|
17536
|
+
init_project_dir_name();
|
|
17312
17537
|
HooksSource = class {
|
|
17313
17538
|
sourceType = "hook";
|
|
17314
17539
|
async *discover() {
|
|
@@ -17321,7 +17546,7 @@ var init_hooks_source = __esm({
|
|
|
17321
17546
|
for (const entry of readdirSync28(projectsRoot, { withFileTypes: true })) {
|
|
17322
17547
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
17323
17548
|
continue;
|
|
17324
|
-
const projectPath = entry.name
|
|
17549
|
+
const projectPath = decodeProjectDirName(entry.name);
|
|
17325
17550
|
const settingsPath2 = join35(projectPath, ".claude", "settings.json");
|
|
17326
17551
|
if (existsSync36(settingsPath2)) {
|
|
17327
17552
|
yield* this.fromSettings(settingsPath2, "project", projectPath);
|
|
@@ -17414,14 +17639,14 @@ var init_hooks_source = __esm({
|
|
|
17414
17639
|
});
|
|
17415
17640
|
|
|
17416
17641
|
// ../engine/dist/parsers/plugins-source.js
|
|
17417
|
-
import { existsSync as existsSync37, readFileSync as
|
|
17642
|
+
import { existsSync as existsSync37, readFileSync as readFileSync27, readdirSync as readdirSync29, statSync as statSync33 } from "fs";
|
|
17418
17643
|
import { homedir as homedir14 } from "os";
|
|
17419
17644
|
import { join as join36 } from "path";
|
|
17420
17645
|
function readJson3(path) {
|
|
17421
17646
|
if (!existsSync37(path))
|
|
17422
17647
|
return null;
|
|
17423
17648
|
try {
|
|
17424
|
-
return JSON.parse(
|
|
17649
|
+
return JSON.parse(readFileSync27(path, "utf-8"));
|
|
17425
17650
|
} catch {
|
|
17426
17651
|
return null;
|
|
17427
17652
|
}
|
|
@@ -17678,7 +17903,7 @@ var init_extractor_version = __esm({
|
|
|
17678
17903
|
});
|
|
17679
17904
|
|
|
17680
17905
|
// src/sync-ledger.ts
|
|
17681
|
-
import { readFileSync as
|
|
17906
|
+
import { readFileSync as readFileSync28, writeFileSync as writeFileSync5, renameSync as renameSync4, mkdirSync as mkdirSync6 } from "node:fs";
|
|
17682
17907
|
import { join as join37, dirname as dirname14 } from "node:path";
|
|
17683
17908
|
function toRow(entry) {
|
|
17684
17909
|
if (entry === void 0) return void 0;
|
|
@@ -17690,24 +17915,77 @@ function ledgerFilePath() {
|
|
|
17690
17915
|
function load() {
|
|
17691
17916
|
if (cache3) return cache3;
|
|
17692
17917
|
try {
|
|
17693
|
-
const parsed = JSON.parse(
|
|
17918
|
+
const parsed = JSON.parse(readFileSync28(ledgerPath(), "utf-8"));
|
|
17694
17919
|
cache3 = parsed && typeof parsed === "object" ? parsed : {};
|
|
17695
17920
|
} catch {
|
|
17696
17921
|
cache3 = {};
|
|
17697
17922
|
}
|
|
17698
17923
|
return cache3;
|
|
17699
17924
|
}
|
|
17700
|
-
function
|
|
17925
|
+
function persistNow(data) {
|
|
17701
17926
|
const path = ledgerPath();
|
|
17702
17927
|
mkdirSync6(dirname14(path), { recursive: true });
|
|
17703
17928
|
const tmp = `${path}.tmp`;
|
|
17704
17929
|
writeFileSync5(tmp, JSON.stringify(data));
|
|
17705
17930
|
renameSync4(tmp, path);
|
|
17931
|
+
pendingWrite = false;
|
|
17932
|
+
}
|
|
17933
|
+
function persist(data) {
|
|
17934
|
+
pendingWrite = true;
|
|
17935
|
+
if (flushTimer) return;
|
|
17936
|
+
flushTimer = setTimeout(() => {
|
|
17937
|
+
flushTimer = null;
|
|
17938
|
+
if (pendingWrite) {
|
|
17939
|
+
try {
|
|
17940
|
+
persistNow(data);
|
|
17941
|
+
} catch {
|
|
17942
|
+
}
|
|
17943
|
+
}
|
|
17944
|
+
}, LEDGER_FLUSH_MS);
|
|
17945
|
+
flushTimer.unref?.();
|
|
17946
|
+
}
|
|
17947
|
+
function pruneLedgerTargets(configuredServers) {
|
|
17948
|
+
const data = load();
|
|
17949
|
+
const keep = new Set(configuredServers);
|
|
17950
|
+
const orphans = {};
|
|
17951
|
+
for (const server of Object.keys(data)) {
|
|
17952
|
+
if (!keep.has(server)) {
|
|
17953
|
+
orphans[server] = data[server];
|
|
17954
|
+
delete data[server];
|
|
17955
|
+
}
|
|
17956
|
+
}
|
|
17957
|
+
const names = Object.keys(orphans);
|
|
17958
|
+
if (names.length === 0) return 0;
|
|
17959
|
+
const path = ledgerPath();
|
|
17960
|
+
const side = `${path}.orphans.json`;
|
|
17961
|
+
try {
|
|
17962
|
+
let prior = {};
|
|
17963
|
+
try {
|
|
17964
|
+
prior = JSON.parse(readFileSync28(side, "utf-8"));
|
|
17965
|
+
} catch {
|
|
17966
|
+
}
|
|
17967
|
+
writeFileSync5(side, JSON.stringify({ ...prior, ...orphans }));
|
|
17968
|
+
} catch {
|
|
17969
|
+
for (const n of names) data[n] = orphans[n];
|
|
17970
|
+
return 0;
|
|
17971
|
+
}
|
|
17972
|
+
const rows = names.reduce((n, s) => n + Object.keys(orphans[s]).length, 0);
|
|
17973
|
+
console.error(`[sync] ledger: parked ${rows} row(s) for ${names.length} server(s) no longer configured (${names.join(", ")}) in ${side}`);
|
|
17974
|
+
persistNow(data);
|
|
17975
|
+
return names.length;
|
|
17976
|
+
}
|
|
17977
|
+
function flushLedger() {
|
|
17978
|
+
if (flushTimer) {
|
|
17979
|
+
clearTimeout(flushTimer);
|
|
17980
|
+
flushTimer = null;
|
|
17981
|
+
}
|
|
17982
|
+
if (!pendingWrite || !cache3) return;
|
|
17983
|
+
persistNow(cache3);
|
|
17706
17984
|
}
|
|
17707
17985
|
function loadItemVersionsAll() {
|
|
17708
17986
|
if (itemVersionsCache) return itemVersionsCache;
|
|
17709
17987
|
try {
|
|
17710
|
-
const parsed = JSON.parse(
|
|
17988
|
+
const parsed = JSON.parse(readFileSync28(itemVersionsPath(), "utf-8"));
|
|
17711
17989
|
itemVersionsCache = parsed && typeof parsed === "object" ? parsed : {};
|
|
17712
17990
|
} catch {
|
|
17713
17991
|
itemVersionsCache = {};
|
|
@@ -17789,7 +18067,7 @@ function markFieldCoverage(server, field, rows) {
|
|
|
17789
18067
|
function loadReconcile() {
|
|
17790
18068
|
if (reconcileCache) return reconcileCache;
|
|
17791
18069
|
try {
|
|
17792
|
-
const parsed = JSON.parse(
|
|
18070
|
+
const parsed = JSON.parse(readFileSync28(reconcilePath(), "utf-8"));
|
|
17793
18071
|
reconcileCache = parsed && typeof parsed === "object" ? parsed : {};
|
|
17794
18072
|
} catch {
|
|
17795
18073
|
reconcileCache = {};
|
|
@@ -17837,7 +18115,7 @@ function syncMode(row, mtime, fileSize, extractorVersion, isAppendOnly) {
|
|
|
17837
18115
|
if (row.m >= Math.floor(mtime)) return "skip";
|
|
17838
18116
|
return "full";
|
|
17839
18117
|
}
|
|
17840
|
-
var ledgerPath, cache3, itemVersionsPath, itemVersionsCache, unackedCursorAttempts, reconcilePath, reconcileCache;
|
|
18118
|
+
var ledgerPath, cache3, LEDGER_FLUSH_MS, pendingWrite, flushTimer, itemVersionsPath, itemVersionsCache, unackedCursorAttempts, reconcilePath, reconcileCache;
|
|
17841
18119
|
var init_sync_ledger = __esm({
|
|
17842
18120
|
"src/sync-ledger.ts"() {
|
|
17843
18121
|
"use strict";
|
|
@@ -17845,6 +18123,9 @@ var init_sync_ledger = __esm({
|
|
|
17845
18123
|
init_extractor_version();
|
|
17846
18124
|
ledgerPath = () => join37(getDataDir(), "sync-ledger.json");
|
|
17847
18125
|
cache3 = null;
|
|
18126
|
+
LEDGER_FLUSH_MS = 2e3;
|
|
18127
|
+
pendingWrite = false;
|
|
18128
|
+
flushTimer = null;
|
|
17848
18129
|
itemVersionsPath = () => join37(getDataDir(), "item-versions.json");
|
|
17849
18130
|
itemVersionsCache = null;
|
|
17850
18131
|
unackedCursorAttempts = 0;
|
|
@@ -17879,7 +18160,7 @@ var init_sync_fields = __esm({
|
|
|
17879
18160
|
});
|
|
17880
18161
|
|
|
17881
18162
|
// ../engine/dist/core/index-lock.js
|
|
17882
|
-
import { existsSync as existsSync38, mkdirSync as mkdirSync7, openSync as
|
|
18163
|
+
import { existsSync as existsSync38, mkdirSync as mkdirSync7, openSync as openSync7, writeFileSync as writeFileSync6, readFileSync as readFileSync29, rmSync as rmSync4, statSync as statSync34, closeSync as closeSync7 } from "fs";
|
|
17883
18164
|
import { dirname as dirname15, join as join38 } from "path";
|
|
17884
18165
|
function acquireIndexLock(opts) {
|
|
17885
18166
|
const lockPath = lockFilePath();
|
|
@@ -17891,7 +18172,7 @@ function acquireIndexLock(opts) {
|
|
|
17891
18172
|
}
|
|
17892
18173
|
let fd;
|
|
17893
18174
|
try {
|
|
17894
|
-
fd =
|
|
18175
|
+
fd = openSync7(lockPath, "wx", 384);
|
|
17895
18176
|
} catch (err) {
|
|
17896
18177
|
if (err.code === "EEXIST")
|
|
17897
18178
|
return null;
|
|
@@ -17901,7 +18182,7 @@ function acquireIndexLock(opts) {
|
|
|
17901
18182
|
try {
|
|
17902
18183
|
writeFileSync6(fd, JSON.stringify(holder));
|
|
17903
18184
|
} finally {
|
|
17904
|
-
|
|
18185
|
+
closeSync7(fd);
|
|
17905
18186
|
}
|
|
17906
18187
|
let released = false;
|
|
17907
18188
|
return {
|
|
@@ -17911,7 +18192,7 @@ function acquireIndexLock(opts) {
|
|
|
17911
18192
|
return;
|
|
17912
18193
|
released = true;
|
|
17913
18194
|
try {
|
|
17914
|
-
const current = JSON.parse(
|
|
18195
|
+
const current = JSON.parse(readFileSync29(lockPath, "utf-8"));
|
|
17915
18196
|
if (current.pid !== holder.pid || current.startedAt !== holder.startedAt)
|
|
17916
18197
|
return;
|
|
17917
18198
|
} catch {
|
|
@@ -17933,7 +18214,7 @@ function stealStaleLock(lockPath, staleAfterMs) {
|
|
|
17933
18214
|
const age = Date.now() - s.mtimeMs;
|
|
17934
18215
|
let payload;
|
|
17935
18216
|
try {
|
|
17936
|
-
payload = JSON.parse(
|
|
18217
|
+
payload = JSON.parse(readFileSync29(lockPath, "utf-8"));
|
|
17937
18218
|
} catch {
|
|
17938
18219
|
rmSync4(lockPath, { force: true });
|
|
17939
18220
|
return true;
|
|
@@ -17977,7 +18258,7 @@ __export(http_exports, {
|
|
|
17977
18258
|
clientHeaders: () => clientHeaders,
|
|
17978
18259
|
fetchWithTimeout: () => fetchWithTimeout
|
|
17979
18260
|
});
|
|
17980
|
-
import { readFileSync as
|
|
18261
|
+
import { readFileSync as readFileSync30 } from "node:fs";
|
|
17981
18262
|
function cliVersion() {
|
|
17982
18263
|
return CLI_VERSION;
|
|
17983
18264
|
}
|
|
@@ -17998,10 +18279,10 @@ var init_http = __esm({
|
|
|
17998
18279
|
"use strict";
|
|
17999
18280
|
CLI_VERSION = "0.0.0";
|
|
18000
18281
|
try {
|
|
18001
|
-
CLI_VERSION = JSON.parse(
|
|
18282
|
+
CLI_VERSION = JSON.parse(readFileSync30(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
|
|
18002
18283
|
} catch {
|
|
18003
18284
|
try {
|
|
18004
|
-
if (true) CLI_VERSION = "0.5.
|
|
18285
|
+
if (true) CLI_VERSION = "0.5.6";
|
|
18005
18286
|
} catch {
|
|
18006
18287
|
}
|
|
18007
18288
|
}
|
|
@@ -18014,7 +18295,7 @@ __export(client_events_exports, {
|
|
|
18014
18295
|
isTelemetryEnabled: () => isTelemetryEnabled,
|
|
18015
18296
|
reportClientEvent: () => reportClientEvent
|
|
18016
18297
|
});
|
|
18017
|
-
import { readFileSync as
|
|
18298
|
+
import { readFileSync as readFileSync31 } from "node:fs";
|
|
18018
18299
|
function scrub(msg) {
|
|
18019
18300
|
if (!msg) return "";
|
|
18020
18301
|
const noHome = msg.replace(/\/(?:home|Users)\/[^/\s]+/g, "~");
|
|
@@ -18067,7 +18348,7 @@ var init_client_events = __esm({
|
|
|
18067
18348
|
init_secret_redactor();
|
|
18068
18349
|
CLI_VERSION2 = "0.0.0";
|
|
18069
18350
|
try {
|
|
18070
|
-
CLI_VERSION2 = JSON.parse(
|
|
18351
|
+
CLI_VERSION2 = JSON.parse(readFileSync31(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION2;
|
|
18071
18352
|
} catch {
|
|
18072
18353
|
}
|
|
18073
18354
|
}
|
|
@@ -18190,6 +18471,7 @@ var sync_client_exports = {};
|
|
|
18190
18471
|
__export(sync_client_exports, {
|
|
18191
18472
|
BATCH_SCAN_MAX_BYTES: () => BATCH_SCAN_MAX_BYTES,
|
|
18192
18473
|
FULL_BUILD_MAX_BYTES: () => FULL_BUILD_MAX_BYTES,
|
|
18474
|
+
_resetCapsCacheForTests: () => _resetCapsCacheForTests,
|
|
18193
18475
|
_resetTenantSecurityConfigCache: () => _resetTenantSecurityConfigCache,
|
|
18194
18476
|
_resetTenantSyncConfigCache: () => _resetTenantSyncConfigCache,
|
|
18195
18477
|
batchScanExternal: () => batchScanExternal,
|
|
@@ -18207,7 +18489,7 @@ __export(sync_client_exports, {
|
|
|
18207
18489
|
syncSessions: () => syncSessions
|
|
18208
18490
|
});
|
|
18209
18491
|
import { join as join40, dirname as dirname16, basename as basename22 } from "node:path";
|
|
18210
|
-
import { readFileSync as
|
|
18492
|
+
import { readFileSync as readFileSync32, writeFileSync as writeFileSync8, mkdirSync as mkdirSync8, mkdtempSync as mkdtempSync4, rmSync as rmSync5, chmodSync as chmodSync3, unlinkSync as unlinkSync2, readdirSync as readdirSync30, statSync as statSync35 } from "node:fs";
|
|
18211
18493
|
import { tmpdir as tmpdir3, hostname } from "node:os";
|
|
18212
18494
|
import { createHash as createHash13 } from "node:crypto";
|
|
18213
18495
|
import { fileURLToPath } from "node:url";
|
|
@@ -18229,8 +18511,10 @@ function saveCredentials(c) {
|
|
|
18229
18511
|
}
|
|
18230
18512
|
}
|
|
18231
18513
|
function loadAllCredentials() {
|
|
18514
|
+
const fromEnv = envCredentials();
|
|
18515
|
+
if (fromEnv) return [{ serverUrl: fromEnv.serverUrl, token: fromEnv.token }];
|
|
18232
18516
|
try {
|
|
18233
|
-
const parsed = JSON.parse(
|
|
18517
|
+
const parsed = JSON.parse(readFileSync32(credPath(), "utf-8"));
|
|
18234
18518
|
if (Array.isArray(parsed?.targets)) return parsed.targets.filter((t) => t?.serverUrl).map((t) => ({ serverUrl: t.serverUrl, token: t.token || "" }));
|
|
18235
18519
|
if (parsed?.serverUrl) return [{ serverUrl: parsed.serverUrl, token: parsed.token || "" }];
|
|
18236
18520
|
} catch {
|
|
@@ -18389,6 +18673,10 @@ function isLocalHost(serverUrl) {
|
|
|
18389
18673
|
async function syncSessions(opts = {}) {
|
|
18390
18674
|
const targets = loadAllCredentials();
|
|
18391
18675
|
if (targets.length === 0) throw new Error("Not logged in \u2014 run `chat-recall login <server-url> --token <token>`");
|
|
18676
|
+
try {
|
|
18677
|
+
pruneLedgerTargets(targets.map((t) => t.serverUrl));
|
|
18678
|
+
} catch {
|
|
18679
|
+
}
|
|
18392
18680
|
let agg = null;
|
|
18393
18681
|
const errors = [];
|
|
18394
18682
|
for (const cred of targets) {
|
|
@@ -18411,6 +18699,7 @@ async function syncSessions(opts = {}) {
|
|
|
18411
18699
|
errors.push(`${cred.serverUrl}: ${e instanceof Error ? e.message : e}`);
|
|
18412
18700
|
}
|
|
18413
18701
|
}
|
|
18702
|
+
flushLedger();
|
|
18414
18703
|
if (!agg) throw new Error(`sync failed for all targets:
|
|
18415
18704
|
${errors.join("\n ")}`);
|
|
18416
18705
|
if (errors.length > 0) console.error(`[sync] ${errors.length} target(s) failed (others succeeded):
|
|
@@ -18436,11 +18725,11 @@ async function reconcileFieldsForTarget(cred, fullRefs, opts = {}) {
|
|
|
18436
18725
|
let pushed = 0, absent = 0, scanned = 0;
|
|
18437
18726
|
for (const field of SYNC_FIELDS) {
|
|
18438
18727
|
const needFull = !!opts.force || fieldNeedsFullPass(base2, field);
|
|
18439
|
-
const
|
|
18728
|
+
const candidates2 = needFull ? fullRefs() : opts.convRefs ?? fullRefs();
|
|
18440
18729
|
const send = [];
|
|
18441
18730
|
const mtimeById = /* @__PURE__ */ new Map();
|
|
18442
18731
|
const absentIds = [];
|
|
18443
|
-
for (const ref of
|
|
18732
|
+
for (const ref of candidates2) {
|
|
18444
18733
|
if (!fieldNeedsScan(ledger.get(ref.prefixedId), field, ref.mtime, opts.force)) continue;
|
|
18445
18734
|
scanned++;
|
|
18446
18735
|
mtimeById.set(ref.prefixedId, ref.mtime);
|
|
@@ -18561,6 +18850,20 @@ function batchScanExternal(items, opts = {}) {
|
|
|
18561
18850
|
}
|
|
18562
18851
|
return { findings, scanned, slices, scanMs };
|
|
18563
18852
|
}
|
|
18853
|
+
function _resetCapsCacheForTests() {
|
|
18854
|
+
capsOk.clear();
|
|
18855
|
+
}
|
|
18856
|
+
async function verifyServerApi(serverUrl, minApi) {
|
|
18857
|
+
const base2 = serverUrl.replace(/\/$/, "");
|
|
18858
|
+
const seen = capsOk.get(base2);
|
|
18859
|
+
if (seen !== void 0 && Date.now() - seen < CAPS_TTL_MS) return true;
|
|
18860
|
+
const caps = await fetchWithTimeout(`${base2}/api/capabilities`).then((r) => r.json());
|
|
18861
|
+
if ((caps.apiVersion ?? 0) < minApi) {
|
|
18862
|
+
throw new Error(`server too old: apiVersion ${caps.apiVersion ?? "none"} < required ${minApi} \u2014 update the server image before syncing`);
|
|
18863
|
+
}
|
|
18864
|
+
capsOk.set(base2, Date.now());
|
|
18865
|
+
return true;
|
|
18866
|
+
}
|
|
18564
18867
|
async function syncToTarget(cred, opts = {}) {
|
|
18565
18868
|
const sync = loadSettings().sync;
|
|
18566
18869
|
const serverCfg = await fetchTenantSyncConfig(cred);
|
|
@@ -18581,14 +18884,9 @@ async function syncToTarget(cred, opts = {}) {
|
|
|
18581
18884
|
return isProjectSyncable(r.source === "ignored" ? "" : r.id, projectPath, { syncMode: "only", syncOnly: syncOnly2 });
|
|
18582
18885
|
};
|
|
18583
18886
|
const MIN_SERVER_API = 2;
|
|
18584
|
-
|
|
18585
|
-
const
|
|
18586
|
-
if ((
|
|
18587
|
-
throw new Error(`server too old: apiVersion ${caps.apiVersion ?? "none"} < required ${MIN_SERVER_API} \u2014 update the server image before syncing`);
|
|
18588
|
-
}
|
|
18589
|
-
} catch (e) {
|
|
18590
|
-
if (e instanceof Error && e.message.startsWith("server too old")) throw e;
|
|
18591
|
-
throw new Error(`cannot verify server version (${e instanceof Error ? e.message : e}) \u2014 refusing to sync blind`);
|
|
18887
|
+
{
|
|
18888
|
+
const ok = await verifyServerApi(cred.serverUrl, MIN_SERVER_API);
|
|
18889
|
+
if (!ok) throw new Error(`cannot verify server version \u2014 refusing to sync blind`);
|
|
18592
18890
|
}
|
|
18593
18891
|
const { tenantRules, verifySecrets } = await fetchTenantSecurityConfig(cred);
|
|
18594
18892
|
const CHANGED_WALK_OVERLAP_MS = 15 * 6e4;
|
|
@@ -18645,8 +18943,11 @@ async function syncToTarget(cred, opts = {}) {
|
|
|
18645
18943
|
try {
|
|
18646
18944
|
const body2 = JSON.parse(text);
|
|
18647
18945
|
detail = body2.error ?? text;
|
|
18946
|
+
if (body2.detail) detail += `
|
|
18947
|
+
${body2.detail}`;
|
|
18648
18948
|
if (body2.resetsAt) detail += ` (resets ${new Date(body2.resetsAt).toISOString().slice(0, 10)})`;
|
|
18649
|
-
if (body2.upgradeUrl) detail += `
|
|
18949
|
+
if (body2.upgradeUrl) detail += `
|
|
18950
|
+
${body2.upgradeUrl}`;
|
|
18650
18951
|
} catch {
|
|
18651
18952
|
}
|
|
18652
18953
|
throw new Error(`sync paused by the server: ${detail}`);
|
|
@@ -18793,16 +19094,21 @@ async function syncToTarget(cred, opts = {}) {
|
|
|
18793
19094
|
const findingsBatch = makeBatcher("findings", 200, true);
|
|
18794
19095
|
const scanSecrets = isSecretScannerAvailable() && upload.findings && process.env.CHAT_RECALL_SCAN_SECRETS !== "0";
|
|
18795
19096
|
const verifySecretsScan = verifySecrets;
|
|
19097
|
+
let skipped = 0, redactions = 0, walked = 0;
|
|
18796
19098
|
const kgSeen = /* @__PURE__ */ new Set();
|
|
18797
19099
|
const kgEntityType = /* @__PURE__ */ new Map();
|
|
18798
|
-
const
|
|
18799
|
-
const
|
|
19100
|
+
const kgEntityNames = /* @__PURE__ */ new Set();
|
|
19101
|
+
const kgKey = (subject, predicate, object, validFrom) => createHash13("sha1").update(`${subject}|${predicate}|${object}|${validFrom}`).digest("hex").slice(0, 16);
|
|
19102
|
+
const accumulateKg = async (triples, sourceSession) => {
|
|
18800
19103
|
for (const t of triples) {
|
|
18801
|
-
const key =
|
|
19104
|
+
const key = kgKey(t.subject, t.predicate, t.object, t.validFrom ?? "");
|
|
18802
19105
|
if (kgSeen.has(key)) continue;
|
|
18803
19106
|
kgSeen.add(key);
|
|
18804
19107
|
if (t.predicate === "is_a" && !kgEntityType.has(t.subject)) kgEntityType.set(t.subject, t.object);
|
|
18805
|
-
|
|
19108
|
+
kgEntityNames.add(t.subject);
|
|
19109
|
+
kgEntityNames.add(t.object);
|
|
19110
|
+
const count = { redactions: 0 };
|
|
19111
|
+
await kgTripleBatch.add(redactDeep({
|
|
18806
19112
|
subject: t.subject,
|
|
18807
19113
|
predicate: t.predicate,
|
|
18808
19114
|
object: t.object,
|
|
@@ -18810,10 +19116,10 @@ async function syncToTarget(cred, opts = {}) {
|
|
|
18810
19116
|
valid_to: null,
|
|
18811
19117
|
confidence: t.confidence ?? 1,
|
|
18812
19118
|
source_session: sourceSession
|
|
18813
|
-
});
|
|
19119
|
+
}, count));
|
|
19120
|
+
redactions += count.redactions;
|
|
18814
19121
|
}
|
|
18815
19122
|
};
|
|
18816
|
-
let skipped = 0, redactions = 0, walked = 0;
|
|
18817
19123
|
let scanMs = 0, scanned = 0;
|
|
18818
19124
|
const slice = refs.slice(0, opts.limit ?? refs.length);
|
|
18819
19125
|
const trace = process.env.CHAT_RECALL_SYNC_TRACE === "1" ? (msg) => {
|
|
@@ -18946,7 +19252,7 @@ async function syncToTarget(cred, opts = {}) {
|
|
|
18946
19252
|
await convBatch.add(built.conv);
|
|
18947
19253
|
if (built.findings.length > 0) await findingsBatch.add(built.findings);
|
|
18948
19254
|
if (upload.sessionMeta) {
|
|
18949
|
-
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);
|
|
19255
|
+
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);
|
|
18950
19256
|
}
|
|
18951
19257
|
if (upload.sessionMeta && sessionFileBytes(ref) <= FULL_BUILD_MAX_BYTES) {
|
|
18952
19258
|
try {
|
|
@@ -19025,7 +19331,7 @@ async function syncToTarget(cred, opts = {}) {
|
|
|
19025
19331
|
chunks: redactedChunks
|
|
19026
19332
|
});
|
|
19027
19333
|
if (upload.sessionMeta && redactedChunks.length > 0) {
|
|
19028
|
-
accumulateKg(
|
|
19334
|
+
await accumulateKg(
|
|
19029
19335
|
extractEntities(redactedChunks.map((c) => c.text).join("\n"), { projectPath: item.projectPath || "", sourceType: item.sourceType, validFrom: item.mtime ? new Date(Number(item.mtime)).toISOString().slice(0, 10) : void 0 }),
|
|
19030
19336
|
null
|
|
19031
19337
|
);
|
|
@@ -19050,16 +19356,8 @@ async function syncToTarget(cred, opts = {}) {
|
|
|
19050
19356
|
}
|
|
19051
19357
|
}
|
|
19052
19358
|
}
|
|
19053
|
-
if (upload.sessionMeta &&
|
|
19054
|
-
const
|
|
19055
|
-
for (const t of kgRows) {
|
|
19056
|
-
const count = { redactions: 0 };
|
|
19057
|
-
await kgTripleBatch.add(redactDeep(t, count));
|
|
19058
|
-
redactions += count.redactions;
|
|
19059
|
-
entityNames.add(t.subject);
|
|
19060
|
-
entityNames.add(t.object);
|
|
19061
|
-
}
|
|
19062
|
-
for (const name of entityNames) {
|
|
19359
|
+
if (upload.sessionMeta && kgEntityNames.size > 0) {
|
|
19360
|
+
for (const name of kgEntityNames) {
|
|
19063
19361
|
const count = { redactions: 0 };
|
|
19064
19362
|
await kgEntityBatch.add(redactDeep({ name, type: kgEntityType.get(name) ?? "unknown", properties: {} }, count));
|
|
19065
19363
|
redactions += count.redactions;
|
|
@@ -19419,56 +19717,58 @@ function collectDerived(ref, mtime, count) {
|
|
|
19419
19717
|
const id = ref.prefixedId;
|
|
19420
19718
|
const compute = [];
|
|
19421
19719
|
let fullOutcome = null;
|
|
19422
|
-
|
|
19423
|
-
|
|
19424
|
-
|
|
19425
|
-
|
|
19426
|
-
|
|
19427
|
-
|
|
19428
|
-
|
|
19429
|
-
|
|
19430
|
-
|
|
19431
|
-
|
|
19432
|
-
if (
|
|
19433
|
-
|
|
19434
|
-
|
|
19435
|
-
|
|
19436
|
-
|
|
19437
|
-
|
|
19438
|
-
|
|
19439
|
-
|
|
19440
|
-
|
|
19720
|
+
return withSessionReadCache(() => {
|
|
19721
|
+
for (const kind of COMPUTE_KINDS) {
|
|
19722
|
+
let data = null;
|
|
19723
|
+
try {
|
|
19724
|
+
if (kind === "diff") {
|
|
19725
|
+
const replay = replaySessionAny(id);
|
|
19726
|
+
if (replay.found) data = replay;
|
|
19727
|
+
} else if (kind === "outcome") {
|
|
19728
|
+
fullOutcome = computeOutcome(id);
|
|
19729
|
+
if (fullOutcome.found) data = fullOutcome;
|
|
19730
|
+
} else if (kind === "commits") {
|
|
19731
|
+
if (!fullOutcome) fullOutcome = computeOutcome(id);
|
|
19732
|
+
if (fullOutcome.found) data = fullOutcome.commits;
|
|
19733
|
+
} else if (kind === "markers") {
|
|
19734
|
+
const turns = extractTurnsAny(id, { maxTurns: 5e4 });
|
|
19735
|
+
const prompts = turns.turns.filter((t) => t.kind === "user" && t.text).map((t) => ({ line: t.line, ts: t.ts, tsIso: t.tsIso, ...markPrompt(t.text) }));
|
|
19736
|
+
data = { sessionId: id, prompts, summary: summarizeMarkers(prompts) };
|
|
19737
|
+
}
|
|
19738
|
+
} catch {
|
|
19739
|
+
data = null;
|
|
19740
|
+
}
|
|
19741
|
+
if (data === null) continue;
|
|
19742
|
+
const redacted = redactDeep(data, count);
|
|
19743
|
+
if (JSON.stringify(redacted).length > MAX_DERIVED_ROW_BYTES) continue;
|
|
19744
|
+
compute.push({ kind, mtime, data: redacted });
|
|
19745
|
+
}
|
|
19746
|
+
let outcomeRow = null;
|
|
19747
|
+
if (fullOutcome?.found) {
|
|
19748
|
+
outcomeRow = {
|
|
19749
|
+
sessionId: id,
|
|
19750
|
+
tool: ref.toolId,
|
|
19751
|
+
status: fullOutcome.status,
|
|
19752
|
+
reason: fullOutcome.reason,
|
|
19753
|
+
fileMtime: mtime,
|
|
19754
|
+
fileSize: 0,
|
|
19755
|
+
contentHash: "",
|
|
19756
|
+
fileCount: fullOutcome.fileCount,
|
|
19757
|
+
linesAdded: fullOutcome.totalLinesAdded,
|
|
19758
|
+
linesRemoved: fullOutcome.totalLinesRemoved,
|
|
19759
|
+
commits: fullOutcome.commits?.totalCommits ?? 0,
|
|
19760
|
+
isFull: true,
|
|
19761
|
+
classifiedAt: Date.now(),
|
|
19762
|
+
lastScannedOffset: 0
|
|
19763
|
+
};
|
|
19441
19764
|
}
|
|
19442
|
-
|
|
19443
|
-
|
|
19444
|
-
|
|
19445
|
-
|
|
19446
|
-
|
|
19447
|
-
let outcomeRow = null;
|
|
19448
|
-
if (fullOutcome?.found) {
|
|
19449
|
-
outcomeRow = {
|
|
19450
|
-
sessionId: id,
|
|
19451
|
-
tool: ref.toolId,
|
|
19452
|
-
status: fullOutcome.status,
|
|
19453
|
-
reason: fullOutcome.reason,
|
|
19454
|
-
fileMtime: mtime,
|
|
19455
|
-
fileSize: 0,
|
|
19456
|
-
contentHash: "",
|
|
19457
|
-
fileCount: fullOutcome.fileCount,
|
|
19458
|
-
linesAdded: fullOutcome.totalLinesAdded,
|
|
19459
|
-
linesRemoved: fullOutcome.totalLinesRemoved,
|
|
19460
|
-
commits: fullOutcome.commits?.totalCommits ?? 0,
|
|
19461
|
-
isFull: true,
|
|
19462
|
-
classifiedAt: Date.now(),
|
|
19463
|
-
lastScannedOffset: 0
|
|
19765
|
+
return {
|
|
19766
|
+
session_id: id,
|
|
19767
|
+
mtime,
|
|
19768
|
+
compute,
|
|
19769
|
+
outcome_row: outcomeRow ? redactDeep({ ...outcomeRow, sessionId: void 0 }, count) : null
|
|
19464
19770
|
};
|
|
19465
|
-
}
|
|
19466
|
-
return {
|
|
19467
|
-
session_id: id,
|
|
19468
|
-
mtime,
|
|
19469
|
-
compute,
|
|
19470
|
-
outcome_row: outcomeRow ? redactDeep({ ...outcomeRow, sessionId: void 0 }, count) : null
|
|
19471
|
-
};
|
|
19771
|
+
});
|
|
19472
19772
|
}
|
|
19473
19773
|
function isSyncSkip(r) {
|
|
19474
19774
|
return typeof r.skipped === "string";
|
|
@@ -19497,10 +19797,11 @@ async function syncIncremental(opts = {}) {
|
|
|
19497
19797
|
lock.release();
|
|
19498
19798
|
}
|
|
19499
19799
|
}
|
|
19500
|
-
var ownVersion, credPath, _securityConfigCache, SECURITY_CONFIG_TTL_MS, _syncConfigCache, hashPath, COMPUTE_KINDS, MAX_DERIVED_ROW_BYTES, FULL_BUILD_MAX_BYTES, FULL_BUILD_TAIL_BYTES, BATCH_SCAN_MAX_BYTES;
|
|
19800
|
+
var ownVersion, credPath, _securityConfigCache, SECURITY_CONFIG_TTL_MS, _syncConfigCache, hashPath, COMPUTE_KINDS, MAX_DERIVED_ROW_BYTES, CAPS_TTL_MS, capsOk, FULL_BUILD_MAX_BYTES, FULL_BUILD_TAIL_BYTES, BATCH_SCAN_MAX_BYTES;
|
|
19501
19801
|
var init_sync_client = __esm({
|
|
19502
19802
|
"src/sync-client.ts"() {
|
|
19503
19803
|
"use strict";
|
|
19804
|
+
init_credentials_env();
|
|
19504
19805
|
init_secret_redactor();
|
|
19505
19806
|
init_source_discovery();
|
|
19506
19807
|
init_home_discovery();
|
|
@@ -19528,14 +19829,15 @@ var init_sync_client = __esm({
|
|
|
19528
19829
|
init_sync_fields();
|
|
19529
19830
|
init_index_lock();
|
|
19530
19831
|
init_http();
|
|
19832
|
+
init_live_session_scan();
|
|
19531
19833
|
init_backends();
|
|
19532
19834
|
ownVersion = "0.0.0";
|
|
19533
19835
|
try {
|
|
19534
19836
|
const dir = dirname16(fileURLToPath(import.meta.url));
|
|
19535
|
-
ownVersion = JSON.parse(
|
|
19837
|
+
ownVersion = JSON.parse(readFileSync32(join40(dir, "../package.json"), "utf-8")).version || ownVersion;
|
|
19536
19838
|
} catch {
|
|
19537
19839
|
try {
|
|
19538
|
-
if (true) ownVersion = "0.5.
|
|
19840
|
+
if (true) ownVersion = "0.5.6";
|
|
19539
19841
|
} catch {
|
|
19540
19842
|
}
|
|
19541
19843
|
}
|
|
@@ -19546,6 +19848,8 @@ var init_sync_client = __esm({
|
|
|
19546
19848
|
hashPath = (p) => p ? "p_" + createHash13("sha256").update(p).digest("hex").slice(0, 12) : "";
|
|
19547
19849
|
COMPUTE_KINDS = ["diff", "outcome", "commits", "markers"];
|
|
19548
19850
|
MAX_DERIVED_ROW_BYTES = 2 * 1024 * 1024;
|
|
19851
|
+
CAPS_TTL_MS = 60 * 6e4;
|
|
19852
|
+
capsOk = /* @__PURE__ */ new Map();
|
|
19549
19853
|
FULL_BUILD_MAX_BYTES = Math.max(8, parseInt(process.env.CHAT_RECALL_FULL_BUILD_MAX_MB || "64", 10)) * 1024 * 1024;
|
|
19550
19854
|
FULL_BUILD_TAIL_BYTES = 16 * 1024 * 1024;
|
|
19551
19855
|
BATCH_SCAN_MAX_BYTES = Math.max(1, parseInt(process.env.CHAT_RECALL_BATCHSCAN_MAX_MB || "64", 10)) * 1024 * 1024;
|
|
@@ -19559,11 +19863,11 @@ __export(update_notice_exports, {
|
|
|
19559
19863
|
refreshUpdateCheck: () => refreshUpdateCheck,
|
|
19560
19864
|
updateNotice: () => updateNotice
|
|
19561
19865
|
});
|
|
19562
|
-
import { readFileSync as
|
|
19866
|
+
import { readFileSync as readFileSync33, writeFileSync as writeFileSync9 } from "node:fs";
|
|
19563
19867
|
import { join as join41 } from "node:path";
|
|
19564
19868
|
function readCheck() {
|
|
19565
19869
|
try {
|
|
19566
|
-
const c = JSON.parse(
|
|
19870
|
+
const c = JSON.parse(readFileSync33(checkPath(), "utf-8"));
|
|
19567
19871
|
return c && typeof c.serverVersion === "string" ? c : null;
|
|
19568
19872
|
} catch {
|
|
19569
19873
|
return null;
|
|
@@ -19639,6 +19943,282 @@ var init_update_notice = __esm({
|
|
|
19639
19943
|
}
|
|
19640
19944
|
});
|
|
19641
19945
|
|
|
19946
|
+
// ../engine/dist/core/which.js
|
|
19947
|
+
import { existsSync as existsSync39, statSync as statSync36, accessSync, constants } from "node:fs";
|
|
19948
|
+
import { join as join42, isAbsolute as isAbsolute2, delimiter as delimiter2, sep as sep2 } from "node:path";
|
|
19949
|
+
function executable(p) {
|
|
19950
|
+
try {
|
|
19951
|
+
if (!statSync36(p).isFile())
|
|
19952
|
+
return false;
|
|
19953
|
+
} catch {
|
|
19954
|
+
return false;
|
|
19955
|
+
}
|
|
19956
|
+
if (isWindows)
|
|
19957
|
+
return true;
|
|
19958
|
+
try {
|
|
19959
|
+
accessSync(p, constants.X_OK);
|
|
19960
|
+
return true;
|
|
19961
|
+
} catch {
|
|
19962
|
+
return false;
|
|
19963
|
+
}
|
|
19964
|
+
}
|
|
19965
|
+
function candidates(name) {
|
|
19966
|
+
if (!isWindows)
|
|
19967
|
+
return [name];
|
|
19968
|
+
const exts = (process.env.PATHEXT || ".COM;.EXE;.BAT;.CMD").split(";").map((e) => e.trim()).filter(Boolean);
|
|
19969
|
+
if (exts.some((e) => name.toLowerCase().endsWith(e.toLowerCase())))
|
|
19970
|
+
return [name];
|
|
19971
|
+
return exts.map((e) => name + e);
|
|
19972
|
+
}
|
|
19973
|
+
function resolveOnPath(name) {
|
|
19974
|
+
if (!name)
|
|
19975
|
+
return null;
|
|
19976
|
+
if (name.includes("/") || isWindows && name.includes(sep2) || isAbsolute2(name)) {
|
|
19977
|
+
for (const c of candidates(name))
|
|
19978
|
+
if (executable(c))
|
|
19979
|
+
return c;
|
|
19980
|
+
return null;
|
|
19981
|
+
}
|
|
19982
|
+
for (const raw of (process.env.PATH || "").split(delimiter2)) {
|
|
19983
|
+
const dir = raw.replace(/^"(.*)"$/, "$1");
|
|
19984
|
+
if (!dir)
|
|
19985
|
+
continue;
|
|
19986
|
+
for (const c of candidates(name)) {
|
|
19987
|
+
const full = join42(dir, c);
|
|
19988
|
+
if (existsSync39(full) && executable(full))
|
|
19989
|
+
return full;
|
|
19990
|
+
}
|
|
19991
|
+
}
|
|
19992
|
+
return null;
|
|
19993
|
+
}
|
|
19994
|
+
function isOnPath(name) {
|
|
19995
|
+
return resolveOnPath(name) !== null;
|
|
19996
|
+
}
|
|
19997
|
+
var isWindows;
|
|
19998
|
+
var init_which = __esm({
|
|
19999
|
+
"../engine/dist/core/which.js"() {
|
|
20000
|
+
"use strict";
|
|
20001
|
+
isWindows = process.platform === "win32";
|
|
20002
|
+
}
|
|
20003
|
+
});
|
|
20004
|
+
|
|
20005
|
+
// ../engine/dist/core/mcp-clients.js
|
|
20006
|
+
var mcp_clients_exports = {};
|
|
20007
|
+
__export(mcp_clients_exports, {
|
|
20008
|
+
MCP_CLIENTS: () => MCP_CLIENTS,
|
|
20009
|
+
MCP_SERVER_NAME: () => MCP_SERVER_NAME,
|
|
20010
|
+
getMcpClient: () => getMcpClient,
|
|
20011
|
+
inspectMcpClients: () => inspectMcpClients,
|
|
20012
|
+
registerMcpEverywhere: () => registerMcpEverywhere
|
|
20013
|
+
});
|
|
20014
|
+
import { existsSync as existsSync40, mkdirSync as mkdirSync10, readFileSync as readFileSync35, writeFileSync as writeFileSync11 } from "fs";
|
|
20015
|
+
import { homedir as homedir15 } from "os";
|
|
20016
|
+
import { dirname as dirname18, join as join44 } from "path";
|
|
20017
|
+
function envHome(varName, fallback) {
|
|
20018
|
+
const v = process.env[varName];
|
|
20019
|
+
return v && v.trim() ? v.trim() : fallback;
|
|
20020
|
+
}
|
|
20021
|
+
function writeFileMkdir(path, body) {
|
|
20022
|
+
mkdirSync10(dirname18(path), { recursive: true });
|
|
20023
|
+
writeFileSync11(path, body);
|
|
20024
|
+
}
|
|
20025
|
+
function registerMcpServersJson(target, path, spec) {
|
|
20026
|
+
let cfg = {};
|
|
20027
|
+
if (existsSync40(path)) {
|
|
20028
|
+
try {
|
|
20029
|
+
cfg = JSON.parse(readFileSync35(path, "utf-8"));
|
|
20030
|
+
} catch (err) {
|
|
20031
|
+
return { id: target.id, label: target.label, path, state: "unparseable", error: String(err) };
|
|
20032
|
+
}
|
|
20033
|
+
}
|
|
20034
|
+
const servers = cfg.mcpServers || {};
|
|
20035
|
+
const existing = servers[MCP_SERVER_NAME];
|
|
20036
|
+
const entry = {
|
|
20037
|
+
command: spec.command,
|
|
20038
|
+
...spec.args ? { args: spec.args } : {}
|
|
20039
|
+
};
|
|
20040
|
+
if (spec.alwaysAllow)
|
|
20041
|
+
entry.alwaysAllow = existing?.alwaysAllow ?? spec.alwaysAllow;
|
|
20042
|
+
if (spec.env)
|
|
20043
|
+
entry.env = { ...existing?.env, ...spec.env };
|
|
20044
|
+
const isCurrent = !!existing && existing.command === spec.command && JSON.stringify(existing.args ?? null) === JSON.stringify(spec.args ?? null) && Object.entries(spec.env ?? {}).every(([k, v]) => existing.env?.[k] === v);
|
|
20045
|
+
if (isCurrent)
|
|
20046
|
+
return { id: target.id, label: target.label, path, state: "current" };
|
|
20047
|
+
servers[MCP_SERVER_NAME] = entry;
|
|
20048
|
+
cfg.mcpServers = servers;
|
|
20049
|
+
writeFileMkdir(path, JSON.stringify(cfg, null, 2) + "\n");
|
|
20050
|
+
return { id: target.id, label: target.label, path, state: existing ? "repaired" : "created" };
|
|
20051
|
+
}
|
|
20052
|
+
function registerOpencodeJson(path, spec) {
|
|
20053
|
+
const id = "opencode";
|
|
20054
|
+
const label = "OpenCode";
|
|
20055
|
+
let cfg = {};
|
|
20056
|
+
if (existsSync40(path)) {
|
|
20057
|
+
try {
|
|
20058
|
+
cfg = JSON.parse(readFileSync35(path, "utf-8"));
|
|
20059
|
+
} catch (err) {
|
|
20060
|
+
return { id, label, path, state: "unparseable", error: String(err) };
|
|
20061
|
+
}
|
|
20062
|
+
}
|
|
20063
|
+
if (!cfg.$schema)
|
|
20064
|
+
cfg.$schema = "https://opencode.ai/config.json";
|
|
20065
|
+
const mcp = cfg.mcp || {};
|
|
20066
|
+
const existing = mcp[MCP_SERVER_NAME];
|
|
20067
|
+
const argv = [spec.command, ...spec.args ?? []];
|
|
20068
|
+
const entry = { type: "local", command: argv, enabled: true };
|
|
20069
|
+
if (spec.env)
|
|
20070
|
+
entry.environment = { ...existing?.environment, ...spec.env };
|
|
20071
|
+
const isCurrent = !!existing && JSON.stringify(existing.command ?? null) === JSON.stringify(argv) && existing.enabled !== false && Object.entries(spec.env ?? {}).every(([k, v]) => existing.environment?.[k] === v);
|
|
20072
|
+
if (isCurrent)
|
|
20073
|
+
return { id, label, path, state: "current" };
|
|
20074
|
+
mcp[MCP_SERVER_NAME] = entry;
|
|
20075
|
+
cfg.mcp = mcp;
|
|
20076
|
+
writeFileMkdir(path, JSON.stringify(cfg, null, 2) + "\n");
|
|
20077
|
+
return { id, label, path, state: existing ? "repaired" : "created" };
|
|
20078
|
+
}
|
|
20079
|
+
function codexBlock(spec) {
|
|
20080
|
+
const lines = [CODEX_HEADER, `command = ${JSON.stringify(spec.command)}`];
|
|
20081
|
+
if (spec.args?.length)
|
|
20082
|
+
lines.push(`args = [${spec.args.map((a) => JSON.stringify(a)).join(", ")}]`);
|
|
20083
|
+
const env = Object.entries(spec.env ?? {});
|
|
20084
|
+
if (env.length) {
|
|
20085
|
+
lines.push(`[mcp_servers.${MCP_SERVER_NAME}.env]`);
|
|
20086
|
+
for (const [k, v] of env)
|
|
20087
|
+
lines.push(`${k} = ${JSON.stringify(v)}`);
|
|
20088
|
+
}
|
|
20089
|
+
return lines.join("\n") + "\n";
|
|
20090
|
+
}
|
|
20091
|
+
function registerCodexToml(path, spec) {
|
|
20092
|
+
const id = "codex";
|
|
20093
|
+
const label = "Codex";
|
|
20094
|
+
const block = codexBlock(spec);
|
|
20095
|
+
const prev = existsSync40(path) ? readFileSync35(path, "utf-8") : "";
|
|
20096
|
+
const lines = prev.length ? prev.split("\n") : [];
|
|
20097
|
+
const start = lines.findIndex((l) => l.trim() === CODEX_HEADER);
|
|
20098
|
+
if (start === -1) {
|
|
20099
|
+
const body = prev.length ? prev.replace(/\n*$/, "\n") + "\n" + block : block;
|
|
20100
|
+
writeFileMkdir(path, body);
|
|
20101
|
+
return { id, label, path, state: "created" };
|
|
20102
|
+
}
|
|
20103
|
+
let end = lines.length;
|
|
20104
|
+
for (let i = start + 1; i < lines.length; i++) {
|
|
20105
|
+
const t = lines[i].trim();
|
|
20106
|
+
if (!t.startsWith("["))
|
|
20107
|
+
continue;
|
|
20108
|
+
if (t.startsWith(`[mcp_servers.${MCP_SERVER_NAME}.`))
|
|
20109
|
+
continue;
|
|
20110
|
+
end = i;
|
|
20111
|
+
break;
|
|
20112
|
+
}
|
|
20113
|
+
const current = lines.slice(start, end).join("\n").replace(/\n*$/, "\n");
|
|
20114
|
+
if (current === block)
|
|
20115
|
+
return { id, label, path, state: "current" };
|
|
20116
|
+
const next = [...lines.slice(0, start), ...block.replace(/\n$/, "").split("\n"), ...lines.slice(end)];
|
|
20117
|
+
writeFileMkdir(path, next.join("\n").replace(/\n*$/, "\n"));
|
|
20118
|
+
return { id, label, path, state: "repaired" };
|
|
20119
|
+
}
|
|
20120
|
+
function getMcpClient(id) {
|
|
20121
|
+
const t = MCP_CLIENTS.find((c) => c.id === id);
|
|
20122
|
+
if (!t)
|
|
20123
|
+
throw new Error(`unknown MCP client: ${id}`);
|
|
20124
|
+
return t;
|
|
20125
|
+
}
|
|
20126
|
+
function registerMcpEverywhere(spec, opts = {}) {
|
|
20127
|
+
const home = opts.home ?? homedir15();
|
|
20128
|
+
const forced = new Set(opts.extraIds ?? []);
|
|
20129
|
+
return MCP_CLIENTS.filter((c) => c.isPresent(home) || forced.has(c.id)).map((c) => c.register(spec, home));
|
|
20130
|
+
}
|
|
20131
|
+
function inspectMcpClients(opts = {}) {
|
|
20132
|
+
const home = opts.home ?? homedir15();
|
|
20133
|
+
return MCP_CLIENTS.map((c) => {
|
|
20134
|
+
const path = c.configPath(home);
|
|
20135
|
+
let registered = false;
|
|
20136
|
+
if (existsSync40(path)) {
|
|
20137
|
+
try {
|
|
20138
|
+
const raw = readFileSync35(path, "utf-8");
|
|
20139
|
+
registered = c.id === "codex" ? raw.includes(CODEX_HEADER) : !!(JSON.parse(raw).mcpServers?.[MCP_SERVER_NAME] ?? JSON.parse(raw).mcp?.[MCP_SERVER_NAME]);
|
|
20140
|
+
} catch {
|
|
20141
|
+
registered = false;
|
|
20142
|
+
}
|
|
20143
|
+
}
|
|
20144
|
+
return { id: c.id, label: c.label, path, present: c.isPresent(home), registered };
|
|
20145
|
+
});
|
|
20146
|
+
}
|
|
20147
|
+
var MCP_SERVER_NAME, CODEX_HEADER, MCP_CLIENTS;
|
|
20148
|
+
var init_mcp_clients = __esm({
|
|
20149
|
+
"../engine/dist/core/mcp-clients.js"() {
|
|
20150
|
+
"use strict";
|
|
20151
|
+
MCP_SERVER_NAME = "chat-recall";
|
|
20152
|
+
CODEX_HEADER = `[mcp_servers.${MCP_SERVER_NAME}]`;
|
|
20153
|
+
MCP_CLIENTS = [
|
|
20154
|
+
{
|
|
20155
|
+
id: "claude",
|
|
20156
|
+
label: "Claude Code",
|
|
20157
|
+
bin: "claude",
|
|
20158
|
+
configPath: (home) => join44(home, ".mcp.json"),
|
|
20159
|
+
// Claude Code is the reference client and `init`'s historical target, so we
|
|
20160
|
+
// always write it — a fresh machine has no ~/.claude yet on first install.
|
|
20161
|
+
isPresent: () => true,
|
|
20162
|
+
register(spec, home) {
|
|
20163
|
+
return registerMcpServersJson(this, this.configPath(home), spec);
|
|
20164
|
+
}
|
|
20165
|
+
},
|
|
20166
|
+
{
|
|
20167
|
+
id: "codex",
|
|
20168
|
+
label: "Codex",
|
|
20169
|
+
bin: "codex",
|
|
20170
|
+
configPath: (home) => join44(envHome("CHAT_RECALL_CODEX_HOME", join44(home, ".codex")), "config.toml"),
|
|
20171
|
+
isPresent(home) {
|
|
20172
|
+
const p = this.configPath(home);
|
|
20173
|
+
return existsSync40(p) || existsSync40(dirname18(p));
|
|
20174
|
+
},
|
|
20175
|
+
register(spec, home) {
|
|
20176
|
+
return registerCodexToml(this.configPath(home), spec);
|
|
20177
|
+
}
|
|
20178
|
+
},
|
|
20179
|
+
{
|
|
20180
|
+
id: "gemini",
|
|
20181
|
+
label: "Gemini CLI",
|
|
20182
|
+
bin: "gemini",
|
|
20183
|
+
configPath: (home) => join44(envHome("CHAT_RECALL_GEMINI_HOME", join44(home, ".gemini")), "settings.json"),
|
|
20184
|
+
isPresent(home) {
|
|
20185
|
+
const p = this.configPath(home);
|
|
20186
|
+
return existsSync40(p) || existsSync40(dirname18(p));
|
|
20187
|
+
},
|
|
20188
|
+
register(spec, home) {
|
|
20189
|
+
return registerMcpServersJson(this, this.configPath(home), spec);
|
|
20190
|
+
}
|
|
20191
|
+
},
|
|
20192
|
+
{
|
|
20193
|
+
id: "opencode",
|
|
20194
|
+
label: "OpenCode",
|
|
20195
|
+
bin: "opencode",
|
|
20196
|
+
configPath: (home) => join44(envHome("XDG_CONFIG_HOME", join44(home, ".config")), "opencode", "opencode.json"),
|
|
20197
|
+
isPresent(home) {
|
|
20198
|
+
const p = this.configPath(home);
|
|
20199
|
+
return existsSync40(p) || existsSync40(dirname18(p));
|
|
20200
|
+
},
|
|
20201
|
+
register(spec, home) {
|
|
20202
|
+
return registerOpencodeJson(this.configPath(home), spec);
|
|
20203
|
+
}
|
|
20204
|
+
},
|
|
20205
|
+
{
|
|
20206
|
+
id: "cursor",
|
|
20207
|
+
label: "Cursor",
|
|
20208
|
+
bin: "cursor",
|
|
20209
|
+
configPath: (home) => join44(home, ".cursor", "mcp.json"),
|
|
20210
|
+
isPresent(home) {
|
|
20211
|
+
const p = this.configPath(home);
|
|
20212
|
+
return existsSync40(p) || existsSync40(dirname18(p));
|
|
20213
|
+
},
|
|
20214
|
+
register(spec, home) {
|
|
20215
|
+
return registerMcpServersJson(this, this.configPath(home), spec);
|
|
20216
|
+
}
|
|
20217
|
+
}
|
|
20218
|
+
];
|
|
20219
|
+
}
|
|
20220
|
+
});
|
|
20221
|
+
|
|
19642
20222
|
// ../engine/dist/core/companions.js
|
|
19643
20223
|
var companions_exports = {};
|
|
19644
20224
|
__export(companions_exports, {
|
|
@@ -19647,27 +20227,39 @@ __export(companions_exports, {
|
|
|
19647
20227
|
CODEINDEX_INSTALL_DIR: () => CODEINDEX_INSTALL_DIR,
|
|
19648
20228
|
checkCodeindexStatus: () => checkCodeindexStatus,
|
|
19649
20229
|
detectPlatform: () => detectPlatform,
|
|
20230
|
+
expectedCodeindexSha256: () => expectedCodeindexSha256,
|
|
19650
20231
|
installCodeindex: () => installCodeindex,
|
|
19651
20232
|
registerCodeindexMcp: () => registerCodeindexMcp,
|
|
19652
20233
|
uninstallCodeindex: () => uninstallCodeindex,
|
|
19653
20234
|
unregisterCodeindexMcp: () => unregisterCodeindexMcp
|
|
19654
20235
|
});
|
|
19655
|
-
import { existsSync as
|
|
19656
|
-
import { homedir as
|
|
19657
|
-
import { join as
|
|
20236
|
+
import { existsSync as existsSync41, mkdirSync as mkdirSync11, statSync as statSync37, chmodSync as chmodSync4, unlinkSync as unlinkSync3, renameSync as renameSync5, createWriteStream, readFileSync as readFileSync36, writeFileSync as writeFileSync12 } from "node:fs";
|
|
20237
|
+
import { homedir as homedir16 } from "node:os";
|
|
20238
|
+
import { join as join45 } from "node:path";
|
|
19658
20239
|
import { execSync as execSync3 } from "node:child_process";
|
|
20240
|
+
import { createHash as createHash14 } from "node:crypto";
|
|
20241
|
+
function expectedCodeindexSha256(artifact) {
|
|
20242
|
+
return CODEINDEX_SHA256[artifact.replace(/^codeindex-/, "").replace(/\.exe$/, "")] ?? null;
|
|
20243
|
+
}
|
|
19659
20244
|
function detectPlatform() {
|
|
19660
20245
|
const arch = process.arch;
|
|
19661
20246
|
const platform = process.platform;
|
|
19662
20247
|
const archMap = { x64: "x86_64", arm64: "aarch64" };
|
|
19663
|
-
const platformMap = { linux: "linux", darwin: "
|
|
20248
|
+
const platformMap = { linux: "linux", darwin: "macos", win32: "windows" };
|
|
19664
20249
|
const a = archMap[arch];
|
|
19665
20250
|
const p = platformMap[platform];
|
|
19666
20251
|
if (!a || !p) {
|
|
19667
20252
|
return { reason: `Unsupported platform: ${arch}-${platform}` };
|
|
19668
20253
|
}
|
|
19669
|
-
const prebuiltCombos = /* @__PURE__ */ new Set([
|
|
19670
|
-
|
|
20254
|
+
const prebuiltCombos = /* @__PURE__ */ new Set([
|
|
20255
|
+
"x86_64-linux",
|
|
20256
|
+
"aarch64-linux",
|
|
20257
|
+
"x86_64-macos",
|
|
20258
|
+
"aarch64-macos",
|
|
20259
|
+
"x86_64-windows",
|
|
20260
|
+
"aarch64-windows"
|
|
20261
|
+
]);
|
|
20262
|
+
const artifact = `codeindex-${a}-${p}${p === "windows" ? ".exe" : ""}`;
|
|
19671
20263
|
if (!prebuiltCombos.has(`${a}-${p}`)) {
|
|
19672
20264
|
return {
|
|
19673
20265
|
artifact,
|
|
@@ -19684,20 +20276,15 @@ function checkCodeindexStatus() {
|
|
|
19684
20276
|
artifactName: platform.artifact,
|
|
19685
20277
|
unsupportedReason: platform.reason
|
|
19686
20278
|
};
|
|
19687
|
-
let foundPath =
|
|
19688
|
-
|
|
19689
|
-
|
|
19690
|
-
if (out)
|
|
19691
|
-
foundPath = out;
|
|
19692
|
-
} catch {
|
|
20279
|
+
let foundPath = resolveOnPath(CODEINDEX_BIN_NAME);
|
|
20280
|
+
if (!foundPath) {
|
|
20281
|
+
foundPath = resolveOnPath(CODEINDEX_BIN_PATH);
|
|
19693
20282
|
}
|
|
19694
|
-
if (!foundPath && existsSync39(CODEINDEX_BIN_PATH))
|
|
19695
|
-
foundPath = CODEINDEX_BIN_PATH;
|
|
19696
20283
|
if (foundPath) {
|
|
19697
20284
|
status.installed = true;
|
|
19698
20285
|
status.path = foundPath;
|
|
19699
20286
|
try {
|
|
19700
|
-
status.size =
|
|
20287
|
+
status.size = statSync37(foundPath).size;
|
|
19701
20288
|
} catch {
|
|
19702
20289
|
}
|
|
19703
20290
|
try {
|
|
@@ -19709,16 +20296,9 @@ function checkCodeindexStatus() {
|
|
|
19709
20296
|
return status;
|
|
19710
20297
|
}
|
|
19711
20298
|
async function downloadArtifact(artifact, dest) {
|
|
19712
|
-
const hasGh = (
|
|
19713
|
-
try {
|
|
19714
|
-
execSync3("command -v gh", { stdio: "ignore" });
|
|
19715
|
-
return true;
|
|
19716
|
-
} catch {
|
|
19717
|
-
return false;
|
|
19718
|
-
}
|
|
19719
|
-
})();
|
|
20299
|
+
const hasGh = isOnPath("gh");
|
|
19720
20300
|
if (hasGh) {
|
|
19721
|
-
execSync3(`gh release download ${CODEINDEX_VERSION} --repo ${CODEINDEX_REPO} -p ${artifact} -O ${dest}`, {
|
|
20301
|
+
execSync3(`gh release download ${CODEINDEX_VERSION} --repo ${CODEINDEX_REPO} -p ${artifact} -O "${dest}"`, {
|
|
19722
20302
|
stdio: ["ignore", "pipe", "pipe"],
|
|
19723
20303
|
timeout: 6e4
|
|
19724
20304
|
});
|
|
@@ -19757,15 +20337,26 @@ async function installCodeindex(opts = {}) {
|
|
|
19757
20337
|
return status;
|
|
19758
20338
|
if (!status.prebuiltAvailable)
|
|
19759
20339
|
return status;
|
|
19760
|
-
|
|
20340
|
+
mkdirSync11(CODEINDEX_INSTALL_DIR, { recursive: true });
|
|
19761
20341
|
const tmpPath = `${CODEINDEX_BIN_PATH}.partial`;
|
|
19762
20342
|
try {
|
|
19763
20343
|
await downloadArtifact(status.artifactName, tmpPath);
|
|
20344
|
+
const expected = expectedCodeindexSha256(status.artifactName);
|
|
20345
|
+
if (!expected) {
|
|
20346
|
+
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.`);
|
|
20347
|
+
}
|
|
20348
|
+
const actual = createHash14("sha256").update(readFileSync36(tmpPath)).digest("hex");
|
|
20349
|
+
if (actual !== expected) {
|
|
20350
|
+
throw new Error(`Checksum mismatch for ${status.artifactName}.
|
|
20351
|
+
expected ${expected}
|
|
20352
|
+
actual ${actual}
|
|
20353
|
+
Refusing to install. The release may have been re-uploaded, or something is serving different bytes.`);
|
|
20354
|
+
}
|
|
19764
20355
|
chmodSync4(tmpPath, 493);
|
|
19765
20356
|
renameSync5(tmpPath, CODEINDEX_BIN_PATH);
|
|
19766
20357
|
} catch (err) {
|
|
19767
20358
|
try {
|
|
19768
|
-
if (
|
|
20359
|
+
if (existsSync41(tmpPath))
|
|
19769
20360
|
unlinkSync3(tmpPath);
|
|
19770
20361
|
} catch {
|
|
19771
20362
|
}
|
|
@@ -19774,7 +20365,7 @@ async function installCodeindex(opts = {}) {
|
|
|
19774
20365
|
return checkCodeindexStatus();
|
|
19775
20366
|
}
|
|
19776
20367
|
function uninstallCodeindex() {
|
|
19777
|
-
if (
|
|
20368
|
+
if (existsSync41(CODEINDEX_BIN_PATH)) {
|
|
19778
20369
|
unlinkSync3(CODEINDEX_BIN_PATH);
|
|
19779
20370
|
return { removed: true, path: CODEINDEX_BIN_PATH };
|
|
19780
20371
|
}
|
|
@@ -19782,9 +20373,9 @@ function uninstallCodeindex() {
|
|
|
19782
20373
|
}
|
|
19783
20374
|
function registerCodeindexMcp(mcpJsonPath, binaryPath) {
|
|
19784
20375
|
let cfg = {};
|
|
19785
|
-
if (
|
|
20376
|
+
if (existsSync41(mcpJsonPath)) {
|
|
19786
20377
|
try {
|
|
19787
|
-
cfg = JSON.parse(
|
|
20378
|
+
cfg = JSON.parse(readFileSync36(mcpJsonPath, "utf-8"));
|
|
19788
20379
|
} catch {
|
|
19789
20380
|
cfg = {};
|
|
19790
20381
|
}
|
|
@@ -19793,33 +20384,42 @@ function registerCodeindexMcp(mcpJsonPath, binaryPath) {
|
|
|
19793
20384
|
if (cfg.mcpServers["codeindex"])
|
|
19794
20385
|
return { added: false };
|
|
19795
20386
|
cfg.mcpServers["codeindex"] = { command: binaryPath, args: ["--mcp"] };
|
|
19796
|
-
|
|
20387
|
+
writeFileSync12(mcpJsonPath, JSON.stringify(cfg, null, 2));
|
|
19797
20388
|
return { added: true };
|
|
19798
20389
|
}
|
|
19799
20390
|
function unregisterCodeindexMcp(mcpJsonPath) {
|
|
19800
|
-
if (!
|
|
20391
|
+
if (!existsSync41(mcpJsonPath))
|
|
19801
20392
|
return { removed: false };
|
|
19802
20393
|
let cfg;
|
|
19803
20394
|
try {
|
|
19804
|
-
cfg = JSON.parse(
|
|
20395
|
+
cfg = JSON.parse(readFileSync36(mcpJsonPath, "utf-8"));
|
|
19805
20396
|
} catch {
|
|
19806
20397
|
return { removed: false };
|
|
19807
20398
|
}
|
|
19808
20399
|
if (!cfg.mcpServers?.["codeindex"])
|
|
19809
20400
|
return { removed: false };
|
|
19810
20401
|
delete cfg.mcpServers["codeindex"];
|
|
19811
|
-
|
|
20402
|
+
writeFileSync12(mcpJsonPath, JSON.stringify(cfg, null, 2));
|
|
19812
20403
|
return { removed: true };
|
|
19813
20404
|
}
|
|
19814
|
-
var CODEINDEX_REPO, CODEINDEX_VERSION, CODEINDEX_INSTALL_DIR, CODEINDEX_BIN_NAME, CODEINDEX_BIN_PATH;
|
|
20405
|
+
var CODEINDEX_REPO, CODEINDEX_VERSION, CODEINDEX_SHA256, CODEINDEX_INSTALL_DIR, CODEINDEX_BIN_NAME, CODEINDEX_BIN_PATH;
|
|
19815
20406
|
var init_companions = __esm({
|
|
19816
20407
|
"../engine/dist/core/companions.js"() {
|
|
19817
20408
|
"use strict";
|
|
20409
|
+
init_which();
|
|
19818
20410
|
CODEINDEX_REPO = "munhq/codeindex";
|
|
19819
|
-
CODEINDEX_VERSION = "v0.1
|
|
19820
|
-
|
|
19821
|
-
|
|
19822
|
-
|
|
20411
|
+
CODEINDEX_VERSION = "v0.3.1";
|
|
20412
|
+
CODEINDEX_SHA256 = {
|
|
20413
|
+
"x86_64-linux": "4378f12e7c80fa8bb53e41c02db4b95955f2f878369abfb28b5edd94b4adbb85",
|
|
20414
|
+
"aarch64-linux": "5a1d6c9c2592a3721547c42cd9b6b11f460e903bfc46407ae27d5879e7259587",
|
|
20415
|
+
"x86_64-macos": "6ad2a2b40faa4ec72ac35fee84f35ea7c848cddc4f6382b4cafedb644f30389f",
|
|
20416
|
+
"aarch64-macos": "f366d00918f79a4a0acc09c6091d97c6c378c79edbdbe3cb22e4014ea57f08d2",
|
|
20417
|
+
"x86_64-windows": "a96fc8c8949bb399a44cc0615b12e458460a529c69f01e8829cc39a20f45ab29",
|
|
20418
|
+
"aarch64-windows": "42620d56272cd9ba9d785569d8d754d6b4a3e80f36f28db3e0c483fd600ed117"
|
|
20419
|
+
};
|
|
20420
|
+
CODEINDEX_INSTALL_DIR = join45(homedir16(), ".local", "bin");
|
|
20421
|
+
CODEINDEX_BIN_NAME = process.platform === "win32" ? "codeindex.exe" : "codeindex";
|
|
20422
|
+
CODEINDEX_BIN_PATH = join45(CODEINDEX_INSTALL_DIR, CODEINDEX_BIN_NAME);
|
|
19823
20423
|
}
|
|
19824
20424
|
});
|
|
19825
20425
|
|
|
@@ -19834,26 +20434,26 @@ __export(install_skills_exports, {
|
|
|
19834
20434
|
skillsSourceDir: () => skillsSourceDir,
|
|
19835
20435
|
uninstallSkills: () => uninstallSkills
|
|
19836
20436
|
});
|
|
19837
|
-
import { readdirSync as readdirSync31, existsSync as
|
|
19838
|
-
import { createHash as
|
|
19839
|
-
import { join as
|
|
20437
|
+
import { readdirSync as readdirSync31, existsSync as existsSync42, mkdirSync as mkdirSync12, rmSync as rmSync6, cpSync, writeFileSync as writeFileSync13, readFileSync as readFileSync37, statSync as statSync38, realpathSync as realpathSync4 } from "fs";
|
|
20438
|
+
import { createHash as createHash15 } from "crypto";
|
|
20439
|
+
import { join as join46, basename as basename23 } from "path";
|
|
19840
20440
|
function skillsSourceDir() {
|
|
19841
|
-
return
|
|
20441
|
+
return join46(import.meta.dirname, "..", "skills");
|
|
19842
20442
|
}
|
|
19843
20443
|
function version() {
|
|
19844
20444
|
try {
|
|
19845
|
-
return JSON.parse(
|
|
20445
|
+
return JSON.parse(readFileSync37(new URL("../package.json", import.meta.url), "utf-8")).version || "0.0.0";
|
|
19846
20446
|
} catch {
|
|
19847
20447
|
return "0.0.0";
|
|
19848
20448
|
}
|
|
19849
20449
|
}
|
|
19850
20450
|
function skillsFingerprint() {
|
|
19851
20451
|
const src = skillsSourceDir();
|
|
19852
|
-
const h =
|
|
20452
|
+
const h = createHash15("sha256");
|
|
19853
20453
|
for (const name of bundledSkillNames()) {
|
|
19854
|
-
for (const rel of filesUnder(
|
|
20454
|
+
for (const rel of filesUnder(join46(src, name)).sort()) {
|
|
19855
20455
|
h.update(name + "/" + rel);
|
|
19856
|
-
h.update(
|
|
20456
|
+
h.update(readFileSync37(join46(src, name, rel)));
|
|
19857
20457
|
}
|
|
19858
20458
|
}
|
|
19859
20459
|
return h.digest("hex").slice(0, 12);
|
|
@@ -19863,7 +20463,7 @@ function filesUnder(dir, prefix = "") {
|
|
|
19863
20463
|
for (const e of readdirSync31(dir, { withFileTypes: true })) {
|
|
19864
20464
|
if (e.name === MARKER) continue;
|
|
19865
20465
|
const rel = prefix ? `${prefix}/${e.name}` : e.name;
|
|
19866
|
-
if (e.isDirectory()) out.push(...filesUnder(
|
|
20466
|
+
if (e.isDirectory()) out.push(...filesUnder(join46(dir, e.name), rel));
|
|
19867
20467
|
else out.push(rel);
|
|
19868
20468
|
}
|
|
19869
20469
|
return out;
|
|
@@ -19873,8 +20473,8 @@ function skillStamp() {
|
|
|
19873
20473
|
}
|
|
19874
20474
|
function bundledSkillNames() {
|
|
19875
20475
|
const src = skillsSourceDir();
|
|
19876
|
-
if (!
|
|
19877
|
-
return readdirSync31(src, { withFileTypes: true }).filter((e) => e.isDirectory() &&
|
|
20476
|
+
if (!existsSync42(src)) return [];
|
|
20477
|
+
return readdirSync31(src, { withFileTypes: true }).filter((e) => e.isDirectory() && existsSync42(join46(src, e.name, "SKILL.md"))).map((e) => e.name).sort();
|
|
19878
20478
|
}
|
|
19879
20479
|
function realPathOrSelf(p) {
|
|
19880
20480
|
try {
|
|
@@ -19887,7 +20487,7 @@ function claudeSkillTargets() {
|
|
|
19887
20487
|
const targets = [];
|
|
19888
20488
|
const seen = /* @__PURE__ */ new Set();
|
|
19889
20489
|
for (const home of claudeHomeDirs()) {
|
|
19890
|
-
const dir =
|
|
20490
|
+
const dir = join46(home, "skills");
|
|
19891
20491
|
const key = realPathOrSelf(dir);
|
|
19892
20492
|
if (seen.has(key)) continue;
|
|
19893
20493
|
seen.add(key);
|
|
@@ -19898,7 +20498,7 @@ function claudeSkillTargets() {
|
|
|
19898
20498
|
dir,
|
|
19899
20499
|
// Judge each profile on ITS OWN transcripts, not the primary's: a home
|
|
19900
20500
|
// with no projects/ is a directory someone made, not a Claude install.
|
|
19901
|
-
available:
|
|
20501
|
+
available: existsSync42(join46(home, "projects"))
|
|
19902
20502
|
});
|
|
19903
20503
|
}
|
|
19904
20504
|
if (targets.length === 0) {
|
|
@@ -19921,7 +20521,7 @@ function skillTargets() {
|
|
|
19921
20521
|
];
|
|
19922
20522
|
}
|
|
19923
20523
|
function isManaged(dir) {
|
|
19924
|
-
return
|
|
20524
|
+
return existsSync42(join46(dir, MARKER));
|
|
19925
20525
|
}
|
|
19926
20526
|
function installSkills(opts = {}) {
|
|
19927
20527
|
const onlyAvailable = opts.onlyAvailable ?? true;
|
|
@@ -19938,15 +20538,15 @@ function installSkills(opts = {}) {
|
|
|
19938
20538
|
continue;
|
|
19939
20539
|
}
|
|
19940
20540
|
for (const name of names) {
|
|
19941
|
-
const dest =
|
|
19942
|
-
if (
|
|
20541
|
+
const dest = join46(t.dir, name);
|
|
20542
|
+
if (existsSync42(dest) && !isManaged(dest)) {
|
|
19943
20543
|
skippedUserOwned.push(name);
|
|
19944
20544
|
continue;
|
|
19945
20545
|
}
|
|
19946
|
-
|
|
20546
|
+
mkdirSync12(t.dir, { recursive: true });
|
|
19947
20547
|
rmSync6(dest, { recursive: true, force: true });
|
|
19948
|
-
cpSync(
|
|
19949
|
-
|
|
20548
|
+
cpSync(join46(src, name), dest, { recursive: true });
|
|
20549
|
+
writeFileSync13(join46(dest, MARKER), `${stamp}
|
|
19950
20550
|
`);
|
|
19951
20551
|
installed.push(name);
|
|
19952
20552
|
}
|
|
@@ -19959,13 +20559,13 @@ function uninstallSkills() {
|
|
|
19959
20559
|
const perTarget = [];
|
|
19960
20560
|
for (const t of skillTargets()) {
|
|
19961
20561
|
const removed = [];
|
|
19962
|
-
if (!
|
|
20562
|
+
if (!existsSync42(t.dir)) {
|
|
19963
20563
|
perTarget.push({ id: t.id, label: t.label, removed });
|
|
19964
20564
|
continue;
|
|
19965
20565
|
}
|
|
19966
20566
|
for (const entry of readdirSync31(t.dir, { withFileTypes: true })) {
|
|
19967
20567
|
if (!entry.isDirectory()) continue;
|
|
19968
|
-
const dir =
|
|
20568
|
+
const dir = join46(t.dir, entry.name);
|
|
19969
20569
|
if (isManaged(dir) && (names.has(entry.name) || entry.name.startsWith("chat-recall"))) {
|
|
19970
20570
|
rmSync6(dir, { recursive: true, force: true });
|
|
19971
20571
|
removed.push(entry.name);
|
|
@@ -19982,10 +20582,10 @@ function skillsNeedRefresh() {
|
|
|
19982
20582
|
for (const t of skillTargets()) {
|
|
19983
20583
|
if (!t.available) continue;
|
|
19984
20584
|
for (const name of names) {
|
|
19985
|
-
const marker =
|
|
19986
|
-
if (!
|
|
20585
|
+
const marker = join46(t.dir, name, MARKER);
|
|
20586
|
+
if (!existsSync42(marker)) return true;
|
|
19987
20587
|
try {
|
|
19988
|
-
if (
|
|
20588
|
+
if (readFileSync37(marker, "utf-8").trim() !== cur) return true;
|
|
19989
20589
|
} catch {
|
|
19990
20590
|
return true;
|
|
19991
20591
|
}
|
|
@@ -20000,11 +20600,11 @@ function skillStatus() {
|
|
|
20000
20600
|
let installed = 0;
|
|
20001
20601
|
let ver = null;
|
|
20002
20602
|
for (const name of names) {
|
|
20003
|
-
const marker =
|
|
20004
|
-
if (
|
|
20603
|
+
const marker = join46(t.dir, name, MARKER);
|
|
20604
|
+
if (existsSync42(marker)) {
|
|
20005
20605
|
installed++;
|
|
20006
20606
|
try {
|
|
20007
|
-
ver =
|
|
20607
|
+
ver = readFileSync37(marker, "utf-8").trim();
|
|
20008
20608
|
} catch {
|
|
20009
20609
|
}
|
|
20010
20610
|
}
|
|
@@ -20033,7 +20633,7 @@ __export(repair_exports, {
|
|
|
20033
20633
|
repairSession: () => repairSession,
|
|
20034
20634
|
repairSessions: () => repairSessions
|
|
20035
20635
|
});
|
|
20036
|
-
import { createHash as
|
|
20636
|
+
import { createHash as createHash16 } from "node:crypto";
|
|
20037
20637
|
function resolveEndpoints(only) {
|
|
20038
20638
|
const settings2 = loadSettings();
|
|
20039
20639
|
const creds = loadAllCredentials();
|
|
@@ -20076,11 +20676,11 @@ async function repairSession(id, opts = {}) {
|
|
|
20076
20676
|
const log6 = (m) => {
|
|
20077
20677
|
if (opts.verbose) console.error(` [repair ${id}] ${m}`);
|
|
20078
20678
|
};
|
|
20079
|
-
const
|
|
20679
|
+
const candidates2 = [];
|
|
20080
20680
|
const localShadow = readShadowContainer(tool, rawId);
|
|
20081
20681
|
if (localShadow) {
|
|
20082
20682
|
try {
|
|
20083
|
-
|
|
20683
|
+
candidates2.push({ container: localShadow, messages: parseTranscriptFromContainer(localShadow).messages.length, source: "local-shadow" });
|
|
20084
20684
|
} catch {
|
|
20085
20685
|
}
|
|
20086
20686
|
}
|
|
@@ -20092,15 +20692,15 @@ async function repairSession(id, opts = {}) {
|
|
|
20092
20692
|
if (arch?.gzB64) {
|
|
20093
20693
|
try {
|
|
20094
20694
|
const container = gunzipContainer(Buffer.from(arch.gzB64, "base64"));
|
|
20095
|
-
if (container)
|
|
20695
|
+
if (container) candidates2.push({ container, messages: parseTranscriptFromContainer(container).messages.length, source: ep.url });
|
|
20096
20696
|
} catch {
|
|
20097
20697
|
}
|
|
20098
20698
|
}
|
|
20099
20699
|
}
|
|
20100
|
-
if (
|
|
20700
|
+
if (candidates2.length === 0) {
|
|
20101
20701
|
return { sessionId: id, status: "no-archive", fullestMessages: 0, fullestSource: "", pushed: [], note: "no shadow or server archive found" };
|
|
20102
20702
|
}
|
|
20103
|
-
const fullest =
|
|
20703
|
+
const fullest = candidates2.reduce((a, b) => b.messages > a.messages ? b : a);
|
|
20104
20704
|
log6(`fullest archive = ${fullest.messages} msg(s) from ${fullest.source}`);
|
|
20105
20705
|
if (opts.dryRun) {
|
|
20106
20706
|
const needy2 = endpoints.filter((ep) => (currentOnServer.get(ep.url) ?? 0) < fullest.messages || opts.force);
|
|
@@ -20202,7 +20802,7 @@ async function repairAll(opts = {}) {
|
|
|
20202
20802
|
if (!page?.hasMore || sessions.length === 0) break;
|
|
20203
20803
|
}
|
|
20204
20804
|
log6(`window=${sinceHours}h \u2192 ${ids.length} session(s) to check on ${primary.url}`);
|
|
20205
|
-
const
|
|
20805
|
+
const candidates2 = [];
|
|
20206
20806
|
let scanned = 0;
|
|
20207
20807
|
for (const id of ids) {
|
|
20208
20808
|
scanned++;
|
|
@@ -20215,9 +20815,9 @@ async function repairAll(opts = {}) {
|
|
|
20215
20815
|
if (archiveMsgs <= current) continue;
|
|
20216
20816
|
const r = await repairSession(id, { dryRun: !opts.apply, verbose: opts.verbose, server: opts.server });
|
|
20217
20817
|
if (r.status === "already-full") continue;
|
|
20218
|
-
|
|
20818
|
+
candidates2.push(r);
|
|
20219
20819
|
}
|
|
20220
|
-
return { scanned, candidates, discoveryServer: primary.url };
|
|
20820
|
+
return { scanned, candidates: candidates2, discoveryServer: primary.url };
|
|
20221
20821
|
}
|
|
20222
20822
|
var hashPath2;
|
|
20223
20823
|
var init_repair = __esm({
|
|
@@ -20229,7 +20829,7 @@ var init_repair = __esm({
|
|
|
20229
20829
|
init_http();
|
|
20230
20830
|
init_sync_client();
|
|
20231
20831
|
init_sync_client();
|
|
20232
|
-
hashPath2 = (p) => p ? "p_" +
|
|
20832
|
+
hashPath2 = (p) => p ? "p_" + createHash16("sha256").update(p).digest("hex").slice(0, 12) : "";
|
|
20233
20833
|
}
|
|
20234
20834
|
});
|
|
20235
20835
|
|
|
@@ -20449,11 +21049,11 @@ var verify_repair_exports = {};
|
|
|
20449
21049
|
__export(verify_repair_exports, {
|
|
20450
21050
|
forceFullResync: () => forceFullResync
|
|
20451
21051
|
});
|
|
20452
|
-
import { copyFileSync as copyFileSync3, existsSync as
|
|
21052
|
+
import { copyFileSync as copyFileSync3, existsSync as existsSync43 } from "fs";
|
|
20453
21053
|
function forceFullResync(server, sessionIds) {
|
|
20454
21054
|
if (sessionIds.length === 0) return 0;
|
|
20455
21055
|
const path = ledgerFilePath();
|
|
20456
|
-
if (
|
|
21056
|
+
if (existsSync43(path)) {
|
|
20457
21057
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "").replace(/-/g, "");
|
|
20458
21058
|
try {
|
|
20459
21059
|
copyFileSync3(path, `${path}.bak-${stamp}`);
|
|
@@ -20591,15 +21191,17 @@ var init_prompts = __esm({
|
|
|
20591
21191
|
var collector_exports = {};
|
|
20592
21192
|
__export(collector_exports, {
|
|
20593
21193
|
COLLECTOR_VERSION: () => COLLECTOR_VERSION,
|
|
21194
|
+
GENERATED_PATTERNS: () => GENERATED_PATTERNS,
|
|
20594
21195
|
collectCode: () => collectCode,
|
|
21196
|
+
isGenerated: () => isGenerated,
|
|
20595
21197
|
isJunkWorkspacePath: () => isJunkWorkspacePath,
|
|
20596
21198
|
isSecretRule: () => isSecretRule,
|
|
20597
21199
|
resolveCodeindexBin: () => resolveCodeindexBin
|
|
20598
21200
|
});
|
|
20599
21201
|
import { spawn } from "node:child_process";
|
|
20600
21202
|
import { execSync as execSync4 } from "node:child_process";
|
|
20601
|
-
import { readFileSync as
|
|
20602
|
-
import { join as
|
|
21203
|
+
import { readFileSync as readFileSync38 } from "node:fs";
|
|
21204
|
+
import { join as join47, basename as basename25 } from "node:path";
|
|
20603
21205
|
async function resolveCodeindexBin(autoInstall = true) {
|
|
20604
21206
|
let st = checkCodeindexStatus();
|
|
20605
21207
|
if (!st.installed && autoInstall)
|
|
@@ -20686,10 +21288,11 @@ function isSecretRule(rule) {
|
|
|
20686
21288
|
return /secret|password|credential|key|token|auth/i.test(rule);
|
|
20687
21289
|
}
|
|
20688
21290
|
function isJunkWorkspacePath(ws) {
|
|
20689
|
-
|
|
21291
|
+
const norm = ws.replace(/\\/g, "/");
|
|
21292
|
+
return /(^|\/)(scratchpad|\.cache|node_modules|\.git|tmp)(\/|$)|claude-1000/i.test(norm);
|
|
20690
21293
|
}
|
|
20691
21294
|
async function collectCode(opts) {
|
|
20692
|
-
const ws = opts.workspace.replace(
|
|
21295
|
+
const ws = opts.workspace.replace(/[/\\]+$/, "");
|
|
20693
21296
|
const log6 = opts.log ?? (() => {
|
|
20694
21297
|
});
|
|
20695
21298
|
if (isJunkWorkspacePath(ws)) {
|
|
@@ -20697,9 +21300,11 @@ async function collectCode(opts) {
|
|
|
20697
21300
|
}
|
|
20698
21301
|
const bin = opts.binPath ?? await resolveCodeindexBin(opts.autoInstall ?? true);
|
|
20699
21302
|
const projectId = resolveProjectId(ws).id || `path:${ws}`;
|
|
20700
|
-
const
|
|
21303
|
+
const wsNorm = ws.replace(/\\/g, "/");
|
|
21304
|
+
const wsPrefix = wsNorm + "/";
|
|
20701
21305
|
const rel = (p) => {
|
|
20702
|
-
|
|
21306
|
+
const n = p.replace(/\\/g, "/");
|
|
21307
|
+
let r = n.startsWith(wsPrefix) ? n.slice(wsPrefix.length) : n;
|
|
20703
21308
|
if (r.startsWith("./"))
|
|
20704
21309
|
r = r.slice(2);
|
|
20705
21310
|
return r;
|
|
@@ -20760,7 +21365,7 @@ async function collectCode(opts) {
|
|
|
20760
21365
|
}
|
|
20761
21366
|
const complexity = (r) => {
|
|
20762
21367
|
try {
|
|
20763
|
-
const txt =
|
|
21368
|
+
const txt = readFileSync38(join47(ws, r), "utf8");
|
|
20764
21369
|
if (txt.length > 2e6)
|
|
20765
21370
|
return 1;
|
|
20766
21371
|
const m = txt.match(CF_RE);
|
|
@@ -21344,7 +21949,7 @@ async function collectCode(opts) {
|
|
|
21344
21949
|
void health;
|
|
21345
21950
|
return { project, findings, hotspots, actions };
|
|
21346
21951
|
}
|
|
21347
|
-
var COLLECTOR_VERSION, ANALYSES, GENERATED, CF_RE, DEPTH, MCP_OUT_MAX_BYTES, call, COMMON_SYMBOL_NAMES;
|
|
21952
|
+
var COLLECTOR_VERSION, ANALYSES, GENERATED, CF_RE, DEPTH, MCP_OUT_MAX_BYTES, call, GENERATED_PATTERNS, COMMON_SYMBOL_NAMES;
|
|
21348
21953
|
var init_collector = __esm({
|
|
21349
21954
|
"../engine/dist/core/code/collector.js"() {
|
|
21350
21955
|
"use strict";
|
|
@@ -21386,7 +21991,13 @@ var init_collector = __esm({
|
|
|
21386
21991
|
"/vendor/",
|
|
21387
21992
|
"/third_party/",
|
|
21388
21993
|
"/site-packages/",
|
|
21994
|
+
// Lockfiles. '.lock' alone catches yarn.lock, Cargo.lock, poetry.lock and
|
|
21995
|
+
// composer.lock, and MISSES the two biggest ones in a JS repo —
|
|
21996
|
+
// package-lock.json and pnpm-lock.yaml are named '-lock.<ext>'. Found by
|
|
21997
|
+
// replacing this file's mirror test with one that calls the real predicate.
|
|
21389
21998
|
".lock",
|
|
21999
|
+
"-lock.json",
|
|
22000
|
+
"-lock.yaml",
|
|
21390
22001
|
"/dist/",
|
|
21391
22002
|
"/build/",
|
|
21392
22003
|
"/out/",
|
|
@@ -21403,6 +22014,7 @@ var init_collector = __esm({
|
|
|
21403
22014
|
DEPTH = 2;
|
|
21404
22015
|
MCP_OUT_MAX_BYTES = 64 * 1024 * 1024;
|
|
21405
22016
|
call = (id, name, args = {}) => ({ jsonrpc: "2.0", id, method: "tools/call", params: { name, arguments: args } });
|
|
22017
|
+
GENERATED_PATTERNS = GENERATED;
|
|
21406
22018
|
COMMON_SYMBOL_NAMES = /* @__PURE__ */ new Set([
|
|
21407
22019
|
"error",
|
|
21408
22020
|
"err",
|
|
@@ -21468,11 +22080,11 @@ var init_collector = __esm({
|
|
|
21468
22080
|
});
|
|
21469
22081
|
|
|
21470
22082
|
// ../engine/dist/core/artifact-codec.js
|
|
21471
|
-
import { readFileSync as
|
|
21472
|
-
import { join as
|
|
21473
|
-
import { homedir as
|
|
22083
|
+
import { readFileSync as readFileSync39 } from "fs";
|
|
22084
|
+
import { join as join48 } from "path";
|
|
22085
|
+
import { homedir as homedir17 } from "os";
|
|
21474
22086
|
function readCommand(filePath, format) {
|
|
21475
|
-
const content =
|
|
22087
|
+
const content = readFileSync39(filePath, "utf-8");
|
|
21476
22088
|
if (format === "toml") {
|
|
21477
22089
|
const t = parseScalarToml(content);
|
|
21478
22090
|
return { name: t.name || base(filePath), description: t.description || "", body: t.prompt || "" };
|
|
@@ -21481,7 +22093,7 @@ function readCommand(filePath, format) {
|
|
|
21481
22093
|
return { name: fm.name || base(filePath), description: fm.description || "", body: body.trim() };
|
|
21482
22094
|
}
|
|
21483
22095
|
function readAgent(filePath, format) {
|
|
21484
|
-
const content =
|
|
22096
|
+
const content = readFileSync39(filePath, "utf-8");
|
|
21485
22097
|
if (format === "toml") {
|
|
21486
22098
|
const t = parseScalarToml(content);
|
|
21487
22099
|
return {
|
|
@@ -21494,35 +22106,35 @@ function readAgent(filePath, format) {
|
|
|
21494
22106
|
return { name: fm.name || base(filePath), description: fm.description || "", tools: fm.tools, body: body.trim() };
|
|
21495
22107
|
}
|
|
21496
22108
|
function readInstructions(filePath, name) {
|
|
21497
|
-
const content =
|
|
22109
|
+
const content = readFileSync39(filePath, "utf-8");
|
|
21498
22110
|
return { name, description: "", body: content };
|
|
21499
22111
|
}
|
|
21500
22112
|
function commandPath(tool, name) {
|
|
21501
22113
|
switch (tool) {
|
|
21502
22114
|
case "claude":
|
|
21503
|
-
return
|
|
22115
|
+
return join48(claudeBackend.commandsDir(), `${name}.md`);
|
|
21504
22116
|
case "agy":
|
|
21505
|
-
return
|
|
22117
|
+
return join48(join48(agyBackend.homeDir(), "commands"), `${name}.toml`);
|
|
21506
22118
|
case "gemini":
|
|
21507
|
-
return
|
|
22119
|
+
return join48(geminiBackend.commandsDir(), `${name}.toml`);
|
|
21508
22120
|
case "opencode":
|
|
21509
|
-
return
|
|
22121
|
+
return join48(opencodeBackend.commandsDir(), `${name}.md`);
|
|
21510
22122
|
case "codex":
|
|
21511
|
-
return
|
|
22123
|
+
return join48(codexBackend.promptsDir(), `${name}.md`);
|
|
21512
22124
|
}
|
|
21513
22125
|
}
|
|
21514
22126
|
function agentPath(tool, name) {
|
|
21515
22127
|
switch (tool) {
|
|
21516
22128
|
case "claude":
|
|
21517
|
-
return
|
|
22129
|
+
return join48(claudeBackend.agentsDir(), `${name}.md`);
|
|
21518
22130
|
case "agy":
|
|
21519
|
-
return
|
|
22131
|
+
return join48(join48(agyBackend.homeDir(), "agents"), `${name}.md`);
|
|
21520
22132
|
case "gemini":
|
|
21521
|
-
return
|
|
22133
|
+
return join48(geminiBackend.agentsDir(), `${name}.md`);
|
|
21522
22134
|
case "opencode":
|
|
21523
|
-
return
|
|
22135
|
+
return join48(opencodeBackend.agentsDir(), `${name}.md`);
|
|
21524
22136
|
case "codex":
|
|
21525
|
-
return
|
|
22137
|
+
return join48(codexBackend.agentsDir(), `${name}.toml`);
|
|
21526
22138
|
}
|
|
21527
22139
|
}
|
|
21528
22140
|
function instructionsFilename(tool) {
|
|
@@ -21540,18 +22152,18 @@ function instructionsFilename(tool) {
|
|
|
21540
22152
|
function instructionsPath(tool, projectPath) {
|
|
21541
22153
|
const file = instructionsFilename(tool);
|
|
21542
22154
|
if (projectPath)
|
|
21543
|
-
return
|
|
22155
|
+
return join48(projectPath, file);
|
|
21544
22156
|
switch (tool) {
|
|
21545
22157
|
case "claude":
|
|
21546
|
-
return
|
|
22158
|
+
return join48(claudeBackend.homeDir(), file);
|
|
21547
22159
|
case "agy":
|
|
21548
|
-
return
|
|
22160
|
+
return join48(agyBackend.homeDir(), file);
|
|
21549
22161
|
case "gemini":
|
|
21550
|
-
return
|
|
22162
|
+
return join48(geminiBackend.homeDir(), file);
|
|
21551
22163
|
case "codex":
|
|
21552
|
-
return
|
|
22164
|
+
return join48(codexBackend.homeDir(), file);
|
|
21553
22165
|
case "opencode":
|
|
21554
|
-
return
|
|
22166
|
+
return join48(homedir17(), ".config", "opencode", file);
|
|
21555
22167
|
}
|
|
21556
22168
|
}
|
|
21557
22169
|
function emit(type, art, toTool, projectPath) {
|
|
@@ -21614,9 +22226,9 @@ __export(toolkit_sync_exports, {
|
|
|
21614
22226
|
supportedTargetsFor: () => supportedTargetsFor,
|
|
21615
22227
|
writeMcpEntry: () => writeMcpEntry
|
|
21616
22228
|
});
|
|
21617
|
-
import { existsSync as
|
|
21618
|
-
import { dirname as
|
|
21619
|
-
import { homedir as
|
|
22229
|
+
import { existsSync as existsSync44, mkdirSync as mkdirSync13, readFileSync as readFileSync40, writeFileSync as writeFileSync14, cpSync as cpSync2 } from "fs";
|
|
22230
|
+
import { dirname as dirname19, join as join49, basename as basename26 } from "path";
|
|
22231
|
+
import { homedir as homedir18 } from "os";
|
|
21620
22232
|
function supportedTargetsFor(type) {
|
|
21621
22233
|
return SUPPORTED_TARGETS[type];
|
|
21622
22234
|
}
|
|
@@ -21657,7 +22269,7 @@ function skillsDirFor(tool) {
|
|
|
21657
22269
|
case "claude":
|
|
21658
22270
|
return claudeBackend.skillsDir();
|
|
21659
22271
|
case "agy":
|
|
21660
|
-
return
|
|
22272
|
+
return join49(agyBackend.homeDir(), "skills");
|
|
21661
22273
|
case "gemini":
|
|
21662
22274
|
return geminiBackend.skillsDir();
|
|
21663
22275
|
case "opencode":
|
|
@@ -21667,15 +22279,15 @@ function skillsDirFor(tool) {
|
|
|
21667
22279
|
}
|
|
21668
22280
|
}
|
|
21669
22281
|
function copySkill(row, toTool) {
|
|
21670
|
-
const skillDir = row.extra.skillDir ||
|
|
21671
|
-
if (!
|
|
22282
|
+
const skillDir = row.extra.skillDir || dirname19(row.filePath);
|
|
22283
|
+
if (!existsSync44(skillDir))
|
|
21672
22284
|
return { ok: false, status: 404, error: `Source dir missing: ${skillDir}` };
|
|
21673
22285
|
const name = row.extra.skillName || basename26(skillDir);
|
|
21674
|
-
const targetDir =
|
|
21675
|
-
if (
|
|
22286
|
+
const targetDir = join49(skillsDirFor(toTool), name);
|
|
22287
|
+
if (existsSync44(targetDir))
|
|
21676
22288
|
return { ok: false, status: 409, error: `Already exists: ${targetDir}` };
|
|
21677
22289
|
try {
|
|
21678
|
-
|
|
22290
|
+
mkdirSync13(dirname19(targetDir), { recursive: true });
|
|
21679
22291
|
cpSync2(skillDir, targetDir, { recursive: true });
|
|
21680
22292
|
return { ok: true, targetPath: targetDir };
|
|
21681
22293
|
} catch (e) {
|
|
@@ -21683,29 +22295,29 @@ function copySkill(row, toTool) {
|
|
|
21683
22295
|
}
|
|
21684
22296
|
}
|
|
21685
22297
|
function readMcpEntry(tool, name) {
|
|
21686
|
-
const home =
|
|
22298
|
+
const home = homedir18();
|
|
21687
22299
|
const tries = [];
|
|
21688
22300
|
if (tool === "claude") {
|
|
21689
|
-
tries.push({ path:
|
|
21690
|
-
tries.push({ path:
|
|
22301
|
+
tries.push({ path: join49(home, ".mcp.json"), key: "mcpServers" });
|
|
22302
|
+
tries.push({ path: join49(home, ".claude.json"), key: "mcpServers" });
|
|
21691
22303
|
} else if (tool === "gemini") {
|
|
21692
|
-
tries.push({ path:
|
|
22304
|
+
tries.push({ path: join49(home, ".gemini", "settings.json"), key: "mcpServers" });
|
|
21693
22305
|
} else if (tool === "agy") {
|
|
21694
|
-
tries.push({ path:
|
|
22306
|
+
tries.push({ path: join49(home, ".gemini", "config", "mcp_config.json"), key: "mcpServers" });
|
|
21695
22307
|
} else if (tool === "opencode") {
|
|
21696
|
-
tries.push({ path:
|
|
21697
|
-
tries.push({ path:
|
|
21698
|
-
tries.push({ path:
|
|
22308
|
+
tries.push({ path: join49(home, ".config", "opencode", "opencode.json"), key: "mcp" });
|
|
22309
|
+
tries.push({ path: join49(home, ".config", "opencode", "config.json"), key: "mcp" });
|
|
22310
|
+
tries.push({ path: join49(home, ".opencode", "config.json"), key: "mcp" });
|
|
21699
22311
|
} else if (tool === "codex") {
|
|
21700
|
-
const entry = readCodexMcpEntry(
|
|
22312
|
+
const entry = readCodexMcpEntry(join49(home, ".codex", "config.toml"), name);
|
|
21701
22313
|
if (entry)
|
|
21702
22314
|
return entry;
|
|
21703
22315
|
}
|
|
21704
22316
|
for (const t of tries) {
|
|
21705
|
-
if (!
|
|
22317
|
+
if (!existsSync44(t.path))
|
|
21706
22318
|
continue;
|
|
21707
22319
|
try {
|
|
21708
|
-
const cfg = JSON.parse(
|
|
22320
|
+
const cfg = JSON.parse(readFileSync40(t.path, "utf-8"));
|
|
21709
22321
|
const block = cfg[t.key] || {};
|
|
21710
22322
|
if (block[name])
|
|
21711
22323
|
return block[name];
|
|
@@ -21715,11 +22327,11 @@ function readMcpEntry(tool, name) {
|
|
|
21715
22327
|
return null;
|
|
21716
22328
|
}
|
|
21717
22329
|
function readCodexMcpEntry(path, target) {
|
|
21718
|
-
if (!
|
|
22330
|
+
if (!existsSync44(path))
|
|
21719
22331
|
return null;
|
|
21720
22332
|
let content;
|
|
21721
22333
|
try {
|
|
21722
|
-
content =
|
|
22334
|
+
content = readFileSync40(path, "utf-8");
|
|
21723
22335
|
} catch {
|
|
21724
22336
|
return null;
|
|
21725
22337
|
}
|
|
@@ -21769,8 +22381,8 @@ function readCodexMcpEntry(path, target) {
|
|
|
21769
22381
|
}
|
|
21770
22382
|
function writeCodexMcpEntry(path, name, entry) {
|
|
21771
22383
|
let content = "";
|
|
21772
|
-
if (
|
|
21773
|
-
content =
|
|
22384
|
+
if (existsSync44(path))
|
|
22385
|
+
content = readFileSync40(path, "utf-8");
|
|
21774
22386
|
const header = `[mcp_servers.${name}]`;
|
|
21775
22387
|
if (content.includes(header))
|
|
21776
22388
|
return false;
|
|
@@ -21799,14 +22411,14 @@ function writeCodexMcpEntry(path, name, entry) {
|
|
|
21799
22411
|
for (const [k, v] of Object.entries(entry.env))
|
|
21800
22412
|
lines.push(`${k} = ${escape(String(v))}`);
|
|
21801
22413
|
}
|
|
21802
|
-
|
|
21803
|
-
|
|
22414
|
+
mkdirSync13(dirname19(path), { recursive: true });
|
|
22415
|
+
writeFileSync14(path, content + lines.join("\n") + "\n");
|
|
21804
22416
|
return true;
|
|
21805
22417
|
}
|
|
21806
22418
|
function writeMcpEntry(toTool, name, entry) {
|
|
21807
|
-
const home =
|
|
22419
|
+
const home = homedir18();
|
|
21808
22420
|
if (toTool === "codex") {
|
|
21809
|
-
const path2 =
|
|
22421
|
+
const path2 = join49(home, ".codex", "config.toml");
|
|
21810
22422
|
if (!writeCodexMcpEntry(path2, name, entry))
|
|
21811
22423
|
return { ok: false, status: 409, error: `MCP "${name}" already exists in ${path2}.` };
|
|
21812
22424
|
return { ok: true, targetPath: path2 };
|
|
@@ -21814,27 +22426,27 @@ function writeMcpEntry(toTool, name, entry) {
|
|
|
21814
22426
|
let path;
|
|
21815
22427
|
let key;
|
|
21816
22428
|
if (toTool === "claude") {
|
|
21817
|
-
path =
|
|
22429
|
+
path = join49(home, ".mcp.json");
|
|
21818
22430
|
key = "mcpServers";
|
|
21819
22431
|
} else if (toTool === "gemini") {
|
|
21820
|
-
path =
|
|
22432
|
+
path = join49(home, ".gemini", "settings.json");
|
|
21821
22433
|
key = "mcpServers";
|
|
21822
22434
|
} else if (toTool === "agy") {
|
|
21823
|
-
path =
|
|
22435
|
+
path = join49(home, ".gemini", "config", "mcp_config.json");
|
|
21824
22436
|
key = "mcpServers";
|
|
21825
22437
|
} else {
|
|
21826
|
-
path =
|
|
22438
|
+
path = join49(home, ".config", "opencode", "opencode.json");
|
|
21827
22439
|
key = "mcp";
|
|
21828
22440
|
}
|
|
21829
22441
|
let cfg = {};
|
|
21830
|
-
if (
|
|
22442
|
+
if (existsSync44(path)) {
|
|
21831
22443
|
try {
|
|
21832
|
-
cfg = JSON.parse(
|
|
22444
|
+
cfg = JSON.parse(readFileSync40(path, "utf-8"));
|
|
21833
22445
|
} catch {
|
|
21834
22446
|
return { ok: false, status: 500, error: `Target config is malformed: ${path}` };
|
|
21835
22447
|
}
|
|
21836
22448
|
} else {
|
|
21837
|
-
|
|
22449
|
+
mkdirSync13(dirname19(path), { recursive: true });
|
|
21838
22450
|
}
|
|
21839
22451
|
cfg[key] = cfg[key] || {};
|
|
21840
22452
|
if (cfg[key][name])
|
|
@@ -21861,7 +22473,7 @@ function writeMcpEntry(toTool, name, entry) {
|
|
|
21861
22473
|
}
|
|
21862
22474
|
cfg[key][name] = normalized;
|
|
21863
22475
|
try {
|
|
21864
|
-
|
|
22476
|
+
writeFileSync14(path, JSON.stringify(cfg, null, 2));
|
|
21865
22477
|
return { ok: true, targetPath: path };
|
|
21866
22478
|
} catch (e) {
|
|
21867
22479
|
return { ok: false, status: 500, error: e instanceof Error ? e.message : "write failed" };
|
|
@@ -21891,11 +22503,11 @@ function copyCommandOrAgent(type, row, toTool) {
|
|
|
21891
22503
|
return { ok: false, status: 404, error: `Source unreadable: ${e instanceof Error ? e.message : "failed"}` };
|
|
21892
22504
|
}
|
|
21893
22505
|
const out = emit(type, art, toTool);
|
|
21894
|
-
if (
|
|
22506
|
+
if (existsSync44(out.path))
|
|
21895
22507
|
return { ok: false, status: 409, error: `Already exists: ${out.path}` };
|
|
21896
22508
|
try {
|
|
21897
|
-
|
|
21898
|
-
|
|
22509
|
+
mkdirSync13(dirname19(out.path), { recursive: true });
|
|
22510
|
+
writeFileSync14(out.path, out.content);
|
|
21899
22511
|
return { ok: true, targetPath: out.path };
|
|
21900
22512
|
} catch (e) {
|
|
21901
22513
|
return { ok: false, status: 500, error: e instanceof Error ? e.message : "write failed" };
|
|
@@ -21911,11 +22523,11 @@ function copyInstructions(row, toTool) {
|
|
|
21911
22523
|
return { ok: false, status: 404, error: `Source unreadable: ${e instanceof Error ? e.message : "failed"}` };
|
|
21912
22524
|
}
|
|
21913
22525
|
const out = emit("instructions", art, toTool, row.projectPath || void 0);
|
|
21914
|
-
if (
|
|
22526
|
+
if (existsSync44(out.path))
|
|
21915
22527
|
return { ok: false, status: 409, error: `Already exists: ${out.path}` };
|
|
21916
22528
|
try {
|
|
21917
|
-
|
|
21918
|
-
|
|
22529
|
+
mkdirSync13(dirname19(out.path), { recursive: true });
|
|
22530
|
+
writeFileSync14(out.path, out.content);
|
|
21919
22531
|
return { ok: true, targetPath: out.path };
|
|
21920
22532
|
} catch (e) {
|
|
21921
22533
|
return { ok: false, status: 500, error: e instanceof Error ? e.message : "write failed" };
|
|
@@ -22087,9 +22699,9 @@ __export(project_tasks_exports, {
|
|
|
22087
22699
|
pushProjectTaskStatuses: () => pushProjectTaskStatuses,
|
|
22088
22700
|
renderTeamTasksMd: () => renderTeamTasksMd
|
|
22089
22701
|
});
|
|
22090
|
-
import { existsSync as
|
|
22091
|
-
import { join as
|
|
22092
|
-
import { homedir as
|
|
22702
|
+
import { existsSync as existsSync45, readFileSync as readFileSync41, writeFileSync as writeFileSync15, mkdirSync as mkdirSync14, statSync as statSync39 } from "node:fs";
|
|
22703
|
+
import { join as join50, dirname as dirname20 } from "node:path";
|
|
22704
|
+
import { homedir as homedir19 } from "node:os";
|
|
22093
22705
|
function isTeamTaskStatus(v) {
|
|
22094
22706
|
return !!v && TEAM_STATUSES.has(v);
|
|
22095
22707
|
}
|
|
@@ -22104,7 +22716,7 @@ function reconcile(kind, was, token, checked) {
|
|
|
22104
22716
|
const done = kind === "secret" ? "rotated" : "done";
|
|
22105
22717
|
if (token && token !== was) return token;
|
|
22106
22718
|
if (kind === "team") {
|
|
22107
|
-
if (checked && was
|
|
22719
|
+
if (checked && was === "todo") return "in_progress";
|
|
22108
22720
|
if (!checked && was === "done") return "todo";
|
|
22109
22721
|
return token ?? was;
|
|
22110
22722
|
}
|
|
@@ -22139,22 +22751,22 @@ function parseTaskFile(content) {
|
|
|
22139
22751
|
return out;
|
|
22140
22752
|
}
|
|
22141
22753
|
function ledgerPath2() {
|
|
22142
|
-
return
|
|
22754
|
+
return join50(homedir19(), ".chat-recall", "project-tasks-ledger.json");
|
|
22143
22755
|
}
|
|
22144
22756
|
function readLedger() {
|
|
22145
22757
|
try {
|
|
22146
|
-
return JSON.parse(
|
|
22758
|
+
return JSON.parse(readFileSync41(ledgerPath2(), "utf8"));
|
|
22147
22759
|
} catch {
|
|
22148
22760
|
return {};
|
|
22149
22761
|
}
|
|
22150
22762
|
}
|
|
22151
22763
|
function writeLedger(l) {
|
|
22152
22764
|
try {
|
|
22153
|
-
|
|
22765
|
+
mkdirSync14(dirname20(ledgerPath2()), { recursive: true });
|
|
22154
22766
|
} catch {
|
|
22155
22767
|
}
|
|
22156
22768
|
try {
|
|
22157
|
-
|
|
22769
|
+
writeFileSync15(ledgerPath2(), JSON.stringify(l));
|
|
22158
22770
|
} catch {
|
|
22159
22771
|
}
|
|
22160
22772
|
}
|
|
@@ -22172,18 +22784,18 @@ async function pushProjectTaskStatuses(base2, authHeaders, opts = {}) {
|
|
|
22172
22784
|
continue;
|
|
22173
22785
|
}
|
|
22174
22786
|
for (const project of projects) {
|
|
22175
|
-
const file =
|
|
22176
|
-
if (!
|
|
22787
|
+
const file = join50(project, fk.filename);
|
|
22788
|
+
if (!existsSync45(file)) continue;
|
|
22177
22789
|
let mtime;
|
|
22178
22790
|
try {
|
|
22179
|
-
mtime =
|
|
22791
|
+
mtime = statSync39(file).mtimeMs;
|
|
22180
22792
|
} catch {
|
|
22181
22793
|
continue;
|
|
22182
22794
|
}
|
|
22183
22795
|
if (ledger[file] === mtime) continue;
|
|
22184
22796
|
let changed;
|
|
22185
22797
|
try {
|
|
22186
|
-
changed = parseTaskFile(
|
|
22798
|
+
changed = parseTaskFile(readFileSync41(file, "utf8")).filter((t) => t.kind === fk.kind);
|
|
22187
22799
|
} catch {
|
|
22188
22800
|
continue;
|
|
22189
22801
|
}
|
|
@@ -22216,7 +22828,8 @@ function renderTeamTasksMd(tasks2) {
|
|
|
22216
22828
|
"# Team tasks",
|
|
22217
22829
|
"",
|
|
22218
22830
|
"<!-- Managed by chat-recall. Tick a box or edit the `status:` token, then run",
|
|
22219
|
-
" `chat-recall tasks push`. Statuses: todo \xB7 in_progress \xB7
|
|
22831
|
+
" `chat-recall tasks push`. Statuses: todo \xB7 in_progress \xB7 done \xB7 rejected.",
|
|
22832
|
+
" A tick claims a task; only the session that does the work can close it. -->",
|
|
22220
22833
|
""
|
|
22221
22834
|
];
|
|
22222
22835
|
if (tasks2.length === 0) lines.push("_No tasks assigned to you here._");
|
|
@@ -22236,7 +22849,7 @@ var init_project_tasks = __esm({
|
|
|
22236
22849
|
init_http();
|
|
22237
22850
|
init_secret_task_status();
|
|
22238
22851
|
init_code_task_status();
|
|
22239
|
-
TEAM_STATUSES = /* @__PURE__ */ new Set(["todo", "in_progress", "
|
|
22852
|
+
TEAM_STATUSES = /* @__PURE__ */ new Set(["todo", "in_progress", "done", "rejected"]);
|
|
22240
22853
|
ANCHOR_RE = /<!--\s*cr-(secret|task)\b(?:\s+kind=([a-z]+))?\s+id=([A-Za-z0-9_-]+)(?:\s+was=([a-z_-]+))?\s*-->/;
|
|
22241
22854
|
CHECKBOX_RE = /^\s*-\s*\[([ xX])\]/;
|
|
22242
22855
|
STATUS_TOKEN_RE = /status:\s*`?([a-z_-]+)`?/i;
|
|
@@ -22252,18 +22865,18 @@ var intent_drain_exports = {};
|
|
|
22252
22865
|
__export(intent_drain_exports, {
|
|
22253
22866
|
drainSyncIntents: () => drainSyncIntents
|
|
22254
22867
|
});
|
|
22255
|
-
import { existsSync as
|
|
22256
|
-
import { join as
|
|
22257
|
-
import { homedir as
|
|
22868
|
+
import { existsSync as existsSync46, readFileSync as readFileSync42, writeFileSync as writeFileSync16, appendFileSync, mkdirSync as mkdirSync15 } from "node:fs";
|
|
22869
|
+
import { join as join51 } from "node:path";
|
|
22870
|
+
import { homedir as homedir20 } from "node:os";
|
|
22258
22871
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
22259
|
-
import { dirname as
|
|
22872
|
+
import { dirname as dirname21 } from "node:path";
|
|
22260
22873
|
function applyCodeRecommendation(intent) {
|
|
22261
22874
|
try {
|
|
22262
22875
|
const meta = JSON.parse(intent.name || "{}");
|
|
22263
22876
|
if (intent.artifact_type === "write_tasks_file") {
|
|
22264
22877
|
if (!meta.rootPath || !meta.content) return { status: "error", result: JSON.stringify({ error: "missing rootPath or content" }) };
|
|
22265
|
-
const file =
|
|
22266
|
-
|
|
22878
|
+
const file = join51(meta.rootPath, meta.filename || "CODE_TASKS.md");
|
|
22879
|
+
writeFileSync16(file, meta.content);
|
|
22267
22880
|
return { status: "done", result: JSON.stringify({ wrote: file }) };
|
|
22268
22881
|
}
|
|
22269
22882
|
if (intent.artifact_type === "append_claude_md") {
|
|
@@ -22272,24 +22885,24 @@ function applyCodeRecommendation(intent) {
|
|
|
22272
22885
|
if (!text) return { status: "error", result: JSON.stringify({ error: "missing text" }) };
|
|
22273
22886
|
let file;
|
|
22274
22887
|
if (isGlobal) {
|
|
22275
|
-
const dir =
|
|
22888
|
+
const dir = join51(homedir20(), ".claude");
|
|
22276
22889
|
try {
|
|
22277
|
-
|
|
22890
|
+
mkdirSync15(dir, { recursive: true });
|
|
22278
22891
|
} catch {
|
|
22279
22892
|
}
|
|
22280
|
-
file =
|
|
22893
|
+
file = join51(dir, "CLAUDE.md");
|
|
22281
22894
|
} else {
|
|
22282
22895
|
if (!meta.rootPath) return { status: "error", result: JSON.stringify({ error: "missing rootPath" }) };
|
|
22283
|
-
file =
|
|
22896
|
+
file = join51(meta.rootPath, "CLAUDE.md");
|
|
22284
22897
|
}
|
|
22285
|
-
const existing =
|
|
22898
|
+
const existing = existsSync46(file) ? readFileSync42(file, "utf8") : "";
|
|
22286
22899
|
if (existing.includes(text)) return { status: "done", result: JSON.stringify({ skipped: "rule already present", file }) };
|
|
22287
22900
|
const block = `${existing && !existing.endsWith("\n") ? "\n" : ""}
|
|
22288
22901
|
## Rule (added by chat-recall recommendation)
|
|
22289
22902
|
${text}
|
|
22290
22903
|
`;
|
|
22291
22904
|
if (existing) appendFileSync(file, block);
|
|
22292
|
-
else
|
|
22905
|
+
else writeFileSync16(file, `# ${meta.rootPath?.split("/").pop() || "Global"} instructions
|
|
22293
22906
|
${block}`);
|
|
22294
22907
|
return { status: "done", result: JSON.stringify({ appended: file }) };
|
|
22295
22908
|
}
|
|
@@ -22388,11 +23001,11 @@ var init_intent_drain = __esm({
|
|
|
22388
23001
|
init_project_tasks();
|
|
22389
23002
|
ownVersion2 = "0.0.0";
|
|
22390
23003
|
try {
|
|
22391
|
-
const dir =
|
|
22392
|
-
ownVersion2 = JSON.parse(
|
|
23004
|
+
const dir = dirname21(fileURLToPath2(import.meta.url));
|
|
23005
|
+
ownVersion2 = JSON.parse(readFileSync42(join51(dir, "../package.json"), "utf-8")).version || ownVersion2;
|
|
22393
23006
|
} catch {
|
|
22394
23007
|
try {
|
|
22395
|
-
if (true) ownVersion2 = "0.5.
|
|
23008
|
+
if (true) ownVersion2 = "0.5.6";
|
|
22396
23009
|
} catch {
|
|
22397
23010
|
}
|
|
22398
23011
|
}
|
|
@@ -22593,43 +23206,43 @@ var team_merge_exports = {};
|
|
|
22593
23206
|
__export(team_merge_exports, {
|
|
22594
23207
|
mergePullResult: () => mergePullResult
|
|
22595
23208
|
});
|
|
22596
|
-
import { existsSync as
|
|
22597
|
-
import { dirname as
|
|
22598
|
-
import { createHash as
|
|
23209
|
+
import { existsSync as existsSync47, mkdirSync as mkdirSync16, readFileSync as readFileSync43, rmSync as rmSync7, writeFileSync as writeFileSync17, statSync as statSync40 } from "fs";
|
|
23210
|
+
import { dirname as dirname22, join as join52 } from "path";
|
|
23211
|
+
import { createHash as createHash17 } from "crypto";
|
|
22599
23212
|
function installPathFor(art, tool) {
|
|
22600
23213
|
switch (art.type) {
|
|
22601
23214
|
case "skill":
|
|
22602
23215
|
switch (tool) {
|
|
22603
23216
|
case "claude":
|
|
22604
|
-
return
|
|
23217
|
+
return join52(claudeBackend.skillsDir(), art.name, "SKILL.md");
|
|
22605
23218
|
case "agy":
|
|
22606
23219
|
case "gemini":
|
|
22607
|
-
return
|
|
23220
|
+
return join52(geminiBackend.skillsDir(), art.name, "SKILL.md");
|
|
22608
23221
|
case "opencode":
|
|
22609
|
-
return
|
|
23222
|
+
return join52(opencodeBackend.skillsDir(), art.name, "SKILL.md");
|
|
22610
23223
|
// User skills go to ~/.codex/skills (NOT .system, which is OpenAI's bundle).
|
|
22611
23224
|
case "codex":
|
|
22612
|
-
return
|
|
23225
|
+
return join52(codexBackend.skillsDir(), art.name, "SKILL.md");
|
|
22613
23226
|
}
|
|
22614
23227
|
break;
|
|
22615
23228
|
case "agent":
|
|
22616
23229
|
if (tool === "claude")
|
|
22617
|
-
return
|
|
23230
|
+
return join52(claudeBackend.agentsDir(), `${art.name}.md`);
|
|
22618
23231
|
return null;
|
|
22619
23232
|
case "command":
|
|
22620
23233
|
if (tool === "claude")
|
|
22621
|
-
return
|
|
23234
|
+
return join52(claudeBackend.commandsDir(), `${art.name}.md`);
|
|
22622
23235
|
return null;
|
|
22623
23236
|
case "hook":
|
|
22624
23237
|
if (tool === "claude")
|
|
22625
|
-
return
|
|
23238
|
+
return join52(claudeBackend.homeDir(), "chat-recall-hooks", `${art.name}.json`);
|
|
22626
23239
|
return null;
|
|
22627
23240
|
case "plan":
|
|
22628
23241
|
switch (tool) {
|
|
22629
23242
|
case "claude":
|
|
22630
|
-
return
|
|
23243
|
+
return join52(claudeBackend.plansDir(), `${art.name}.md`);
|
|
22631
23244
|
case "opencode":
|
|
22632
|
-
return
|
|
23245
|
+
return join52(opencodeBackend.plansDir(), `${art.name}.md`);
|
|
22633
23246
|
case "agy":
|
|
22634
23247
|
case "gemini":
|
|
22635
23248
|
return null;
|
|
@@ -22639,11 +23252,11 @@ function installPathFor(art, tool) {
|
|
|
22639
23252
|
}
|
|
22640
23253
|
break;
|
|
22641
23254
|
case "instructions":
|
|
22642
|
-
return
|
|
23255
|
+
return join52(getDataDir(), "team-instructions", tool, `${art.name}.md`);
|
|
22643
23256
|
case "mcp":
|
|
22644
|
-
return
|
|
23257
|
+
return join52(getDataDir(), "team-mcps", `${art.name}.json`);
|
|
22645
23258
|
case "plugin":
|
|
22646
|
-
return
|
|
23259
|
+
return join52(getDataDir(), "team-plugins", tool, art.name, "manifest.json");
|
|
22647
23260
|
}
|
|
22648
23261
|
return null;
|
|
22649
23262
|
}
|
|
@@ -22669,20 +23282,20 @@ async function mergePullResult(opts) {
|
|
|
22669
23282
|
continue;
|
|
22670
23283
|
}
|
|
22671
23284
|
const body = Buffer.from(a.bodyB64, "base64");
|
|
22672
|
-
const sha =
|
|
23285
|
+
const sha = createHash17("sha256").update(body).digest("hex");
|
|
22673
23286
|
for (const tool of targets) {
|
|
22674
23287
|
const path = installPathFor(a, tool);
|
|
22675
23288
|
if (!path)
|
|
22676
23289
|
continue;
|
|
22677
23290
|
try {
|
|
22678
23291
|
const existing = readFileIfExists(path);
|
|
22679
|
-
if (existing &&
|
|
23292
|
+
if (existing && createHash17("sha256").update(existing).digest("hex") === sha) {
|
|
22680
23293
|
report.skipped.push({ artifactId: a.id, path, reason: "unchanged" });
|
|
22681
23294
|
pending.push({ artifactId: a.id, tool, artifactType: a.type, artifactName: a.name, sha256: sha, installedAt: Date.now() });
|
|
22682
23295
|
continue;
|
|
22683
23296
|
}
|
|
22684
|
-
|
|
22685
|
-
|
|
23297
|
+
mkdirSync16(dirname22(path), { recursive: true });
|
|
23298
|
+
writeFileSync17(path, body);
|
|
22686
23299
|
pending.push({ artifactId: a.id, tool, artifactType: a.type, artifactName: a.name, sha256: sha, installedAt: Date.now() });
|
|
22687
23300
|
report.written.push({ artifactId: a.id, path });
|
|
22688
23301
|
} catch (err) {
|
|
@@ -22703,7 +23316,7 @@ async function mergePullResult(opts) {
|
|
|
22703
23316
|
if (!path)
|
|
22704
23317
|
continue;
|
|
22705
23318
|
try {
|
|
22706
|
-
if (
|
|
23319
|
+
if (existsSync47(path))
|
|
22707
23320
|
rmSync7(path, { force: true });
|
|
22708
23321
|
await teamInstallsForget(id, row.tool);
|
|
22709
23322
|
report.removed.push({ artifactId: id, path });
|
|
@@ -22721,12 +23334,12 @@ async function mergePullResult(opts) {
|
|
|
22721
23334
|
}
|
|
22722
23335
|
function readFileIfExists(path) {
|
|
22723
23336
|
try {
|
|
22724
|
-
if (!
|
|
23337
|
+
if (!existsSync47(path))
|
|
22725
23338
|
return null;
|
|
22726
|
-
const s =
|
|
23339
|
+
const s = statSync40(path);
|
|
22727
23340
|
if (!s.isFile())
|
|
22728
23341
|
return null;
|
|
22729
|
-
return
|
|
23342
|
+
return readFileSync43(path);
|
|
22730
23343
|
} catch {
|
|
22731
23344
|
return null;
|
|
22732
23345
|
}
|
|
@@ -22805,8 +23418,8 @@ var init_vault_crypto = __esm({
|
|
|
22805
23418
|
});
|
|
22806
23419
|
|
|
22807
23420
|
// ../engine/dist/core/vault-source.js
|
|
22808
|
-
import { existsSync as
|
|
22809
|
-
import { extname, join as
|
|
23421
|
+
import { existsSync as existsSync48, readdirSync as readdirSync32, statSync as statSync41 } from "fs";
|
|
23422
|
+
import { extname, join as join53 } from "path";
|
|
22810
23423
|
function* walkVaultSources() {
|
|
22811
23424
|
const t = loadSettings().team.vault;
|
|
22812
23425
|
const include2 = new Set(t.syncTools);
|
|
@@ -22821,7 +23434,7 @@ function* walkVaultSources() {
|
|
|
22821
23434
|
}
|
|
22822
23435
|
function safeStat(path) {
|
|
22823
23436
|
try {
|
|
22824
|
-
const s =
|
|
23437
|
+
const s = statSync41(path);
|
|
22825
23438
|
if (!s.isFile())
|
|
22826
23439
|
return null;
|
|
22827
23440
|
return { mtimeMs: s.mtimeMs, size: s.size };
|
|
@@ -22831,7 +23444,7 @@ function safeStat(path) {
|
|
|
22831
23444
|
}
|
|
22832
23445
|
function* walkClaude() {
|
|
22833
23446
|
const root = claudeBackend.projectsDir();
|
|
22834
|
-
if (!
|
|
23447
|
+
if (!existsSync48(root))
|
|
22835
23448
|
return;
|
|
22836
23449
|
let projectDirs = [];
|
|
22837
23450
|
try {
|
|
@@ -22842,8 +23455,8 @@ function* walkClaude() {
|
|
|
22842
23455
|
for (const proj of projectDirs) {
|
|
22843
23456
|
if (proj.startsWith("."))
|
|
22844
23457
|
continue;
|
|
22845
|
-
const projectPath =
|
|
22846
|
-
const projDir =
|
|
23458
|
+
const projectPath = decodeProjectDirName(proj);
|
|
23459
|
+
const projDir = join53(root, proj);
|
|
22847
23460
|
let entries = [];
|
|
22848
23461
|
try {
|
|
22849
23462
|
entries = readdirSync32(projDir);
|
|
@@ -22853,7 +23466,7 @@ function* walkClaude() {
|
|
|
22853
23466
|
for (const f of entries) {
|
|
22854
23467
|
if (extname(f) !== ".jsonl")
|
|
22855
23468
|
continue;
|
|
22856
|
-
const path =
|
|
23469
|
+
const path = join53(projDir, f);
|
|
22857
23470
|
const s = safeStat(path);
|
|
22858
23471
|
if (!s)
|
|
22859
23472
|
continue;
|
|
@@ -22864,7 +23477,7 @@ function* walkClaude() {
|
|
|
22864
23477
|
}
|
|
22865
23478
|
function* walkGemini() {
|
|
22866
23479
|
const tmp = geminiBackend.tmpDir();
|
|
22867
|
-
if (!
|
|
23480
|
+
if (!existsSync48(tmp))
|
|
22868
23481
|
return;
|
|
22869
23482
|
let hashDirs = [];
|
|
22870
23483
|
try {
|
|
@@ -22873,8 +23486,8 @@ function* walkGemini() {
|
|
|
22873
23486
|
return;
|
|
22874
23487
|
}
|
|
22875
23488
|
for (const hash of hashDirs) {
|
|
22876
|
-
const chatsDir =
|
|
22877
|
-
if (!
|
|
23489
|
+
const chatsDir = join53(tmp, hash, "chats");
|
|
23490
|
+
if (!existsSync48(chatsDir))
|
|
22878
23491
|
continue;
|
|
22879
23492
|
let entries = [];
|
|
22880
23493
|
try {
|
|
@@ -22886,7 +23499,7 @@ function* walkGemini() {
|
|
|
22886
23499
|
const ext = extname(f);
|
|
22887
23500
|
if (ext !== ".json" && ext !== ".jsonl")
|
|
22888
23501
|
continue;
|
|
22889
|
-
const path =
|
|
23502
|
+
const path = join53(chatsDir, f);
|
|
22890
23503
|
const s = safeStat(path);
|
|
22891
23504
|
if (!s)
|
|
22892
23505
|
continue;
|
|
@@ -22896,8 +23509,8 @@ function* walkGemini() {
|
|
|
22896
23509
|
}
|
|
22897
23510
|
}
|
|
22898
23511
|
function* walkCodex() {
|
|
22899
|
-
const sessionsRoot =
|
|
22900
|
-
if (!
|
|
23512
|
+
const sessionsRoot = join53(codexBackend.homeDir(), "sessions");
|
|
23513
|
+
if (!existsSync48(sessionsRoot))
|
|
22901
23514
|
return;
|
|
22902
23515
|
const stack = [sessionsRoot];
|
|
22903
23516
|
while (stack.length) {
|
|
@@ -22909,7 +23522,7 @@ function* walkCodex() {
|
|
|
22909
23522
|
continue;
|
|
22910
23523
|
}
|
|
22911
23524
|
for (const e of entries) {
|
|
22912
|
-
const path =
|
|
23525
|
+
const path = join53(dir, e.name);
|
|
22913
23526
|
if (e.isDirectory()) {
|
|
22914
23527
|
stack.push(path);
|
|
22915
23528
|
continue;
|
|
@@ -22925,8 +23538,8 @@ function* walkCodex() {
|
|
|
22925
23538
|
}
|
|
22926
23539
|
}
|
|
22927
23540
|
function* walkAgy() {
|
|
22928
|
-
const brainDir =
|
|
22929
|
-
if (!
|
|
23541
|
+
const brainDir = join53(agyBackend.homeDir(), "brain");
|
|
23542
|
+
if (!existsSync48(brainDir))
|
|
22930
23543
|
return;
|
|
22931
23544
|
let sessionDirs = [];
|
|
22932
23545
|
try {
|
|
@@ -22935,18 +23548,18 @@ function* walkAgy() {
|
|
|
22935
23548
|
return;
|
|
22936
23549
|
}
|
|
22937
23550
|
for (const rawId of sessionDirs) {
|
|
22938
|
-
const sessionPath =
|
|
23551
|
+
const sessionPath = join53(brainDir, rawId);
|
|
22939
23552
|
try {
|
|
22940
|
-
if (!
|
|
23553
|
+
if (!statSync41(sessionPath).isDirectory())
|
|
22941
23554
|
continue;
|
|
22942
23555
|
} catch {
|
|
22943
23556
|
continue;
|
|
22944
23557
|
}
|
|
22945
|
-
let filePath =
|
|
22946
|
-
if (!
|
|
22947
|
-
filePath =
|
|
23558
|
+
let filePath = join53(sessionPath, ".system_generated", "logs", "transcript.jsonl");
|
|
23559
|
+
if (!existsSync48(filePath)) {
|
|
23560
|
+
filePath = join53(sessionPath, ".system_generated", "logs", "transcript_full.jsonl");
|
|
22948
23561
|
}
|
|
22949
|
-
if (!
|
|
23562
|
+
if (!existsSync48(filePath))
|
|
22950
23563
|
continue;
|
|
22951
23564
|
const s = safeStat(filePath);
|
|
22952
23565
|
if (!s)
|
|
@@ -22963,6 +23576,7 @@ var init_vault_source = __esm({
|
|
|
22963
23576
|
init_codex2();
|
|
22964
23577
|
init_agy();
|
|
22965
23578
|
init_settings();
|
|
23579
|
+
init_project_dir_name();
|
|
22966
23580
|
}
|
|
22967
23581
|
});
|
|
22968
23582
|
|
|
@@ -22979,8 +23593,8 @@ __export(vault_client_exports, {
|
|
|
22979
23593
|
vaultStatus: () => vaultStatus,
|
|
22980
23594
|
vaultSync: () => vaultSync
|
|
22981
23595
|
});
|
|
22982
|
-
import { mkdirSync as
|
|
22983
|
-
import { dirname as
|
|
23596
|
+
import { mkdirSync as mkdirSync17, readFileSync as readFileSync44, writeFileSync as writeFileSync18, existsSync as existsSync49 } from "fs";
|
|
23597
|
+
import { dirname as dirname23, join as join54 } from "path";
|
|
22984
23598
|
function context2() {
|
|
22985
23599
|
const s = loadSettings().team;
|
|
22986
23600
|
if (!s.enabled)
|
|
@@ -23119,7 +23733,7 @@ async function vaultSync(passphrase) {
|
|
|
23119
23733
|
continue;
|
|
23120
23734
|
}
|
|
23121
23735
|
try {
|
|
23122
|
-
const plaintext =
|
|
23736
|
+
const plaintext = readFileSync44(src.path);
|
|
23123
23737
|
const sourceSha = sha256Hex(plaintext);
|
|
23124
23738
|
const priorSha = uploaded.get(uploadKey(src.sessionId, src.tool));
|
|
23125
23739
|
if (priorSha === sourceSha) {
|
|
@@ -23171,7 +23785,7 @@ async function vaultSync(passphrase) {
|
|
|
23171
23785
|
}
|
|
23172
23786
|
function importedPathFor(tool, sessionId) {
|
|
23173
23787
|
const base2 = sessionId.replace(/^gemini_/, "").replace(/^codex_/, "").replace(/^opencode_/, "");
|
|
23174
|
-
return
|
|
23788
|
+
return join54(IMPORTED_ROOT(), tool, `${base2}.jsonl`);
|
|
23175
23789
|
}
|
|
23176
23790
|
async function vaultRestore(passphrase, opts = {}) {
|
|
23177
23791
|
const ctx = context2();
|
|
@@ -23192,7 +23806,7 @@ async function vaultRestore(passphrase, opts = {}) {
|
|
|
23192
23806
|
}
|
|
23193
23807
|
try {
|
|
23194
23808
|
const path = importedPathFor(blob.tool, blob.sessionId);
|
|
23195
|
-
if (
|
|
23809
|
+
if (existsSync49(path)) {
|
|
23196
23810
|
const localStat = await import("fs").then((m) => m.statSync(path));
|
|
23197
23811
|
if (Math.abs(localStat.mtimeMs - blob.mtimeSourceMs) < 1) {
|
|
23198
23812
|
report.skipped.push({ sessionId: blob.sessionId, tool: blob.tool, reason: "unchanged" });
|
|
@@ -23208,8 +23822,8 @@ async function vaultRestore(passphrase, opts = {}) {
|
|
|
23208
23822
|
throw new Error("cipher integrity check failed");
|
|
23209
23823
|
}
|
|
23210
23824
|
const plaintext = decryptBlob(key, cipher);
|
|
23211
|
-
|
|
23212
|
-
|
|
23825
|
+
mkdirSync17(dirname23(path), { recursive: true });
|
|
23826
|
+
writeFileSync18(path, Buffer.from(plaintext));
|
|
23213
23827
|
const { utimesSync } = await import("fs");
|
|
23214
23828
|
const t = blob.mtimeSourceMs / 1e3;
|
|
23215
23829
|
utimesSync(path, t, t);
|
|
@@ -23260,7 +23874,7 @@ var init_vault_client = __esm({
|
|
|
23260
23874
|
uploadKey = (sessionId, tool) => `${sessionId}\0${tool}`;
|
|
23261
23875
|
VaultPassphraseMismatchError = class extends Error {
|
|
23262
23876
|
};
|
|
23263
|
-
IMPORTED_ROOT = () =>
|
|
23877
|
+
IMPORTED_ROOT = () => join54(getDataDir(), "imported");
|
|
23264
23878
|
}
|
|
23265
23879
|
});
|
|
23266
23880
|
|
|
@@ -23414,15 +24028,15 @@ __export(service_installer_exports, {
|
|
|
23414
24028
|
uninstallService: () => uninstallService
|
|
23415
24029
|
});
|
|
23416
24030
|
import { execSync as execSync5 } from "child_process";
|
|
23417
|
-
import { existsSync as
|
|
23418
|
-
import { homedir as
|
|
23419
|
-
import { join as
|
|
24031
|
+
import { existsSync as existsSync50, mkdirSync as mkdirSync18, rmSync as rmSync8, writeFileSync as writeFileSync19 } from "fs";
|
|
24032
|
+
import { homedir as homedir21 } from "os";
|
|
24033
|
+
import { join as join55 } from "path";
|
|
23420
24034
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
23421
24035
|
function resolveDaemonPaths() {
|
|
23422
24036
|
const watchJs = fileURLToPath3(new URL("./watch.js", import.meta.url));
|
|
23423
24037
|
const node = process.execPath;
|
|
23424
|
-
const dataDir =
|
|
23425
|
-
const logFile =
|
|
24038
|
+
const dataDir = join55(homedir21(), ".chat-recall");
|
|
24039
|
+
const logFile = join55(dataDir, "watch.log");
|
|
23426
24040
|
return { watchJs, node, logFile, dataDir };
|
|
23427
24041
|
}
|
|
23428
24042
|
function tryCmd(cmd) {
|
|
@@ -23447,7 +24061,7 @@ function isServiceRunning() {
|
|
|
23447
24061
|
}
|
|
23448
24062
|
function installService() {
|
|
23449
24063
|
const { watchJs, node, logFile, dataDir } = resolveDaemonPaths();
|
|
23450
|
-
|
|
24064
|
+
mkdirSync18(dataDir, { recursive: true });
|
|
23451
24065
|
if (process.platform === "linux") {
|
|
23452
24066
|
return installSystemd(watchJs, node, logFile);
|
|
23453
24067
|
}
|
|
@@ -23463,11 +24077,11 @@ function installService() {
|
|
|
23463
24077
|
);
|
|
23464
24078
|
}
|
|
23465
24079
|
function installSystemd(watchJs, node, logFile) {
|
|
23466
|
-
const unitDir =
|
|
23467
|
-
const unitPath =
|
|
24080
|
+
const unitDir = join55(homedir21(), ".config", "systemd", "user");
|
|
24081
|
+
const unitPath = join55(unitDir, "chat-recall-watch.service");
|
|
23468
24082
|
const unit = renderSystemdUnit(watchJs, node, logFile);
|
|
23469
|
-
|
|
23470
|
-
|
|
24083
|
+
mkdirSync18(unitDir, { recursive: true });
|
|
24084
|
+
writeFileSync19(unitPath, unit);
|
|
23471
24085
|
try {
|
|
23472
24086
|
execSync5("systemctl --user daemon-reload && systemctl --user enable chat-recall-watch.service && systemctl --user restart chat-recall-watch.service", { stdio: "inherit" });
|
|
23473
24087
|
try {
|
|
@@ -23495,10 +24109,14 @@ function renderSystemdUnit(watchJs, node, logFile) {
|
|
|
23495
24109
|
"Restart=on-failure",
|
|
23496
24110
|
"RestartSec=10",
|
|
23497
24111
|
"Nice=10",
|
|
23498
|
-
//
|
|
23499
|
-
//
|
|
23500
|
-
|
|
23501
|
-
|
|
24112
|
+
// JOURNAL, not append:. The file version had no rotation and nothing to
|
|
24113
|
+
// give it any: systemd holds the fd open, so the daemon cannot rename or
|
|
24114
|
+
// truncate its own log without leaving systemd writing into a hole. It
|
|
24115
|
+
// reached 45 MB on this developer's machine and would have grown forever.
|
|
24116
|
+
// journald already rotates and applies disk limits. Read it with
|
|
24117
|
+
// journalctl --user -u chat-recall-watch -f
|
|
24118
|
+
"StandardOutput=journal",
|
|
24119
|
+
"StandardError=journal",
|
|
23502
24120
|
"",
|
|
23503
24121
|
"[Install]",
|
|
23504
24122
|
"WantedBy=default.target",
|
|
@@ -23507,11 +24125,11 @@ function renderSystemdUnit(watchJs, node, logFile) {
|
|
|
23507
24125
|
}
|
|
23508
24126
|
function installLaunchd(watchJs, node, logFile) {
|
|
23509
24127
|
const label = "com.chat-recall.watch";
|
|
23510
|
-
const plistDir =
|
|
23511
|
-
const plistPath =
|
|
24128
|
+
const plistDir = join55(homedir21(), "Library", "LaunchAgents");
|
|
24129
|
+
const plistPath = join55(plistDir, `${label}.plist`);
|
|
23512
24130
|
const plist = renderLaunchdPlist(watchJs, node, logFile, label);
|
|
23513
|
-
|
|
23514
|
-
|
|
24131
|
+
mkdirSync18(plistDir, { recursive: true });
|
|
24132
|
+
writeFileSync19(plistPath, plist);
|
|
23515
24133
|
try {
|
|
23516
24134
|
try {
|
|
23517
24135
|
execSync5(`launchctl unload "${plistPath}"`, { stdio: "ignore" });
|
|
@@ -23540,7 +24158,7 @@ function renderLaunchdPlist(watchJs, node, logFile, label = "com.chat-recall.wat
|
|
|
23540
24158
|
}
|
|
23541
24159
|
function installWindowsTask(watchJs, node, logFile) {
|
|
23542
24160
|
const taskName = "chat-recall-watch";
|
|
23543
|
-
const tr =
|
|
24161
|
+
const tr = `cmd /c \\"\\"${node}\\" --max-old-space-size=1536 \\"${watchJs}\\" >> \\"${logFile}\\" 2>&1\\"`;
|
|
23544
24162
|
try {
|
|
23545
24163
|
execSync5(`schtasks /create /tn "${taskName}" /tr "${tr}" /sc onlogon /rl LIMITED /f`, { stdio: "inherit" });
|
|
23546
24164
|
try {
|
|
@@ -23552,8 +24170,8 @@ function installWindowsTask(watchJs, node, logFile) {
|
|
|
23552
24170
|
}
|
|
23553
24171
|
return { definitionPath: null, logFile };
|
|
23554
24172
|
}
|
|
23555
|
-
function renderWindowsTaskCommand(watchJs, node, taskName = "chat-recall-watch") {
|
|
23556
|
-
const tr = `\\"${node}\\" --max-old-space-size=1536 \\"${watchJs}\\"`;
|
|
24173
|
+
function renderWindowsTaskCommand(watchJs, node, taskName = "chat-recall-watch", logFile) {
|
|
24174
|
+
const tr = logFile ? `cmd /c \\"\\"${node}\\" --max-old-space-size=1536 \\"${watchJs}\\" >> \\"${logFile}\\" 2>&1\\"` : `\\"${node}\\" --max-old-space-size=1536 \\"${watchJs}\\"`;
|
|
23557
24175
|
return `schtasks /create /tn "${taskName}" /tr "${tr}" /sc onlogon /rl LIMITED /f`;
|
|
23558
24176
|
}
|
|
23559
24177
|
function uninstallService() {
|
|
@@ -23564,8 +24182,8 @@ function uninstallService() {
|
|
|
23564
24182
|
removed = true;
|
|
23565
24183
|
} catch {
|
|
23566
24184
|
}
|
|
23567
|
-
const unitPath =
|
|
23568
|
-
if (
|
|
24185
|
+
const unitPath = join55(homedir21(), ".config", "systemd", "user", "chat-recall-watch.service");
|
|
24186
|
+
if (existsSync50(unitPath)) {
|
|
23569
24187
|
rmSync8(unitPath, { force: true });
|
|
23570
24188
|
removed = true;
|
|
23571
24189
|
}
|
|
@@ -23576,13 +24194,13 @@ function uninstallService() {
|
|
|
23576
24194
|
return removed;
|
|
23577
24195
|
}
|
|
23578
24196
|
if (process.platform === "darwin") {
|
|
23579
|
-
const plistPath =
|
|
24197
|
+
const plistPath = join55(homedir21(), "Library", "LaunchAgents", "com.chat-recall.watch.plist");
|
|
23580
24198
|
try {
|
|
23581
24199
|
execSync5(`launchctl unload "${plistPath}" 2>/dev/null`, { stdio: "ignore" });
|
|
23582
24200
|
} catch {
|
|
23583
24201
|
}
|
|
23584
24202
|
let removed = false;
|
|
23585
|
-
if (
|
|
24203
|
+
if (existsSync50(plistPath)) {
|
|
23586
24204
|
rmSync8(plistPath, { force: true });
|
|
23587
24205
|
removed = true;
|
|
23588
24206
|
}
|
|
@@ -23627,7 +24245,7 @@ __export(device_auth_exports, {
|
|
|
23627
24245
|
betterAuthDeviceLogin: () => betterAuthDeviceLogin,
|
|
23628
24246
|
deviceLogin: () => deviceLogin
|
|
23629
24247
|
});
|
|
23630
|
-
import { createHash as
|
|
24248
|
+
import { createHash as createHash18, randomBytes } from "node:crypto";
|
|
23631
24249
|
async function deviceLogin(opts, onPrompt) {
|
|
23632
24250
|
const issuer = (opts.issuer || DEFAULT_ISSUER).replace(/\/+$/, "");
|
|
23633
24251
|
if (!issuer) {
|
|
@@ -23638,7 +24256,7 @@ async function deviceLogin(opts, onPrompt) {
|
|
|
23638
24256
|
const clientId = opts.clientId || DEFAULT_CLIENT_ID;
|
|
23639
24257
|
const scope = opts.scope || "openid email profile";
|
|
23640
24258
|
const codeVerifier = b64url(randomBytes(32));
|
|
23641
|
-
const codeChallenge = b64url(
|
|
24259
|
+
const codeChallenge = b64url(createHash18("sha256").update(codeVerifier).digest());
|
|
23642
24260
|
const startRes = await fetch(`${issuer}/protocol/openid-connect/auth/device`, {
|
|
23643
24261
|
method: "POST",
|
|
23644
24262
|
headers: { "content-type": "application/x-www-form-urlencoded" },
|
|
@@ -23760,10 +24378,9 @@ init_project_resolver();
|
|
|
23760
24378
|
import { config } from "dotenv";
|
|
23761
24379
|
import { Command } from "commander";
|
|
23762
24380
|
import chalk from "chalk";
|
|
23763
|
-
import { existsSync as
|
|
23764
|
-
import { homedir as
|
|
23765
|
-
import { join as
|
|
23766
|
-
import { execSync as execSync6 } from "child_process";
|
|
24381
|
+
import { existsSync as existsSync51, readFileSync as readFileSync45, writeFileSync as writeFileSync20, realpathSync as realpathSync5 } from "fs";
|
|
24382
|
+
import { homedir as homedir22 } from "os";
|
|
24383
|
+
import { join as join56, resolve as resolve2, dirname as dirname24, basename as basename27 } from "path";
|
|
23767
24384
|
|
|
23768
24385
|
// ../engine/dist/core/score-tier.js
|
|
23769
24386
|
var STRONG_RATIO = 0.85;
|
|
@@ -23790,6 +24407,68 @@ function tierAll(results) {
|
|
|
23790
24407
|
// src/cli.ts
|
|
23791
24408
|
init_sync_client();
|
|
23792
24409
|
init_update_notice();
|
|
24410
|
+
init_which();
|
|
24411
|
+
|
|
24412
|
+
// ../engine/dist/core/collector-health.js
|
|
24413
|
+
init_paths();
|
|
24414
|
+
import { readFileSync as readFileSync34, writeFileSync as writeFileSync10, mkdirSync as mkdirSync9 } from "node:fs";
|
|
24415
|
+
import { join as join43, dirname as dirname17 } from "node:path";
|
|
24416
|
+
var healthPath = () => join43(getDataDir(), "collector-health.json");
|
|
24417
|
+
function collectorHealthPath() {
|
|
24418
|
+
return healthPath();
|
|
24419
|
+
}
|
|
24420
|
+
function readCollectorHealth() {
|
|
24421
|
+
try {
|
|
24422
|
+
const h = JSON.parse(readFileSync34(healthPath(), "utf-8"));
|
|
24423
|
+
return h && h.v === 1 && typeof h.updatedAt === "number" ? h : null;
|
|
24424
|
+
} catch {
|
|
24425
|
+
return null;
|
|
24426
|
+
}
|
|
24427
|
+
}
|
|
24428
|
+
var STALE_AFTER_MS = 30 * 6e4;
|
|
24429
|
+
var CRASHLOOP_RESTARTS = 3;
|
|
24430
|
+
var ago = (ms) => {
|
|
24431
|
+
const m = Math.floor(ms / 6e4);
|
|
24432
|
+
if (m < 60)
|
|
24433
|
+
return `${m}m`;
|
|
24434
|
+
const h = Math.floor(m / 60);
|
|
24435
|
+
return h < 48 ? `${h}h` : `${Math.floor(h / 24)}d`;
|
|
24436
|
+
};
|
|
24437
|
+
function judgeHealth(h, now = Date.now()) {
|
|
24438
|
+
if (!h)
|
|
24439
|
+
return { ok: true, summary: null, reasons: [] };
|
|
24440
|
+
const reasons = [];
|
|
24441
|
+
const silent = now - h.updatedAt;
|
|
24442
|
+
if (silent > STALE_AFTER_MS) {
|
|
24443
|
+
reasons.push(`the collector has not reported for ${ago(silent)} \u2014 it may not be running`);
|
|
24444
|
+
}
|
|
24445
|
+
if (h.restartsLastHour >= CRASHLOOP_RESTARTS) {
|
|
24446
|
+
reasons.push(`it restarted ${h.restartsLastHour} times in the last hour`);
|
|
24447
|
+
}
|
|
24448
|
+
const targets = Object.entries(h.targets ?? {});
|
|
24449
|
+
const stale = targets.filter(([, t]) => t.lastOkAt === null || now - t.lastOkAt > STALE_AFTER_MS);
|
|
24450
|
+
if (targets.length > 0 && stale.length === targets.length) {
|
|
24451
|
+
const ranked = stale.map(([url, t]) => ({ url, t })).sort((a, b) => {
|
|
24452
|
+
const err = Number(!!b.t.lastError) - Number(!!a.t.lastError);
|
|
24453
|
+
if (err !== 0)
|
|
24454
|
+
return err;
|
|
24455
|
+
return (a.t.lastOkAt ?? 0) - (b.t.lastOkAt ?? 0);
|
|
24456
|
+
});
|
|
24457
|
+
const worst = ranked[0];
|
|
24458
|
+
const when = worst.t.lastOkAt ? `${ago(now - worst.t.lastOkAt)} ago` : "never";
|
|
24459
|
+
const why = worst.t.lastError ? ` (${worst.t.lastError})` : "";
|
|
24460
|
+
reasons.push(`nothing has synced since ${when}${why}`);
|
|
24461
|
+
}
|
|
24462
|
+
if (reasons.length === 0)
|
|
24463
|
+
return { ok: true, summary: null, reasons: [] };
|
|
24464
|
+
return {
|
|
24465
|
+
ok: false,
|
|
24466
|
+
summary: `chat-recall is not syncing: ${reasons.join("; ")}.`,
|
|
24467
|
+
reasons
|
|
24468
|
+
};
|
|
24469
|
+
}
|
|
24470
|
+
|
|
24471
|
+
// src/cli.ts
|
|
23793
24472
|
function matchLabel(tier) {
|
|
23794
24473
|
switch (tier) {
|
|
23795
24474
|
case "strong":
|
|
@@ -23807,8 +24486,8 @@ function claudeHookConfigFiles() {
|
|
|
23807
24486
|
const out = [];
|
|
23808
24487
|
const seen = /* @__PURE__ */ new Set();
|
|
23809
24488
|
for (const home of claudeHomeDirs()) {
|
|
23810
|
-
if (!
|
|
23811
|
-
const file =
|
|
24489
|
+
if (!existsSync51(join56(home, "projects"))) continue;
|
|
24490
|
+
const file = join56(home, "hooks.json");
|
|
23812
24491
|
let key;
|
|
23813
24492
|
try {
|
|
23814
24493
|
key = realpathSync5(file);
|
|
@@ -23882,7 +24561,7 @@ async function serverDelete(path, body) {
|
|
|
23882
24561
|
return res.json();
|
|
23883
24562
|
}
|
|
23884
24563
|
var pkgVersion = JSON.parse(
|
|
23885
|
-
|
|
24564
|
+
readFileSync45(new URL("../package.json", import.meta.url), "utf-8")
|
|
23886
24565
|
).version;
|
|
23887
24566
|
var DEFAULT_SERVER = "https://chatrecall.dev";
|
|
23888
24567
|
var DEFAULT_ALLOW = [
|
|
@@ -23964,7 +24643,7 @@ program.command("init").description("Set up chat-recall: connect to your server,
|
|
|
23964
24643
|
];
|
|
23965
24644
|
for (const cli of clis) {
|
|
23966
24645
|
try {
|
|
23967
|
-
|
|
24646
|
+
if (!isOnPath(cli.cmd)) throw new Error("not on PATH");
|
|
23968
24647
|
cli.available = true;
|
|
23969
24648
|
} catch {
|
|
23970
24649
|
}
|
|
@@ -23996,37 +24675,22 @@ program.command("init").description("Set up chat-recall: connect to your server,
|
|
|
23996
24675
|
console.log();
|
|
23997
24676
|
if (!options.skipMcp) {
|
|
23998
24677
|
console.log(chalk.bold("4. Configuring MCP server..."));
|
|
23999
|
-
const
|
|
24000
|
-
let mcpConfig = {};
|
|
24001
|
-
if (existsSync49(mcpJsonPath)) {
|
|
24002
|
-
try {
|
|
24003
|
-
mcpConfig = JSON.parse(readFileSync44(mcpJsonPath, "utf-8"));
|
|
24004
|
-
} catch {
|
|
24005
|
-
mcpConfig = {};
|
|
24006
|
-
}
|
|
24007
|
-
}
|
|
24008
|
-
const mcpServers = mcpConfig.mcpServers || {};
|
|
24009
|
-
const projectRoot = join53(import.meta.dirname, "..");
|
|
24678
|
+
const projectRoot = join56(import.meta.dirname, "..");
|
|
24010
24679
|
let mcpBinOnPath = false;
|
|
24011
|
-
|
|
24012
|
-
|
|
24013
|
-
mcpBinOnPath = true;
|
|
24014
|
-
} catch {
|
|
24015
|
-
}
|
|
24016
|
-
const launch = mcpBinOnPath ? { command: "chat-recall-mcp" } : { command: "node", args: [join53(projectRoot, "dist", "mcp.js")] };
|
|
24680
|
+
mcpBinOnPath = isOnPath("chat-recall-mcp");
|
|
24681
|
+
const launch = mcpBinOnPath ? { command: "chat-recall-mcp" } : { command: "node", args: [join56(projectRoot, "dist", "mcp.js")] };
|
|
24017
24682
|
const MCP_ENV = { NODE_OPTIONS: "--max-old-space-size=1024" };
|
|
24018
|
-
const
|
|
24019
|
-
const
|
|
24020
|
-
|
|
24021
|
-
|
|
24022
|
-
|
|
24023
|
-
|
|
24024
|
-
|
|
24025
|
-
|
|
24026
|
-
|
|
24027
|
-
writeFileSync18(mcpJsonPath, JSON.stringify(mcpConfig, null, 2));
|
|
24028
|
-
console.log(` MCP server: ${chalk.green(existing ? "repaired" : "configured")} (\u2192 ${launch.command}) in ${mcpJsonPath}`);
|
|
24683
|
+
const { registerMcpEverywhere: registerMcpEverywhere2 } = await Promise.resolve().then(() => (init_mcp_clients(), mcp_clients_exports));
|
|
24684
|
+
const detectedClients = clis.filter((c) => c.available).map((c) => c.cmd).filter((c) => c === "gemini" || c === "opencode" || c === "codex");
|
|
24685
|
+
const results = registerMcpEverywhere2(
|
|
24686
|
+
{ ...launch, env: MCP_ENV, alwaysAllow: DEFAULT_ALLOW },
|
|
24687
|
+
{ extraIds: detectedClients }
|
|
24688
|
+
);
|
|
24689
|
+
for (const r of results) {
|
|
24690
|
+
const word = r.state === "current" ? chalk.green("already configured") : r.state === "created" ? chalk.green("configured") : r.state === "repaired" ? chalk.green("repaired") : chalk.yellow("left alone \u2014 file does not parse");
|
|
24691
|
+
console.log(` ${r.label}: ${word} \u2192 ${r.path}`);
|
|
24029
24692
|
}
|
|
24693
|
+
console.log(chalk.dim(` Launch: ${launch.command}${launch.args ? " " + launch.args.join(" ") : ""}`));
|
|
24030
24694
|
} else {
|
|
24031
24695
|
console.log(chalk.bold("4. Skipping MCP configuration (--skip-mcp)"));
|
|
24032
24696
|
}
|
|
@@ -24047,7 +24711,7 @@ program.command("init").description("Set up chat-recall: connect to your server,
|
|
|
24047
24711
|
console.log(chalk.bold("5. Detected codeindex companion"));
|
|
24048
24712
|
console.log(` ${chalk.green("codeindex")}: ${detected.path}`);
|
|
24049
24713
|
if (!options.skipMcp) {
|
|
24050
|
-
const mcpJsonPath =
|
|
24714
|
+
const mcpJsonPath = join56(homedir22(), ".mcp.json");
|
|
24051
24715
|
const reg = registerCodeindexMcp2(mcpJsonPath, detected.path);
|
|
24052
24716
|
if (reg.added) console.log(` ${chalk.green("codeindex MCP server registered")} in ${mcpJsonPath}`);
|
|
24053
24717
|
else console.log(` codeindex MCP server: ${chalk.green("already registered")}`);
|
|
@@ -24060,7 +24724,7 @@ program.command("init").description("Set up chat-recall: connect to your server,
|
|
|
24060
24724
|
const sizeMb = result.size ? `${(result.size / 1024 / 1024).toFixed(1)} MB` : "?";
|
|
24061
24725
|
console.log(` ${chalk.green("codeindex installed")} (${sizeMb}) \u2192 ${result.path}`);
|
|
24062
24726
|
if (!options.skipMcp) {
|
|
24063
|
-
const mcpJsonPath =
|
|
24727
|
+
const mcpJsonPath = join56(homedir22(), ".mcp.json");
|
|
24064
24728
|
const reg = registerCodeindexMcp2(mcpJsonPath, CODEINDEX_BIN_PATH2);
|
|
24065
24729
|
if (reg.added) console.log(` ${chalk.green("codeindex MCP server registered")} in ${mcpJsonPath}`);
|
|
24066
24730
|
}
|
|
@@ -24458,8 +25122,8 @@ memory.command("wake-up").description("Generate wake-up context (high-importance
|
|
|
24458
25122
|
try {
|
|
24459
25123
|
const identityFile = getIdentityFilePath();
|
|
24460
25124
|
let identity = "AI coding assistant";
|
|
24461
|
-
if (
|
|
24462
|
-
identity =
|
|
25125
|
+
if (existsSync51(identityFile)) {
|
|
25126
|
+
identity = readFileSync45(identityFile, "utf-8").trim();
|
|
24463
25127
|
}
|
|
24464
25128
|
const lines = [
|
|
24465
25129
|
chalk.bold("# Wake-Up Context"),
|
|
@@ -24516,8 +25180,8 @@ program.command("escalate [sessionId]").description("Escalate a finished session
|
|
|
24516
25180
|
}
|
|
24517
25181
|
});
|
|
24518
25182
|
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) => {
|
|
24519
|
-
const { existsSync:
|
|
24520
|
-
const { execSync:
|
|
25183
|
+
const { existsSync: existsSync52, readFileSync: readFileSync46, statSync: statSync42 } = await import("fs");
|
|
25184
|
+
const { execSync: execSync6 } = await import("child_process");
|
|
24521
25185
|
const rows = [];
|
|
24522
25186
|
const note = (ok, label, detail) => rows.push({ ok, label, detail });
|
|
24523
25187
|
const targets = loadAllCredentials();
|
|
@@ -24541,36 +25205,50 @@ program.command("doctor").description("Quick health check across login, server,
|
|
|
24541
25205
|
} else {
|
|
24542
25206
|
note(false, "Server reachable", "N/A (not logged in)");
|
|
24543
25207
|
}
|
|
24544
|
-
|
|
24545
|
-
|
|
25208
|
+
{
|
|
25209
|
+
const h = readCollectorHealth();
|
|
25210
|
+
if (!h) {
|
|
25211
|
+
note(false, "Collector reporting", `no health report at ${collectorHealthPath()} \u2014 the watch daemon may never have run (\`chat-recall watch --install-service\`)`);
|
|
25212
|
+
} else {
|
|
25213
|
+
const v = judgeHealth(h);
|
|
25214
|
+
note(v.ok, "Collector healthy", v.ok ? `last reported ${Math.max(0, Math.round((Date.now() - h.updatedAt) / 1e3))}s ago, ${Object.keys(h.targets).length} target(s)` : v.reasons.join("; "));
|
|
25215
|
+
for (const [url, t] of Object.entries(h.targets)) {
|
|
25216
|
+
const okRecently = t.lastOkAt !== null && Date.now() - t.lastOkAt < STALE_AFTER_MS;
|
|
25217
|
+
note(okRecently, `Synced to ${url}`, t.lastOkAt === null ? `never \u2014 ${t.failures} consecutive failure(s)${t.lastError ? `: ${t.lastError}` : ""}` : `${Math.round((Date.now() - t.lastOkAt) / 6e4)}m ago${t.failures ? ` (${t.failures} failure(s) since)` : ""}`);
|
|
25218
|
+
}
|
|
25219
|
+
}
|
|
25220
|
+
}
|
|
25221
|
+
const credFile = join56(getDataDir(), "credentials.json");
|
|
25222
|
+
if (!existsSync52(credFile)) {
|
|
24546
25223
|
note(false, "Credentials file", `missing \u2014 run \`chat-recall login <server-url>\``);
|
|
24547
25224
|
} else {
|
|
24548
25225
|
try {
|
|
24549
|
-
const mode =
|
|
24550
|
-
const
|
|
24551
|
-
|
|
25226
|
+
const mode = statSync42(credFile).mode & 511;
|
|
25227
|
+
const isWin = process.platform === "win32";
|
|
25228
|
+
const safe = isWin || (mode & 63) === 0;
|
|
25229
|
+
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"})`);
|
|
24552
25230
|
} catch (err) {
|
|
24553
25231
|
note(false, "Credentials file", `error: ${err}`);
|
|
24554
25232
|
}
|
|
24555
25233
|
}
|
|
24556
25234
|
for (const hooksJson of claudeHookConfigFiles()) {
|
|
24557
|
-
const profile = basename27(
|
|
25235
|
+
const profile = basename27(dirname24(hooksJson));
|
|
24558
25236
|
const label = `Claude hooks (${profile})`;
|
|
24559
|
-
if (!
|
|
25237
|
+
if (!existsSync52(hooksJson)) {
|
|
24560
25238
|
note(false, label, `no ${hooksJson} \u2014 run \`chat-recall install-hooks\``);
|
|
24561
25239
|
continue;
|
|
24562
25240
|
}
|
|
24563
25241
|
try {
|
|
24564
25242
|
const readHooks = (file) => {
|
|
24565
|
-
if (!
|
|
25243
|
+
if (!existsSync52(file)) return {};
|
|
24566
25244
|
try {
|
|
24567
|
-
return JSON.parse(
|
|
25245
|
+
return JSON.parse(readFileSync46(file, "utf-8")).hooks || {};
|
|
24568
25246
|
} catch {
|
|
24569
25247
|
return {};
|
|
24570
25248
|
}
|
|
24571
25249
|
};
|
|
24572
25250
|
const cfg = readHooks(hooksJson);
|
|
24573
|
-
const settings2 = readHooks(
|
|
25251
|
+
const settings2 = readHooks(join56(dirname24(hooksJson), "settings.json"));
|
|
24574
25252
|
const all = ["SessionStart", "UserPromptSubmit", "Stop", "PreCompact", "SessionEnd"];
|
|
24575
25253
|
const hits = [];
|
|
24576
25254
|
for (const ev of all) {
|
|
@@ -24594,7 +25272,7 @@ program.command("doctor").description("Quick health check across login, server,
|
|
|
24594
25272
|
const want = bundledSkillNames2().length;
|
|
24595
25273
|
for (const t of skillTargets2()) {
|
|
24596
25274
|
if (!t.available) continue;
|
|
24597
|
-
const have = want === 0 ? 0 : bundledSkillNames2().filter((n) =>
|
|
25275
|
+
const have = want === 0 ? 0 : bundledSkillNames2().filter((n) => existsSync52(join56(t.dir, n, ".chat-recall-managed"))).length;
|
|
24598
25276
|
note(
|
|
24599
25277
|
have === want,
|
|
24600
25278
|
`Skills \u2014 ${t.label}`,
|
|
@@ -24604,17 +25282,18 @@ program.command("doctor").description("Quick health check across login, server,
|
|
|
24604
25282
|
} catch (err) {
|
|
24605
25283
|
note(false, "Skills", `check failed: ${err}`);
|
|
24606
25284
|
}
|
|
24607
|
-
|
|
24608
|
-
|
|
24609
|
-
|
|
24610
|
-
|
|
24611
|
-
|
|
24612
|
-
|
|
24613
|
-
|
|
24614
|
-
|
|
24615
|
-
|
|
24616
|
-
note(false, "chat-recall MCP server", `${mcpJsonPath} unparseable`);
|
|
25285
|
+
try {
|
|
25286
|
+
const { inspectMcpClients: inspectMcpClients2 } = await Promise.resolve().then(() => (init_mcp_clients(), mcp_clients_exports));
|
|
25287
|
+
for (const c of inspectMcpClients2()) {
|
|
25288
|
+
if (!c.present && !c.registered) continue;
|
|
25289
|
+
note(
|
|
25290
|
+
c.registered,
|
|
25291
|
+
`MCP server \u2014 ${c.label}`,
|
|
25292
|
+
c.registered ? `registered in ${c.path}` : `missing from ${c.path} \u2014 run \`chat-recall init\``
|
|
25293
|
+
);
|
|
24617
25294
|
}
|
|
25295
|
+
} catch (err) {
|
|
25296
|
+
note(false, "MCP server registration", `check failed: ${err}`);
|
|
24618
25297
|
}
|
|
24619
25298
|
try {
|
|
24620
25299
|
const { checkCodeindexStatus: checkCodeindexStatus2 } = await Promise.resolve().then(() => (init_companions(), companions_exports));
|
|
@@ -24652,7 +25331,7 @@ program.command("doctor").description("Quick health check across login, server,
|
|
|
24652
25331
|
let watchRunning = false;
|
|
24653
25332
|
const tryCmd2 = (cmd) => {
|
|
24654
25333
|
try {
|
|
24655
|
-
return
|
|
25334
|
+
return execSync6(cmd, { stdio: ["ignore", "pipe", "ignore"] }).toString();
|
|
24656
25335
|
} catch {
|
|
24657
25336
|
return "";
|
|
24658
25337
|
}
|
|
@@ -24668,14 +25347,14 @@ program.command("doctor").description("Quick health check across login, server,
|
|
|
24668
25347
|
note(watchRunning, "Watch daemon", watchRunning ? "running" : "not running (run `chat-recall watch --install-service` to keep collection running)");
|
|
24669
25348
|
const dataDir = getDataDir();
|
|
24670
25349
|
const legacyPaths = [
|
|
24671
|
-
|
|
24672
|
-
|
|
24673
|
-
|
|
24674
|
-
|
|
24675
|
-
|
|
24676
|
-
|
|
25350
|
+
join56(dataDir, "cache.db"),
|
|
25351
|
+
join56(dataDir, "cache.db-wal"),
|
|
25352
|
+
join56(dataDir, "cache.db-shm"),
|
|
25353
|
+
join56(dataDir, "index", "lancedb"),
|
|
25354
|
+
join56(dataDir, "index", "knowledge_graph.db"),
|
|
25355
|
+
join56(dataDir, "index", "metadata.db")
|
|
24677
25356
|
];
|
|
24678
|
-
const legacyPresent = legacyPaths.filter((p) =>
|
|
25357
|
+
const legacyPresent = legacyPaths.filter((p) => existsSync52(p));
|
|
24679
25358
|
if (opts.purgeLocal) {
|
|
24680
25359
|
if (!target) {
|
|
24681
25360
|
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");
|
|
@@ -24746,7 +25425,7 @@ companions.command("install").description("Install codeindex (downloads from mun
|
|
|
24746
25425
|
if (result.installed) {
|
|
24747
25426
|
const sizeMb = result.size ? `${(result.size / 1024 / 1024).toFixed(1)} MB` : "?";
|
|
24748
25427
|
console.log(chalk.green(`\u2713 codeindex installed (${sizeMb}) \u2192 ${result.path}`));
|
|
24749
|
-
const mcpJsonPath =
|
|
25428
|
+
const mcpJsonPath = join56(homedir22(), ".mcp.json");
|
|
24750
25429
|
const reg = registerCodeindexMcp2(mcpJsonPath, CODEINDEX_BIN_PATH2);
|
|
24751
25430
|
if (reg.added) console.log(chalk.dim(` Registered as MCP server in ${mcpJsonPath}`));
|
|
24752
25431
|
else console.log(chalk.dim(` Already registered as MCP server`));
|
|
@@ -24768,7 +25447,7 @@ companions.command("uninstall").description("Remove the codeindex binary chat-re
|
|
|
24768
25447
|
const r = uninstallCodeindex2();
|
|
24769
25448
|
if (r.removed) console.log(chalk.green(`\u2713 Removed ${r.path}`));
|
|
24770
25449
|
else console.log(chalk.dim(` Nothing to remove at ${r.path}`));
|
|
24771
|
-
const mcpJsonPath =
|
|
25450
|
+
const mcpJsonPath = join56(homedir22(), ".mcp.json");
|
|
24772
25451
|
const u = unregisterCodeindexMcp2(mcpJsonPath);
|
|
24773
25452
|
if (u.removed) console.log(chalk.dim(` Unregistered MCP server from ${mcpJsonPath}`));
|
|
24774
25453
|
});
|
|
@@ -25263,10 +25942,10 @@ tasks.command("pull [dir]").description("Write TEAM_TASKS.md for your tasks in t
|
|
|
25263
25942
|
try {
|
|
25264
25943
|
const { resolveProjectId: resolveProjectId2 } = await Promise.resolve().then(() => (init_project_resolver(), project_resolver_exports));
|
|
25265
25944
|
const { renderTeamTasksMd: renderTeamTasksMd2, parseTeamTasksFile: parseTeamTasksFile2 } = await Promise.resolve().then(() => (init_project_tasks(), project_tasks_exports));
|
|
25266
|
-
const { writeFileSync:
|
|
25267
|
-
const { join:
|
|
25268
|
-
const file =
|
|
25269
|
-
if (!opts.force &&
|
|
25945
|
+
const { writeFileSync: writeFileSync21, readFileSync: readFileSync46, existsSync: existsSync52 } = await import("node:fs");
|
|
25946
|
+
const { join: join57 } = await import("node:path");
|
|
25947
|
+
const file = join57(cwd, "TEAM_TASKS.md");
|
|
25948
|
+
if (!opts.force && existsSync52(file) && parseTeamTasksFile2(readFileSync46(file, "utf8")).length > 0) {
|
|
25270
25949
|
console.error(chalk.red("TEAM_TASKS.md has unpushed edits."), "Run", chalk.bold("chat-recall tasks push"), "first, or", chalk.bold("tasks pull --force"), "to discard.");
|
|
25271
25950
|
process.exit(1);
|
|
25272
25951
|
}
|
|
@@ -25274,7 +25953,7 @@ tasks.command("pull [dir]").description("Write TEAM_TASKS.md for your tasks in t
|
|
|
25274
25953
|
const pid = resolved && resolved.source !== "ignored" ? resolved.id : "";
|
|
25275
25954
|
const { tasks: tasks2 } = await serverGet("/api/tasks?assignee=@me");
|
|
25276
25955
|
const mine = tasks2.filter((t) => !pid || !t.projectId || t.projectId === pid);
|
|
25277
|
-
|
|
25956
|
+
writeFileSync21(file, renderTeamTasksMd2(mine));
|
|
25278
25957
|
console.log(chalk.green("\u2713 wrote"), "TEAM_TASKS.md", chalk.gray(`(${mine.length} task(s))`), "\u2014 edit, then", chalk.bold("chat-recall tasks push"));
|
|
25279
25958
|
} catch (e) {
|
|
25280
25959
|
console.error(chalk.red(e instanceof Error ? e.message : String(e)));
|
|
@@ -25285,14 +25964,14 @@ tasks.command("push [dir]").description("Push TEAM_TASKS.md status edits back to
|
|
|
25285
25964
|
const cwd = dir || process.cwd();
|
|
25286
25965
|
try {
|
|
25287
25966
|
const { parseTeamTasksFile: parseTeamTasksFile2 } = await Promise.resolve().then(() => (init_project_tasks(), project_tasks_exports));
|
|
25288
|
-
const { readFileSync:
|
|
25289
|
-
const { join:
|
|
25290
|
-
const file =
|
|
25291
|
-
if (!
|
|
25967
|
+
const { readFileSync: readFileSync46, existsSync: existsSync52 } = await import("node:fs");
|
|
25968
|
+
const { join: join57 } = await import("node:path");
|
|
25969
|
+
const file = join57(cwd, "TEAM_TASKS.md");
|
|
25970
|
+
if (!existsSync52(file)) {
|
|
25292
25971
|
console.error(chalk.red("no TEAM_TASKS.md here \u2014"), "run", chalk.bold("chat-recall tasks pull"), "first");
|
|
25293
25972
|
process.exit(1);
|
|
25294
25973
|
}
|
|
25295
|
-
const edits = parseTeamTasksFile2(
|
|
25974
|
+
const edits = parseTeamTasksFile2(readFileSync46(file, "utf8"));
|
|
25296
25975
|
let n = 0;
|
|
25297
25976
|
for (const e of edits) {
|
|
25298
25977
|
await serverPatch(`/api/tasks/${encodeURIComponent(e.id)}`, { status: e.intent });
|
|
@@ -25398,8 +26077,8 @@ team.command("publish <type> <name> <file>").description("Publish a local file a
|
|
|
25398
26077
|
console.error(chalk.red(`Invalid tool: ${opts.tool}. Must be one of: ${validTools.join(", ")}`));
|
|
25399
26078
|
process.exit(1);
|
|
25400
26079
|
}
|
|
25401
|
-
const { readFileSync:
|
|
25402
|
-
const body =
|
|
26080
|
+
const { readFileSync: readFileSync46 } = await import("fs");
|
|
26081
|
+
const body = readFileSync46(file);
|
|
25403
26082
|
const { teamPublish: teamPublish2 } = await Promise.resolve().then(() => (init_team_client(), team_client_exports));
|
|
25404
26083
|
const a = await teamPublish2({
|
|
25405
26084
|
type,
|
|
@@ -25586,15 +26265,15 @@ vault.command("forget").description("Remove the stored passphrase from this mach
|
|
|
25586
26265
|
console.log(keyringDelete2() ? chalk.green("\u2713 Passphrase removed from the OS keyring.") : chalk.dim("Nothing stored in the OS keyring."));
|
|
25587
26266
|
}));
|
|
25588
26267
|
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").action(async (opts) => {
|
|
25589
|
-
const { mkdirSync:
|
|
26268
|
+
const { mkdirSync: mkdirSync19, copyFileSync: copyFileSync4, chmodSync: chmodSync5, existsSync: existsSync52, readFileSync: readFileSync46, writeFileSync: writeFileSync21, statSync: statSync42 } = await import("fs");
|
|
25590
26269
|
const { fileURLToPath: fileURLToPath4 } = await import("url");
|
|
25591
26270
|
const here = fileURLToPath4(new URL(".", import.meta.url));
|
|
25592
26271
|
const findHook = (name) => {
|
|
25593
|
-
const
|
|
25594
|
-
|
|
25595
|
-
|
|
26272
|
+
const candidates2 = [
|
|
26273
|
+
join56(here, "..", "hooks", name),
|
|
26274
|
+
join56(here, "..", "..", "hooks", name)
|
|
25596
26275
|
];
|
|
25597
|
-
return
|
|
26276
|
+
return candidates2.find((p) => existsSync52(p));
|
|
25598
26277
|
};
|
|
25599
26278
|
const sourceSaveHook = findHook("chat_recall_save_hook.sh");
|
|
25600
26279
|
const sourceResumeHook = findHook("chat_recall_resume_hook.sh");
|
|
@@ -25605,15 +26284,15 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
|
|
|
25605
26284
|
process.exit(1);
|
|
25606
26285
|
}
|
|
25607
26286
|
const hooksDir = getHooksDir();
|
|
25608
|
-
const installedSaveHook =
|
|
25609
|
-
const installedResumeHook =
|
|
25610
|
-
const installedEscalateHook =
|
|
25611
|
-
const installedWakeupHook =
|
|
26287
|
+
const installedSaveHook = join56(hooksDir, "chat_recall_save_hook.sh");
|
|
26288
|
+
const installedResumeHook = join56(hooksDir, "chat_recall_resume_hook.sh");
|
|
26289
|
+
const installedEscalateHook = join56(hooksDir, "chat_recall_escalate_hook.sh");
|
|
26290
|
+
const installedWakeupHook = join56(hooksDir, "chat_recall_wakeup_hook.sh");
|
|
25612
26291
|
const wakeupWiredInSettings = (home) => {
|
|
25613
|
-
const settings2 =
|
|
25614
|
-
if (!
|
|
26292
|
+
const settings2 = join56(home, "settings.json");
|
|
26293
|
+
if (!existsSync52(settings2)) return false;
|
|
25615
26294
|
try {
|
|
25616
|
-
const cfg = JSON.parse(
|
|
26295
|
+
const cfg = JSON.parse(readFileSync46(settings2, "utf-8"));
|
|
25617
26296
|
const arr = Array.isArray(cfg.hooks?.SessionStart) ? cfg.hooks.SessionStart : [];
|
|
25618
26297
|
return arr.some((h) => (h?.hooks?.[0]?.command || "").includes("chat_recall_wakeup_hook"));
|
|
25619
26298
|
} catch {
|
|
@@ -25622,9 +26301,9 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
|
|
|
25622
26301
|
};
|
|
25623
26302
|
const hookConfigFiles = claudeHookConfigFiles();
|
|
25624
26303
|
const readHookConfig = (file) => {
|
|
25625
|
-
if (!
|
|
26304
|
+
if (!existsSync52(file)) return { hooks: {} };
|
|
25626
26305
|
try {
|
|
25627
|
-
const c = JSON.parse(
|
|
26306
|
+
const c = JSON.parse(readFileSync46(file, "utf-8"));
|
|
25628
26307
|
if (!c.hooks || typeof c.hooks !== "object") c.hooks = {};
|
|
25629
26308
|
return c;
|
|
25630
26309
|
} catch (err) {
|
|
@@ -25650,8 +26329,8 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
|
|
|
25650
26329
|
if (filtered.length) config2.hooks[event] = filtered;
|
|
25651
26330
|
else delete config2.hooks[event];
|
|
25652
26331
|
}
|
|
25653
|
-
if (removed === 0 && !
|
|
25654
|
-
|
|
26332
|
+
if (removed === 0 && !existsSync52(hooksJson)) continue;
|
|
26333
|
+
writeFileSync21(hooksJson, JSON.stringify(config2, null, 2) + "\n");
|
|
25655
26334
|
total += removed;
|
|
25656
26335
|
console.log(chalk.green(`\u2713 Removed ${removed} chat-recall hook entr${removed === 1 ? "y" : "ies"} from ${hooksJson}`));
|
|
25657
26336
|
}
|
|
@@ -25659,7 +26338,20 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
|
|
|
25659
26338
|
console.log(chalk.dim(` (Hook scripts left in ${hooksDir} \u2014 delete manually if you want.)`));
|
|
25660
26339
|
return;
|
|
25661
26340
|
}
|
|
25662
|
-
|
|
26341
|
+
if (process.platform === "win32") {
|
|
26342
|
+
console.log(chalk.yellow("Hooks are not installed on Windows."));
|
|
26343
|
+
console.log(chalk.dim(" They are POSIX shell scripts, and Claude Code runs hook commands through"));
|
|
26344
|
+
console.log(chalk.dim(" cmd.exe, which cannot execute them. Registering them would put an error on"));
|
|
26345
|
+
console.log(chalk.dim(" every turn instead of saving anything."));
|
|
26346
|
+
console.log(chalk.dim(""));
|
|
26347
|
+
console.log(chalk.dim(" Everything else works: indexing, sync, search and the MCP server are"));
|
|
26348
|
+
console.log(chalk.dim(" unaffected. Hooks only add automatic fact-saving and the wake-up bundle,"));
|
|
26349
|
+
console.log(chalk.dim(" and you can get the same context by calling recall_wake_up from the agent."));
|
|
26350
|
+
console.log(chalk.dim(""));
|
|
26351
|
+
console.log(chalk.dim(" Under WSL, run this from inside the WSL shell and it installs normally."));
|
|
26352
|
+
return;
|
|
26353
|
+
}
|
|
26354
|
+
mkdirSync19(hooksDir, { recursive: true });
|
|
25663
26355
|
copyFileSync4(sourceSaveHook, installedSaveHook);
|
|
25664
26356
|
chmodSync5(installedSaveHook, 493);
|
|
25665
26357
|
const installResume = opts.resumeHint !== false && !!sourceResumeHook;
|
|
@@ -25678,7 +26370,7 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
|
|
|
25678
26370
|
chmodSync5(installedWakeupHook, 493);
|
|
25679
26371
|
}
|
|
25680
26372
|
const stopEntry = { matcher: "", hooks: [{ type: "command", command: installedSaveHook }] };
|
|
25681
|
-
const precompactEntry = { matcher: "", hooks: [{ type: "command", command:
|
|
26373
|
+
const precompactEntry = { matcher: "", hooks: [{ type: "command", command: `"${installedSaveHook}" --precompact` }] };
|
|
25682
26374
|
const resumeEntry = { matcher: "", hooks: [{ type: "command", command: installedResumeHook }] };
|
|
25683
26375
|
const escalateEntry = { matcher: "", hooks: [{ type: "command", command: installedEscalateHook }] };
|
|
25684
26376
|
const wakeupEntry = { matcher: "startup|clear", hooks: [{ type: "command", command: installedWakeupHook }] };
|
|
@@ -25691,9 +26383,9 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
|
|
|
25691
26383
|
const wakeupSkipped = [];
|
|
25692
26384
|
for (const hooksJson of hookConfigFiles) {
|
|
25693
26385
|
const config2 = readHookConfig(hooksJson);
|
|
25694
|
-
const home =
|
|
26386
|
+
const home = dirname24(hooksJson);
|
|
25695
26387
|
const alreadyWired = wakeupWiredInSettings(home);
|
|
25696
|
-
if (alreadyWired) wakeupSkipped.push(
|
|
26388
|
+
if (alreadyWired) wakeupSkipped.push(join56(home, "settings.json"));
|
|
25697
26389
|
const perProfile = installWakeup && !alreadyWired ? [...events, ["SessionStart", wakeupEntry]] : events;
|
|
25698
26390
|
for (const event of HOOK_EVENTS) {
|
|
25699
26391
|
const arr = Array.isArray(config2.hooks[event]) ? config2.hooks[event] : [];
|
|
@@ -25703,21 +26395,21 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
|
|
|
25703
26395
|
if (without.length) config2.hooks[event] = without;
|
|
25704
26396
|
else delete config2.hooks[event];
|
|
25705
26397
|
}
|
|
25706
|
-
|
|
25707
|
-
|
|
26398
|
+
mkdirSync19(dirname24(hooksJson), { recursive: true });
|
|
26399
|
+
writeFileSync21(hooksJson, JSON.stringify(config2, null, 2) + "\n");
|
|
25708
26400
|
}
|
|
25709
|
-
const saveSz =
|
|
26401
|
+
const saveSz = statSync42(installedSaveHook).size;
|
|
25710
26402
|
console.log(chalk.green(`\u2713 Installed chat-recall save hook (${saveSz} bytes)`));
|
|
25711
26403
|
if (installResume) {
|
|
25712
|
-
const resumeSz =
|
|
26404
|
+
const resumeSz = statSync42(installedResumeHook).size;
|
|
25713
26405
|
console.log(chalk.green(`\u2713 Installed chat-recall resume-hint hook (${resumeSz} bytes)`));
|
|
25714
26406
|
}
|
|
25715
26407
|
if (installEscalate) {
|
|
25716
|
-
const escalateSz =
|
|
26408
|
+
const escalateSz = statSync42(installedEscalateHook).size;
|
|
25717
26409
|
console.log(chalk.green(`\u2713 Installed chat-recall learnings-escalation hook (${escalateSz} bytes)`));
|
|
25718
26410
|
}
|
|
25719
26411
|
if (installWakeup) {
|
|
25720
|
-
const wakeupSz =
|
|
26412
|
+
const wakeupSz = statSync42(installedWakeupHook).size;
|
|
25721
26413
|
console.log(chalk.green(`\u2713 Installed chat-recall wake-up hook (${wakeupSz} bytes)`));
|
|
25722
26414
|
for (const f of wakeupSkipped) {
|
|
25723
26415
|
console.log(chalk.dim(` (SessionStart already wired in ${f} \u2014 left as is, not duplicated)`));
|
|
@@ -25749,7 +26441,7 @@ program.command("dossier <project>").description("Generate a project dossier (ov
|
|
|
25749
26441
|
);
|
|
25750
26442
|
const md = dossier.markdown;
|
|
25751
26443
|
if (options.out) {
|
|
25752
|
-
|
|
26444
|
+
writeFileSync20(options.out, md);
|
|
25753
26445
|
console.log(chalk.green(`Wrote dossier to ${options.out} (${md.length} chars)`));
|
|
25754
26446
|
} else {
|
|
25755
26447
|
console.log(md);
|
|
@@ -25783,12 +26475,12 @@ program.command("watch").description("Run the live indexer daemon (watches all A
|
|
|
25783
26475
|
}
|
|
25784
26476
|
return;
|
|
25785
26477
|
}
|
|
25786
|
-
const
|
|
26478
|
+
const candidates2 = [
|
|
25787
26479
|
new URL("./watch.js", import.meta.url).href,
|
|
25788
26480
|
new URL("../auto-indexer/indexer.js", import.meta.url).href
|
|
25789
26481
|
];
|
|
25790
26482
|
let lastErr;
|
|
25791
|
-
for (const spec of
|
|
26483
|
+
for (const spec of candidates2) {
|
|
25792
26484
|
try {
|
|
25793
26485
|
await import(spec);
|
|
25794
26486
|
return;
|
|
@@ -25965,8 +26657,8 @@ include.command("list", { isDefault: true }).description("Show paths opted back
|
|
|
25965
26657
|
include.command("project <path>").description("Re-permit a path under a personal folder (substring match; e.g. ~/Documents/code)").action(async (path) => {
|
|
25966
26658
|
const { loadSettings: loadSettings2, saveSettings: saveSettings2 } = await Promise.resolve().then(() => (init_settings(), settings_exports));
|
|
25967
26659
|
const { resolve: resolve3 } = await import("node:path");
|
|
25968
|
-
const { homedir:
|
|
25969
|
-
const abs = resolve3(path.replace(/^~(?=\/|$)/,
|
|
26660
|
+
const { homedir: homedir23 } = await import("node:os");
|
|
26661
|
+
const abs = resolve3(path.replace(/^~(?=\/|$)/, homedir23()));
|
|
25970
26662
|
const s = loadSettings2();
|
|
25971
26663
|
s.sync.includeProjects = s.sync.includeProjects || [];
|
|
25972
26664
|
if (s.sync.includeProjects.includes(abs)) {
|
|
@@ -25980,8 +26672,8 @@ include.command("project <path>").description("Re-permit a path under a personal
|
|
|
25980
26672
|
include.command("remove <path>").description("Undo an opt-in (personal folder goes back to skipped)").action(async (path) => {
|
|
25981
26673
|
const { loadSettings: loadSettings2, saveSettings: saveSettings2 } = await Promise.resolve().then(() => (init_settings(), settings_exports));
|
|
25982
26674
|
const { resolve: resolve3 } = await import("node:path");
|
|
25983
|
-
const { homedir:
|
|
25984
|
-
const abs = resolve3(path.replace(/^~(?=\/|$)/,
|
|
26675
|
+
const { homedir: homedir23 } = await import("node:os");
|
|
26676
|
+
const abs = resolve3(path.replace(/^~(?=\/|$)/, homedir23()));
|
|
25985
26677
|
const s = loadSettings2();
|
|
25986
26678
|
const before = (s.sync.includeProjects || []).length;
|
|
25987
26679
|
s.sync.includeProjects = (s.sync.includeProjects || []).filter((p) => p !== path && p !== abs);
|
|
@@ -26060,8 +26752,8 @@ program.command("projects").description("List distinct project ids discovered on
|
|
|
26060
26752
|
exclude.command("project <path>").description("Exclude a project path from syncing (substring match on the project path; e.g. ~/.claude-pr-bot)").action(async (path) => {
|
|
26061
26753
|
const { loadSettings: loadSettings2, saveSettings: saveSettings2 } = await Promise.resolve().then(() => (init_settings(), settings_exports));
|
|
26062
26754
|
const { resolve: resolve3 } = await import("node:path");
|
|
26063
|
-
const { homedir:
|
|
26064
|
-
const abs = resolve3(path.replace(/^~(?=\/|$)/,
|
|
26755
|
+
const { homedir: homedir23 } = await import("node:os");
|
|
26756
|
+
const abs = resolve3(path.replace(/^~(?=\/|$)/, homedir23()));
|
|
26065
26757
|
const s = loadSettings2();
|
|
26066
26758
|
if (s.sync.excludeProjects.includes(abs)) {
|
|
26067
26759
|
console.log(chalk.dim(`Already excluded: ${abs}`));
|
|
@@ -26090,8 +26782,8 @@ exclude.command("tool <tool>").description("Exclude an AI tool entirely (claude
|
|
|
26090
26782
|
exclude.command("remove <value>").description("Remove an exclusion (tool name or project path)").action(async (value) => {
|
|
26091
26783
|
const { loadSettings: loadSettings2, saveSettings: saveSettings2 } = await Promise.resolve().then(() => (init_settings(), settings_exports));
|
|
26092
26784
|
const { resolve: resolve3 } = await import("node:path");
|
|
26093
|
-
const { homedir:
|
|
26094
|
-
const abs = resolve3(value.replace(/^~(?=\/|$)/,
|
|
26785
|
+
const { homedir: homedir23 } = await import("node:os");
|
|
26786
|
+
const abs = resolve3(value.replace(/^~(?=\/|$)/, homedir23()));
|
|
26095
26787
|
const s = loadSettings2();
|
|
26096
26788
|
const beforeTools = s.sync.excludeTools.length;
|
|
26097
26789
|
const beforeProjects = s.sync.excludeProjects.length;
|