chat-recall 0.5.4 → 0.5.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +1506 -733
- package/dist/cli.js.map +1 -1
- package/dist/mcp-diagnostics.d.ts +45 -0
- package/dist/mcp-diagnostics.d.ts.map +1 -0
- package/dist/mcp-diagnostics.js +98 -0
- package/dist/mcp-diagnostics.js.map +1 -0
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +2096 -1151
- package/dist/mcp.js.map +1 -1
- package/dist/project-tasks.d.ts.map +1 -1
- package/dist/project-tasks.js +12 -7
- package/dist/project-tasks.js.map +1 -1
- package/dist/service-installer.d.ts +1 -1
- package/dist/service-installer.d.ts.map +1 -1
- package/dist/service-installer.js +20 -6
- package/dist/service-installer.js.map +1 -1
- package/dist/sync-client.d.ts +1 -0
- package/dist/sync-client.d.ts.map +1 -1
- package/dist/sync-client.js +179 -92
- package/dist/sync-client.js.map +1 -1
- package/dist/sync-ledger.d.ts +22 -0
- package/dist/sync-ledger.d.ts.map +1 -1
- package/dist/sync-ledger.js +108 -1
- package/dist/sync-ledger.js.map +1 -1
- package/dist/watch.js +1104 -481
- package/hooks/chat_recall_escalate_hook.sh +28 -2
- package/hooks/chat_recall_save_hook.sh +17 -11
- package/hooks/chat_recall_wakeup_hook.sh +27 -1
- package/package.json +7 -3
- package/skills/chat-recall/SKILL.md +3 -2
package/dist/watch.js
CHANGED
|
@@ -2110,7 +2110,7 @@ var require_thread_stream = __commonJS({
|
|
|
2110
2110
|
var { version } = 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: sep4 } = __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() + sep4 : 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 = `
|
|
@@ -4721,7 +4721,8 @@ function defaultSync() {
|
|
|
4721
4721
|
function isPersonalPath(projectPath, includeProjects = []) {
|
|
4722
4722
|
if (includeProjects.some((inc) => inc && projectPath.includes(inc)))
|
|
4723
4723
|
return false;
|
|
4724
|
-
|
|
4724
|
+
const norm = (projectPath.replace(/\\/g, "/") + "/").toLowerCase();
|
|
4725
|
+
return PERSONAL_DIR_NAMES.some((n) => norm.includes(`/${n.toLowerCase()}/`));
|
|
4725
4726
|
}
|
|
4726
4727
|
function defaultTeam() {
|
|
4727
4728
|
return {
|
|
@@ -4843,6 +4844,16 @@ function loadSecrets() {
|
|
|
4843
4844
|
const p = secretsPath();
|
|
4844
4845
|
if (!existsSync2(p))
|
|
4845
4846
|
return out;
|
|
4847
|
+
let mtimeMs = -1, size = -1;
|
|
4848
|
+
try {
|
|
4849
|
+
const st = statSync2(p);
|
|
4850
|
+
mtimeMs = st.mtimeMs;
|
|
4851
|
+
size = st.size;
|
|
4852
|
+
} catch {
|
|
4853
|
+
}
|
|
4854
|
+
if (_secretsCache && _secretsCache.mtimeMs === mtimeMs && _secretsCache.size === size) {
|
|
4855
|
+
return { ..._secretsCache.value };
|
|
4856
|
+
}
|
|
4846
4857
|
try {
|
|
4847
4858
|
for (const line of readFileSync(p, "utf-8").split("\n")) {
|
|
4848
4859
|
const t = line.trim();
|
|
@@ -4860,9 +4871,12 @@ function loadSecrets() {
|
|
|
4860
4871
|
}
|
|
4861
4872
|
} catch {
|
|
4862
4873
|
}
|
|
4874
|
+
if (mtimeMs >= 0)
|
|
4875
|
+
_secretsCache = { mtimeMs, size, value: { ...out } };
|
|
4863
4876
|
return out;
|
|
4864
4877
|
}
|
|
4865
4878
|
function writeSecrets(secrets) {
|
|
4879
|
+
_secretsCache = null;
|
|
4866
4880
|
const p = secretsPath();
|
|
4867
4881
|
mkdirSync2(dirname2(p), { recursive: true });
|
|
4868
4882
|
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";
|
|
@@ -4872,10 +4886,31 @@ function writeSecrets(secrets) {
|
|
|
4872
4886
|
} catch {
|
|
4873
4887
|
}
|
|
4874
4888
|
}
|
|
4889
|
+
function applySecretOverlay(result) {
|
|
4890
|
+
const secrets = loadSecrets();
|
|
4891
|
+
for (const { block, field, env } of SECRET_FIELDS) {
|
|
4892
|
+
const blk = result[block];
|
|
4893
|
+
const value = process.env[env] || secrets[env] || blk[field];
|
|
4894
|
+
if (value)
|
|
4895
|
+
blk[field] = value;
|
|
4896
|
+
}
|
|
4897
|
+
return result;
|
|
4898
|
+
}
|
|
4875
4899
|
function loadSettings() {
|
|
4876
4900
|
const path = settingsPath();
|
|
4877
4901
|
if (!existsSync2(path))
|
|
4878
4902
|
return freshDefaults();
|
|
4903
|
+
let mtimeMs = -1, size = -1;
|
|
4904
|
+
try {
|
|
4905
|
+
const st = statSync2(path);
|
|
4906
|
+
mtimeMs = st.mtimeMs;
|
|
4907
|
+
size = st.size;
|
|
4908
|
+
} catch {
|
|
4909
|
+
}
|
|
4910
|
+
if (_settingsCache && _settingsCache.mtimeMs === mtimeMs && _settingsCache.size === size) {
|
|
4911
|
+
const cached = structuredClone(_settingsCache.value);
|
|
4912
|
+
return applySecretOverlay(cached);
|
|
4913
|
+
}
|
|
4879
4914
|
try {
|
|
4880
4915
|
const parsed = JSON.parse(readFileSync(path, "utf-8"));
|
|
4881
4916
|
const base2 = freshDefaults();
|
|
@@ -4888,19 +4923,15 @@ function loadSettings() {
|
|
|
4888
4923
|
sync: mergeSync(base2.sync, parsed.sync),
|
|
4889
4924
|
team: mergeTeam(base2.team, parsed.team)
|
|
4890
4925
|
};
|
|
4891
|
-
|
|
4892
|
-
|
|
4893
|
-
|
|
4894
|
-
const value = process.env[env] || secrets[env] || blk[field];
|
|
4895
|
-
if (value)
|
|
4896
|
-
blk[field] = value;
|
|
4897
|
-
}
|
|
4898
|
-
return result;
|
|
4926
|
+
if (mtimeMs >= 0)
|
|
4927
|
+
_settingsCache = { mtimeMs, size, value: structuredClone(result) };
|
|
4928
|
+
return applySecretOverlay(result);
|
|
4899
4929
|
} catch {
|
|
4900
4930
|
return freshDefaults();
|
|
4901
4931
|
}
|
|
4902
4932
|
}
|
|
4903
4933
|
function saveSettings(settings2) {
|
|
4934
|
+
_settingsCache = null;
|
|
4904
4935
|
const secrets = loadSecrets();
|
|
4905
4936
|
const stripped = {
|
|
4906
4937
|
...settings2,
|
|
@@ -4924,7 +4955,7 @@ function saveSettings(settings2) {
|
|
|
4924
4955
|
} catch {
|
|
4925
4956
|
}
|
|
4926
4957
|
}
|
|
4927
|
-
var CLI_DETECTION_ORDER, SCHEMA_VERSION, PERSONAL_DIR_PATTERNS, _sourceSettingsCache, SECRET_FIELDS;
|
|
4958
|
+
var CLI_DETECTION_ORDER, SCHEMA_VERSION, PERSONAL_DIR_NAMES, PERSONAL_DIR_PATTERNS, _sourceSettingsCache, SECRET_FIELDS, _secretsCache, _settingsCache;
|
|
4928
4959
|
var init_settings = __esm({
|
|
4929
4960
|
"../engine/dist/core/settings.js"() {
|
|
4930
4961
|
"use strict";
|
|
@@ -4938,17 +4969,18 @@ var init_settings = __esm({
|
|
|
4938
4969
|
{ preset: "aichat", bin: "aichat", cmd: "aichat --no-stream" }
|
|
4939
4970
|
];
|
|
4940
4971
|
SCHEMA_VERSION = 3;
|
|
4941
|
-
|
|
4942
|
-
"
|
|
4943
|
-
"
|
|
4944
|
-
"
|
|
4945
|
-
"
|
|
4946
|
-
"
|
|
4947
|
-
"
|
|
4948
|
-
"
|
|
4949
|
-
"
|
|
4950
|
-
"
|
|
4972
|
+
PERSONAL_DIR_NAMES = [
|
|
4973
|
+
"Pictures",
|
|
4974
|
+
"Music",
|
|
4975
|
+
"Movies",
|
|
4976
|
+
"Videos",
|
|
4977
|
+
"Photos Library",
|
|
4978
|
+
"Documents",
|
|
4979
|
+
"Desktop",
|
|
4980
|
+
"Downloads",
|
|
4981
|
+
"Library"
|
|
4951
4982
|
];
|
|
4983
|
+
PERSONAL_DIR_PATTERNS = PERSONAL_DIR_NAMES.map((n) => `/${n}/`);
|
|
4952
4984
|
_sourceSettingsCache = null;
|
|
4953
4985
|
SECRET_FIELDS = [
|
|
4954
4986
|
{ block: "summary", field: "apiKey", env: "SUMMARY_API_KEY" },
|
|
@@ -4959,6 +4991,8 @@ var init_settings = __esm({
|
|
|
4959
4991
|
{ block: "embedding", field: "ollamaCloudApiKey", env: "OLLAMA_API_KEY" },
|
|
4960
4992
|
{ block: "embedding", field: "openaiCompatApiKey", env: "OPENAI_COMPAT_API_KEY" }
|
|
4961
4993
|
];
|
|
4994
|
+
_secretsCache = null;
|
|
4995
|
+
_settingsCache = null;
|
|
4962
4996
|
}
|
|
4963
4997
|
});
|
|
4964
4998
|
|
|
@@ -5048,14 +5082,14 @@ function primaryHomes() {
|
|
|
5048
5082
|
s = void 0;
|
|
5049
5083
|
}
|
|
5050
5084
|
const opencodeDb = env.CHAT_RECALL_OPENCODE_DB || s?.opencodeDbPath || join3(home, ".local", "share", "opencode", "opencode.db");
|
|
5051
|
-
const
|
|
5085
|
+
const candidates2 = [
|
|
5052
5086
|
env.CHAT_RECALL_CLAUDE_HOME || s?.claudeHome || join3(home, ".claude"),
|
|
5053
5087
|
env.CHAT_RECALL_GEMINI_HOME || s?.geminiHome || join3(home, ".gemini"),
|
|
5054
5088
|
env.CHAT_RECALL_CODEX_HOME || s?.codexHome || join3(home, ".codex"),
|
|
5055
5089
|
env.CHAT_RECALL_AGY_HOME || s?.agyHome || join3(home, ".gemini", "antigravity-cli"),
|
|
5056
5090
|
dirOf(opencodeDb)
|
|
5057
5091
|
];
|
|
5058
|
-
return
|
|
5092
|
+
return candidates2.map(normalizeHomePath);
|
|
5059
5093
|
}
|
|
5060
5094
|
function homeDecision(path) {
|
|
5061
5095
|
const p = normalizeHomePath(path);
|
|
@@ -5408,28 +5442,55 @@ function maskSecret(s) {
|
|
|
5408
5442
|
return "*".repeat(s.length);
|
|
5409
5443
|
return "*".repeat(Math.min(s.length - 4, 60)) + s.slice(-4);
|
|
5410
5444
|
}
|
|
5445
|
+
function globalRegexFor(pattern) {
|
|
5446
|
+
const flags = pattern.flags.includes("g") ? pattern.flags : pattern.flags + "g";
|
|
5447
|
+
const key = pattern.source + "\0" + flags;
|
|
5448
|
+
let re = globalRegexCache.get(key);
|
|
5449
|
+
if (!re) {
|
|
5450
|
+
re = new RegExp(pattern.source, flags);
|
|
5451
|
+
globalRegexCache.set(key, re);
|
|
5452
|
+
}
|
|
5453
|
+
return re;
|
|
5454
|
+
}
|
|
5455
|
+
function makeLineResolver(text) {
|
|
5456
|
+
const starts = [];
|
|
5457
|
+
for (let i = text.indexOf("\n"); i !== -1; i = text.indexOf("\n", i + 1))
|
|
5458
|
+
starts.push(i);
|
|
5459
|
+
return (index) => {
|
|
5460
|
+
let lo = 0, hi = starts.length;
|
|
5461
|
+
while (lo < hi) {
|
|
5462
|
+
const mid = lo + hi >> 1;
|
|
5463
|
+
if (starts[mid] < index)
|
|
5464
|
+
lo = mid + 1;
|
|
5465
|
+
else
|
|
5466
|
+
hi = mid;
|
|
5467
|
+
}
|
|
5468
|
+
return lo + 1;
|
|
5469
|
+
};
|
|
5470
|
+
}
|
|
5411
5471
|
function scanTextForFindings(text, opts = {}) {
|
|
5412
5472
|
if (!text)
|
|
5413
5473
|
return [];
|
|
5414
5474
|
const rules = opts.rules || activeRules();
|
|
5415
5475
|
const findings = [];
|
|
5416
5476
|
const seenSpans = /* @__PURE__ */ new Set();
|
|
5477
|
+
const lineAt = makeLineResolver(text);
|
|
5417
5478
|
for (const r of rules) {
|
|
5418
|
-
const re =
|
|
5479
|
+
const re = globalRegexFor(r.pattern);
|
|
5480
|
+
re.lastIndex = 0;
|
|
5419
5481
|
let m;
|
|
5420
5482
|
while ((m = re.exec(text)) !== null) {
|
|
5421
5483
|
const span = `${m.index}:${m[0].length}`;
|
|
5422
5484
|
if (!seenSpans.has(span)) {
|
|
5423
5485
|
seenSpans.add(span);
|
|
5424
|
-
|
|
5425
|
-
findings.push({ rule: r.label, line, preview: maskSecret(m[0]) });
|
|
5486
|
+
findings.push({ rule: r.label, line: lineAt(m.index), preview: maskSecret(m[0]) });
|
|
5426
5487
|
}
|
|
5427
5488
|
if (re.lastIndex === m.index)
|
|
5428
5489
|
re.lastIndex++;
|
|
5429
5490
|
}
|
|
5430
5491
|
}
|
|
5431
5492
|
for (const { start, end } of findContextualSecrets(text)) {
|
|
5432
|
-
const line =
|
|
5493
|
+
const line = lineAt(start);
|
|
5433
5494
|
findings.push({ rule: "secret-context", line, preview: maskSecret(text.slice(start, end)) });
|
|
5434
5495
|
}
|
|
5435
5496
|
return findings;
|
|
@@ -5460,7 +5521,7 @@ function redactToolResultBody(toolName, body) {
|
|
|
5460
5521
|
return body;
|
|
5461
5522
|
return `[redacted: ${toolName} output, ${body.length} chars]`;
|
|
5462
5523
|
}
|
|
5463
|
-
var DEFAULT_REDACTION_RULES, SECRET_CONTEXT_RE, HIGH_ENTROPY_TOKEN_RE, cache, CANARY, MAX_PACK_RULES, MAX_PATTERN_LEN, serverPack, privacyCache;
|
|
5524
|
+
var DEFAULT_REDACTION_RULES, SECRET_CONTEXT_RE, HIGH_ENTROPY_TOKEN_RE, cache, CANARY, MAX_PACK_RULES, MAX_PATTERN_LEN, serverPack, globalRegexCache, privacyCache;
|
|
5464
5525
|
var init_secret_redactor = __esm({
|
|
5465
5526
|
"../engine/dist/core/secret-redactor.js"() {
|
|
5466
5527
|
"use strict";
|
|
@@ -5598,6 +5659,7 @@ var init_secret_redactor = __esm({
|
|
|
5598
5659
|
MAX_PACK_RULES = 200;
|
|
5599
5660
|
MAX_PATTERN_LEN = 512;
|
|
5600
5661
|
serverPack = null;
|
|
5662
|
+
globalRegexCache = /* @__PURE__ */ new Map();
|
|
5601
5663
|
privacyCache = null;
|
|
5602
5664
|
}
|
|
5603
5665
|
});
|
|
@@ -6141,6 +6203,24 @@ async function parseSessionFile(sessionPath, maxMessages = 50) {
|
|
|
6141
6203
|
}
|
|
6142
6204
|
const filesToParse = hasSubagentsDir(sessionPath) ? [sessionPath, ...getSubagentPaths(sessionPath)] : [sessionPath];
|
|
6143
6205
|
let userCount = 0;
|
|
6206
|
+
const seenPrompts = /* @__PURE__ */ new Set();
|
|
6207
|
+
const recordPrompt = (raw, line, dedupe = false) => {
|
|
6208
|
+
if (userCount >= maxMessages)
|
|
6209
|
+
return;
|
|
6210
|
+
const withoutReminders = raw.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g, "");
|
|
6211
|
+
if (!withoutReminders.trim() || withoutReminders.trim().length <= 10)
|
|
6212
|
+
return;
|
|
6213
|
+
const cleanedText = stripInjectedBanners(withoutReminders).trim();
|
|
6214
|
+
if (cleanedText.length < 10)
|
|
6215
|
+
return;
|
|
6216
|
+
if (dedupe && seenPrompts.has(cleanedText))
|
|
6217
|
+
return;
|
|
6218
|
+
seenPrompts.add(cleanedText);
|
|
6219
|
+
content.userMessages.push({ text: cleanedText, lineNumber: line, contentType: "user" });
|
|
6220
|
+
userCount++;
|
|
6221
|
+
if (!content.firstPrompt)
|
|
6222
|
+
content.firstPrompt = cleanedText.slice(0, 1e3);
|
|
6223
|
+
};
|
|
6144
6224
|
let assistantCount = 0;
|
|
6145
6225
|
let toolCount = 0;
|
|
6146
6226
|
let lineNum = 0;
|
|
@@ -6219,19 +6299,11 @@ async function parseSessionFile(sessionPath, maxMessages = 50) {
|
|
|
6219
6299
|
text = textParts.join("\n");
|
|
6220
6300
|
}
|
|
6221
6301
|
}
|
|
6222
|
-
if (text
|
|
6223
|
-
|
|
6224
|
-
|
|
6225
|
-
|
|
6226
|
-
content
|
|
6227
|
-
text: cleanedText,
|
|
6228
|
-
lineNumber: lineNum,
|
|
6229
|
-
contentType: "user"
|
|
6230
|
-
});
|
|
6231
|
-
userCount++;
|
|
6232
|
-
if (!content.firstPrompt) {
|
|
6233
|
-
content.firstPrompt = cleanedText.slice(0, 1e3);
|
|
6234
|
-
}
|
|
6302
|
+
if (text)
|
|
6303
|
+
recordPrompt(text, lineNum);
|
|
6304
|
+
} else if (msgType === "queue-operation") {
|
|
6305
|
+
if (obj.operation === "enqueue" && typeof obj.content === "string") {
|
|
6306
|
+
recordPrompt(obj.content, lineNum, true);
|
|
6235
6307
|
}
|
|
6236
6308
|
} else if (msgType === "assistant") {
|
|
6237
6309
|
const msg = obj.message;
|
|
@@ -6347,8 +6419,8 @@ function decodeDirName(dirName) {
|
|
|
6347
6419
|
}
|
|
6348
6420
|
for (let len = 2; len <= segments.length - i; len++) {
|
|
6349
6421
|
const joinedSegments = segments.slice(i, i + len);
|
|
6350
|
-
for (const
|
|
6351
|
-
const candidate = join5(currentPath, joinedSegments.join(
|
|
6422
|
+
for (const sep4 of ["-", "_", "."]) {
|
|
6423
|
+
const candidate = join5(currentPath, joinedSegments.join(sep4));
|
|
6352
6424
|
if (existsSync5(candidate)) {
|
|
6353
6425
|
currentPath = candidate;
|
|
6354
6426
|
i += len;
|
|
@@ -7100,7 +7172,7 @@ async function archiveRawSession(store, sessionId) {
|
|
|
7100
7172
|
}
|
|
7101
7173
|
function detectForkPredecessor(sessionPath) {
|
|
7102
7174
|
const { readFileSync: readFileSync41, readdirSync: readdirSync31 } = requireFs();
|
|
7103
|
-
const { dirname:
|
|
7175
|
+
const { dirname: dirname22, join: join50, basename: basename26 } = requirePath();
|
|
7104
7176
|
let text;
|
|
7105
7177
|
try {
|
|
7106
7178
|
text = readFileSync41(sessionPath, "utf-8");
|
|
@@ -7125,7 +7197,7 @@ function detectForkPredecessor(sessionPath) {
|
|
|
7125
7197
|
return null;
|
|
7126
7198
|
if (text.includes(`"uuid":"${headParent}"`))
|
|
7127
7199
|
return null;
|
|
7128
|
-
const dir =
|
|
7200
|
+
const dir = dirname22(sessionPath);
|
|
7129
7201
|
const self = basename26(sessionPath);
|
|
7130
7202
|
let entries;
|
|
7131
7203
|
try {
|
|
@@ -7137,7 +7209,7 @@ function detectForkPredecessor(sessionPath) {
|
|
|
7137
7209
|
if (!f.endsWith(".jsonl") || f === self || f === "sessions-index.json")
|
|
7138
7210
|
continue;
|
|
7139
7211
|
try {
|
|
7140
|
-
if (readFileSync41(
|
|
7212
|
+
if (readFileSync41(join50(dir, f), "utf-8").includes(`"uuid":"${headParent}"`)) {
|
|
7141
7213
|
return basename26(f, ".jsonl");
|
|
7142
7214
|
}
|
|
7143
7215
|
} catch {
|
|
@@ -7341,18 +7413,43 @@ function updateShadow(sessionId, exp) {
|
|
|
7341
7413
|
path
|
|
7342
7414
|
};
|
|
7343
7415
|
}
|
|
7344
|
-
async function snapshotShadow(sessionId) {
|
|
7416
|
+
async function snapshotShadow(sessionId, opts = {}) {
|
|
7345
7417
|
await Promise.resolve().then(() => (init_backends(), backends_exports));
|
|
7346
7418
|
const { getBackendForId: getBackendForId2, getBackend: getBackend2 } = await Promise.resolve().then(() => (init_tool_backend(), tool_backend_exports));
|
|
7347
7419
|
const backend = getBackendForId2(sessionId) ?? getBackend2("claude");
|
|
7348
7420
|
const rawId = backend.toRawId(sessionId);
|
|
7421
|
+
const fp = liveFingerprint(backend, rawId);
|
|
7422
|
+
if (!opts.force && fp && lastLiveFingerprint.get(rawId) === fp) {
|
|
7423
|
+
return {
|
|
7424
|
+
status: "skipped",
|
|
7425
|
+
sessionId,
|
|
7426
|
+
tool: backend.id,
|
|
7427
|
+
container: null,
|
|
7428
|
+
recovered: 0,
|
|
7429
|
+
path: shadowFileFor(backend.id, rawId)
|
|
7430
|
+
};
|
|
7431
|
+
}
|
|
7349
7432
|
let exp = null;
|
|
7350
7433
|
try {
|
|
7351
7434
|
exp = backend.exportRawSession(rawId);
|
|
7352
7435
|
} catch {
|
|
7353
7436
|
exp = null;
|
|
7354
7437
|
}
|
|
7355
|
-
|
|
7438
|
+
const result = updateShadow(rawId, exp);
|
|
7439
|
+
if (fp && result.status !== "unavailable")
|
|
7440
|
+
lastLiveFingerprint.set(rawId, fp);
|
|
7441
|
+
return result;
|
|
7442
|
+
}
|
|
7443
|
+
function liveFingerprint(backend, rawId) {
|
|
7444
|
+
try {
|
|
7445
|
+
const loc = backend.findSession(rawId);
|
|
7446
|
+
if (!loc?.path)
|
|
7447
|
+
return "";
|
|
7448
|
+
const st = statSync5(loc.path);
|
|
7449
|
+
return `${st.mtimeMs}:${st.size}`;
|
|
7450
|
+
} catch {
|
|
7451
|
+
return "";
|
|
7452
|
+
}
|
|
7356
7453
|
}
|
|
7357
7454
|
function seedShadow(sessionId, container) {
|
|
7358
7455
|
const tool = container.tool;
|
|
@@ -7371,7 +7468,7 @@ function shadowSizeOnDisk(tool, rawId) {
|
|
|
7371
7468
|
return 0;
|
|
7372
7469
|
}
|
|
7373
7470
|
}
|
|
7374
|
-
var WHOLE_FILE_TOOLS, SINGLETON_META;
|
|
7471
|
+
var WHOLE_FILE_TOOLS, SINGLETON_META, lastLiveFingerprint;
|
|
7375
7472
|
var init_shadow = __esm({
|
|
7376
7473
|
"../engine/dist/transcript/shadow.js"() {
|
|
7377
7474
|
"use strict";
|
|
@@ -7379,6 +7476,27 @@ var init_shadow = __esm({
|
|
|
7379
7476
|
init_raw();
|
|
7380
7477
|
WHOLE_FILE_TOOLS = /* @__PURE__ */ new Set(["gemini"]);
|
|
7381
7478
|
SINGLETON_META = /* @__PURE__ */ new Set(["mode", "permission-mode", "ai-title", "last-prompt", "pr-link", "summary"]);
|
|
7479
|
+
lastLiveFingerprint = /* @__PURE__ */ new Map();
|
|
7480
|
+
}
|
|
7481
|
+
});
|
|
7482
|
+
|
|
7483
|
+
// ../engine/dist/core/project-dir-name.js
|
|
7484
|
+
function looksWindowsEncoded(dirName) {
|
|
7485
|
+
return /^[A-Za-z]--/.test(dirName);
|
|
7486
|
+
}
|
|
7487
|
+
function decodeProjectDirName(dirName) {
|
|
7488
|
+
if (!dirName)
|
|
7489
|
+
return "";
|
|
7490
|
+
if (looksWindowsEncoded(dirName)) {
|
|
7491
|
+
const drive = dirName[0].toUpperCase();
|
|
7492
|
+
const rest = dirName.slice(3).replace(/-/g, "\\");
|
|
7493
|
+
return `${drive}:\\${rest}`;
|
|
7494
|
+
}
|
|
7495
|
+
return "/" + dirName.replace(/^-/, "").replace(/-/g, "/");
|
|
7496
|
+
}
|
|
7497
|
+
var init_project_dir_name = __esm({
|
|
7498
|
+
"../engine/dist/core/project-dir-name.js"() {
|
|
7499
|
+
"use strict";
|
|
7382
7500
|
}
|
|
7383
7501
|
});
|
|
7384
7502
|
|
|
@@ -7405,7 +7523,7 @@ function findSessionFile(sessionId) {
|
|
|
7405
7523
|
path: candidate,
|
|
7406
7524
|
projectDir: entry.name,
|
|
7407
7525
|
// Project path is encoded by replacing slashes with dashes.
|
|
7408
|
-
projectPath: entry.name
|
|
7526
|
+
projectPath: decodeProjectDirName(entry.name)
|
|
7409
7527
|
};
|
|
7410
7528
|
}
|
|
7411
7529
|
}
|
|
@@ -7434,7 +7552,7 @@ function findSessionFiles(sessionId) {
|
|
|
7434
7552
|
out.push({
|
|
7435
7553
|
path: candidate,
|
|
7436
7554
|
projectDir: entry.name,
|
|
7437
|
-
projectPath: entry.name
|
|
7555
|
+
projectPath: decodeProjectDirName(entry.name)
|
|
7438
7556
|
});
|
|
7439
7557
|
}
|
|
7440
7558
|
}
|
|
@@ -7458,7 +7576,31 @@ function resolveSessionContentGroups(sessionId) {
|
|
|
7458
7576
|
const names = [...groups.keys()].sort((a, b) => a === "main" ? -1 : b === "main" ? 1 : a.localeCompare(b));
|
|
7459
7577
|
return names.map((name) => ({ name, paths: groups.get(name) }));
|
|
7460
7578
|
}
|
|
7579
|
+
function withSessionReadCache(fn) {
|
|
7580
|
+
readScopeDepth++;
|
|
7581
|
+
try {
|
|
7582
|
+
return fn();
|
|
7583
|
+
} finally {
|
|
7584
|
+
if (--readScopeDepth === 0)
|
|
7585
|
+
readScope = null;
|
|
7586
|
+
}
|
|
7587
|
+
}
|
|
7461
7588
|
function readSessionGroupText(group) {
|
|
7589
|
+
let key = "";
|
|
7590
|
+
if (readScopeDepth > 0) {
|
|
7591
|
+
const parts = [];
|
|
7592
|
+
for (const p of group.paths) {
|
|
7593
|
+
try {
|
|
7594
|
+
const st = statSync6(p);
|
|
7595
|
+
parts.push(`${p}:${st.mtimeMs}:${st.size}`);
|
|
7596
|
+
} catch {
|
|
7597
|
+
parts.push(`${p}:missing`);
|
|
7598
|
+
}
|
|
7599
|
+
}
|
|
7600
|
+
key = parts.join("|");
|
|
7601
|
+
if (readScope && readScope.key === key)
|
|
7602
|
+
return readScope.value;
|
|
7603
|
+
}
|
|
7462
7604
|
let text = "";
|
|
7463
7605
|
let mtime = 0;
|
|
7464
7606
|
for (const p of group.paths) {
|
|
@@ -7474,7 +7616,10 @@ function readSessionGroupText(group) {
|
|
|
7474
7616
|
}
|
|
7475
7617
|
text = text ? mergeLineText(text, raw).text : raw;
|
|
7476
7618
|
}
|
|
7477
|
-
|
|
7619
|
+
const out = { text, mtime };
|
|
7620
|
+
if (readScopeDepth > 0 && key)
|
|
7621
|
+
readScope = { key, value: out };
|
|
7622
|
+
return out;
|
|
7478
7623
|
}
|
|
7479
7624
|
function resolveSessionContentPaths(sessionFile) {
|
|
7480
7625
|
if (!hasSubagentsDir(sessionFile))
|
|
@@ -7697,7 +7842,7 @@ function findCodexSessionFileIn(root, sessionId) {
|
|
|
7697
7842
|
}
|
|
7698
7843
|
return scanDir(root);
|
|
7699
7844
|
}
|
|
7700
|
-
var geminiProjectMapCache, MAX_EVENT_LINE_BYTES;
|
|
7845
|
+
var readScope, readScopeDepth, geminiProjectMapCache, MAX_EVENT_LINE_BYTES;
|
|
7701
7846
|
var init_live_session_scan = __esm({
|
|
7702
7847
|
"../engine/dist/core/live-session-scan.js"() {
|
|
7703
7848
|
"use strict";
|
|
@@ -7706,6 +7851,9 @@ var init_live_session_scan = __esm({
|
|
|
7706
7851
|
init_tool_backend();
|
|
7707
7852
|
init_tool_paths();
|
|
7708
7853
|
init_backends();
|
|
7854
|
+
init_project_dir_name();
|
|
7855
|
+
readScope = null;
|
|
7856
|
+
readScopeDepth = 0;
|
|
7709
7857
|
geminiProjectMapCache = null;
|
|
7710
7858
|
MAX_EVENT_LINE_BYTES = 8 * 1024 * 1024;
|
|
7711
7859
|
}
|
|
@@ -8166,74 +8314,123 @@ var init_session_outcome = __esm({
|
|
|
8166
8314
|
}
|
|
8167
8315
|
});
|
|
8168
8316
|
|
|
8317
|
+
// ../engine/dist/core/flat-string.js
|
|
8318
|
+
function flatString(s) {
|
|
8319
|
+
if (!s)
|
|
8320
|
+
return "";
|
|
8321
|
+
if (s.length < 13)
|
|
8322
|
+
return s;
|
|
8323
|
+
return Buffer.from(s, "utf8").toString("utf8");
|
|
8324
|
+
}
|
|
8325
|
+
var init_flat_string = __esm({
|
|
8326
|
+
"../engine/dist/core/flat-string.js"() {
|
|
8327
|
+
"use strict";
|
|
8328
|
+
}
|
|
8329
|
+
});
|
|
8330
|
+
|
|
8169
8331
|
// ../engine/dist/core/first-prompt.js
|
|
8170
|
-
import { createReadStream as createReadStream2, existsSync as existsSync9,
|
|
8332
|
+
import { createReadStream as createReadStream2, existsSync as existsSync9, openSync as openSync3, readSync as readSync3, closeSync as closeSync3 } from "fs";
|
|
8333
|
+
import { StringDecoder } from "string_decoder";
|
|
8171
8334
|
function stripBanners2(s) {
|
|
8172
8335
|
let out = s;
|
|
8173
8336
|
for (const re of BANNERS)
|
|
8174
8337
|
out = out.replace(re, " ");
|
|
8175
8338
|
return out.replace(/[ \t]{2,}/g, " ").trim();
|
|
8176
8339
|
}
|
|
8340
|
+
function promptFromLine(raw, maxLength) {
|
|
8341
|
+
if (!raw.trim())
|
|
8342
|
+
return null;
|
|
8343
|
+
let obj;
|
|
8344
|
+
try {
|
|
8345
|
+
obj = JSON.parse(raw);
|
|
8346
|
+
} catch {
|
|
8347
|
+
return null;
|
|
8348
|
+
}
|
|
8349
|
+
if (obj.type !== "user")
|
|
8350
|
+
return null;
|
|
8351
|
+
if (obj.isSidechain === true)
|
|
8352
|
+
return null;
|
|
8353
|
+
const message = obj.message;
|
|
8354
|
+
if (!message)
|
|
8355
|
+
return null;
|
|
8356
|
+
const content = message.content;
|
|
8357
|
+
let text = "";
|
|
8358
|
+
if (typeof content === "string") {
|
|
8359
|
+
text = content;
|
|
8360
|
+
} else if (Array.isArray(content)) {
|
|
8361
|
+
const parts = [];
|
|
8362
|
+
for (const block of content) {
|
|
8363
|
+
if (block && typeof block === "object" && block.type === "text" && typeof block.text === "string") {
|
|
8364
|
+
parts.push(block.text);
|
|
8365
|
+
}
|
|
8366
|
+
}
|
|
8367
|
+
text = parts.join("\n");
|
|
8368
|
+
}
|
|
8369
|
+
if (!text)
|
|
8370
|
+
return null;
|
|
8371
|
+
if (text.includes("<system-reminder>"))
|
|
8372
|
+
return null;
|
|
8373
|
+
if (text.trim() === "[Request interrupted by user]")
|
|
8374
|
+
return null;
|
|
8375
|
+
const cleaned = stripBanners2(text);
|
|
8376
|
+
if (cleaned.length < 10)
|
|
8377
|
+
return null;
|
|
8378
|
+
return flatString(cleaned.slice(0, maxLength));
|
|
8379
|
+
}
|
|
8177
8380
|
function extractFirstUserPromptSync(filePath, options = {}) {
|
|
8178
8381
|
const maxLines = options.maxLines ?? 500;
|
|
8179
8382
|
const maxLength = options.maxLength ?? 1e3;
|
|
8180
|
-
|
|
8181
|
-
|
|
8182
|
-
let raw;
|
|
8383
|
+
const maxBytes = options.maxBytes ?? 4 * 1024 * 1024;
|
|
8384
|
+
let fd;
|
|
8183
8385
|
try {
|
|
8184
|
-
|
|
8386
|
+
fd = openSync3(filePath, "r");
|
|
8185
8387
|
} catch {
|
|
8186
8388
|
return "";
|
|
8187
8389
|
}
|
|
8188
|
-
|
|
8189
|
-
|
|
8190
|
-
|
|
8191
|
-
const
|
|
8192
|
-
|
|
8193
|
-
|
|
8194
|
-
let
|
|
8390
|
+
try {
|
|
8391
|
+
const CHUNK = 64 * 1024;
|
|
8392
|
+
const buf = Buffer.allocUnsafe(CHUNK);
|
|
8393
|
+
const decoder = new StringDecoder("utf-8");
|
|
8394
|
+
let carry = "";
|
|
8395
|
+
let pos = 0;
|
|
8396
|
+
let lineNo = 0;
|
|
8397
|
+
for (; ; ) {
|
|
8398
|
+
const n = readSync3(fd, buf, 0, CHUNK, pos);
|
|
8399
|
+
if (n <= 0)
|
|
8400
|
+
break;
|
|
8401
|
+
pos += n;
|
|
8402
|
+
carry += decoder.write(buf.subarray(0, n));
|
|
8403
|
+
const parts = carry.split("\n");
|
|
8404
|
+
carry = parts.pop() ?? "";
|
|
8405
|
+
for (const line of parts) {
|
|
8406
|
+
if (++lineNo > maxLines)
|
|
8407
|
+
return "";
|
|
8408
|
+
const found = promptFromLine(line, maxLength);
|
|
8409
|
+
if (found !== null)
|
|
8410
|
+
return found;
|
|
8411
|
+
}
|
|
8412
|
+
if (pos >= maxBytes)
|
|
8413
|
+
return "";
|
|
8414
|
+
}
|
|
8415
|
+
carry += decoder.end();
|
|
8416
|
+
if (carry && lineNo < maxLines) {
|
|
8417
|
+
const found = promptFromLine(carry, maxLength);
|
|
8418
|
+
if (found !== null)
|
|
8419
|
+
return found;
|
|
8420
|
+
}
|
|
8421
|
+
return "";
|
|
8422
|
+
} finally {
|
|
8195
8423
|
try {
|
|
8196
|
-
|
|
8424
|
+
closeSync3(fd);
|
|
8197
8425
|
} catch {
|
|
8198
|
-
continue;
|
|
8199
|
-
}
|
|
8200
|
-
if (obj.type !== "user")
|
|
8201
|
-
continue;
|
|
8202
|
-
if (obj.isSidechain === true)
|
|
8203
|
-
continue;
|
|
8204
|
-
const message = obj.message;
|
|
8205
|
-
if (!message)
|
|
8206
|
-
continue;
|
|
8207
|
-
const content = message.content;
|
|
8208
|
-
let text = "";
|
|
8209
|
-
if (typeof content === "string") {
|
|
8210
|
-
text = content;
|
|
8211
|
-
} else if (Array.isArray(content)) {
|
|
8212
|
-
const parts = [];
|
|
8213
|
-
for (const block of content) {
|
|
8214
|
-
if (block && typeof block === "object" && block.type === "text" && typeof block.text === "string") {
|
|
8215
|
-
parts.push(block.text);
|
|
8216
|
-
}
|
|
8217
|
-
}
|
|
8218
|
-
text = parts.join("\n");
|
|
8219
8426
|
}
|
|
8220
|
-
if (!text)
|
|
8221
|
-
continue;
|
|
8222
|
-
if (text.includes("<system-reminder>"))
|
|
8223
|
-
continue;
|
|
8224
|
-
if (text.trim() === "[Request interrupted by user]")
|
|
8225
|
-
continue;
|
|
8226
|
-
const cleaned = stripBanners2(text);
|
|
8227
|
-
if (cleaned.length < 10)
|
|
8228
|
-
continue;
|
|
8229
|
-
return cleaned.slice(0, maxLength);
|
|
8230
8427
|
}
|
|
8231
|
-
return "";
|
|
8232
8428
|
}
|
|
8233
8429
|
var BANNERS;
|
|
8234
8430
|
var init_first_prompt = __esm({
|
|
8235
8431
|
"../engine/dist/core/first-prompt.js"() {
|
|
8236
8432
|
"use strict";
|
|
8433
|
+
init_flat_string();
|
|
8237
8434
|
BANNERS = [
|
|
8238
8435
|
/MCP issues detected\. ?Run \/mcp list for status\.?/g,
|
|
8239
8436
|
/Context low[^\n]*Run \/compact[^\n]*/g,
|
|
@@ -8243,7 +8440,7 @@ var init_first_prompt = __esm({
|
|
|
8243
8440
|
});
|
|
8244
8441
|
|
|
8245
8442
|
// ../engine/dist/core/backends/tail-read.js
|
|
8246
|
-
import { openSync as
|
|
8443
|
+
import { openSync as openSync4, readSync as readSync4, closeSync as closeSync4, statSync as statSync7 } from "node:fs";
|
|
8247
8444
|
function readTailFromOffset(path, offset) {
|
|
8248
8445
|
let size = 0;
|
|
8249
8446
|
try {
|
|
@@ -8257,10 +8454,10 @@ function readTailFromOffset(path, offset) {
|
|
|
8257
8454
|
const buf = Buffer.allocUnsafe(len);
|
|
8258
8455
|
let fd = null;
|
|
8259
8456
|
try {
|
|
8260
|
-
fd =
|
|
8457
|
+
fd = openSync4(path, "r");
|
|
8261
8458
|
let got = 0;
|
|
8262
8459
|
while (got < len) {
|
|
8263
|
-
const n =
|
|
8460
|
+
const n = readSync4(fd, buf, got, len - got, offset + got);
|
|
8264
8461
|
if (n <= 0)
|
|
8265
8462
|
break;
|
|
8266
8463
|
got += n;
|
|
@@ -8279,7 +8476,7 @@ function readTailFromOffset(path, offset) {
|
|
|
8279
8476
|
} finally {
|
|
8280
8477
|
if (fd !== null) {
|
|
8281
8478
|
try {
|
|
8282
|
-
|
|
8479
|
+
closeSync4(fd);
|
|
8283
8480
|
} catch {
|
|
8284
8481
|
}
|
|
8285
8482
|
}
|
|
@@ -8564,8 +8761,11 @@ var init_generic_engine = __esm({
|
|
|
8564
8761
|
});
|
|
8565
8762
|
|
|
8566
8763
|
// ../engine/dist/core/backends/claude.js
|
|
8567
|
-
import { existsSync as existsSync10, readdirSync as readdirSync6, readFileSync as
|
|
8764
|
+
import { existsSync as existsSync10, readdirSync as readdirSync6, readFileSync as readFileSync5, statSync as statSync8, openSync as openSync5, readSync as readSync5, closeSync as closeSync5 } from "fs";
|
|
8568
8765
|
import { join as join10, basename as basename8 } from "path";
|
|
8766
|
+
function stripReminders(text) {
|
|
8767
|
+
return text.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g, "").trim();
|
|
8768
|
+
}
|
|
8569
8769
|
function parseExitCode(text) {
|
|
8570
8770
|
const m = text.match(/(?:^|\n)\s*(?:exit\s+code|returncode|exit\s+status|exit)\s*[:=]\s*(\d+)\b/i);
|
|
8571
8771
|
return m ? Number(m[1]) : void 0;
|
|
@@ -8580,6 +8780,7 @@ var init_claude2 = __esm({
|
|
|
8580
8780
|
init_session_git();
|
|
8581
8781
|
init_first_prompt();
|
|
8582
8782
|
init_tail_read();
|
|
8783
|
+
init_project_dir_name();
|
|
8583
8784
|
init_generic_engine();
|
|
8584
8785
|
UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
8585
8786
|
ClaudeBackend = class {
|
|
@@ -8656,13 +8857,13 @@ var init_claude2 = __esm({
|
|
|
8656
8857
|
return null;
|
|
8657
8858
|
let head;
|
|
8658
8859
|
try {
|
|
8659
|
-
const fd =
|
|
8860
|
+
const fd = openSync5(located.path, "r");
|
|
8660
8861
|
try {
|
|
8661
8862
|
const buf = Buffer.alloc(65536);
|
|
8662
|
-
const n =
|
|
8863
|
+
const n = readSync5(fd, buf, 0, buf.length, 0);
|
|
8663
8864
|
head = buf.toString("utf-8", 0, n);
|
|
8664
8865
|
} finally {
|
|
8665
|
-
|
|
8866
|
+
closeSync5(fd);
|
|
8666
8867
|
}
|
|
8667
8868
|
} catch {
|
|
8668
8869
|
return null;
|
|
@@ -8721,11 +8922,11 @@ var init_claude2 = __esm({
|
|
|
8721
8922
|
if (filter && !proj.name.toLowerCase().includes(filter))
|
|
8722
8923
|
continue;
|
|
8723
8924
|
const projPath = join10(root, proj.name);
|
|
8724
|
-
const projectPath = proj.name
|
|
8925
|
+
const projectPath = decodeProjectDirName(proj.name);
|
|
8725
8926
|
const indexPath = join10(projPath, "sessions-index.json");
|
|
8726
8927
|
if (existsSync10(indexPath)) {
|
|
8727
8928
|
try {
|
|
8728
|
-
const indexData = JSON.parse(
|
|
8929
|
+
const indexData = JSON.parse(readFileSync5(indexPath, "utf-8"));
|
|
8729
8930
|
const entries = indexData.entries || [];
|
|
8730
8931
|
for (const entry of entries) {
|
|
8731
8932
|
if (!entry.fullPath || !existsSync10(entry.fullPath))
|
|
@@ -8874,6 +9075,15 @@ var init_claude2 = __esm({
|
|
|
8874
9075
|
}
|
|
8875
9076
|
const tsIso = typeof obj.timestamp === "string" ? obj.timestamp : void 0;
|
|
8876
9077
|
const ts2 = tsIso ? Date.parse(tsIso) || mtime : mtime;
|
|
9078
|
+
if (obj.type === "queue-operation") {
|
|
9079
|
+
if (obj.operation === "enqueue" && typeof obj.content === "string") {
|
|
9080
|
+
const queued = stripReminders(obj.content);
|
|
9081
|
+
if (queued && !queued.startsWith("<task-notification")) {
|
|
9082
|
+
events.push({ kind: "user", ts: ts2, tsIso, line: lineNum, text: queued });
|
|
9083
|
+
}
|
|
9084
|
+
}
|
|
9085
|
+
continue;
|
|
9086
|
+
}
|
|
8877
9087
|
if (obj.type === "user") {
|
|
8878
9088
|
const msg = obj.message;
|
|
8879
9089
|
const content = msg?.content;
|
|
@@ -8907,9 +9117,9 @@ var init_claude2 = __esm({
|
|
|
8907
9117
|
}
|
|
8908
9118
|
}
|
|
8909
9119
|
}
|
|
8910
|
-
|
|
8911
|
-
|
|
8912
|
-
|
|
9120
|
+
const spoken = stripReminders(text);
|
|
9121
|
+
if (spoken)
|
|
9122
|
+
events.push({ kind: "user", ts: ts2, tsIso, line: lineNum, text: spoken });
|
|
8913
9123
|
for (const tr of toolResults) {
|
|
8914
9124
|
events.push({
|
|
8915
9125
|
kind: "tool_result",
|
|
@@ -9008,7 +9218,7 @@ var init_claude2 = __esm({
|
|
|
9008
9218
|
* with quiet main + active subagents still surfaces.
|
|
9009
9219
|
*/
|
|
9010
9220
|
collectRecentEdits(opts) {
|
|
9011
|
-
const
|
|
9221
|
+
const candidates2 = [];
|
|
9012
9222
|
for (const root of claudeProjectDirs()) {
|
|
9013
9223
|
if (!existsSync10(root))
|
|
9014
9224
|
continue;
|
|
@@ -9044,14 +9254,14 @@ var init_claude2 = __esm({
|
|
|
9044
9254
|
}
|
|
9045
9255
|
if (mtime < opts.sinceMs)
|
|
9046
9256
|
continue;
|
|
9047
|
-
|
|
9257
|
+
candidates2.push({ rawId: basename8(f, ".jsonl"), mtime });
|
|
9048
9258
|
} catch {
|
|
9049
9259
|
}
|
|
9050
9260
|
}
|
|
9051
9261
|
}
|
|
9052
9262
|
}
|
|
9053
|
-
|
|
9054
|
-
const limited = opts.limitSessions ?
|
|
9263
|
+
candidates2.sort((a, b) => b.mtime - a.mtime);
|
|
9264
|
+
const limited = opts.limitSessions ? candidates2.slice(0, opts.limitSessions) : candidates2;
|
|
9055
9265
|
const edits = [];
|
|
9056
9266
|
for (const c of limited) {
|
|
9057
9267
|
const scan = this.liveScanEdits(c.rawId);
|
|
@@ -9138,12 +9348,12 @@ var init_claude2 = __esm({
|
|
|
9138
9348
|
|
|
9139
9349
|
// ../engine/dist/core/backends/gemini.js
|
|
9140
9350
|
import { createHash as createHash4 } from "crypto";
|
|
9141
|
-
import { existsSync as existsSync11, readdirSync as readdirSync7, readFileSync as
|
|
9351
|
+
import { existsSync as existsSync11, readdirSync as readdirSync7, readFileSync as readFileSync6, statSync as statSync9 } from "fs";
|
|
9142
9352
|
import { basename as basename9, join as join11 } from "path";
|
|
9143
9353
|
function readSessionId(path, format) {
|
|
9144
9354
|
try {
|
|
9145
9355
|
if (format === "json") {
|
|
9146
|
-
const json = JSON.parse(
|
|
9356
|
+
const json = JSON.parse(readFileSync6(path, "utf-8"));
|
|
9147
9357
|
return typeof json?.sessionId === "string" ? json.sessionId : null;
|
|
9148
9358
|
}
|
|
9149
9359
|
const head = readHeadSync(path).split("\n", 1)[0] || "";
|
|
@@ -9177,6 +9387,7 @@ var init_gemini2 = __esm({
|
|
|
9177
9387
|
init_session_git();
|
|
9178
9388
|
init_generic_engine();
|
|
9179
9389
|
init_tail_read();
|
|
9390
|
+
init_flat_string();
|
|
9180
9391
|
PREFIX = "gemini_";
|
|
9181
9392
|
FULL_PARSE_MAX = 4 * 1024 * 1024;
|
|
9182
9393
|
GeminiBackend = class {
|
|
@@ -9286,7 +9497,7 @@ var init_gemini2 = __esm({
|
|
|
9286
9497
|
sessionId = readSessionId(fullPath, format);
|
|
9287
9498
|
const messages = readGeminiMessages(fullPath, format);
|
|
9288
9499
|
const firstUser = messages.find((m) => m.type === "user");
|
|
9289
|
-
firstPrompt = (typeof firstUser?.text === "string" ? firstUser.text : flatten(firstUser?.content)).slice(0, 200);
|
|
9500
|
+
firstPrompt = flatString((typeof firstUser?.text === "string" ? firstUser.text : flatten(firstUser?.content)).slice(0, 200));
|
|
9290
9501
|
messageCount = messages.length;
|
|
9291
9502
|
} else if (format === "jsonl") {
|
|
9292
9503
|
const lines = readHeadSync(fullPath, 1048576).split("\n");
|
|
@@ -9308,7 +9519,7 @@ var init_gemini2 = __esm({
|
|
|
9308
9519
|
}
|
|
9309
9520
|
if (m?.type !== "user")
|
|
9310
9521
|
continue;
|
|
9311
|
-
firstPrompt = (typeof m.text === "string" ? m.text : flatten(m.content)).slice(0, 200);
|
|
9522
|
+
firstPrompt = flatString((typeof m.text === "string" ? m.text : flatten(m.content)).slice(0, 200));
|
|
9312
9523
|
break;
|
|
9313
9524
|
}
|
|
9314
9525
|
}
|
|
@@ -9484,7 +9695,7 @@ var init_gemini2 = __esm({
|
|
|
9484
9695
|
if (!existsSync11(tmpRoot))
|
|
9485
9696
|
return [];
|
|
9486
9697
|
const projMap = this.loadProjectMap();
|
|
9487
|
-
const
|
|
9698
|
+
const candidates2 = [];
|
|
9488
9699
|
for (const proj of readdirSync7(tmpRoot, { withFileTypes: true })) {
|
|
9489
9700
|
if (!proj.isDirectory())
|
|
9490
9701
|
continue;
|
|
@@ -9515,13 +9726,13 @@ var init_gemini2 = __esm({
|
|
|
9515
9726
|
if (st.mtimeMs < opts.sinceMs)
|
|
9516
9727
|
continue;
|
|
9517
9728
|
const trimLen = isJsonl ? 6 : 5;
|
|
9518
|
-
|
|
9729
|
+
candidates2.push({ rawIdHint: f.slice(0, -trimLen), mtime: st.mtimeMs });
|
|
9519
9730
|
} catch {
|
|
9520
9731
|
}
|
|
9521
9732
|
}
|
|
9522
9733
|
}
|
|
9523
|
-
|
|
9524
|
-
const limited = opts.limitSessions ?
|
|
9734
|
+
candidates2.sort((a, b) => b.mtime - a.mtime);
|
|
9735
|
+
const limited = opts.limitSessions ? candidates2.slice(0, opts.limitSessions) : candidates2;
|
|
9525
9736
|
const edits = [];
|
|
9526
9737
|
for (const c of limited) {
|
|
9527
9738
|
const scan = this.liveScanEdits(c.rawIdHint);
|
|
@@ -9540,7 +9751,7 @@ var init_gemini2 = __esm({
|
|
|
9540
9751
|
if (!existsSync11(path))
|
|
9541
9752
|
return map;
|
|
9542
9753
|
try {
|
|
9543
|
-
const json = JSON.parse(
|
|
9754
|
+
const json = JSON.parse(readFileSync6(path, "utf-8"));
|
|
9544
9755
|
const projects = json?.projects ?? {};
|
|
9545
9756
|
for (const projectPath of Object.keys(projects)) {
|
|
9546
9757
|
const hash = createHash4("sha256").update(projectPath).digest("hex");
|
|
@@ -9558,7 +9769,7 @@ var init_gemini2 = __esm({
|
|
|
9558
9769
|
return {
|
|
9559
9770
|
tool: "gemini",
|
|
9560
9771
|
mtime: statSync9(loc.path).mtimeMs,
|
|
9561
|
-
files: [{ name: basename9(loc.path), bytes:
|
|
9772
|
+
files: [{ name: basename9(loc.path), bytes: readFileSync6(loc.path) }]
|
|
9562
9773
|
};
|
|
9563
9774
|
} catch {
|
|
9564
9775
|
return null;
|
|
@@ -9653,6 +9864,7 @@ var init_opencode = __esm({
|
|
|
9653
9864
|
init_session_outcome();
|
|
9654
9865
|
init_session_git();
|
|
9655
9866
|
init_generic_engine();
|
|
9867
|
+
init_flat_string();
|
|
9656
9868
|
PREFIX2 = "opencode_";
|
|
9657
9869
|
OpencodeBackend = class {
|
|
9658
9870
|
id = "opencode";
|
|
@@ -9820,7 +10032,7 @@ var init_opencode = __esm({
|
|
|
9820
10032
|
if (firstUser) {
|
|
9821
10033
|
try {
|
|
9822
10034
|
const parsed = JSON.parse(firstUser.data);
|
|
9823
|
-
firstPrompt = String(parsed?.text || "").slice(0, 200);
|
|
10035
|
+
firstPrompt = flatString(String(parsed?.text || "").slice(0, 200));
|
|
9824
10036
|
} catch {
|
|
9825
10037
|
}
|
|
9826
10038
|
}
|
|
@@ -10164,7 +10376,7 @@ var init_opencode = __esm({
|
|
|
10164
10376
|
});
|
|
10165
10377
|
|
|
10166
10378
|
// ../engine/dist/core/backends/codex.js
|
|
10167
|
-
import { readdirSync as readdirSync8, readFileSync as
|
|
10379
|
+
import { readdirSync as readdirSync8, readFileSync as readFileSync7, statSync as statSync10, openSync as openSync6, readSync as readSync6, closeSync as closeSync6 } from "fs";
|
|
10168
10380
|
import { basename as basename10, dirname as dirname10, join as join13 } from "path";
|
|
10169
10381
|
function parseShellWrites(cmd) {
|
|
10170
10382
|
const out = [];
|
|
@@ -10293,7 +10505,7 @@ function flattenContent(content) {
|
|
|
10293
10505
|
}
|
|
10294
10506
|
function readFirstLine(path) {
|
|
10295
10507
|
try {
|
|
10296
|
-
const head =
|
|
10508
|
+
const head = readFileSync7(path, "utf-8").split("\n", 1)[0] || "";
|
|
10297
10509
|
if (!head)
|
|
10298
10510
|
return null;
|
|
10299
10511
|
return JSON.parse(head);
|
|
@@ -10311,6 +10523,7 @@ var init_codex2 = __esm({
|
|
|
10311
10523
|
init_session_git();
|
|
10312
10524
|
init_generic_engine();
|
|
10313
10525
|
init_tail_read();
|
|
10526
|
+
init_flat_string();
|
|
10314
10527
|
PREFIX3 = "codex_";
|
|
10315
10528
|
CodexBackend = class {
|
|
10316
10529
|
id = "codex";
|
|
@@ -10410,7 +10623,7 @@ var init_codex2 = __esm({
|
|
|
10410
10623
|
let firstPrompt = "";
|
|
10411
10624
|
let messageCount = 0;
|
|
10412
10625
|
try {
|
|
10413
|
-
const lines =
|
|
10626
|
+
const lines = readFileSync7(filePath, "utf-8").split("\n");
|
|
10414
10627
|
for (const line of lines) {
|
|
10415
10628
|
if (!line.trim())
|
|
10416
10629
|
continue;
|
|
@@ -10423,7 +10636,7 @@ var init_codex2 = __esm({
|
|
|
10423
10636
|
if (ev.type === "event_msg" && ev.payload?.type === "user_message") {
|
|
10424
10637
|
messageCount++;
|
|
10425
10638
|
if (!firstPrompt && ev.payload.message) {
|
|
10426
|
-
firstPrompt = String(ev.payload.message).slice(0, 200);
|
|
10639
|
+
firstPrompt = flatString(String(ev.payload.message).slice(0, 200));
|
|
10427
10640
|
}
|
|
10428
10641
|
} else if (ev.type === "response_item" && ev.payload?.type === "message") {
|
|
10429
10642
|
messageCount++;
|
|
@@ -10524,23 +10737,24 @@ var init_codex2 = __esm({
|
|
|
10524
10737
|
return null;
|
|
10525
10738
|
}
|
|
10526
10739
|
/**
|
|
10527
|
-
|
|
10528
|
-
|
|
10529
|
-
|
|
10530
|
-
|
|
10531
|
-
|
|
10532
|
-
|
|
10533
|
-
|
|
10534
|
-
|
|
10535
|
-
|
|
10536
|
-
|
|
10537
|
-
|
|
10538
|
-
|
|
10539
|
-
|
|
10540
|
-
|
|
10541
|
-
|
|
10542
|
-
|
|
10543
|
-
|
|
10740
|
+
* Stream a Codex JSONL rollout into canonical events. Codex separates:
|
|
10741
|
+
* - event_msg + payload.type='user_message' → user
|
|
10742
|
+
* - response_item + payload.type='message' → user OR assistant_text,
|
|
10743
|
+
* by payload.role
|
|
10744
|
+
* - response_item + payload.type='function_call' → tool_use
|
|
10745
|
+
* - response_item + payload.type='function_call_output' → tool_result
|
|
10746
|
+
*
|
|
10747
|
+
* Filters Codex's wrapper-bearing user messages (environment_context etc.).
|
|
10748
|
+
*
|
|
10749
|
+
* **Subagent fan-out:** Codex orchestrates work via `spawn_agent` calls
|
|
10750
|
+
* that produce sibling rollout files in the same YYYY/MM/DD directory.
|
|
10751
|
+
* Sub-agent rollouts carry `payload.source.subagent.thread_spawn` linking
|
|
10752
|
+
* back to the parent. The actual file edits often happen inside those
|
|
10753
|
+
* subagent rollouts — without folding their events into the parent's
|
|
10754
|
+
* stream, replay/scan would see the parent as edit-free. We append every
|
|
10755
|
+
* subagent rollout's events here so the generic engine sees one unified
|
|
10756
|
+
* stream per user-facing session.
|
|
10757
|
+
*/
|
|
10544
10758
|
readEvents(rawId) {
|
|
10545
10759
|
const located = findCodexSessionFile(this.toRawId(rawId));
|
|
10546
10760
|
if (!located)
|
|
@@ -10561,7 +10775,7 @@ var init_codex2 = __esm({
|
|
|
10561
10775
|
continue;
|
|
10562
10776
|
let firstLine = "";
|
|
10563
10777
|
try {
|
|
10564
|
-
firstLine =
|
|
10778
|
+
firstLine = readFileSync7(path, "utf-8").split("\n", 1)[0] || "";
|
|
10565
10779
|
} catch {
|
|
10566
10780
|
continue;
|
|
10567
10781
|
}
|
|
@@ -10585,7 +10799,7 @@ var init_codex2 = __esm({
|
|
|
10585
10799
|
let raw = "";
|
|
10586
10800
|
let mtime = 0;
|
|
10587
10801
|
try {
|
|
10588
|
-
raw =
|
|
10802
|
+
raw = readFileSync7(path, "utf-8");
|
|
10589
10803
|
mtime = statSync10(path).mtimeMs;
|
|
10590
10804
|
} catch {
|
|
10591
10805
|
return [];
|
|
@@ -10610,6 +10824,11 @@ var init_codex2 = __esm({
|
|
|
10610
10824
|
if (text && !isCodexInjectedWrapper2(text)) {
|
|
10611
10825
|
events.push({ kind: "user", ts: ts2, tsIso, line: lineNum, text });
|
|
10612
10826
|
}
|
|
10827
|
+
} else if (obj.type === "response_item" && payload.type === "message" && payload.role === "user") {
|
|
10828
|
+
const text = flattenContent(payload.content).trim();
|
|
10829
|
+
if (text && !isCodexInjectedWrapper2(text)) {
|
|
10830
|
+
events.push({ kind: "user", ts: ts2, tsIso, line: lineNum, text });
|
|
10831
|
+
}
|
|
10613
10832
|
} else if (obj.type === "response_item" && payload.type === "message" && payload.role === "assistant") {
|
|
10614
10833
|
const text = flattenContent(payload.content).trim();
|
|
10615
10834
|
if (text)
|
|
@@ -10757,7 +10976,7 @@ var init_codex2 = __esm({
|
|
|
10757
10976
|
let parentId = null;
|
|
10758
10977
|
let isSubagent = false;
|
|
10759
10978
|
try {
|
|
10760
|
-
const first =
|
|
10979
|
+
const first = readFileSync7(p, "utf-8").split("\n")[0];
|
|
10761
10980
|
if (first) {
|
|
10762
10981
|
const meta = JSON.parse(first);
|
|
10763
10982
|
const payload = meta?.payload || {};
|
|
@@ -10813,7 +11032,7 @@ var init_codex2 = __esm({
|
|
|
10813
11032
|
const push = (path, name) => {
|
|
10814
11033
|
try {
|
|
10815
11034
|
const st = statSync10(path);
|
|
10816
|
-
files.push({ name, bytes:
|
|
11035
|
+
files.push({ name, bytes: readFileSync7(path) });
|
|
10817
11036
|
if (st.mtimeMs > mtime)
|
|
10818
11037
|
mtime = st.mtimeMs;
|
|
10819
11038
|
} catch {
|
|
@@ -10831,10 +11050,10 @@ var init_codex2 = __esm({
|
|
|
10831
11050
|
if (p === loc.path)
|
|
10832
11051
|
continue;
|
|
10833
11052
|
try {
|
|
10834
|
-
const fd =
|
|
11053
|
+
const fd = openSync6(p, "r");
|
|
10835
11054
|
const buf = Buffer.alloc(4096);
|
|
10836
|
-
const n =
|
|
10837
|
-
|
|
11055
|
+
const n = readSync6(fd, buf, 0, 4096, 0);
|
|
11056
|
+
closeSync6(fd);
|
|
10838
11057
|
const head = buf.toString("utf-8", 0, n);
|
|
10839
11058
|
if (head.includes(parentId) && head.includes("parent_thread_id"))
|
|
10840
11059
|
push(p, `subagents/${f}`);
|
|
@@ -10871,13 +11090,13 @@ var init_codex2 = __esm({
|
|
|
10871
11090
|
});
|
|
10872
11091
|
|
|
10873
11092
|
// ../engine/dist/core/backends/agy.js
|
|
10874
|
-
import { existsSync as existsSync13, readdirSync as readdirSync9, readFileSync as
|
|
11093
|
+
import { existsSync as existsSync13, readdirSync as readdirSync9, readFileSync as readFileSync8, statSync as statSync11 } from "fs";
|
|
10875
11094
|
import { basename as basename11, dirname as dirname11, join as join14 } from "path";
|
|
10876
11095
|
function getFallbackProjectPath(homeDir) {
|
|
10877
11096
|
try {
|
|
10878
11097
|
const settingsPath2 = join14(homeDir, "settings.json");
|
|
10879
11098
|
if (existsSync13(settingsPath2)) {
|
|
10880
|
-
const json = JSON.parse(
|
|
11099
|
+
const json = JSON.parse(readFileSync8(settingsPath2, "utf-8"));
|
|
10881
11100
|
if (Array.isArray(json?.trustedWorkspaces) && json.trustedWorkspaces[0]) {
|
|
10882
11101
|
return json.trustedWorkspaces[0];
|
|
10883
11102
|
}
|
|
@@ -10904,7 +11123,7 @@ function resolveAgyProject(logsDir, homeDir) {
|
|
|
10904
11123
|
function extractProjectPathFromTranscript(path, homeDir) {
|
|
10905
11124
|
let content;
|
|
10906
11125
|
try {
|
|
10907
|
-
content =
|
|
11126
|
+
content = readFileSync8(path, "utf-8");
|
|
10908
11127
|
} catch {
|
|
10909
11128
|
return "";
|
|
10910
11129
|
}
|
|
@@ -10990,6 +11209,7 @@ var init_agy = __esm({
|
|
|
10990
11209
|
init_session_outcome();
|
|
10991
11210
|
init_session_git();
|
|
10992
11211
|
init_generic_engine();
|
|
11212
|
+
init_flat_string();
|
|
10993
11213
|
PREFIX4 = "agy_";
|
|
10994
11214
|
AgyBackend = class {
|
|
10995
11215
|
id = "agy";
|
|
@@ -11082,7 +11302,7 @@ var init_agy = __esm({
|
|
|
11082
11302
|
let firstPrompt = "";
|
|
11083
11303
|
let messageCount = 0;
|
|
11084
11304
|
try {
|
|
11085
|
-
const lines =
|
|
11305
|
+
const lines = readFileSync8(filePath, "utf-8").split("\n").filter(Boolean);
|
|
11086
11306
|
messageCount = lines.length;
|
|
11087
11307
|
for (const line of lines) {
|
|
11088
11308
|
const obj = JSON.parse(line);
|
|
@@ -11090,7 +11310,7 @@ var init_agy = __esm({
|
|
|
11090
11310
|
const content = obj.content;
|
|
11091
11311
|
const match = content.match(/<USER_REQUEST>([\s\S]*?)<\/USER_REQUEST>/);
|
|
11092
11312
|
const rawText = match ? match[1].trim() : content.trim();
|
|
11093
|
-
firstPrompt = rawText.slice(0, 200);
|
|
11313
|
+
firstPrompt = flatString(rawText.slice(0, 200));
|
|
11094
11314
|
break;
|
|
11095
11315
|
}
|
|
11096
11316
|
}
|
|
@@ -11172,7 +11392,7 @@ var init_agy = __esm({
|
|
|
11172
11392
|
return [];
|
|
11173
11393
|
let rawText;
|
|
11174
11394
|
try {
|
|
11175
|
-
rawText =
|
|
11395
|
+
rawText = readFileSync8(located.path, "utf-8");
|
|
11176
11396
|
} catch {
|
|
11177
11397
|
return [];
|
|
11178
11398
|
}
|
|
@@ -11324,7 +11544,7 @@ var init_agy = __esm({
|
|
|
11324
11544
|
if (brainRoots.length === 0)
|
|
11325
11545
|
return [];
|
|
11326
11546
|
const brainDir = brainRoots[0];
|
|
11327
|
-
const
|
|
11547
|
+
const candidates2 = [];
|
|
11328
11548
|
let sessionDirs;
|
|
11329
11549
|
try {
|
|
11330
11550
|
sessionDirs = readdirSync9(brainDir);
|
|
@@ -11346,12 +11566,12 @@ var init_agy = __esm({
|
|
|
11346
11566
|
const st = statSync11(filePath);
|
|
11347
11567
|
if (st.mtimeMs < opts.sinceMs)
|
|
11348
11568
|
continue;
|
|
11349
|
-
|
|
11569
|
+
candidates2.push({ rawId, mtime: st.mtimeMs });
|
|
11350
11570
|
} catch {
|
|
11351
11571
|
}
|
|
11352
11572
|
}
|
|
11353
|
-
|
|
11354
|
-
const limited = opts.limitSessions ?
|
|
11573
|
+
candidates2.sort((a, b) => b.mtime - a.mtime);
|
|
11574
|
+
const limited = opts.limitSessions ? candidates2.slice(0, opts.limitSessions) : candidates2;
|
|
11355
11575
|
const edits = [];
|
|
11356
11576
|
for (const c of limited) {
|
|
11357
11577
|
const scan = this.liveScanEdits(c.rawId);
|
|
@@ -11372,7 +11592,7 @@ var init_agy = __esm({
|
|
|
11372
11592
|
return {
|
|
11373
11593
|
tool: "agy",
|
|
11374
11594
|
mtime: statSync11(loc.path).mtimeMs,
|
|
11375
|
-
files: [{ name: basename11(loc.path), bytes:
|
|
11595
|
+
files: [{ name: basename11(loc.path), bytes: readFileSync8(loc.path) }]
|
|
11376
11596
|
};
|
|
11377
11597
|
} catch {
|
|
11378
11598
|
return null;
|
|
@@ -11444,6 +11664,24 @@ var init_backends = __esm({
|
|
|
11444
11664
|
}
|
|
11445
11665
|
});
|
|
11446
11666
|
|
|
11667
|
+
// ../engine/dist/core/credentials-env.js
|
|
11668
|
+
function envCredentials(env = process.env) {
|
|
11669
|
+
const token = (env.CHAT_RECALL_TOKEN || "").trim();
|
|
11670
|
+
const server = (env.CHAT_RECALL_SERVER || "").trim();
|
|
11671
|
+
if (!token || !server)
|
|
11672
|
+
return null;
|
|
11673
|
+
if (!/^https?:\/\//i.test(server))
|
|
11674
|
+
return null;
|
|
11675
|
+
return { serverUrl: normalise(server), token };
|
|
11676
|
+
}
|
|
11677
|
+
var normalise;
|
|
11678
|
+
var init_credentials_env = __esm({
|
|
11679
|
+
"../engine/dist/core/credentials-env.js"() {
|
|
11680
|
+
"use strict";
|
|
11681
|
+
normalise = (u) => u.trim().replace(/\/+$/, "");
|
|
11682
|
+
}
|
|
11683
|
+
});
|
|
11684
|
+
|
|
11447
11685
|
// ../engine/dist/core/source-discovery.js
|
|
11448
11686
|
import { createHash as createHash5 } from "crypto";
|
|
11449
11687
|
import { existsSync as existsSync14, readdirSync as readdirSync10, statSync as statSync12 } from "fs";
|
|
@@ -11550,7 +11788,7 @@ var init_source_discovery = __esm({
|
|
|
11550
11788
|
|
|
11551
11789
|
// ../engine/dist/core/home-discovery.js
|
|
11552
11790
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
11553
|
-
import { existsSync as existsSync15, readdirSync as readdirSync11, readFileSync as
|
|
11791
|
+
import { existsSync as existsSync15, readdirSync as readdirSync11, readFileSync as readFileSync9, realpathSync as realpathSync2, statSync as statSync13 } from "fs";
|
|
11554
11792
|
import { homedir as homedir5, platform as osPlatform } from "os";
|
|
11555
11793
|
import { join as join16 } from "path";
|
|
11556
11794
|
function candidateRoots(plat = osPlatform(), env = process.env) {
|
|
@@ -11672,7 +11910,7 @@ function declaredHomes(env = process.env, plat = osPlatform()) {
|
|
|
11672
11910
|
for (const rc of rcs) {
|
|
11673
11911
|
let text;
|
|
11674
11912
|
try {
|
|
11675
|
-
text =
|
|
11913
|
+
text = readFileSync9(rc, "utf-8");
|
|
11676
11914
|
} catch {
|
|
11677
11915
|
continue;
|
|
11678
11916
|
}
|
|
@@ -11697,7 +11935,7 @@ function runningToolHomes(plat = osPlatform()) {
|
|
|
11697
11935
|
for (const pid of pids) {
|
|
11698
11936
|
let env;
|
|
11699
11937
|
try {
|
|
11700
|
-
env =
|
|
11938
|
+
env = readFileSync9(`/proc/${pid}/environ`, "utf-8");
|
|
11701
11939
|
} catch {
|
|
11702
11940
|
continue;
|
|
11703
11941
|
}
|
|
@@ -11818,7 +12056,7 @@ var init_home_discovery = __esm({
|
|
|
11818
12056
|
|
|
11819
12057
|
// ../engine/dist/core/detector-install.js
|
|
11820
12058
|
import { createHash as createHash6 } from "crypto";
|
|
11821
|
-
import { existsSync as existsSync16, mkdirSync as mkdirSync4, mkdtempSync, chmodSync as chmodSync2, renameSync as renameSync3, rmSync as rmSync2, writeFileSync as writeFileSync3, readFileSync as
|
|
12059
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync4, mkdtempSync, chmodSync as chmodSync2, renameSync as renameSync3, rmSync as rmSync2, writeFileSync as writeFileSync3, readFileSync as readFileSync10, statSync as statSync14, copyFileSync as copyFileSync2 } from "fs";
|
|
11822
12060
|
import { join as join17 } from "path";
|
|
11823
12061
|
function managedDetectorPath(name) {
|
|
11824
12062
|
return join17(getDetectorBinDir(), name + exeSuffix());
|
|
@@ -11827,11 +12065,11 @@ function receiptPath(name) {
|
|
|
11827
12065
|
return join17(getDetectorBinDir(), `${name}.receipt.json`);
|
|
11828
12066
|
}
|
|
11829
12067
|
function sha256File(path) {
|
|
11830
|
-
return createHash6("sha256").update(
|
|
12068
|
+
return createHash6("sha256").update(readFileSync10(path)).digest("hex");
|
|
11831
12069
|
}
|
|
11832
12070
|
function readReceipt(name) {
|
|
11833
12071
|
try {
|
|
11834
|
-
return JSON.parse(
|
|
12072
|
+
return JSON.parse(readFileSync10(receiptPath(name), "utf-8"));
|
|
11835
12073
|
} catch {
|
|
11836
12074
|
return null;
|
|
11837
12075
|
}
|
|
@@ -11922,7 +12160,7 @@ var init_detector_install = __esm({
|
|
|
11922
12160
|
|
|
11923
12161
|
// ../engine/dist/core/secret-scanner.js
|
|
11924
12162
|
import { spawnSync } from "child_process";
|
|
11925
|
-
import { existsSync as existsSync17, unlinkSync, readFileSync as
|
|
12163
|
+
import { existsSync as existsSync17, unlinkSync, readFileSync as readFileSync11, mkdtempSync as mkdtempSync2, rmSync as rmSync3 } from "fs";
|
|
11926
12164
|
import { tmpdir } from "os";
|
|
11927
12165
|
import { join as join18 } from "path";
|
|
11928
12166
|
function mask(s) {
|
|
@@ -11983,7 +12221,7 @@ function runGitleaks(binary, filePath) {
|
|
|
11983
12221
|
return [];
|
|
11984
12222
|
let parsed = [];
|
|
11985
12223
|
try {
|
|
11986
|
-
parsed = JSON.parse(
|
|
12224
|
+
parsed = JSON.parse(readFileSync11(reportPath, "utf-8")) || [];
|
|
11987
12225
|
} catch {
|
|
11988
12226
|
}
|
|
11989
12227
|
try {
|
|
@@ -12047,7 +12285,7 @@ function runGitleaksDir(binary, dir) {
|
|
|
12047
12285
|
}
|
|
12048
12286
|
let parsed = [];
|
|
12049
12287
|
try {
|
|
12050
|
-
parsed = JSON.parse(
|
|
12288
|
+
parsed = JSON.parse(readFileSync11(reportPath, "utf-8")) || [];
|
|
12051
12289
|
} catch {
|
|
12052
12290
|
}
|
|
12053
12291
|
try {
|
|
@@ -12138,7 +12376,7 @@ function scanFileForSecrets(filePath, opts = {}) {
|
|
|
12138
12376
|
out.push({ detector: "trufflehog", ...f });
|
|
12139
12377
|
if (opts.tenantRules && opts.tenantRules.length > 0) {
|
|
12140
12378
|
try {
|
|
12141
|
-
const text =
|
|
12379
|
+
const text = readFileSync11(filePath, "utf-8");
|
|
12142
12380
|
out.push(...scanTenantRules(text, opts.tenantRules));
|
|
12143
12381
|
} catch {
|
|
12144
12382
|
}
|
|
@@ -12263,10 +12501,10 @@ var init_types = __esm({
|
|
|
12263
12501
|
|
|
12264
12502
|
// ../engine/dist/transcript/opencode.js
|
|
12265
12503
|
async function parseOpenCodeSubagents(parentSessionId) {
|
|
12266
|
-
const { existsSync:
|
|
12504
|
+
const { existsSync: existsSync46 } = await import("fs");
|
|
12267
12505
|
const { opencodeBackend: opencodeBackend2 } = await Promise.resolve().then(() => (init_opencode(), opencode_exports));
|
|
12268
12506
|
const dbPath = opencodeBackend2.dbPath();
|
|
12269
|
-
if (!
|
|
12507
|
+
if (!existsSync46(dbPath))
|
|
12270
12508
|
return [];
|
|
12271
12509
|
const realParent = parentSessionId.replace("opencode_", "");
|
|
12272
12510
|
const db = openSqliteReadonlyOrThrow(dbPath);
|
|
@@ -12307,10 +12545,10 @@ async function parseOpenCodeSubagents(parentSessionId) {
|
|
|
12307
12545
|
}
|
|
12308
12546
|
}
|
|
12309
12547
|
async function parseOpenCodeTranscript(sessionId) {
|
|
12310
|
-
const { existsSync:
|
|
12548
|
+
const { existsSync: existsSync46 } = await import("fs");
|
|
12311
12549
|
const { opencodeBackend: opencodeBackend2 } = await Promise.resolve().then(() => (init_opencode(), opencode_exports));
|
|
12312
12550
|
const dbPath = opencodeBackend2.dbPath();
|
|
12313
|
-
if (!
|
|
12551
|
+
if (!existsSync46(dbPath))
|
|
12314
12552
|
return [];
|
|
12315
12553
|
const realId = sessionId.replace("opencode_", "");
|
|
12316
12554
|
const db = openSqliteReadonlyOrThrow(dbPath);
|
|
@@ -12544,7 +12782,7 @@ var init_transcript = __esm({
|
|
|
12544
12782
|
// ../engine/dist/core/project-resolver.js
|
|
12545
12783
|
import { execSync } from "child_process";
|
|
12546
12784
|
import { createHash as createHash7 } from "crypto";
|
|
12547
|
-
import { existsSync as existsSync18, readFileSync as
|
|
12785
|
+
import { existsSync as existsSync18, readFileSync as readFileSync12, realpathSync as realpathSync3, readdirSync as readdirSync12, statSync as statSync16 } from "fs";
|
|
12548
12786
|
import { basename as basename12, dirname as dirname12, isAbsolute, join as join19, resolve, sep } from "path";
|
|
12549
12787
|
function getProjectsConfigPath() {
|
|
12550
12788
|
return join19(getDataDir(), "projects.json");
|
|
@@ -12562,7 +12800,7 @@ function loadProjectsConfig() {
|
|
|
12562
12800
|
if (cachedConfig && cachedConfig.mtime === mtime)
|
|
12563
12801
|
return cachedConfig.cfg;
|
|
12564
12802
|
try {
|
|
12565
|
-
const raw =
|
|
12803
|
+
const raw = readFileSync12(path, "utf-8");
|
|
12566
12804
|
const cfg = JSON.parse(raw);
|
|
12567
12805
|
cachedConfig = { mtime, cfg };
|
|
12568
12806
|
return cfg;
|
|
@@ -12630,8 +12868,8 @@ function resolveBotWorktree(realPath) {
|
|
|
12630
12868
|
};
|
|
12631
12869
|
}
|
|
12632
12870
|
function matchDeclaredProject(realPath, projects) {
|
|
12633
|
-
const
|
|
12634
|
-
for (const proj of
|
|
12871
|
+
const candidates2 = [...projects].sort((a, b) => b.root.length - a.root.length);
|
|
12872
|
+
for (const proj of candidates2) {
|
|
12635
12873
|
const root = safeRealpath(proj.root);
|
|
12636
12874
|
if (!isInside(realPath, root))
|
|
12637
12875
|
continue;
|
|
@@ -13665,7 +13903,7 @@ var init_utils = __esm({
|
|
|
13665
13903
|
});
|
|
13666
13904
|
|
|
13667
13905
|
// ../engine/dist/parsers/plan-source.js
|
|
13668
|
-
import { existsSync as existsSync20, readdirSync as readdirSync14, readFileSync as
|
|
13906
|
+
import { existsSync as existsSync20, readdirSync as readdirSync14, readFileSync as readFileSync13, statSync as statSync18 } from "fs";
|
|
13669
13907
|
import { homedir as homedir7 } from "os";
|
|
13670
13908
|
import { join as join21, basename as basename13 } from "path";
|
|
13671
13909
|
import { createHash as createHash8 } from "crypto";
|
|
@@ -13707,6 +13945,7 @@ var init_plan_source = __esm({
|
|
|
13707
13945
|
init_claude2();
|
|
13708
13946
|
init_agy();
|
|
13709
13947
|
init_settings();
|
|
13948
|
+
init_project_dir_name();
|
|
13710
13949
|
MAX_CHUNK_CHARS = 2e3;
|
|
13711
13950
|
UUID_RE3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
13712
13951
|
PlanSource = class {
|
|
@@ -13731,7 +13970,7 @@ var init_plan_source = __esm({
|
|
|
13731
13970
|
for (const entry of entries) {
|
|
13732
13971
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
13733
13972
|
continue;
|
|
13734
|
-
const projectPath = entry.name
|
|
13973
|
+
const projectPath = decodeProjectDirName(entry.name);
|
|
13735
13974
|
if (existsSync20(projectPath)) {
|
|
13736
13975
|
this._knownProjectDirs.push(projectPath);
|
|
13737
13976
|
}
|
|
@@ -13769,7 +14008,7 @@ var init_plan_source = __esm({
|
|
|
13769
14008
|
const stat3 = statSync18(filePath);
|
|
13770
14009
|
const planName = basename13(file, ".md");
|
|
13771
14010
|
const isAgentPlan = planName.includes("-agent-");
|
|
13772
|
-
const content =
|
|
14011
|
+
const content = readFileSync13(filePath, "utf-8");
|
|
13773
14012
|
const fm = parseFrontmatter(content);
|
|
13774
14013
|
const body = fm.body;
|
|
13775
14014
|
const firstLine = body.split("\n").find((l) => l.trim())?.replace(/^#+\s*/, "").trim() || planName;
|
|
@@ -13811,7 +14050,7 @@ var init_plan_source = __esm({
|
|
|
13811
14050
|
const filePath = join21(plansDir, file);
|
|
13812
14051
|
try {
|
|
13813
14052
|
const stat3 = statSync18(filePath);
|
|
13814
|
-
const content =
|
|
14053
|
+
const content = readFileSync13(filePath, "utf-8");
|
|
13815
14054
|
const firstLine = content.split("\n").find((l) => l.trim())?.replace(/^#+\s*/, "").trim() || file;
|
|
13816
14055
|
const planName = `${opencodeBackend.idPrefix}plan_${basename13(file, ".md")}`;
|
|
13817
14056
|
const projectPath = this.extractProjectPath(content);
|
|
@@ -13841,7 +14080,7 @@ var init_plan_source = __esm({
|
|
|
13841
14080
|
const projectsPath = geminiBackend.projectsJson();
|
|
13842
14081
|
if (existsSync20(projectsPath)) {
|
|
13843
14082
|
try {
|
|
13844
|
-
const data = JSON.parse(
|
|
14083
|
+
const data = JSON.parse(readFileSync13(projectsPath, "utf-8"));
|
|
13845
14084
|
for (const path of Object.keys(data.projects || {})) {
|
|
13846
14085
|
projMap.set(createHash8("sha256").update(path).digest("hex"), path);
|
|
13847
14086
|
}
|
|
@@ -13877,7 +14116,7 @@ var init_plan_source = __esm({
|
|
|
13877
14116
|
const filePath = join21(plansDir, file);
|
|
13878
14117
|
try {
|
|
13879
14118
|
const stat3 = statSync18(filePath);
|
|
13880
|
-
const content =
|
|
14119
|
+
const content = readFileSync13(filePath, "utf-8");
|
|
13881
14120
|
const firstLine = content.split("\n").find((l) => l.trim())?.replace(/^#+\s*/, "").trim() || file;
|
|
13882
14121
|
const planName = `${geminiBackend.idPrefix}plan_${sess}_${basename13(file, ".md")}`;
|
|
13883
14122
|
yield {
|
|
@@ -13956,7 +14195,7 @@ var init_plan_source = __esm({
|
|
|
13956
14195
|
async parse(item) {
|
|
13957
14196
|
if (!existsSync20(item.filePath))
|
|
13958
14197
|
return [];
|
|
13959
|
-
const content =
|
|
14198
|
+
const content = readFileSync13(item.filePath, "utf-8");
|
|
13960
14199
|
const chunks = [];
|
|
13961
14200
|
const { body } = parseFrontmatter(content);
|
|
13962
14201
|
const sections = splitByHeaders(body);
|
|
@@ -14100,7 +14339,7 @@ var init_plan_source = __esm({
|
|
|
14100
14339
|
const filePath = join21(sessionPath, file);
|
|
14101
14340
|
try {
|
|
14102
14341
|
const stat3 = statSync18(filePath);
|
|
14103
|
-
const content =
|
|
14342
|
+
const content = readFileSync13(filePath, "utf-8");
|
|
14104
14343
|
const firstLine = content.split("\n").find((l) => l.trim())?.replace(/^#+\s*/, "").trim() || file;
|
|
14105
14344
|
const sessionLoc = agyBackend.findSession(rawId);
|
|
14106
14345
|
const projectPath = sessionLoc?.projectPath || this.extractProjectPath(content);
|
|
@@ -14129,7 +14368,7 @@ var init_plan_source = __esm({
|
|
|
14129
14368
|
});
|
|
14130
14369
|
|
|
14131
14370
|
// ../engine/dist/parsers/task-source.js
|
|
14132
|
-
import { existsSync as existsSync21, readdirSync as readdirSync15, readFileSync as
|
|
14371
|
+
import { existsSync as existsSync21, readdirSync as readdirSync15, readFileSync as readFileSync14, statSync as statSync19 } from "fs";
|
|
14133
14372
|
import { join as join22 } from "path";
|
|
14134
14373
|
var MAX_CHUNK_CHARS2, TaskSource;
|
|
14135
14374
|
var init_task_source = __esm({
|
|
@@ -14179,7 +14418,7 @@ var init_task_source = __esm({
|
|
|
14179
14418
|
continue;
|
|
14180
14419
|
let parsed;
|
|
14181
14420
|
try {
|
|
14182
|
-
const raw =
|
|
14421
|
+
const raw = readFileSync14(filePath, "utf-8");
|
|
14183
14422
|
parsed = JSON.parse(raw);
|
|
14184
14423
|
if (!Array.isArray(parsed) || parsed.length === 0)
|
|
14185
14424
|
continue;
|
|
@@ -14317,7 +14556,7 @@ ${task.description}`.slice(0, MAX_CHUNK_CHARS2);
|
|
|
14317
14556
|
return [];
|
|
14318
14557
|
let parsed;
|
|
14319
14558
|
try {
|
|
14320
|
-
parsed = JSON.parse(
|
|
14559
|
+
parsed = JSON.parse(readFileSync14(item.filePath, "utf-8"));
|
|
14321
14560
|
} catch {
|
|
14322
14561
|
return [];
|
|
14323
14562
|
}
|
|
@@ -14349,7 +14588,7 @@ ${task.description}`.slice(0, MAX_CHUNK_CHARS2);
|
|
|
14349
14588
|
});
|
|
14350
14589
|
for (const file of sorted) {
|
|
14351
14590
|
try {
|
|
14352
|
-
const content =
|
|
14591
|
+
const content = readFileSync14(join22(taskDir, file), "utf-8");
|
|
14353
14592
|
const task = JSON.parse(content);
|
|
14354
14593
|
if (task.subject) {
|
|
14355
14594
|
tasks.push(task);
|
|
@@ -14365,7 +14604,7 @@ ${task.description}`.slice(0, MAX_CHUNK_CHARS2);
|
|
|
14365
14604
|
});
|
|
14366
14605
|
|
|
14367
14606
|
// ../engine/dist/parsers/claude-md-source.js
|
|
14368
|
-
import { existsSync as existsSync22, readFileSync as
|
|
14607
|
+
import { existsSync as existsSync22, readFileSync as readFileSync15, readdirSync as readdirSync16, statSync as statSync20 } from "fs";
|
|
14369
14608
|
import { homedir as homedir8 } from "os";
|
|
14370
14609
|
import { join as join23, basename as basename14, dirname as dirname13 } from "path";
|
|
14371
14610
|
import { createHash as createHash9 } from "crypto";
|
|
@@ -14386,7 +14625,7 @@ function discoverProjectDirs(claudeDir) {
|
|
|
14386
14625
|
for (const entry of entries) {
|
|
14387
14626
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
14388
14627
|
continue;
|
|
14389
|
-
const projectPath = entry.name
|
|
14628
|
+
const projectPath = decodeProjectDirName(entry.name);
|
|
14390
14629
|
addProject(projectPath);
|
|
14391
14630
|
}
|
|
14392
14631
|
} catch {
|
|
@@ -14409,7 +14648,7 @@ function discoverProjectDirs(claudeDir) {
|
|
|
14409
14648
|
const gemProjects = geminiBackend.projectsJson();
|
|
14410
14649
|
if (existsSync22(gemProjects)) {
|
|
14411
14650
|
try {
|
|
14412
|
-
const data = JSON.parse(
|
|
14651
|
+
const data = JSON.parse(readFileSync15(gemProjects, "utf-8"));
|
|
14413
14652
|
for (const path of Object.keys(data.projects || {}))
|
|
14414
14653
|
addProject(path);
|
|
14415
14654
|
} catch {
|
|
@@ -14443,6 +14682,7 @@ var init_claude_md_source = __esm({
|
|
|
14443
14682
|
init_gemini2();
|
|
14444
14683
|
init_settings();
|
|
14445
14684
|
init_opencode();
|
|
14685
|
+
init_project_dir_name();
|
|
14446
14686
|
MAX_CHUNK_CHARS3 = 2e3;
|
|
14447
14687
|
NOTE_FILES = [
|
|
14448
14688
|
{ filename: "CLAUDE.md", tool: "claude" },
|
|
@@ -14523,7 +14763,7 @@ var init_claude_md_source = __esm({
|
|
|
14523
14763
|
async parse(item) {
|
|
14524
14764
|
if (!existsSync22(item.filePath))
|
|
14525
14765
|
return [];
|
|
14526
|
-
const content =
|
|
14766
|
+
const content = readFileSync15(item.filePath, "utf-8");
|
|
14527
14767
|
const chunks = [];
|
|
14528
14768
|
const sections = splitByHeaders(content);
|
|
14529
14769
|
for (let i = 0; i < sections.length; i++) {
|
|
@@ -14565,7 +14805,7 @@ var init_claude_md_source = __esm({
|
|
|
14565
14805
|
const projectDir = dirname13(filePath);
|
|
14566
14806
|
const projectName = basename14(projectDir);
|
|
14567
14807
|
const projectPath = projectDir;
|
|
14568
|
-
const content =
|
|
14808
|
+
const content = readFileSync15(filePath, "utf-8");
|
|
14569
14809
|
const firstLine = content.split("\n").find((l) => l.trim() && !l.startsWith("#"))?.trim()?.slice(0, 200) || `${filename} for ${projectName}`;
|
|
14570
14810
|
const id = tool === "claude" ? projectName : `${projectName}_${tool}`;
|
|
14571
14811
|
return {
|
|
@@ -14590,7 +14830,7 @@ var init_claude_md_source = __esm({
|
|
|
14590
14830
|
});
|
|
14591
14831
|
|
|
14592
14832
|
// ../engine/dist/parsers/agent-memory-source.js
|
|
14593
|
-
import { existsSync as existsSync23, readFileSync as
|
|
14833
|
+
import { existsSync as existsSync23, readFileSync as readFileSync16, readdirSync as readdirSync17, statSync as statSync21 } from "fs";
|
|
14594
14834
|
import { homedir as homedir9 } from "os";
|
|
14595
14835
|
import { join as join24, basename as basename15 } from "path";
|
|
14596
14836
|
function parseFrontmatter2(content) {
|
|
@@ -14618,7 +14858,7 @@ function parseFrontmatter2(content) {
|
|
|
14618
14858
|
return { fm, body };
|
|
14619
14859
|
}
|
|
14620
14860
|
function projectHashToPath(hashDir) {
|
|
14621
|
-
return hashDir
|
|
14861
|
+
return decodeProjectDirName(hashDir);
|
|
14622
14862
|
}
|
|
14623
14863
|
function discoverMemoryDirs() {
|
|
14624
14864
|
const out = [];
|
|
@@ -14660,6 +14900,7 @@ var init_agent_memory_source = __esm({
|
|
|
14660
14900
|
init_utils();
|
|
14661
14901
|
init_claude2();
|
|
14662
14902
|
init_settings();
|
|
14903
|
+
init_project_dir_name();
|
|
14663
14904
|
MAX_CHUNK_CHARS4 = 2e3;
|
|
14664
14905
|
MAX_CHUNKS = 12;
|
|
14665
14906
|
AgentMemorySource = class {
|
|
@@ -14690,7 +14931,7 @@ var init_agent_memory_source = __esm({
|
|
|
14690
14931
|
async parse(item) {
|
|
14691
14932
|
if (!existsSync23(item.filePath))
|
|
14692
14933
|
return [];
|
|
14693
|
-
const content =
|
|
14934
|
+
const content = readFileSync16(item.filePath, "utf-8");
|
|
14694
14935
|
const { body } = parseFrontmatter2(content);
|
|
14695
14936
|
const chunks = [];
|
|
14696
14937
|
const sections = splitByHeaders(body);
|
|
@@ -14743,7 +14984,7 @@ var init_agent_memory_source = __esm({
|
|
|
14743
14984
|
fileToItem(filePath, filename, projectPath, _projectHash) {
|
|
14744
14985
|
try {
|
|
14745
14986
|
const stat3 = statSync21(filePath);
|
|
14746
|
-
const content =
|
|
14987
|
+
const content = readFileSync16(filePath, "utf-8");
|
|
14747
14988
|
const { fm } = parseFrontmatter2(content);
|
|
14748
14989
|
const stem = filename.replace(/\.md$/, "");
|
|
14749
14990
|
const idBase = fm.name || stem;
|
|
@@ -14958,7 +15199,7 @@ var init_history_source = __esm({
|
|
|
14958
15199
|
});
|
|
14959
15200
|
|
|
14960
15201
|
// ../engine/dist/parsers/paste-source.js
|
|
14961
|
-
import { existsSync as existsSync25, readdirSync as readdirSync19, readFileSync as
|
|
15202
|
+
import { existsSync as existsSync25, readdirSync as readdirSync19, readFileSync as readFileSync17, statSync as statSync23 } from "fs";
|
|
14962
15203
|
import { homedir as homedir11 } from "os";
|
|
14963
15204
|
import { join as join26, basename as basename16 } from "path";
|
|
14964
15205
|
var MAX_CHUNK_CHARS6, MAX_FILE_SIZE, PasteSource;
|
|
@@ -15014,7 +15255,7 @@ var init_paste_source = __esm({
|
|
|
15014
15255
|
if (stat3.size < 10)
|
|
15015
15256
|
continue;
|
|
15016
15257
|
const hash = basename16(file, ".txt");
|
|
15017
|
-
const content =
|
|
15258
|
+
const content = readFileSync17(filePath, "utf-8");
|
|
15018
15259
|
const firstLine = content.split("\n").find((l) => l.trim().length > 5)?.trim()?.slice(0, 100) || `Paste ${hash.slice(0, 8)}`;
|
|
15019
15260
|
yield {
|
|
15020
15261
|
id: hash,
|
|
@@ -15035,7 +15276,7 @@ var init_paste_source = __esm({
|
|
|
15035
15276
|
async parse(item) {
|
|
15036
15277
|
if (!existsSync25(item.filePath))
|
|
15037
15278
|
return [];
|
|
15038
|
-
const content =
|
|
15279
|
+
const content = readFileSync17(item.filePath, "utf-8");
|
|
15039
15280
|
if (content.trim().length < 20)
|
|
15040
15281
|
return [];
|
|
15041
15282
|
return [{
|
|
@@ -15058,7 +15299,7 @@ var init_paste_source = __esm({
|
|
|
15058
15299
|
});
|
|
15059
15300
|
|
|
15060
15301
|
// ../engine/dist/parsers/gemini-source.js
|
|
15061
|
-
import { existsSync as existsSync26, readdirSync as readdirSync20, readFileSync as
|
|
15302
|
+
import { existsSync as existsSync26, readdirSync as readdirSync20, readFileSync as readFileSync18, statSync as statSync24 } from "fs";
|
|
15062
15303
|
import { join as join27, basename as basename17 } from "path";
|
|
15063
15304
|
import { createHash as createHash10 } from "crypto";
|
|
15064
15305
|
function loadGeminiProjectMap2() {
|
|
@@ -15067,7 +15308,7 @@ function loadGeminiProjectMap2() {
|
|
|
15067
15308
|
if (!existsSync26(projectsPath))
|
|
15068
15309
|
return map;
|
|
15069
15310
|
try {
|
|
15070
|
-
const data = JSON.parse(
|
|
15311
|
+
const data = JSON.parse(readFileSync18(projectsPath, "utf-8"));
|
|
15071
15312
|
const projects = data.projects || {};
|
|
15072
15313
|
for (const [path] of Object.entries(projects)) {
|
|
15073
15314
|
const hash = createHash10("sha256").update(path).digest("hex");
|
|
@@ -15112,7 +15353,7 @@ var init_gemini_source = __esm({
|
|
|
15112
15353
|
const filePath = join27(chatsDir, file);
|
|
15113
15354
|
try {
|
|
15114
15355
|
const stat3 = statSync24(filePath);
|
|
15115
|
-
const content = JSON.parse(
|
|
15356
|
+
const content = JSON.parse(readFileSync18(filePath, "utf-8"));
|
|
15116
15357
|
const sessionId = content.sessionId || basename17(file, ".json");
|
|
15117
15358
|
if (seen.has(sessionId))
|
|
15118
15359
|
continue;
|
|
@@ -15193,7 +15434,7 @@ var init_gemini_source = __esm({
|
|
|
15193
15434
|
async parse(item) {
|
|
15194
15435
|
if (!existsSync26(item.filePath))
|
|
15195
15436
|
return [];
|
|
15196
|
-
const content = JSON.parse(
|
|
15437
|
+
const content = JSON.parse(readFileSync18(item.filePath, "utf-8"));
|
|
15197
15438
|
const messages = content.messages || [];
|
|
15198
15439
|
const chunks = [];
|
|
15199
15440
|
const getText = (m) => {
|
|
@@ -15241,7 +15482,7 @@ var init_gemini_source = __esm({
|
|
|
15241
15482
|
});
|
|
15242
15483
|
|
|
15243
15484
|
// ../engine/dist/parsers/gemini-brain-source.js
|
|
15244
|
-
import { existsSync as existsSync27, readdirSync as readdirSync21, readFileSync as
|
|
15485
|
+
import { existsSync as existsSync27, readdirSync as readdirSync21, readFileSync as readFileSync19, statSync as statSync25 } from "fs";
|
|
15245
15486
|
import { join as join28 } from "path";
|
|
15246
15487
|
var MAX_CHUNK_CHARS8, GeminiBrainSource;
|
|
15247
15488
|
var init_gemini_brain_source = __esm({
|
|
@@ -15274,14 +15515,14 @@ var init_gemini_brain_source = __esm({
|
|
|
15274
15515
|
const filePath = join28(sessionDir, file);
|
|
15275
15516
|
try {
|
|
15276
15517
|
const stat3 = statSync25(filePath);
|
|
15277
|
-
const content =
|
|
15518
|
+
const content = readFileSync19(filePath, "utf-8");
|
|
15278
15519
|
const firstLine = content.split("\n").find((l) => l.trim() && !l.startsWith("#"))?.trim() || "";
|
|
15279
15520
|
const heading = content.split("\n").find((l) => l.startsWith("#"))?.replace(/^#+\s*/, "").trim() || file;
|
|
15280
15521
|
const metaPath = `${filePath}.metadata.json`;
|
|
15281
15522
|
let metaSummary = "";
|
|
15282
15523
|
if (existsSync27(metaPath)) {
|
|
15283
15524
|
try {
|
|
15284
|
-
const meta = JSON.parse(
|
|
15525
|
+
const meta = JSON.parse(readFileSync19(metaPath, "utf-8"));
|
|
15285
15526
|
metaSummary = meta.summary || "";
|
|
15286
15527
|
} catch {
|
|
15287
15528
|
}
|
|
@@ -15312,7 +15553,7 @@ var init_gemini_brain_source = __esm({
|
|
|
15312
15553
|
async parse(item) {
|
|
15313
15554
|
if (!existsSync27(item.filePath))
|
|
15314
15555
|
return [];
|
|
15315
|
-
const content =
|
|
15556
|
+
const content = readFileSync19(item.filePath, "utf-8");
|
|
15316
15557
|
const chunks = [];
|
|
15317
15558
|
const sections = splitByHeaders(content);
|
|
15318
15559
|
for (let i = 0; i < sections.length; i++) {
|
|
@@ -15655,7 +15896,7 @@ var init_opencode_todo_source = __esm({
|
|
|
15655
15896
|
});
|
|
15656
15897
|
|
|
15657
15898
|
// ../engine/dist/parsers/codex-session-source.js
|
|
15658
|
-
import { existsSync as existsSync30, readdirSync as readdirSync22, readFileSync as
|
|
15899
|
+
import { existsSync as existsSync30, readdirSync as readdirSync22, readFileSync as readFileSync20, statSync as statSync26 } from "fs";
|
|
15659
15900
|
import { join as join29, basename as basename18 } from "path";
|
|
15660
15901
|
function getCodexSessionsDir() {
|
|
15661
15902
|
return codexBackend.sessionsDir();
|
|
@@ -15683,7 +15924,7 @@ function extractReasoningText(event) {
|
|
|
15683
15924
|
return "";
|
|
15684
15925
|
}
|
|
15685
15926
|
function readJsonlLines(filePath) {
|
|
15686
|
-
const text =
|
|
15927
|
+
const text = readFileSync20(filePath, "utf-8");
|
|
15687
15928
|
const lines = text.split("\n");
|
|
15688
15929
|
const events = [];
|
|
15689
15930
|
for (const line of lines) {
|
|
@@ -15718,7 +15959,7 @@ var init_codex_session_source = __esm({
|
|
|
15718
15959
|
for (const filePath of jsonlFiles) {
|
|
15719
15960
|
try {
|
|
15720
15961
|
const stat3 = statSync26(filePath);
|
|
15721
|
-
const lines =
|
|
15962
|
+
const lines = readFileSync20(filePath, "utf-8").split("\n");
|
|
15722
15963
|
const firstLine = lines.find((l) => l.trim());
|
|
15723
15964
|
if (!firstLine)
|
|
15724
15965
|
continue;
|
|
@@ -15891,7 +16132,7 @@ var init_codex_session_source = __esm({
|
|
|
15891
16132
|
});
|
|
15892
16133
|
|
|
15893
16134
|
// ../engine/dist/parsers/diary-source.js
|
|
15894
|
-
import { existsSync as existsSync31, mkdirSync as mkdirSync5, readdirSync as readdirSync23, readFileSync as
|
|
16135
|
+
import { existsSync as existsSync31, mkdirSync as mkdirSync5, readdirSync as readdirSync23, readFileSync as readFileSync21, writeFileSync as writeFileSync4, statSync as statSync27 } from "fs";
|
|
15895
16136
|
import { join as join30, basename as basename19 } from "path";
|
|
15896
16137
|
var MAX_CHUNK_CHARS11, DiarySource;
|
|
15897
16138
|
var init_diary_source = __esm({
|
|
@@ -15917,7 +16158,7 @@ var init_diary_source = __esm({
|
|
|
15917
16158
|
const filePath = join30(agentPath2, file);
|
|
15918
16159
|
try {
|
|
15919
16160
|
const stat3 = statSync27(filePath);
|
|
15920
|
-
const raw =
|
|
16161
|
+
const raw = readFileSync21(filePath, "utf-8");
|
|
15921
16162
|
const entry = JSON.parse(raw);
|
|
15922
16163
|
const entryId = basename19(file, ".json");
|
|
15923
16164
|
const title = `[${entry.agent}] ${entry.topic}: ${entry.content.slice(0, 80)}`;
|
|
@@ -15944,7 +16185,7 @@ var init_diary_source = __esm({
|
|
|
15944
16185
|
async parse(item) {
|
|
15945
16186
|
if (!existsSync31(item.filePath))
|
|
15946
16187
|
return [];
|
|
15947
|
-
const raw =
|
|
16188
|
+
const raw = readFileSync21(item.filePath, "utf-8");
|
|
15948
16189
|
const entry = JSON.parse(raw);
|
|
15949
16190
|
if (!entry.content || entry.content.trim().length < 10)
|
|
15950
16191
|
return [];
|
|
@@ -16007,7 +16248,7 @@ var init_diary_source = __esm({
|
|
|
16007
16248
|
const entries = [];
|
|
16008
16249
|
for (const file of files) {
|
|
16009
16250
|
try {
|
|
16010
|
-
const raw =
|
|
16251
|
+
const raw = readFileSync21(join30(agentDir, file), "utf-8");
|
|
16011
16252
|
entries.push(JSON.parse(raw));
|
|
16012
16253
|
} catch {
|
|
16013
16254
|
continue;
|
|
@@ -16020,7 +16261,7 @@ var init_diary_source = __esm({
|
|
|
16020
16261
|
});
|
|
16021
16262
|
|
|
16022
16263
|
// ../engine/dist/parsers/skills-source.js
|
|
16023
|
-
import { existsSync as existsSync32, readdirSync as readdirSync24, readFileSync as
|
|
16264
|
+
import { existsSync as existsSync32, readdirSync as readdirSync24, readFileSync as readFileSync22, statSync as statSync28 } from "fs";
|
|
16024
16265
|
import { homedir as homedir12 } from "os";
|
|
16025
16266
|
import { join as join31 } from "path";
|
|
16026
16267
|
function resolveRoots() {
|
|
@@ -16113,7 +16354,7 @@ var init_skills_source = __esm({
|
|
|
16113
16354
|
continue;
|
|
16114
16355
|
let content;
|
|
16115
16356
|
try {
|
|
16116
|
-
content =
|
|
16357
|
+
content = readFileSync22(skillMd, "utf-8");
|
|
16117
16358
|
} catch {
|
|
16118
16359
|
continue;
|
|
16119
16360
|
}
|
|
@@ -16173,7 +16414,7 @@ var init_skills_source = __esm({
|
|
|
16173
16414
|
async parse(item) {
|
|
16174
16415
|
if (!existsSync32(item.filePath))
|
|
16175
16416
|
return [];
|
|
16176
|
-
const content =
|
|
16417
|
+
const content = readFileSync22(item.filePath, "utf-8");
|
|
16177
16418
|
if (!content.trim())
|
|
16178
16419
|
return [];
|
|
16179
16420
|
return [{
|
|
@@ -16196,14 +16437,14 @@ var init_skills_source = __esm({
|
|
|
16196
16437
|
});
|
|
16197
16438
|
|
|
16198
16439
|
// ../engine/dist/parsers/mcps-source.js
|
|
16199
|
-
import { existsSync as existsSync33, readdirSync as readdirSync25, readFileSync as
|
|
16440
|
+
import { existsSync as existsSync33, readdirSync as readdirSync25, readFileSync as readFileSync23, statSync as statSync29 } from "fs";
|
|
16200
16441
|
import { homedir as homedir13 } from "os";
|
|
16201
16442
|
import { join as join32 } from "path";
|
|
16202
16443
|
function readJson(path) {
|
|
16203
16444
|
if (!existsSync33(path))
|
|
16204
16445
|
return null;
|
|
16205
16446
|
try {
|
|
16206
|
-
const raw =
|
|
16447
|
+
const raw = readFileSync23(path, "utf-8");
|
|
16207
16448
|
const stripped = path.endsWith(".jsonc") ? raw.replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|[^:])\/\/.*$/gm, "$1").replace(/,(\s*[}\]])/g, "$1") : raw;
|
|
16208
16449
|
return JSON.parse(stripped);
|
|
16209
16450
|
} catch {
|
|
@@ -16316,7 +16557,7 @@ var init_mcps_source = __esm({
|
|
|
16316
16557
|
return;
|
|
16317
16558
|
let content;
|
|
16318
16559
|
try {
|
|
16319
|
-
content =
|
|
16560
|
+
content = readFileSync23(path, "utf-8");
|
|
16320
16561
|
} catch {
|
|
16321
16562
|
return;
|
|
16322
16563
|
}
|
|
@@ -16485,7 +16726,7 @@ var init_toolkit_format = __esm({
|
|
|
16485
16726
|
});
|
|
16486
16727
|
|
|
16487
16728
|
// ../engine/dist/parsers/slash-commands-source.js
|
|
16488
|
-
import { existsSync as existsSync34, readdirSync as readdirSync26, readFileSync as
|
|
16729
|
+
import { existsSync as existsSync34, readdirSync as readdirSync26, readFileSync as readFileSync24, statSync as statSync30 } from "fs";
|
|
16489
16730
|
import { join as join33, basename as basename20 } from "path";
|
|
16490
16731
|
function parseCommand(content, fallbackName, format) {
|
|
16491
16732
|
if (format === "toml") {
|
|
@@ -16513,6 +16754,7 @@ var init_slash_commands_source = __esm({
|
|
|
16513
16754
|
init_codex2();
|
|
16514
16755
|
init_settings();
|
|
16515
16756
|
init_toolkit_format();
|
|
16757
|
+
init_project_dir_name();
|
|
16516
16758
|
MAX_CHUNK_CHARS13 = 2e3;
|
|
16517
16759
|
SlashCommandsSource = class {
|
|
16518
16760
|
sourceType = "command";
|
|
@@ -16526,7 +16768,7 @@ var init_slash_commands_source = __esm({
|
|
|
16526
16768
|
for (const entry of readdirSync26(projectsRoot, { withFileTypes: true })) {
|
|
16527
16769
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
16528
16770
|
continue;
|
|
16529
|
-
const projectPath = entry.name
|
|
16771
|
+
const projectPath = decodeProjectDirName(entry.name);
|
|
16530
16772
|
const cmdDir = join33(projectPath, ".claude", "commands");
|
|
16531
16773
|
if (existsSync34(cmdDir))
|
|
16532
16774
|
roots.push({ path: cmdDir, tool: "claude", scope: "project", projectPath, format: "md" });
|
|
@@ -16559,7 +16801,7 @@ var init_slash_commands_source = __esm({
|
|
|
16559
16801
|
const filePath = join33(root.path, file);
|
|
16560
16802
|
try {
|
|
16561
16803
|
const stat3 = statSync30(filePath);
|
|
16562
|
-
const content =
|
|
16804
|
+
const content = readFileSync24(filePath, "utf-8");
|
|
16563
16805
|
const parsed = parseCommand(content, basename20(file, ext), root.format);
|
|
16564
16806
|
yield {
|
|
16565
16807
|
id: `${root.tool}_cmd_${root.scope}_${parsed.name}`,
|
|
@@ -16585,7 +16827,7 @@ var init_slash_commands_source = __esm({
|
|
|
16585
16827
|
async parse(item) {
|
|
16586
16828
|
if (!existsSync34(item.filePath))
|
|
16587
16829
|
return [];
|
|
16588
|
-
const content =
|
|
16830
|
+
const content = readFileSync24(item.filePath, "utf-8");
|
|
16589
16831
|
if (!content.trim())
|
|
16590
16832
|
return [];
|
|
16591
16833
|
return [{
|
|
@@ -16608,7 +16850,7 @@ var init_slash_commands_source = __esm({
|
|
|
16608
16850
|
});
|
|
16609
16851
|
|
|
16610
16852
|
// ../engine/dist/parsers/subagents-source.js
|
|
16611
|
-
import { existsSync as existsSync35, readdirSync as readdirSync27, readFileSync as
|
|
16853
|
+
import { existsSync as existsSync35, readdirSync as readdirSync27, readFileSync as readFileSync25, statSync as statSync31 } from "fs";
|
|
16612
16854
|
import { join as join34, basename as basename21 } from "path";
|
|
16613
16855
|
function parseAgent(content, fallbackName, format) {
|
|
16614
16856
|
if (format === "toml") {
|
|
@@ -16638,6 +16880,7 @@ var init_subagents_source = __esm({
|
|
|
16638
16880
|
init_codex2();
|
|
16639
16881
|
init_settings();
|
|
16640
16882
|
init_toolkit_format();
|
|
16883
|
+
init_project_dir_name();
|
|
16641
16884
|
MAX_CHUNK_CHARS14 = 2e3;
|
|
16642
16885
|
SubagentsSource = class {
|
|
16643
16886
|
sourceType = "agent";
|
|
@@ -16651,7 +16894,7 @@ var init_subagents_source = __esm({
|
|
|
16651
16894
|
for (const entry of readdirSync27(projectsRoot, { withFileTypes: true })) {
|
|
16652
16895
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
16653
16896
|
continue;
|
|
16654
|
-
const projectPath = entry.name
|
|
16897
|
+
const projectPath = decodeProjectDirName(entry.name);
|
|
16655
16898
|
const agentDir = join34(projectPath, ".claude", "agents");
|
|
16656
16899
|
if (existsSync35(agentDir))
|
|
16657
16900
|
roots.push({ path: agentDir, tool: "claude", scope: "project", projectPath, format: "md" });
|
|
@@ -16684,7 +16927,7 @@ var init_subagents_source = __esm({
|
|
|
16684
16927
|
const filePath = join34(root.path, file);
|
|
16685
16928
|
try {
|
|
16686
16929
|
const stat3 = statSync31(filePath);
|
|
16687
|
-
const content =
|
|
16930
|
+
const content = readFileSync25(filePath, "utf-8");
|
|
16688
16931
|
const parsed = parseAgent(content, basename21(file, ext), root.format);
|
|
16689
16932
|
yield {
|
|
16690
16933
|
id: `${root.tool}_agent_${root.scope}_${parsed.name}`,
|
|
@@ -16711,7 +16954,7 @@ var init_subagents_source = __esm({
|
|
|
16711
16954
|
async parse(item) {
|
|
16712
16955
|
if (!existsSync35(item.filePath))
|
|
16713
16956
|
return [];
|
|
16714
|
-
const content =
|
|
16957
|
+
const content = readFileSync25(item.filePath, "utf-8");
|
|
16715
16958
|
if (!content.trim())
|
|
16716
16959
|
return [];
|
|
16717
16960
|
return [{
|
|
@@ -16734,13 +16977,13 @@ var init_subagents_source = __esm({
|
|
|
16734
16977
|
});
|
|
16735
16978
|
|
|
16736
16979
|
// ../engine/dist/parsers/hooks-source.js
|
|
16737
|
-
import { existsSync as existsSync36, readFileSync as
|
|
16980
|
+
import { existsSync as existsSync36, readFileSync as readFileSync26, readdirSync as readdirSync28, statSync as statSync32 } from "fs";
|
|
16738
16981
|
import { join as join35 } from "path";
|
|
16739
16982
|
function readJson2(path) {
|
|
16740
16983
|
if (!existsSync36(path))
|
|
16741
16984
|
return null;
|
|
16742
16985
|
try {
|
|
16743
|
-
return JSON.parse(
|
|
16986
|
+
return JSON.parse(readFileSync26(path, "utf-8"));
|
|
16744
16987
|
} catch {
|
|
16745
16988
|
return null;
|
|
16746
16989
|
}
|
|
@@ -16751,6 +16994,7 @@ var init_hooks_source = __esm({
|
|
|
16751
16994
|
"use strict";
|
|
16752
16995
|
init_claude2();
|
|
16753
16996
|
init_settings();
|
|
16997
|
+
init_project_dir_name();
|
|
16754
16998
|
HooksSource = class {
|
|
16755
16999
|
sourceType = "hook";
|
|
16756
17000
|
async *discover() {
|
|
@@ -16763,7 +17007,7 @@ var init_hooks_source = __esm({
|
|
|
16763
17007
|
for (const entry of readdirSync28(projectsRoot, { withFileTypes: true })) {
|
|
16764
17008
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
16765
17009
|
continue;
|
|
16766
|
-
const projectPath = entry.name
|
|
17010
|
+
const projectPath = decodeProjectDirName(entry.name);
|
|
16767
17011
|
const settingsPath2 = join35(projectPath, ".claude", "settings.json");
|
|
16768
17012
|
if (existsSync36(settingsPath2)) {
|
|
16769
17013
|
yield* this.fromSettings(settingsPath2, "project", projectPath);
|
|
@@ -16856,14 +17100,14 @@ var init_hooks_source = __esm({
|
|
|
16856
17100
|
});
|
|
16857
17101
|
|
|
16858
17102
|
// ../engine/dist/parsers/plugins-source.js
|
|
16859
|
-
import { existsSync as existsSync37, readFileSync as
|
|
17103
|
+
import { existsSync as existsSync37, readFileSync as readFileSync27, readdirSync as readdirSync29, statSync as statSync33 } from "fs";
|
|
16860
17104
|
import { homedir as homedir14 } from "os";
|
|
16861
17105
|
import { join as join36 } from "path";
|
|
16862
17106
|
function readJson3(path) {
|
|
16863
17107
|
if (!existsSync37(path))
|
|
16864
17108
|
return null;
|
|
16865
17109
|
try {
|
|
16866
|
-
return JSON.parse(
|
|
17110
|
+
return JSON.parse(readFileSync27(path, "utf-8"));
|
|
16867
17111
|
} catch {
|
|
16868
17112
|
return null;
|
|
16869
17113
|
}
|
|
@@ -17111,14 +17355,16 @@ var init_extractor_version = __esm({
|
|
|
17111
17355
|
"use strict";
|
|
17112
17356
|
BASE_EXTRACTOR_VERSION = 2;
|
|
17113
17357
|
TOOL_EXTRACTOR_BUMP = {
|
|
17114
|
-
agy: 2
|
|
17358
|
+
agy: 2,
|
|
17359
|
+
claude: 1,
|
|
17360
|
+
codex: 1
|
|
17115
17361
|
};
|
|
17116
17362
|
EXTRACTOR_VERSION = BASE_EXTRACTOR_VERSION;
|
|
17117
17363
|
}
|
|
17118
17364
|
});
|
|
17119
17365
|
|
|
17120
17366
|
// src/sync-ledger.ts
|
|
17121
|
-
import { readFileSync as
|
|
17367
|
+
import { readFileSync as readFileSync28, writeFileSync as writeFileSync5, renameSync as renameSync4, mkdirSync as mkdirSync6 } from "node:fs";
|
|
17122
17368
|
import { join as join37, dirname as dirname14 } from "node:path";
|
|
17123
17369
|
function toRow(entry) {
|
|
17124
17370
|
if (entry === void 0) return void 0;
|
|
@@ -17127,24 +17373,77 @@ function toRow(entry) {
|
|
|
17127
17373
|
function load() {
|
|
17128
17374
|
if (cache3) return cache3;
|
|
17129
17375
|
try {
|
|
17130
|
-
const parsed = JSON.parse(
|
|
17376
|
+
const parsed = JSON.parse(readFileSync28(ledgerPath(), "utf-8"));
|
|
17131
17377
|
cache3 = parsed && typeof parsed === "object" ? parsed : {};
|
|
17132
17378
|
} catch {
|
|
17133
17379
|
cache3 = {};
|
|
17134
17380
|
}
|
|
17135
17381
|
return cache3;
|
|
17136
17382
|
}
|
|
17137
|
-
function
|
|
17383
|
+
function persistNow(data) {
|
|
17138
17384
|
const path = ledgerPath();
|
|
17139
17385
|
mkdirSync6(dirname14(path), { recursive: true });
|
|
17140
17386
|
const tmp = `${path}.tmp`;
|
|
17141
17387
|
writeFileSync5(tmp, JSON.stringify(data));
|
|
17142
17388
|
renameSync4(tmp, path);
|
|
17389
|
+
pendingWrite = false;
|
|
17390
|
+
}
|
|
17391
|
+
function persist(data) {
|
|
17392
|
+
pendingWrite = true;
|
|
17393
|
+
if (flushTimer) return;
|
|
17394
|
+
flushTimer = setTimeout(() => {
|
|
17395
|
+
flushTimer = null;
|
|
17396
|
+
if (pendingWrite) {
|
|
17397
|
+
try {
|
|
17398
|
+
persistNow(data);
|
|
17399
|
+
} catch {
|
|
17400
|
+
}
|
|
17401
|
+
}
|
|
17402
|
+
}, LEDGER_FLUSH_MS);
|
|
17403
|
+
flushTimer.unref?.();
|
|
17404
|
+
}
|
|
17405
|
+
function pruneLedgerTargets(configuredServers) {
|
|
17406
|
+
const data = load();
|
|
17407
|
+
const keep = new Set(configuredServers);
|
|
17408
|
+
const orphans = {};
|
|
17409
|
+
for (const server of Object.keys(data)) {
|
|
17410
|
+
if (!keep.has(server)) {
|
|
17411
|
+
orphans[server] = data[server];
|
|
17412
|
+
delete data[server];
|
|
17413
|
+
}
|
|
17414
|
+
}
|
|
17415
|
+
const names = Object.keys(orphans);
|
|
17416
|
+
if (names.length === 0) return 0;
|
|
17417
|
+
const path = ledgerPath();
|
|
17418
|
+
const side = `${path}.orphans.json`;
|
|
17419
|
+
try {
|
|
17420
|
+
let prior = {};
|
|
17421
|
+
try {
|
|
17422
|
+
prior = JSON.parse(readFileSync28(side, "utf-8"));
|
|
17423
|
+
} catch {
|
|
17424
|
+
}
|
|
17425
|
+
writeFileSync5(side, JSON.stringify({ ...prior, ...orphans }));
|
|
17426
|
+
} catch {
|
|
17427
|
+
for (const n of names) data[n] = orphans[n];
|
|
17428
|
+
return 0;
|
|
17429
|
+
}
|
|
17430
|
+
const rows = names.reduce((n, s) => n + Object.keys(orphans[s]).length, 0);
|
|
17431
|
+
console.error(`[sync] ledger: parked ${rows} row(s) for ${names.length} server(s) no longer configured (${names.join(", ")}) in ${side}`);
|
|
17432
|
+
persistNow(data);
|
|
17433
|
+
return names.length;
|
|
17434
|
+
}
|
|
17435
|
+
function flushLedger() {
|
|
17436
|
+
if (flushTimer) {
|
|
17437
|
+
clearTimeout(flushTimer);
|
|
17438
|
+
flushTimer = null;
|
|
17439
|
+
}
|
|
17440
|
+
if (!pendingWrite || !cache3) return;
|
|
17441
|
+
persistNow(cache3);
|
|
17143
17442
|
}
|
|
17144
17443
|
function loadItemVersionsAll() {
|
|
17145
17444
|
if (itemVersionsCache) return itemVersionsCache;
|
|
17146
17445
|
try {
|
|
17147
|
-
const parsed = JSON.parse(
|
|
17446
|
+
const parsed = JSON.parse(readFileSync28(itemVersionsPath(), "utf-8"));
|
|
17148
17447
|
itemVersionsCache = parsed && typeof parsed === "object" ? parsed : {};
|
|
17149
17448
|
} catch {
|
|
17150
17449
|
itemVersionsCache = {};
|
|
@@ -17226,7 +17525,7 @@ function markFieldCoverage(server, field, rows) {
|
|
|
17226
17525
|
function loadReconcile() {
|
|
17227
17526
|
if (reconcileCache) return reconcileCache;
|
|
17228
17527
|
try {
|
|
17229
|
-
const parsed = JSON.parse(
|
|
17528
|
+
const parsed = JSON.parse(readFileSync28(reconcilePath(), "utf-8"));
|
|
17230
17529
|
reconcileCache = parsed && typeof parsed === "object" ? parsed : {};
|
|
17231
17530
|
} catch {
|
|
17232
17531
|
reconcileCache = {};
|
|
@@ -17274,7 +17573,7 @@ function syncMode(row, mtime, fileSize, extractorVersion, isAppendOnly) {
|
|
|
17274
17573
|
if (row.m >= Math.floor(mtime)) return "skip";
|
|
17275
17574
|
return "full";
|
|
17276
17575
|
}
|
|
17277
|
-
var ledgerPath, cache3, itemVersionsPath, itemVersionsCache, unackedCursorAttempts, reconcilePath, reconcileCache;
|
|
17576
|
+
var ledgerPath, cache3, LEDGER_FLUSH_MS, pendingWrite, flushTimer, itemVersionsPath, itemVersionsCache, unackedCursorAttempts, reconcilePath, reconcileCache;
|
|
17278
17577
|
var init_sync_ledger = __esm({
|
|
17279
17578
|
"src/sync-ledger.ts"() {
|
|
17280
17579
|
"use strict";
|
|
@@ -17282,6 +17581,9 @@ var init_sync_ledger = __esm({
|
|
|
17282
17581
|
init_extractor_version();
|
|
17283
17582
|
ledgerPath = () => join37(getDataDir(), "sync-ledger.json");
|
|
17284
17583
|
cache3 = null;
|
|
17584
|
+
LEDGER_FLUSH_MS = 2e3;
|
|
17585
|
+
pendingWrite = false;
|
|
17586
|
+
flushTimer = null;
|
|
17285
17587
|
itemVersionsPath = () => join37(getDataDir(), "item-versions.json");
|
|
17286
17588
|
itemVersionsCache = null;
|
|
17287
17589
|
unackedCursorAttempts = 0;
|
|
@@ -17316,7 +17618,7 @@ var init_sync_fields = __esm({
|
|
|
17316
17618
|
});
|
|
17317
17619
|
|
|
17318
17620
|
// ../engine/dist/core/index-lock.js
|
|
17319
|
-
import { existsSync as existsSync38, mkdirSync as mkdirSync7, openSync as
|
|
17621
|
+
import { existsSync as existsSync38, mkdirSync as mkdirSync7, openSync as openSync7, writeFileSync as writeFileSync6, readFileSync as readFileSync29, rmSync as rmSync4, statSync as statSync34, closeSync as closeSync7 } from "fs";
|
|
17320
17622
|
import { dirname as dirname15, join as join38 } from "path";
|
|
17321
17623
|
function acquireIndexLock(opts) {
|
|
17322
17624
|
const lockPath = lockFilePath();
|
|
@@ -17328,7 +17630,7 @@ function acquireIndexLock(opts) {
|
|
|
17328
17630
|
}
|
|
17329
17631
|
let fd;
|
|
17330
17632
|
try {
|
|
17331
|
-
fd =
|
|
17633
|
+
fd = openSync7(lockPath, "wx", 384);
|
|
17332
17634
|
} catch (err) {
|
|
17333
17635
|
if (err.code === "EEXIST")
|
|
17334
17636
|
return null;
|
|
@@ -17338,7 +17640,7 @@ function acquireIndexLock(opts) {
|
|
|
17338
17640
|
try {
|
|
17339
17641
|
writeFileSync6(fd, JSON.stringify(holder));
|
|
17340
17642
|
} finally {
|
|
17341
|
-
|
|
17643
|
+
closeSync7(fd);
|
|
17342
17644
|
}
|
|
17343
17645
|
let released = false;
|
|
17344
17646
|
return {
|
|
@@ -17348,7 +17650,7 @@ function acquireIndexLock(opts) {
|
|
|
17348
17650
|
return;
|
|
17349
17651
|
released = true;
|
|
17350
17652
|
try {
|
|
17351
|
-
const current = JSON.parse(
|
|
17653
|
+
const current = JSON.parse(readFileSync29(lockPath, "utf-8"));
|
|
17352
17654
|
if (current.pid !== holder.pid || current.startedAt !== holder.startedAt)
|
|
17353
17655
|
return;
|
|
17354
17656
|
} catch {
|
|
@@ -17370,7 +17672,7 @@ function stealStaleLock(lockPath, staleAfterMs) {
|
|
|
17370
17672
|
const age = Date.now() - s.mtimeMs;
|
|
17371
17673
|
let payload;
|
|
17372
17674
|
try {
|
|
17373
|
-
payload = JSON.parse(
|
|
17675
|
+
payload = JSON.parse(readFileSync29(lockPath, "utf-8"));
|
|
17374
17676
|
} catch {
|
|
17375
17677
|
rmSync4(lockPath, { force: true });
|
|
17376
17678
|
return true;
|
|
@@ -17408,7 +17710,7 @@ var init_index_lock = __esm({
|
|
|
17408
17710
|
});
|
|
17409
17711
|
|
|
17410
17712
|
// src/http.ts
|
|
17411
|
-
import { readFileSync as
|
|
17713
|
+
import { readFileSync as readFileSync30 } from "node:fs";
|
|
17412
17714
|
function clientHeaders() {
|
|
17413
17715
|
return {
|
|
17414
17716
|
"x-chat-recall-cli": CLI_VERSION,
|
|
@@ -17426,10 +17728,10 @@ var init_http = __esm({
|
|
|
17426
17728
|
"use strict";
|
|
17427
17729
|
CLI_VERSION = "0.0.0";
|
|
17428
17730
|
try {
|
|
17429
|
-
CLI_VERSION = JSON.parse(
|
|
17731
|
+
CLI_VERSION = JSON.parse(readFileSync30(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
|
|
17430
17732
|
} catch {
|
|
17431
17733
|
try {
|
|
17432
|
-
if (true) CLI_VERSION = "0.5.
|
|
17734
|
+
if (true) CLI_VERSION = "0.5.6";
|
|
17433
17735
|
} catch {
|
|
17434
17736
|
}
|
|
17435
17737
|
}
|
|
@@ -17442,7 +17744,7 @@ __export(client_events_exports, {
|
|
|
17442
17744
|
isTelemetryEnabled: () => isTelemetryEnabled,
|
|
17443
17745
|
reportClientEvent: () => reportClientEvent
|
|
17444
17746
|
});
|
|
17445
|
-
import { readFileSync as
|
|
17747
|
+
import { readFileSync as readFileSync31 } from "node:fs";
|
|
17446
17748
|
function scrub(msg) {
|
|
17447
17749
|
if (!msg) return "";
|
|
17448
17750
|
const noHome = msg.replace(/\/(?:home|Users)\/[^/\s]+/g, "~");
|
|
@@ -17495,7 +17797,7 @@ var init_client_events = __esm({
|
|
|
17495
17797
|
init_secret_redactor();
|
|
17496
17798
|
CLI_VERSION2 = "0.0.0";
|
|
17497
17799
|
try {
|
|
17498
|
-
CLI_VERSION2 = JSON.parse(
|
|
17800
|
+
CLI_VERSION2 = JSON.parse(readFileSync31(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION2;
|
|
17499
17801
|
} catch {
|
|
17500
17802
|
}
|
|
17501
17803
|
}
|
|
@@ -17615,13 +17917,15 @@ var init_auto_update = __esm({
|
|
|
17615
17917
|
|
|
17616
17918
|
// src/sync-client.ts
|
|
17617
17919
|
import { join as join40, dirname as dirname16, basename as basename22 } from "node:path";
|
|
17618
|
-
import { readFileSync as
|
|
17920
|
+
import { readFileSync as readFileSync32, writeFileSync as writeFileSync8, mkdirSync as mkdirSync8, mkdtempSync as mkdtempSync4, rmSync as rmSync5, chmodSync as chmodSync3, unlinkSync as unlinkSync2, readdirSync as readdirSync30, statSync as statSync35 } from "node:fs";
|
|
17619
17921
|
import { tmpdir as tmpdir3, hostname } from "node:os";
|
|
17620
17922
|
import { createHash as createHash12 } from "node:crypto";
|
|
17621
17923
|
import { fileURLToPath } from "node:url";
|
|
17622
17924
|
function loadAllCredentials() {
|
|
17925
|
+
const fromEnv = envCredentials();
|
|
17926
|
+
if (fromEnv) return [{ serverUrl: fromEnv.serverUrl, token: fromEnv.token }];
|
|
17623
17927
|
try {
|
|
17624
|
-
const parsed = JSON.parse(
|
|
17928
|
+
const parsed = JSON.parse(readFileSync32(credPath(), "utf-8"));
|
|
17625
17929
|
if (Array.isArray(parsed?.targets)) return parsed.targets.filter((t) => t?.serverUrl).map((t) => ({ serverUrl: t.serverUrl, token: t.token || "" }));
|
|
17626
17930
|
if (parsed?.serverUrl) return [{ serverUrl: parsed.serverUrl, token: parsed.token || "" }];
|
|
17627
17931
|
} catch {
|
|
@@ -17767,6 +18071,10 @@ function isLocalHost(serverUrl) {
|
|
|
17767
18071
|
async function syncSessions(opts = {}) {
|
|
17768
18072
|
const targets = loadAllCredentials();
|
|
17769
18073
|
if (targets.length === 0) throw new Error("Not logged in \u2014 run `chat-recall login <server-url> --token <token>`");
|
|
18074
|
+
try {
|
|
18075
|
+
pruneLedgerTargets(targets.map((t) => t.serverUrl));
|
|
18076
|
+
} catch {
|
|
18077
|
+
}
|
|
17770
18078
|
let agg = null;
|
|
17771
18079
|
const errors = [];
|
|
17772
18080
|
for (const cred of targets) {
|
|
@@ -17789,6 +18097,7 @@ async function syncSessions(opts = {}) {
|
|
|
17789
18097
|
errors.push(`${cred.serverUrl}: ${e instanceof Error ? e.message : e}`);
|
|
17790
18098
|
}
|
|
17791
18099
|
}
|
|
18100
|
+
flushLedger();
|
|
17792
18101
|
if (!agg) throw new Error(`sync failed for all targets:
|
|
17793
18102
|
${errors.join("\n ")}`);
|
|
17794
18103
|
if (errors.length > 0) console.error(`[sync] ${errors.length} target(s) failed (others succeeded):
|
|
@@ -17814,11 +18123,11 @@ async function reconcileFieldsForTarget(cred, fullRefs, opts = {}) {
|
|
|
17814
18123
|
let pushed = 0, absent = 0, scanned = 0;
|
|
17815
18124
|
for (const field of SYNC_FIELDS) {
|
|
17816
18125
|
const needFull = !!opts.force || fieldNeedsFullPass(base2, field);
|
|
17817
|
-
const
|
|
18126
|
+
const candidates2 = needFull ? fullRefs() : opts.convRefs ?? fullRefs();
|
|
17818
18127
|
const send = [];
|
|
17819
18128
|
const mtimeById = /* @__PURE__ */ new Map();
|
|
17820
18129
|
const absentIds = [];
|
|
17821
|
-
for (const ref of
|
|
18130
|
+
for (const ref of candidates2) {
|
|
17822
18131
|
if (!fieldNeedsScan(ledger.get(ref.prefixedId), field, ref.mtime, opts.force)) continue;
|
|
17823
18132
|
scanned++;
|
|
17824
18133
|
mtimeById.set(ref.prefixedId, ref.mtime);
|
|
@@ -17917,6 +18226,17 @@ function batchScanExternal(items, opts = {}) {
|
|
|
17917
18226
|
}
|
|
17918
18227
|
return { findings, scanned, slices, scanMs };
|
|
17919
18228
|
}
|
|
18229
|
+
async function verifyServerApi(serverUrl, minApi) {
|
|
18230
|
+
const base2 = serverUrl.replace(/\/$/, "");
|
|
18231
|
+
const seen = capsOk.get(base2);
|
|
18232
|
+
if (seen !== void 0 && Date.now() - seen < CAPS_TTL_MS) return true;
|
|
18233
|
+
const caps = await fetchWithTimeout(`${base2}/api/capabilities`).then((r) => r.json());
|
|
18234
|
+
if ((caps.apiVersion ?? 0) < minApi) {
|
|
18235
|
+
throw new Error(`server too old: apiVersion ${caps.apiVersion ?? "none"} < required ${minApi} \u2014 update the server image before syncing`);
|
|
18236
|
+
}
|
|
18237
|
+
capsOk.set(base2, Date.now());
|
|
18238
|
+
return true;
|
|
18239
|
+
}
|
|
17920
18240
|
async function syncToTarget(cred, opts = {}) {
|
|
17921
18241
|
const sync = loadSettings().sync;
|
|
17922
18242
|
const serverCfg = await fetchTenantSyncConfig(cred);
|
|
@@ -17937,14 +18257,9 @@ async function syncToTarget(cred, opts = {}) {
|
|
|
17937
18257
|
return isProjectSyncable(r.source === "ignored" ? "" : r.id, projectPath, { syncMode: "only", syncOnly });
|
|
17938
18258
|
};
|
|
17939
18259
|
const MIN_SERVER_API = 2;
|
|
17940
|
-
|
|
17941
|
-
const
|
|
17942
|
-
if ((
|
|
17943
|
-
throw new Error(`server too old: apiVersion ${caps.apiVersion ?? "none"} < required ${MIN_SERVER_API} \u2014 update the server image before syncing`);
|
|
17944
|
-
}
|
|
17945
|
-
} catch (e) {
|
|
17946
|
-
if (e instanceof Error && e.message.startsWith("server too old")) throw e;
|
|
17947
|
-
throw new Error(`cannot verify server version (${e instanceof Error ? e.message : e}) \u2014 refusing to sync blind`);
|
|
18260
|
+
{
|
|
18261
|
+
const ok = await verifyServerApi(cred.serverUrl, MIN_SERVER_API);
|
|
18262
|
+
if (!ok) throw new Error(`cannot verify server version \u2014 refusing to sync blind`);
|
|
17948
18263
|
}
|
|
17949
18264
|
const { tenantRules, verifySecrets } = await fetchTenantSecurityConfig(cred);
|
|
17950
18265
|
const CHANGED_WALK_OVERLAP_MS = 15 * 6e4;
|
|
@@ -17996,6 +18311,20 @@ async function syncToTarget(cred, opts = {}) {
|
|
|
17996
18311
|
if (res.status === 401 || res.status === 403) {
|
|
17997
18312
|
throw new Error(`server rejected this machine's device token (HTTP ${res.status} \u2014 revoked?). Reconnect with: chat-recall login ${base2}`);
|
|
17998
18313
|
}
|
|
18314
|
+
if (res.status === 402) {
|
|
18315
|
+
let detail = text;
|
|
18316
|
+
try {
|
|
18317
|
+
const body2 = JSON.parse(text);
|
|
18318
|
+
detail = body2.error ?? text;
|
|
18319
|
+
if (body2.detail) detail += `
|
|
18320
|
+
${body2.detail}`;
|
|
18321
|
+
if (body2.resetsAt) detail += ` (resets ${new Date(body2.resetsAt).toISOString().slice(0, 10)})`;
|
|
18322
|
+
if (body2.upgradeUrl) detail += `
|
|
18323
|
+
${body2.upgradeUrl}`;
|
|
18324
|
+
} catch {
|
|
18325
|
+
}
|
|
18326
|
+
throw new Error(`sync paused by the server: ${detail}`);
|
|
18327
|
+
}
|
|
17999
18328
|
if (!retryable) throw new Error(`sync failed: HTTP ${res.status} ${text}`);
|
|
18000
18329
|
if (attempt >= RETRY_DELAYS_MS.length) throw new Error(`sync failed after ${attempt + 1} attempts: HTTP ${res.status} ${text}`);
|
|
18001
18330
|
const retryAfterS = Number(res.headers.get("retry-after"));
|
|
@@ -18138,16 +18467,21 @@ async function syncToTarget(cred, opts = {}) {
|
|
|
18138
18467
|
const findingsBatch = makeBatcher("findings", 200, true);
|
|
18139
18468
|
const scanSecrets = isSecretScannerAvailable() && upload.findings && process.env.CHAT_RECALL_SCAN_SECRETS !== "0";
|
|
18140
18469
|
const verifySecretsScan = verifySecrets;
|
|
18470
|
+
let skipped = 0, redactions = 0, walked = 0;
|
|
18141
18471
|
const kgSeen = /* @__PURE__ */ new Set();
|
|
18142
18472
|
const kgEntityType = /* @__PURE__ */ new Map();
|
|
18143
|
-
const
|
|
18144
|
-
const
|
|
18473
|
+
const kgEntityNames = /* @__PURE__ */ new Set();
|
|
18474
|
+
const kgKey = (subject, predicate, object, validFrom) => createHash12("sha1").update(`${subject}|${predicate}|${object}|${validFrom}`).digest("hex").slice(0, 16);
|
|
18475
|
+
const accumulateKg = async (triples, sourceSession) => {
|
|
18145
18476
|
for (const t of triples) {
|
|
18146
|
-
const key =
|
|
18477
|
+
const key = kgKey(t.subject, t.predicate, t.object, t.validFrom ?? "");
|
|
18147
18478
|
if (kgSeen.has(key)) continue;
|
|
18148
18479
|
kgSeen.add(key);
|
|
18149
18480
|
if (t.predicate === "is_a" && !kgEntityType.has(t.subject)) kgEntityType.set(t.subject, t.object);
|
|
18150
|
-
|
|
18481
|
+
kgEntityNames.add(t.subject);
|
|
18482
|
+
kgEntityNames.add(t.object);
|
|
18483
|
+
const count = { redactions: 0 };
|
|
18484
|
+
await kgTripleBatch.add(redactDeep({
|
|
18151
18485
|
subject: t.subject,
|
|
18152
18486
|
predicate: t.predicate,
|
|
18153
18487
|
object: t.object,
|
|
@@ -18155,10 +18489,10 @@ async function syncToTarget(cred, opts = {}) {
|
|
|
18155
18489
|
valid_to: null,
|
|
18156
18490
|
confidence: t.confidence ?? 1,
|
|
18157
18491
|
source_session: sourceSession
|
|
18158
|
-
});
|
|
18492
|
+
}, count));
|
|
18493
|
+
redactions += count.redactions;
|
|
18159
18494
|
}
|
|
18160
18495
|
};
|
|
18161
|
-
let skipped = 0, redactions = 0, walked = 0;
|
|
18162
18496
|
let scanMs = 0, scanned = 0;
|
|
18163
18497
|
const slice = refs.slice(0, opts.limit ?? refs.length);
|
|
18164
18498
|
const trace = process.env.CHAT_RECALL_SYNC_TRACE === "1" ? (msg) => {
|
|
@@ -18291,7 +18625,7 @@ async function syncToTarget(cred, opts = {}) {
|
|
|
18291
18625
|
await convBatch.add(built.conv);
|
|
18292
18626
|
if (built.findings.length > 0) await findingsBatch.add(built.findings);
|
|
18293
18627
|
if (upload.sessionMeta) {
|
|
18294
|
-
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);
|
|
18628
|
+
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);
|
|
18295
18629
|
}
|
|
18296
18630
|
if (upload.sessionMeta && sessionFileBytes(ref) <= FULL_BUILD_MAX_BYTES) {
|
|
18297
18631
|
try {
|
|
@@ -18370,7 +18704,7 @@ async function syncToTarget(cred, opts = {}) {
|
|
|
18370
18704
|
chunks: redactedChunks
|
|
18371
18705
|
});
|
|
18372
18706
|
if (upload.sessionMeta && redactedChunks.length > 0) {
|
|
18373
|
-
accumulateKg(
|
|
18707
|
+
await accumulateKg(
|
|
18374
18708
|
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 }),
|
|
18375
18709
|
null
|
|
18376
18710
|
);
|
|
@@ -18395,16 +18729,8 @@ async function syncToTarget(cred, opts = {}) {
|
|
|
18395
18729
|
}
|
|
18396
18730
|
}
|
|
18397
18731
|
}
|
|
18398
|
-
if (upload.sessionMeta &&
|
|
18399
|
-
const
|
|
18400
|
-
for (const t of kgRows) {
|
|
18401
|
-
const count = { redactions: 0 };
|
|
18402
|
-
await kgTripleBatch.add(redactDeep(t, count));
|
|
18403
|
-
redactions += count.redactions;
|
|
18404
|
-
entityNames.add(t.subject);
|
|
18405
|
-
entityNames.add(t.object);
|
|
18406
|
-
}
|
|
18407
|
-
for (const name of entityNames) {
|
|
18732
|
+
if (upload.sessionMeta && kgEntityNames.size > 0) {
|
|
18733
|
+
for (const name of kgEntityNames) {
|
|
18408
18734
|
const count = { redactions: 0 };
|
|
18409
18735
|
await kgEntityBatch.add(redactDeep({ name, type: kgEntityType.get(name) ?? "unknown", properties: {} }, count));
|
|
18410
18736
|
redactions += count.redactions;
|
|
@@ -18764,56 +19090,58 @@ function collectDerived(ref, mtime, count) {
|
|
|
18764
19090
|
const id = ref.prefixedId;
|
|
18765
19091
|
const compute = [];
|
|
18766
19092
|
let fullOutcome = null;
|
|
18767
|
-
|
|
18768
|
-
|
|
18769
|
-
|
|
18770
|
-
|
|
18771
|
-
|
|
18772
|
-
|
|
18773
|
-
|
|
18774
|
-
|
|
18775
|
-
|
|
18776
|
-
|
|
18777
|
-
if (
|
|
18778
|
-
|
|
18779
|
-
|
|
18780
|
-
|
|
18781
|
-
|
|
18782
|
-
|
|
18783
|
-
|
|
18784
|
-
|
|
18785
|
-
|
|
19093
|
+
return withSessionReadCache(() => {
|
|
19094
|
+
for (const kind of COMPUTE_KINDS) {
|
|
19095
|
+
let data = null;
|
|
19096
|
+
try {
|
|
19097
|
+
if (kind === "diff") {
|
|
19098
|
+
const replay = replaySessionAny(id);
|
|
19099
|
+
if (replay.found) data = replay;
|
|
19100
|
+
} else if (kind === "outcome") {
|
|
19101
|
+
fullOutcome = computeOutcome(id);
|
|
19102
|
+
if (fullOutcome.found) data = fullOutcome;
|
|
19103
|
+
} else if (kind === "commits") {
|
|
19104
|
+
if (!fullOutcome) fullOutcome = computeOutcome(id);
|
|
19105
|
+
if (fullOutcome.found) data = fullOutcome.commits;
|
|
19106
|
+
} else if (kind === "markers") {
|
|
19107
|
+
const turns = extractTurnsAny(id, { maxTurns: 5e4 });
|
|
19108
|
+
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) }));
|
|
19109
|
+
data = { sessionId: id, prompts, summary: summarizeMarkers(prompts) };
|
|
19110
|
+
}
|
|
19111
|
+
} catch {
|
|
19112
|
+
data = null;
|
|
19113
|
+
}
|
|
19114
|
+
if (data === null) continue;
|
|
19115
|
+
const redacted = redactDeep(data, count);
|
|
19116
|
+
if (JSON.stringify(redacted).length > MAX_DERIVED_ROW_BYTES) continue;
|
|
19117
|
+
compute.push({ kind, mtime, data: redacted });
|
|
19118
|
+
}
|
|
19119
|
+
let outcomeRow = null;
|
|
19120
|
+
if (fullOutcome?.found) {
|
|
19121
|
+
outcomeRow = {
|
|
19122
|
+
sessionId: id,
|
|
19123
|
+
tool: ref.toolId,
|
|
19124
|
+
status: fullOutcome.status,
|
|
19125
|
+
reason: fullOutcome.reason,
|
|
19126
|
+
fileMtime: mtime,
|
|
19127
|
+
fileSize: 0,
|
|
19128
|
+
contentHash: "",
|
|
19129
|
+
fileCount: fullOutcome.fileCount,
|
|
19130
|
+
linesAdded: fullOutcome.totalLinesAdded,
|
|
19131
|
+
linesRemoved: fullOutcome.totalLinesRemoved,
|
|
19132
|
+
commits: fullOutcome.commits?.totalCommits ?? 0,
|
|
19133
|
+
isFull: true,
|
|
19134
|
+
classifiedAt: Date.now(),
|
|
19135
|
+
lastScannedOffset: 0
|
|
19136
|
+
};
|
|
18786
19137
|
}
|
|
18787
|
-
|
|
18788
|
-
|
|
18789
|
-
|
|
18790
|
-
|
|
18791
|
-
|
|
18792
|
-
let outcomeRow = null;
|
|
18793
|
-
if (fullOutcome?.found) {
|
|
18794
|
-
outcomeRow = {
|
|
18795
|
-
sessionId: id,
|
|
18796
|
-
tool: ref.toolId,
|
|
18797
|
-
status: fullOutcome.status,
|
|
18798
|
-
reason: fullOutcome.reason,
|
|
18799
|
-
fileMtime: mtime,
|
|
18800
|
-
fileSize: 0,
|
|
18801
|
-
contentHash: "",
|
|
18802
|
-
fileCount: fullOutcome.fileCount,
|
|
18803
|
-
linesAdded: fullOutcome.totalLinesAdded,
|
|
18804
|
-
linesRemoved: fullOutcome.totalLinesRemoved,
|
|
18805
|
-
commits: fullOutcome.commits?.totalCommits ?? 0,
|
|
18806
|
-
isFull: true,
|
|
18807
|
-
classifiedAt: Date.now(),
|
|
18808
|
-
lastScannedOffset: 0
|
|
19138
|
+
return {
|
|
19139
|
+
session_id: id,
|
|
19140
|
+
mtime,
|
|
19141
|
+
compute,
|
|
19142
|
+
outcome_row: outcomeRow ? redactDeep({ ...outcomeRow, sessionId: void 0 }, count) : null
|
|
18809
19143
|
};
|
|
18810
|
-
}
|
|
18811
|
-
return {
|
|
18812
|
-
session_id: id,
|
|
18813
|
-
mtime,
|
|
18814
|
-
compute,
|
|
18815
|
-
outcome_row: outcomeRow ? redactDeep({ ...outcomeRow, sessionId: void 0 }, count) : null
|
|
18816
|
-
};
|
|
19144
|
+
});
|
|
18817
19145
|
}
|
|
18818
19146
|
function isSyncSkip(r) {
|
|
18819
19147
|
return typeof r.skipped === "string";
|
|
@@ -18842,10 +19170,11 @@ async function syncIncremental(opts = {}) {
|
|
|
18842
19170
|
lock.release();
|
|
18843
19171
|
}
|
|
18844
19172
|
}
|
|
18845
|
-
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;
|
|
19173
|
+
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;
|
|
18846
19174
|
var init_sync_client = __esm({
|
|
18847
19175
|
"src/sync-client.ts"() {
|
|
18848
19176
|
"use strict";
|
|
19177
|
+
init_credentials_env();
|
|
18849
19178
|
init_secret_redactor();
|
|
18850
19179
|
init_source_discovery();
|
|
18851
19180
|
init_home_discovery();
|
|
@@ -18873,14 +19202,15 @@ var init_sync_client = __esm({
|
|
|
18873
19202
|
init_sync_fields();
|
|
18874
19203
|
init_index_lock();
|
|
18875
19204
|
init_http();
|
|
19205
|
+
init_live_session_scan();
|
|
18876
19206
|
init_backends();
|
|
18877
19207
|
ownVersion = "0.0.0";
|
|
18878
19208
|
try {
|
|
18879
19209
|
const dir = dirname16(fileURLToPath(import.meta.url));
|
|
18880
|
-
ownVersion = JSON.parse(
|
|
19210
|
+
ownVersion = JSON.parse(readFileSync32(join40(dir, "../package.json"), "utf-8")).version || ownVersion;
|
|
18881
19211
|
} catch {
|
|
18882
19212
|
try {
|
|
18883
|
-
if (true) ownVersion = "0.5.
|
|
19213
|
+
if (true) ownVersion = "0.5.6";
|
|
18884
19214
|
} catch {
|
|
18885
19215
|
}
|
|
18886
19216
|
}
|
|
@@ -18891,6 +19221,8 @@ var init_sync_client = __esm({
|
|
|
18891
19221
|
hashPath = (p) => p ? "p_" + createHash12("sha256").update(p).digest("hex").slice(0, 12) : "";
|
|
18892
19222
|
COMPUTE_KINDS = ["diff", "outcome", "commits", "markers"];
|
|
18893
19223
|
MAX_DERIVED_ROW_BYTES = 2 * 1024 * 1024;
|
|
19224
|
+
CAPS_TTL_MS = 60 * 6e4;
|
|
19225
|
+
capsOk = /* @__PURE__ */ new Map();
|
|
18894
19226
|
FULL_BUILD_MAX_BYTES = Math.max(8, parseInt(process.env.CHAT_RECALL_FULL_BUILD_MAX_MB || "64", 10)) * 1024 * 1024;
|
|
18895
19227
|
FULL_BUILD_TAIL_BYTES = 16 * 1024 * 1024;
|
|
18896
19228
|
BATCH_SCAN_MAX_BYTES = Math.max(1, parseInt(process.env.CHAT_RECALL_BATCHSCAN_MAX_MB || "64", 10)) * 1024 * 1024;
|
|
@@ -18947,11 +19279,11 @@ async function repairSession(id, opts = {}) {
|
|
|
18947
19279
|
const log6 = (m) => {
|
|
18948
19280
|
if (opts.verbose) console.error(` [repair ${id}] ${m}`);
|
|
18949
19281
|
};
|
|
18950
|
-
const
|
|
19282
|
+
const candidates2 = [];
|
|
18951
19283
|
const localShadow = readShadowContainer(tool, rawId);
|
|
18952
19284
|
if (localShadow) {
|
|
18953
19285
|
try {
|
|
18954
|
-
|
|
19286
|
+
candidates2.push({ container: localShadow, messages: parseTranscriptFromContainer(localShadow).messages.length, source: "local-shadow" });
|
|
18955
19287
|
} catch {
|
|
18956
19288
|
}
|
|
18957
19289
|
}
|
|
@@ -18963,15 +19295,15 @@ async function repairSession(id, opts = {}) {
|
|
|
18963
19295
|
if (arch?.gzB64) {
|
|
18964
19296
|
try {
|
|
18965
19297
|
const container = gunzipContainer(Buffer.from(arch.gzB64, "base64"));
|
|
18966
|
-
if (container)
|
|
19298
|
+
if (container) candidates2.push({ container, messages: parseTranscriptFromContainer(container).messages.length, source: ep.url });
|
|
18967
19299
|
} catch {
|
|
18968
19300
|
}
|
|
18969
19301
|
}
|
|
18970
19302
|
}
|
|
18971
|
-
if (
|
|
19303
|
+
if (candidates2.length === 0) {
|
|
18972
19304
|
return { sessionId: id, status: "no-archive", fullestMessages: 0, fullestSource: "", pushed: [], note: "no shadow or server archive found" };
|
|
18973
19305
|
}
|
|
18974
|
-
const fullest =
|
|
19306
|
+
const fullest = candidates2.reduce((a, b) => b.messages > a.messages ? b : a);
|
|
18975
19307
|
log6(`fullest archive = ${fullest.messages} msg(s) from ${fullest.source}`);
|
|
18976
19308
|
if (opts.dryRun) {
|
|
18977
19309
|
const needy2 = endpoints.filter((ep) => (currentOnServer.get(ep.url) ?? 0) < fullest.messages || opts.force);
|
|
@@ -19073,7 +19405,7 @@ async function repairAll(opts = {}) {
|
|
|
19073
19405
|
if (!page?.hasMore || sessions.length === 0) break;
|
|
19074
19406
|
}
|
|
19075
19407
|
log6(`window=${sinceHours}h \u2192 ${ids.length} session(s) to check on ${primary.url}`);
|
|
19076
|
-
const
|
|
19408
|
+
const candidates2 = [];
|
|
19077
19409
|
let scanned = 0;
|
|
19078
19410
|
for (const id of ids) {
|
|
19079
19411
|
scanned++;
|
|
@@ -19086,9 +19418,9 @@ async function repairAll(opts = {}) {
|
|
|
19086
19418
|
if (archiveMsgs <= current) continue;
|
|
19087
19419
|
const r = await repairSession(id, { dryRun: !opts.apply, verbose: opts.verbose, server: opts.server });
|
|
19088
19420
|
if (r.status === "already-full") continue;
|
|
19089
|
-
|
|
19421
|
+
candidates2.push(r);
|
|
19090
19422
|
}
|
|
19091
|
-
return { scanned, candidates, discoveryServer: primary.url };
|
|
19423
|
+
return { scanned, candidates: candidates2, discoveryServer: primary.url };
|
|
19092
19424
|
}
|
|
19093
19425
|
var hashPath2;
|
|
19094
19426
|
var init_repair = __esm({
|
|
@@ -19104,23 +19436,93 @@ var init_repair = __esm({
|
|
|
19104
19436
|
}
|
|
19105
19437
|
});
|
|
19106
19438
|
|
|
19439
|
+
// ../engine/dist/core/which.js
|
|
19440
|
+
import { existsSync as existsSync43, statSync as statSync38, accessSync, constants } from "node:fs";
|
|
19441
|
+
import { join as join46, isAbsolute as isAbsolute2, delimiter as delimiter2, sep as sep2 } from "node:path";
|
|
19442
|
+
function executable(p) {
|
|
19443
|
+
try {
|
|
19444
|
+
if (!statSync38(p).isFile())
|
|
19445
|
+
return false;
|
|
19446
|
+
} catch {
|
|
19447
|
+
return false;
|
|
19448
|
+
}
|
|
19449
|
+
if (isWindows)
|
|
19450
|
+
return true;
|
|
19451
|
+
try {
|
|
19452
|
+
accessSync(p, constants.X_OK);
|
|
19453
|
+
return true;
|
|
19454
|
+
} catch {
|
|
19455
|
+
return false;
|
|
19456
|
+
}
|
|
19457
|
+
}
|
|
19458
|
+
function candidates(name) {
|
|
19459
|
+
if (!isWindows)
|
|
19460
|
+
return [name];
|
|
19461
|
+
const exts = (process.env.PATHEXT || ".COM;.EXE;.BAT;.CMD").split(";").map((e) => e.trim()).filter(Boolean);
|
|
19462
|
+
if (exts.some((e) => name.toLowerCase().endsWith(e.toLowerCase())))
|
|
19463
|
+
return [name];
|
|
19464
|
+
return exts.map((e) => name + e);
|
|
19465
|
+
}
|
|
19466
|
+
function resolveOnPath(name) {
|
|
19467
|
+
if (!name)
|
|
19468
|
+
return null;
|
|
19469
|
+
if (name.includes("/") || isWindows && name.includes(sep2) || isAbsolute2(name)) {
|
|
19470
|
+
for (const c of candidates(name))
|
|
19471
|
+
if (executable(c))
|
|
19472
|
+
return c;
|
|
19473
|
+
return null;
|
|
19474
|
+
}
|
|
19475
|
+
for (const raw of (process.env.PATH || "").split(delimiter2)) {
|
|
19476
|
+
const dir = raw.replace(/^"(.*)"$/, "$1");
|
|
19477
|
+
if (!dir)
|
|
19478
|
+
continue;
|
|
19479
|
+
for (const c of candidates(name)) {
|
|
19480
|
+
const full = join46(dir, c);
|
|
19481
|
+
if (existsSync43(full) && executable(full))
|
|
19482
|
+
return full;
|
|
19483
|
+
}
|
|
19484
|
+
}
|
|
19485
|
+
return null;
|
|
19486
|
+
}
|
|
19487
|
+
function isOnPath(name) {
|
|
19488
|
+
return resolveOnPath(name) !== null;
|
|
19489
|
+
}
|
|
19490
|
+
var isWindows;
|
|
19491
|
+
var init_which = __esm({
|
|
19492
|
+
"../engine/dist/core/which.js"() {
|
|
19493
|
+
"use strict";
|
|
19494
|
+
isWindows = process.platform === "win32";
|
|
19495
|
+
}
|
|
19496
|
+
});
|
|
19497
|
+
|
|
19107
19498
|
// ../engine/dist/core/companions.js
|
|
19108
|
-
import { existsSync as
|
|
19499
|
+
import { existsSync as existsSync44, mkdirSync as mkdirSync13, statSync as statSync39, chmodSync as chmodSync4, unlinkSync as unlinkSync3, renameSync as renameSync5, createWriteStream, readFileSync as readFileSync38, writeFileSync as writeFileSync13 } from "node:fs";
|
|
19109
19500
|
import { homedir as homedir19 } from "node:os";
|
|
19110
|
-
import { join as
|
|
19501
|
+
import { join as join47 } from "node:path";
|
|
19111
19502
|
import { execSync as execSync3 } from "node:child_process";
|
|
19503
|
+
import { createHash as createHash14 } from "node:crypto";
|
|
19504
|
+
function expectedCodeindexSha256(artifact) {
|
|
19505
|
+
return CODEINDEX_SHA256[artifact.replace(/^codeindex-/, "").replace(/\.exe$/, "")] ?? null;
|
|
19506
|
+
}
|
|
19112
19507
|
function detectPlatform() {
|
|
19113
19508
|
const arch = process.arch;
|
|
19114
19509
|
const platform = process.platform;
|
|
19115
19510
|
const archMap = { x64: "x86_64", arm64: "aarch64" };
|
|
19116
|
-
const platformMap = { linux: "linux", darwin: "
|
|
19511
|
+
const platformMap = { linux: "linux", darwin: "macos", win32: "windows" };
|
|
19117
19512
|
const a = archMap[arch];
|
|
19118
19513
|
const p = platformMap[platform];
|
|
19119
19514
|
if (!a || !p) {
|
|
19120
19515
|
return { reason: `Unsupported platform: ${arch}-${platform}` };
|
|
19121
19516
|
}
|
|
19122
|
-
const prebuiltCombos = /* @__PURE__ */ new Set([
|
|
19123
|
-
|
|
19517
|
+
const prebuiltCombos = /* @__PURE__ */ new Set([
|
|
19518
|
+
"x86_64-linux",
|
|
19519
|
+
"aarch64-linux",
|
|
19520
|
+
"x86_64-macos",
|
|
19521
|
+
"aarch64-macos",
|
|
19522
|
+
"x86_64-windows",
|
|
19523
|
+
"aarch64-windows"
|
|
19524
|
+
]);
|
|
19525
|
+
const artifact = `codeindex-${a}-${p}${p === "windows" ? ".exe" : ""}`;
|
|
19124
19526
|
if (!prebuiltCombos.has(`${a}-${p}`)) {
|
|
19125
19527
|
return {
|
|
19126
19528
|
artifact,
|
|
@@ -19137,20 +19539,15 @@ function checkCodeindexStatus() {
|
|
|
19137
19539
|
artifactName: platform.artifact,
|
|
19138
19540
|
unsupportedReason: platform.reason
|
|
19139
19541
|
};
|
|
19140
|
-
let foundPath =
|
|
19141
|
-
|
|
19142
|
-
|
|
19143
|
-
if (out)
|
|
19144
|
-
foundPath = out;
|
|
19145
|
-
} catch {
|
|
19542
|
+
let foundPath = resolveOnPath(CODEINDEX_BIN_NAME);
|
|
19543
|
+
if (!foundPath) {
|
|
19544
|
+
foundPath = resolveOnPath(CODEINDEX_BIN_PATH);
|
|
19146
19545
|
}
|
|
19147
|
-
if (!foundPath && existsSync43(CODEINDEX_BIN_PATH))
|
|
19148
|
-
foundPath = CODEINDEX_BIN_PATH;
|
|
19149
19546
|
if (foundPath) {
|
|
19150
19547
|
status.installed = true;
|
|
19151
19548
|
status.path = foundPath;
|
|
19152
19549
|
try {
|
|
19153
|
-
status.size =
|
|
19550
|
+
status.size = statSync39(foundPath).size;
|
|
19154
19551
|
} catch {
|
|
19155
19552
|
}
|
|
19156
19553
|
try {
|
|
@@ -19162,16 +19559,9 @@ function checkCodeindexStatus() {
|
|
|
19162
19559
|
return status;
|
|
19163
19560
|
}
|
|
19164
19561
|
async function downloadArtifact(artifact, dest) {
|
|
19165
|
-
const hasGh = (
|
|
19166
|
-
try {
|
|
19167
|
-
execSync3("command -v gh", { stdio: "ignore" });
|
|
19168
|
-
return true;
|
|
19169
|
-
} catch {
|
|
19170
|
-
return false;
|
|
19171
|
-
}
|
|
19172
|
-
})();
|
|
19562
|
+
const hasGh = isOnPath("gh");
|
|
19173
19563
|
if (hasGh) {
|
|
19174
|
-
execSync3(`gh release download ${CODEINDEX_VERSION} --repo ${CODEINDEX_REPO} -p ${artifact} -O ${dest}`, {
|
|
19564
|
+
execSync3(`gh release download ${CODEINDEX_VERSION} --repo ${CODEINDEX_REPO} -p ${artifact} -O "${dest}"`, {
|
|
19175
19565
|
stdio: ["ignore", "pipe", "pipe"],
|
|
19176
19566
|
timeout: 6e4
|
|
19177
19567
|
});
|
|
@@ -19184,7 +19574,7 @@ async function downloadArtifact(artifact, dest) {
|
|
|
19184
19574
|
if (!res.body)
|
|
19185
19575
|
throw new Error("Download returned empty body");
|
|
19186
19576
|
const file = createWriteStream(dest);
|
|
19187
|
-
await new Promise((
|
|
19577
|
+
await new Promise((resolve3, reject) => {
|
|
19188
19578
|
const reader = res.body.getReader();
|
|
19189
19579
|
const pump = async () => {
|
|
19190
19580
|
try {
|
|
@@ -19195,7 +19585,7 @@ async function downloadArtifact(artifact, dest) {
|
|
|
19195
19585
|
file.write(value);
|
|
19196
19586
|
}
|
|
19197
19587
|
file.end();
|
|
19198
|
-
file.on("finish", () =>
|
|
19588
|
+
file.on("finish", () => resolve3());
|
|
19199
19589
|
file.on("error", reject);
|
|
19200
19590
|
} catch (e) {
|
|
19201
19591
|
reject(e);
|
|
@@ -19210,15 +19600,26 @@ async function installCodeindex(opts = {}) {
|
|
|
19210
19600
|
return status;
|
|
19211
19601
|
if (!status.prebuiltAvailable)
|
|
19212
19602
|
return status;
|
|
19213
|
-
|
|
19603
|
+
mkdirSync13(CODEINDEX_INSTALL_DIR, { recursive: true });
|
|
19214
19604
|
const tmpPath = `${CODEINDEX_BIN_PATH}.partial`;
|
|
19215
19605
|
try {
|
|
19216
19606
|
await downloadArtifact(status.artifactName, tmpPath);
|
|
19607
|
+
const expected = expectedCodeindexSha256(status.artifactName);
|
|
19608
|
+
if (!expected) {
|
|
19609
|
+
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.`);
|
|
19610
|
+
}
|
|
19611
|
+
const actual = createHash14("sha256").update(readFileSync38(tmpPath)).digest("hex");
|
|
19612
|
+
if (actual !== expected) {
|
|
19613
|
+
throw new Error(`Checksum mismatch for ${status.artifactName}.
|
|
19614
|
+
expected ${expected}
|
|
19615
|
+
actual ${actual}
|
|
19616
|
+
Refusing to install. The release may have been re-uploaded, or something is serving different bytes.`);
|
|
19617
|
+
}
|
|
19217
19618
|
chmodSync4(tmpPath, 493);
|
|
19218
19619
|
renameSync5(tmpPath, CODEINDEX_BIN_PATH);
|
|
19219
19620
|
} catch (err) {
|
|
19220
19621
|
try {
|
|
19221
|
-
if (
|
|
19622
|
+
if (existsSync44(tmpPath))
|
|
19222
19623
|
unlinkSync3(tmpPath);
|
|
19223
19624
|
} catch {
|
|
19224
19625
|
}
|
|
@@ -19226,15 +19627,24 @@ async function installCodeindex(opts = {}) {
|
|
|
19226
19627
|
}
|
|
19227
19628
|
return checkCodeindexStatus();
|
|
19228
19629
|
}
|
|
19229
|
-
var CODEINDEX_REPO, CODEINDEX_VERSION, CODEINDEX_INSTALL_DIR, CODEINDEX_BIN_NAME, CODEINDEX_BIN_PATH;
|
|
19630
|
+
var CODEINDEX_REPO, CODEINDEX_VERSION, CODEINDEX_SHA256, CODEINDEX_INSTALL_DIR, CODEINDEX_BIN_NAME, CODEINDEX_BIN_PATH;
|
|
19230
19631
|
var init_companions = __esm({
|
|
19231
19632
|
"../engine/dist/core/companions.js"() {
|
|
19232
19633
|
"use strict";
|
|
19634
|
+
init_which();
|
|
19233
19635
|
CODEINDEX_REPO = "munhq/codeindex";
|
|
19234
|
-
CODEINDEX_VERSION = "v0.1
|
|
19235
|
-
|
|
19236
|
-
|
|
19237
|
-
|
|
19636
|
+
CODEINDEX_VERSION = "v0.3.1";
|
|
19637
|
+
CODEINDEX_SHA256 = {
|
|
19638
|
+
"x86_64-linux": "4378f12e7c80fa8bb53e41c02db4b95955f2f878369abfb28b5edd94b4adbb85",
|
|
19639
|
+
"aarch64-linux": "5a1d6c9c2592a3721547c42cd9b6b11f460e903bfc46407ae27d5879e7259587",
|
|
19640
|
+
"x86_64-macos": "6ad2a2b40faa4ec72ac35fee84f35ea7c848cddc4f6382b4cafedb644f30389f",
|
|
19641
|
+
"aarch64-macos": "f366d00918f79a4a0acc09c6091d97c6c378c79edbdbe3cb22e4014ea57f08d2",
|
|
19642
|
+
"x86_64-windows": "a96fc8c8949bb399a44cc0615b12e458460a529c69f01e8829cc39a20f45ab29",
|
|
19643
|
+
"aarch64-windows": "42620d56272cd9ba9d785569d8d754d6b4a3e80f36f28db3e0c483fd600ed117"
|
|
19644
|
+
};
|
|
19645
|
+
CODEINDEX_INSTALL_DIR = join47(homedir19(), ".local", "bin");
|
|
19646
|
+
CODEINDEX_BIN_NAME = process.platform === "win32" ? "codeindex.exe" : "codeindex";
|
|
19647
|
+
CODEINDEX_BIN_PATH = join47(CODEINDEX_INSTALL_DIR, CODEINDEX_BIN_NAME);
|
|
19238
19648
|
}
|
|
19239
19649
|
});
|
|
19240
19650
|
|
|
@@ -19340,7 +19750,9 @@ var init_prompts = __esm({
|
|
|
19340
19750
|
var collector_exports = {};
|
|
19341
19751
|
__export(collector_exports, {
|
|
19342
19752
|
COLLECTOR_VERSION: () => COLLECTOR_VERSION,
|
|
19753
|
+
GENERATED_PATTERNS: () => GENERATED_PATTERNS,
|
|
19343
19754
|
collectCode: () => collectCode,
|
|
19755
|
+
isGenerated: () => isGenerated,
|
|
19344
19756
|
isJunkWorkspacePath: () => isJunkWorkspacePath,
|
|
19345
19757
|
isSecretRule: () => isSecretRule,
|
|
19346
19758
|
resolveCodeindexBin: () => resolveCodeindexBin
|
|
@@ -19348,7 +19760,7 @@ __export(collector_exports, {
|
|
|
19348
19760
|
import { spawn as spawn2 } from "node:child_process";
|
|
19349
19761
|
import { execSync as execSync4 } from "node:child_process";
|
|
19350
19762
|
import { readFileSync as readFileSync39 } from "node:fs";
|
|
19351
|
-
import { join as
|
|
19763
|
+
import { join as join48, basename as basename24 } from "node:path";
|
|
19352
19764
|
async function resolveCodeindexBin(autoInstall = true) {
|
|
19353
19765
|
let st = checkCodeindexStatus();
|
|
19354
19766
|
if (!st.installed && autoInstall)
|
|
@@ -19359,7 +19771,7 @@ async function resolveCodeindexBin(autoInstall = true) {
|
|
|
19359
19771
|
return st.path;
|
|
19360
19772
|
}
|
|
19361
19773
|
function runMcp(binPath, workspace, calls, timeoutMs = 18e4) {
|
|
19362
|
-
return new Promise((
|
|
19774
|
+
return new Promise((resolve3, reject) => {
|
|
19363
19775
|
const p = spawn2(binPath, ["--mcp", "--workspace", workspace], { stdio: ["pipe", "pipe", "ignore"] });
|
|
19364
19776
|
let out = "";
|
|
19365
19777
|
const timer = setTimeout(() => {
|
|
@@ -19402,7 +19814,7 @@ function runMcp(binPath, workspace, calls, timeoutMs = 18e4) {
|
|
|
19402
19814
|
if (m?.id != null && typeof text === "string")
|
|
19403
19815
|
res.set(Number(m.id), text);
|
|
19404
19816
|
}
|
|
19405
|
-
|
|
19817
|
+
resolve3(res);
|
|
19406
19818
|
});
|
|
19407
19819
|
p.stdin.write(calls.map((c) => JSON.stringify(c) + "\n").join(""));
|
|
19408
19820
|
p.stdin.end();
|
|
@@ -19435,10 +19847,11 @@ function isSecretRule(rule) {
|
|
|
19435
19847
|
return /secret|password|credential|key|token|auth/i.test(rule);
|
|
19436
19848
|
}
|
|
19437
19849
|
function isJunkWorkspacePath(ws) {
|
|
19438
|
-
|
|
19850
|
+
const norm = ws.replace(/\\/g, "/");
|
|
19851
|
+
return /(^|\/)(scratchpad|\.cache|node_modules|\.git|tmp)(\/|$)|claude-1000/i.test(norm);
|
|
19439
19852
|
}
|
|
19440
19853
|
async function collectCode(opts) {
|
|
19441
|
-
const ws = opts.workspace.replace(
|
|
19854
|
+
const ws = opts.workspace.replace(/[/\\]+$/, "");
|
|
19442
19855
|
const log6 = opts.log ?? (() => {
|
|
19443
19856
|
});
|
|
19444
19857
|
if (isJunkWorkspacePath(ws)) {
|
|
@@ -19446,9 +19859,11 @@ async function collectCode(opts) {
|
|
|
19446
19859
|
}
|
|
19447
19860
|
const bin = opts.binPath ?? await resolveCodeindexBin(opts.autoInstall ?? true);
|
|
19448
19861
|
const projectId = resolveProjectId(ws).id || `path:${ws}`;
|
|
19449
|
-
const
|
|
19862
|
+
const wsNorm = ws.replace(/\\/g, "/");
|
|
19863
|
+
const wsPrefix = wsNorm + "/";
|
|
19450
19864
|
const rel = (p) => {
|
|
19451
|
-
|
|
19865
|
+
const n = p.replace(/\\/g, "/");
|
|
19866
|
+
let r = n.startsWith(wsPrefix) ? n.slice(wsPrefix.length) : n;
|
|
19452
19867
|
if (r.startsWith("./"))
|
|
19453
19868
|
r = r.slice(2);
|
|
19454
19869
|
return r;
|
|
@@ -19509,7 +19924,7 @@ async function collectCode(opts) {
|
|
|
19509
19924
|
}
|
|
19510
19925
|
const complexity = (r) => {
|
|
19511
19926
|
try {
|
|
19512
|
-
const txt = readFileSync39(
|
|
19927
|
+
const txt = readFileSync39(join48(ws, r), "utf8");
|
|
19513
19928
|
if (txt.length > 2e6)
|
|
19514
19929
|
return 1;
|
|
19515
19930
|
const m = txt.match(CF_RE);
|
|
@@ -19863,6 +20278,14 @@ async function collectCode(opts) {
|
|
|
19863
20278
|
agentPrompt: manifestPrompt(v.violation_type ?? "", file, v.line ?? null, v.description ?? "")
|
|
19864
20279
|
});
|
|
19865
20280
|
}
|
|
20281
|
+
{
|
|
20282
|
+
const before = findings.length;
|
|
20283
|
+
const own = findings.filter((f) => !f.file || !isGenerated(f.file));
|
|
20284
|
+
if (own.length !== before) {
|
|
20285
|
+
findings.splice(0, before, ...own);
|
|
20286
|
+
log6(`dropped ${before - own.length} finding(s) in vendored/generated files`);
|
|
20287
|
+
}
|
|
20288
|
+
}
|
|
19866
20289
|
const godSet = new Set((coup?.god_modules ?? []).map((m) => rel(m.file)));
|
|
19867
20290
|
const cloneSet = /* @__PURE__ */ new Set();
|
|
19868
20291
|
for (const g of clones?.groups ?? [])
|
|
@@ -19948,7 +20371,9 @@ async function collectCode(opts) {
|
|
|
19948
20371
|
}
|
|
19949
20372
|
for (const g of clones?.groups ?? []) {
|
|
19950
20373
|
if ((g.count ?? 0) >= 3 || (g.lines ?? 0) >= 12) {
|
|
19951
|
-
const fns = (g.functions ?? []).filter((x) => x && typeof x === "object");
|
|
20374
|
+
const fns = (g.functions ?? []).filter((x) => x && typeof x === "object").filter((x) => !isGenerated(rel(x.file)));
|
|
20375
|
+
if (fns.length < 2)
|
|
20376
|
+
continue;
|
|
19952
20377
|
const names = [...new Set(fns.map((x) => x.name))];
|
|
19953
20378
|
const locs = fns.map((x) => rel(x.file)).slice(0, 5);
|
|
19954
20379
|
pushAction((g.lines ?? 0) * (g.count ?? 0) >= 150 ? 1 : 2, "duplication", `${names.join(", ")} copy-pasted ${g.count}\xD7 (${g.lines} lines each)`, "Extract one shared implementation and replace the copies.", locs.map((f) => ({ file: f })), clonePrompt(names, g.lines ?? 0, g.count ?? 0, locs));
|
|
@@ -19967,10 +20392,14 @@ async function collectCode(opts) {
|
|
|
19967
20392
|
}
|
|
19968
20393
|
for (const m of (coup?.god_modules ?? []).slice(0, 5)) {
|
|
19969
20394
|
const file = rel(m.file);
|
|
20395
|
+
if (isGenerated(file))
|
|
20396
|
+
continue;
|
|
19970
20397
|
pushAction(2, "modularity", `God module ${file} (fan-in ${m.fan_in}, fan-out ${m.fan_out})`, "Split into cohesive sub-modules; introduce interfaces to cut fan-out.", [{ file }], couplingPrompt(file, m.fan_in ?? 0, m.fan_out ?? 0, Math.round((m.instability ?? 0) * 100) / 100));
|
|
19971
20398
|
}
|
|
19972
20399
|
for (const c of (cyc?.cycles ?? []).slice(0, 5)) {
|
|
19973
|
-
const chain = (c.files ?? []).map(rel);
|
|
20400
|
+
const chain = (c.files ?? []).map(rel).filter((f) => !isGenerated(f));
|
|
20401
|
+
if (chain.length < 2)
|
|
20402
|
+
continue;
|
|
19974
20403
|
pushAction(2, "architecture", `Circular dependency (${chain.length} files)`, "Break the cycle: extract the shared type/interface into a separate module.", chain.slice(0, 4).map((f) => ({ file: f })), cyclePrompt(chain.slice(0, 6)));
|
|
19975
20404
|
}
|
|
19976
20405
|
for (const h of hotspotsAll.slice(0, 5)) {
|
|
@@ -20079,7 +20508,7 @@ async function collectCode(opts) {
|
|
|
20079
20508
|
void health;
|
|
20080
20509
|
return { project, findings, hotspots, actions };
|
|
20081
20510
|
}
|
|
20082
|
-
var COLLECTOR_VERSION, ANALYSES, GENERATED, CF_RE, DEPTH, MCP_OUT_MAX_BYTES, call, COMMON_SYMBOL_NAMES;
|
|
20511
|
+
var COLLECTOR_VERSION, ANALYSES, GENERATED, CF_RE, DEPTH, MCP_OUT_MAX_BYTES, call, GENERATED_PATTERNS, COMMON_SYMBOL_NAMES;
|
|
20083
20512
|
var init_collector = __esm({
|
|
20084
20513
|
"../engine/dist/core/code/collector.js"() {
|
|
20085
20514
|
"use strict";
|
|
@@ -20109,11 +20538,42 @@ var init_collector = __esm({
|
|
|
20109
20538
|
"migration_parity",
|
|
20110
20539
|
"manifest_compliance"
|
|
20111
20540
|
];
|
|
20112
|
-
GENERATED = [
|
|
20541
|
+
GENERATED = [
|
|
20542
|
+
"generated/",
|
|
20543
|
+
"__generated__/",
|
|
20544
|
+
".pb.go",
|
|
20545
|
+
".gen.",
|
|
20546
|
+
"_pb2.py",
|
|
20547
|
+
"/gen/",
|
|
20548
|
+
".g.dart",
|
|
20549
|
+
"/node_modules/",
|
|
20550
|
+
"/vendor/",
|
|
20551
|
+
"/third_party/",
|
|
20552
|
+
"/site-packages/",
|
|
20553
|
+
// Lockfiles. '.lock' alone catches yarn.lock, Cargo.lock, poetry.lock and
|
|
20554
|
+
// composer.lock, and MISSES the two biggest ones in a JS repo —
|
|
20555
|
+
// package-lock.json and pnpm-lock.yaml are named '-lock.<ext>'. Found by
|
|
20556
|
+
// replacing this file's mirror test with one that calls the real predicate.
|
|
20557
|
+
".lock",
|
|
20558
|
+
"-lock.json",
|
|
20559
|
+
"-lock.yaml",
|
|
20560
|
+
"/dist/",
|
|
20561
|
+
"/build/",
|
|
20562
|
+
"/out/",
|
|
20563
|
+
"/target/",
|
|
20564
|
+
"/.next/",
|
|
20565
|
+
"/coverage/",
|
|
20566
|
+
".min.js",
|
|
20567
|
+
".min.css",
|
|
20568
|
+
".bundle.js",
|
|
20569
|
+
"-bundle.js",
|
|
20570
|
+
".map"
|
|
20571
|
+
];
|
|
20113
20572
|
CF_RE = /\b(if|for|while|switch|case|catch|elif|when|loop|&&|\|\||\?)\b|\?/g;
|
|
20114
20573
|
DEPTH = 2;
|
|
20115
20574
|
MCP_OUT_MAX_BYTES = 64 * 1024 * 1024;
|
|
20116
20575
|
call = (id, name, args = {}) => ({ jsonrpc: "2.0", id, method: "tools/call", params: { name, arguments: args } });
|
|
20576
|
+
GENERATED_PATTERNS = GENERATED;
|
|
20117
20577
|
COMMON_SYMBOL_NAMES = /* @__PURE__ */ new Set([
|
|
20118
20578
|
"error",
|
|
20119
20579
|
"err",
|
|
@@ -20185,12 +20645,13 @@ init_settings();
|
|
|
20185
20645
|
init_sync_client();
|
|
20186
20646
|
init_http();
|
|
20187
20647
|
import chokidar from "chokidar";
|
|
20188
|
-
import { dirname as
|
|
20648
|
+
import { dirname as dirname21, basename as basename25, join as join49, resolve as resolve2, sep as sep3 } from "path";
|
|
20649
|
+
import { homedir as homedir20 } from "os";
|
|
20189
20650
|
|
|
20190
20651
|
// src/intent-drain.ts
|
|
20191
20652
|
init_http();
|
|
20192
20653
|
init_sync_client();
|
|
20193
|
-
import { existsSync as existsSync41, readFileSync as
|
|
20654
|
+
import { existsSync as existsSync41, readFileSync as readFileSync36, writeFileSync as writeFileSync11, appendFileSync, mkdirSync as mkdirSync11 } from "node:fs";
|
|
20194
20655
|
import { join as join44 } from "node:path";
|
|
20195
20656
|
import { homedir as homedir18 } from "node:os";
|
|
20196
20657
|
|
|
@@ -20200,7 +20661,7 @@ init_gemini2();
|
|
|
20200
20661
|
init_opencode();
|
|
20201
20662
|
init_codex2();
|
|
20202
20663
|
init_agy();
|
|
20203
|
-
import { existsSync as existsSync39, mkdirSync as mkdirSync9, readFileSync as
|
|
20664
|
+
import { existsSync as existsSync39, mkdirSync as mkdirSync9, readFileSync as readFileSync34, writeFileSync as writeFileSync9, cpSync } from "fs";
|
|
20204
20665
|
import { dirname as dirname17, join as join42, basename as basename23 } from "path";
|
|
20205
20666
|
import { homedir as homedir16 } from "os";
|
|
20206
20667
|
|
|
@@ -20211,11 +20672,11 @@ init_opencode();
|
|
|
20211
20672
|
init_codex2();
|
|
20212
20673
|
init_agy();
|
|
20213
20674
|
init_toolkit_format();
|
|
20214
|
-
import { readFileSync as
|
|
20675
|
+
import { readFileSync as readFileSync33 } from "fs";
|
|
20215
20676
|
import { join as join41 } from "path";
|
|
20216
20677
|
import { homedir as homedir15 } from "os";
|
|
20217
20678
|
function readCommand(filePath, format) {
|
|
20218
|
-
const content =
|
|
20679
|
+
const content = readFileSync33(filePath, "utf-8");
|
|
20219
20680
|
if (format === "toml") {
|
|
20220
20681
|
const t = parseScalarToml(content);
|
|
20221
20682
|
return { name: t.name || base(filePath), description: t.description || "", body: t.prompt || "" };
|
|
@@ -20224,7 +20685,7 @@ function readCommand(filePath, format) {
|
|
|
20224
20685
|
return { name: fm.name || base(filePath), description: fm.description || "", body: body.trim() };
|
|
20225
20686
|
}
|
|
20226
20687
|
function readAgent(filePath, format) {
|
|
20227
|
-
const content =
|
|
20688
|
+
const content = readFileSync33(filePath, "utf-8");
|
|
20228
20689
|
if (format === "toml") {
|
|
20229
20690
|
const t = parseScalarToml(content);
|
|
20230
20691
|
return {
|
|
@@ -20237,7 +20698,7 @@ function readAgent(filePath, format) {
|
|
|
20237
20698
|
return { name: fm.name || base(filePath), description: fm.description || "", tools: fm.tools, body: body.trim() };
|
|
20238
20699
|
}
|
|
20239
20700
|
function readInstructions(filePath, name) {
|
|
20240
|
-
const content =
|
|
20701
|
+
const content = readFileSync33(filePath, "utf-8");
|
|
20241
20702
|
return { name, description: "", body: content };
|
|
20242
20703
|
}
|
|
20243
20704
|
function commandPath(tool, name) {
|
|
@@ -20424,7 +20885,7 @@ function readMcpEntry(tool, name) {
|
|
|
20424
20885
|
if (!existsSync39(t.path))
|
|
20425
20886
|
continue;
|
|
20426
20887
|
try {
|
|
20427
|
-
const cfg = JSON.parse(
|
|
20888
|
+
const cfg = JSON.parse(readFileSync34(t.path, "utf-8"));
|
|
20428
20889
|
const block = cfg[t.key] || {};
|
|
20429
20890
|
if (block[name])
|
|
20430
20891
|
return block[name];
|
|
@@ -20438,7 +20899,7 @@ function readCodexMcpEntry(path, target) {
|
|
|
20438
20899
|
return null;
|
|
20439
20900
|
let content;
|
|
20440
20901
|
try {
|
|
20441
|
-
content =
|
|
20902
|
+
content = readFileSync34(path, "utf-8");
|
|
20442
20903
|
} catch {
|
|
20443
20904
|
return null;
|
|
20444
20905
|
}
|
|
@@ -20489,7 +20950,7 @@ function readCodexMcpEntry(path, target) {
|
|
|
20489
20950
|
function writeCodexMcpEntry(path, name, entry) {
|
|
20490
20951
|
let content = "";
|
|
20491
20952
|
if (existsSync39(path))
|
|
20492
|
-
content =
|
|
20953
|
+
content = readFileSync34(path, "utf-8");
|
|
20493
20954
|
const header = `[mcp_servers.${name}]`;
|
|
20494
20955
|
if (content.includes(header))
|
|
20495
20956
|
return false;
|
|
@@ -20548,7 +21009,7 @@ function writeMcpEntry(toTool, name, entry) {
|
|
|
20548
21009
|
let cfg = {};
|
|
20549
21010
|
if (existsSync39(path)) {
|
|
20550
21011
|
try {
|
|
20551
|
-
cfg = JSON.parse(
|
|
21012
|
+
cfg = JSON.parse(readFileSync34(path, "utf-8"));
|
|
20552
21013
|
} catch {
|
|
20553
21014
|
return { ok: false, status: 500, error: `Target config is malformed: ${path}` };
|
|
20554
21015
|
}
|
|
@@ -20735,7 +21196,7 @@ async function executeCopy(type, name, fromTool, toTool) {
|
|
|
20735
21196
|
|
|
20736
21197
|
// src/project-tasks.ts
|
|
20737
21198
|
init_http();
|
|
20738
|
-
import { existsSync as existsSync40, readFileSync as
|
|
21199
|
+
import { existsSync as existsSync40, readFileSync as readFileSync35, writeFileSync as writeFileSync10, mkdirSync as mkdirSync10, statSync as statSync36 } from "node:fs";
|
|
20739
21200
|
import { join as join43, dirname as dirname18 } from "node:path";
|
|
20740
21201
|
import { homedir as homedir17 } from "node:os";
|
|
20741
21202
|
|
|
@@ -20752,7 +21213,7 @@ function isCodeTaskStatus(v) {
|
|
|
20752
21213
|
}
|
|
20753
21214
|
|
|
20754
21215
|
// src/project-tasks.ts
|
|
20755
|
-
var TEAM_STATUSES = /* @__PURE__ */ new Set(["todo", "in_progress", "
|
|
21216
|
+
var TEAM_STATUSES = /* @__PURE__ */ new Set(["todo", "in_progress", "done", "rejected"]);
|
|
20756
21217
|
function isTeamTaskStatus(v) {
|
|
20757
21218
|
return !!v && TEAM_STATUSES.has(v);
|
|
20758
21219
|
}
|
|
@@ -20770,7 +21231,7 @@ function reconcile(kind, was, token, checked) {
|
|
|
20770
21231
|
const done = kind === "secret" ? "rotated" : "done";
|
|
20771
21232
|
if (token && token !== was) return token;
|
|
20772
21233
|
if (kind === "team") {
|
|
20773
|
-
if (checked && was
|
|
21234
|
+
if (checked && was === "todo") return "in_progress";
|
|
20774
21235
|
if (!checked && was === "done") return "todo";
|
|
20775
21236
|
return token ?? was;
|
|
20776
21237
|
}
|
|
@@ -20809,7 +21270,7 @@ function ledgerPath2() {
|
|
|
20809
21270
|
}
|
|
20810
21271
|
function readLedger() {
|
|
20811
21272
|
try {
|
|
20812
|
-
return JSON.parse(
|
|
21273
|
+
return JSON.parse(readFileSync35(ledgerPath2(), "utf8"));
|
|
20813
21274
|
} catch {
|
|
20814
21275
|
return {};
|
|
20815
21276
|
}
|
|
@@ -20853,7 +21314,7 @@ async function pushProjectTaskStatuses(base2, authHeaders, opts = {}) {
|
|
|
20853
21314
|
if (ledger[file] === mtime) continue;
|
|
20854
21315
|
let changed;
|
|
20855
21316
|
try {
|
|
20856
|
-
changed = parseTaskFile(
|
|
21317
|
+
changed = parseTaskFile(readFileSync35(file, "utf8")).filter((t) => t.kind === fk.kind);
|
|
20857
21318
|
} catch {
|
|
20858
21319
|
continue;
|
|
20859
21320
|
}
|
|
@@ -20910,7 +21371,7 @@ function applyCodeRecommendation(intent) {
|
|
|
20910
21371
|
if (!meta.rootPath) return { status: "error", result: JSON.stringify({ error: "missing rootPath" }) };
|
|
20911
21372
|
file = join44(meta.rootPath, "CLAUDE.md");
|
|
20912
21373
|
}
|
|
20913
|
-
const existing = existsSync41(file) ?
|
|
21374
|
+
const existing = existsSync41(file) ? readFileSync36(file, "utf8") : "";
|
|
20914
21375
|
if (existing.includes(text)) return { status: "done", result: JSON.stringify({ skipped: "rule already present", file }) };
|
|
20915
21376
|
const block = `${existing && !existing.endsWith("\n") ? "\n" : ""}
|
|
20916
21377
|
## Rule (added by chat-recall recommendation)
|
|
@@ -20956,10 +21417,10 @@ async function runIntent(intent, ctx) {
|
|
|
20956
21417
|
var ownVersion2 = "0.0.0";
|
|
20957
21418
|
try {
|
|
20958
21419
|
const dir = dirname19(fileURLToPath2(import.meta.url));
|
|
20959
|
-
ownVersion2 = JSON.parse(
|
|
21420
|
+
ownVersion2 = JSON.parse(readFileSync36(join44(dir, "../package.json"), "utf-8")).version || ownVersion2;
|
|
20960
21421
|
} catch {
|
|
20961
21422
|
try {
|
|
20962
|
-
if (true) ownVersion2 = "0.5.
|
|
21423
|
+
if (true) ownVersion2 = "0.5.6";
|
|
20963
21424
|
} catch {
|
|
20964
21425
|
}
|
|
20965
21426
|
}
|
|
@@ -21133,8 +21594,37 @@ async function runCollectorMigration(opts) {
|
|
|
21133
21594
|
}
|
|
21134
21595
|
|
|
21135
21596
|
// auto-indexer/indexer.ts
|
|
21136
|
-
|
|
21137
|
-
|
|
21597
|
+
init_sync_ledger();
|
|
21598
|
+
import { existsSync as existsSync45, readFileSync as readFileSync40, statSync as statSync40, renameSync as renameSync6, unlinkSync as unlinkSync4 } from "fs";
|
|
21599
|
+
|
|
21600
|
+
// ../engine/dist/core/collector-health.js
|
|
21601
|
+
init_paths();
|
|
21602
|
+
import { readFileSync as readFileSync37, writeFileSync as writeFileSync12, mkdirSync as mkdirSync12 } from "node:fs";
|
|
21603
|
+
import { join as join45, dirname as dirname20 } from "node:path";
|
|
21604
|
+
var healthPath = () => join45(getDataDir(), "collector-health.json");
|
|
21605
|
+
function collectorHealthPath() {
|
|
21606
|
+
return healthPath();
|
|
21607
|
+
}
|
|
21608
|
+
function readCollectorHealth() {
|
|
21609
|
+
try {
|
|
21610
|
+
const h = JSON.parse(readFileSync37(healthPath(), "utf-8"));
|
|
21611
|
+
return h && h.v === 1 && typeof h.updatedAt === "number" ? h : null;
|
|
21612
|
+
} catch {
|
|
21613
|
+
return null;
|
|
21614
|
+
}
|
|
21615
|
+
}
|
|
21616
|
+
function writeCollectorHealth(h) {
|
|
21617
|
+
try {
|
|
21618
|
+
const p = healthPath();
|
|
21619
|
+
mkdirSync12(dirname20(p), { recursive: true });
|
|
21620
|
+
writeFileSync12(p, JSON.stringify(h));
|
|
21621
|
+
} catch {
|
|
21622
|
+
}
|
|
21623
|
+
}
|
|
21624
|
+
var STALE_AFTER_MS = 30 * 6e4;
|
|
21625
|
+
|
|
21626
|
+
// auto-indexer/indexer.ts
|
|
21627
|
+
var CLI_VERSION3 = true ? "0.5.6" : "0.0.0";
|
|
21138
21628
|
var DEBOUNCE_MS = 5e3;
|
|
21139
21629
|
function ts() {
|
|
21140
21630
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -21147,9 +21637,9 @@ var DIARY_DIR = getDiaryDir();
|
|
|
21147
21637
|
var CODEX_SESSIONS_DIR = codexBackend.sessionsDir();
|
|
21148
21638
|
var GEMINI_TMP_DIR = geminiBackend.tmpDir();
|
|
21149
21639
|
var OPENCODE_DB_PATH = opencodeBackend.dbPath();
|
|
21150
|
-
var OPENCODE_DB_DIR =
|
|
21151
|
-
var CURRENT_RESUME_PATH =
|
|
21152
|
-
var LAST_CLEANUP_PATH =
|
|
21640
|
+
var OPENCODE_DB_DIR = dirname21(OPENCODE_DB_PATH);
|
|
21641
|
+
var CURRENT_RESUME_PATH = join49(claudeBackend.homeDir(), "current-resume");
|
|
21642
|
+
var LAST_CLEANUP_PATH = join49(claudeBackend.homeDir(), ".last-cleanup");
|
|
21153
21643
|
var debounceTimer = null;
|
|
21154
21644
|
var syncInFlight = false;
|
|
21155
21645
|
var pendingFileCount = 0;
|
|
@@ -21171,9 +21661,11 @@ async function shipToServer(trigger) {
|
|
|
21171
21661
|
`[${ts()}] Sync (${trigger}): ${result.uploaded} session(s) pushed, ${result.redactions} secret(s) redacted, ${result.skipped} skipped, ${result.items} items, ${result.links} links, ${result.derived} derived, ${result.kgEntities} KG entities, ${result.kgTriples} KG triples`
|
|
21172
21662
|
);
|
|
21173
21663
|
}
|
|
21664
|
+
for (const server of syncTargetUrls()) noteSyncOutcome(server, true);
|
|
21174
21665
|
} catch (err) {
|
|
21175
21666
|
const msg = err instanceof Error ? err.message : String(err);
|
|
21176
21667
|
console.error(`[${ts()}] Sync failed (${trigger}, will retry next flush): ${msg.slice(0, 200)}`);
|
|
21668
|
+
for (const server of syncTargetUrls()) noteSyncOutcome(server, false, msg);
|
|
21177
21669
|
} finally {
|
|
21178
21670
|
syncInFlight = false;
|
|
21179
21671
|
}
|
|
@@ -21201,39 +21693,58 @@ async function onResumeSignal(path) {
|
|
|
21201
21693
|
lastResumeAt.set(id, now);
|
|
21202
21694
|
const { snapshotShadow: snapshotShadow2 } = await Promise.resolve().then(() => (init_transcript(), transcript_exports));
|
|
21203
21695
|
const r = await snapshotShadow2(id);
|
|
21696
|
+
if (r.status === "skipped") return;
|
|
21204
21697
|
console.log(`[${ts()}] [resume-guard] shadow ${r.status} for ${id.slice(0, 8)}\u2026` + (r.recovered > 0 ? ` (recovered ${r.recovered} record(s))` : ""));
|
|
21205
21698
|
} catch (e) {
|
|
21206
21699
|
console.error(`[${ts()}] [resume-guard] ${e instanceof Error ? e.message : e}`);
|
|
21207
21700
|
}
|
|
21208
21701
|
}
|
|
21209
|
-
var
|
|
21210
|
-
|
|
21702
|
+
var FORCE_POLL = process.env.CHAT_RECALL_WATCH_POLL === "1";
|
|
21703
|
+
var POLL = (interval) => FORCE_POLL ? { usePolling: true, interval } : {};
|
|
21704
|
+
var watchOpts = (t, poll = FORCE_POLL) => ({
|
|
21211
21705
|
persistent: true,
|
|
21212
|
-
ignoreInitial: true,
|
|
21213
|
-
|
|
21214
|
-
interval:
|
|
21215
|
-
|
|
21706
|
+
ignoreInitial: t.ignoreInitial ?? true,
|
|
21707
|
+
...t.ignored ? { ignored: t.ignored } : {},
|
|
21708
|
+
...poll ? { usePolling: true, interval: t.interval } : {}
|
|
21709
|
+
});
|
|
21710
|
+
function watchWithFallback(name, pattern, t) {
|
|
21711
|
+
let w = chokidar.watch(pattern, watchOpts(t));
|
|
21712
|
+
let swapped = false;
|
|
21713
|
+
w.on("error", (err) => {
|
|
21714
|
+
const code = err?.code;
|
|
21715
|
+
if (swapped || FORCE_POLL || code !== "ENOSPC" && code !== "EMFILE") {
|
|
21716
|
+
console.error(`[${ts()}] ${name} watcher error: ${String(err)}`);
|
|
21717
|
+
return;
|
|
21718
|
+
}
|
|
21719
|
+
swapped = true;
|
|
21720
|
+
console.log(`[${ts()}] ${name} watcher: native watching hit ${code} \u2014 falling back to polling every ${t.interval}ms. Raise fs.inotify.max_user_watches to get native events back.`);
|
|
21721
|
+
void w.close().catch(() => {
|
|
21722
|
+
});
|
|
21723
|
+
w = chokidar.watch(pattern, watchOpts(t, true));
|
|
21724
|
+
});
|
|
21725
|
+
return w;
|
|
21726
|
+
}
|
|
21727
|
+
var sessionWatcher = watchWithFallback("sessions", `${CLAUDE_DIR}/**/*.jsonl`, {
|
|
21728
|
+
ignored: (p) => /agent-/.test(p) || /^\./.test(basename25(p)),
|
|
21729
|
+
interval: 5e3
|
|
21216
21730
|
});
|
|
21217
21731
|
var plansWatcher = chokidar.watch(`${PLANS_DIR}/*.md`, {
|
|
21218
21732
|
persistent: true,
|
|
21219
21733
|
ignoreInitial: true,
|
|
21220
21734
|
awaitWriteFinish: { stabilityThreshold: 1e3, pollInterval: 100 },
|
|
21221
|
-
|
|
21222
|
-
interval: 1e4
|
|
21735
|
+
...POLL(1e4)
|
|
21223
21736
|
});
|
|
21224
21737
|
var tasksWatcher = chokidar.watch(`${TASKS_DIR}/**/*.json`, {
|
|
21225
21738
|
persistent: true,
|
|
21226
21739
|
ignoreInitial: true,
|
|
21227
21740
|
awaitWriteFinish: { stabilityThreshold: 1e3, pollInterval: 100 },
|
|
21228
|
-
|
|
21229
|
-
interval: 1e4
|
|
21741
|
+
...POLL(1e4)
|
|
21230
21742
|
});
|
|
21231
21743
|
var historyWatcher = chokidar.watch(HISTORY_PATH, {
|
|
21232
21744
|
persistent: true,
|
|
21233
21745
|
ignoreInitial: true,
|
|
21234
21746
|
awaitWriteFinish: { stabilityThreshold: 2e3, pollInterval: 500 },
|
|
21235
|
-
|
|
21236
|
-
interval: 3e4
|
|
21747
|
+
...POLL(3e4)
|
|
21237
21748
|
// check less frequently
|
|
21238
21749
|
});
|
|
21239
21750
|
var diaryWatcher = chokidar.watch(`${DIARY_DIR}/**/*.json`, {
|
|
@@ -21247,15 +21758,13 @@ var codexWatcher = chokidar.watch(`${CODEX_SESSIONS_DIR}/**/rollout-*.jsonl`, {
|
|
|
21247
21758
|
// Codex rolls every event into its own JSONL line — wait for ~2s of
|
|
21248
21759
|
// write quiescence so we don't ship mid-write.
|
|
21249
21760
|
awaitWriteFinish: { stabilityThreshold: 2e3, pollInterval: 200 },
|
|
21250
|
-
|
|
21251
|
-
interval: 5e3
|
|
21761
|
+
...POLL(5e3)
|
|
21252
21762
|
});
|
|
21253
21763
|
var geminiWatcher = chokidar.watch(`${GEMINI_TMP_DIR}/**/session-*.json`, {
|
|
21254
21764
|
persistent: true,
|
|
21255
21765
|
ignoreInitial: true,
|
|
21256
21766
|
awaitWriteFinish: { stabilityThreshold: 1500, pollInterval: 200 },
|
|
21257
|
-
|
|
21258
|
-
interval: 5e3
|
|
21767
|
+
...POLL(5e3)
|
|
21259
21768
|
});
|
|
21260
21769
|
var opencodeWatcher = chokidar.watch(
|
|
21261
21770
|
[`${OPENCODE_DB_PATH}`, `${OPENCODE_DB_PATH}-wal`],
|
|
@@ -21263,23 +21772,20 @@ var opencodeWatcher = chokidar.watch(
|
|
|
21263
21772
|
persistent: true,
|
|
21264
21773
|
ignoreInitial: true,
|
|
21265
21774
|
awaitWriteFinish: { stabilityThreshold: 2500, pollInterval: 500 },
|
|
21266
|
-
|
|
21267
|
-
interval: 1e4
|
|
21775
|
+
...POLL(1e4)
|
|
21268
21776
|
}
|
|
21269
21777
|
);
|
|
21270
21778
|
var agentMemoryWatcher = chokidar.watch(`${CLAUDE_DIR}/*/memory/*.md`, {
|
|
21271
21779
|
persistent: true,
|
|
21272
21780
|
ignoreInitial: true,
|
|
21273
21781
|
awaitWriteFinish: { stabilityThreshold: 1e3, pollInterval: 100 },
|
|
21274
|
-
|
|
21275
|
-
interval: 1e4
|
|
21782
|
+
...POLL(1e4)
|
|
21276
21783
|
});
|
|
21277
21784
|
var cleanupWatcher = chokidar.watch(LAST_CLEANUP_PATH, {
|
|
21278
21785
|
persistent: true,
|
|
21279
21786
|
ignoreInitial: true,
|
|
21280
21787
|
awaitWriteFinish: { stabilityThreshold: 1e3, pollInterval: 200 },
|
|
21281
|
-
|
|
21282
|
-
interval: 3e4
|
|
21788
|
+
...POLL(3e4)
|
|
21283
21789
|
});
|
|
21284
21790
|
var watchers = {
|
|
21285
21791
|
sessions: sessionWatcher,
|
|
@@ -21293,12 +21799,10 @@ var watchers = {
|
|
|
21293
21799
|
agentMemory: agentMemoryWatcher,
|
|
21294
21800
|
cleanup: cleanupWatcher
|
|
21295
21801
|
};
|
|
21296
|
-
var resumeWatcher = chokidar.watch(CURRENT_RESUME_PATH, {
|
|
21297
|
-
|
|
21298
|
-
ignoreInitial: false
|
|
21299
|
-
|
|
21300
|
-
interval: 1e3
|
|
21301
|
-
});
|
|
21802
|
+
var resumeWatcher = chokidar.watch(CURRENT_RESUME_PATH, watchOpts({
|
|
21803
|
+
interval: 1e3,
|
|
21804
|
+
ignoreInitial: false
|
|
21805
|
+
}));
|
|
21302
21806
|
resumeWatcher.on("add", (p) => {
|
|
21303
21807
|
void onResumeSignal(p);
|
|
21304
21808
|
}).on("change", (p) => {
|
|
@@ -21342,9 +21846,71 @@ var BOOT_CODE = codeFingerprint();
|
|
|
21342
21846
|
if (BOOT_CODE) {
|
|
21343
21847
|
console.log(`[${ts()}] running bundle ${BOOT_CODE.path} (${BOOT_CODE.size} bytes)`);
|
|
21344
21848
|
}
|
|
21849
|
+
function rotateLogIfLarge() {
|
|
21850
|
+
const LOG_MAX_BYTES = 32 * 1024 * 1024;
|
|
21851
|
+
try {
|
|
21852
|
+
const logPath = join49(getDataDir(), "watch.log");
|
|
21853
|
+
const st = statSync40(logPath);
|
|
21854
|
+
if (st.size < LOG_MAX_BYTES) return;
|
|
21855
|
+
const prev = `${logPath}.1`;
|
|
21856
|
+
try {
|
|
21857
|
+
unlinkSync4(prev);
|
|
21858
|
+
} catch {
|
|
21859
|
+
}
|
|
21860
|
+
renameSync6(logPath, prev);
|
|
21861
|
+
console.log(`[${ts()}] rotated watch.log at ${(st.size / 1048576).toFixed(0)}MB \u2192 watch.log.1`);
|
|
21862
|
+
} catch {
|
|
21863
|
+
}
|
|
21864
|
+
}
|
|
21865
|
+
rotateLogIfLarge();
|
|
21866
|
+
var PROC_START = Date.now();
|
|
21867
|
+
var targetHealth = {};
|
|
21868
|
+
function recentStarts() {
|
|
21869
|
+
const prior = readCollectorHealth();
|
|
21870
|
+
const cutoff = Date.now() - 36e5;
|
|
21871
|
+
return [...prior?.starts ?? [], PROC_START].filter((t) => typeof t === "number" && t > cutoff).filter((t, i, a) => a.indexOf(t) === i).sort((a, b) => a - b).slice(-20);
|
|
21872
|
+
}
|
|
21873
|
+
function publishHealth() {
|
|
21874
|
+
const starts = recentStarts();
|
|
21875
|
+
writeCollectorHealth(Object.assign({
|
|
21876
|
+
v: 1,
|
|
21877
|
+
updatedAt: Date.now(),
|
|
21878
|
+
startedAt: PROC_START,
|
|
21879
|
+
restartsLastHour: starts.length,
|
|
21880
|
+
targets: targetHealth
|
|
21881
|
+
}, { starts }));
|
|
21882
|
+
}
|
|
21883
|
+
function syncTargetUrls() {
|
|
21884
|
+
try {
|
|
21885
|
+
return loadAllCredentials().map((c) => c.serverUrl);
|
|
21886
|
+
} catch {
|
|
21887
|
+
return [];
|
|
21888
|
+
}
|
|
21889
|
+
}
|
|
21890
|
+
function noteSyncOutcome(server, ok, err) {
|
|
21891
|
+
const t = targetHealth[server] ?? { lastOkAt: null, failures: 0 };
|
|
21892
|
+
if (ok) {
|
|
21893
|
+
t.lastOkAt = Date.now();
|
|
21894
|
+
t.failures = 0;
|
|
21895
|
+
delete t.lastError;
|
|
21896
|
+
} else {
|
|
21897
|
+
t.failures += 1;
|
|
21898
|
+
t.lastError = (err ?? "unknown error").slice(0, 160);
|
|
21899
|
+
}
|
|
21900
|
+
targetHealth[server] = t;
|
|
21901
|
+
publishHealth();
|
|
21902
|
+
}
|
|
21903
|
+
publishHealth();
|
|
21904
|
+
{
|
|
21905
|
+
const n = recentStarts().length;
|
|
21906
|
+
if (n >= 3) {
|
|
21907
|
+
console.error(`[${ts()}] WARNING: this collector has restarted ${n} times in the last hour. Sync is probably falling behind. Health: ${collectorHealthPath()}`);
|
|
21908
|
+
}
|
|
21909
|
+
}
|
|
21345
21910
|
setInterval(() => {
|
|
21346
21911
|
if (checkSelfRestart({ boot: BOOT_CODE, log: (m) => console.log(`[${ts()}] ${m}`) })) return;
|
|
21347
21912
|
console.log(`[${ts()}] Heartbeat - ${pendingFileCount} pending file event(s), sync ${syncInFlight ? "in-flight" : "idle"}`);
|
|
21913
|
+
publishHealth();
|
|
21348
21914
|
}, 6e4);
|
|
21349
21915
|
var intentDrainInFlight = false;
|
|
21350
21916
|
var intentDrainStartedAt = 0;
|
|
@@ -21353,7 +21919,7 @@ var DRAIN_STALL_MS = 5 * 6e4;
|
|
|
21353
21919
|
async function drainIntentsTick() {
|
|
21354
21920
|
if (intentDrainInFlight) {
|
|
21355
21921
|
const stuckMs = Date.now() - intentDrainStartedAt;
|
|
21356
|
-
if (stuckMs < DRAIN_STALL_MS) return;
|
|
21922
|
+
if (stuckMs < DRAIN_STALL_MS) return false;
|
|
21357
21923
|
console.error(`[${ts()}] sync-intents: previous drain has been running ${Math.round(stuckMs / 1e3)}s \u2014 abandoning it and starting a fresh tick`);
|
|
21358
21924
|
}
|
|
21359
21925
|
intentDrainInFlight = true;
|
|
@@ -21365,18 +21931,28 @@ async function drainIntentsTick() {
|
|
|
21365
21931
|
console.log(`[${ts()}] sync-intents: ${r.done} done, ${r.errored} errored`);
|
|
21366
21932
|
if (r.done > 0) await shipToServer("intent-applied");
|
|
21367
21933
|
}
|
|
21934
|
+
return r.processed > 0;
|
|
21368
21935
|
} catch (err) {
|
|
21369
21936
|
console.error(`[${ts()}] sync-intents drain failed: ${err instanceof Error ? err.message : err}`);
|
|
21937
|
+
return false;
|
|
21370
21938
|
} finally {
|
|
21371
21939
|
if (gen === intentDrainGeneration) intentDrainInFlight = false;
|
|
21372
21940
|
}
|
|
21373
21941
|
}
|
|
21374
|
-
|
|
21375
|
-
|
|
21376
|
-
|
|
21377
|
-
|
|
21378
|
-
|
|
21379
|
-
|
|
21942
|
+
var INTENT_POLL_MIN_MS = 15e3;
|
|
21943
|
+
var INTENT_POLL_MAX_MS = 5 * 6e4;
|
|
21944
|
+
var intentPollMs = INTENT_POLL_MIN_MS;
|
|
21945
|
+
var intentTimer = null;
|
|
21946
|
+
function scheduleIntentPoll(ms) {
|
|
21947
|
+
if (intentTimer) clearTimeout(intentTimer);
|
|
21948
|
+
intentTimer = setTimeout(async () => {
|
|
21949
|
+
const found = await drainIntentsTick();
|
|
21950
|
+
intentPollMs = found ? INTENT_POLL_MIN_MS : Math.min(intentPollMs * 2, INTENT_POLL_MAX_MS);
|
|
21951
|
+
scheduleIntentPoll(intentPollMs);
|
|
21952
|
+
}, ms);
|
|
21953
|
+
intentTimer.unref?.();
|
|
21954
|
+
}
|
|
21955
|
+
scheduleIntentPoll(5e3);
|
|
21380
21956
|
var CODE_INDEX_ON = process.env.CHAT_RECALL_CODE_INDEX !== "0";
|
|
21381
21957
|
var CODE_INDEX_MS = Math.max(15, parseInt(process.env.CHAT_RECALL_CODE_INDEX_MINUTES || "180", 10)) * 60 * 1e3;
|
|
21382
21958
|
var CODE_INDEX_MAX = Math.max(1, parseInt(process.env.CHAT_RECALL_CODE_INDEX_MAX || "50", 10));
|
|
@@ -21412,13 +21988,45 @@ function discoverWorkspaces() {
|
|
|
21412
21988
|
} catch {
|
|
21413
21989
|
}
|
|
21414
21990
|
const isExcluded = (p) => excluded.some((x) => p.includes(x));
|
|
21415
|
-
|
|
21991
|
+
const candidates2 = [...newest.entries()].filter(([p]) => !isExcluded(p)).filter(([p]) => !isPersonalPath(p, includeProjects)).filter(([p]) => {
|
|
21992
|
+
try {
|
|
21993
|
+
return existsSync45(p);
|
|
21994
|
+
} catch {
|
|
21995
|
+
return false;
|
|
21996
|
+
}
|
|
21997
|
+
}).filter(([p]) => isCodeWorkspace(p)).sort((a, b) => b[1] - a[1]);
|
|
21998
|
+
const roots = candidates2.map(([p]) => p);
|
|
21999
|
+
const notAnAncestor = ([p]) => !roots.some((other) => other !== p && other.startsWith(p.endsWith(sep3) ? p : p + sep3));
|
|
22000
|
+
return candidates2.filter(notAnAncestor).slice(0, CODE_INDEX_MAX).map(([p]) => p);
|
|
22001
|
+
}
|
|
22002
|
+
var WORKSPACE_MARKERS = [
|
|
22003
|
+
".git",
|
|
22004
|
+
"package.json",
|
|
22005
|
+
"go.mod",
|
|
22006
|
+
"Cargo.toml",
|
|
22007
|
+
"pyproject.toml",
|
|
22008
|
+
"setup.py",
|
|
22009
|
+
"pom.xml",
|
|
22010
|
+
"build.gradle",
|
|
22011
|
+
"composer.json",
|
|
22012
|
+
"Gemfile",
|
|
22013
|
+
"mix.exs",
|
|
22014
|
+
"deno.json"
|
|
22015
|
+
];
|
|
22016
|
+
function isCodeWorkspace(p) {
|
|
22017
|
+
try {
|
|
22018
|
+
const resolved = resolve2(p);
|
|
22019
|
+
if (resolved === sep3 || resolved === homedir20() || dirname21(resolved) === resolved) return false;
|
|
22020
|
+
} catch {
|
|
22021
|
+
return false;
|
|
22022
|
+
}
|
|
22023
|
+
return WORKSPACE_MARKERS.some((m) => {
|
|
21416
22024
|
try {
|
|
21417
|
-
return
|
|
22025
|
+
return existsSync45(join49(p, m));
|
|
21418
22026
|
} catch {
|
|
21419
22027
|
return false;
|
|
21420
22028
|
}
|
|
21421
|
-
})
|
|
22029
|
+
});
|
|
21422
22030
|
}
|
|
21423
22031
|
async function codeIndexTick() {
|
|
21424
22032
|
if (codeIndexInFlight) return;
|
|
@@ -21523,6 +22131,11 @@ if (CODE_INDEX_ON) setTimeout(() => {
|
|
|
21523
22131
|
}, 15e4);
|
|
21524
22132
|
function shutdown(signal) {
|
|
21525
22133
|
console.log(`[${ts()}] Received ${signal}, shutting down...`);
|
|
22134
|
+
try {
|
|
22135
|
+
flushLedger();
|
|
22136
|
+
} catch (e) {
|
|
22137
|
+
console.error(`[${ts()}] ledger flush on shutdown failed: ${String(e)}`);
|
|
22138
|
+
}
|
|
21526
22139
|
for (const watcher of Object.values(watchers)) {
|
|
21527
22140
|
void watcher.close();
|
|
21528
22141
|
}
|
|
@@ -21531,3 +22144,13 @@ function shutdown(signal) {
|
|
|
21531
22144
|
}
|
|
21532
22145
|
process.on("SIGTERM", () => shutdown("SIGTERM"));
|
|
21533
22146
|
process.on("SIGINT", () => shutdown("SIGINT"));
|
|
22147
|
+
if (process.platform === "win32") {
|
|
22148
|
+
process.on("SIGBREAK", () => shutdown("SIGBREAK"));
|
|
22149
|
+
process.on("SIGHUP", () => shutdown("SIGHUP"));
|
|
22150
|
+
}
|
|
22151
|
+
process.on("exit", () => {
|
|
22152
|
+
try {
|
|
22153
|
+
flushLedger();
|
|
22154
|
+
} catch {
|
|
22155
|
+
}
|
|
22156
|
+
});
|