chat-recall 0.5.4 → 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 +1506 -733
- package/dist/cli.js.map +1 -1
- package/dist/mcp-diagnostics.d.ts +45 -0
- package/dist/mcp-diagnostics.d.ts.map +1 -0
- package/dist/mcp-diagnostics.js +98 -0
- package/dist/mcp-diagnostics.js.map +1 -0
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +2096 -1151
- 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 +179 -92
- 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 +1104 -481
- 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/skills/chat-recall/SKILL.md +3 -2
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
|
}
|
|
@@ -6278,6 +6349,24 @@ async function parseSessionFile(sessionPath, maxMessages = 50) {
|
|
|
6278
6349
|
}
|
|
6279
6350
|
const filesToParse = hasSubagentsDir(sessionPath) ? [sessionPath, ...getSubagentPaths(sessionPath)] : [sessionPath];
|
|
6280
6351
|
let userCount = 0;
|
|
6352
|
+
const seenPrompts = /* @__PURE__ */ new Set();
|
|
6353
|
+
const recordPrompt = (raw, line, dedupe = false) => {
|
|
6354
|
+
if (userCount >= maxMessages)
|
|
6355
|
+
return;
|
|
6356
|
+
const withoutReminders = raw.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g, "");
|
|
6357
|
+
if (!withoutReminders.trim() || withoutReminders.trim().length <= 10)
|
|
6358
|
+
return;
|
|
6359
|
+
const cleanedText = stripInjectedBanners(withoutReminders).trim();
|
|
6360
|
+
if (cleanedText.length < 10)
|
|
6361
|
+
return;
|
|
6362
|
+
if (dedupe && seenPrompts.has(cleanedText))
|
|
6363
|
+
return;
|
|
6364
|
+
seenPrompts.add(cleanedText);
|
|
6365
|
+
content.userMessages.push({ text: cleanedText, lineNumber: line, contentType: "user" });
|
|
6366
|
+
userCount++;
|
|
6367
|
+
if (!content.firstPrompt)
|
|
6368
|
+
content.firstPrompt = cleanedText.slice(0, 1e3);
|
|
6369
|
+
};
|
|
6281
6370
|
let assistantCount = 0;
|
|
6282
6371
|
let toolCount = 0;
|
|
6283
6372
|
let lineNum = 0;
|
|
@@ -6356,19 +6445,11 @@ async function parseSessionFile(sessionPath, maxMessages = 50) {
|
|
|
6356
6445
|
text = textParts.join("\n");
|
|
6357
6446
|
}
|
|
6358
6447
|
}
|
|
6359
|
-
if (text
|
|
6360
|
-
|
|
6361
|
-
|
|
6362
|
-
|
|
6363
|
-
content
|
|
6364
|
-
text: cleanedText,
|
|
6365
|
-
lineNumber: lineNum,
|
|
6366
|
-
contentType: "user"
|
|
6367
|
-
});
|
|
6368
|
-
userCount++;
|
|
6369
|
-
if (!content.firstPrompt) {
|
|
6370
|
-
content.firstPrompt = cleanedText.slice(0, 1e3);
|
|
6371
|
-
}
|
|
6448
|
+
if (text)
|
|
6449
|
+
recordPrompt(text, lineNum);
|
|
6450
|
+
} else if (msgType === "queue-operation") {
|
|
6451
|
+
if (obj.operation === "enqueue" && typeof obj.content === "string") {
|
|
6452
|
+
recordPrompt(obj.content, lineNum, true);
|
|
6372
6453
|
}
|
|
6373
6454
|
} else if (msgType === "assistant") {
|
|
6374
6455
|
const msg = obj.message;
|
|
@@ -6484,8 +6565,8 @@ function decodeDirName(dirName) {
|
|
|
6484
6565
|
}
|
|
6485
6566
|
for (let len = 2; len <= segments.length - i; len++) {
|
|
6486
6567
|
const joinedSegments = segments.slice(i, i + len);
|
|
6487
|
-
for (const
|
|
6488
|
-
const candidate = join5(currentPath, joinedSegments.join(
|
|
6568
|
+
for (const sep3 of ["-", "_", "."]) {
|
|
6569
|
+
const candidate = join5(currentPath, joinedSegments.join(sep3));
|
|
6489
6570
|
if (existsSync5(candidate)) {
|
|
6490
6571
|
currentPath = candidate;
|
|
6491
6572
|
i += len;
|
|
@@ -6855,8 +6936,8 @@ var init_claude = __esm({
|
|
|
6855
6936
|
|
|
6856
6937
|
// ../engine/dist/transcript/gemini.js
|
|
6857
6938
|
async function parseGeminiTranscript(sessionPath) {
|
|
6858
|
-
const { readFileSync:
|
|
6859
|
-
return parseGeminiTranscriptText(
|
|
6939
|
+
const { readFileSync: readFileSync46 } = await import("fs");
|
|
6940
|
+
return parseGeminiTranscriptText(readFileSync46(sessionPath, "utf-8"));
|
|
6860
6941
|
}
|
|
6861
6942
|
function parseGeminiTranscriptText(text) {
|
|
6862
6943
|
let content;
|
|
@@ -7312,11 +7393,11 @@ async function archiveRawSession(store, sessionId) {
|
|
|
7312
7393
|
return await store.putRawSession(sessionId, exp.tool, Math.floor(exp.mtime), gz, size);
|
|
7313
7394
|
}
|
|
7314
7395
|
function detectForkPredecessor(sessionPath) {
|
|
7315
|
-
const { readFileSync:
|
|
7316
|
-
const { dirname:
|
|
7396
|
+
const { readFileSync: readFileSync46, readdirSync: readdirSync33 } = requireFs();
|
|
7397
|
+
const { dirname: dirname25, join: join57, basename: basename28 } = requirePath();
|
|
7317
7398
|
let text;
|
|
7318
7399
|
try {
|
|
7319
|
-
text =
|
|
7400
|
+
text = readFileSync46(sessionPath, "utf-8");
|
|
7320
7401
|
} catch {
|
|
7321
7402
|
return null;
|
|
7322
7403
|
}
|
|
@@ -7338,7 +7419,7 @@ function detectForkPredecessor(sessionPath) {
|
|
|
7338
7419
|
return null;
|
|
7339
7420
|
if (text.includes(`"uuid":"${headParent}"`))
|
|
7340
7421
|
return null;
|
|
7341
|
-
const dir =
|
|
7422
|
+
const dir = dirname25(sessionPath);
|
|
7342
7423
|
const self = basename28(sessionPath);
|
|
7343
7424
|
let entries;
|
|
7344
7425
|
try {
|
|
@@ -7350,7 +7431,7 @@ function detectForkPredecessor(sessionPath) {
|
|
|
7350
7431
|
if (!f.endsWith(".jsonl") || f === self || f === "sessions-index.json")
|
|
7351
7432
|
continue;
|
|
7352
7433
|
try {
|
|
7353
|
-
if (
|
|
7434
|
+
if (readFileSync46(join57(dir, f), "utf-8").includes(`"uuid":"${headParent}"`)) {
|
|
7354
7435
|
return basename28(f, ".jsonl");
|
|
7355
7436
|
}
|
|
7356
7437
|
} catch {
|
|
@@ -8151,6 +8232,20 @@ var init_tail_read = __esm({
|
|
|
8151
8232
|
}
|
|
8152
8233
|
});
|
|
8153
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
|
+
|
|
8154
8249
|
// ../engine/dist/core/backends/gemini.js
|
|
8155
8250
|
import { createHash as createHash3 } from "crypto";
|
|
8156
8251
|
import { existsSync as existsSync7, readdirSync as readdirSync5, readFileSync as readFileSync3, statSync as statSync6 } from "fs";
|
|
@@ -8192,6 +8287,7 @@ var init_gemini2 = __esm({
|
|
|
8192
8287
|
init_session_git();
|
|
8193
8288
|
init_generic_engine();
|
|
8194
8289
|
init_tail_read();
|
|
8290
|
+
init_flat_string();
|
|
8195
8291
|
PREFIX = "gemini_";
|
|
8196
8292
|
FULL_PARSE_MAX = 4 * 1024 * 1024;
|
|
8197
8293
|
GeminiBackend = class {
|
|
@@ -8301,7 +8397,7 @@ var init_gemini2 = __esm({
|
|
|
8301
8397
|
sessionId = readSessionId(fullPath, format);
|
|
8302
8398
|
const messages = readGeminiMessages(fullPath, format);
|
|
8303
8399
|
const firstUser = messages.find((m) => m.type === "user");
|
|
8304
|
-
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));
|
|
8305
8401
|
messageCount = messages.length;
|
|
8306
8402
|
} else if (format === "jsonl") {
|
|
8307
8403
|
const lines = readHeadSync(fullPath, 1048576).split("\n");
|
|
@@ -8323,7 +8419,7 @@ var init_gemini2 = __esm({
|
|
|
8323
8419
|
}
|
|
8324
8420
|
if (m?.type !== "user")
|
|
8325
8421
|
continue;
|
|
8326
|
-
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));
|
|
8327
8423
|
break;
|
|
8328
8424
|
}
|
|
8329
8425
|
}
|
|
@@ -8499,7 +8595,7 @@ var init_gemini2 = __esm({
|
|
|
8499
8595
|
if (!existsSync7(tmpRoot))
|
|
8500
8596
|
return [];
|
|
8501
8597
|
const projMap = this.loadProjectMap();
|
|
8502
|
-
const
|
|
8598
|
+
const candidates2 = [];
|
|
8503
8599
|
for (const proj of readdirSync5(tmpRoot, { withFileTypes: true })) {
|
|
8504
8600
|
if (!proj.isDirectory())
|
|
8505
8601
|
continue;
|
|
@@ -8530,13 +8626,13 @@ var init_gemini2 = __esm({
|
|
|
8530
8626
|
if (st.mtimeMs < opts.sinceMs)
|
|
8531
8627
|
continue;
|
|
8532
8628
|
const trimLen = isJsonl ? 6 : 5;
|
|
8533
|
-
|
|
8629
|
+
candidates2.push({ rawIdHint: f.slice(0, -trimLen), mtime: st.mtimeMs });
|
|
8534
8630
|
} catch {
|
|
8535
8631
|
}
|
|
8536
8632
|
}
|
|
8537
8633
|
}
|
|
8538
|
-
|
|
8539
|
-
const limited = opts.limitSessions ?
|
|
8634
|
+
candidates2.sort((a, b) => b.mtime - a.mtime);
|
|
8635
|
+
const limited = opts.limitSessions ? candidates2.slice(0, opts.limitSessions) : candidates2;
|
|
8540
8636
|
const edits = [];
|
|
8541
8637
|
for (const c of limited) {
|
|
8542
8638
|
const scan = this.liveScanEdits(c.rawIdHint);
|
|
@@ -8668,6 +8764,7 @@ var init_opencode = __esm({
|
|
|
8668
8764
|
init_session_outcome();
|
|
8669
8765
|
init_session_git();
|
|
8670
8766
|
init_generic_engine();
|
|
8767
|
+
init_flat_string();
|
|
8671
8768
|
PREFIX2 = "opencode_";
|
|
8672
8769
|
OpencodeBackend = class {
|
|
8673
8770
|
id = "opencode";
|
|
@@ -8835,7 +8932,7 @@ var init_opencode = __esm({
|
|
|
8835
8932
|
if (firstUser) {
|
|
8836
8933
|
try {
|
|
8837
8934
|
const parsed = JSON.parse(firstUser.data);
|
|
8838
|
-
firstPrompt = String(parsed?.text || "").slice(0, 200);
|
|
8935
|
+
firstPrompt = flatString(String(parsed?.text || "").slice(0, 200));
|
|
8839
8936
|
} catch {
|
|
8840
8937
|
}
|
|
8841
8938
|
}
|
|
@@ -9326,6 +9423,7 @@ var init_codex2 = __esm({
|
|
|
9326
9423
|
init_session_git();
|
|
9327
9424
|
init_generic_engine();
|
|
9328
9425
|
init_tail_read();
|
|
9426
|
+
init_flat_string();
|
|
9329
9427
|
PREFIX3 = "codex_";
|
|
9330
9428
|
CodexBackend = class {
|
|
9331
9429
|
id = "codex";
|
|
@@ -9438,7 +9536,7 @@ var init_codex2 = __esm({
|
|
|
9438
9536
|
if (ev.type === "event_msg" && ev.payload?.type === "user_message") {
|
|
9439
9537
|
messageCount++;
|
|
9440
9538
|
if (!firstPrompt && ev.payload.message) {
|
|
9441
|
-
firstPrompt = String(ev.payload.message).slice(0, 200);
|
|
9539
|
+
firstPrompt = flatString(String(ev.payload.message).slice(0, 200));
|
|
9442
9540
|
}
|
|
9443
9541
|
} else if (ev.type === "response_item" && ev.payload?.type === "message") {
|
|
9444
9542
|
messageCount++;
|
|
@@ -9539,23 +9637,24 @@ var init_codex2 = __esm({
|
|
|
9539
9637
|
return null;
|
|
9540
9638
|
}
|
|
9541
9639
|
/**
|
|
9542
|
-
|
|
9543
|
-
|
|
9544
|
-
|
|
9545
|
-
|
|
9546
|
-
|
|
9547
|
-
|
|
9548
|
-
|
|
9549
|
-
|
|
9550
|
-
|
|
9551
|
-
|
|
9552
|
-
|
|
9553
|
-
|
|
9554
|
-
|
|
9555
|
-
|
|
9556
|
-
|
|
9557
|
-
|
|
9558
|
-
|
|
9640
|
+
* Stream a Codex JSONL rollout into canonical events. Codex separates:
|
|
9641
|
+
* - event_msg + payload.type='user_message' → user
|
|
9642
|
+
* - response_item + payload.type='message' → user OR assistant_text,
|
|
9643
|
+
* by payload.role
|
|
9644
|
+
* - response_item + payload.type='function_call' → tool_use
|
|
9645
|
+
* - response_item + payload.type='function_call_output' → tool_result
|
|
9646
|
+
*
|
|
9647
|
+
* Filters Codex's wrapper-bearing user messages (environment_context etc.).
|
|
9648
|
+
*
|
|
9649
|
+
* **Subagent fan-out:** Codex orchestrates work via `spawn_agent` calls
|
|
9650
|
+
* that produce sibling rollout files in the same YYYY/MM/DD directory.
|
|
9651
|
+
* Sub-agent rollouts carry `payload.source.subagent.thread_spawn` linking
|
|
9652
|
+
* back to the parent. The actual file edits often happen inside those
|
|
9653
|
+
* subagent rollouts — without folding their events into the parent's
|
|
9654
|
+
* stream, replay/scan would see the parent as edit-free. We append every
|
|
9655
|
+
* subagent rollout's events here so the generic engine sees one unified
|
|
9656
|
+
* stream per user-facing session.
|
|
9657
|
+
*/
|
|
9559
9658
|
readEvents(rawId) {
|
|
9560
9659
|
const located = findCodexSessionFile(this.toRawId(rawId));
|
|
9561
9660
|
if (!located)
|
|
@@ -9625,6 +9724,11 @@ var init_codex2 = __esm({
|
|
|
9625
9724
|
if (text && !isCodexInjectedWrapper2(text)) {
|
|
9626
9725
|
events.push({ kind: "user", ts, tsIso, line: lineNum, text });
|
|
9627
9726
|
}
|
|
9727
|
+
} else if (obj.type === "response_item" && payload.type === "message" && payload.role === "user") {
|
|
9728
|
+
const text = flattenContent(payload.content).trim();
|
|
9729
|
+
if (text && !isCodexInjectedWrapper2(text)) {
|
|
9730
|
+
events.push({ kind: "user", ts, tsIso, line: lineNum, text });
|
|
9731
|
+
}
|
|
9628
9732
|
} else if (obj.type === "response_item" && payload.type === "message" && payload.role === "assistant") {
|
|
9629
9733
|
const text = flattenContent(payload.content).trim();
|
|
9630
9734
|
if (text)
|
|
@@ -10005,6 +10109,7 @@ var init_agy = __esm({
|
|
|
10005
10109
|
init_session_outcome();
|
|
10006
10110
|
init_session_git();
|
|
10007
10111
|
init_generic_engine();
|
|
10112
|
+
init_flat_string();
|
|
10008
10113
|
PREFIX4 = "agy_";
|
|
10009
10114
|
AgyBackend = class {
|
|
10010
10115
|
id = "agy";
|
|
@@ -10105,7 +10210,7 @@ var init_agy = __esm({
|
|
|
10105
10210
|
const content = obj.content;
|
|
10106
10211
|
const match = content.match(/<USER_REQUEST>([\s\S]*?)<\/USER_REQUEST>/);
|
|
10107
10212
|
const rawText = match ? match[1].trim() : content.trim();
|
|
10108
|
-
firstPrompt = rawText.slice(0, 200);
|
|
10213
|
+
firstPrompt = flatString(rawText.slice(0, 200));
|
|
10109
10214
|
break;
|
|
10110
10215
|
}
|
|
10111
10216
|
}
|
|
@@ -10339,7 +10444,7 @@ var init_agy = __esm({
|
|
|
10339
10444
|
if (brainRoots.length === 0)
|
|
10340
10445
|
return [];
|
|
10341
10446
|
const brainDir = brainRoots[0];
|
|
10342
|
-
const
|
|
10447
|
+
const candidates2 = [];
|
|
10343
10448
|
let sessionDirs;
|
|
10344
10449
|
try {
|
|
10345
10450
|
sessionDirs = readdirSync7(brainDir);
|
|
@@ -10361,12 +10466,12 @@ var init_agy = __esm({
|
|
|
10361
10466
|
const st = statSync8(filePath);
|
|
10362
10467
|
if (st.mtimeMs < opts.sinceMs)
|
|
10363
10468
|
continue;
|
|
10364
|
-
|
|
10469
|
+
candidates2.push({ rawId, mtime: st.mtimeMs });
|
|
10365
10470
|
} catch {
|
|
10366
10471
|
}
|
|
10367
10472
|
}
|
|
10368
|
-
|
|
10369
|
-
const limited = opts.limitSessions ?
|
|
10473
|
+
candidates2.sort((a, b) => b.mtime - a.mtime);
|
|
10474
|
+
const limited = opts.limitSessions ? candidates2.slice(0, opts.limitSessions) : candidates2;
|
|
10370
10475
|
const edits = [];
|
|
10371
10476
|
for (const c of limited) {
|
|
10372
10477
|
const scan = this.liveScanEdits(c.rawId);
|
|
@@ -10638,18 +10743,43 @@ function updateShadow(sessionId, exp) {
|
|
|
10638
10743
|
path
|
|
10639
10744
|
};
|
|
10640
10745
|
}
|
|
10641
|
-
async function snapshotShadow(sessionId) {
|
|
10746
|
+
async function snapshotShadow(sessionId, opts = {}) {
|
|
10642
10747
|
await Promise.resolve().then(() => (init_backends(), backends_exports));
|
|
10643
10748
|
const { getBackendForId: getBackendForId2, getBackend: getBackend2 } = await Promise.resolve().then(() => (init_tool_backend(), tool_backend_exports));
|
|
10644
10749
|
const backend = getBackendForId2(sessionId) ?? getBackend2("claude");
|
|
10645
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
|
+
}
|
|
10646
10762
|
let exp = null;
|
|
10647
10763
|
try {
|
|
10648
10764
|
exp = backend.exportRawSession(rawId);
|
|
10649
10765
|
} catch {
|
|
10650
10766
|
exp = null;
|
|
10651
10767
|
}
|
|
10652
|
-
|
|
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
|
+
}
|
|
10653
10783
|
}
|
|
10654
10784
|
function seedShadow(sessionId, container) {
|
|
10655
10785
|
const tool = container.tool;
|
|
@@ -10668,7 +10798,7 @@ function shadowSizeOnDisk(tool, rawId) {
|
|
|
10668
10798
|
return 0;
|
|
10669
10799
|
}
|
|
10670
10800
|
}
|
|
10671
|
-
var WHOLE_FILE_TOOLS, SINGLETON_META;
|
|
10801
|
+
var WHOLE_FILE_TOOLS, SINGLETON_META, lastLiveFingerprint;
|
|
10672
10802
|
var init_shadow = __esm({
|
|
10673
10803
|
"../engine/dist/transcript/shadow.js"() {
|
|
10674
10804
|
"use strict";
|
|
@@ -10676,6 +10806,27 @@ var init_shadow = __esm({
|
|
|
10676
10806
|
init_raw();
|
|
10677
10807
|
WHOLE_FILE_TOOLS = /* @__PURE__ */ new Set(["gemini"]);
|
|
10678
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";
|
|
10679
10830
|
}
|
|
10680
10831
|
});
|
|
10681
10832
|
|
|
@@ -10702,7 +10853,7 @@ function findSessionFile(sessionId) {
|
|
|
10702
10853
|
path: candidate,
|
|
10703
10854
|
projectDir: entry.name,
|
|
10704
10855
|
// Project path is encoded by replacing slashes with dashes.
|
|
10705
|
-
projectPath: entry.name
|
|
10856
|
+
projectPath: decodeProjectDirName(entry.name)
|
|
10706
10857
|
};
|
|
10707
10858
|
}
|
|
10708
10859
|
}
|
|
@@ -10731,7 +10882,7 @@ function findSessionFiles(sessionId) {
|
|
|
10731
10882
|
out.push({
|
|
10732
10883
|
path: candidate,
|
|
10733
10884
|
projectDir: entry.name,
|
|
10734
|
-
projectPath: entry.name
|
|
10885
|
+
projectPath: decodeProjectDirName(entry.name)
|
|
10735
10886
|
});
|
|
10736
10887
|
}
|
|
10737
10888
|
}
|
|
@@ -10755,7 +10906,31 @@ function resolveSessionContentGroups(sessionId) {
|
|
|
10755
10906
|
const names = [...groups.keys()].sort((a, b) => a === "main" ? -1 : b === "main" ? 1 : a.localeCompare(b));
|
|
10756
10907
|
return names.map((name) => ({ name, paths: groups.get(name) }));
|
|
10757
10908
|
}
|
|
10909
|
+
function withSessionReadCache(fn) {
|
|
10910
|
+
readScopeDepth++;
|
|
10911
|
+
try {
|
|
10912
|
+
return fn();
|
|
10913
|
+
} finally {
|
|
10914
|
+
if (--readScopeDepth === 0)
|
|
10915
|
+
readScope = null;
|
|
10916
|
+
}
|
|
10917
|
+
}
|
|
10758
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
|
+
}
|
|
10759
10934
|
let text = "";
|
|
10760
10935
|
let mtime = 0;
|
|
10761
10936
|
for (const p of group.paths) {
|
|
@@ -10771,7 +10946,10 @@ function readSessionGroupText(group) {
|
|
|
10771
10946
|
}
|
|
10772
10947
|
text = text ? mergeLineText(text, raw).text : raw;
|
|
10773
10948
|
}
|
|
10774
|
-
|
|
10949
|
+
const out = { text, mtime };
|
|
10950
|
+
if (readScopeDepth > 0 && key)
|
|
10951
|
+
readScope = { key, value: out };
|
|
10952
|
+
return out;
|
|
10775
10953
|
}
|
|
10776
10954
|
function resolveSessionContentPaths(sessionFile) {
|
|
10777
10955
|
if (!hasSubagentsDir(sessionFile))
|
|
@@ -10994,7 +11172,7 @@ function findCodexSessionFileIn(root, sessionId) {
|
|
|
10994
11172
|
}
|
|
10995
11173
|
return scanDir(root);
|
|
10996
11174
|
}
|
|
10997
|
-
var geminiProjectMapCache, MAX_EVENT_LINE_BYTES;
|
|
11175
|
+
var readScope, readScopeDepth, geminiProjectMapCache, MAX_EVENT_LINE_BYTES;
|
|
10998
11176
|
var init_live_session_scan = __esm({
|
|
10999
11177
|
"../engine/dist/core/live-session-scan.js"() {
|
|
11000
11178
|
"use strict";
|
|
@@ -11003,79 +11181,117 @@ var init_live_session_scan = __esm({
|
|
|
11003
11181
|
init_tool_backend();
|
|
11004
11182
|
init_tool_paths();
|
|
11005
11183
|
init_backends();
|
|
11184
|
+
init_project_dir_name();
|
|
11185
|
+
readScope = null;
|
|
11186
|
+
readScopeDepth = 0;
|
|
11006
11187
|
geminiProjectMapCache = null;
|
|
11007
11188
|
MAX_EVENT_LINE_BYTES = 8 * 1024 * 1024;
|
|
11008
11189
|
}
|
|
11009
11190
|
});
|
|
11010
11191
|
|
|
11011
11192
|
// ../engine/dist/core/first-prompt.js
|
|
11012
|
-
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";
|
|
11013
11195
|
function stripBanners2(s) {
|
|
11014
11196
|
let out = s;
|
|
11015
11197
|
for (const re of BANNERS)
|
|
11016
11198
|
out = out.replace(re, " ");
|
|
11017
11199
|
return out.replace(/[ \t]{2,}/g, " ").trim();
|
|
11018
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
|
+
}
|
|
11019
11241
|
function extractFirstUserPromptSync(filePath, options = {}) {
|
|
11020
11242
|
const maxLines = options.maxLines ?? 500;
|
|
11021
11243
|
const maxLength = options.maxLength ?? 1e3;
|
|
11022
|
-
|
|
11023
|
-
|
|
11024
|
-
let raw;
|
|
11244
|
+
const maxBytes = options.maxBytes ?? 4 * 1024 * 1024;
|
|
11245
|
+
let fd;
|
|
11025
11246
|
try {
|
|
11026
|
-
|
|
11247
|
+
fd = openSync5(filePath, "r");
|
|
11027
11248
|
} catch {
|
|
11028
11249
|
return "";
|
|
11029
11250
|
}
|
|
11030
|
-
|
|
11031
|
-
|
|
11032
|
-
|
|
11033
|
-
const
|
|
11034
|
-
|
|
11035
|
-
|
|
11036
|
-
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 {
|
|
11037
11284
|
try {
|
|
11038
|
-
|
|
11285
|
+
closeSync5(fd);
|
|
11039
11286
|
} catch {
|
|
11040
|
-
continue;
|
|
11041
11287
|
}
|
|
11042
|
-
if (obj.type !== "user")
|
|
11043
|
-
continue;
|
|
11044
|
-
if (obj.isSidechain === true)
|
|
11045
|
-
continue;
|
|
11046
|
-
const message = obj.message;
|
|
11047
|
-
if (!message)
|
|
11048
|
-
continue;
|
|
11049
|
-
const content = message.content;
|
|
11050
|
-
let text = "";
|
|
11051
|
-
if (typeof content === "string") {
|
|
11052
|
-
text = content;
|
|
11053
|
-
} else if (Array.isArray(content)) {
|
|
11054
|
-
const parts = [];
|
|
11055
|
-
for (const block of content) {
|
|
11056
|
-
if (block && typeof block === "object" && block.type === "text" && typeof block.text === "string") {
|
|
11057
|
-
parts.push(block.text);
|
|
11058
|
-
}
|
|
11059
|
-
}
|
|
11060
|
-
text = parts.join("\n");
|
|
11061
|
-
}
|
|
11062
|
-
if (!text)
|
|
11063
|
-
continue;
|
|
11064
|
-
if (text.includes("<system-reminder>"))
|
|
11065
|
-
continue;
|
|
11066
|
-
if (text.trim() === "[Request interrupted by user]")
|
|
11067
|
-
continue;
|
|
11068
|
-
const cleaned = stripBanners2(text);
|
|
11069
|
-
if (cleaned.length < 10)
|
|
11070
|
-
continue;
|
|
11071
|
-
return cleaned.slice(0, maxLength);
|
|
11072
11288
|
}
|
|
11073
|
-
return "";
|
|
11074
11289
|
}
|
|
11075
11290
|
var BANNERS;
|
|
11076
11291
|
var init_first_prompt = __esm({
|
|
11077
11292
|
"../engine/dist/core/first-prompt.js"() {
|
|
11078
11293
|
"use strict";
|
|
11294
|
+
init_flat_string();
|
|
11079
11295
|
BANNERS = [
|
|
11080
11296
|
/MCP issues detected\. ?Run \/mcp list for status\.?/g,
|
|
11081
11297
|
/Context low[^\n]*Run \/compact[^\n]*/g,
|
|
@@ -11085,8 +11301,11 @@ var init_first_prompt = __esm({
|
|
|
11085
11301
|
});
|
|
11086
11302
|
|
|
11087
11303
|
// ../engine/dist/core/backends/claude.js
|
|
11088
|
-
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";
|
|
11089
11305
|
import { join as join14, basename as basename11 } from "path";
|
|
11306
|
+
function stripReminders(text) {
|
|
11307
|
+
return text.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g, "").trim();
|
|
11308
|
+
}
|
|
11090
11309
|
function parseExitCode(text) {
|
|
11091
11310
|
const m = text.match(/(?:^|\n)\s*(?:exit\s+code|returncode|exit\s+status|exit)\s*[:=]\s*(\d+)\b/i);
|
|
11092
11311
|
return m ? Number(m[1]) : void 0;
|
|
@@ -11101,6 +11320,7 @@ var init_claude2 = __esm({
|
|
|
11101
11320
|
init_session_git();
|
|
11102
11321
|
init_first_prompt();
|
|
11103
11322
|
init_tail_read();
|
|
11323
|
+
init_project_dir_name();
|
|
11104
11324
|
init_generic_engine();
|
|
11105
11325
|
UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
11106
11326
|
ClaudeBackend = class {
|
|
@@ -11177,13 +11397,13 @@ var init_claude2 = __esm({
|
|
|
11177
11397
|
return null;
|
|
11178
11398
|
let head;
|
|
11179
11399
|
try {
|
|
11180
|
-
const fd =
|
|
11400
|
+
const fd = openSync6(located.path, "r");
|
|
11181
11401
|
try {
|
|
11182
11402
|
const buf = Buffer.alloc(65536);
|
|
11183
|
-
const n =
|
|
11403
|
+
const n = readSync6(fd, buf, 0, buf.length, 0);
|
|
11184
11404
|
head = buf.toString("utf-8", 0, n);
|
|
11185
11405
|
} finally {
|
|
11186
|
-
|
|
11406
|
+
closeSync6(fd);
|
|
11187
11407
|
}
|
|
11188
11408
|
} catch {
|
|
11189
11409
|
return null;
|
|
@@ -11242,11 +11462,11 @@ var init_claude2 = __esm({
|
|
|
11242
11462
|
if (filter && !proj.name.toLowerCase().includes(filter))
|
|
11243
11463
|
continue;
|
|
11244
11464
|
const projPath = join14(root, proj.name);
|
|
11245
|
-
const projectPath = proj.name
|
|
11465
|
+
const projectPath = decodeProjectDirName(proj.name);
|
|
11246
11466
|
const indexPath = join14(projPath, "sessions-index.json");
|
|
11247
11467
|
if (existsSync13(indexPath)) {
|
|
11248
11468
|
try {
|
|
11249
|
-
const indexData = JSON.parse(
|
|
11469
|
+
const indexData = JSON.parse(readFileSync8(indexPath, "utf-8"));
|
|
11250
11470
|
const entries = indexData.entries || [];
|
|
11251
11471
|
for (const entry of entries) {
|
|
11252
11472
|
if (!entry.fullPath || !existsSync13(entry.fullPath))
|
|
@@ -11395,6 +11615,15 @@ var init_claude2 = __esm({
|
|
|
11395
11615
|
}
|
|
11396
11616
|
const tsIso = typeof obj.timestamp === "string" ? obj.timestamp : void 0;
|
|
11397
11617
|
const ts = tsIso ? Date.parse(tsIso) || mtime : mtime;
|
|
11618
|
+
if (obj.type === "queue-operation") {
|
|
11619
|
+
if (obj.operation === "enqueue" && typeof obj.content === "string") {
|
|
11620
|
+
const queued = stripReminders(obj.content);
|
|
11621
|
+
if (queued && !queued.startsWith("<task-notification")) {
|
|
11622
|
+
events.push({ kind: "user", ts, tsIso, line: lineNum, text: queued });
|
|
11623
|
+
}
|
|
11624
|
+
}
|
|
11625
|
+
continue;
|
|
11626
|
+
}
|
|
11398
11627
|
if (obj.type === "user") {
|
|
11399
11628
|
const msg = obj.message;
|
|
11400
11629
|
const content = msg?.content;
|
|
@@ -11428,9 +11657,9 @@ var init_claude2 = __esm({
|
|
|
11428
11657
|
}
|
|
11429
11658
|
}
|
|
11430
11659
|
}
|
|
11431
|
-
|
|
11432
|
-
|
|
11433
|
-
|
|
11660
|
+
const spoken = stripReminders(text);
|
|
11661
|
+
if (spoken)
|
|
11662
|
+
events.push({ kind: "user", ts, tsIso, line: lineNum, text: spoken });
|
|
11434
11663
|
for (const tr of toolResults) {
|
|
11435
11664
|
events.push({
|
|
11436
11665
|
kind: "tool_result",
|
|
@@ -11529,7 +11758,7 @@ var init_claude2 = __esm({
|
|
|
11529
11758
|
* with quiet main + active subagents still surfaces.
|
|
11530
11759
|
*/
|
|
11531
11760
|
collectRecentEdits(opts) {
|
|
11532
|
-
const
|
|
11761
|
+
const candidates2 = [];
|
|
11533
11762
|
for (const root of claudeProjectDirs()) {
|
|
11534
11763
|
if (!existsSync13(root))
|
|
11535
11764
|
continue;
|
|
@@ -11565,14 +11794,14 @@ var init_claude2 = __esm({
|
|
|
11565
11794
|
}
|
|
11566
11795
|
if (mtime < opts.sinceMs)
|
|
11567
11796
|
continue;
|
|
11568
|
-
|
|
11797
|
+
candidates2.push({ rawId: basename11(f, ".jsonl"), mtime });
|
|
11569
11798
|
} catch {
|
|
11570
11799
|
}
|
|
11571
11800
|
}
|
|
11572
11801
|
}
|
|
11573
11802
|
}
|
|
11574
|
-
|
|
11575
|
-
const limited = opts.limitSessions ?
|
|
11803
|
+
candidates2.sort((a, b) => b.mtime - a.mtime);
|
|
11804
|
+
const limited = opts.limitSessions ? candidates2.slice(0, opts.limitSessions) : candidates2;
|
|
11576
11805
|
const edits = [];
|
|
11577
11806
|
for (const c of limited) {
|
|
11578
11807
|
const scan = this.liveScanEdits(c.rawId);
|
|
@@ -11671,7 +11900,7 @@ __export(project_resolver_exports, {
|
|
|
11671
11900
|
});
|
|
11672
11901
|
import { execSync } from "child_process";
|
|
11673
11902
|
import { createHash as createHash6 } from "crypto";
|
|
11674
|
-
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";
|
|
11675
11904
|
import { basename as basename12, dirname as dirname12, isAbsolute, join as join15, resolve, sep } from "path";
|
|
11676
11905
|
function getProjectsConfigPath() {
|
|
11677
11906
|
return join15(getDataDir(), "projects.json");
|
|
@@ -11689,7 +11918,7 @@ function loadProjectsConfig() {
|
|
|
11689
11918
|
if (cachedConfig && cachedConfig.mtime === mtime)
|
|
11690
11919
|
return cachedConfig.cfg;
|
|
11691
11920
|
try {
|
|
11692
|
-
const raw =
|
|
11921
|
+
const raw = readFileSync9(path, "utf-8");
|
|
11693
11922
|
const cfg = JSON.parse(raw);
|
|
11694
11923
|
cachedConfig = { mtime, cfg };
|
|
11695
11924
|
return cfg;
|
|
@@ -11790,8 +12019,8 @@ function resolveBotWorktree(realPath) {
|
|
|
11790
12019
|
};
|
|
11791
12020
|
}
|
|
11792
12021
|
function matchDeclaredProject(realPath, projects) {
|
|
11793
|
-
const
|
|
11794
|
-
for (const proj of
|
|
12022
|
+
const candidates2 = [...projects].sort((a, b) => b.root.length - a.root.length);
|
|
12023
|
+
for (const proj of candidates2) {
|
|
11795
12024
|
const root = safeRealpath(proj.root);
|
|
11796
12025
|
if (!isInside(realPath, root))
|
|
11797
12026
|
continue;
|
|
@@ -12016,6 +12245,24 @@ var init_project_resolver = __esm({
|
|
|
12016
12245
|
}
|
|
12017
12246
|
});
|
|
12018
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
|
+
|
|
12019
12266
|
// ../engine/dist/core/source-discovery.js
|
|
12020
12267
|
import { createHash as createHash7 } from "crypto";
|
|
12021
12268
|
import { existsSync as existsSync15, readdirSync as readdirSync11, statSync as statSync13 } from "fs";
|
|
@@ -12131,7 +12378,7 @@ __export(home_discovery_exports, {
|
|
|
12131
12378
|
sessionIdsInHome: () => sessionIdsInHome
|
|
12132
12379
|
});
|
|
12133
12380
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
12134
|
-
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";
|
|
12135
12382
|
import { homedir as homedir5, platform as osPlatform } from "os";
|
|
12136
12383
|
import { join as join17 } from "path";
|
|
12137
12384
|
function candidateRoots(plat = osPlatform(), env = process.env) {
|
|
@@ -12319,7 +12566,7 @@ function declaredHomes(env = process.env, plat = osPlatform()) {
|
|
|
12319
12566
|
for (const rc of rcs) {
|
|
12320
12567
|
let text;
|
|
12321
12568
|
try {
|
|
12322
|
-
text =
|
|
12569
|
+
text = readFileSync10(rc, "utf-8");
|
|
12323
12570
|
} catch {
|
|
12324
12571
|
continue;
|
|
12325
12572
|
}
|
|
@@ -12344,7 +12591,7 @@ function runningToolHomes(plat = osPlatform()) {
|
|
|
12344
12591
|
for (const pid of pids) {
|
|
12345
12592
|
let env;
|
|
12346
12593
|
try {
|
|
12347
|
-
env =
|
|
12594
|
+
env = readFileSync10(`/proc/${pid}/environ`, "utf-8");
|
|
12348
12595
|
} catch {
|
|
12349
12596
|
continue;
|
|
12350
12597
|
}
|
|
@@ -12478,7 +12725,7 @@ __export(detector_install_exports, {
|
|
|
12478
12725
|
});
|
|
12479
12726
|
import { spawnSync } from "child_process";
|
|
12480
12727
|
import { createHash as createHash8 } from "crypto";
|
|
12481
|
-
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";
|
|
12482
12729
|
import { join as join18 } from "path";
|
|
12483
12730
|
function managedDetectorPath(name) {
|
|
12484
12731
|
return join18(getDetectorBinDir(), name + exeSuffix());
|
|
@@ -12487,11 +12734,11 @@ function receiptPath(name) {
|
|
|
12487
12734
|
return join18(getDetectorBinDir(), `${name}.receipt.json`);
|
|
12488
12735
|
}
|
|
12489
12736
|
function sha256File(path) {
|
|
12490
|
-
return createHash8("sha256").update(
|
|
12737
|
+
return createHash8("sha256").update(readFileSync11(path)).digest("hex");
|
|
12491
12738
|
}
|
|
12492
12739
|
function readReceipt(name) {
|
|
12493
12740
|
try {
|
|
12494
|
-
return JSON.parse(
|
|
12741
|
+
return JSON.parse(readFileSync11(receiptPath(name), "utf-8"));
|
|
12495
12742
|
} catch {
|
|
12496
12743
|
return null;
|
|
12497
12744
|
}
|
|
@@ -12702,7 +12949,7 @@ __export(secret_scanner_exports, {
|
|
|
12702
12949
|
scanTenantRules: () => scanTenantRules
|
|
12703
12950
|
});
|
|
12704
12951
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
12705
|
-
import { existsSync as existsSync18, unlinkSync, readFileSync as
|
|
12952
|
+
import { existsSync as existsSync18, unlinkSync, readFileSync as readFileSync12, mkdtempSync as mkdtempSync2, rmSync as rmSync3 } from "fs";
|
|
12706
12953
|
import { tmpdir } from "os";
|
|
12707
12954
|
import { join as join19 } from "path";
|
|
12708
12955
|
function mask(s) {
|
|
@@ -12766,7 +13013,7 @@ function runGitleaks(binary, filePath) {
|
|
|
12766
13013
|
return [];
|
|
12767
13014
|
let parsed = [];
|
|
12768
13015
|
try {
|
|
12769
|
-
parsed = JSON.parse(
|
|
13016
|
+
parsed = JSON.parse(readFileSync12(reportPath, "utf-8")) || [];
|
|
12770
13017
|
} catch {
|
|
12771
13018
|
}
|
|
12772
13019
|
try {
|
|
@@ -12830,7 +13077,7 @@ function runGitleaksDir(binary, dir) {
|
|
|
12830
13077
|
}
|
|
12831
13078
|
let parsed = [];
|
|
12832
13079
|
try {
|
|
12833
|
-
parsed = JSON.parse(
|
|
13080
|
+
parsed = JSON.parse(readFileSync12(reportPath, "utf-8")) || [];
|
|
12834
13081
|
} catch {
|
|
12835
13082
|
}
|
|
12836
13083
|
try {
|
|
@@ -12921,7 +13168,7 @@ function scanFileForSecrets(filePath, opts = {}) {
|
|
|
12921
13168
|
out.push({ detector: "trufflehog", ...f });
|
|
12922
13169
|
if (opts.tenantRules && opts.tenantRules.length > 0) {
|
|
12923
13170
|
try {
|
|
12924
|
-
const text =
|
|
13171
|
+
const text = readFileSync12(filePath, "utf-8");
|
|
12925
13172
|
out.push(...scanTenantRules(text, opts.tenantRules));
|
|
12926
13173
|
} catch {
|
|
12927
13174
|
}
|
|
@@ -12949,7 +13196,7 @@ async function scanSessionForSecrets(opts) {
|
|
|
12949
13196
|
try {
|
|
12950
13197
|
const tenantRules = (await opts.store.listSecretRules()).filter((r) => r.enabled).map((r) => ({ name: r.name, regex: r.regex, severity: r.severity }));
|
|
12951
13198
|
if (tenantRules.length > 0) {
|
|
12952
|
-
const text =
|
|
13199
|
+
const text = readFileSync12(opts.filePath, "utf-8");
|
|
12953
13200
|
const lines = text.split("\n");
|
|
12954
13201
|
for (const r of tenantRules) {
|
|
12955
13202
|
let re;
|
|
@@ -13107,10 +13354,10 @@ var init_types = __esm({
|
|
|
13107
13354
|
|
|
13108
13355
|
// ../engine/dist/transcript/opencode.js
|
|
13109
13356
|
async function parseOpenCodeSubagents(parentSessionId) {
|
|
13110
|
-
const { existsSync:
|
|
13357
|
+
const { existsSync: existsSync52 } = await import("fs");
|
|
13111
13358
|
const { opencodeBackend: opencodeBackend2 } = await Promise.resolve().then(() => (init_opencode(), opencode_exports));
|
|
13112
13359
|
const dbPath = opencodeBackend2.dbPath();
|
|
13113
|
-
if (!
|
|
13360
|
+
if (!existsSync52(dbPath))
|
|
13114
13361
|
return [];
|
|
13115
13362
|
const realParent = parentSessionId.replace("opencode_", "");
|
|
13116
13363
|
const db = openSqliteReadonlyOrThrow(dbPath);
|
|
@@ -13151,10 +13398,10 @@ async function parseOpenCodeSubagents(parentSessionId) {
|
|
|
13151
13398
|
}
|
|
13152
13399
|
}
|
|
13153
13400
|
async function parseOpenCodeTranscript(sessionId) {
|
|
13154
|
-
const { existsSync:
|
|
13401
|
+
const { existsSync: existsSync52 } = await import("fs");
|
|
13155
13402
|
const { opencodeBackend: opencodeBackend2 } = await Promise.resolve().then(() => (init_opencode(), opencode_exports));
|
|
13156
13403
|
const dbPath = opencodeBackend2.dbPath();
|
|
13157
|
-
if (!
|
|
13404
|
+
if (!existsSync52(dbPath))
|
|
13158
13405
|
return [];
|
|
13159
13406
|
const realId = sessionId.replace("opencode_", "");
|
|
13160
13407
|
const db = openSqliteReadonlyOrThrow(dbPath);
|
|
@@ -14195,7 +14442,7 @@ var init_utils = __esm({
|
|
|
14195
14442
|
});
|
|
14196
14443
|
|
|
14197
14444
|
// ../engine/dist/parsers/plan-source.js
|
|
14198
|
-
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";
|
|
14199
14446
|
import { homedir as homedir7 } from "os";
|
|
14200
14447
|
import { join as join21, basename as basename13 } from "path";
|
|
14201
14448
|
import { createHash as createHash9 } from "crypto";
|
|
@@ -14237,6 +14484,7 @@ var init_plan_source = __esm({
|
|
|
14237
14484
|
init_claude2();
|
|
14238
14485
|
init_agy();
|
|
14239
14486
|
init_settings();
|
|
14487
|
+
init_project_dir_name();
|
|
14240
14488
|
MAX_CHUNK_CHARS = 2e3;
|
|
14241
14489
|
UUID_RE3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
14242
14490
|
PlanSource = class {
|
|
@@ -14261,7 +14509,7 @@ var init_plan_source = __esm({
|
|
|
14261
14509
|
for (const entry of entries) {
|
|
14262
14510
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
14263
14511
|
continue;
|
|
14264
|
-
const projectPath = entry.name
|
|
14512
|
+
const projectPath = decodeProjectDirName(entry.name);
|
|
14265
14513
|
if (existsSync20(projectPath)) {
|
|
14266
14514
|
this._knownProjectDirs.push(projectPath);
|
|
14267
14515
|
}
|
|
@@ -14299,7 +14547,7 @@ var init_plan_source = __esm({
|
|
|
14299
14547
|
const stat3 = statSync18(filePath);
|
|
14300
14548
|
const planName = basename13(file, ".md");
|
|
14301
14549
|
const isAgentPlan = planName.includes("-agent-");
|
|
14302
|
-
const content =
|
|
14550
|
+
const content = readFileSync13(filePath, "utf-8");
|
|
14303
14551
|
const fm = parseFrontmatter(content);
|
|
14304
14552
|
const body = fm.body;
|
|
14305
14553
|
const firstLine = body.split("\n").find((l) => l.trim())?.replace(/^#+\s*/, "").trim() || planName;
|
|
@@ -14341,7 +14589,7 @@ var init_plan_source = __esm({
|
|
|
14341
14589
|
const filePath = join21(plansDir, file);
|
|
14342
14590
|
try {
|
|
14343
14591
|
const stat3 = statSync18(filePath);
|
|
14344
|
-
const content =
|
|
14592
|
+
const content = readFileSync13(filePath, "utf-8");
|
|
14345
14593
|
const firstLine = content.split("\n").find((l) => l.trim())?.replace(/^#+\s*/, "").trim() || file;
|
|
14346
14594
|
const planName = `${opencodeBackend.idPrefix}plan_${basename13(file, ".md")}`;
|
|
14347
14595
|
const projectPath = this.extractProjectPath(content);
|
|
@@ -14371,7 +14619,7 @@ var init_plan_source = __esm({
|
|
|
14371
14619
|
const projectsPath = geminiBackend.projectsJson();
|
|
14372
14620
|
if (existsSync20(projectsPath)) {
|
|
14373
14621
|
try {
|
|
14374
|
-
const data = JSON.parse(
|
|
14622
|
+
const data = JSON.parse(readFileSync13(projectsPath, "utf-8"));
|
|
14375
14623
|
for (const path of Object.keys(data.projects || {})) {
|
|
14376
14624
|
projMap.set(createHash9("sha256").update(path).digest("hex"), path);
|
|
14377
14625
|
}
|
|
@@ -14407,7 +14655,7 @@ var init_plan_source = __esm({
|
|
|
14407
14655
|
const filePath = join21(plansDir, file);
|
|
14408
14656
|
try {
|
|
14409
14657
|
const stat3 = statSync18(filePath);
|
|
14410
|
-
const content =
|
|
14658
|
+
const content = readFileSync13(filePath, "utf-8");
|
|
14411
14659
|
const firstLine = content.split("\n").find((l) => l.trim())?.replace(/^#+\s*/, "").trim() || file;
|
|
14412
14660
|
const planName = `${geminiBackend.idPrefix}plan_${sess}_${basename13(file, ".md")}`;
|
|
14413
14661
|
yield {
|
|
@@ -14486,7 +14734,7 @@ var init_plan_source = __esm({
|
|
|
14486
14734
|
async parse(item) {
|
|
14487
14735
|
if (!existsSync20(item.filePath))
|
|
14488
14736
|
return [];
|
|
14489
|
-
const content =
|
|
14737
|
+
const content = readFileSync13(item.filePath, "utf-8");
|
|
14490
14738
|
const chunks = [];
|
|
14491
14739
|
const { body } = parseFrontmatter(content);
|
|
14492
14740
|
const sections = splitByHeaders(body);
|
|
@@ -14630,7 +14878,7 @@ var init_plan_source = __esm({
|
|
|
14630
14878
|
const filePath = join21(sessionPath, file);
|
|
14631
14879
|
try {
|
|
14632
14880
|
const stat3 = statSync18(filePath);
|
|
14633
|
-
const content =
|
|
14881
|
+
const content = readFileSync13(filePath, "utf-8");
|
|
14634
14882
|
const firstLine = content.split("\n").find((l) => l.trim())?.replace(/^#+\s*/, "").trim() || file;
|
|
14635
14883
|
const sessionLoc = agyBackend.findSession(rawId);
|
|
14636
14884
|
const projectPath = sessionLoc?.projectPath || this.extractProjectPath(content);
|
|
@@ -14659,7 +14907,7 @@ var init_plan_source = __esm({
|
|
|
14659
14907
|
});
|
|
14660
14908
|
|
|
14661
14909
|
// ../engine/dist/parsers/task-source.js
|
|
14662
|
-
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";
|
|
14663
14911
|
import { join as join22 } from "path";
|
|
14664
14912
|
var MAX_CHUNK_CHARS2, TaskSource;
|
|
14665
14913
|
var init_task_source = __esm({
|
|
@@ -14709,7 +14957,7 @@ var init_task_source = __esm({
|
|
|
14709
14957
|
continue;
|
|
14710
14958
|
let parsed;
|
|
14711
14959
|
try {
|
|
14712
|
-
const raw =
|
|
14960
|
+
const raw = readFileSync14(filePath, "utf-8");
|
|
14713
14961
|
parsed = JSON.parse(raw);
|
|
14714
14962
|
if (!Array.isArray(parsed) || parsed.length === 0)
|
|
14715
14963
|
continue;
|
|
@@ -14847,7 +15095,7 @@ ${task.description}`.slice(0, MAX_CHUNK_CHARS2);
|
|
|
14847
15095
|
return [];
|
|
14848
15096
|
let parsed;
|
|
14849
15097
|
try {
|
|
14850
|
-
parsed = JSON.parse(
|
|
15098
|
+
parsed = JSON.parse(readFileSync14(item.filePath, "utf-8"));
|
|
14851
15099
|
} catch {
|
|
14852
15100
|
return [];
|
|
14853
15101
|
}
|
|
@@ -14879,7 +15127,7 @@ ${task.description}`.slice(0, MAX_CHUNK_CHARS2);
|
|
|
14879
15127
|
});
|
|
14880
15128
|
for (const file of sorted) {
|
|
14881
15129
|
try {
|
|
14882
|
-
const content =
|
|
15130
|
+
const content = readFileSync14(join22(taskDir, file), "utf-8");
|
|
14883
15131
|
const task = JSON.parse(content);
|
|
14884
15132
|
if (task.subject) {
|
|
14885
15133
|
tasks2.push(task);
|
|
@@ -14895,7 +15143,7 @@ ${task.description}`.slice(0, MAX_CHUNK_CHARS2);
|
|
|
14895
15143
|
});
|
|
14896
15144
|
|
|
14897
15145
|
// ../engine/dist/parsers/claude-md-source.js
|
|
14898
|
-
import { existsSync as existsSync22, readFileSync as
|
|
15146
|
+
import { existsSync as existsSync22, readFileSync as readFileSync15, readdirSync as readdirSync16, statSync as statSync20 } from "fs";
|
|
14899
15147
|
import { homedir as homedir8 } from "os";
|
|
14900
15148
|
import { join as join23, basename as basename14, dirname as dirname13 } from "path";
|
|
14901
15149
|
import { createHash as createHash10 } from "crypto";
|
|
@@ -14916,7 +15164,7 @@ function discoverProjectDirs(claudeDir) {
|
|
|
14916
15164
|
for (const entry of entries) {
|
|
14917
15165
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
14918
15166
|
continue;
|
|
14919
|
-
const projectPath = entry.name
|
|
15167
|
+
const projectPath = decodeProjectDirName(entry.name);
|
|
14920
15168
|
addProject(projectPath);
|
|
14921
15169
|
}
|
|
14922
15170
|
} catch {
|
|
@@ -14939,7 +15187,7 @@ function discoverProjectDirs(claudeDir) {
|
|
|
14939
15187
|
const gemProjects = geminiBackend.projectsJson();
|
|
14940
15188
|
if (existsSync22(gemProjects)) {
|
|
14941
15189
|
try {
|
|
14942
|
-
const data = JSON.parse(
|
|
15190
|
+
const data = JSON.parse(readFileSync15(gemProjects, "utf-8"));
|
|
14943
15191
|
for (const path of Object.keys(data.projects || {}))
|
|
14944
15192
|
addProject(path);
|
|
14945
15193
|
} catch {
|
|
@@ -14973,6 +15221,7 @@ var init_claude_md_source = __esm({
|
|
|
14973
15221
|
init_gemini2();
|
|
14974
15222
|
init_settings();
|
|
14975
15223
|
init_opencode();
|
|
15224
|
+
init_project_dir_name();
|
|
14976
15225
|
MAX_CHUNK_CHARS3 = 2e3;
|
|
14977
15226
|
NOTE_FILES = [
|
|
14978
15227
|
{ filename: "CLAUDE.md", tool: "claude" },
|
|
@@ -15053,7 +15302,7 @@ var init_claude_md_source = __esm({
|
|
|
15053
15302
|
async parse(item) {
|
|
15054
15303
|
if (!existsSync22(item.filePath))
|
|
15055
15304
|
return [];
|
|
15056
|
-
const content =
|
|
15305
|
+
const content = readFileSync15(item.filePath, "utf-8");
|
|
15057
15306
|
const chunks = [];
|
|
15058
15307
|
const sections = splitByHeaders(content);
|
|
15059
15308
|
for (let i = 0; i < sections.length; i++) {
|
|
@@ -15095,7 +15344,7 @@ var init_claude_md_source = __esm({
|
|
|
15095
15344
|
const projectDir = dirname13(filePath);
|
|
15096
15345
|
const projectName = basename14(projectDir);
|
|
15097
15346
|
const projectPath = projectDir;
|
|
15098
|
-
const content =
|
|
15347
|
+
const content = readFileSync15(filePath, "utf-8");
|
|
15099
15348
|
const firstLine = content.split("\n").find((l) => l.trim() && !l.startsWith("#"))?.trim()?.slice(0, 200) || `${filename} for ${projectName}`;
|
|
15100
15349
|
const id = tool === "claude" ? projectName : `${projectName}_${tool}`;
|
|
15101
15350
|
return {
|
|
@@ -15120,7 +15369,7 @@ var init_claude_md_source = __esm({
|
|
|
15120
15369
|
});
|
|
15121
15370
|
|
|
15122
15371
|
// ../engine/dist/parsers/agent-memory-source.js
|
|
15123
|
-
import { existsSync as existsSync23, readFileSync as
|
|
15372
|
+
import { existsSync as existsSync23, readFileSync as readFileSync16, readdirSync as readdirSync17, statSync as statSync21 } from "fs";
|
|
15124
15373
|
import { homedir as homedir9 } from "os";
|
|
15125
15374
|
import { join as join24, basename as basename15 } from "path";
|
|
15126
15375
|
function parseFrontmatter2(content) {
|
|
@@ -15148,7 +15397,7 @@ function parseFrontmatter2(content) {
|
|
|
15148
15397
|
return { fm, body };
|
|
15149
15398
|
}
|
|
15150
15399
|
function projectHashToPath(hashDir) {
|
|
15151
|
-
return hashDir
|
|
15400
|
+
return decodeProjectDirName(hashDir);
|
|
15152
15401
|
}
|
|
15153
15402
|
function discoverMemoryDirs() {
|
|
15154
15403
|
const out = [];
|
|
@@ -15190,6 +15439,7 @@ var init_agent_memory_source = __esm({
|
|
|
15190
15439
|
init_utils();
|
|
15191
15440
|
init_claude2();
|
|
15192
15441
|
init_settings();
|
|
15442
|
+
init_project_dir_name();
|
|
15193
15443
|
MAX_CHUNK_CHARS4 = 2e3;
|
|
15194
15444
|
MAX_CHUNKS = 12;
|
|
15195
15445
|
AgentMemorySource = class {
|
|
@@ -15220,7 +15470,7 @@ var init_agent_memory_source = __esm({
|
|
|
15220
15470
|
async parse(item) {
|
|
15221
15471
|
if (!existsSync23(item.filePath))
|
|
15222
15472
|
return [];
|
|
15223
|
-
const content =
|
|
15473
|
+
const content = readFileSync16(item.filePath, "utf-8");
|
|
15224
15474
|
const { body } = parseFrontmatter2(content);
|
|
15225
15475
|
const chunks = [];
|
|
15226
15476
|
const sections = splitByHeaders(body);
|
|
@@ -15273,7 +15523,7 @@ var init_agent_memory_source = __esm({
|
|
|
15273
15523
|
fileToItem(filePath, filename, projectPath, _projectHash) {
|
|
15274
15524
|
try {
|
|
15275
15525
|
const stat3 = statSync21(filePath);
|
|
15276
|
-
const content =
|
|
15526
|
+
const content = readFileSync16(filePath, "utf-8");
|
|
15277
15527
|
const { fm } = parseFrontmatter2(content);
|
|
15278
15528
|
const stem = filename.replace(/\.md$/, "");
|
|
15279
15529
|
const idBase = fm.name || stem;
|
|
@@ -15488,7 +15738,7 @@ var init_history_source = __esm({
|
|
|
15488
15738
|
});
|
|
15489
15739
|
|
|
15490
15740
|
// ../engine/dist/parsers/paste-source.js
|
|
15491
|
-
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";
|
|
15492
15742
|
import { homedir as homedir11 } from "os";
|
|
15493
15743
|
import { join as join26, basename as basename16 } from "path";
|
|
15494
15744
|
var MAX_CHUNK_CHARS6, MAX_FILE_SIZE, PasteSource;
|
|
@@ -15544,7 +15794,7 @@ var init_paste_source = __esm({
|
|
|
15544
15794
|
if (stat3.size < 10)
|
|
15545
15795
|
continue;
|
|
15546
15796
|
const hash = basename16(file, ".txt");
|
|
15547
|
-
const content =
|
|
15797
|
+
const content = readFileSync17(filePath, "utf-8");
|
|
15548
15798
|
const firstLine = content.split("\n").find((l) => l.trim().length > 5)?.trim()?.slice(0, 100) || `Paste ${hash.slice(0, 8)}`;
|
|
15549
15799
|
yield {
|
|
15550
15800
|
id: hash,
|
|
@@ -15565,7 +15815,7 @@ var init_paste_source = __esm({
|
|
|
15565
15815
|
async parse(item) {
|
|
15566
15816
|
if (!existsSync25(item.filePath))
|
|
15567
15817
|
return [];
|
|
15568
|
-
const content =
|
|
15818
|
+
const content = readFileSync17(item.filePath, "utf-8");
|
|
15569
15819
|
if (content.trim().length < 20)
|
|
15570
15820
|
return [];
|
|
15571
15821
|
return [{
|
|
@@ -15588,7 +15838,7 @@ var init_paste_source = __esm({
|
|
|
15588
15838
|
});
|
|
15589
15839
|
|
|
15590
15840
|
// ../engine/dist/parsers/gemini-source.js
|
|
15591
|
-
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";
|
|
15592
15842
|
import { join as join27, basename as basename17 } from "path";
|
|
15593
15843
|
import { createHash as createHash11 } from "crypto";
|
|
15594
15844
|
function loadGeminiProjectMap2() {
|
|
@@ -15597,7 +15847,7 @@ function loadGeminiProjectMap2() {
|
|
|
15597
15847
|
if (!existsSync26(projectsPath))
|
|
15598
15848
|
return map;
|
|
15599
15849
|
try {
|
|
15600
|
-
const data = JSON.parse(
|
|
15850
|
+
const data = JSON.parse(readFileSync18(projectsPath, "utf-8"));
|
|
15601
15851
|
const projects = data.projects || {};
|
|
15602
15852
|
for (const [path] of Object.entries(projects)) {
|
|
15603
15853
|
const hash = createHash11("sha256").update(path).digest("hex");
|
|
@@ -15642,7 +15892,7 @@ var init_gemini_source = __esm({
|
|
|
15642
15892
|
const filePath = join27(chatsDir, file);
|
|
15643
15893
|
try {
|
|
15644
15894
|
const stat3 = statSync24(filePath);
|
|
15645
|
-
const content = JSON.parse(
|
|
15895
|
+
const content = JSON.parse(readFileSync18(filePath, "utf-8"));
|
|
15646
15896
|
const sessionId = content.sessionId || basename17(file, ".json");
|
|
15647
15897
|
if (seen.has(sessionId))
|
|
15648
15898
|
continue;
|
|
@@ -15723,7 +15973,7 @@ var init_gemini_source = __esm({
|
|
|
15723
15973
|
async parse(item) {
|
|
15724
15974
|
if (!existsSync26(item.filePath))
|
|
15725
15975
|
return [];
|
|
15726
|
-
const content = JSON.parse(
|
|
15976
|
+
const content = JSON.parse(readFileSync18(item.filePath, "utf-8"));
|
|
15727
15977
|
const messages = content.messages || [];
|
|
15728
15978
|
const chunks = [];
|
|
15729
15979
|
const getText = (m) => {
|
|
@@ -15771,7 +16021,7 @@ var init_gemini_source = __esm({
|
|
|
15771
16021
|
});
|
|
15772
16022
|
|
|
15773
16023
|
// ../engine/dist/parsers/gemini-brain-source.js
|
|
15774
|
-
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";
|
|
15775
16025
|
import { join as join28 } from "path";
|
|
15776
16026
|
var MAX_CHUNK_CHARS8, GeminiBrainSource;
|
|
15777
16027
|
var init_gemini_brain_source = __esm({
|
|
@@ -15804,14 +16054,14 @@ var init_gemini_brain_source = __esm({
|
|
|
15804
16054
|
const filePath = join28(sessionDir, file);
|
|
15805
16055
|
try {
|
|
15806
16056
|
const stat3 = statSync25(filePath);
|
|
15807
|
-
const content =
|
|
16057
|
+
const content = readFileSync19(filePath, "utf-8");
|
|
15808
16058
|
const firstLine = content.split("\n").find((l) => l.trim() && !l.startsWith("#"))?.trim() || "";
|
|
15809
16059
|
const heading = content.split("\n").find((l) => l.startsWith("#"))?.replace(/^#+\s*/, "").trim() || file;
|
|
15810
16060
|
const metaPath = `${filePath}.metadata.json`;
|
|
15811
16061
|
let metaSummary = "";
|
|
15812
16062
|
if (existsSync27(metaPath)) {
|
|
15813
16063
|
try {
|
|
15814
|
-
const meta = JSON.parse(
|
|
16064
|
+
const meta = JSON.parse(readFileSync19(metaPath, "utf-8"));
|
|
15815
16065
|
metaSummary = meta.summary || "";
|
|
15816
16066
|
} catch {
|
|
15817
16067
|
}
|
|
@@ -15842,7 +16092,7 @@ var init_gemini_brain_source = __esm({
|
|
|
15842
16092
|
async parse(item) {
|
|
15843
16093
|
if (!existsSync27(item.filePath))
|
|
15844
16094
|
return [];
|
|
15845
|
-
const content =
|
|
16095
|
+
const content = readFileSync19(item.filePath, "utf-8");
|
|
15846
16096
|
const chunks = [];
|
|
15847
16097
|
const sections = splitByHeaders(content);
|
|
15848
16098
|
for (let i = 0; i < sections.length; i++) {
|
|
@@ -16185,7 +16435,7 @@ var init_opencode_todo_source = __esm({
|
|
|
16185
16435
|
});
|
|
16186
16436
|
|
|
16187
16437
|
// ../engine/dist/parsers/codex-session-source.js
|
|
16188
|
-
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";
|
|
16189
16439
|
import { join as join29, basename as basename18 } from "path";
|
|
16190
16440
|
function getCodexSessionsDir() {
|
|
16191
16441
|
return codexBackend.sessionsDir();
|
|
@@ -16213,7 +16463,7 @@ function extractReasoningText(event) {
|
|
|
16213
16463
|
return "";
|
|
16214
16464
|
}
|
|
16215
16465
|
function readJsonlLines(filePath) {
|
|
16216
|
-
const text =
|
|
16466
|
+
const text = readFileSync20(filePath, "utf-8");
|
|
16217
16467
|
const lines = text.split("\n");
|
|
16218
16468
|
const events = [];
|
|
16219
16469
|
for (const line of lines) {
|
|
@@ -16248,7 +16498,7 @@ var init_codex_session_source = __esm({
|
|
|
16248
16498
|
for (const filePath of jsonlFiles) {
|
|
16249
16499
|
try {
|
|
16250
16500
|
const stat3 = statSync26(filePath);
|
|
16251
|
-
const lines =
|
|
16501
|
+
const lines = readFileSync20(filePath, "utf-8").split("\n");
|
|
16252
16502
|
const firstLine = lines.find((l) => l.trim());
|
|
16253
16503
|
if (!firstLine)
|
|
16254
16504
|
continue;
|
|
@@ -16421,7 +16671,7 @@ var init_codex_session_source = __esm({
|
|
|
16421
16671
|
});
|
|
16422
16672
|
|
|
16423
16673
|
// ../engine/dist/parsers/diary-source.js
|
|
16424
|
-
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";
|
|
16425
16675
|
import { join as join30, basename as basename19 } from "path";
|
|
16426
16676
|
var MAX_CHUNK_CHARS11, DiarySource;
|
|
16427
16677
|
var init_diary_source = __esm({
|
|
@@ -16447,7 +16697,7 @@ var init_diary_source = __esm({
|
|
|
16447
16697
|
const filePath = join30(agentPath2, file);
|
|
16448
16698
|
try {
|
|
16449
16699
|
const stat3 = statSync27(filePath);
|
|
16450
|
-
const raw =
|
|
16700
|
+
const raw = readFileSync21(filePath, "utf-8");
|
|
16451
16701
|
const entry = JSON.parse(raw);
|
|
16452
16702
|
const entryId = basename19(file, ".json");
|
|
16453
16703
|
const title = `[${entry.agent}] ${entry.topic}: ${entry.content.slice(0, 80)}`;
|
|
@@ -16474,7 +16724,7 @@ var init_diary_source = __esm({
|
|
|
16474
16724
|
async parse(item) {
|
|
16475
16725
|
if (!existsSync31(item.filePath))
|
|
16476
16726
|
return [];
|
|
16477
|
-
const raw =
|
|
16727
|
+
const raw = readFileSync21(item.filePath, "utf-8");
|
|
16478
16728
|
const entry = JSON.parse(raw);
|
|
16479
16729
|
if (!entry.content || entry.content.trim().length < 10)
|
|
16480
16730
|
return [];
|
|
@@ -16537,7 +16787,7 @@ var init_diary_source = __esm({
|
|
|
16537
16787
|
const entries = [];
|
|
16538
16788
|
for (const file of files) {
|
|
16539
16789
|
try {
|
|
16540
|
-
const raw =
|
|
16790
|
+
const raw = readFileSync21(join30(agentDir, file), "utf-8");
|
|
16541
16791
|
entries.push(JSON.parse(raw));
|
|
16542
16792
|
} catch {
|
|
16543
16793
|
continue;
|
|
@@ -16550,7 +16800,7 @@ var init_diary_source = __esm({
|
|
|
16550
16800
|
});
|
|
16551
16801
|
|
|
16552
16802
|
// ../engine/dist/parsers/skills-source.js
|
|
16553
|
-
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";
|
|
16554
16804
|
import { homedir as homedir12 } from "os";
|
|
16555
16805
|
import { join as join31 } from "path";
|
|
16556
16806
|
function resolveRoots() {
|
|
@@ -16643,7 +16893,7 @@ var init_skills_source = __esm({
|
|
|
16643
16893
|
continue;
|
|
16644
16894
|
let content;
|
|
16645
16895
|
try {
|
|
16646
|
-
content =
|
|
16896
|
+
content = readFileSync22(skillMd, "utf-8");
|
|
16647
16897
|
} catch {
|
|
16648
16898
|
continue;
|
|
16649
16899
|
}
|
|
@@ -16703,7 +16953,7 @@ var init_skills_source = __esm({
|
|
|
16703
16953
|
async parse(item) {
|
|
16704
16954
|
if (!existsSync32(item.filePath))
|
|
16705
16955
|
return [];
|
|
16706
|
-
const content =
|
|
16956
|
+
const content = readFileSync22(item.filePath, "utf-8");
|
|
16707
16957
|
if (!content.trim())
|
|
16708
16958
|
return [];
|
|
16709
16959
|
return [{
|
|
@@ -16726,14 +16976,14 @@ var init_skills_source = __esm({
|
|
|
16726
16976
|
});
|
|
16727
16977
|
|
|
16728
16978
|
// ../engine/dist/parsers/mcps-source.js
|
|
16729
|
-
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";
|
|
16730
16980
|
import { homedir as homedir13 } from "os";
|
|
16731
16981
|
import { join as join32 } from "path";
|
|
16732
16982
|
function readJson(path) {
|
|
16733
16983
|
if (!existsSync33(path))
|
|
16734
16984
|
return null;
|
|
16735
16985
|
try {
|
|
16736
|
-
const raw =
|
|
16986
|
+
const raw = readFileSync23(path, "utf-8");
|
|
16737
16987
|
const stripped = path.endsWith(".jsonc") ? raw.replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|[^:])\/\/.*$/gm, "$1").replace(/,(\s*[}\]])/g, "$1") : raw;
|
|
16738
16988
|
return JSON.parse(stripped);
|
|
16739
16989
|
} catch {
|
|
@@ -16846,7 +17096,7 @@ var init_mcps_source = __esm({
|
|
|
16846
17096
|
return;
|
|
16847
17097
|
let content;
|
|
16848
17098
|
try {
|
|
16849
|
-
content =
|
|
17099
|
+
content = readFileSync23(path, "utf-8");
|
|
16850
17100
|
} catch {
|
|
16851
17101
|
return;
|
|
16852
17102
|
}
|
|
@@ -17015,7 +17265,7 @@ var init_toolkit_format = __esm({
|
|
|
17015
17265
|
});
|
|
17016
17266
|
|
|
17017
17267
|
// ../engine/dist/parsers/slash-commands-source.js
|
|
17018
|
-
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";
|
|
17019
17269
|
import { join as join33, basename as basename20 } from "path";
|
|
17020
17270
|
function parseCommand(content, fallbackName, format) {
|
|
17021
17271
|
if (format === "toml") {
|
|
@@ -17043,6 +17293,7 @@ var init_slash_commands_source = __esm({
|
|
|
17043
17293
|
init_codex2();
|
|
17044
17294
|
init_settings();
|
|
17045
17295
|
init_toolkit_format();
|
|
17296
|
+
init_project_dir_name();
|
|
17046
17297
|
MAX_CHUNK_CHARS13 = 2e3;
|
|
17047
17298
|
SlashCommandsSource = class {
|
|
17048
17299
|
sourceType = "command";
|
|
@@ -17056,7 +17307,7 @@ var init_slash_commands_source = __esm({
|
|
|
17056
17307
|
for (const entry of readdirSync26(projectsRoot, { withFileTypes: true })) {
|
|
17057
17308
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
17058
17309
|
continue;
|
|
17059
|
-
const projectPath = entry.name
|
|
17310
|
+
const projectPath = decodeProjectDirName(entry.name);
|
|
17060
17311
|
const cmdDir = join33(projectPath, ".claude", "commands");
|
|
17061
17312
|
if (existsSync34(cmdDir))
|
|
17062
17313
|
roots.push({ path: cmdDir, tool: "claude", scope: "project", projectPath, format: "md" });
|
|
@@ -17089,7 +17340,7 @@ var init_slash_commands_source = __esm({
|
|
|
17089
17340
|
const filePath = join33(root.path, file);
|
|
17090
17341
|
try {
|
|
17091
17342
|
const stat3 = statSync30(filePath);
|
|
17092
|
-
const content =
|
|
17343
|
+
const content = readFileSync24(filePath, "utf-8");
|
|
17093
17344
|
const parsed = parseCommand(content, basename20(file, ext), root.format);
|
|
17094
17345
|
yield {
|
|
17095
17346
|
id: `${root.tool}_cmd_${root.scope}_${parsed.name}`,
|
|
@@ -17115,7 +17366,7 @@ var init_slash_commands_source = __esm({
|
|
|
17115
17366
|
async parse(item) {
|
|
17116
17367
|
if (!existsSync34(item.filePath))
|
|
17117
17368
|
return [];
|
|
17118
|
-
const content =
|
|
17369
|
+
const content = readFileSync24(item.filePath, "utf-8");
|
|
17119
17370
|
if (!content.trim())
|
|
17120
17371
|
return [];
|
|
17121
17372
|
return [{
|
|
@@ -17138,7 +17389,7 @@ var init_slash_commands_source = __esm({
|
|
|
17138
17389
|
});
|
|
17139
17390
|
|
|
17140
17391
|
// ../engine/dist/parsers/subagents-source.js
|
|
17141
|
-
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";
|
|
17142
17393
|
import { join as join34, basename as basename21 } from "path";
|
|
17143
17394
|
function parseAgent(content, fallbackName, format) {
|
|
17144
17395
|
if (format === "toml") {
|
|
@@ -17168,6 +17419,7 @@ var init_subagents_source = __esm({
|
|
|
17168
17419
|
init_codex2();
|
|
17169
17420
|
init_settings();
|
|
17170
17421
|
init_toolkit_format();
|
|
17422
|
+
init_project_dir_name();
|
|
17171
17423
|
MAX_CHUNK_CHARS14 = 2e3;
|
|
17172
17424
|
SubagentsSource = class {
|
|
17173
17425
|
sourceType = "agent";
|
|
@@ -17181,7 +17433,7 @@ var init_subagents_source = __esm({
|
|
|
17181
17433
|
for (const entry of readdirSync27(projectsRoot, { withFileTypes: true })) {
|
|
17182
17434
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
17183
17435
|
continue;
|
|
17184
|
-
const projectPath = entry.name
|
|
17436
|
+
const projectPath = decodeProjectDirName(entry.name);
|
|
17185
17437
|
const agentDir = join34(projectPath, ".claude", "agents");
|
|
17186
17438
|
if (existsSync35(agentDir))
|
|
17187
17439
|
roots.push({ path: agentDir, tool: "claude", scope: "project", projectPath, format: "md" });
|
|
@@ -17214,7 +17466,7 @@ var init_subagents_source = __esm({
|
|
|
17214
17466
|
const filePath = join34(root.path, file);
|
|
17215
17467
|
try {
|
|
17216
17468
|
const stat3 = statSync31(filePath);
|
|
17217
|
-
const content =
|
|
17469
|
+
const content = readFileSync25(filePath, "utf-8");
|
|
17218
17470
|
const parsed = parseAgent(content, basename21(file, ext), root.format);
|
|
17219
17471
|
yield {
|
|
17220
17472
|
id: `${root.tool}_agent_${root.scope}_${parsed.name}`,
|
|
@@ -17241,7 +17493,7 @@ var init_subagents_source = __esm({
|
|
|
17241
17493
|
async parse(item) {
|
|
17242
17494
|
if (!existsSync35(item.filePath))
|
|
17243
17495
|
return [];
|
|
17244
|
-
const content =
|
|
17496
|
+
const content = readFileSync25(item.filePath, "utf-8");
|
|
17245
17497
|
if (!content.trim())
|
|
17246
17498
|
return [];
|
|
17247
17499
|
return [{
|
|
@@ -17264,13 +17516,13 @@ var init_subagents_source = __esm({
|
|
|
17264
17516
|
});
|
|
17265
17517
|
|
|
17266
17518
|
// ../engine/dist/parsers/hooks-source.js
|
|
17267
|
-
import { existsSync as existsSync36, readFileSync as
|
|
17519
|
+
import { existsSync as existsSync36, readFileSync as readFileSync26, readdirSync as readdirSync28, statSync as statSync32 } from "fs";
|
|
17268
17520
|
import { join as join35 } from "path";
|
|
17269
17521
|
function readJson2(path) {
|
|
17270
17522
|
if (!existsSync36(path))
|
|
17271
17523
|
return null;
|
|
17272
17524
|
try {
|
|
17273
|
-
return JSON.parse(
|
|
17525
|
+
return JSON.parse(readFileSync26(path, "utf-8"));
|
|
17274
17526
|
} catch {
|
|
17275
17527
|
return null;
|
|
17276
17528
|
}
|
|
@@ -17281,6 +17533,7 @@ var init_hooks_source = __esm({
|
|
|
17281
17533
|
"use strict";
|
|
17282
17534
|
init_claude2();
|
|
17283
17535
|
init_settings();
|
|
17536
|
+
init_project_dir_name();
|
|
17284
17537
|
HooksSource = class {
|
|
17285
17538
|
sourceType = "hook";
|
|
17286
17539
|
async *discover() {
|
|
@@ -17293,7 +17546,7 @@ var init_hooks_source = __esm({
|
|
|
17293
17546
|
for (const entry of readdirSync28(projectsRoot, { withFileTypes: true })) {
|
|
17294
17547
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
17295
17548
|
continue;
|
|
17296
|
-
const projectPath = entry.name
|
|
17549
|
+
const projectPath = decodeProjectDirName(entry.name);
|
|
17297
17550
|
const settingsPath2 = join35(projectPath, ".claude", "settings.json");
|
|
17298
17551
|
if (existsSync36(settingsPath2)) {
|
|
17299
17552
|
yield* this.fromSettings(settingsPath2, "project", projectPath);
|
|
@@ -17386,14 +17639,14 @@ var init_hooks_source = __esm({
|
|
|
17386
17639
|
});
|
|
17387
17640
|
|
|
17388
17641
|
// ../engine/dist/parsers/plugins-source.js
|
|
17389
|
-
import { existsSync as existsSync37, readFileSync as
|
|
17642
|
+
import { existsSync as existsSync37, readFileSync as readFileSync27, readdirSync as readdirSync29, statSync as statSync33 } from "fs";
|
|
17390
17643
|
import { homedir as homedir14 } from "os";
|
|
17391
17644
|
import { join as join36 } from "path";
|
|
17392
17645
|
function readJson3(path) {
|
|
17393
17646
|
if (!existsSync37(path))
|
|
17394
17647
|
return null;
|
|
17395
17648
|
try {
|
|
17396
|
-
return JSON.parse(
|
|
17649
|
+
return JSON.parse(readFileSync27(path, "utf-8"));
|
|
17397
17650
|
} catch {
|
|
17398
17651
|
return null;
|
|
17399
17652
|
}
|
|
@@ -17641,14 +17894,16 @@ var init_extractor_version = __esm({
|
|
|
17641
17894
|
"use strict";
|
|
17642
17895
|
BASE_EXTRACTOR_VERSION = 2;
|
|
17643
17896
|
TOOL_EXTRACTOR_BUMP = {
|
|
17644
|
-
agy: 2
|
|
17897
|
+
agy: 2,
|
|
17898
|
+
claude: 1,
|
|
17899
|
+
codex: 1
|
|
17645
17900
|
};
|
|
17646
17901
|
EXTRACTOR_VERSION = BASE_EXTRACTOR_VERSION;
|
|
17647
17902
|
}
|
|
17648
17903
|
});
|
|
17649
17904
|
|
|
17650
17905
|
// src/sync-ledger.ts
|
|
17651
|
-
import { readFileSync as
|
|
17906
|
+
import { readFileSync as readFileSync28, writeFileSync as writeFileSync5, renameSync as renameSync4, mkdirSync as mkdirSync6 } from "node:fs";
|
|
17652
17907
|
import { join as join37, dirname as dirname14 } from "node:path";
|
|
17653
17908
|
function toRow(entry) {
|
|
17654
17909
|
if (entry === void 0) return void 0;
|
|
@@ -17660,24 +17915,77 @@ function ledgerFilePath() {
|
|
|
17660
17915
|
function load() {
|
|
17661
17916
|
if (cache3) return cache3;
|
|
17662
17917
|
try {
|
|
17663
|
-
const parsed = JSON.parse(
|
|
17918
|
+
const parsed = JSON.parse(readFileSync28(ledgerPath(), "utf-8"));
|
|
17664
17919
|
cache3 = parsed && typeof parsed === "object" ? parsed : {};
|
|
17665
17920
|
} catch {
|
|
17666
17921
|
cache3 = {};
|
|
17667
17922
|
}
|
|
17668
17923
|
return cache3;
|
|
17669
17924
|
}
|
|
17670
|
-
function
|
|
17925
|
+
function persistNow(data) {
|
|
17671
17926
|
const path = ledgerPath();
|
|
17672
17927
|
mkdirSync6(dirname14(path), { recursive: true });
|
|
17673
17928
|
const tmp = `${path}.tmp`;
|
|
17674
17929
|
writeFileSync5(tmp, JSON.stringify(data));
|
|
17675
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);
|
|
17676
17984
|
}
|
|
17677
17985
|
function loadItemVersionsAll() {
|
|
17678
17986
|
if (itemVersionsCache) return itemVersionsCache;
|
|
17679
17987
|
try {
|
|
17680
|
-
const parsed = JSON.parse(
|
|
17988
|
+
const parsed = JSON.parse(readFileSync28(itemVersionsPath(), "utf-8"));
|
|
17681
17989
|
itemVersionsCache = parsed && typeof parsed === "object" ? parsed : {};
|
|
17682
17990
|
} catch {
|
|
17683
17991
|
itemVersionsCache = {};
|
|
@@ -17759,7 +18067,7 @@ function markFieldCoverage(server, field, rows) {
|
|
|
17759
18067
|
function loadReconcile() {
|
|
17760
18068
|
if (reconcileCache) return reconcileCache;
|
|
17761
18069
|
try {
|
|
17762
|
-
const parsed = JSON.parse(
|
|
18070
|
+
const parsed = JSON.parse(readFileSync28(reconcilePath(), "utf-8"));
|
|
17763
18071
|
reconcileCache = parsed && typeof parsed === "object" ? parsed : {};
|
|
17764
18072
|
} catch {
|
|
17765
18073
|
reconcileCache = {};
|
|
@@ -17807,7 +18115,7 @@ function syncMode(row, mtime, fileSize, extractorVersion, isAppendOnly) {
|
|
|
17807
18115
|
if (row.m >= Math.floor(mtime)) return "skip";
|
|
17808
18116
|
return "full";
|
|
17809
18117
|
}
|
|
17810
|
-
var ledgerPath, cache3, itemVersionsPath, itemVersionsCache, unackedCursorAttempts, reconcilePath, reconcileCache;
|
|
18118
|
+
var ledgerPath, cache3, LEDGER_FLUSH_MS, pendingWrite, flushTimer, itemVersionsPath, itemVersionsCache, unackedCursorAttempts, reconcilePath, reconcileCache;
|
|
17811
18119
|
var init_sync_ledger = __esm({
|
|
17812
18120
|
"src/sync-ledger.ts"() {
|
|
17813
18121
|
"use strict";
|
|
@@ -17815,6 +18123,9 @@ var init_sync_ledger = __esm({
|
|
|
17815
18123
|
init_extractor_version();
|
|
17816
18124
|
ledgerPath = () => join37(getDataDir(), "sync-ledger.json");
|
|
17817
18125
|
cache3 = null;
|
|
18126
|
+
LEDGER_FLUSH_MS = 2e3;
|
|
18127
|
+
pendingWrite = false;
|
|
18128
|
+
flushTimer = null;
|
|
17818
18129
|
itemVersionsPath = () => join37(getDataDir(), "item-versions.json");
|
|
17819
18130
|
itemVersionsCache = null;
|
|
17820
18131
|
unackedCursorAttempts = 0;
|
|
@@ -17849,7 +18160,7 @@ var init_sync_fields = __esm({
|
|
|
17849
18160
|
});
|
|
17850
18161
|
|
|
17851
18162
|
// ../engine/dist/core/index-lock.js
|
|
17852
|
-
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";
|
|
17853
18164
|
import { dirname as dirname15, join as join38 } from "path";
|
|
17854
18165
|
function acquireIndexLock(opts) {
|
|
17855
18166
|
const lockPath = lockFilePath();
|
|
@@ -17861,7 +18172,7 @@ function acquireIndexLock(opts) {
|
|
|
17861
18172
|
}
|
|
17862
18173
|
let fd;
|
|
17863
18174
|
try {
|
|
17864
|
-
fd =
|
|
18175
|
+
fd = openSync7(lockPath, "wx", 384);
|
|
17865
18176
|
} catch (err) {
|
|
17866
18177
|
if (err.code === "EEXIST")
|
|
17867
18178
|
return null;
|
|
@@ -17871,7 +18182,7 @@ function acquireIndexLock(opts) {
|
|
|
17871
18182
|
try {
|
|
17872
18183
|
writeFileSync6(fd, JSON.stringify(holder));
|
|
17873
18184
|
} finally {
|
|
17874
|
-
|
|
18185
|
+
closeSync7(fd);
|
|
17875
18186
|
}
|
|
17876
18187
|
let released = false;
|
|
17877
18188
|
return {
|
|
@@ -17881,7 +18192,7 @@ function acquireIndexLock(opts) {
|
|
|
17881
18192
|
return;
|
|
17882
18193
|
released = true;
|
|
17883
18194
|
try {
|
|
17884
|
-
const current = JSON.parse(
|
|
18195
|
+
const current = JSON.parse(readFileSync29(lockPath, "utf-8"));
|
|
17885
18196
|
if (current.pid !== holder.pid || current.startedAt !== holder.startedAt)
|
|
17886
18197
|
return;
|
|
17887
18198
|
} catch {
|
|
@@ -17903,7 +18214,7 @@ function stealStaleLock(lockPath, staleAfterMs) {
|
|
|
17903
18214
|
const age = Date.now() - s.mtimeMs;
|
|
17904
18215
|
let payload;
|
|
17905
18216
|
try {
|
|
17906
|
-
payload = JSON.parse(
|
|
18217
|
+
payload = JSON.parse(readFileSync29(lockPath, "utf-8"));
|
|
17907
18218
|
} catch {
|
|
17908
18219
|
rmSync4(lockPath, { force: true });
|
|
17909
18220
|
return true;
|
|
@@ -17947,7 +18258,7 @@ __export(http_exports, {
|
|
|
17947
18258
|
clientHeaders: () => clientHeaders,
|
|
17948
18259
|
fetchWithTimeout: () => fetchWithTimeout
|
|
17949
18260
|
});
|
|
17950
|
-
import { readFileSync as
|
|
18261
|
+
import { readFileSync as readFileSync30 } from "node:fs";
|
|
17951
18262
|
function cliVersion() {
|
|
17952
18263
|
return CLI_VERSION;
|
|
17953
18264
|
}
|
|
@@ -17968,10 +18279,10 @@ var init_http = __esm({
|
|
|
17968
18279
|
"use strict";
|
|
17969
18280
|
CLI_VERSION = "0.0.0";
|
|
17970
18281
|
try {
|
|
17971
|
-
CLI_VERSION = JSON.parse(
|
|
18282
|
+
CLI_VERSION = JSON.parse(readFileSync30(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
|
|
17972
18283
|
} catch {
|
|
17973
18284
|
try {
|
|
17974
|
-
if (true) CLI_VERSION = "0.5.
|
|
18285
|
+
if (true) CLI_VERSION = "0.5.6";
|
|
17975
18286
|
} catch {
|
|
17976
18287
|
}
|
|
17977
18288
|
}
|
|
@@ -17984,7 +18295,7 @@ __export(client_events_exports, {
|
|
|
17984
18295
|
isTelemetryEnabled: () => isTelemetryEnabled,
|
|
17985
18296
|
reportClientEvent: () => reportClientEvent
|
|
17986
18297
|
});
|
|
17987
|
-
import { readFileSync as
|
|
18298
|
+
import { readFileSync as readFileSync31 } from "node:fs";
|
|
17988
18299
|
function scrub(msg) {
|
|
17989
18300
|
if (!msg) return "";
|
|
17990
18301
|
const noHome = msg.replace(/\/(?:home|Users)\/[^/\s]+/g, "~");
|
|
@@ -18037,7 +18348,7 @@ var init_client_events = __esm({
|
|
|
18037
18348
|
init_secret_redactor();
|
|
18038
18349
|
CLI_VERSION2 = "0.0.0";
|
|
18039
18350
|
try {
|
|
18040
|
-
CLI_VERSION2 = JSON.parse(
|
|
18351
|
+
CLI_VERSION2 = JSON.parse(readFileSync31(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION2;
|
|
18041
18352
|
} catch {
|
|
18042
18353
|
}
|
|
18043
18354
|
}
|
|
@@ -18160,6 +18471,7 @@ var sync_client_exports = {};
|
|
|
18160
18471
|
__export(sync_client_exports, {
|
|
18161
18472
|
BATCH_SCAN_MAX_BYTES: () => BATCH_SCAN_MAX_BYTES,
|
|
18162
18473
|
FULL_BUILD_MAX_BYTES: () => FULL_BUILD_MAX_BYTES,
|
|
18474
|
+
_resetCapsCacheForTests: () => _resetCapsCacheForTests,
|
|
18163
18475
|
_resetTenantSecurityConfigCache: () => _resetTenantSecurityConfigCache,
|
|
18164
18476
|
_resetTenantSyncConfigCache: () => _resetTenantSyncConfigCache,
|
|
18165
18477
|
batchScanExternal: () => batchScanExternal,
|
|
@@ -18177,7 +18489,7 @@ __export(sync_client_exports, {
|
|
|
18177
18489
|
syncSessions: () => syncSessions
|
|
18178
18490
|
});
|
|
18179
18491
|
import { join as join40, dirname as dirname16, basename as basename22 } from "node:path";
|
|
18180
|
-
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";
|
|
18181
18493
|
import { tmpdir as tmpdir3, hostname } from "node:os";
|
|
18182
18494
|
import { createHash as createHash13 } from "node:crypto";
|
|
18183
18495
|
import { fileURLToPath } from "node:url";
|
|
@@ -18199,8 +18511,10 @@ function saveCredentials(c) {
|
|
|
18199
18511
|
}
|
|
18200
18512
|
}
|
|
18201
18513
|
function loadAllCredentials() {
|
|
18514
|
+
const fromEnv = envCredentials();
|
|
18515
|
+
if (fromEnv) return [{ serverUrl: fromEnv.serverUrl, token: fromEnv.token }];
|
|
18202
18516
|
try {
|
|
18203
|
-
const parsed = JSON.parse(
|
|
18517
|
+
const parsed = JSON.parse(readFileSync32(credPath(), "utf-8"));
|
|
18204
18518
|
if (Array.isArray(parsed?.targets)) return parsed.targets.filter((t) => t?.serverUrl).map((t) => ({ serverUrl: t.serverUrl, token: t.token || "" }));
|
|
18205
18519
|
if (parsed?.serverUrl) return [{ serverUrl: parsed.serverUrl, token: parsed.token || "" }];
|
|
18206
18520
|
} catch {
|
|
@@ -18359,6 +18673,10 @@ function isLocalHost(serverUrl) {
|
|
|
18359
18673
|
async function syncSessions(opts = {}) {
|
|
18360
18674
|
const targets = loadAllCredentials();
|
|
18361
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
|
+
}
|
|
18362
18680
|
let agg = null;
|
|
18363
18681
|
const errors = [];
|
|
18364
18682
|
for (const cred of targets) {
|
|
@@ -18381,6 +18699,7 @@ async function syncSessions(opts = {}) {
|
|
|
18381
18699
|
errors.push(`${cred.serverUrl}: ${e instanceof Error ? e.message : e}`);
|
|
18382
18700
|
}
|
|
18383
18701
|
}
|
|
18702
|
+
flushLedger();
|
|
18384
18703
|
if (!agg) throw new Error(`sync failed for all targets:
|
|
18385
18704
|
${errors.join("\n ")}`);
|
|
18386
18705
|
if (errors.length > 0) console.error(`[sync] ${errors.length} target(s) failed (others succeeded):
|
|
@@ -18406,11 +18725,11 @@ async function reconcileFieldsForTarget(cred, fullRefs, opts = {}) {
|
|
|
18406
18725
|
let pushed = 0, absent = 0, scanned = 0;
|
|
18407
18726
|
for (const field of SYNC_FIELDS) {
|
|
18408
18727
|
const needFull = !!opts.force || fieldNeedsFullPass(base2, field);
|
|
18409
|
-
const
|
|
18728
|
+
const candidates2 = needFull ? fullRefs() : opts.convRefs ?? fullRefs();
|
|
18410
18729
|
const send = [];
|
|
18411
18730
|
const mtimeById = /* @__PURE__ */ new Map();
|
|
18412
18731
|
const absentIds = [];
|
|
18413
|
-
for (const ref of
|
|
18732
|
+
for (const ref of candidates2) {
|
|
18414
18733
|
if (!fieldNeedsScan(ledger.get(ref.prefixedId), field, ref.mtime, opts.force)) continue;
|
|
18415
18734
|
scanned++;
|
|
18416
18735
|
mtimeById.set(ref.prefixedId, ref.mtime);
|
|
@@ -18531,6 +18850,20 @@ function batchScanExternal(items, opts = {}) {
|
|
|
18531
18850
|
}
|
|
18532
18851
|
return { findings, scanned, slices, scanMs };
|
|
18533
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
|
+
}
|
|
18534
18867
|
async function syncToTarget(cred, opts = {}) {
|
|
18535
18868
|
const sync = loadSettings().sync;
|
|
18536
18869
|
const serverCfg = await fetchTenantSyncConfig(cred);
|
|
@@ -18551,14 +18884,9 @@ async function syncToTarget(cred, opts = {}) {
|
|
|
18551
18884
|
return isProjectSyncable(r.source === "ignored" ? "" : r.id, projectPath, { syncMode: "only", syncOnly: syncOnly2 });
|
|
18552
18885
|
};
|
|
18553
18886
|
const MIN_SERVER_API = 2;
|
|
18554
|
-
|
|
18555
|
-
const
|
|
18556
|
-
if ((
|
|
18557
|
-
throw new Error(`server too old: apiVersion ${caps.apiVersion ?? "none"} < required ${MIN_SERVER_API} \u2014 update the server image before syncing`);
|
|
18558
|
-
}
|
|
18559
|
-
} catch (e) {
|
|
18560
|
-
if (e instanceof Error && e.message.startsWith("server too old")) throw e;
|
|
18561
|
-
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`);
|
|
18562
18890
|
}
|
|
18563
18891
|
const { tenantRules, verifySecrets } = await fetchTenantSecurityConfig(cred);
|
|
18564
18892
|
const CHANGED_WALK_OVERLAP_MS = 15 * 6e4;
|
|
@@ -18610,6 +18938,20 @@ async function syncToTarget(cred, opts = {}) {
|
|
|
18610
18938
|
if (res.status === 401 || res.status === 403) {
|
|
18611
18939
|
throw new Error(`server rejected this machine's device token (HTTP ${res.status} \u2014 revoked?). Reconnect with: chat-recall login ${base2}`);
|
|
18612
18940
|
}
|
|
18941
|
+
if (res.status === 402) {
|
|
18942
|
+
let detail = text;
|
|
18943
|
+
try {
|
|
18944
|
+
const body2 = JSON.parse(text);
|
|
18945
|
+
detail = body2.error ?? text;
|
|
18946
|
+
if (body2.detail) detail += `
|
|
18947
|
+
${body2.detail}`;
|
|
18948
|
+
if (body2.resetsAt) detail += ` (resets ${new Date(body2.resetsAt).toISOString().slice(0, 10)})`;
|
|
18949
|
+
if (body2.upgradeUrl) detail += `
|
|
18950
|
+
${body2.upgradeUrl}`;
|
|
18951
|
+
} catch {
|
|
18952
|
+
}
|
|
18953
|
+
throw new Error(`sync paused by the server: ${detail}`);
|
|
18954
|
+
}
|
|
18613
18955
|
if (!retryable) throw new Error(`sync failed: HTTP ${res.status} ${text}`);
|
|
18614
18956
|
if (attempt >= RETRY_DELAYS_MS.length) throw new Error(`sync failed after ${attempt + 1} attempts: HTTP ${res.status} ${text}`);
|
|
18615
18957
|
const retryAfterS = Number(res.headers.get("retry-after"));
|
|
@@ -18752,16 +19094,21 @@ async function syncToTarget(cred, opts = {}) {
|
|
|
18752
19094
|
const findingsBatch = makeBatcher("findings", 200, true);
|
|
18753
19095
|
const scanSecrets = isSecretScannerAvailable() && upload.findings && process.env.CHAT_RECALL_SCAN_SECRETS !== "0";
|
|
18754
19096
|
const verifySecretsScan = verifySecrets;
|
|
19097
|
+
let skipped = 0, redactions = 0, walked = 0;
|
|
18755
19098
|
const kgSeen = /* @__PURE__ */ new Set();
|
|
18756
19099
|
const kgEntityType = /* @__PURE__ */ new Map();
|
|
18757
|
-
const
|
|
18758
|
-
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) => {
|
|
18759
19103
|
for (const t of triples) {
|
|
18760
|
-
const key =
|
|
19104
|
+
const key = kgKey(t.subject, t.predicate, t.object, t.validFrom ?? "");
|
|
18761
19105
|
if (kgSeen.has(key)) continue;
|
|
18762
19106
|
kgSeen.add(key);
|
|
18763
19107
|
if (t.predicate === "is_a" && !kgEntityType.has(t.subject)) kgEntityType.set(t.subject, t.object);
|
|
18764
|
-
|
|
19108
|
+
kgEntityNames.add(t.subject);
|
|
19109
|
+
kgEntityNames.add(t.object);
|
|
19110
|
+
const count = { redactions: 0 };
|
|
19111
|
+
await kgTripleBatch.add(redactDeep({
|
|
18765
19112
|
subject: t.subject,
|
|
18766
19113
|
predicate: t.predicate,
|
|
18767
19114
|
object: t.object,
|
|
@@ -18769,10 +19116,10 @@ async function syncToTarget(cred, opts = {}) {
|
|
|
18769
19116
|
valid_to: null,
|
|
18770
19117
|
confidence: t.confidence ?? 1,
|
|
18771
19118
|
source_session: sourceSession
|
|
18772
|
-
});
|
|
19119
|
+
}, count));
|
|
19120
|
+
redactions += count.redactions;
|
|
18773
19121
|
}
|
|
18774
19122
|
};
|
|
18775
|
-
let skipped = 0, redactions = 0, walked = 0;
|
|
18776
19123
|
let scanMs = 0, scanned = 0;
|
|
18777
19124
|
const slice = refs.slice(0, opts.limit ?? refs.length);
|
|
18778
19125
|
const trace = process.env.CHAT_RECALL_SYNC_TRACE === "1" ? (msg) => {
|
|
@@ -18905,7 +19252,7 @@ async function syncToTarget(cred, opts = {}) {
|
|
|
18905
19252
|
await convBatch.add(built.conv);
|
|
18906
19253
|
if (built.findings.length > 0) await findingsBatch.add(built.findings);
|
|
18907
19254
|
if (upload.sessionMeta) {
|
|
18908
|
-
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);
|
|
18909
19256
|
}
|
|
18910
19257
|
if (upload.sessionMeta && sessionFileBytes(ref) <= FULL_BUILD_MAX_BYTES) {
|
|
18911
19258
|
try {
|
|
@@ -18984,7 +19331,7 @@ async function syncToTarget(cred, opts = {}) {
|
|
|
18984
19331
|
chunks: redactedChunks
|
|
18985
19332
|
});
|
|
18986
19333
|
if (upload.sessionMeta && redactedChunks.length > 0) {
|
|
18987
|
-
accumulateKg(
|
|
19334
|
+
await accumulateKg(
|
|
18988
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 }),
|
|
18989
19336
|
null
|
|
18990
19337
|
);
|
|
@@ -19009,16 +19356,8 @@ async function syncToTarget(cred, opts = {}) {
|
|
|
19009
19356
|
}
|
|
19010
19357
|
}
|
|
19011
19358
|
}
|
|
19012
|
-
if (upload.sessionMeta &&
|
|
19013
|
-
const
|
|
19014
|
-
for (const t of kgRows) {
|
|
19015
|
-
const count = { redactions: 0 };
|
|
19016
|
-
await kgTripleBatch.add(redactDeep(t, count));
|
|
19017
|
-
redactions += count.redactions;
|
|
19018
|
-
entityNames.add(t.subject);
|
|
19019
|
-
entityNames.add(t.object);
|
|
19020
|
-
}
|
|
19021
|
-
for (const name of entityNames) {
|
|
19359
|
+
if (upload.sessionMeta && kgEntityNames.size > 0) {
|
|
19360
|
+
for (const name of kgEntityNames) {
|
|
19022
19361
|
const count = { redactions: 0 };
|
|
19023
19362
|
await kgEntityBatch.add(redactDeep({ name, type: kgEntityType.get(name) ?? "unknown", properties: {} }, count));
|
|
19024
19363
|
redactions += count.redactions;
|
|
@@ -19378,56 +19717,58 @@ function collectDerived(ref, mtime, count) {
|
|
|
19378
19717
|
const id = ref.prefixedId;
|
|
19379
19718
|
const compute = [];
|
|
19380
19719
|
let fullOutcome = null;
|
|
19381
|
-
|
|
19382
|
-
|
|
19383
|
-
|
|
19384
|
-
|
|
19385
|
-
|
|
19386
|
-
|
|
19387
|
-
|
|
19388
|
-
|
|
19389
|
-
|
|
19390
|
-
|
|
19391
|
-
if (
|
|
19392
|
-
|
|
19393
|
-
|
|
19394
|
-
|
|
19395
|
-
|
|
19396
|
-
|
|
19397
|
-
|
|
19398
|
-
|
|
19399
|
-
|
|
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
|
+
};
|
|
19400
19764
|
}
|
|
19401
|
-
|
|
19402
|
-
|
|
19403
|
-
|
|
19404
|
-
|
|
19405
|
-
|
|
19406
|
-
let outcomeRow = null;
|
|
19407
|
-
if (fullOutcome?.found) {
|
|
19408
|
-
outcomeRow = {
|
|
19409
|
-
sessionId: id,
|
|
19410
|
-
tool: ref.toolId,
|
|
19411
|
-
status: fullOutcome.status,
|
|
19412
|
-
reason: fullOutcome.reason,
|
|
19413
|
-
fileMtime: mtime,
|
|
19414
|
-
fileSize: 0,
|
|
19415
|
-
contentHash: "",
|
|
19416
|
-
fileCount: fullOutcome.fileCount,
|
|
19417
|
-
linesAdded: fullOutcome.totalLinesAdded,
|
|
19418
|
-
linesRemoved: fullOutcome.totalLinesRemoved,
|
|
19419
|
-
commits: fullOutcome.commits?.totalCommits ?? 0,
|
|
19420
|
-
isFull: true,
|
|
19421
|
-
classifiedAt: Date.now(),
|
|
19422
|
-
lastScannedOffset: 0
|
|
19765
|
+
return {
|
|
19766
|
+
session_id: id,
|
|
19767
|
+
mtime,
|
|
19768
|
+
compute,
|
|
19769
|
+
outcome_row: outcomeRow ? redactDeep({ ...outcomeRow, sessionId: void 0 }, count) : null
|
|
19423
19770
|
};
|
|
19424
|
-
}
|
|
19425
|
-
return {
|
|
19426
|
-
session_id: id,
|
|
19427
|
-
mtime,
|
|
19428
|
-
compute,
|
|
19429
|
-
outcome_row: outcomeRow ? redactDeep({ ...outcomeRow, sessionId: void 0 }, count) : null
|
|
19430
|
-
};
|
|
19771
|
+
});
|
|
19431
19772
|
}
|
|
19432
19773
|
function isSyncSkip(r) {
|
|
19433
19774
|
return typeof r.skipped === "string";
|
|
@@ -19456,10 +19797,11 @@ async function syncIncremental(opts = {}) {
|
|
|
19456
19797
|
lock.release();
|
|
19457
19798
|
}
|
|
19458
19799
|
}
|
|
19459
|
-
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;
|
|
19460
19801
|
var init_sync_client = __esm({
|
|
19461
19802
|
"src/sync-client.ts"() {
|
|
19462
19803
|
"use strict";
|
|
19804
|
+
init_credentials_env();
|
|
19463
19805
|
init_secret_redactor();
|
|
19464
19806
|
init_source_discovery();
|
|
19465
19807
|
init_home_discovery();
|
|
@@ -19487,14 +19829,15 @@ var init_sync_client = __esm({
|
|
|
19487
19829
|
init_sync_fields();
|
|
19488
19830
|
init_index_lock();
|
|
19489
19831
|
init_http();
|
|
19832
|
+
init_live_session_scan();
|
|
19490
19833
|
init_backends();
|
|
19491
19834
|
ownVersion = "0.0.0";
|
|
19492
19835
|
try {
|
|
19493
19836
|
const dir = dirname16(fileURLToPath(import.meta.url));
|
|
19494
|
-
ownVersion = JSON.parse(
|
|
19837
|
+
ownVersion = JSON.parse(readFileSync32(join40(dir, "../package.json"), "utf-8")).version || ownVersion;
|
|
19495
19838
|
} catch {
|
|
19496
19839
|
try {
|
|
19497
|
-
if (true) ownVersion = "0.5.
|
|
19840
|
+
if (true) ownVersion = "0.5.6";
|
|
19498
19841
|
} catch {
|
|
19499
19842
|
}
|
|
19500
19843
|
}
|
|
@@ -19505,6 +19848,8 @@ var init_sync_client = __esm({
|
|
|
19505
19848
|
hashPath = (p) => p ? "p_" + createHash13("sha256").update(p).digest("hex").slice(0, 12) : "";
|
|
19506
19849
|
COMPUTE_KINDS = ["diff", "outcome", "commits", "markers"];
|
|
19507
19850
|
MAX_DERIVED_ROW_BYTES = 2 * 1024 * 1024;
|
|
19851
|
+
CAPS_TTL_MS = 60 * 6e4;
|
|
19852
|
+
capsOk = /* @__PURE__ */ new Map();
|
|
19508
19853
|
FULL_BUILD_MAX_BYTES = Math.max(8, parseInt(process.env.CHAT_RECALL_FULL_BUILD_MAX_MB || "64", 10)) * 1024 * 1024;
|
|
19509
19854
|
FULL_BUILD_TAIL_BYTES = 16 * 1024 * 1024;
|
|
19510
19855
|
BATCH_SCAN_MAX_BYTES = Math.max(1, parseInt(process.env.CHAT_RECALL_BATCHSCAN_MAX_MB || "64", 10)) * 1024 * 1024;
|
|
@@ -19518,11 +19863,11 @@ __export(update_notice_exports, {
|
|
|
19518
19863
|
refreshUpdateCheck: () => refreshUpdateCheck,
|
|
19519
19864
|
updateNotice: () => updateNotice
|
|
19520
19865
|
});
|
|
19521
|
-
import { readFileSync as
|
|
19866
|
+
import { readFileSync as readFileSync33, writeFileSync as writeFileSync9 } from "node:fs";
|
|
19522
19867
|
import { join as join41 } from "node:path";
|
|
19523
19868
|
function readCheck() {
|
|
19524
19869
|
try {
|
|
19525
|
-
const c = JSON.parse(
|
|
19870
|
+
const c = JSON.parse(readFileSync33(checkPath(), "utf-8"));
|
|
19526
19871
|
return c && typeof c.serverVersion === "string" ? c : null;
|
|
19527
19872
|
} catch {
|
|
19528
19873
|
return null;
|
|
@@ -19598,6 +19943,282 @@ var init_update_notice = __esm({
|
|
|
19598
19943
|
}
|
|
19599
19944
|
});
|
|
19600
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
|
+
|
|
19601
20222
|
// ../engine/dist/core/companions.js
|
|
19602
20223
|
var companions_exports = {};
|
|
19603
20224
|
__export(companions_exports, {
|
|
@@ -19606,27 +20227,39 @@ __export(companions_exports, {
|
|
|
19606
20227
|
CODEINDEX_INSTALL_DIR: () => CODEINDEX_INSTALL_DIR,
|
|
19607
20228
|
checkCodeindexStatus: () => checkCodeindexStatus,
|
|
19608
20229
|
detectPlatform: () => detectPlatform,
|
|
20230
|
+
expectedCodeindexSha256: () => expectedCodeindexSha256,
|
|
19609
20231
|
installCodeindex: () => installCodeindex,
|
|
19610
20232
|
registerCodeindexMcp: () => registerCodeindexMcp,
|
|
19611
20233
|
uninstallCodeindex: () => uninstallCodeindex,
|
|
19612
20234
|
unregisterCodeindexMcp: () => unregisterCodeindexMcp
|
|
19613
20235
|
});
|
|
19614
|
-
import { existsSync as
|
|
19615
|
-
import { homedir as
|
|
19616
|
-
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";
|
|
19617
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
|
+
}
|
|
19618
20244
|
function detectPlatform() {
|
|
19619
20245
|
const arch = process.arch;
|
|
19620
20246
|
const platform = process.platform;
|
|
19621
20247
|
const archMap = { x64: "x86_64", arm64: "aarch64" };
|
|
19622
|
-
const platformMap = { linux: "linux", darwin: "
|
|
20248
|
+
const platformMap = { linux: "linux", darwin: "macos", win32: "windows" };
|
|
19623
20249
|
const a = archMap[arch];
|
|
19624
20250
|
const p = platformMap[platform];
|
|
19625
20251
|
if (!a || !p) {
|
|
19626
20252
|
return { reason: `Unsupported platform: ${arch}-${platform}` };
|
|
19627
20253
|
}
|
|
19628
|
-
const prebuiltCombos = /* @__PURE__ */ new Set([
|
|
19629
|
-
|
|
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" : ""}`;
|
|
19630
20263
|
if (!prebuiltCombos.has(`${a}-${p}`)) {
|
|
19631
20264
|
return {
|
|
19632
20265
|
artifact,
|
|
@@ -19643,20 +20276,15 @@ function checkCodeindexStatus() {
|
|
|
19643
20276
|
artifactName: platform.artifact,
|
|
19644
20277
|
unsupportedReason: platform.reason
|
|
19645
20278
|
};
|
|
19646
|
-
let foundPath =
|
|
19647
|
-
|
|
19648
|
-
|
|
19649
|
-
if (out)
|
|
19650
|
-
foundPath = out;
|
|
19651
|
-
} catch {
|
|
20279
|
+
let foundPath = resolveOnPath(CODEINDEX_BIN_NAME);
|
|
20280
|
+
if (!foundPath) {
|
|
20281
|
+
foundPath = resolveOnPath(CODEINDEX_BIN_PATH);
|
|
19652
20282
|
}
|
|
19653
|
-
if (!foundPath && existsSync39(CODEINDEX_BIN_PATH))
|
|
19654
|
-
foundPath = CODEINDEX_BIN_PATH;
|
|
19655
20283
|
if (foundPath) {
|
|
19656
20284
|
status.installed = true;
|
|
19657
20285
|
status.path = foundPath;
|
|
19658
20286
|
try {
|
|
19659
|
-
status.size =
|
|
20287
|
+
status.size = statSync37(foundPath).size;
|
|
19660
20288
|
} catch {
|
|
19661
20289
|
}
|
|
19662
20290
|
try {
|
|
@@ -19668,16 +20296,9 @@ function checkCodeindexStatus() {
|
|
|
19668
20296
|
return status;
|
|
19669
20297
|
}
|
|
19670
20298
|
async function downloadArtifact(artifact, dest) {
|
|
19671
|
-
const hasGh = (
|
|
19672
|
-
try {
|
|
19673
|
-
execSync3("command -v gh", { stdio: "ignore" });
|
|
19674
|
-
return true;
|
|
19675
|
-
} catch {
|
|
19676
|
-
return false;
|
|
19677
|
-
}
|
|
19678
|
-
})();
|
|
20299
|
+
const hasGh = isOnPath("gh");
|
|
19679
20300
|
if (hasGh) {
|
|
19680
|
-
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}"`, {
|
|
19681
20302
|
stdio: ["ignore", "pipe", "pipe"],
|
|
19682
20303
|
timeout: 6e4
|
|
19683
20304
|
});
|
|
@@ -19716,15 +20337,26 @@ async function installCodeindex(opts = {}) {
|
|
|
19716
20337
|
return status;
|
|
19717
20338
|
if (!status.prebuiltAvailable)
|
|
19718
20339
|
return status;
|
|
19719
|
-
|
|
20340
|
+
mkdirSync11(CODEINDEX_INSTALL_DIR, { recursive: true });
|
|
19720
20341
|
const tmpPath = `${CODEINDEX_BIN_PATH}.partial`;
|
|
19721
20342
|
try {
|
|
19722
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
|
+
}
|
|
19723
20355
|
chmodSync4(tmpPath, 493);
|
|
19724
20356
|
renameSync5(tmpPath, CODEINDEX_BIN_PATH);
|
|
19725
20357
|
} catch (err) {
|
|
19726
20358
|
try {
|
|
19727
|
-
if (
|
|
20359
|
+
if (existsSync41(tmpPath))
|
|
19728
20360
|
unlinkSync3(tmpPath);
|
|
19729
20361
|
} catch {
|
|
19730
20362
|
}
|
|
@@ -19733,7 +20365,7 @@ async function installCodeindex(opts = {}) {
|
|
|
19733
20365
|
return checkCodeindexStatus();
|
|
19734
20366
|
}
|
|
19735
20367
|
function uninstallCodeindex() {
|
|
19736
|
-
if (
|
|
20368
|
+
if (existsSync41(CODEINDEX_BIN_PATH)) {
|
|
19737
20369
|
unlinkSync3(CODEINDEX_BIN_PATH);
|
|
19738
20370
|
return { removed: true, path: CODEINDEX_BIN_PATH };
|
|
19739
20371
|
}
|
|
@@ -19741,9 +20373,9 @@ function uninstallCodeindex() {
|
|
|
19741
20373
|
}
|
|
19742
20374
|
function registerCodeindexMcp(mcpJsonPath, binaryPath) {
|
|
19743
20375
|
let cfg = {};
|
|
19744
|
-
if (
|
|
20376
|
+
if (existsSync41(mcpJsonPath)) {
|
|
19745
20377
|
try {
|
|
19746
|
-
cfg = JSON.parse(
|
|
20378
|
+
cfg = JSON.parse(readFileSync36(mcpJsonPath, "utf-8"));
|
|
19747
20379
|
} catch {
|
|
19748
20380
|
cfg = {};
|
|
19749
20381
|
}
|
|
@@ -19752,33 +20384,42 @@ function registerCodeindexMcp(mcpJsonPath, binaryPath) {
|
|
|
19752
20384
|
if (cfg.mcpServers["codeindex"])
|
|
19753
20385
|
return { added: false };
|
|
19754
20386
|
cfg.mcpServers["codeindex"] = { command: binaryPath, args: ["--mcp"] };
|
|
19755
|
-
|
|
20387
|
+
writeFileSync12(mcpJsonPath, JSON.stringify(cfg, null, 2));
|
|
19756
20388
|
return { added: true };
|
|
19757
20389
|
}
|
|
19758
20390
|
function unregisterCodeindexMcp(mcpJsonPath) {
|
|
19759
|
-
if (!
|
|
20391
|
+
if (!existsSync41(mcpJsonPath))
|
|
19760
20392
|
return { removed: false };
|
|
19761
20393
|
let cfg;
|
|
19762
20394
|
try {
|
|
19763
|
-
cfg = JSON.parse(
|
|
20395
|
+
cfg = JSON.parse(readFileSync36(mcpJsonPath, "utf-8"));
|
|
19764
20396
|
} catch {
|
|
19765
20397
|
return { removed: false };
|
|
19766
20398
|
}
|
|
19767
20399
|
if (!cfg.mcpServers?.["codeindex"])
|
|
19768
20400
|
return { removed: false };
|
|
19769
20401
|
delete cfg.mcpServers["codeindex"];
|
|
19770
|
-
|
|
20402
|
+
writeFileSync12(mcpJsonPath, JSON.stringify(cfg, null, 2));
|
|
19771
20403
|
return { removed: true };
|
|
19772
20404
|
}
|
|
19773
|
-
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;
|
|
19774
20406
|
var init_companions = __esm({
|
|
19775
20407
|
"../engine/dist/core/companions.js"() {
|
|
19776
20408
|
"use strict";
|
|
20409
|
+
init_which();
|
|
19777
20410
|
CODEINDEX_REPO = "munhq/codeindex";
|
|
19778
|
-
CODEINDEX_VERSION = "v0.1
|
|
19779
|
-
|
|
19780
|
-
|
|
19781
|
-
|
|
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);
|
|
19782
20423
|
}
|
|
19783
20424
|
});
|
|
19784
20425
|
|
|
@@ -19793,26 +20434,26 @@ __export(install_skills_exports, {
|
|
|
19793
20434
|
skillsSourceDir: () => skillsSourceDir,
|
|
19794
20435
|
uninstallSkills: () => uninstallSkills
|
|
19795
20436
|
});
|
|
19796
|
-
import { readdirSync as readdirSync31, existsSync as
|
|
19797
|
-
import { createHash as
|
|
19798
|
-
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";
|
|
19799
20440
|
function skillsSourceDir() {
|
|
19800
|
-
return
|
|
20441
|
+
return join46(import.meta.dirname, "..", "skills");
|
|
19801
20442
|
}
|
|
19802
20443
|
function version() {
|
|
19803
20444
|
try {
|
|
19804
|
-
return JSON.parse(
|
|
20445
|
+
return JSON.parse(readFileSync37(new URL("../package.json", import.meta.url), "utf-8")).version || "0.0.0";
|
|
19805
20446
|
} catch {
|
|
19806
20447
|
return "0.0.0";
|
|
19807
20448
|
}
|
|
19808
20449
|
}
|
|
19809
20450
|
function skillsFingerprint() {
|
|
19810
20451
|
const src = skillsSourceDir();
|
|
19811
|
-
const h =
|
|
20452
|
+
const h = createHash15("sha256");
|
|
19812
20453
|
for (const name of bundledSkillNames()) {
|
|
19813
|
-
for (const rel of filesUnder(
|
|
20454
|
+
for (const rel of filesUnder(join46(src, name)).sort()) {
|
|
19814
20455
|
h.update(name + "/" + rel);
|
|
19815
|
-
h.update(
|
|
20456
|
+
h.update(readFileSync37(join46(src, name, rel)));
|
|
19816
20457
|
}
|
|
19817
20458
|
}
|
|
19818
20459
|
return h.digest("hex").slice(0, 12);
|
|
@@ -19822,7 +20463,7 @@ function filesUnder(dir, prefix = "") {
|
|
|
19822
20463
|
for (const e of readdirSync31(dir, { withFileTypes: true })) {
|
|
19823
20464
|
if (e.name === MARKER) continue;
|
|
19824
20465
|
const rel = prefix ? `${prefix}/${e.name}` : e.name;
|
|
19825
|
-
if (e.isDirectory()) out.push(...filesUnder(
|
|
20466
|
+
if (e.isDirectory()) out.push(...filesUnder(join46(dir, e.name), rel));
|
|
19826
20467
|
else out.push(rel);
|
|
19827
20468
|
}
|
|
19828
20469
|
return out;
|
|
@@ -19832,8 +20473,8 @@ function skillStamp() {
|
|
|
19832
20473
|
}
|
|
19833
20474
|
function bundledSkillNames() {
|
|
19834
20475
|
const src = skillsSourceDir();
|
|
19835
|
-
if (!
|
|
19836
|
-
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();
|
|
19837
20478
|
}
|
|
19838
20479
|
function realPathOrSelf(p) {
|
|
19839
20480
|
try {
|
|
@@ -19846,7 +20487,7 @@ function claudeSkillTargets() {
|
|
|
19846
20487
|
const targets = [];
|
|
19847
20488
|
const seen = /* @__PURE__ */ new Set();
|
|
19848
20489
|
for (const home of claudeHomeDirs()) {
|
|
19849
|
-
const dir =
|
|
20490
|
+
const dir = join46(home, "skills");
|
|
19850
20491
|
const key = realPathOrSelf(dir);
|
|
19851
20492
|
if (seen.has(key)) continue;
|
|
19852
20493
|
seen.add(key);
|
|
@@ -19857,7 +20498,7 @@ function claudeSkillTargets() {
|
|
|
19857
20498
|
dir,
|
|
19858
20499
|
// Judge each profile on ITS OWN transcripts, not the primary's: a home
|
|
19859
20500
|
// with no projects/ is a directory someone made, not a Claude install.
|
|
19860
|
-
available:
|
|
20501
|
+
available: existsSync42(join46(home, "projects"))
|
|
19861
20502
|
});
|
|
19862
20503
|
}
|
|
19863
20504
|
if (targets.length === 0) {
|
|
@@ -19880,7 +20521,7 @@ function skillTargets() {
|
|
|
19880
20521
|
];
|
|
19881
20522
|
}
|
|
19882
20523
|
function isManaged(dir) {
|
|
19883
|
-
return
|
|
20524
|
+
return existsSync42(join46(dir, MARKER));
|
|
19884
20525
|
}
|
|
19885
20526
|
function installSkills(opts = {}) {
|
|
19886
20527
|
const onlyAvailable = opts.onlyAvailable ?? true;
|
|
@@ -19897,15 +20538,15 @@ function installSkills(opts = {}) {
|
|
|
19897
20538
|
continue;
|
|
19898
20539
|
}
|
|
19899
20540
|
for (const name of names) {
|
|
19900
|
-
const dest =
|
|
19901
|
-
if (
|
|
20541
|
+
const dest = join46(t.dir, name);
|
|
20542
|
+
if (existsSync42(dest) && !isManaged(dest)) {
|
|
19902
20543
|
skippedUserOwned.push(name);
|
|
19903
20544
|
continue;
|
|
19904
20545
|
}
|
|
19905
|
-
|
|
20546
|
+
mkdirSync12(t.dir, { recursive: true });
|
|
19906
20547
|
rmSync6(dest, { recursive: true, force: true });
|
|
19907
|
-
cpSync(
|
|
19908
|
-
|
|
20548
|
+
cpSync(join46(src, name), dest, { recursive: true });
|
|
20549
|
+
writeFileSync13(join46(dest, MARKER), `${stamp}
|
|
19909
20550
|
`);
|
|
19910
20551
|
installed.push(name);
|
|
19911
20552
|
}
|
|
@@ -19918,13 +20559,13 @@ function uninstallSkills() {
|
|
|
19918
20559
|
const perTarget = [];
|
|
19919
20560
|
for (const t of skillTargets()) {
|
|
19920
20561
|
const removed = [];
|
|
19921
|
-
if (!
|
|
20562
|
+
if (!existsSync42(t.dir)) {
|
|
19922
20563
|
perTarget.push({ id: t.id, label: t.label, removed });
|
|
19923
20564
|
continue;
|
|
19924
20565
|
}
|
|
19925
20566
|
for (const entry of readdirSync31(t.dir, { withFileTypes: true })) {
|
|
19926
20567
|
if (!entry.isDirectory()) continue;
|
|
19927
|
-
const dir =
|
|
20568
|
+
const dir = join46(t.dir, entry.name);
|
|
19928
20569
|
if (isManaged(dir) && (names.has(entry.name) || entry.name.startsWith("chat-recall"))) {
|
|
19929
20570
|
rmSync6(dir, { recursive: true, force: true });
|
|
19930
20571
|
removed.push(entry.name);
|
|
@@ -19941,10 +20582,10 @@ function skillsNeedRefresh() {
|
|
|
19941
20582
|
for (const t of skillTargets()) {
|
|
19942
20583
|
if (!t.available) continue;
|
|
19943
20584
|
for (const name of names) {
|
|
19944
|
-
const marker =
|
|
19945
|
-
if (!
|
|
20585
|
+
const marker = join46(t.dir, name, MARKER);
|
|
20586
|
+
if (!existsSync42(marker)) return true;
|
|
19946
20587
|
try {
|
|
19947
|
-
if (
|
|
20588
|
+
if (readFileSync37(marker, "utf-8").trim() !== cur) return true;
|
|
19948
20589
|
} catch {
|
|
19949
20590
|
return true;
|
|
19950
20591
|
}
|
|
@@ -19959,11 +20600,11 @@ function skillStatus() {
|
|
|
19959
20600
|
let installed = 0;
|
|
19960
20601
|
let ver = null;
|
|
19961
20602
|
for (const name of names) {
|
|
19962
|
-
const marker =
|
|
19963
|
-
if (
|
|
20603
|
+
const marker = join46(t.dir, name, MARKER);
|
|
20604
|
+
if (existsSync42(marker)) {
|
|
19964
20605
|
installed++;
|
|
19965
20606
|
try {
|
|
19966
|
-
ver =
|
|
20607
|
+
ver = readFileSync37(marker, "utf-8").trim();
|
|
19967
20608
|
} catch {
|
|
19968
20609
|
}
|
|
19969
20610
|
}
|
|
@@ -19992,7 +20633,7 @@ __export(repair_exports, {
|
|
|
19992
20633
|
repairSession: () => repairSession,
|
|
19993
20634
|
repairSessions: () => repairSessions
|
|
19994
20635
|
});
|
|
19995
|
-
import { createHash as
|
|
20636
|
+
import { createHash as createHash16 } from "node:crypto";
|
|
19996
20637
|
function resolveEndpoints(only) {
|
|
19997
20638
|
const settings2 = loadSettings();
|
|
19998
20639
|
const creds = loadAllCredentials();
|
|
@@ -20035,11 +20676,11 @@ async function repairSession(id, opts = {}) {
|
|
|
20035
20676
|
const log6 = (m) => {
|
|
20036
20677
|
if (opts.verbose) console.error(` [repair ${id}] ${m}`);
|
|
20037
20678
|
};
|
|
20038
|
-
const
|
|
20679
|
+
const candidates2 = [];
|
|
20039
20680
|
const localShadow = readShadowContainer(tool, rawId);
|
|
20040
20681
|
if (localShadow) {
|
|
20041
20682
|
try {
|
|
20042
|
-
|
|
20683
|
+
candidates2.push({ container: localShadow, messages: parseTranscriptFromContainer(localShadow).messages.length, source: "local-shadow" });
|
|
20043
20684
|
} catch {
|
|
20044
20685
|
}
|
|
20045
20686
|
}
|
|
@@ -20051,15 +20692,15 @@ async function repairSession(id, opts = {}) {
|
|
|
20051
20692
|
if (arch?.gzB64) {
|
|
20052
20693
|
try {
|
|
20053
20694
|
const container = gunzipContainer(Buffer.from(arch.gzB64, "base64"));
|
|
20054
|
-
if (container)
|
|
20695
|
+
if (container) candidates2.push({ container, messages: parseTranscriptFromContainer(container).messages.length, source: ep.url });
|
|
20055
20696
|
} catch {
|
|
20056
20697
|
}
|
|
20057
20698
|
}
|
|
20058
20699
|
}
|
|
20059
|
-
if (
|
|
20700
|
+
if (candidates2.length === 0) {
|
|
20060
20701
|
return { sessionId: id, status: "no-archive", fullestMessages: 0, fullestSource: "", pushed: [], note: "no shadow or server archive found" };
|
|
20061
20702
|
}
|
|
20062
|
-
const fullest =
|
|
20703
|
+
const fullest = candidates2.reduce((a, b) => b.messages > a.messages ? b : a);
|
|
20063
20704
|
log6(`fullest archive = ${fullest.messages} msg(s) from ${fullest.source}`);
|
|
20064
20705
|
if (opts.dryRun) {
|
|
20065
20706
|
const needy2 = endpoints.filter((ep) => (currentOnServer.get(ep.url) ?? 0) < fullest.messages || opts.force);
|
|
@@ -20161,7 +20802,7 @@ async function repairAll(opts = {}) {
|
|
|
20161
20802
|
if (!page?.hasMore || sessions.length === 0) break;
|
|
20162
20803
|
}
|
|
20163
20804
|
log6(`window=${sinceHours}h \u2192 ${ids.length} session(s) to check on ${primary.url}`);
|
|
20164
|
-
const
|
|
20805
|
+
const candidates2 = [];
|
|
20165
20806
|
let scanned = 0;
|
|
20166
20807
|
for (const id of ids) {
|
|
20167
20808
|
scanned++;
|
|
@@ -20174,9 +20815,9 @@ async function repairAll(opts = {}) {
|
|
|
20174
20815
|
if (archiveMsgs <= current) continue;
|
|
20175
20816
|
const r = await repairSession(id, { dryRun: !opts.apply, verbose: opts.verbose, server: opts.server });
|
|
20176
20817
|
if (r.status === "already-full") continue;
|
|
20177
|
-
|
|
20818
|
+
candidates2.push(r);
|
|
20178
20819
|
}
|
|
20179
|
-
return { scanned, candidates, discoveryServer: primary.url };
|
|
20820
|
+
return { scanned, candidates: candidates2, discoveryServer: primary.url };
|
|
20180
20821
|
}
|
|
20181
20822
|
var hashPath2;
|
|
20182
20823
|
var init_repair = __esm({
|
|
@@ -20188,7 +20829,7 @@ var init_repair = __esm({
|
|
|
20188
20829
|
init_http();
|
|
20189
20830
|
init_sync_client();
|
|
20190
20831
|
init_sync_client();
|
|
20191
|
-
hashPath2 = (p) => p ? "p_" +
|
|
20832
|
+
hashPath2 = (p) => p ? "p_" + createHash16("sha256").update(p).digest("hex").slice(0, 12) : "";
|
|
20192
20833
|
}
|
|
20193
20834
|
});
|
|
20194
20835
|
|
|
@@ -20408,11 +21049,11 @@ var verify_repair_exports = {};
|
|
|
20408
21049
|
__export(verify_repair_exports, {
|
|
20409
21050
|
forceFullResync: () => forceFullResync
|
|
20410
21051
|
});
|
|
20411
|
-
import { copyFileSync as copyFileSync3, existsSync as
|
|
21052
|
+
import { copyFileSync as copyFileSync3, existsSync as existsSync43 } from "fs";
|
|
20412
21053
|
function forceFullResync(server, sessionIds) {
|
|
20413
21054
|
if (sessionIds.length === 0) return 0;
|
|
20414
21055
|
const path = ledgerFilePath();
|
|
20415
|
-
if (
|
|
21056
|
+
if (existsSync43(path)) {
|
|
20416
21057
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "").replace(/-/g, "");
|
|
20417
21058
|
try {
|
|
20418
21059
|
copyFileSync3(path, `${path}.bak-${stamp}`);
|
|
@@ -20550,15 +21191,17 @@ var init_prompts = __esm({
|
|
|
20550
21191
|
var collector_exports = {};
|
|
20551
21192
|
__export(collector_exports, {
|
|
20552
21193
|
COLLECTOR_VERSION: () => COLLECTOR_VERSION,
|
|
21194
|
+
GENERATED_PATTERNS: () => GENERATED_PATTERNS,
|
|
20553
21195
|
collectCode: () => collectCode,
|
|
21196
|
+
isGenerated: () => isGenerated,
|
|
20554
21197
|
isJunkWorkspacePath: () => isJunkWorkspacePath,
|
|
20555
21198
|
isSecretRule: () => isSecretRule,
|
|
20556
21199
|
resolveCodeindexBin: () => resolveCodeindexBin
|
|
20557
21200
|
});
|
|
20558
21201
|
import { spawn } from "node:child_process";
|
|
20559
21202
|
import { execSync as execSync4 } from "node:child_process";
|
|
20560
|
-
import { readFileSync as
|
|
20561
|
-
import { join as
|
|
21203
|
+
import { readFileSync as readFileSync38 } from "node:fs";
|
|
21204
|
+
import { join as join47, basename as basename25 } from "node:path";
|
|
20562
21205
|
async function resolveCodeindexBin(autoInstall = true) {
|
|
20563
21206
|
let st = checkCodeindexStatus();
|
|
20564
21207
|
if (!st.installed && autoInstall)
|
|
@@ -20645,10 +21288,11 @@ function isSecretRule(rule) {
|
|
|
20645
21288
|
return /secret|password|credential|key|token|auth/i.test(rule);
|
|
20646
21289
|
}
|
|
20647
21290
|
function isJunkWorkspacePath(ws) {
|
|
20648
|
-
|
|
21291
|
+
const norm = ws.replace(/\\/g, "/");
|
|
21292
|
+
return /(^|\/)(scratchpad|\.cache|node_modules|\.git|tmp)(\/|$)|claude-1000/i.test(norm);
|
|
20649
21293
|
}
|
|
20650
21294
|
async function collectCode(opts) {
|
|
20651
|
-
const ws = opts.workspace.replace(
|
|
21295
|
+
const ws = opts.workspace.replace(/[/\\]+$/, "");
|
|
20652
21296
|
const log6 = opts.log ?? (() => {
|
|
20653
21297
|
});
|
|
20654
21298
|
if (isJunkWorkspacePath(ws)) {
|
|
@@ -20656,9 +21300,11 @@ async function collectCode(opts) {
|
|
|
20656
21300
|
}
|
|
20657
21301
|
const bin = opts.binPath ?? await resolveCodeindexBin(opts.autoInstall ?? true);
|
|
20658
21302
|
const projectId = resolveProjectId(ws).id || `path:${ws}`;
|
|
20659
|
-
const
|
|
21303
|
+
const wsNorm = ws.replace(/\\/g, "/");
|
|
21304
|
+
const wsPrefix = wsNorm + "/";
|
|
20660
21305
|
const rel = (p) => {
|
|
20661
|
-
|
|
21306
|
+
const n = p.replace(/\\/g, "/");
|
|
21307
|
+
let r = n.startsWith(wsPrefix) ? n.slice(wsPrefix.length) : n;
|
|
20662
21308
|
if (r.startsWith("./"))
|
|
20663
21309
|
r = r.slice(2);
|
|
20664
21310
|
return r;
|
|
@@ -20719,7 +21365,7 @@ async function collectCode(opts) {
|
|
|
20719
21365
|
}
|
|
20720
21366
|
const complexity = (r) => {
|
|
20721
21367
|
try {
|
|
20722
|
-
const txt =
|
|
21368
|
+
const txt = readFileSync38(join47(ws, r), "utf8");
|
|
20723
21369
|
if (txt.length > 2e6)
|
|
20724
21370
|
return 1;
|
|
20725
21371
|
const m = txt.match(CF_RE);
|
|
@@ -21073,6 +21719,14 @@ async function collectCode(opts) {
|
|
|
21073
21719
|
agentPrompt: manifestPrompt(v.violation_type ?? "", file, v.line ?? null, v.description ?? "")
|
|
21074
21720
|
});
|
|
21075
21721
|
}
|
|
21722
|
+
{
|
|
21723
|
+
const before = findings.length;
|
|
21724
|
+
const own = findings.filter((f) => !f.file || !isGenerated(f.file));
|
|
21725
|
+
if (own.length !== before) {
|
|
21726
|
+
findings.splice(0, before, ...own);
|
|
21727
|
+
log6(`dropped ${before - own.length} finding(s) in vendored/generated files`);
|
|
21728
|
+
}
|
|
21729
|
+
}
|
|
21076
21730
|
const godSet = new Set((coup?.god_modules ?? []).map((m) => rel(m.file)));
|
|
21077
21731
|
const cloneSet = /* @__PURE__ */ new Set();
|
|
21078
21732
|
for (const g of clones?.groups ?? [])
|
|
@@ -21158,7 +21812,9 @@ async function collectCode(opts) {
|
|
|
21158
21812
|
}
|
|
21159
21813
|
for (const g of clones?.groups ?? []) {
|
|
21160
21814
|
if ((g.count ?? 0) >= 3 || (g.lines ?? 0) >= 12) {
|
|
21161
|
-
const fns = (g.functions ?? []).filter((x) => x && typeof x === "object");
|
|
21815
|
+
const fns = (g.functions ?? []).filter((x) => x && typeof x === "object").filter((x) => !isGenerated(rel(x.file)));
|
|
21816
|
+
if (fns.length < 2)
|
|
21817
|
+
continue;
|
|
21162
21818
|
const names = [...new Set(fns.map((x) => x.name))];
|
|
21163
21819
|
const locs = fns.map((x) => rel(x.file)).slice(0, 5);
|
|
21164
21820
|
pushAction((g.lines ?? 0) * (g.count ?? 0) >= 150 ? 1 : 2, "duplication", `${names.join(", ")} copy-pasted ${g.count}\xD7 (${g.lines} lines each)`, "Extract one shared implementation and replace the copies.", locs.map((f) => ({ file: f })), clonePrompt(names, g.lines ?? 0, g.count ?? 0, locs));
|
|
@@ -21177,10 +21833,14 @@ async function collectCode(opts) {
|
|
|
21177
21833
|
}
|
|
21178
21834
|
for (const m of (coup?.god_modules ?? []).slice(0, 5)) {
|
|
21179
21835
|
const file = rel(m.file);
|
|
21836
|
+
if (isGenerated(file))
|
|
21837
|
+
continue;
|
|
21180
21838
|
pushAction(2, "modularity", `God module ${file} (fan-in ${m.fan_in}, fan-out ${m.fan_out})`, "Split into cohesive sub-modules; introduce interfaces to cut fan-out.", [{ file }], couplingPrompt(file, m.fan_in ?? 0, m.fan_out ?? 0, Math.round((m.instability ?? 0) * 100) / 100));
|
|
21181
21839
|
}
|
|
21182
21840
|
for (const c of (cyc?.cycles ?? []).slice(0, 5)) {
|
|
21183
|
-
const chain = (c.files ?? []).map(rel);
|
|
21841
|
+
const chain = (c.files ?? []).map(rel).filter((f) => !isGenerated(f));
|
|
21842
|
+
if (chain.length < 2)
|
|
21843
|
+
continue;
|
|
21184
21844
|
pushAction(2, "architecture", `Circular dependency (${chain.length} files)`, "Break the cycle: extract the shared type/interface into a separate module.", chain.slice(0, 4).map((f) => ({ file: f })), cyclePrompt(chain.slice(0, 6)));
|
|
21185
21845
|
}
|
|
21186
21846
|
for (const h of hotspotsAll.slice(0, 5)) {
|
|
@@ -21289,7 +21949,7 @@ async function collectCode(opts) {
|
|
|
21289
21949
|
void health;
|
|
21290
21950
|
return { project, findings, hotspots, actions };
|
|
21291
21951
|
}
|
|
21292
|
-
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;
|
|
21293
21953
|
var init_collector = __esm({
|
|
21294
21954
|
"../engine/dist/core/code/collector.js"() {
|
|
21295
21955
|
"use strict";
|
|
@@ -21319,11 +21979,42 @@ var init_collector = __esm({
|
|
|
21319
21979
|
"migration_parity",
|
|
21320
21980
|
"manifest_compliance"
|
|
21321
21981
|
];
|
|
21322
|
-
GENERATED = [
|
|
21982
|
+
GENERATED = [
|
|
21983
|
+
"generated/",
|
|
21984
|
+
"__generated__/",
|
|
21985
|
+
".pb.go",
|
|
21986
|
+
".gen.",
|
|
21987
|
+
"_pb2.py",
|
|
21988
|
+
"/gen/",
|
|
21989
|
+
".g.dart",
|
|
21990
|
+
"/node_modules/",
|
|
21991
|
+
"/vendor/",
|
|
21992
|
+
"/third_party/",
|
|
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.
|
|
21998
|
+
".lock",
|
|
21999
|
+
"-lock.json",
|
|
22000
|
+
"-lock.yaml",
|
|
22001
|
+
"/dist/",
|
|
22002
|
+
"/build/",
|
|
22003
|
+
"/out/",
|
|
22004
|
+
"/target/",
|
|
22005
|
+
"/.next/",
|
|
22006
|
+
"/coverage/",
|
|
22007
|
+
".min.js",
|
|
22008
|
+
".min.css",
|
|
22009
|
+
".bundle.js",
|
|
22010
|
+
"-bundle.js",
|
|
22011
|
+
".map"
|
|
22012
|
+
];
|
|
21323
22013
|
CF_RE = /\b(if|for|while|switch|case|catch|elif|when|loop|&&|\|\||\?)\b|\?/g;
|
|
21324
22014
|
DEPTH = 2;
|
|
21325
22015
|
MCP_OUT_MAX_BYTES = 64 * 1024 * 1024;
|
|
21326
22016
|
call = (id, name, args = {}) => ({ jsonrpc: "2.0", id, method: "tools/call", params: { name, arguments: args } });
|
|
22017
|
+
GENERATED_PATTERNS = GENERATED;
|
|
21327
22018
|
COMMON_SYMBOL_NAMES = /* @__PURE__ */ new Set([
|
|
21328
22019
|
"error",
|
|
21329
22020
|
"err",
|
|
@@ -21389,11 +22080,11 @@ var init_collector = __esm({
|
|
|
21389
22080
|
});
|
|
21390
22081
|
|
|
21391
22082
|
// ../engine/dist/core/artifact-codec.js
|
|
21392
|
-
import { readFileSync as
|
|
21393
|
-
import { join as
|
|
21394
|
-
import { homedir as
|
|
22083
|
+
import { readFileSync as readFileSync39 } from "fs";
|
|
22084
|
+
import { join as join48 } from "path";
|
|
22085
|
+
import { homedir as homedir17 } from "os";
|
|
21395
22086
|
function readCommand(filePath, format) {
|
|
21396
|
-
const content =
|
|
22087
|
+
const content = readFileSync39(filePath, "utf-8");
|
|
21397
22088
|
if (format === "toml") {
|
|
21398
22089
|
const t = parseScalarToml(content);
|
|
21399
22090
|
return { name: t.name || base(filePath), description: t.description || "", body: t.prompt || "" };
|
|
@@ -21402,7 +22093,7 @@ function readCommand(filePath, format) {
|
|
|
21402
22093
|
return { name: fm.name || base(filePath), description: fm.description || "", body: body.trim() };
|
|
21403
22094
|
}
|
|
21404
22095
|
function readAgent(filePath, format) {
|
|
21405
|
-
const content =
|
|
22096
|
+
const content = readFileSync39(filePath, "utf-8");
|
|
21406
22097
|
if (format === "toml") {
|
|
21407
22098
|
const t = parseScalarToml(content);
|
|
21408
22099
|
return {
|
|
@@ -21415,35 +22106,35 @@ function readAgent(filePath, format) {
|
|
|
21415
22106
|
return { name: fm.name || base(filePath), description: fm.description || "", tools: fm.tools, body: body.trim() };
|
|
21416
22107
|
}
|
|
21417
22108
|
function readInstructions(filePath, name) {
|
|
21418
|
-
const content =
|
|
22109
|
+
const content = readFileSync39(filePath, "utf-8");
|
|
21419
22110
|
return { name, description: "", body: content };
|
|
21420
22111
|
}
|
|
21421
22112
|
function commandPath(tool, name) {
|
|
21422
22113
|
switch (tool) {
|
|
21423
22114
|
case "claude":
|
|
21424
|
-
return
|
|
22115
|
+
return join48(claudeBackend.commandsDir(), `${name}.md`);
|
|
21425
22116
|
case "agy":
|
|
21426
|
-
return
|
|
22117
|
+
return join48(join48(agyBackend.homeDir(), "commands"), `${name}.toml`);
|
|
21427
22118
|
case "gemini":
|
|
21428
|
-
return
|
|
22119
|
+
return join48(geminiBackend.commandsDir(), `${name}.toml`);
|
|
21429
22120
|
case "opencode":
|
|
21430
|
-
return
|
|
22121
|
+
return join48(opencodeBackend.commandsDir(), `${name}.md`);
|
|
21431
22122
|
case "codex":
|
|
21432
|
-
return
|
|
22123
|
+
return join48(codexBackend.promptsDir(), `${name}.md`);
|
|
21433
22124
|
}
|
|
21434
22125
|
}
|
|
21435
22126
|
function agentPath(tool, name) {
|
|
21436
22127
|
switch (tool) {
|
|
21437
22128
|
case "claude":
|
|
21438
|
-
return
|
|
22129
|
+
return join48(claudeBackend.agentsDir(), `${name}.md`);
|
|
21439
22130
|
case "agy":
|
|
21440
|
-
return
|
|
22131
|
+
return join48(join48(agyBackend.homeDir(), "agents"), `${name}.md`);
|
|
21441
22132
|
case "gemini":
|
|
21442
|
-
return
|
|
22133
|
+
return join48(geminiBackend.agentsDir(), `${name}.md`);
|
|
21443
22134
|
case "opencode":
|
|
21444
|
-
return
|
|
22135
|
+
return join48(opencodeBackend.agentsDir(), `${name}.md`);
|
|
21445
22136
|
case "codex":
|
|
21446
|
-
return
|
|
22137
|
+
return join48(codexBackend.agentsDir(), `${name}.toml`);
|
|
21447
22138
|
}
|
|
21448
22139
|
}
|
|
21449
22140
|
function instructionsFilename(tool) {
|
|
@@ -21461,18 +22152,18 @@ function instructionsFilename(tool) {
|
|
|
21461
22152
|
function instructionsPath(tool, projectPath) {
|
|
21462
22153
|
const file = instructionsFilename(tool);
|
|
21463
22154
|
if (projectPath)
|
|
21464
|
-
return
|
|
22155
|
+
return join48(projectPath, file);
|
|
21465
22156
|
switch (tool) {
|
|
21466
22157
|
case "claude":
|
|
21467
|
-
return
|
|
22158
|
+
return join48(claudeBackend.homeDir(), file);
|
|
21468
22159
|
case "agy":
|
|
21469
|
-
return
|
|
22160
|
+
return join48(agyBackend.homeDir(), file);
|
|
21470
22161
|
case "gemini":
|
|
21471
|
-
return
|
|
22162
|
+
return join48(geminiBackend.homeDir(), file);
|
|
21472
22163
|
case "codex":
|
|
21473
|
-
return
|
|
22164
|
+
return join48(codexBackend.homeDir(), file);
|
|
21474
22165
|
case "opencode":
|
|
21475
|
-
return
|
|
22166
|
+
return join48(homedir17(), ".config", "opencode", file);
|
|
21476
22167
|
}
|
|
21477
22168
|
}
|
|
21478
22169
|
function emit(type, art, toTool, projectPath) {
|
|
@@ -21535,9 +22226,9 @@ __export(toolkit_sync_exports, {
|
|
|
21535
22226
|
supportedTargetsFor: () => supportedTargetsFor,
|
|
21536
22227
|
writeMcpEntry: () => writeMcpEntry
|
|
21537
22228
|
});
|
|
21538
|
-
import { existsSync as
|
|
21539
|
-
import { dirname as
|
|
21540
|
-
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";
|
|
21541
22232
|
function supportedTargetsFor(type) {
|
|
21542
22233
|
return SUPPORTED_TARGETS[type];
|
|
21543
22234
|
}
|
|
@@ -21578,7 +22269,7 @@ function skillsDirFor(tool) {
|
|
|
21578
22269
|
case "claude":
|
|
21579
22270
|
return claudeBackend.skillsDir();
|
|
21580
22271
|
case "agy":
|
|
21581
|
-
return
|
|
22272
|
+
return join49(agyBackend.homeDir(), "skills");
|
|
21582
22273
|
case "gemini":
|
|
21583
22274
|
return geminiBackend.skillsDir();
|
|
21584
22275
|
case "opencode":
|
|
@@ -21588,15 +22279,15 @@ function skillsDirFor(tool) {
|
|
|
21588
22279
|
}
|
|
21589
22280
|
}
|
|
21590
22281
|
function copySkill(row, toTool) {
|
|
21591
|
-
const skillDir = row.extra.skillDir ||
|
|
21592
|
-
if (!
|
|
22282
|
+
const skillDir = row.extra.skillDir || dirname19(row.filePath);
|
|
22283
|
+
if (!existsSync44(skillDir))
|
|
21593
22284
|
return { ok: false, status: 404, error: `Source dir missing: ${skillDir}` };
|
|
21594
22285
|
const name = row.extra.skillName || basename26(skillDir);
|
|
21595
|
-
const targetDir =
|
|
21596
|
-
if (
|
|
22286
|
+
const targetDir = join49(skillsDirFor(toTool), name);
|
|
22287
|
+
if (existsSync44(targetDir))
|
|
21597
22288
|
return { ok: false, status: 409, error: `Already exists: ${targetDir}` };
|
|
21598
22289
|
try {
|
|
21599
|
-
|
|
22290
|
+
mkdirSync13(dirname19(targetDir), { recursive: true });
|
|
21600
22291
|
cpSync2(skillDir, targetDir, { recursive: true });
|
|
21601
22292
|
return { ok: true, targetPath: targetDir };
|
|
21602
22293
|
} catch (e) {
|
|
@@ -21604,29 +22295,29 @@ function copySkill(row, toTool) {
|
|
|
21604
22295
|
}
|
|
21605
22296
|
}
|
|
21606
22297
|
function readMcpEntry(tool, name) {
|
|
21607
|
-
const home =
|
|
22298
|
+
const home = homedir18();
|
|
21608
22299
|
const tries = [];
|
|
21609
22300
|
if (tool === "claude") {
|
|
21610
|
-
tries.push({ path:
|
|
21611
|
-
tries.push({ path:
|
|
22301
|
+
tries.push({ path: join49(home, ".mcp.json"), key: "mcpServers" });
|
|
22302
|
+
tries.push({ path: join49(home, ".claude.json"), key: "mcpServers" });
|
|
21612
22303
|
} else if (tool === "gemini") {
|
|
21613
|
-
tries.push({ path:
|
|
22304
|
+
tries.push({ path: join49(home, ".gemini", "settings.json"), key: "mcpServers" });
|
|
21614
22305
|
} else if (tool === "agy") {
|
|
21615
|
-
tries.push({ path:
|
|
22306
|
+
tries.push({ path: join49(home, ".gemini", "config", "mcp_config.json"), key: "mcpServers" });
|
|
21616
22307
|
} else if (tool === "opencode") {
|
|
21617
|
-
tries.push({ path:
|
|
21618
|
-
tries.push({ path:
|
|
21619
|
-
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" });
|
|
21620
22311
|
} else if (tool === "codex") {
|
|
21621
|
-
const entry = readCodexMcpEntry(
|
|
22312
|
+
const entry = readCodexMcpEntry(join49(home, ".codex", "config.toml"), name);
|
|
21622
22313
|
if (entry)
|
|
21623
22314
|
return entry;
|
|
21624
22315
|
}
|
|
21625
22316
|
for (const t of tries) {
|
|
21626
|
-
if (!
|
|
22317
|
+
if (!existsSync44(t.path))
|
|
21627
22318
|
continue;
|
|
21628
22319
|
try {
|
|
21629
|
-
const cfg = JSON.parse(
|
|
22320
|
+
const cfg = JSON.parse(readFileSync40(t.path, "utf-8"));
|
|
21630
22321
|
const block = cfg[t.key] || {};
|
|
21631
22322
|
if (block[name])
|
|
21632
22323
|
return block[name];
|
|
@@ -21636,11 +22327,11 @@ function readMcpEntry(tool, name) {
|
|
|
21636
22327
|
return null;
|
|
21637
22328
|
}
|
|
21638
22329
|
function readCodexMcpEntry(path, target) {
|
|
21639
|
-
if (!
|
|
22330
|
+
if (!existsSync44(path))
|
|
21640
22331
|
return null;
|
|
21641
22332
|
let content;
|
|
21642
22333
|
try {
|
|
21643
|
-
content =
|
|
22334
|
+
content = readFileSync40(path, "utf-8");
|
|
21644
22335
|
} catch {
|
|
21645
22336
|
return null;
|
|
21646
22337
|
}
|
|
@@ -21690,8 +22381,8 @@ function readCodexMcpEntry(path, target) {
|
|
|
21690
22381
|
}
|
|
21691
22382
|
function writeCodexMcpEntry(path, name, entry) {
|
|
21692
22383
|
let content = "";
|
|
21693
|
-
if (
|
|
21694
|
-
content =
|
|
22384
|
+
if (existsSync44(path))
|
|
22385
|
+
content = readFileSync40(path, "utf-8");
|
|
21695
22386
|
const header = `[mcp_servers.${name}]`;
|
|
21696
22387
|
if (content.includes(header))
|
|
21697
22388
|
return false;
|
|
@@ -21720,14 +22411,14 @@ function writeCodexMcpEntry(path, name, entry) {
|
|
|
21720
22411
|
for (const [k, v] of Object.entries(entry.env))
|
|
21721
22412
|
lines.push(`${k} = ${escape(String(v))}`);
|
|
21722
22413
|
}
|
|
21723
|
-
|
|
21724
|
-
|
|
22414
|
+
mkdirSync13(dirname19(path), { recursive: true });
|
|
22415
|
+
writeFileSync14(path, content + lines.join("\n") + "\n");
|
|
21725
22416
|
return true;
|
|
21726
22417
|
}
|
|
21727
22418
|
function writeMcpEntry(toTool, name, entry) {
|
|
21728
|
-
const home =
|
|
22419
|
+
const home = homedir18();
|
|
21729
22420
|
if (toTool === "codex") {
|
|
21730
|
-
const path2 =
|
|
22421
|
+
const path2 = join49(home, ".codex", "config.toml");
|
|
21731
22422
|
if (!writeCodexMcpEntry(path2, name, entry))
|
|
21732
22423
|
return { ok: false, status: 409, error: `MCP "${name}" already exists in ${path2}.` };
|
|
21733
22424
|
return { ok: true, targetPath: path2 };
|
|
@@ -21735,27 +22426,27 @@ function writeMcpEntry(toTool, name, entry) {
|
|
|
21735
22426
|
let path;
|
|
21736
22427
|
let key;
|
|
21737
22428
|
if (toTool === "claude") {
|
|
21738
|
-
path =
|
|
22429
|
+
path = join49(home, ".mcp.json");
|
|
21739
22430
|
key = "mcpServers";
|
|
21740
22431
|
} else if (toTool === "gemini") {
|
|
21741
|
-
path =
|
|
22432
|
+
path = join49(home, ".gemini", "settings.json");
|
|
21742
22433
|
key = "mcpServers";
|
|
21743
22434
|
} else if (toTool === "agy") {
|
|
21744
|
-
path =
|
|
22435
|
+
path = join49(home, ".gemini", "config", "mcp_config.json");
|
|
21745
22436
|
key = "mcpServers";
|
|
21746
22437
|
} else {
|
|
21747
|
-
path =
|
|
22438
|
+
path = join49(home, ".config", "opencode", "opencode.json");
|
|
21748
22439
|
key = "mcp";
|
|
21749
22440
|
}
|
|
21750
22441
|
let cfg = {};
|
|
21751
|
-
if (
|
|
22442
|
+
if (existsSync44(path)) {
|
|
21752
22443
|
try {
|
|
21753
|
-
cfg = JSON.parse(
|
|
22444
|
+
cfg = JSON.parse(readFileSync40(path, "utf-8"));
|
|
21754
22445
|
} catch {
|
|
21755
22446
|
return { ok: false, status: 500, error: `Target config is malformed: ${path}` };
|
|
21756
22447
|
}
|
|
21757
22448
|
} else {
|
|
21758
|
-
|
|
22449
|
+
mkdirSync13(dirname19(path), { recursive: true });
|
|
21759
22450
|
}
|
|
21760
22451
|
cfg[key] = cfg[key] || {};
|
|
21761
22452
|
if (cfg[key][name])
|
|
@@ -21782,7 +22473,7 @@ function writeMcpEntry(toTool, name, entry) {
|
|
|
21782
22473
|
}
|
|
21783
22474
|
cfg[key][name] = normalized;
|
|
21784
22475
|
try {
|
|
21785
|
-
|
|
22476
|
+
writeFileSync14(path, JSON.stringify(cfg, null, 2));
|
|
21786
22477
|
return { ok: true, targetPath: path };
|
|
21787
22478
|
} catch (e) {
|
|
21788
22479
|
return { ok: false, status: 500, error: e instanceof Error ? e.message : "write failed" };
|
|
@@ -21812,11 +22503,11 @@ function copyCommandOrAgent(type, row, toTool) {
|
|
|
21812
22503
|
return { ok: false, status: 404, error: `Source unreadable: ${e instanceof Error ? e.message : "failed"}` };
|
|
21813
22504
|
}
|
|
21814
22505
|
const out = emit(type, art, toTool);
|
|
21815
|
-
if (
|
|
22506
|
+
if (existsSync44(out.path))
|
|
21816
22507
|
return { ok: false, status: 409, error: `Already exists: ${out.path}` };
|
|
21817
22508
|
try {
|
|
21818
|
-
|
|
21819
|
-
|
|
22509
|
+
mkdirSync13(dirname19(out.path), { recursive: true });
|
|
22510
|
+
writeFileSync14(out.path, out.content);
|
|
21820
22511
|
return { ok: true, targetPath: out.path };
|
|
21821
22512
|
} catch (e) {
|
|
21822
22513
|
return { ok: false, status: 500, error: e instanceof Error ? e.message : "write failed" };
|
|
@@ -21832,11 +22523,11 @@ function copyInstructions(row, toTool) {
|
|
|
21832
22523
|
return { ok: false, status: 404, error: `Source unreadable: ${e instanceof Error ? e.message : "failed"}` };
|
|
21833
22524
|
}
|
|
21834
22525
|
const out = emit("instructions", art, toTool, row.projectPath || void 0);
|
|
21835
|
-
if (
|
|
22526
|
+
if (existsSync44(out.path))
|
|
21836
22527
|
return { ok: false, status: 409, error: `Already exists: ${out.path}` };
|
|
21837
22528
|
try {
|
|
21838
|
-
|
|
21839
|
-
|
|
22529
|
+
mkdirSync13(dirname19(out.path), { recursive: true });
|
|
22530
|
+
writeFileSync14(out.path, out.content);
|
|
21840
22531
|
return { ok: true, targetPath: out.path };
|
|
21841
22532
|
} catch (e) {
|
|
21842
22533
|
return { ok: false, status: 500, error: e instanceof Error ? e.message : "write failed" };
|
|
@@ -22008,9 +22699,9 @@ __export(project_tasks_exports, {
|
|
|
22008
22699
|
pushProjectTaskStatuses: () => pushProjectTaskStatuses,
|
|
22009
22700
|
renderTeamTasksMd: () => renderTeamTasksMd
|
|
22010
22701
|
});
|
|
22011
|
-
import { existsSync as
|
|
22012
|
-
import { join as
|
|
22013
|
-
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";
|
|
22014
22705
|
function isTeamTaskStatus(v) {
|
|
22015
22706
|
return !!v && TEAM_STATUSES.has(v);
|
|
22016
22707
|
}
|
|
@@ -22025,7 +22716,7 @@ function reconcile(kind, was, token, checked) {
|
|
|
22025
22716
|
const done = kind === "secret" ? "rotated" : "done";
|
|
22026
22717
|
if (token && token !== was) return token;
|
|
22027
22718
|
if (kind === "team") {
|
|
22028
|
-
if (checked && was
|
|
22719
|
+
if (checked && was === "todo") return "in_progress";
|
|
22029
22720
|
if (!checked && was === "done") return "todo";
|
|
22030
22721
|
return token ?? was;
|
|
22031
22722
|
}
|
|
@@ -22060,22 +22751,22 @@ function parseTaskFile(content) {
|
|
|
22060
22751
|
return out;
|
|
22061
22752
|
}
|
|
22062
22753
|
function ledgerPath2() {
|
|
22063
|
-
return
|
|
22754
|
+
return join50(homedir19(), ".chat-recall", "project-tasks-ledger.json");
|
|
22064
22755
|
}
|
|
22065
22756
|
function readLedger() {
|
|
22066
22757
|
try {
|
|
22067
|
-
return JSON.parse(
|
|
22758
|
+
return JSON.parse(readFileSync41(ledgerPath2(), "utf8"));
|
|
22068
22759
|
} catch {
|
|
22069
22760
|
return {};
|
|
22070
22761
|
}
|
|
22071
22762
|
}
|
|
22072
22763
|
function writeLedger(l) {
|
|
22073
22764
|
try {
|
|
22074
|
-
|
|
22765
|
+
mkdirSync14(dirname20(ledgerPath2()), { recursive: true });
|
|
22075
22766
|
} catch {
|
|
22076
22767
|
}
|
|
22077
22768
|
try {
|
|
22078
|
-
|
|
22769
|
+
writeFileSync15(ledgerPath2(), JSON.stringify(l));
|
|
22079
22770
|
} catch {
|
|
22080
22771
|
}
|
|
22081
22772
|
}
|
|
@@ -22093,18 +22784,18 @@ async function pushProjectTaskStatuses(base2, authHeaders, opts = {}) {
|
|
|
22093
22784
|
continue;
|
|
22094
22785
|
}
|
|
22095
22786
|
for (const project of projects) {
|
|
22096
|
-
const file =
|
|
22097
|
-
if (!
|
|
22787
|
+
const file = join50(project, fk.filename);
|
|
22788
|
+
if (!existsSync45(file)) continue;
|
|
22098
22789
|
let mtime;
|
|
22099
22790
|
try {
|
|
22100
|
-
mtime =
|
|
22791
|
+
mtime = statSync39(file).mtimeMs;
|
|
22101
22792
|
} catch {
|
|
22102
22793
|
continue;
|
|
22103
22794
|
}
|
|
22104
22795
|
if (ledger[file] === mtime) continue;
|
|
22105
22796
|
let changed;
|
|
22106
22797
|
try {
|
|
22107
|
-
changed = parseTaskFile(
|
|
22798
|
+
changed = parseTaskFile(readFileSync41(file, "utf8")).filter((t) => t.kind === fk.kind);
|
|
22108
22799
|
} catch {
|
|
22109
22800
|
continue;
|
|
22110
22801
|
}
|
|
@@ -22137,7 +22828,8 @@ function renderTeamTasksMd(tasks2) {
|
|
|
22137
22828
|
"# Team tasks",
|
|
22138
22829
|
"",
|
|
22139
22830
|
"<!-- Managed by chat-recall. Tick a box or edit the `status:` token, then run",
|
|
22140
|
-
" `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. -->",
|
|
22141
22833
|
""
|
|
22142
22834
|
];
|
|
22143
22835
|
if (tasks2.length === 0) lines.push("_No tasks assigned to you here._");
|
|
@@ -22157,7 +22849,7 @@ var init_project_tasks = __esm({
|
|
|
22157
22849
|
init_http();
|
|
22158
22850
|
init_secret_task_status();
|
|
22159
22851
|
init_code_task_status();
|
|
22160
|
-
TEAM_STATUSES = /* @__PURE__ */ new Set(["todo", "in_progress", "
|
|
22852
|
+
TEAM_STATUSES = /* @__PURE__ */ new Set(["todo", "in_progress", "done", "rejected"]);
|
|
22161
22853
|
ANCHOR_RE = /<!--\s*cr-(secret|task)\b(?:\s+kind=([a-z]+))?\s+id=([A-Za-z0-9_-]+)(?:\s+was=([a-z_-]+))?\s*-->/;
|
|
22162
22854
|
CHECKBOX_RE = /^\s*-\s*\[([ xX])\]/;
|
|
22163
22855
|
STATUS_TOKEN_RE = /status:\s*`?([a-z_-]+)`?/i;
|
|
@@ -22173,18 +22865,18 @@ var intent_drain_exports = {};
|
|
|
22173
22865
|
__export(intent_drain_exports, {
|
|
22174
22866
|
drainSyncIntents: () => drainSyncIntents
|
|
22175
22867
|
});
|
|
22176
|
-
import { existsSync as
|
|
22177
|
-
import { join as
|
|
22178
|
-
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";
|
|
22179
22871
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
22180
|
-
import { dirname as
|
|
22872
|
+
import { dirname as dirname21 } from "node:path";
|
|
22181
22873
|
function applyCodeRecommendation(intent) {
|
|
22182
22874
|
try {
|
|
22183
22875
|
const meta = JSON.parse(intent.name || "{}");
|
|
22184
22876
|
if (intent.artifact_type === "write_tasks_file") {
|
|
22185
22877
|
if (!meta.rootPath || !meta.content) return { status: "error", result: JSON.stringify({ error: "missing rootPath or content" }) };
|
|
22186
|
-
const file =
|
|
22187
|
-
|
|
22878
|
+
const file = join51(meta.rootPath, meta.filename || "CODE_TASKS.md");
|
|
22879
|
+
writeFileSync16(file, meta.content);
|
|
22188
22880
|
return { status: "done", result: JSON.stringify({ wrote: file }) };
|
|
22189
22881
|
}
|
|
22190
22882
|
if (intent.artifact_type === "append_claude_md") {
|
|
@@ -22193,24 +22885,24 @@ function applyCodeRecommendation(intent) {
|
|
|
22193
22885
|
if (!text) return { status: "error", result: JSON.stringify({ error: "missing text" }) };
|
|
22194
22886
|
let file;
|
|
22195
22887
|
if (isGlobal) {
|
|
22196
|
-
const dir =
|
|
22888
|
+
const dir = join51(homedir20(), ".claude");
|
|
22197
22889
|
try {
|
|
22198
|
-
|
|
22890
|
+
mkdirSync15(dir, { recursive: true });
|
|
22199
22891
|
} catch {
|
|
22200
22892
|
}
|
|
22201
|
-
file =
|
|
22893
|
+
file = join51(dir, "CLAUDE.md");
|
|
22202
22894
|
} else {
|
|
22203
22895
|
if (!meta.rootPath) return { status: "error", result: JSON.stringify({ error: "missing rootPath" }) };
|
|
22204
|
-
file =
|
|
22896
|
+
file = join51(meta.rootPath, "CLAUDE.md");
|
|
22205
22897
|
}
|
|
22206
|
-
const existing =
|
|
22898
|
+
const existing = existsSync46(file) ? readFileSync42(file, "utf8") : "";
|
|
22207
22899
|
if (existing.includes(text)) return { status: "done", result: JSON.stringify({ skipped: "rule already present", file }) };
|
|
22208
22900
|
const block = `${existing && !existing.endsWith("\n") ? "\n" : ""}
|
|
22209
22901
|
## Rule (added by chat-recall recommendation)
|
|
22210
22902
|
${text}
|
|
22211
22903
|
`;
|
|
22212
22904
|
if (existing) appendFileSync(file, block);
|
|
22213
|
-
else
|
|
22905
|
+
else writeFileSync16(file, `# ${meta.rootPath?.split("/").pop() || "Global"} instructions
|
|
22214
22906
|
${block}`);
|
|
22215
22907
|
return { status: "done", result: JSON.stringify({ appended: file }) };
|
|
22216
22908
|
}
|
|
@@ -22309,11 +23001,11 @@ var init_intent_drain = __esm({
|
|
|
22309
23001
|
init_project_tasks();
|
|
22310
23002
|
ownVersion2 = "0.0.0";
|
|
22311
23003
|
try {
|
|
22312
|
-
const dir =
|
|
22313
|
-
ownVersion2 = JSON.parse(
|
|
23004
|
+
const dir = dirname21(fileURLToPath2(import.meta.url));
|
|
23005
|
+
ownVersion2 = JSON.parse(readFileSync42(join51(dir, "../package.json"), "utf-8")).version || ownVersion2;
|
|
22314
23006
|
} catch {
|
|
22315
23007
|
try {
|
|
22316
|
-
if (true) ownVersion2 = "0.5.
|
|
23008
|
+
if (true) ownVersion2 = "0.5.6";
|
|
22317
23009
|
} catch {
|
|
22318
23010
|
}
|
|
22319
23011
|
}
|
|
@@ -22514,43 +23206,43 @@ var team_merge_exports = {};
|
|
|
22514
23206
|
__export(team_merge_exports, {
|
|
22515
23207
|
mergePullResult: () => mergePullResult
|
|
22516
23208
|
});
|
|
22517
|
-
import { existsSync as
|
|
22518
|
-
import { dirname as
|
|
22519
|
-
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";
|
|
22520
23212
|
function installPathFor(art, tool) {
|
|
22521
23213
|
switch (art.type) {
|
|
22522
23214
|
case "skill":
|
|
22523
23215
|
switch (tool) {
|
|
22524
23216
|
case "claude":
|
|
22525
|
-
return
|
|
23217
|
+
return join52(claudeBackend.skillsDir(), art.name, "SKILL.md");
|
|
22526
23218
|
case "agy":
|
|
22527
23219
|
case "gemini":
|
|
22528
|
-
return
|
|
23220
|
+
return join52(geminiBackend.skillsDir(), art.name, "SKILL.md");
|
|
22529
23221
|
case "opencode":
|
|
22530
|
-
return
|
|
23222
|
+
return join52(opencodeBackend.skillsDir(), art.name, "SKILL.md");
|
|
22531
23223
|
// User skills go to ~/.codex/skills (NOT .system, which is OpenAI's bundle).
|
|
22532
23224
|
case "codex":
|
|
22533
|
-
return
|
|
23225
|
+
return join52(codexBackend.skillsDir(), art.name, "SKILL.md");
|
|
22534
23226
|
}
|
|
22535
23227
|
break;
|
|
22536
23228
|
case "agent":
|
|
22537
23229
|
if (tool === "claude")
|
|
22538
|
-
return
|
|
23230
|
+
return join52(claudeBackend.agentsDir(), `${art.name}.md`);
|
|
22539
23231
|
return null;
|
|
22540
23232
|
case "command":
|
|
22541
23233
|
if (tool === "claude")
|
|
22542
|
-
return
|
|
23234
|
+
return join52(claudeBackend.commandsDir(), `${art.name}.md`);
|
|
22543
23235
|
return null;
|
|
22544
23236
|
case "hook":
|
|
22545
23237
|
if (tool === "claude")
|
|
22546
|
-
return
|
|
23238
|
+
return join52(claudeBackend.homeDir(), "chat-recall-hooks", `${art.name}.json`);
|
|
22547
23239
|
return null;
|
|
22548
23240
|
case "plan":
|
|
22549
23241
|
switch (tool) {
|
|
22550
23242
|
case "claude":
|
|
22551
|
-
return
|
|
23243
|
+
return join52(claudeBackend.plansDir(), `${art.name}.md`);
|
|
22552
23244
|
case "opencode":
|
|
22553
|
-
return
|
|
23245
|
+
return join52(opencodeBackend.plansDir(), `${art.name}.md`);
|
|
22554
23246
|
case "agy":
|
|
22555
23247
|
case "gemini":
|
|
22556
23248
|
return null;
|
|
@@ -22560,11 +23252,11 @@ function installPathFor(art, tool) {
|
|
|
22560
23252
|
}
|
|
22561
23253
|
break;
|
|
22562
23254
|
case "instructions":
|
|
22563
|
-
return
|
|
23255
|
+
return join52(getDataDir(), "team-instructions", tool, `${art.name}.md`);
|
|
22564
23256
|
case "mcp":
|
|
22565
|
-
return
|
|
23257
|
+
return join52(getDataDir(), "team-mcps", `${art.name}.json`);
|
|
22566
23258
|
case "plugin":
|
|
22567
|
-
return
|
|
23259
|
+
return join52(getDataDir(), "team-plugins", tool, art.name, "manifest.json");
|
|
22568
23260
|
}
|
|
22569
23261
|
return null;
|
|
22570
23262
|
}
|
|
@@ -22590,20 +23282,20 @@ async function mergePullResult(opts) {
|
|
|
22590
23282
|
continue;
|
|
22591
23283
|
}
|
|
22592
23284
|
const body = Buffer.from(a.bodyB64, "base64");
|
|
22593
|
-
const sha =
|
|
23285
|
+
const sha = createHash17("sha256").update(body).digest("hex");
|
|
22594
23286
|
for (const tool of targets) {
|
|
22595
23287
|
const path = installPathFor(a, tool);
|
|
22596
23288
|
if (!path)
|
|
22597
23289
|
continue;
|
|
22598
23290
|
try {
|
|
22599
23291
|
const existing = readFileIfExists(path);
|
|
22600
|
-
if (existing &&
|
|
23292
|
+
if (existing && createHash17("sha256").update(existing).digest("hex") === sha) {
|
|
22601
23293
|
report.skipped.push({ artifactId: a.id, path, reason: "unchanged" });
|
|
22602
23294
|
pending.push({ artifactId: a.id, tool, artifactType: a.type, artifactName: a.name, sha256: sha, installedAt: Date.now() });
|
|
22603
23295
|
continue;
|
|
22604
23296
|
}
|
|
22605
|
-
|
|
22606
|
-
|
|
23297
|
+
mkdirSync16(dirname22(path), { recursive: true });
|
|
23298
|
+
writeFileSync17(path, body);
|
|
22607
23299
|
pending.push({ artifactId: a.id, tool, artifactType: a.type, artifactName: a.name, sha256: sha, installedAt: Date.now() });
|
|
22608
23300
|
report.written.push({ artifactId: a.id, path });
|
|
22609
23301
|
} catch (err) {
|
|
@@ -22624,7 +23316,7 @@ async function mergePullResult(opts) {
|
|
|
22624
23316
|
if (!path)
|
|
22625
23317
|
continue;
|
|
22626
23318
|
try {
|
|
22627
|
-
if (
|
|
23319
|
+
if (existsSync47(path))
|
|
22628
23320
|
rmSync7(path, { force: true });
|
|
22629
23321
|
await teamInstallsForget(id, row.tool);
|
|
22630
23322
|
report.removed.push({ artifactId: id, path });
|
|
@@ -22642,12 +23334,12 @@ async function mergePullResult(opts) {
|
|
|
22642
23334
|
}
|
|
22643
23335
|
function readFileIfExists(path) {
|
|
22644
23336
|
try {
|
|
22645
|
-
if (!
|
|
23337
|
+
if (!existsSync47(path))
|
|
22646
23338
|
return null;
|
|
22647
|
-
const s =
|
|
23339
|
+
const s = statSync40(path);
|
|
22648
23340
|
if (!s.isFile())
|
|
22649
23341
|
return null;
|
|
22650
|
-
return
|
|
23342
|
+
return readFileSync43(path);
|
|
22651
23343
|
} catch {
|
|
22652
23344
|
return null;
|
|
22653
23345
|
}
|
|
@@ -22726,8 +23418,8 @@ var init_vault_crypto = __esm({
|
|
|
22726
23418
|
});
|
|
22727
23419
|
|
|
22728
23420
|
// ../engine/dist/core/vault-source.js
|
|
22729
|
-
import { existsSync as
|
|
22730
|
-
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";
|
|
22731
23423
|
function* walkVaultSources() {
|
|
22732
23424
|
const t = loadSettings().team.vault;
|
|
22733
23425
|
const include2 = new Set(t.syncTools);
|
|
@@ -22742,7 +23434,7 @@ function* walkVaultSources() {
|
|
|
22742
23434
|
}
|
|
22743
23435
|
function safeStat(path) {
|
|
22744
23436
|
try {
|
|
22745
|
-
const s =
|
|
23437
|
+
const s = statSync41(path);
|
|
22746
23438
|
if (!s.isFile())
|
|
22747
23439
|
return null;
|
|
22748
23440
|
return { mtimeMs: s.mtimeMs, size: s.size };
|
|
@@ -22752,7 +23444,7 @@ function safeStat(path) {
|
|
|
22752
23444
|
}
|
|
22753
23445
|
function* walkClaude() {
|
|
22754
23446
|
const root = claudeBackend.projectsDir();
|
|
22755
|
-
if (!
|
|
23447
|
+
if (!existsSync48(root))
|
|
22756
23448
|
return;
|
|
22757
23449
|
let projectDirs = [];
|
|
22758
23450
|
try {
|
|
@@ -22763,8 +23455,8 @@ function* walkClaude() {
|
|
|
22763
23455
|
for (const proj of projectDirs) {
|
|
22764
23456
|
if (proj.startsWith("."))
|
|
22765
23457
|
continue;
|
|
22766
|
-
const projectPath =
|
|
22767
|
-
const projDir =
|
|
23458
|
+
const projectPath = decodeProjectDirName(proj);
|
|
23459
|
+
const projDir = join53(root, proj);
|
|
22768
23460
|
let entries = [];
|
|
22769
23461
|
try {
|
|
22770
23462
|
entries = readdirSync32(projDir);
|
|
@@ -22774,7 +23466,7 @@ function* walkClaude() {
|
|
|
22774
23466
|
for (const f of entries) {
|
|
22775
23467
|
if (extname(f) !== ".jsonl")
|
|
22776
23468
|
continue;
|
|
22777
|
-
const path =
|
|
23469
|
+
const path = join53(projDir, f);
|
|
22778
23470
|
const s = safeStat(path);
|
|
22779
23471
|
if (!s)
|
|
22780
23472
|
continue;
|
|
@@ -22785,7 +23477,7 @@ function* walkClaude() {
|
|
|
22785
23477
|
}
|
|
22786
23478
|
function* walkGemini() {
|
|
22787
23479
|
const tmp = geminiBackend.tmpDir();
|
|
22788
|
-
if (!
|
|
23480
|
+
if (!existsSync48(tmp))
|
|
22789
23481
|
return;
|
|
22790
23482
|
let hashDirs = [];
|
|
22791
23483
|
try {
|
|
@@ -22794,8 +23486,8 @@ function* walkGemini() {
|
|
|
22794
23486
|
return;
|
|
22795
23487
|
}
|
|
22796
23488
|
for (const hash of hashDirs) {
|
|
22797
|
-
const chatsDir =
|
|
22798
|
-
if (!
|
|
23489
|
+
const chatsDir = join53(tmp, hash, "chats");
|
|
23490
|
+
if (!existsSync48(chatsDir))
|
|
22799
23491
|
continue;
|
|
22800
23492
|
let entries = [];
|
|
22801
23493
|
try {
|
|
@@ -22807,7 +23499,7 @@ function* walkGemini() {
|
|
|
22807
23499
|
const ext = extname(f);
|
|
22808
23500
|
if (ext !== ".json" && ext !== ".jsonl")
|
|
22809
23501
|
continue;
|
|
22810
|
-
const path =
|
|
23502
|
+
const path = join53(chatsDir, f);
|
|
22811
23503
|
const s = safeStat(path);
|
|
22812
23504
|
if (!s)
|
|
22813
23505
|
continue;
|
|
@@ -22817,8 +23509,8 @@ function* walkGemini() {
|
|
|
22817
23509
|
}
|
|
22818
23510
|
}
|
|
22819
23511
|
function* walkCodex() {
|
|
22820
|
-
const sessionsRoot =
|
|
22821
|
-
if (!
|
|
23512
|
+
const sessionsRoot = join53(codexBackend.homeDir(), "sessions");
|
|
23513
|
+
if (!existsSync48(sessionsRoot))
|
|
22822
23514
|
return;
|
|
22823
23515
|
const stack = [sessionsRoot];
|
|
22824
23516
|
while (stack.length) {
|
|
@@ -22830,7 +23522,7 @@ function* walkCodex() {
|
|
|
22830
23522
|
continue;
|
|
22831
23523
|
}
|
|
22832
23524
|
for (const e of entries) {
|
|
22833
|
-
const path =
|
|
23525
|
+
const path = join53(dir, e.name);
|
|
22834
23526
|
if (e.isDirectory()) {
|
|
22835
23527
|
stack.push(path);
|
|
22836
23528
|
continue;
|
|
@@ -22846,8 +23538,8 @@ function* walkCodex() {
|
|
|
22846
23538
|
}
|
|
22847
23539
|
}
|
|
22848
23540
|
function* walkAgy() {
|
|
22849
|
-
const brainDir =
|
|
22850
|
-
if (!
|
|
23541
|
+
const brainDir = join53(agyBackend.homeDir(), "brain");
|
|
23542
|
+
if (!existsSync48(brainDir))
|
|
22851
23543
|
return;
|
|
22852
23544
|
let sessionDirs = [];
|
|
22853
23545
|
try {
|
|
@@ -22856,18 +23548,18 @@ function* walkAgy() {
|
|
|
22856
23548
|
return;
|
|
22857
23549
|
}
|
|
22858
23550
|
for (const rawId of sessionDirs) {
|
|
22859
|
-
const sessionPath =
|
|
23551
|
+
const sessionPath = join53(brainDir, rawId);
|
|
22860
23552
|
try {
|
|
22861
|
-
if (!
|
|
23553
|
+
if (!statSync41(sessionPath).isDirectory())
|
|
22862
23554
|
continue;
|
|
22863
23555
|
} catch {
|
|
22864
23556
|
continue;
|
|
22865
23557
|
}
|
|
22866
|
-
let filePath =
|
|
22867
|
-
if (!
|
|
22868
|
-
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");
|
|
22869
23561
|
}
|
|
22870
|
-
if (!
|
|
23562
|
+
if (!existsSync48(filePath))
|
|
22871
23563
|
continue;
|
|
22872
23564
|
const s = safeStat(filePath);
|
|
22873
23565
|
if (!s)
|
|
@@ -22884,6 +23576,7 @@ var init_vault_source = __esm({
|
|
|
22884
23576
|
init_codex2();
|
|
22885
23577
|
init_agy();
|
|
22886
23578
|
init_settings();
|
|
23579
|
+
init_project_dir_name();
|
|
22887
23580
|
}
|
|
22888
23581
|
});
|
|
22889
23582
|
|
|
@@ -22900,8 +23593,8 @@ __export(vault_client_exports, {
|
|
|
22900
23593
|
vaultStatus: () => vaultStatus,
|
|
22901
23594
|
vaultSync: () => vaultSync
|
|
22902
23595
|
});
|
|
22903
|
-
import { mkdirSync as
|
|
22904
|
-
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";
|
|
22905
23598
|
function context2() {
|
|
22906
23599
|
const s = loadSettings().team;
|
|
22907
23600
|
if (!s.enabled)
|
|
@@ -23040,7 +23733,7 @@ async function vaultSync(passphrase) {
|
|
|
23040
23733
|
continue;
|
|
23041
23734
|
}
|
|
23042
23735
|
try {
|
|
23043
|
-
const plaintext =
|
|
23736
|
+
const plaintext = readFileSync44(src.path);
|
|
23044
23737
|
const sourceSha = sha256Hex(plaintext);
|
|
23045
23738
|
const priorSha = uploaded.get(uploadKey(src.sessionId, src.tool));
|
|
23046
23739
|
if (priorSha === sourceSha) {
|
|
@@ -23092,7 +23785,7 @@ async function vaultSync(passphrase) {
|
|
|
23092
23785
|
}
|
|
23093
23786
|
function importedPathFor(tool, sessionId) {
|
|
23094
23787
|
const base2 = sessionId.replace(/^gemini_/, "").replace(/^codex_/, "").replace(/^opencode_/, "");
|
|
23095
|
-
return
|
|
23788
|
+
return join54(IMPORTED_ROOT(), tool, `${base2}.jsonl`);
|
|
23096
23789
|
}
|
|
23097
23790
|
async function vaultRestore(passphrase, opts = {}) {
|
|
23098
23791
|
const ctx = context2();
|
|
@@ -23113,7 +23806,7 @@ async function vaultRestore(passphrase, opts = {}) {
|
|
|
23113
23806
|
}
|
|
23114
23807
|
try {
|
|
23115
23808
|
const path = importedPathFor(blob.tool, blob.sessionId);
|
|
23116
|
-
if (
|
|
23809
|
+
if (existsSync49(path)) {
|
|
23117
23810
|
const localStat = await import("fs").then((m) => m.statSync(path));
|
|
23118
23811
|
if (Math.abs(localStat.mtimeMs - blob.mtimeSourceMs) < 1) {
|
|
23119
23812
|
report.skipped.push({ sessionId: blob.sessionId, tool: blob.tool, reason: "unchanged" });
|
|
@@ -23129,8 +23822,8 @@ async function vaultRestore(passphrase, opts = {}) {
|
|
|
23129
23822
|
throw new Error("cipher integrity check failed");
|
|
23130
23823
|
}
|
|
23131
23824
|
const plaintext = decryptBlob(key, cipher);
|
|
23132
|
-
|
|
23133
|
-
|
|
23825
|
+
mkdirSync17(dirname23(path), { recursive: true });
|
|
23826
|
+
writeFileSync18(path, Buffer.from(plaintext));
|
|
23134
23827
|
const { utimesSync } = await import("fs");
|
|
23135
23828
|
const t = blob.mtimeSourceMs / 1e3;
|
|
23136
23829
|
utimesSync(path, t, t);
|
|
@@ -23181,7 +23874,7 @@ var init_vault_client = __esm({
|
|
|
23181
23874
|
uploadKey = (sessionId, tool) => `${sessionId}\0${tool}`;
|
|
23182
23875
|
VaultPassphraseMismatchError = class extends Error {
|
|
23183
23876
|
};
|
|
23184
|
-
IMPORTED_ROOT = () =>
|
|
23877
|
+
IMPORTED_ROOT = () => join54(getDataDir(), "imported");
|
|
23185
23878
|
}
|
|
23186
23879
|
});
|
|
23187
23880
|
|
|
@@ -23335,15 +24028,15 @@ __export(service_installer_exports, {
|
|
|
23335
24028
|
uninstallService: () => uninstallService
|
|
23336
24029
|
});
|
|
23337
24030
|
import { execSync as execSync5 } from "child_process";
|
|
23338
|
-
import { existsSync as
|
|
23339
|
-
import { homedir as
|
|
23340
|
-
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";
|
|
23341
24034
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
23342
24035
|
function resolveDaemonPaths() {
|
|
23343
24036
|
const watchJs = fileURLToPath3(new URL("./watch.js", import.meta.url));
|
|
23344
24037
|
const node = process.execPath;
|
|
23345
|
-
const dataDir =
|
|
23346
|
-
const logFile =
|
|
24038
|
+
const dataDir = join55(homedir21(), ".chat-recall");
|
|
24039
|
+
const logFile = join55(dataDir, "watch.log");
|
|
23347
24040
|
return { watchJs, node, logFile, dataDir };
|
|
23348
24041
|
}
|
|
23349
24042
|
function tryCmd(cmd) {
|
|
@@ -23368,7 +24061,7 @@ function isServiceRunning() {
|
|
|
23368
24061
|
}
|
|
23369
24062
|
function installService() {
|
|
23370
24063
|
const { watchJs, node, logFile, dataDir } = resolveDaemonPaths();
|
|
23371
|
-
|
|
24064
|
+
mkdirSync18(dataDir, { recursive: true });
|
|
23372
24065
|
if (process.platform === "linux") {
|
|
23373
24066
|
return installSystemd(watchJs, node, logFile);
|
|
23374
24067
|
}
|
|
@@ -23384,11 +24077,11 @@ function installService() {
|
|
|
23384
24077
|
);
|
|
23385
24078
|
}
|
|
23386
24079
|
function installSystemd(watchJs, node, logFile) {
|
|
23387
|
-
const unitDir =
|
|
23388
|
-
const unitPath =
|
|
24080
|
+
const unitDir = join55(homedir21(), ".config", "systemd", "user");
|
|
24081
|
+
const unitPath = join55(unitDir, "chat-recall-watch.service");
|
|
23389
24082
|
const unit = renderSystemdUnit(watchJs, node, logFile);
|
|
23390
|
-
|
|
23391
|
-
|
|
24083
|
+
mkdirSync18(unitDir, { recursive: true });
|
|
24084
|
+
writeFileSync19(unitPath, unit);
|
|
23392
24085
|
try {
|
|
23393
24086
|
execSync5("systemctl --user daemon-reload && systemctl --user enable chat-recall-watch.service && systemctl --user restart chat-recall-watch.service", { stdio: "inherit" });
|
|
23394
24087
|
try {
|
|
@@ -23416,10 +24109,14 @@ function renderSystemdUnit(watchJs, node, logFile) {
|
|
|
23416
24109
|
"Restart=on-failure",
|
|
23417
24110
|
"RestartSec=10",
|
|
23418
24111
|
"Nice=10",
|
|
23419
|
-
//
|
|
23420
|
-
//
|
|
23421
|
-
|
|
23422
|
-
|
|
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",
|
|
23423
24120
|
"",
|
|
23424
24121
|
"[Install]",
|
|
23425
24122
|
"WantedBy=default.target",
|
|
@@ -23428,11 +24125,11 @@ function renderSystemdUnit(watchJs, node, logFile) {
|
|
|
23428
24125
|
}
|
|
23429
24126
|
function installLaunchd(watchJs, node, logFile) {
|
|
23430
24127
|
const label = "com.chat-recall.watch";
|
|
23431
|
-
const plistDir =
|
|
23432
|
-
const plistPath =
|
|
24128
|
+
const plistDir = join55(homedir21(), "Library", "LaunchAgents");
|
|
24129
|
+
const plistPath = join55(plistDir, `${label}.plist`);
|
|
23433
24130
|
const plist = renderLaunchdPlist(watchJs, node, logFile, label);
|
|
23434
|
-
|
|
23435
|
-
|
|
24131
|
+
mkdirSync18(plistDir, { recursive: true });
|
|
24132
|
+
writeFileSync19(plistPath, plist);
|
|
23436
24133
|
try {
|
|
23437
24134
|
try {
|
|
23438
24135
|
execSync5(`launchctl unload "${plistPath}"`, { stdio: "ignore" });
|
|
@@ -23461,7 +24158,7 @@ function renderLaunchdPlist(watchJs, node, logFile, label = "com.chat-recall.wat
|
|
|
23461
24158
|
}
|
|
23462
24159
|
function installWindowsTask(watchJs, node, logFile) {
|
|
23463
24160
|
const taskName = "chat-recall-watch";
|
|
23464
|
-
const tr =
|
|
24161
|
+
const tr = `cmd /c \\"\\"${node}\\" --max-old-space-size=1536 \\"${watchJs}\\" >> \\"${logFile}\\" 2>&1\\"`;
|
|
23465
24162
|
try {
|
|
23466
24163
|
execSync5(`schtasks /create /tn "${taskName}" /tr "${tr}" /sc onlogon /rl LIMITED /f`, { stdio: "inherit" });
|
|
23467
24164
|
try {
|
|
@@ -23473,8 +24170,8 @@ function installWindowsTask(watchJs, node, logFile) {
|
|
|
23473
24170
|
}
|
|
23474
24171
|
return { definitionPath: null, logFile };
|
|
23475
24172
|
}
|
|
23476
|
-
function renderWindowsTaskCommand(watchJs, node, taskName = "chat-recall-watch") {
|
|
23477
|
-
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}\\"`;
|
|
23478
24175
|
return `schtasks /create /tn "${taskName}" /tr "${tr}" /sc onlogon /rl LIMITED /f`;
|
|
23479
24176
|
}
|
|
23480
24177
|
function uninstallService() {
|
|
@@ -23485,8 +24182,8 @@ function uninstallService() {
|
|
|
23485
24182
|
removed = true;
|
|
23486
24183
|
} catch {
|
|
23487
24184
|
}
|
|
23488
|
-
const unitPath =
|
|
23489
|
-
if (
|
|
24185
|
+
const unitPath = join55(homedir21(), ".config", "systemd", "user", "chat-recall-watch.service");
|
|
24186
|
+
if (existsSync50(unitPath)) {
|
|
23490
24187
|
rmSync8(unitPath, { force: true });
|
|
23491
24188
|
removed = true;
|
|
23492
24189
|
}
|
|
@@ -23497,13 +24194,13 @@ function uninstallService() {
|
|
|
23497
24194
|
return removed;
|
|
23498
24195
|
}
|
|
23499
24196
|
if (process.platform === "darwin") {
|
|
23500
|
-
const plistPath =
|
|
24197
|
+
const plistPath = join55(homedir21(), "Library", "LaunchAgents", "com.chat-recall.watch.plist");
|
|
23501
24198
|
try {
|
|
23502
24199
|
execSync5(`launchctl unload "${plistPath}" 2>/dev/null`, { stdio: "ignore" });
|
|
23503
24200
|
} catch {
|
|
23504
24201
|
}
|
|
23505
24202
|
let removed = false;
|
|
23506
|
-
if (
|
|
24203
|
+
if (existsSync50(plistPath)) {
|
|
23507
24204
|
rmSync8(plistPath, { force: true });
|
|
23508
24205
|
removed = true;
|
|
23509
24206
|
}
|
|
@@ -23548,7 +24245,7 @@ __export(device_auth_exports, {
|
|
|
23548
24245
|
betterAuthDeviceLogin: () => betterAuthDeviceLogin,
|
|
23549
24246
|
deviceLogin: () => deviceLogin
|
|
23550
24247
|
});
|
|
23551
|
-
import { createHash as
|
|
24248
|
+
import { createHash as createHash18, randomBytes } from "node:crypto";
|
|
23552
24249
|
async function deviceLogin(opts, onPrompt) {
|
|
23553
24250
|
const issuer = (opts.issuer || DEFAULT_ISSUER).replace(/\/+$/, "");
|
|
23554
24251
|
if (!issuer) {
|
|
@@ -23559,7 +24256,7 @@ async function deviceLogin(opts, onPrompt) {
|
|
|
23559
24256
|
const clientId = opts.clientId || DEFAULT_CLIENT_ID;
|
|
23560
24257
|
const scope = opts.scope || "openid email profile";
|
|
23561
24258
|
const codeVerifier = b64url(randomBytes(32));
|
|
23562
|
-
const codeChallenge = b64url(
|
|
24259
|
+
const codeChallenge = b64url(createHash18("sha256").update(codeVerifier).digest());
|
|
23563
24260
|
const startRes = await fetch(`${issuer}/protocol/openid-connect/auth/device`, {
|
|
23564
24261
|
method: "POST",
|
|
23565
24262
|
headers: { "content-type": "application/x-www-form-urlencoded" },
|
|
@@ -23681,10 +24378,9 @@ init_project_resolver();
|
|
|
23681
24378
|
import { config } from "dotenv";
|
|
23682
24379
|
import { Command } from "commander";
|
|
23683
24380
|
import chalk from "chalk";
|
|
23684
|
-
import { existsSync as
|
|
23685
|
-
import { homedir as
|
|
23686
|
-
import { join as
|
|
23687
|
-
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";
|
|
23688
24384
|
|
|
23689
24385
|
// ../engine/dist/core/score-tier.js
|
|
23690
24386
|
var STRONG_RATIO = 0.85;
|
|
@@ -23711,6 +24407,68 @@ function tierAll(results) {
|
|
|
23711
24407
|
// src/cli.ts
|
|
23712
24408
|
init_sync_client();
|
|
23713
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
|
|
23714
24472
|
function matchLabel(tier) {
|
|
23715
24473
|
switch (tier) {
|
|
23716
24474
|
case "strong":
|
|
@@ -23728,8 +24486,8 @@ function claudeHookConfigFiles() {
|
|
|
23728
24486
|
const out = [];
|
|
23729
24487
|
const seen = /* @__PURE__ */ new Set();
|
|
23730
24488
|
for (const home of claudeHomeDirs()) {
|
|
23731
|
-
if (!
|
|
23732
|
-
const file =
|
|
24489
|
+
if (!existsSync51(join56(home, "projects"))) continue;
|
|
24490
|
+
const file = join56(home, "hooks.json");
|
|
23733
24491
|
let key;
|
|
23734
24492
|
try {
|
|
23735
24493
|
key = realpathSync5(file);
|
|
@@ -23803,7 +24561,7 @@ async function serverDelete(path, body) {
|
|
|
23803
24561
|
return res.json();
|
|
23804
24562
|
}
|
|
23805
24563
|
var pkgVersion = JSON.parse(
|
|
23806
|
-
|
|
24564
|
+
readFileSync45(new URL("../package.json", import.meta.url), "utf-8")
|
|
23807
24565
|
).version;
|
|
23808
24566
|
var DEFAULT_SERVER = "https://chatrecall.dev";
|
|
23809
24567
|
var DEFAULT_ALLOW = [
|
|
@@ -23826,6 +24584,8 @@ var DEFAULT_ALLOW = [
|
|
|
23826
24584
|
"recall_tasks",
|
|
23827
24585
|
"recall_task_create",
|
|
23828
24586
|
"recall_task_update",
|
|
24587
|
+
"recall_task_comment",
|
|
24588
|
+
"recall_help",
|
|
23829
24589
|
"recall_smart_resume",
|
|
23830
24590
|
"recall_project_context",
|
|
23831
24591
|
"recall_weekly_digest",
|
|
@@ -23883,7 +24643,7 @@ program.command("init").description("Set up chat-recall: connect to your server,
|
|
|
23883
24643
|
];
|
|
23884
24644
|
for (const cli of clis) {
|
|
23885
24645
|
try {
|
|
23886
|
-
|
|
24646
|
+
if (!isOnPath(cli.cmd)) throw new Error("not on PATH");
|
|
23887
24647
|
cli.available = true;
|
|
23888
24648
|
} catch {
|
|
23889
24649
|
}
|
|
@@ -23915,37 +24675,22 @@ program.command("init").description("Set up chat-recall: connect to your server,
|
|
|
23915
24675
|
console.log();
|
|
23916
24676
|
if (!options.skipMcp) {
|
|
23917
24677
|
console.log(chalk.bold("4. Configuring MCP server..."));
|
|
23918
|
-
const
|
|
23919
|
-
let mcpConfig = {};
|
|
23920
|
-
if (existsSync49(mcpJsonPath)) {
|
|
23921
|
-
try {
|
|
23922
|
-
mcpConfig = JSON.parse(readFileSync44(mcpJsonPath, "utf-8"));
|
|
23923
|
-
} catch {
|
|
23924
|
-
mcpConfig = {};
|
|
23925
|
-
}
|
|
23926
|
-
}
|
|
23927
|
-
const mcpServers = mcpConfig.mcpServers || {};
|
|
23928
|
-
const projectRoot = join53(import.meta.dirname, "..");
|
|
24678
|
+
const projectRoot = join56(import.meta.dirname, "..");
|
|
23929
24679
|
let mcpBinOnPath = false;
|
|
23930
|
-
|
|
23931
|
-
|
|
23932
|
-
mcpBinOnPath = true;
|
|
23933
|
-
} catch {
|
|
23934
|
-
}
|
|
23935
|
-
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")] };
|
|
23936
24682
|
const MCP_ENV = { NODE_OPTIONS: "--max-old-space-size=1024" };
|
|
23937
|
-
const
|
|
23938
|
-
const
|
|
23939
|
-
|
|
23940
|
-
|
|
23941
|
-
|
|
23942
|
-
|
|
23943
|
-
|
|
23944
|
-
|
|
23945
|
-
|
|
23946
|
-
writeFileSync18(mcpJsonPath, JSON.stringify(mcpConfig, null, 2));
|
|
23947
|
-
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}`);
|
|
23948
24692
|
}
|
|
24693
|
+
console.log(chalk.dim(` Launch: ${launch.command}${launch.args ? " " + launch.args.join(" ") : ""}`));
|
|
23949
24694
|
} else {
|
|
23950
24695
|
console.log(chalk.bold("4. Skipping MCP configuration (--skip-mcp)"));
|
|
23951
24696
|
}
|
|
@@ -23966,7 +24711,7 @@ program.command("init").description("Set up chat-recall: connect to your server,
|
|
|
23966
24711
|
console.log(chalk.bold("5. Detected codeindex companion"));
|
|
23967
24712
|
console.log(` ${chalk.green("codeindex")}: ${detected.path}`);
|
|
23968
24713
|
if (!options.skipMcp) {
|
|
23969
|
-
const mcpJsonPath =
|
|
24714
|
+
const mcpJsonPath = join56(homedir22(), ".mcp.json");
|
|
23970
24715
|
const reg = registerCodeindexMcp2(mcpJsonPath, detected.path);
|
|
23971
24716
|
if (reg.added) console.log(` ${chalk.green("codeindex MCP server registered")} in ${mcpJsonPath}`);
|
|
23972
24717
|
else console.log(` codeindex MCP server: ${chalk.green("already registered")}`);
|
|
@@ -23979,7 +24724,7 @@ program.command("init").description("Set up chat-recall: connect to your server,
|
|
|
23979
24724
|
const sizeMb = result.size ? `${(result.size / 1024 / 1024).toFixed(1)} MB` : "?";
|
|
23980
24725
|
console.log(` ${chalk.green("codeindex installed")} (${sizeMb}) \u2192 ${result.path}`);
|
|
23981
24726
|
if (!options.skipMcp) {
|
|
23982
|
-
const mcpJsonPath =
|
|
24727
|
+
const mcpJsonPath = join56(homedir22(), ".mcp.json");
|
|
23983
24728
|
const reg = registerCodeindexMcp2(mcpJsonPath, CODEINDEX_BIN_PATH2);
|
|
23984
24729
|
if (reg.added) console.log(` ${chalk.green("codeindex MCP server registered")} in ${mcpJsonPath}`);
|
|
23985
24730
|
}
|
|
@@ -24377,8 +25122,8 @@ memory.command("wake-up").description("Generate wake-up context (high-importance
|
|
|
24377
25122
|
try {
|
|
24378
25123
|
const identityFile = getIdentityFilePath();
|
|
24379
25124
|
let identity = "AI coding assistant";
|
|
24380
|
-
if (
|
|
24381
|
-
identity =
|
|
25125
|
+
if (existsSync51(identityFile)) {
|
|
25126
|
+
identity = readFileSync45(identityFile, "utf-8").trim();
|
|
24382
25127
|
}
|
|
24383
25128
|
const lines = [
|
|
24384
25129
|
chalk.bold("# Wake-Up Context"),
|
|
@@ -24435,8 +25180,8 @@ program.command("escalate [sessionId]").description("Escalate a finished session
|
|
|
24435
25180
|
}
|
|
24436
25181
|
});
|
|
24437
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) => {
|
|
24438
|
-
const { existsSync:
|
|
24439
|
-
const { execSync:
|
|
25183
|
+
const { existsSync: existsSync52, readFileSync: readFileSync46, statSync: statSync42 } = await import("fs");
|
|
25184
|
+
const { execSync: execSync6 } = await import("child_process");
|
|
24440
25185
|
const rows = [];
|
|
24441
25186
|
const note = (ok, label, detail) => rows.push({ ok, label, detail });
|
|
24442
25187
|
const targets = loadAllCredentials();
|
|
@@ -24460,36 +25205,50 @@ program.command("doctor").description("Quick health check across login, server,
|
|
|
24460
25205
|
} else {
|
|
24461
25206
|
note(false, "Server reachable", "N/A (not logged in)");
|
|
24462
25207
|
}
|
|
24463
|
-
|
|
24464
|
-
|
|
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)) {
|
|
24465
25223
|
note(false, "Credentials file", `missing \u2014 run \`chat-recall login <server-url>\``);
|
|
24466
25224
|
} else {
|
|
24467
25225
|
try {
|
|
24468
|
-
const mode =
|
|
24469
|
-
const
|
|
24470
|
-
|
|
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"})`);
|
|
24471
25230
|
} catch (err) {
|
|
24472
25231
|
note(false, "Credentials file", `error: ${err}`);
|
|
24473
25232
|
}
|
|
24474
25233
|
}
|
|
24475
25234
|
for (const hooksJson of claudeHookConfigFiles()) {
|
|
24476
|
-
const profile = basename27(
|
|
25235
|
+
const profile = basename27(dirname24(hooksJson));
|
|
24477
25236
|
const label = `Claude hooks (${profile})`;
|
|
24478
|
-
if (!
|
|
25237
|
+
if (!existsSync52(hooksJson)) {
|
|
24479
25238
|
note(false, label, `no ${hooksJson} \u2014 run \`chat-recall install-hooks\``);
|
|
24480
25239
|
continue;
|
|
24481
25240
|
}
|
|
24482
25241
|
try {
|
|
24483
25242
|
const readHooks = (file) => {
|
|
24484
|
-
if (!
|
|
25243
|
+
if (!existsSync52(file)) return {};
|
|
24485
25244
|
try {
|
|
24486
|
-
return JSON.parse(
|
|
25245
|
+
return JSON.parse(readFileSync46(file, "utf-8")).hooks || {};
|
|
24487
25246
|
} catch {
|
|
24488
25247
|
return {};
|
|
24489
25248
|
}
|
|
24490
25249
|
};
|
|
24491
25250
|
const cfg = readHooks(hooksJson);
|
|
24492
|
-
const settings2 = readHooks(
|
|
25251
|
+
const settings2 = readHooks(join56(dirname24(hooksJson), "settings.json"));
|
|
24493
25252
|
const all = ["SessionStart", "UserPromptSubmit", "Stop", "PreCompact", "SessionEnd"];
|
|
24494
25253
|
const hits = [];
|
|
24495
25254
|
for (const ev of all) {
|
|
@@ -24513,7 +25272,7 @@ program.command("doctor").description("Quick health check across login, server,
|
|
|
24513
25272
|
const want = bundledSkillNames2().length;
|
|
24514
25273
|
for (const t of skillTargets2()) {
|
|
24515
25274
|
if (!t.available) continue;
|
|
24516
|
-
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;
|
|
24517
25276
|
note(
|
|
24518
25277
|
have === want,
|
|
24519
25278
|
`Skills \u2014 ${t.label}`,
|
|
@@ -24523,17 +25282,18 @@ program.command("doctor").description("Quick health check across login, server,
|
|
|
24523
25282
|
} catch (err) {
|
|
24524
25283
|
note(false, "Skills", `check failed: ${err}`);
|
|
24525
25284
|
}
|
|
24526
|
-
|
|
24527
|
-
|
|
24528
|
-
|
|
24529
|
-
|
|
24530
|
-
|
|
24531
|
-
|
|
24532
|
-
|
|
24533
|
-
|
|
24534
|
-
|
|
24535
|
-
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
|
+
);
|
|
24536
25294
|
}
|
|
25295
|
+
} catch (err) {
|
|
25296
|
+
note(false, "MCP server registration", `check failed: ${err}`);
|
|
24537
25297
|
}
|
|
24538
25298
|
try {
|
|
24539
25299
|
const { checkCodeindexStatus: checkCodeindexStatus2 } = await Promise.resolve().then(() => (init_companions(), companions_exports));
|
|
@@ -24571,7 +25331,7 @@ program.command("doctor").description("Quick health check across login, server,
|
|
|
24571
25331
|
let watchRunning = false;
|
|
24572
25332
|
const tryCmd2 = (cmd) => {
|
|
24573
25333
|
try {
|
|
24574
|
-
return
|
|
25334
|
+
return execSync6(cmd, { stdio: ["ignore", "pipe", "ignore"] }).toString();
|
|
24575
25335
|
} catch {
|
|
24576
25336
|
return "";
|
|
24577
25337
|
}
|
|
@@ -24587,14 +25347,14 @@ program.command("doctor").description("Quick health check across login, server,
|
|
|
24587
25347
|
note(watchRunning, "Watch daemon", watchRunning ? "running" : "not running (run `chat-recall watch --install-service` to keep collection running)");
|
|
24588
25348
|
const dataDir = getDataDir();
|
|
24589
25349
|
const legacyPaths = [
|
|
24590
|
-
|
|
24591
|
-
|
|
24592
|
-
|
|
24593
|
-
|
|
24594
|
-
|
|
24595
|
-
|
|
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")
|
|
24596
25356
|
];
|
|
24597
|
-
const legacyPresent = legacyPaths.filter((p) =>
|
|
25357
|
+
const legacyPresent = legacyPaths.filter((p) => existsSync52(p));
|
|
24598
25358
|
if (opts.purgeLocal) {
|
|
24599
25359
|
if (!target) {
|
|
24600
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");
|
|
@@ -24665,7 +25425,7 @@ companions.command("install").description("Install codeindex (downloads from mun
|
|
|
24665
25425
|
if (result.installed) {
|
|
24666
25426
|
const sizeMb = result.size ? `${(result.size / 1024 / 1024).toFixed(1)} MB` : "?";
|
|
24667
25427
|
console.log(chalk.green(`\u2713 codeindex installed (${sizeMb}) \u2192 ${result.path}`));
|
|
24668
|
-
const mcpJsonPath =
|
|
25428
|
+
const mcpJsonPath = join56(homedir22(), ".mcp.json");
|
|
24669
25429
|
const reg = registerCodeindexMcp2(mcpJsonPath, CODEINDEX_BIN_PATH2);
|
|
24670
25430
|
if (reg.added) console.log(chalk.dim(` Registered as MCP server in ${mcpJsonPath}`));
|
|
24671
25431
|
else console.log(chalk.dim(` Already registered as MCP server`));
|
|
@@ -24687,7 +25447,7 @@ companions.command("uninstall").description("Remove the codeindex binary chat-re
|
|
|
24687
25447
|
const r = uninstallCodeindex2();
|
|
24688
25448
|
if (r.removed) console.log(chalk.green(`\u2713 Removed ${r.path}`));
|
|
24689
25449
|
else console.log(chalk.dim(` Nothing to remove at ${r.path}`));
|
|
24690
|
-
const mcpJsonPath =
|
|
25450
|
+
const mcpJsonPath = join56(homedir22(), ".mcp.json");
|
|
24691
25451
|
const u = unregisterCodeindexMcp2(mcpJsonPath);
|
|
24692
25452
|
if (u.removed) console.log(chalk.dim(` Unregistered MCP server from ${mcpJsonPath}`));
|
|
24693
25453
|
});
|
|
@@ -25182,10 +25942,10 @@ tasks.command("pull [dir]").description("Write TEAM_TASKS.md for your tasks in t
|
|
|
25182
25942
|
try {
|
|
25183
25943
|
const { resolveProjectId: resolveProjectId2 } = await Promise.resolve().then(() => (init_project_resolver(), project_resolver_exports));
|
|
25184
25944
|
const { renderTeamTasksMd: renderTeamTasksMd2, parseTeamTasksFile: parseTeamTasksFile2 } = await Promise.resolve().then(() => (init_project_tasks(), project_tasks_exports));
|
|
25185
|
-
const { writeFileSync:
|
|
25186
|
-
const { join:
|
|
25187
|
-
const file =
|
|
25188
|
-
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) {
|
|
25189
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.");
|
|
25190
25950
|
process.exit(1);
|
|
25191
25951
|
}
|
|
@@ -25193,7 +25953,7 @@ tasks.command("pull [dir]").description("Write TEAM_TASKS.md for your tasks in t
|
|
|
25193
25953
|
const pid = resolved && resolved.source !== "ignored" ? resolved.id : "";
|
|
25194
25954
|
const { tasks: tasks2 } = await serverGet("/api/tasks?assignee=@me");
|
|
25195
25955
|
const mine = tasks2.filter((t) => !pid || !t.projectId || t.projectId === pid);
|
|
25196
|
-
|
|
25956
|
+
writeFileSync21(file, renderTeamTasksMd2(mine));
|
|
25197
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"));
|
|
25198
25958
|
} catch (e) {
|
|
25199
25959
|
console.error(chalk.red(e instanceof Error ? e.message : String(e)));
|
|
@@ -25204,14 +25964,14 @@ tasks.command("push [dir]").description("Push TEAM_TASKS.md status edits back to
|
|
|
25204
25964
|
const cwd = dir || process.cwd();
|
|
25205
25965
|
try {
|
|
25206
25966
|
const { parseTeamTasksFile: parseTeamTasksFile2 } = await Promise.resolve().then(() => (init_project_tasks(), project_tasks_exports));
|
|
25207
|
-
const { readFileSync:
|
|
25208
|
-
const { join:
|
|
25209
|
-
const file =
|
|
25210
|
-
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)) {
|
|
25211
25971
|
console.error(chalk.red("no TEAM_TASKS.md here \u2014"), "run", chalk.bold("chat-recall tasks pull"), "first");
|
|
25212
25972
|
process.exit(1);
|
|
25213
25973
|
}
|
|
25214
|
-
const edits = parseTeamTasksFile2(
|
|
25974
|
+
const edits = parseTeamTasksFile2(readFileSync46(file, "utf8"));
|
|
25215
25975
|
let n = 0;
|
|
25216
25976
|
for (const e of edits) {
|
|
25217
25977
|
await serverPatch(`/api/tasks/${encodeURIComponent(e.id)}`, { status: e.intent });
|
|
@@ -25317,8 +26077,8 @@ team.command("publish <type> <name> <file>").description("Publish a local file a
|
|
|
25317
26077
|
console.error(chalk.red(`Invalid tool: ${opts.tool}. Must be one of: ${validTools.join(", ")}`));
|
|
25318
26078
|
process.exit(1);
|
|
25319
26079
|
}
|
|
25320
|
-
const { readFileSync:
|
|
25321
|
-
const body =
|
|
26080
|
+
const { readFileSync: readFileSync46 } = await import("fs");
|
|
26081
|
+
const body = readFileSync46(file);
|
|
25322
26082
|
const { teamPublish: teamPublish2 } = await Promise.resolve().then(() => (init_team_client(), team_client_exports));
|
|
25323
26083
|
const a = await teamPublish2({
|
|
25324
26084
|
type,
|
|
@@ -25505,15 +26265,15 @@ vault.command("forget").description("Remove the stored passphrase from this mach
|
|
|
25505
26265
|
console.log(keyringDelete2() ? chalk.green("\u2713 Passphrase removed from the OS keyring.") : chalk.dim("Nothing stored in the OS keyring."));
|
|
25506
26266
|
}));
|
|
25507
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) => {
|
|
25508
|
-
const { mkdirSync:
|
|
26268
|
+
const { mkdirSync: mkdirSync19, copyFileSync: copyFileSync4, chmodSync: chmodSync5, existsSync: existsSync52, readFileSync: readFileSync46, writeFileSync: writeFileSync21, statSync: statSync42 } = await import("fs");
|
|
25509
26269
|
const { fileURLToPath: fileURLToPath4 } = await import("url");
|
|
25510
26270
|
const here = fileURLToPath4(new URL(".", import.meta.url));
|
|
25511
26271
|
const findHook = (name) => {
|
|
25512
|
-
const
|
|
25513
|
-
|
|
25514
|
-
|
|
26272
|
+
const candidates2 = [
|
|
26273
|
+
join56(here, "..", "hooks", name),
|
|
26274
|
+
join56(here, "..", "..", "hooks", name)
|
|
25515
26275
|
];
|
|
25516
|
-
return
|
|
26276
|
+
return candidates2.find((p) => existsSync52(p));
|
|
25517
26277
|
};
|
|
25518
26278
|
const sourceSaveHook = findHook("chat_recall_save_hook.sh");
|
|
25519
26279
|
const sourceResumeHook = findHook("chat_recall_resume_hook.sh");
|
|
@@ -25524,15 +26284,15 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
|
|
|
25524
26284
|
process.exit(1);
|
|
25525
26285
|
}
|
|
25526
26286
|
const hooksDir = getHooksDir();
|
|
25527
|
-
const installedSaveHook =
|
|
25528
|
-
const installedResumeHook =
|
|
25529
|
-
const installedEscalateHook =
|
|
25530
|
-
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");
|
|
25531
26291
|
const wakeupWiredInSettings = (home) => {
|
|
25532
|
-
const settings2 =
|
|
25533
|
-
if (!
|
|
26292
|
+
const settings2 = join56(home, "settings.json");
|
|
26293
|
+
if (!existsSync52(settings2)) return false;
|
|
25534
26294
|
try {
|
|
25535
|
-
const cfg = JSON.parse(
|
|
26295
|
+
const cfg = JSON.parse(readFileSync46(settings2, "utf-8"));
|
|
25536
26296
|
const arr = Array.isArray(cfg.hooks?.SessionStart) ? cfg.hooks.SessionStart : [];
|
|
25537
26297
|
return arr.some((h) => (h?.hooks?.[0]?.command || "").includes("chat_recall_wakeup_hook"));
|
|
25538
26298
|
} catch {
|
|
@@ -25541,9 +26301,9 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
|
|
|
25541
26301
|
};
|
|
25542
26302
|
const hookConfigFiles = claudeHookConfigFiles();
|
|
25543
26303
|
const readHookConfig = (file) => {
|
|
25544
|
-
if (!
|
|
26304
|
+
if (!existsSync52(file)) return { hooks: {} };
|
|
25545
26305
|
try {
|
|
25546
|
-
const c = JSON.parse(
|
|
26306
|
+
const c = JSON.parse(readFileSync46(file, "utf-8"));
|
|
25547
26307
|
if (!c.hooks || typeof c.hooks !== "object") c.hooks = {};
|
|
25548
26308
|
return c;
|
|
25549
26309
|
} catch (err) {
|
|
@@ -25569,8 +26329,8 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
|
|
|
25569
26329
|
if (filtered.length) config2.hooks[event] = filtered;
|
|
25570
26330
|
else delete config2.hooks[event];
|
|
25571
26331
|
}
|
|
25572
|
-
if (removed === 0 && !
|
|
25573
|
-
|
|
26332
|
+
if (removed === 0 && !existsSync52(hooksJson)) continue;
|
|
26333
|
+
writeFileSync21(hooksJson, JSON.stringify(config2, null, 2) + "\n");
|
|
25574
26334
|
total += removed;
|
|
25575
26335
|
console.log(chalk.green(`\u2713 Removed ${removed} chat-recall hook entr${removed === 1 ? "y" : "ies"} from ${hooksJson}`));
|
|
25576
26336
|
}
|
|
@@ -25578,7 +26338,20 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
|
|
|
25578
26338
|
console.log(chalk.dim(` (Hook scripts left in ${hooksDir} \u2014 delete manually if you want.)`));
|
|
25579
26339
|
return;
|
|
25580
26340
|
}
|
|
25581
|
-
|
|
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 });
|
|
25582
26355
|
copyFileSync4(sourceSaveHook, installedSaveHook);
|
|
25583
26356
|
chmodSync5(installedSaveHook, 493);
|
|
25584
26357
|
const installResume = opts.resumeHint !== false && !!sourceResumeHook;
|
|
@@ -25597,7 +26370,7 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
|
|
|
25597
26370
|
chmodSync5(installedWakeupHook, 493);
|
|
25598
26371
|
}
|
|
25599
26372
|
const stopEntry = { matcher: "", hooks: [{ type: "command", command: installedSaveHook }] };
|
|
25600
|
-
const precompactEntry = { matcher: "", hooks: [{ type: "command", command:
|
|
26373
|
+
const precompactEntry = { matcher: "", hooks: [{ type: "command", command: `"${installedSaveHook}" --precompact` }] };
|
|
25601
26374
|
const resumeEntry = { matcher: "", hooks: [{ type: "command", command: installedResumeHook }] };
|
|
25602
26375
|
const escalateEntry = { matcher: "", hooks: [{ type: "command", command: installedEscalateHook }] };
|
|
25603
26376
|
const wakeupEntry = { matcher: "startup|clear", hooks: [{ type: "command", command: installedWakeupHook }] };
|
|
@@ -25610,9 +26383,9 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
|
|
|
25610
26383
|
const wakeupSkipped = [];
|
|
25611
26384
|
for (const hooksJson of hookConfigFiles) {
|
|
25612
26385
|
const config2 = readHookConfig(hooksJson);
|
|
25613
|
-
const home =
|
|
26386
|
+
const home = dirname24(hooksJson);
|
|
25614
26387
|
const alreadyWired = wakeupWiredInSettings(home);
|
|
25615
|
-
if (alreadyWired) wakeupSkipped.push(
|
|
26388
|
+
if (alreadyWired) wakeupSkipped.push(join56(home, "settings.json"));
|
|
25616
26389
|
const perProfile = installWakeup && !alreadyWired ? [...events, ["SessionStart", wakeupEntry]] : events;
|
|
25617
26390
|
for (const event of HOOK_EVENTS) {
|
|
25618
26391
|
const arr = Array.isArray(config2.hooks[event]) ? config2.hooks[event] : [];
|
|
@@ -25622,21 +26395,21 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
|
|
|
25622
26395
|
if (without.length) config2.hooks[event] = without;
|
|
25623
26396
|
else delete config2.hooks[event];
|
|
25624
26397
|
}
|
|
25625
|
-
|
|
25626
|
-
|
|
26398
|
+
mkdirSync19(dirname24(hooksJson), { recursive: true });
|
|
26399
|
+
writeFileSync21(hooksJson, JSON.stringify(config2, null, 2) + "\n");
|
|
25627
26400
|
}
|
|
25628
|
-
const saveSz =
|
|
26401
|
+
const saveSz = statSync42(installedSaveHook).size;
|
|
25629
26402
|
console.log(chalk.green(`\u2713 Installed chat-recall save hook (${saveSz} bytes)`));
|
|
25630
26403
|
if (installResume) {
|
|
25631
|
-
const resumeSz =
|
|
26404
|
+
const resumeSz = statSync42(installedResumeHook).size;
|
|
25632
26405
|
console.log(chalk.green(`\u2713 Installed chat-recall resume-hint hook (${resumeSz} bytes)`));
|
|
25633
26406
|
}
|
|
25634
26407
|
if (installEscalate) {
|
|
25635
|
-
const escalateSz =
|
|
26408
|
+
const escalateSz = statSync42(installedEscalateHook).size;
|
|
25636
26409
|
console.log(chalk.green(`\u2713 Installed chat-recall learnings-escalation hook (${escalateSz} bytes)`));
|
|
25637
26410
|
}
|
|
25638
26411
|
if (installWakeup) {
|
|
25639
|
-
const wakeupSz =
|
|
26412
|
+
const wakeupSz = statSync42(installedWakeupHook).size;
|
|
25640
26413
|
console.log(chalk.green(`\u2713 Installed chat-recall wake-up hook (${wakeupSz} bytes)`));
|
|
25641
26414
|
for (const f of wakeupSkipped) {
|
|
25642
26415
|
console.log(chalk.dim(` (SessionStart already wired in ${f} \u2014 left as is, not duplicated)`));
|
|
@@ -25668,7 +26441,7 @@ program.command("dossier <project>").description("Generate a project dossier (ov
|
|
|
25668
26441
|
);
|
|
25669
26442
|
const md = dossier.markdown;
|
|
25670
26443
|
if (options.out) {
|
|
25671
|
-
|
|
26444
|
+
writeFileSync20(options.out, md);
|
|
25672
26445
|
console.log(chalk.green(`Wrote dossier to ${options.out} (${md.length} chars)`));
|
|
25673
26446
|
} else {
|
|
25674
26447
|
console.log(md);
|
|
@@ -25702,12 +26475,12 @@ program.command("watch").description("Run the live indexer daemon (watches all A
|
|
|
25702
26475
|
}
|
|
25703
26476
|
return;
|
|
25704
26477
|
}
|
|
25705
|
-
const
|
|
26478
|
+
const candidates2 = [
|
|
25706
26479
|
new URL("./watch.js", import.meta.url).href,
|
|
25707
26480
|
new URL("../auto-indexer/indexer.js", import.meta.url).href
|
|
25708
26481
|
];
|
|
25709
26482
|
let lastErr;
|
|
25710
|
-
for (const spec of
|
|
26483
|
+
for (const spec of candidates2) {
|
|
25711
26484
|
try {
|
|
25712
26485
|
await import(spec);
|
|
25713
26486
|
return;
|
|
@@ -25884,8 +26657,8 @@ include.command("list", { isDefault: true }).description("Show paths opted back
|
|
|
25884
26657
|
include.command("project <path>").description("Re-permit a path under a personal folder (substring match; e.g. ~/Documents/code)").action(async (path) => {
|
|
25885
26658
|
const { loadSettings: loadSettings2, saveSettings: saveSettings2 } = await Promise.resolve().then(() => (init_settings(), settings_exports));
|
|
25886
26659
|
const { resolve: resolve3 } = await import("node:path");
|
|
25887
|
-
const { homedir:
|
|
25888
|
-
const abs = resolve3(path.replace(/^~(?=\/|$)/,
|
|
26660
|
+
const { homedir: homedir23 } = await import("node:os");
|
|
26661
|
+
const abs = resolve3(path.replace(/^~(?=\/|$)/, homedir23()));
|
|
25889
26662
|
const s = loadSettings2();
|
|
25890
26663
|
s.sync.includeProjects = s.sync.includeProjects || [];
|
|
25891
26664
|
if (s.sync.includeProjects.includes(abs)) {
|
|
@@ -25899,8 +26672,8 @@ include.command("project <path>").description("Re-permit a path under a personal
|
|
|
25899
26672
|
include.command("remove <path>").description("Undo an opt-in (personal folder goes back to skipped)").action(async (path) => {
|
|
25900
26673
|
const { loadSettings: loadSettings2, saveSettings: saveSettings2 } = await Promise.resolve().then(() => (init_settings(), settings_exports));
|
|
25901
26674
|
const { resolve: resolve3 } = await import("node:path");
|
|
25902
|
-
const { homedir:
|
|
25903
|
-
const abs = resolve3(path.replace(/^~(?=\/|$)/,
|
|
26675
|
+
const { homedir: homedir23 } = await import("node:os");
|
|
26676
|
+
const abs = resolve3(path.replace(/^~(?=\/|$)/, homedir23()));
|
|
25904
26677
|
const s = loadSettings2();
|
|
25905
26678
|
const before = (s.sync.includeProjects || []).length;
|
|
25906
26679
|
s.sync.includeProjects = (s.sync.includeProjects || []).filter((p) => p !== path && p !== abs);
|
|
@@ -25979,8 +26752,8 @@ program.command("projects").description("List distinct project ids discovered on
|
|
|
25979
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) => {
|
|
25980
26753
|
const { loadSettings: loadSettings2, saveSettings: saveSettings2 } = await Promise.resolve().then(() => (init_settings(), settings_exports));
|
|
25981
26754
|
const { resolve: resolve3 } = await import("node:path");
|
|
25982
|
-
const { homedir:
|
|
25983
|
-
const abs = resolve3(path.replace(/^~(?=\/|$)/,
|
|
26755
|
+
const { homedir: homedir23 } = await import("node:os");
|
|
26756
|
+
const abs = resolve3(path.replace(/^~(?=\/|$)/, homedir23()));
|
|
25984
26757
|
const s = loadSettings2();
|
|
25985
26758
|
if (s.sync.excludeProjects.includes(abs)) {
|
|
25986
26759
|
console.log(chalk.dim(`Already excluded: ${abs}`));
|
|
@@ -26009,8 +26782,8 @@ exclude.command("tool <tool>").description("Exclude an AI tool entirely (claude
|
|
|
26009
26782
|
exclude.command("remove <value>").description("Remove an exclusion (tool name or project path)").action(async (value) => {
|
|
26010
26783
|
const { loadSettings: loadSettings2, saveSettings: saveSettings2 } = await Promise.resolve().then(() => (init_settings(), settings_exports));
|
|
26011
26784
|
const { resolve: resolve3 } = await import("node:path");
|
|
26012
|
-
const { homedir:
|
|
26013
|
-
const abs = resolve3(value.replace(/^~(?=\/|$)/,
|
|
26785
|
+
const { homedir: homedir23 } = await import("node:os");
|
|
26786
|
+
const abs = resolve3(value.replace(/^~(?=\/|$)/, homedir23()));
|
|
26014
26787
|
const s = loadSettings2();
|
|
26015
26788
|
const beforeTools = s.sync.excludeTools.length;
|
|
26016
26789
|
const beforeProjects = s.sync.excludeProjects.length;
|