engine7 7.1.22 → 7.1.24
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.mjs +15 -5
- package/dist/engine-startup.mjs +785 -325
- package/dist/main.mjs +786 -326
- package/package.json +2 -1
- package/src/memory/everos/python/__pycache__/agentic_search.cpython-314.pyc +0 -0
- package/src/memory/everos/python/__pycache__/agentic_server.cpython-314.pyc +0 -0
- package/src/memory/everos/python/agentic_search.py +980 -0
- package/src/memory/everos/python/agentic_server.py +383 -0
- package/src/memory/everos/python/fcntl_compat.py +23 -0
- package/src/memory/everos/python/requirements.txt +7 -0
package/dist/engine-startup.mjs
CHANGED
|
@@ -725,8 +725,10 @@ async function executeStopHooks(ctx, signal, lastAssistantMessage) {
|
|
|
725
725
|
cwd: ctx.cwd,
|
|
726
726
|
stop_hook_active: false,
|
|
727
727
|
last_assistant_message: lastAssistantMessage,
|
|
728
|
-
channel: ctx.channel
|
|
728
|
+
channel: ctx.channel,
|
|
729
729
|
// 让 callback hook 能判断来源
|
|
730
|
+
source: ctx.source || ""
|
|
731
|
+
// 消息来源(heartbeat/cron/system 等注入 turn 可据此跳过)
|
|
730
732
|
};
|
|
731
733
|
return executeHooks("Stop", hookInput, ctx, signal);
|
|
732
734
|
}
|
|
@@ -1078,6 +1080,7 @@ function collectSurfacedMemories(messages) {
|
|
|
1078
1080
|
return { paths };
|
|
1079
1081
|
}
|
|
1080
1082
|
function normalizePath(p2) {
|
|
1083
|
+
if (p2.startsWith("everos://")) return p2;
|
|
1081
1084
|
return pathResolve(p2);
|
|
1082
1085
|
}
|
|
1083
1086
|
function memoryHeader(filePath, mtimeMs) {
|
|
@@ -2524,10 +2527,12 @@ function breakdownMessages(messages) {
|
|
|
2524
2527
|
if (memCount === 0) console.log(`[context-analyzer] WARNING: relevant_memories attachment with 0 memories! keys=${Object.keys(m2.attachment).join(",")}`);
|
|
2525
2528
|
for (const mem of m2.attachment.memories || []) {
|
|
2526
2529
|
const fileName = mem.path.split(/[/\\]/).pop() || mem.path;
|
|
2530
|
+
const scoreMatch = mem.header?.match(/score=([\d.]+)/);
|
|
2527
2531
|
recalledTopics.push({
|
|
2528
2532
|
path: fileName,
|
|
2529
2533
|
tokens: roughTokenCountEstimation(mem.content),
|
|
2530
|
-
stable: false
|
|
2534
|
+
stable: false,
|
|
2535
|
+
score: scoreMatch ? scoreMatch[1] : void 0
|
|
2531
2536
|
});
|
|
2532
2537
|
}
|
|
2533
2538
|
}
|
|
@@ -2738,13 +2743,25 @@ function formatContextReport(report) {
|
|
|
2738
2743
|
output += `### Recalled Memories (${rt.length})
|
|
2739
2744
|
|
|
2740
2745
|
`;
|
|
2741
|
-
|
|
2746
|
+
const hasScore = rt.some((t) => t.score);
|
|
2747
|
+
if (hasScore) {
|
|
2748
|
+
output += `| File | Score | Tokens |
|
|
2742
2749
|
`;
|
|
2743
|
-
|
|
2750
|
+
output += `|------|-------|--------|
|
|
2751
|
+
`;
|
|
2752
|
+
for (const t of rt) {
|
|
2753
|
+
output += `| ${t.path} | ${t.score ?? "-"} | ${formatTokens(t.tokens)} |
|
|
2754
|
+
`;
|
|
2755
|
+
}
|
|
2756
|
+
} else {
|
|
2757
|
+
output += `| File | Tokens |
|
|
2758
|
+
`;
|
|
2759
|
+
output += `|------|--------|
|
|
2744
2760
|
`;
|
|
2745
|
-
|
|
2746
|
-
|
|
2761
|
+
for (const t of rt) {
|
|
2762
|
+
output += `| ${t.path} | ${formatTokens(t.tokens)} |
|
|
2747
2763
|
`;
|
|
2764
|
+
}
|
|
2748
2765
|
}
|
|
2749
2766
|
output += "\n";
|
|
2750
2767
|
}
|
|
@@ -3082,7 +3099,8 @@ ${perTurnSystemDynamic}` : deferredHint || perTurnSystemDynamic;
|
|
|
3082
3099
|
sessionId: context?.sessionId || "default",
|
|
3083
3100
|
workspace: context?.workspace || "",
|
|
3084
3101
|
channel: context?.channel || "",
|
|
3085
|
-
cwd: context?.workspace || ""
|
|
3102
|
+
cwd: context?.workspace || "",
|
|
3103
|
+
source: typeof context?.source === "string" ? context.source : ""
|
|
3086
3104
|
};
|
|
3087
3105
|
const stopResult = await executeStopHooks(stopCtx, ac.signal, textContent);
|
|
3088
3106
|
if (stopResult.preventContinuation) {
|
|
@@ -5729,11 +5747,11 @@ async function readLastConsolidatedAt(memoryDir) {
|
|
|
5729
5747
|
}
|
|
5730
5748
|
}
|
|
5731
5749
|
async function tryAcquireConsolidationLock(memoryDir) {
|
|
5732
|
-
const
|
|
5750
|
+
const path44 = lockPath(memoryDir);
|
|
5733
5751
|
let mtimeMs;
|
|
5734
5752
|
let holderPid;
|
|
5735
5753
|
try {
|
|
5736
|
-
const [s2, raw] = await Promise.all([stat3(
|
|
5754
|
+
const [s2, raw] = await Promise.all([stat3(path44), readFile5(path44, "utf8")]);
|
|
5737
5755
|
mtimeMs = s2.mtimeMs;
|
|
5738
5756
|
const parsed = parseInt(raw.trim(), 10);
|
|
5739
5757
|
holderPid = Number.isFinite(parsed) ? parsed : void 0;
|
|
@@ -5746,10 +5764,10 @@ async function tryAcquireConsolidationLock(memoryDir) {
|
|
|
5746
5764
|
}
|
|
5747
5765
|
}
|
|
5748
5766
|
await mkdir3(memoryDir, { recursive: true });
|
|
5749
|
-
await writeFile4(
|
|
5767
|
+
await writeFile4(path44, String(process.pid));
|
|
5750
5768
|
let verify2;
|
|
5751
5769
|
try {
|
|
5752
|
-
verify2 = await readFile5(
|
|
5770
|
+
verify2 = await readFile5(path44, "utf8");
|
|
5753
5771
|
} catch {
|
|
5754
5772
|
return null;
|
|
5755
5773
|
}
|
|
@@ -5757,15 +5775,15 @@ async function tryAcquireConsolidationLock(memoryDir) {
|
|
|
5757
5775
|
return mtimeMs ?? 0;
|
|
5758
5776
|
}
|
|
5759
5777
|
async function rollbackConsolidationLock(memoryDir, priorMtime) {
|
|
5760
|
-
const
|
|
5778
|
+
const path44 = lockPath(memoryDir);
|
|
5761
5779
|
try {
|
|
5762
5780
|
if (priorMtime === 0) {
|
|
5763
|
-
await unlink(
|
|
5781
|
+
await unlink(path44);
|
|
5764
5782
|
return;
|
|
5765
5783
|
}
|
|
5766
|
-
await writeFile4(
|
|
5784
|
+
await writeFile4(path44, "");
|
|
5767
5785
|
const t = priorMtime / 1e3;
|
|
5768
|
-
await utimes(
|
|
5786
|
+
await utimes(path44, t, t);
|
|
5769
5787
|
} catch (e) {
|
|
5770
5788
|
console.log(`[autoDream] rollback failed: ${e.message} \u2014 next trigger delayed to minHours`);
|
|
5771
5789
|
}
|
|
@@ -6098,15 +6116,15 @@ __export(TodoWriteTool_exports, {
|
|
|
6098
6116
|
loadTodos: () => loadTodos
|
|
6099
6117
|
});
|
|
6100
6118
|
import fs31 from "node:fs";
|
|
6101
|
-
import
|
|
6119
|
+
import path31 from "node:path";
|
|
6102
6120
|
function initTodoStore(stateDir) {
|
|
6103
|
-
todosDir =
|
|
6121
|
+
todosDir = path31.join(stateDir, "todos");
|
|
6104
6122
|
if (!fs31.existsSync(todosDir)) {
|
|
6105
6123
|
fs31.mkdirSync(todosDir, { recursive: true });
|
|
6106
6124
|
}
|
|
6107
6125
|
}
|
|
6108
6126
|
function todoFilePath(sessionId) {
|
|
6109
|
-
return
|
|
6127
|
+
return path31.join(todosDir, `${sessionId}.json`);
|
|
6110
6128
|
}
|
|
6111
6129
|
function loadTodos(sessionId) {
|
|
6112
6130
|
if (!todosDir) return [];
|
|
@@ -6202,15 +6220,15 @@ __export(tasks_exports, {
|
|
|
6202
6220
|
updateTask: () => updateTask
|
|
6203
6221
|
});
|
|
6204
6222
|
import * as fs33 from "node:fs";
|
|
6205
|
-
import * as
|
|
6223
|
+
import * as path33 from "node:path";
|
|
6206
6224
|
function sanitizePathComponent2(input) {
|
|
6207
6225
|
return input.replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
6208
6226
|
}
|
|
6209
6227
|
function getTasksDir2(stateDir, listId) {
|
|
6210
|
-
return
|
|
6228
|
+
return path33.join(stateDir, "tasks", sanitizePathComponent2(listId));
|
|
6211
6229
|
}
|
|
6212
6230
|
function getTaskPath(stateDir, listId, taskId) {
|
|
6213
|
-
return
|
|
6231
|
+
return path33.join(getTasksDir2(stateDir, listId), `${sanitizePathComponent2(taskId)}.json`);
|
|
6214
6232
|
}
|
|
6215
6233
|
function ensureTasksDir2(stateDir, listId) {
|
|
6216
6234
|
const dir = getTasksDir2(stateDir, listId);
|
|
@@ -6218,7 +6236,7 @@ function ensureTasksDir2(stateDir, listId) {
|
|
|
6218
6236
|
return dir;
|
|
6219
6237
|
}
|
|
6220
6238
|
function getHighWaterMarkPath(stateDir, listId) {
|
|
6221
|
-
return
|
|
6239
|
+
return path33.join(getTasksDir2(stateDir, listId), HIGH_WATER_MARK_FILE);
|
|
6222
6240
|
}
|
|
6223
6241
|
function readHighWaterMark(stateDir, listId) {
|
|
6224
6242
|
try {
|
|
@@ -6424,7 +6442,7 @@ __export(read_exports, {
|
|
|
6424
6442
|
readFileState: () => readFileState
|
|
6425
6443
|
});
|
|
6426
6444
|
import * as fs34 from "node:fs";
|
|
6427
|
-
import * as
|
|
6445
|
+
import * as path34 from "node:path";
|
|
6428
6446
|
function isBlockedDevicePath(filePath) {
|
|
6429
6447
|
if (BLOCKED_DEVICE_PATHS.has(filePath)) return true;
|
|
6430
6448
|
if (filePath.startsWith("/proc/") && (filePath.endsWith("/fd/0") || filePath.endsWith("/fd/1") || filePath.endsWith("/fd/2"))) return true;
|
|
@@ -6603,7 +6621,7 @@ Usage:
|
|
|
6603
6621
|
return { content: `\u6587\u4EF6\u4E0D\u5B58\u5728: ${filePath}`, isError: true };
|
|
6604
6622
|
}
|
|
6605
6623
|
const stat4 = fs34.statSync(filePath);
|
|
6606
|
-
const baseName =
|
|
6624
|
+
const baseName = path34.basename(filePath).toUpperCase();
|
|
6607
6625
|
if (BLOCKED_BASENAMES.has(baseName)) {
|
|
6608
6626
|
return { content: `\u8BBE\u5907\u6587\u4EF6\u4E0D\u652F\u6301\u8BFB\u53D6: ${filePath}`, isError: true };
|
|
6609
6627
|
}
|
|
@@ -6613,7 +6631,7 @@ Usage:
|
|
|
6613
6631
|
if (stat4.isDirectory()) {
|
|
6614
6632
|
const entries = fs34.readdirSync(filePath);
|
|
6615
6633
|
const items = entries.map((e) => {
|
|
6616
|
-
const full =
|
|
6634
|
+
const full = path34.join(filePath, e);
|
|
6617
6635
|
try {
|
|
6618
6636
|
const s2 = fs34.statSync(full);
|
|
6619
6637
|
return s2.isDirectory() ? `${e}/` : e;
|
|
@@ -6624,7 +6642,7 @@ Usage:
|
|
|
6624
6642
|
return { content: `\u76EE\u5F55 (${entries.length} \u9879):
|
|
6625
6643
|
${items.join("\n")}` };
|
|
6626
6644
|
}
|
|
6627
|
-
const ext =
|
|
6645
|
+
const ext = path34.extname(filePath).toLowerCase();
|
|
6628
6646
|
if (BINARY_EXTENSIONS.has(ext)) {
|
|
6629
6647
|
return { content: `\u4E8C\u8FDB\u5236\u6587\u4EF6\u4E0D\u652F\u6301\u8BFB\u53D6 (${ext}): ${filePath}`, isError: true };
|
|
6630
6648
|
}
|
|
@@ -6673,7 +6691,7 @@ ${result}` : result };
|
|
|
6673
6691
|
// src/tools/write.ts
|
|
6674
6692
|
var write_exports = {};
|
|
6675
6693
|
import * as fs35 from "node:fs";
|
|
6676
|
-
import * as
|
|
6694
|
+
import * as path35 from "node:path";
|
|
6677
6695
|
function isBlockedPath(filePath) {
|
|
6678
6696
|
return BLOCKED_PATTERNS.some((p2) => p2.test(filePath));
|
|
6679
6697
|
}
|
|
@@ -6817,7 +6835,7 @@ Usage:
|
|
|
6817
6835
|
}
|
|
6818
6836
|
}
|
|
6819
6837
|
}
|
|
6820
|
-
const dir =
|
|
6838
|
+
const dir = path35.dirname(filePath);
|
|
6821
6839
|
try {
|
|
6822
6840
|
fs35.mkdirSync(dir, { recursive: true });
|
|
6823
6841
|
} catch (e) {
|
|
@@ -6853,7 +6871,7 @@ ${simpleDiff(oldContent, content)}`;
|
|
|
6853
6871
|
// src/tools/edit.ts
|
|
6854
6872
|
var edit_exports = {};
|
|
6855
6873
|
import * as fs36 from "node:fs";
|
|
6856
|
-
import * as
|
|
6874
|
+
import * as path36 from "node:path";
|
|
6857
6875
|
function normalizeQuotes(str) {
|
|
6858
6876
|
return str.replaceAll(LEFT_SINGLE_CURLY, "'").replaceAll(RIGHT_SINGLE_CURLY, "'").replaceAll(LEFT_DOUBLE_CURLY, '"').replaceAll(RIGHT_DOUBLE_CURLY, '"');
|
|
6859
6877
|
}
|
|
@@ -7016,7 +7034,7 @@ Usage:
|
|
|
7016
7034
|
} catch (e) {
|
|
7017
7035
|
if (e.code === "ENOENT") {
|
|
7018
7036
|
if (oldString === "") {
|
|
7019
|
-
const dir =
|
|
7037
|
+
const dir = path36.dirname(filePath);
|
|
7020
7038
|
fs36.mkdirSync(dir, { recursive: true });
|
|
7021
7039
|
fs36.writeFileSync(filePath, newString, "utf-8");
|
|
7022
7040
|
readFileState.set(filePath, { timestamp: fs36.statSync(filePath).mtimeMs });
|
|
@@ -7096,7 +7114,7 @@ ${diffView}`
|
|
|
7096
7114
|
// src/tools/glob.ts
|
|
7097
7115
|
var glob_exports = {};
|
|
7098
7116
|
import * as fs37 from "node:fs";
|
|
7099
|
-
import * as
|
|
7117
|
+
import * as path37 from "node:path";
|
|
7100
7118
|
function globMatch(pattern, filename) {
|
|
7101
7119
|
const regexStr = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "{{GLOBSTAR}}").replace(/\*/g, "[^/]*").replace(/\?/g, "[^/]").replace(/\{\{GLOBSTAR\}\}/g, ".*");
|
|
7102
7120
|
try {
|
|
@@ -7122,12 +7140,12 @@ function findFiles(dir, pattern, limit, baseDir) {
|
|
|
7122
7140
|
}
|
|
7123
7141
|
for (const entry of entries) {
|
|
7124
7142
|
if (truncated) return;
|
|
7125
|
-
const fullPath =
|
|
7143
|
+
const fullPath = path37.join(currentDir, entry.name);
|
|
7126
7144
|
if (entry.isDirectory()) {
|
|
7127
7145
|
if (VCS_DIRS.has(entry.name)) continue;
|
|
7128
7146
|
walk(fullPath);
|
|
7129
7147
|
} else if (entry.isFile()) {
|
|
7130
|
-
const relativePath =
|
|
7148
|
+
const relativePath = path37.relative(baseDir, fullPath).replace(/\\/g, "/");
|
|
7131
7149
|
const patternsToTry = [pattern];
|
|
7132
7150
|
if (pattern.startsWith("**/")) {
|
|
7133
7151
|
patternsToTry.push(pattern.slice(3));
|
|
@@ -7154,7 +7172,7 @@ function findFiles(dir, pattern, limit, baseDir) {
|
|
|
7154
7172
|
};
|
|
7155
7173
|
}
|
|
7156
7174
|
function toRelativePath(absolutePath, cwd) {
|
|
7157
|
-
if (absolutePath.startsWith(cwd +
|
|
7175
|
+
if (absolutePath.startsWith(cwd + path37.sep)) {
|
|
7158
7176
|
return absolutePath.slice(cwd.length + 1);
|
|
7159
7177
|
}
|
|
7160
7178
|
return absolutePath;
|
|
@@ -7215,7 +7233,7 @@ ${filenames.join("\n")}${truncatedNote}`
|
|
|
7215
7233
|
// src/tools/grep.ts
|
|
7216
7234
|
var grep_exports = {};
|
|
7217
7235
|
import { execFile as execFile2 } from "node:child_process";
|
|
7218
|
-
import * as
|
|
7236
|
+
import * as path38 from "node:path";
|
|
7219
7237
|
function ripGrep(args, searchPath, signal) {
|
|
7220
7238
|
return new Promise((resolve10) => {
|
|
7221
7239
|
const fullArgs = [...args, searchPath];
|
|
@@ -7247,7 +7265,7 @@ function applyHeadLimit(items, limit, offset = 0) {
|
|
|
7247
7265
|
};
|
|
7248
7266
|
}
|
|
7249
7267
|
function toRelativePath2(absolutePath, cwd) {
|
|
7250
|
-
if (absolutePath.startsWith(cwd +
|
|
7268
|
+
if (absolutePath.startsWith(cwd + path38.sep)) {
|
|
7251
7269
|
return absolutePath.slice(cwd.length + 1);
|
|
7252
7270
|
}
|
|
7253
7271
|
if (absolutePath.startsWith(cwd)) {
|
|
@@ -9916,7 +9934,7 @@ var init_web_fetch = __esm({
|
|
|
9916
9934
|
|
|
9917
9935
|
// src/cron/tasks.ts
|
|
9918
9936
|
import fs38 from "node:fs";
|
|
9919
|
-
import
|
|
9937
|
+
import path39 from "node:path";
|
|
9920
9938
|
import crypto5 from "node:crypto";
|
|
9921
9939
|
function getStorageDir() {
|
|
9922
9940
|
return storageDir;
|
|
@@ -9971,7 +9989,7 @@ function readTasksFromDisk() {
|
|
|
9971
9989
|
}
|
|
9972
9990
|
}
|
|
9973
9991
|
async function writeTasksToDisk(tasks2) {
|
|
9974
|
-
const lockPath2 =
|
|
9992
|
+
const lockPath2 = path39.join(storageDir, "tasks.json.lock");
|
|
9975
9993
|
await withFileLock(lockPath2, () => {
|
|
9976
9994
|
const store = {
|
|
9977
9995
|
version: 1,
|
|
@@ -9983,7 +10001,7 @@ async function writeTasksToDisk(tasks2) {
|
|
|
9983
10001
|
}
|
|
9984
10002
|
function initTaskStore(dir) {
|
|
9985
10003
|
storageDir = dir;
|
|
9986
|
-
tasksFilePath =
|
|
10004
|
+
tasksFilePath = path39.join(dir, "tasks.json");
|
|
9987
10005
|
if (!fs38.existsSync(dir)) {
|
|
9988
10006
|
fs38.mkdirSync(dir, { recursive: true });
|
|
9989
10007
|
}
|
|
@@ -10897,9 +10915,9 @@ async function executeAndDeliver(task, now, deps) {
|
|
|
10897
10915
|
let filePath = promptText.slice(1).trim();
|
|
10898
10916
|
try {
|
|
10899
10917
|
const fs42 = await import("fs");
|
|
10900
|
-
const
|
|
10901
|
-
if (!
|
|
10902
|
-
filePath =
|
|
10918
|
+
const path44 = await import("path");
|
|
10919
|
+
if (!path44.isAbsolute(filePath)) {
|
|
10920
|
+
filePath = path44.join(deps.sessions["config"].stateDir, filePath);
|
|
10903
10921
|
}
|
|
10904
10922
|
promptText = fs42.readFileSync(filePath, "utf-8");
|
|
10905
10923
|
console.log(`[cron] Loaded prompt from ${filePath} (${promptText.length} chars)`);
|
|
@@ -10928,15 +10946,15 @@ async function executeAndDeliver(task, now, deps) {
|
|
|
10928
10946
|
let finalResult = result;
|
|
10929
10947
|
if (task.postProcess) {
|
|
10930
10948
|
try {
|
|
10931
|
-
const
|
|
10949
|
+
const path44 = await import("path");
|
|
10932
10950
|
const fs42 = await import("fs");
|
|
10933
10951
|
let scriptPath = task.postProcess;
|
|
10934
|
-
if (!
|
|
10935
|
-
scriptPath =
|
|
10952
|
+
if (!path44.isAbsolute(scriptPath)) {
|
|
10953
|
+
scriptPath = path44.join(deps.sessions["config"].stateDir, scriptPath);
|
|
10936
10954
|
}
|
|
10937
|
-
const resultsDirTmp =
|
|
10955
|
+
const resultsDirTmp = path44.join(getStorageDir(), "results");
|
|
10938
10956
|
fs42.mkdirSync(resultsDirTmp, { recursive: true });
|
|
10939
|
-
const inputFile =
|
|
10957
|
+
const inputFile = path44.join(resultsDirTmp, `${task.id}.input.txt`);
|
|
10940
10958
|
fs42.writeFileSync(inputFile, result, "utf-8");
|
|
10941
10959
|
const { execFile: execFile3 } = await import("child_process");
|
|
10942
10960
|
await new Promise((resolve10) => {
|
|
@@ -10965,10 +10983,10 @@ async function executeAndDeliver(task, now, deps) {
|
|
|
10965
10983
|
}
|
|
10966
10984
|
try {
|
|
10967
10985
|
const fs42 = await import("fs");
|
|
10968
|
-
const
|
|
10969
|
-
const resultsDir =
|
|
10986
|
+
const path44 = await import("path");
|
|
10987
|
+
const resultsDir = path44.join(getStorageDir(), "results");
|
|
10970
10988
|
fs42.mkdirSync(resultsDir, { recursive: true });
|
|
10971
|
-
const resultFile =
|
|
10989
|
+
const resultFile = path44.join(resultsDir, `${task.id}.json`);
|
|
10972
10990
|
fs42.writeFileSync(resultFile, JSON.stringify({
|
|
10973
10991
|
taskId: task.id,
|
|
10974
10992
|
description: task.description,
|
|
@@ -11217,13 +11235,13 @@ function registerCronTools() {
|
|
|
11217
11235
|
},
|
|
11218
11236
|
handler: async (args) => {
|
|
11219
11237
|
const fs42 = await import("fs");
|
|
11220
|
-
const
|
|
11221
|
-
const resultsDir =
|
|
11238
|
+
const path44 = await import("path");
|
|
11239
|
+
const resultsDir = path44.join(getStorageDir(), "results");
|
|
11222
11240
|
if (!fs42.existsSync(resultsDir)) {
|
|
11223
11241
|
return { content: "\u6682\u65E0cron\u6267\u884C\u7ED3\u679C" };
|
|
11224
11242
|
}
|
|
11225
11243
|
if (args.task_id) {
|
|
11226
|
-
const file =
|
|
11244
|
+
const file = path44.join(resultsDir, `${args.task_id}.json`);
|
|
11227
11245
|
if (!fs42.existsSync(file)) {
|
|
11228
11246
|
return { content: `\u4EFB\u52A1 ${args.task_id} \u6682\u65E0\u6267\u884C\u7ED3\u679C`, isError: true };
|
|
11229
11247
|
}
|
|
@@ -11239,7 +11257,7 @@ ${data.result}` };
|
|
|
11239
11257
|
return { content: "\u6682\u65E0cron\u6267\u884C\u7ED3\u679C" };
|
|
11240
11258
|
}
|
|
11241
11259
|
const results = files.map((f2) => {
|
|
11242
|
-
const data = JSON.parse(fs42.readFileSync(
|
|
11260
|
+
const data = JSON.parse(fs42.readFileSync(path44.join(resultsDir, f2), "utf-8"));
|
|
11243
11261
|
return `### ${data.description} (${data.taskId.slice(0, 8)})
|
|
11244
11262
|
\u6267\u884C: ${data.executedAt} | \u7B2C${data.runCount}\u6B21
|
|
11245
11263
|
${data.result.slice(0, 500)}${data.result.length > 500 ? "..." : ""}`;
|
|
@@ -11401,7 +11419,7 @@ __export(manager_exports, {
|
|
|
11401
11419
|
McpManager: () => McpManager
|
|
11402
11420
|
});
|
|
11403
11421
|
import * as fs40 from "node:fs";
|
|
11404
|
-
import * as
|
|
11422
|
+
import * as path41 from "node:path";
|
|
11405
11423
|
import { Client as Client3 } from "@modelcontextprotocol/sdk/client/index.js";
|
|
11406
11424
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
11407
11425
|
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
@@ -11434,9 +11452,9 @@ function convertInputSchema(inputSchema) {
|
|
|
11434
11452
|
}
|
|
11435
11453
|
function persistBinary(base64Data, mimeType, persistId) {
|
|
11436
11454
|
const ext = mimeType?.split("/")[1] || "bin";
|
|
11437
|
-
const dir =
|
|
11455
|
+
const dir = path41.join(process.env.ENGINE_STATE_DIR || ".engine", "mcp-blobs");
|
|
11438
11456
|
fs40.mkdirSync(dir, { recursive: true });
|
|
11439
|
-
const filepath =
|
|
11457
|
+
const filepath = path41.join(dir, `${persistId}.${ext}`);
|
|
11440
11458
|
try {
|
|
11441
11459
|
const buf = Buffer.from(base64Data, "base64");
|
|
11442
11460
|
fs40.writeFileSync(filepath, buf);
|
|
@@ -11773,7 +11791,7 @@ __export(resources_exports, {
|
|
|
11773
11791
|
registerMcpResourceTools: () => registerMcpResourceTools,
|
|
11774
11792
|
unregisterMcpResourceTools: () => unregisterMcpResourceTools
|
|
11775
11793
|
});
|
|
11776
|
-
import * as
|
|
11794
|
+
import * as path42 from "node:path";
|
|
11777
11795
|
function registerMcpResourceTools(manager) {
|
|
11778
11796
|
mcpManagerRef = manager;
|
|
11779
11797
|
registry.register(listResourcesTool);
|
|
@@ -11791,7 +11809,7 @@ var init_resources = __esm({
|
|
|
11791
11809
|
"use strict";
|
|
11792
11810
|
init_registry();
|
|
11793
11811
|
MAX_RESULT_CHARS2 = 1e5;
|
|
11794
|
-
MEDIA_DIR = process.env.ENGINE_MEDIA_DIR ||
|
|
11812
|
+
MEDIA_DIR = process.env.ENGINE_MEDIA_DIR || path42.join(process.env.ENGINE_STATE_DIR || ".engine", "media", "inbound");
|
|
11795
11813
|
MCP_LIST_RESOURCES_TOOL = "mcp__list_resources";
|
|
11796
11814
|
MCP_READ_RESOURCE_TOOL = "mcp__read_resource";
|
|
11797
11815
|
mcpManagerRef = null;
|
|
@@ -11881,11 +11899,21 @@ var everos_sync_exports = {};
|
|
|
11881
11899
|
__export(everos_sync_exports, {
|
|
11882
11900
|
createEverosSync: () => createEverosSync
|
|
11883
11901
|
});
|
|
11902
|
+
function parseMeta(text) {
|
|
11903
|
+
const m2 = text.match(/^\[meta:\s*(.+?)\s*\((.+?)\)\s*@(\S+)\s*[^\]]*\]/);
|
|
11904
|
+
if (!m2) return null;
|
|
11905
|
+
return { senderName: m2[1].trim(), senderId: m2[2].trim(), platform: m2[3].trim() };
|
|
11906
|
+
}
|
|
11884
11907
|
function createEverosSync(cfg) {
|
|
11885
|
-
const { enabled, url, appId, userId } = cfg;
|
|
11908
|
+
const { enabled, url, appId, userId, agentName } = cfg;
|
|
11886
11909
|
async function push(event) {
|
|
11887
11910
|
if (!enabled) return;
|
|
11888
11911
|
if (!event.text.trim()) return;
|
|
11912
|
+
return;
|
|
11913
|
+
const meta = event.role === "user" ? parseMeta(event.text) : null;
|
|
11914
|
+
const senderId = appId;
|
|
11915
|
+
const senderName = meta?.senderName ?? (event.role === "assistant" ? agentName : void 0) ?? event.senderName ?? event.role;
|
|
11916
|
+
console.log(`[everos-sync] role=${event.role} sender_id=${senderId} sender_name=${senderName} metaParsed=${!!meta} textLen=${event.text.length}`);
|
|
11889
11917
|
try {
|
|
11890
11918
|
const resp = await fetch(`${url}/api/v1/memory/add`, {
|
|
11891
11919
|
method: "POST",
|
|
@@ -11895,8 +11923,8 @@ function createEverosSync(cfg) {
|
|
|
11895
11923
|
app_id: appId,
|
|
11896
11924
|
project_id: "default",
|
|
11897
11925
|
messages: [{
|
|
11898
|
-
sender_id:
|
|
11899
|
-
sender_name:
|
|
11926
|
+
sender_id: senderId,
|
|
11927
|
+
sender_name: senderName,
|
|
11900
11928
|
role: event.role,
|
|
11901
11929
|
timestamp: event.timestamp,
|
|
11902
11930
|
content: event.text
|
|
@@ -11920,13 +11948,17 @@ function createEverosSync(cfg) {
|
|
|
11920
11948
|
session_id: events[0].sessionId,
|
|
11921
11949
|
app_id: appId,
|
|
11922
11950
|
project_id: "default",
|
|
11923
|
-
messages: events.map((e) =>
|
|
11924
|
-
|
|
11925
|
-
|
|
11926
|
-
|
|
11927
|
-
|
|
11928
|
-
|
|
11929
|
-
|
|
11951
|
+
messages: events.map((e) => {
|
|
11952
|
+
const meta = e.role === "user" ? parseMeta(e.text) : null;
|
|
11953
|
+
const name = meta?.senderName ?? (e.role === "assistant" ? agentName : void 0) ?? e.senderName ?? e.role;
|
|
11954
|
+
return {
|
|
11955
|
+
sender_id: appId,
|
|
11956
|
+
sender_name: name,
|
|
11957
|
+
role: e.role,
|
|
11958
|
+
timestamp: e.timestamp,
|
|
11959
|
+
content: e.text
|
|
11960
|
+
};
|
|
11961
|
+
})
|
|
11930
11962
|
}),
|
|
11931
11963
|
signal: AbortSignal.timeout(3e4)
|
|
11932
11964
|
});
|
|
@@ -12028,10 +12060,10 @@ function ensureLoaded(workspace, configIds) {
|
|
|
12028
12060
|
if (!state.blockedUserIds.includes(id)) state.blockedUserIds.push(id);
|
|
12029
12061
|
}
|
|
12030
12062
|
}
|
|
12031
|
-
const
|
|
12063
|
+
const path44 = join36(workspace, ".reply-blocklist.json");
|
|
12032
12064
|
try {
|
|
12033
|
-
if (existsSync24(
|
|
12034
|
-
const raw = readFileSync26(
|
|
12065
|
+
if (existsSync24(path44)) {
|
|
12066
|
+
const raw = readFileSync26(path44, "utf-8");
|
|
12035
12067
|
const parsed = JSON.parse(raw);
|
|
12036
12068
|
if (parsed.blockedUserIds) {
|
|
12037
12069
|
for (const id of parsed.blockedUserIds) {
|
|
@@ -12047,9 +12079,9 @@ function ensureLoaded(workspace, configIds) {
|
|
|
12047
12079
|
loaded = true;
|
|
12048
12080
|
}
|
|
12049
12081
|
function save(workspace) {
|
|
12050
|
-
const
|
|
12082
|
+
const path44 = join36(workspace, ".reply-blocklist.json");
|
|
12051
12083
|
try {
|
|
12052
|
-
writeFileSync15(
|
|
12084
|
+
writeFileSync15(path44, JSON.stringify(state, null, 2), "utf-8");
|
|
12053
12085
|
} catch (err) {
|
|
12054
12086
|
console.warn(`[reply-blocklist] Failed to save: ${err.message}`);
|
|
12055
12087
|
}
|
|
@@ -12646,7 +12678,7 @@ var init_cognifold_intent_watcher = __esm({
|
|
|
12646
12678
|
});
|
|
12647
12679
|
|
|
12648
12680
|
// src/engine-startup.ts
|
|
12649
|
-
import * as
|
|
12681
|
+
import * as path43 from "node:path";
|
|
12650
12682
|
import * as fs41 from "node:fs";
|
|
12651
12683
|
import { fileURLToPath } from "node:url";
|
|
12652
12684
|
|
|
@@ -13990,11 +14022,11 @@ var DiscordAdapter = class _DiscordAdapter {
|
|
|
13990
14022
|
/** 发送媒体附件(图片/文件/音频)— discord.js channel.send({ files }) */
|
|
13991
14023
|
async sendFile(target, message, attachment) {
|
|
13992
14024
|
const fs42 = await import("node:fs");
|
|
13993
|
-
const
|
|
14025
|
+
const path44 = await import("node:path");
|
|
13994
14026
|
if (!fs42.existsSync(attachment.path)) {
|
|
13995
14027
|
throw new Error(`File not found: ${attachment.path}`);
|
|
13996
14028
|
}
|
|
13997
|
-
const filename = attachment.filename ||
|
|
14029
|
+
const filename = attachment.filename || path44.basename(attachment.path);
|
|
13998
14030
|
const fileBuffer = fs42.readFileSync(attachment.path);
|
|
13999
14031
|
const filePayload = {
|
|
14000
14032
|
attachment: fileBuffer,
|
|
@@ -14436,11 +14468,11 @@ var FeishuAdapter = class _FeishuAdapter {
|
|
|
14436
14468
|
/** 发送媒体附件(图片/文件) */
|
|
14437
14469
|
async sendFile(target, message, attachment) {
|
|
14438
14470
|
const fs42 = await import("node:fs");
|
|
14439
|
-
const
|
|
14471
|
+
const path44 = await import("node:path");
|
|
14440
14472
|
if (!fs42.existsSync(attachment.path)) {
|
|
14441
14473
|
throw new Error(`File not found: ${attachment.path}`);
|
|
14442
14474
|
}
|
|
14443
|
-
const filename = attachment.filename ||
|
|
14475
|
+
const filename = attachment.filename || path44.basename(attachment.path);
|
|
14444
14476
|
const fileBuffer = fs42.readFileSync(attachment.path);
|
|
14445
14477
|
const receiveIdType = target.startsWith("ou_") ? "open_id" : "chat_id";
|
|
14446
14478
|
const mimeType = attachment.mimeType || "application/octet-stream";
|
|
@@ -18052,22 +18084,8 @@ ${skillsListing}`);
|
|
|
18052
18084
|
parts.push(getEnvInfoSection(options.workspace));
|
|
18053
18085
|
const now = /* @__PURE__ */ new Date();
|
|
18054
18086
|
const dateStr = now.toLocaleString("zh-CN", { timeZone: "Asia/Shanghai" });
|
|
18055
|
-
const osPlatform = process.platform === "win32" ? "Windows" : process.platform === "darwin" ? "macOS" : process.platform;
|
|
18056
|
-
const contextParts = [`\u5F53\u524D\u65F6\u95F4: ${dateStr}`, `\u7CFB\u7EDF: ${osPlatform} (${process.platform})`];
|
|
18057
|
-
const meta = options.inboundMeta;
|
|
18058
|
-
if (meta) {
|
|
18059
|
-
contextParts.push(`\u6765\u6E90: ${meta.channel}`);
|
|
18060
|
-
if (meta.channelType) contextParts.push(`\u6D88\u606F\u7C7B\u578B: ${meta.channelType === "dm" ? "\u79C1\u4FE1" : "\u7FA4\u804A"}`);
|
|
18061
|
-
if (meta.channel_id) contextParts.push(`\u9891\u9053ID: ${meta.channel_id}`);
|
|
18062
|
-
contextParts.push(`\u53D1\u9001\u8005ID: ${meta.from}`);
|
|
18063
|
-
if (meta.fromName) contextParts.push(`\u53D1\u9001\u8005\u540D\u79F0: ${meta.fromName}`);
|
|
18064
|
-
if (meta.messageId) contextParts.push(`\u6D88\u606FID: ${meta.messageId}`);
|
|
18065
|
-
} else if (options.channel) {
|
|
18066
|
-
contextParts.push(`\u6765\u6E90: ${options.channel}`);
|
|
18067
|
-
}
|
|
18068
|
-
if (options.sessionId) contextParts.push(`\u4F1A\u8BDDID: ${options.sessionId}`);
|
|
18069
18087
|
parts.push(`# \u8FD0\u884C\u65F6\u4E0A\u4E0B\u6587
|
|
18070
|
-
${
|
|
18088
|
+
\u5F53\u524D\u65F6\u95F4: ${dateStr}`);
|
|
18071
18089
|
console.log(`[dynamic-prompt] Loaded: ${loaded2.length > 0 ? loaded2.join(", ") : "(none)"}`);
|
|
18072
18090
|
return parts.join("\n\n");
|
|
18073
18091
|
}
|
|
@@ -18369,6 +18387,169 @@ async function findRelevantMemoriesVector(query, memoryDir, alreadySurfaced = /*
|
|
|
18369
18387
|
}));
|
|
18370
18388
|
}
|
|
18371
18389
|
|
|
18390
|
+
// src/memory/memdir/findRelevantMemoriesEveros.ts
|
|
18391
|
+
var ROUND1_TOP_N = 30;
|
|
18392
|
+
var RERANK_BATCH_SIZE = 100;
|
|
18393
|
+
function formatEverosHeader(ep) {
|
|
18394
|
+
const score = ep.score.toFixed(3);
|
|
18395
|
+
const ts = ep.timestamp?.slice(0, 10) ?? "";
|
|
18396
|
+
let ageLabel = "";
|
|
18397
|
+
if (ts) {
|
|
18398
|
+
const days = Math.floor((Date.now() - new Date(ts).getTime()) / 864e5);
|
|
18399
|
+
if (days <= 1) ageLabel = "\u4ECA\u5929";
|
|
18400
|
+
else if (days <= 3) ageLabel = `${days}\u5929\u524D`;
|
|
18401
|
+
else if (days <= 14) ageLabel = `${days}\u5929\u524D`;
|
|
18402
|
+
else if (days <= 30) ageLabel = `~${Math.ceil(days / 7)}\u5468\u524D`;
|
|
18403
|
+
else ageLabel = `~${Math.ceil(days / 30)}\u4E2A\u6708\u524D`;
|
|
18404
|
+
}
|
|
18405
|
+
return `[EverOS score=${score} ${ts} (${ageLabel})]`;
|
|
18406
|
+
}
|
|
18407
|
+
async function hybridSearch(query, everosUrl, userId, topK) {
|
|
18408
|
+
const resp = await fetch(`${everosUrl}/api/v1/memory/search`, {
|
|
18409
|
+
method: "POST",
|
|
18410
|
+
headers: { "Content-Type": "application/json" },
|
|
18411
|
+
body: JSON.stringify({
|
|
18412
|
+
query: query.slice(0, 2e3),
|
|
18413
|
+
user_id: userId,
|
|
18414
|
+
app_id: userId,
|
|
18415
|
+
project_id: "default",
|
|
18416
|
+
top_k: topK,
|
|
18417
|
+
method: "hybrid"
|
|
18418
|
+
}),
|
|
18419
|
+
signal: AbortSignal.timeout(15e3)
|
|
18420
|
+
});
|
|
18421
|
+
if (!resp.ok) {
|
|
18422
|
+
console.warn(`[memdir] everos hybrid: search failed ${resp.status}`);
|
|
18423
|
+
return [];
|
|
18424
|
+
}
|
|
18425
|
+
const body = await resp.json();
|
|
18426
|
+
const episodes = body.data?.episodes ?? [];
|
|
18427
|
+
return episodes;
|
|
18428
|
+
}
|
|
18429
|
+
async function deepinfraRerank(query, episodes, rerankUrl, rerankApiKey, rerankModel, provider) {
|
|
18430
|
+
if (episodes.length === 0) return [];
|
|
18431
|
+
const documents = episodes.map(
|
|
18432
|
+
(ep) => ep.episode?.slice(0, 500) || ep.summary?.slice(0, 500) || ep.subject
|
|
18433
|
+
);
|
|
18434
|
+
const allScores = [];
|
|
18435
|
+
const isDashscope = provider === "dashscope";
|
|
18436
|
+
for (let i = 0; i < documents.length; i += RERANK_BATCH_SIZE) {
|
|
18437
|
+
const batch = documents.slice(i, i + RERANK_BATCH_SIZE);
|
|
18438
|
+
const body = isDashscope ? JSON.stringify({
|
|
18439
|
+
model: rerankModel || "qwen3-rerank",
|
|
18440
|
+
input: { query, documents: batch },
|
|
18441
|
+
parameters: { return_documents: false, top_n: batch.length }
|
|
18442
|
+
}) : JSON.stringify({ queries: [query], documents: batch });
|
|
18443
|
+
const makeRequest = () => fetch(rerankUrl, {
|
|
18444
|
+
method: "POST",
|
|
18445
|
+
headers: {
|
|
18446
|
+
"Authorization": `Bearer ${rerankApiKey}`,
|
|
18447
|
+
"Content-Type": "application/json"
|
|
18448
|
+
},
|
|
18449
|
+
body,
|
|
18450
|
+
signal: AbortSignal.timeout(3e4)
|
|
18451
|
+
});
|
|
18452
|
+
let resp = await makeRequest();
|
|
18453
|
+
if (resp.status === 429) {
|
|
18454
|
+
await new Promise((r) => setTimeout(r, 2e3));
|
|
18455
|
+
resp = await makeRequest();
|
|
18456
|
+
}
|
|
18457
|
+
if (!resp.ok) {
|
|
18458
|
+
console.warn(`[memdir] everos rerank: failed ${resp.status}`);
|
|
18459
|
+
return episodes;
|
|
18460
|
+
}
|
|
18461
|
+
if (isDashscope) {
|
|
18462
|
+
const data = await resp.json();
|
|
18463
|
+
const results = data.output?.results ?? [];
|
|
18464
|
+
const scoreMap = new Array(batch.length).fill(0);
|
|
18465
|
+
for (const r of results) {
|
|
18466
|
+
scoreMap[r.index] = r.relevance_score;
|
|
18467
|
+
}
|
|
18468
|
+
allScores.push(...scoreMap);
|
|
18469
|
+
} else {
|
|
18470
|
+
const data = await resp.json();
|
|
18471
|
+
let batchScores = data.scores ?? [];
|
|
18472
|
+
if (Array.isArray(batchScores) && batchScores.length > 0 && Array.isArray(batchScores[0])) {
|
|
18473
|
+
batchScores = batchScores[0];
|
|
18474
|
+
}
|
|
18475
|
+
allScores.push(...batchScores);
|
|
18476
|
+
}
|
|
18477
|
+
}
|
|
18478
|
+
const ranked = episodes.map((ep, idx) => ({ ep, score: allScores[idx] ?? 0 })).sort((a, b2) => b2.score - a.score);
|
|
18479
|
+
for (const { ep, score } of ranked) {
|
|
18480
|
+
ep.score = score;
|
|
18481
|
+
}
|
|
18482
|
+
return ranked.map((r) => r.ep);
|
|
18483
|
+
}
|
|
18484
|
+
var DEFAULT_MIN_SCORE2 = 0.5;
|
|
18485
|
+
async function findRelevantMemoriesEveros(query, _memoryDir, alreadySurfaced = /* @__PURE__ */ new Set(), options) {
|
|
18486
|
+
const everosUrl = options?.everosUrl ?? "http://127.0.0.1:8100";
|
|
18487
|
+
const userId = options?.userId ?? "xiaomei";
|
|
18488
|
+
const topK = options?.topK ?? 3;
|
|
18489
|
+
const minScore = options?.minScore ?? DEFAULT_MIN_SCORE2;
|
|
18490
|
+
console.log(`[memdir] everos recall: query="${query.slice(0, 50)}..." url=${everosUrl} userId=${userId} topK=${topK}`);
|
|
18491
|
+
const t0 = Date.now();
|
|
18492
|
+
try {
|
|
18493
|
+
const tH1 = Date.now();
|
|
18494
|
+
let episodes = await hybridSearch(query, everosUrl, userId, ROUND1_TOP_N);
|
|
18495
|
+
const tH2 = Date.now();
|
|
18496
|
+
console.log(`[memdir] everos recall: hybrid ${episodes.length} candidates in ${tH2 - tH1}ms`);
|
|
18497
|
+
if (episodes.length === 0) return [];
|
|
18498
|
+
const rerankUrl = options?.rerankUrl;
|
|
18499
|
+
const rerankApiKey = options?.rerankApiKey;
|
|
18500
|
+
if (rerankUrl && rerankApiKey) {
|
|
18501
|
+
const tR1 = Date.now();
|
|
18502
|
+
episodes = await deepinfraRerank(
|
|
18503
|
+
query,
|
|
18504
|
+
episodes,
|
|
18505
|
+
rerankUrl,
|
|
18506
|
+
rerankApiKey,
|
|
18507
|
+
options?.rerankModel,
|
|
18508
|
+
options?.rerankProvider
|
|
18509
|
+
);
|
|
18510
|
+
const tR2 = Date.now();
|
|
18511
|
+
console.log(`[memdir] everos recall: rerank done in ${tR2 - tR1}ms (${options?.rerankProvider || "deepinfra"})`);
|
|
18512
|
+
} else {
|
|
18513
|
+
console.log(`[memdir] everos recall: no rerank key, using hybrid scores as-is`);
|
|
18514
|
+
}
|
|
18515
|
+
const ms = Date.now() - t0;
|
|
18516
|
+
console.log(`[memdir] everos recall: ${episodes.length} episodes in ${ms}ms total (hybrid+rerank)`);
|
|
18517
|
+
const surfacedSubjects = /* @__PURE__ */ new Set();
|
|
18518
|
+
for (const p2 of alreadySurfaced) {
|
|
18519
|
+
if (p2.startsWith("everos://")) {
|
|
18520
|
+
surfacedSubjects.add(p2.slice(8));
|
|
18521
|
+
} else {
|
|
18522
|
+
}
|
|
18523
|
+
}
|
|
18524
|
+
const result = [];
|
|
18525
|
+
const seenSubjects = /* @__PURE__ */ new Set();
|
|
18526
|
+
for (const ep of episodes) {
|
|
18527
|
+
if (ep.score < minScore) continue;
|
|
18528
|
+
const subject = (ep.subject || ep.id).slice(0, 80).replace(/[\n\r]/g, " ");
|
|
18529
|
+
const virtualPath = `everos://${subject}`;
|
|
18530
|
+
if (alreadySurfaced.has(virtualPath)) continue;
|
|
18531
|
+
if (surfacedSubjects.has(subject)) continue;
|
|
18532
|
+
if (seenSubjects.has(subject)) continue;
|
|
18533
|
+
seenSubjects.add(subject);
|
|
18534
|
+
result.push({
|
|
18535
|
+
path: virtualPath,
|
|
18536
|
+
mtimeMs: ep.timestamp ? new Date(ep.timestamp).getTime() : Date.now(),
|
|
18537
|
+
content: `### ${ep.subject}
|
|
18538
|
+
|
|
18539
|
+
${ep.episode || ep.summary}`,
|
|
18540
|
+
header: formatEverosHeader(ep)
|
|
18541
|
+
});
|
|
18542
|
+
if (result.length >= topK) break;
|
|
18543
|
+
}
|
|
18544
|
+
console.log(`[memdir] everos recall: returning ${result.length} memories (after dedup)`);
|
|
18545
|
+
return result;
|
|
18546
|
+
} catch (e) {
|
|
18547
|
+
const ms = Date.now() - t0;
|
|
18548
|
+
console.warn(`[memdir] everos recall: error after ${ms}ms: ${e?.message ?? e}`);
|
|
18549
|
+
return [];
|
|
18550
|
+
}
|
|
18551
|
+
}
|
|
18552
|
+
|
|
18372
18553
|
// src/handle-query.ts
|
|
18373
18554
|
init_paths();
|
|
18374
18555
|
import { readFileSync as readFileSync15, existsSync as existsSync12 } from "node:fs";
|
|
@@ -18441,18 +18622,18 @@ function truncate(s2, maxLen) {
|
|
|
18441
18622
|
}
|
|
18442
18623
|
var externalChanRulesCache = null;
|
|
18443
18624
|
function loadExternalChanRules(workspace) {
|
|
18444
|
-
const
|
|
18445
|
-
if (externalChanRulesCache && externalChanRulesCache.path ===
|
|
18625
|
+
const path44 = join20(workspace, "prompts", "external-chan-rules.md");
|
|
18626
|
+
if (externalChanRulesCache && externalChanRulesCache.path === path44) return externalChanRulesCache;
|
|
18446
18627
|
let content = "";
|
|
18447
|
-
if (existsSync12(
|
|
18628
|
+
if (existsSync12(path44)) {
|
|
18448
18629
|
try {
|
|
18449
|
-
content = readFileSync15(
|
|
18630
|
+
content = readFileSync15(path44, "utf-8").trim();
|
|
18450
18631
|
} catch (e) {
|
|
18451
18632
|
console.warn(`[external-chan-rules] Failed to load: ${e}`);
|
|
18452
18633
|
}
|
|
18453
18634
|
}
|
|
18454
|
-
externalChanRulesCache = { path:
|
|
18455
|
-
console.log(`[external-chan-rules] Loaded ${content.length} chars from ${
|
|
18635
|
+
externalChanRulesCache = { path: path44, content };
|
|
18636
|
+
console.log(`[external-chan-rules] Loaded ${content.length} chars from ${path44}`);
|
|
18456
18637
|
return externalChanRulesCache;
|
|
18457
18638
|
}
|
|
18458
18639
|
function getExternalChanRulesBlock(inboundMeta, workspace) {
|
|
@@ -18475,10 +18656,10 @@ function getExternalChanWhitelist(workspace, configExternalChannels) {
|
|
|
18475
18656
|
if (!externalChanWhitelist) loadContactMap(workspace);
|
|
18476
18657
|
return externalChanWhitelist;
|
|
18477
18658
|
}
|
|
18478
|
-
async function handleQuery(text, sessionId, channelName, cb, deps, channelTarget, inboundMeta, skipRecall) {
|
|
18479
|
-
return handleQueryInner(text, sessionId, channelName, cb, deps, channelTarget, inboundMeta, skipRecall);
|
|
18659
|
+
async function handleQuery(text, sessionId, channelName, cb, deps, channelTarget, inboundMeta, skipRecall, source) {
|
|
18660
|
+
return handleQueryInner(text, sessionId, channelName, cb, deps, channelTarget, inboundMeta, skipRecall, source);
|
|
18480
18661
|
}
|
|
18481
|
-
async function handleQueryInner(text, sessionId, channelName, cb, deps, channelTarget, inboundMeta, skipRecall) {
|
|
18662
|
+
async function handleQueryInner(text, sessionId, channelName, cb, deps, channelTarget, inboundMeta, skipRecall, source) {
|
|
18482
18663
|
const { engine, sessions, channelManager, workspace, providerId, providerApi, model } = deps;
|
|
18483
18664
|
const features = deps.features || {};
|
|
18484
18665
|
const preQueryAbort = new AbortController();
|
|
@@ -18655,6 +18836,8 @@ ${text}` : text });
|
|
|
18655
18836
|
const toolContext = {
|
|
18656
18837
|
sessionId,
|
|
18657
18838
|
channel: channelName === "cli" ? "console" : channelName,
|
|
18839
|
+
source: source || "",
|
|
18840
|
+
// 消息来源(user/inbox/heartbeat/cron/system/inner-voice),Stop hook 用来区分注入 turn
|
|
18658
18841
|
workspace,
|
|
18659
18842
|
stateDir: deps.stateDir || workspace,
|
|
18660
18843
|
channelManager,
|
|
@@ -18829,7 +19012,23 @@ ${text}` : text });
|
|
|
18829
19012
|
const recallP = deps.recallProvider;
|
|
18830
19013
|
const recallMode = deps.topics?.recall?.mode || "llm";
|
|
18831
19014
|
let relevantMemories;
|
|
18832
|
-
if (recallMode === "
|
|
19015
|
+
if (recallMode === "everos") {
|
|
19016
|
+
const everosCfg = deps?.everosCfg;
|
|
19017
|
+
relevantMemories = await findRelevantMemoriesEveros(
|
|
19018
|
+
textForMemory,
|
|
19019
|
+
memoryDir,
|
|
19020
|
+
surfaced.paths,
|
|
19021
|
+
everosCfg ? {
|
|
19022
|
+
everosUrl: everosCfg.everosUrl || "http://127.0.0.1:8100",
|
|
19023
|
+
userId: everosCfg.userId || "xiaomei",
|
|
19024
|
+
rerankUrl: everosCfg.rerank?.baseUrl,
|
|
19025
|
+
rerankApiKey: everosCfg.rerank?.apiKey,
|
|
19026
|
+
rerankModel: everosCfg.rerank?.model,
|
|
19027
|
+
rerankProvider: everosCfg.rerank?.provider,
|
|
19028
|
+
minScore: deps.topics?.recall?.minScore
|
|
19029
|
+
} : void 0
|
|
19030
|
+
);
|
|
19031
|
+
} else if (recallMode === "vector") {
|
|
18833
19032
|
relevantMemories = await findRelevantMemoriesVector(
|
|
18834
19033
|
textForMemory,
|
|
18835
19034
|
memoryDir,
|
|
@@ -18852,8 +19051,8 @@ ${text}` : text });
|
|
|
18852
19051
|
const attachmentMemories = [];
|
|
18853
19052
|
for (const mem of relevantMemories) {
|
|
18854
19053
|
try {
|
|
18855
|
-
const content = readFileSync15(mem.path, "utf-8");
|
|
18856
|
-
const header = memoryHeader(mem.path, mem.mtimeMs);
|
|
19054
|
+
const content = mem.content ?? readFileSync15(mem.path, "utf-8");
|
|
19055
|
+
const header = mem.header ?? memoryHeader(mem.path, mem.mtimeMs);
|
|
18857
19056
|
attachmentMemories.push({ path: mem.path, content, mtimeMs: mem.mtimeMs, header });
|
|
18858
19057
|
} catch {
|
|
18859
19058
|
}
|
|
@@ -19401,7 +19600,9 @@ function registerCognifoldBridge(config) {
|
|
|
19401
19600
|
messageId: ctx.inbound.messageId
|
|
19402
19601
|
}
|
|
19403
19602
|
};
|
|
19404
|
-
|
|
19603
|
+
const sm = globalThis.__cognifoldSessions;
|
|
19604
|
+
const dynamicSessionId = sm?.getSessionId?.("main") || cognifoldConfig.sessionId;
|
|
19605
|
+
void enqueueEvent(dynamicSessionId, event);
|
|
19405
19606
|
return null;
|
|
19406
19607
|
}, 80);
|
|
19407
19608
|
}
|
|
@@ -19725,7 +19926,8 @@ var MessageDispatcher = class {
|
|
|
19725
19926
|
msg2.deps,
|
|
19726
19927
|
msg2.channelTarget,
|
|
19727
19928
|
msg2.inboundMeta,
|
|
19728
|
-
msg2.skipRecall
|
|
19929
|
+
msg2.skipRecall,
|
|
19930
|
+
msg2.source
|
|
19729
19931
|
);
|
|
19730
19932
|
} catch (err) {
|
|
19731
19933
|
console.error(`[dispatcher] Query error (session=${msg2.sessionId}): ${err.message}`);
|
|
@@ -19885,13 +20087,19 @@ function startCliLoop(deps, cliConfig, channelManager, dispatcher) {
|
|
|
19885
20087
|
|
|
19886
20088
|
// src/session/session-history.ts
|
|
19887
20089
|
import fs14 from "node:fs";
|
|
20090
|
+
import path14 from "node:path";
|
|
19888
20091
|
var BEIJING_OFFSET_MS = 8 * 36e5;
|
|
19889
20092
|
var INJECTED_CONTENT_PATTERNS = [
|
|
19890
20093
|
/【定时心跳】/,
|
|
19891
20094
|
/\[内心对话测试\]/,
|
|
19892
20095
|
/\[inner-voice\]/,
|
|
19893
20096
|
/\[微信巡检\]/,
|
|
19894
|
-
/\[plugin\]
|
|
20097
|
+
/\[plugin\]/,
|
|
20098
|
+
/<nudge-notification>/,
|
|
20099
|
+
/<task-notification>/,
|
|
20100
|
+
/<calendar-notification>/,
|
|
20101
|
+
/## Actions \(\d+\s*个\)/
|
|
20102
|
+
// CogniFold proactive 注入(block[0] 固定格式,engine-startup 拼的)
|
|
19895
20103
|
];
|
|
19896
20104
|
function parseJsonlEntries(lines) {
|
|
19897
20105
|
const entries = [];
|
|
@@ -19926,6 +20134,20 @@ function resolveScopeMainJsonl(sessions) {
|
|
|
19926
20134
|
if (!sessionId) return null;
|
|
19927
20135
|
return sessions.getSessionFilePath(sessionId);
|
|
19928
20136
|
}
|
|
20137
|
+
function scopeMainJsonlPaths(sessions) {
|
|
20138
|
+
const current = resolveScopeMainJsonl(sessions);
|
|
20139
|
+
let latestArchive = null;
|
|
20140
|
+
if (current) {
|
|
20141
|
+
try {
|
|
20142
|
+
const dir = path14.dirname(current);
|
|
20143
|
+
const base = path14.basename(current);
|
|
20144
|
+
const archives = fs14.readdirSync(dir).filter((f2) => f2.startsWith(base + ".archived.")).sort();
|
|
20145
|
+
if (archives.length > 0) latestArchive = path14.join(dir, archives[archives.length - 1]);
|
|
20146
|
+
} catch {
|
|
20147
|
+
}
|
|
20148
|
+
}
|
|
20149
|
+
return { current, latestArchive };
|
|
20150
|
+
}
|
|
19929
20151
|
function cleanText(rawText) {
|
|
19930
20152
|
let clean = rawText.replace(/<system-reminder>.*?<\/system-reminder>/gs, "").replace(/(?:Sender|Conversation info|Replied message) \(untrusted[^)]*\):\s*```json\s*\{[^}]*\}\s*```/g, "").replace(/\[\w{3} \d{4}-\d{2}-\d{2} \d{2}:\d{2}(?::\d{2})? GMT[+-]\d+\]/g, "").replace(/\[message_id:\s*\S+\]/g, "").replace(/\[\[reply_to_current\]\]/g, "").replace(/\[\[reply_to:\S+\]\]/g, "").replace(/<@\d+>/g, "").replace(/^System:.*$/gm, "").replace(/Reply target.*?```json\s*\{[^}]*\}\s*```/gs, "").replace(/\[media attached:.*?\]/g, "[\u56FE\u7247]");
|
|
19931
20153
|
return clean.trim();
|
|
@@ -20016,6 +20238,7 @@ function recentMessages(sessions, hours = 12, limit = 60) {
|
|
|
20016
20238
|
time: `${p2(bj.getHours())}:${p2(bj.getMinutes())}`,
|
|
20017
20239
|
role,
|
|
20018
20240
|
text: clean.slice(0, 80),
|
|
20241
|
+
timestamp: dtMs,
|
|
20019
20242
|
_utc: dtMs
|
|
20020
20243
|
});
|
|
20021
20244
|
}
|
|
@@ -20147,6 +20370,8 @@ ${basePrompt}`;
|
|
|
20147
20370
|
channelName: "heartbeat",
|
|
20148
20371
|
source: "heartbeat",
|
|
20149
20372
|
priority: "later",
|
|
20373
|
+
skipRecall: true,
|
|
20374
|
+
// 心跳不需要记忆召回,避免重复注入心跳相关记忆
|
|
20150
20375
|
callbacks: {
|
|
20151
20376
|
onResult: () => resolveDone()
|
|
20152
20377
|
},
|
|
@@ -20164,7 +20389,7 @@ ${basePrompt}`;
|
|
|
20164
20389
|
|
|
20165
20390
|
// src/nudge/plugin.ts
|
|
20166
20391
|
import fs17 from "node:fs";
|
|
20167
|
-
import
|
|
20392
|
+
import path17 from "node:path";
|
|
20168
20393
|
|
|
20169
20394
|
// src/nudge/judge.ts
|
|
20170
20395
|
function shouldNudge(task, taskState, cfg) {
|
|
@@ -20333,10 +20558,10 @@ function formatDuration2(ms) {
|
|
|
20333
20558
|
|
|
20334
20559
|
// src/nudge/session-state-reader.ts
|
|
20335
20560
|
import fs15 from "node:fs";
|
|
20336
|
-
import
|
|
20561
|
+
import path15 from "node:path";
|
|
20337
20562
|
function parseSessionStateFull(workspace, sessionStateFile) {
|
|
20338
20563
|
const stateFile = sessionStateFile || "SESSION-STATE.md";
|
|
20339
|
-
const statePath =
|
|
20564
|
+
const statePath = path15.isAbsolute(stateFile) ? stateFile : path15.join(workspace, stateFile);
|
|
20340
20565
|
let content;
|
|
20341
20566
|
try {
|
|
20342
20567
|
content = fs15.readFileSync(statePath, "utf-8");
|
|
@@ -20391,13 +20616,13 @@ function taskIdFromTitle(title) {
|
|
|
20391
20616
|
|
|
20392
20617
|
// src/calendar/db.ts
|
|
20393
20618
|
import { DatabaseSync } from "node:sqlite";
|
|
20394
|
-
import * as
|
|
20619
|
+
import * as path16 from "node:path";
|
|
20395
20620
|
import * as fs16 from "node:fs";
|
|
20396
20621
|
var TZ_OFFSET_MS = 8 * 60 * 60 * 1e3;
|
|
20397
20622
|
function openDb(workspace) {
|
|
20398
|
-
const dir =
|
|
20623
|
+
const dir = path16.join(workspace, ".calendar");
|
|
20399
20624
|
fs16.mkdirSync(dir, { recursive: true });
|
|
20400
|
-
const dbPath =
|
|
20625
|
+
const dbPath = path16.join(dir, "calendar.db");
|
|
20401
20626
|
const db = new DatabaseSync(dbPath);
|
|
20402
20627
|
db.exec("PRAGMA journal_mode=WAL");
|
|
20403
20628
|
db.exec(`CREATE TABLE IF NOT EXISTS events (
|
|
@@ -20486,7 +20711,7 @@ var NudgePlugin = class {
|
|
|
20486
20711
|
provider;
|
|
20487
20712
|
model;
|
|
20488
20713
|
loadPrompt(workspace, promptFile) {
|
|
20489
|
-
const promptPath = promptFile ?
|
|
20714
|
+
const promptPath = promptFile ? path17.isAbsolute(promptFile) ? promptFile : path17.join(workspace, promptFile) : path17.join(workspace, "prompts", "nudge-prompt.md");
|
|
20490
20715
|
try {
|
|
20491
20716
|
const content = fs17.readFileSync(promptPath, "utf-8").trim();
|
|
20492
20717
|
if (content) {
|
|
@@ -20523,11 +20748,20 @@ var NudgePlugin = class {
|
|
|
20523
20748
|
const lastMsg = input?.last_assistant_message || "";
|
|
20524
20749
|
const sessionId = input?.session_id || "";
|
|
20525
20750
|
console.log(`[stop-hook] lastMsg len=${lastMsg.length}, text="${lastMsg.slice(0, 80)}"`);
|
|
20751
|
+
const repliedIds = this.extractWakeReplyIds(lastMsg);
|
|
20752
|
+
if (repliedIds.length > 0) {
|
|
20753
|
+
this.removeNotificationsById(repliedIds);
|
|
20754
|
+
}
|
|
20526
20755
|
const msgChannel = input?.channel || "";
|
|
20527
20756
|
if (sessionId.includes("voice-chat") || msgChannel === "voice-chat") {
|
|
20528
20757
|
console.log(`[stop-hook] skipping voice-chat (channel=${msgChannel})`);
|
|
20529
20758
|
return { outcome: { outcome: "success" } };
|
|
20530
20759
|
}
|
|
20760
|
+
const msgSource = input?.source || "";
|
|
20761
|
+
if (msgSource && msgSource !== "user" && msgSource !== "inbox") {
|
|
20762
|
+
console.log(`[stop-hook] skipping non-conversation turn (source=${msgSource})`);
|
|
20763
|
+
return { outcome: { outcome: "success" } };
|
|
20764
|
+
}
|
|
20531
20765
|
if (!lastMsg) {
|
|
20532
20766
|
return { outcome: { outcome: "success" } };
|
|
20533
20767
|
}
|
|
@@ -20600,8 +20834,8 @@ var NudgePlugin = class {
|
|
|
20600
20834
|
if (pushedDecision && waitDesc) {
|
|
20601
20835
|
console.log(`[stop-hook] DETECTED pushedDecision! Injecting corrective message to ${sessionId}`);
|
|
20602
20836
|
try {
|
|
20603
|
-
const correctiveMsg = [
|
|
20604
|
-
"
|
|
20837
|
+
const correctiveMsg = buildNudgeNotification("prompt", [
|
|
20838
|
+
"[stop-hook \u81EA\u4E3B\u6267\u884C\u7EA0\u6B63] \u4F60\u521A\u624D\u628A\u4E00\u4E2A\u81EA\u5DF1\u80FD\u5B9A\u7684\u51B3\u5B9A\u63A8\u7ED9\u4E86\u5BF9\u65B9\u3002",
|
|
20605
20839
|
"",
|
|
20606
20840
|
`\u8BCA\u65AD\uFF1A${waitDesc}`,
|
|
20607
20841
|
"",
|
|
@@ -20614,9 +20848,10 @@ var NudgePlugin = class {
|
|
|
20614
20848
|
'3. \u6267\u884C\u5B8C\u6C47\u62A5\u7ED3\u679C\uFF08"\u5DF2\u5904\u7406" / "\u5DF2 commit" / "\u5DF2 archive"\uFF09',
|
|
20615
20849
|
"",
|
|
20616
20850
|
"\u5982\u679C\u4E0D\u662F\u5FC5\u987B\u95EE\u7684\uFF08\u6D89\u53CA\u82B1\u94B1/\u5BF9\u5916\u53D1\u5E03/\u91CD\u5927\u51B3\u7B56\uFF09\uFF0C\u4E0D\u8981\u95EE\u3002"
|
|
20617
|
-
].join("\n");
|
|
20618
|
-
|
|
20619
|
-
|
|
20851
|
+
].join("\n"));
|
|
20852
|
+
const route = this.getRoute(sessions);
|
|
20853
|
+
if (route) {
|
|
20854
|
+
enqueueNotification(correctiveMsg, route);
|
|
20620
20855
|
}
|
|
20621
20856
|
} catch (e) {
|
|
20622
20857
|
console.warn(`[stop-hook] Failed to inject corrective message: ${e.message}`);
|
|
@@ -20625,14 +20860,21 @@ var NudgePlugin = class {
|
|
|
20625
20860
|
if (!isWaiting) {
|
|
20626
20861
|
return { outcome: { outcome: "success" } };
|
|
20627
20862
|
}
|
|
20628
|
-
const nudgeDir =
|
|
20629
|
-
const notifPath =
|
|
20863
|
+
const nudgeDir = path17.join(this.workspace, ".nudge");
|
|
20864
|
+
const notifPath = path17.join(nudgeDir, "stop-hook-notifications.json");
|
|
20630
20865
|
try {
|
|
20631
20866
|
if (!fs17.existsSync(nudgeDir)) fs17.mkdirSync(nudgeDir, { recursive: true });
|
|
20632
20867
|
let notifs = [];
|
|
20633
20868
|
if (fs17.existsSync(notifPath)) {
|
|
20634
20869
|
notifs = JSON.parse(fs17.readFileSync(notifPath, "utf-8"));
|
|
20635
20870
|
const now = Date.now();
|
|
20871
|
+
const dup = notifs.find((n) => !n.notified && n.description === (waitDesc || lastMsg.slice(0, 200)));
|
|
20872
|
+
if (dup) {
|
|
20873
|
+
dup.wakeAt = new Date(now + 5 * 6e4).toISOString();
|
|
20874
|
+
fs17.writeFileSync(notifPath, JSON.stringify(notifs, null, 2));
|
|
20875
|
+
console.log(`[stop-hook] Duplicate wait (same desc, not fired yet), refreshed wakeAt: ${dup.id}`);
|
|
20876
|
+
return { outcome: { outcome: "success" } };
|
|
20877
|
+
}
|
|
20636
20878
|
const recentReg = notifs.find((n) => now - new Date(n.createdAt).getTime() < 3 * 6e4);
|
|
20637
20879
|
if (recentReg) {
|
|
20638
20880
|
console.log(`[stop-hook] Skip (recent registration within 3min)`);
|
|
@@ -20681,9 +20923,14 @@ var NudgePlugin = class {
|
|
|
20681
20923
|
return null;
|
|
20682
20924
|
}
|
|
20683
20925
|
}
|
|
20684
|
-
/**
|
|
20685
|
-
|
|
20686
|
-
|
|
20926
|
+
/**
|
|
20927
|
+
* 收集到期的 stop-hook notifications,批量构建一条 wake 消息。
|
|
20928
|
+
* 不标 notified——投递成功后由 tick 调 markNotified 标(route 拿不到时保留原样下个 tick 重试,
|
|
20929
|
+
* 避免"消息没投出去但已标 notified"的死账)。
|
|
20930
|
+
* 已 notified 的不会再触发,等 agent 回复 "<id> 过期了" 由 cleanup 删。
|
|
20931
|
+
*/
|
|
20932
|
+
collectDueStopHookNotifications() {
|
|
20933
|
+
const notifPath = path17.join(this.workspace, ".nudge", "stop-hook-notifications.json");
|
|
20687
20934
|
try {
|
|
20688
20935
|
if (!fs17.existsSync(notifPath)) return null;
|
|
20689
20936
|
const notifs = JSON.parse(fs17.readFileSync(notifPath, "utf-8"));
|
|
@@ -20691,54 +20938,161 @@ var NudgePlugin = class {
|
|
|
20691
20938
|
const now = Date.now();
|
|
20692
20939
|
const due = notifs.filter((n) => new Date(n.wakeAt).getTime() <= now && !n.notified);
|
|
20693
20940
|
if (due.length === 0) return null;
|
|
20694
|
-
|
|
20695
|
-
|
|
20696
|
-
|
|
20697
|
-
|
|
20698
|
-
|
|
20941
|
+
console.log(`[nudge] ${due.length} stop-hook notification(s) due: ${due.map((n) => n.id).join(", ")}`);
|
|
20942
|
+
const items = due.map((n) => `[\u901A\u77E5ID: ${n.id}]
|
|
20943
|
+
\u4E0A\u6B21\u8BF4\uFF1A${n.description}`).join("\n\n");
|
|
20944
|
+
const desc = due.length === 1 ? `\u4F60\u4E4B\u524D\u5728\u7B49\u5F85\u67D0\u4E2A\u5916\u90E8\u6761\u4EF6\uFF0C\u65F6\u95F4\u5230\u4E86\uFF0C\u56DE\u53BB\u68C0\u67E5\uFF01
|
|
20945
|
+
|
|
20946
|
+
${items}
|
|
20699
20947
|
|
|
20700
|
-
[\
|
|
20701
|
-
\u4E0A\u6B21\u8BF4\uFF1A${latest.description}
|
|
20948
|
+
\u68C0\u67E5\u6761\u4EF6\u662F\u5426\u6EE1\u8DB3\uFF0C\u6EE1\u8DB3\u5C31\u7EE7\u7EED\u5E72\u6D3B\uFF0C\u4E0D\u6EE1\u8DB3\u5C31\u56DE\u590D"${due[0].id} \u8FC7\u671F\u4E86"\u544A\u8BC9 nudge \u7CBE\u786E\u6E05\u7406\u8FD9\u6761\u3002` : `\u4F60\u4E4B\u524D\u6709 ${due.length} \u4E2A\u7B49\u5F85\u4E2D\u7684\u5916\u90E8\u6761\u4EF6\u90FD\u5230\u671F\u4E86\uFF0C\u56DE\u53BB\u9010\u4E2A\u68C0\u67E5\uFF01
|
|
20702
20949
|
|
|
20703
|
-
|
|
20950
|
+
${items}
|
|
20951
|
+
|
|
20952
|
+
\u5BF9\u6BCF\u4E00\u6761\uFF1A\u6761\u4EF6\u6EE1\u8DB3\u5C31\u7EE7\u7EED\u5E72\u6D3B\uFF0C\u4E0D\u6EE1\u8DB3\u5C31\u56DE\u590D\u5BF9\u5E94\u7684"<\u901A\u77E5ID> \u8FC7\u671F\u4E86"\u544A\u8BC9 nudge \u7CBE\u786E\u6E05\u7406\u3002`;
|
|
20953
|
+
return { message: buildNudgeNotification("wake", desc), ids: due.map((n) => n.id) };
|
|
20704
20954
|
} catch (e) {
|
|
20705
|
-
console.warn(`[nudge]
|
|
20955
|
+
console.warn(`[nudge] collectDueStopHookNotifications error: ${e.message}`);
|
|
20706
20956
|
return null;
|
|
20707
20957
|
}
|
|
20708
20958
|
}
|
|
20709
|
-
/**
|
|
20959
|
+
/** 从回复文本里提取 "<id> 过期了" 的 wake id(一条回复可能处置多个) */
|
|
20960
|
+
extractWakeReplyIds(text) {
|
|
20961
|
+
if (!text) return [];
|
|
20962
|
+
const ids = [];
|
|
20963
|
+
const re = /(wake-\d+-[a-z0-9]+)\s*过期了/g;
|
|
20964
|
+
let m2;
|
|
20965
|
+
while ((m2 = re.exec(text)) !== null) {
|
|
20966
|
+
if (!ids.includes(m2[1])) ids.push(m2[1]);
|
|
20967
|
+
}
|
|
20968
|
+
return ids;
|
|
20969
|
+
}
|
|
20970
|
+
/** 按 id 删除条目(stop-hook 实时清理用;正常删除路径,agent 回复即删) */
|
|
20971
|
+
removeNotificationsById(ids) {
|
|
20972
|
+
const notifPath = path17.join(this.workspace, ".nudge", "stop-hook-notifications.json");
|
|
20973
|
+
try {
|
|
20974
|
+
if (!fs17.existsSync(notifPath)) return;
|
|
20975
|
+
const notifs = JSON.parse(fs17.readFileSync(notifPath, "utf-8"));
|
|
20976
|
+
const idSet = new Set(ids);
|
|
20977
|
+
const remaining = notifs.filter((n) => !idSet.has(n.id));
|
|
20978
|
+
const removed = notifs.length - remaining.length;
|
|
20979
|
+
if (removed === 0) return;
|
|
20980
|
+
if (remaining.length > 0) {
|
|
20981
|
+
fs17.writeFileSync(notifPath, JSON.stringify(remaining, null, 2));
|
|
20982
|
+
} else {
|
|
20983
|
+
fs17.unlinkSync(notifPath);
|
|
20984
|
+
}
|
|
20985
|
+
console.log(`[stop-hook] Cleaned ${removed} notification(s) from reply: ${ids.join(", ")}`);
|
|
20986
|
+
} catch (e) {
|
|
20987
|
+
console.warn(`[stop-hook] removeNotificationsById error: ${e.message}`);
|
|
20988
|
+
}
|
|
20989
|
+
}
|
|
20990
|
+
/** 投递成功后标记 notified(防重复触发);不删除——删除只走 agent 回复 "<id> 过期了" */
|
|
20991
|
+
markNotified(ids) {
|
|
20992
|
+
const notifPath = path17.join(this.workspace, ".nudge", "stop-hook-notifications.json");
|
|
20993
|
+
try {
|
|
20994
|
+
if (!fs17.existsSync(notifPath)) return;
|
|
20995
|
+
const notifs = JSON.parse(fs17.readFileSync(notifPath, "utf-8"));
|
|
20996
|
+
const idSet = new Set(ids);
|
|
20997
|
+
const updated = notifs.map((n) => idSet.has(n.id) ? { ...n, notified: true } : n);
|
|
20998
|
+
fs17.writeFileSync(notifPath, JSON.stringify(updated, null, 2));
|
|
20999
|
+
} catch (e) {
|
|
21000
|
+
console.warn(`[nudge] markNotified error: ${e.message}`);
|
|
21001
|
+
}
|
|
21002
|
+
}
|
|
21003
|
+
/**
|
|
21004
|
+
* tick 兜底清理。正常删除走 stop-hook 实时路径(agent 回复 "<id> 过期了" 当 turn 就删,
|
|
21005
|
+
* 见 registerStopHook 第 0 步),这里只接两种漏网:
|
|
21006
|
+
* ① 回复已落盘但 stop-hook 没来得及执行(进程中途崩等边缘情况)→ 扫 jsonl 补删;
|
|
21007
|
+
* ② TTL 清道夫:wakeAt 超过 cleanupTtlHours(默认 24h)仍无回复 → 回复永远来不了,删。
|
|
21008
|
+
*
|
|
21009
|
+
* 扫描不走 recentMessages()——它截断 80 字符、会过滤"对注入消息的回复"(wake 回复恰好
|
|
21010
|
+
* 被过滤掉)、限 20 条窗口。直接读 jsonl 原始条目:倒序扫、扫过最老 pending 的 wakeAt
|
|
21011
|
+
* 即停、全命中提前退、archive 只在 current 被 2MB 轮转切断时才读。
|
|
21012
|
+
*/
|
|
20710
21013
|
cleanupStaleNotificationsFromMessages(sessions) {
|
|
20711
21014
|
try {
|
|
20712
|
-
const
|
|
20713
|
-
const fiveMinAgo = Date.now() - 5 * 60 * 1e3;
|
|
20714
|
-
const recentTexts = recent.filter((r) => new Date(r.timestamp || r.createdAt || Date.now()).getTime() > fiveMinAgo).map((r) => r.text);
|
|
20715
|
-
const notifPath = path16.join(this.workspace, ".nudge", "stop-hook-notifications.json");
|
|
21015
|
+
const notifPath = path17.join(this.workspace, ".nudge", "stop-hook-notifications.json");
|
|
20716
21016
|
if (!fs17.existsSync(notifPath)) return;
|
|
20717
21017
|
const notifs = JSON.parse(fs17.readFileSync(notifPath, "utf-8"));
|
|
20718
21018
|
if (notifs.length === 0) return;
|
|
20719
|
-
const expiredIds =
|
|
20720
|
-
|
|
20721
|
-
|
|
20722
|
-
|
|
20723
|
-
|
|
20724
|
-
|
|
20725
|
-
|
|
21019
|
+
const expiredIds = this.findExpiredReplyIds(sessions, notifs);
|
|
21020
|
+
const ttlMs = (this.cfg.cleanupTtlHours || 24) * 36e5;
|
|
21021
|
+
const now = Date.now();
|
|
21022
|
+
const ttlIds = new Set(
|
|
21023
|
+
notifs.filter((n) => now - new Date(n.wakeAt).getTime() > ttlMs && !expiredIds.has(n.id)).map((n) => n.id)
|
|
21024
|
+
);
|
|
21025
|
+
const removeIds = /* @__PURE__ */ new Set([...expiredIds, ...ttlIds]);
|
|
21026
|
+
if (removeIds.size === 0) return;
|
|
21027
|
+
const remaining = notifs.filter((n) => !removeIds.has(n.id));
|
|
21028
|
+
if (remaining.length > 0) {
|
|
21029
|
+
fs17.writeFileSync(notifPath, JSON.stringify(remaining, null, 2));
|
|
21030
|
+
} else {
|
|
21031
|
+
fs17.unlinkSync(notifPath);
|
|
20726
21032
|
}
|
|
20727
|
-
if (expiredIds.size
|
|
20728
|
-
|
|
20729
|
-
|
|
20730
|
-
if (
|
|
20731
|
-
|
|
20732
|
-
fs17.writeFileSync(notifPath, JSON.stringify(remaining, null, 2));
|
|
20733
|
-
} else {
|
|
20734
|
-
fs17.unlinkSync(notifPath);
|
|
20735
|
-
}
|
|
20736
|
-
console.log(`[nudge] Cleaned ${cleaned} stale notification(s) by explicit id: ${[...expiredIds].join(", ")}`);
|
|
21033
|
+
if (expiredIds.size > 0) {
|
|
21034
|
+
console.log(`[nudge] Cleaned ${expiredIds.size} notification(s) by reply: ${[...expiredIds].join(", ")}`);
|
|
21035
|
+
}
|
|
21036
|
+
if (ttlIds.size > 0) {
|
|
21037
|
+
console.log(`[nudge] Cleaned ${ttlIds.size} zombie notification(s) by TTL (>${this.cfg.cleanupTtlHours || 24}h no reply): ${[...ttlIds].join(", ")}`);
|
|
20737
21038
|
}
|
|
20738
21039
|
} catch (e) {
|
|
20739
21040
|
console.warn(`[nudge] cleanupStaleNotificationsFromMessages error: ${e.message}`);
|
|
20740
21041
|
}
|
|
20741
21042
|
}
|
|
21043
|
+
/**
|
|
21044
|
+
* 扫 "<id> 过期了" 回复,返回匹配到的 id 集合。
|
|
21045
|
+
* 不做全文扫描:倒序扫(回复紧跟在 fire 之后,通常就在尾部几条);
|
|
21046
|
+
* 扫过最老 pending 条目的 wakeAt 就停(回复不可能早于触发时间);
|
|
21047
|
+
* 全部命中提前退出;archive 只在 current 没覆盖时间范围(被 2MB 轮转切断)时才读。
|
|
21048
|
+
* 典型开销:解析几十条而不是上千条。
|
|
21049
|
+
*/
|
|
21050
|
+
findExpiredReplyIds(sessions, notifs) {
|
|
21051
|
+
const found = /* @__PURE__ */ new Set();
|
|
21052
|
+
if (notifs.length === 0) return found;
|
|
21053
|
+
const oldestMs = Math.min(...notifs.map((n) => new Date(n.wakeAt).getTime()));
|
|
21054
|
+
const { current, latestArchive } = scopeMainJsonlPaths(sessions);
|
|
21055
|
+
for (const file of [current, latestArchive]) {
|
|
21056
|
+
if (!file || !fs17.existsSync(file)) continue;
|
|
21057
|
+
let lines;
|
|
21058
|
+
try {
|
|
21059
|
+
lines = fs17.readFileSync(file, "utf-8").split("\n");
|
|
21060
|
+
} catch (e) {
|
|
21061
|
+
console.warn(`[nudge] findExpiredReplyIds read error on ${file}: ${e.message}`);
|
|
21062
|
+
continue;
|
|
21063
|
+
}
|
|
21064
|
+
let coveredOldest = false;
|
|
21065
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
21066
|
+
const trimmed = lines[i].trim();
|
|
21067
|
+
if (!trimmed) continue;
|
|
21068
|
+
let entry;
|
|
21069
|
+
try {
|
|
21070
|
+
entry = JSON.parse(trimmed);
|
|
21071
|
+
} catch {
|
|
21072
|
+
continue;
|
|
21073
|
+
}
|
|
21074
|
+
const tsMs = entry?.timestamp ? new Date(entry.timestamp).getTime() : 0;
|
|
21075
|
+
if (tsMs > 0 && tsMs < oldestMs) {
|
|
21076
|
+
coveredOldest = true;
|
|
21077
|
+
break;
|
|
21078
|
+
}
|
|
21079
|
+
if (entry?.type !== "message") continue;
|
|
21080
|
+
const msg2 = entry.message;
|
|
21081
|
+
if (!msg2 || msg2.role !== "assistant") continue;
|
|
21082
|
+
const content = msg2.content;
|
|
21083
|
+
const text = typeof content === "string" ? content : Array.isArray(content) && content[0] && typeof content[0].text === "string" ? content[0].text : "";
|
|
21084
|
+
if (!text) continue;
|
|
21085
|
+
for (const n of notifs) {
|
|
21086
|
+
if (!found.has(n.id) && (text.includes(`${n.id} \u8FC7\u671F\u4E86`) || text.includes(`${n.id}\u8FC7\u671F\u4E86`))) {
|
|
21087
|
+
found.add(n.id);
|
|
21088
|
+
}
|
|
21089
|
+
}
|
|
21090
|
+
if (found.size === notifs.length) return found;
|
|
21091
|
+
}
|
|
21092
|
+
if (coveredOldest) break;
|
|
21093
|
+
}
|
|
21094
|
+
return found;
|
|
21095
|
+
}
|
|
20742
21096
|
async tick(sessions, deps) {
|
|
20743
21097
|
if (this.running) {
|
|
20744
21098
|
console.log("[nudge] Previous tick still running, skipping");
|
|
@@ -20753,7 +21107,7 @@ var NudgePlugin = class {
|
|
|
20753
21107
|
const recent = recentMessages(sessions, 0.5, 6);
|
|
20754
21108
|
const lastUserMsg2 = recent.filter((r) => r.role === "user").slice(-1)[0];
|
|
20755
21109
|
if (lastUserMsg2) {
|
|
20756
|
-
const elapsed = Date.now() -
|
|
21110
|
+
const elapsed = lastUserMsg2.timestamp ? Date.now() - lastUserMsg2.timestamp : 0;
|
|
20757
21111
|
if (elapsed < activeThresholdMs) {
|
|
20758
21112
|
console.log(`[nudge] User active ${Math.round(elapsed / 1e3)}s ago (<${activeThresholdMs / 1e3}s), skipping tick`);
|
|
20759
21113
|
return;
|
|
@@ -20765,10 +21119,15 @@ var NudgePlugin = class {
|
|
|
20765
21119
|
this.running = true;
|
|
20766
21120
|
try {
|
|
20767
21121
|
this.cleanupStaleNotificationsFromMessages(sessions);
|
|
20768
|
-
const
|
|
20769
|
-
if (
|
|
21122
|
+
const dueNotifs = this.collectDueStopHookNotifications();
|
|
21123
|
+
if (dueNotifs) {
|
|
20770
21124
|
const route2 = this.getRoute(sessions);
|
|
20771
|
-
if (route2)
|
|
21125
|
+
if (route2) {
|
|
21126
|
+
enqueueNotification(dueNotifs.message, route2);
|
|
21127
|
+
this.markNotified(dueNotifs.ids);
|
|
21128
|
+
} else {
|
|
21129
|
+
console.warn(`[nudge] No route for ${dueNotifs.ids.length} stop-hook notification(s), keeping for retry next tick`);
|
|
21130
|
+
}
|
|
20772
21131
|
const state0 = this.loadState();
|
|
20773
21132
|
state0.lastAnyNudgeAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
20774
21133
|
this.saveState(state0);
|
|
@@ -20954,7 +21313,7 @@ var NudgePlugin = class {
|
|
|
20954
21313
|
// === state 持久化 ===
|
|
20955
21314
|
loadState() {
|
|
20956
21315
|
const stateFile = this.cfg.stateFile || "nudge-state.json";
|
|
20957
|
-
const statePath =
|
|
21316
|
+
const statePath = path17.isAbsolute(stateFile) ? stateFile : path17.join(this.workspace, stateFile);
|
|
20958
21317
|
try {
|
|
20959
21318
|
const content = fs17.readFileSync(statePath, "utf-8");
|
|
20960
21319
|
return JSON.parse(content);
|
|
@@ -20964,7 +21323,7 @@ var NudgePlugin = class {
|
|
|
20964
21323
|
}
|
|
20965
21324
|
saveState(state2) {
|
|
20966
21325
|
const stateFile = this.cfg.stateFile || "nudge-state.json";
|
|
20967
|
-
const statePath =
|
|
21326
|
+
const statePath = path17.isAbsolute(stateFile) ? stateFile : path17.join(this.workspace, stateFile);
|
|
20968
21327
|
fs17.writeFileSync(statePath, JSON.stringify(state2, null, 2), "utf-8");
|
|
20969
21328
|
}
|
|
20970
21329
|
newTaskState() {
|
|
@@ -21050,30 +21409,47 @@ var NudgePlugin = class {
|
|
|
21050
21409
|
const now = /* @__PURE__ */ new Date();
|
|
21051
21410
|
const bjOffset = (8 * 60 + now.getTimezoneOffset()) * 6e4;
|
|
21052
21411
|
const bj = new Date(now.getTime() + bjOffset);
|
|
21053
|
-
const month = bj.getMonth() + 1;
|
|
21054
|
-
const day = bj.getDate();
|
|
21055
21412
|
const bjHour = bj.getHours();
|
|
21056
21413
|
const bjMinute = bj.getMinutes();
|
|
21414
|
+
const todayStart = new Date(bj.getFullYear(), bj.getMonth(), bj.getDate()).getTime();
|
|
21057
21415
|
const rows = db.prepare(
|
|
21058
|
-
"SELECT id, event, date_str, time_exact FROM events WHERE status='pending' AND type='task' AND
|
|
21059
|
-
).all(
|
|
21416
|
+
"SELECT id, event, date_str, time_exact FROM events WHERE status='pending' AND type='task' AND date_str IS NOT NULL"
|
|
21417
|
+
).all();
|
|
21060
21418
|
db.close();
|
|
21061
|
-
|
|
21062
|
-
const
|
|
21063
|
-
|
|
21064
|
-
|
|
21065
|
-
|
|
21066
|
-
if (
|
|
21067
|
-
|
|
21419
|
+
const due = [];
|
|
21420
|
+
for (const r2 of rows) {
|
|
21421
|
+
const dayMs = this.parseCalendarDateStr(r2.date_str, bj);
|
|
21422
|
+
if (dayMs === null || dayMs > todayStart) continue;
|
|
21423
|
+
const isToday2 = dayMs === todayStart;
|
|
21424
|
+
if (isToday2 && r2.time_exact) {
|
|
21425
|
+
const [h, m2] = String(r2.time_exact).split(":").map(Number);
|
|
21426
|
+
if (h > bjHour || h === bjHour && m2 > bjMinute) continue;
|
|
21427
|
+
}
|
|
21428
|
+
due.push({ id: r2.id, event: r2.event, date_str: r2.date_str, time_exact: r2.time_exact, dayMs, isToday: isToday2 });
|
|
21429
|
+
}
|
|
21430
|
+
if (due.length === 0) return null;
|
|
21431
|
+
due.sort((a, b2) => {
|
|
21432
|
+
if (a.isToday !== b2.isToday) return a.isToday ? -1 : 1;
|
|
21433
|
+
return b2.dayMs - a.dayMs;
|
|
21068
21434
|
});
|
|
21069
|
-
|
|
21070
|
-
|
|
21071
|
-
return `#${r.id} ${r.event} (${r.date_str} ${r.time_exact || ""})`.trim();
|
|
21435
|
+
const r = due[0];
|
|
21436
|
+
return `#${r.id} ${r.event} (${r.date_str} ${r.time_exact || ""})${r.isToday ? "" : "\uFF08\u5DF2\u903E\u671F\uFF09"}`.trim();
|
|
21072
21437
|
} catch (e) {
|
|
21073
21438
|
console.warn(`[nudge] checkCalendarDue error: ${e.message}`);
|
|
21074
21439
|
return null;
|
|
21075
21440
|
}
|
|
21076
21441
|
}
|
|
21442
|
+
/** 解析 date_str 为当日 0 点 epoch ms(北京时间);"M/D" 按当前年,"YYYY-M-D" 按字面年 */
|
|
21443
|
+
parseCalendarDateStr(ds, bj) {
|
|
21444
|
+
if (!ds) return null;
|
|
21445
|
+
if (/^\d{4}-\d{1,2}-\d{1,2}$/.test(ds)) {
|
|
21446
|
+
const t = (/* @__PURE__ */ new Date(ds + "T00:00:00+08:00")).getTime();
|
|
21447
|
+
return Number.isNaN(t) ? null : t;
|
|
21448
|
+
}
|
|
21449
|
+
const m2 = String(ds).match(/^(\d{1,2})\/(\d{1,2})$/);
|
|
21450
|
+
if (!m2) return null;
|
|
21451
|
+
return new Date(bj.getFullYear(), Number(m2[1]) - 1, Number(m2[2])).getTime();
|
|
21452
|
+
}
|
|
21077
21453
|
/** 检查 carry-over:如果 in_progress task 24h+ 没推进,自动 calendar add-task 排明天 */
|
|
21078
21454
|
checkCarryOver(task, _sessions) {
|
|
21079
21455
|
try {
|
|
@@ -21127,7 +21503,7 @@ var NudgePlugin = class {
|
|
|
21127
21503
|
|
|
21128
21504
|
// src/inner-voice/plugin.ts
|
|
21129
21505
|
import fs21 from "node:fs";
|
|
21130
|
-
import
|
|
21506
|
+
import path21 from "node:path";
|
|
21131
21507
|
|
|
21132
21508
|
// src/inner-voice/activity.ts
|
|
21133
21509
|
function checkActivity(sessions, activeThresholdMs) {
|
|
@@ -21167,7 +21543,7 @@ function calcHintProb(min) {
|
|
|
21167
21543
|
|
|
21168
21544
|
// src/inner-voice/emotional-state.ts
|
|
21169
21545
|
import fs18 from "node:fs";
|
|
21170
|
-
import
|
|
21546
|
+
import path18 from "node:path";
|
|
21171
21547
|
var NEUTRAL = 0.5;
|
|
21172
21548
|
var DECAY_RATE = 0.17;
|
|
21173
21549
|
var MAX_EVENTS = 20;
|
|
@@ -21218,7 +21594,7 @@ function initialState() {
|
|
|
21218
21594
|
return { version: 1, mood: NEUTRAL, trend: "stable", updatedAt: nowIsoBj(), events: [] };
|
|
21219
21595
|
}
|
|
21220
21596
|
async function updateEmotionalState(workspace, sessions) {
|
|
21221
|
-
const stateFile =
|
|
21597
|
+
const stateFile = path18.join(workspace, "inner-voice", "emotional-state.json");
|
|
21222
21598
|
const messages = readRecentMessages(sessions, RECENT_N);
|
|
21223
21599
|
if (messages.length === 0) {
|
|
21224
21600
|
console.log("[emotional-state] no messages");
|
|
@@ -21251,7 +21627,7 @@ async function updateEmotionalState(workspace, sessions) {
|
|
|
21251
21627
|
function readRecentMessages(sessions, n) {
|
|
21252
21628
|
const mainId = sessions.getSessionId("scope:main");
|
|
21253
21629
|
if (!mainId) return [];
|
|
21254
|
-
const file =
|
|
21630
|
+
const file = path18.join(sessions.sessionsDir, `${mainId}.jsonl`);
|
|
21255
21631
|
if (!fs18.existsSync(file)) return [];
|
|
21256
21632
|
const lines = readLastNLines(file, n * 4 + 20);
|
|
21257
21633
|
const entries = [];
|
|
@@ -21369,7 +21745,7 @@ function refreshHoursAgo(events) {
|
|
|
21369
21745
|
}
|
|
21370
21746
|
function appendMoodLog(workspace, state2, summary) {
|
|
21371
21747
|
try {
|
|
21372
|
-
const logPath =
|
|
21748
|
+
const logPath = path18.join(workspace, "mood-history.log");
|
|
21373
21749
|
const ts = formatBj(/* @__PURE__ */ new Date(), false);
|
|
21374
21750
|
fs18.appendFileSync(logPath, `${ts} mood=${state2.mood.toFixed(2)} trend=${state2.trend} ${summary}
|
|
21375
21751
|
`);
|
|
@@ -21386,7 +21762,7 @@ function loadJson(file) {
|
|
|
21386
21762
|
}
|
|
21387
21763
|
function saveJson(file, data) {
|
|
21388
21764
|
try {
|
|
21389
|
-
fs18.mkdirSync(
|
|
21765
|
+
fs18.mkdirSync(path18.dirname(file), { recursive: true });
|
|
21390
21766
|
fs18.writeFileSync(file, JSON.stringify(data, null, 2));
|
|
21391
21767
|
} catch (err) {
|
|
21392
21768
|
console.warn(`[emotional-state] save failed: ${err.message}`);
|
|
@@ -21432,7 +21808,7 @@ function formatBj(d, withSec) {
|
|
|
21432
21808
|
|
|
21433
21809
|
// src/inner-voice/topics-scorer.ts
|
|
21434
21810
|
import fs19 from "node:fs";
|
|
21435
|
-
import
|
|
21811
|
+
import path19 from "node:path";
|
|
21436
21812
|
var HALF_LIFE_DAYS = 3;
|
|
21437
21813
|
var PROJECT_HALF_LIFE_DAYS = 1.5;
|
|
21438
21814
|
var COOLDOWN_HOURS = 6;
|
|
@@ -21440,8 +21816,8 @@ var MAX_CHARS = 8e3;
|
|
|
21440
21816
|
var SKIP_NAMES = /* @__PURE__ */ new Set(["MEMORY.md", "archive"]);
|
|
21441
21817
|
var SKIP_DIRS = /* @__PURE__ */ new Set(["archive"]);
|
|
21442
21818
|
function pickTopic(workspace, typeFilter, opts) {
|
|
21443
|
-
const topicsDir =
|
|
21444
|
-
const usageFile =
|
|
21819
|
+
const topicsDir = path19.join(workspace, "topics");
|
|
21820
|
+
const usageFile = path19.join(workspace, "inner-voice", "topics-usage.json");
|
|
21445
21821
|
const files = scanTopics(topicsDir, typeFilter);
|
|
21446
21822
|
if (files.length === 0) {
|
|
21447
21823
|
console.log(`[topics-scorer] no topics found (type=${typeFilter})`);
|
|
@@ -21473,7 +21849,7 @@ function pickTopic(workspace, typeFilter, opts) {
|
|
|
21473
21849
|
recency: Math.round(recency * 1e3) / 1e3,
|
|
21474
21850
|
freq: Math.round(freq * 1e3) / 1e3,
|
|
21475
21851
|
type: type2,
|
|
21476
|
-
name: meta.name ||
|
|
21852
|
+
name: meta.name || path19.basename(relpath),
|
|
21477
21853
|
description: meta.description || "",
|
|
21478
21854
|
mtime
|
|
21479
21855
|
});
|
|
@@ -21531,14 +21907,14 @@ function scanTopics(topicsDir, typeFilter) {
|
|
|
21531
21907
|
const out = [];
|
|
21532
21908
|
const walk = (dir) => {
|
|
21533
21909
|
for (const name of fs19.readdirSync(dir)) {
|
|
21534
|
-
const full =
|
|
21910
|
+
const full = path19.join(dir, name);
|
|
21535
21911
|
const stat4 = fs19.statSync(full);
|
|
21536
21912
|
if (stat4.isDirectory()) {
|
|
21537
21913
|
if (SKIP_DIRS.has(name)) continue;
|
|
21538
21914
|
walk(full);
|
|
21539
21915
|
} else {
|
|
21540
21916
|
if (!name.endsWith(".md") || SKIP_NAMES.has(name)) continue;
|
|
21541
|
-
const relpath =
|
|
21917
|
+
const relpath = path19.relative(topicsDir, full).replace(/\\/g, "/");
|
|
21542
21918
|
if (typeFilter && !relpath.startsWith(typeFilter + "/") && !relpath.startsWith(typeFilter + "_")) continue;
|
|
21543
21919
|
out.push({ relpath, fullpath: full });
|
|
21544
21920
|
}
|
|
@@ -21583,7 +21959,7 @@ function loadJson2(file) {
|
|
|
21583
21959
|
}
|
|
21584
21960
|
function saveJson2(file, data) {
|
|
21585
21961
|
try {
|
|
21586
|
-
fs19.mkdirSync(
|
|
21962
|
+
fs19.mkdirSync(path19.dirname(file), { recursive: true });
|
|
21587
21963
|
fs19.writeFileSync(file, JSON.stringify(data, null, 2));
|
|
21588
21964
|
} catch (err) {
|
|
21589
21965
|
console.warn(`[topics-scorer] usage save failed: ${err.message}`);
|
|
@@ -21592,21 +21968,21 @@ function saveJson2(file, data) {
|
|
|
21592
21968
|
|
|
21593
21969
|
// src/inner-voice/memory-reader.ts
|
|
21594
21970
|
import fs20 from "node:fs";
|
|
21595
|
-
import
|
|
21971
|
+
import path20 from "node:path";
|
|
21596
21972
|
var US_HALF_LIFE_DAYS = 10;
|
|
21597
21973
|
var US_MAX_LINES = 60;
|
|
21598
21974
|
function readRecentMemory(workspace) {
|
|
21599
|
-
const dir =
|
|
21975
|
+
const dir = path20.join(workspace, "memory");
|
|
21600
21976
|
const now = new Date(Date.now() + 8 * 36e5);
|
|
21601
21977
|
const today = formatYmd(now);
|
|
21602
21978
|
const yesterday = formatYmd(new Date(now.getTime() - 864e5));
|
|
21603
21979
|
return {
|
|
21604
|
-
today: readIfExists(
|
|
21605
|
-
yesterday: readIfExists(
|
|
21980
|
+
today: readIfExists(path20.join(dir, `${today}.md`)),
|
|
21981
|
+
yesterday: readIfExists(path20.join(dir, `${yesterday}.md`))
|
|
21606
21982
|
};
|
|
21607
21983
|
}
|
|
21608
21984
|
function sampleUs(workspace) {
|
|
21609
|
-
const usFile =
|
|
21985
|
+
const usFile = path20.join(workspace, "memory", "us.md");
|
|
21610
21986
|
let content;
|
|
21611
21987
|
try {
|
|
21612
21988
|
content = fs20.readFileSync(usFile, "utf-8");
|
|
@@ -21946,7 +22322,7 @@ var InnerVoicePlugin = class {
|
|
|
21946
22322
|
}
|
|
21947
22323
|
/** 读 workspace/prompts/my-inner-voice.md,不存在用 DEFAULT_PROMPT */
|
|
21948
22324
|
loadPrompt(workspace) {
|
|
21949
|
-
const promptPath =
|
|
22325
|
+
const promptPath = path21.join(workspace, "prompts", "my-inner-voice.md");
|
|
21950
22326
|
try {
|
|
21951
22327
|
const content = fs21.readFileSync(promptPath, "utf-8").trim();
|
|
21952
22328
|
if (content) {
|
|
@@ -22020,7 +22396,7 @@ var InnerVoicePlugin = class {
|
|
|
22020
22396
|
console.warn(`[inner-voice] emotional-state failed: ${err.message}`);
|
|
22021
22397
|
}
|
|
22022
22398
|
try {
|
|
22023
|
-
const content = fs21.readFileSync(
|
|
22399
|
+
const content = fs21.readFileSync(path21.join(this.workspace, "SESSION-STATE.md"), "utf-8");
|
|
22024
22400
|
lines.push("\n--- SESSION-STATE\uFF08\u5C3E\u90E8\uFF09 ---");
|
|
22025
22401
|
lines.push(content.slice(-2e3));
|
|
22026
22402
|
} catch {
|
|
@@ -22131,7 +22507,7 @@ var InnerVoicePlugin = class {
|
|
|
22131
22507
|
if (Math.random() >= activity.hintProb) {
|
|
22132
22508
|
return { text: thought, hintTriggered: false, hintText: "" };
|
|
22133
22509
|
}
|
|
22134
|
-
const poolPath =
|
|
22510
|
+
const poolPath = path21.join(this.workspace, "inner-voice", "hints_pool.txt");
|
|
22135
22511
|
let hint = "\u60F3\u4ED6\u5C31\u53D1\u6D88\u606F\u5427";
|
|
22136
22512
|
try {
|
|
22137
22513
|
const pool = fs21.readFileSync(poolPath, "utf-8").split("\n").map((s2) => s2.trim()).filter(Boolean);
|
|
@@ -22159,7 +22535,7 @@ var InnerVoicePlugin = class {
|
|
|
22159
22535
|
try {
|
|
22160
22536
|
const writer = sessions.getWriter(mainSessionId);
|
|
22161
22537
|
const history = sessions.getHistory(mainSessionId);
|
|
22162
|
-
const fullPath =
|
|
22538
|
+
const fullPath = path21.resolve(this.workspace, emoTopic.file);
|
|
22163
22539
|
const memories = [{
|
|
22164
22540
|
path: fullPath,
|
|
22165
22541
|
content: emoTopic.content,
|
|
@@ -22187,9 +22563,9 @@ var InnerVoicePlugin = class {
|
|
|
22187
22563
|
/** 写 xiaoyi.log(格式对齐旧 memory_whisper.py,便于既有日志分析复用)。 */
|
|
22188
22564
|
writeLog(status, delivered, activity, hintTriggered, hintText) {
|
|
22189
22565
|
try {
|
|
22190
|
-
const logDir =
|
|
22566
|
+
const logDir = path21.join(this.workspace, "inner-voice");
|
|
22191
22567
|
fs21.mkdirSync(logDir, { recursive: true });
|
|
22192
|
-
const logPath =
|
|
22568
|
+
const logPath = path21.join(logDir, "xiaoyi.log");
|
|
22193
22569
|
const ts = formatBeijingTs(/* @__PURE__ */ new Date());
|
|
22194
22570
|
const hintStatus = hintTriggered ? `YES (${(hintText || "").trim()})` : "no";
|
|
22195
22571
|
fs21.appendFileSync(
|
|
@@ -22728,7 +23104,7 @@ var PluginManager = class {
|
|
|
22728
23104
|
// src/voice-chat/plugin.ts
|
|
22729
23105
|
import { spawn as spawn4, exec } from "node:child_process";
|
|
22730
23106
|
import net from "node:net";
|
|
22731
|
-
import
|
|
23107
|
+
import path22 from "node:path";
|
|
22732
23108
|
import fs22 from "node:fs";
|
|
22733
23109
|
|
|
22734
23110
|
// src/voice-chat/bridge.ts
|
|
@@ -23105,13 +23481,13 @@ var VoiceChatPlugin = class _VoiceChatPlugin {
|
|
|
23105
23481
|
}
|
|
23106
23482
|
getPythonDir() {
|
|
23107
23483
|
const dir = import.meta.dirname;
|
|
23108
|
-
const srcDir =
|
|
23109
|
-
const localDir =
|
|
23484
|
+
const srcDir = path22.resolve(dir, "..", "src", "voice-chat", "python");
|
|
23485
|
+
const localDir = path22.join(dir, "python");
|
|
23110
23486
|
return fs22.existsSync(srcDir) ? srcDir : localDir;
|
|
23111
23487
|
}
|
|
23112
23488
|
startPython() {
|
|
23113
23489
|
const pythonDir = this.getPythonDir();
|
|
23114
|
-
const serverPy =
|
|
23490
|
+
const serverPy = path22.join(pythonDir, "server.py");
|
|
23115
23491
|
const pythonBin = this.findPython();
|
|
23116
23492
|
const args = [serverPy];
|
|
23117
23493
|
if (this.config.pythonPort) args.push("--port", String(this.config.pythonPort));
|
|
@@ -23196,7 +23572,7 @@ var VoiceChatPlugin = class _VoiceChatPlugin {
|
|
|
23196
23572
|
init_BashTool();
|
|
23197
23573
|
import { spawn as spawn5, exec as exec2 } from "node:child_process";
|
|
23198
23574
|
import net2 from "node:net";
|
|
23199
|
-
import
|
|
23575
|
+
import path23 from "node:path";
|
|
23200
23576
|
import fs23 from "node:fs";
|
|
23201
23577
|
|
|
23202
23578
|
// src/memory/cognifold/config.ts
|
|
@@ -23220,7 +23596,8 @@ function parseCognifoldConfig(raw) {
|
|
|
23220
23596
|
persistDir: raw.persistDir ?? DEFAULTS3.persistDir,
|
|
23221
23597
|
scopes: raw.scopes,
|
|
23222
23598
|
readyTimeoutMs: raw.readyTimeoutMs ?? DEFAULTS3.readyTimeoutMs,
|
|
23223
|
-
maxRestarts: raw.maxRestarts ?? DEFAULTS3.maxRestarts
|
|
23599
|
+
maxRestarts: raw.maxRestarts ?? DEFAULTS3.maxRestarts,
|
|
23600
|
+
llm: raw.llm
|
|
23224
23601
|
};
|
|
23225
23602
|
}
|
|
23226
23603
|
|
|
@@ -23228,15 +23605,17 @@ function parseCognifoldConfig(raw) {
|
|
|
23228
23605
|
var CogniFoldClient = class {
|
|
23229
23606
|
baseUrl;
|
|
23230
23607
|
timeoutMs;
|
|
23231
|
-
|
|
23608
|
+
modelName;
|
|
23609
|
+
constructor(baseUrl, timeoutMs = 3e4, modelName = "openai:MiniMax-M3") {
|
|
23232
23610
|
this.baseUrl = baseUrl.replace(/\/$/, "");
|
|
23233
23611
|
this.timeoutMs = timeoutMs;
|
|
23612
|
+
this.modelName = modelName;
|
|
23234
23613
|
}
|
|
23235
|
-
async req(
|
|
23614
|
+
async req(path44, options = {}) {
|
|
23236
23615
|
const ctrl = new AbortController();
|
|
23237
23616
|
const timer = setTimeout(() => ctrl.abort(), this.timeoutMs);
|
|
23238
23617
|
try {
|
|
23239
|
-
const resp = await fetch(`${this.baseUrl}${
|
|
23618
|
+
const resp = await fetch(`${this.baseUrl}${path44}`, {
|
|
23240
23619
|
...options,
|
|
23241
23620
|
signal: ctrl.signal,
|
|
23242
23621
|
headers: {
|
|
@@ -23274,7 +23653,7 @@ var CogniFoldClient = class {
|
|
|
23274
23653
|
method: "POST",
|
|
23275
23654
|
body: JSON.stringify({
|
|
23276
23655
|
user_id: userId,
|
|
23277
|
-
config: { model_name:
|
|
23656
|
+
config: { model_name: this.modelName }
|
|
23278
23657
|
})
|
|
23279
23658
|
});
|
|
23280
23659
|
}
|
|
@@ -23326,8 +23705,8 @@ var CogniFoldClient = class {
|
|
|
23326
23705
|
});
|
|
23327
23706
|
}
|
|
23328
23707
|
/** 兼容老版命名 */
|
|
23329
|
-
async recl(
|
|
23330
|
-
return this.req(
|
|
23708
|
+
async recl(path44, options = {}) {
|
|
23709
|
+
return this.req(path44, options);
|
|
23331
23710
|
}
|
|
23332
23711
|
};
|
|
23333
23712
|
|
|
@@ -23432,7 +23811,8 @@ var CogniFoldPlugin = class {
|
|
|
23432
23811
|
baseUrl = baseUrl.replace(/\/$/, "") + "/api/v1";
|
|
23433
23812
|
}
|
|
23434
23813
|
this.config.baseUrl = baseUrl;
|
|
23435
|
-
this.
|
|
23814
|
+
const modelName = this.config.llm?.model ? this.config.llm.model.startsWith("openai:") ? this.config.llm.model : `openai:${this.config.llm.model}` : "openai:MiniMax-M3";
|
|
23815
|
+
this.client = new CogniFoldClient(baseUrl, 3e4, modelName);
|
|
23436
23816
|
}
|
|
23437
23817
|
workspacePath;
|
|
23438
23818
|
name = "cognifold";
|
|
@@ -23607,16 +23987,16 @@ var CogniFoldPlugin = class {
|
|
|
23607
23987
|
const dir = import.meta.dirname;
|
|
23608
23988
|
const candidates = [
|
|
23609
23989
|
// 从 dist/ 往回找 src
|
|
23610
|
-
|
|
23611
|
-
|
|
23612
|
-
|
|
23990
|
+
path23.resolve(dir, "..", "src", "memory", "cognifold", "python"),
|
|
23991
|
+
path23.resolve(dir, "..", "..", "src", "memory", "cognifold", "python"),
|
|
23992
|
+
path23.resolve(dir, "..", "..", "..", "src", "memory", "cognifold", "python"),
|
|
23613
23993
|
// 从 src/memory/cognifold/ 找本地
|
|
23614
|
-
|
|
23994
|
+
path23.join(dir, "python"),
|
|
23615
23995
|
// 从 dist/memory/cognifold/ 找本地
|
|
23616
|
-
|
|
23996
|
+
path23.resolve(dir, "python")
|
|
23617
23997
|
];
|
|
23618
23998
|
for (const candidate of candidates) {
|
|
23619
|
-
if (fs23.existsSync(
|
|
23999
|
+
if (fs23.existsSync(path23.join(candidate, "cognifold"))) {
|
|
23620
24000
|
return candidate;
|
|
23621
24001
|
}
|
|
23622
24002
|
}
|
|
@@ -23642,12 +24022,18 @@ var CogniFoldPlugin = class {
|
|
|
23642
24022
|
const pythonBin = this.findPython();
|
|
23643
24023
|
console.log(`[cognifold] Starting Python: ${pythonBin} ${args.join(" ")}`);
|
|
23644
24024
|
console.log(`[cognifold] Python dir: ${pythonDir}`);
|
|
23645
|
-
if (!fs23.existsSync(
|
|
24025
|
+
if (!fs23.existsSync(path23.join(pythonDir, "cognifold"))) {
|
|
23646
24026
|
console.error(`[cognifold] FATAL: Python module not found at ${pythonDir}/cognifold`);
|
|
23647
24027
|
throw new Error(`cognifold: python module not found`);
|
|
23648
24028
|
}
|
|
23649
24029
|
const childEnv = { ...process.env, PYTHONUNBUFFERED: "1" };
|
|
23650
|
-
|
|
24030
|
+
if (this.config.llm?.apiKey) {
|
|
24031
|
+
childEnv["OPENAI_API_KEY"] = this.config.llm.apiKey;
|
|
24032
|
+
}
|
|
24033
|
+
if (this.config.llm?.baseUrl) {
|
|
24034
|
+
childEnv["OPENAI_BASE_URL"] = this.config.llm.baseUrl;
|
|
24035
|
+
}
|
|
24036
|
+
const envFile = path23.join(pythonDir, ".env");
|
|
23651
24037
|
try {
|
|
23652
24038
|
if (fs23.existsSync(envFile)) {
|
|
23653
24039
|
const envContent = fs23.readFileSync(envFile, "utf-8");
|
|
@@ -23719,7 +24105,7 @@ var CogniFoldPlugin = class {
|
|
|
23719
24105
|
init_BashTool();
|
|
23720
24106
|
import { spawn as spawn6 } from "node:child_process";
|
|
23721
24107
|
import net3 from "node:net";
|
|
23722
|
-
import
|
|
24108
|
+
import path24 from "node:path";
|
|
23723
24109
|
import fs24 from "node:fs";
|
|
23724
24110
|
|
|
23725
24111
|
// src/memory/everos/config.ts
|
|
@@ -23753,7 +24139,8 @@ function parseEverosConfig(raw) {
|
|
|
23753
24139
|
llm: raw.llm ?? { model: "glm-5.2", apiKey: "", baseUrl: "https://open.bigmodel.cn/api/coding/paas/v4" },
|
|
23754
24140
|
rerank: raw.rerank ?? { model: "Qwen/Qwen3-Reranker-4B", apiKey: "", baseUrl: "https://api.deepinfra.com/v1/inference" },
|
|
23755
24141
|
lancedbPath: raw.lancedbPath ?? "",
|
|
23756
|
-
sqlitePath: raw.sqlitePath ?? ""
|
|
24142
|
+
sqlitePath: raw.sqlitePath ?? "",
|
|
24143
|
+
minScore: raw.minScore
|
|
23757
24144
|
};
|
|
23758
24145
|
}
|
|
23759
24146
|
|
|
@@ -23791,21 +24178,31 @@ var EverosSearchClient = class {
|
|
|
23791
24178
|
clearTimeout(timer);
|
|
23792
24179
|
}
|
|
23793
24180
|
}
|
|
23794
|
-
/** Search —
|
|
24181
|
+
/** Search — routes to 8101 (agentic) or 8100 (hybrid) based on mode */
|
|
23795
24182
|
async search(params) {
|
|
23796
24183
|
const ctrl = new AbortController();
|
|
23797
24184
|
const timer = setTimeout(() => ctrl.abort(), this.timeoutMs);
|
|
23798
24185
|
try {
|
|
23799
|
-
const
|
|
24186
|
+
const mode = params.mode || "hybrid";
|
|
24187
|
+
const useAgentic = mode === "hybrid_agentic" || mode === "agentic";
|
|
24188
|
+
const url = useAgentic ? `${this.agenticUrl}/api/v1/search` : `${this.everosUrl}/api/v1/memory/search`;
|
|
24189
|
+
const body = useAgentic ? JSON.stringify({
|
|
24190
|
+
query: params.query,
|
|
24191
|
+
user_id: params.userId || "xiaomei",
|
|
24192
|
+
mode,
|
|
24193
|
+
top_k: params.topK ?? 5,
|
|
24194
|
+
strategy: params.strategy || "multi_query"
|
|
24195
|
+
}) : JSON.stringify({
|
|
24196
|
+
query: params.query,
|
|
24197
|
+
user_id: params.userId || "user",
|
|
24198
|
+
app_id: "xiaomei",
|
|
24199
|
+
project_id: "default",
|
|
24200
|
+
top_k: params.topK ?? 5
|
|
24201
|
+
});
|
|
24202
|
+
const resp = await fetch(url, {
|
|
23800
24203
|
method: "POST",
|
|
23801
24204
|
headers: { "Content-Type": "application/json" },
|
|
23802
|
-
body
|
|
23803
|
-
query: params.query,
|
|
23804
|
-
user_id: params.userId || "xiaomei",
|
|
23805
|
-
mode: params.mode || "hybrid_agentic",
|
|
23806
|
-
top_k: params.topK ?? 5,
|
|
23807
|
-
strategy: params.strategy || "multi_query"
|
|
23808
|
-
}),
|
|
24205
|
+
body,
|
|
23809
24206
|
signal: ctrl.signal
|
|
23810
24207
|
});
|
|
23811
24208
|
if (!resp.ok) {
|
|
@@ -23845,6 +24242,7 @@ var EverosPlugin = class {
|
|
|
23845
24242
|
}
|
|
23846
24243
|
async start(ctx) {
|
|
23847
24244
|
if (!this.config.enabled) return;
|
|
24245
|
+
await this.ensureVenv();
|
|
23848
24246
|
try {
|
|
23849
24247
|
await this.client.healthEveros();
|
|
23850
24248
|
console.log(`[everos] EverOS already running at ${this.config.everosUrl}`);
|
|
@@ -23915,13 +24313,15 @@ var EverosPlugin = class {
|
|
|
23915
24313
|
}, 3e5);
|
|
23916
24314
|
}
|
|
23917
24315
|
async startEveros() {
|
|
23918
|
-
const pythonDir =
|
|
23919
|
-
const configPath =
|
|
24316
|
+
const pythonDir = path24.dirname(this.config.lancedbPath);
|
|
24317
|
+
const configPath = path24.join(pythonDir, "config.toml");
|
|
23920
24318
|
await this.ensureFcntlCompat();
|
|
23921
24319
|
const venvPython = this.findVenvPython();
|
|
24320
|
+
const everosBin = venvPython.replace(/python\.exe$/, "everos.exe");
|
|
23922
24321
|
const args = ["server", "start"];
|
|
23923
|
-
const cmd = `${
|
|
24322
|
+
const cmd = `${everosBin} ${args.join(" ")}`;
|
|
23924
24323
|
console.log(`[everos] Starting EverOS: ${cmd}`);
|
|
24324
|
+
console.log(`[everos] LLM config: ${this.config.llm.model} @ ${this.config.llm.baseUrl}`);
|
|
23925
24325
|
if (process.platform === "win32") {
|
|
23926
24326
|
const { shell, args: shellArgs } = findShell();
|
|
23927
24327
|
spawn6(shell, [...shellArgs, cmd], {
|
|
@@ -23936,7 +24336,7 @@ var EverosPlugin = class {
|
|
|
23936
24336
|
env: { ...process.env, PYTHONUNBUFFERED: "1" }
|
|
23937
24337
|
});
|
|
23938
24338
|
}
|
|
23939
|
-
await this.waitForReady(`${this.config.everosUrl}/health`,
|
|
24339
|
+
await this.waitForReady(`${this.config.everosUrl}/health`, 6e4);
|
|
23940
24340
|
}
|
|
23941
24341
|
startAgenticServer() {
|
|
23942
24342
|
const pythonDir = this.getPythonDir();
|
|
@@ -23946,6 +24346,7 @@ var EverosPlugin = class {
|
|
|
23946
24346
|
const cmd = `${venvPython} ${args.join(" ")}`;
|
|
23947
24347
|
console.log(`[everos] Starting agentic server: ${cmd}`);
|
|
23948
24348
|
console.log(`[everos] Python dir: ${pythonDir}`);
|
|
24349
|
+
console.log(`[everos] LLM: ${this.config.llm.model} @ ${this.config.llm.baseUrl}`);
|
|
23949
24350
|
const childEnv = {
|
|
23950
24351
|
...process.env,
|
|
23951
24352
|
PYTHONUNBUFFERED: "1",
|
|
@@ -23954,15 +24355,25 @@ var EverosPlugin = class {
|
|
|
23954
24355
|
LLM_API_KEY: this.config.llm.apiKey,
|
|
23955
24356
|
LLM_BASE_URL: this.config.llm.baseUrl,
|
|
23956
24357
|
RERANK_API_KEY: this.config.rerank.apiKey,
|
|
23957
|
-
RERANK_URL:
|
|
24358
|
+
RERANK_URL: this.config.rerank.baseUrl,
|
|
23958
24359
|
LANCEDB_PATH: this.config.lancedbPath,
|
|
23959
24360
|
SQLITE_PATH: this.config.sqlitePath,
|
|
23960
24361
|
EVEROS_USER_ID: this.config.userId
|
|
23961
24362
|
};
|
|
24363
|
+
const maskKey = (k2) => k2 ? `${k2.slice(0, 4)}\u2026${k2.slice(-4)}` : "(empty!)";
|
|
24364
|
+
console.log(`[everos] agentic env:`);
|
|
24365
|
+
console.log(`[everos] EVEROS_URL=${childEnv.EVEROS_URL}`);
|
|
24366
|
+
console.log(`[everos] LLM_MODEL=${childEnv.LLM_MODEL}`);
|
|
24367
|
+
console.log(`[everos] LLM_API_KEY=${maskKey(childEnv.LLM_API_KEY)}`);
|
|
24368
|
+
console.log(`[everos] LLM_BASE_URL=${childEnv.LLM_BASE_URL}`);
|
|
24369
|
+
console.log(`[everos] RERANK_API_KEY=${maskKey(childEnv.RERANK_API_KEY)}`);
|
|
24370
|
+
console.log(`[everos] RERANK_URL=${childEnv.RERANK_URL}`);
|
|
24371
|
+
console.log(`[everos] LANCEDB_PATH=${childEnv.LANCEDB_PATH}`);
|
|
24372
|
+
console.log(`[everos] SQLITE_PATH=${childEnv.SQLITE_PATH}`);
|
|
24373
|
+
console.log(`[everos] EVEROS_USER_ID=${childEnv.EVEROS_USER_ID}`);
|
|
23962
24374
|
let child;
|
|
23963
24375
|
if (process.platform === "win32") {
|
|
23964
|
-
|
|
23965
|
-
child = spawn6(shell, [...shellArgs, cmd], {
|
|
24376
|
+
child = spawn6(venvPython, args, {
|
|
23966
24377
|
cwd: pythonDir,
|
|
23967
24378
|
stdio: ["ignore", "pipe", "pipe"],
|
|
23968
24379
|
env: childEnv
|
|
@@ -23992,21 +24403,64 @@ var EverosPlugin = class {
|
|
|
23992
24403
|
return child;
|
|
23993
24404
|
}
|
|
23994
24405
|
findVenvPython() {
|
|
23995
|
-
const stateDir = process.env.OPENCLAW_STATE_DIR ||
|
|
24406
|
+
const stateDir = process.env.OPENCLAW_STATE_DIR || path24.join(process.env.HOME || process.env.USERPROFILE || ".", ".openclaw");
|
|
23996
24407
|
if (process.platform === "win32") {
|
|
23997
|
-
return
|
|
24408
|
+
return path24.join(stateDir, "everos-venv", "Scripts", "python.exe");
|
|
24409
|
+
}
|
|
24410
|
+
return path24.join(stateDir, "everos-venv", "bin", "python");
|
|
24411
|
+
}
|
|
24412
|
+
/** 检测 venv 是否存在,不存在就自动创建 + 装 EverOS */
|
|
24413
|
+
async ensureVenv() {
|
|
24414
|
+
const venvPython = this.findVenvPython();
|
|
24415
|
+
if (fs24.existsSync(venvPython)) return;
|
|
24416
|
+
const stateDir = process.env.OPENCLAW_STATE_DIR || path24.join(process.env.HOME || process.env.USERPROFILE || ".", ".openclaw");
|
|
24417
|
+
const venvDir = path24.join(stateDir, "everos-venv");
|
|
24418
|
+
const everosSrc = path24.join(stateDir, "workspace", "research", "EverOS");
|
|
24419
|
+
console.log(`[everos] venv not found at ${venvDir}, auto-creating...`);
|
|
24420
|
+
console.log(`[everos] \u23F3 This may take a few minutes on first run...`);
|
|
24421
|
+
const pyCandidates = process.platform === "win32" ? ["python", "python3", "C:\\Python314\\python.exe", "C:\\Python313\\python.exe", "C:\\Python312\\python.exe"] : ["python3", "python"];
|
|
24422
|
+
let sysPython = "";
|
|
24423
|
+
for (const cmd of pyCandidates) {
|
|
24424
|
+
try {
|
|
24425
|
+
const { execSync: execSync3 } = await import("node:child_process");
|
|
24426
|
+
execSync3(`"${cmd}" --version`, { stdio: "pipe", shell: true });
|
|
24427
|
+
sysPython = cmd;
|
|
24428
|
+
break;
|
|
24429
|
+
} catch {
|
|
24430
|
+
}
|
|
24431
|
+
}
|
|
24432
|
+
if (!sysPython) {
|
|
24433
|
+
console.error(`[everos] \u2717 Python not found. Install Python 3.10+ first.`);
|
|
24434
|
+
return;
|
|
24435
|
+
}
|
|
24436
|
+
try {
|
|
24437
|
+
console.log(`[everos] Creating venv with ${sysPython}...`);
|
|
24438
|
+
const { execSync: execSync3 } = await import("node:child_process");
|
|
24439
|
+
execSync3(`"${sysPython}" -m venv "${venvDir}"`, { stdio: "pipe", shell: true });
|
|
24440
|
+
const pip = process.platform === "win32" ? path24.join(venvDir, "Scripts", "pip.exe") : path24.join(venvDir, "bin", "pip");
|
|
24441
|
+
const everosReq = path24.join(this.getPythonDir(), "requirements.txt");
|
|
24442
|
+
if (fs24.existsSync(everosReq)) {
|
|
24443
|
+
console.log(`[everos] Installing from requirements.txt...`);
|
|
24444
|
+
execSync3(`"${pip}" install -r "${everosReq}" -q`, { stdio: "pipe", shell: true, timeout: 3e5 });
|
|
24445
|
+
} else {
|
|
24446
|
+
console.log(`[everos] No requirements.txt found, installing everos from PyPI...`);
|
|
24447
|
+
execSync3(`"${pip}" install everos -q`, { stdio: "pipe", shell: true, timeout: 3e5 });
|
|
24448
|
+
}
|
|
24449
|
+
console.log(`[everos] \u2705 venv created successfully`);
|
|
24450
|
+
} catch (err) {
|
|
24451
|
+
console.error(`[everos] \u2717 Failed to create venv: ${err.message}`);
|
|
24452
|
+
console.error(`[everos] Manual setup: see workspace/scripts/everos-setup.sh`);
|
|
23998
24453
|
}
|
|
23999
|
-
return path23.join(stateDir, "everos-venv", "bin", "python");
|
|
24000
24454
|
}
|
|
24001
24455
|
getPythonDir() {
|
|
24002
24456
|
const dir = import.meta.dirname;
|
|
24003
24457
|
const candidates = [
|
|
24004
|
-
|
|
24005
|
-
|
|
24006
|
-
|
|
24458
|
+
path24.join(dir, "python"),
|
|
24459
|
+
path24.resolve(dir, "..", "src", "memory", "everos", "python"),
|
|
24460
|
+
path24.resolve(dir, "..", "..", "..", "src", "memory", "everos", "python")
|
|
24007
24461
|
];
|
|
24008
24462
|
for (const candidate of candidates) {
|
|
24009
|
-
if (fs24.existsSync(
|
|
24463
|
+
if (fs24.existsSync(path24.join(candidate, "agentic_server.py"))) {
|
|
24010
24464
|
return candidate;
|
|
24011
24465
|
}
|
|
24012
24466
|
}
|
|
@@ -24015,11 +24469,11 @@ var EverosPlugin = class {
|
|
|
24015
24469
|
async ensureFcntlCompat() {
|
|
24016
24470
|
if (process.platform !== "win32") return;
|
|
24017
24471
|
const venvPython = this.findVenvPython();
|
|
24018
|
-
const venvDir =
|
|
24019
|
-
const sitePackages =
|
|
24020
|
-
const target =
|
|
24472
|
+
const venvDir = path24.dirname(path24.dirname(venvPython));
|
|
24473
|
+
const sitePackages = path24.join(venvDir, "Lib", "site-packages");
|
|
24474
|
+
const target = path24.join(sitePackages, "fcntl.py");
|
|
24021
24475
|
if (fs24.existsSync(target)) return;
|
|
24022
|
-
const source =
|
|
24476
|
+
const source = path24.join(this.getPythonDir(), "fcntl_compat.py");
|
|
24023
24477
|
if (fs24.existsSync(source)) {
|
|
24024
24478
|
try {
|
|
24025
24479
|
fs24.copyFileSync(source, target);
|
|
@@ -24069,7 +24523,7 @@ var EverosPlugin = class {
|
|
|
24069
24523
|
init_task_manager();
|
|
24070
24524
|
|
|
24071
24525
|
// src/skills/scanner.ts
|
|
24072
|
-
import * as
|
|
24526
|
+
import * as path25 from "node:path";
|
|
24073
24527
|
import * as fs25 from "node:fs";
|
|
24074
24528
|
function scanSkills(skillsDir) {
|
|
24075
24529
|
if (!fs25.existsSync(skillsDir)) {
|
|
@@ -24080,7 +24534,7 @@ function scanSkills(skillsDir) {
|
|
|
24080
24534
|
const skills = [];
|
|
24081
24535
|
for (const entry of entries) {
|
|
24082
24536
|
if (!entry.isDirectory()) continue;
|
|
24083
|
-
const skillMdPath =
|
|
24537
|
+
const skillMdPath = path25.join(skillsDir, entry.name, "SKILL.md");
|
|
24084
24538
|
if (!fs25.existsSync(skillMdPath)) continue;
|
|
24085
24539
|
try {
|
|
24086
24540
|
const content = fs25.readFileSync(skillMdPath, "utf-8");
|
|
@@ -24148,7 +24602,7 @@ function parseFrontmatter2(content) {
|
|
|
24148
24602
|
// src/tools/SkillTool/SkillTool.ts
|
|
24149
24603
|
init_registry();
|
|
24150
24604
|
import * as fs26 from "node:fs";
|
|
24151
|
-
import * as
|
|
24605
|
+
import * as path26 from "node:path";
|
|
24152
24606
|
|
|
24153
24607
|
// src/tools/SkillTool/constants.ts
|
|
24154
24608
|
var SKILL_TOOL_NAME2 = "Skill";
|
|
@@ -24225,12 +24679,12 @@ Important:
|
|
|
24225
24679
|
`;
|
|
24226
24680
|
}
|
|
24227
24681
|
function loadSkillContent(skillName) {
|
|
24228
|
-
const skillMdPath =
|
|
24682
|
+
const skillMdPath = path26.join(skillsDirPath, skillName, "SKILL.md");
|
|
24229
24683
|
if (!fs26.existsSync(skillMdPath)) return null;
|
|
24230
24684
|
const content = fs26.readFileSync(skillMdPath, "utf-8");
|
|
24231
24685
|
const bodyMatch = content.match(/^---\s*\n[\s\S]*?\n---\s*\n([\s\S]*)/);
|
|
24232
24686
|
const body = bodyMatch ? bodyMatch[1] : content;
|
|
24233
|
-
const skillDir =
|
|
24687
|
+
const skillDir = path26.dirname(skillMdPath);
|
|
24234
24688
|
const normalizedDir = process.platform === "win32" ? skillDir.replace(/\\/g, "/") : skillDir;
|
|
24235
24689
|
let finalContent = `Base directory for this skill: ${normalizedDir}
|
|
24236
24690
|
|
|
@@ -24505,9 +24959,9 @@ Examples:
|
|
|
24505
24959
|
init_registry();
|
|
24506
24960
|
init_live();
|
|
24507
24961
|
import fs27 from "node:fs";
|
|
24508
|
-
import
|
|
24962
|
+
import path27 from "node:path";
|
|
24509
24963
|
function getHusbandFeishuId(workspace) {
|
|
24510
|
-
const contactsPath =
|
|
24964
|
+
const contactsPath = path27.join(workspace, "prompts", "contacts.md");
|
|
24511
24965
|
try {
|
|
24512
24966
|
const text = fs27.readFileSync(contactsPath, "utf-8");
|
|
24513
24967
|
const m2 = text.match(/\|\s*翀哥\s*\|\s*(ou_[a-f0-9]+)\s*\|/);
|
|
@@ -24710,7 +25164,7 @@ Examples:
|
|
|
24710
25164
|
init_live();
|
|
24711
25165
|
init_registry();
|
|
24712
25166
|
import * as fs28 from "node:fs";
|
|
24713
|
-
import * as
|
|
25167
|
+
import * as path28 from "node:path";
|
|
24714
25168
|
var MIME_MAP = {
|
|
24715
25169
|
".jpg": "jpeg",
|
|
24716
25170
|
".jpeg": "jpeg",
|
|
@@ -24722,7 +25176,7 @@ var MIME_MAP = {
|
|
|
24722
25176
|
function resolveLatestImage(specifiedPath, mediaDir) {
|
|
24723
25177
|
if (specifiedPath && fs28.existsSync(specifiedPath)) return specifiedPath;
|
|
24724
25178
|
if (!fs28.existsSync(mediaDir)) return null;
|
|
24725
|
-
const files = fs28.readdirSync(mediaDir).filter((f2) => /\.(jpg|jpeg|png|webp|gif|bmp)$/i.test(f2)).map((f2) => ({ name: f2, p:
|
|
25179
|
+
const files = fs28.readdirSync(mediaDir).filter((f2) => /\.(jpg|jpeg|png|webp|gif|bmp)$/i.test(f2)).map((f2) => ({ name: f2, p: path28.join(mediaDir, f2), mtime: fs28.statSync(path28.join(mediaDir, f2)).mtimeMs })).sort((a, b2) => b2.mtime - a.mtime);
|
|
24726
25180
|
return files[0]?.p || null;
|
|
24727
25181
|
}
|
|
24728
25182
|
registry.register({
|
|
@@ -24746,13 +25200,13 @@ registry.register({
|
|
|
24746
25200
|
if (!provider?.streamChat) {
|
|
24747
25201
|
return { content: "Error: provider \u4E0D\u53EF\u7528\u3002", isError: true };
|
|
24748
25202
|
}
|
|
24749
|
-
const mediaDir =
|
|
25203
|
+
const mediaDir = path28.join(ctx.stateDir, "media", "inbound");
|
|
24750
25204
|
const imagePath = resolveLatestImage(args.image_path, mediaDir);
|
|
24751
25205
|
if (!imagePath) {
|
|
24752
25206
|
return { content: "Error: no image found. Provide image_path or ensure media/inbound has images.", isError: true };
|
|
24753
25207
|
}
|
|
24754
25208
|
const rawPrompt = args.prompt?.trim() || "\u63CF\u8FF0\u8FD9\u5F20\u56FE\u7247\u7684\u5185\u5BB9";
|
|
24755
|
-
const ext =
|
|
25209
|
+
const ext = path28.extname(imagePath).toLowerCase();
|
|
24756
25210
|
const mime = MIME_MAP[ext] || "jpeg";
|
|
24757
25211
|
const imgB64 = fs28.readFileSync(imagePath).toString("base64");
|
|
24758
25212
|
const userMsg = {
|
|
@@ -24792,13 +25246,13 @@ init_registry();
|
|
|
24792
25246
|
import { execFile } from "node:child_process";
|
|
24793
25247
|
import { promisify } from "node:util";
|
|
24794
25248
|
import * as fs29 from "node:fs";
|
|
24795
|
-
import * as
|
|
25249
|
+
import * as path29 from "node:path";
|
|
24796
25250
|
import * as os3 from "node:os";
|
|
24797
25251
|
var execFileAsync = promisify(execFile);
|
|
24798
|
-
var VOICE_DIR =
|
|
25252
|
+
var VOICE_DIR = path29.join(os3.tmpdir(), "engine-voice");
|
|
24799
25253
|
async function ttsCosyvoice(text, apiKey, model, voice, workspaceId) {
|
|
24800
25254
|
fs29.mkdirSync(VOICE_DIR, { recursive: true });
|
|
24801
|
-
const output =
|
|
25255
|
+
const output = path29.join(VOICE_DIR, `tts_${Date.now()}.wav`);
|
|
24802
25256
|
const script = `
|
|
24803
25257
|
import sys, json, wave, time, threading
|
|
24804
25258
|
import dashscope
|
|
@@ -24863,7 +25317,7 @@ var GPTSOVITS_REF_TEXT = "\u6625\u7720\u4E0D\u89C9\u6653\uFF0C\u5904\u5904\u95FB
|
|
|
24863
25317
|
var GPTSOVITS_REF_LANG = "zh";
|
|
24864
25318
|
async function ttsGptsovits(text) {
|
|
24865
25319
|
fs29.mkdirSync(VOICE_DIR, { recursive: true });
|
|
24866
|
-
const output =
|
|
25320
|
+
const output = path29.join(VOICE_DIR, `tts_${Date.now()}.wav`);
|
|
24867
25321
|
const params = new URLSearchParams({
|
|
24868
25322
|
text,
|
|
24869
25323
|
text_language: "zh",
|
|
@@ -24880,7 +25334,7 @@ async function ttsGptsovits(text) {
|
|
|
24880
25334
|
var EDGE_VOICE = "zh-CN-XiaoxiaoNeural";
|
|
24881
25335
|
async function ttsEdge(text) {
|
|
24882
25336
|
fs29.mkdirSync(VOICE_DIR, { recursive: true });
|
|
24883
|
-
const output =
|
|
25337
|
+
const output = path29.join(VOICE_DIR, `tts_${Date.now()}.mp3`);
|
|
24884
25338
|
const script = `
|
|
24885
25339
|
import asyncio, edge_tts, sys
|
|
24886
25340
|
async def main():
|
|
@@ -24973,7 +25427,7 @@ registry.register({
|
|
|
24973
25427
|
} catch (e) {
|
|
24974
25428
|
return { content: `TTS failed: ${e.message}`, isError: true };
|
|
24975
25429
|
}
|
|
24976
|
-
const ext =
|
|
25430
|
+
const ext = path29.extname(audioPath).toLowerCase();
|
|
24977
25431
|
const mimeMap = { ".mp3": "audio/mpeg", ".wav": "audio/wav", ".m4a": "audio/mp4", ".ogg": "audio/ogg" };
|
|
24978
25432
|
const mimeType = mimeMap[ext] || "audio/mpeg";
|
|
24979
25433
|
const sizeKB = fs29.statSync(audioPath).size / 1024;
|
|
@@ -25004,7 +25458,7 @@ registry.register({
|
|
|
25004
25458
|
init_live();
|
|
25005
25459
|
init_registry();
|
|
25006
25460
|
import * as fs30 from "node:fs";
|
|
25007
|
-
import * as
|
|
25461
|
+
import * as path30 from "node:path";
|
|
25008
25462
|
var FAL_KEY = "3b848fc6-bee5-46e5-8db7-ae81ac16dc28:2f1f15cf394db2d32c9bb9a4f23f3bee";
|
|
25009
25463
|
var FAL_ENDPOINT = "https://fal.run/xai/grok-imagine-image/edit";
|
|
25010
25464
|
var DEFAULT_RESOLUTION = "1k";
|
|
@@ -25120,7 +25574,7 @@ registry.register({
|
|
|
25120
25574
|
const REFERENCES = getReferences(ctx);
|
|
25121
25575
|
const refName = args.reference || "default";
|
|
25122
25576
|
const refEntry = REFERENCES.find((r) => r.name === refName) || REFERENCES[0];
|
|
25123
|
-
const refPath =
|
|
25577
|
+
const refPath = path30.join(ctx.workspace, refEntry.p);
|
|
25124
25578
|
if (!fs30.existsSync(refPath)) {
|
|
25125
25579
|
return { content: `Error: reference image not found at ${refPath}`, isError: true };
|
|
25126
25580
|
}
|
|
@@ -25139,10 +25593,10 @@ registry.register({
|
|
|
25139
25593
|
} catch (err) {
|
|
25140
25594
|
return { content: `Selfie generation failed: ${err.message}`, isError: true };
|
|
25141
25595
|
}
|
|
25142
|
-
const imagesDir =
|
|
25596
|
+
const imagesDir = path30.join(ctx.workspace, "images");
|
|
25143
25597
|
if (!fs30.existsSync(imagesDir)) fs30.mkdirSync(imagesDir, { recursive: true });
|
|
25144
25598
|
const filename = `selfie_${Date.now()}.jpg`;
|
|
25145
|
-
const outputPath =
|
|
25599
|
+
const outputPath = path30.join(imagesDir, filename);
|
|
25146
25600
|
fs30.writeFileSync(outputPath, imageBuffer);
|
|
25147
25601
|
const mgr = ctx.channelManager;
|
|
25148
25602
|
if (mgr) {
|
|
@@ -25154,11 +25608,11 @@ registry.register({
|
|
|
25154
25608
|
mimeType: "image/jpeg"
|
|
25155
25609
|
});
|
|
25156
25610
|
} catch (err) {
|
|
25157
|
-
return { content: `Selfie generated but send failed: ${err.message}. Image: ${
|
|
25611
|
+
return { content: `Selfie generated but send failed: ${err.message}. Image: ${path30.resolve(outputPath)}`, isError: false };
|
|
25158
25612
|
}
|
|
25159
25613
|
return { content: `Selfie sent! Mode: ${mode}, Provider: ${getProvider(ctx)}, Ref: ${refEntry.name}` };
|
|
25160
25614
|
}
|
|
25161
|
-
return { content: `Selfie generated! Mode: ${mode}, Ref: ${refEntry.name}. Image: ${
|
|
25615
|
+
return { content: `Selfie generated! Mode: ${mode}, Ref: ${refEntry.name}. Image: ${path30.resolve(outputPath)}` };
|
|
25162
25616
|
},
|
|
25163
25617
|
isConcurrencySafe: () => false,
|
|
25164
25618
|
interruptBehavior: () => "block",
|
|
@@ -25625,14 +26079,14 @@ init_planModeState();
|
|
|
25625
26079
|
|
|
25626
26080
|
// src/utils/plans.ts
|
|
25627
26081
|
import * as fs32 from "node:fs";
|
|
25628
|
-
import * as
|
|
26082
|
+
import * as path32 from "node:path";
|
|
25629
26083
|
import * as crypto4 from "node:crypto";
|
|
25630
26084
|
var MAX_SLUG_RETRIES = 10;
|
|
25631
26085
|
function generateSlug() {
|
|
25632
26086
|
return crypto4.randomBytes(4).toString("hex");
|
|
25633
26087
|
}
|
|
25634
26088
|
function getPlansDirectory(stateDir) {
|
|
25635
|
-
const plansDir =
|
|
26089
|
+
const plansDir = path32.join(stateDir, "plans");
|
|
25636
26090
|
fs32.mkdirSync(plansDir, { recursive: true });
|
|
25637
26091
|
return plansDir;
|
|
25638
26092
|
}
|
|
@@ -25643,7 +26097,7 @@ function getPlanSlug(sessionId, stateDir) {
|
|
|
25643
26097
|
const plansDir = getPlansDirectory(stateDir);
|
|
25644
26098
|
for (let i = 0; i < MAX_SLUG_RETRIES; i++) {
|
|
25645
26099
|
slug = generateSlug();
|
|
25646
|
-
const filePath =
|
|
26100
|
+
const filePath = path32.join(plansDir, `${slug}.md`);
|
|
25647
26101
|
if (!fs32.existsSync(filePath)) {
|
|
25648
26102
|
break;
|
|
25649
26103
|
}
|
|
@@ -25655,9 +26109,9 @@ function getPlanSlug(sessionId, stateDir) {
|
|
|
25655
26109
|
function getPlanFilePath(sessionId, stateDir, agentId) {
|
|
25656
26110
|
const slug = getPlanSlug(sessionId, stateDir);
|
|
25657
26111
|
if (!agentId) {
|
|
25658
|
-
return
|
|
26112
|
+
return path32.join(getPlansDirectory(stateDir), `${slug}.md`);
|
|
25659
26113
|
}
|
|
25660
|
-
return
|
|
26114
|
+
return path32.join(getPlansDirectory(stateDir), `${slug}-agent-${agentId}.md`);
|
|
25661
26115
|
}
|
|
25662
26116
|
function getPlan(sessionId, stateDir, agentId) {
|
|
25663
26117
|
const filePath = getPlanFilePath(sessionId, stateDir, agentId);
|
|
@@ -26508,7 +26962,7 @@ async function setupFeatures(features, licensedFeatures) {
|
|
|
26508
26962
|
// src/license/license.ts
|
|
26509
26963
|
import * as crypto6 from "node:crypto";
|
|
26510
26964
|
import * as fs39 from "node:fs";
|
|
26511
|
-
import * as
|
|
26965
|
+
import * as path40 from "node:path";
|
|
26512
26966
|
var EMBEDDED_PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----
|
|
26513
26967
|
MCowBQYDK2VwAyEAaKBEX+e8+D59qwtidazsu7WYDglApyvsVI3APwFoakA=
|
|
26514
26968
|
-----END PUBLIC KEY-----`;
|
|
@@ -26539,7 +26993,7 @@ function loadLicense(stateDir, devMode) {
|
|
|
26539
26993
|
_cachedLicense = allActive;
|
|
26540
26994
|
return allActive;
|
|
26541
26995
|
}
|
|
26542
|
-
const licensePath =
|
|
26996
|
+
const licensePath = path40.join(stateDir, "license.json");
|
|
26543
26997
|
if (!fs39.existsSync(licensePath)) {
|
|
26544
26998
|
console.log("[license] No license.json found, running basic engine only");
|
|
26545
26999
|
return null;
|
|
@@ -26608,14 +27062,14 @@ var EverosSearchSchema = {
|
|
|
26608
27062
|
type: "object",
|
|
26609
27063
|
properties: {
|
|
26610
27064
|
query: { type: "string", description: "\u641C\u7D22\u67E5\u8BE2" },
|
|
26611
|
-
maxResults: { type: "number", description: "\u6700\u5927\u8FD4\u56DE\u6570 (\u9ED8\
|
|
27065
|
+
maxResults: { type: "number", description: "\u6700\u5927\u8FD4\u56DE\u6570 (\u9ED8\u8BA410)" },
|
|
27066
|
+
mode: { type: "string", enum: ["hybrid", "hybrid_agentic", "agentic"], description: "\u68C0\u7D22\u6A21\u5F0F: hybrid=\u5FEB(3s\u7CBE\u786E\u5B9E\u4F53), hybrid_agentic=\u6027\u4EF7\u6BD4\u4E4B\u738B(5-14s\u9ED8\u8BA4), agentic=\u6DF1\u5EA6\u63A8\u7406(44s\u590D\u6742\u67E5\u8BE2)" }
|
|
26612
27067
|
},
|
|
26613
27068
|
required: ["query"]
|
|
26614
27069
|
};
|
|
26615
27070
|
function createEverosSearchTool(everosCfg) {
|
|
26616
27071
|
const agenticUrl = (everosCfg?.agenticUrl || "http://127.0.0.1:8101").replace(/\/$/, "");
|
|
26617
27072
|
const userId = everosCfg?.userId || "xiaomei";
|
|
26618
|
-
const defaultMode = everosCfg?.defaultMode || "hybrid_agentic";
|
|
26619
27073
|
return {
|
|
26620
27074
|
name: "memory_search",
|
|
26621
27075
|
description: "Mandatory recall step: semantically search memory before answering questions about prior work, decisions, dates, people, preferences, or todos.",
|
|
@@ -26624,6 +27078,7 @@ function createEverosSearchTool(everosCfg) {
|
|
|
26624
27078
|
const query = args.query;
|
|
26625
27079
|
if (!query) return { content: "\u7F3A\u5C11 query \u53C2\u6570" };
|
|
26626
27080
|
const topK = args.maxResults ?? 10;
|
|
27081
|
+
const mode = args.mode || "hybrid_agentic";
|
|
26627
27082
|
const ctrl = new AbortController();
|
|
26628
27083
|
const timer = setTimeout(() => ctrl.abort(), 3e4);
|
|
26629
27084
|
try {
|
|
@@ -26633,7 +27088,7 @@ function createEverosSearchTool(everosCfg) {
|
|
|
26633
27088
|
body: JSON.stringify({
|
|
26634
27089
|
query,
|
|
26635
27090
|
user_id: userId,
|
|
26636
|
-
mode
|
|
27091
|
+
mode,
|
|
26637
27092
|
top_k: topK
|
|
26638
27093
|
}),
|
|
26639
27094
|
signal: ctrl.signal
|
|
@@ -26641,7 +27096,7 @@ function createEverosSearchTool(everosCfg) {
|
|
|
26641
27096
|
clearTimeout(timer);
|
|
26642
27097
|
if (!resp.ok) {
|
|
26643
27098
|
const text = await resp.text();
|
|
26644
|
-
console.warn(`[
|
|
27099
|
+
console.warn(`[memory_search] failed: ${resp.status} ${text.slice(0, 200)}`);
|
|
26645
27100
|
return { content: "\u6CA1\u6709\u627E\u5230\u76F8\u5173\u8BB0\u5FC6\u3002" };
|
|
26646
27101
|
}
|
|
26647
27102
|
const data = await resp.json();
|
|
@@ -26650,7 +27105,7 @@ function createEverosSearchTool(everosCfg) {
|
|
|
26650
27105
|
return { content: "\u6CA1\u6709\u627E\u5230\u76F8\u5173\u8BB0\u5FC6\u3002" };
|
|
26651
27106
|
}
|
|
26652
27107
|
const formatted = episodes.map((ep, i) => {
|
|
26653
|
-
const score = ep.score != null ? ` (score: ${ep.score.toFixed(3)})` : "";
|
|
27108
|
+
const score = ep.score != null ? ` (score: ${typeof ep.score === "number" ? ep.score.toFixed(3) : ep.score})` : "";
|
|
26654
27109
|
const subject = ep.subject || "";
|
|
26655
27110
|
const ts = ep.timestamp ? ` [${ep.timestamp}]` : "";
|
|
26656
27111
|
return `### ${i + 1}. ${subject}${ts}${score}
|
|
@@ -26662,9 +27117,9 @@ ${formatted}` };
|
|
|
26662
27117
|
} catch (err) {
|
|
26663
27118
|
clearTimeout(timer);
|
|
26664
27119
|
if (err.name === "AbortError") {
|
|
26665
|
-
console.warn(`[
|
|
27120
|
+
console.warn(`[memory_search] timeout: ${query.slice(0, 50)}`);
|
|
26666
27121
|
} else {
|
|
26667
|
-
console.warn(`[
|
|
27122
|
+
console.warn(`[memory_search] error: ${err.message}`);
|
|
26668
27123
|
}
|
|
26669
27124
|
return { content: "\u6CA1\u6709\u627E\u5230\u76F8\u5173\u8BB0\u5FC6\u3002" };
|
|
26670
27125
|
}
|
|
@@ -27163,9 +27618,9 @@ async function startEngine(config, opts) {
|
|
|
27163
27618
|
process.env.ENGINE_MEDIA_DIR = config.mediaDir;
|
|
27164
27619
|
process.env.ENGINE7_WORKSPACE = config.workspace;
|
|
27165
27620
|
process.env.OPENCLAW_WORKSPACE = config.workspace;
|
|
27166
|
-
fs41.mkdirSync(
|
|
27167
|
-
fs41.mkdirSync(
|
|
27168
|
-
fs41.mkdirSync(
|
|
27621
|
+
fs41.mkdirSync(path43.join(config.stateDir, "agents", "main", "memory"), { recursive: true });
|
|
27622
|
+
fs41.mkdirSync(path43.join(config.stateDir, "agents", "main", "sessions"), { recursive: true });
|
|
27623
|
+
fs41.mkdirSync(path43.join(config.stateDir, "logs"), { recursive: true });
|
|
27169
27624
|
fs41.mkdirSync(config.workspace, { recursive: true });
|
|
27170
27625
|
fs41.mkdirSync(config.mediaDir, { recursive: true });
|
|
27171
27626
|
try {
|
|
@@ -27275,7 +27730,7 @@ async function startEngine(config, opts) {
|
|
|
27275
27730
|
const { initSessionMemory: initSessionMemory2 } = await Promise.resolve().then(() => (init_sessionMemory(), sessionMemory_exports));
|
|
27276
27731
|
initSessionMemory2({
|
|
27277
27732
|
workspace: config.workspace,
|
|
27278
|
-
stateDir:
|
|
27733
|
+
stateDir: path43.join(config.stateDir, "session-memory"),
|
|
27279
27734
|
provider,
|
|
27280
27735
|
model: config.provider.modelId || config.model || "deepseek-v4-flash",
|
|
27281
27736
|
features: config.profile.features
|
|
@@ -27305,9 +27760,9 @@ async function startEngine(config, opts) {
|
|
|
27305
27760
|
if (config.hooks) {
|
|
27306
27761
|
loadHooksFromConfig({ hooks: config.hooks });
|
|
27307
27762
|
}
|
|
27308
|
-
const hooksPath =
|
|
27763
|
+
const hooksPath = path43.join(config.workspace, ".hooks.json");
|
|
27309
27764
|
loadHooksFromFile(hooksPath);
|
|
27310
|
-
const settingsHooksPath =
|
|
27765
|
+
const settingsHooksPath = path43.join(config.stateDir, "settings.json");
|
|
27311
27766
|
loadHooksFromFile(settingsHooksPath);
|
|
27312
27767
|
console.log(`[hooks] Loaded hooks configuration`);
|
|
27313
27768
|
registerCallbackHook("PreCompact", {
|
|
@@ -27321,15 +27776,15 @@ async function startEngine(config, opts) {
|
|
|
27321
27776
|
const bjTime = new Date(now.getTime() + (bjOffset + now.getTimezoneOffset()) * 6e4);
|
|
27322
27777
|
const dateStr = `${bjTime.getFullYear()}-${String(bjTime.getMonth() + 1).padStart(2, "0")}-${String(bjTime.getDate()).padStart(2, "0")}`;
|
|
27323
27778
|
const timeStr = `${String(bjTime.getHours()).padStart(2, "0")}:${String(bjTime.getMinutes()).padStart(2, "0")}`;
|
|
27324
|
-
const dailyDir =
|
|
27325
|
-
const dailyPath =
|
|
27779
|
+
const dailyDir = path43.join(workspace, "memory", "daily");
|
|
27780
|
+
const dailyPath = path43.join(dailyDir, `${dateStr}.md`);
|
|
27326
27781
|
try {
|
|
27327
27782
|
const fs42 = await import("node:fs");
|
|
27328
27783
|
if (!fs42.existsSync(dailyDir)) {
|
|
27329
27784
|
fs42.mkdirSync(dailyDir, { recursive: true });
|
|
27330
27785
|
}
|
|
27331
|
-
const sessionsDir =
|
|
27332
|
-
const sessionFile =
|
|
27786
|
+
const sessionsDir = path43.join(config.stateDir, "agents", "main", "sessions");
|
|
27787
|
+
const sessionFile = path43.join(sessionsDir, `${sessionId}.jsonl`);
|
|
27333
27788
|
const recentLines = [];
|
|
27334
27789
|
if (fs42.existsSync(sessionFile)) {
|
|
27335
27790
|
const content = fs42.readFileSync(sessionFile, "utf-8");
|
|
@@ -27382,7 +27837,7 @@ ${entry}`);
|
|
|
27382
27837
|
if (!workspace) return { continue: true };
|
|
27383
27838
|
try {
|
|
27384
27839
|
const fs42 = await import("node:fs");
|
|
27385
|
-
const bufferPath =
|
|
27840
|
+
const bufferPath = path43.join(workspace, "memory", "working-buffer.md");
|
|
27386
27841
|
if (fs42.existsSync(bufferPath)) {
|
|
27387
27842
|
const stat4 = fs42.statSync(bufferPath);
|
|
27388
27843
|
const ageMs = Date.now() - stat4.mtimeMs;
|
|
@@ -27435,7 +27890,7 @@ ${content}`
|
|
|
27435
27890
|
return `${hr}h ${remMin}m`;
|
|
27436
27891
|
}
|
|
27437
27892
|
if (config.skills?.enabled !== false) {
|
|
27438
|
-
const skillsDir = config.skills?.path ?
|
|
27893
|
+
const skillsDir = config.skills?.path ? path43.isAbsolute(config.skills.path) ? config.skills.path : path43.resolve(config.workspace, config.skills.path) : path43.resolve(config.workspace, "skills");
|
|
27439
27894
|
const modelDef2 = config.provider.models.find((m2) => m2.id === config.model);
|
|
27440
27895
|
const contextWindowTokens = modelDef2?.contextWindow;
|
|
27441
27896
|
const skills = scanSkills(skillsDir);
|
|
@@ -27454,7 +27909,7 @@ ${content}`
|
|
|
27454
27909
|
workspace: config.workspace
|
|
27455
27910
|
});
|
|
27456
27911
|
const systemPrompt = [systemStable, systemDynamic].join("\n\n");
|
|
27457
|
-
const promptDumpPath =
|
|
27912
|
+
const promptDumpPath = path43.join(config.workspace, ".system-prompt.txt");
|
|
27458
27913
|
fs41.writeFileSync(promptDumpPath, systemPrompt);
|
|
27459
27914
|
console.log(`System prompt: ${systemStable.length} chars stable + ${systemDynamic.length} chars dynamic \u2192 ${promptDumpPath}`);
|
|
27460
27915
|
const modelDef = config.provider.models.find((m2) => m2.id === config.model);
|
|
@@ -27565,20 +28020,23 @@ ${content}`
|
|
|
27565
28020
|
enabled: true,
|
|
27566
28021
|
url: everosCfg.everosUrl || "http://127.0.0.1:8100",
|
|
27567
28022
|
appId: everosCfg.userId || "default",
|
|
27568
|
-
userId: everosCfg.userId || "default"
|
|
28023
|
+
userId: everosCfg.userId || "default",
|
|
28024
|
+
agentName: everosCfg.agentName || everosCfg.userId || "assistant"
|
|
27569
28025
|
});
|
|
27570
28026
|
sessions.onWriterCreated = (writer, sessionId) => {
|
|
27571
28027
|
writer.onMessageWritten = (msg2) => {
|
|
28028
|
+
console.log(`[everos-sync] onMessageWritten fired: role=${msg2.role} len=${msg2.text.length}`);
|
|
27572
28029
|
everosSync.push({
|
|
27573
28030
|
sessionId: writer.engineSessionId || sessionId,
|
|
27574
28031
|
role: msg2.role === "toolResult" ? "tool" : msg2.role,
|
|
27575
28032
|
text: msg2.text,
|
|
27576
28033
|
timestamp: new Date(msg2.timestamp).getTime()
|
|
27577
|
-
}).catch(() => {
|
|
27578
|
-
});
|
|
28034
|
+
}).catch((e) => console.warn(`[everos-sync] push error: ${e}`));
|
|
27579
28035
|
};
|
|
27580
28036
|
};
|
|
27581
28037
|
console.log(`[everos-sync] hook registered (appId=${everosCfg.userId})`);
|
|
28038
|
+
} else {
|
|
28039
|
+
console.log(`[everos-sync] SKIPPED \u2014 config.everos not enabled or missing`);
|
|
27582
28040
|
}
|
|
27583
28041
|
const channelManager = new ChannelManager();
|
|
27584
28042
|
const memoryRecallProvider = createMemorySideProvider(
|
|
@@ -27609,6 +28067,7 @@ ${content}`
|
|
|
27609
28067
|
recallProvider: memoryRecallProvider || void 0,
|
|
27610
28068
|
extractProvider: memoryExtractProvider || void 0,
|
|
27611
28069
|
topics: config.topics,
|
|
28070
|
+
everosCfg: config.everos,
|
|
27612
28071
|
mcpManager
|
|
27613
28072
|
};
|
|
27614
28073
|
if (visionEngine && visionConfig) {
|
|
@@ -28529,8 +28988,8 @@ Auto-routing disabled \u2014 all messages use this model.
|
|
|
28529
28988
|
let writePath = configPath;
|
|
28530
28989
|
if (configPath && !fs41.existsSync(configPath)) {
|
|
28531
28990
|
const __pFile = fileURLToPath(import.meta.url);
|
|
28532
|
-
const __pDir =
|
|
28533
|
-
const altPath =
|
|
28991
|
+
const __pDir = path43.dirname(__pFile);
|
|
28992
|
+
const altPath = path43.join(path43.resolve(__pDir, "../configs"), path43.basename(configPath));
|
|
28534
28993
|
if (fs41.existsSync(altPath)) {
|
|
28535
28994
|
console.warn(`[primary] Config not found at ${configPath}, falling back to ${altPath}`);
|
|
28536
28995
|
writePath = altPath;
|
|
@@ -28810,7 +29269,7 @@ Use full ref like \`/vision-model ${candidates[0].ref}\``);
|
|
|
28810
29269
|
const ext = detected.split("/")[1] || "png";
|
|
28811
29270
|
const resized = await maybeResizeAndDownsampleImageBuffer2(rawBuffer, rawBuffer.length, ext);
|
|
28812
29271
|
const imageId = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
28813
|
-
const savedPath =
|
|
29272
|
+
const savedPath = path43.join(config.mediaDir, `${imageId}.${ext}`);
|
|
28814
29273
|
fs41.writeFileSync(savedPath, resized.buffer);
|
|
28815
29274
|
savedPaths.push(savedPath);
|
|
28816
29275
|
console.log(`[vision] Saved: ${savedPath} (${resized.buffer.length}B)`);
|
|
@@ -28837,7 +29296,7 @@ ${pathStr}` }];
|
|
|
28837
29296
|
}
|
|
28838
29297
|
const nonImageAttachments = inbound.attachments?.filter((a) => !a.contentType.startsWith("image/"));
|
|
28839
29298
|
if (nonImageAttachments && nonImageAttachments.length > 0) {
|
|
28840
|
-
const outDir =
|
|
29299
|
+
const outDir = path43.join(config.mediaDir, sessionId);
|
|
28841
29300
|
fs41.mkdirSync(outDir, { recursive: true });
|
|
28842
29301
|
const resolved = [];
|
|
28843
29302
|
for (const att of nonImageAttachments) {
|
|
@@ -28846,8 +29305,8 @@ ${pathStr}` }];
|
|
|
28846
29305
|
const resp = await fetch(att.url);
|
|
28847
29306
|
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
|
|
28848
29307
|
const buffer = Buffer.from(await resp.arrayBuffer());
|
|
28849
|
-
const safeName2 =
|
|
28850
|
-
const savedPath =
|
|
29308
|
+
const safeName2 = path43.basename(att.filename).replace(/[<>:"/\\|?*\x00-\x1f]/g, "_") || "attachment";
|
|
29309
|
+
const savedPath = path43.join(outDir, safeName2);
|
|
28851
29310
|
fs41.writeFileSync(savedPath, buffer);
|
|
28852
29311
|
resolved.push(savedPath);
|
|
28853
29312
|
console.log(`[file] Saved: ${savedPath} (${buffer.length}B)`);
|
|
@@ -29195,7 +29654,8 @@ ${pathStr}` }];
|
|
|
29195
29654
|
if (config.cognifold?.intentWatcher?.enabled) {
|
|
29196
29655
|
try {
|
|
29197
29656
|
const { registerCognifoldIntentWatcher: registerCognifoldIntentWatcher2 } = await Promise.resolve().then(() => (init_cognifold_intent_watcher(), cognifold_intent_watcher_exports));
|
|
29198
|
-
const
|
|
29657
|
+
const sm = globalThis.__cognifoldSessions;
|
|
29658
|
+
const cfSessionId = sm?.getSessionId?.("main") || config.cognifold.sessionId;
|
|
29199
29659
|
if (!cfSessionId) {
|
|
29200
29660
|
console.warn("[cognifold] intent-watcher: config.cognifold.sessionId \u672A\u914D\u7F6E\uFF0C\u8DF3\u8FC7 watcher");
|
|
29201
29661
|
} else {
|
|
@@ -29208,7 +29668,7 @@ ${pathStr}` }];
|
|
|
29208
29668
|
console.warn("[cognifold] watcher: config.workspace \u672A\u914D\u7F6E\uFF0C\u8DF3\u8FC7 proactive \u5199\u5165");
|
|
29209
29669
|
return;
|
|
29210
29670
|
}
|
|
29211
|
-
const pFile =
|
|
29671
|
+
const pFile = path43.join(wsDir, ".cognifold-proactive.json");
|
|
29212
29672
|
const cognifoldBaseUrl = config.cognifold?.baseUrl || "http://127.0.0.1:9001";
|
|
29213
29673
|
const cognifoldSessionId = cfSessionId;
|
|
29214
29674
|
const rawSuggestions = data.suggestions || data.actions || (data.intent_id ? [data] : []);
|
|
@@ -29262,7 +29722,7 @@ ${pathStr}` }];
|
|
|
29262
29722
|
console.error(`[cognifold] failed to save proactive: ${e.message}`);
|
|
29263
29723
|
}
|
|
29264
29724
|
if (enriched.length > 0) {
|
|
29265
|
-
const promptFile =
|
|
29725
|
+
const promptFile = path43.join(config.workspace, "prompts", "cognifold-proactive.md");
|
|
29266
29726
|
const promptText = fs41.existsSync(promptFile) ? fs41.readFileSync(promptFile, "utf-8") : "[CogniFold proactive] \u6709 " + enriched.length + " \u4E2A action \u5230\u671F\u4E86";
|
|
29267
29727
|
const actionsJson = JSON.stringify(enriched, null, 2);
|
|
29268
29728
|
const sessionId = cfSessionId;
|
|
@@ -29368,9 +29828,9 @@ async function doReloadConfig(config, deps, provider) {
|
|
|
29368
29828
|
let reloadConfigPath = savedConfigPath;
|
|
29369
29829
|
if (!fs41.existsSync(reloadConfigPath)) {
|
|
29370
29830
|
const __filename = fileURLToPath(import.meta.url);
|
|
29371
|
-
const __dirname =
|
|
29372
|
-
const engineConfigsDir =
|
|
29373
|
-
const altPath =
|
|
29831
|
+
const __dirname = path43.dirname(__filename);
|
|
29832
|
+
const engineConfigsDir = path43.resolve(__dirname, "../configs");
|
|
29833
|
+
const altPath = path43.join(engineConfigsDir, path43.basename(savedConfigPath));
|
|
29374
29834
|
if (fs41.existsSync(altPath)) {
|
|
29375
29835
|
console.warn(`[reload] Config not found at ${reloadConfigPath}, falling back to ${altPath} (dev mode)`);
|
|
29376
29836
|
reloadConfigPath = altPath;
|
|
@@ -29423,7 +29883,7 @@ async function doReloadConfig(config, deps, provider) {
|
|
|
29423
29883
|
} catch (err) {
|
|
29424
29884
|
console.error(`[reload] Failed: ${err.message}`);
|
|
29425
29885
|
try {
|
|
29426
|
-
fs41.appendFileSync(
|
|
29886
|
+
fs41.appendFileSync(path43.join(config.stateDir, "logs", "engine-config-watch.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] RELOAD FAILED: ${err.message}
|
|
29427
29887
|
${err.stack}
|
|
29428
29888
|
`);
|
|
29429
29889
|
} catch {
|
|
@@ -29435,17 +29895,17 @@ function startConfigWatcher(config, deps, provider) {
|
|
|
29435
29895
|
const raw = config._configFilePath;
|
|
29436
29896
|
let configPath = raw;
|
|
29437
29897
|
if (!fs41.existsSync(configPath)) {
|
|
29438
|
-
configPath =
|
|
29898
|
+
configPath = path43.resolve(raw);
|
|
29439
29899
|
}
|
|
29440
29900
|
if (!fs41.existsSync(configPath)) {
|
|
29441
29901
|
const __filename2 = fileURLToPath(import.meta.url);
|
|
29442
|
-
const __dirname2 =
|
|
29443
|
-
configPath =
|
|
29902
|
+
const __dirname2 = path43.dirname(__filename2);
|
|
29903
|
+
configPath = path43.resolve(__dirname2, "..", raw);
|
|
29444
29904
|
}
|
|
29445
29905
|
if (!fs41.existsSync(configPath)) {
|
|
29446
29906
|
console.warn(`[config-watch] config path invalid: ${configPath}, watcher disabled`);
|
|
29447
29907
|
try {
|
|
29448
|
-
fs41.appendFileSync(
|
|
29908
|
+
fs41.appendFileSync(path43.join(config.stateDir, "logs", "engine-config-watch.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] DISABLED: configPath=${configPath}
|
|
29449
29909
|
`);
|
|
29450
29910
|
} catch {
|
|
29451
29911
|
}
|
|
@@ -29457,13 +29917,13 @@ function startConfigWatcher(config, deps, provider) {
|
|
|
29457
29917
|
debounceTimer = setTimeout(async () => {
|
|
29458
29918
|
console.log(`[config-watch] file changed (${eventType}), reloading...`);
|
|
29459
29919
|
try {
|
|
29460
|
-
fs41.appendFileSync(
|
|
29920
|
+
fs41.appendFileSync(path43.join(config.stateDir, "logs", "engine-config-watch.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] CHANGE eventType=${eventType}, calling doReloadConfig
|
|
29461
29921
|
`);
|
|
29462
29922
|
} catch {
|
|
29463
29923
|
}
|
|
29464
29924
|
const result = await doReloadConfig(config, deps, provider);
|
|
29465
29925
|
try {
|
|
29466
|
-
fs41.appendFileSync(
|
|
29926
|
+
fs41.appendFileSync(path43.join(config.stateDir, "logs", "engine-config-watch.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] RELOAD DONE: ok=${result.ok} changes=${result.changes.join(",")}
|
|
29467
29927
|
`);
|
|
29468
29928
|
} catch {
|
|
29469
29929
|
}
|
|
@@ -29472,14 +29932,14 @@ function startConfigWatcher(config, deps, provider) {
|
|
|
29472
29932
|
watcher.on("error", (err) => {
|
|
29473
29933
|
console.error(`[config-watch] error: ${err.message}`);
|
|
29474
29934
|
try {
|
|
29475
|
-
fs41.appendFileSync(
|
|
29935
|
+
fs41.appendFileSync(path43.join(config.stateDir, "logs", "engine-config-watch.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] ERROR: ${err.message}
|
|
29476
29936
|
`);
|
|
29477
29937
|
} catch {
|
|
29478
29938
|
}
|
|
29479
29939
|
});
|
|
29480
29940
|
console.log(`[config-watch] watching ${configPath}`);
|
|
29481
29941
|
try {
|
|
29482
|
-
fs41.appendFileSync(
|
|
29942
|
+
fs41.appendFileSync(path43.join(config.stateDir, "logs", "engine-config-watch.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] STARTED watching=${configPath}
|
|
29483
29943
|
`);
|
|
29484
29944
|
} catch {
|
|
29485
29945
|
}
|