chat-recall 0.5.5 → 0.5.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +1389 -697
- package/dist/cli.js.map +1 -1
- package/dist/mcp-diagnostics.d.ts.map +1 -1
- package/dist/mcp-diagnostics.js +10 -8
- package/dist/mcp-diagnostics.js.map +1 -1
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +1133 -457
- package/dist/mcp.js.map +1 -1
- package/dist/project-tasks.d.ts.map +1 -1
- package/dist/project-tasks.js +12 -7
- package/dist/project-tasks.js.map +1 -1
- package/dist/service-installer.d.ts +1 -1
- package/dist/service-installer.d.ts.map +1 -1
- package/dist/service-installer.js +20 -6
- package/dist/service-installer.js.map +1 -1
- package/dist/sync-client.d.ts +1 -0
- package/dist/sync-client.d.ts.map +1 -1
- package/dist/sync-client.js +162 -93
- package/dist/sync-client.js.map +1 -1
- package/dist/sync-ledger.d.ts +22 -0
- package/dist/sync-ledger.d.ts.map +1 -1
- package/dist/sync-ledger.js +108 -1
- package/dist/sync-ledger.js.map +1 -1
- package/dist/watch.js +989 -445
- package/hooks/chat_recall_escalate_hook.sh +28 -2
- package/hooks/chat_recall_save_hook.sh +17 -11
- package/hooks/chat_recall_wakeup_hook.sh +27 -1
- package/package.json +7 -3
package/dist/mcp.js
CHANGED
|
@@ -2110,7 +2110,7 @@ var require_thread_stream = __commonJS({
|
|
|
2110
2110
|
var { version: version2 } = require_package();
|
|
2111
2111
|
var { EventEmitter } = __require("events");
|
|
2112
2112
|
var { Worker } = __require("worker_threads");
|
|
2113
|
-
var { join:
|
|
2113
|
+
var { join: join50 } = __require("path");
|
|
2114
2114
|
var { pathToFileURL } = __require("url");
|
|
2115
2115
|
var { wait } = require_wait();
|
|
2116
2116
|
var {
|
|
@@ -2153,7 +2153,7 @@ var require_thread_stream = __commonJS({
|
|
|
2153
2153
|
function createWorker(stream, opts) {
|
|
2154
2154
|
const { filename, workerData } = opts;
|
|
2155
2155
|
const bundlerOverrides = "__bundlerPathsOverrides" in globalThis ? globalThis.__bundlerPathsOverrides : {};
|
|
2156
|
-
const toExecute = bundlerOverrides["thread-stream-worker"] ||
|
|
2156
|
+
const toExecute = bundlerOverrides["thread-stream-worker"] || join50(__dirname, "lib", "worker.js");
|
|
2157
2157
|
const worker = new Worker(toExecute, {
|
|
2158
2158
|
...opts.workerOpts,
|
|
2159
2159
|
trackUnmanagedFds: false,
|
|
@@ -2556,7 +2556,7 @@ var require_transport = __commonJS({
|
|
|
2556
2556
|
"use strict";
|
|
2557
2557
|
var { createRequire: createRequire3 } = __require("module");
|
|
2558
2558
|
var getCallers = require_caller();
|
|
2559
|
-
var { join:
|
|
2559
|
+
var { join: join50, isAbsolute: isAbsolute3, sep: sep3 } = __require("node:path");
|
|
2560
2560
|
var sleep = require_atomic_sleep();
|
|
2561
2561
|
var onExit = require_on_exit_leak_free();
|
|
2562
2562
|
var ThreadStream = require_thread_stream();
|
|
@@ -2619,7 +2619,7 @@ var require_transport = __commonJS({
|
|
|
2619
2619
|
throw new Error("only one of target or targets can be specified");
|
|
2620
2620
|
}
|
|
2621
2621
|
if (targets) {
|
|
2622
|
-
target = bundlerOverrides["pino-worker"] ||
|
|
2622
|
+
target = bundlerOverrides["pino-worker"] || join50(__dirname, "worker.js");
|
|
2623
2623
|
options.targets = targets.filter((dest) => dest.target).map((dest) => {
|
|
2624
2624
|
return {
|
|
2625
2625
|
...dest,
|
|
@@ -2637,7 +2637,7 @@ var require_transport = __commonJS({
|
|
|
2637
2637
|
});
|
|
2638
2638
|
});
|
|
2639
2639
|
} else if (pipeline) {
|
|
2640
|
-
target = bundlerOverrides["pino-worker"] ||
|
|
2640
|
+
target = bundlerOverrides["pino-worker"] || join50(__dirname, "worker.js");
|
|
2641
2641
|
options.pipelines = [pipeline.map((dest) => {
|
|
2642
2642
|
return {
|
|
2643
2643
|
...dest,
|
|
@@ -2655,16 +2655,16 @@ var require_transport = __commonJS({
|
|
|
2655
2655
|
return buildStream(fixTarget(target), options, worker, sync);
|
|
2656
2656
|
function fixTarget(origin) {
|
|
2657
2657
|
origin = bundlerOverrides[origin] || origin;
|
|
2658
|
-
if (
|
|
2658
|
+
if (isAbsolute3(origin) || origin.indexOf("file://") === 0) {
|
|
2659
2659
|
return origin;
|
|
2660
2660
|
}
|
|
2661
2661
|
if (origin === "pino/file") {
|
|
2662
|
-
return
|
|
2662
|
+
return join50(__dirname, "..", "file.js");
|
|
2663
2663
|
}
|
|
2664
2664
|
let fixTarget2;
|
|
2665
2665
|
for (const filePath of callers) {
|
|
2666
2666
|
try {
|
|
2667
|
-
const context = filePath === "node:repl" ? process.cwd() +
|
|
2667
|
+
const context = filePath === "node:repl" ? process.cwd() + sep3 : filePath;
|
|
2668
2668
|
fixTarget2 = createRequire3(context).resolve(origin);
|
|
2669
2669
|
break;
|
|
2670
2670
|
} catch (err) {
|
|
@@ -3648,7 +3648,7 @@ var require_safe_stable_stringify = __commonJS({
|
|
|
3648
3648
|
return circularValue;
|
|
3649
3649
|
}
|
|
3650
3650
|
let res = "";
|
|
3651
|
-
let
|
|
3651
|
+
let join50 = ",";
|
|
3652
3652
|
const originalIndentation = indentation;
|
|
3653
3653
|
if (Array.isArray(value)) {
|
|
3654
3654
|
if (value.length === 0) {
|
|
@@ -3662,7 +3662,7 @@ var require_safe_stable_stringify = __commonJS({
|
|
|
3662
3662
|
indentation += spacer;
|
|
3663
3663
|
res += `
|
|
3664
3664
|
${indentation}`;
|
|
3665
|
-
|
|
3665
|
+
join50 = `,
|
|
3666
3666
|
${indentation}`;
|
|
3667
3667
|
}
|
|
3668
3668
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
@@ -3670,13 +3670,13 @@ ${indentation}`;
|
|
|
3670
3670
|
for (; i < maximumValuesToStringify - 1; i++) {
|
|
3671
3671
|
const tmp2 = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
|
|
3672
3672
|
res += tmp2 !== void 0 ? tmp2 : "null";
|
|
3673
|
-
res +=
|
|
3673
|
+
res += join50;
|
|
3674
3674
|
}
|
|
3675
3675
|
const tmp = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
|
|
3676
3676
|
res += tmp !== void 0 ? tmp : "null";
|
|
3677
3677
|
if (value.length - 1 > maximumBreadth) {
|
|
3678
3678
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
3679
|
-
res += `${
|
|
3679
|
+
res += `${join50}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
3680
3680
|
}
|
|
3681
3681
|
if (spacer !== "") {
|
|
3682
3682
|
res += `
|
|
@@ -3697,7 +3697,7 @@ ${originalIndentation}`;
|
|
|
3697
3697
|
let separator = "";
|
|
3698
3698
|
if (spacer !== "") {
|
|
3699
3699
|
indentation += spacer;
|
|
3700
|
-
|
|
3700
|
+
join50 = `,
|
|
3701
3701
|
${indentation}`;
|
|
3702
3702
|
whitespace = " ";
|
|
3703
3703
|
}
|
|
@@ -3711,13 +3711,13 @@ ${indentation}`;
|
|
|
3711
3711
|
const tmp = stringifyFnReplacer(key2, value, stack, replacer, spacer, indentation);
|
|
3712
3712
|
if (tmp !== void 0) {
|
|
3713
3713
|
res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
|
|
3714
|
-
separator =
|
|
3714
|
+
separator = join50;
|
|
3715
3715
|
}
|
|
3716
3716
|
}
|
|
3717
3717
|
if (keyLength > maximumBreadth) {
|
|
3718
3718
|
const removedKeys = keyLength - maximumBreadth;
|
|
3719
3719
|
res += `${separator}"...":${whitespace}"${getItemCount(removedKeys)} not stringified"`;
|
|
3720
|
-
separator =
|
|
3720
|
+
separator = join50;
|
|
3721
3721
|
}
|
|
3722
3722
|
if (spacer !== "" && separator.length > 1) {
|
|
3723
3723
|
res = `
|
|
@@ -3758,7 +3758,7 @@ ${originalIndentation}`;
|
|
|
3758
3758
|
}
|
|
3759
3759
|
const originalIndentation = indentation;
|
|
3760
3760
|
let res = "";
|
|
3761
|
-
let
|
|
3761
|
+
let join50 = ",";
|
|
3762
3762
|
if (Array.isArray(value)) {
|
|
3763
3763
|
if (value.length === 0) {
|
|
3764
3764
|
return "[]";
|
|
@@ -3771,7 +3771,7 @@ ${originalIndentation}`;
|
|
|
3771
3771
|
indentation += spacer;
|
|
3772
3772
|
res += `
|
|
3773
3773
|
${indentation}`;
|
|
3774
|
-
|
|
3774
|
+
join50 = `,
|
|
3775
3775
|
${indentation}`;
|
|
3776
3776
|
}
|
|
3777
3777
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
@@ -3779,13 +3779,13 @@ ${indentation}`;
|
|
|
3779
3779
|
for (; i < maximumValuesToStringify - 1; i++) {
|
|
3780
3780
|
const tmp2 = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
|
|
3781
3781
|
res += tmp2 !== void 0 ? tmp2 : "null";
|
|
3782
|
-
res +=
|
|
3782
|
+
res += join50;
|
|
3783
3783
|
}
|
|
3784
3784
|
const tmp = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
|
|
3785
3785
|
res += tmp !== void 0 ? tmp : "null";
|
|
3786
3786
|
if (value.length - 1 > maximumBreadth) {
|
|
3787
3787
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
3788
|
-
res += `${
|
|
3788
|
+
res += `${join50}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
3789
3789
|
}
|
|
3790
3790
|
if (spacer !== "") {
|
|
3791
3791
|
res += `
|
|
@@ -3798,7 +3798,7 @@ ${originalIndentation}`;
|
|
|
3798
3798
|
let whitespace = "";
|
|
3799
3799
|
if (spacer !== "") {
|
|
3800
3800
|
indentation += spacer;
|
|
3801
|
-
|
|
3801
|
+
join50 = `,
|
|
3802
3802
|
${indentation}`;
|
|
3803
3803
|
whitespace = " ";
|
|
3804
3804
|
}
|
|
@@ -3807,7 +3807,7 @@ ${indentation}`;
|
|
|
3807
3807
|
const tmp = stringifyArrayReplacer(key2, value[key2], stack, replacer, spacer, indentation);
|
|
3808
3808
|
if (tmp !== void 0) {
|
|
3809
3809
|
res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
|
|
3810
|
-
separator =
|
|
3810
|
+
separator = join50;
|
|
3811
3811
|
}
|
|
3812
3812
|
}
|
|
3813
3813
|
if (spacer !== "" && separator.length > 1) {
|
|
@@ -3865,20 +3865,20 @@ ${originalIndentation}`;
|
|
|
3865
3865
|
indentation += spacer;
|
|
3866
3866
|
let res2 = `
|
|
3867
3867
|
${indentation}`;
|
|
3868
|
-
const
|
|
3868
|
+
const join51 = `,
|
|
3869
3869
|
${indentation}`;
|
|
3870
3870
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
3871
3871
|
let i = 0;
|
|
3872
3872
|
for (; i < maximumValuesToStringify - 1; i++) {
|
|
3873
3873
|
const tmp2 = stringifyIndent(String(i), value[i], stack, spacer, indentation);
|
|
3874
3874
|
res2 += tmp2 !== void 0 ? tmp2 : "null";
|
|
3875
|
-
res2 +=
|
|
3875
|
+
res2 += join51;
|
|
3876
3876
|
}
|
|
3877
3877
|
const tmp = stringifyIndent(String(i), value[i], stack, spacer, indentation);
|
|
3878
3878
|
res2 += tmp !== void 0 ? tmp : "null";
|
|
3879
3879
|
if (value.length - 1 > maximumBreadth) {
|
|
3880
3880
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
3881
|
-
res2 += `${
|
|
3881
|
+
res2 += `${join51}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
3882
3882
|
}
|
|
3883
3883
|
res2 += `
|
|
3884
3884
|
${originalIndentation}`;
|
|
@@ -3894,16 +3894,16 @@ ${originalIndentation}`;
|
|
|
3894
3894
|
return '"[Object]"';
|
|
3895
3895
|
}
|
|
3896
3896
|
indentation += spacer;
|
|
3897
|
-
const
|
|
3897
|
+
const join50 = `,
|
|
3898
3898
|
${indentation}`;
|
|
3899
3899
|
let res = "";
|
|
3900
3900
|
let separator = "";
|
|
3901
3901
|
let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth);
|
|
3902
3902
|
if (isTypedArrayWithEntries(value)) {
|
|
3903
|
-
res += stringifyTypedArray(value,
|
|
3903
|
+
res += stringifyTypedArray(value, join50, maximumBreadth);
|
|
3904
3904
|
keys = keys.slice(value.length);
|
|
3905
3905
|
maximumPropertiesToStringify -= value.length;
|
|
3906
|
-
separator =
|
|
3906
|
+
separator = join50;
|
|
3907
3907
|
}
|
|
3908
3908
|
if (deterministic) {
|
|
3909
3909
|
keys = sort(keys, comparator);
|
|
@@ -3914,13 +3914,13 @@ ${indentation}`;
|
|
|
3914
3914
|
const tmp = stringifyIndent(key2, value[key2], stack, spacer, indentation);
|
|
3915
3915
|
if (tmp !== void 0) {
|
|
3916
3916
|
res += `${separator}${strEscape(key2)}: ${tmp}`;
|
|
3917
|
-
separator =
|
|
3917
|
+
separator = join50;
|
|
3918
3918
|
}
|
|
3919
3919
|
}
|
|
3920
3920
|
if (keyLength > maximumBreadth) {
|
|
3921
3921
|
const removedKeys = keyLength - maximumBreadth;
|
|
3922
3922
|
res += `${separator}"...": "${getItemCount(removedKeys)} not stringified"`;
|
|
3923
|
-
separator =
|
|
3923
|
+
separator = join50;
|
|
3924
3924
|
}
|
|
3925
3925
|
if (separator !== "") {
|
|
3926
3926
|
res = `
|
|
@@ -4848,6 +4848,16 @@ function loadSecrets() {
|
|
|
4848
4848
|
const p = secretsPath();
|
|
4849
4849
|
if (!existsSync2(p))
|
|
4850
4850
|
return out;
|
|
4851
|
+
let mtimeMs = -1, size = -1;
|
|
4852
|
+
try {
|
|
4853
|
+
const st = statSync2(p);
|
|
4854
|
+
mtimeMs = st.mtimeMs;
|
|
4855
|
+
size = st.size;
|
|
4856
|
+
} catch {
|
|
4857
|
+
}
|
|
4858
|
+
if (_secretsCache && _secretsCache.mtimeMs === mtimeMs && _secretsCache.size === size) {
|
|
4859
|
+
return { ..._secretsCache.value };
|
|
4860
|
+
}
|
|
4851
4861
|
try {
|
|
4852
4862
|
for (const line of readFileSync(p, "utf-8").split("\n")) {
|
|
4853
4863
|
const t = line.trim();
|
|
@@ -4865,9 +4875,12 @@ function loadSecrets() {
|
|
|
4865
4875
|
}
|
|
4866
4876
|
} catch {
|
|
4867
4877
|
}
|
|
4878
|
+
if (mtimeMs >= 0)
|
|
4879
|
+
_secretsCache = { mtimeMs, size, value: { ...out } };
|
|
4868
4880
|
return out;
|
|
4869
4881
|
}
|
|
4870
4882
|
function writeSecrets(secrets) {
|
|
4883
|
+
_secretsCache = null;
|
|
4871
4884
|
const p = secretsPath();
|
|
4872
4885
|
mkdirSync2(dirname2(p), { recursive: true });
|
|
4873
4886
|
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";
|
|
@@ -4877,10 +4890,31 @@ function writeSecrets(secrets) {
|
|
|
4877
4890
|
} catch {
|
|
4878
4891
|
}
|
|
4879
4892
|
}
|
|
4893
|
+
function applySecretOverlay(result) {
|
|
4894
|
+
const secrets = loadSecrets();
|
|
4895
|
+
for (const { block, field, env } of SECRET_FIELDS) {
|
|
4896
|
+
const blk = result[block];
|
|
4897
|
+
const value = process.env[env] || secrets[env] || blk[field];
|
|
4898
|
+
if (value)
|
|
4899
|
+
blk[field] = value;
|
|
4900
|
+
}
|
|
4901
|
+
return result;
|
|
4902
|
+
}
|
|
4880
4903
|
function loadSettings() {
|
|
4881
4904
|
const path = settingsPath();
|
|
4882
4905
|
if (!existsSync2(path))
|
|
4883
4906
|
return freshDefaults();
|
|
4907
|
+
let mtimeMs = -1, size = -1;
|
|
4908
|
+
try {
|
|
4909
|
+
const st = statSync2(path);
|
|
4910
|
+
mtimeMs = st.mtimeMs;
|
|
4911
|
+
size = st.size;
|
|
4912
|
+
} catch {
|
|
4913
|
+
}
|
|
4914
|
+
if (_settingsCache && _settingsCache.mtimeMs === mtimeMs && _settingsCache.size === size) {
|
|
4915
|
+
const cached = structuredClone(_settingsCache.value);
|
|
4916
|
+
return applySecretOverlay(cached);
|
|
4917
|
+
}
|
|
4884
4918
|
try {
|
|
4885
4919
|
const parsed = JSON.parse(readFileSync(path, "utf-8"));
|
|
4886
4920
|
const base = freshDefaults();
|
|
@@ -4893,19 +4927,15 @@ function loadSettings() {
|
|
|
4893
4927
|
sync: mergeSync(base.sync, parsed.sync),
|
|
4894
4928
|
team: mergeTeam(base.team, parsed.team)
|
|
4895
4929
|
};
|
|
4896
|
-
|
|
4897
|
-
|
|
4898
|
-
|
|
4899
|
-
const value = process.env[env] || secrets[env] || blk[field];
|
|
4900
|
-
if (value)
|
|
4901
|
-
blk[field] = value;
|
|
4902
|
-
}
|
|
4903
|
-
return result;
|
|
4930
|
+
if (mtimeMs >= 0)
|
|
4931
|
+
_settingsCache = { mtimeMs, size, value: structuredClone(result) };
|
|
4932
|
+
return applySecretOverlay(result);
|
|
4904
4933
|
} catch {
|
|
4905
4934
|
return freshDefaults();
|
|
4906
4935
|
}
|
|
4907
4936
|
}
|
|
4908
4937
|
function saveSettings(settings2) {
|
|
4938
|
+
_settingsCache = null;
|
|
4909
4939
|
const secrets = loadSecrets();
|
|
4910
4940
|
const stripped = {
|
|
4911
4941
|
...settings2,
|
|
@@ -4929,7 +4959,7 @@ function saveSettings(settings2) {
|
|
|
4929
4959
|
} catch {
|
|
4930
4960
|
}
|
|
4931
4961
|
}
|
|
4932
|
-
var CLI_DETECTION_ORDER, SCHEMA_VERSION, _sourceSettingsCache, SECRET_FIELDS;
|
|
4962
|
+
var CLI_DETECTION_ORDER, SCHEMA_VERSION, PERSONAL_DIR_NAMES, PERSONAL_DIR_PATTERNS, _sourceSettingsCache, SECRET_FIELDS, _secretsCache, _settingsCache;
|
|
4933
4963
|
var init_settings = __esm({
|
|
4934
4964
|
"../engine/dist/core/settings.js"() {
|
|
4935
4965
|
"use strict";
|
|
@@ -4943,6 +4973,18 @@ var init_settings = __esm({
|
|
|
4943
4973
|
{ preset: "aichat", bin: "aichat", cmd: "aichat --no-stream" }
|
|
4944
4974
|
];
|
|
4945
4975
|
SCHEMA_VERSION = 3;
|
|
4976
|
+
PERSONAL_DIR_NAMES = [
|
|
4977
|
+
"Pictures",
|
|
4978
|
+
"Music",
|
|
4979
|
+
"Movies",
|
|
4980
|
+
"Videos",
|
|
4981
|
+
"Photos Library",
|
|
4982
|
+
"Documents",
|
|
4983
|
+
"Desktop",
|
|
4984
|
+
"Downloads",
|
|
4985
|
+
"Library"
|
|
4986
|
+
];
|
|
4987
|
+
PERSONAL_DIR_PATTERNS = PERSONAL_DIR_NAMES.map((n) => `/${n}/`);
|
|
4946
4988
|
_sourceSettingsCache = null;
|
|
4947
4989
|
SECRET_FIELDS = [
|
|
4948
4990
|
{ block: "summary", field: "apiKey", env: "SUMMARY_API_KEY" },
|
|
@@ -4953,6 +4995,8 @@ var init_settings = __esm({
|
|
|
4953
4995
|
{ block: "embedding", field: "ollamaCloudApiKey", env: "OLLAMA_API_KEY" },
|
|
4954
4996
|
{ block: "embedding", field: "openaiCompatApiKey", env: "OPENAI_COMPAT_API_KEY" }
|
|
4955
4997
|
];
|
|
4998
|
+
_secretsCache = null;
|
|
4999
|
+
_settingsCache = null;
|
|
4956
5000
|
}
|
|
4957
5001
|
});
|
|
4958
5002
|
|
|
@@ -5042,14 +5086,14 @@ function primaryHomes() {
|
|
|
5042
5086
|
s = void 0;
|
|
5043
5087
|
}
|
|
5044
5088
|
const opencodeDb = env.CHAT_RECALL_OPENCODE_DB || s?.opencodeDbPath || join3(home, ".local", "share", "opencode", "opencode.db");
|
|
5045
|
-
const
|
|
5089
|
+
const candidates2 = [
|
|
5046
5090
|
env.CHAT_RECALL_CLAUDE_HOME || s?.claudeHome || join3(home, ".claude"),
|
|
5047
5091
|
env.CHAT_RECALL_GEMINI_HOME || s?.geminiHome || join3(home, ".gemini"),
|
|
5048
5092
|
env.CHAT_RECALL_CODEX_HOME || s?.codexHome || join3(home, ".codex"),
|
|
5049
5093
|
env.CHAT_RECALL_AGY_HOME || s?.agyHome || join3(home, ".gemini", "antigravity-cli"),
|
|
5050
5094
|
dirOf(opencodeDb)
|
|
5051
5095
|
];
|
|
5052
|
-
return
|
|
5096
|
+
return candidates2.map(normalizeHomePath);
|
|
5053
5097
|
}
|
|
5054
5098
|
function homeDecision(path) {
|
|
5055
5099
|
const p = normalizeHomePath(path);
|
|
@@ -5416,28 +5460,55 @@ function maskSecret(s) {
|
|
|
5416
5460
|
return "*".repeat(s.length);
|
|
5417
5461
|
return "*".repeat(Math.min(s.length - 4, 60)) + s.slice(-4);
|
|
5418
5462
|
}
|
|
5463
|
+
function globalRegexFor(pattern) {
|
|
5464
|
+
const flags = pattern.flags.includes("g") ? pattern.flags : pattern.flags + "g";
|
|
5465
|
+
const key = pattern.source + "\0" + flags;
|
|
5466
|
+
let re = globalRegexCache.get(key);
|
|
5467
|
+
if (!re) {
|
|
5468
|
+
re = new RegExp(pattern.source, flags);
|
|
5469
|
+
globalRegexCache.set(key, re);
|
|
5470
|
+
}
|
|
5471
|
+
return re;
|
|
5472
|
+
}
|
|
5473
|
+
function makeLineResolver(text) {
|
|
5474
|
+
const starts = [];
|
|
5475
|
+
for (let i = text.indexOf("\n"); i !== -1; i = text.indexOf("\n", i + 1))
|
|
5476
|
+
starts.push(i);
|
|
5477
|
+
return (index) => {
|
|
5478
|
+
let lo = 0, hi = starts.length;
|
|
5479
|
+
while (lo < hi) {
|
|
5480
|
+
const mid = lo + hi >> 1;
|
|
5481
|
+
if (starts[mid] < index)
|
|
5482
|
+
lo = mid + 1;
|
|
5483
|
+
else
|
|
5484
|
+
hi = mid;
|
|
5485
|
+
}
|
|
5486
|
+
return lo + 1;
|
|
5487
|
+
};
|
|
5488
|
+
}
|
|
5419
5489
|
function scanTextForFindings(text, opts = {}) {
|
|
5420
5490
|
if (!text)
|
|
5421
5491
|
return [];
|
|
5422
5492
|
const rules = opts.rules || activeRules();
|
|
5423
5493
|
const findings = [];
|
|
5424
5494
|
const seenSpans = /* @__PURE__ */ new Set();
|
|
5495
|
+
const lineAt = makeLineResolver(text);
|
|
5425
5496
|
for (const r of rules) {
|
|
5426
|
-
const re =
|
|
5497
|
+
const re = globalRegexFor(r.pattern);
|
|
5498
|
+
re.lastIndex = 0;
|
|
5427
5499
|
let m;
|
|
5428
5500
|
while ((m = re.exec(text)) !== null) {
|
|
5429
5501
|
const span = `${m.index}:${m[0].length}`;
|
|
5430
5502
|
if (!seenSpans.has(span)) {
|
|
5431
5503
|
seenSpans.add(span);
|
|
5432
|
-
|
|
5433
|
-
findings.push({ rule: r.label, line, preview: maskSecret(m[0]) });
|
|
5504
|
+
findings.push({ rule: r.label, line: lineAt(m.index), preview: maskSecret(m[0]) });
|
|
5434
5505
|
}
|
|
5435
5506
|
if (re.lastIndex === m.index)
|
|
5436
5507
|
re.lastIndex++;
|
|
5437
5508
|
}
|
|
5438
5509
|
}
|
|
5439
5510
|
for (const { start, end } of findContextualSecrets(text)) {
|
|
5440
|
-
const line =
|
|
5511
|
+
const line = lineAt(start);
|
|
5441
5512
|
findings.push({ rule: "secret-context", line, preview: maskSecret(text.slice(start, end)) });
|
|
5442
5513
|
}
|
|
5443
5514
|
return findings;
|
|
@@ -5468,7 +5539,7 @@ function redactToolResultBody(toolName, body) {
|
|
|
5468
5539
|
return body;
|
|
5469
5540
|
return `[redacted: ${toolName} output, ${body.length} chars]`;
|
|
5470
5541
|
}
|
|
5471
|
-
var DEFAULT_REDACTION_RULES, SECRET_CONTEXT_RE, HIGH_ENTROPY_TOKEN_RE, cache, CANARY, MAX_PACK_RULES, MAX_PATTERN_LEN, serverPack, privacyCache;
|
|
5542
|
+
var DEFAULT_REDACTION_RULES, SECRET_CONTEXT_RE, HIGH_ENTROPY_TOKEN_RE, cache, CANARY, MAX_PACK_RULES, MAX_PATTERN_LEN, serverPack, globalRegexCache, privacyCache;
|
|
5472
5543
|
var init_secret_redactor = __esm({
|
|
5473
5544
|
"../engine/dist/core/secret-redactor.js"() {
|
|
5474
5545
|
"use strict";
|
|
@@ -5606,6 +5677,7 @@ var init_secret_redactor = __esm({
|
|
|
5606
5677
|
MAX_PACK_RULES = 200;
|
|
5607
5678
|
MAX_PATTERN_LEN = 512;
|
|
5608
5679
|
serverPack = null;
|
|
5680
|
+
globalRegexCache = /* @__PURE__ */ new Map();
|
|
5609
5681
|
privacyCache = null;
|
|
5610
5682
|
}
|
|
5611
5683
|
});
|
|
@@ -6365,8 +6437,8 @@ function decodeDirName(dirName) {
|
|
|
6365
6437
|
}
|
|
6366
6438
|
for (let len = 2; len <= segments.length - i; len++) {
|
|
6367
6439
|
const joinedSegments = segments.slice(i, i + len);
|
|
6368
|
-
for (const
|
|
6369
|
-
const candidate = join5(currentPath, joinedSegments.join(
|
|
6440
|
+
for (const sep3 of ["-", "_", "."]) {
|
|
6441
|
+
const candidate = join5(currentPath, joinedSegments.join(sep3));
|
|
6370
6442
|
if (existsSync5(candidate)) {
|
|
6371
6443
|
currentPath = candidate;
|
|
6372
6444
|
i += len;
|
|
@@ -6657,8 +6729,8 @@ var init_claude = __esm({
|
|
|
6657
6729
|
|
|
6658
6730
|
// ../engine/dist/transcript/gemini.js
|
|
6659
6731
|
async function parseGeminiTranscript(sessionPath) {
|
|
6660
|
-
const { readFileSync:
|
|
6661
|
-
return parseGeminiTranscriptText(
|
|
6732
|
+
const { readFileSync: readFileSync39 } = await import("fs");
|
|
6733
|
+
return parseGeminiTranscriptText(readFileSync39(sessionPath, "utf-8"));
|
|
6662
6734
|
}
|
|
6663
6735
|
function parseGeminiTranscriptText(text) {
|
|
6664
6736
|
let content;
|
|
@@ -7114,11 +7186,11 @@ async function archiveRawSession(store, sessionId) {
|
|
|
7114
7186
|
return await store.putRawSession(sessionId, exp.tool, Math.floor(exp.mtime), gz, size);
|
|
7115
7187
|
}
|
|
7116
7188
|
function detectForkPredecessor(sessionPath) {
|
|
7117
|
-
const { readFileSync:
|
|
7118
|
-
const { dirname:
|
|
7189
|
+
const { readFileSync: readFileSync39, readdirSync: readdirSync32 } = requireFs();
|
|
7190
|
+
const { dirname: dirname18, join: join50, basename: basename25 } = requirePath();
|
|
7119
7191
|
let text;
|
|
7120
7192
|
try {
|
|
7121
|
-
text =
|
|
7193
|
+
text = readFileSync39(sessionPath, "utf-8");
|
|
7122
7194
|
} catch {
|
|
7123
7195
|
return null;
|
|
7124
7196
|
}
|
|
@@ -7140,7 +7212,7 @@ function detectForkPredecessor(sessionPath) {
|
|
|
7140
7212
|
return null;
|
|
7141
7213
|
if (text.includes(`"uuid":"${headParent}"`))
|
|
7142
7214
|
return null;
|
|
7143
|
-
const dir =
|
|
7215
|
+
const dir = dirname18(sessionPath);
|
|
7144
7216
|
const self = basename25(sessionPath);
|
|
7145
7217
|
let entries;
|
|
7146
7218
|
try {
|
|
@@ -7152,7 +7224,7 @@ function detectForkPredecessor(sessionPath) {
|
|
|
7152
7224
|
if (!f.endsWith(".jsonl") || f === self || f === "sessions-index.json")
|
|
7153
7225
|
continue;
|
|
7154
7226
|
try {
|
|
7155
|
-
if (
|
|
7227
|
+
if (readFileSync39(join50(dir, f), "utf-8").includes(`"uuid":"${headParent}"`)) {
|
|
7156
7228
|
return basename25(f, ".jsonl");
|
|
7157
7229
|
}
|
|
7158
7230
|
} catch {
|
|
@@ -7367,6 +7439,26 @@ var init_shadow = __esm({
|
|
|
7367
7439
|
}
|
|
7368
7440
|
});
|
|
7369
7441
|
|
|
7442
|
+
// ../engine/dist/core/project-dir-name.js
|
|
7443
|
+
function looksWindowsEncoded(dirName) {
|
|
7444
|
+
return /^[A-Za-z]--/.test(dirName);
|
|
7445
|
+
}
|
|
7446
|
+
function decodeProjectDirName(dirName) {
|
|
7447
|
+
if (!dirName)
|
|
7448
|
+
return "";
|
|
7449
|
+
if (looksWindowsEncoded(dirName)) {
|
|
7450
|
+
const drive = dirName[0].toUpperCase();
|
|
7451
|
+
const rest = dirName.slice(3).replace(/-/g, "\\");
|
|
7452
|
+
return `${drive}:\\${rest}`;
|
|
7453
|
+
}
|
|
7454
|
+
return "/" + dirName.replace(/^-/, "").replace(/-/g, "/");
|
|
7455
|
+
}
|
|
7456
|
+
var init_project_dir_name = __esm({
|
|
7457
|
+
"../engine/dist/core/project-dir-name.js"() {
|
|
7458
|
+
"use strict";
|
|
7459
|
+
}
|
|
7460
|
+
});
|
|
7461
|
+
|
|
7370
7462
|
// ../engine/dist/core/live-session-scan.js
|
|
7371
7463
|
import { existsSync as existsSync7, readdirSync as readdirSync5, readFileSync as readFileSync4, statSync as statSync6, openSync as openSync2, readSync as readSync2, closeSync as closeSync2 } from "fs";
|
|
7372
7464
|
import { join as join9, basename as basename5 } from "path";
|
|
@@ -7390,7 +7482,7 @@ function findSessionFile(sessionId) {
|
|
|
7390
7482
|
path: candidate,
|
|
7391
7483
|
projectDir: entry.name,
|
|
7392
7484
|
// Project path is encoded by replacing slashes with dashes.
|
|
7393
|
-
projectPath: entry.name
|
|
7485
|
+
projectPath: decodeProjectDirName(entry.name)
|
|
7394
7486
|
};
|
|
7395
7487
|
}
|
|
7396
7488
|
}
|
|
@@ -7419,7 +7511,7 @@ function findSessionFiles(sessionId) {
|
|
|
7419
7511
|
out.push({
|
|
7420
7512
|
path: candidate,
|
|
7421
7513
|
projectDir: entry.name,
|
|
7422
|
-
projectPath: entry.name
|
|
7514
|
+
projectPath: decodeProjectDirName(entry.name)
|
|
7423
7515
|
});
|
|
7424
7516
|
}
|
|
7425
7517
|
}
|
|
@@ -7443,7 +7535,31 @@ function resolveSessionContentGroups(sessionId) {
|
|
|
7443
7535
|
const names = [...groups.keys()].sort((a, b) => a === "main" ? -1 : b === "main" ? 1 : a.localeCompare(b));
|
|
7444
7536
|
return names.map((name) => ({ name, paths: groups.get(name) }));
|
|
7445
7537
|
}
|
|
7538
|
+
function withSessionReadCache(fn) {
|
|
7539
|
+
readScopeDepth++;
|
|
7540
|
+
try {
|
|
7541
|
+
return fn();
|
|
7542
|
+
} finally {
|
|
7543
|
+
if (--readScopeDepth === 0)
|
|
7544
|
+
readScope = null;
|
|
7545
|
+
}
|
|
7546
|
+
}
|
|
7446
7547
|
function readSessionGroupText(group) {
|
|
7548
|
+
let key = "";
|
|
7549
|
+
if (readScopeDepth > 0) {
|
|
7550
|
+
const parts = [];
|
|
7551
|
+
for (const p of group.paths) {
|
|
7552
|
+
try {
|
|
7553
|
+
const st = statSync6(p);
|
|
7554
|
+
parts.push(`${p}:${st.mtimeMs}:${st.size}`);
|
|
7555
|
+
} catch {
|
|
7556
|
+
parts.push(`${p}:missing`);
|
|
7557
|
+
}
|
|
7558
|
+
}
|
|
7559
|
+
key = parts.join("|");
|
|
7560
|
+
if (readScope && readScope.key === key)
|
|
7561
|
+
return readScope.value;
|
|
7562
|
+
}
|
|
7447
7563
|
let text = "";
|
|
7448
7564
|
let mtime = 0;
|
|
7449
7565
|
for (const p of group.paths) {
|
|
@@ -7459,7 +7575,10 @@ function readSessionGroupText(group) {
|
|
|
7459
7575
|
}
|
|
7460
7576
|
text = text ? mergeLineText(text, raw).text : raw;
|
|
7461
7577
|
}
|
|
7462
|
-
|
|
7578
|
+
const out = { text, mtime };
|
|
7579
|
+
if (readScopeDepth > 0 && key)
|
|
7580
|
+
readScope = { key, value: out };
|
|
7581
|
+
return out;
|
|
7463
7582
|
}
|
|
7464
7583
|
function resolveSessionContentPaths(sessionFile) {
|
|
7465
7584
|
if (!hasSubagentsDir(sessionFile))
|
|
@@ -7682,7 +7801,7 @@ function findCodexSessionFileIn(root, sessionId) {
|
|
|
7682
7801
|
}
|
|
7683
7802
|
return scanDir(root);
|
|
7684
7803
|
}
|
|
7685
|
-
var geminiProjectMapCache, MAX_EVENT_LINE_BYTES;
|
|
7804
|
+
var readScope, readScopeDepth, geminiProjectMapCache, MAX_EVENT_LINE_BYTES;
|
|
7686
7805
|
var init_live_session_scan = __esm({
|
|
7687
7806
|
"../engine/dist/core/live-session-scan.js"() {
|
|
7688
7807
|
"use strict";
|
|
@@ -7691,6 +7810,9 @@ var init_live_session_scan = __esm({
|
|
|
7691
7810
|
init_tool_backend();
|
|
7692
7811
|
init_tool_paths();
|
|
7693
7812
|
init_backends();
|
|
7813
|
+
init_project_dir_name();
|
|
7814
|
+
readScope = null;
|
|
7815
|
+
readScopeDepth = 0;
|
|
7694
7816
|
geminiProjectMapCache = null;
|
|
7695
7817
|
MAX_EVENT_LINE_BYTES = 8 * 1024 * 1024;
|
|
7696
7818
|
}
|
|
@@ -8151,74 +8273,123 @@ var init_session_outcome = __esm({
|
|
|
8151
8273
|
}
|
|
8152
8274
|
});
|
|
8153
8275
|
|
|
8276
|
+
// ../engine/dist/core/flat-string.js
|
|
8277
|
+
function flatString(s) {
|
|
8278
|
+
if (!s)
|
|
8279
|
+
return "";
|
|
8280
|
+
if (s.length < 13)
|
|
8281
|
+
return s;
|
|
8282
|
+
return Buffer.from(s, "utf8").toString("utf8");
|
|
8283
|
+
}
|
|
8284
|
+
var init_flat_string = __esm({
|
|
8285
|
+
"../engine/dist/core/flat-string.js"() {
|
|
8286
|
+
"use strict";
|
|
8287
|
+
}
|
|
8288
|
+
});
|
|
8289
|
+
|
|
8154
8290
|
// ../engine/dist/core/first-prompt.js
|
|
8155
|
-
import { createReadStream as createReadStream2, existsSync as existsSync9,
|
|
8291
|
+
import { createReadStream as createReadStream2, existsSync as existsSync9, openSync as openSync3, readSync as readSync3, closeSync as closeSync3 } from "fs";
|
|
8292
|
+
import { StringDecoder } from "string_decoder";
|
|
8156
8293
|
function stripBanners2(s) {
|
|
8157
8294
|
let out = s;
|
|
8158
8295
|
for (const re of BANNERS)
|
|
8159
8296
|
out = out.replace(re, " ");
|
|
8160
8297
|
return out.replace(/[ \t]{2,}/g, " ").trim();
|
|
8161
8298
|
}
|
|
8299
|
+
function promptFromLine(raw, maxLength) {
|
|
8300
|
+
if (!raw.trim())
|
|
8301
|
+
return null;
|
|
8302
|
+
let obj;
|
|
8303
|
+
try {
|
|
8304
|
+
obj = JSON.parse(raw);
|
|
8305
|
+
} catch {
|
|
8306
|
+
return null;
|
|
8307
|
+
}
|
|
8308
|
+
if (obj.type !== "user")
|
|
8309
|
+
return null;
|
|
8310
|
+
if (obj.isSidechain === true)
|
|
8311
|
+
return null;
|
|
8312
|
+
const message = obj.message;
|
|
8313
|
+
if (!message)
|
|
8314
|
+
return null;
|
|
8315
|
+
const content = message.content;
|
|
8316
|
+
let text = "";
|
|
8317
|
+
if (typeof content === "string") {
|
|
8318
|
+
text = content;
|
|
8319
|
+
} else if (Array.isArray(content)) {
|
|
8320
|
+
const parts = [];
|
|
8321
|
+
for (const block of content) {
|
|
8322
|
+
if (block && typeof block === "object" && block.type === "text" && typeof block.text === "string") {
|
|
8323
|
+
parts.push(block.text);
|
|
8324
|
+
}
|
|
8325
|
+
}
|
|
8326
|
+
text = parts.join("\n");
|
|
8327
|
+
}
|
|
8328
|
+
if (!text)
|
|
8329
|
+
return null;
|
|
8330
|
+
if (text.includes("<system-reminder>"))
|
|
8331
|
+
return null;
|
|
8332
|
+
if (text.trim() === "[Request interrupted by user]")
|
|
8333
|
+
return null;
|
|
8334
|
+
const cleaned = stripBanners2(text);
|
|
8335
|
+
if (cleaned.length < 10)
|
|
8336
|
+
return null;
|
|
8337
|
+
return flatString(cleaned.slice(0, maxLength));
|
|
8338
|
+
}
|
|
8162
8339
|
function extractFirstUserPromptSync(filePath, options = {}) {
|
|
8163
8340
|
const maxLines = options.maxLines ?? 500;
|
|
8164
8341
|
const maxLength = options.maxLength ?? 1e3;
|
|
8165
|
-
|
|
8166
|
-
|
|
8167
|
-
let raw;
|
|
8342
|
+
const maxBytes = options.maxBytes ?? 4 * 1024 * 1024;
|
|
8343
|
+
let fd;
|
|
8168
8344
|
try {
|
|
8169
|
-
|
|
8345
|
+
fd = openSync3(filePath, "r");
|
|
8170
8346
|
} catch {
|
|
8171
8347
|
return "";
|
|
8172
8348
|
}
|
|
8173
|
-
|
|
8174
|
-
|
|
8175
|
-
|
|
8176
|
-
const
|
|
8177
|
-
|
|
8178
|
-
|
|
8179
|
-
let
|
|
8349
|
+
try {
|
|
8350
|
+
const CHUNK = 64 * 1024;
|
|
8351
|
+
const buf = Buffer.allocUnsafe(CHUNK);
|
|
8352
|
+
const decoder = new StringDecoder("utf-8");
|
|
8353
|
+
let carry = "";
|
|
8354
|
+
let pos = 0;
|
|
8355
|
+
let lineNo = 0;
|
|
8356
|
+
for (; ; ) {
|
|
8357
|
+
const n = readSync3(fd, buf, 0, CHUNK, pos);
|
|
8358
|
+
if (n <= 0)
|
|
8359
|
+
break;
|
|
8360
|
+
pos += n;
|
|
8361
|
+
carry += decoder.write(buf.subarray(0, n));
|
|
8362
|
+
const parts = carry.split("\n");
|
|
8363
|
+
carry = parts.pop() ?? "";
|
|
8364
|
+
for (const line of parts) {
|
|
8365
|
+
if (++lineNo > maxLines)
|
|
8366
|
+
return "";
|
|
8367
|
+
const found = promptFromLine(line, maxLength);
|
|
8368
|
+
if (found !== null)
|
|
8369
|
+
return found;
|
|
8370
|
+
}
|
|
8371
|
+
if (pos >= maxBytes)
|
|
8372
|
+
return "";
|
|
8373
|
+
}
|
|
8374
|
+
carry += decoder.end();
|
|
8375
|
+
if (carry && lineNo < maxLines) {
|
|
8376
|
+
const found = promptFromLine(carry, maxLength);
|
|
8377
|
+
if (found !== null)
|
|
8378
|
+
return found;
|
|
8379
|
+
}
|
|
8380
|
+
return "";
|
|
8381
|
+
} finally {
|
|
8180
8382
|
try {
|
|
8181
|
-
|
|
8383
|
+
closeSync3(fd);
|
|
8182
8384
|
} catch {
|
|
8183
|
-
continue;
|
|
8184
|
-
}
|
|
8185
|
-
if (obj.type !== "user")
|
|
8186
|
-
continue;
|
|
8187
|
-
if (obj.isSidechain === true)
|
|
8188
|
-
continue;
|
|
8189
|
-
const message = obj.message;
|
|
8190
|
-
if (!message)
|
|
8191
|
-
continue;
|
|
8192
|
-
const content = message.content;
|
|
8193
|
-
let text = "";
|
|
8194
|
-
if (typeof content === "string") {
|
|
8195
|
-
text = content;
|
|
8196
|
-
} else if (Array.isArray(content)) {
|
|
8197
|
-
const parts = [];
|
|
8198
|
-
for (const block of content) {
|
|
8199
|
-
if (block && typeof block === "object" && block.type === "text" && typeof block.text === "string") {
|
|
8200
|
-
parts.push(block.text);
|
|
8201
|
-
}
|
|
8202
|
-
}
|
|
8203
|
-
text = parts.join("\n");
|
|
8204
8385
|
}
|
|
8205
|
-
if (!text)
|
|
8206
|
-
continue;
|
|
8207
|
-
if (text.includes("<system-reminder>"))
|
|
8208
|
-
continue;
|
|
8209
|
-
if (text.trim() === "[Request interrupted by user]")
|
|
8210
|
-
continue;
|
|
8211
|
-
const cleaned = stripBanners2(text);
|
|
8212
|
-
if (cleaned.length < 10)
|
|
8213
|
-
continue;
|
|
8214
|
-
return cleaned.slice(0, maxLength);
|
|
8215
8386
|
}
|
|
8216
|
-
return "";
|
|
8217
8387
|
}
|
|
8218
8388
|
var BANNERS;
|
|
8219
8389
|
var init_first_prompt = __esm({
|
|
8220
8390
|
"../engine/dist/core/first-prompt.js"() {
|
|
8221
8391
|
"use strict";
|
|
8392
|
+
init_flat_string();
|
|
8222
8393
|
BANNERS = [
|
|
8223
8394
|
/MCP issues detected\. ?Run \/mcp list for status\.?/g,
|
|
8224
8395
|
/Context low[^\n]*Run \/compact[^\n]*/g,
|
|
@@ -8228,7 +8399,7 @@ var init_first_prompt = __esm({
|
|
|
8228
8399
|
});
|
|
8229
8400
|
|
|
8230
8401
|
// ../engine/dist/core/backends/tail-read.js
|
|
8231
|
-
import { openSync as
|
|
8402
|
+
import { openSync as openSync4, readSync as readSync4, closeSync as closeSync4, statSync as statSync7 } from "node:fs";
|
|
8232
8403
|
function readTailFromOffset(path, offset) {
|
|
8233
8404
|
let size = 0;
|
|
8234
8405
|
try {
|
|
@@ -8242,10 +8413,10 @@ function readTailFromOffset(path, offset) {
|
|
|
8242
8413
|
const buf = Buffer.allocUnsafe(len);
|
|
8243
8414
|
let fd = null;
|
|
8244
8415
|
try {
|
|
8245
|
-
fd =
|
|
8416
|
+
fd = openSync4(path, "r");
|
|
8246
8417
|
let got = 0;
|
|
8247
8418
|
while (got < len) {
|
|
8248
|
-
const n =
|
|
8419
|
+
const n = readSync4(fd, buf, got, len - got, offset + got);
|
|
8249
8420
|
if (n <= 0)
|
|
8250
8421
|
break;
|
|
8251
8422
|
got += n;
|
|
@@ -8264,7 +8435,7 @@ function readTailFromOffset(path, offset) {
|
|
|
8264
8435
|
} finally {
|
|
8265
8436
|
if (fd !== null) {
|
|
8266
8437
|
try {
|
|
8267
|
-
|
|
8438
|
+
closeSync4(fd);
|
|
8268
8439
|
} catch {
|
|
8269
8440
|
}
|
|
8270
8441
|
}
|
|
@@ -8549,7 +8720,7 @@ var init_generic_engine = __esm({
|
|
|
8549
8720
|
});
|
|
8550
8721
|
|
|
8551
8722
|
// ../engine/dist/core/backends/claude.js
|
|
8552
|
-
import { existsSync as existsSync10, readdirSync as readdirSync6, readFileSync as
|
|
8723
|
+
import { existsSync as existsSync10, readdirSync as readdirSync6, readFileSync as readFileSync5, statSync as statSync8, openSync as openSync5, readSync as readSync5, closeSync as closeSync5 } from "fs";
|
|
8553
8724
|
import { join as join10, basename as basename8 } from "path";
|
|
8554
8725
|
function stripReminders(text) {
|
|
8555
8726
|
return text.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g, "").trim();
|
|
@@ -8568,6 +8739,7 @@ var init_claude2 = __esm({
|
|
|
8568
8739
|
init_session_git();
|
|
8569
8740
|
init_first_prompt();
|
|
8570
8741
|
init_tail_read();
|
|
8742
|
+
init_project_dir_name();
|
|
8571
8743
|
init_generic_engine();
|
|
8572
8744
|
UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
8573
8745
|
ClaudeBackend = class {
|
|
@@ -8644,13 +8816,13 @@ var init_claude2 = __esm({
|
|
|
8644
8816
|
return null;
|
|
8645
8817
|
let head;
|
|
8646
8818
|
try {
|
|
8647
|
-
const fd =
|
|
8819
|
+
const fd = openSync5(located.path, "r");
|
|
8648
8820
|
try {
|
|
8649
8821
|
const buf = Buffer.alloc(65536);
|
|
8650
|
-
const n =
|
|
8822
|
+
const n = readSync5(fd, buf, 0, buf.length, 0);
|
|
8651
8823
|
head = buf.toString("utf-8", 0, n);
|
|
8652
8824
|
} finally {
|
|
8653
|
-
|
|
8825
|
+
closeSync5(fd);
|
|
8654
8826
|
}
|
|
8655
8827
|
} catch {
|
|
8656
8828
|
return null;
|
|
@@ -8709,11 +8881,11 @@ var init_claude2 = __esm({
|
|
|
8709
8881
|
if (filter && !proj.name.toLowerCase().includes(filter))
|
|
8710
8882
|
continue;
|
|
8711
8883
|
const projPath = join10(root, proj.name);
|
|
8712
|
-
const projectPath = proj.name
|
|
8884
|
+
const projectPath = decodeProjectDirName(proj.name);
|
|
8713
8885
|
const indexPath = join10(projPath, "sessions-index.json");
|
|
8714
8886
|
if (existsSync10(indexPath)) {
|
|
8715
8887
|
try {
|
|
8716
|
-
const indexData = JSON.parse(
|
|
8888
|
+
const indexData = JSON.parse(readFileSync5(indexPath, "utf-8"));
|
|
8717
8889
|
const entries = indexData.entries || [];
|
|
8718
8890
|
for (const entry of entries) {
|
|
8719
8891
|
if (!entry.fullPath || !existsSync10(entry.fullPath))
|
|
@@ -9005,7 +9177,7 @@ var init_claude2 = __esm({
|
|
|
9005
9177
|
* with quiet main + active subagents still surfaces.
|
|
9006
9178
|
*/
|
|
9007
9179
|
collectRecentEdits(opts) {
|
|
9008
|
-
const
|
|
9180
|
+
const candidates2 = [];
|
|
9009
9181
|
for (const root of claudeProjectDirs()) {
|
|
9010
9182
|
if (!existsSync10(root))
|
|
9011
9183
|
continue;
|
|
@@ -9041,14 +9213,14 @@ var init_claude2 = __esm({
|
|
|
9041
9213
|
}
|
|
9042
9214
|
if (mtime < opts.sinceMs)
|
|
9043
9215
|
continue;
|
|
9044
|
-
|
|
9216
|
+
candidates2.push({ rawId: basename8(f, ".jsonl"), mtime });
|
|
9045
9217
|
} catch {
|
|
9046
9218
|
}
|
|
9047
9219
|
}
|
|
9048
9220
|
}
|
|
9049
9221
|
}
|
|
9050
|
-
|
|
9051
|
-
const limited = opts.limitSessions ?
|
|
9222
|
+
candidates2.sort((a, b) => b.mtime - a.mtime);
|
|
9223
|
+
const limited = opts.limitSessions ? candidates2.slice(0, opts.limitSessions) : candidates2;
|
|
9052
9224
|
const edits = [];
|
|
9053
9225
|
for (const c of limited) {
|
|
9054
9226
|
const scan = this.liveScanEdits(c.rawId);
|
|
@@ -9135,12 +9307,12 @@ var init_claude2 = __esm({
|
|
|
9135
9307
|
|
|
9136
9308
|
// ../engine/dist/core/backends/gemini.js
|
|
9137
9309
|
import { createHash as createHash4 } from "crypto";
|
|
9138
|
-
import { existsSync as existsSync11, readdirSync as readdirSync7, readFileSync as
|
|
9310
|
+
import { existsSync as existsSync11, readdirSync as readdirSync7, readFileSync as readFileSync6, statSync as statSync9 } from "fs";
|
|
9139
9311
|
import { basename as basename9, join as join11 } from "path";
|
|
9140
9312
|
function readSessionId(path, format) {
|
|
9141
9313
|
try {
|
|
9142
9314
|
if (format === "json") {
|
|
9143
|
-
const json = JSON.parse(
|
|
9315
|
+
const json = JSON.parse(readFileSync6(path, "utf-8"));
|
|
9144
9316
|
return typeof json?.sessionId === "string" ? json.sessionId : null;
|
|
9145
9317
|
}
|
|
9146
9318
|
const head = readHeadSync(path).split("\n", 1)[0] || "";
|
|
@@ -9174,6 +9346,7 @@ var init_gemini2 = __esm({
|
|
|
9174
9346
|
init_session_git();
|
|
9175
9347
|
init_generic_engine();
|
|
9176
9348
|
init_tail_read();
|
|
9349
|
+
init_flat_string();
|
|
9177
9350
|
PREFIX = "gemini_";
|
|
9178
9351
|
FULL_PARSE_MAX = 4 * 1024 * 1024;
|
|
9179
9352
|
GeminiBackend = class {
|
|
@@ -9283,7 +9456,7 @@ var init_gemini2 = __esm({
|
|
|
9283
9456
|
sessionId = readSessionId(fullPath, format);
|
|
9284
9457
|
const messages = readGeminiMessages(fullPath, format);
|
|
9285
9458
|
const firstUser = messages.find((m) => m.type === "user");
|
|
9286
|
-
firstPrompt = (typeof firstUser?.text === "string" ? firstUser.text : flatten(firstUser?.content)).slice(0, 200);
|
|
9459
|
+
firstPrompt = flatString((typeof firstUser?.text === "string" ? firstUser.text : flatten(firstUser?.content)).slice(0, 200));
|
|
9287
9460
|
messageCount = messages.length;
|
|
9288
9461
|
} else if (format === "jsonl") {
|
|
9289
9462
|
const lines = readHeadSync(fullPath, 1048576).split("\n");
|
|
@@ -9305,7 +9478,7 @@ var init_gemini2 = __esm({
|
|
|
9305
9478
|
}
|
|
9306
9479
|
if (m?.type !== "user")
|
|
9307
9480
|
continue;
|
|
9308
|
-
firstPrompt = (typeof m.text === "string" ? m.text : flatten(m.content)).slice(0, 200);
|
|
9481
|
+
firstPrompt = flatString((typeof m.text === "string" ? m.text : flatten(m.content)).slice(0, 200));
|
|
9309
9482
|
break;
|
|
9310
9483
|
}
|
|
9311
9484
|
}
|
|
@@ -9481,7 +9654,7 @@ var init_gemini2 = __esm({
|
|
|
9481
9654
|
if (!existsSync11(tmpRoot))
|
|
9482
9655
|
return [];
|
|
9483
9656
|
const projMap = this.loadProjectMap();
|
|
9484
|
-
const
|
|
9657
|
+
const candidates2 = [];
|
|
9485
9658
|
for (const proj of readdirSync7(tmpRoot, { withFileTypes: true })) {
|
|
9486
9659
|
if (!proj.isDirectory())
|
|
9487
9660
|
continue;
|
|
@@ -9512,13 +9685,13 @@ var init_gemini2 = __esm({
|
|
|
9512
9685
|
if (st.mtimeMs < opts.sinceMs)
|
|
9513
9686
|
continue;
|
|
9514
9687
|
const trimLen = isJsonl ? 6 : 5;
|
|
9515
|
-
|
|
9688
|
+
candidates2.push({ rawIdHint: f.slice(0, -trimLen), mtime: st.mtimeMs });
|
|
9516
9689
|
} catch {
|
|
9517
9690
|
}
|
|
9518
9691
|
}
|
|
9519
9692
|
}
|
|
9520
|
-
|
|
9521
|
-
const limited = opts.limitSessions ?
|
|
9693
|
+
candidates2.sort((a, b) => b.mtime - a.mtime);
|
|
9694
|
+
const limited = opts.limitSessions ? candidates2.slice(0, opts.limitSessions) : candidates2;
|
|
9522
9695
|
const edits = [];
|
|
9523
9696
|
for (const c of limited) {
|
|
9524
9697
|
const scan = this.liveScanEdits(c.rawIdHint);
|
|
@@ -9537,7 +9710,7 @@ var init_gemini2 = __esm({
|
|
|
9537
9710
|
if (!existsSync11(path))
|
|
9538
9711
|
return map;
|
|
9539
9712
|
try {
|
|
9540
|
-
const json = JSON.parse(
|
|
9713
|
+
const json = JSON.parse(readFileSync6(path, "utf-8"));
|
|
9541
9714
|
const projects = json?.projects ?? {};
|
|
9542
9715
|
for (const projectPath of Object.keys(projects)) {
|
|
9543
9716
|
const hash = createHash4("sha256").update(projectPath).digest("hex");
|
|
@@ -9555,7 +9728,7 @@ var init_gemini2 = __esm({
|
|
|
9555
9728
|
return {
|
|
9556
9729
|
tool: "gemini",
|
|
9557
9730
|
mtime: statSync9(loc.path).mtimeMs,
|
|
9558
|
-
files: [{ name: basename9(loc.path), bytes:
|
|
9731
|
+
files: [{ name: basename9(loc.path), bytes: readFileSync6(loc.path) }]
|
|
9559
9732
|
};
|
|
9560
9733
|
} catch {
|
|
9561
9734
|
return null;
|
|
@@ -9650,6 +9823,7 @@ var init_opencode = __esm({
|
|
|
9650
9823
|
init_session_outcome();
|
|
9651
9824
|
init_session_git();
|
|
9652
9825
|
init_generic_engine();
|
|
9826
|
+
init_flat_string();
|
|
9653
9827
|
PREFIX2 = "opencode_";
|
|
9654
9828
|
OpencodeBackend = class {
|
|
9655
9829
|
id = "opencode";
|
|
@@ -9817,7 +9991,7 @@ var init_opencode = __esm({
|
|
|
9817
9991
|
if (firstUser) {
|
|
9818
9992
|
try {
|
|
9819
9993
|
const parsed = JSON.parse(firstUser.data);
|
|
9820
|
-
firstPrompt = String(parsed?.text || "").slice(0, 200);
|
|
9994
|
+
firstPrompt = flatString(String(parsed?.text || "").slice(0, 200));
|
|
9821
9995
|
} catch {
|
|
9822
9996
|
}
|
|
9823
9997
|
}
|
|
@@ -10161,7 +10335,7 @@ var init_opencode = __esm({
|
|
|
10161
10335
|
});
|
|
10162
10336
|
|
|
10163
10337
|
// ../engine/dist/core/backends/codex.js
|
|
10164
|
-
import { readdirSync as readdirSync8, readFileSync as
|
|
10338
|
+
import { readdirSync as readdirSync8, readFileSync as readFileSync7, statSync as statSync10, openSync as openSync6, readSync as readSync6, closeSync as closeSync6 } from "fs";
|
|
10165
10339
|
import { basename as basename10, dirname as dirname10, join as join13 } from "path";
|
|
10166
10340
|
function parseShellWrites(cmd) {
|
|
10167
10341
|
const out = [];
|
|
@@ -10290,7 +10464,7 @@ function flattenContent(content) {
|
|
|
10290
10464
|
}
|
|
10291
10465
|
function readFirstLine(path) {
|
|
10292
10466
|
try {
|
|
10293
|
-
const head =
|
|
10467
|
+
const head = readFileSync7(path, "utf-8").split("\n", 1)[0] || "";
|
|
10294
10468
|
if (!head)
|
|
10295
10469
|
return null;
|
|
10296
10470
|
return JSON.parse(head);
|
|
@@ -10308,6 +10482,7 @@ var init_codex2 = __esm({
|
|
|
10308
10482
|
init_session_git();
|
|
10309
10483
|
init_generic_engine();
|
|
10310
10484
|
init_tail_read();
|
|
10485
|
+
init_flat_string();
|
|
10311
10486
|
PREFIX3 = "codex_";
|
|
10312
10487
|
CodexBackend = class {
|
|
10313
10488
|
id = "codex";
|
|
@@ -10407,7 +10582,7 @@ var init_codex2 = __esm({
|
|
|
10407
10582
|
let firstPrompt = "";
|
|
10408
10583
|
let messageCount = 0;
|
|
10409
10584
|
try {
|
|
10410
|
-
const lines =
|
|
10585
|
+
const lines = readFileSync7(filePath, "utf-8").split("\n");
|
|
10411
10586
|
for (const line of lines) {
|
|
10412
10587
|
if (!line.trim())
|
|
10413
10588
|
continue;
|
|
@@ -10420,7 +10595,7 @@ var init_codex2 = __esm({
|
|
|
10420
10595
|
if (ev.type === "event_msg" && ev.payload?.type === "user_message") {
|
|
10421
10596
|
messageCount++;
|
|
10422
10597
|
if (!firstPrompt && ev.payload.message) {
|
|
10423
|
-
firstPrompt = String(ev.payload.message).slice(0, 200);
|
|
10598
|
+
firstPrompt = flatString(String(ev.payload.message).slice(0, 200));
|
|
10424
10599
|
}
|
|
10425
10600
|
} else if (ev.type === "response_item" && ev.payload?.type === "message") {
|
|
10426
10601
|
messageCount++;
|
|
@@ -10559,7 +10734,7 @@ var init_codex2 = __esm({
|
|
|
10559
10734
|
continue;
|
|
10560
10735
|
let firstLine = "";
|
|
10561
10736
|
try {
|
|
10562
|
-
firstLine =
|
|
10737
|
+
firstLine = readFileSync7(path, "utf-8").split("\n", 1)[0] || "";
|
|
10563
10738
|
} catch {
|
|
10564
10739
|
continue;
|
|
10565
10740
|
}
|
|
@@ -10583,7 +10758,7 @@ var init_codex2 = __esm({
|
|
|
10583
10758
|
let raw = "";
|
|
10584
10759
|
let mtime = 0;
|
|
10585
10760
|
try {
|
|
10586
|
-
raw =
|
|
10761
|
+
raw = readFileSync7(path, "utf-8");
|
|
10587
10762
|
mtime = statSync10(path).mtimeMs;
|
|
10588
10763
|
} catch {
|
|
10589
10764
|
return [];
|
|
@@ -10760,7 +10935,7 @@ var init_codex2 = __esm({
|
|
|
10760
10935
|
let parentId = null;
|
|
10761
10936
|
let isSubagent = false;
|
|
10762
10937
|
try {
|
|
10763
|
-
const first =
|
|
10938
|
+
const first = readFileSync7(p, "utf-8").split("\n")[0];
|
|
10764
10939
|
if (first) {
|
|
10765
10940
|
const meta = JSON.parse(first);
|
|
10766
10941
|
const payload = meta?.payload || {};
|
|
@@ -10816,7 +10991,7 @@ var init_codex2 = __esm({
|
|
|
10816
10991
|
const push = (path, name) => {
|
|
10817
10992
|
try {
|
|
10818
10993
|
const st = statSync10(path);
|
|
10819
|
-
files.push({ name, bytes:
|
|
10994
|
+
files.push({ name, bytes: readFileSync7(path) });
|
|
10820
10995
|
if (st.mtimeMs > mtime)
|
|
10821
10996
|
mtime = st.mtimeMs;
|
|
10822
10997
|
} catch {
|
|
@@ -10834,10 +11009,10 @@ var init_codex2 = __esm({
|
|
|
10834
11009
|
if (p === loc.path)
|
|
10835
11010
|
continue;
|
|
10836
11011
|
try {
|
|
10837
|
-
const fd =
|
|
11012
|
+
const fd = openSync6(p, "r");
|
|
10838
11013
|
const buf = Buffer.alloc(4096);
|
|
10839
|
-
const n =
|
|
10840
|
-
|
|
11014
|
+
const n = readSync6(fd, buf, 0, 4096, 0);
|
|
11015
|
+
closeSync6(fd);
|
|
10841
11016
|
const head = buf.toString("utf-8", 0, n);
|
|
10842
11017
|
if (head.includes(parentId) && head.includes("parent_thread_id"))
|
|
10843
11018
|
push(p, `subagents/${f}`);
|
|
@@ -10874,13 +11049,13 @@ var init_codex2 = __esm({
|
|
|
10874
11049
|
});
|
|
10875
11050
|
|
|
10876
11051
|
// ../engine/dist/core/backends/agy.js
|
|
10877
|
-
import { existsSync as existsSync13, readdirSync as readdirSync9, readFileSync as
|
|
11052
|
+
import { existsSync as existsSync13, readdirSync as readdirSync9, readFileSync as readFileSync8, statSync as statSync11 } from "fs";
|
|
10878
11053
|
import { basename as basename11, dirname as dirname11, join as join14 } from "path";
|
|
10879
11054
|
function getFallbackProjectPath(homeDir) {
|
|
10880
11055
|
try {
|
|
10881
11056
|
const settingsPath2 = join14(homeDir, "settings.json");
|
|
10882
11057
|
if (existsSync13(settingsPath2)) {
|
|
10883
|
-
const json = JSON.parse(
|
|
11058
|
+
const json = JSON.parse(readFileSync8(settingsPath2, "utf-8"));
|
|
10884
11059
|
if (Array.isArray(json?.trustedWorkspaces) && json.trustedWorkspaces[0]) {
|
|
10885
11060
|
return json.trustedWorkspaces[0];
|
|
10886
11061
|
}
|
|
@@ -10907,7 +11082,7 @@ function resolveAgyProject(logsDir, homeDir) {
|
|
|
10907
11082
|
function extractProjectPathFromTranscript(path, homeDir) {
|
|
10908
11083
|
let content;
|
|
10909
11084
|
try {
|
|
10910
|
-
content =
|
|
11085
|
+
content = readFileSync8(path, "utf-8");
|
|
10911
11086
|
} catch {
|
|
10912
11087
|
return "";
|
|
10913
11088
|
}
|
|
@@ -10993,6 +11168,7 @@ var init_agy = __esm({
|
|
|
10993
11168
|
init_session_outcome();
|
|
10994
11169
|
init_session_git();
|
|
10995
11170
|
init_generic_engine();
|
|
11171
|
+
init_flat_string();
|
|
10996
11172
|
PREFIX4 = "agy_";
|
|
10997
11173
|
AgyBackend = class {
|
|
10998
11174
|
id = "agy";
|
|
@@ -11085,7 +11261,7 @@ var init_agy = __esm({
|
|
|
11085
11261
|
let firstPrompt = "";
|
|
11086
11262
|
let messageCount = 0;
|
|
11087
11263
|
try {
|
|
11088
|
-
const lines =
|
|
11264
|
+
const lines = readFileSync8(filePath, "utf-8").split("\n").filter(Boolean);
|
|
11089
11265
|
messageCount = lines.length;
|
|
11090
11266
|
for (const line of lines) {
|
|
11091
11267
|
const obj = JSON.parse(line);
|
|
@@ -11093,7 +11269,7 @@ var init_agy = __esm({
|
|
|
11093
11269
|
const content = obj.content;
|
|
11094
11270
|
const match = content.match(/<USER_REQUEST>([\s\S]*?)<\/USER_REQUEST>/);
|
|
11095
11271
|
const rawText = match ? match[1].trim() : content.trim();
|
|
11096
|
-
firstPrompt = rawText.slice(0, 200);
|
|
11272
|
+
firstPrompt = flatString(rawText.slice(0, 200));
|
|
11097
11273
|
break;
|
|
11098
11274
|
}
|
|
11099
11275
|
}
|
|
@@ -11175,7 +11351,7 @@ var init_agy = __esm({
|
|
|
11175
11351
|
return [];
|
|
11176
11352
|
let rawText;
|
|
11177
11353
|
try {
|
|
11178
|
-
rawText =
|
|
11354
|
+
rawText = readFileSync8(located.path, "utf-8");
|
|
11179
11355
|
} catch {
|
|
11180
11356
|
return [];
|
|
11181
11357
|
}
|
|
@@ -11327,7 +11503,7 @@ var init_agy = __esm({
|
|
|
11327
11503
|
if (brainRoots.length === 0)
|
|
11328
11504
|
return [];
|
|
11329
11505
|
const brainDir = brainRoots[0];
|
|
11330
|
-
const
|
|
11506
|
+
const candidates2 = [];
|
|
11331
11507
|
let sessionDirs;
|
|
11332
11508
|
try {
|
|
11333
11509
|
sessionDirs = readdirSync9(brainDir);
|
|
@@ -11349,12 +11525,12 @@ var init_agy = __esm({
|
|
|
11349
11525
|
const st = statSync11(filePath);
|
|
11350
11526
|
if (st.mtimeMs < opts.sinceMs)
|
|
11351
11527
|
continue;
|
|
11352
|
-
|
|
11528
|
+
candidates2.push({ rawId, mtime: st.mtimeMs });
|
|
11353
11529
|
} catch {
|
|
11354
11530
|
}
|
|
11355
11531
|
}
|
|
11356
|
-
|
|
11357
|
-
const limited = opts.limitSessions ?
|
|
11532
|
+
candidates2.sort((a, b) => b.mtime - a.mtime);
|
|
11533
|
+
const limited = opts.limitSessions ? candidates2.slice(0, opts.limitSessions) : candidates2;
|
|
11358
11534
|
const edits = [];
|
|
11359
11535
|
for (const c of limited) {
|
|
11360
11536
|
const scan = this.liveScanEdits(c.rawId);
|
|
@@ -11375,7 +11551,7 @@ var init_agy = __esm({
|
|
|
11375
11551
|
return {
|
|
11376
11552
|
tool: "agy",
|
|
11377
11553
|
mtime: statSync11(loc.path).mtimeMs,
|
|
11378
|
-
files: [{ name: basename11(loc.path), bytes:
|
|
11554
|
+
files: [{ name: basename11(loc.path), bytes: readFileSync8(loc.path) }]
|
|
11379
11555
|
};
|
|
11380
11556
|
} catch {
|
|
11381
11557
|
return null;
|
|
@@ -11427,6 +11603,24 @@ var init_backends = __esm({
|
|
|
11427
11603
|
}
|
|
11428
11604
|
});
|
|
11429
11605
|
|
|
11606
|
+
// ../engine/dist/core/credentials-env.js
|
|
11607
|
+
function envCredentials(env = process.env) {
|
|
11608
|
+
const token = (env.CHAT_RECALL_TOKEN || "").trim();
|
|
11609
|
+
const server2 = (env.CHAT_RECALL_SERVER || "").trim();
|
|
11610
|
+
if (!token || !server2)
|
|
11611
|
+
return null;
|
|
11612
|
+
if (!/^https?:\/\//i.test(server2))
|
|
11613
|
+
return null;
|
|
11614
|
+
return { serverUrl: normalise(server2), token };
|
|
11615
|
+
}
|
|
11616
|
+
var normalise;
|
|
11617
|
+
var init_credentials_env = __esm({
|
|
11618
|
+
"../engine/dist/core/credentials-env.js"() {
|
|
11619
|
+
"use strict";
|
|
11620
|
+
normalise = (u) => u.trim().replace(/\/+$/, "");
|
|
11621
|
+
}
|
|
11622
|
+
});
|
|
11623
|
+
|
|
11430
11624
|
// ../engine/dist/core/source-discovery.js
|
|
11431
11625
|
import { createHash as createHash5 } from "crypto";
|
|
11432
11626
|
import { existsSync as existsSync15, readdirSync as readdirSync10, statSync as statSync12 } from "fs";
|
|
@@ -11533,7 +11727,7 @@ var init_source_discovery = __esm({
|
|
|
11533
11727
|
|
|
11534
11728
|
// ../engine/dist/core/home-discovery.js
|
|
11535
11729
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
11536
|
-
import { existsSync as existsSync16, readdirSync as readdirSync11, readFileSync as
|
|
11730
|
+
import { existsSync as existsSync16, readdirSync as readdirSync11, readFileSync as readFileSync9, realpathSync as realpathSync2, statSync as statSync13 } from "fs";
|
|
11537
11731
|
import { homedir as homedir5, platform as osPlatform } from "os";
|
|
11538
11732
|
import { join as join17 } from "path";
|
|
11539
11733
|
function candidateRoots(plat = osPlatform(), env = process.env) {
|
|
@@ -11655,7 +11849,7 @@ function declaredHomes(env = process.env, plat = osPlatform()) {
|
|
|
11655
11849
|
for (const rc of rcs) {
|
|
11656
11850
|
let text;
|
|
11657
11851
|
try {
|
|
11658
|
-
text =
|
|
11852
|
+
text = readFileSync9(rc, "utf-8");
|
|
11659
11853
|
} catch {
|
|
11660
11854
|
continue;
|
|
11661
11855
|
}
|
|
@@ -11680,7 +11874,7 @@ function runningToolHomes(plat = osPlatform()) {
|
|
|
11680
11874
|
for (const pid of pids) {
|
|
11681
11875
|
let env;
|
|
11682
11876
|
try {
|
|
11683
|
-
env =
|
|
11877
|
+
env = readFileSync9(`/proc/${pid}/environ`, "utf-8");
|
|
11684
11878
|
} catch {
|
|
11685
11879
|
continue;
|
|
11686
11880
|
}
|
|
@@ -11801,7 +11995,7 @@ var init_home_discovery = __esm({
|
|
|
11801
11995
|
|
|
11802
11996
|
// ../engine/dist/core/detector-install.js
|
|
11803
11997
|
import { createHash as createHash6 } from "crypto";
|
|
11804
|
-
import { existsSync as existsSync17, mkdirSync as mkdirSync5, mkdtempSync, chmodSync as chmodSync3, renameSync as renameSync3, rmSync as rmSync2, writeFileSync as writeFileSync3, readFileSync as
|
|
11998
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync5, mkdtempSync, chmodSync as chmodSync3, renameSync as renameSync3, rmSync as rmSync2, writeFileSync as writeFileSync3, readFileSync as readFileSync10, statSync as statSync14, copyFileSync as copyFileSync2 } from "fs";
|
|
11805
11999
|
import { join as join18 } from "path";
|
|
11806
12000
|
function managedDetectorPath(name) {
|
|
11807
12001
|
return join18(getDetectorBinDir(), name + exeSuffix());
|
|
@@ -11810,11 +12004,11 @@ function receiptPath(name) {
|
|
|
11810
12004
|
return join18(getDetectorBinDir(), `${name}.receipt.json`);
|
|
11811
12005
|
}
|
|
11812
12006
|
function sha256File(path) {
|
|
11813
|
-
return createHash6("sha256").update(
|
|
12007
|
+
return createHash6("sha256").update(readFileSync10(path)).digest("hex");
|
|
11814
12008
|
}
|
|
11815
12009
|
function readReceipt(name) {
|
|
11816
12010
|
try {
|
|
11817
|
-
return JSON.parse(
|
|
12011
|
+
return JSON.parse(readFileSync10(receiptPath(name), "utf-8"));
|
|
11818
12012
|
} catch {
|
|
11819
12013
|
return null;
|
|
11820
12014
|
}
|
|
@@ -11905,7 +12099,7 @@ var init_detector_install = __esm({
|
|
|
11905
12099
|
|
|
11906
12100
|
// ../engine/dist/core/secret-scanner.js
|
|
11907
12101
|
import { spawnSync } from "child_process";
|
|
11908
|
-
import { existsSync as existsSync18, unlinkSync, readFileSync as
|
|
12102
|
+
import { existsSync as existsSync18, unlinkSync, readFileSync as readFileSync11, mkdtempSync as mkdtempSync2, rmSync as rmSync3 } from "fs";
|
|
11909
12103
|
import { tmpdir } from "os";
|
|
11910
12104
|
import { join as join19 } from "path";
|
|
11911
12105
|
function mask(s) {
|
|
@@ -11966,7 +12160,7 @@ function runGitleaks(binary, filePath) {
|
|
|
11966
12160
|
return [];
|
|
11967
12161
|
let parsed = [];
|
|
11968
12162
|
try {
|
|
11969
|
-
parsed = JSON.parse(
|
|
12163
|
+
parsed = JSON.parse(readFileSync11(reportPath, "utf-8")) || [];
|
|
11970
12164
|
} catch {
|
|
11971
12165
|
}
|
|
11972
12166
|
try {
|
|
@@ -12030,7 +12224,7 @@ function runGitleaksDir(binary, dir) {
|
|
|
12030
12224
|
}
|
|
12031
12225
|
let parsed = [];
|
|
12032
12226
|
try {
|
|
12033
|
-
parsed = JSON.parse(
|
|
12227
|
+
parsed = JSON.parse(readFileSync11(reportPath, "utf-8")) || [];
|
|
12034
12228
|
} catch {
|
|
12035
12229
|
}
|
|
12036
12230
|
try {
|
|
@@ -12121,7 +12315,7 @@ function scanFileForSecrets(filePath, opts = {}) {
|
|
|
12121
12315
|
out.push({ detector: "trufflehog", ...f });
|
|
12122
12316
|
if (opts.tenantRules && opts.tenantRules.length > 0) {
|
|
12123
12317
|
try {
|
|
12124
|
-
const text =
|
|
12318
|
+
const text = readFileSync11(filePath, "utf-8");
|
|
12125
12319
|
out.push(...scanTenantRules(text, opts.tenantRules));
|
|
12126
12320
|
} catch {
|
|
12127
12321
|
}
|
|
@@ -12246,10 +12440,10 @@ var init_types = __esm({
|
|
|
12246
12440
|
|
|
12247
12441
|
// ../engine/dist/transcript/opencode.js
|
|
12248
12442
|
async function parseOpenCodeSubagents(parentSessionId) {
|
|
12249
|
-
const { existsSync:
|
|
12443
|
+
const { existsSync: existsSync45 } = await import("fs");
|
|
12250
12444
|
const { opencodeBackend: opencodeBackend2 } = await Promise.resolve().then(() => (init_opencode(), opencode_exports));
|
|
12251
12445
|
const dbPath = opencodeBackend2.dbPath();
|
|
12252
|
-
if (!
|
|
12446
|
+
if (!existsSync45(dbPath))
|
|
12253
12447
|
return [];
|
|
12254
12448
|
const realParent = parentSessionId.replace("opencode_", "");
|
|
12255
12449
|
const db = openSqliteReadonlyOrThrow(dbPath);
|
|
@@ -12290,10 +12484,10 @@ async function parseOpenCodeSubagents(parentSessionId) {
|
|
|
12290
12484
|
}
|
|
12291
12485
|
}
|
|
12292
12486
|
async function parseOpenCodeTranscript(sessionId) {
|
|
12293
|
-
const { existsSync:
|
|
12487
|
+
const { existsSync: existsSync45 } = await import("fs");
|
|
12294
12488
|
const { opencodeBackend: opencodeBackend2 } = await Promise.resolve().then(() => (init_opencode(), opencode_exports));
|
|
12295
12489
|
const dbPath = opencodeBackend2.dbPath();
|
|
12296
|
-
if (!
|
|
12490
|
+
if (!existsSync45(dbPath))
|
|
12297
12491
|
return [];
|
|
12298
12492
|
const realId = sessionId.replace("opencode_", "");
|
|
12299
12493
|
const db = openSqliteReadonlyOrThrow(dbPath);
|
|
@@ -12486,7 +12680,7 @@ var init_transcript = __esm({
|
|
|
12486
12680
|
// ../engine/dist/core/project-resolver.js
|
|
12487
12681
|
import { execSync } from "child_process";
|
|
12488
12682
|
import { createHash as createHash7 } from "crypto";
|
|
12489
|
-
import { existsSync as existsSync19, readFileSync as
|
|
12683
|
+
import { existsSync as existsSync19, readFileSync as readFileSync12, realpathSync as realpathSync3, readdirSync as readdirSync12, statSync as statSync16 } from "fs";
|
|
12490
12684
|
import { basename as basename12, dirname as dirname12, isAbsolute, join as join20, resolve, sep } from "path";
|
|
12491
12685
|
function getProjectsConfigPath() {
|
|
12492
12686
|
return join20(getDataDir(), "projects.json");
|
|
@@ -12504,7 +12698,7 @@ function loadProjectsConfig() {
|
|
|
12504
12698
|
if (cachedConfig && cachedConfig.mtime === mtime)
|
|
12505
12699
|
return cachedConfig.cfg;
|
|
12506
12700
|
try {
|
|
12507
|
-
const raw =
|
|
12701
|
+
const raw = readFileSync12(path, "utf-8");
|
|
12508
12702
|
const cfg = JSON.parse(raw);
|
|
12509
12703
|
cachedConfig = { mtime, cfg };
|
|
12510
12704
|
return cfg;
|
|
@@ -12572,8 +12766,8 @@ function resolveBotWorktree(realPath) {
|
|
|
12572
12766
|
};
|
|
12573
12767
|
}
|
|
12574
12768
|
function matchDeclaredProject(realPath, projects) {
|
|
12575
|
-
const
|
|
12576
|
-
for (const proj of
|
|
12769
|
+
const candidates2 = [...projects].sort((a, b) => b.root.length - a.root.length);
|
|
12770
|
+
for (const proj of candidates2) {
|
|
12577
12771
|
const root = safeRealpath(proj.root);
|
|
12578
12772
|
if (!isInside(realPath, root))
|
|
12579
12773
|
continue;
|
|
@@ -13607,7 +13801,7 @@ var init_utils = __esm({
|
|
|
13607
13801
|
});
|
|
13608
13802
|
|
|
13609
13803
|
// ../engine/dist/parsers/plan-source.js
|
|
13610
|
-
import { existsSync as existsSync21, readdirSync as readdirSync14, readFileSync as
|
|
13804
|
+
import { existsSync as existsSync21, readdirSync as readdirSync14, readFileSync as readFileSync13, statSync as statSync18 } from "fs";
|
|
13611
13805
|
import { homedir as homedir7 } from "os";
|
|
13612
13806
|
import { join as join22, basename as basename13 } from "path";
|
|
13613
13807
|
import { createHash as createHash8 } from "crypto";
|
|
@@ -13649,6 +13843,7 @@ var init_plan_source = __esm({
|
|
|
13649
13843
|
init_claude2();
|
|
13650
13844
|
init_agy();
|
|
13651
13845
|
init_settings();
|
|
13846
|
+
init_project_dir_name();
|
|
13652
13847
|
MAX_CHUNK_CHARS = 2e3;
|
|
13653
13848
|
UUID_RE3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
13654
13849
|
PlanSource = class {
|
|
@@ -13673,7 +13868,7 @@ var init_plan_source = __esm({
|
|
|
13673
13868
|
for (const entry of entries) {
|
|
13674
13869
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
13675
13870
|
continue;
|
|
13676
|
-
const projectPath = entry.name
|
|
13871
|
+
const projectPath = decodeProjectDirName(entry.name);
|
|
13677
13872
|
if (existsSync21(projectPath)) {
|
|
13678
13873
|
this._knownProjectDirs.push(projectPath);
|
|
13679
13874
|
}
|
|
@@ -13711,7 +13906,7 @@ var init_plan_source = __esm({
|
|
|
13711
13906
|
const stat3 = statSync18(filePath);
|
|
13712
13907
|
const planName = basename13(file, ".md");
|
|
13713
13908
|
const isAgentPlan = planName.includes("-agent-");
|
|
13714
|
-
const content =
|
|
13909
|
+
const content = readFileSync13(filePath, "utf-8");
|
|
13715
13910
|
const fm = parseFrontmatter(content);
|
|
13716
13911
|
const body = fm.body;
|
|
13717
13912
|
const firstLine = body.split("\n").find((l) => l.trim())?.replace(/^#+\s*/, "").trim() || planName;
|
|
@@ -13753,7 +13948,7 @@ var init_plan_source = __esm({
|
|
|
13753
13948
|
const filePath = join22(plansDir, file);
|
|
13754
13949
|
try {
|
|
13755
13950
|
const stat3 = statSync18(filePath);
|
|
13756
|
-
const content =
|
|
13951
|
+
const content = readFileSync13(filePath, "utf-8");
|
|
13757
13952
|
const firstLine = content.split("\n").find((l) => l.trim())?.replace(/^#+\s*/, "").trim() || file;
|
|
13758
13953
|
const planName = `${opencodeBackend.idPrefix}plan_${basename13(file, ".md")}`;
|
|
13759
13954
|
const projectPath = this.extractProjectPath(content);
|
|
@@ -13783,7 +13978,7 @@ var init_plan_source = __esm({
|
|
|
13783
13978
|
const projectsPath = geminiBackend.projectsJson();
|
|
13784
13979
|
if (existsSync21(projectsPath)) {
|
|
13785
13980
|
try {
|
|
13786
|
-
const data = JSON.parse(
|
|
13981
|
+
const data = JSON.parse(readFileSync13(projectsPath, "utf-8"));
|
|
13787
13982
|
for (const path of Object.keys(data.projects || {})) {
|
|
13788
13983
|
projMap.set(createHash8("sha256").update(path).digest("hex"), path);
|
|
13789
13984
|
}
|
|
@@ -13819,7 +14014,7 @@ var init_plan_source = __esm({
|
|
|
13819
14014
|
const filePath = join22(plansDir, file);
|
|
13820
14015
|
try {
|
|
13821
14016
|
const stat3 = statSync18(filePath);
|
|
13822
|
-
const content =
|
|
14017
|
+
const content = readFileSync13(filePath, "utf-8");
|
|
13823
14018
|
const firstLine = content.split("\n").find((l) => l.trim())?.replace(/^#+\s*/, "").trim() || file;
|
|
13824
14019
|
const planName = `${geminiBackend.idPrefix}plan_${sess}_${basename13(file, ".md")}`;
|
|
13825
14020
|
yield {
|
|
@@ -13898,7 +14093,7 @@ var init_plan_source = __esm({
|
|
|
13898
14093
|
async parse(item) {
|
|
13899
14094
|
if (!existsSync21(item.filePath))
|
|
13900
14095
|
return [];
|
|
13901
|
-
const content =
|
|
14096
|
+
const content = readFileSync13(item.filePath, "utf-8");
|
|
13902
14097
|
const chunks = [];
|
|
13903
14098
|
const { body } = parseFrontmatter(content);
|
|
13904
14099
|
const sections = splitByHeaders(body);
|
|
@@ -14042,7 +14237,7 @@ var init_plan_source = __esm({
|
|
|
14042
14237
|
const filePath = join22(sessionPath, file);
|
|
14043
14238
|
try {
|
|
14044
14239
|
const stat3 = statSync18(filePath);
|
|
14045
|
-
const content =
|
|
14240
|
+
const content = readFileSync13(filePath, "utf-8");
|
|
14046
14241
|
const firstLine = content.split("\n").find((l) => l.trim())?.replace(/^#+\s*/, "").trim() || file;
|
|
14047
14242
|
const sessionLoc = agyBackend.findSession(rawId);
|
|
14048
14243
|
const projectPath = sessionLoc?.projectPath || this.extractProjectPath(content);
|
|
@@ -14071,7 +14266,7 @@ var init_plan_source = __esm({
|
|
|
14071
14266
|
});
|
|
14072
14267
|
|
|
14073
14268
|
// ../engine/dist/parsers/task-source.js
|
|
14074
|
-
import { existsSync as existsSync22, readdirSync as readdirSync15, readFileSync as
|
|
14269
|
+
import { existsSync as existsSync22, readdirSync as readdirSync15, readFileSync as readFileSync14, statSync as statSync19 } from "fs";
|
|
14075
14270
|
import { join as join23 } from "path";
|
|
14076
14271
|
var MAX_CHUNK_CHARS2, TaskSource;
|
|
14077
14272
|
var init_task_source = __esm({
|
|
@@ -14121,7 +14316,7 @@ var init_task_source = __esm({
|
|
|
14121
14316
|
continue;
|
|
14122
14317
|
let parsed;
|
|
14123
14318
|
try {
|
|
14124
|
-
const raw =
|
|
14319
|
+
const raw = readFileSync14(filePath, "utf-8");
|
|
14125
14320
|
parsed = JSON.parse(raw);
|
|
14126
14321
|
if (!Array.isArray(parsed) || parsed.length === 0)
|
|
14127
14322
|
continue;
|
|
@@ -14259,7 +14454,7 @@ ${task.description}`.slice(0, MAX_CHUNK_CHARS2);
|
|
|
14259
14454
|
return [];
|
|
14260
14455
|
let parsed;
|
|
14261
14456
|
try {
|
|
14262
|
-
parsed = JSON.parse(
|
|
14457
|
+
parsed = JSON.parse(readFileSync14(item.filePath, "utf-8"));
|
|
14263
14458
|
} catch {
|
|
14264
14459
|
return [];
|
|
14265
14460
|
}
|
|
@@ -14291,7 +14486,7 @@ ${task.description}`.slice(0, MAX_CHUNK_CHARS2);
|
|
|
14291
14486
|
});
|
|
14292
14487
|
for (const file of sorted) {
|
|
14293
14488
|
try {
|
|
14294
|
-
const content =
|
|
14489
|
+
const content = readFileSync14(join23(taskDir, file), "utf-8");
|
|
14295
14490
|
const task = JSON.parse(content);
|
|
14296
14491
|
if (task.subject) {
|
|
14297
14492
|
tasks.push(task);
|
|
@@ -14307,7 +14502,7 @@ ${task.description}`.slice(0, MAX_CHUNK_CHARS2);
|
|
|
14307
14502
|
});
|
|
14308
14503
|
|
|
14309
14504
|
// ../engine/dist/parsers/claude-md-source.js
|
|
14310
|
-
import { existsSync as existsSync23, readFileSync as
|
|
14505
|
+
import { existsSync as existsSync23, readFileSync as readFileSync15, readdirSync as readdirSync16, statSync as statSync20 } from "fs";
|
|
14311
14506
|
import { homedir as homedir8 } from "os";
|
|
14312
14507
|
import { join as join24, basename as basename14, dirname as dirname13 } from "path";
|
|
14313
14508
|
import { createHash as createHash9 } from "crypto";
|
|
@@ -14328,7 +14523,7 @@ function discoverProjectDirs(claudeDir) {
|
|
|
14328
14523
|
for (const entry of entries) {
|
|
14329
14524
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
14330
14525
|
continue;
|
|
14331
|
-
const projectPath = entry.name
|
|
14526
|
+
const projectPath = decodeProjectDirName(entry.name);
|
|
14332
14527
|
addProject(projectPath);
|
|
14333
14528
|
}
|
|
14334
14529
|
} catch {
|
|
@@ -14351,7 +14546,7 @@ function discoverProjectDirs(claudeDir) {
|
|
|
14351
14546
|
const gemProjects = geminiBackend.projectsJson();
|
|
14352
14547
|
if (existsSync23(gemProjects)) {
|
|
14353
14548
|
try {
|
|
14354
|
-
const data = JSON.parse(
|
|
14549
|
+
const data = JSON.parse(readFileSync15(gemProjects, "utf-8"));
|
|
14355
14550
|
for (const path of Object.keys(data.projects || {}))
|
|
14356
14551
|
addProject(path);
|
|
14357
14552
|
} catch {
|
|
@@ -14385,6 +14580,7 @@ var init_claude_md_source = __esm({
|
|
|
14385
14580
|
init_gemini2();
|
|
14386
14581
|
init_settings();
|
|
14387
14582
|
init_opencode();
|
|
14583
|
+
init_project_dir_name();
|
|
14388
14584
|
MAX_CHUNK_CHARS3 = 2e3;
|
|
14389
14585
|
NOTE_FILES = [
|
|
14390
14586
|
{ filename: "CLAUDE.md", tool: "claude" },
|
|
@@ -14465,7 +14661,7 @@ var init_claude_md_source = __esm({
|
|
|
14465
14661
|
async parse(item) {
|
|
14466
14662
|
if (!existsSync23(item.filePath))
|
|
14467
14663
|
return [];
|
|
14468
|
-
const content =
|
|
14664
|
+
const content = readFileSync15(item.filePath, "utf-8");
|
|
14469
14665
|
const chunks = [];
|
|
14470
14666
|
const sections = splitByHeaders(content);
|
|
14471
14667
|
for (let i = 0; i < sections.length; i++) {
|
|
@@ -14507,7 +14703,7 @@ var init_claude_md_source = __esm({
|
|
|
14507
14703
|
const projectDir = dirname13(filePath);
|
|
14508
14704
|
const projectName = basename14(projectDir);
|
|
14509
14705
|
const projectPath = projectDir;
|
|
14510
|
-
const content =
|
|
14706
|
+
const content = readFileSync15(filePath, "utf-8");
|
|
14511
14707
|
const firstLine = content.split("\n").find((l) => l.trim() && !l.startsWith("#"))?.trim()?.slice(0, 200) || `${filename} for ${projectName}`;
|
|
14512
14708
|
const id = tool === "claude" ? projectName : `${projectName}_${tool}`;
|
|
14513
14709
|
return {
|
|
@@ -14532,7 +14728,7 @@ var init_claude_md_source = __esm({
|
|
|
14532
14728
|
});
|
|
14533
14729
|
|
|
14534
14730
|
// ../engine/dist/parsers/agent-memory-source.js
|
|
14535
|
-
import { existsSync as existsSync24, readFileSync as
|
|
14731
|
+
import { existsSync as existsSync24, readFileSync as readFileSync16, readdirSync as readdirSync17, statSync as statSync21 } from "fs";
|
|
14536
14732
|
import { homedir as homedir9 } from "os";
|
|
14537
14733
|
import { join as join25, basename as basename15 } from "path";
|
|
14538
14734
|
function parseFrontmatter2(content) {
|
|
@@ -14560,7 +14756,7 @@ function parseFrontmatter2(content) {
|
|
|
14560
14756
|
return { fm, body };
|
|
14561
14757
|
}
|
|
14562
14758
|
function projectHashToPath(hashDir) {
|
|
14563
|
-
return hashDir
|
|
14759
|
+
return decodeProjectDirName(hashDir);
|
|
14564
14760
|
}
|
|
14565
14761
|
function discoverMemoryDirs() {
|
|
14566
14762
|
const out = [];
|
|
@@ -14602,6 +14798,7 @@ var init_agent_memory_source = __esm({
|
|
|
14602
14798
|
init_utils();
|
|
14603
14799
|
init_claude2();
|
|
14604
14800
|
init_settings();
|
|
14801
|
+
init_project_dir_name();
|
|
14605
14802
|
MAX_CHUNK_CHARS4 = 2e3;
|
|
14606
14803
|
MAX_CHUNKS = 12;
|
|
14607
14804
|
AgentMemorySource = class {
|
|
@@ -14632,7 +14829,7 @@ var init_agent_memory_source = __esm({
|
|
|
14632
14829
|
async parse(item) {
|
|
14633
14830
|
if (!existsSync24(item.filePath))
|
|
14634
14831
|
return [];
|
|
14635
|
-
const content =
|
|
14832
|
+
const content = readFileSync16(item.filePath, "utf-8");
|
|
14636
14833
|
const { body } = parseFrontmatter2(content);
|
|
14637
14834
|
const chunks = [];
|
|
14638
14835
|
const sections = splitByHeaders(body);
|
|
@@ -14685,7 +14882,7 @@ var init_agent_memory_source = __esm({
|
|
|
14685
14882
|
fileToItem(filePath, filename, projectPath, _projectHash) {
|
|
14686
14883
|
try {
|
|
14687
14884
|
const stat3 = statSync21(filePath);
|
|
14688
|
-
const content =
|
|
14885
|
+
const content = readFileSync16(filePath, "utf-8");
|
|
14689
14886
|
const { fm } = parseFrontmatter2(content);
|
|
14690
14887
|
const stem = filename.replace(/\.md$/, "");
|
|
14691
14888
|
const idBase = fm.name || stem;
|
|
@@ -14900,7 +15097,7 @@ var init_history_source = __esm({
|
|
|
14900
15097
|
});
|
|
14901
15098
|
|
|
14902
15099
|
// ../engine/dist/parsers/paste-source.js
|
|
14903
|
-
import { existsSync as existsSync26, readdirSync as readdirSync19, readFileSync as
|
|
15100
|
+
import { existsSync as existsSync26, readdirSync as readdirSync19, readFileSync as readFileSync17, statSync as statSync23 } from "fs";
|
|
14904
15101
|
import { homedir as homedir11 } from "os";
|
|
14905
15102
|
import { join as join27, basename as basename16 } from "path";
|
|
14906
15103
|
var MAX_CHUNK_CHARS6, MAX_FILE_SIZE, PasteSource;
|
|
@@ -14956,7 +15153,7 @@ var init_paste_source = __esm({
|
|
|
14956
15153
|
if (stat3.size < 10)
|
|
14957
15154
|
continue;
|
|
14958
15155
|
const hash = basename16(file, ".txt");
|
|
14959
|
-
const content =
|
|
15156
|
+
const content = readFileSync17(filePath, "utf-8");
|
|
14960
15157
|
const firstLine = content.split("\n").find((l) => l.trim().length > 5)?.trim()?.slice(0, 100) || `Paste ${hash.slice(0, 8)}`;
|
|
14961
15158
|
yield {
|
|
14962
15159
|
id: hash,
|
|
@@ -14977,7 +15174,7 @@ var init_paste_source = __esm({
|
|
|
14977
15174
|
async parse(item) {
|
|
14978
15175
|
if (!existsSync26(item.filePath))
|
|
14979
15176
|
return [];
|
|
14980
|
-
const content =
|
|
15177
|
+
const content = readFileSync17(item.filePath, "utf-8");
|
|
14981
15178
|
if (content.trim().length < 20)
|
|
14982
15179
|
return [];
|
|
14983
15180
|
return [{
|
|
@@ -15000,7 +15197,7 @@ var init_paste_source = __esm({
|
|
|
15000
15197
|
});
|
|
15001
15198
|
|
|
15002
15199
|
// ../engine/dist/parsers/gemini-source.js
|
|
15003
|
-
import { existsSync as existsSync27, readdirSync as readdirSync20, readFileSync as
|
|
15200
|
+
import { existsSync as existsSync27, readdirSync as readdirSync20, readFileSync as readFileSync18, statSync as statSync24 } from "fs";
|
|
15004
15201
|
import { join as join28, basename as basename17 } from "path";
|
|
15005
15202
|
import { createHash as createHash10 } from "crypto";
|
|
15006
15203
|
function loadGeminiProjectMap2() {
|
|
@@ -15009,7 +15206,7 @@ function loadGeminiProjectMap2() {
|
|
|
15009
15206
|
if (!existsSync27(projectsPath))
|
|
15010
15207
|
return map;
|
|
15011
15208
|
try {
|
|
15012
|
-
const data = JSON.parse(
|
|
15209
|
+
const data = JSON.parse(readFileSync18(projectsPath, "utf-8"));
|
|
15013
15210
|
const projects = data.projects || {};
|
|
15014
15211
|
for (const [path] of Object.entries(projects)) {
|
|
15015
15212
|
const hash = createHash10("sha256").update(path).digest("hex");
|
|
@@ -15054,7 +15251,7 @@ var init_gemini_source = __esm({
|
|
|
15054
15251
|
const filePath = join28(chatsDir, file);
|
|
15055
15252
|
try {
|
|
15056
15253
|
const stat3 = statSync24(filePath);
|
|
15057
|
-
const content = JSON.parse(
|
|
15254
|
+
const content = JSON.parse(readFileSync18(filePath, "utf-8"));
|
|
15058
15255
|
const sessionId = content.sessionId || basename17(file, ".json");
|
|
15059
15256
|
if (seen.has(sessionId))
|
|
15060
15257
|
continue;
|
|
@@ -15135,7 +15332,7 @@ var init_gemini_source = __esm({
|
|
|
15135
15332
|
async parse(item) {
|
|
15136
15333
|
if (!existsSync27(item.filePath))
|
|
15137
15334
|
return [];
|
|
15138
|
-
const content = JSON.parse(
|
|
15335
|
+
const content = JSON.parse(readFileSync18(item.filePath, "utf-8"));
|
|
15139
15336
|
const messages = content.messages || [];
|
|
15140
15337
|
const chunks = [];
|
|
15141
15338
|
const getText = (m) => {
|
|
@@ -15183,7 +15380,7 @@ var init_gemini_source = __esm({
|
|
|
15183
15380
|
});
|
|
15184
15381
|
|
|
15185
15382
|
// ../engine/dist/parsers/gemini-brain-source.js
|
|
15186
|
-
import { existsSync as existsSync28, readdirSync as readdirSync21, readFileSync as
|
|
15383
|
+
import { existsSync as existsSync28, readdirSync as readdirSync21, readFileSync as readFileSync19, statSync as statSync25 } from "fs";
|
|
15187
15384
|
import { join as join29 } from "path";
|
|
15188
15385
|
var MAX_CHUNK_CHARS8, GeminiBrainSource;
|
|
15189
15386
|
var init_gemini_brain_source = __esm({
|
|
@@ -15216,14 +15413,14 @@ var init_gemini_brain_source = __esm({
|
|
|
15216
15413
|
const filePath = join29(sessionDir, file);
|
|
15217
15414
|
try {
|
|
15218
15415
|
const stat3 = statSync25(filePath);
|
|
15219
|
-
const content =
|
|
15416
|
+
const content = readFileSync19(filePath, "utf-8");
|
|
15220
15417
|
const firstLine = content.split("\n").find((l) => l.trim() && !l.startsWith("#"))?.trim() || "";
|
|
15221
15418
|
const heading = content.split("\n").find((l) => l.startsWith("#"))?.replace(/^#+\s*/, "").trim() || file;
|
|
15222
15419
|
const metaPath = `${filePath}.metadata.json`;
|
|
15223
15420
|
let metaSummary = "";
|
|
15224
15421
|
if (existsSync28(metaPath)) {
|
|
15225
15422
|
try {
|
|
15226
|
-
const meta = JSON.parse(
|
|
15423
|
+
const meta = JSON.parse(readFileSync19(metaPath, "utf-8"));
|
|
15227
15424
|
metaSummary = meta.summary || "";
|
|
15228
15425
|
} catch {
|
|
15229
15426
|
}
|
|
@@ -15254,7 +15451,7 @@ var init_gemini_brain_source = __esm({
|
|
|
15254
15451
|
async parse(item) {
|
|
15255
15452
|
if (!existsSync28(item.filePath))
|
|
15256
15453
|
return [];
|
|
15257
|
-
const content =
|
|
15454
|
+
const content = readFileSync19(item.filePath, "utf-8");
|
|
15258
15455
|
const chunks = [];
|
|
15259
15456
|
const sections = splitByHeaders(content);
|
|
15260
15457
|
for (let i = 0; i < sections.length; i++) {
|
|
@@ -15597,7 +15794,7 @@ var init_opencode_todo_source = __esm({
|
|
|
15597
15794
|
});
|
|
15598
15795
|
|
|
15599
15796
|
// ../engine/dist/parsers/codex-session-source.js
|
|
15600
|
-
import { existsSync as existsSync31, readdirSync as readdirSync22, readFileSync as
|
|
15797
|
+
import { existsSync as existsSync31, readdirSync as readdirSync22, readFileSync as readFileSync20, statSync as statSync26 } from "fs";
|
|
15601
15798
|
import { join as join30, basename as basename18 } from "path";
|
|
15602
15799
|
function getCodexSessionsDir() {
|
|
15603
15800
|
return codexBackend.sessionsDir();
|
|
@@ -15625,7 +15822,7 @@ function extractReasoningText(event) {
|
|
|
15625
15822
|
return "";
|
|
15626
15823
|
}
|
|
15627
15824
|
function readJsonlLines(filePath) {
|
|
15628
|
-
const text =
|
|
15825
|
+
const text = readFileSync20(filePath, "utf-8");
|
|
15629
15826
|
const lines = text.split("\n");
|
|
15630
15827
|
const events = [];
|
|
15631
15828
|
for (const line of lines) {
|
|
@@ -15660,7 +15857,7 @@ var init_codex_session_source = __esm({
|
|
|
15660
15857
|
for (const filePath of jsonlFiles) {
|
|
15661
15858
|
try {
|
|
15662
15859
|
const stat3 = statSync26(filePath);
|
|
15663
|
-
const lines =
|
|
15860
|
+
const lines = readFileSync20(filePath, "utf-8").split("\n");
|
|
15664
15861
|
const firstLine = lines.find((l) => l.trim());
|
|
15665
15862
|
if (!firstLine)
|
|
15666
15863
|
continue;
|
|
@@ -15833,7 +16030,7 @@ var init_codex_session_source = __esm({
|
|
|
15833
16030
|
});
|
|
15834
16031
|
|
|
15835
16032
|
// ../engine/dist/parsers/diary-source.js
|
|
15836
|
-
import { existsSync as existsSync32, mkdirSync as mkdirSync6, readdirSync as readdirSync23, readFileSync as
|
|
16033
|
+
import { existsSync as existsSync32, mkdirSync as mkdirSync6, readdirSync as readdirSync23, readFileSync as readFileSync21, writeFileSync as writeFileSync4, statSync as statSync27 } from "fs";
|
|
15837
16034
|
import { join as join31, basename as basename19 } from "path";
|
|
15838
16035
|
var MAX_CHUNK_CHARS11, DiarySource;
|
|
15839
16036
|
var init_diary_source = __esm({
|
|
@@ -15859,7 +16056,7 @@ var init_diary_source = __esm({
|
|
|
15859
16056
|
const filePath = join31(agentPath, file);
|
|
15860
16057
|
try {
|
|
15861
16058
|
const stat3 = statSync27(filePath);
|
|
15862
|
-
const raw =
|
|
16059
|
+
const raw = readFileSync21(filePath, "utf-8");
|
|
15863
16060
|
const entry = JSON.parse(raw);
|
|
15864
16061
|
const entryId = basename19(file, ".json");
|
|
15865
16062
|
const title = `[${entry.agent}] ${entry.topic}: ${entry.content.slice(0, 80)}`;
|
|
@@ -15886,7 +16083,7 @@ var init_diary_source = __esm({
|
|
|
15886
16083
|
async parse(item) {
|
|
15887
16084
|
if (!existsSync32(item.filePath))
|
|
15888
16085
|
return [];
|
|
15889
|
-
const raw =
|
|
16086
|
+
const raw = readFileSync21(item.filePath, "utf-8");
|
|
15890
16087
|
const entry = JSON.parse(raw);
|
|
15891
16088
|
if (!entry.content || entry.content.trim().length < 10)
|
|
15892
16089
|
return [];
|
|
@@ -15949,7 +16146,7 @@ var init_diary_source = __esm({
|
|
|
15949
16146
|
const entries = [];
|
|
15950
16147
|
for (const file of files) {
|
|
15951
16148
|
try {
|
|
15952
|
-
const raw =
|
|
16149
|
+
const raw = readFileSync21(join31(agentDir, file), "utf-8");
|
|
15953
16150
|
entries.push(JSON.parse(raw));
|
|
15954
16151
|
} catch {
|
|
15955
16152
|
continue;
|
|
@@ -15962,7 +16159,7 @@ var init_diary_source = __esm({
|
|
|
15962
16159
|
});
|
|
15963
16160
|
|
|
15964
16161
|
// ../engine/dist/parsers/skills-source.js
|
|
15965
|
-
import { existsSync as existsSync33, readdirSync as readdirSync24, readFileSync as
|
|
16162
|
+
import { existsSync as existsSync33, readdirSync as readdirSync24, readFileSync as readFileSync22, statSync as statSync28 } from "fs";
|
|
15966
16163
|
import { homedir as homedir12 } from "os";
|
|
15967
16164
|
import { join as join32 } from "path";
|
|
15968
16165
|
function resolveRoots() {
|
|
@@ -16055,7 +16252,7 @@ var init_skills_source = __esm({
|
|
|
16055
16252
|
continue;
|
|
16056
16253
|
let content;
|
|
16057
16254
|
try {
|
|
16058
|
-
content =
|
|
16255
|
+
content = readFileSync22(skillMd, "utf-8");
|
|
16059
16256
|
} catch {
|
|
16060
16257
|
continue;
|
|
16061
16258
|
}
|
|
@@ -16115,7 +16312,7 @@ var init_skills_source = __esm({
|
|
|
16115
16312
|
async parse(item) {
|
|
16116
16313
|
if (!existsSync33(item.filePath))
|
|
16117
16314
|
return [];
|
|
16118
|
-
const content =
|
|
16315
|
+
const content = readFileSync22(item.filePath, "utf-8");
|
|
16119
16316
|
if (!content.trim())
|
|
16120
16317
|
return [];
|
|
16121
16318
|
return [{
|
|
@@ -16138,14 +16335,14 @@ var init_skills_source = __esm({
|
|
|
16138
16335
|
});
|
|
16139
16336
|
|
|
16140
16337
|
// ../engine/dist/parsers/mcps-source.js
|
|
16141
|
-
import { existsSync as existsSync34, readdirSync as readdirSync25, readFileSync as
|
|
16338
|
+
import { existsSync as existsSync34, readdirSync as readdirSync25, readFileSync as readFileSync23, statSync as statSync29 } from "fs";
|
|
16142
16339
|
import { homedir as homedir13 } from "os";
|
|
16143
16340
|
import { join as join33 } from "path";
|
|
16144
16341
|
function readJson(path) {
|
|
16145
16342
|
if (!existsSync34(path))
|
|
16146
16343
|
return null;
|
|
16147
16344
|
try {
|
|
16148
|
-
const raw =
|
|
16345
|
+
const raw = readFileSync23(path, "utf-8");
|
|
16149
16346
|
const stripped = path.endsWith(".jsonc") ? raw.replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|[^:])\/\/.*$/gm, "$1").replace(/,(\s*[}\]])/g, "$1") : raw;
|
|
16150
16347
|
return JSON.parse(stripped);
|
|
16151
16348
|
} catch {
|
|
@@ -16258,7 +16455,7 @@ var init_mcps_source = __esm({
|
|
|
16258
16455
|
return;
|
|
16259
16456
|
let content;
|
|
16260
16457
|
try {
|
|
16261
|
-
content =
|
|
16458
|
+
content = readFileSync23(path, "utf-8");
|
|
16262
16459
|
} catch {
|
|
16263
16460
|
return;
|
|
16264
16461
|
}
|
|
@@ -16410,7 +16607,7 @@ var init_toolkit_format = __esm({
|
|
|
16410
16607
|
});
|
|
16411
16608
|
|
|
16412
16609
|
// ../engine/dist/parsers/slash-commands-source.js
|
|
16413
|
-
import { existsSync as existsSync35, readdirSync as readdirSync26, readFileSync as
|
|
16610
|
+
import { existsSync as existsSync35, readdirSync as readdirSync26, readFileSync as readFileSync24, statSync as statSync30 } from "fs";
|
|
16414
16611
|
import { join as join34, basename as basename20 } from "path";
|
|
16415
16612
|
function parseCommand(content, fallbackName, format) {
|
|
16416
16613
|
if (format === "toml") {
|
|
@@ -16438,6 +16635,7 @@ var init_slash_commands_source = __esm({
|
|
|
16438
16635
|
init_codex2();
|
|
16439
16636
|
init_settings();
|
|
16440
16637
|
init_toolkit_format();
|
|
16638
|
+
init_project_dir_name();
|
|
16441
16639
|
MAX_CHUNK_CHARS13 = 2e3;
|
|
16442
16640
|
SlashCommandsSource = class {
|
|
16443
16641
|
sourceType = "command";
|
|
@@ -16451,7 +16649,7 @@ var init_slash_commands_source = __esm({
|
|
|
16451
16649
|
for (const entry of readdirSync26(projectsRoot, { withFileTypes: true })) {
|
|
16452
16650
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
16453
16651
|
continue;
|
|
16454
|
-
const projectPath = entry.name
|
|
16652
|
+
const projectPath = decodeProjectDirName(entry.name);
|
|
16455
16653
|
const cmdDir = join34(projectPath, ".claude", "commands");
|
|
16456
16654
|
if (existsSync35(cmdDir))
|
|
16457
16655
|
roots.push({ path: cmdDir, tool: "claude", scope: "project", projectPath, format: "md" });
|
|
@@ -16484,7 +16682,7 @@ var init_slash_commands_source = __esm({
|
|
|
16484
16682
|
const filePath = join34(root.path, file);
|
|
16485
16683
|
try {
|
|
16486
16684
|
const stat3 = statSync30(filePath);
|
|
16487
|
-
const content =
|
|
16685
|
+
const content = readFileSync24(filePath, "utf-8");
|
|
16488
16686
|
const parsed = parseCommand(content, basename20(file, ext), root.format);
|
|
16489
16687
|
yield {
|
|
16490
16688
|
id: `${root.tool}_cmd_${root.scope}_${parsed.name}`,
|
|
@@ -16510,7 +16708,7 @@ var init_slash_commands_source = __esm({
|
|
|
16510
16708
|
async parse(item) {
|
|
16511
16709
|
if (!existsSync35(item.filePath))
|
|
16512
16710
|
return [];
|
|
16513
|
-
const content =
|
|
16711
|
+
const content = readFileSync24(item.filePath, "utf-8");
|
|
16514
16712
|
if (!content.trim())
|
|
16515
16713
|
return [];
|
|
16516
16714
|
return [{
|
|
@@ -16533,7 +16731,7 @@ var init_slash_commands_source = __esm({
|
|
|
16533
16731
|
});
|
|
16534
16732
|
|
|
16535
16733
|
// ../engine/dist/parsers/subagents-source.js
|
|
16536
|
-
import { existsSync as existsSync36, readdirSync as readdirSync27, readFileSync as
|
|
16734
|
+
import { existsSync as existsSync36, readdirSync as readdirSync27, readFileSync as readFileSync25, statSync as statSync31 } from "fs";
|
|
16537
16735
|
import { join as join35, basename as basename21 } from "path";
|
|
16538
16736
|
function parseAgent(content, fallbackName, format) {
|
|
16539
16737
|
if (format === "toml") {
|
|
@@ -16563,6 +16761,7 @@ var init_subagents_source = __esm({
|
|
|
16563
16761
|
init_codex2();
|
|
16564
16762
|
init_settings();
|
|
16565
16763
|
init_toolkit_format();
|
|
16764
|
+
init_project_dir_name();
|
|
16566
16765
|
MAX_CHUNK_CHARS14 = 2e3;
|
|
16567
16766
|
SubagentsSource = class {
|
|
16568
16767
|
sourceType = "agent";
|
|
@@ -16576,7 +16775,7 @@ var init_subagents_source = __esm({
|
|
|
16576
16775
|
for (const entry of readdirSync27(projectsRoot, { withFileTypes: true })) {
|
|
16577
16776
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
16578
16777
|
continue;
|
|
16579
|
-
const projectPath = entry.name
|
|
16778
|
+
const projectPath = decodeProjectDirName(entry.name);
|
|
16580
16779
|
const agentDir = join35(projectPath, ".claude", "agents");
|
|
16581
16780
|
if (existsSync36(agentDir))
|
|
16582
16781
|
roots.push({ path: agentDir, tool: "claude", scope: "project", projectPath, format: "md" });
|
|
@@ -16609,7 +16808,7 @@ var init_subagents_source = __esm({
|
|
|
16609
16808
|
const filePath = join35(root.path, file);
|
|
16610
16809
|
try {
|
|
16611
16810
|
const stat3 = statSync31(filePath);
|
|
16612
|
-
const content =
|
|
16811
|
+
const content = readFileSync25(filePath, "utf-8");
|
|
16613
16812
|
const parsed = parseAgent(content, basename21(file, ext), root.format);
|
|
16614
16813
|
yield {
|
|
16615
16814
|
id: `${root.tool}_agent_${root.scope}_${parsed.name}`,
|
|
@@ -16636,7 +16835,7 @@ var init_subagents_source = __esm({
|
|
|
16636
16835
|
async parse(item) {
|
|
16637
16836
|
if (!existsSync36(item.filePath))
|
|
16638
16837
|
return [];
|
|
16639
|
-
const content =
|
|
16838
|
+
const content = readFileSync25(item.filePath, "utf-8");
|
|
16640
16839
|
if (!content.trim())
|
|
16641
16840
|
return [];
|
|
16642
16841
|
return [{
|
|
@@ -16659,13 +16858,13 @@ var init_subagents_source = __esm({
|
|
|
16659
16858
|
});
|
|
16660
16859
|
|
|
16661
16860
|
// ../engine/dist/parsers/hooks-source.js
|
|
16662
|
-
import { existsSync as existsSync37, readFileSync as
|
|
16861
|
+
import { existsSync as existsSync37, readFileSync as readFileSync26, readdirSync as readdirSync28, statSync as statSync32 } from "fs";
|
|
16663
16862
|
import { join as join36 } from "path";
|
|
16664
16863
|
function readJson2(path) {
|
|
16665
16864
|
if (!existsSync37(path))
|
|
16666
16865
|
return null;
|
|
16667
16866
|
try {
|
|
16668
|
-
return JSON.parse(
|
|
16867
|
+
return JSON.parse(readFileSync26(path, "utf-8"));
|
|
16669
16868
|
} catch {
|
|
16670
16869
|
return null;
|
|
16671
16870
|
}
|
|
@@ -16676,6 +16875,7 @@ var init_hooks_source = __esm({
|
|
|
16676
16875
|
"use strict";
|
|
16677
16876
|
init_claude2();
|
|
16678
16877
|
init_settings();
|
|
16878
|
+
init_project_dir_name();
|
|
16679
16879
|
HooksSource = class {
|
|
16680
16880
|
sourceType = "hook";
|
|
16681
16881
|
async *discover() {
|
|
@@ -16688,7 +16888,7 @@ var init_hooks_source = __esm({
|
|
|
16688
16888
|
for (const entry of readdirSync28(projectsRoot, { withFileTypes: true })) {
|
|
16689
16889
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
16690
16890
|
continue;
|
|
16691
|
-
const projectPath = entry.name
|
|
16891
|
+
const projectPath = decodeProjectDirName(entry.name);
|
|
16692
16892
|
const settingsPath2 = join36(projectPath, ".claude", "settings.json");
|
|
16693
16893
|
if (existsSync37(settingsPath2)) {
|
|
16694
16894
|
yield* this.fromSettings(settingsPath2, "project", projectPath);
|
|
@@ -16781,14 +16981,14 @@ var init_hooks_source = __esm({
|
|
|
16781
16981
|
});
|
|
16782
16982
|
|
|
16783
16983
|
// ../engine/dist/parsers/plugins-source.js
|
|
16784
|
-
import { existsSync as existsSync38, readFileSync as
|
|
16984
|
+
import { existsSync as existsSync38, readFileSync as readFileSync27, readdirSync as readdirSync29, statSync as statSync33 } from "fs";
|
|
16785
16985
|
import { homedir as homedir14 } from "os";
|
|
16786
16986
|
import { join as join37 } from "path";
|
|
16787
16987
|
function readJson3(path) {
|
|
16788
16988
|
if (!existsSync38(path))
|
|
16789
16989
|
return null;
|
|
16790
16990
|
try {
|
|
16791
|
-
return JSON.parse(
|
|
16991
|
+
return JSON.parse(readFileSync27(path, "utf-8"));
|
|
16792
16992
|
} catch {
|
|
16793
16993
|
return null;
|
|
16794
16994
|
}
|
|
@@ -17045,7 +17245,7 @@ var init_extractor_version = __esm({
|
|
|
17045
17245
|
});
|
|
17046
17246
|
|
|
17047
17247
|
// src/sync-ledger.ts
|
|
17048
|
-
import { readFileSync as
|
|
17248
|
+
import { readFileSync as readFileSync28, writeFileSync as writeFileSync5, renameSync as renameSync4, mkdirSync as mkdirSync7 } from "node:fs";
|
|
17049
17249
|
import { join as join38, dirname as dirname14 } from "node:path";
|
|
17050
17250
|
function toRow(entry) {
|
|
17051
17251
|
if (entry === void 0) return void 0;
|
|
@@ -17054,24 +17254,77 @@ function toRow(entry) {
|
|
|
17054
17254
|
function load() {
|
|
17055
17255
|
if (cache3) return cache3;
|
|
17056
17256
|
try {
|
|
17057
|
-
const parsed = JSON.parse(
|
|
17257
|
+
const parsed = JSON.parse(readFileSync28(ledgerPath(), "utf-8"));
|
|
17058
17258
|
cache3 = parsed && typeof parsed === "object" ? parsed : {};
|
|
17059
17259
|
} catch {
|
|
17060
17260
|
cache3 = {};
|
|
17061
17261
|
}
|
|
17062
17262
|
return cache3;
|
|
17063
17263
|
}
|
|
17064
|
-
function
|
|
17264
|
+
function persistNow(data) {
|
|
17065
17265
|
const path = ledgerPath();
|
|
17066
17266
|
mkdirSync7(dirname14(path), { recursive: true });
|
|
17067
17267
|
const tmp = `${path}.tmp`;
|
|
17068
17268
|
writeFileSync5(tmp, JSON.stringify(data));
|
|
17069
17269
|
renameSync4(tmp, path);
|
|
17270
|
+
pendingWrite = false;
|
|
17271
|
+
}
|
|
17272
|
+
function persist(data) {
|
|
17273
|
+
pendingWrite = true;
|
|
17274
|
+
if (flushTimer) return;
|
|
17275
|
+
flushTimer = setTimeout(() => {
|
|
17276
|
+
flushTimer = null;
|
|
17277
|
+
if (pendingWrite) {
|
|
17278
|
+
try {
|
|
17279
|
+
persistNow(data);
|
|
17280
|
+
} catch {
|
|
17281
|
+
}
|
|
17282
|
+
}
|
|
17283
|
+
}, LEDGER_FLUSH_MS);
|
|
17284
|
+
flushTimer.unref?.();
|
|
17285
|
+
}
|
|
17286
|
+
function pruneLedgerTargets(configuredServers) {
|
|
17287
|
+
const data = load();
|
|
17288
|
+
const keep = new Set(configuredServers);
|
|
17289
|
+
const orphans = {};
|
|
17290
|
+
for (const server2 of Object.keys(data)) {
|
|
17291
|
+
if (!keep.has(server2)) {
|
|
17292
|
+
orphans[server2] = data[server2];
|
|
17293
|
+
delete data[server2];
|
|
17294
|
+
}
|
|
17295
|
+
}
|
|
17296
|
+
const names = Object.keys(orphans);
|
|
17297
|
+
if (names.length === 0) return 0;
|
|
17298
|
+
const path = ledgerPath();
|
|
17299
|
+
const side = `${path}.orphans.json`;
|
|
17300
|
+
try {
|
|
17301
|
+
let prior = {};
|
|
17302
|
+
try {
|
|
17303
|
+
prior = JSON.parse(readFileSync28(side, "utf-8"));
|
|
17304
|
+
} catch {
|
|
17305
|
+
}
|
|
17306
|
+
writeFileSync5(side, JSON.stringify({ ...prior, ...orphans }));
|
|
17307
|
+
} catch {
|
|
17308
|
+
for (const n of names) data[n] = orphans[n];
|
|
17309
|
+
return 0;
|
|
17310
|
+
}
|
|
17311
|
+
const rows = names.reduce((n, s) => n + Object.keys(orphans[s]).length, 0);
|
|
17312
|
+
console.error(`[sync] ledger: parked ${rows} row(s) for ${names.length} server(s) no longer configured (${names.join(", ")}) in ${side}`);
|
|
17313
|
+
persistNow(data);
|
|
17314
|
+
return names.length;
|
|
17315
|
+
}
|
|
17316
|
+
function flushLedger() {
|
|
17317
|
+
if (flushTimer) {
|
|
17318
|
+
clearTimeout(flushTimer);
|
|
17319
|
+
flushTimer = null;
|
|
17320
|
+
}
|
|
17321
|
+
if (!pendingWrite || !cache3) return;
|
|
17322
|
+
persistNow(cache3);
|
|
17070
17323
|
}
|
|
17071
17324
|
function loadItemVersionsAll() {
|
|
17072
17325
|
if (itemVersionsCache) return itemVersionsCache;
|
|
17073
17326
|
try {
|
|
17074
|
-
const parsed = JSON.parse(
|
|
17327
|
+
const parsed = JSON.parse(readFileSync28(itemVersionsPath(), "utf-8"));
|
|
17075
17328
|
itemVersionsCache = parsed && typeof parsed === "object" ? parsed : {};
|
|
17076
17329
|
} catch {
|
|
17077
17330
|
itemVersionsCache = {};
|
|
@@ -17153,7 +17406,7 @@ function markFieldCoverage(server2, field, rows) {
|
|
|
17153
17406
|
function loadReconcile() {
|
|
17154
17407
|
if (reconcileCache) return reconcileCache;
|
|
17155
17408
|
try {
|
|
17156
|
-
const parsed = JSON.parse(
|
|
17409
|
+
const parsed = JSON.parse(readFileSync28(reconcilePath(), "utf-8"));
|
|
17157
17410
|
reconcileCache = parsed && typeof parsed === "object" ? parsed : {};
|
|
17158
17411
|
} catch {
|
|
17159
17412
|
reconcileCache = {};
|
|
@@ -17201,7 +17454,7 @@ function syncMode(row, mtime, fileSize, extractorVersion, isAppendOnly) {
|
|
|
17201
17454
|
if (row.m >= Math.floor(mtime)) return "skip";
|
|
17202
17455
|
return "full";
|
|
17203
17456
|
}
|
|
17204
|
-
var ledgerPath, cache3, itemVersionsPath, itemVersionsCache, unackedCursorAttempts, reconcilePath, reconcileCache;
|
|
17457
|
+
var ledgerPath, cache3, LEDGER_FLUSH_MS, pendingWrite, flushTimer, itemVersionsPath, itemVersionsCache, unackedCursorAttempts, reconcilePath, reconcileCache;
|
|
17205
17458
|
var init_sync_ledger = __esm({
|
|
17206
17459
|
"src/sync-ledger.ts"() {
|
|
17207
17460
|
"use strict";
|
|
@@ -17209,6 +17462,9 @@ var init_sync_ledger = __esm({
|
|
|
17209
17462
|
init_extractor_version();
|
|
17210
17463
|
ledgerPath = () => join38(getDataDir(), "sync-ledger.json");
|
|
17211
17464
|
cache3 = null;
|
|
17465
|
+
LEDGER_FLUSH_MS = 2e3;
|
|
17466
|
+
pendingWrite = false;
|
|
17467
|
+
flushTimer = null;
|
|
17212
17468
|
itemVersionsPath = () => join38(getDataDir(), "item-versions.json");
|
|
17213
17469
|
itemVersionsCache = null;
|
|
17214
17470
|
unackedCursorAttempts = 0;
|
|
@@ -17243,7 +17499,7 @@ var init_sync_fields = __esm({
|
|
|
17243
17499
|
});
|
|
17244
17500
|
|
|
17245
17501
|
// ../engine/dist/core/index-lock.js
|
|
17246
|
-
import { existsSync as existsSync39, mkdirSync as mkdirSync8, openSync as
|
|
17502
|
+
import { existsSync as existsSync39, mkdirSync as mkdirSync8, openSync as openSync8, writeFileSync as writeFileSync6, readFileSync as readFileSync29, rmSync as rmSync4, statSync as statSync34, closeSync as closeSync8 } from "fs";
|
|
17247
17503
|
import { dirname as dirname15, join as join39 } from "path";
|
|
17248
17504
|
function acquireIndexLock(opts) {
|
|
17249
17505
|
const lockPath = lockFilePath();
|
|
@@ -17255,7 +17511,7 @@ function acquireIndexLock(opts) {
|
|
|
17255
17511
|
}
|
|
17256
17512
|
let fd;
|
|
17257
17513
|
try {
|
|
17258
|
-
fd =
|
|
17514
|
+
fd = openSync8(lockPath, "wx", 384);
|
|
17259
17515
|
} catch (err) {
|
|
17260
17516
|
if (err.code === "EEXIST")
|
|
17261
17517
|
return null;
|
|
@@ -17265,7 +17521,7 @@ function acquireIndexLock(opts) {
|
|
|
17265
17521
|
try {
|
|
17266
17522
|
writeFileSync6(fd, JSON.stringify(holder));
|
|
17267
17523
|
} finally {
|
|
17268
|
-
|
|
17524
|
+
closeSync8(fd);
|
|
17269
17525
|
}
|
|
17270
17526
|
let released = false;
|
|
17271
17527
|
return {
|
|
@@ -17275,7 +17531,7 @@ function acquireIndexLock(opts) {
|
|
|
17275
17531
|
return;
|
|
17276
17532
|
released = true;
|
|
17277
17533
|
try {
|
|
17278
|
-
const current = JSON.parse(
|
|
17534
|
+
const current = JSON.parse(readFileSync29(lockPath, "utf-8"));
|
|
17279
17535
|
if (current.pid !== holder.pid || current.startedAt !== holder.startedAt)
|
|
17280
17536
|
return;
|
|
17281
17537
|
} catch {
|
|
@@ -17297,7 +17553,7 @@ function stealStaleLock(lockPath, staleAfterMs) {
|
|
|
17297
17553
|
const age = Date.now() - s.mtimeMs;
|
|
17298
17554
|
let payload;
|
|
17299
17555
|
try {
|
|
17300
|
-
payload = JSON.parse(
|
|
17556
|
+
payload = JSON.parse(readFileSync29(lockPath, "utf-8"));
|
|
17301
17557
|
} catch {
|
|
17302
17558
|
rmSync4(lockPath, { force: true });
|
|
17303
17559
|
return true;
|
|
@@ -17335,7 +17591,10 @@ var init_index_lock = __esm({
|
|
|
17335
17591
|
});
|
|
17336
17592
|
|
|
17337
17593
|
// src/http.ts
|
|
17338
|
-
import { readFileSync as
|
|
17594
|
+
import { readFileSync as readFileSync30 } from "node:fs";
|
|
17595
|
+
function cliVersion() {
|
|
17596
|
+
return CLI_VERSION;
|
|
17597
|
+
}
|
|
17339
17598
|
function clientHeaders() {
|
|
17340
17599
|
return {
|
|
17341
17600
|
"x-chat-recall-cli": CLI_VERSION,
|
|
@@ -17353,10 +17612,10 @@ var init_http = __esm({
|
|
|
17353
17612
|
"use strict";
|
|
17354
17613
|
CLI_VERSION = "0.0.0";
|
|
17355
17614
|
try {
|
|
17356
|
-
CLI_VERSION = JSON.parse(
|
|
17615
|
+
CLI_VERSION = JSON.parse(readFileSync30(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
|
|
17357
17616
|
} catch {
|
|
17358
17617
|
try {
|
|
17359
|
-
if (true) CLI_VERSION = "0.5.
|
|
17618
|
+
if (true) CLI_VERSION = "0.5.6";
|
|
17360
17619
|
} catch {
|
|
17361
17620
|
}
|
|
17362
17621
|
}
|
|
@@ -17480,6 +17739,7 @@ var sync_client_exports = {};
|
|
|
17480
17739
|
__export(sync_client_exports, {
|
|
17481
17740
|
BATCH_SCAN_MAX_BYTES: () => BATCH_SCAN_MAX_BYTES,
|
|
17482
17741
|
FULL_BUILD_MAX_BYTES: () => FULL_BUILD_MAX_BYTES,
|
|
17742
|
+
_resetCapsCacheForTests: () => _resetCapsCacheForTests,
|
|
17483
17743
|
_resetTenantSecurityConfigCache: () => _resetTenantSecurityConfigCache,
|
|
17484
17744
|
_resetTenantSyncConfigCache: () => _resetTenantSyncConfigCache,
|
|
17485
17745
|
batchScanExternal: () => batchScanExternal,
|
|
@@ -17497,7 +17757,7 @@ __export(sync_client_exports, {
|
|
|
17497
17757
|
syncSessions: () => syncSessions
|
|
17498
17758
|
});
|
|
17499
17759
|
import { join as join41, dirname as dirname16, basename as basename22 } from "node:path";
|
|
17500
|
-
import { readFileSync as
|
|
17760
|
+
import { readFileSync as readFileSync31, writeFileSync as writeFileSync8, mkdirSync as mkdirSync9, mkdtempSync as mkdtempSync4, rmSync as rmSync5, chmodSync as chmodSync4, unlinkSync as unlinkSync2, readdirSync as readdirSync30, statSync as statSync35 } from "node:fs";
|
|
17501
17761
|
import { tmpdir as tmpdir3, hostname } from "node:os";
|
|
17502
17762
|
import { createHash as createHash12 } from "node:crypto";
|
|
17503
17763
|
import { fileURLToPath } from "node:url";
|
|
@@ -17519,8 +17779,10 @@ function saveCredentials(c) {
|
|
|
17519
17779
|
}
|
|
17520
17780
|
}
|
|
17521
17781
|
function loadAllCredentials() {
|
|
17782
|
+
const fromEnv = envCredentials();
|
|
17783
|
+
if (fromEnv) return [{ serverUrl: fromEnv.serverUrl, token: fromEnv.token }];
|
|
17522
17784
|
try {
|
|
17523
|
-
const parsed = JSON.parse(
|
|
17785
|
+
const parsed = JSON.parse(readFileSync31(credPath(), "utf-8"));
|
|
17524
17786
|
if (Array.isArray(parsed?.targets)) return parsed.targets.filter((t) => t?.serverUrl).map((t) => ({ serverUrl: t.serverUrl, token: t.token || "" }));
|
|
17525
17787
|
if (parsed?.serverUrl) return [{ serverUrl: parsed.serverUrl, token: parsed.token || "" }];
|
|
17526
17788
|
} catch {
|
|
@@ -17679,6 +17941,10 @@ function isLocalHost(serverUrl) {
|
|
|
17679
17941
|
async function syncSessions(opts = {}) {
|
|
17680
17942
|
const targets = loadAllCredentials();
|
|
17681
17943
|
if (targets.length === 0) throw new Error("Not logged in \u2014 run `chat-recall login <server-url> --token <token>`");
|
|
17944
|
+
try {
|
|
17945
|
+
pruneLedgerTargets(targets.map((t) => t.serverUrl));
|
|
17946
|
+
} catch {
|
|
17947
|
+
}
|
|
17682
17948
|
let agg = null;
|
|
17683
17949
|
const errors = [];
|
|
17684
17950
|
for (const cred of targets) {
|
|
@@ -17701,6 +17967,7 @@ async function syncSessions(opts = {}) {
|
|
|
17701
17967
|
errors.push(`${cred.serverUrl}: ${e instanceof Error ? e.message : e}`);
|
|
17702
17968
|
}
|
|
17703
17969
|
}
|
|
17970
|
+
flushLedger();
|
|
17704
17971
|
if (!agg) throw new Error(`sync failed for all targets:
|
|
17705
17972
|
${errors.join("\n ")}`);
|
|
17706
17973
|
if (errors.length > 0) console.error(`[sync] ${errors.length} target(s) failed (others succeeded):
|
|
@@ -17726,11 +17993,11 @@ async function reconcileFieldsForTarget(cred, fullRefs, opts = {}) {
|
|
|
17726
17993
|
let pushed = 0, absent = 0, scanned = 0;
|
|
17727
17994
|
for (const field of SYNC_FIELDS) {
|
|
17728
17995
|
const needFull = !!opts.force || fieldNeedsFullPass(base, field);
|
|
17729
|
-
const
|
|
17996
|
+
const candidates2 = needFull ? fullRefs() : opts.convRefs ?? fullRefs();
|
|
17730
17997
|
const send = [];
|
|
17731
17998
|
const mtimeById = /* @__PURE__ */ new Map();
|
|
17732
17999
|
const absentIds = [];
|
|
17733
|
-
for (const ref of
|
|
18000
|
+
for (const ref of candidates2) {
|
|
17734
18001
|
if (!fieldNeedsScan(ledger.get(ref.prefixedId), field, ref.mtime, opts.force)) continue;
|
|
17735
18002
|
scanned++;
|
|
17736
18003
|
mtimeById.set(ref.prefixedId, ref.mtime);
|
|
@@ -17851,6 +18118,20 @@ function batchScanExternal(items, opts = {}) {
|
|
|
17851
18118
|
}
|
|
17852
18119
|
return { findings, scanned, slices, scanMs };
|
|
17853
18120
|
}
|
|
18121
|
+
function _resetCapsCacheForTests() {
|
|
18122
|
+
capsOk.clear();
|
|
18123
|
+
}
|
|
18124
|
+
async function verifyServerApi(serverUrl, minApi) {
|
|
18125
|
+
const base = serverUrl.replace(/\/$/, "");
|
|
18126
|
+
const seen = capsOk.get(base);
|
|
18127
|
+
if (seen !== void 0 && Date.now() - seen < CAPS_TTL_MS) return true;
|
|
18128
|
+
const caps = await fetchWithTimeout(`${base}/api/capabilities`).then((r) => r.json());
|
|
18129
|
+
if ((caps.apiVersion ?? 0) < minApi) {
|
|
18130
|
+
throw new Error(`server too old: apiVersion ${caps.apiVersion ?? "none"} < required ${minApi} \u2014 update the server image before syncing`);
|
|
18131
|
+
}
|
|
18132
|
+
capsOk.set(base, Date.now());
|
|
18133
|
+
return true;
|
|
18134
|
+
}
|
|
17854
18135
|
async function syncToTarget(cred, opts = {}) {
|
|
17855
18136
|
const sync = loadSettings().sync;
|
|
17856
18137
|
const serverCfg = await fetchTenantSyncConfig(cred);
|
|
@@ -17871,14 +18152,9 @@ async function syncToTarget(cred, opts = {}) {
|
|
|
17871
18152
|
return isProjectSyncable(r.source === "ignored" ? "" : r.id, projectPath, { syncMode: "only", syncOnly });
|
|
17872
18153
|
};
|
|
17873
18154
|
const MIN_SERVER_API = 2;
|
|
17874
|
-
|
|
17875
|
-
const
|
|
17876
|
-
if ((
|
|
17877
|
-
throw new Error(`server too old: apiVersion ${caps.apiVersion ?? "none"} < required ${MIN_SERVER_API} \u2014 update the server image before syncing`);
|
|
17878
|
-
}
|
|
17879
|
-
} catch (e) {
|
|
17880
|
-
if (e instanceof Error && e.message.startsWith("server too old")) throw e;
|
|
17881
|
-
throw new Error(`cannot verify server version (${e instanceof Error ? e.message : e}) \u2014 refusing to sync blind`);
|
|
18155
|
+
{
|
|
18156
|
+
const ok = await verifyServerApi(cred.serverUrl, MIN_SERVER_API);
|
|
18157
|
+
if (!ok) throw new Error(`cannot verify server version \u2014 refusing to sync blind`);
|
|
17882
18158
|
}
|
|
17883
18159
|
const { tenantRules, verifySecrets } = await fetchTenantSecurityConfig(cred);
|
|
17884
18160
|
const CHANGED_WALK_OVERLAP_MS = 15 * 6e4;
|
|
@@ -17935,8 +18211,11 @@ async function syncToTarget(cred, opts = {}) {
|
|
|
17935
18211
|
try {
|
|
17936
18212
|
const body2 = JSON.parse(text);
|
|
17937
18213
|
detail = body2.error ?? text;
|
|
18214
|
+
if (body2.detail) detail += `
|
|
18215
|
+
${body2.detail}`;
|
|
17938
18216
|
if (body2.resetsAt) detail += ` (resets ${new Date(body2.resetsAt).toISOString().slice(0, 10)})`;
|
|
17939
|
-
if (body2.upgradeUrl) detail += `
|
|
18217
|
+
if (body2.upgradeUrl) detail += `
|
|
18218
|
+
${body2.upgradeUrl}`;
|
|
17940
18219
|
} catch {
|
|
17941
18220
|
}
|
|
17942
18221
|
throw new Error(`sync paused by the server: ${detail}`);
|
|
@@ -18083,16 +18362,21 @@ async function syncToTarget(cred, opts = {}) {
|
|
|
18083
18362
|
const findingsBatch = makeBatcher("findings", 200, true);
|
|
18084
18363
|
const scanSecrets = isSecretScannerAvailable() && upload.findings && process.env.CHAT_RECALL_SCAN_SECRETS !== "0";
|
|
18085
18364
|
const verifySecretsScan = verifySecrets;
|
|
18365
|
+
let skipped = 0, redactions = 0, walked = 0;
|
|
18086
18366
|
const kgSeen = /* @__PURE__ */ new Set();
|
|
18087
18367
|
const kgEntityType = /* @__PURE__ */ new Map();
|
|
18088
|
-
const
|
|
18089
|
-
const
|
|
18368
|
+
const kgEntityNames = /* @__PURE__ */ new Set();
|
|
18369
|
+
const kgKey = (subject, predicate, object, validFrom) => createHash12("sha1").update(`${subject}|${predicate}|${object}|${validFrom}`).digest("hex").slice(0, 16);
|
|
18370
|
+
const accumulateKg = async (triples, sourceSession) => {
|
|
18090
18371
|
for (const t of triples) {
|
|
18091
|
-
const key =
|
|
18372
|
+
const key = kgKey(t.subject, t.predicate, t.object, t.validFrom ?? "");
|
|
18092
18373
|
if (kgSeen.has(key)) continue;
|
|
18093
18374
|
kgSeen.add(key);
|
|
18094
18375
|
if (t.predicate === "is_a" && !kgEntityType.has(t.subject)) kgEntityType.set(t.subject, t.object);
|
|
18095
|
-
|
|
18376
|
+
kgEntityNames.add(t.subject);
|
|
18377
|
+
kgEntityNames.add(t.object);
|
|
18378
|
+
const count = { redactions: 0 };
|
|
18379
|
+
await kgTripleBatch.add(redactDeep({
|
|
18096
18380
|
subject: t.subject,
|
|
18097
18381
|
predicate: t.predicate,
|
|
18098
18382
|
object: t.object,
|
|
@@ -18100,10 +18384,10 @@ async function syncToTarget(cred, opts = {}) {
|
|
|
18100
18384
|
valid_to: null,
|
|
18101
18385
|
confidence: t.confidence ?? 1,
|
|
18102
18386
|
source_session: sourceSession
|
|
18103
|
-
});
|
|
18387
|
+
}, count));
|
|
18388
|
+
redactions += count.redactions;
|
|
18104
18389
|
}
|
|
18105
18390
|
};
|
|
18106
|
-
let skipped = 0, redactions = 0, walked = 0;
|
|
18107
18391
|
let scanMs = 0, scanned = 0;
|
|
18108
18392
|
const slice = refs.slice(0, opts.limit ?? refs.length);
|
|
18109
18393
|
const trace = process.env.CHAT_RECALL_SYNC_TRACE === "1" ? (msg) => {
|
|
@@ -18236,7 +18520,7 @@ async function syncToTarget(cred, opts = {}) {
|
|
|
18236
18520
|
await convBatch.add(built.conv);
|
|
18237
18521
|
if (built.findings.length > 0) await findingsBatch.add(built.findings);
|
|
18238
18522
|
if (upload.sessionMeta) {
|
|
18239
|
-
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);
|
|
18523
|
+
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);
|
|
18240
18524
|
}
|
|
18241
18525
|
if (upload.sessionMeta && sessionFileBytes(ref) <= FULL_BUILD_MAX_BYTES) {
|
|
18242
18526
|
try {
|
|
@@ -18315,7 +18599,7 @@ async function syncToTarget(cred, opts = {}) {
|
|
|
18315
18599
|
chunks: redactedChunks
|
|
18316
18600
|
});
|
|
18317
18601
|
if (upload.sessionMeta && redactedChunks.length > 0) {
|
|
18318
|
-
accumulateKg(
|
|
18602
|
+
await accumulateKg(
|
|
18319
18603
|
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 }),
|
|
18320
18604
|
null
|
|
18321
18605
|
);
|
|
@@ -18340,16 +18624,8 @@ async function syncToTarget(cred, opts = {}) {
|
|
|
18340
18624
|
}
|
|
18341
18625
|
}
|
|
18342
18626
|
}
|
|
18343
|
-
if (upload.sessionMeta &&
|
|
18344
|
-
const
|
|
18345
|
-
for (const t of kgRows) {
|
|
18346
|
-
const count = { redactions: 0 };
|
|
18347
|
-
await kgTripleBatch.add(redactDeep(t, count));
|
|
18348
|
-
redactions += count.redactions;
|
|
18349
|
-
entityNames.add(t.subject);
|
|
18350
|
-
entityNames.add(t.object);
|
|
18351
|
-
}
|
|
18352
|
-
for (const name of entityNames) {
|
|
18627
|
+
if (upload.sessionMeta && kgEntityNames.size > 0) {
|
|
18628
|
+
for (const name of kgEntityNames) {
|
|
18353
18629
|
const count = { redactions: 0 };
|
|
18354
18630
|
await kgEntityBatch.add(redactDeep({ name, type: kgEntityType.get(name) ?? "unknown", properties: {} }, count));
|
|
18355
18631
|
redactions += count.redactions;
|
|
@@ -18709,56 +18985,58 @@ function collectDerived(ref, mtime, count) {
|
|
|
18709
18985
|
const id = ref.prefixedId;
|
|
18710
18986
|
const compute = [];
|
|
18711
18987
|
let fullOutcome = null;
|
|
18712
|
-
|
|
18713
|
-
|
|
18714
|
-
|
|
18715
|
-
|
|
18716
|
-
|
|
18717
|
-
|
|
18718
|
-
|
|
18719
|
-
|
|
18720
|
-
|
|
18721
|
-
|
|
18722
|
-
if (
|
|
18723
|
-
|
|
18724
|
-
|
|
18725
|
-
|
|
18726
|
-
|
|
18727
|
-
|
|
18728
|
-
|
|
18729
|
-
|
|
18730
|
-
|
|
18988
|
+
return withSessionReadCache(() => {
|
|
18989
|
+
for (const kind of COMPUTE_KINDS) {
|
|
18990
|
+
let data = null;
|
|
18991
|
+
try {
|
|
18992
|
+
if (kind === "diff") {
|
|
18993
|
+
const replay = replaySessionAny(id);
|
|
18994
|
+
if (replay.found) data = replay;
|
|
18995
|
+
} else if (kind === "outcome") {
|
|
18996
|
+
fullOutcome = computeOutcome(id);
|
|
18997
|
+
if (fullOutcome.found) data = fullOutcome;
|
|
18998
|
+
} else if (kind === "commits") {
|
|
18999
|
+
if (!fullOutcome) fullOutcome = computeOutcome(id);
|
|
19000
|
+
if (fullOutcome.found) data = fullOutcome.commits;
|
|
19001
|
+
} else if (kind === "markers") {
|
|
19002
|
+
const turns = extractTurnsAny(id, { maxTurns: 5e4 });
|
|
19003
|
+
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) }));
|
|
19004
|
+
data = { sessionId: id, prompts, summary: summarizeMarkers(prompts) };
|
|
19005
|
+
}
|
|
19006
|
+
} catch {
|
|
19007
|
+
data = null;
|
|
19008
|
+
}
|
|
19009
|
+
if (data === null) continue;
|
|
19010
|
+
const redacted = redactDeep(data, count);
|
|
19011
|
+
if (JSON.stringify(redacted).length > MAX_DERIVED_ROW_BYTES) continue;
|
|
19012
|
+
compute.push({ kind, mtime, data: redacted });
|
|
19013
|
+
}
|
|
19014
|
+
let outcomeRow = null;
|
|
19015
|
+
if (fullOutcome?.found) {
|
|
19016
|
+
outcomeRow = {
|
|
19017
|
+
sessionId: id,
|
|
19018
|
+
tool: ref.toolId,
|
|
19019
|
+
status: fullOutcome.status,
|
|
19020
|
+
reason: fullOutcome.reason,
|
|
19021
|
+
fileMtime: mtime,
|
|
19022
|
+
fileSize: 0,
|
|
19023
|
+
contentHash: "",
|
|
19024
|
+
fileCount: fullOutcome.fileCount,
|
|
19025
|
+
linesAdded: fullOutcome.totalLinesAdded,
|
|
19026
|
+
linesRemoved: fullOutcome.totalLinesRemoved,
|
|
19027
|
+
commits: fullOutcome.commits?.totalCommits ?? 0,
|
|
19028
|
+
isFull: true,
|
|
19029
|
+
classifiedAt: Date.now(),
|
|
19030
|
+
lastScannedOffset: 0
|
|
19031
|
+
};
|
|
18731
19032
|
}
|
|
18732
|
-
|
|
18733
|
-
|
|
18734
|
-
|
|
18735
|
-
|
|
18736
|
-
|
|
18737
|
-
let outcomeRow = null;
|
|
18738
|
-
if (fullOutcome?.found) {
|
|
18739
|
-
outcomeRow = {
|
|
18740
|
-
sessionId: id,
|
|
18741
|
-
tool: ref.toolId,
|
|
18742
|
-
status: fullOutcome.status,
|
|
18743
|
-
reason: fullOutcome.reason,
|
|
18744
|
-
fileMtime: mtime,
|
|
18745
|
-
fileSize: 0,
|
|
18746
|
-
contentHash: "",
|
|
18747
|
-
fileCount: fullOutcome.fileCount,
|
|
18748
|
-
linesAdded: fullOutcome.totalLinesAdded,
|
|
18749
|
-
linesRemoved: fullOutcome.totalLinesRemoved,
|
|
18750
|
-
commits: fullOutcome.commits?.totalCommits ?? 0,
|
|
18751
|
-
isFull: true,
|
|
18752
|
-
classifiedAt: Date.now(),
|
|
18753
|
-
lastScannedOffset: 0
|
|
19033
|
+
return {
|
|
19034
|
+
session_id: id,
|
|
19035
|
+
mtime,
|
|
19036
|
+
compute,
|
|
19037
|
+
outcome_row: outcomeRow ? redactDeep({ ...outcomeRow, sessionId: void 0 }, count) : null
|
|
18754
19038
|
};
|
|
18755
|
-
}
|
|
18756
|
-
return {
|
|
18757
|
-
session_id: id,
|
|
18758
|
-
mtime,
|
|
18759
|
-
compute,
|
|
18760
|
-
outcome_row: outcomeRow ? redactDeep({ ...outcomeRow, sessionId: void 0 }, count) : null
|
|
18761
|
-
};
|
|
19039
|
+
});
|
|
18762
19040
|
}
|
|
18763
19041
|
function isSyncSkip(r) {
|
|
18764
19042
|
return typeof r.skipped === "string";
|
|
@@ -18787,10 +19065,11 @@ async function syncIncremental(opts = {}) {
|
|
|
18787
19065
|
lock.release();
|
|
18788
19066
|
}
|
|
18789
19067
|
}
|
|
18790
|
-
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;
|
|
19068
|
+
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;
|
|
18791
19069
|
var init_sync_client = __esm({
|
|
18792
19070
|
"src/sync-client.ts"() {
|
|
18793
19071
|
"use strict";
|
|
19072
|
+
init_credentials_env();
|
|
18794
19073
|
init_secret_redactor();
|
|
18795
19074
|
init_source_discovery();
|
|
18796
19075
|
init_home_discovery();
|
|
@@ -18818,14 +19097,15 @@ var init_sync_client = __esm({
|
|
|
18818
19097
|
init_sync_fields();
|
|
18819
19098
|
init_index_lock();
|
|
18820
19099
|
init_http();
|
|
19100
|
+
init_live_session_scan();
|
|
18821
19101
|
init_backends();
|
|
18822
19102
|
ownVersion = "0.0.0";
|
|
18823
19103
|
try {
|
|
18824
19104
|
const dir = dirname16(fileURLToPath(import.meta.url));
|
|
18825
|
-
ownVersion = JSON.parse(
|
|
19105
|
+
ownVersion = JSON.parse(readFileSync31(join41(dir, "../package.json"), "utf-8")).version || ownVersion;
|
|
18826
19106
|
} catch {
|
|
18827
19107
|
try {
|
|
18828
|
-
if (true) ownVersion = "0.5.
|
|
19108
|
+
if (true) ownVersion = "0.5.6";
|
|
18829
19109
|
} catch {
|
|
18830
19110
|
}
|
|
18831
19111
|
}
|
|
@@ -18836,6 +19116,8 @@ var init_sync_client = __esm({
|
|
|
18836
19116
|
hashPath = (p) => p ? "p_" + createHash12("sha256").update(p).digest("hex").slice(0, 12) : "";
|
|
18837
19117
|
COMPUTE_KINDS = ["diff", "outcome", "commits", "markers"];
|
|
18838
19118
|
MAX_DERIVED_ROW_BYTES = 2 * 1024 * 1024;
|
|
19119
|
+
CAPS_TTL_MS = 60 * 6e4;
|
|
19120
|
+
capsOk = /* @__PURE__ */ new Map();
|
|
18839
19121
|
FULL_BUILD_MAX_BYTES = Math.max(8, parseInt(process.env.CHAT_RECALL_FULL_BUILD_MAX_MB || "64", 10)) * 1024 * 1024;
|
|
18840
19122
|
FULL_BUILD_TAIL_BYTES = 16 * 1024 * 1024;
|
|
18841
19123
|
BATCH_SCAN_MAX_BYTES = Math.max(1, parseInt(process.env.CHAT_RECALL_BATCHSCAN_MAX_MB || "64", 10)) * 1024 * 1024;
|
|
@@ -18848,7 +19130,7 @@ __export(client_events_exports, {
|
|
|
18848
19130
|
isTelemetryEnabled: () => isTelemetryEnabled,
|
|
18849
19131
|
reportClientEvent: () => reportClientEvent
|
|
18850
19132
|
});
|
|
18851
|
-
import { readFileSync as
|
|
19133
|
+
import { readFileSync as readFileSync32 } from "node:fs";
|
|
18852
19134
|
function scrub(msg) {
|
|
18853
19135
|
if (!msg) return "";
|
|
18854
19136
|
const noHome = msg.replace(/\/(?:home|Users)\/[^/\s]+/g, "~");
|
|
@@ -18901,29 +19183,186 @@ var init_client_events = __esm({
|
|
|
18901
19183
|
init_secret_redactor();
|
|
18902
19184
|
CLI_VERSION2 = "0.0.0";
|
|
18903
19185
|
try {
|
|
18904
|
-
CLI_VERSION2 = JSON.parse(
|
|
19186
|
+
CLI_VERSION2 = JSON.parse(readFileSync32(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION2;
|
|
18905
19187
|
} catch {
|
|
18906
19188
|
}
|
|
18907
19189
|
}
|
|
18908
19190
|
});
|
|
18909
19191
|
|
|
19192
|
+
// ../engine/dist/core/which.js
|
|
19193
|
+
import { existsSync as existsSync40, statSync as statSync36, accessSync, constants } from "node:fs";
|
|
19194
|
+
import { join as join42, isAbsolute as isAbsolute2, delimiter as delimiter2, sep as sep2 } from "node:path";
|
|
19195
|
+
function executable(p) {
|
|
19196
|
+
try {
|
|
19197
|
+
if (!statSync36(p).isFile())
|
|
19198
|
+
return false;
|
|
19199
|
+
} catch {
|
|
19200
|
+
return false;
|
|
19201
|
+
}
|
|
19202
|
+
if (isWindows)
|
|
19203
|
+
return true;
|
|
19204
|
+
try {
|
|
19205
|
+
accessSync(p, constants.X_OK);
|
|
19206
|
+
return true;
|
|
19207
|
+
} catch {
|
|
19208
|
+
return false;
|
|
19209
|
+
}
|
|
19210
|
+
}
|
|
19211
|
+
function candidates(name) {
|
|
19212
|
+
if (!isWindows)
|
|
19213
|
+
return [name];
|
|
19214
|
+
const exts = (process.env.PATHEXT || ".COM;.EXE;.BAT;.CMD").split(";").map((e) => e.trim()).filter(Boolean);
|
|
19215
|
+
if (exts.some((e) => name.toLowerCase().endsWith(e.toLowerCase())))
|
|
19216
|
+
return [name];
|
|
19217
|
+
return exts.map((e) => name + e);
|
|
19218
|
+
}
|
|
19219
|
+
function resolveOnPath(name) {
|
|
19220
|
+
if (!name)
|
|
19221
|
+
return null;
|
|
19222
|
+
if (name.includes("/") || isWindows && name.includes(sep2) || isAbsolute2(name)) {
|
|
19223
|
+
for (const c of candidates(name))
|
|
19224
|
+
if (executable(c))
|
|
19225
|
+
return c;
|
|
19226
|
+
return null;
|
|
19227
|
+
}
|
|
19228
|
+
for (const raw of (process.env.PATH || "").split(delimiter2)) {
|
|
19229
|
+
const dir = raw.replace(/^"(.*)"$/, "$1");
|
|
19230
|
+
if (!dir)
|
|
19231
|
+
continue;
|
|
19232
|
+
for (const c of candidates(name)) {
|
|
19233
|
+
const full = join42(dir, c);
|
|
19234
|
+
if (existsSync40(full) && executable(full))
|
|
19235
|
+
return full;
|
|
19236
|
+
}
|
|
19237
|
+
}
|
|
19238
|
+
return null;
|
|
19239
|
+
}
|
|
19240
|
+
function isOnPath(name) {
|
|
19241
|
+
return resolveOnPath(name) !== null;
|
|
19242
|
+
}
|
|
19243
|
+
var isWindows;
|
|
19244
|
+
var init_which = __esm({
|
|
19245
|
+
"../engine/dist/core/which.js"() {
|
|
19246
|
+
"use strict";
|
|
19247
|
+
isWindows = process.platform === "win32";
|
|
19248
|
+
}
|
|
19249
|
+
});
|
|
19250
|
+
|
|
19251
|
+
// src/update-notice.ts
|
|
19252
|
+
var update_notice_exports = {};
|
|
19253
|
+
__export(update_notice_exports, {
|
|
19254
|
+
printUpdateNotice: () => printUpdateNotice,
|
|
19255
|
+
refreshUpdateCheck: () => refreshUpdateCheck,
|
|
19256
|
+
updateNotice: () => updateNotice
|
|
19257
|
+
});
|
|
19258
|
+
import { readFileSync as readFileSync34, writeFileSync as writeFileSync10 } from "node:fs";
|
|
19259
|
+
import { join as join44 } from "node:path";
|
|
19260
|
+
function readCheck() {
|
|
19261
|
+
try {
|
|
19262
|
+
const c = JSON.parse(readFileSync34(checkPath(), "utf-8"));
|
|
19263
|
+
return c && typeof c.serverVersion === "string" ? c : null;
|
|
19264
|
+
} catch {
|
|
19265
|
+
return null;
|
|
19266
|
+
}
|
|
19267
|
+
}
|
|
19268
|
+
function writeCheck(c) {
|
|
19269
|
+
try {
|
|
19270
|
+
writeFileSync10(checkPath(), JSON.stringify(c));
|
|
19271
|
+
} catch {
|
|
19272
|
+
}
|
|
19273
|
+
}
|
|
19274
|
+
function updateNotice() {
|
|
19275
|
+
const c = readCheck();
|
|
19276
|
+
if (!c) return null;
|
|
19277
|
+
const own = cliVersion();
|
|
19278
|
+
if (compareVersions(c.serverVersion, own) <= 0) return null;
|
|
19279
|
+
return `chat-recall ${c.serverVersion} is available (you have ${own}). Auto-update should apply it; force it now with: chat-recall update`;
|
|
19280
|
+
}
|
|
19281
|
+
async function refreshUpdateCheck(force = false) {
|
|
19282
|
+
const prev = readCheck();
|
|
19283
|
+
if (!force && prev && Date.now() - prev.checkedAt < CHECK_TTL_MS) return prev;
|
|
19284
|
+
let newest = "0.0.0";
|
|
19285
|
+
try {
|
|
19286
|
+
const { loadAllCredentials: loadAllCredentials2 } = await Promise.resolve().then(() => (init_sync_client(), sync_client_exports));
|
|
19287
|
+
for (const cred of loadAllCredentials2()) {
|
|
19288
|
+
if (!cred.serverUrl) continue;
|
|
19289
|
+
const base = cred.serverUrl.replace(/\/+$/, "");
|
|
19290
|
+
try {
|
|
19291
|
+
const res = await fetchWithTimeout(`${base}/api/capabilities`, {
|
|
19292
|
+
headers: cred.token ? { authorization: `Bearer ${cred.token}` } : {}
|
|
19293
|
+
}, 5e3);
|
|
19294
|
+
if (!res.ok) continue;
|
|
19295
|
+
const caps = await res.json();
|
|
19296
|
+
const v = caps?.cli?.version;
|
|
19297
|
+
if (v && compareVersions(v, newest) > 0) newest = v;
|
|
19298
|
+
} catch {
|
|
19299
|
+
}
|
|
19300
|
+
}
|
|
19301
|
+
} catch {
|
|
19302
|
+
return prev;
|
|
19303
|
+
}
|
|
19304
|
+
if (newest === "0.0.0") return prev;
|
|
19305
|
+
const next = { serverVersion: newest, checkedAt: Date.now() };
|
|
19306
|
+
writeCheck(next);
|
|
19307
|
+
return next;
|
|
19308
|
+
}
|
|
19309
|
+
function printUpdateNotice() {
|
|
19310
|
+
if (printed) return;
|
|
19311
|
+
printed = true;
|
|
19312
|
+
try {
|
|
19313
|
+
const msg = updateNotice();
|
|
19314
|
+
if (msg) console.error(`
|
|
19315
|
+
\u26A0 ${msg}
|
|
19316
|
+
`);
|
|
19317
|
+
const t = setTimeout(() => {
|
|
19318
|
+
void refreshUpdateCheck().catch(() => {
|
|
19319
|
+
});
|
|
19320
|
+
}, 0);
|
|
19321
|
+
if (typeof t.unref === "function") t.unref();
|
|
19322
|
+
} catch {
|
|
19323
|
+
}
|
|
19324
|
+
}
|
|
19325
|
+
var CHECK_TTL_MS, checkPath, printed;
|
|
19326
|
+
var init_update_notice = __esm({
|
|
19327
|
+
"src/update-notice.ts"() {
|
|
19328
|
+
"use strict";
|
|
19329
|
+
init_paths();
|
|
19330
|
+
init_auto_update();
|
|
19331
|
+
init_http();
|
|
19332
|
+
CHECK_TTL_MS = 6 * 3600 * 1e3;
|
|
19333
|
+
checkPath = () => join44(getDataDir(), "update-check.json");
|
|
19334
|
+
printed = false;
|
|
19335
|
+
}
|
|
19336
|
+
});
|
|
19337
|
+
|
|
18910
19338
|
// ../engine/dist/core/companions.js
|
|
18911
|
-
import { existsSync as
|
|
19339
|
+
import { existsSync as existsSync41, mkdirSync as mkdirSync11, statSync as statSync37, chmodSync as chmodSync5, unlinkSync as unlinkSync3, renameSync as renameSync5, createWriteStream, readFileSync as readFileSync35, writeFileSync as writeFileSync11 } from "node:fs";
|
|
18912
19340
|
import { homedir as homedir15 } from "node:os";
|
|
18913
|
-
import { join as
|
|
19341
|
+
import { join as join45 } from "node:path";
|
|
18914
19342
|
import { execSync as execSync3 } from "node:child_process";
|
|
19343
|
+
import { createHash as createHash13 } from "node:crypto";
|
|
19344
|
+
function expectedCodeindexSha256(artifact) {
|
|
19345
|
+
return CODEINDEX_SHA256[artifact.replace(/^codeindex-/, "").replace(/\.exe$/, "")] ?? null;
|
|
19346
|
+
}
|
|
18915
19347
|
function detectPlatform() {
|
|
18916
19348
|
const arch = process.arch;
|
|
18917
19349
|
const platform = process.platform;
|
|
18918
19350
|
const archMap = { x64: "x86_64", arm64: "aarch64" };
|
|
18919
|
-
const platformMap = { linux: "linux", darwin: "
|
|
19351
|
+
const platformMap = { linux: "linux", darwin: "macos", win32: "windows" };
|
|
18920
19352
|
const a = archMap[arch];
|
|
18921
19353
|
const p = platformMap[platform];
|
|
18922
19354
|
if (!a || !p) {
|
|
18923
19355
|
return { reason: `Unsupported platform: ${arch}-${platform}` };
|
|
18924
19356
|
}
|
|
18925
|
-
const prebuiltCombos = /* @__PURE__ */ new Set([
|
|
18926
|
-
|
|
19357
|
+
const prebuiltCombos = /* @__PURE__ */ new Set([
|
|
19358
|
+
"x86_64-linux",
|
|
19359
|
+
"aarch64-linux",
|
|
19360
|
+
"x86_64-macos",
|
|
19361
|
+
"aarch64-macos",
|
|
19362
|
+
"x86_64-windows",
|
|
19363
|
+
"aarch64-windows"
|
|
19364
|
+
]);
|
|
19365
|
+
const artifact = `codeindex-${a}-${p}${p === "windows" ? ".exe" : ""}`;
|
|
18927
19366
|
if (!prebuiltCombos.has(`${a}-${p}`)) {
|
|
18928
19367
|
return {
|
|
18929
19368
|
artifact,
|
|
@@ -18940,20 +19379,15 @@ function checkCodeindexStatus() {
|
|
|
18940
19379
|
artifactName: platform.artifact,
|
|
18941
19380
|
unsupportedReason: platform.reason
|
|
18942
19381
|
};
|
|
18943
|
-
let foundPath =
|
|
18944
|
-
|
|
18945
|
-
|
|
18946
|
-
if (out)
|
|
18947
|
-
foundPath = out;
|
|
18948
|
-
} catch {
|
|
19382
|
+
let foundPath = resolveOnPath(CODEINDEX_BIN_NAME);
|
|
19383
|
+
if (!foundPath) {
|
|
19384
|
+
foundPath = resolveOnPath(CODEINDEX_BIN_PATH);
|
|
18949
19385
|
}
|
|
18950
|
-
if (!foundPath && existsSync40(CODEINDEX_BIN_PATH))
|
|
18951
|
-
foundPath = CODEINDEX_BIN_PATH;
|
|
18952
19386
|
if (foundPath) {
|
|
18953
19387
|
status.installed = true;
|
|
18954
19388
|
status.path = foundPath;
|
|
18955
19389
|
try {
|
|
18956
|
-
status.size =
|
|
19390
|
+
status.size = statSync37(foundPath).size;
|
|
18957
19391
|
} catch {
|
|
18958
19392
|
}
|
|
18959
19393
|
try {
|
|
@@ -18965,16 +19399,9 @@ function checkCodeindexStatus() {
|
|
|
18965
19399
|
return status;
|
|
18966
19400
|
}
|
|
18967
19401
|
async function downloadArtifact(artifact, dest) {
|
|
18968
|
-
const hasGh = (
|
|
18969
|
-
try {
|
|
18970
|
-
execSync3("command -v gh", { stdio: "ignore" });
|
|
18971
|
-
return true;
|
|
18972
|
-
} catch {
|
|
18973
|
-
return false;
|
|
18974
|
-
}
|
|
18975
|
-
})();
|
|
19402
|
+
const hasGh = isOnPath("gh");
|
|
18976
19403
|
if (hasGh) {
|
|
18977
|
-
execSync3(`gh release download ${CODEINDEX_VERSION} --repo ${CODEINDEX_REPO} -p ${artifact} -O ${dest}`, {
|
|
19404
|
+
execSync3(`gh release download ${CODEINDEX_VERSION} --repo ${CODEINDEX_REPO} -p ${artifact} -O "${dest}"`, {
|
|
18978
19405
|
stdio: ["ignore", "pipe", "pipe"],
|
|
18979
19406
|
timeout: 6e4
|
|
18980
19407
|
});
|
|
@@ -19013,15 +19440,26 @@ async function installCodeindex(opts = {}) {
|
|
|
19013
19440
|
return status;
|
|
19014
19441
|
if (!status.prebuiltAvailable)
|
|
19015
19442
|
return status;
|
|
19016
|
-
|
|
19443
|
+
mkdirSync11(CODEINDEX_INSTALL_DIR, { recursive: true });
|
|
19017
19444
|
const tmpPath = `${CODEINDEX_BIN_PATH}.partial`;
|
|
19018
19445
|
try {
|
|
19019
19446
|
await downloadArtifact(status.artifactName, tmpPath);
|
|
19447
|
+
const expected = expectedCodeindexSha256(status.artifactName);
|
|
19448
|
+
if (!expected) {
|
|
19449
|
+
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.`);
|
|
19450
|
+
}
|
|
19451
|
+
const actual = createHash13("sha256").update(readFileSync35(tmpPath)).digest("hex");
|
|
19452
|
+
if (actual !== expected) {
|
|
19453
|
+
throw new Error(`Checksum mismatch for ${status.artifactName}.
|
|
19454
|
+
expected ${expected}
|
|
19455
|
+
actual ${actual}
|
|
19456
|
+
Refusing to install. The release may have been re-uploaded, or something is serving different bytes.`);
|
|
19457
|
+
}
|
|
19020
19458
|
chmodSync5(tmpPath, 493);
|
|
19021
19459
|
renameSync5(tmpPath, CODEINDEX_BIN_PATH);
|
|
19022
19460
|
} catch (err) {
|
|
19023
19461
|
try {
|
|
19024
|
-
if (
|
|
19462
|
+
if (existsSync41(tmpPath))
|
|
19025
19463
|
unlinkSync3(tmpPath);
|
|
19026
19464
|
} catch {
|
|
19027
19465
|
}
|
|
@@ -19029,15 +19467,24 @@ async function installCodeindex(opts = {}) {
|
|
|
19029
19467
|
}
|
|
19030
19468
|
return checkCodeindexStatus();
|
|
19031
19469
|
}
|
|
19032
|
-
var CODEINDEX_REPO, CODEINDEX_VERSION, CODEINDEX_INSTALL_DIR, CODEINDEX_BIN_NAME, CODEINDEX_BIN_PATH;
|
|
19470
|
+
var CODEINDEX_REPO, CODEINDEX_VERSION, CODEINDEX_SHA256, CODEINDEX_INSTALL_DIR, CODEINDEX_BIN_NAME, CODEINDEX_BIN_PATH;
|
|
19033
19471
|
var init_companions = __esm({
|
|
19034
19472
|
"../engine/dist/core/companions.js"() {
|
|
19035
19473
|
"use strict";
|
|
19474
|
+
init_which();
|
|
19036
19475
|
CODEINDEX_REPO = "munhq/codeindex";
|
|
19037
|
-
CODEINDEX_VERSION = "v0.1
|
|
19038
|
-
|
|
19039
|
-
|
|
19040
|
-
|
|
19476
|
+
CODEINDEX_VERSION = "v0.3.1";
|
|
19477
|
+
CODEINDEX_SHA256 = {
|
|
19478
|
+
"x86_64-linux": "4378f12e7c80fa8bb53e41c02db4b95955f2f878369abfb28b5edd94b4adbb85",
|
|
19479
|
+
"aarch64-linux": "5a1d6c9c2592a3721547c42cd9b6b11f460e903bfc46407ae27d5879e7259587",
|
|
19480
|
+
"x86_64-macos": "6ad2a2b40faa4ec72ac35fee84f35ea7c848cddc4f6382b4cafedb644f30389f",
|
|
19481
|
+
"aarch64-macos": "f366d00918f79a4a0acc09c6091d97c6c378c79edbdbe3cb22e4014ea57f08d2",
|
|
19482
|
+
"x86_64-windows": "a96fc8c8949bb399a44cc0615b12e458460a529c69f01e8829cc39a20f45ab29",
|
|
19483
|
+
"aarch64-windows": "42620d56272cd9ba9d785569d8d754d6b4a3e80f36f28db3e0c483fd600ed117"
|
|
19484
|
+
};
|
|
19485
|
+
CODEINDEX_INSTALL_DIR = join45(homedir15(), ".local", "bin");
|
|
19486
|
+
CODEINDEX_BIN_NAME = process.platform === "win32" ? "codeindex.exe" : "codeindex";
|
|
19487
|
+
CODEINDEX_BIN_PATH = join45(CODEINDEX_INSTALL_DIR, CODEINDEX_BIN_NAME);
|
|
19041
19488
|
}
|
|
19042
19489
|
});
|
|
19043
19490
|
|
|
@@ -19143,15 +19590,17 @@ var init_prompts = __esm({
|
|
|
19143
19590
|
var collector_exports = {};
|
|
19144
19591
|
__export(collector_exports, {
|
|
19145
19592
|
COLLECTOR_VERSION: () => COLLECTOR_VERSION,
|
|
19593
|
+
GENERATED_PATTERNS: () => GENERATED_PATTERNS,
|
|
19146
19594
|
collectCode: () => collectCode,
|
|
19595
|
+
isGenerated: () => isGenerated,
|
|
19147
19596
|
isJunkWorkspacePath: () => isJunkWorkspacePath,
|
|
19148
19597
|
isSecretRule: () => isSecretRule,
|
|
19149
19598
|
resolveCodeindexBin: () => resolveCodeindexBin
|
|
19150
19599
|
});
|
|
19151
19600
|
import { spawn } from "node:child_process";
|
|
19152
19601
|
import { execSync as execSync4 } from "node:child_process";
|
|
19153
|
-
import { readFileSync as
|
|
19154
|
-
import { join as
|
|
19602
|
+
import { readFileSync as readFileSync36 } from "node:fs";
|
|
19603
|
+
import { join as join46, basename as basename23 } from "node:path";
|
|
19155
19604
|
async function resolveCodeindexBin(autoInstall = true) {
|
|
19156
19605
|
let st = checkCodeindexStatus();
|
|
19157
19606
|
if (!st.installed && autoInstall)
|
|
@@ -19238,10 +19687,11 @@ function isSecretRule(rule) {
|
|
|
19238
19687
|
return /secret|password|credential|key|token|auth/i.test(rule);
|
|
19239
19688
|
}
|
|
19240
19689
|
function isJunkWorkspacePath(ws) {
|
|
19241
|
-
|
|
19690
|
+
const norm = ws.replace(/\\/g, "/");
|
|
19691
|
+
return /(^|\/)(scratchpad|\.cache|node_modules|\.git|tmp)(\/|$)|claude-1000/i.test(norm);
|
|
19242
19692
|
}
|
|
19243
19693
|
async function collectCode(opts) {
|
|
19244
|
-
const ws = opts.workspace.replace(
|
|
19694
|
+
const ws = opts.workspace.replace(/[/\\]+$/, "");
|
|
19245
19695
|
const log6 = opts.log ?? (() => {
|
|
19246
19696
|
});
|
|
19247
19697
|
if (isJunkWorkspacePath(ws)) {
|
|
@@ -19249,9 +19699,11 @@ async function collectCode(opts) {
|
|
|
19249
19699
|
}
|
|
19250
19700
|
const bin = opts.binPath ?? await resolveCodeindexBin(opts.autoInstall ?? true);
|
|
19251
19701
|
const projectId = resolveProjectId(ws).id || `path:${ws}`;
|
|
19252
|
-
const
|
|
19702
|
+
const wsNorm = ws.replace(/\\/g, "/");
|
|
19703
|
+
const wsPrefix = wsNorm + "/";
|
|
19253
19704
|
const rel = (p) => {
|
|
19254
|
-
|
|
19705
|
+
const n = p.replace(/\\/g, "/");
|
|
19706
|
+
let r = n.startsWith(wsPrefix) ? n.slice(wsPrefix.length) : n;
|
|
19255
19707
|
if (r.startsWith("./"))
|
|
19256
19708
|
r = r.slice(2);
|
|
19257
19709
|
return r;
|
|
@@ -19312,7 +19764,7 @@ async function collectCode(opts) {
|
|
|
19312
19764
|
}
|
|
19313
19765
|
const complexity = (r) => {
|
|
19314
19766
|
try {
|
|
19315
|
-
const txt =
|
|
19767
|
+
const txt = readFileSync36(join46(ws, r), "utf8");
|
|
19316
19768
|
if (txt.length > 2e6)
|
|
19317
19769
|
return 1;
|
|
19318
19770
|
const m = txt.match(CF_RE);
|
|
@@ -19896,7 +20348,7 @@ async function collectCode(opts) {
|
|
|
19896
20348
|
void health;
|
|
19897
20349
|
return { project, findings, hotspots, actions };
|
|
19898
20350
|
}
|
|
19899
|
-
var COLLECTOR_VERSION, ANALYSES, GENERATED, CF_RE, DEPTH, MCP_OUT_MAX_BYTES, call, COMMON_SYMBOL_NAMES;
|
|
20351
|
+
var COLLECTOR_VERSION, ANALYSES, GENERATED, CF_RE, DEPTH, MCP_OUT_MAX_BYTES, call, GENERATED_PATTERNS, COMMON_SYMBOL_NAMES;
|
|
19900
20352
|
var init_collector = __esm({
|
|
19901
20353
|
"../engine/dist/core/code/collector.js"() {
|
|
19902
20354
|
"use strict";
|
|
@@ -19938,7 +20390,13 @@ var init_collector = __esm({
|
|
|
19938
20390
|
"/vendor/",
|
|
19939
20391
|
"/third_party/",
|
|
19940
20392
|
"/site-packages/",
|
|
20393
|
+
// Lockfiles. '.lock' alone catches yarn.lock, Cargo.lock, poetry.lock and
|
|
20394
|
+
// composer.lock, and MISSES the two biggest ones in a JS repo —
|
|
20395
|
+
// package-lock.json and pnpm-lock.yaml are named '-lock.<ext>'. Found by
|
|
20396
|
+
// replacing this file's mirror test with one that calls the real predicate.
|
|
19941
20397
|
".lock",
|
|
20398
|
+
"-lock.json",
|
|
20399
|
+
"-lock.yaml",
|
|
19942
20400
|
"/dist/",
|
|
19943
20401
|
"/build/",
|
|
19944
20402
|
"/out/",
|
|
@@ -19955,6 +20413,7 @@ var init_collector = __esm({
|
|
|
19955
20413
|
DEPTH = 2;
|
|
19956
20414
|
MCP_OUT_MAX_BYTES = 64 * 1024 * 1024;
|
|
19957
20415
|
call = (id, name, args = {}) => ({ jsonrpc: "2.0", id, method: "tools/call", params: { name, arguments: args } });
|
|
20416
|
+
GENERATED_PATTERNS = GENERATED;
|
|
19958
20417
|
COMMON_SYMBOL_NAMES = /* @__PURE__ */ new Set([
|
|
19959
20418
|
"error",
|
|
19960
20419
|
"err",
|
|
@@ -20030,26 +20489,26 @@ __export(install_skills_exports, {
|
|
|
20030
20489
|
skillsSourceDir: () => skillsSourceDir,
|
|
20031
20490
|
uninstallSkills: () => uninstallSkills
|
|
20032
20491
|
});
|
|
20033
|
-
import { readdirSync as readdirSync31, existsSync as
|
|
20034
|
-
import { createHash as
|
|
20035
|
-
import { join as
|
|
20492
|
+
import { readdirSync as readdirSync31, existsSync as existsSync42, mkdirSync as mkdirSync12, rmSync as rmSync6, cpSync, writeFileSync as writeFileSync12, readFileSync as readFileSync37, statSync as statSync38, realpathSync as realpathSync4 } from "fs";
|
|
20493
|
+
import { createHash as createHash14 } from "crypto";
|
|
20494
|
+
import { join as join47, basename as basename24 } from "path";
|
|
20036
20495
|
function skillsSourceDir() {
|
|
20037
|
-
return
|
|
20496
|
+
return join47(import.meta.dirname, "..", "skills");
|
|
20038
20497
|
}
|
|
20039
20498
|
function version() {
|
|
20040
20499
|
try {
|
|
20041
|
-
return JSON.parse(
|
|
20500
|
+
return JSON.parse(readFileSync37(new URL("../package.json", import.meta.url), "utf-8")).version || "0.0.0";
|
|
20042
20501
|
} catch {
|
|
20043
20502
|
return "0.0.0";
|
|
20044
20503
|
}
|
|
20045
20504
|
}
|
|
20046
20505
|
function skillsFingerprint() {
|
|
20047
20506
|
const src = skillsSourceDir();
|
|
20048
|
-
const h =
|
|
20507
|
+
const h = createHash14("sha256");
|
|
20049
20508
|
for (const name of bundledSkillNames()) {
|
|
20050
|
-
for (const rel of filesUnder(
|
|
20509
|
+
for (const rel of filesUnder(join47(src, name)).sort()) {
|
|
20051
20510
|
h.update(name + "/" + rel);
|
|
20052
|
-
h.update(
|
|
20511
|
+
h.update(readFileSync37(join47(src, name, rel)));
|
|
20053
20512
|
}
|
|
20054
20513
|
}
|
|
20055
20514
|
return h.digest("hex").slice(0, 12);
|
|
@@ -20059,7 +20518,7 @@ function filesUnder(dir, prefix = "") {
|
|
|
20059
20518
|
for (const e of readdirSync31(dir, { withFileTypes: true })) {
|
|
20060
20519
|
if (e.name === MARKER) continue;
|
|
20061
20520
|
const rel = prefix ? `${prefix}/${e.name}` : e.name;
|
|
20062
|
-
if (e.isDirectory()) out.push(...filesUnder(
|
|
20521
|
+
if (e.isDirectory()) out.push(...filesUnder(join47(dir, e.name), rel));
|
|
20063
20522
|
else out.push(rel);
|
|
20064
20523
|
}
|
|
20065
20524
|
return out;
|
|
@@ -20069,8 +20528,8 @@ function skillStamp() {
|
|
|
20069
20528
|
}
|
|
20070
20529
|
function bundledSkillNames() {
|
|
20071
20530
|
const src = skillsSourceDir();
|
|
20072
|
-
if (!
|
|
20073
|
-
return readdirSync31(src, { withFileTypes: true }).filter((e) => e.isDirectory() &&
|
|
20531
|
+
if (!existsSync42(src)) return [];
|
|
20532
|
+
return readdirSync31(src, { withFileTypes: true }).filter((e) => e.isDirectory() && existsSync42(join47(src, e.name, "SKILL.md"))).map((e) => e.name).sort();
|
|
20074
20533
|
}
|
|
20075
20534
|
function realPathOrSelf(p) {
|
|
20076
20535
|
try {
|
|
@@ -20083,7 +20542,7 @@ function claudeSkillTargets() {
|
|
|
20083
20542
|
const targets = [];
|
|
20084
20543
|
const seen = /* @__PURE__ */ new Set();
|
|
20085
20544
|
for (const home of claudeHomeDirs()) {
|
|
20086
|
-
const dir =
|
|
20545
|
+
const dir = join47(home, "skills");
|
|
20087
20546
|
const key = realPathOrSelf(dir);
|
|
20088
20547
|
if (seen.has(key)) continue;
|
|
20089
20548
|
seen.add(key);
|
|
@@ -20094,7 +20553,7 @@ function claudeSkillTargets() {
|
|
|
20094
20553
|
dir,
|
|
20095
20554
|
// Judge each profile on ITS OWN transcripts, not the primary's: a home
|
|
20096
20555
|
// with no projects/ is a directory someone made, not a Claude install.
|
|
20097
|
-
available:
|
|
20556
|
+
available: existsSync42(join47(home, "projects"))
|
|
20098
20557
|
});
|
|
20099
20558
|
}
|
|
20100
20559
|
if (targets.length === 0) {
|
|
@@ -20117,7 +20576,7 @@ function skillTargets() {
|
|
|
20117
20576
|
];
|
|
20118
20577
|
}
|
|
20119
20578
|
function isManaged(dir) {
|
|
20120
|
-
return
|
|
20579
|
+
return existsSync42(join47(dir, MARKER));
|
|
20121
20580
|
}
|
|
20122
20581
|
function installSkills(opts = {}) {
|
|
20123
20582
|
const onlyAvailable = opts.onlyAvailable ?? true;
|
|
@@ -20134,15 +20593,15 @@ function installSkills(opts = {}) {
|
|
|
20134
20593
|
continue;
|
|
20135
20594
|
}
|
|
20136
20595
|
for (const name of names) {
|
|
20137
|
-
const dest =
|
|
20138
|
-
if (
|
|
20596
|
+
const dest = join47(t.dir, name);
|
|
20597
|
+
if (existsSync42(dest) && !isManaged(dest)) {
|
|
20139
20598
|
skippedUserOwned.push(name);
|
|
20140
20599
|
continue;
|
|
20141
20600
|
}
|
|
20142
|
-
|
|
20601
|
+
mkdirSync12(t.dir, { recursive: true });
|
|
20143
20602
|
rmSync6(dest, { recursive: true, force: true });
|
|
20144
|
-
cpSync(
|
|
20145
|
-
|
|
20603
|
+
cpSync(join47(src, name), dest, { recursive: true });
|
|
20604
|
+
writeFileSync12(join47(dest, MARKER), `${stamp}
|
|
20146
20605
|
`);
|
|
20147
20606
|
installed.push(name);
|
|
20148
20607
|
}
|
|
@@ -20155,13 +20614,13 @@ function uninstallSkills() {
|
|
|
20155
20614
|
const perTarget = [];
|
|
20156
20615
|
for (const t of skillTargets()) {
|
|
20157
20616
|
const removed = [];
|
|
20158
|
-
if (!
|
|
20617
|
+
if (!existsSync42(t.dir)) {
|
|
20159
20618
|
perTarget.push({ id: t.id, label: t.label, removed });
|
|
20160
20619
|
continue;
|
|
20161
20620
|
}
|
|
20162
20621
|
for (const entry of readdirSync31(t.dir, { withFileTypes: true })) {
|
|
20163
20622
|
if (!entry.isDirectory()) continue;
|
|
20164
|
-
const dir =
|
|
20623
|
+
const dir = join47(t.dir, entry.name);
|
|
20165
20624
|
if (isManaged(dir) && (names.has(entry.name) || entry.name.startsWith("chat-recall"))) {
|
|
20166
20625
|
rmSync6(dir, { recursive: true, force: true });
|
|
20167
20626
|
removed.push(entry.name);
|
|
@@ -20178,10 +20637,10 @@ function skillsNeedRefresh() {
|
|
|
20178
20637
|
for (const t of skillTargets()) {
|
|
20179
20638
|
if (!t.available) continue;
|
|
20180
20639
|
for (const name of names) {
|
|
20181
|
-
const marker =
|
|
20182
|
-
if (!
|
|
20640
|
+
const marker = join47(t.dir, name, MARKER);
|
|
20641
|
+
if (!existsSync42(marker)) return true;
|
|
20183
20642
|
try {
|
|
20184
|
-
if (
|
|
20643
|
+
if (readFileSync37(marker, "utf-8").trim() !== cur) return true;
|
|
20185
20644
|
} catch {
|
|
20186
20645
|
return true;
|
|
20187
20646
|
}
|
|
@@ -20196,11 +20655,11 @@ function skillStatus() {
|
|
|
20196
20655
|
let installed = 0;
|
|
20197
20656
|
let ver = null;
|
|
20198
20657
|
for (const name of names) {
|
|
20199
|
-
const marker =
|
|
20200
|
-
if (
|
|
20658
|
+
const marker = join47(t.dir, name, MARKER);
|
|
20659
|
+
if (existsSync42(marker)) {
|
|
20201
20660
|
installed++;
|
|
20202
20661
|
try {
|
|
20203
|
-
ver =
|
|
20662
|
+
ver = readFileSync37(marker, "utf-8").trim();
|
|
20204
20663
|
} catch {
|
|
20205
20664
|
}
|
|
20206
20665
|
}
|
|
@@ -20235,15 +20694,15 @@ __export(service_installer_exports, {
|
|
|
20235
20694
|
uninstallService: () => uninstallService
|
|
20236
20695
|
});
|
|
20237
20696
|
import { execSync as execSync5 } from "child_process";
|
|
20238
|
-
import { existsSync as
|
|
20697
|
+
import { existsSync as existsSync43, mkdirSync as mkdirSync13, rmSync as rmSync7, writeFileSync as writeFileSync13 } from "fs";
|
|
20239
20698
|
import { homedir as homedir16 } from "os";
|
|
20240
|
-
import { join as
|
|
20699
|
+
import { join as join48 } from "path";
|
|
20241
20700
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
20242
20701
|
function resolveDaemonPaths() {
|
|
20243
20702
|
const watchJs = fileURLToPath2(new URL("./watch.js", import.meta.url));
|
|
20244
20703
|
const node = process.execPath;
|
|
20245
|
-
const dataDir =
|
|
20246
|
-
const logFile =
|
|
20704
|
+
const dataDir = join48(homedir16(), ".chat-recall");
|
|
20705
|
+
const logFile = join48(dataDir, "watch.log");
|
|
20247
20706
|
return { watchJs, node, logFile, dataDir };
|
|
20248
20707
|
}
|
|
20249
20708
|
function tryCmd(cmd) {
|
|
@@ -20268,7 +20727,7 @@ function isServiceRunning() {
|
|
|
20268
20727
|
}
|
|
20269
20728
|
function installService() {
|
|
20270
20729
|
const { watchJs, node, logFile, dataDir } = resolveDaemonPaths();
|
|
20271
|
-
|
|
20730
|
+
mkdirSync13(dataDir, { recursive: true });
|
|
20272
20731
|
if (process.platform === "linux") {
|
|
20273
20732
|
return installSystemd(watchJs, node, logFile);
|
|
20274
20733
|
}
|
|
@@ -20284,11 +20743,11 @@ function installService() {
|
|
|
20284
20743
|
);
|
|
20285
20744
|
}
|
|
20286
20745
|
function installSystemd(watchJs, node, logFile) {
|
|
20287
|
-
const unitDir =
|
|
20288
|
-
const unitPath =
|
|
20746
|
+
const unitDir = join48(homedir16(), ".config", "systemd", "user");
|
|
20747
|
+
const unitPath = join48(unitDir, "chat-recall-watch.service");
|
|
20289
20748
|
const unit = renderSystemdUnit(watchJs, node, logFile);
|
|
20290
|
-
|
|
20291
|
-
|
|
20749
|
+
mkdirSync13(unitDir, { recursive: true });
|
|
20750
|
+
writeFileSync13(unitPath, unit);
|
|
20292
20751
|
try {
|
|
20293
20752
|
execSync5("systemctl --user daemon-reload && systemctl --user enable chat-recall-watch.service && systemctl --user restart chat-recall-watch.service", { stdio: "inherit" });
|
|
20294
20753
|
try {
|
|
@@ -20316,10 +20775,14 @@ function renderSystemdUnit(watchJs, node, logFile) {
|
|
|
20316
20775
|
"Restart=on-failure",
|
|
20317
20776
|
"RestartSec=10",
|
|
20318
20777
|
"Nice=10",
|
|
20319
|
-
//
|
|
20320
|
-
//
|
|
20321
|
-
|
|
20322
|
-
|
|
20778
|
+
// JOURNAL, not append:. The file version had no rotation and nothing to
|
|
20779
|
+
// give it any: systemd holds the fd open, so the daemon cannot rename or
|
|
20780
|
+
// truncate its own log without leaving systemd writing into a hole. It
|
|
20781
|
+
// reached 45 MB on this developer's machine and would have grown forever.
|
|
20782
|
+
// journald already rotates and applies disk limits. Read it with
|
|
20783
|
+
// journalctl --user -u chat-recall-watch -f
|
|
20784
|
+
"StandardOutput=journal",
|
|
20785
|
+
"StandardError=journal",
|
|
20323
20786
|
"",
|
|
20324
20787
|
"[Install]",
|
|
20325
20788
|
"WantedBy=default.target",
|
|
@@ -20328,11 +20791,11 @@ function renderSystemdUnit(watchJs, node, logFile) {
|
|
|
20328
20791
|
}
|
|
20329
20792
|
function installLaunchd(watchJs, node, logFile) {
|
|
20330
20793
|
const label = "com.chat-recall.watch";
|
|
20331
|
-
const plistDir =
|
|
20332
|
-
const plistPath =
|
|
20794
|
+
const plistDir = join48(homedir16(), "Library", "LaunchAgents");
|
|
20795
|
+
const plistPath = join48(plistDir, `${label}.plist`);
|
|
20333
20796
|
const plist = renderLaunchdPlist(watchJs, node, logFile, label);
|
|
20334
|
-
|
|
20335
|
-
|
|
20797
|
+
mkdirSync13(plistDir, { recursive: true });
|
|
20798
|
+
writeFileSync13(plistPath, plist);
|
|
20336
20799
|
try {
|
|
20337
20800
|
try {
|
|
20338
20801
|
execSync5(`launchctl unload "${plistPath}"`, { stdio: "ignore" });
|
|
@@ -20361,7 +20824,7 @@ function renderLaunchdPlist(watchJs, node, logFile, label = "com.chat-recall.wat
|
|
|
20361
20824
|
}
|
|
20362
20825
|
function installWindowsTask(watchJs, node, logFile) {
|
|
20363
20826
|
const taskName = "chat-recall-watch";
|
|
20364
|
-
const tr =
|
|
20827
|
+
const tr = `cmd /c \\"\\"${node}\\" --max-old-space-size=1536 \\"${watchJs}\\" >> \\"${logFile}\\" 2>&1\\"`;
|
|
20365
20828
|
try {
|
|
20366
20829
|
execSync5(`schtasks /create /tn "${taskName}" /tr "${tr}" /sc onlogon /rl LIMITED /f`, { stdio: "inherit" });
|
|
20367
20830
|
try {
|
|
@@ -20373,8 +20836,8 @@ function installWindowsTask(watchJs, node, logFile) {
|
|
|
20373
20836
|
}
|
|
20374
20837
|
return { definitionPath: null, logFile };
|
|
20375
20838
|
}
|
|
20376
|
-
function renderWindowsTaskCommand(watchJs, node, taskName = "chat-recall-watch") {
|
|
20377
|
-
const tr = `\\"${node}\\" --max-old-space-size=1536 \\"${watchJs}\\"`;
|
|
20839
|
+
function renderWindowsTaskCommand(watchJs, node, taskName = "chat-recall-watch", logFile) {
|
|
20840
|
+
const tr = logFile ? `cmd /c \\"\\"${node}\\" --max-old-space-size=1536 \\"${watchJs}\\" >> \\"${logFile}\\" 2>&1\\"` : `\\"${node}\\" --max-old-space-size=1536 \\"${watchJs}\\"`;
|
|
20378
20841
|
return `schtasks /create /tn "${taskName}" /tr "${tr}" /sc onlogon /rl LIMITED /f`;
|
|
20379
20842
|
}
|
|
20380
20843
|
function uninstallService() {
|
|
@@ -20385,8 +20848,8 @@ function uninstallService() {
|
|
|
20385
20848
|
removed = true;
|
|
20386
20849
|
} catch {
|
|
20387
20850
|
}
|
|
20388
|
-
const unitPath =
|
|
20389
|
-
if (
|
|
20851
|
+
const unitPath = join48(homedir16(), ".config", "systemd", "user", "chat-recall-watch.service");
|
|
20852
|
+
if (existsSync43(unitPath)) {
|
|
20390
20853
|
rmSync7(unitPath, { force: true });
|
|
20391
20854
|
removed = true;
|
|
20392
20855
|
}
|
|
@@ -20397,13 +20860,13 @@ function uninstallService() {
|
|
|
20397
20860
|
return removed;
|
|
20398
20861
|
}
|
|
20399
20862
|
if (process.platform === "darwin") {
|
|
20400
|
-
const plistPath =
|
|
20863
|
+
const plistPath = join48(homedir16(), "Library", "LaunchAgents", "com.chat-recall.watch.plist");
|
|
20401
20864
|
try {
|
|
20402
20865
|
execSync5(`launchctl unload "${plistPath}" 2>/dev/null`, { stdio: "ignore" });
|
|
20403
20866
|
} catch {
|
|
20404
20867
|
}
|
|
20405
20868
|
let removed = false;
|
|
20406
|
-
if (
|
|
20869
|
+
if (existsSync43(plistPath)) {
|
|
20407
20870
|
rmSync7(plistPath, { force: true });
|
|
20408
20871
|
removed = true;
|
|
20409
20872
|
}
|
|
@@ -20472,11 +20935,11 @@ function stalenessBanner(state) {
|
|
|
20472
20935
|
const days = state.periodEnd ? Math.max(0, Math.floor((Date.now() - state.periodEnd) / 864e5)) : null;
|
|
20473
20936
|
const reason = state.status === "trialing" ? "the trial has ended" : state.status === "past_due" ? "a payment has not gone through" : "the subscription has lapsed";
|
|
20474
20937
|
return [
|
|
20475
|
-
`\u26A0
|
|
20476
|
-
"Search and lists cover
|
|
20938
|
+
`\u26A0 SYNCING IS OFF \u2014 ${reason}.`,
|
|
20939
|
+
"Search and lists cover the WHOLE synced history; nothing is windowed or locked.",
|
|
20477
20940
|
since ? `The plan lapsed ${since}${days !== null ? ` (${days} days ago)` : ""}.` : "",
|
|
20478
|
-
"
|
|
20479
|
-
"
|
|
20941
|
+
"What is missing is only work done SINCE the lapse, because new sessions stopped uploading.",
|
|
20942
|
+
"Do not tell the user their history is gone or locked. Say new sessions are not syncing, and that subscribing plus one `chat-recall sync --full` brings everything current. Export always works."
|
|
20480
20943
|
].filter(Boolean).join(" ");
|
|
20481
20944
|
}
|
|
20482
20945
|
|
|
@@ -20488,9 +20951,9 @@ import {
|
|
|
20488
20951
|
ListToolsRequestSchema
|
|
20489
20952
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
20490
20953
|
import { z } from "zod";
|
|
20491
|
-
import { existsSync as
|
|
20492
|
-
import { join as
|
|
20493
|
-
import {
|
|
20954
|
+
import { existsSync as existsSync44, readFileSync as readFileSync38 } from "fs";
|
|
20955
|
+
import { join as join49 } from "path";
|
|
20956
|
+
import { spawn as spawn2 } from "child_process";
|
|
20494
20957
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
20495
20958
|
|
|
20496
20959
|
// ../engine/dist/core/context.js
|
|
@@ -20544,6 +21007,7 @@ function formatContext(context) {
|
|
|
20544
21007
|
|
|
20545
21008
|
// src/mcp.ts
|
|
20546
21009
|
init_paths();
|
|
21010
|
+
init_credentials_env();
|
|
20547
21011
|
init_backends();
|
|
20548
21012
|
init_tool_backend();
|
|
20549
21013
|
|
|
@@ -20635,7 +21099,7 @@ function sanitizeQuery(query) {
|
|
|
20635
21099
|
|
|
20636
21100
|
// ../engine/dist/core/write-ahead-log.js
|
|
20637
21101
|
init_paths();
|
|
20638
|
-
import { existsSync as existsSync14, mkdirSync as mkdirSync4, appendFileSync, openSync as
|
|
21102
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync4, appendFileSync, openSync as openSync7, closeSync as closeSync7, chmodSync as chmodSync2 } from "fs";
|
|
20639
21103
|
import { join as join15 } from "path";
|
|
20640
21104
|
var REDACT_KEYS = /* @__PURE__ */ new Set([
|
|
20641
21105
|
"content",
|
|
@@ -20661,8 +21125,8 @@ var WriteAheadLog = class {
|
|
|
20661
21125
|
}
|
|
20662
21126
|
this.walPath = join15(dir, "write_log.jsonl");
|
|
20663
21127
|
if (!existsSync14(this.walPath)) {
|
|
20664
|
-
const fd =
|
|
20665
|
-
|
|
21128
|
+
const fd = openSync7(this.walPath, "w", 384);
|
|
21129
|
+
closeSync7(fd);
|
|
20666
21130
|
}
|
|
20667
21131
|
}
|
|
20668
21132
|
/**
|
|
@@ -20716,6 +21180,63 @@ function getWAL() {
|
|
|
20716
21180
|
|
|
20717
21181
|
// src/mcp.ts
|
|
20718
21182
|
init_client_events();
|
|
21183
|
+
init_which();
|
|
21184
|
+
|
|
21185
|
+
// ../engine/dist/core/collector-health.js
|
|
21186
|
+
init_paths();
|
|
21187
|
+
import { readFileSync as readFileSync33, writeFileSync as writeFileSync9, mkdirSync as mkdirSync10 } from "node:fs";
|
|
21188
|
+
import { join as join43, dirname as dirname17 } from "node:path";
|
|
21189
|
+
var healthPath = () => join43(getDataDir(), "collector-health.json");
|
|
21190
|
+
function readCollectorHealth() {
|
|
21191
|
+
try {
|
|
21192
|
+
const h = JSON.parse(readFileSync33(healthPath(), "utf-8"));
|
|
21193
|
+
return h && h.v === 1 && typeof h.updatedAt === "number" ? h : null;
|
|
21194
|
+
} catch {
|
|
21195
|
+
return null;
|
|
21196
|
+
}
|
|
21197
|
+
}
|
|
21198
|
+
var STALE_AFTER_MS = 30 * 6e4;
|
|
21199
|
+
var CRASHLOOP_RESTARTS = 3;
|
|
21200
|
+
var ago = (ms) => {
|
|
21201
|
+
const m = Math.floor(ms / 6e4);
|
|
21202
|
+
if (m < 60)
|
|
21203
|
+
return `${m}m`;
|
|
21204
|
+
const h = Math.floor(m / 60);
|
|
21205
|
+
return h < 48 ? `${h}h` : `${Math.floor(h / 24)}d`;
|
|
21206
|
+
};
|
|
21207
|
+
function judgeHealth(h, now = Date.now()) {
|
|
21208
|
+
if (!h)
|
|
21209
|
+
return { ok: true, summary: null, reasons: [] };
|
|
21210
|
+
const reasons = [];
|
|
21211
|
+
const silent = now - h.updatedAt;
|
|
21212
|
+
if (silent > STALE_AFTER_MS) {
|
|
21213
|
+
reasons.push(`the collector has not reported for ${ago(silent)} \u2014 it may not be running`);
|
|
21214
|
+
}
|
|
21215
|
+
if (h.restartsLastHour >= CRASHLOOP_RESTARTS) {
|
|
21216
|
+
reasons.push(`it restarted ${h.restartsLastHour} times in the last hour`);
|
|
21217
|
+
}
|
|
21218
|
+
const targets = Object.entries(h.targets ?? {});
|
|
21219
|
+
const stale = targets.filter(([, t]) => t.lastOkAt === null || now - t.lastOkAt > STALE_AFTER_MS);
|
|
21220
|
+
if (targets.length > 0 && stale.length === targets.length) {
|
|
21221
|
+
const ranked = stale.map(([url, t]) => ({ url, t })).sort((a, b) => {
|
|
21222
|
+
const err = Number(!!b.t.lastError) - Number(!!a.t.lastError);
|
|
21223
|
+
if (err !== 0)
|
|
21224
|
+
return err;
|
|
21225
|
+
return (a.t.lastOkAt ?? 0) - (b.t.lastOkAt ?? 0);
|
|
21226
|
+
});
|
|
21227
|
+
const worst = ranked[0];
|
|
21228
|
+
const when = worst.t.lastOkAt ? `${ago(now - worst.t.lastOkAt)} ago` : "never";
|
|
21229
|
+
const why = worst.t.lastError ? ` (${worst.t.lastError})` : "";
|
|
21230
|
+
reasons.push(`nothing has synced since ${when}${why}`);
|
|
21231
|
+
}
|
|
21232
|
+
if (reasons.length === 0)
|
|
21233
|
+
return { ok: true, summary: null, reasons: [] };
|
|
21234
|
+
return {
|
|
21235
|
+
ok: false,
|
|
21236
|
+
summary: `chat-recall is not syncing: ${reasons.join("; ")}.`,
|
|
21237
|
+
reasons
|
|
21238
|
+
};
|
|
21239
|
+
}
|
|
20719
21240
|
|
|
20720
21241
|
// src/recommendation-merge.ts
|
|
20721
21242
|
var INSTRUCTION_KINDS = ["rule", "skill"];
|
|
@@ -20783,7 +21304,7 @@ var _codeindexAvailable = null;
|
|
|
20783
21304
|
function codeindexAvailable() {
|
|
20784
21305
|
if (_codeindexAvailable !== null) return _codeindexAvailable;
|
|
20785
21306
|
try {
|
|
20786
|
-
|
|
21307
|
+
if (!isOnPath("codeindex")) throw new Error("codeindex not on PATH");
|
|
20787
21308
|
_codeindexAvailable = true;
|
|
20788
21309
|
} catch {
|
|
20789
21310
|
_codeindexAvailable = false;
|
|
@@ -20799,8 +21320,10 @@ function withCodeindexHint(body, kind) {
|
|
|
20799
21320
|
return body + hints[kind];
|
|
20800
21321
|
}
|
|
20801
21322
|
function remoteCredentials() {
|
|
21323
|
+
const fromEnv = envCredentials();
|
|
21324
|
+
if (fromEnv) return { base: fromEnv.serverUrl, token: fromEnv.token };
|
|
20802
21325
|
try {
|
|
20803
|
-
const raw =
|
|
21326
|
+
const raw = readFileSync38(join49(getDataDir(), "credentials.json"), "utf-8");
|
|
20804
21327
|
const parsed = JSON.parse(raw);
|
|
20805
21328
|
if (Array.isArray(parsed.targets) && parsed.targets.length) {
|
|
20806
21329
|
const valid = parsed.targets.filter((t) => t?.serverUrl);
|
|
@@ -21013,21 +21536,25 @@ var RecallTeamActivitySchema = z.object({
|
|
|
21013
21536
|
member: z.string().optional().describe("Filter to one teammate by their user id (sub)"),
|
|
21014
21537
|
since_days: z.number().optional().describe("Only activity in the last N days")
|
|
21015
21538
|
});
|
|
21016
|
-
var
|
|
21539
|
+
var TASK_STATUS_FILTER = ["todo", "in_progress", "done", "rejected"];
|
|
21540
|
+
var TASK_STATUS_SETTABLE = ["todo", "in_progress", "done"];
|
|
21017
21541
|
var RecallTasksSchema = z.object({
|
|
21018
21542
|
mine: z.boolean().optional().describe("Only tasks assigned to me"),
|
|
21019
21543
|
project: z.string().optional().describe("Filter to one project_id"),
|
|
21020
|
-
status: z.enum(
|
|
21544
|
+
status: z.enum(TASK_STATUS_FILTER).optional().describe("Filter by status"),
|
|
21545
|
+
detail: z.boolean().optional().describe("Return the full brief per task \u2014 the fix, the file locations and the agent prompt \u2014 plus how to claim and close one. Use this when you intend to DO the tasks, not just list them.")
|
|
21021
21546
|
});
|
|
21022
21547
|
var RecallTaskCreateSchema = z.object({
|
|
21023
21548
|
title: z.string().describe("Task title"),
|
|
21024
21549
|
description: z.string().optional(),
|
|
21025
21550
|
project: z.string().optional().describe("project_id this task belongs to"),
|
|
21026
|
-
assignee: z.string().optional().describe("Teammate user id (sub) to assign; omit to leave unassigned")
|
|
21551
|
+
assignee: z.string().optional().describe("Teammate user id (sub) to assign; omit to leave unassigned"),
|
|
21552
|
+
due: z.number().optional().describe("Due date, epoch milliseconds. Set one when the work is time-bound; omit otherwise."),
|
|
21553
|
+
linked_finding_id: z.string().optional().describe("The code finding this task comes from (ca_\u2026) \u2014 lets the card auto-close and dedupe.")
|
|
21027
21554
|
});
|
|
21028
21555
|
var RecallTaskUpdateSchema = z.object({
|
|
21029
21556
|
id: z.string().describe("Task id (t_\u2026)"),
|
|
21030
|
-
status: z.enum(
|
|
21557
|
+
status: z.enum(TASK_STATUS_SETTABLE).optional(),
|
|
21031
21558
|
assignee: z.string().optional().describe("Reassign to this user id (sub); empty string unassigns"),
|
|
21032
21559
|
title: z.string().optional(),
|
|
21033
21560
|
comment: z.string().optional().describe("Add a comment to the task"),
|
|
@@ -21126,7 +21653,13 @@ var RecallWakeUpSchema = z.object({
|
|
|
21126
21653
|
max_facts: z.number().optional().default(10).describe("How many high-importance classifier hits to include"),
|
|
21127
21654
|
max_kg_facts: z.number().optional().default(15).describe("How many current knowledge-graph facts to include"),
|
|
21128
21655
|
identity: z.string().optional().describe('Optional override for the identity blurb. Defaults to <data dir>/identity.txt or "AI coding assistant"'),
|
|
21129
|
-
project_filter: z.string().optional().describe("Scope facts
|
|
21656
|
+
project_filter: z.string().optional().describe("Scope facts, KG entities and the task count to a project (substring match against project_path / entity name). Without this, facts are global and bleed across unrelated projects."),
|
|
21657
|
+
// Alias. Its sibling tools (recall_tasks, recall_project_context) all take
|
|
21658
|
+
// `project`, and passing that here used to be silently ignored: no error, and
|
|
21659
|
+
// a WHOLE-TENANT answer that looks exactly like a scoped one. That is the
|
|
21660
|
+
// failure this tool exists to prevent — being told about another project's
|
|
21661
|
+
// backlog — so accepting both names is worth more than naming purity.
|
|
21662
|
+
project: z.string().optional().describe("Alias for project_filter.")
|
|
21130
21663
|
});
|
|
21131
21664
|
var RecallSetSchema = z.object({
|
|
21132
21665
|
key: z.string().describe('Key name (e.g. "current-pr", "default-test-runner")'),
|
|
@@ -21164,7 +21697,7 @@ var server = new Server(
|
|
|
21164
21697
|
name: "chat-recall",
|
|
21165
21698
|
// Resolves to packages/cli/package.json from both src/ and the bundled dist/
|
|
21166
21699
|
version: JSON.parse(
|
|
21167
|
-
|
|
21700
|
+
readFileSync38(new URL("../package.json", import.meta.url), "utf-8")
|
|
21168
21701
|
).version
|
|
21169
21702
|
},
|
|
21170
21703
|
{
|
|
@@ -21209,6 +21742,59 @@ var LEAN_TOOLS = /* @__PURE__ */ new Set([
|
|
|
21209
21742
|
function toolProfile() {
|
|
21210
21743
|
return (process.env.CHAT_RECALL_MCP_PROFILE || "").toLowerCase() === "full" ? "full" : "lean";
|
|
21211
21744
|
}
|
|
21745
|
+
var WRITE_TOOLS = /* @__PURE__ */ new Set([
|
|
21746
|
+
"recall_index",
|
|
21747
|
+
// indexes and ships new rows
|
|
21748
|
+
"recall_code_index",
|
|
21749
|
+
// runs the analyzer, then syncs findings
|
|
21750
|
+
"recall_kg_add",
|
|
21751
|
+
"recall_kg_invalidate",
|
|
21752
|
+
"recall_diary_write",
|
|
21753
|
+
"recall_decision_record",
|
|
21754
|
+
"recall_set",
|
|
21755
|
+
"recall_task_create",
|
|
21756
|
+
"recall_task_update",
|
|
21757
|
+
"recall_task_comment",
|
|
21758
|
+
"recall_security_dismiss",
|
|
21759
|
+
"recall_reclassify",
|
|
21760
|
+
// rewrites classifier tags on indexed chunks
|
|
21761
|
+
"recall_regenerate_summary",
|
|
21762
|
+
// overwrites a stored summary
|
|
21763
|
+
"recall_rename_session"
|
|
21764
|
+
// overwrites the session name
|
|
21765
|
+
]);
|
|
21766
|
+
var DESTRUCTIVE_TOOLS = /* @__PURE__ */ new Set([
|
|
21767
|
+
"recall_kg_invalidate",
|
|
21768
|
+
"recall_reclassify",
|
|
21769
|
+
"recall_regenerate_summary",
|
|
21770
|
+
"recall_rename_session",
|
|
21771
|
+
"recall_security_dismiss"
|
|
21772
|
+
]);
|
|
21773
|
+
var IDEMPOTENT_TOOLS = /* @__PURE__ */ new Set([
|
|
21774
|
+
"recall_set",
|
|
21775
|
+
"recall_kg_invalidate",
|
|
21776
|
+
"recall_rename_session",
|
|
21777
|
+
"recall_security_dismiss",
|
|
21778
|
+
"recall_reclassify",
|
|
21779
|
+
"recall_task_update"
|
|
21780
|
+
]);
|
|
21781
|
+
function toolTitle(name) {
|
|
21782
|
+
const words = name.replace(/^recall_/, "").replace(/_/g, " ");
|
|
21783
|
+
return words.charAt(0).toUpperCase() + words.slice(1);
|
|
21784
|
+
}
|
|
21785
|
+
function annotate(t) {
|
|
21786
|
+
const writes = WRITE_TOOLS.has(t.name);
|
|
21787
|
+
return {
|
|
21788
|
+
...t,
|
|
21789
|
+
annotations: {
|
|
21790
|
+
title: toolTitle(t.name),
|
|
21791
|
+
readOnlyHint: !writes,
|
|
21792
|
+
destructiveHint: DESTRUCTIVE_TOOLS.has(t.name),
|
|
21793
|
+
idempotentHint: writes ? IDEMPOTENT_TOOLS.has(t.name) : true,
|
|
21794
|
+
openWorldHint: true
|
|
21795
|
+
}
|
|
21796
|
+
};
|
|
21797
|
+
}
|
|
21212
21798
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
21213
21799
|
const all = [
|
|
21214
21800
|
{
|
|
@@ -21575,17 +22161,28 @@ or standup/status. Filter by project, by member, or by recency (since_days).`,
|
|
|
21575
22161
|
},
|
|
21576
22162
|
{
|
|
21577
22163
|
name: "recall_tasks",
|
|
21578
|
-
description: `List
|
|
22164
|
+
description: `List the task board \u2014 and, with detail, the work itself.
|
|
22165
|
+
|
|
22166
|
+
Without \`detail\`: one line per card (title, id, assignee). Use for "what's on
|
|
22167
|
+
the team's plate", "my tasks", or to find a task id to update.
|
|
22168
|
+
|
|
22169
|
+
With \`detail: true\`: the full brief per open card \u2014 the fix, the file
|
|
22170
|
+
locations and the agent prompt that the auto-filer already wrote \u2014 plus how to
|
|
22171
|
+
claim a card and how it gets closed. Use that whenever you intend to DO the
|
|
22172
|
+
work rather than report on it.
|
|
21579
22173
|
|
|
21580
|
-
|
|
21581
|
-
|
|
21582
|
-
project / status.`,
|
|
22174
|
+
Closing is earned: 'done' is refused without a linked session. Rejecting is the
|
|
22175
|
+
user's call, never yours.`,
|
|
21583
22176
|
inputSchema: {
|
|
21584
22177
|
type: "object",
|
|
21585
22178
|
properties: {
|
|
21586
22179
|
mine: { type: "boolean", description: "Only tasks assigned to me" },
|
|
21587
22180
|
project: { type: "string", description: "Filter to one project_id" },
|
|
21588
|
-
status: { type: "string", enum: [...
|
|
22181
|
+
status: { type: "string", enum: [...TASK_STATUS_FILTER], description: "Filter by status" },
|
|
22182
|
+
detail: {
|
|
22183
|
+
type: "boolean",
|
|
22184
|
+
description: "Return the full brief per task \u2014 the fix, the file locations and the agent prompt \u2014 plus how to claim and close one. Use this when you intend to DO the tasks, not just list them."
|
|
22185
|
+
}
|
|
21589
22186
|
}
|
|
21590
22187
|
}
|
|
21591
22188
|
},
|
|
@@ -21603,7 +22200,9 @@ lets the board verify the work actually shipped.`,
|
|
|
21603
22200
|
title: { type: "string", description: "Task title" },
|
|
21604
22201
|
description: { type: "string" },
|
|
21605
22202
|
project: { type: "string", description: "project_id this task belongs to" },
|
|
21606
|
-
assignee: { type: "string", description: "Teammate user id (sub) to assign" }
|
|
22203
|
+
assignee: { type: "string", description: "Teammate user id (sub) to assign" },
|
|
22204
|
+
due: { type: "number", description: "Due date, epoch milliseconds. Set one when the work is time-bound; omit otherwise." },
|
|
22205
|
+
linked_finding_id: { type: "string", description: "The code finding this task comes from (ca_\u2026). Setting it lets the card close itself when a re-index stops reporting the finding, and dedupes against an existing card for the same finding." }
|
|
21607
22206
|
},
|
|
21608
22207
|
required: ["title"]
|
|
21609
22208
|
}
|
|
@@ -21623,7 +22222,7 @@ WORKFLOW \u2014 do this whenever the user asks you to work on a task from the bo
|
|
|
21623
22222
|
type: "object",
|
|
21624
22223
|
properties: {
|
|
21625
22224
|
id: { type: "string", description: "Task id (t_\u2026)" },
|
|
21626
|
-
status: { type: "string", enum: [...
|
|
22225
|
+
status: { type: "string", enum: [...TASK_STATUS_SETTABLE], description: "Set the card's state. There is no 'rejected' here on purpose: rejecting is the user's verdict, not yours." },
|
|
21627
22226
|
assignee: { type: "string", description: "Reassign to this user id (sub)" },
|
|
21628
22227
|
title: { type: "string" },
|
|
21629
22228
|
comment: { type: "string", description: "Add a comment" },
|
|
@@ -21922,7 +22521,8 @@ the start of a session to "remember who you are and what's true right now".`,
|
|
|
21922
22521
|
max_facts: { type: "number", default: 10 },
|
|
21923
22522
|
max_kg_facts: { type: "number", default: 15 },
|
|
21924
22523
|
identity: { type: "string" },
|
|
21925
|
-
project_filter: { type: "string", description: "Scope facts
|
|
22524
|
+
project_filter: { type: "string", description: "Scope facts, KG entities and the task count to a project (substring match). Without it, facts are global." },
|
|
22525
|
+
project: { type: "string", description: "Alias for project_filter \u2014 the name every sibling tool uses." }
|
|
21926
22526
|
}
|
|
21927
22527
|
}
|
|
21928
22528
|
},
|
|
@@ -22115,7 +22715,7 @@ Complements recall_memory_search: search finds candidates, this reads the specif
|
|
|
22115
22715
|
inputSchema: { type: "object", properties: {} }
|
|
22116
22716
|
}
|
|
22117
22717
|
];
|
|
22118
|
-
if (toolProfile() === "full") return { tools: all };
|
|
22718
|
+
if (toolProfile() === "full") return { tools: all.map(annotate) };
|
|
22119
22719
|
const lean = all.filter((t) => LEAN_TOOLS.has(t.name));
|
|
22120
22720
|
const hidden = all.length - lean.length;
|
|
22121
22721
|
if (hidden > 0) {
|
|
@@ -22125,7 +22725,7 @@ Complements recall_memory_search: search finds candidates, this reads the specif
|
|
|
22125
22725
|
inputSchema: { type: "object", properties: {} }
|
|
22126
22726
|
});
|
|
22127
22727
|
}
|
|
22128
|
-
return { tools: lean };
|
|
22728
|
+
return { tools: lean.map(annotate) };
|
|
22129
22729
|
});
|
|
22130
22730
|
var syncStateCache = null;
|
|
22131
22731
|
var SYNC_STATE_TTL_MS = 5 * 60 * 1e3;
|
|
@@ -22157,8 +22757,13 @@ async function syncState() {
|
|
|
22157
22757
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
22158
22758
|
const result = await dispatchTool(request);
|
|
22159
22759
|
try {
|
|
22160
|
-
const
|
|
22161
|
-
|
|
22760
|
+
const health = judgeHealth(readCollectorHealth());
|
|
22761
|
+
const banners = [
|
|
22762
|
+
health.ok ? null : `\u26A0 ${health.summary} Recent work may be missing from these answers. Tell the user, and suggest \`chat-recall doctor\`.`,
|
|
22763
|
+
stalenessBanner(await syncState())
|
|
22764
|
+
].filter(Boolean);
|
|
22765
|
+
if (banners.length === 0) return result;
|
|
22766
|
+
const banner = banners.join("\n\n");
|
|
22162
22767
|
const content = result.content;
|
|
22163
22768
|
if (!Array.isArray(content) || !content.length) return result;
|
|
22164
22769
|
return { ...result, content: [{ type: "text", text: banner }, ...content] };
|
|
@@ -22288,6 +22893,11 @@ async function dispatchTool(request) {
|
|
|
22288
22893
|
`FTS5 chunks: ${status.totalChunks}`,
|
|
22289
22894
|
`Raw archives: ${sync.rawArchived}`
|
|
22290
22895
|
];
|
|
22896
|
+
{
|
|
22897
|
+
const { updateNotice: updateNotice2 } = await Promise.resolve().then(() => (init_update_notice(), update_notice_exports));
|
|
22898
|
+
const notice = updateNotice2();
|
|
22899
|
+
if (notice) lines.push("", `\u26A0 ${notice}`);
|
|
22900
|
+
}
|
|
22291
22901
|
if (sync.newestSessionAgeMs !== null) {
|
|
22292
22902
|
const mins = Math.round(sync.newestSessionAgeMs / 6e4);
|
|
22293
22903
|
lines.push(`Freshness: newest synced session ${mins} min ago`);
|
|
@@ -23016,21 +23626,67 @@ _Edits stayed local or window was off \u2014 try increasing buffer_minutes._` }]
|
|
|
23016
23626
|
if (params.status) qs.status = params.status;
|
|
23017
23627
|
const { tasks } = await remoteGetQS("/api/tasks", qs);
|
|
23018
23628
|
if (!tasks || tasks.length === 0) return { content: [{ type: "text", text: "No team tasks match." }] };
|
|
23019
|
-
|
|
23020
|
-
|
|
23629
|
+
if (!params.detail) {
|
|
23630
|
+
const lines = tasks.map((t) => `- [${t.status}] ${t.title} \`${t.id}\`${t.projectId ? ` \xB7 ${t.projectId}` : ""}${t.assigneeSub ? ` \xB7 @${t.assigneeSub.slice(0, 8)}` : " \xB7 unassigned"}`);
|
|
23631
|
+
return { content: [{ type: "text", text: `# Team tasks (${tasks.length})
|
|
23632
|
+
|
|
23633
|
+
${lines.join("\n")}
|
|
23021
23634
|
|
|
23022
|
-
|
|
23635
|
+
_Call again with \`detail: true\` for the full brief (fix, locations, agent prompt) so you can start work._` }] };
|
|
23636
|
+
}
|
|
23637
|
+
const open3 = tasks.filter((t) => t.status !== "done" && t.status !== "rejected");
|
|
23638
|
+
const claimed = open3.filter((t) => t.status === "in_progress");
|
|
23639
|
+
const blocks = open3.map((t, i) => {
|
|
23640
|
+
const head = `## ${i + 1}. ${t.title}
|
|
23641
|
+
|
|
23642
|
+
- id: \`${t.id}\` \xB7 status: ${t.status}${t.projectId ? ` \xB7 project: ${t.projectId}` : ""}${t.linkedSessionId ? ` \xB7 already claimed by session ${t.linkedSessionId.slice(0, 8)}` : ""}`;
|
|
23643
|
+
const body = (t.description || "").trim();
|
|
23644
|
+
return body ? `${head}
|
|
23645
|
+
|
|
23646
|
+
${body}` : head;
|
|
23647
|
+
});
|
|
23648
|
+
const howTo = [
|
|
23649
|
+
"---",
|
|
23650
|
+
"",
|
|
23651
|
+
"### Working these tasks",
|
|
23652
|
+
"",
|
|
23653
|
+
'1. Claim one before you touch code: `recall_task_update` with `id`, `status: "in_progress"`',
|
|
23654
|
+
" and `linked_session_id` set to YOUR current session id.",
|
|
23655
|
+
"2. Do the work. Each brief above carries the fix and, where the task came from a code finding,",
|
|
23656
|
+
" an agent prompt written for exactly this.",
|
|
23657
|
+
'3. Close it with `recall_task_update` `status: "done"` and a `comment` saying what you changed.',
|
|
23658
|
+
"",
|
|
23659
|
+
"The session link is not bookkeeping: **done is refused without it**. A card asserts a problem",
|
|
23660
|
+
"exists in the code, so closing one asserts the code changed, and the board shows the files,",
|
|
23661
|
+
"lines and commits from your session as the evidence. A person cannot mark these done by hand.",
|
|
23662
|
+
"",
|
|
23663
|
+
"If a task is wrong \u2014 not a real problem, or not worth doing \u2014 do NOT close it. Tell the user;",
|
|
23664
|
+
"rejecting is their call, and it dismisses the finding so it stops being re-filed.",
|
|
23665
|
+
"",
|
|
23666
|
+
"Auto-filed cards also close themselves once a re-index no longer reports their finding, so a",
|
|
23667
|
+
"real fix ends the task either way."
|
|
23668
|
+
].join("\n");
|
|
23669
|
+
const header = `# Tasks ready to work (${open3.length}${tasks.length !== open3.length ? ` of ${tasks.length}` : ""})${params.project ? ` \xB7 ${params.project}` : ""}${claimed.length ? `
|
|
23670
|
+
|
|
23671
|
+
_${claimed.length} already in progress \u2014 check the session link before starting one of those._` : ""}`;
|
|
23672
|
+
return { content: [{ type: "text", text: `${header}
|
|
23673
|
+
|
|
23674
|
+
${blocks.join("\n\n")}
|
|
23675
|
+
|
|
23676
|
+
${howTo}` }] };
|
|
23023
23677
|
}
|
|
23024
23678
|
case "recall_task_create": {
|
|
23025
23679
|
const params = RecallTaskCreateSchema.parse(args);
|
|
23026
23680
|
requireRemote();
|
|
23027
|
-
const { task } = await remotePost("/api/tasks", {
|
|
23681
|
+
const { task, deduped } = await remotePost("/api/tasks", {
|
|
23028
23682
|
title: params.title,
|
|
23029
23683
|
description: params.description,
|
|
23030
23684
|
projectId: params.project,
|
|
23031
|
-
assigneeSub: params.assignee ?? null
|
|
23685
|
+
assigneeSub: params.assignee ?? null,
|
|
23686
|
+
due: params.due,
|
|
23687
|
+
linkedFindingId: params.linked_finding_id
|
|
23032
23688
|
});
|
|
23033
|
-
return { content: [{ type: "text", text: `Created task \`${task.id}\`: ${task.title}` }] };
|
|
23689
|
+
return { content: [{ type: "text", text: deduped ? `A task for that finding already exists: \`${task.id}\`: ${task.title}` : `Created task \`${task.id}\`: ${task.title}` }] };
|
|
23034
23690
|
}
|
|
23035
23691
|
case "recall_task_update": {
|
|
23036
23692
|
const params = RecallTaskUpdateSchema.parse(args);
|
|
@@ -23713,8 +24369,8 @@ Subject: ${params.subject}`;
|
|
|
23713
24369
|
`];
|
|
23714
24370
|
for (const r of rows) {
|
|
23715
24371
|
const preview = r.value.length > 80 ? r.value.slice(0, 80) + "\u2026" : r.value;
|
|
23716
|
-
const
|
|
23717
|
-
lines.push(`- **${r.scope}:${r.key}** \u2014 ${preview} _(${
|
|
24372
|
+
const ago3 = Math.floor((Date.now() - r.updated_at) / 1e3);
|
|
24373
|
+
lines.push(`- **${r.scope}:${r.key}** \u2014 ${preview} _(${ago3}s ago)_`);
|
|
23718
24374
|
}
|
|
23719
24375
|
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
23720
24376
|
}
|
|
@@ -23724,11 +24380,11 @@ Subject: ${params.subject}`;
|
|
|
23724
24380
|
{ scope, key: params.key }
|
|
23725
24381
|
);
|
|
23726
24382
|
if (!row) return { content: [{ type: "text", text: `(no value at ${scope}:${params.key})` }] };
|
|
23727
|
-
const
|
|
24383
|
+
const ago2 = Math.floor((Date.now() - row.updated_at) / 1e3);
|
|
23728
24384
|
return {
|
|
23729
24385
|
content: [{
|
|
23730
24386
|
type: "text",
|
|
23731
|
-
text: `${scope}:${params.key} (set ${
|
|
24387
|
+
text: `${scope}:${params.key} (set ${ago2}s ago)
|
|
23732
24388
|
|
|
23733
24389
|
${row.value}`
|
|
23734
24390
|
}]
|
|
@@ -23736,13 +24392,14 @@ ${row.value}`
|
|
|
23736
24392
|
}
|
|
23737
24393
|
// ── Wake-up context ────────────────────────────────────────
|
|
23738
24394
|
case "recall_wake_up": {
|
|
23739
|
-
const
|
|
24395
|
+
const parsedWake = RecallWakeUpSchema.parse(args);
|
|
24396
|
+
const params = { ...parsedWake, project_filter: parsedWake.project_filter ?? parsedWake.project };
|
|
23740
24397
|
let identity = params.identity ?? "AI coding assistant";
|
|
23741
24398
|
if (!params.identity) {
|
|
23742
24399
|
const idFile = getIdentityFilePath();
|
|
23743
|
-
if (
|
|
24400
|
+
if (existsSync44(idFile)) {
|
|
23744
24401
|
try {
|
|
23745
|
-
identity =
|
|
24402
|
+
identity = readFileSync38(idFile, "utf-8").trim() || identity;
|
|
23746
24403
|
} catch {
|
|
23747
24404
|
}
|
|
23748
24405
|
}
|
|
@@ -23766,8 +24423,12 @@ ${row.value}`
|
|
|
23766
24423
|
});
|
|
23767
24424
|
const ot = wake.openTasks;
|
|
23768
24425
|
if (ot && ot.total > 0) {
|
|
24426
|
+
const scope = ot.scope;
|
|
23769
24427
|
lines.push("## Task board");
|
|
23770
|
-
lines.push(` ${ot.total} open task(s)${ot.auto ? ` \u2014 ${ot.auto} auto-filed from code findings` : ""}
|
|
24428
|
+
lines.push(` ${ot.total} open task(s)${scope ? ` in \`${scope}\`` : ""}${ot.auto ? ` \u2014 ${ot.auto} auto-filed from code findings` : ""}.`);
|
|
24429
|
+
lines.push(` Offer to work them: \`recall_tasks\` with \`detail: true\`${scope ? ` and \`project\`` : ""} returns each task's fix, file locations and agent prompt.`);
|
|
24430
|
+
lines.push(' Claim one before editing: `recall_task_update` with `status: "in_progress"` and your session id as `linked_session_id`.');
|
|
24431
|
+
lines.push(" You close them, not the user: `done` is refused without a linked session, because the board shows the diff behind it.");
|
|
23771
24432
|
lines.push("");
|
|
23772
24433
|
}
|
|
23773
24434
|
if (wake.highFacts.length > 0) {
|
|
@@ -24151,6 +24812,21 @@ function startBackgroundSync() {
|
|
|
24151
24812
|
setTimeout(() => {
|
|
24152
24813
|
void tick("full");
|
|
24153
24814
|
}, 15e3).unref();
|
|
24815
|
+
const updateTick = async () => {
|
|
24816
|
+
try {
|
|
24817
|
+
const { refreshUpdateCheck: refreshUpdateCheck2, updateNotice: updateNotice2 } = await Promise.resolve().then(() => (init_update_notice(), update_notice_exports));
|
|
24818
|
+
await refreshUpdateCheck2();
|
|
24819
|
+
const notice = updateNotice2();
|
|
24820
|
+
if (notice) console.error(`[mcp] ${notice}`);
|
|
24821
|
+
} catch {
|
|
24822
|
+
}
|
|
24823
|
+
};
|
|
24824
|
+
setTimeout(() => {
|
|
24825
|
+
void updateTick();
|
|
24826
|
+
}, 2e4).unref();
|
|
24827
|
+
setInterval(() => {
|
|
24828
|
+
void updateTick();
|
|
24829
|
+
}, 6 * 60 * 60 * 1e3).unref();
|
|
24154
24830
|
}
|
|
24155
24831
|
function installCrashGuards() {
|
|
24156
24832
|
process.on("unhandledRejection", (reason) => {
|