engine7 7.1.23 → 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 +786 -311
- package/dist/main.mjs +787 -312
- 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/main.mjs
CHANGED
|
@@ -985,8 +985,10 @@ async function executeStopHooks(ctx, signal, lastAssistantMessage) {
|
|
|
985
985
|
cwd: ctx.cwd,
|
|
986
986
|
stop_hook_active: false,
|
|
987
987
|
last_assistant_message: lastAssistantMessage,
|
|
988
|
-
channel: ctx.channel
|
|
988
|
+
channel: ctx.channel,
|
|
989
989
|
// 让 callback hook 能判断来源
|
|
990
|
+
source: ctx.source || ""
|
|
991
|
+
// 消息来源(heartbeat/cron/system 等注入 turn 可据此跳过)
|
|
990
992
|
};
|
|
991
993
|
return executeHooks("Stop", hookInput, ctx, signal);
|
|
992
994
|
}
|
|
@@ -1338,6 +1340,7 @@ function collectSurfacedMemories(messages) {
|
|
|
1338
1340
|
return { paths };
|
|
1339
1341
|
}
|
|
1340
1342
|
function normalizePath(p2) {
|
|
1343
|
+
if (p2.startsWith("everos://")) return p2;
|
|
1341
1344
|
return pathResolve(p2);
|
|
1342
1345
|
}
|
|
1343
1346
|
function memoryHeader(filePath, mtimeMs) {
|
|
@@ -2784,10 +2787,12 @@ function breakdownMessages(messages) {
|
|
|
2784
2787
|
if (memCount === 0) console.log(`[context-analyzer] WARNING: relevant_memories attachment with 0 memories! keys=${Object.keys(m2.attachment).join(",")}`);
|
|
2785
2788
|
for (const mem of m2.attachment.memories || []) {
|
|
2786
2789
|
const fileName = mem.path.split(/[/\\]/).pop() || mem.path;
|
|
2790
|
+
const scoreMatch = mem.header?.match(/score=([\d.]+)/);
|
|
2787
2791
|
recalledTopics.push({
|
|
2788
2792
|
path: fileName,
|
|
2789
2793
|
tokens: roughTokenCountEstimation(mem.content),
|
|
2790
|
-
stable: false
|
|
2794
|
+
stable: false,
|
|
2795
|
+
score: scoreMatch ? scoreMatch[1] : void 0
|
|
2791
2796
|
});
|
|
2792
2797
|
}
|
|
2793
2798
|
}
|
|
@@ -2998,13 +3003,25 @@ function formatContextReport(report) {
|
|
|
2998
3003
|
output += `### Recalled Memories (${rt.length})
|
|
2999
3004
|
|
|
3000
3005
|
`;
|
|
3001
|
-
|
|
3006
|
+
const hasScore = rt.some((t) => t.score);
|
|
3007
|
+
if (hasScore) {
|
|
3008
|
+
output += `| File | Score | Tokens |
|
|
3002
3009
|
`;
|
|
3003
|
-
|
|
3010
|
+
output += `|------|-------|--------|
|
|
3011
|
+
`;
|
|
3012
|
+
for (const t of rt) {
|
|
3013
|
+
output += `| ${t.path} | ${t.score ?? "-"} | ${formatTokens(t.tokens)} |
|
|
3014
|
+
`;
|
|
3015
|
+
}
|
|
3016
|
+
} else {
|
|
3017
|
+
output += `| File | Tokens |
|
|
3018
|
+
`;
|
|
3019
|
+
output += `|------|--------|
|
|
3004
3020
|
`;
|
|
3005
|
-
|
|
3006
|
-
|
|
3021
|
+
for (const t of rt) {
|
|
3022
|
+
output += `| ${t.path} | ${formatTokens(t.tokens)} |
|
|
3007
3023
|
`;
|
|
3024
|
+
}
|
|
3008
3025
|
}
|
|
3009
3026
|
output += "\n";
|
|
3010
3027
|
}
|
|
@@ -3342,7 +3359,8 @@ ${perTurnSystemDynamic}` : deferredHint || perTurnSystemDynamic;
|
|
|
3342
3359
|
sessionId: context?.sessionId || "default",
|
|
3343
3360
|
workspace: context?.workspace || "",
|
|
3344
3361
|
channel: context?.channel || "",
|
|
3345
|
-
cwd: context?.workspace || ""
|
|
3362
|
+
cwd: context?.workspace || "",
|
|
3363
|
+
source: typeof context?.source === "string" ? context.source : ""
|
|
3346
3364
|
};
|
|
3347
3365
|
const stopResult = await executeStopHooks(stopCtx, ac.signal, textContent);
|
|
3348
3366
|
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(args2, searchPath, signal) {
|
|
7220
7238
|
return new Promise((resolve10) => {
|
|
7221
7239
|
const fullArgs = [...args2, 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 (args2) => {
|
|
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 (args2.task_id) {
|
|
11226
|
-
const file =
|
|
11244
|
+
const file = path44.join(resultsDir, `${args2.task_id}.json`);
|
|
11227
11245
|
if (!fs42.existsSync(file)) {
|
|
11228
11246
|
return { content: `\u4EFB\u52A1 ${args2.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 ? "..." : ""}`;
|
|
@@ -11622,7 +11640,7 @@ __export(license_exports, {
|
|
|
11622
11640
|
});
|
|
11623
11641
|
import * as crypto6 from "node:crypto";
|
|
11624
11642
|
import * as fs39 from "node:fs";
|
|
11625
|
-
import * as
|
|
11643
|
+
import * as path40 from "node:path";
|
|
11626
11644
|
function loadLicense(stateDir, devMode) {
|
|
11627
11645
|
if (_licenseChecked) return _cachedLicense;
|
|
11628
11646
|
_licenseChecked = true;
|
|
@@ -11635,7 +11653,7 @@ function loadLicense(stateDir, devMode) {
|
|
|
11635
11653
|
_cachedLicense = allActive;
|
|
11636
11654
|
return allActive;
|
|
11637
11655
|
}
|
|
11638
|
-
const licensePath =
|
|
11656
|
+
const licensePath = path40.join(stateDir, "license.json");
|
|
11639
11657
|
if (!fs39.existsSync(licensePath)) {
|
|
11640
11658
|
console.log("[license] No license.json found, running basic engine only");
|
|
11641
11659
|
return null;
|
|
@@ -11691,7 +11709,7 @@ function isFeatureLicensed(featureId) {
|
|
|
11691
11709
|
return f2?.active === true;
|
|
11692
11710
|
}
|
|
11693
11711
|
function getLicenseStatus(stateDir) {
|
|
11694
|
-
const licensePath =
|
|
11712
|
+
const licensePath = path40.join(stateDir, "license.json");
|
|
11695
11713
|
if (!fs39.existsSync(licensePath)) {
|
|
11696
11714
|
return { licensed: false, features: {} };
|
|
11697
11715
|
}
|
|
@@ -11756,7 +11774,7 @@ __export(manager_exports, {
|
|
|
11756
11774
|
McpManager: () => McpManager
|
|
11757
11775
|
});
|
|
11758
11776
|
import * as fs40 from "node:fs";
|
|
11759
|
-
import * as
|
|
11777
|
+
import * as path41 from "node:path";
|
|
11760
11778
|
import { Client as Client3 } from "@modelcontextprotocol/sdk/client/index.js";
|
|
11761
11779
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
11762
11780
|
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
@@ -11789,9 +11807,9 @@ function convertInputSchema(inputSchema) {
|
|
|
11789
11807
|
}
|
|
11790
11808
|
function persistBinary(base64Data, mimeType, persistId) {
|
|
11791
11809
|
const ext = mimeType?.split("/")[1] || "bin";
|
|
11792
|
-
const dir =
|
|
11810
|
+
const dir = path41.join(process.env.ENGINE_STATE_DIR || ".engine", "mcp-blobs");
|
|
11793
11811
|
fs40.mkdirSync(dir, { recursive: true });
|
|
11794
|
-
const filepath =
|
|
11812
|
+
const filepath = path41.join(dir, `${persistId}.${ext}`);
|
|
11795
11813
|
try {
|
|
11796
11814
|
const buf = Buffer.from(base64Data, "base64");
|
|
11797
11815
|
fs40.writeFileSync(filepath, buf);
|
|
@@ -12128,7 +12146,7 @@ __export(resources_exports, {
|
|
|
12128
12146
|
registerMcpResourceTools: () => registerMcpResourceTools,
|
|
12129
12147
|
unregisterMcpResourceTools: () => unregisterMcpResourceTools
|
|
12130
12148
|
});
|
|
12131
|
-
import * as
|
|
12149
|
+
import * as path42 from "node:path";
|
|
12132
12150
|
function registerMcpResourceTools(manager) {
|
|
12133
12151
|
mcpManagerRef = manager;
|
|
12134
12152
|
registry.register(listResourcesTool);
|
|
@@ -12146,7 +12164,7 @@ var init_resources = __esm({
|
|
|
12146
12164
|
"use strict";
|
|
12147
12165
|
init_registry();
|
|
12148
12166
|
MAX_RESULT_CHARS2 = 1e5;
|
|
12149
|
-
MEDIA_DIR = process.env.ENGINE_MEDIA_DIR ||
|
|
12167
|
+
MEDIA_DIR = process.env.ENGINE_MEDIA_DIR || path42.join(process.env.ENGINE_STATE_DIR || ".engine", "media", "inbound");
|
|
12150
12168
|
MCP_LIST_RESOURCES_TOOL = "mcp__list_resources";
|
|
12151
12169
|
MCP_READ_RESOURCE_TOOL = "mcp__read_resource";
|
|
12152
12170
|
mcpManagerRef = null;
|
|
@@ -12236,11 +12254,21 @@ var everos_sync_exports = {};
|
|
|
12236
12254
|
__export(everos_sync_exports, {
|
|
12237
12255
|
createEverosSync: () => createEverosSync
|
|
12238
12256
|
});
|
|
12257
|
+
function parseMeta(text) {
|
|
12258
|
+
const m2 = text.match(/^\[meta:\s*(.+?)\s*\((.+?)\)\s*@(\S+)\s*[^\]]*\]/);
|
|
12259
|
+
if (!m2) return null;
|
|
12260
|
+
return { senderName: m2[1].trim(), senderId: m2[2].trim(), platform: m2[3].trim() };
|
|
12261
|
+
}
|
|
12239
12262
|
function createEverosSync(cfg) {
|
|
12240
|
-
const { enabled, url, appId, userId } = cfg;
|
|
12263
|
+
const { enabled, url, appId, userId, agentName } = cfg;
|
|
12241
12264
|
async function push(event) {
|
|
12242
12265
|
if (!enabled) return;
|
|
12243
12266
|
if (!event.text.trim()) return;
|
|
12267
|
+
return;
|
|
12268
|
+
const meta = event.role === "user" ? parseMeta(event.text) : null;
|
|
12269
|
+
const senderId = appId;
|
|
12270
|
+
const senderName = meta?.senderName ?? (event.role === "assistant" ? agentName : void 0) ?? event.senderName ?? event.role;
|
|
12271
|
+
console.log(`[everos-sync] role=${event.role} sender_id=${senderId} sender_name=${senderName} metaParsed=${!!meta} textLen=${event.text.length}`);
|
|
12244
12272
|
try {
|
|
12245
12273
|
const resp = await fetch(`${url}/api/v1/memory/add`, {
|
|
12246
12274
|
method: "POST",
|
|
@@ -12250,8 +12278,8 @@ function createEverosSync(cfg) {
|
|
|
12250
12278
|
app_id: appId,
|
|
12251
12279
|
project_id: "default",
|
|
12252
12280
|
messages: [{
|
|
12253
|
-
sender_id:
|
|
12254
|
-
sender_name:
|
|
12281
|
+
sender_id: senderId,
|
|
12282
|
+
sender_name: senderName,
|
|
12255
12283
|
role: event.role,
|
|
12256
12284
|
timestamp: event.timestamp,
|
|
12257
12285
|
content: event.text
|
|
@@ -12275,13 +12303,17 @@ function createEverosSync(cfg) {
|
|
|
12275
12303
|
session_id: events[0].sessionId,
|
|
12276
12304
|
app_id: appId,
|
|
12277
12305
|
project_id: "default",
|
|
12278
|
-
messages: events.map((e) =>
|
|
12279
|
-
|
|
12280
|
-
|
|
12281
|
-
|
|
12282
|
-
|
|
12283
|
-
|
|
12284
|
-
|
|
12306
|
+
messages: events.map((e) => {
|
|
12307
|
+
const meta = e.role === "user" ? parseMeta(e.text) : null;
|
|
12308
|
+
const name = meta?.senderName ?? (e.role === "assistant" ? agentName : void 0) ?? e.senderName ?? e.role;
|
|
12309
|
+
return {
|
|
12310
|
+
sender_id: appId,
|
|
12311
|
+
sender_name: name,
|
|
12312
|
+
role: e.role,
|
|
12313
|
+
timestamp: e.timestamp,
|
|
12314
|
+
content: e.text
|
|
12315
|
+
};
|
|
12316
|
+
})
|
|
12285
12317
|
}),
|
|
12286
12318
|
signal: AbortSignal.timeout(3e4)
|
|
12287
12319
|
});
|
|
@@ -12383,10 +12415,10 @@ function ensureLoaded(workspace, configIds) {
|
|
|
12383
12415
|
if (!state.blockedUserIds.includes(id)) state.blockedUserIds.push(id);
|
|
12384
12416
|
}
|
|
12385
12417
|
}
|
|
12386
|
-
const
|
|
12418
|
+
const path44 = join36(workspace, ".reply-blocklist.json");
|
|
12387
12419
|
try {
|
|
12388
|
-
if (existsSync24(
|
|
12389
|
-
const raw = readFileSync26(
|
|
12420
|
+
if (existsSync24(path44)) {
|
|
12421
|
+
const raw = readFileSync26(path44, "utf-8");
|
|
12390
12422
|
const parsed = JSON.parse(raw);
|
|
12391
12423
|
if (parsed.blockedUserIds) {
|
|
12392
12424
|
for (const id of parsed.blockedUserIds) {
|
|
@@ -12402,9 +12434,9 @@ function ensureLoaded(workspace, configIds) {
|
|
|
12402
12434
|
loaded = true;
|
|
12403
12435
|
}
|
|
12404
12436
|
function save(workspace) {
|
|
12405
|
-
const
|
|
12437
|
+
const path44 = join36(workspace, ".reply-blocklist.json");
|
|
12406
12438
|
try {
|
|
12407
|
-
writeFileSync15(
|
|
12439
|
+
writeFileSync15(path44, JSON.stringify(state, null, 2), "utf-8");
|
|
12408
12440
|
} catch (err) {
|
|
12409
12441
|
console.warn(`[reply-blocklist] Failed to save: ${err.message}`);
|
|
12410
12442
|
}
|
|
@@ -13004,7 +13036,7 @@ var init_cognifold_intent_watcher = __esm({
|
|
|
13004
13036
|
init_loader();
|
|
13005
13037
|
|
|
13006
13038
|
// src/engine-startup.ts
|
|
13007
|
-
import * as
|
|
13039
|
+
import * as path43 from "node:path";
|
|
13008
13040
|
import * as fs41 from "node:fs";
|
|
13009
13041
|
import { fileURLToPath } from "node:url";
|
|
13010
13042
|
|
|
@@ -14348,11 +14380,11 @@ var DiscordAdapter = class _DiscordAdapter {
|
|
|
14348
14380
|
/** 发送媒体附件(图片/文件/音频)— discord.js channel.send({ files }) */
|
|
14349
14381
|
async sendFile(target, message, attachment) {
|
|
14350
14382
|
const fs42 = await import("node:fs");
|
|
14351
|
-
const
|
|
14383
|
+
const path44 = await import("node:path");
|
|
14352
14384
|
if (!fs42.existsSync(attachment.path)) {
|
|
14353
14385
|
throw new Error(`File not found: ${attachment.path}`);
|
|
14354
14386
|
}
|
|
14355
|
-
const filename = attachment.filename ||
|
|
14387
|
+
const filename = attachment.filename || path44.basename(attachment.path);
|
|
14356
14388
|
const fileBuffer = fs42.readFileSync(attachment.path);
|
|
14357
14389
|
const filePayload = {
|
|
14358
14390
|
attachment: fileBuffer,
|
|
@@ -14794,11 +14826,11 @@ var FeishuAdapter = class _FeishuAdapter {
|
|
|
14794
14826
|
/** 发送媒体附件(图片/文件) */
|
|
14795
14827
|
async sendFile(target, message, attachment) {
|
|
14796
14828
|
const fs42 = await import("node:fs");
|
|
14797
|
-
const
|
|
14829
|
+
const path44 = await import("node:path");
|
|
14798
14830
|
if (!fs42.existsSync(attachment.path)) {
|
|
14799
14831
|
throw new Error(`File not found: ${attachment.path}`);
|
|
14800
14832
|
}
|
|
14801
|
-
const filename = attachment.filename ||
|
|
14833
|
+
const filename = attachment.filename || path44.basename(attachment.path);
|
|
14802
14834
|
const fileBuffer = fs42.readFileSync(attachment.path);
|
|
14803
14835
|
const receiveIdType = target.startsWith("ou_") ? "open_id" : "chat_id";
|
|
14804
14836
|
const mimeType = attachment.mimeType || "application/octet-stream";
|
|
@@ -18410,7 +18442,8 @@ ${skillsListing}`);
|
|
|
18410
18442
|
parts.push(getEnvInfoSection(options.workspace));
|
|
18411
18443
|
const now = /* @__PURE__ */ new Date();
|
|
18412
18444
|
const dateStr = now.toLocaleString("zh-CN", { timeZone: "Asia/Shanghai" });
|
|
18413
|
-
parts.push(
|
|
18445
|
+
parts.push(`# \u8FD0\u884C\u65F6\u4E0A\u4E0B\u6587
|
|
18446
|
+
\u5F53\u524D\u65F6\u95F4: ${dateStr}`);
|
|
18414
18447
|
console.log(`[dynamic-prompt] Loaded: ${loaded2.length > 0 ? loaded2.join(", ") : "(none)"}`);
|
|
18415
18448
|
return parts.join("\n\n");
|
|
18416
18449
|
}
|
|
@@ -18712,6 +18745,169 @@ async function findRelevantMemoriesVector(query, memoryDir, alreadySurfaced = /*
|
|
|
18712
18745
|
}));
|
|
18713
18746
|
}
|
|
18714
18747
|
|
|
18748
|
+
// src/memory/memdir/findRelevantMemoriesEveros.ts
|
|
18749
|
+
var ROUND1_TOP_N = 30;
|
|
18750
|
+
var RERANK_BATCH_SIZE = 100;
|
|
18751
|
+
function formatEverosHeader(ep) {
|
|
18752
|
+
const score = ep.score.toFixed(3);
|
|
18753
|
+
const ts = ep.timestamp?.slice(0, 10) ?? "";
|
|
18754
|
+
let ageLabel = "";
|
|
18755
|
+
if (ts) {
|
|
18756
|
+
const days = Math.floor((Date.now() - new Date(ts).getTime()) / 864e5);
|
|
18757
|
+
if (days <= 1) ageLabel = "\u4ECA\u5929";
|
|
18758
|
+
else if (days <= 3) ageLabel = `${days}\u5929\u524D`;
|
|
18759
|
+
else if (days <= 14) ageLabel = `${days}\u5929\u524D`;
|
|
18760
|
+
else if (days <= 30) ageLabel = `~${Math.ceil(days / 7)}\u5468\u524D`;
|
|
18761
|
+
else ageLabel = `~${Math.ceil(days / 30)}\u4E2A\u6708\u524D`;
|
|
18762
|
+
}
|
|
18763
|
+
return `[EverOS score=${score} ${ts} (${ageLabel})]`;
|
|
18764
|
+
}
|
|
18765
|
+
async function hybridSearch(query, everosUrl, userId, topK) {
|
|
18766
|
+
const resp = await fetch(`${everosUrl}/api/v1/memory/search`, {
|
|
18767
|
+
method: "POST",
|
|
18768
|
+
headers: { "Content-Type": "application/json" },
|
|
18769
|
+
body: JSON.stringify({
|
|
18770
|
+
query: query.slice(0, 2e3),
|
|
18771
|
+
user_id: userId,
|
|
18772
|
+
app_id: userId,
|
|
18773
|
+
project_id: "default",
|
|
18774
|
+
top_k: topK,
|
|
18775
|
+
method: "hybrid"
|
|
18776
|
+
}),
|
|
18777
|
+
signal: AbortSignal.timeout(15e3)
|
|
18778
|
+
});
|
|
18779
|
+
if (!resp.ok) {
|
|
18780
|
+
console.warn(`[memdir] everos hybrid: search failed ${resp.status}`);
|
|
18781
|
+
return [];
|
|
18782
|
+
}
|
|
18783
|
+
const body = await resp.json();
|
|
18784
|
+
const episodes = body.data?.episodes ?? [];
|
|
18785
|
+
return episodes;
|
|
18786
|
+
}
|
|
18787
|
+
async function deepinfraRerank(query, episodes, rerankUrl, rerankApiKey, rerankModel, provider) {
|
|
18788
|
+
if (episodes.length === 0) return [];
|
|
18789
|
+
const documents = episodes.map(
|
|
18790
|
+
(ep) => ep.episode?.slice(0, 500) || ep.summary?.slice(0, 500) || ep.subject
|
|
18791
|
+
);
|
|
18792
|
+
const allScores = [];
|
|
18793
|
+
const isDashscope = provider === "dashscope";
|
|
18794
|
+
for (let i = 0; i < documents.length; i += RERANK_BATCH_SIZE) {
|
|
18795
|
+
const batch = documents.slice(i, i + RERANK_BATCH_SIZE);
|
|
18796
|
+
const body = isDashscope ? JSON.stringify({
|
|
18797
|
+
model: rerankModel || "qwen3-rerank",
|
|
18798
|
+
input: { query, documents: batch },
|
|
18799
|
+
parameters: { return_documents: false, top_n: batch.length }
|
|
18800
|
+
}) : JSON.stringify({ queries: [query], documents: batch });
|
|
18801
|
+
const makeRequest = () => fetch(rerankUrl, {
|
|
18802
|
+
method: "POST",
|
|
18803
|
+
headers: {
|
|
18804
|
+
"Authorization": `Bearer ${rerankApiKey}`,
|
|
18805
|
+
"Content-Type": "application/json"
|
|
18806
|
+
},
|
|
18807
|
+
body,
|
|
18808
|
+
signal: AbortSignal.timeout(3e4)
|
|
18809
|
+
});
|
|
18810
|
+
let resp = await makeRequest();
|
|
18811
|
+
if (resp.status === 429) {
|
|
18812
|
+
await new Promise((r) => setTimeout(r, 2e3));
|
|
18813
|
+
resp = await makeRequest();
|
|
18814
|
+
}
|
|
18815
|
+
if (!resp.ok) {
|
|
18816
|
+
console.warn(`[memdir] everos rerank: failed ${resp.status}`);
|
|
18817
|
+
return episodes;
|
|
18818
|
+
}
|
|
18819
|
+
if (isDashscope) {
|
|
18820
|
+
const data = await resp.json();
|
|
18821
|
+
const results = data.output?.results ?? [];
|
|
18822
|
+
const scoreMap = new Array(batch.length).fill(0);
|
|
18823
|
+
for (const r of results) {
|
|
18824
|
+
scoreMap[r.index] = r.relevance_score;
|
|
18825
|
+
}
|
|
18826
|
+
allScores.push(...scoreMap);
|
|
18827
|
+
} else {
|
|
18828
|
+
const data = await resp.json();
|
|
18829
|
+
let batchScores = data.scores ?? [];
|
|
18830
|
+
if (Array.isArray(batchScores) && batchScores.length > 0 && Array.isArray(batchScores[0])) {
|
|
18831
|
+
batchScores = batchScores[0];
|
|
18832
|
+
}
|
|
18833
|
+
allScores.push(...batchScores);
|
|
18834
|
+
}
|
|
18835
|
+
}
|
|
18836
|
+
const ranked = episodes.map((ep, idx) => ({ ep, score: allScores[idx] ?? 0 })).sort((a, b2) => b2.score - a.score);
|
|
18837
|
+
for (const { ep, score } of ranked) {
|
|
18838
|
+
ep.score = score;
|
|
18839
|
+
}
|
|
18840
|
+
return ranked.map((r) => r.ep);
|
|
18841
|
+
}
|
|
18842
|
+
var DEFAULT_MIN_SCORE2 = 0.5;
|
|
18843
|
+
async function findRelevantMemoriesEveros(query, _memoryDir, alreadySurfaced = /* @__PURE__ */ new Set(), options) {
|
|
18844
|
+
const everosUrl = options?.everosUrl ?? "http://127.0.0.1:8100";
|
|
18845
|
+
const userId = options?.userId ?? "xiaomei";
|
|
18846
|
+
const topK = options?.topK ?? 3;
|
|
18847
|
+
const minScore = options?.minScore ?? DEFAULT_MIN_SCORE2;
|
|
18848
|
+
console.log(`[memdir] everos recall: query="${query.slice(0, 50)}..." url=${everosUrl} userId=${userId} topK=${topK}`);
|
|
18849
|
+
const t0 = Date.now();
|
|
18850
|
+
try {
|
|
18851
|
+
const tH1 = Date.now();
|
|
18852
|
+
let episodes = await hybridSearch(query, everosUrl, userId, ROUND1_TOP_N);
|
|
18853
|
+
const tH2 = Date.now();
|
|
18854
|
+
console.log(`[memdir] everos recall: hybrid ${episodes.length} candidates in ${tH2 - tH1}ms`);
|
|
18855
|
+
if (episodes.length === 0) return [];
|
|
18856
|
+
const rerankUrl = options?.rerankUrl;
|
|
18857
|
+
const rerankApiKey = options?.rerankApiKey;
|
|
18858
|
+
if (rerankUrl && rerankApiKey) {
|
|
18859
|
+
const tR1 = Date.now();
|
|
18860
|
+
episodes = await deepinfraRerank(
|
|
18861
|
+
query,
|
|
18862
|
+
episodes,
|
|
18863
|
+
rerankUrl,
|
|
18864
|
+
rerankApiKey,
|
|
18865
|
+
options?.rerankModel,
|
|
18866
|
+
options?.rerankProvider
|
|
18867
|
+
);
|
|
18868
|
+
const tR2 = Date.now();
|
|
18869
|
+
console.log(`[memdir] everos recall: rerank done in ${tR2 - tR1}ms (${options?.rerankProvider || "deepinfra"})`);
|
|
18870
|
+
} else {
|
|
18871
|
+
console.log(`[memdir] everos recall: no rerank key, using hybrid scores as-is`);
|
|
18872
|
+
}
|
|
18873
|
+
const ms = Date.now() - t0;
|
|
18874
|
+
console.log(`[memdir] everos recall: ${episodes.length} episodes in ${ms}ms total (hybrid+rerank)`);
|
|
18875
|
+
const surfacedSubjects = /* @__PURE__ */ new Set();
|
|
18876
|
+
for (const p2 of alreadySurfaced) {
|
|
18877
|
+
if (p2.startsWith("everos://")) {
|
|
18878
|
+
surfacedSubjects.add(p2.slice(8));
|
|
18879
|
+
} else {
|
|
18880
|
+
}
|
|
18881
|
+
}
|
|
18882
|
+
const result = [];
|
|
18883
|
+
const seenSubjects = /* @__PURE__ */ new Set();
|
|
18884
|
+
for (const ep of episodes) {
|
|
18885
|
+
if (ep.score < minScore) continue;
|
|
18886
|
+
const subject = (ep.subject || ep.id).slice(0, 80).replace(/[\n\r]/g, " ");
|
|
18887
|
+
const virtualPath = `everos://${subject}`;
|
|
18888
|
+
if (alreadySurfaced.has(virtualPath)) continue;
|
|
18889
|
+
if (surfacedSubjects.has(subject)) continue;
|
|
18890
|
+
if (seenSubjects.has(subject)) continue;
|
|
18891
|
+
seenSubjects.add(subject);
|
|
18892
|
+
result.push({
|
|
18893
|
+
path: virtualPath,
|
|
18894
|
+
mtimeMs: ep.timestamp ? new Date(ep.timestamp).getTime() : Date.now(),
|
|
18895
|
+
content: `### ${ep.subject}
|
|
18896
|
+
|
|
18897
|
+
${ep.episode || ep.summary}`,
|
|
18898
|
+
header: formatEverosHeader(ep)
|
|
18899
|
+
});
|
|
18900
|
+
if (result.length >= topK) break;
|
|
18901
|
+
}
|
|
18902
|
+
console.log(`[memdir] everos recall: returning ${result.length} memories (after dedup)`);
|
|
18903
|
+
return result;
|
|
18904
|
+
} catch (e) {
|
|
18905
|
+
const ms = Date.now() - t0;
|
|
18906
|
+
console.warn(`[memdir] everos recall: error after ${ms}ms: ${e?.message ?? e}`);
|
|
18907
|
+
return [];
|
|
18908
|
+
}
|
|
18909
|
+
}
|
|
18910
|
+
|
|
18715
18911
|
// src/handle-query.ts
|
|
18716
18912
|
init_paths();
|
|
18717
18913
|
import { readFileSync as readFileSync15, existsSync as existsSync12 } from "node:fs";
|
|
@@ -18784,18 +18980,18 @@ function truncate(s2, maxLen) {
|
|
|
18784
18980
|
}
|
|
18785
18981
|
var externalChanRulesCache = null;
|
|
18786
18982
|
function loadExternalChanRules(workspace) {
|
|
18787
|
-
const
|
|
18788
|
-
if (externalChanRulesCache && externalChanRulesCache.path ===
|
|
18983
|
+
const path44 = join20(workspace, "prompts", "external-chan-rules.md");
|
|
18984
|
+
if (externalChanRulesCache && externalChanRulesCache.path === path44) return externalChanRulesCache;
|
|
18789
18985
|
let content = "";
|
|
18790
|
-
if (existsSync12(
|
|
18986
|
+
if (existsSync12(path44)) {
|
|
18791
18987
|
try {
|
|
18792
|
-
content = readFileSync15(
|
|
18988
|
+
content = readFileSync15(path44, "utf-8").trim();
|
|
18793
18989
|
} catch (e) {
|
|
18794
18990
|
console.warn(`[external-chan-rules] Failed to load: ${e}`);
|
|
18795
18991
|
}
|
|
18796
18992
|
}
|
|
18797
|
-
externalChanRulesCache = { path:
|
|
18798
|
-
console.log(`[external-chan-rules] Loaded ${content.length} chars from ${
|
|
18993
|
+
externalChanRulesCache = { path: path44, content };
|
|
18994
|
+
console.log(`[external-chan-rules] Loaded ${content.length} chars from ${path44}`);
|
|
18799
18995
|
return externalChanRulesCache;
|
|
18800
18996
|
}
|
|
18801
18997
|
function getExternalChanRulesBlock(inboundMeta, workspace) {
|
|
@@ -18818,10 +19014,10 @@ function getExternalChanWhitelist(workspace, configExternalChannels) {
|
|
|
18818
19014
|
if (!externalChanWhitelist) loadContactMap(workspace);
|
|
18819
19015
|
return externalChanWhitelist;
|
|
18820
19016
|
}
|
|
18821
|
-
async function handleQuery(text, sessionId, channelName, cb, deps, channelTarget, inboundMeta, skipRecall) {
|
|
18822
|
-
return handleQueryInner(text, sessionId, channelName, cb, deps, channelTarget, inboundMeta, skipRecall);
|
|
19017
|
+
async function handleQuery(text, sessionId, channelName, cb, deps, channelTarget, inboundMeta, skipRecall, source) {
|
|
19018
|
+
return handleQueryInner(text, sessionId, channelName, cb, deps, channelTarget, inboundMeta, skipRecall, source);
|
|
18823
19019
|
}
|
|
18824
|
-
async function handleQueryInner(text, sessionId, channelName, cb, deps, channelTarget, inboundMeta, skipRecall) {
|
|
19020
|
+
async function handleQueryInner(text, sessionId, channelName, cb, deps, channelTarget, inboundMeta, skipRecall, source) {
|
|
18825
19021
|
const { engine, sessions, channelManager, workspace, providerId, providerApi, model } = deps;
|
|
18826
19022
|
const features = deps.features || {};
|
|
18827
19023
|
const preQueryAbort = new AbortController();
|
|
@@ -18998,6 +19194,8 @@ ${text}` : text });
|
|
|
18998
19194
|
const toolContext = {
|
|
18999
19195
|
sessionId,
|
|
19000
19196
|
channel: channelName === "cli" ? "console" : channelName,
|
|
19197
|
+
source: source || "",
|
|
19198
|
+
// 消息来源(user/inbox/heartbeat/cron/system/inner-voice),Stop hook 用来区分注入 turn
|
|
19001
19199
|
workspace,
|
|
19002
19200
|
stateDir: deps.stateDir || workspace,
|
|
19003
19201
|
channelManager,
|
|
@@ -19172,7 +19370,23 @@ ${text}` : text });
|
|
|
19172
19370
|
const recallP = deps.recallProvider;
|
|
19173
19371
|
const recallMode = deps.topics?.recall?.mode || "llm";
|
|
19174
19372
|
let relevantMemories;
|
|
19175
|
-
if (recallMode === "
|
|
19373
|
+
if (recallMode === "everos") {
|
|
19374
|
+
const everosCfg = deps?.everosCfg;
|
|
19375
|
+
relevantMemories = await findRelevantMemoriesEveros(
|
|
19376
|
+
textForMemory,
|
|
19377
|
+
memoryDir,
|
|
19378
|
+
surfaced.paths,
|
|
19379
|
+
everosCfg ? {
|
|
19380
|
+
everosUrl: everosCfg.everosUrl || "http://127.0.0.1:8100",
|
|
19381
|
+
userId: everosCfg.userId || "xiaomei",
|
|
19382
|
+
rerankUrl: everosCfg.rerank?.baseUrl,
|
|
19383
|
+
rerankApiKey: everosCfg.rerank?.apiKey,
|
|
19384
|
+
rerankModel: everosCfg.rerank?.model,
|
|
19385
|
+
rerankProvider: everosCfg.rerank?.provider,
|
|
19386
|
+
minScore: deps.topics?.recall?.minScore
|
|
19387
|
+
} : void 0
|
|
19388
|
+
);
|
|
19389
|
+
} else if (recallMode === "vector") {
|
|
19176
19390
|
relevantMemories = await findRelevantMemoriesVector(
|
|
19177
19391
|
textForMemory,
|
|
19178
19392
|
memoryDir,
|
|
@@ -19195,8 +19409,8 @@ ${text}` : text });
|
|
|
19195
19409
|
const attachmentMemories = [];
|
|
19196
19410
|
for (const mem of relevantMemories) {
|
|
19197
19411
|
try {
|
|
19198
|
-
const content = readFileSync15(mem.path, "utf-8");
|
|
19199
|
-
const header = memoryHeader(mem.path, mem.mtimeMs);
|
|
19412
|
+
const content = mem.content ?? readFileSync15(mem.path, "utf-8");
|
|
19413
|
+
const header = mem.header ?? memoryHeader(mem.path, mem.mtimeMs);
|
|
19200
19414
|
attachmentMemories.push({ path: mem.path, content, mtimeMs: mem.mtimeMs, header });
|
|
19201
19415
|
} catch {
|
|
19202
19416
|
}
|
|
@@ -19744,7 +19958,9 @@ function registerCognifoldBridge(config2) {
|
|
|
19744
19958
|
messageId: ctx.inbound.messageId
|
|
19745
19959
|
}
|
|
19746
19960
|
};
|
|
19747
|
-
|
|
19961
|
+
const sm = globalThis.__cognifoldSessions;
|
|
19962
|
+
const dynamicSessionId = sm?.getSessionId?.("main") || cognifoldConfig.sessionId;
|
|
19963
|
+
void enqueueEvent(dynamicSessionId, event);
|
|
19748
19964
|
return null;
|
|
19749
19965
|
}, 80);
|
|
19750
19966
|
}
|
|
@@ -20068,7 +20284,8 @@ var MessageDispatcher = class {
|
|
|
20068
20284
|
msg2.deps,
|
|
20069
20285
|
msg2.channelTarget,
|
|
20070
20286
|
msg2.inboundMeta,
|
|
20071
|
-
msg2.skipRecall
|
|
20287
|
+
msg2.skipRecall,
|
|
20288
|
+
msg2.source
|
|
20072
20289
|
);
|
|
20073
20290
|
} catch (err) {
|
|
20074
20291
|
console.error(`[dispatcher] Query error (session=${msg2.sessionId}): ${err.message}`);
|
|
@@ -20228,13 +20445,19 @@ function startCliLoop(deps, cliConfig, channelManager, dispatcher) {
|
|
|
20228
20445
|
|
|
20229
20446
|
// src/session/session-history.ts
|
|
20230
20447
|
import fs14 from "node:fs";
|
|
20448
|
+
import path14 from "node:path";
|
|
20231
20449
|
var BEIJING_OFFSET_MS = 8 * 36e5;
|
|
20232
20450
|
var INJECTED_CONTENT_PATTERNS = [
|
|
20233
20451
|
/【定时心跳】/,
|
|
20234
20452
|
/\[内心对话测试\]/,
|
|
20235
20453
|
/\[inner-voice\]/,
|
|
20236
20454
|
/\[微信巡检\]/,
|
|
20237
|
-
/\[plugin\]
|
|
20455
|
+
/\[plugin\]/,
|
|
20456
|
+
/<nudge-notification>/,
|
|
20457
|
+
/<task-notification>/,
|
|
20458
|
+
/<calendar-notification>/,
|
|
20459
|
+
/## Actions \(\d+\s*个\)/
|
|
20460
|
+
// CogniFold proactive 注入(block[0] 固定格式,engine-startup 拼的)
|
|
20238
20461
|
];
|
|
20239
20462
|
function parseJsonlEntries(lines) {
|
|
20240
20463
|
const entries = [];
|
|
@@ -20269,6 +20492,20 @@ function resolveScopeMainJsonl(sessions) {
|
|
|
20269
20492
|
if (!sessionId) return null;
|
|
20270
20493
|
return sessions.getSessionFilePath(sessionId);
|
|
20271
20494
|
}
|
|
20495
|
+
function scopeMainJsonlPaths(sessions) {
|
|
20496
|
+
const current = resolveScopeMainJsonl(sessions);
|
|
20497
|
+
let latestArchive = null;
|
|
20498
|
+
if (current) {
|
|
20499
|
+
try {
|
|
20500
|
+
const dir = path14.dirname(current);
|
|
20501
|
+
const base = path14.basename(current);
|
|
20502
|
+
const archives = fs14.readdirSync(dir).filter((f2) => f2.startsWith(base + ".archived.")).sort();
|
|
20503
|
+
if (archives.length > 0) latestArchive = path14.join(dir, archives[archives.length - 1]);
|
|
20504
|
+
} catch {
|
|
20505
|
+
}
|
|
20506
|
+
}
|
|
20507
|
+
return { current, latestArchive };
|
|
20508
|
+
}
|
|
20272
20509
|
function cleanText(rawText) {
|
|
20273
20510
|
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]");
|
|
20274
20511
|
return clean.trim();
|
|
@@ -20359,6 +20596,7 @@ function recentMessages(sessions, hours = 12, limit = 60) {
|
|
|
20359
20596
|
time: `${p2(bj.getHours())}:${p2(bj.getMinutes())}`,
|
|
20360
20597
|
role,
|
|
20361
20598
|
text: clean.slice(0, 80),
|
|
20599
|
+
timestamp: dtMs,
|
|
20362
20600
|
_utc: dtMs
|
|
20363
20601
|
});
|
|
20364
20602
|
}
|
|
@@ -20490,6 +20728,8 @@ ${basePrompt}`;
|
|
|
20490
20728
|
channelName: "heartbeat",
|
|
20491
20729
|
source: "heartbeat",
|
|
20492
20730
|
priority: "later",
|
|
20731
|
+
skipRecall: true,
|
|
20732
|
+
// 心跳不需要记忆召回,避免重复注入心跳相关记忆
|
|
20493
20733
|
callbacks: {
|
|
20494
20734
|
onResult: () => resolveDone()
|
|
20495
20735
|
},
|
|
@@ -20507,7 +20747,7 @@ ${basePrompt}`;
|
|
|
20507
20747
|
|
|
20508
20748
|
// src/nudge/plugin.ts
|
|
20509
20749
|
import fs17 from "node:fs";
|
|
20510
|
-
import
|
|
20750
|
+
import path17 from "node:path";
|
|
20511
20751
|
|
|
20512
20752
|
// src/nudge/judge.ts
|
|
20513
20753
|
function shouldNudge(task, taskState, cfg) {
|
|
@@ -20676,10 +20916,10 @@ function formatDuration2(ms) {
|
|
|
20676
20916
|
|
|
20677
20917
|
// src/nudge/session-state-reader.ts
|
|
20678
20918
|
import fs15 from "node:fs";
|
|
20679
|
-
import
|
|
20919
|
+
import path15 from "node:path";
|
|
20680
20920
|
function parseSessionStateFull(workspace, sessionStateFile) {
|
|
20681
20921
|
const stateFile = sessionStateFile || "SESSION-STATE.md";
|
|
20682
|
-
const statePath =
|
|
20922
|
+
const statePath = path15.isAbsolute(stateFile) ? stateFile : path15.join(workspace, stateFile);
|
|
20683
20923
|
let content;
|
|
20684
20924
|
try {
|
|
20685
20925
|
content = fs15.readFileSync(statePath, "utf-8");
|
|
@@ -20734,13 +20974,13 @@ function taskIdFromTitle(title) {
|
|
|
20734
20974
|
|
|
20735
20975
|
// src/calendar/db.ts
|
|
20736
20976
|
import { DatabaseSync } from "node:sqlite";
|
|
20737
|
-
import * as
|
|
20977
|
+
import * as path16 from "node:path";
|
|
20738
20978
|
import * as fs16 from "node:fs";
|
|
20739
20979
|
var TZ_OFFSET_MS = 8 * 60 * 60 * 1e3;
|
|
20740
20980
|
function openDb(workspace) {
|
|
20741
|
-
const dir =
|
|
20981
|
+
const dir = path16.join(workspace, ".calendar");
|
|
20742
20982
|
fs16.mkdirSync(dir, { recursive: true });
|
|
20743
|
-
const dbPath =
|
|
20983
|
+
const dbPath = path16.join(dir, "calendar.db");
|
|
20744
20984
|
const db = new DatabaseSync(dbPath);
|
|
20745
20985
|
db.exec("PRAGMA journal_mode=WAL");
|
|
20746
20986
|
db.exec(`CREATE TABLE IF NOT EXISTS events (
|
|
@@ -20829,7 +21069,7 @@ var NudgePlugin = class {
|
|
|
20829
21069
|
provider;
|
|
20830
21070
|
model;
|
|
20831
21071
|
loadPrompt(workspace, promptFile) {
|
|
20832
|
-
const promptPath = promptFile ?
|
|
21072
|
+
const promptPath = promptFile ? path17.isAbsolute(promptFile) ? promptFile : path17.join(workspace, promptFile) : path17.join(workspace, "prompts", "nudge-prompt.md");
|
|
20833
21073
|
try {
|
|
20834
21074
|
const content = fs17.readFileSync(promptPath, "utf-8").trim();
|
|
20835
21075
|
if (content) {
|
|
@@ -20866,11 +21106,20 @@ var NudgePlugin = class {
|
|
|
20866
21106
|
const lastMsg = input?.last_assistant_message || "";
|
|
20867
21107
|
const sessionId = input?.session_id || "";
|
|
20868
21108
|
console.log(`[stop-hook] lastMsg len=${lastMsg.length}, text="${lastMsg.slice(0, 80)}"`);
|
|
21109
|
+
const repliedIds = this.extractWakeReplyIds(lastMsg);
|
|
21110
|
+
if (repliedIds.length > 0) {
|
|
21111
|
+
this.removeNotificationsById(repliedIds);
|
|
21112
|
+
}
|
|
20869
21113
|
const msgChannel = input?.channel || "";
|
|
20870
21114
|
if (sessionId.includes("voice-chat") || msgChannel === "voice-chat") {
|
|
20871
21115
|
console.log(`[stop-hook] skipping voice-chat (channel=${msgChannel})`);
|
|
20872
21116
|
return { outcome: { outcome: "success" } };
|
|
20873
21117
|
}
|
|
21118
|
+
const msgSource = input?.source || "";
|
|
21119
|
+
if (msgSource && msgSource !== "user" && msgSource !== "inbox") {
|
|
21120
|
+
console.log(`[stop-hook] skipping non-conversation turn (source=${msgSource})`);
|
|
21121
|
+
return { outcome: { outcome: "success" } };
|
|
21122
|
+
}
|
|
20874
21123
|
if (!lastMsg) {
|
|
20875
21124
|
return { outcome: { outcome: "success" } };
|
|
20876
21125
|
}
|
|
@@ -20943,8 +21192,8 @@ var NudgePlugin = class {
|
|
|
20943
21192
|
if (pushedDecision && waitDesc) {
|
|
20944
21193
|
console.log(`[stop-hook] DETECTED pushedDecision! Injecting corrective message to ${sessionId}`);
|
|
20945
21194
|
try {
|
|
20946
|
-
const correctiveMsg = [
|
|
20947
|
-
"
|
|
21195
|
+
const correctiveMsg = buildNudgeNotification("prompt", [
|
|
21196
|
+
"[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",
|
|
20948
21197
|
"",
|
|
20949
21198
|
`\u8BCA\u65AD\uFF1A${waitDesc}`,
|
|
20950
21199
|
"",
|
|
@@ -20957,9 +21206,10 @@ var NudgePlugin = class {
|
|
|
20957
21206
|
'3. \u6267\u884C\u5B8C\u6C47\u62A5\u7ED3\u679C\uFF08"\u5DF2\u5904\u7406" / "\u5DF2 commit" / "\u5DF2 archive"\uFF09',
|
|
20958
21207
|
"",
|
|
20959
21208
|
"\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"
|
|
20960
|
-
].join("\n");
|
|
20961
|
-
|
|
20962
|
-
|
|
21209
|
+
].join("\n"));
|
|
21210
|
+
const route = this.getRoute(sessions);
|
|
21211
|
+
if (route) {
|
|
21212
|
+
enqueueNotification(correctiveMsg, route);
|
|
20963
21213
|
}
|
|
20964
21214
|
} catch (e) {
|
|
20965
21215
|
console.warn(`[stop-hook] Failed to inject corrective message: ${e.message}`);
|
|
@@ -20968,14 +21218,21 @@ var NudgePlugin = class {
|
|
|
20968
21218
|
if (!isWaiting) {
|
|
20969
21219
|
return { outcome: { outcome: "success" } };
|
|
20970
21220
|
}
|
|
20971
|
-
const nudgeDir =
|
|
20972
|
-
const notifPath =
|
|
21221
|
+
const nudgeDir = path17.join(this.workspace, ".nudge");
|
|
21222
|
+
const notifPath = path17.join(nudgeDir, "stop-hook-notifications.json");
|
|
20973
21223
|
try {
|
|
20974
21224
|
if (!fs17.existsSync(nudgeDir)) fs17.mkdirSync(nudgeDir, { recursive: true });
|
|
20975
21225
|
let notifs = [];
|
|
20976
21226
|
if (fs17.existsSync(notifPath)) {
|
|
20977
21227
|
notifs = JSON.parse(fs17.readFileSync(notifPath, "utf-8"));
|
|
20978
21228
|
const now = Date.now();
|
|
21229
|
+
const dup = notifs.find((n) => !n.notified && n.description === (waitDesc || lastMsg.slice(0, 200)));
|
|
21230
|
+
if (dup) {
|
|
21231
|
+
dup.wakeAt = new Date(now + 5 * 6e4).toISOString();
|
|
21232
|
+
fs17.writeFileSync(notifPath, JSON.stringify(notifs, null, 2));
|
|
21233
|
+
console.log(`[stop-hook] Duplicate wait (same desc, not fired yet), refreshed wakeAt: ${dup.id}`);
|
|
21234
|
+
return { outcome: { outcome: "success" } };
|
|
21235
|
+
}
|
|
20979
21236
|
const recentReg = notifs.find((n) => now - new Date(n.createdAt).getTime() < 3 * 6e4);
|
|
20980
21237
|
if (recentReg) {
|
|
20981
21238
|
console.log(`[stop-hook] Skip (recent registration within 3min)`);
|
|
@@ -21024,9 +21281,14 @@ var NudgePlugin = class {
|
|
|
21024
21281
|
return null;
|
|
21025
21282
|
}
|
|
21026
21283
|
}
|
|
21027
|
-
/**
|
|
21028
|
-
|
|
21029
|
-
|
|
21284
|
+
/**
|
|
21285
|
+
* 收集到期的 stop-hook notifications,批量构建一条 wake 消息。
|
|
21286
|
+
* 不标 notified——投递成功后由 tick 调 markNotified 标(route 拿不到时保留原样下个 tick 重试,
|
|
21287
|
+
* 避免"消息没投出去但已标 notified"的死账)。
|
|
21288
|
+
* 已 notified 的不会再触发,等 agent 回复 "<id> 过期了" 由 cleanup 删。
|
|
21289
|
+
*/
|
|
21290
|
+
collectDueStopHookNotifications() {
|
|
21291
|
+
const notifPath = path17.join(this.workspace, ".nudge", "stop-hook-notifications.json");
|
|
21030
21292
|
try {
|
|
21031
21293
|
if (!fs17.existsSync(notifPath)) return null;
|
|
21032
21294
|
const notifs = JSON.parse(fs17.readFileSync(notifPath, "utf-8"));
|
|
@@ -21034,54 +21296,161 @@ var NudgePlugin = class {
|
|
|
21034
21296
|
const now = Date.now();
|
|
21035
21297
|
const due = notifs.filter((n) => new Date(n.wakeAt).getTime() <= now && !n.notified);
|
|
21036
21298
|
if (due.length === 0) return null;
|
|
21037
|
-
|
|
21038
|
-
|
|
21039
|
-
|
|
21040
|
-
|
|
21041
|
-
return buildNudgeNotification("wake", `\u4F60\u4E4B\u524D\u5728\u7B49\u5F85\u67D0\u4E2A\u5916\u90E8\u6761\u4EF6\uFF0C\u65F6\u95F4\u5230\u4E86\uFF0C\u56DE\u53BB\u68C0\u67E5\uFF01
|
|
21299
|
+
console.log(`[nudge] ${due.length} stop-hook notification(s) due: ${due.map((n) => n.id).join(", ")}`);
|
|
21300
|
+
const items = due.map((n) => `[\u901A\u77E5ID: ${n.id}]
|
|
21301
|
+
\u4E0A\u6B21\u8BF4\uFF1A${n.description}`).join("\n\n");
|
|
21302
|
+
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
|
|
21042
21303
|
|
|
21043
|
-
|
|
21044
|
-
\u4E0A\u6B21\u8BF4\uFF1A${latest.description}
|
|
21304
|
+
${items}
|
|
21045
21305
|
|
|
21046
|
-
\u68C0\u67E5\u6761\u4EF6\u662F\u5426\u6EE1\u8DB3\uFF0C\u6EE1\u8DB3\u5C31\u7EE7\u7EED\u5E72\u6D3B\uFF0C\u4E0D\u6EE1\u8DB3\u5C31\u56DE\u590D"${
|
|
21306
|
+
\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
|
|
21307
|
+
|
|
21308
|
+
${items}
|
|
21309
|
+
|
|
21310
|
+
\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`;
|
|
21311
|
+
return { message: buildNudgeNotification("wake", desc), ids: due.map((n) => n.id) };
|
|
21047
21312
|
} catch (e) {
|
|
21048
|
-
console.warn(`[nudge]
|
|
21313
|
+
console.warn(`[nudge] collectDueStopHookNotifications error: ${e.message}`);
|
|
21049
21314
|
return null;
|
|
21050
21315
|
}
|
|
21051
21316
|
}
|
|
21052
|
-
/**
|
|
21317
|
+
/** 从回复文本里提取 "<id> 过期了" 的 wake id(一条回复可能处置多个) */
|
|
21318
|
+
extractWakeReplyIds(text) {
|
|
21319
|
+
if (!text) return [];
|
|
21320
|
+
const ids = [];
|
|
21321
|
+
const re = /(wake-\d+-[a-z0-9]+)\s*过期了/g;
|
|
21322
|
+
let m2;
|
|
21323
|
+
while ((m2 = re.exec(text)) !== null) {
|
|
21324
|
+
if (!ids.includes(m2[1])) ids.push(m2[1]);
|
|
21325
|
+
}
|
|
21326
|
+
return ids;
|
|
21327
|
+
}
|
|
21328
|
+
/** 按 id 删除条目(stop-hook 实时清理用;正常删除路径,agent 回复即删) */
|
|
21329
|
+
removeNotificationsById(ids) {
|
|
21330
|
+
const notifPath = path17.join(this.workspace, ".nudge", "stop-hook-notifications.json");
|
|
21331
|
+
try {
|
|
21332
|
+
if (!fs17.existsSync(notifPath)) return;
|
|
21333
|
+
const notifs = JSON.parse(fs17.readFileSync(notifPath, "utf-8"));
|
|
21334
|
+
const idSet = new Set(ids);
|
|
21335
|
+
const remaining = notifs.filter((n) => !idSet.has(n.id));
|
|
21336
|
+
const removed = notifs.length - remaining.length;
|
|
21337
|
+
if (removed === 0) return;
|
|
21338
|
+
if (remaining.length > 0) {
|
|
21339
|
+
fs17.writeFileSync(notifPath, JSON.stringify(remaining, null, 2));
|
|
21340
|
+
} else {
|
|
21341
|
+
fs17.unlinkSync(notifPath);
|
|
21342
|
+
}
|
|
21343
|
+
console.log(`[stop-hook] Cleaned ${removed} notification(s) from reply: ${ids.join(", ")}`);
|
|
21344
|
+
} catch (e) {
|
|
21345
|
+
console.warn(`[stop-hook] removeNotificationsById error: ${e.message}`);
|
|
21346
|
+
}
|
|
21347
|
+
}
|
|
21348
|
+
/** 投递成功后标记 notified(防重复触发);不删除——删除只走 agent 回复 "<id> 过期了" */
|
|
21349
|
+
markNotified(ids) {
|
|
21350
|
+
const notifPath = path17.join(this.workspace, ".nudge", "stop-hook-notifications.json");
|
|
21351
|
+
try {
|
|
21352
|
+
if (!fs17.existsSync(notifPath)) return;
|
|
21353
|
+
const notifs = JSON.parse(fs17.readFileSync(notifPath, "utf-8"));
|
|
21354
|
+
const idSet = new Set(ids);
|
|
21355
|
+
const updated = notifs.map((n) => idSet.has(n.id) ? { ...n, notified: true } : n);
|
|
21356
|
+
fs17.writeFileSync(notifPath, JSON.stringify(updated, null, 2));
|
|
21357
|
+
} catch (e) {
|
|
21358
|
+
console.warn(`[nudge] markNotified error: ${e.message}`);
|
|
21359
|
+
}
|
|
21360
|
+
}
|
|
21361
|
+
/**
|
|
21362
|
+
* tick 兜底清理。正常删除走 stop-hook 实时路径(agent 回复 "<id> 过期了" 当 turn 就删,
|
|
21363
|
+
* 见 registerStopHook 第 0 步),这里只接两种漏网:
|
|
21364
|
+
* ① 回复已落盘但 stop-hook 没来得及执行(进程中途崩等边缘情况)→ 扫 jsonl 补删;
|
|
21365
|
+
* ② TTL 清道夫:wakeAt 超过 cleanupTtlHours(默认 24h)仍无回复 → 回复永远来不了,删。
|
|
21366
|
+
*
|
|
21367
|
+
* 扫描不走 recentMessages()——它截断 80 字符、会过滤"对注入消息的回复"(wake 回复恰好
|
|
21368
|
+
* 被过滤掉)、限 20 条窗口。直接读 jsonl 原始条目:倒序扫、扫过最老 pending 的 wakeAt
|
|
21369
|
+
* 即停、全命中提前退、archive 只在 current 被 2MB 轮转切断时才读。
|
|
21370
|
+
*/
|
|
21053
21371
|
cleanupStaleNotificationsFromMessages(sessions) {
|
|
21054
21372
|
try {
|
|
21055
|
-
const
|
|
21056
|
-
const fiveMinAgo = Date.now() - 5 * 60 * 1e3;
|
|
21057
|
-
const recentTexts = recent.filter((r) => new Date(r.timestamp || r.createdAt || Date.now()).getTime() > fiveMinAgo).map((r) => r.text);
|
|
21058
|
-
const notifPath = path16.join(this.workspace, ".nudge", "stop-hook-notifications.json");
|
|
21373
|
+
const notifPath = path17.join(this.workspace, ".nudge", "stop-hook-notifications.json");
|
|
21059
21374
|
if (!fs17.existsSync(notifPath)) return;
|
|
21060
21375
|
const notifs = JSON.parse(fs17.readFileSync(notifPath, "utf-8"));
|
|
21061
21376
|
if (notifs.length === 0) return;
|
|
21062
|
-
const expiredIds =
|
|
21063
|
-
|
|
21064
|
-
|
|
21065
|
-
|
|
21066
|
-
|
|
21067
|
-
|
|
21068
|
-
|
|
21377
|
+
const expiredIds = this.findExpiredReplyIds(sessions, notifs);
|
|
21378
|
+
const ttlMs = (this.cfg.cleanupTtlHours || 24) * 36e5;
|
|
21379
|
+
const now = Date.now();
|
|
21380
|
+
const ttlIds = new Set(
|
|
21381
|
+
notifs.filter((n) => now - new Date(n.wakeAt).getTime() > ttlMs && !expiredIds.has(n.id)).map((n) => n.id)
|
|
21382
|
+
);
|
|
21383
|
+
const removeIds = /* @__PURE__ */ new Set([...expiredIds, ...ttlIds]);
|
|
21384
|
+
if (removeIds.size === 0) return;
|
|
21385
|
+
const remaining = notifs.filter((n) => !removeIds.has(n.id));
|
|
21386
|
+
if (remaining.length > 0) {
|
|
21387
|
+
fs17.writeFileSync(notifPath, JSON.stringify(remaining, null, 2));
|
|
21388
|
+
} else {
|
|
21389
|
+
fs17.unlinkSync(notifPath);
|
|
21069
21390
|
}
|
|
21070
|
-
if (expiredIds.size
|
|
21071
|
-
|
|
21072
|
-
|
|
21073
|
-
if (
|
|
21074
|
-
|
|
21075
|
-
fs17.writeFileSync(notifPath, JSON.stringify(remaining, null, 2));
|
|
21076
|
-
} else {
|
|
21077
|
-
fs17.unlinkSync(notifPath);
|
|
21078
|
-
}
|
|
21079
|
-
console.log(`[nudge] Cleaned ${cleaned} stale notification(s) by explicit id: ${[...expiredIds].join(", ")}`);
|
|
21391
|
+
if (expiredIds.size > 0) {
|
|
21392
|
+
console.log(`[nudge] Cleaned ${expiredIds.size} notification(s) by reply: ${[...expiredIds].join(", ")}`);
|
|
21393
|
+
}
|
|
21394
|
+
if (ttlIds.size > 0) {
|
|
21395
|
+
console.log(`[nudge] Cleaned ${ttlIds.size} zombie notification(s) by TTL (>${this.cfg.cleanupTtlHours || 24}h no reply): ${[...ttlIds].join(", ")}`);
|
|
21080
21396
|
}
|
|
21081
21397
|
} catch (e) {
|
|
21082
21398
|
console.warn(`[nudge] cleanupStaleNotificationsFromMessages error: ${e.message}`);
|
|
21083
21399
|
}
|
|
21084
21400
|
}
|
|
21401
|
+
/**
|
|
21402
|
+
* 扫 "<id> 过期了" 回复,返回匹配到的 id 集合。
|
|
21403
|
+
* 不做全文扫描:倒序扫(回复紧跟在 fire 之后,通常就在尾部几条);
|
|
21404
|
+
* 扫过最老 pending 条目的 wakeAt 就停(回复不可能早于触发时间);
|
|
21405
|
+
* 全部命中提前退出;archive 只在 current 没覆盖时间范围(被 2MB 轮转切断)时才读。
|
|
21406
|
+
* 典型开销:解析几十条而不是上千条。
|
|
21407
|
+
*/
|
|
21408
|
+
findExpiredReplyIds(sessions, notifs) {
|
|
21409
|
+
const found = /* @__PURE__ */ new Set();
|
|
21410
|
+
if (notifs.length === 0) return found;
|
|
21411
|
+
const oldestMs = Math.min(...notifs.map((n) => new Date(n.wakeAt).getTime()));
|
|
21412
|
+
const { current, latestArchive } = scopeMainJsonlPaths(sessions);
|
|
21413
|
+
for (const file of [current, latestArchive]) {
|
|
21414
|
+
if (!file || !fs17.existsSync(file)) continue;
|
|
21415
|
+
let lines;
|
|
21416
|
+
try {
|
|
21417
|
+
lines = fs17.readFileSync(file, "utf-8").split("\n");
|
|
21418
|
+
} catch (e) {
|
|
21419
|
+
console.warn(`[nudge] findExpiredReplyIds read error on ${file}: ${e.message}`);
|
|
21420
|
+
continue;
|
|
21421
|
+
}
|
|
21422
|
+
let coveredOldest = false;
|
|
21423
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
21424
|
+
const trimmed = lines[i].trim();
|
|
21425
|
+
if (!trimmed) continue;
|
|
21426
|
+
let entry;
|
|
21427
|
+
try {
|
|
21428
|
+
entry = JSON.parse(trimmed);
|
|
21429
|
+
} catch {
|
|
21430
|
+
continue;
|
|
21431
|
+
}
|
|
21432
|
+
const tsMs = entry?.timestamp ? new Date(entry.timestamp).getTime() : 0;
|
|
21433
|
+
if (tsMs > 0 && tsMs < oldestMs) {
|
|
21434
|
+
coveredOldest = true;
|
|
21435
|
+
break;
|
|
21436
|
+
}
|
|
21437
|
+
if (entry?.type !== "message") continue;
|
|
21438
|
+
const msg2 = entry.message;
|
|
21439
|
+
if (!msg2 || msg2.role !== "assistant") continue;
|
|
21440
|
+
const content = msg2.content;
|
|
21441
|
+
const text = typeof content === "string" ? content : Array.isArray(content) && content[0] && typeof content[0].text === "string" ? content[0].text : "";
|
|
21442
|
+
if (!text) continue;
|
|
21443
|
+
for (const n of notifs) {
|
|
21444
|
+
if (!found.has(n.id) && (text.includes(`${n.id} \u8FC7\u671F\u4E86`) || text.includes(`${n.id}\u8FC7\u671F\u4E86`))) {
|
|
21445
|
+
found.add(n.id);
|
|
21446
|
+
}
|
|
21447
|
+
}
|
|
21448
|
+
if (found.size === notifs.length) return found;
|
|
21449
|
+
}
|
|
21450
|
+
if (coveredOldest) break;
|
|
21451
|
+
}
|
|
21452
|
+
return found;
|
|
21453
|
+
}
|
|
21085
21454
|
async tick(sessions, deps) {
|
|
21086
21455
|
if (this.running) {
|
|
21087
21456
|
console.log("[nudge] Previous tick still running, skipping");
|
|
@@ -21096,7 +21465,7 @@ var NudgePlugin = class {
|
|
|
21096
21465
|
const recent = recentMessages(sessions, 0.5, 6);
|
|
21097
21466
|
const lastUserMsg2 = recent.filter((r) => r.role === "user").slice(-1)[0];
|
|
21098
21467
|
if (lastUserMsg2) {
|
|
21099
|
-
const elapsed = Date.now() -
|
|
21468
|
+
const elapsed = lastUserMsg2.timestamp ? Date.now() - lastUserMsg2.timestamp : 0;
|
|
21100
21469
|
if (elapsed < activeThresholdMs) {
|
|
21101
21470
|
console.log(`[nudge] User active ${Math.round(elapsed / 1e3)}s ago (<${activeThresholdMs / 1e3}s), skipping tick`);
|
|
21102
21471
|
return;
|
|
@@ -21108,10 +21477,15 @@ var NudgePlugin = class {
|
|
|
21108
21477
|
this.running = true;
|
|
21109
21478
|
try {
|
|
21110
21479
|
this.cleanupStaleNotificationsFromMessages(sessions);
|
|
21111
|
-
const
|
|
21112
|
-
if (
|
|
21480
|
+
const dueNotifs = this.collectDueStopHookNotifications();
|
|
21481
|
+
if (dueNotifs) {
|
|
21113
21482
|
const route2 = this.getRoute(sessions);
|
|
21114
|
-
if (route2)
|
|
21483
|
+
if (route2) {
|
|
21484
|
+
enqueueNotification(dueNotifs.message, route2);
|
|
21485
|
+
this.markNotified(dueNotifs.ids);
|
|
21486
|
+
} else {
|
|
21487
|
+
console.warn(`[nudge] No route for ${dueNotifs.ids.length} stop-hook notification(s), keeping for retry next tick`);
|
|
21488
|
+
}
|
|
21115
21489
|
const state0 = this.loadState();
|
|
21116
21490
|
state0.lastAnyNudgeAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
21117
21491
|
this.saveState(state0);
|
|
@@ -21297,7 +21671,7 @@ var NudgePlugin = class {
|
|
|
21297
21671
|
// === state 持久化 ===
|
|
21298
21672
|
loadState() {
|
|
21299
21673
|
const stateFile = this.cfg.stateFile || "nudge-state.json";
|
|
21300
|
-
const statePath =
|
|
21674
|
+
const statePath = path17.isAbsolute(stateFile) ? stateFile : path17.join(this.workspace, stateFile);
|
|
21301
21675
|
try {
|
|
21302
21676
|
const content = fs17.readFileSync(statePath, "utf-8");
|
|
21303
21677
|
return JSON.parse(content);
|
|
@@ -21307,7 +21681,7 @@ var NudgePlugin = class {
|
|
|
21307
21681
|
}
|
|
21308
21682
|
saveState(state2) {
|
|
21309
21683
|
const stateFile = this.cfg.stateFile || "nudge-state.json";
|
|
21310
|
-
const statePath =
|
|
21684
|
+
const statePath = path17.isAbsolute(stateFile) ? stateFile : path17.join(this.workspace, stateFile);
|
|
21311
21685
|
fs17.writeFileSync(statePath, JSON.stringify(state2, null, 2), "utf-8");
|
|
21312
21686
|
}
|
|
21313
21687
|
newTaskState() {
|
|
@@ -21393,30 +21767,47 @@ var NudgePlugin = class {
|
|
|
21393
21767
|
const now = /* @__PURE__ */ new Date();
|
|
21394
21768
|
const bjOffset = (8 * 60 + now.getTimezoneOffset()) * 6e4;
|
|
21395
21769
|
const bj = new Date(now.getTime() + bjOffset);
|
|
21396
|
-
const month = bj.getMonth() + 1;
|
|
21397
|
-
const day = bj.getDate();
|
|
21398
21770
|
const bjHour = bj.getHours();
|
|
21399
21771
|
const bjMinute = bj.getMinutes();
|
|
21772
|
+
const todayStart = new Date(bj.getFullYear(), bj.getMonth(), bj.getDate()).getTime();
|
|
21400
21773
|
const rows = db.prepare(
|
|
21401
|
-
"SELECT id, event, date_str, time_exact FROM events WHERE status='pending' AND type='task' AND
|
|
21402
|
-
).all(
|
|
21774
|
+
"SELECT id, event, date_str, time_exact FROM events WHERE status='pending' AND type='task' AND date_str IS NOT NULL"
|
|
21775
|
+
).all();
|
|
21403
21776
|
db.close();
|
|
21404
|
-
|
|
21405
|
-
const
|
|
21406
|
-
|
|
21407
|
-
|
|
21408
|
-
|
|
21409
|
-
if (
|
|
21410
|
-
|
|
21777
|
+
const due = [];
|
|
21778
|
+
for (const r2 of rows) {
|
|
21779
|
+
const dayMs = this.parseCalendarDateStr(r2.date_str, bj);
|
|
21780
|
+
if (dayMs === null || dayMs > todayStart) continue;
|
|
21781
|
+
const isToday2 = dayMs === todayStart;
|
|
21782
|
+
if (isToday2 && r2.time_exact) {
|
|
21783
|
+
const [h, m2] = String(r2.time_exact).split(":").map(Number);
|
|
21784
|
+
if (h > bjHour || h === bjHour && m2 > bjMinute) continue;
|
|
21785
|
+
}
|
|
21786
|
+
due.push({ id: r2.id, event: r2.event, date_str: r2.date_str, time_exact: r2.time_exact, dayMs, isToday: isToday2 });
|
|
21787
|
+
}
|
|
21788
|
+
if (due.length === 0) return null;
|
|
21789
|
+
due.sort((a, b2) => {
|
|
21790
|
+
if (a.isToday !== b2.isToday) return a.isToday ? -1 : 1;
|
|
21791
|
+
return b2.dayMs - a.dayMs;
|
|
21411
21792
|
});
|
|
21412
|
-
|
|
21413
|
-
|
|
21414
|
-
return `#${r.id} ${r.event} (${r.date_str} ${r.time_exact || ""})`.trim();
|
|
21793
|
+
const r = due[0];
|
|
21794
|
+
return `#${r.id} ${r.event} (${r.date_str} ${r.time_exact || ""})${r.isToday ? "" : "\uFF08\u5DF2\u903E\u671F\uFF09"}`.trim();
|
|
21415
21795
|
} catch (e) {
|
|
21416
21796
|
console.warn(`[nudge] checkCalendarDue error: ${e.message}`);
|
|
21417
21797
|
return null;
|
|
21418
21798
|
}
|
|
21419
21799
|
}
|
|
21800
|
+
/** 解析 date_str 为当日 0 点 epoch ms(北京时间);"M/D" 按当前年,"YYYY-M-D" 按字面年 */
|
|
21801
|
+
parseCalendarDateStr(ds, bj) {
|
|
21802
|
+
if (!ds) return null;
|
|
21803
|
+
if (/^\d{4}-\d{1,2}-\d{1,2}$/.test(ds)) {
|
|
21804
|
+
const t = (/* @__PURE__ */ new Date(ds + "T00:00:00+08:00")).getTime();
|
|
21805
|
+
return Number.isNaN(t) ? null : t;
|
|
21806
|
+
}
|
|
21807
|
+
const m2 = String(ds).match(/^(\d{1,2})\/(\d{1,2})$/);
|
|
21808
|
+
if (!m2) return null;
|
|
21809
|
+
return new Date(bj.getFullYear(), Number(m2[1]) - 1, Number(m2[2])).getTime();
|
|
21810
|
+
}
|
|
21420
21811
|
/** 检查 carry-over:如果 in_progress task 24h+ 没推进,自动 calendar add-task 排明天 */
|
|
21421
21812
|
checkCarryOver(task, _sessions) {
|
|
21422
21813
|
try {
|
|
@@ -21470,7 +21861,7 @@ var NudgePlugin = class {
|
|
|
21470
21861
|
|
|
21471
21862
|
// src/inner-voice/plugin.ts
|
|
21472
21863
|
import fs21 from "node:fs";
|
|
21473
|
-
import
|
|
21864
|
+
import path21 from "node:path";
|
|
21474
21865
|
|
|
21475
21866
|
// src/inner-voice/activity.ts
|
|
21476
21867
|
function checkActivity(sessions, activeThresholdMs) {
|
|
@@ -21510,7 +21901,7 @@ function calcHintProb(min) {
|
|
|
21510
21901
|
|
|
21511
21902
|
// src/inner-voice/emotional-state.ts
|
|
21512
21903
|
import fs18 from "node:fs";
|
|
21513
|
-
import
|
|
21904
|
+
import path18 from "node:path";
|
|
21514
21905
|
var NEUTRAL = 0.5;
|
|
21515
21906
|
var DECAY_RATE = 0.17;
|
|
21516
21907
|
var MAX_EVENTS = 20;
|
|
@@ -21561,7 +21952,7 @@ function initialState() {
|
|
|
21561
21952
|
return { version: 1, mood: NEUTRAL, trend: "stable", updatedAt: nowIsoBj(), events: [] };
|
|
21562
21953
|
}
|
|
21563
21954
|
async function updateEmotionalState(workspace, sessions) {
|
|
21564
|
-
const stateFile =
|
|
21955
|
+
const stateFile = path18.join(workspace, "inner-voice", "emotional-state.json");
|
|
21565
21956
|
const messages = readRecentMessages(sessions, RECENT_N);
|
|
21566
21957
|
if (messages.length === 0) {
|
|
21567
21958
|
console.log("[emotional-state] no messages");
|
|
@@ -21594,7 +21985,7 @@ async function updateEmotionalState(workspace, sessions) {
|
|
|
21594
21985
|
function readRecentMessages(sessions, n) {
|
|
21595
21986
|
const mainId = sessions.getSessionId("scope:main");
|
|
21596
21987
|
if (!mainId) return [];
|
|
21597
|
-
const file =
|
|
21988
|
+
const file = path18.join(sessions.sessionsDir, `${mainId}.jsonl`);
|
|
21598
21989
|
if (!fs18.existsSync(file)) return [];
|
|
21599
21990
|
const lines = readLastNLines(file, n * 4 + 20);
|
|
21600
21991
|
const entries = [];
|
|
@@ -21712,7 +22103,7 @@ function refreshHoursAgo(events) {
|
|
|
21712
22103
|
}
|
|
21713
22104
|
function appendMoodLog(workspace, state2, summary) {
|
|
21714
22105
|
try {
|
|
21715
|
-
const logPath =
|
|
22106
|
+
const logPath = path18.join(workspace, "mood-history.log");
|
|
21716
22107
|
const ts = formatBj(/* @__PURE__ */ new Date(), false);
|
|
21717
22108
|
fs18.appendFileSync(logPath, `${ts} mood=${state2.mood.toFixed(2)} trend=${state2.trend} ${summary}
|
|
21718
22109
|
`);
|
|
@@ -21729,7 +22120,7 @@ function loadJson(file) {
|
|
|
21729
22120
|
}
|
|
21730
22121
|
function saveJson(file, data) {
|
|
21731
22122
|
try {
|
|
21732
|
-
fs18.mkdirSync(
|
|
22123
|
+
fs18.mkdirSync(path18.dirname(file), { recursive: true });
|
|
21733
22124
|
fs18.writeFileSync(file, JSON.stringify(data, null, 2));
|
|
21734
22125
|
} catch (err) {
|
|
21735
22126
|
console.warn(`[emotional-state] save failed: ${err.message}`);
|
|
@@ -21775,7 +22166,7 @@ function formatBj(d, withSec) {
|
|
|
21775
22166
|
|
|
21776
22167
|
// src/inner-voice/topics-scorer.ts
|
|
21777
22168
|
import fs19 from "node:fs";
|
|
21778
|
-
import
|
|
22169
|
+
import path19 from "node:path";
|
|
21779
22170
|
var HALF_LIFE_DAYS = 3;
|
|
21780
22171
|
var PROJECT_HALF_LIFE_DAYS = 1.5;
|
|
21781
22172
|
var COOLDOWN_HOURS = 6;
|
|
@@ -21783,8 +22174,8 @@ var MAX_CHARS = 8e3;
|
|
|
21783
22174
|
var SKIP_NAMES = /* @__PURE__ */ new Set(["MEMORY.md", "archive"]);
|
|
21784
22175
|
var SKIP_DIRS = /* @__PURE__ */ new Set(["archive"]);
|
|
21785
22176
|
function pickTopic(workspace, typeFilter, opts) {
|
|
21786
|
-
const topicsDir =
|
|
21787
|
-
const usageFile =
|
|
22177
|
+
const topicsDir = path19.join(workspace, "topics");
|
|
22178
|
+
const usageFile = path19.join(workspace, "inner-voice", "topics-usage.json");
|
|
21788
22179
|
const files = scanTopics(topicsDir, typeFilter);
|
|
21789
22180
|
if (files.length === 0) {
|
|
21790
22181
|
console.log(`[topics-scorer] no topics found (type=${typeFilter})`);
|
|
@@ -21816,7 +22207,7 @@ function pickTopic(workspace, typeFilter, opts) {
|
|
|
21816
22207
|
recency: Math.round(recency * 1e3) / 1e3,
|
|
21817
22208
|
freq: Math.round(freq * 1e3) / 1e3,
|
|
21818
22209
|
type: type2,
|
|
21819
|
-
name: meta.name ||
|
|
22210
|
+
name: meta.name || path19.basename(relpath),
|
|
21820
22211
|
description: meta.description || "",
|
|
21821
22212
|
mtime
|
|
21822
22213
|
});
|
|
@@ -21874,14 +22265,14 @@ function scanTopics(topicsDir, typeFilter) {
|
|
|
21874
22265
|
const out = [];
|
|
21875
22266
|
const walk = (dir) => {
|
|
21876
22267
|
for (const name of fs19.readdirSync(dir)) {
|
|
21877
|
-
const full =
|
|
22268
|
+
const full = path19.join(dir, name);
|
|
21878
22269
|
const stat4 = fs19.statSync(full);
|
|
21879
22270
|
if (stat4.isDirectory()) {
|
|
21880
22271
|
if (SKIP_DIRS.has(name)) continue;
|
|
21881
22272
|
walk(full);
|
|
21882
22273
|
} else {
|
|
21883
22274
|
if (!name.endsWith(".md") || SKIP_NAMES.has(name)) continue;
|
|
21884
|
-
const relpath =
|
|
22275
|
+
const relpath = path19.relative(topicsDir, full).replace(/\\/g, "/");
|
|
21885
22276
|
if (typeFilter && !relpath.startsWith(typeFilter + "/") && !relpath.startsWith(typeFilter + "_")) continue;
|
|
21886
22277
|
out.push({ relpath, fullpath: full });
|
|
21887
22278
|
}
|
|
@@ -21926,7 +22317,7 @@ function loadJson2(file) {
|
|
|
21926
22317
|
}
|
|
21927
22318
|
function saveJson2(file, data) {
|
|
21928
22319
|
try {
|
|
21929
|
-
fs19.mkdirSync(
|
|
22320
|
+
fs19.mkdirSync(path19.dirname(file), { recursive: true });
|
|
21930
22321
|
fs19.writeFileSync(file, JSON.stringify(data, null, 2));
|
|
21931
22322
|
} catch (err) {
|
|
21932
22323
|
console.warn(`[topics-scorer] usage save failed: ${err.message}`);
|
|
@@ -21935,21 +22326,21 @@ function saveJson2(file, data) {
|
|
|
21935
22326
|
|
|
21936
22327
|
// src/inner-voice/memory-reader.ts
|
|
21937
22328
|
import fs20 from "node:fs";
|
|
21938
|
-
import
|
|
22329
|
+
import path20 from "node:path";
|
|
21939
22330
|
var US_HALF_LIFE_DAYS = 10;
|
|
21940
22331
|
var US_MAX_LINES = 60;
|
|
21941
22332
|
function readRecentMemory(workspace) {
|
|
21942
|
-
const dir =
|
|
22333
|
+
const dir = path20.join(workspace, "memory");
|
|
21943
22334
|
const now = new Date(Date.now() + 8 * 36e5);
|
|
21944
22335
|
const today = formatYmd(now);
|
|
21945
22336
|
const yesterday = formatYmd(new Date(now.getTime() - 864e5));
|
|
21946
22337
|
return {
|
|
21947
|
-
today: readIfExists(
|
|
21948
|
-
yesterday: readIfExists(
|
|
22338
|
+
today: readIfExists(path20.join(dir, `${today}.md`)),
|
|
22339
|
+
yesterday: readIfExists(path20.join(dir, `${yesterday}.md`))
|
|
21949
22340
|
};
|
|
21950
22341
|
}
|
|
21951
22342
|
function sampleUs(workspace) {
|
|
21952
|
-
const usFile =
|
|
22343
|
+
const usFile = path20.join(workspace, "memory", "us.md");
|
|
21953
22344
|
let content;
|
|
21954
22345
|
try {
|
|
21955
22346
|
content = fs20.readFileSync(usFile, "utf-8");
|
|
@@ -22289,7 +22680,7 @@ var InnerVoicePlugin = class {
|
|
|
22289
22680
|
}
|
|
22290
22681
|
/** 读 workspace/prompts/my-inner-voice.md,不存在用 DEFAULT_PROMPT */
|
|
22291
22682
|
loadPrompt(workspace) {
|
|
22292
|
-
const promptPath =
|
|
22683
|
+
const promptPath = path21.join(workspace, "prompts", "my-inner-voice.md");
|
|
22293
22684
|
try {
|
|
22294
22685
|
const content = fs21.readFileSync(promptPath, "utf-8").trim();
|
|
22295
22686
|
if (content) {
|
|
@@ -22363,7 +22754,7 @@ var InnerVoicePlugin = class {
|
|
|
22363
22754
|
console.warn(`[inner-voice] emotional-state failed: ${err.message}`);
|
|
22364
22755
|
}
|
|
22365
22756
|
try {
|
|
22366
|
-
const content = fs21.readFileSync(
|
|
22757
|
+
const content = fs21.readFileSync(path21.join(this.workspace, "SESSION-STATE.md"), "utf-8");
|
|
22367
22758
|
lines.push("\n--- SESSION-STATE\uFF08\u5C3E\u90E8\uFF09 ---");
|
|
22368
22759
|
lines.push(content.slice(-2e3));
|
|
22369
22760
|
} catch {
|
|
@@ -22474,7 +22865,7 @@ var InnerVoicePlugin = class {
|
|
|
22474
22865
|
if (Math.random() >= activity.hintProb) {
|
|
22475
22866
|
return { text: thought, hintTriggered: false, hintText: "" };
|
|
22476
22867
|
}
|
|
22477
|
-
const poolPath =
|
|
22868
|
+
const poolPath = path21.join(this.workspace, "inner-voice", "hints_pool.txt");
|
|
22478
22869
|
let hint = "\u60F3\u4ED6\u5C31\u53D1\u6D88\u606F\u5427";
|
|
22479
22870
|
try {
|
|
22480
22871
|
const pool = fs21.readFileSync(poolPath, "utf-8").split("\n").map((s2) => s2.trim()).filter(Boolean);
|
|
@@ -22502,7 +22893,7 @@ var InnerVoicePlugin = class {
|
|
|
22502
22893
|
try {
|
|
22503
22894
|
const writer = sessions.getWriter(mainSessionId);
|
|
22504
22895
|
const history = sessions.getHistory(mainSessionId);
|
|
22505
|
-
const fullPath =
|
|
22896
|
+
const fullPath = path21.resolve(this.workspace, emoTopic.file);
|
|
22506
22897
|
const memories = [{
|
|
22507
22898
|
path: fullPath,
|
|
22508
22899
|
content: emoTopic.content,
|
|
@@ -22530,9 +22921,9 @@ var InnerVoicePlugin = class {
|
|
|
22530
22921
|
/** 写 xiaoyi.log(格式对齐旧 memory_whisper.py,便于既有日志分析复用)。 */
|
|
22531
22922
|
writeLog(status, delivered, activity, hintTriggered, hintText) {
|
|
22532
22923
|
try {
|
|
22533
|
-
const logDir =
|
|
22924
|
+
const logDir = path21.join(this.workspace, "inner-voice");
|
|
22534
22925
|
fs21.mkdirSync(logDir, { recursive: true });
|
|
22535
|
-
const logPath =
|
|
22926
|
+
const logPath = path21.join(logDir, "xiaoyi.log");
|
|
22536
22927
|
const ts = formatBeijingTs(/* @__PURE__ */ new Date());
|
|
22537
22928
|
const hintStatus = hintTriggered ? `YES (${(hintText || "").trim()})` : "no";
|
|
22538
22929
|
fs21.appendFileSync(
|
|
@@ -23071,7 +23462,7 @@ var PluginManager = class {
|
|
|
23071
23462
|
// src/voice-chat/plugin.ts
|
|
23072
23463
|
import { spawn as spawn4, exec } from "node:child_process";
|
|
23073
23464
|
import net from "node:net";
|
|
23074
|
-
import
|
|
23465
|
+
import path22 from "node:path";
|
|
23075
23466
|
import fs22 from "node:fs";
|
|
23076
23467
|
|
|
23077
23468
|
// src/voice-chat/bridge.ts
|
|
@@ -23448,13 +23839,13 @@ var VoiceChatPlugin = class _VoiceChatPlugin {
|
|
|
23448
23839
|
}
|
|
23449
23840
|
getPythonDir() {
|
|
23450
23841
|
const dir = import.meta.dirname;
|
|
23451
|
-
const srcDir =
|
|
23452
|
-
const localDir =
|
|
23842
|
+
const srcDir = path22.resolve(dir, "..", "src", "voice-chat", "python");
|
|
23843
|
+
const localDir = path22.join(dir, "python");
|
|
23453
23844
|
return fs22.existsSync(srcDir) ? srcDir : localDir;
|
|
23454
23845
|
}
|
|
23455
23846
|
startPython() {
|
|
23456
23847
|
const pythonDir = this.getPythonDir();
|
|
23457
|
-
const serverPy =
|
|
23848
|
+
const serverPy = path22.join(pythonDir, "server.py");
|
|
23458
23849
|
const pythonBin = this.findPython();
|
|
23459
23850
|
const args2 = [serverPy];
|
|
23460
23851
|
if (this.config.pythonPort) args2.push("--port", String(this.config.pythonPort));
|
|
@@ -23539,7 +23930,7 @@ var VoiceChatPlugin = class _VoiceChatPlugin {
|
|
|
23539
23930
|
init_BashTool();
|
|
23540
23931
|
import { spawn as spawn5, exec as exec2 } from "node:child_process";
|
|
23541
23932
|
import net2 from "node:net";
|
|
23542
|
-
import
|
|
23933
|
+
import path23 from "node:path";
|
|
23543
23934
|
import fs23 from "node:fs";
|
|
23544
23935
|
|
|
23545
23936
|
// src/memory/cognifold/config.ts
|
|
@@ -23563,7 +23954,8 @@ function parseCognifoldConfig(raw) {
|
|
|
23563
23954
|
persistDir: raw.persistDir ?? DEFAULTS3.persistDir,
|
|
23564
23955
|
scopes: raw.scopes,
|
|
23565
23956
|
readyTimeoutMs: raw.readyTimeoutMs ?? DEFAULTS3.readyTimeoutMs,
|
|
23566
|
-
maxRestarts: raw.maxRestarts ?? DEFAULTS3.maxRestarts
|
|
23957
|
+
maxRestarts: raw.maxRestarts ?? DEFAULTS3.maxRestarts,
|
|
23958
|
+
llm: raw.llm
|
|
23567
23959
|
};
|
|
23568
23960
|
}
|
|
23569
23961
|
|
|
@@ -23571,15 +23963,17 @@ function parseCognifoldConfig(raw) {
|
|
|
23571
23963
|
var CogniFoldClient = class {
|
|
23572
23964
|
baseUrl;
|
|
23573
23965
|
timeoutMs;
|
|
23574
|
-
|
|
23966
|
+
modelName;
|
|
23967
|
+
constructor(baseUrl, timeoutMs = 3e4, modelName = "openai:MiniMax-M3") {
|
|
23575
23968
|
this.baseUrl = baseUrl.replace(/\/$/, "");
|
|
23576
23969
|
this.timeoutMs = timeoutMs;
|
|
23970
|
+
this.modelName = modelName;
|
|
23577
23971
|
}
|
|
23578
|
-
async req(
|
|
23972
|
+
async req(path44, options = {}) {
|
|
23579
23973
|
const ctrl = new AbortController();
|
|
23580
23974
|
const timer = setTimeout(() => ctrl.abort(), this.timeoutMs);
|
|
23581
23975
|
try {
|
|
23582
|
-
const resp = await fetch(`${this.baseUrl}${
|
|
23976
|
+
const resp = await fetch(`${this.baseUrl}${path44}`, {
|
|
23583
23977
|
...options,
|
|
23584
23978
|
signal: ctrl.signal,
|
|
23585
23979
|
headers: {
|
|
@@ -23617,7 +24011,7 @@ var CogniFoldClient = class {
|
|
|
23617
24011
|
method: "POST",
|
|
23618
24012
|
body: JSON.stringify({
|
|
23619
24013
|
user_id: userId,
|
|
23620
|
-
config: { model_name:
|
|
24014
|
+
config: { model_name: this.modelName }
|
|
23621
24015
|
})
|
|
23622
24016
|
});
|
|
23623
24017
|
}
|
|
@@ -23669,8 +24063,8 @@ var CogniFoldClient = class {
|
|
|
23669
24063
|
});
|
|
23670
24064
|
}
|
|
23671
24065
|
/** 兼容老版命名 */
|
|
23672
|
-
async recl(
|
|
23673
|
-
return this.req(
|
|
24066
|
+
async recl(path44, options = {}) {
|
|
24067
|
+
return this.req(path44, options);
|
|
23674
24068
|
}
|
|
23675
24069
|
};
|
|
23676
24070
|
|
|
@@ -23775,7 +24169,8 @@ var CogniFoldPlugin = class {
|
|
|
23775
24169
|
baseUrl = baseUrl.replace(/\/$/, "") + "/api/v1";
|
|
23776
24170
|
}
|
|
23777
24171
|
this.config.baseUrl = baseUrl;
|
|
23778
|
-
this.
|
|
24172
|
+
const modelName = this.config.llm?.model ? this.config.llm.model.startsWith("openai:") ? this.config.llm.model : `openai:${this.config.llm.model}` : "openai:MiniMax-M3";
|
|
24173
|
+
this.client = new CogniFoldClient(baseUrl, 3e4, modelName);
|
|
23779
24174
|
}
|
|
23780
24175
|
workspacePath;
|
|
23781
24176
|
name = "cognifold";
|
|
@@ -23950,16 +24345,16 @@ var CogniFoldPlugin = class {
|
|
|
23950
24345
|
const dir = import.meta.dirname;
|
|
23951
24346
|
const candidates = [
|
|
23952
24347
|
// 从 dist/ 往回找 src
|
|
23953
|
-
|
|
23954
|
-
|
|
23955
|
-
|
|
24348
|
+
path23.resolve(dir, "..", "src", "memory", "cognifold", "python"),
|
|
24349
|
+
path23.resolve(dir, "..", "..", "src", "memory", "cognifold", "python"),
|
|
24350
|
+
path23.resolve(dir, "..", "..", "..", "src", "memory", "cognifold", "python"),
|
|
23956
24351
|
// 从 src/memory/cognifold/ 找本地
|
|
23957
|
-
|
|
24352
|
+
path23.join(dir, "python"),
|
|
23958
24353
|
// 从 dist/memory/cognifold/ 找本地
|
|
23959
|
-
|
|
24354
|
+
path23.resolve(dir, "python")
|
|
23960
24355
|
];
|
|
23961
24356
|
for (const candidate of candidates) {
|
|
23962
|
-
if (fs23.existsSync(
|
|
24357
|
+
if (fs23.existsSync(path23.join(candidate, "cognifold"))) {
|
|
23963
24358
|
return candidate;
|
|
23964
24359
|
}
|
|
23965
24360
|
}
|
|
@@ -23985,12 +24380,18 @@ var CogniFoldPlugin = class {
|
|
|
23985
24380
|
const pythonBin = this.findPython();
|
|
23986
24381
|
console.log(`[cognifold] Starting Python: ${pythonBin} ${args2.join(" ")}`);
|
|
23987
24382
|
console.log(`[cognifold] Python dir: ${pythonDir}`);
|
|
23988
|
-
if (!fs23.existsSync(
|
|
24383
|
+
if (!fs23.existsSync(path23.join(pythonDir, "cognifold"))) {
|
|
23989
24384
|
console.error(`[cognifold] FATAL: Python module not found at ${pythonDir}/cognifold`);
|
|
23990
24385
|
throw new Error(`cognifold: python module not found`);
|
|
23991
24386
|
}
|
|
23992
24387
|
const childEnv = { ...process.env, PYTHONUNBUFFERED: "1" };
|
|
23993
|
-
|
|
24388
|
+
if (this.config.llm?.apiKey) {
|
|
24389
|
+
childEnv["OPENAI_API_KEY"] = this.config.llm.apiKey;
|
|
24390
|
+
}
|
|
24391
|
+
if (this.config.llm?.baseUrl) {
|
|
24392
|
+
childEnv["OPENAI_BASE_URL"] = this.config.llm.baseUrl;
|
|
24393
|
+
}
|
|
24394
|
+
const envFile = path23.join(pythonDir, ".env");
|
|
23994
24395
|
try {
|
|
23995
24396
|
if (fs23.existsSync(envFile)) {
|
|
23996
24397
|
const envContent = fs23.readFileSync(envFile, "utf-8");
|
|
@@ -24062,7 +24463,7 @@ var CogniFoldPlugin = class {
|
|
|
24062
24463
|
init_BashTool();
|
|
24063
24464
|
import { spawn as spawn6 } from "node:child_process";
|
|
24064
24465
|
import net3 from "node:net";
|
|
24065
|
-
import
|
|
24466
|
+
import path24 from "node:path";
|
|
24066
24467
|
import fs24 from "node:fs";
|
|
24067
24468
|
|
|
24068
24469
|
// src/memory/everos/config.ts
|
|
@@ -24096,7 +24497,8 @@ function parseEverosConfig(raw) {
|
|
|
24096
24497
|
llm: raw.llm ?? { model: "glm-5.2", apiKey: "", baseUrl: "https://open.bigmodel.cn/api/coding/paas/v4" },
|
|
24097
24498
|
rerank: raw.rerank ?? { model: "Qwen/Qwen3-Reranker-4B", apiKey: "", baseUrl: "https://api.deepinfra.com/v1/inference" },
|
|
24098
24499
|
lancedbPath: raw.lancedbPath ?? "",
|
|
24099
|
-
sqlitePath: raw.sqlitePath ?? ""
|
|
24500
|
+
sqlitePath: raw.sqlitePath ?? "",
|
|
24501
|
+
minScore: raw.minScore
|
|
24100
24502
|
};
|
|
24101
24503
|
}
|
|
24102
24504
|
|
|
@@ -24134,21 +24536,31 @@ var EverosSearchClient = class {
|
|
|
24134
24536
|
clearTimeout(timer);
|
|
24135
24537
|
}
|
|
24136
24538
|
}
|
|
24137
|
-
/** Search —
|
|
24539
|
+
/** Search — routes to 8101 (agentic) or 8100 (hybrid) based on mode */
|
|
24138
24540
|
async search(params) {
|
|
24139
24541
|
const ctrl = new AbortController();
|
|
24140
24542
|
const timer = setTimeout(() => ctrl.abort(), this.timeoutMs);
|
|
24141
24543
|
try {
|
|
24142
|
-
const
|
|
24544
|
+
const mode = params.mode || "hybrid";
|
|
24545
|
+
const useAgentic = mode === "hybrid_agentic" || mode === "agentic";
|
|
24546
|
+
const url = useAgentic ? `${this.agenticUrl}/api/v1/search` : `${this.everosUrl}/api/v1/memory/search`;
|
|
24547
|
+
const body = useAgentic ? JSON.stringify({
|
|
24548
|
+
query: params.query,
|
|
24549
|
+
user_id: params.userId || "xiaomei",
|
|
24550
|
+
mode,
|
|
24551
|
+
top_k: params.topK ?? 5,
|
|
24552
|
+
strategy: params.strategy || "multi_query"
|
|
24553
|
+
}) : JSON.stringify({
|
|
24554
|
+
query: params.query,
|
|
24555
|
+
user_id: params.userId || "user",
|
|
24556
|
+
app_id: "xiaomei",
|
|
24557
|
+
project_id: "default",
|
|
24558
|
+
top_k: params.topK ?? 5
|
|
24559
|
+
});
|
|
24560
|
+
const resp = await fetch(url, {
|
|
24143
24561
|
method: "POST",
|
|
24144
24562
|
headers: { "Content-Type": "application/json" },
|
|
24145
|
-
body
|
|
24146
|
-
query: params.query,
|
|
24147
|
-
user_id: params.userId || "xiaomei",
|
|
24148
|
-
mode: params.mode || "hybrid_agentic",
|
|
24149
|
-
top_k: params.topK ?? 5,
|
|
24150
|
-
strategy: params.strategy || "multi_query"
|
|
24151
|
-
}),
|
|
24563
|
+
body,
|
|
24152
24564
|
signal: ctrl.signal
|
|
24153
24565
|
});
|
|
24154
24566
|
if (!resp.ok) {
|
|
@@ -24188,6 +24600,7 @@ var EverosPlugin = class {
|
|
|
24188
24600
|
}
|
|
24189
24601
|
async start(ctx) {
|
|
24190
24602
|
if (!this.config.enabled) return;
|
|
24603
|
+
await this.ensureVenv();
|
|
24191
24604
|
try {
|
|
24192
24605
|
await this.client.healthEveros();
|
|
24193
24606
|
console.log(`[everos] EverOS already running at ${this.config.everosUrl}`);
|
|
@@ -24258,13 +24671,15 @@ var EverosPlugin = class {
|
|
|
24258
24671
|
}, 3e5);
|
|
24259
24672
|
}
|
|
24260
24673
|
async startEveros() {
|
|
24261
|
-
const pythonDir =
|
|
24262
|
-
const configPath2 =
|
|
24674
|
+
const pythonDir = path24.dirname(this.config.lancedbPath);
|
|
24675
|
+
const configPath2 = path24.join(pythonDir, "config.toml");
|
|
24263
24676
|
await this.ensureFcntlCompat();
|
|
24264
24677
|
const venvPython = this.findVenvPython();
|
|
24678
|
+
const everosBin = venvPython.replace(/python\.exe$/, "everos.exe");
|
|
24265
24679
|
const args2 = ["server", "start"];
|
|
24266
|
-
const cmd = `${
|
|
24680
|
+
const cmd = `${everosBin} ${args2.join(" ")}`;
|
|
24267
24681
|
console.log(`[everos] Starting EverOS: ${cmd}`);
|
|
24682
|
+
console.log(`[everos] LLM config: ${this.config.llm.model} @ ${this.config.llm.baseUrl}`);
|
|
24268
24683
|
if (process.platform === "win32") {
|
|
24269
24684
|
const { shell, args: shellArgs } = findShell();
|
|
24270
24685
|
spawn6(shell, [...shellArgs, cmd], {
|
|
@@ -24279,7 +24694,7 @@ var EverosPlugin = class {
|
|
|
24279
24694
|
env: { ...process.env, PYTHONUNBUFFERED: "1" }
|
|
24280
24695
|
});
|
|
24281
24696
|
}
|
|
24282
|
-
await this.waitForReady(`${this.config.everosUrl}/health`,
|
|
24697
|
+
await this.waitForReady(`${this.config.everosUrl}/health`, 6e4);
|
|
24283
24698
|
}
|
|
24284
24699
|
startAgenticServer() {
|
|
24285
24700
|
const pythonDir = this.getPythonDir();
|
|
@@ -24289,6 +24704,7 @@ var EverosPlugin = class {
|
|
|
24289
24704
|
const cmd = `${venvPython} ${args2.join(" ")}`;
|
|
24290
24705
|
console.log(`[everos] Starting agentic server: ${cmd}`);
|
|
24291
24706
|
console.log(`[everos] Python dir: ${pythonDir}`);
|
|
24707
|
+
console.log(`[everos] LLM: ${this.config.llm.model} @ ${this.config.llm.baseUrl}`);
|
|
24292
24708
|
const childEnv = {
|
|
24293
24709
|
...process.env,
|
|
24294
24710
|
PYTHONUNBUFFERED: "1",
|
|
@@ -24297,15 +24713,25 @@ var EverosPlugin = class {
|
|
|
24297
24713
|
LLM_API_KEY: this.config.llm.apiKey,
|
|
24298
24714
|
LLM_BASE_URL: this.config.llm.baseUrl,
|
|
24299
24715
|
RERANK_API_KEY: this.config.rerank.apiKey,
|
|
24300
|
-
RERANK_URL:
|
|
24716
|
+
RERANK_URL: this.config.rerank.baseUrl,
|
|
24301
24717
|
LANCEDB_PATH: this.config.lancedbPath,
|
|
24302
24718
|
SQLITE_PATH: this.config.sqlitePath,
|
|
24303
24719
|
EVEROS_USER_ID: this.config.userId
|
|
24304
24720
|
};
|
|
24721
|
+
const maskKey = (k2) => k2 ? `${k2.slice(0, 4)}\u2026${k2.slice(-4)}` : "(empty!)";
|
|
24722
|
+
console.log(`[everos] agentic env:`);
|
|
24723
|
+
console.log(`[everos] EVEROS_URL=${childEnv.EVEROS_URL}`);
|
|
24724
|
+
console.log(`[everos] LLM_MODEL=${childEnv.LLM_MODEL}`);
|
|
24725
|
+
console.log(`[everos] LLM_API_KEY=${maskKey(childEnv.LLM_API_KEY)}`);
|
|
24726
|
+
console.log(`[everos] LLM_BASE_URL=${childEnv.LLM_BASE_URL}`);
|
|
24727
|
+
console.log(`[everos] RERANK_API_KEY=${maskKey(childEnv.RERANK_API_KEY)}`);
|
|
24728
|
+
console.log(`[everos] RERANK_URL=${childEnv.RERANK_URL}`);
|
|
24729
|
+
console.log(`[everos] LANCEDB_PATH=${childEnv.LANCEDB_PATH}`);
|
|
24730
|
+
console.log(`[everos] SQLITE_PATH=${childEnv.SQLITE_PATH}`);
|
|
24731
|
+
console.log(`[everos] EVEROS_USER_ID=${childEnv.EVEROS_USER_ID}`);
|
|
24305
24732
|
let child;
|
|
24306
24733
|
if (process.platform === "win32") {
|
|
24307
|
-
|
|
24308
|
-
child = spawn6(shell, [...shellArgs, cmd], {
|
|
24734
|
+
child = spawn6(venvPython, args2, {
|
|
24309
24735
|
cwd: pythonDir,
|
|
24310
24736
|
stdio: ["ignore", "pipe", "pipe"],
|
|
24311
24737
|
env: childEnv
|
|
@@ -24335,21 +24761,64 @@ var EverosPlugin = class {
|
|
|
24335
24761
|
return child;
|
|
24336
24762
|
}
|
|
24337
24763
|
findVenvPython() {
|
|
24338
|
-
const stateDir = process.env.OPENCLAW_STATE_DIR ||
|
|
24764
|
+
const stateDir = process.env.OPENCLAW_STATE_DIR || path24.join(process.env.HOME || process.env.USERPROFILE || ".", ".openclaw");
|
|
24339
24765
|
if (process.platform === "win32") {
|
|
24340
|
-
return
|
|
24766
|
+
return path24.join(stateDir, "everos-venv", "Scripts", "python.exe");
|
|
24767
|
+
}
|
|
24768
|
+
return path24.join(stateDir, "everos-venv", "bin", "python");
|
|
24769
|
+
}
|
|
24770
|
+
/** 检测 venv 是否存在,不存在就自动创建 + 装 EverOS */
|
|
24771
|
+
async ensureVenv() {
|
|
24772
|
+
const venvPython = this.findVenvPython();
|
|
24773
|
+
if (fs24.existsSync(venvPython)) return;
|
|
24774
|
+
const stateDir = process.env.OPENCLAW_STATE_DIR || path24.join(process.env.HOME || process.env.USERPROFILE || ".", ".openclaw");
|
|
24775
|
+
const venvDir = path24.join(stateDir, "everos-venv");
|
|
24776
|
+
const everosSrc = path24.join(stateDir, "workspace", "research", "EverOS");
|
|
24777
|
+
console.log(`[everos] venv not found at ${venvDir}, auto-creating...`);
|
|
24778
|
+
console.log(`[everos] \u23F3 This may take a few minutes on first run...`);
|
|
24779
|
+
const pyCandidates = process.platform === "win32" ? ["python", "python3", "C:\\Python314\\python.exe", "C:\\Python313\\python.exe", "C:\\Python312\\python.exe"] : ["python3", "python"];
|
|
24780
|
+
let sysPython = "";
|
|
24781
|
+
for (const cmd of pyCandidates) {
|
|
24782
|
+
try {
|
|
24783
|
+
const { execSync: execSync3 } = await import("node:child_process");
|
|
24784
|
+
execSync3(`"${cmd}" --version`, { stdio: "pipe", shell: true });
|
|
24785
|
+
sysPython = cmd;
|
|
24786
|
+
break;
|
|
24787
|
+
} catch {
|
|
24788
|
+
}
|
|
24789
|
+
}
|
|
24790
|
+
if (!sysPython) {
|
|
24791
|
+
console.error(`[everos] \u2717 Python not found. Install Python 3.10+ first.`);
|
|
24792
|
+
return;
|
|
24793
|
+
}
|
|
24794
|
+
try {
|
|
24795
|
+
console.log(`[everos] Creating venv with ${sysPython}...`);
|
|
24796
|
+
const { execSync: execSync3 } = await import("node:child_process");
|
|
24797
|
+
execSync3(`"${sysPython}" -m venv "${venvDir}"`, { stdio: "pipe", shell: true });
|
|
24798
|
+
const pip = process.platform === "win32" ? path24.join(venvDir, "Scripts", "pip.exe") : path24.join(venvDir, "bin", "pip");
|
|
24799
|
+
const everosReq = path24.join(this.getPythonDir(), "requirements.txt");
|
|
24800
|
+
if (fs24.existsSync(everosReq)) {
|
|
24801
|
+
console.log(`[everos] Installing from requirements.txt...`);
|
|
24802
|
+
execSync3(`"${pip}" install -r "${everosReq}" -q`, { stdio: "pipe", shell: true, timeout: 3e5 });
|
|
24803
|
+
} else {
|
|
24804
|
+
console.log(`[everos] No requirements.txt found, installing everos from PyPI...`);
|
|
24805
|
+
execSync3(`"${pip}" install everos -q`, { stdio: "pipe", shell: true, timeout: 3e5 });
|
|
24806
|
+
}
|
|
24807
|
+
console.log(`[everos] \u2705 venv created successfully`);
|
|
24808
|
+
} catch (err) {
|
|
24809
|
+
console.error(`[everos] \u2717 Failed to create venv: ${err.message}`);
|
|
24810
|
+
console.error(`[everos] Manual setup: see workspace/scripts/everos-setup.sh`);
|
|
24341
24811
|
}
|
|
24342
|
-
return path23.join(stateDir, "everos-venv", "bin", "python");
|
|
24343
24812
|
}
|
|
24344
24813
|
getPythonDir() {
|
|
24345
24814
|
const dir = import.meta.dirname;
|
|
24346
24815
|
const candidates = [
|
|
24347
|
-
|
|
24348
|
-
|
|
24349
|
-
|
|
24816
|
+
path24.join(dir, "python"),
|
|
24817
|
+
path24.resolve(dir, "..", "src", "memory", "everos", "python"),
|
|
24818
|
+
path24.resolve(dir, "..", "..", "..", "src", "memory", "everos", "python")
|
|
24350
24819
|
];
|
|
24351
24820
|
for (const candidate of candidates) {
|
|
24352
|
-
if (fs24.existsSync(
|
|
24821
|
+
if (fs24.existsSync(path24.join(candidate, "agentic_server.py"))) {
|
|
24353
24822
|
return candidate;
|
|
24354
24823
|
}
|
|
24355
24824
|
}
|
|
@@ -24358,11 +24827,11 @@ var EverosPlugin = class {
|
|
|
24358
24827
|
async ensureFcntlCompat() {
|
|
24359
24828
|
if (process.platform !== "win32") return;
|
|
24360
24829
|
const venvPython = this.findVenvPython();
|
|
24361
|
-
const venvDir =
|
|
24362
|
-
const sitePackages =
|
|
24363
|
-
const target =
|
|
24830
|
+
const venvDir = path24.dirname(path24.dirname(venvPython));
|
|
24831
|
+
const sitePackages = path24.join(venvDir, "Lib", "site-packages");
|
|
24832
|
+
const target = path24.join(sitePackages, "fcntl.py");
|
|
24364
24833
|
if (fs24.existsSync(target)) return;
|
|
24365
|
-
const source =
|
|
24834
|
+
const source = path24.join(this.getPythonDir(), "fcntl_compat.py");
|
|
24366
24835
|
if (fs24.existsSync(source)) {
|
|
24367
24836
|
try {
|
|
24368
24837
|
fs24.copyFileSync(source, target);
|
|
@@ -24412,7 +24881,7 @@ var EverosPlugin = class {
|
|
|
24412
24881
|
init_task_manager();
|
|
24413
24882
|
|
|
24414
24883
|
// src/skills/scanner.ts
|
|
24415
|
-
import * as
|
|
24884
|
+
import * as path25 from "node:path";
|
|
24416
24885
|
import * as fs25 from "node:fs";
|
|
24417
24886
|
function scanSkills(skillsDir) {
|
|
24418
24887
|
if (!fs25.existsSync(skillsDir)) {
|
|
@@ -24423,7 +24892,7 @@ function scanSkills(skillsDir) {
|
|
|
24423
24892
|
const skills = [];
|
|
24424
24893
|
for (const entry of entries) {
|
|
24425
24894
|
if (!entry.isDirectory()) continue;
|
|
24426
|
-
const skillMdPath =
|
|
24895
|
+
const skillMdPath = path25.join(skillsDir, entry.name, "SKILL.md");
|
|
24427
24896
|
if (!fs25.existsSync(skillMdPath)) continue;
|
|
24428
24897
|
try {
|
|
24429
24898
|
const content = fs25.readFileSync(skillMdPath, "utf-8");
|
|
@@ -24491,7 +24960,7 @@ function parseFrontmatter2(content) {
|
|
|
24491
24960
|
// src/tools/SkillTool/SkillTool.ts
|
|
24492
24961
|
init_registry();
|
|
24493
24962
|
import * as fs26 from "node:fs";
|
|
24494
|
-
import * as
|
|
24963
|
+
import * as path26 from "node:path";
|
|
24495
24964
|
|
|
24496
24965
|
// src/tools/SkillTool/constants.ts
|
|
24497
24966
|
var SKILL_TOOL_NAME2 = "Skill";
|
|
@@ -24568,12 +25037,12 @@ Important:
|
|
|
24568
25037
|
`;
|
|
24569
25038
|
}
|
|
24570
25039
|
function loadSkillContent(skillName) {
|
|
24571
|
-
const skillMdPath =
|
|
25040
|
+
const skillMdPath = path26.join(skillsDirPath, skillName, "SKILL.md");
|
|
24572
25041
|
if (!fs26.existsSync(skillMdPath)) return null;
|
|
24573
25042
|
const content = fs26.readFileSync(skillMdPath, "utf-8");
|
|
24574
25043
|
const bodyMatch = content.match(/^---\s*\n[\s\S]*?\n---\s*\n([\s\S]*)/);
|
|
24575
25044
|
const body = bodyMatch ? bodyMatch[1] : content;
|
|
24576
|
-
const skillDir =
|
|
25045
|
+
const skillDir = path26.dirname(skillMdPath);
|
|
24577
25046
|
const normalizedDir = process.platform === "win32" ? skillDir.replace(/\\/g, "/") : skillDir;
|
|
24578
25047
|
let finalContent = `Base directory for this skill: ${normalizedDir}
|
|
24579
25048
|
|
|
@@ -24848,9 +25317,9 @@ Examples:
|
|
|
24848
25317
|
init_registry();
|
|
24849
25318
|
init_live();
|
|
24850
25319
|
import fs27 from "node:fs";
|
|
24851
|
-
import
|
|
25320
|
+
import path27 from "node:path";
|
|
24852
25321
|
function getHusbandFeishuId(workspace) {
|
|
24853
|
-
const contactsPath =
|
|
25322
|
+
const contactsPath = path27.join(workspace, "prompts", "contacts.md");
|
|
24854
25323
|
try {
|
|
24855
25324
|
const text = fs27.readFileSync(contactsPath, "utf-8");
|
|
24856
25325
|
const m2 = text.match(/\|\s*翀哥\s*\|\s*(ou_[a-f0-9]+)\s*\|/);
|
|
@@ -25053,7 +25522,7 @@ Examples:
|
|
|
25053
25522
|
init_live();
|
|
25054
25523
|
init_registry();
|
|
25055
25524
|
import * as fs28 from "node:fs";
|
|
25056
|
-
import * as
|
|
25525
|
+
import * as path28 from "node:path";
|
|
25057
25526
|
var MIME_MAP = {
|
|
25058
25527
|
".jpg": "jpeg",
|
|
25059
25528
|
".jpeg": "jpeg",
|
|
@@ -25065,7 +25534,7 @@ var MIME_MAP = {
|
|
|
25065
25534
|
function resolveLatestImage(specifiedPath, mediaDir) {
|
|
25066
25535
|
if (specifiedPath && fs28.existsSync(specifiedPath)) return specifiedPath;
|
|
25067
25536
|
if (!fs28.existsSync(mediaDir)) return null;
|
|
25068
|
-
const files = fs28.readdirSync(mediaDir).filter((f2) => /\.(jpg|jpeg|png|webp|gif|bmp)$/i.test(f2)).map((f2) => ({ name: f2, p:
|
|
25537
|
+
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);
|
|
25069
25538
|
return files[0]?.p || null;
|
|
25070
25539
|
}
|
|
25071
25540
|
registry.register({
|
|
@@ -25089,13 +25558,13 @@ registry.register({
|
|
|
25089
25558
|
if (!provider?.streamChat) {
|
|
25090
25559
|
return { content: "Error: provider \u4E0D\u53EF\u7528\u3002", isError: true };
|
|
25091
25560
|
}
|
|
25092
|
-
const mediaDir =
|
|
25561
|
+
const mediaDir = path28.join(ctx.stateDir, "media", "inbound");
|
|
25093
25562
|
const imagePath = resolveLatestImage(args2.image_path, mediaDir);
|
|
25094
25563
|
if (!imagePath) {
|
|
25095
25564
|
return { content: "Error: no image found. Provide image_path or ensure media/inbound has images.", isError: true };
|
|
25096
25565
|
}
|
|
25097
25566
|
const rawPrompt = args2.prompt?.trim() || "\u63CF\u8FF0\u8FD9\u5F20\u56FE\u7247\u7684\u5185\u5BB9";
|
|
25098
|
-
const ext =
|
|
25567
|
+
const ext = path28.extname(imagePath).toLowerCase();
|
|
25099
25568
|
const mime = MIME_MAP[ext] || "jpeg";
|
|
25100
25569
|
const imgB64 = fs28.readFileSync(imagePath).toString("base64");
|
|
25101
25570
|
const userMsg = {
|
|
@@ -25135,13 +25604,13 @@ init_registry();
|
|
|
25135
25604
|
import { execFile } from "node:child_process";
|
|
25136
25605
|
import { promisify } from "node:util";
|
|
25137
25606
|
import * as fs29 from "node:fs";
|
|
25138
|
-
import * as
|
|
25607
|
+
import * as path29 from "node:path";
|
|
25139
25608
|
import * as os3 from "node:os";
|
|
25140
25609
|
var execFileAsync = promisify(execFile);
|
|
25141
|
-
var VOICE_DIR =
|
|
25610
|
+
var VOICE_DIR = path29.join(os3.tmpdir(), "engine-voice");
|
|
25142
25611
|
async function ttsCosyvoice(text, apiKey, model, voice, workspaceId) {
|
|
25143
25612
|
fs29.mkdirSync(VOICE_DIR, { recursive: true });
|
|
25144
|
-
const output =
|
|
25613
|
+
const output = path29.join(VOICE_DIR, `tts_${Date.now()}.wav`);
|
|
25145
25614
|
const script = `
|
|
25146
25615
|
import sys, json, wave, time, threading
|
|
25147
25616
|
import dashscope
|
|
@@ -25206,7 +25675,7 @@ var GPTSOVITS_REF_TEXT = "\u6625\u7720\u4E0D\u89C9\u6653\uFF0C\u5904\u5904\u95FB
|
|
|
25206
25675
|
var GPTSOVITS_REF_LANG = "zh";
|
|
25207
25676
|
async function ttsGptsovits(text) {
|
|
25208
25677
|
fs29.mkdirSync(VOICE_DIR, { recursive: true });
|
|
25209
|
-
const output =
|
|
25678
|
+
const output = path29.join(VOICE_DIR, `tts_${Date.now()}.wav`);
|
|
25210
25679
|
const params = new URLSearchParams({
|
|
25211
25680
|
text,
|
|
25212
25681
|
text_language: "zh",
|
|
@@ -25223,7 +25692,7 @@ async function ttsGptsovits(text) {
|
|
|
25223
25692
|
var EDGE_VOICE = "zh-CN-XiaoxiaoNeural";
|
|
25224
25693
|
async function ttsEdge(text) {
|
|
25225
25694
|
fs29.mkdirSync(VOICE_DIR, { recursive: true });
|
|
25226
|
-
const output =
|
|
25695
|
+
const output = path29.join(VOICE_DIR, `tts_${Date.now()}.mp3`);
|
|
25227
25696
|
const script = `
|
|
25228
25697
|
import asyncio, edge_tts, sys
|
|
25229
25698
|
async def main():
|
|
@@ -25316,7 +25785,7 @@ registry.register({
|
|
|
25316
25785
|
} catch (e) {
|
|
25317
25786
|
return { content: `TTS failed: ${e.message}`, isError: true };
|
|
25318
25787
|
}
|
|
25319
|
-
const ext =
|
|
25788
|
+
const ext = path29.extname(audioPath).toLowerCase();
|
|
25320
25789
|
const mimeMap = { ".mp3": "audio/mpeg", ".wav": "audio/wav", ".m4a": "audio/mp4", ".ogg": "audio/ogg" };
|
|
25321
25790
|
const mimeType = mimeMap[ext] || "audio/mpeg";
|
|
25322
25791
|
const sizeKB = fs29.statSync(audioPath).size / 1024;
|
|
@@ -25347,7 +25816,7 @@ registry.register({
|
|
|
25347
25816
|
init_live();
|
|
25348
25817
|
init_registry();
|
|
25349
25818
|
import * as fs30 from "node:fs";
|
|
25350
|
-
import * as
|
|
25819
|
+
import * as path30 from "node:path";
|
|
25351
25820
|
var FAL_KEY = "3b848fc6-bee5-46e5-8db7-ae81ac16dc28:2f1f15cf394db2d32c9bb9a4f23f3bee";
|
|
25352
25821
|
var FAL_ENDPOINT = "https://fal.run/xai/grok-imagine-image/edit";
|
|
25353
25822
|
var DEFAULT_RESOLUTION = "1k";
|
|
@@ -25463,7 +25932,7 @@ registry.register({
|
|
|
25463
25932
|
const REFERENCES = getReferences(ctx);
|
|
25464
25933
|
const refName = args2.reference || "default";
|
|
25465
25934
|
const refEntry = REFERENCES.find((r) => r.name === refName) || REFERENCES[0];
|
|
25466
|
-
const refPath =
|
|
25935
|
+
const refPath = path30.join(ctx.workspace, refEntry.p);
|
|
25467
25936
|
if (!fs30.existsSync(refPath)) {
|
|
25468
25937
|
return { content: `Error: reference image not found at ${refPath}`, isError: true };
|
|
25469
25938
|
}
|
|
@@ -25482,10 +25951,10 @@ registry.register({
|
|
|
25482
25951
|
} catch (err) {
|
|
25483
25952
|
return { content: `Selfie generation failed: ${err.message}`, isError: true };
|
|
25484
25953
|
}
|
|
25485
|
-
const imagesDir =
|
|
25954
|
+
const imagesDir = path30.join(ctx.workspace, "images");
|
|
25486
25955
|
if (!fs30.existsSync(imagesDir)) fs30.mkdirSync(imagesDir, { recursive: true });
|
|
25487
25956
|
const filename = `selfie_${Date.now()}.jpg`;
|
|
25488
|
-
const outputPath =
|
|
25957
|
+
const outputPath = path30.join(imagesDir, filename);
|
|
25489
25958
|
fs30.writeFileSync(outputPath, imageBuffer);
|
|
25490
25959
|
const mgr = ctx.channelManager;
|
|
25491
25960
|
if (mgr) {
|
|
@@ -25497,11 +25966,11 @@ registry.register({
|
|
|
25497
25966
|
mimeType: "image/jpeg"
|
|
25498
25967
|
});
|
|
25499
25968
|
} catch (err) {
|
|
25500
|
-
return { content: `Selfie generated but send failed: ${err.message}. Image: ${
|
|
25969
|
+
return { content: `Selfie generated but send failed: ${err.message}. Image: ${path30.resolve(outputPath)}`, isError: false };
|
|
25501
25970
|
}
|
|
25502
25971
|
return { content: `Selfie sent! Mode: ${mode}, Provider: ${getProvider(ctx)}, Ref: ${refEntry.name}` };
|
|
25503
25972
|
}
|
|
25504
|
-
return { content: `Selfie generated! Mode: ${mode}, Ref: ${refEntry.name}. Image: ${
|
|
25973
|
+
return { content: `Selfie generated! Mode: ${mode}, Ref: ${refEntry.name}. Image: ${path30.resolve(outputPath)}` };
|
|
25505
25974
|
},
|
|
25506
25975
|
isConcurrencySafe: () => false,
|
|
25507
25976
|
interruptBehavior: () => "block",
|
|
@@ -25968,14 +26437,14 @@ init_planModeState();
|
|
|
25968
26437
|
|
|
25969
26438
|
// src/utils/plans.ts
|
|
25970
26439
|
import * as fs32 from "node:fs";
|
|
25971
|
-
import * as
|
|
26440
|
+
import * as path32 from "node:path";
|
|
25972
26441
|
import * as crypto4 from "node:crypto";
|
|
25973
26442
|
var MAX_SLUG_RETRIES = 10;
|
|
25974
26443
|
function generateSlug() {
|
|
25975
26444
|
return crypto4.randomBytes(4).toString("hex");
|
|
25976
26445
|
}
|
|
25977
26446
|
function getPlansDirectory(stateDir) {
|
|
25978
|
-
const plansDir =
|
|
26447
|
+
const plansDir = path32.join(stateDir, "plans");
|
|
25979
26448
|
fs32.mkdirSync(plansDir, { recursive: true });
|
|
25980
26449
|
return plansDir;
|
|
25981
26450
|
}
|
|
@@ -25986,7 +26455,7 @@ function getPlanSlug(sessionId, stateDir) {
|
|
|
25986
26455
|
const plansDir = getPlansDirectory(stateDir);
|
|
25987
26456
|
for (let i = 0; i < MAX_SLUG_RETRIES; i++) {
|
|
25988
26457
|
slug = generateSlug();
|
|
25989
|
-
const filePath =
|
|
26458
|
+
const filePath = path32.join(plansDir, `${slug}.md`);
|
|
25990
26459
|
if (!fs32.existsSync(filePath)) {
|
|
25991
26460
|
break;
|
|
25992
26461
|
}
|
|
@@ -25998,9 +26467,9 @@ function getPlanSlug(sessionId, stateDir) {
|
|
|
25998
26467
|
function getPlanFilePath(sessionId, stateDir, agentId) {
|
|
25999
26468
|
const slug = getPlanSlug(sessionId, stateDir);
|
|
26000
26469
|
if (!agentId) {
|
|
26001
|
-
return
|
|
26470
|
+
return path32.join(getPlansDirectory(stateDir), `${slug}.md`);
|
|
26002
26471
|
}
|
|
26003
|
-
return
|
|
26472
|
+
return path32.join(getPlansDirectory(stateDir), `${slug}-agent-${agentId}.md`);
|
|
26004
26473
|
}
|
|
26005
26474
|
function getPlan(sessionId, stateDir, agentId) {
|
|
26006
26475
|
const filePath = getPlanFilePath(sessionId, stateDir, agentId);
|
|
@@ -26659,14 +27128,14 @@ var EverosSearchSchema = {
|
|
|
26659
27128
|
type: "object",
|
|
26660
27129
|
properties: {
|
|
26661
27130
|
query: { type: "string", description: "\u641C\u7D22\u67E5\u8BE2" },
|
|
26662
|
-
maxResults: { type: "number", description: "\u6700\u5927\u8FD4\u56DE\u6570 (\u9ED8\
|
|
27131
|
+
maxResults: { type: "number", description: "\u6700\u5927\u8FD4\u56DE\u6570 (\u9ED8\u8BA410)" },
|
|
27132
|
+
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)" }
|
|
26663
27133
|
},
|
|
26664
27134
|
required: ["query"]
|
|
26665
27135
|
};
|
|
26666
27136
|
function createEverosSearchTool(everosCfg) {
|
|
26667
27137
|
const agenticUrl = (everosCfg?.agenticUrl || "http://127.0.0.1:8101").replace(/\/$/, "");
|
|
26668
27138
|
const userId = everosCfg?.userId || "xiaomei";
|
|
26669
|
-
const defaultMode = everosCfg?.defaultMode || "hybrid_agentic";
|
|
26670
27139
|
return {
|
|
26671
27140
|
name: "memory_search",
|
|
26672
27141
|
description: "Mandatory recall step: semantically search memory before answering questions about prior work, decisions, dates, people, preferences, or todos.",
|
|
@@ -26675,6 +27144,7 @@ function createEverosSearchTool(everosCfg) {
|
|
|
26675
27144
|
const query = args2.query;
|
|
26676
27145
|
if (!query) return { content: "\u7F3A\u5C11 query \u53C2\u6570" };
|
|
26677
27146
|
const topK = args2.maxResults ?? 10;
|
|
27147
|
+
const mode = args2.mode || "hybrid_agentic";
|
|
26678
27148
|
const ctrl = new AbortController();
|
|
26679
27149
|
const timer = setTimeout(() => ctrl.abort(), 3e4);
|
|
26680
27150
|
try {
|
|
@@ -26684,7 +27154,7 @@ function createEverosSearchTool(everosCfg) {
|
|
|
26684
27154
|
body: JSON.stringify({
|
|
26685
27155
|
query,
|
|
26686
27156
|
user_id: userId,
|
|
26687
|
-
mode
|
|
27157
|
+
mode,
|
|
26688
27158
|
top_k: topK
|
|
26689
27159
|
}),
|
|
26690
27160
|
signal: ctrl.signal
|
|
@@ -26692,7 +27162,7 @@ function createEverosSearchTool(everosCfg) {
|
|
|
26692
27162
|
clearTimeout(timer);
|
|
26693
27163
|
if (!resp.ok) {
|
|
26694
27164
|
const text = await resp.text();
|
|
26695
|
-
console.warn(`[
|
|
27165
|
+
console.warn(`[memory_search] failed: ${resp.status} ${text.slice(0, 200)}`);
|
|
26696
27166
|
return { content: "\u6CA1\u6709\u627E\u5230\u76F8\u5173\u8BB0\u5FC6\u3002" };
|
|
26697
27167
|
}
|
|
26698
27168
|
const data = await resp.json();
|
|
@@ -26701,7 +27171,7 @@ function createEverosSearchTool(everosCfg) {
|
|
|
26701
27171
|
return { content: "\u6CA1\u6709\u627E\u5230\u76F8\u5173\u8BB0\u5FC6\u3002" };
|
|
26702
27172
|
}
|
|
26703
27173
|
const formatted = episodes.map((ep, i) => {
|
|
26704
|
-
const score = ep.score != null ? ` (score: ${ep.score.toFixed(3)})` : "";
|
|
27174
|
+
const score = ep.score != null ? ` (score: ${typeof ep.score === "number" ? ep.score.toFixed(3) : ep.score})` : "";
|
|
26705
27175
|
const subject = ep.subject || "";
|
|
26706
27176
|
const ts = ep.timestamp ? ` [${ep.timestamp}]` : "";
|
|
26707
27177
|
return `### ${i + 1}. ${subject}${ts}${score}
|
|
@@ -26713,9 +27183,9 @@ ${formatted}` };
|
|
|
26713
27183
|
} catch (err) {
|
|
26714
27184
|
clearTimeout(timer);
|
|
26715
27185
|
if (err.name === "AbortError") {
|
|
26716
|
-
console.warn(`[
|
|
27186
|
+
console.warn(`[memory_search] timeout: ${query.slice(0, 50)}`);
|
|
26717
27187
|
} else {
|
|
26718
|
-
console.warn(`[
|
|
27188
|
+
console.warn(`[memory_search] error: ${err.message}`);
|
|
26719
27189
|
}
|
|
26720
27190
|
return { content: "\u6CA1\u6709\u627E\u5230\u76F8\u5173\u8BB0\u5FC6\u3002" };
|
|
26721
27191
|
}
|
|
@@ -27214,9 +27684,9 @@ async function startEngine(config2, opts) {
|
|
|
27214
27684
|
process.env.ENGINE_MEDIA_DIR = config2.mediaDir;
|
|
27215
27685
|
process.env.ENGINE7_WORKSPACE = config2.workspace;
|
|
27216
27686
|
process.env.OPENCLAW_WORKSPACE = config2.workspace;
|
|
27217
|
-
fs41.mkdirSync(
|
|
27218
|
-
fs41.mkdirSync(
|
|
27219
|
-
fs41.mkdirSync(
|
|
27687
|
+
fs41.mkdirSync(path43.join(config2.stateDir, "agents", "main", "memory"), { recursive: true });
|
|
27688
|
+
fs41.mkdirSync(path43.join(config2.stateDir, "agents", "main", "sessions"), { recursive: true });
|
|
27689
|
+
fs41.mkdirSync(path43.join(config2.stateDir, "logs"), { recursive: true });
|
|
27220
27690
|
fs41.mkdirSync(config2.workspace, { recursive: true });
|
|
27221
27691
|
fs41.mkdirSync(config2.mediaDir, { recursive: true });
|
|
27222
27692
|
try {
|
|
@@ -27326,7 +27796,7 @@ async function startEngine(config2, opts) {
|
|
|
27326
27796
|
const { initSessionMemory: initSessionMemory2 } = await Promise.resolve().then(() => (init_sessionMemory(), sessionMemory_exports));
|
|
27327
27797
|
initSessionMemory2({
|
|
27328
27798
|
workspace: config2.workspace,
|
|
27329
|
-
stateDir:
|
|
27799
|
+
stateDir: path43.join(config2.stateDir, "session-memory"),
|
|
27330
27800
|
provider,
|
|
27331
27801
|
model: config2.provider.modelId || config2.model || "deepseek-v4-flash",
|
|
27332
27802
|
features: config2.profile.features
|
|
@@ -27356,9 +27826,9 @@ async function startEngine(config2, opts) {
|
|
|
27356
27826
|
if (config2.hooks) {
|
|
27357
27827
|
loadHooksFromConfig({ hooks: config2.hooks });
|
|
27358
27828
|
}
|
|
27359
|
-
const hooksPath =
|
|
27829
|
+
const hooksPath = path43.join(config2.workspace, ".hooks.json");
|
|
27360
27830
|
loadHooksFromFile(hooksPath);
|
|
27361
|
-
const settingsHooksPath =
|
|
27831
|
+
const settingsHooksPath = path43.join(config2.stateDir, "settings.json");
|
|
27362
27832
|
loadHooksFromFile(settingsHooksPath);
|
|
27363
27833
|
console.log(`[hooks] Loaded hooks configuration`);
|
|
27364
27834
|
registerCallbackHook("PreCompact", {
|
|
@@ -27372,15 +27842,15 @@ async function startEngine(config2, opts) {
|
|
|
27372
27842
|
const bjTime = new Date(now.getTime() + (bjOffset + now.getTimezoneOffset()) * 6e4);
|
|
27373
27843
|
const dateStr = `${bjTime.getFullYear()}-${String(bjTime.getMonth() + 1).padStart(2, "0")}-${String(bjTime.getDate()).padStart(2, "0")}`;
|
|
27374
27844
|
const timeStr = `${String(bjTime.getHours()).padStart(2, "0")}:${String(bjTime.getMinutes()).padStart(2, "0")}`;
|
|
27375
|
-
const dailyDir =
|
|
27376
|
-
const dailyPath =
|
|
27845
|
+
const dailyDir = path43.join(workspace, "memory", "daily");
|
|
27846
|
+
const dailyPath = path43.join(dailyDir, `${dateStr}.md`);
|
|
27377
27847
|
try {
|
|
27378
27848
|
const fs42 = await import("node:fs");
|
|
27379
27849
|
if (!fs42.existsSync(dailyDir)) {
|
|
27380
27850
|
fs42.mkdirSync(dailyDir, { recursive: true });
|
|
27381
27851
|
}
|
|
27382
|
-
const sessionsDir =
|
|
27383
|
-
const sessionFile =
|
|
27852
|
+
const sessionsDir = path43.join(config2.stateDir, "agents", "main", "sessions");
|
|
27853
|
+
const sessionFile = path43.join(sessionsDir, `${sessionId}.jsonl`);
|
|
27384
27854
|
const recentLines = [];
|
|
27385
27855
|
if (fs42.existsSync(sessionFile)) {
|
|
27386
27856
|
const content = fs42.readFileSync(sessionFile, "utf-8");
|
|
@@ -27433,7 +27903,7 @@ ${entry}`);
|
|
|
27433
27903
|
if (!workspace) return { continue: true };
|
|
27434
27904
|
try {
|
|
27435
27905
|
const fs42 = await import("node:fs");
|
|
27436
|
-
const bufferPath =
|
|
27906
|
+
const bufferPath = path43.join(workspace, "memory", "working-buffer.md");
|
|
27437
27907
|
if (fs42.existsSync(bufferPath)) {
|
|
27438
27908
|
const stat4 = fs42.statSync(bufferPath);
|
|
27439
27909
|
const ageMs = Date.now() - stat4.mtimeMs;
|
|
@@ -27486,7 +27956,7 @@ ${content}`
|
|
|
27486
27956
|
return `${hr}h ${remMin}m`;
|
|
27487
27957
|
}
|
|
27488
27958
|
if (config2.skills?.enabled !== false) {
|
|
27489
|
-
const skillsDir = config2.skills?.path ?
|
|
27959
|
+
const skillsDir = config2.skills?.path ? path43.isAbsolute(config2.skills.path) ? config2.skills.path : path43.resolve(config2.workspace, config2.skills.path) : path43.resolve(config2.workspace, "skills");
|
|
27490
27960
|
const modelDef2 = config2.provider.models.find((m2) => m2.id === config2.model);
|
|
27491
27961
|
const contextWindowTokens = modelDef2?.contextWindow;
|
|
27492
27962
|
const skills = scanSkills(skillsDir);
|
|
@@ -27505,7 +27975,7 @@ ${content}`
|
|
|
27505
27975
|
workspace: config2.workspace
|
|
27506
27976
|
});
|
|
27507
27977
|
const systemPrompt = [systemStable, systemDynamic].join("\n\n");
|
|
27508
|
-
const promptDumpPath =
|
|
27978
|
+
const promptDumpPath = path43.join(config2.workspace, ".system-prompt.txt");
|
|
27509
27979
|
fs41.writeFileSync(promptDumpPath, systemPrompt);
|
|
27510
27980
|
console.log(`System prompt: ${systemStable.length} chars stable + ${systemDynamic.length} chars dynamic \u2192 ${promptDumpPath}`);
|
|
27511
27981
|
const modelDef = config2.provider.models.find((m2) => m2.id === config2.model);
|
|
@@ -27616,20 +28086,23 @@ ${content}`
|
|
|
27616
28086
|
enabled: true,
|
|
27617
28087
|
url: everosCfg.everosUrl || "http://127.0.0.1:8100",
|
|
27618
28088
|
appId: everosCfg.userId || "default",
|
|
27619
|
-
userId: everosCfg.userId || "default"
|
|
28089
|
+
userId: everosCfg.userId || "default",
|
|
28090
|
+
agentName: everosCfg.agentName || everosCfg.userId || "assistant"
|
|
27620
28091
|
});
|
|
27621
28092
|
sessions.onWriterCreated = (writer, sessionId) => {
|
|
27622
28093
|
writer.onMessageWritten = (msg2) => {
|
|
28094
|
+
console.log(`[everos-sync] onMessageWritten fired: role=${msg2.role} len=${msg2.text.length}`);
|
|
27623
28095
|
everosSync.push({
|
|
27624
28096
|
sessionId: writer.engineSessionId || sessionId,
|
|
27625
28097
|
role: msg2.role === "toolResult" ? "tool" : msg2.role,
|
|
27626
28098
|
text: msg2.text,
|
|
27627
28099
|
timestamp: new Date(msg2.timestamp).getTime()
|
|
27628
|
-
}).catch(() => {
|
|
27629
|
-
});
|
|
28100
|
+
}).catch((e) => console.warn(`[everos-sync] push error: ${e}`));
|
|
27630
28101
|
};
|
|
27631
28102
|
};
|
|
27632
28103
|
console.log(`[everos-sync] hook registered (appId=${everosCfg.userId})`);
|
|
28104
|
+
} else {
|
|
28105
|
+
console.log(`[everos-sync] SKIPPED \u2014 config.everos not enabled or missing`);
|
|
27633
28106
|
}
|
|
27634
28107
|
const channelManager = new ChannelManager();
|
|
27635
28108
|
const memoryRecallProvider = createMemorySideProvider(
|
|
@@ -27660,6 +28133,7 @@ ${content}`
|
|
|
27660
28133
|
recallProvider: memoryRecallProvider || void 0,
|
|
27661
28134
|
extractProvider: memoryExtractProvider || void 0,
|
|
27662
28135
|
topics: config2.topics,
|
|
28136
|
+
everosCfg: config2.everos,
|
|
27663
28137
|
mcpManager
|
|
27664
28138
|
};
|
|
27665
28139
|
if (visionEngine && visionConfig) {
|
|
@@ -28580,8 +29054,8 @@ Auto-routing disabled \u2014 all messages use this model.
|
|
|
28580
29054
|
let writePath = configPath2;
|
|
28581
29055
|
if (configPath2 && !fs41.existsSync(configPath2)) {
|
|
28582
29056
|
const __pFile = fileURLToPath(import.meta.url);
|
|
28583
|
-
const __pDir =
|
|
28584
|
-
const altPath =
|
|
29057
|
+
const __pDir = path43.dirname(__pFile);
|
|
29058
|
+
const altPath = path43.join(path43.resolve(__pDir, "../configs"), path43.basename(configPath2));
|
|
28585
29059
|
if (fs41.existsSync(altPath)) {
|
|
28586
29060
|
console.warn(`[primary] Config not found at ${configPath2}, falling back to ${altPath}`);
|
|
28587
29061
|
writePath = altPath;
|
|
@@ -28861,7 +29335,7 @@ Use full ref like \`/vision-model ${candidates[0].ref}\``);
|
|
|
28861
29335
|
const ext = detected.split("/")[1] || "png";
|
|
28862
29336
|
const resized = await maybeResizeAndDownsampleImageBuffer2(rawBuffer, rawBuffer.length, ext);
|
|
28863
29337
|
const imageId = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
28864
|
-
const savedPath =
|
|
29338
|
+
const savedPath = path43.join(config2.mediaDir, `${imageId}.${ext}`);
|
|
28865
29339
|
fs41.writeFileSync(savedPath, resized.buffer);
|
|
28866
29340
|
savedPaths.push(savedPath);
|
|
28867
29341
|
console.log(`[vision] Saved: ${savedPath} (${resized.buffer.length}B)`);
|
|
@@ -28888,7 +29362,7 @@ ${pathStr}` }];
|
|
|
28888
29362
|
}
|
|
28889
29363
|
const nonImageAttachments = inbound.attachments?.filter((a) => !a.contentType.startsWith("image/"));
|
|
28890
29364
|
if (nonImageAttachments && nonImageAttachments.length > 0) {
|
|
28891
|
-
const outDir =
|
|
29365
|
+
const outDir = path43.join(config2.mediaDir, sessionId);
|
|
28892
29366
|
fs41.mkdirSync(outDir, { recursive: true });
|
|
28893
29367
|
const resolved = [];
|
|
28894
29368
|
for (const att of nonImageAttachments) {
|
|
@@ -28897,8 +29371,8 @@ ${pathStr}` }];
|
|
|
28897
29371
|
const resp = await fetch(att.url);
|
|
28898
29372
|
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
|
|
28899
29373
|
const buffer = Buffer.from(await resp.arrayBuffer());
|
|
28900
|
-
const safeName2 =
|
|
28901
|
-
const savedPath =
|
|
29374
|
+
const safeName2 = path43.basename(att.filename).replace(/[<>:"/\\|?*\x00-\x1f]/g, "_") || "attachment";
|
|
29375
|
+
const savedPath = path43.join(outDir, safeName2);
|
|
28902
29376
|
fs41.writeFileSync(savedPath, buffer);
|
|
28903
29377
|
resolved.push(savedPath);
|
|
28904
29378
|
console.log(`[file] Saved: ${savedPath} (${buffer.length}B)`);
|
|
@@ -29246,7 +29720,8 @@ ${pathStr}` }];
|
|
|
29246
29720
|
if (config2.cognifold?.intentWatcher?.enabled) {
|
|
29247
29721
|
try {
|
|
29248
29722
|
const { registerCognifoldIntentWatcher: registerCognifoldIntentWatcher2 } = await Promise.resolve().then(() => (init_cognifold_intent_watcher(), cognifold_intent_watcher_exports));
|
|
29249
|
-
const
|
|
29723
|
+
const sm = globalThis.__cognifoldSessions;
|
|
29724
|
+
const cfSessionId = sm?.getSessionId?.("main") || config2.cognifold.sessionId;
|
|
29250
29725
|
if (!cfSessionId) {
|
|
29251
29726
|
console.warn("[cognifold] intent-watcher: config.cognifold.sessionId \u672A\u914D\u7F6E\uFF0C\u8DF3\u8FC7 watcher");
|
|
29252
29727
|
} else {
|
|
@@ -29259,7 +29734,7 @@ ${pathStr}` }];
|
|
|
29259
29734
|
console.warn("[cognifold] watcher: config.workspace \u672A\u914D\u7F6E\uFF0C\u8DF3\u8FC7 proactive \u5199\u5165");
|
|
29260
29735
|
return;
|
|
29261
29736
|
}
|
|
29262
|
-
const pFile =
|
|
29737
|
+
const pFile = path43.join(wsDir, ".cognifold-proactive.json");
|
|
29263
29738
|
const cognifoldBaseUrl = config2.cognifold?.baseUrl || "http://127.0.0.1:9001";
|
|
29264
29739
|
const cognifoldSessionId = cfSessionId;
|
|
29265
29740
|
const rawSuggestions = data.suggestions || data.actions || (data.intent_id ? [data] : []);
|
|
@@ -29313,7 +29788,7 @@ ${pathStr}` }];
|
|
|
29313
29788
|
console.error(`[cognifold] failed to save proactive: ${e.message}`);
|
|
29314
29789
|
}
|
|
29315
29790
|
if (enriched.length > 0) {
|
|
29316
|
-
const promptFile =
|
|
29791
|
+
const promptFile = path43.join(config2.workspace, "prompts", "cognifold-proactive.md");
|
|
29317
29792
|
const promptText = fs41.existsSync(promptFile) ? fs41.readFileSync(promptFile, "utf-8") : "[CogniFold proactive] \u6709 " + enriched.length + " \u4E2A action \u5230\u671F\u4E86";
|
|
29318
29793
|
const actionsJson = JSON.stringify(enriched, null, 2);
|
|
29319
29794
|
const sessionId = cfSessionId;
|
|
@@ -29419,9 +29894,9 @@ async function doReloadConfig(config2, deps, provider) {
|
|
|
29419
29894
|
let reloadConfigPath = savedConfigPath;
|
|
29420
29895
|
if (!fs41.existsSync(reloadConfigPath)) {
|
|
29421
29896
|
const __filename = fileURLToPath(import.meta.url);
|
|
29422
|
-
const __dirname =
|
|
29423
|
-
const engineConfigsDir =
|
|
29424
|
-
const altPath =
|
|
29897
|
+
const __dirname = path43.dirname(__filename);
|
|
29898
|
+
const engineConfigsDir = path43.resolve(__dirname, "../configs");
|
|
29899
|
+
const altPath = path43.join(engineConfigsDir, path43.basename(savedConfigPath));
|
|
29425
29900
|
if (fs41.existsSync(altPath)) {
|
|
29426
29901
|
console.warn(`[reload] Config not found at ${reloadConfigPath}, falling back to ${altPath} (dev mode)`);
|
|
29427
29902
|
reloadConfigPath = altPath;
|
|
@@ -29474,7 +29949,7 @@ async function doReloadConfig(config2, deps, provider) {
|
|
|
29474
29949
|
} catch (err) {
|
|
29475
29950
|
console.error(`[reload] Failed: ${err.message}`);
|
|
29476
29951
|
try {
|
|
29477
|
-
fs41.appendFileSync(
|
|
29952
|
+
fs41.appendFileSync(path43.join(config2.stateDir, "logs", "engine-config-watch.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] RELOAD FAILED: ${err.message}
|
|
29478
29953
|
${err.stack}
|
|
29479
29954
|
`);
|
|
29480
29955
|
} catch {
|
|
@@ -29486,17 +29961,17 @@ function startConfigWatcher(config2, deps, provider) {
|
|
|
29486
29961
|
const raw = config2._configFilePath;
|
|
29487
29962
|
let configPath2 = raw;
|
|
29488
29963
|
if (!fs41.existsSync(configPath2)) {
|
|
29489
|
-
configPath2 =
|
|
29964
|
+
configPath2 = path43.resolve(raw);
|
|
29490
29965
|
}
|
|
29491
29966
|
if (!fs41.existsSync(configPath2)) {
|
|
29492
29967
|
const __filename2 = fileURLToPath(import.meta.url);
|
|
29493
|
-
const __dirname22 =
|
|
29494
|
-
configPath2 =
|
|
29968
|
+
const __dirname22 = path43.dirname(__filename2);
|
|
29969
|
+
configPath2 = path43.resolve(__dirname22, "..", raw);
|
|
29495
29970
|
}
|
|
29496
29971
|
if (!fs41.existsSync(configPath2)) {
|
|
29497
29972
|
console.warn(`[config-watch] config path invalid: ${configPath2}, watcher disabled`);
|
|
29498
29973
|
try {
|
|
29499
|
-
fs41.appendFileSync(
|
|
29974
|
+
fs41.appendFileSync(path43.join(config2.stateDir, "logs", "engine-config-watch.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] DISABLED: configPath=${configPath2}
|
|
29500
29975
|
`);
|
|
29501
29976
|
} catch {
|
|
29502
29977
|
}
|
|
@@ -29508,13 +29983,13 @@ function startConfigWatcher(config2, deps, provider) {
|
|
|
29508
29983
|
debounceTimer = setTimeout(async () => {
|
|
29509
29984
|
console.log(`[config-watch] file changed (${eventType}), reloading...`);
|
|
29510
29985
|
try {
|
|
29511
|
-
fs41.appendFileSync(
|
|
29986
|
+
fs41.appendFileSync(path43.join(config2.stateDir, "logs", "engine-config-watch.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] CHANGE eventType=${eventType}, calling doReloadConfig
|
|
29512
29987
|
`);
|
|
29513
29988
|
} catch {
|
|
29514
29989
|
}
|
|
29515
29990
|
const result = await doReloadConfig(config2, deps, provider);
|
|
29516
29991
|
try {
|
|
29517
|
-
fs41.appendFileSync(
|
|
29992
|
+
fs41.appendFileSync(path43.join(config2.stateDir, "logs", "engine-config-watch.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] RELOAD DONE: ok=${result.ok} changes=${result.changes.join(",")}
|
|
29518
29993
|
`);
|
|
29519
29994
|
} catch {
|
|
29520
29995
|
}
|
|
@@ -29523,14 +29998,14 @@ function startConfigWatcher(config2, deps, provider) {
|
|
|
29523
29998
|
watcher.on("error", (err) => {
|
|
29524
29999
|
console.error(`[config-watch] error: ${err.message}`);
|
|
29525
30000
|
try {
|
|
29526
|
-
fs41.appendFileSync(
|
|
30001
|
+
fs41.appendFileSync(path43.join(config2.stateDir, "logs", "engine-config-watch.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] ERROR: ${err.message}
|
|
29527
30002
|
`);
|
|
29528
30003
|
} catch {
|
|
29529
30004
|
}
|
|
29530
30005
|
});
|
|
29531
30006
|
console.log(`[config-watch] watching ${configPath2}`);
|
|
29532
30007
|
try {
|
|
29533
|
-
fs41.appendFileSync(
|
|
30008
|
+
fs41.appendFileSync(path43.join(config2.stateDir, "logs", "engine-config-watch.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] STARTED watching=${configPath2}
|
|
29534
30009
|
`);
|
|
29535
30010
|
} catch {
|
|
29536
30011
|
}
|