engine7 7.1.35 → 7.1.37
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/engine-startup.mjs +919 -712
- package/dist/main.mjs +969 -762
- package/package.json +1 -1
package/dist/main.mjs
CHANGED
|
@@ -26,6 +26,119 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
26
26
|
};
|
|
27
27
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
28
|
|
|
29
|
+
// src/config/live.ts
|
|
30
|
+
var live_exports = {};
|
|
31
|
+
__export(live_exports, {
|
|
32
|
+
liveConfig: () => liveConfig
|
|
33
|
+
});
|
|
34
|
+
var LiveConfigClass, liveConfig;
|
|
35
|
+
var init_live = __esm({
|
|
36
|
+
"src/config/live.ts"() {
|
|
37
|
+
"use strict";
|
|
38
|
+
LiveConfigClass = class {
|
|
39
|
+
current = null;
|
|
40
|
+
/** 启动时注入(替代 registry.config = config) */
|
|
41
|
+
init(config2) {
|
|
42
|
+
this.current = config2;
|
|
43
|
+
}
|
|
44
|
+
/** 取整个 config 对象(只读引用,不要缓存) */
|
|
45
|
+
all() {
|
|
46
|
+
if (!this.current) {
|
|
47
|
+
throw new Error("[liveConfig] not initialized \u2014 call liveConfig.init() first");
|
|
48
|
+
}
|
|
49
|
+
return this.current;
|
|
50
|
+
}
|
|
51
|
+
/** 安全取子段('services.voice-chat.start' → current.services.voice-chat.start) */
|
|
52
|
+
get(dotPath) {
|
|
53
|
+
if (!this.current) return void 0;
|
|
54
|
+
return dotPath.split(".").reduce((acc, key) => acc == null ? void 0 : acc[key], this.current);
|
|
55
|
+
}
|
|
56
|
+
/** reload 时原地更新(Object.assign 保持引用不变) */
|
|
57
|
+
assign(newConfig) {
|
|
58
|
+
if (!this.current) {
|
|
59
|
+
this.current = newConfig;
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
Object.assign(this.current, newConfig);
|
|
63
|
+
}
|
|
64
|
+
/** 改活树上的值;文件承载路径同步持久化(read-modify-write 回 config 文件) */
|
|
65
|
+
async set(dotPath, val) {
|
|
66
|
+
if (!this.current) throw new Error("[liveConfig] not initialized \u2014 call liveConfig.init() first");
|
|
67
|
+
const keys = dotPath.split(".");
|
|
68
|
+
let obj = this.current;
|
|
69
|
+
for (let i = 0; i < keys.length - 1; i++) {
|
|
70
|
+
if (obj[keys[i]] == null) obj[keys[i]] = {};
|
|
71
|
+
obj = obj[keys[i]];
|
|
72
|
+
}
|
|
73
|
+
obj[keys[keys.length - 1]] = val;
|
|
74
|
+
await this.persistToFile(dotPath, val);
|
|
75
|
+
}
|
|
76
|
+
/** 把改动写回 config 文件对应段(找不到文件路径则只内存生效) */
|
|
77
|
+
async persistToFile(dotPath, val) {
|
|
78
|
+
const fs43 = await import("node:fs");
|
|
79
|
+
const cfgPath = this.current?._configFilePath;
|
|
80
|
+
if (!cfgPath || !fs43.existsSync(cfgPath)) {
|
|
81
|
+
console.warn(`[liveConfig] set: no config file path, in-memory only (${dotPath})`);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
try {
|
|
85
|
+
const raw = JSON.parse(fs43.readFileSync(cfgPath, "utf-8"));
|
|
86
|
+
const keys = dotPath.split(".");
|
|
87
|
+
let o = raw;
|
|
88
|
+
for (let i = 0; i < keys.length - 1; i++) {
|
|
89
|
+
if (o[keys[i]] == null) o[keys[i]] = {};
|
|
90
|
+
o = o[keys[i]];
|
|
91
|
+
}
|
|
92
|
+
o[keys[keys.length - 1]] = val;
|
|
93
|
+
fs43.writeFileSync(cfgPath, JSON.stringify(raw, null, 2) + "\n", "utf-8");
|
|
94
|
+
console.log(`[liveConfig] persisted ${dotPath} = ${JSON.stringify(val)} to ${cfgPath}`);
|
|
95
|
+
} catch (e) {
|
|
96
|
+
console.warn(`[liveConfig] persist failed (${dotPath}): ${e.message}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/** 是否已初始化 */
|
|
100
|
+
isReady() {
|
|
101
|
+
return this.current !== null;
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
liveConfig = new LiveConfigClass();
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// src/config/features.ts
|
|
109
|
+
function getFeature(key) {
|
|
110
|
+
const v = liveConfig.get(`agents.defaults.features.${key}`);
|
|
111
|
+
return v === void 0 ? FEATURE_DEFAULTS[key] : v;
|
|
112
|
+
}
|
|
113
|
+
var FEATURE_DEFAULTS;
|
|
114
|
+
var init_features = __esm({
|
|
115
|
+
"src/config/features.ts"() {
|
|
116
|
+
"use strict";
|
|
117
|
+
init_live();
|
|
118
|
+
FEATURE_DEFAULTS = {
|
|
119
|
+
filesystem: true,
|
|
120
|
+
shell: true,
|
|
121
|
+
memory: true,
|
|
122
|
+
"topic-extract": true,
|
|
123
|
+
"topic-recall": true,
|
|
124
|
+
"session-memory": true,
|
|
125
|
+
todo: true,
|
|
126
|
+
cron: false,
|
|
127
|
+
voice: false,
|
|
128
|
+
selfie: false,
|
|
129
|
+
eyes: false,
|
|
130
|
+
calendar: false,
|
|
131
|
+
webSearch: true,
|
|
132
|
+
webFetch: true,
|
|
133
|
+
agentTeams: true,
|
|
134
|
+
autoDream: true,
|
|
135
|
+
processOutput: "verbose",
|
|
136
|
+
interrupt: "command",
|
|
137
|
+
debounceMs: 5e3
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
|
|
29
142
|
// src/tools/ToolSearchTool/constants.ts
|
|
30
143
|
var TOOL_SEARCH_TOOL_NAME;
|
|
31
144
|
var init_constants = __esm({
|
|
@@ -174,17 +287,19 @@ var init_types = __esm({
|
|
|
174
287
|
"src/messages/types.ts"() {
|
|
175
288
|
"use strict";
|
|
176
289
|
msg = {
|
|
177
|
-
system: (content) => ({ role: "system", content }),
|
|
178
|
-
user: (content) => ({ role: "user", content }),
|
|
290
|
+
system: (content) => ({ role: "system", content, timestamp: (/* @__PURE__ */ new Date()).toISOString() }),
|
|
291
|
+
user: (content) => ({ role: "user", content, timestamp: (/* @__PURE__ */ new Date()).toISOString() }),
|
|
179
292
|
assistant: (content, tool_calls) => ({
|
|
180
293
|
role: "assistant",
|
|
181
294
|
content,
|
|
295
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
182
296
|
...tool_calls ? { tool_calls } : {}
|
|
183
297
|
}),
|
|
184
298
|
tool: (tool_call_id, content, isError) => ({
|
|
185
299
|
role: "tool",
|
|
186
300
|
tool_call_id,
|
|
187
301
|
content,
|
|
302
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
188
303
|
...isError ? { is_error: true } : {}
|
|
189
304
|
})
|
|
190
305
|
};
|
|
@@ -2139,9 +2254,9 @@ function isAutoMemPath(absolutePath, workspace) {
|
|
|
2139
2254
|
return normalizedPath.startsWith(getAutoMemPath(workspace));
|
|
2140
2255
|
}
|
|
2141
2256
|
async function ensureMemoryDirExists(memoryDir) {
|
|
2142
|
-
const
|
|
2257
|
+
const fs43 = await import("node:fs");
|
|
2143
2258
|
try {
|
|
2144
|
-
await
|
|
2259
|
+
await fs43.promises.mkdir(memoryDir, { recursive: true });
|
|
2145
2260
|
} catch (e) {
|
|
2146
2261
|
const code = e?.code;
|
|
2147
2262
|
if (code !== "EEXIST") {
|
|
@@ -3308,50 +3423,6 @@ ${perTurnSystemDynamic}` : deferredHint || perTurnSystemDynamic;
|
|
|
3308
3423
|
}
|
|
3309
3424
|
});
|
|
3310
3425
|
|
|
3311
|
-
// src/config/live.ts
|
|
3312
|
-
var live_exports = {};
|
|
3313
|
-
__export(live_exports, {
|
|
3314
|
-
liveConfig: () => liveConfig
|
|
3315
|
-
});
|
|
3316
|
-
var LiveConfigClass, liveConfig;
|
|
3317
|
-
var init_live = __esm({
|
|
3318
|
-
"src/config/live.ts"() {
|
|
3319
|
-
"use strict";
|
|
3320
|
-
LiveConfigClass = class {
|
|
3321
|
-
current = null;
|
|
3322
|
-
/** 启动时注入(替代 registry.config = config) */
|
|
3323
|
-
init(config2) {
|
|
3324
|
-
this.current = config2;
|
|
3325
|
-
}
|
|
3326
|
-
/** 取整个 config 对象(只读引用,不要缓存) */
|
|
3327
|
-
all() {
|
|
3328
|
-
if (!this.current) {
|
|
3329
|
-
throw new Error("[liveConfig] not initialized \u2014 call liveConfig.init() first");
|
|
3330
|
-
}
|
|
3331
|
-
return this.current;
|
|
3332
|
-
}
|
|
3333
|
-
/** 安全取子段('services.voice-chat.start' → current.services.voice-chat.start) */
|
|
3334
|
-
get(dotPath) {
|
|
3335
|
-
if (!this.current) return void 0;
|
|
3336
|
-
return dotPath.split(".").reduce((acc, key) => acc == null ? void 0 : acc[key], this.current);
|
|
3337
|
-
}
|
|
3338
|
-
/** reload 时原地更新(Object.assign 保持引用不变) */
|
|
3339
|
-
assign(newConfig) {
|
|
3340
|
-
if (!this.current) {
|
|
3341
|
-
this.current = newConfig;
|
|
3342
|
-
return;
|
|
3343
|
-
}
|
|
3344
|
-
Object.assign(this.current, newConfig);
|
|
3345
|
-
}
|
|
3346
|
-
/** 是否已初始化 */
|
|
3347
|
-
isReady() {
|
|
3348
|
-
return this.current !== null;
|
|
3349
|
-
}
|
|
3350
|
-
};
|
|
3351
|
-
liveConfig = new LiveConfigClass();
|
|
3352
|
-
}
|
|
3353
|
-
});
|
|
3354
|
-
|
|
3355
3426
|
// src/utils/path.ts
|
|
3356
3427
|
var path_exports = {};
|
|
3357
3428
|
__export(path_exports, {
|
|
@@ -4400,7 +4471,7 @@ async function acquireLock(inboxPath) {
|
|
|
4400
4471
|
for (let i = 0; i < LOCK_RETRIES; i++) {
|
|
4401
4472
|
if (await isLockStale(lockPath2)) {
|
|
4402
4473
|
try {
|
|
4403
|
-
await import("node:fs/promises").then((
|
|
4474
|
+
await import("node:fs/promises").then((fs43) => fs43.rm(lockPath2, { force: true }));
|
|
4404
4475
|
} catch {
|
|
4405
4476
|
}
|
|
4406
4477
|
}
|
|
@@ -4408,7 +4479,7 @@ async function acquireLock(inboxPath) {
|
|
|
4408
4479
|
await writeFile2(lockPath2, `${process.pid}-${Date.now()}`, { encoding: "utf-8", flag: "wx" });
|
|
4409
4480
|
return async () => {
|
|
4410
4481
|
try {
|
|
4411
|
-
await import("node:fs/promises").then((
|
|
4482
|
+
await import("node:fs/promises").then((fs43) => fs43.rm(lockPath2, { force: true }));
|
|
4412
4483
|
} catch {
|
|
4413
4484
|
}
|
|
4414
4485
|
};
|
|
@@ -4827,76 +4898,6 @@ var init_extractPrompts = __esm({
|
|
|
4827
4898
|
}
|
|
4828
4899
|
});
|
|
4829
4900
|
|
|
4830
|
-
// src/memory/everos/ingest.ts
|
|
4831
|
-
function parseMeta(text) {
|
|
4832
|
-
const m = text.match(/^\[meta:\s*(.+?)\s*\((.+?)\)\s*@(\S+)\s*[^\]]*\]/);
|
|
4833
|
-
if (!m) return null;
|
|
4834
|
-
return { senderName: m[1].trim() };
|
|
4835
|
-
}
|
|
4836
|
-
async function readConfig() {
|
|
4837
|
-
const defaults = {
|
|
4838
|
-
url: "http://127.0.0.1:8100",
|
|
4839
|
-
appId: "default",
|
|
4840
|
-
agentName: "assistant",
|
|
4841
|
-
enabled: false
|
|
4842
|
-
};
|
|
4843
|
-
try {
|
|
4844
|
-
const { liveConfig: liveConfig2 } = await Promise.resolve().then(() => (init_live(), live_exports));
|
|
4845
|
-
const cfg = liveConfig2.all()?.everos;
|
|
4846
|
-
if (!cfg) return defaults;
|
|
4847
|
-
return {
|
|
4848
|
-
url: cfg.everosUrl || defaults.url,
|
|
4849
|
-
appId: cfg.userId || defaults.appId,
|
|
4850
|
-
agentName: cfg.agentName || cfg.userId || defaults.agentName,
|
|
4851
|
-
enabled: cfg.enabled === true
|
|
4852
|
-
};
|
|
4853
|
-
} catch {
|
|
4854
|
-
return defaults;
|
|
4855
|
-
}
|
|
4856
|
-
}
|
|
4857
|
-
async function pushConversation(messages, sessionId) {
|
|
4858
|
-
const cfg = await readConfig();
|
|
4859
|
-
if (!cfg.enabled) return;
|
|
4860
|
-
if (!messages.length) return;
|
|
4861
|
-
const payload = {
|
|
4862
|
-
session_id: `extract-${sessionId}`,
|
|
4863
|
-
app_id: cfg.appId,
|
|
4864
|
-
project_id: "default",
|
|
4865
|
-
messages: messages.map((m) => {
|
|
4866
|
-
const text = typeof m.content === "string" ? m.content : "[content blocks]";
|
|
4867
|
-
const meta = m.role === "user" ? parseMeta(text) : null;
|
|
4868
|
-
const senderName = meta?.senderName ?? (m.role === "assistant" ? cfg.agentName : void 0) ?? m.role;
|
|
4869
|
-
return {
|
|
4870
|
-
sender_id: cfg.appId,
|
|
4871
|
-
sender_name: senderName,
|
|
4872
|
-
role: m.role === "toolResult" ? "tool" : m.role,
|
|
4873
|
-
timestamp: Date.now(),
|
|
4874
|
-
content: text
|
|
4875
|
-
};
|
|
4876
|
-
})
|
|
4877
|
-
};
|
|
4878
|
-
console.log(`[everos-ingest] pushing ${payload.messages.length} messages to ${cfg.url} (appId=${cfg.appId})`);
|
|
4879
|
-
try {
|
|
4880
|
-
const resp = await fetch(`${cfg.url}/api/v1/memory/add`, {
|
|
4881
|
-
method: "POST",
|
|
4882
|
-
headers: { "Content-Type": "application/json" },
|
|
4883
|
-
body: JSON.stringify(payload),
|
|
4884
|
-
signal: AbortSignal.timeout(1e4)
|
|
4885
|
-
});
|
|
4886
|
-
if (resp.ok) {
|
|
4887
|
-
console.log(`[everos-ingest] \u2705 pushed ${payload.messages.length} messages`);
|
|
4888
|
-
} else {
|
|
4889
|
-
console.warn(`[everos-ingest] memory/add ${resp.status}`);
|
|
4890
|
-
}
|
|
4891
|
-
} catch {
|
|
4892
|
-
}
|
|
4893
|
-
}
|
|
4894
|
-
var init_ingest = __esm({
|
|
4895
|
-
"src/memory/everos/ingest.ts"() {
|
|
4896
|
-
"use strict";
|
|
4897
|
-
}
|
|
4898
|
-
});
|
|
4899
|
-
|
|
4900
4901
|
// src/memory/memdir/extractMemories.ts
|
|
4901
4902
|
var extractMemories_exports = {};
|
|
4902
4903
|
__export(extractMemories_exports, {
|
|
@@ -4907,17 +4908,18 @@ import * as path12 from "path";
|
|
|
4907
4908
|
function isModelVisibleMessage(message) {
|
|
4908
4909
|
return message.role === "user" || message.role === "assistant";
|
|
4909
4910
|
}
|
|
4910
|
-
function
|
|
4911
|
-
|
|
4912
|
-
|
|
4913
|
-
|
|
4914
|
-
|
|
4915
|
-
|
|
4916
|
-
|
|
4917
|
-
|
|
4918
|
-
|
|
4911
|
+
function filterNewMessagesByTs(messages, lastTs) {
|
|
4912
|
+
const newMessages = [];
|
|
4913
|
+
let maxNewTs = lastTs ?? 0;
|
|
4914
|
+
for (const m of messages) {
|
|
4915
|
+
if (!isModelVisibleMessage(m)) continue;
|
|
4916
|
+
const ts = m.timestamp;
|
|
4917
|
+
const tsMs = ts ? new Date(ts).getTime() : NaN;
|
|
4918
|
+
if (lastTs !== void 0 && !Number.isNaN(tsMs) && tsMs <= lastTs) continue;
|
|
4919
|
+
if (!Number.isNaN(tsMs)) maxNewTs = Math.max(maxNewTs, tsMs);
|
|
4920
|
+
newMessages.push(m);
|
|
4919
4921
|
}
|
|
4920
|
-
return
|
|
4922
|
+
return { newMessages, maxNewTs };
|
|
4921
4923
|
}
|
|
4922
4924
|
function getMemoryTools() {
|
|
4923
4925
|
const MEMORY_TOOL_NAMES = ["write", "read", "edit", "glob", "grep"];
|
|
@@ -4932,13 +4934,13 @@ function loadPersistedState(workspace) {
|
|
|
4932
4934
|
const p = getStatePath(workspace);
|
|
4933
4935
|
if (fs12.existsSync(p)) {
|
|
4934
4936
|
const data = JSON.parse(fs12.readFileSync(p, "utf-8"));
|
|
4935
|
-
for (const [sid,
|
|
4936
|
-
|
|
4937
|
+
for (const [sid, ts] of Object.entries(data.lastTs ?? {})) {
|
|
4938
|
+
lastTsMap.set(sid, ts);
|
|
4937
4939
|
}
|
|
4938
4940
|
for (const [sid, ts] of Object.entries(data.timestamps ?? {})) {
|
|
4939
4941
|
lastExtractTimeMap.set(sid, ts);
|
|
4940
4942
|
}
|
|
4941
|
-
console.log(`[memory] loaded extract state for ${Object.keys(data.
|
|
4943
|
+
console.log(`[memory] loaded extract state for ${Object.keys(data.lastTs ?? {}).length} session(s) from ${STATE_FILE}`);
|
|
4942
4944
|
}
|
|
4943
4945
|
} catch (e) {
|
|
4944
4946
|
console.warn(`[memory] failed to load extract state: ${e?.message ?? e}`);
|
|
@@ -4946,11 +4948,11 @@ function loadPersistedState(workspace) {
|
|
|
4946
4948
|
}
|
|
4947
4949
|
function persistState(workspace) {
|
|
4948
4950
|
try {
|
|
4949
|
-
const
|
|
4951
|
+
const lastTs = {};
|
|
4950
4952
|
const timestamps = {};
|
|
4951
|
-
for (const [sid,
|
|
4953
|
+
for (const [sid, ts] of lastTsMap.entries()) lastTs[sid] = ts;
|
|
4952
4954
|
for (const [sid, ts] of lastExtractTimeMap.entries()) timestamps[sid] = ts;
|
|
4953
|
-
const data = JSON.stringify({
|
|
4955
|
+
const data = JSON.stringify({ lastTs, timestamps }, null, 2);
|
|
4954
4956
|
fs12.writeFileSync(getStatePath(workspace), data, "utf-8");
|
|
4955
4957
|
} catch (e) {
|
|
4956
4958
|
console.warn(`[memory] failed to persist extract state: ${e?.message ?? e}`);
|
|
@@ -4961,7 +4963,7 @@ function createMemoryExtractor(workspace, enabled) {
|
|
|
4961
4963
|
loadPersistedState(workspace);
|
|
4962
4964
|
return {
|
|
4963
4965
|
reset(sessionId) {
|
|
4964
|
-
|
|
4966
|
+
lastTsMap.delete(sessionId);
|
|
4965
4967
|
lastExtractTimeMap.delete(sessionId);
|
|
4966
4968
|
persistState(workspace);
|
|
4967
4969
|
inProgress = false;
|
|
@@ -4977,13 +4979,12 @@ function createMemoryExtractor(workspace, enabled) {
|
|
|
4977
4979
|
return;
|
|
4978
4980
|
}
|
|
4979
4981
|
}
|
|
4980
|
-
const
|
|
4981
|
-
const
|
|
4982
|
-
const newMessageCount =
|
|
4983
|
-
|
|
4984
|
-
lastProcessedIndex
|
|
4985
|
-
);
|
|
4982
|
+
const lastTs = lastTsMap.get(sessionId);
|
|
4983
|
+
const { newMessages, maxNewTs } = filterNewMessagesByTs(messages, lastTs);
|
|
4984
|
+
const newMessageCount = newMessages.length;
|
|
4985
|
+
console.log(`[memory] extract ts-watermark: session=${sessionId.slice(0, 8)} lastTs=${lastTs ? new Date(lastTs).toISOString().slice(11, 19) : "\u2205(\u9996\u6B21)"} new=${newMessageCount}/${messages.length}`);
|
|
4986
4986
|
if (newMessageCount === 0) return;
|
|
4987
|
+
const memoryDir = getAutoMemPath(workspace);
|
|
4987
4988
|
inProgress = true;
|
|
4988
4989
|
const startTime = Date.now();
|
|
4989
4990
|
try {
|
|
@@ -5022,8 +5023,7 @@ Check this list before writing \u2014 update an existing file rather than creati
|
|
|
5022
5023
|
false
|
|
5023
5024
|
);
|
|
5024
5025
|
}
|
|
5025
|
-
const
|
|
5026
|
-
const recentMessages2 = visibleMessages.slice(-newMessageCount);
|
|
5026
|
+
const recentMessages2 = newMessages;
|
|
5027
5027
|
const conversationText = recentMessages2.map((m) => `[${m.role}]: ${(typeof m.content === "string" ? m.content : "[content blocks]").slice(0, 500)}`).join("\n\n");
|
|
5028
5028
|
const extractMessages = [
|
|
5029
5029
|
{
|
|
@@ -5060,11 +5060,9 @@ ${conversationText}`
|
|
|
5060
5060
|
toolCount++;
|
|
5061
5061
|
}
|
|
5062
5062
|
}
|
|
5063
|
-
|
|
5063
|
+
lastTsMap.set(sessionId, Math.max(maxNewTs, Date.now()));
|
|
5064
5064
|
lastExtractTimeMap.set(sessionId, Date.now());
|
|
5065
5065
|
persistState(workspace);
|
|
5066
|
-
pushConversation(recentMessages2, sessionId).catch(() => {
|
|
5067
|
-
});
|
|
5068
5066
|
const duration = Date.now() - startTime;
|
|
5069
5067
|
console.log(
|
|
5070
5068
|
`[memory] extractMemories finished in ${duration}ms \u2014 ${toolCount} tools used, ${result.length} chars`
|
|
@@ -5079,7 +5077,7 @@ ${conversationText}`
|
|
|
5079
5077
|
}
|
|
5080
5078
|
};
|
|
5081
5079
|
}
|
|
5082
|
-
var
|
|
5080
|
+
var lastTsMap, lastExtractTimeMap, STATE_FILE;
|
|
5083
5081
|
var init_extractMemories = __esm({
|
|
5084
5082
|
"src/memory/memdir/extractMemories.ts"() {
|
|
5085
5083
|
"use strict";
|
|
@@ -5088,13 +5086,207 @@ var init_extractMemories = __esm({
|
|
|
5088
5086
|
init_paths();
|
|
5089
5087
|
init_memoryScan();
|
|
5090
5088
|
init_extractPrompts();
|
|
5091
|
-
|
|
5092
|
-
lastIndexMap = /* @__PURE__ */ new Map();
|
|
5089
|
+
lastTsMap = /* @__PURE__ */ new Map();
|
|
5093
5090
|
lastExtractTimeMap = /* @__PURE__ */ new Map();
|
|
5094
5091
|
STATE_FILE = ".extract-state.json";
|
|
5095
5092
|
}
|
|
5096
5093
|
});
|
|
5097
5094
|
|
|
5095
|
+
// src/memory/everos/ingest.ts
|
|
5096
|
+
var ingest_exports = {};
|
|
5097
|
+
__export(ingest_exports, {
|
|
5098
|
+
pushConversation: () => pushConversation
|
|
5099
|
+
});
|
|
5100
|
+
import fs13 from "node:fs";
|
|
5101
|
+
import path13 from "node:path";
|
|
5102
|
+
function parseMeta(text) {
|
|
5103
|
+
const m = text.match(/^\[meta:\s*(.+?)\s*\((.+?)\)\s*@(\S+)\s*[^\]]*\]/);
|
|
5104
|
+
if (!m) return null;
|
|
5105
|
+
return { senderName: m[1].trim() };
|
|
5106
|
+
}
|
|
5107
|
+
async function readConfig() {
|
|
5108
|
+
const defaults = {
|
|
5109
|
+
url: "http://127.0.0.1:8100",
|
|
5110
|
+
appId: "default",
|
|
5111
|
+
agentName: "assistant",
|
|
5112
|
+
enabled: false,
|
|
5113
|
+
ingestTimeoutMs: 3e4,
|
|
5114
|
+
syncIntervalMs: 9e5
|
|
5115
|
+
};
|
|
5116
|
+
try {
|
|
5117
|
+
const { liveConfig: liveConfig2 } = await Promise.resolve().then(() => (init_live(), live_exports));
|
|
5118
|
+
const cfg = liveConfig2.all()?.everos;
|
|
5119
|
+
if (!cfg) return defaults;
|
|
5120
|
+
return {
|
|
5121
|
+
url: cfg.everosUrl || defaults.url,
|
|
5122
|
+
appId: cfg.userId || defaults.appId,
|
|
5123
|
+
agentName: cfg.agentName || cfg.userId || defaults.agentName,
|
|
5124
|
+
enabled: cfg.enabled === true,
|
|
5125
|
+
ingestTimeoutMs: typeof cfg.ingestTimeoutMs === "number" ? cfg.ingestTimeoutMs : defaults.ingestTimeoutMs,
|
|
5126
|
+
syncIntervalMs: typeof cfg.syncIntervalMs === "number" ? cfg.syncIntervalMs : defaults.syncIntervalMs
|
|
5127
|
+
};
|
|
5128
|
+
} catch {
|
|
5129
|
+
return defaults;
|
|
5130
|
+
}
|
|
5131
|
+
}
|
|
5132
|
+
function loadPushTs(workspace, sessionId) {
|
|
5133
|
+
try {
|
|
5134
|
+
const p = path13.join(workspace, PUSH_STATE_FILE);
|
|
5135
|
+
if (fs13.existsSync(p)) {
|
|
5136
|
+
const data = JSON.parse(fs13.readFileSync(p, "utf-8"));
|
|
5137
|
+
return typeof data[sessionId] === "number" ? data[sessionId] : 0;
|
|
5138
|
+
}
|
|
5139
|
+
} catch (e) {
|
|
5140
|
+
console.warn(`[everos-ingest] load pushTs failed: ${e?.message ?? e}`);
|
|
5141
|
+
}
|
|
5142
|
+
return 0;
|
|
5143
|
+
}
|
|
5144
|
+
function savePushTs(workspace, sessionId, ts) {
|
|
5145
|
+
try {
|
|
5146
|
+
const p = path13.join(workspace, PUSH_STATE_FILE);
|
|
5147
|
+
let data = {};
|
|
5148
|
+
try {
|
|
5149
|
+
if (fs13.existsSync(p)) data = JSON.parse(fs13.readFileSync(p, "utf-8"));
|
|
5150
|
+
} catch {
|
|
5151
|
+
}
|
|
5152
|
+
data[sessionId] = ts;
|
|
5153
|
+
fs13.writeFileSync(p, JSON.stringify(data, null, 2), "utf-8");
|
|
5154
|
+
} catch (e) {
|
|
5155
|
+
console.warn(`[everos-ingest] save pushTs failed: ${e?.message ?? e}`);
|
|
5156
|
+
}
|
|
5157
|
+
}
|
|
5158
|
+
function buildPayload(messages, cfg, sessionId) {
|
|
5159
|
+
return {
|
|
5160
|
+
session_id: `extract-${sessionId}`,
|
|
5161
|
+
app_id: cfg.appId,
|
|
5162
|
+
project_id: "default",
|
|
5163
|
+
messages: messages.map((m) => {
|
|
5164
|
+
const text = typeof m.content === "string" ? m.content : "[content blocks]";
|
|
5165
|
+
const meta = m.role === "user" ? parseMeta(text) : null;
|
|
5166
|
+
const senderName = meta?.senderName ?? (m.role === "assistant" ? cfg.agentName : void 0) ?? m.role;
|
|
5167
|
+
const rawRole = m.role === "toolResult" ? "tool" : m.role;
|
|
5168
|
+
const validRoles = ["user", "assistant", "tool"];
|
|
5169
|
+
return {
|
|
5170
|
+
sender_id: cfg.appId,
|
|
5171
|
+
sender_name: senderName,
|
|
5172
|
+
role: validRoles.includes(rawRole) ? rawRole : "user",
|
|
5173
|
+
timestamp: Date.now(),
|
|
5174
|
+
content: text
|
|
5175
|
+
};
|
|
5176
|
+
})
|
|
5177
|
+
};
|
|
5178
|
+
}
|
|
5179
|
+
async function fetchWithTimeout(url, options, timeoutMs) {
|
|
5180
|
+
const controller = new AbortController();
|
|
5181
|
+
let timer;
|
|
5182
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
5183
|
+
timer = setTimeout(() => {
|
|
5184
|
+
try {
|
|
5185
|
+
controller.abort();
|
|
5186
|
+
} catch {
|
|
5187
|
+
}
|
|
5188
|
+
reject(new Error(`fetch timeout ${timeoutMs}ms`));
|
|
5189
|
+
}, timeoutMs);
|
|
5190
|
+
});
|
|
5191
|
+
try {
|
|
5192
|
+
return await Promise.race([
|
|
5193
|
+
fetch(url, { ...options, signal: controller.signal }),
|
|
5194
|
+
timeoutPromise
|
|
5195
|
+
]);
|
|
5196
|
+
} finally {
|
|
5197
|
+
if (timer) clearTimeout(timer);
|
|
5198
|
+
}
|
|
5199
|
+
}
|
|
5200
|
+
async function pushConversation(messages, sessionId, workspace) {
|
|
5201
|
+
const cfg = await readConfig();
|
|
5202
|
+
if (!cfg.enabled) return;
|
|
5203
|
+
if (!messages.length) return;
|
|
5204
|
+
if (Date.now() - lastPushAt < cfg.syncIntervalMs) return;
|
|
5205
|
+
if (pushInProgress) {
|
|
5206
|
+
console.log("[everos-ingest] previous push still running, skip (pushTs \u4F1A\u7EED\u63A8\uFF0C\u4E0D\u4E22)");
|
|
5207
|
+
return;
|
|
5208
|
+
}
|
|
5209
|
+
lastPushAt = Date.now();
|
|
5210
|
+
pushInProgress = true;
|
|
5211
|
+
try {
|
|
5212
|
+
if (!workspace) {
|
|
5213
|
+
const payload = buildPayload(messages, cfg, sessionId);
|
|
5214
|
+
console.log(`[everos-ingest] pushing ${payload.messages.length} messages to ${cfg.url} (no pushTs, one-shot, timeout=${cfg.ingestTimeoutMs}ms)`);
|
|
5215
|
+
try {
|
|
5216
|
+
const resp = await fetchWithTimeout(`${cfg.url}/api/v1/memory/add`, {
|
|
5217
|
+
method: "POST",
|
|
5218
|
+
headers: { "Content-Type": "application/json" },
|
|
5219
|
+
body: JSON.stringify(payload)
|
|
5220
|
+
}, cfg.ingestTimeoutMs);
|
|
5221
|
+
if (resp.ok) console.log(`[everos-ingest] \u2705 pushed ${payload.messages.length} messages`);
|
|
5222
|
+
else console.warn(`[everos-ingest] memory/add ${resp.status}`);
|
|
5223
|
+
} catch (e) {
|
|
5224
|
+
console.warn(`[everos-ingest] push failed (${e?.name || "error"}: ${e?.message || "unknown"})`);
|
|
5225
|
+
}
|
|
5226
|
+
return;
|
|
5227
|
+
}
|
|
5228
|
+
const pushTs = loadPushTs(workspace, sessionId);
|
|
5229
|
+
const toPush = [];
|
|
5230
|
+
let maxTs = pushTs;
|
|
5231
|
+
for (const m of messages) {
|
|
5232
|
+
const ms = m.timestamp ? new Date(m.timestamp).getTime() : NaN;
|
|
5233
|
+
if (Number.isNaN(ms)) {
|
|
5234
|
+
toPush.push(m);
|
|
5235
|
+
continue;
|
|
5236
|
+
}
|
|
5237
|
+
if (ms <= pushTs) continue;
|
|
5238
|
+
toPush.push(m);
|
|
5239
|
+
if (ms > maxTs) maxTs = ms;
|
|
5240
|
+
}
|
|
5241
|
+
if (toPush.length === 0) return;
|
|
5242
|
+
const total = toPush.length;
|
|
5243
|
+
const chunkTotal = Math.ceil(total / PUSH_CHUNK);
|
|
5244
|
+
let pushed = 0;
|
|
5245
|
+
for (let i = 0; i < total; i += PUSH_CHUNK) {
|
|
5246
|
+
const chunk = toPush.slice(i, i + PUSH_CHUNK);
|
|
5247
|
+
const chunkMaxTs = chunk.reduce((mx, m) => {
|
|
5248
|
+
const ms = m.timestamp ? new Date(m.timestamp).getTime() : 0;
|
|
5249
|
+
return Number.isNaN(ms) || ms < mx ? mx : ms;
|
|
5250
|
+
}, pushTs);
|
|
5251
|
+
const chunkNo = Math.floor(i / PUSH_CHUNK) + 1;
|
|
5252
|
+
const payload = buildPayload(chunk, cfg, sessionId);
|
|
5253
|
+
console.log(`[everos-ingest] pushing chunk ${chunkNo}/${chunkTotal} (${chunk.length} msgs) to ${cfg.url} (timeout=${cfg.ingestTimeoutMs}ms)`);
|
|
5254
|
+
try {
|
|
5255
|
+
const resp = await fetchWithTimeout(`${cfg.url}/api/v1/memory/add`, {
|
|
5256
|
+
method: "POST",
|
|
5257
|
+
headers: { "Content-Type": "application/json" },
|
|
5258
|
+
body: JSON.stringify(payload)
|
|
5259
|
+
}, cfg.ingestTimeoutMs);
|
|
5260
|
+
if (resp.ok) {
|
|
5261
|
+
savePushTs(workspace, sessionId, chunkMaxTs);
|
|
5262
|
+
pushed += chunk.length;
|
|
5263
|
+
console.log(`[everos-ingest] \u2705 pushed chunk ${chunkNo}/${chunkTotal} (${chunk.length} msgs, pushTs\u2192${new Date(chunkMaxTs).toISOString().slice(11, 19)})`);
|
|
5264
|
+
} else {
|
|
5265
|
+
savePushTs(workspace, sessionId, chunkMaxTs);
|
|
5266
|
+
const errBody = await resp.text().catch(() => "?");
|
|
5267
|
+
console.warn(`[everos-ingest] memory/add ${resp.status} on chunk ${chunkNo}, body=${errBody.slice(0, 300)}, skip & advance pushTs\u2192${new Date(chunkMaxTs).toISOString().slice(11, 19)}`);
|
|
5268
|
+
}
|
|
5269
|
+
} catch (e) {
|
|
5270
|
+
savePushTs(workspace, sessionId, chunkMaxTs);
|
|
5271
|
+
console.warn(`[everos-ingest] chunk ${chunkNo} push failed (${e?.name || "error"}: ${e?.message || "unknown"}), skip & advance pushTs\u2192${new Date(chunkMaxTs).toISOString().slice(11, 19)}`);
|
|
5272
|
+
}
|
|
5273
|
+
}
|
|
5274
|
+
console.log(`[everos-ingest] done: ${pushed}/${total} msgs pushed`);
|
|
5275
|
+
} finally {
|
|
5276
|
+
pushInProgress = false;
|
|
5277
|
+
}
|
|
5278
|
+
}
|
|
5279
|
+
var PUSH_CHUNK, PUSH_STATE_FILE, pushInProgress, lastPushAt;
|
|
5280
|
+
var init_ingest = __esm({
|
|
5281
|
+
"src/memory/everos/ingest.ts"() {
|
|
5282
|
+
"use strict";
|
|
5283
|
+
PUSH_CHUNK = 10;
|
|
5284
|
+
PUSH_STATE_FILE = ".everos-push-state.json";
|
|
5285
|
+
pushInProgress = false;
|
|
5286
|
+
lastPushAt = 0;
|
|
5287
|
+
}
|
|
5288
|
+
});
|
|
5289
|
+
|
|
5098
5290
|
// src/memory/sessionMemory/sessionMemoryUtils.ts
|
|
5099
5291
|
import { join as join17 } from "node:path";
|
|
5100
5292
|
import { mkdirSync as mkdirSync6, readFileSync as readFileSync13 } from "node:fs";
|
|
@@ -5452,7 +5644,7 @@ async function extractSessionMemory(messages, overrideProvider, overrideModel) {
|
|
|
5452
5644
|
if (!_deps) return { fired: false, reason: "not initialized" };
|
|
5453
5645
|
if (isExtractionInProgress()) return { fired: false, reason: "extraction already in progress" };
|
|
5454
5646
|
const provider = overrideProvider || _deps.provider;
|
|
5455
|
-
const model = overrideModel ||
|
|
5647
|
+
const model = overrideModel || liveConfig.get("model") || "";
|
|
5456
5648
|
markExtractionStarted();
|
|
5457
5649
|
try {
|
|
5458
5650
|
const { memoryPath, currentMemory } = await setupSessionMemoryFile();
|
|
@@ -5525,7 +5717,7 @@ function getSessionMemoryForCompaction() {
|
|
|
5525
5717
|
}
|
|
5526
5718
|
function isSessionMemoryEnabled() {
|
|
5527
5719
|
if (!_deps) return false;
|
|
5528
|
-
if (
|
|
5720
|
+
if (getFeature("session-memory") === false) return false;
|
|
5529
5721
|
return true;
|
|
5530
5722
|
}
|
|
5531
5723
|
var _deps, lastMemoryMessageIndex;
|
|
@@ -5536,6 +5728,8 @@ var init_sessionMemory = __esm({
|
|
|
5536
5728
|
init_prompts();
|
|
5537
5729
|
init_query();
|
|
5538
5730
|
init_registry();
|
|
5731
|
+
init_features();
|
|
5732
|
+
init_live();
|
|
5539
5733
|
_deps = null;
|
|
5540
5734
|
}
|
|
5541
5735
|
});
|
|
@@ -5551,23 +5745,11 @@ __export(config_exports, {
|
|
|
5551
5745
|
isAutoDreamEnabled: () => isAutoDreamEnabled,
|
|
5552
5746
|
setAutoDreamConfig: () => setAutoDreamConfig
|
|
5553
5747
|
});
|
|
5554
|
-
function dlog(msg2) {
|
|
5555
|
-
if (process.env.AUTODREAM_DEBUG) console.log(`[autoDream] ${msg2}`);
|
|
5556
|
-
}
|
|
5557
5748
|
function setAutoDreamConfig(config2) {
|
|
5558
5749
|
_config = config2;
|
|
5559
|
-
const c = config2;
|
|
5560
|
-
dlog(`setAutoDreamConfig: keys=${Object.keys(c).join(",")} | config.features.autoDream=${c.features?.autoDream} | config.agents.defaults.features.autoDream=${c.agents?.defaults?.features?.autoDream} | config.topics.autoDream=${c.topics?.autoDream ? JSON.stringify(c.topics.autoDream) : "(none)"}`);
|
|
5561
5750
|
}
|
|
5562
5751
|
function isAutoDreamEnabled() {
|
|
5563
|
-
|
|
5564
|
-
dlog("isAutoDreamEnabled: _config null");
|
|
5565
|
-
return false;
|
|
5566
|
-
}
|
|
5567
|
-
const features = _config.profile?.features ?? _config.features ?? _config.agents?.defaults?.features;
|
|
5568
|
-
const result = features?.autoDream === true;
|
|
5569
|
-
dlog(`isAutoDreamEnabled: config.features.autoDream=${_config.features?.autoDream} | agents.defaults.features.autoDream=${_config.agents?.defaults?.features?.autoDream} | resolved=${features?.autoDream} | result=${result}`);
|
|
5570
|
-
return result;
|
|
5752
|
+
return getFeature("autoDream") === true;
|
|
5571
5753
|
}
|
|
5572
5754
|
function getAutoDreamConfig() {
|
|
5573
5755
|
const raw = _config?.topics?.autoDream ?? _config?.autoDream;
|
|
@@ -5593,6 +5775,7 @@ var _config, DEFAULTS;
|
|
|
5593
5775
|
var init_config2 = __esm({
|
|
5594
5776
|
"src/memory/autoDream/config.ts"() {
|
|
5595
5777
|
"use strict";
|
|
5778
|
+
init_features();
|
|
5596
5779
|
_config = null;
|
|
5597
5780
|
DEFAULTS = {
|
|
5598
5781
|
minHours: 24,
|
|
@@ -5616,11 +5799,11 @@ async function readLastConsolidatedAt(memoryDir) {
|
|
|
5616
5799
|
}
|
|
5617
5800
|
}
|
|
5618
5801
|
async function tryAcquireConsolidationLock(memoryDir) {
|
|
5619
|
-
const
|
|
5802
|
+
const path46 = lockPath(memoryDir);
|
|
5620
5803
|
let mtimeMs;
|
|
5621
5804
|
let holderPid;
|
|
5622
5805
|
try {
|
|
5623
|
-
const [s, raw] = await Promise.all([stat3(
|
|
5806
|
+
const [s, raw] = await Promise.all([stat3(path46), readFile5(path46, "utf8")]);
|
|
5624
5807
|
mtimeMs = s.mtimeMs;
|
|
5625
5808
|
const parsed = parseInt(raw.trim(), 10);
|
|
5626
5809
|
holderPid = Number.isFinite(parsed) ? parsed : void 0;
|
|
@@ -5633,10 +5816,10 @@ async function tryAcquireConsolidationLock(memoryDir) {
|
|
|
5633
5816
|
}
|
|
5634
5817
|
}
|
|
5635
5818
|
await mkdir3(memoryDir, { recursive: true });
|
|
5636
|
-
await writeFile4(
|
|
5819
|
+
await writeFile4(path46, String(process.pid));
|
|
5637
5820
|
let verify2;
|
|
5638
5821
|
try {
|
|
5639
|
-
verify2 = await readFile5(
|
|
5822
|
+
verify2 = await readFile5(path46, "utf8");
|
|
5640
5823
|
} catch {
|
|
5641
5824
|
return null;
|
|
5642
5825
|
}
|
|
@@ -5644,15 +5827,15 @@ async function tryAcquireConsolidationLock(memoryDir) {
|
|
|
5644
5827
|
return mtimeMs ?? 0;
|
|
5645
5828
|
}
|
|
5646
5829
|
async function rollbackConsolidationLock(memoryDir, priorMtime) {
|
|
5647
|
-
const
|
|
5830
|
+
const path46 = lockPath(memoryDir);
|
|
5648
5831
|
try {
|
|
5649
5832
|
if (priorMtime === 0) {
|
|
5650
|
-
await unlink(
|
|
5833
|
+
await unlink(path46);
|
|
5651
5834
|
return;
|
|
5652
5835
|
}
|
|
5653
|
-
await writeFile4(
|
|
5836
|
+
await writeFile4(path46, "");
|
|
5654
5837
|
const t = priorMtime / 1e3;
|
|
5655
|
-
await utimes(
|
|
5838
|
+
await utimes(path46, t, t);
|
|
5656
5839
|
} catch (e) {
|
|
5657
5840
|
console.log(`[autoDream] rollback failed: ${e.message} \u2014 next trigger delayed to minHours`);
|
|
5658
5841
|
}
|
|
@@ -5783,48 +5966,48 @@ var init_consolidationPrompt = __esm({
|
|
|
5783
5966
|
// src/memory/autoDream/autoDream.ts
|
|
5784
5967
|
var autoDream_exports = {};
|
|
5785
5968
|
__export(autoDream_exports, {
|
|
5786
|
-
dlog: () =>
|
|
5969
|
+
dlog: () => dlog,
|
|
5787
5970
|
executeAutoDream: () => executeAutoDream,
|
|
5788
5971
|
initAutoDream: () => initAutoDream
|
|
5789
5972
|
});
|
|
5790
|
-
function
|
|
5973
|
+
function dlog(msg2) {
|
|
5791
5974
|
if (process.env.AUTODREAM_DEBUG) console.log(`[autoDream] ${msg2}`);
|
|
5792
5975
|
}
|
|
5793
5976
|
function initAutoDream(deps) {
|
|
5794
5977
|
_deps2 = deps;
|
|
5795
5978
|
lastSessionScanAt = 0;
|
|
5796
|
-
|
|
5979
|
+
dlog(`initAutoDream: workspace=${deps.workspace} sessionsDir=${deps.sessionsDir} model=${deps.model} provider=${deps.provider?.constructor?.name}`);
|
|
5797
5980
|
}
|
|
5798
5981
|
async function executeAutoDream() {
|
|
5799
|
-
|
|
5982
|
+
dlog(`=== executeAutoDream START === _deps=${_deps2 ? "set" : "null"} isAutoDreamEnabled=${isAutoDreamEnabled()}`);
|
|
5800
5983
|
if (!_deps2) {
|
|
5801
|
-
|
|
5984
|
+
dlog("EXIT: not initialized");
|
|
5802
5985
|
return { fired: false, reason: "not initialized" };
|
|
5803
5986
|
}
|
|
5804
5987
|
if (!isAutoDreamEnabled()) {
|
|
5805
|
-
|
|
5988
|
+
dlog("EXIT: disabled (features.autoDream not true)");
|
|
5806
5989
|
return { fired: false, reason: "disabled" };
|
|
5807
5990
|
}
|
|
5808
5991
|
const cfg = getAutoDreamConfig();
|
|
5809
5992
|
const { workspace, sessionsDir, provider, model, toolOverride, disableThinking } = _deps2;
|
|
5810
5993
|
const memoryDir = getAutoMemPath(workspace);
|
|
5811
|
-
|
|
5994
|
+
dlog(`cfg: minHours=${cfg.minHours} minSessions=${cfg.minSessions} | memoryDir=${memoryDir} | distillOutput=${getDistillOutput() ?? "(none)"} dailyLogDir=${getDailyLogDir() ?? "(none)"} | sessionsDir=${sessionsDir}`);
|
|
5812
5995
|
let lastAt;
|
|
5813
5996
|
try {
|
|
5814
5997
|
lastAt = await readLastConsolidatedAt(memoryDir);
|
|
5815
5998
|
} catch (e) {
|
|
5816
|
-
|
|
5999
|
+
dlog(`EXIT: readLastConsolidatedAt failed: ${e.message}`);
|
|
5817
6000
|
return { fired: false, reason: `readLastConsolidatedAt failed: ${e.message}` };
|
|
5818
6001
|
}
|
|
5819
6002
|
const hoursSince = (Date.now() - lastAt) / 36e5;
|
|
5820
|
-
|
|
6003
|
+
dlog(`time gate: lastAt=${lastAt}(${lastAt === 0 ? "no lock \u2192 \u6C38\u8FDC\u6EE1\u8DB3" : new Date(lastAt).toISOString()}) hoursSince=${hoursSince.toFixed(1)} need>=${cfg.minHours}`);
|
|
5821
6004
|
if (hoursSince < cfg.minHours) {
|
|
5822
|
-
|
|
6005
|
+
dlog("EXIT: time gate not met");
|
|
5823
6006
|
return { fired: false, reason: `time gate: ${hoursSince.toFixed(1)}h < ${cfg.minHours}h` };
|
|
5824
6007
|
}
|
|
5825
6008
|
const sinceScanMs = Date.now() - lastSessionScanAt;
|
|
5826
6009
|
if (sinceScanMs < SESSION_SCAN_INTERVAL_MS) {
|
|
5827
|
-
|
|
6010
|
+
dlog(`EXIT: scan throttle ${Math.round(sinceScanMs / 1e3)}s ago < 10min`);
|
|
5828
6011
|
return { fired: false, reason: `scan throttle: last scan ${Math.round(sinceScanMs / 1e3)}s ago` };
|
|
5829
6012
|
}
|
|
5830
6013
|
lastSessionScanAt = Date.now();
|
|
@@ -5832,27 +6015,27 @@ async function executeAutoDream() {
|
|
|
5832
6015
|
try {
|
|
5833
6016
|
sessionIds = await listSessionsTouchedSince(sessionsDir, lastAt);
|
|
5834
6017
|
} catch (e) {
|
|
5835
|
-
|
|
6018
|
+
dlog(`EXIT: listSessionsTouchedSince failed: ${e.message} | sessionsDir=${sessionsDir}`);
|
|
5836
6019
|
return { fired: false, reason: `listSessionsTouchedSince failed: ${e.message}` };
|
|
5837
6020
|
}
|
|
5838
|
-
|
|
6021
|
+
dlog(`session gate: ${sessionIds.length} sessions touched since lastAt, need>=${cfg.minSessions} | sessionsDir=${sessionsDir}`);
|
|
5839
6022
|
if (sessionIds.length < cfg.minSessions) {
|
|
5840
|
-
|
|
6023
|
+
dlog("EXIT: session gate not met");
|
|
5841
6024
|
return { fired: false, reason: `session gate: ${sessionIds.length} < ${cfg.minSessions}` };
|
|
5842
6025
|
}
|
|
5843
6026
|
let priorMtime;
|
|
5844
6027
|
try {
|
|
5845
6028
|
priorMtime = await tryAcquireConsolidationLock(memoryDir);
|
|
5846
6029
|
} catch (e) {
|
|
5847
|
-
|
|
6030
|
+
dlog(`EXIT: lock acquire failed: ${e.message}`);
|
|
5848
6031
|
return { fired: false, reason: `lock acquire failed: ${e.message}` };
|
|
5849
6032
|
}
|
|
5850
6033
|
if (priorMtime === null) {
|
|
5851
|
-
|
|
6034
|
+
dlog("EXIT: lock held by another process");
|
|
5852
6035
|
return { fired: false, reason: "lock held by another process" };
|
|
5853
6036
|
}
|
|
5854
|
-
|
|
5855
|
-
|
|
6037
|
+
dlog(`lock acquired: priorMtime=${priorMtime}`);
|
|
6038
|
+
dlog(`FIRING \u2014 ${hoursSince.toFixed(1)}h since last, ${sessionIds.length} sessions to review`);
|
|
5856
6039
|
console.log(`[autoDream] firing \u2014 ${hoursSince.toFixed(1)}h since last, ${sessionIds.length} sessions to review`);
|
|
5857
6040
|
try {
|
|
5858
6041
|
const extra = `
|
|
@@ -5860,14 +6043,14 @@ async function executeAutoDream() {
|
|
|
5860
6043
|
Sessions since last consolidation (${sessionIds.length}):
|
|
5861
6044
|
${sessionIds.map((id) => `- ${id}`).join("\n")}`;
|
|
5862
6045
|
const prompt = buildConsolidationPrompt(memoryDir, sessionsDir, extra, getDailyLogDir(), getDistillOutput(), getMaxEntrypointLines());
|
|
5863
|
-
|
|
6046
|
+
dlog(`prompt built (${prompt.length} chars)`);
|
|
5864
6047
|
const { QueryEngine: QueryEngine2 } = await Promise.resolve().then(() => (init_query(), query_exports));
|
|
5865
|
-
|
|
6048
|
+
dlog("QueryEngine imported");
|
|
5866
6049
|
const { registry: registry2 } = await Promise.resolve().then(() => (init_registry(), registry_exports));
|
|
5867
6050
|
const SAFE_TOOL_NAMES = /* @__PURE__ */ new Set(["read", "write", "edit", "grep", "glob"]);
|
|
5868
6051
|
const safeTools = registry2.definitions().filter((d) => SAFE_TOOL_NAMES.has(d.function.name));
|
|
5869
6052
|
const memoryTools = toolOverride && toolOverride.length > 0 ? toolOverride : safeTools;
|
|
5870
|
-
|
|
6053
|
+
dlog(`tools: memoryTools=${memoryTools.length} (registry total=${registry2.list().length})`);
|
|
5871
6054
|
const dreamEngine = new QueryEngine2(provider, {
|
|
5872
6055
|
model,
|
|
5873
6056
|
systemPrompt: prompt,
|
|
@@ -5876,7 +6059,7 @@ ${sessionIds.map((id) => `- ${id}`).join("\n")}`;
|
|
|
5876
6059
|
disableThinking: disableThinking ?? true,
|
|
5877
6060
|
agentLabel: "auto-dream"
|
|
5878
6061
|
});
|
|
5879
|
-
|
|
6062
|
+
dlog("dreamEngine created");
|
|
5880
6063
|
const messages = [{ role: "user", content: prompt }];
|
|
5881
6064
|
const toolContext = {
|
|
5882
6065
|
sessionId: "auto-dream",
|
|
@@ -5886,24 +6069,24 @@ ${sessionIds.map((id) => `- ${id}`).join("\n")}`;
|
|
|
5886
6069
|
};
|
|
5887
6070
|
let result = "";
|
|
5888
6071
|
let turnCount = 0;
|
|
5889
|
-
|
|
6072
|
+
dlog("dream query START");
|
|
5890
6073
|
for await (const chunk of dreamEngine.query(messages, void 0, toolContext)) {
|
|
5891
6074
|
if (chunk.type === "text") {
|
|
5892
6075
|
result += chunk.text || "";
|
|
5893
6076
|
}
|
|
5894
6077
|
if (chunk.type === "tool_call") {
|
|
5895
6078
|
turnCount++;
|
|
5896
|
-
|
|
6079
|
+
dlog(`dream turn ${turnCount}: tool_call`);
|
|
5897
6080
|
}
|
|
5898
6081
|
}
|
|
5899
|
-
|
|
6082
|
+
dlog(`dream query DONE \u2014 ${turnCount} tool_calls, result=${result.length} chars`);
|
|
5900
6083
|
await recordConsolidation(memoryDir);
|
|
5901
|
-
|
|
6084
|
+
dlog(`recordConsolidation OK \u2014 wrote .consolidate-lock`);
|
|
5902
6085
|
console.log(`[autoDream] completed \u2014 reviewed ${sessionIds.length} sessions`);
|
|
5903
6086
|
return { fired: true, summary: result.slice(0, 500) };
|
|
5904
6087
|
} catch (e) {
|
|
5905
6088
|
const err = e;
|
|
5906
|
-
|
|
6089
|
+
dlog(`CATCH failed: ${err.message}
|
|
5907
6090
|
stack: ${err.stack ?? "(no stack)"}`);
|
|
5908
6091
|
console.log(`[autoDream] failed: ${err.message}`);
|
|
5909
6092
|
await rollbackConsolidationLock(memoryDir, priorMtime);
|
|
@@ -5984,30 +6167,30 @@ __export(TodoWriteTool_exports, {
|
|
|
5984
6167
|
initTodoStore: () => initTodoStore,
|
|
5985
6168
|
loadTodos: () => loadTodos
|
|
5986
6169
|
});
|
|
5987
|
-
import
|
|
5988
|
-
import
|
|
6170
|
+
import fs32 from "node:fs";
|
|
6171
|
+
import path33 from "node:path";
|
|
5989
6172
|
function initTodoStore(stateDir) {
|
|
5990
|
-
todosDir =
|
|
5991
|
-
if (!
|
|
5992
|
-
|
|
6173
|
+
todosDir = path33.join(stateDir, "todos");
|
|
6174
|
+
if (!fs32.existsSync(todosDir)) {
|
|
6175
|
+
fs32.mkdirSync(todosDir, { recursive: true });
|
|
5993
6176
|
}
|
|
5994
6177
|
}
|
|
5995
6178
|
function todoFilePath(sessionId) {
|
|
5996
|
-
return
|
|
6179
|
+
return path33.join(todosDir, `${sessionId}.json`);
|
|
5997
6180
|
}
|
|
5998
6181
|
function loadTodos(sessionId) {
|
|
5999
6182
|
if (!todosDir) return [];
|
|
6000
6183
|
try {
|
|
6001
6184
|
const filePath = todoFilePath(sessionId);
|
|
6002
|
-
if (!
|
|
6003
|
-
return JSON.parse(
|
|
6185
|
+
if (!fs32.existsSync(filePath)) return [];
|
|
6186
|
+
return JSON.parse(fs32.readFileSync(filePath, "utf-8"));
|
|
6004
6187
|
} catch {
|
|
6005
6188
|
return [];
|
|
6006
6189
|
}
|
|
6007
6190
|
}
|
|
6008
6191
|
function saveTodos(sessionId, todos) {
|
|
6009
6192
|
if (!todosDir) return;
|
|
6010
|
-
|
|
6193
|
+
fs32.writeFileSync(todoFilePath(sessionId), JSON.stringify(todos, null, 2), "utf-8");
|
|
6011
6194
|
}
|
|
6012
6195
|
var todosDir;
|
|
6013
6196
|
var init_TodoWriteTool = __esm({
|
|
@@ -6088,28 +6271,28 @@ __export(tasks_exports, {
|
|
|
6088
6271
|
unassignTeammateTasks: () => unassignTeammateTasks,
|
|
6089
6272
|
updateTask: () => updateTask
|
|
6090
6273
|
});
|
|
6091
|
-
import * as
|
|
6092
|
-
import * as
|
|
6274
|
+
import * as fs34 from "node:fs";
|
|
6275
|
+
import * as path35 from "node:path";
|
|
6093
6276
|
function sanitizePathComponent2(input) {
|
|
6094
6277
|
return input.replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
6095
6278
|
}
|
|
6096
6279
|
function getTasksDir2(stateDir, listId) {
|
|
6097
|
-
return
|
|
6280
|
+
return path35.join(stateDir, "tasks", sanitizePathComponent2(listId));
|
|
6098
6281
|
}
|
|
6099
6282
|
function getTaskPath(stateDir, listId, taskId) {
|
|
6100
|
-
return
|
|
6283
|
+
return path35.join(getTasksDir2(stateDir, listId), `${sanitizePathComponent2(taskId)}.json`);
|
|
6101
6284
|
}
|
|
6102
6285
|
function ensureTasksDir2(stateDir, listId) {
|
|
6103
6286
|
const dir = getTasksDir2(stateDir, listId);
|
|
6104
|
-
|
|
6287
|
+
fs34.mkdirSync(dir, { recursive: true });
|
|
6105
6288
|
return dir;
|
|
6106
6289
|
}
|
|
6107
6290
|
function getHighWaterMarkPath(stateDir, listId) {
|
|
6108
|
-
return
|
|
6291
|
+
return path35.join(getTasksDir2(stateDir, listId), HIGH_WATER_MARK_FILE);
|
|
6109
6292
|
}
|
|
6110
6293
|
function readHighWaterMark(stateDir, listId) {
|
|
6111
6294
|
try {
|
|
6112
|
-
const content =
|
|
6295
|
+
const content = fs34.readFileSync(getHighWaterMarkPath(stateDir, listId), "utf-8").trim();
|
|
6113
6296
|
const value = parseInt(content, 10);
|
|
6114
6297
|
return isNaN(value) ? 0 : value;
|
|
6115
6298
|
} catch {
|
|
@@ -6117,13 +6300,13 @@ function readHighWaterMark(stateDir, listId) {
|
|
|
6117
6300
|
}
|
|
6118
6301
|
}
|
|
6119
6302
|
function writeHighWaterMark(stateDir, listId, value) {
|
|
6120
|
-
|
|
6303
|
+
fs34.writeFileSync(getHighWaterMarkPath(stateDir, listId), String(value));
|
|
6121
6304
|
}
|
|
6122
6305
|
function findHighestTaskIdFromFiles(stateDir, listId) {
|
|
6123
6306
|
const dir = getTasksDir2(stateDir, listId);
|
|
6124
6307
|
let files;
|
|
6125
6308
|
try {
|
|
6126
|
-
files =
|
|
6309
|
+
files = fs34.readdirSync(dir);
|
|
6127
6310
|
} catch {
|
|
6128
6311
|
return 0;
|
|
6129
6312
|
}
|
|
@@ -6149,14 +6332,14 @@ function createTask(stateDir, listId, taskData) {
|
|
|
6149
6332
|
const id = String(highestId + 1);
|
|
6150
6333
|
const task = { id, ...taskData };
|
|
6151
6334
|
const filePath = getTaskPath(stateDir, listId, id);
|
|
6152
|
-
|
|
6335
|
+
fs34.writeFileSync(filePath, JSON.stringify(task, null, 2));
|
|
6153
6336
|
return id;
|
|
6154
6337
|
});
|
|
6155
6338
|
}
|
|
6156
6339
|
function getTask2(stateDir, listId, taskId) {
|
|
6157
6340
|
const filePath = getTaskPath(stateDir, listId, taskId);
|
|
6158
6341
|
try {
|
|
6159
|
-
const content =
|
|
6342
|
+
const content = fs34.readFileSync(filePath, "utf-8");
|
|
6160
6343
|
return JSON.parse(content);
|
|
6161
6344
|
} catch {
|
|
6162
6345
|
return null;
|
|
@@ -6166,7 +6349,7 @@ function listTasks2(stateDir, listId) {
|
|
|
6166
6349
|
const dir = getTasksDir2(stateDir, listId);
|
|
6167
6350
|
let files;
|
|
6168
6351
|
try {
|
|
6169
|
-
files =
|
|
6352
|
+
files = fs34.readdirSync(dir);
|
|
6170
6353
|
} catch {
|
|
6171
6354
|
return [];
|
|
6172
6355
|
}
|
|
@@ -6178,7 +6361,7 @@ function updateTask(stateDir, listId, taskId, updates) {
|
|
|
6178
6361
|
if (!existing) return null;
|
|
6179
6362
|
const updated = { ...existing, ...updates, id: taskId };
|
|
6180
6363
|
const filePath = getTaskPath(stateDir, listId, taskId);
|
|
6181
|
-
|
|
6364
|
+
fs34.writeFileSync(filePath, JSON.stringify(updated, null, 2));
|
|
6182
6365
|
return updated;
|
|
6183
6366
|
}
|
|
6184
6367
|
function deleteTask(stateDir, listId, taskId) {
|
|
@@ -6192,7 +6375,7 @@ function deleteTask(stateDir, listId, taskId) {
|
|
|
6192
6375
|
}
|
|
6193
6376
|
}
|
|
6194
6377
|
try {
|
|
6195
|
-
|
|
6378
|
+
fs34.unlinkSync(filePath);
|
|
6196
6379
|
} catch {
|
|
6197
6380
|
return false;
|
|
6198
6381
|
}
|
|
@@ -6310,15 +6493,15 @@ var read_exports = {};
|
|
|
6310
6493
|
__export(read_exports, {
|
|
6311
6494
|
readFileState: () => readFileState
|
|
6312
6495
|
});
|
|
6313
|
-
import * as
|
|
6314
|
-
import * as
|
|
6496
|
+
import * as fs35 from "node:fs";
|
|
6497
|
+
import * as path36 from "node:path";
|
|
6315
6498
|
function isBlockedDevicePath(filePath) {
|
|
6316
6499
|
if (BLOCKED_DEVICE_PATHS.has(filePath)) return true;
|
|
6317
6500
|
if (filePath.startsWith("/proc/") && (filePath.endsWith("/fd/0") || filePath.endsWith("/fd/1") || filePath.endsWith("/fd/2"))) return true;
|
|
6318
6501
|
return false;
|
|
6319
6502
|
}
|
|
6320
6503
|
function checkReadLoop(filePath, offset, limit) {
|
|
6321
|
-
const stat4 =
|
|
6504
|
+
const stat4 = fs35.statSync(filePath);
|
|
6322
6505
|
const mtimeMs = stat4.mtimeMs;
|
|
6323
6506
|
const prev = readHistory.get(filePath);
|
|
6324
6507
|
if (prev && prev.offset === offset && prev.limit === limit && prev.mtimeMs === mtimeMs) {
|
|
@@ -6332,19 +6515,19 @@ function checkReadLoop(filePath, offset, limit) {
|
|
|
6332
6515
|
return null;
|
|
6333
6516
|
}
|
|
6334
6517
|
function readFileContent(filePath) {
|
|
6335
|
-
const fd =
|
|
6518
|
+
const fd = fs35.openSync(filePath, "r");
|
|
6336
6519
|
const bom = Buffer.alloc(2);
|
|
6337
|
-
|
|
6338
|
-
|
|
6520
|
+
fs35.readSync(fd, bom, 0, 2, 0);
|
|
6521
|
+
fs35.closeSync(fd);
|
|
6339
6522
|
let encoding = "utf8";
|
|
6340
6523
|
if (bom[0] === 255 && bom[1] === 254) {
|
|
6341
6524
|
encoding = "utf16le";
|
|
6342
6525
|
}
|
|
6343
|
-
const stat4 =
|
|
6526
|
+
const stat4 = fs35.statSync(filePath);
|
|
6344
6527
|
if (stat4.size > MAX_FILE_SIZE) {
|
|
6345
6528
|
throw new Error(`\u6587\u4EF6\u592A\u5927 (${(stat4.size / 1024).toFixed(1)}KB)\uFF0C\u8D85\u8FC7 ${MAX_FILE_SIZE / 1024}KB \u9650\u5236\u3002\u8BF7\u4F7F\u7528 offset + limit \u5206\u6BB5\u8BFB\u53D6\u3002`);
|
|
6346
6529
|
}
|
|
6347
|
-
const raw =
|
|
6530
|
+
const raw = fs35.readFileSync(filePath, encoding);
|
|
6348
6531
|
const content = raw.toString().replaceAll("\r\n", "\n");
|
|
6349
6532
|
return { content, encoding };
|
|
6350
6533
|
}
|
|
@@ -6486,11 +6669,11 @@ Usage:
|
|
|
6486
6669
|
} catch (e) {
|
|
6487
6670
|
return { content: e.message, isError: true };
|
|
6488
6671
|
}
|
|
6489
|
-
if (!
|
|
6672
|
+
if (!fs35.existsSync(filePath)) {
|
|
6490
6673
|
return { content: `\u6587\u4EF6\u4E0D\u5B58\u5728: ${filePath}`, isError: true };
|
|
6491
6674
|
}
|
|
6492
|
-
const stat4 =
|
|
6493
|
-
const baseName =
|
|
6675
|
+
const stat4 = fs35.statSync(filePath);
|
|
6676
|
+
const baseName = path36.basename(filePath).toUpperCase();
|
|
6494
6677
|
if (BLOCKED_BASENAMES.has(baseName)) {
|
|
6495
6678
|
return { content: `\u8BBE\u5907\u6587\u4EF6\u4E0D\u652F\u6301\u8BFB\u53D6: ${filePath}`, isError: true };
|
|
6496
6679
|
}
|
|
@@ -6498,11 +6681,11 @@ Usage:
|
|
|
6498
6681
|
return { content: `\u8BBE\u5907\u6587\u4EF6\u4F1A\u963B\u585E\u6216\u4EA7\u751F\u65E0\u9650\u8F93\u51FA: ${filePath}`, isError: true };
|
|
6499
6682
|
}
|
|
6500
6683
|
if (stat4.isDirectory()) {
|
|
6501
|
-
const entries =
|
|
6684
|
+
const entries = fs35.readdirSync(filePath);
|
|
6502
6685
|
const items = entries.map((e) => {
|
|
6503
|
-
const full =
|
|
6686
|
+
const full = path36.join(filePath, e);
|
|
6504
6687
|
try {
|
|
6505
|
-
const s =
|
|
6688
|
+
const s = fs35.statSync(full);
|
|
6506
6689
|
return s.isDirectory() ? `${e}/` : e;
|
|
6507
6690
|
} catch {
|
|
6508
6691
|
return e;
|
|
@@ -6511,7 +6694,7 @@ Usage:
|
|
|
6511
6694
|
return { content: `\u76EE\u5F55 (${entries.length} \u9879):
|
|
6512
6695
|
${items.join("\n")}` };
|
|
6513
6696
|
}
|
|
6514
|
-
const ext =
|
|
6697
|
+
const ext = path36.extname(filePath).toLowerCase();
|
|
6515
6698
|
if (BINARY_EXTENSIONS.has(ext)) {
|
|
6516
6699
|
return { content: `\u4E8C\u8FDB\u5236\u6587\u4EF6\u4E0D\u652F\u6301\u8BFB\u53D6 (${ext}): ${filePath}`, isError: true };
|
|
6517
6700
|
}
|
|
@@ -6559,22 +6742,22 @@ ${result}` : result };
|
|
|
6559
6742
|
|
|
6560
6743
|
// src/tools/write.ts
|
|
6561
6744
|
var write_exports = {};
|
|
6562
|
-
import * as
|
|
6563
|
-
import * as
|
|
6745
|
+
import * as fs36 from "node:fs";
|
|
6746
|
+
import * as path37 from "node:path";
|
|
6564
6747
|
function isBlockedPath(filePath) {
|
|
6565
6748
|
return BLOCKED_PATTERNS.some((p) => p.test(filePath));
|
|
6566
6749
|
}
|
|
6567
6750
|
function atomicWrite(filePath, content) {
|
|
6568
6751
|
const tmpPath = filePath + ".tmp." + Date.now() + ".write";
|
|
6569
|
-
|
|
6752
|
+
fs36.writeFileSync(tmpPath, content, "utf-8");
|
|
6570
6753
|
try {
|
|
6571
|
-
|
|
6754
|
+
fs36.renameSync(tmpPath, filePath);
|
|
6572
6755
|
} catch (e) {
|
|
6573
6756
|
try {
|
|
6574
|
-
|
|
6757
|
+
fs36.unlinkSync(tmpPath);
|
|
6575
6758
|
} catch {
|
|
6576
6759
|
}
|
|
6577
|
-
|
|
6760
|
+
fs36.writeFileSync(filePath, content, "utf-8");
|
|
6578
6761
|
}
|
|
6579
6762
|
}
|
|
6580
6763
|
function simpleDiff(oldContent, newContent) {
|
|
@@ -6668,15 +6851,15 @@ Usage:
|
|
|
6668
6851
|
}
|
|
6669
6852
|
const rawContent = args2.content;
|
|
6670
6853
|
const content = rawContent.replaceAll("\r\n", "\n");
|
|
6671
|
-
if (
|
|
6854
|
+
if (fs36.existsSync(filePath) && fs36.statSync(filePath).isDirectory()) {
|
|
6672
6855
|
return { content: `\u8DEF\u5F84\u662F\u76EE\u5F55\u4E0D\u662F\u6587\u4EF6: ${filePath}`, isError: true };
|
|
6673
6856
|
}
|
|
6674
6857
|
let oldContent = null;
|
|
6675
6858
|
let isCreate = true;
|
|
6676
|
-
if (
|
|
6859
|
+
if (fs36.existsSync(filePath)) {
|
|
6677
6860
|
isCreate = false;
|
|
6678
6861
|
try {
|
|
6679
|
-
oldContent =
|
|
6862
|
+
oldContent = fs36.readFileSync(filePath, "utf-8").replaceAll("\r\n", "\n");
|
|
6680
6863
|
} catch {
|
|
6681
6864
|
isCreate = true;
|
|
6682
6865
|
}
|
|
@@ -6692,10 +6875,10 @@ Usage:
|
|
|
6692
6875
|
isError: true
|
|
6693
6876
|
};
|
|
6694
6877
|
}
|
|
6695
|
-
const currentStat =
|
|
6878
|
+
const currentStat = fs36.statSync(filePath);
|
|
6696
6879
|
const lastWriteTime = Math.floor(currentStat.mtimeMs);
|
|
6697
6880
|
if (lastWriteTime > readState.timestamp) {
|
|
6698
|
-
const currentContent =
|
|
6881
|
+
const currentContent = fs36.readFileSync(filePath, "utf-8").replaceAll("\r\n", "\n");
|
|
6699
6882
|
if (currentContent !== oldContent) {
|
|
6700
6883
|
return {
|
|
6701
6884
|
content: `\u6587\u4EF6\u5728\u8BFB\u53D6\u540E\u88AB\u4FEE\u6539\u3002\u8BF7\u5148\u91CD\u65B0\u8BFB\u53D6\u6587\u4EF6\u518D\u5199\u5165: ${filePath}`,
|
|
@@ -6704,9 +6887,9 @@ Usage:
|
|
|
6704
6887
|
}
|
|
6705
6888
|
}
|
|
6706
6889
|
}
|
|
6707
|
-
const dir =
|
|
6890
|
+
const dir = path37.dirname(filePath);
|
|
6708
6891
|
try {
|
|
6709
|
-
|
|
6892
|
+
fs36.mkdirSync(dir, { recursive: true });
|
|
6710
6893
|
} catch (e) {
|
|
6711
6894
|
return { content: `\u65E0\u6CD5\u521B\u5EFA\u76EE\u5F55: ${dir} \u2014 ${e.message}`, isError: true };
|
|
6712
6895
|
}
|
|
@@ -6715,11 +6898,11 @@ Usage:
|
|
|
6715
6898
|
} catch (e) {
|
|
6716
6899
|
return { content: `\u5199\u5165\u5931\u8D25: ${e.message}`, isError: true };
|
|
6717
6900
|
}
|
|
6718
|
-
readFileState.set(filePath, { timestamp:
|
|
6901
|
+
readFileState.set(filePath, { timestamp: fs36.statSync(filePath).mtimeMs });
|
|
6719
6902
|
const action = isCreate ? "\u521B\u5EFA" : "\u66F4\u65B0";
|
|
6720
6903
|
const lines = content.split("\n").length;
|
|
6721
6904
|
const chars = content.length;
|
|
6722
|
-
const stat4 =
|
|
6905
|
+
const stat4 = fs36.statSync(filePath);
|
|
6723
6906
|
let diff = "";
|
|
6724
6907
|
if (!isCreate && oldContent !== null) {
|
|
6725
6908
|
diff = `
|
|
@@ -6739,8 +6922,8 @@ ${simpleDiff(oldContent, content)}`;
|
|
|
6739
6922
|
|
|
6740
6923
|
// src/tools/edit.ts
|
|
6741
6924
|
var edit_exports = {};
|
|
6742
|
-
import * as
|
|
6743
|
-
import * as
|
|
6925
|
+
import * as fs37 from "node:fs";
|
|
6926
|
+
import * as path38 from "node:path";
|
|
6744
6927
|
function normalizeQuotes(str) {
|
|
6745
6928
|
return str.replaceAll(LEFT_SINGLE_CURLY, "'").replaceAll(RIGHT_SINGLE_CURLY, "'").replaceAll(LEFT_DOUBLE_CURLY, '"').replaceAll(RIGHT_DOUBLE_CURLY, '"');
|
|
6746
6929
|
}
|
|
@@ -6893,7 +7076,7 @@ Usage:
|
|
|
6893
7076
|
}
|
|
6894
7077
|
let fileContent = null;
|
|
6895
7078
|
try {
|
|
6896
|
-
const stat4 =
|
|
7079
|
+
const stat4 = fs37.statSync(filePath);
|
|
6897
7080
|
if (stat4.isDirectory()) {
|
|
6898
7081
|
return { content: `\u8DEF\u5F84\u662F\u76EE\u5F55\u4E0D\u662F\u6587\u4EF6: ${filePath}`, isError: true };
|
|
6899
7082
|
}
|
|
@@ -6903,21 +7086,21 @@ Usage:
|
|
|
6903
7086
|
} catch (e) {
|
|
6904
7087
|
if (e.code === "ENOENT") {
|
|
6905
7088
|
if (oldString === "") {
|
|
6906
|
-
const dir =
|
|
6907
|
-
|
|
6908
|
-
|
|
6909
|
-
readFileState.set(filePath, { timestamp:
|
|
7089
|
+
const dir = path38.dirname(filePath);
|
|
7090
|
+
fs37.mkdirSync(dir, { recursive: true });
|
|
7091
|
+
fs37.writeFileSync(filePath, newString, "utf-8");
|
|
7092
|
+
readFileState.set(filePath, { timestamp: fs37.statSync(filePath).mtimeMs });
|
|
6910
7093
|
return { content: `\u521B\u5EFA\u6587\u4EF6: ${filePath} (${newString.split("\n").length} \u884C)` };
|
|
6911
7094
|
}
|
|
6912
7095
|
return { content: `\u6587\u4EF6\u4E0D\u5B58\u5728: ${filePath}`, isError: true };
|
|
6913
7096
|
}
|
|
6914
7097
|
throw e;
|
|
6915
7098
|
}
|
|
6916
|
-
const rawContent =
|
|
7099
|
+
const rawContent = fs37.readFileSync(filePath, "utf-8");
|
|
6917
7100
|
fileContent = rawContent.replaceAll("\r\n", "\n");
|
|
6918
7101
|
if (oldString === "" && fileContent.trim() === "") {
|
|
6919
|
-
|
|
6920
|
-
readFileState.set(filePath, { timestamp:
|
|
7102
|
+
fs37.writeFileSync(filePath, newString, "utf-8");
|
|
7103
|
+
readFileState.set(filePath, { timestamp: fs37.statSync(filePath).mtimeMs });
|
|
6921
7104
|
return { content: `\u5199\u5165\u7A7A\u6587\u4EF6: ${filePath} (${newString.split("\n").length} \u884C)` };
|
|
6922
7105
|
}
|
|
6923
7106
|
const readState = readFileState.get(filePath);
|
|
@@ -6927,11 +7110,11 @@ Usage:
|
|
|
6927
7110
|
isError: true
|
|
6928
7111
|
};
|
|
6929
7112
|
}
|
|
6930
|
-
const currentStat =
|
|
7113
|
+
const currentStat = fs37.statSync(filePath);
|
|
6931
7114
|
const lastWriteTime = Math.floor(currentStat.mtimeMs);
|
|
6932
7115
|
if (lastWriteTime > readState.timestamp) {
|
|
6933
7116
|
if (fileContent !== rawContent.replaceAll("\r\n", "\n")) {
|
|
6934
|
-
if (fileContent !==
|
|
7117
|
+
if (fileContent !== fs37.readFileSync(filePath, "utf-8").replaceAll("\r\n", "\n")) {
|
|
6935
7118
|
return {
|
|
6936
7119
|
content: `\u6587\u4EF6\u5728\u8BFB\u53D6\u540E\u88AB\u4FEE\u6539\u3002\u8BF7\u5148\u91CD\u65B0\u8BFB\u53D6\u6587\u4EF6\u518D\u7F16\u8F91: ${filePath}`,
|
|
6937
7120
|
isError: true
|
|
@@ -6963,8 +7146,8 @@ ${preview}
|
|
|
6963
7146
|
const actualNewString = preserveQuoteStyle(oldString, actualOldString, newString);
|
|
6964
7147
|
const diffView = generateEditDiff(fileContent, actualOldString, actualNewString);
|
|
6965
7148
|
const newContent = applyEditToFile(fileContent, actualOldString, actualNewString, replaceAll);
|
|
6966
|
-
|
|
6967
|
-
readFileState.set(filePath, { timestamp:
|
|
7149
|
+
fs37.writeFileSync(filePath, newContent, "utf-8");
|
|
7150
|
+
readFileState.set(filePath, { timestamp: fs37.statSync(filePath).mtimeMs });
|
|
6968
7151
|
const strategy = actualOldString === oldString ? "\u7CBE\u786E\u5339\u914D" : "\u5F15\u53F7\u89C4\u8303\u5316\u5339\u914D";
|
|
6969
7152
|
const count = replaceAll ? matchCount : 1;
|
|
6970
7153
|
const diff = `${oldString.length}\u2192${newString.length}\u5B57\u7B26`;
|
|
@@ -6982,8 +7165,8 @@ ${diffView}`
|
|
|
6982
7165
|
|
|
6983
7166
|
// src/tools/glob.ts
|
|
6984
7167
|
var glob_exports = {};
|
|
6985
|
-
import * as
|
|
6986
|
-
import * as
|
|
7168
|
+
import * as fs38 from "node:fs";
|
|
7169
|
+
import * as path39 from "node:path";
|
|
6987
7170
|
function globMatch(pattern, filename) {
|
|
6988
7171
|
const regexStr = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "{{GLOBSTAR}}").replace(/\*/g, "[^/]*").replace(/\?/g, "[^/]").replace(/\{\{GLOBSTAR\}\}/g, ".*");
|
|
6989
7172
|
try {
|
|
@@ -7003,18 +7186,18 @@ function findFiles(dir, pattern, limit, baseDir) {
|
|
|
7003
7186
|
}
|
|
7004
7187
|
let entries;
|
|
7005
7188
|
try {
|
|
7006
|
-
entries =
|
|
7189
|
+
entries = fs38.readdirSync(currentDir, { withFileTypes: true });
|
|
7007
7190
|
} catch {
|
|
7008
7191
|
return;
|
|
7009
7192
|
}
|
|
7010
7193
|
for (const entry of entries) {
|
|
7011
7194
|
if (truncated) return;
|
|
7012
|
-
const fullPath =
|
|
7195
|
+
const fullPath = path39.join(currentDir, entry.name);
|
|
7013
7196
|
if (entry.isDirectory()) {
|
|
7014
7197
|
if (VCS_DIRS.has(entry.name)) continue;
|
|
7015
7198
|
walk(fullPath);
|
|
7016
7199
|
} else if (entry.isFile()) {
|
|
7017
|
-
const relativePath =
|
|
7200
|
+
const relativePath = path39.relative(baseDir, fullPath).replace(/\\/g, "/");
|
|
7018
7201
|
const patternsToTry = [pattern];
|
|
7019
7202
|
if (pattern.startsWith("**/")) {
|
|
7020
7203
|
patternsToTry.push(pattern.slice(3));
|
|
@@ -7024,7 +7207,7 @@ function findFiles(dir, pattern, limit, baseDir) {
|
|
|
7024
7207
|
);
|
|
7025
7208
|
if (matched) {
|
|
7026
7209
|
try {
|
|
7027
|
-
const stat4 =
|
|
7210
|
+
const stat4 = fs38.statSync(fullPath);
|
|
7028
7211
|
results.push({ path: fullPath, mtimeMs: stat4.mtimeMs });
|
|
7029
7212
|
} catch {
|
|
7030
7213
|
}
|
|
@@ -7041,7 +7224,7 @@ function findFiles(dir, pattern, limit, baseDir) {
|
|
|
7041
7224
|
};
|
|
7042
7225
|
}
|
|
7043
7226
|
function toRelativePath(absolutePath, cwd) {
|
|
7044
|
-
if (absolutePath.startsWith(cwd +
|
|
7227
|
+
if (absolutePath.startsWith(cwd + path39.sep)) {
|
|
7045
7228
|
return absolutePath.slice(cwd.length + 1);
|
|
7046
7229
|
}
|
|
7047
7230
|
return absolutePath;
|
|
@@ -7074,10 +7257,10 @@ var init_glob = __esm({
|
|
|
7074
7257
|
const searchPath = args2.path ? resolvePath(args2.path, ctx.workspace) : ctx.workspace;
|
|
7075
7258
|
const pattern = args2.pattern;
|
|
7076
7259
|
const limit = args2.limit || DEFAULT_LIMIT;
|
|
7077
|
-
if (!
|
|
7260
|
+
if (!fs38.existsSync(searchPath)) {
|
|
7078
7261
|
return { content: `\u76EE\u5F55\u4E0D\u5B58\u5728: ${searchPath}`, isError: true };
|
|
7079
7262
|
}
|
|
7080
|
-
if (!
|
|
7263
|
+
if (!fs38.statSync(searchPath).isDirectory()) {
|
|
7081
7264
|
return { content: `\u8DEF\u5F84\u4E0D\u662F\u76EE\u5F55: ${searchPath}`, isError: true };
|
|
7082
7265
|
}
|
|
7083
7266
|
const start = Date.now();
|
|
@@ -7102,7 +7285,7 @@ ${filenames.join("\n")}${truncatedNote}`
|
|
|
7102
7285
|
// src/tools/grep.ts
|
|
7103
7286
|
var grep_exports = {};
|
|
7104
7287
|
import { execFile as execFile2 } from "node:child_process";
|
|
7105
|
-
import * as
|
|
7288
|
+
import * as path40 from "node:path";
|
|
7106
7289
|
function ripGrep(args2, searchPath, signal) {
|
|
7107
7290
|
return new Promise((resolve10) => {
|
|
7108
7291
|
const fullArgs = [...args2, searchPath];
|
|
@@ -7134,7 +7317,7 @@ function applyHeadLimit(items, limit, offset = 0) {
|
|
|
7134
7317
|
};
|
|
7135
7318
|
}
|
|
7136
7319
|
function toRelativePath2(absolutePath, cwd) {
|
|
7137
|
-
if (absolutePath.startsWith(cwd +
|
|
7320
|
+
if (absolutePath.startsWith(cwd + path40.sep)) {
|
|
7138
7321
|
return absolutePath.slice(cwd.length + 1);
|
|
7139
7322
|
}
|
|
7140
7323
|
if (absolutePath.startsWith(cwd)) {
|
|
@@ -8200,7 +8383,7 @@ function setSwarmsConfig(config2) {
|
|
|
8200
8383
|
_config2 = config2;
|
|
8201
8384
|
}
|
|
8202
8385
|
function isAgentSwarmsEnabled() {
|
|
8203
|
-
const feat =
|
|
8386
|
+
const feat = getFeature("agentTeams");
|
|
8204
8387
|
if (feat === true || feat?.enabled === true) {
|
|
8205
8388
|
return true;
|
|
8206
8389
|
}
|
|
@@ -8217,6 +8400,7 @@ var _config2;
|
|
|
8217
8400
|
var init_agentSwarmsEnabled = __esm({
|
|
8218
8401
|
"src/swarm/agentSwarmsEnabled.ts"() {
|
|
8219
8402
|
"use strict";
|
|
8403
|
+
init_features();
|
|
8220
8404
|
_config2 = null;
|
|
8221
8405
|
}
|
|
8222
8406
|
});
|
|
@@ -9802,8 +9986,8 @@ var init_web_fetch = __esm({
|
|
|
9802
9986
|
});
|
|
9803
9987
|
|
|
9804
9988
|
// src/cron/tasks.ts
|
|
9805
|
-
import
|
|
9806
|
-
import
|
|
9989
|
+
import fs39 from "node:fs";
|
|
9990
|
+
import path41 from "node:path";
|
|
9807
9991
|
import crypto5 from "node:crypto";
|
|
9808
9992
|
function getStorageDir() {
|
|
9809
9993
|
return storageDir;
|
|
@@ -9811,14 +9995,14 @@ function getStorageDir() {
|
|
|
9811
9995
|
async function withFileLock(lockPath2, fn) {
|
|
9812
9996
|
for (let attempt = 0; attempt < LOCK_RETRY_COUNT; attempt++) {
|
|
9813
9997
|
try {
|
|
9814
|
-
|
|
9998
|
+
fs39.mkdirSync(lockPath2, { recursive: false });
|
|
9815
9999
|
break;
|
|
9816
10000
|
} catch (err) {
|
|
9817
10001
|
if (err.code !== "EEXIST") throw err;
|
|
9818
10002
|
try {
|
|
9819
|
-
const stat4 =
|
|
10003
|
+
const stat4 = fs39.statSync(lockPath2);
|
|
9820
10004
|
if (Date.now() - stat4.mtimeMs > LOCK_STALE_THRESHOLD_MS) {
|
|
9821
|
-
|
|
10005
|
+
fs39.rmSync(lockPath2, { recursive: true, force: true });
|
|
9822
10006
|
continue;
|
|
9823
10007
|
}
|
|
9824
10008
|
} catch {
|
|
@@ -9834,22 +10018,22 @@ async function withFileLock(lockPath2, fn) {
|
|
|
9834
10018
|
return fn();
|
|
9835
10019
|
} finally {
|
|
9836
10020
|
try {
|
|
9837
|
-
|
|
10021
|
+
fs39.rmSync(lockPath2, { recursive: true, force: true });
|
|
9838
10022
|
} catch {
|
|
9839
10023
|
}
|
|
9840
10024
|
}
|
|
9841
10025
|
}
|
|
9842
10026
|
function atomicWriteJSON(filePath, data) {
|
|
9843
10027
|
const tmpPath = filePath + ".tmp";
|
|
9844
|
-
|
|
9845
|
-
|
|
10028
|
+
fs39.writeFileSync(tmpPath, JSON.stringify(data, null, 2), "utf-8");
|
|
10029
|
+
fs39.renameSync(tmpPath, filePath);
|
|
9846
10030
|
}
|
|
9847
10031
|
function readTasksFromDisk() {
|
|
9848
|
-
if (!tasksFilePath || !
|
|
10032
|
+
if (!tasksFilePath || !fs39.existsSync(tasksFilePath)) {
|
|
9849
10033
|
return [];
|
|
9850
10034
|
}
|
|
9851
10035
|
try {
|
|
9852
|
-
const raw =
|
|
10036
|
+
const raw = fs39.readFileSync(tasksFilePath, "utf-8");
|
|
9853
10037
|
const store = JSON.parse(raw);
|
|
9854
10038
|
return store.tasks ?? [];
|
|
9855
10039
|
} catch (err) {
|
|
@@ -9858,7 +10042,7 @@ function readTasksFromDisk() {
|
|
|
9858
10042
|
}
|
|
9859
10043
|
}
|
|
9860
10044
|
async function writeTasksToDisk(tasks2) {
|
|
9861
|
-
const lockPath2 =
|
|
10045
|
+
const lockPath2 = path41.join(storageDir, "tasks.json.lock");
|
|
9862
10046
|
await withFileLock(lockPath2, () => {
|
|
9863
10047
|
const store = {
|
|
9864
10048
|
version: 1,
|
|
@@ -9870,9 +10054,9 @@ async function writeTasksToDisk(tasks2) {
|
|
|
9870
10054
|
}
|
|
9871
10055
|
function initTaskStore(dir) {
|
|
9872
10056
|
storageDir = dir;
|
|
9873
|
-
tasksFilePath =
|
|
9874
|
-
if (!
|
|
9875
|
-
|
|
10057
|
+
tasksFilePath = path41.join(dir, "tasks.json");
|
|
10058
|
+
if (!fs39.existsSync(dir)) {
|
|
10059
|
+
fs39.mkdirSync(dir, { recursive: true });
|
|
9876
10060
|
}
|
|
9877
10061
|
const tasks2 = readTasksFromDisk();
|
|
9878
10062
|
console.log(`[cron] Task store initialized: ${dir} (${tasks2.length} tasks loaded)`);
|
|
@@ -10121,12 +10305,12 @@ async function executeAndDeliver(task, now, deps) {
|
|
|
10121
10305
|
if (promptText.startsWith("@")) {
|
|
10122
10306
|
let filePath = promptText.slice(1).trim();
|
|
10123
10307
|
try {
|
|
10124
|
-
const
|
|
10125
|
-
const
|
|
10126
|
-
if (!
|
|
10127
|
-
filePath =
|
|
10308
|
+
const fs43 = await import("fs");
|
|
10309
|
+
const path46 = await import("path");
|
|
10310
|
+
if (!path46.isAbsolute(filePath)) {
|
|
10311
|
+
filePath = path46.join(deps.sessions["config"].stateDir, filePath);
|
|
10128
10312
|
}
|
|
10129
|
-
promptText =
|
|
10313
|
+
promptText = fs43.readFileSync(filePath, "utf-8");
|
|
10130
10314
|
console.log(`[cron] Loaded prompt from ${filePath} (${promptText.length} chars)`);
|
|
10131
10315
|
} catch (err) {
|
|
10132
10316
|
throw new Error(`Prompt file not found: ${filePath}: ${err.message}`);
|
|
@@ -10153,16 +10337,16 @@ async function executeAndDeliver(task, now, deps) {
|
|
|
10153
10337
|
let finalResult = result;
|
|
10154
10338
|
if (task.postProcess) {
|
|
10155
10339
|
try {
|
|
10156
|
-
const
|
|
10157
|
-
const
|
|
10340
|
+
const path46 = await import("path");
|
|
10341
|
+
const fs43 = await import("fs");
|
|
10158
10342
|
let scriptPath = task.postProcess;
|
|
10159
|
-
if (!
|
|
10160
|
-
scriptPath =
|
|
10343
|
+
if (!path46.isAbsolute(scriptPath)) {
|
|
10344
|
+
scriptPath = path46.join(deps.sessions["config"].stateDir, scriptPath);
|
|
10161
10345
|
}
|
|
10162
|
-
const resultsDirTmp =
|
|
10163
|
-
|
|
10164
|
-
const inputFile =
|
|
10165
|
-
|
|
10346
|
+
const resultsDirTmp = path46.join(getStorageDir(), "results");
|
|
10347
|
+
fs43.mkdirSync(resultsDirTmp, { recursive: true });
|
|
10348
|
+
const inputFile = path46.join(resultsDirTmp, `${task.id}.input.txt`);
|
|
10349
|
+
fs43.writeFileSync(inputFile, result, "utf-8");
|
|
10166
10350
|
const { execFile: execFile3 } = await import("child_process");
|
|
10167
10351
|
await new Promise((resolve10) => {
|
|
10168
10352
|
execFile3("python", [scriptPath, "main", "--file", inputFile], {
|
|
@@ -10189,12 +10373,12 @@ async function executeAndDeliver(task, now, deps) {
|
|
|
10189
10373
|
}
|
|
10190
10374
|
}
|
|
10191
10375
|
try {
|
|
10192
|
-
const
|
|
10193
|
-
const
|
|
10194
|
-
const resultsDir =
|
|
10195
|
-
|
|
10196
|
-
const resultFile =
|
|
10197
|
-
|
|
10376
|
+
const fs43 = await import("fs");
|
|
10377
|
+
const path46 = await import("path");
|
|
10378
|
+
const resultsDir = path46.join(getStorageDir(), "results");
|
|
10379
|
+
fs43.mkdirSync(resultsDir, { recursive: true });
|
|
10380
|
+
const resultFile = path46.join(resultsDir, `${task.id}.json`);
|
|
10381
|
+
fs43.writeFileSync(resultFile, JSON.stringify({
|
|
10198
10382
|
taskId: task.id,
|
|
10199
10383
|
description: task.description,
|
|
10200
10384
|
executedAt: now.toISOString(),
|
|
@@ -10440,30 +10624,30 @@ function registerCronTools() {
|
|
|
10440
10624
|
}
|
|
10441
10625
|
},
|
|
10442
10626
|
handler: async (args2) => {
|
|
10443
|
-
const
|
|
10444
|
-
const
|
|
10445
|
-
const resultsDir =
|
|
10446
|
-
if (!
|
|
10627
|
+
const fs43 = await import("fs");
|
|
10628
|
+
const path46 = await import("path");
|
|
10629
|
+
const resultsDir = path46.join(getStorageDir(), "results");
|
|
10630
|
+
if (!fs43.existsSync(resultsDir)) {
|
|
10447
10631
|
return { content: "\u6682\u65E0cron\u6267\u884C\u7ED3\u679C" };
|
|
10448
10632
|
}
|
|
10449
10633
|
if (args2.task_id) {
|
|
10450
|
-
const file =
|
|
10451
|
-
if (!
|
|
10634
|
+
const file = path46.join(resultsDir, `${args2.task_id}.json`);
|
|
10635
|
+
if (!fs43.existsSync(file)) {
|
|
10452
10636
|
return { content: `\u4EFB\u52A1 ${args2.task_id} \u6682\u65E0\u6267\u884C\u7ED3\u679C`, isError: true };
|
|
10453
10637
|
}
|
|
10454
|
-
const data = JSON.parse(
|
|
10638
|
+
const data = JSON.parse(fs43.readFileSync(file, "utf-8"));
|
|
10455
10639
|
return { content: `## ${data.description}
|
|
10456
10640
|
\u6267\u884C\u65F6\u95F4: ${data.executedAt}
|
|
10457
10641
|
\u7B2C${data.runCount}\u6B21\u6267\u884C
|
|
10458
10642
|
|
|
10459
10643
|
${data.result}` };
|
|
10460
10644
|
}
|
|
10461
|
-
const files =
|
|
10645
|
+
const files = fs43.readdirSync(resultsDir).filter((f) => f.endsWith(".json"));
|
|
10462
10646
|
if (files.length === 0) {
|
|
10463
10647
|
return { content: "\u6682\u65E0cron\u6267\u884C\u7ED3\u679C" };
|
|
10464
10648
|
}
|
|
10465
10649
|
const results = files.map((f) => {
|
|
10466
|
-
const data = JSON.parse(
|
|
10650
|
+
const data = JSON.parse(fs43.readFileSync(path46.join(resultsDir, f), "utf-8"));
|
|
10467
10651
|
return `### ${data.description} (${data.taskId.slice(0, 8)})
|
|
10468
10652
|
\u6267\u884C: ${data.executedAt} | \u7B2C${data.runCount}\u6B21
|
|
10469
10653
|
${data.result.slice(0, 500)}${data.result.length > 500 ? "..." : ""}`;
|
|
@@ -10667,7 +10851,7 @@ async function setupFeatures(features, licensedFeatures) {
|
|
|
10667
10851
|
}
|
|
10668
10852
|
}
|
|
10669
10853
|
var builtInFeatures, customFeatures;
|
|
10670
|
-
var
|
|
10854
|
+
var init_features2 = __esm({
|
|
10671
10855
|
"src/tools/features.ts"() {
|
|
10672
10856
|
"use strict";
|
|
10673
10857
|
builtInFeatures = [
|
|
@@ -10845,8 +11029,8 @@ __export(license_exports, {
|
|
|
10845
11029
|
resetLicenseCache: () => resetLicenseCache
|
|
10846
11030
|
});
|
|
10847
11031
|
import * as crypto6 from "node:crypto";
|
|
10848
|
-
import * as
|
|
10849
|
-
import * as
|
|
11032
|
+
import * as fs40 from "node:fs";
|
|
11033
|
+
import * as path42 from "node:path";
|
|
10850
11034
|
function loadLicense(stateDir, devMode) {
|
|
10851
11035
|
if (_licenseChecked) return _cachedLicense;
|
|
10852
11036
|
_licenseChecked = true;
|
|
@@ -10859,13 +11043,13 @@ function loadLicense(stateDir, devMode) {
|
|
|
10859
11043
|
_cachedLicense = allActive;
|
|
10860
11044
|
return allActive;
|
|
10861
11045
|
}
|
|
10862
|
-
const licensePath =
|
|
10863
|
-
if (!
|
|
11046
|
+
const licensePath = path42.join(stateDir, "license.json");
|
|
11047
|
+
if (!fs40.existsSync(licensePath)) {
|
|
10864
11048
|
console.log("[license] No license.json found, running basic engine only");
|
|
10865
11049
|
return null;
|
|
10866
11050
|
}
|
|
10867
11051
|
try {
|
|
10868
|
-
const raw =
|
|
11052
|
+
const raw = fs40.readFileSync(licensePath, "utf-8");
|
|
10869
11053
|
const license = JSON.parse(raw);
|
|
10870
11054
|
const { signature, ...payload } = license;
|
|
10871
11055
|
if (!signature) {
|
|
@@ -10915,12 +11099,12 @@ function isFeatureLicensed(featureId) {
|
|
|
10915
11099
|
return f?.active === true;
|
|
10916
11100
|
}
|
|
10917
11101
|
function getLicenseStatus(stateDir) {
|
|
10918
|
-
const licensePath =
|
|
10919
|
-
if (!
|
|
11102
|
+
const licensePath = path42.join(stateDir, "license.json");
|
|
11103
|
+
if (!fs40.existsSync(licensePath)) {
|
|
10920
11104
|
return { licensed: false, features: {} };
|
|
10921
11105
|
}
|
|
10922
11106
|
try {
|
|
10923
|
-
const raw =
|
|
11107
|
+
const raw = fs40.readFileSync(licensePath, "utf-8");
|
|
10924
11108
|
const license = JSON.parse(raw);
|
|
10925
11109
|
const active = loadLicense(stateDir);
|
|
10926
11110
|
return {
|
|
@@ -10979,8 +11163,8 @@ var manager_exports = {};
|
|
|
10979
11163
|
__export(manager_exports, {
|
|
10980
11164
|
McpManager: () => McpManager
|
|
10981
11165
|
});
|
|
10982
|
-
import * as
|
|
10983
|
-
import * as
|
|
11166
|
+
import * as fs41 from "node:fs";
|
|
11167
|
+
import * as path43 from "node:path";
|
|
10984
11168
|
import { Client as Client3 } from "@modelcontextprotocol/sdk/client/index.js";
|
|
10985
11169
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
10986
11170
|
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
@@ -11013,12 +11197,12 @@ function convertInputSchema(inputSchema) {
|
|
|
11013
11197
|
}
|
|
11014
11198
|
function persistBinary(base64Data, mimeType, persistId) {
|
|
11015
11199
|
const ext = mimeType?.split("/")[1] || "bin";
|
|
11016
|
-
const dir =
|
|
11017
|
-
|
|
11018
|
-
const filepath =
|
|
11200
|
+
const dir = path43.join(process.env.ENGINE_STATE_DIR || ".engine", "mcp-blobs");
|
|
11201
|
+
fs41.mkdirSync(dir, { recursive: true });
|
|
11202
|
+
const filepath = path43.join(dir, `${persistId}.${ext}`);
|
|
11019
11203
|
try {
|
|
11020
11204
|
const buf = Buffer.from(base64Data, "base64");
|
|
11021
|
-
|
|
11205
|
+
fs41.writeFileSync(filepath, buf);
|
|
11022
11206
|
return { filepath, size: buf.length };
|
|
11023
11207
|
} catch (err) {
|
|
11024
11208
|
return { error: err.message };
|
|
@@ -11352,7 +11536,7 @@ __export(resources_exports, {
|
|
|
11352
11536
|
registerMcpResourceTools: () => registerMcpResourceTools,
|
|
11353
11537
|
unregisterMcpResourceTools: () => unregisterMcpResourceTools
|
|
11354
11538
|
});
|
|
11355
|
-
import * as
|
|
11539
|
+
import * as path44 from "node:path";
|
|
11356
11540
|
function registerMcpResourceTools(manager) {
|
|
11357
11541
|
mcpManagerRef = manager;
|
|
11358
11542
|
registry.register(listResourcesTool);
|
|
@@ -11370,7 +11554,7 @@ var init_resources = __esm({
|
|
|
11370
11554
|
"use strict";
|
|
11371
11555
|
init_registry();
|
|
11372
11556
|
MAX_RESULT_CHARS2 = 1e5;
|
|
11373
|
-
MEDIA_DIR = process.env.ENGINE_MEDIA_DIR ||
|
|
11557
|
+
MEDIA_DIR = process.env.ENGINE_MEDIA_DIR || path44.join(process.env.ENGINE_STATE_DIR || ".engine", "media", "inbound");
|
|
11374
11558
|
MCP_LIST_RESOURCES_TOOL = "mcp__list_resources";
|
|
11375
11559
|
MCP_READ_RESOURCE_TOOL = "mcp__read_resource";
|
|
11376
11560
|
mcpManagerRef = null;
|
|
@@ -11539,10 +11723,10 @@ function ensureLoaded(workspace, configIds) {
|
|
|
11539
11723
|
if (!state.blockedUserIds.includes(id)) state.blockedUserIds.push(id);
|
|
11540
11724
|
}
|
|
11541
11725
|
}
|
|
11542
|
-
const
|
|
11726
|
+
const path46 = join38(workspace, ".reply-blocklist.json");
|
|
11543
11727
|
try {
|
|
11544
|
-
if (existsSync24(
|
|
11545
|
-
const raw = readFileSync26(
|
|
11728
|
+
if (existsSync24(path46)) {
|
|
11729
|
+
const raw = readFileSync26(path46, "utf-8");
|
|
11546
11730
|
const parsed = JSON.parse(raw);
|
|
11547
11731
|
if (parsed.blockedUserIds) {
|
|
11548
11732
|
for (const id of parsed.blockedUserIds) {
|
|
@@ -11558,9 +11742,9 @@ function ensureLoaded(workspace, configIds) {
|
|
|
11558
11742
|
loaded = true;
|
|
11559
11743
|
}
|
|
11560
11744
|
function save(workspace) {
|
|
11561
|
-
const
|
|
11745
|
+
const path46 = join38(workspace, ".reply-blocklist.json");
|
|
11562
11746
|
try {
|
|
11563
|
-
writeFileSync16(
|
|
11747
|
+
writeFileSync16(path46, JSON.stringify(state, null, 2), "utf-8");
|
|
11564
11748
|
} catch (err) {
|
|
11565
11749
|
console.warn(`[reply-blocklist] Failed to save: ${err.message}`);
|
|
11566
11750
|
}
|
|
@@ -12200,6 +12384,7 @@ function loadDisplayConfig(raw) {
|
|
|
12200
12384
|
}
|
|
12201
12385
|
|
|
12202
12386
|
// src/config/loader.ts
|
|
12387
|
+
init_features();
|
|
12203
12388
|
function parseModelRef(ref) {
|
|
12204
12389
|
const idx = ref.indexOf("/");
|
|
12205
12390
|
if (idx <= 0 || idx === ref.length - 1) {
|
|
@@ -12293,6 +12478,13 @@ function loadConfig(configPath2) {
|
|
|
12293
12478
|
const stateDir = raw.stateDir || process.env.ENGINE_STATE_DIR || path.resolve(".engine");
|
|
12294
12479
|
const workspace = process.env.ENGINE_WORKSPACE || agentDefaults.workspace || path.join(stateDir, "workspace");
|
|
12295
12480
|
const mediaDir = raw.mediaDir || path.join(stateDir, "media", "inbound");
|
|
12481
|
+
if (!agentDefaults.features) agentDefaults.features = {};
|
|
12482
|
+
for (const [k, v] of Object.entries(FEATURE_DEFAULTS)) {
|
|
12483
|
+
if (agentDefaults.features[k] === void 0) {
|
|
12484
|
+
;
|
|
12485
|
+
agentDefaults.features[k] = v;
|
|
12486
|
+
}
|
|
12487
|
+
}
|
|
12296
12488
|
const profile = {
|
|
12297
12489
|
id: process.env.ENGINE_AGENT || "default",
|
|
12298
12490
|
name: agentDefaults.name || "AI Assistant",
|
|
@@ -12300,27 +12492,8 @@ function loadConfig(configPath2) {
|
|
|
12300
12492
|
workspace,
|
|
12301
12493
|
soul: agentDefaults.soul,
|
|
12302
12494
|
agents: agentDefaults.agents,
|
|
12303
|
-
features:
|
|
12304
|
-
|
|
12305
|
-
shell: true,
|
|
12306
|
-
memory: true,
|
|
12307
|
-
"topic-extract": true,
|
|
12308
|
-
"topic-recall": true,
|
|
12309
|
-
"session-memory": true,
|
|
12310
|
-
todo: true,
|
|
12311
|
-
cron: false,
|
|
12312
|
-
voice: false,
|
|
12313
|
-
selfie: false,
|
|
12314
|
-
eyes: false,
|
|
12315
|
-
calendar: false,
|
|
12316
|
-
webSearch: true,
|
|
12317
|
-
webFetch: true,
|
|
12318
|
-
agentTeams: true,
|
|
12319
|
-
processOutput: "verbose",
|
|
12320
|
-
interrupt: "command",
|
|
12321
|
-
debounceMs: 5e3,
|
|
12322
|
-
...agentDefaults.features || {}
|
|
12323
|
-
},
|
|
12495
|
+
features: agentDefaults.features,
|
|
12496
|
+
// canonical:profile.features 即 agents.defaults.features(同一对象,过渡兼容)
|
|
12324
12497
|
channels: agentDefaults.channels || [],
|
|
12325
12498
|
extensions: agentDefaults.extensions,
|
|
12326
12499
|
maxTurns: agentDefaults.maxTurns,
|
|
@@ -12429,8 +12602,8 @@ function configSummary(config2) {
|
|
|
12429
12602
|
}
|
|
12430
12603
|
|
|
12431
12604
|
// src/engine-startup.ts
|
|
12432
|
-
import * as
|
|
12433
|
-
import * as
|
|
12605
|
+
import * as path45 from "node:path";
|
|
12606
|
+
import * as fs42 from "node:fs";
|
|
12434
12607
|
import { fileURLToPath } from "node:url";
|
|
12435
12608
|
|
|
12436
12609
|
// src/pid-lock.ts
|
|
@@ -12544,6 +12717,7 @@ function getActiveQueryEngine(sessionId) {
|
|
|
12544
12717
|
|
|
12545
12718
|
// src/engine-startup.ts
|
|
12546
12719
|
init_live();
|
|
12720
|
+
init_features();
|
|
12547
12721
|
|
|
12548
12722
|
// src/services/withRetry.ts
|
|
12549
12723
|
import { ProxyAgent } from "undici";
|
|
@@ -13804,13 +13978,13 @@ var DiscordAdapter = class _DiscordAdapter {
|
|
|
13804
13978
|
}
|
|
13805
13979
|
/** 发送媒体附件(图片/文件/音频)— discord.js channel.send({ files }) */
|
|
13806
13980
|
async sendFile(target, message, attachment) {
|
|
13807
|
-
const
|
|
13808
|
-
const
|
|
13809
|
-
if (!
|
|
13981
|
+
const fs43 = await import("node:fs");
|
|
13982
|
+
const path46 = await import("node:path");
|
|
13983
|
+
if (!fs43.existsSync(attachment.path)) {
|
|
13810
13984
|
throw new Error(`File not found: ${attachment.path}`);
|
|
13811
13985
|
}
|
|
13812
|
-
const filename = attachment.filename ||
|
|
13813
|
-
const fileBuffer =
|
|
13986
|
+
const filename = attachment.filename || path46.basename(attachment.path);
|
|
13987
|
+
const fileBuffer = fs43.readFileSync(attachment.path);
|
|
13814
13988
|
const filePayload = {
|
|
13815
13989
|
attachment: fileBuffer,
|
|
13816
13990
|
name: filename
|
|
@@ -14250,13 +14424,13 @@ var FeishuAdapter = class _FeishuAdapter {
|
|
|
14250
14424
|
}
|
|
14251
14425
|
/** 发送媒体附件(图片/文件) */
|
|
14252
14426
|
async sendFile(target, message, attachment) {
|
|
14253
|
-
const
|
|
14254
|
-
const
|
|
14255
|
-
if (!
|
|
14427
|
+
const fs43 = await import("node:fs");
|
|
14428
|
+
const path46 = await import("node:path");
|
|
14429
|
+
if (!fs43.existsSync(attachment.path)) {
|
|
14256
14430
|
throw new Error(`File not found: ${attachment.path}`);
|
|
14257
14431
|
}
|
|
14258
|
-
const filename = attachment.filename ||
|
|
14259
|
-
const fileBuffer =
|
|
14432
|
+
const filename = attachment.filename || path46.basename(attachment.path);
|
|
14433
|
+
const fileBuffer = fs43.readFileSync(attachment.path);
|
|
14260
14434
|
const receiveIdType = target.startsWith("ou_") ? "open_id" : "chat_id";
|
|
14261
14435
|
const mimeType = attachment.mimeType || "application/octet-stream";
|
|
14262
14436
|
if (mimeType.startsWith("image/")) {
|
|
@@ -14533,6 +14707,7 @@ var FeishuAdapter = class _FeishuAdapter {
|
|
|
14533
14707
|
const message = data?.message;
|
|
14534
14708
|
if (!sender || !message) return;
|
|
14535
14709
|
const messageId = message.message_id || "";
|
|
14710
|
+
console.log(`[feishu] recv msg_type=${message.message_type} chat=${message.chat_type} from=${sender.sender_id?.open_id?.slice(0, 10)}`);
|
|
14536
14711
|
if (this.recentMessageIds.has(messageId)) return;
|
|
14537
14712
|
this.recentMessageIds.add(messageId);
|
|
14538
14713
|
if (this.recentMessageIds.size > 500) {
|
|
@@ -14647,6 +14822,13 @@ var FeishuAdapter = class _FeishuAdapter {
|
|
|
14647
14822
|
if (msgType === "file") {
|
|
14648
14823
|
return { text: `[\u6587\u4EF6: ${parsed.file_name || "\u672A\u77E5\u6587\u4EF6"}]`, imageKeys, fileKey: parsed.file_key, fileName: parsed.file_name };
|
|
14649
14824
|
}
|
|
14825
|
+
if (msgType === "share_location" || msgType === "location") {
|
|
14826
|
+
const name = parsed.name || "";
|
|
14827
|
+
const lat = parsed.latitude || "";
|
|
14828
|
+
const lng = parsed.longitude || "";
|
|
14829
|
+
const text = `[\u4F4D\u7F6E: ${name}${lat && lng ? ` (${lat}, ${lng})` : ""}]`;
|
|
14830
|
+
return { text, imageKeys };
|
|
14831
|
+
}
|
|
14650
14832
|
if (msgType === "post") {
|
|
14651
14833
|
const lines = [];
|
|
14652
14834
|
if (Array.isArray(parsed.content)) {
|
|
@@ -17004,7 +17186,7 @@ function entryToSessionMessage(entry) {
|
|
|
17004
17186
|
if (role === "user") {
|
|
17005
17187
|
const text = extractText2(m.content);
|
|
17006
17188
|
if (text !== null) {
|
|
17007
|
-
return { role: "user", content: text, _raw: entry.raw };
|
|
17189
|
+
return { role: "user", content: text, timestamp: entry.timestamp, _raw: entry.raw };
|
|
17008
17190
|
}
|
|
17009
17191
|
return null;
|
|
17010
17192
|
} else if (role === "assistant") {
|
|
@@ -17027,6 +17209,7 @@ function entryToSessionMessage(entry) {
|
|
|
17027
17209
|
const result = {
|
|
17028
17210
|
role: "assistant",
|
|
17029
17211
|
content: textContent,
|
|
17212
|
+
timestamp: entry.timestamp,
|
|
17030
17213
|
_raw: entry.raw
|
|
17031
17214
|
};
|
|
17032
17215
|
if (toolCalls.length > 0) {
|
|
@@ -17038,6 +17221,7 @@ function entryToSessionMessage(entry) {
|
|
|
17038
17221
|
return {
|
|
17039
17222
|
role: "tool",
|
|
17040
17223
|
content: text || "",
|
|
17224
|
+
timestamp: entry.timestamp,
|
|
17041
17225
|
tool_call_id: m.toolCallId,
|
|
17042
17226
|
_raw: entry.raw
|
|
17043
17227
|
};
|
|
@@ -17451,16 +17635,22 @@ var SessionManager = class {
|
|
|
17451
17635
|
continue;
|
|
17452
17636
|
}
|
|
17453
17637
|
if (m.role === "user") {
|
|
17454
|
-
|
|
17638
|
+
const u = msg.user(m.content);
|
|
17639
|
+
if (m.timestamp) u.timestamp = m.timestamp;
|
|
17640
|
+
allMessages.push(u);
|
|
17455
17641
|
} else if (m.role === "assistant") {
|
|
17456
17642
|
const toolCalls = m.tool_calls?.map((tc) => ({
|
|
17457
17643
|
id: tc.id,
|
|
17458
17644
|
type: "function",
|
|
17459
17645
|
function: { name: tc.function.name, arguments: tc.function.arguments }
|
|
17460
17646
|
}));
|
|
17461
|
-
|
|
17647
|
+
const a = msg.assistant(m.content, toolCalls);
|
|
17648
|
+
if (m.timestamp) a.timestamp = m.timestamp;
|
|
17649
|
+
allMessages.push(a);
|
|
17462
17650
|
} else if (m.role === "tool") {
|
|
17463
|
-
|
|
17651
|
+
const t = msg.tool(m.tool_call_id || "", m.content);
|
|
17652
|
+
if (m.timestamp) t.timestamp = m.timestamp;
|
|
17653
|
+
allMessages.push(t);
|
|
17464
17654
|
}
|
|
17465
17655
|
}
|
|
17466
17656
|
}
|
|
@@ -18185,6 +18375,8 @@ var MessageQueue = class {
|
|
|
18185
18375
|
// src/handle-query.ts
|
|
18186
18376
|
init_types();
|
|
18187
18377
|
init_attachments();
|
|
18378
|
+
init_live();
|
|
18379
|
+
init_features();
|
|
18188
18380
|
init_task_manager();
|
|
18189
18381
|
|
|
18190
18382
|
// src/prompt.ts
|
|
@@ -18965,7 +19157,7 @@ ${ep.episode || ep.summary}`,
|
|
|
18965
19157
|
init_paths();
|
|
18966
19158
|
import { readFileSync as readFileSync15, existsSync as existsSync12 } from "node:fs";
|
|
18967
19159
|
import { join as join20, resolve as resolve6 } from "node:path";
|
|
18968
|
-
import * as
|
|
19160
|
+
import * as path14 from "node:path";
|
|
18969
19161
|
var contactMap = null;
|
|
18970
19162
|
var externalChanWhitelist = null;
|
|
18971
19163
|
function loadContactMap(workspace) {
|
|
@@ -19033,18 +19225,18 @@ function truncate(s, maxLen) {
|
|
|
19033
19225
|
}
|
|
19034
19226
|
var externalChanRulesCache = null;
|
|
19035
19227
|
function loadExternalChanRules(workspace) {
|
|
19036
|
-
const
|
|
19037
|
-
if (externalChanRulesCache && externalChanRulesCache.path ===
|
|
19228
|
+
const path46 = join20(workspace, "prompts", "external-chan-rules.md");
|
|
19229
|
+
if (externalChanRulesCache && externalChanRulesCache.path === path46) return externalChanRulesCache;
|
|
19038
19230
|
let content = "";
|
|
19039
|
-
if (existsSync12(
|
|
19231
|
+
if (existsSync12(path46)) {
|
|
19040
19232
|
try {
|
|
19041
|
-
content = readFileSync15(
|
|
19233
|
+
content = readFileSync15(path46, "utf-8").trim();
|
|
19042
19234
|
} catch (e) {
|
|
19043
19235
|
console.warn(`[external-chan-rules] Failed to load: ${e}`);
|
|
19044
19236
|
}
|
|
19045
19237
|
}
|
|
19046
|
-
externalChanRulesCache = { path:
|
|
19047
|
-
console.log(`[external-chan-rules] Loaded ${content.length} chars from ${
|
|
19238
|
+
externalChanRulesCache = { path: path46, content };
|
|
19239
|
+
console.log(`[external-chan-rules] Loaded ${content.length} chars from ${path46}`);
|
|
19048
19240
|
return externalChanRulesCache;
|
|
19049
19241
|
}
|
|
19050
19242
|
function getExternalChanRulesBlock(inboundMeta, workspace) {
|
|
@@ -19072,7 +19264,7 @@ async function handleQuery(text, sessionId, channelName, cb, deps, channelTarget
|
|
|
19072
19264
|
}
|
|
19073
19265
|
async function handleQueryInner(text, sessionId, channelName, cb, deps, channelTarget, inboundMeta, skipRecall, source) {
|
|
19074
19266
|
const { engine, sessions, channelManager, workspace, providerId, providerApi, model } = deps;
|
|
19075
|
-
const
|
|
19267
|
+
const topics = liveConfig.get("topics") || {};
|
|
19076
19268
|
const preQueryAbort = new AbortController();
|
|
19077
19269
|
engine.setPreQueryAbort(preQueryAbort);
|
|
19078
19270
|
let history = sessions.getHistory(sessionId);
|
|
@@ -19081,7 +19273,7 @@ async function handleQueryInner(text, sessionId, channelName, cb, deps, channelT
|
|
|
19081
19273
|
if (restored.length > 0) {
|
|
19082
19274
|
history = restored;
|
|
19083
19275
|
sessions.setHistory(sessionId, history);
|
|
19084
|
-
if (
|
|
19276
|
+
if (topics?.restoreRecall === false) {
|
|
19085
19277
|
let stripped = 0;
|
|
19086
19278
|
for (let i = history.length - 1; i >= 0; i--) {
|
|
19087
19279
|
const m = history[i];
|
|
@@ -19271,7 +19463,7 @@ ${text}` : text });
|
|
|
19271
19463
|
// 对齐 CC: fork subagent 继承父对话历史
|
|
19272
19464
|
parentSystemPrompt: deps.systemPrompt,
|
|
19273
19465
|
// 对齐 CC: fork 共享 prompt cache
|
|
19274
|
-
features:
|
|
19466
|
+
features: liveConfig.get("agents.defaults.features"),
|
|
19275
19467
|
// engine config features(AgentTool 读 agentTool.showProgress)
|
|
19276
19468
|
channelTarget: channelTarget ?? "",
|
|
19277
19469
|
// 回复目标(Discord channel ID / user ID)
|
|
@@ -19387,13 +19579,13 @@ ${text}` : text });
|
|
|
19387
19579
|
engine.setExternalAbort(queryAbortController);
|
|
19388
19580
|
setActiveQueryEngine(sessionId, engine);
|
|
19389
19581
|
const shouldSkipRecall = skipRecall ?? channelName === "cron";
|
|
19390
|
-
if (
|
|
19582
|
+
if (getFeature("topic-recall") !== false && !shouldSkipRecall) {
|
|
19391
19583
|
try {
|
|
19392
19584
|
const memoryDir = getAutoMemPath(workspace);
|
|
19393
19585
|
const provider = deps.engine.getProvider();
|
|
19394
19586
|
const surfacedHistory = collectSurfacedMemories(history);
|
|
19395
19587
|
const cumulativePaths = sessions.getRestoredRecallPaths(sessionId);
|
|
19396
|
-
const doRestore =
|
|
19588
|
+
const doRestore = topics?.restoreRecall === true;
|
|
19397
19589
|
const surfaced = doRestore ? { paths: /* @__PURE__ */ new Set([...surfacedHistory.paths, ...cumulativePaths]) } : surfacedHistory;
|
|
19398
19590
|
console.log(`[handle-query] surfaced: history=${surfacedHistory.paths.size} cumulative=${cumulativePaths.size} merged=${surfaced.paths.size} restoreRecall=${doRestore}`);
|
|
19399
19591
|
if (doRestore) {
|
|
@@ -19432,7 +19624,7 @@ ${text}` : text });
|
|
|
19432
19624
|
console.log(`[handle-query] Memory recall starting: dir=${memoryDir} query="${(typeof text === "string" ? text : "[content blocks]").slice(0, 50)}..." alreadySurfaced=${surfaced.paths.size}`);
|
|
19433
19625
|
const textForMemory = typeof text === "string" ? text : text.filter((b) => b.type === "text").map((b) => b.text).join(" ");
|
|
19434
19626
|
const recallP = deps.recallProvider;
|
|
19435
|
-
const recallMode =
|
|
19627
|
+
const recallMode = topics?.recall?.mode || "llm";
|
|
19436
19628
|
let relevantMemories;
|
|
19437
19629
|
if (recallMode === "everos") {
|
|
19438
19630
|
const everosCfg = deps?.everosCfg;
|
|
@@ -19447,7 +19639,7 @@ ${text}` : text });
|
|
|
19447
19639
|
rerankApiKey: everosCfg.rerank?.apiKey,
|
|
19448
19640
|
rerankModel: everosCfg.rerank?.model,
|
|
19449
19641
|
rerankProvider: everosCfg.rerank?.provider,
|
|
19450
|
-
minScore:
|
|
19642
|
+
minScore: topics?.recall?.minScore
|
|
19451
19643
|
} : void 0
|
|
19452
19644
|
);
|
|
19453
19645
|
} else if (recallMode === "vector") {
|
|
@@ -19465,7 +19657,7 @@ ${text}` : text });
|
|
|
19465
19657
|
queryAbortController.signal,
|
|
19466
19658
|
surfaced.paths,
|
|
19467
19659
|
recallP?.disableThinking,
|
|
19468
|
-
|
|
19660
|
+
topics?.maxScanFiles
|
|
19469
19661
|
);
|
|
19470
19662
|
}
|
|
19471
19663
|
console.log(`[handle-query] Memory recall result: ${relevantMemories.length} memories found: ${relevantMemories.map((m) => m.path.split(/[/\\]/).pop()).join(", ")}`);
|
|
@@ -19649,7 +19841,7 @@ ${text}` : text });
|
|
|
19649
19841
|
}
|
|
19650
19842
|
}
|
|
19651
19843
|
sessions.setHistory(sessionId, history);
|
|
19652
|
-
if (
|
|
19844
|
+
if (getFeature("topic-extract") === true && sessionId === deps.sessions.getSessionId("scope:main")) {
|
|
19653
19845
|
try {
|
|
19654
19846
|
const { createMemoryExtractor: createMemoryExtractor2 } = await Promise.resolve().then(() => (init_extractMemories(), extractMemories_exports));
|
|
19655
19847
|
const extractor = createMemoryExtractor2(workspace, true);
|
|
@@ -19664,6 +19856,15 @@ ${text}` : text });
|
|
|
19664
19856
|
console.warn(`[handle-query] Memory extraction init failed: ${err.message}`);
|
|
19665
19857
|
}
|
|
19666
19858
|
}
|
|
19859
|
+
if (liveConfig.get("everos.enabled") === true && sessionId === deps.sessions.getSessionId("scope:main")) {
|
|
19860
|
+
try {
|
|
19861
|
+
const { pushConversation: pushConversation2 } = await Promise.resolve().then(() => (init_ingest(), ingest_exports));
|
|
19862
|
+
pushConversation2(messages, sessionId, workspace).catch(() => {
|
|
19863
|
+
});
|
|
19864
|
+
} catch (e) {
|
|
19865
|
+
console.warn(`[handle-query] everos push init failed: ${e?.message ?? e}`);
|
|
19866
|
+
}
|
|
19867
|
+
}
|
|
19667
19868
|
try {
|
|
19668
19869
|
const { isSessionMemoryEnabled: isSessionMemoryEnabled2, shouldExtractMemory: shouldExtractMemory2, extractSessionMemory: extractSessionMemory2 } = await Promise.resolve().then(() => (init_sessionMemory(), sessionMemory_exports));
|
|
19669
19870
|
if (isSessionMemoryEnabled2()) {
|
|
@@ -19710,7 +19911,7 @@ stack: ${err.stack ?? "(none)"}`);
|
|
|
19710
19911
|
}
|
|
19711
19912
|
} catch (err) {
|
|
19712
19913
|
try {
|
|
19713
|
-
(await import("node:fs")).appendFileSync(join20(process.env.ENGINE7_STATE_DIR || process.env.OPENCLAW_STATE_DIR ||
|
|
19914
|
+
(await import("node:fs")).appendFileSync(join20(process.env.ENGINE7_STATE_DIR || process.env.OPENCLAW_STATE_DIR || path14.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7"), "logs", "autoDream-debug.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] [handle-query] autoDream trigger TRY-CATCH: ${err.message}
|
|
19714
19915
|
stack: ${err.stack ?? "(none)"}
|
|
19715
19916
|
`);
|
|
19716
19917
|
} catch {
|
|
@@ -19909,17 +20110,17 @@ var MessageDispatcher = class {
|
|
|
19909
20110
|
};
|
|
19910
20111
|
|
|
19911
20112
|
// src/cli-startup.ts
|
|
19912
|
-
import * as
|
|
19913
|
-
import * as
|
|
20113
|
+
import * as path15 from "node:path";
|
|
20114
|
+
import * as fs14 from "node:fs";
|
|
19914
20115
|
import * as readline2 from "node:readline";
|
|
19915
20116
|
function getDailyLogPath(stateDir) {
|
|
19916
20117
|
const dateStr = (/* @__PURE__ */ new Date()).toLocaleDateString("sv-SE", { timeZone: "Asia/Shanghai" });
|
|
19917
|
-
return
|
|
20118
|
+
return path15.join(stateDir, "logs", `engine-${dateStr}.log`);
|
|
19918
20119
|
}
|
|
19919
20120
|
function setupFileLogging(stateDir) {
|
|
19920
20121
|
const LOG_PATH = getDailyLogPath(stateDir);
|
|
19921
|
-
|
|
19922
|
-
const logStream =
|
|
20122
|
+
fs14.mkdirSync(path15.join(stateDir, "logs"), { recursive: true });
|
|
20123
|
+
const logStream = fs14.createWriteStream(LOG_PATH, { flags: "a" });
|
|
19923
20124
|
logStream.on("error", (err) => console.error(`[log] Write error: ${err.message}`));
|
|
19924
20125
|
function ts() {
|
|
19925
20126
|
return (/* @__PURE__ */ new Date()).toLocaleString("sv-SE", { timeZone: "Asia/Shanghai", hour12: false }) + "." + String(Date.now() % 1e3).padStart(3, "0");
|
|
@@ -20009,8 +20210,8 @@ function startCliLoop(deps, cliConfig, channelManager, dispatcher) {
|
|
|
20009
20210
|
}
|
|
20010
20211
|
|
|
20011
20212
|
// src/session/session-history.ts
|
|
20012
|
-
import
|
|
20013
|
-
import
|
|
20213
|
+
import fs15 from "node:fs";
|
|
20214
|
+
import path16 from "node:path";
|
|
20014
20215
|
var BEIJING_OFFSET_MS = 8 * 36e5;
|
|
20015
20216
|
var INJECTED_CONTENT_PATTERNS = [
|
|
20016
20217
|
/【定时心跳】/,
|
|
@@ -20064,10 +20265,10 @@ function scopeMainJsonlPaths(sessions) {
|
|
|
20064
20265
|
let latestArchive = null;
|
|
20065
20266
|
if (current) {
|
|
20066
20267
|
try {
|
|
20067
|
-
const dir =
|
|
20068
|
-
const base =
|
|
20069
|
-
const archives =
|
|
20070
|
-
if (archives.length > 0) latestArchive =
|
|
20268
|
+
const dir = path16.dirname(current);
|
|
20269
|
+
const base = path16.basename(current);
|
|
20270
|
+
const archives = fs15.readdirSync(dir).filter((f) => f.startsWith(base + ".archived.")).sort();
|
|
20271
|
+
if (archives.length > 0) latestArchive = path16.join(dir, archives[archives.length - 1]);
|
|
20071
20272
|
} catch {
|
|
20072
20273
|
}
|
|
20073
20274
|
}
|
|
@@ -20085,7 +20286,7 @@ function extractText3(content) {
|
|
|
20085
20286
|
function findLastRealUserMsg(jsonlPath) {
|
|
20086
20287
|
let lines;
|
|
20087
20288
|
try {
|
|
20088
|
-
lines =
|
|
20289
|
+
lines = fs15.readFileSync(jsonlPath, "utf-8").split("\n");
|
|
20089
20290
|
} catch {
|
|
20090
20291
|
return null;
|
|
20091
20292
|
}
|
|
@@ -20129,7 +20330,7 @@ function lastUserMsg(sessions) {
|
|
|
20129
20330
|
function recentMessages(sessions, hours = 12, limit = 60) {
|
|
20130
20331
|
const jsonlPath = resolveScopeMainJsonl(sessions);
|
|
20131
20332
|
if (!jsonlPath) return [];
|
|
20132
|
-
const lines =
|
|
20333
|
+
const lines = fs15.readFileSync(jsonlPath, "utf-8").split("\n");
|
|
20133
20334
|
const entries = parseJsonlEntries(lines);
|
|
20134
20335
|
const nowMs = Date.now();
|
|
20135
20336
|
const cutoffMs = nowMs - hours * 36e5;
|
|
@@ -20325,8 +20526,8 @@ ${basePrompt}`;
|
|
|
20325
20526
|
};
|
|
20326
20527
|
|
|
20327
20528
|
// src/nudge/plugin.ts
|
|
20328
|
-
import
|
|
20329
|
-
import
|
|
20529
|
+
import fs18 from "node:fs";
|
|
20530
|
+
import path19 from "node:path";
|
|
20330
20531
|
|
|
20331
20532
|
// src/nudge/judge.ts
|
|
20332
20533
|
function shouldNudge(task, taskState, cfg) {
|
|
@@ -20494,14 +20695,14 @@ function formatDuration2(ms) {
|
|
|
20494
20695
|
}
|
|
20495
20696
|
|
|
20496
20697
|
// src/nudge/session-state-reader.ts
|
|
20497
|
-
import
|
|
20498
|
-
import
|
|
20698
|
+
import fs16 from "node:fs";
|
|
20699
|
+
import path17 from "node:path";
|
|
20499
20700
|
function parseSessionStateFull(workspace, sessionStateFile) {
|
|
20500
20701
|
const stateFile = sessionStateFile || "SESSION-STATE.md";
|
|
20501
|
-
const statePath =
|
|
20702
|
+
const statePath = path17.isAbsolute(stateFile) ? stateFile : path17.join(workspace, stateFile);
|
|
20502
20703
|
let content;
|
|
20503
20704
|
try {
|
|
20504
|
-
content =
|
|
20705
|
+
content = fs16.readFileSync(statePath, "utf-8");
|
|
20505
20706
|
} catch {
|
|
20506
20707
|
console.warn(`[nudge] SESSION-STATE not found at ${statePath}`);
|
|
20507
20708
|
return { activeTasks: [], orphanPendings: [] };
|
|
@@ -20553,13 +20754,13 @@ function taskIdFromTitle(title) {
|
|
|
20553
20754
|
|
|
20554
20755
|
// src/calendar/db.ts
|
|
20555
20756
|
import { DatabaseSync } from "node:sqlite";
|
|
20556
|
-
import * as
|
|
20557
|
-
import * as
|
|
20757
|
+
import * as path18 from "node:path";
|
|
20758
|
+
import * as fs17 from "node:fs";
|
|
20558
20759
|
var TZ_OFFSET_MS = 8 * 60 * 60 * 1e3;
|
|
20559
20760
|
function openDb(workspace) {
|
|
20560
|
-
const dir =
|
|
20561
|
-
|
|
20562
|
-
const dbPath =
|
|
20761
|
+
const dir = path18.join(workspace, ".calendar");
|
|
20762
|
+
fs17.mkdirSync(dir, { recursive: true });
|
|
20763
|
+
const dbPath = path18.join(dir, "calendar.db");
|
|
20563
20764
|
const db = new DatabaseSync(dbPath);
|
|
20564
20765
|
db.exec("PRAGMA journal_mode=WAL");
|
|
20565
20766
|
db.exec(`CREATE TABLE IF NOT EXISTS events (
|
|
@@ -20648,9 +20849,9 @@ var NudgePlugin = class {
|
|
|
20648
20849
|
provider;
|
|
20649
20850
|
model;
|
|
20650
20851
|
loadPrompt(workspace, promptFile) {
|
|
20651
|
-
const promptPath = promptFile ?
|
|
20852
|
+
const promptPath = promptFile ? path19.isAbsolute(promptFile) ? promptFile : path19.join(workspace, promptFile) : path19.join(workspace, "prompts", "nudge-prompt.md");
|
|
20652
20853
|
try {
|
|
20653
|
-
const content =
|
|
20854
|
+
const content = fs18.readFileSync(promptPath, "utf-8").trim();
|
|
20654
20855
|
if (content) {
|
|
20655
20856
|
console.log(`[nudge] Loaded custom prompt from ${promptPath}`);
|
|
20656
20857
|
return content;
|
|
@@ -20681,6 +20882,18 @@ var NudgePlugin = class {
|
|
|
20681
20882
|
registerCallbackHook("Stop", {
|
|
20682
20883
|
type: "callback",
|
|
20683
20884
|
callback: async (input, _toolUseID, _signal) => {
|
|
20885
|
+
const mode = this.cfg.stopHookMode || "sync";
|
|
20886
|
+
if (mode === "async") {
|
|
20887
|
+
console.log("[stop-hook] async mode \u2014 firing judge in background, not blocking");
|
|
20888
|
+
this.runStopHookJudge(input, sessions).catch((err) => {
|
|
20889
|
+
if (/judge \d+ms timeout/i.test(err?.message || "")) {
|
|
20890
|
+
console.warn(`[stop-hook] async judge timed out (abandoned)`);
|
|
20891
|
+
} else {
|
|
20892
|
+
console.warn(`[stop-hook] async judge error: ${err.message}`);
|
|
20893
|
+
}
|
|
20894
|
+
});
|
|
20895
|
+
return { outcome: { outcome: "success" } };
|
|
20896
|
+
}
|
|
20684
20897
|
const timeoutMs = this.cfg.timeoutMs ?? 15e3;
|
|
20685
20898
|
let judgeTimer;
|
|
20686
20899
|
const judgeTimeout = new Promise((_, reject) => {
|
|
@@ -20703,7 +20916,7 @@ var NudgePlugin = class {
|
|
|
20703
20916
|
return { outcome: { outcome: "success" } };
|
|
20704
20917
|
}
|
|
20705
20918
|
});
|
|
20706
|
-
console.log(
|
|
20919
|
+
console.log(`[stop-hook] Registered Stop callback hook (mode=${this.cfg.stopHookMode || "sync"}, LLM semantic judge + 5min wake-up)`);
|
|
20707
20920
|
}
|
|
20708
20921
|
/** Judge 完整逻辑(被 callback 用 Promise.race 调用,可被 timeout 截断) */
|
|
20709
20922
|
async runStopHookJudge(input, sessions) {
|
|
@@ -20738,6 +20951,12 @@ var NudgePlugin = class {
|
|
|
20738
20951
|
if (!lastMsg) {
|
|
20739
20952
|
return;
|
|
20740
20953
|
}
|
|
20954
|
+
const currentHour = (/* @__PURE__ */ new Date()).getHours();
|
|
20955
|
+
const isNightTime = currentHour >= 22 || currentHour < 8;
|
|
20956
|
+
if (isNightTime) {
|
|
20957
|
+
console.log(`[stop-hook] night time (${currentHour}:xx), skipping needLanding/waiting judge`);
|
|
20958
|
+
return;
|
|
20959
|
+
}
|
|
20741
20960
|
let contextStr = "";
|
|
20742
20961
|
try {
|
|
20743
20962
|
const recent = recentMessages(sessions, 0.5, 6);
|
|
@@ -20860,18 +21079,18 @@ var NudgePlugin = class {
|
|
|
20860
21079
|
if (!isWaiting) {
|
|
20861
21080
|
return;
|
|
20862
21081
|
}
|
|
20863
|
-
const nudgeDir =
|
|
20864
|
-
const notifPath =
|
|
21082
|
+
const nudgeDir = path19.join(this.workspace, ".nudge");
|
|
21083
|
+
const notifPath = path19.join(nudgeDir, "stop-hook-notifications.json");
|
|
20865
21084
|
try {
|
|
20866
|
-
if (!
|
|
21085
|
+
if (!fs18.existsSync(nudgeDir)) fs18.mkdirSync(nudgeDir, { recursive: true });
|
|
20867
21086
|
let notifs = [];
|
|
20868
|
-
if (
|
|
20869
|
-
notifs = JSON.parse(
|
|
21087
|
+
if (fs18.existsSync(notifPath)) {
|
|
21088
|
+
notifs = JSON.parse(fs18.readFileSync(notifPath, "utf-8"));
|
|
20870
21089
|
const now = Date.now();
|
|
20871
21090
|
const dup = notifs.find((n) => !n.notified && n.description === (waitDesc || lastMsg.slice(0, 200)));
|
|
20872
21091
|
if (dup) {
|
|
20873
21092
|
dup.wakeAt = new Date(now + 5 * 6e4).toISOString();
|
|
20874
|
-
|
|
21093
|
+
fs18.writeFileSync(notifPath, JSON.stringify(notifs, null, 2));
|
|
20875
21094
|
console.log(`[stop-hook] Duplicate wait (same desc, not fired yet), refreshed wakeAt: ${dup.id}`);
|
|
20876
21095
|
return;
|
|
20877
21096
|
}
|
|
@@ -20889,7 +21108,7 @@ var NudgePlugin = class {
|
|
|
20889
21108
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
20890
21109
|
wakeAt
|
|
20891
21110
|
});
|
|
20892
|
-
|
|
21111
|
+
fs18.writeFileSync(notifPath, JSON.stringify(notifs, null, 2));
|
|
20893
21112
|
console.log(`[stop-hook] Registered wake-up ${notifId} at ${wakeAt} (sessionId=${sessionId}): ${waitDesc}`);
|
|
20894
21113
|
} catch (e) {
|
|
20895
21114
|
console.warn(`[stop-hook] Failed to register: ${e.message}`);
|
|
@@ -20926,10 +21145,10 @@ var NudgePlugin = class {
|
|
|
20926
21145
|
* 已 notified 的不会再触发,等 agent 回复 "<id> 过期了" 由 cleanup 删。
|
|
20927
21146
|
*/
|
|
20928
21147
|
collectDueStopHookNotifications() {
|
|
20929
|
-
const notifPath =
|
|
21148
|
+
const notifPath = path19.join(this.workspace, ".nudge", "stop-hook-notifications.json");
|
|
20930
21149
|
try {
|
|
20931
|
-
if (!
|
|
20932
|
-
const notifs = JSON.parse(
|
|
21150
|
+
if (!fs18.existsSync(notifPath)) return null;
|
|
21151
|
+
const notifs = JSON.parse(fs18.readFileSync(notifPath, "utf-8"));
|
|
20933
21152
|
if (notifs.length === 0) return null;
|
|
20934
21153
|
const now = Date.now();
|
|
20935
21154
|
const due = notifs.filter((n) => new Date(n.wakeAt).getTime() <= now && !n.notified);
|
|
@@ -20965,18 +21184,18 @@ ${items}
|
|
|
20965
21184
|
}
|
|
20966
21185
|
/** 按 id 删除条目(stop-hook 实时清理用;正常删除路径,agent 回复即删) */
|
|
20967
21186
|
removeNotificationsById(ids) {
|
|
20968
|
-
const notifPath =
|
|
21187
|
+
const notifPath = path19.join(this.workspace, ".nudge", "stop-hook-notifications.json");
|
|
20969
21188
|
try {
|
|
20970
|
-
if (!
|
|
20971
|
-
const notifs = JSON.parse(
|
|
21189
|
+
if (!fs18.existsSync(notifPath)) return;
|
|
21190
|
+
const notifs = JSON.parse(fs18.readFileSync(notifPath, "utf-8"));
|
|
20972
21191
|
const idSet = new Set(ids);
|
|
20973
21192
|
const remaining = notifs.filter((n) => !idSet.has(n.id));
|
|
20974
21193
|
const removed = notifs.length - remaining.length;
|
|
20975
21194
|
if (removed === 0) return;
|
|
20976
21195
|
if (remaining.length > 0) {
|
|
20977
|
-
|
|
21196
|
+
fs18.writeFileSync(notifPath, JSON.stringify(remaining, null, 2));
|
|
20978
21197
|
} else {
|
|
20979
|
-
|
|
21198
|
+
fs18.unlinkSync(notifPath);
|
|
20980
21199
|
}
|
|
20981
21200
|
console.log(`[stop-hook] Cleaned ${removed} notification(s) from reply: ${ids.join(", ")}`);
|
|
20982
21201
|
} catch (e) {
|
|
@@ -20985,13 +21204,13 @@ ${items}
|
|
|
20985
21204
|
}
|
|
20986
21205
|
/** 投递成功后标记 notified(防重复触发);不删除——删除只走 agent 回复 "<id> 过期了" */
|
|
20987
21206
|
markNotified(ids) {
|
|
20988
|
-
const notifPath =
|
|
21207
|
+
const notifPath = path19.join(this.workspace, ".nudge", "stop-hook-notifications.json");
|
|
20989
21208
|
try {
|
|
20990
|
-
if (!
|
|
20991
|
-
const notifs = JSON.parse(
|
|
21209
|
+
if (!fs18.existsSync(notifPath)) return;
|
|
21210
|
+
const notifs = JSON.parse(fs18.readFileSync(notifPath, "utf-8"));
|
|
20992
21211
|
const idSet = new Set(ids);
|
|
20993
21212
|
const updated = notifs.map((n) => idSet.has(n.id) ? { ...n, notified: true } : n);
|
|
20994
|
-
|
|
21213
|
+
fs18.writeFileSync(notifPath, JSON.stringify(updated, null, 2));
|
|
20995
21214
|
} catch (e) {
|
|
20996
21215
|
console.warn(`[nudge] markNotified error: ${e.message}`);
|
|
20997
21216
|
}
|
|
@@ -21008,9 +21227,9 @@ ${items}
|
|
|
21008
21227
|
*/
|
|
21009
21228
|
cleanupStaleNotificationsFromMessages(sessions) {
|
|
21010
21229
|
try {
|
|
21011
|
-
const notifPath =
|
|
21012
|
-
if (!
|
|
21013
|
-
const notifs = JSON.parse(
|
|
21230
|
+
const notifPath = path19.join(this.workspace, ".nudge", "stop-hook-notifications.json");
|
|
21231
|
+
if (!fs18.existsSync(notifPath)) return;
|
|
21232
|
+
const notifs = JSON.parse(fs18.readFileSync(notifPath, "utf-8"));
|
|
21014
21233
|
if (notifs.length === 0) return;
|
|
21015
21234
|
const expiredIds = this.findExpiredReplyIds(sessions, notifs);
|
|
21016
21235
|
const ttlMs = (this.cfg.cleanupTtlHours || 24) * 36e5;
|
|
@@ -21022,9 +21241,9 @@ ${items}
|
|
|
21022
21241
|
if (removeIds.size === 0) return;
|
|
21023
21242
|
const remaining = notifs.filter((n) => !removeIds.has(n.id));
|
|
21024
21243
|
if (remaining.length > 0) {
|
|
21025
|
-
|
|
21244
|
+
fs18.writeFileSync(notifPath, JSON.stringify(remaining, null, 2));
|
|
21026
21245
|
} else {
|
|
21027
|
-
|
|
21246
|
+
fs18.unlinkSync(notifPath);
|
|
21028
21247
|
}
|
|
21029
21248
|
if (expiredIds.size > 0) {
|
|
21030
21249
|
console.log(`[nudge] Cleaned ${expiredIds.size} notification(s) by reply: ${[...expiredIds].join(", ")}`);
|
|
@@ -21049,10 +21268,10 @@ ${items}
|
|
|
21049
21268
|
const oldestMs = Math.min(...notifs.map((n) => new Date(n.wakeAt).getTime()));
|
|
21050
21269
|
const { current, latestArchive } = scopeMainJsonlPaths(sessions);
|
|
21051
21270
|
for (const file of [current, latestArchive]) {
|
|
21052
|
-
if (!file || !
|
|
21271
|
+
if (!file || !fs18.existsSync(file)) continue;
|
|
21053
21272
|
let lines;
|
|
21054
21273
|
try {
|
|
21055
|
-
lines =
|
|
21274
|
+
lines = fs18.readFileSync(file, "utf-8").split("\n");
|
|
21056
21275
|
} catch (e) {
|
|
21057
21276
|
console.warn(`[nudge] findExpiredReplyIds read error on ${file}: ${e.message}`);
|
|
21058
21277
|
continue;
|
|
@@ -21309,9 +21528,9 @@ ${items}
|
|
|
21309
21528
|
// === state 持久化 ===
|
|
21310
21529
|
loadState() {
|
|
21311
21530
|
const stateFile = this.cfg.stateFile || "nudge-state.json";
|
|
21312
|
-
const statePath =
|
|
21531
|
+
const statePath = path19.isAbsolute(stateFile) ? stateFile : path19.join(this.workspace, stateFile);
|
|
21313
21532
|
try {
|
|
21314
|
-
const content =
|
|
21533
|
+
const content = fs18.readFileSync(statePath, "utf-8");
|
|
21315
21534
|
return JSON.parse(content);
|
|
21316
21535
|
} catch {
|
|
21317
21536
|
return { tasks: {} };
|
|
@@ -21319,8 +21538,8 @@ ${items}
|
|
|
21319
21538
|
}
|
|
21320
21539
|
saveState(state2) {
|
|
21321
21540
|
const stateFile = this.cfg.stateFile || "nudge-state.json";
|
|
21322
|
-
const statePath =
|
|
21323
|
-
|
|
21541
|
+
const statePath = path19.isAbsolute(stateFile) ? stateFile : path19.join(this.workspace, stateFile);
|
|
21542
|
+
fs18.writeFileSync(statePath, JSON.stringify(state2, null, 2), "utf-8");
|
|
21324
21543
|
}
|
|
21325
21544
|
newTaskState() {
|
|
21326
21545
|
return {
|
|
@@ -21498,8 +21717,8 @@ ${items}
|
|
|
21498
21717
|
};
|
|
21499
21718
|
|
|
21500
21719
|
// src/inner-voice/plugin.ts
|
|
21501
|
-
import
|
|
21502
|
-
import
|
|
21720
|
+
import fs22 from "node:fs";
|
|
21721
|
+
import path23 from "node:path";
|
|
21503
21722
|
|
|
21504
21723
|
// src/inner-voice/activity.ts
|
|
21505
21724
|
function checkActivity(sessions, activeThresholdMs) {
|
|
@@ -21538,8 +21757,8 @@ function calcHintProb(min) {
|
|
|
21538
21757
|
}
|
|
21539
21758
|
|
|
21540
21759
|
// src/inner-voice/emotional-state.ts
|
|
21541
|
-
import
|
|
21542
|
-
import
|
|
21760
|
+
import fs19 from "node:fs";
|
|
21761
|
+
import path20 from "node:path";
|
|
21543
21762
|
var NEUTRAL = 0.5;
|
|
21544
21763
|
var DECAY_RATE = 0.17;
|
|
21545
21764
|
var MAX_EVENTS = 20;
|
|
@@ -21590,7 +21809,7 @@ function initialState() {
|
|
|
21590
21809
|
return { version: 1, mood: NEUTRAL, trend: "stable", updatedAt: nowIsoBj(), events: [] };
|
|
21591
21810
|
}
|
|
21592
21811
|
async function updateEmotionalState(workspace, sessions) {
|
|
21593
|
-
const stateFile =
|
|
21812
|
+
const stateFile = path20.join(workspace, "inner-voice", "emotional-state.json");
|
|
21594
21813
|
const messages = readRecentMessages(sessions, RECENT_N);
|
|
21595
21814
|
if (messages.length === 0) {
|
|
21596
21815
|
console.log("[emotional-state] no messages");
|
|
@@ -21623,8 +21842,8 @@ async function updateEmotionalState(workspace, sessions) {
|
|
|
21623
21842
|
function readRecentMessages(sessions, n) {
|
|
21624
21843
|
const mainId = sessions.getSessionId("scope:main");
|
|
21625
21844
|
if (!mainId) return [];
|
|
21626
|
-
const file =
|
|
21627
|
-
if (!
|
|
21845
|
+
const file = path20.join(sessions.sessionsDir, `${mainId}.jsonl`);
|
|
21846
|
+
if (!fs19.existsSync(file)) return [];
|
|
21628
21847
|
const lines = readLastNLines(file, n * 4 + 20);
|
|
21629
21848
|
const entries = [];
|
|
21630
21849
|
for (const line of lines) {
|
|
@@ -21741,9 +21960,9 @@ function refreshHoursAgo(events) {
|
|
|
21741
21960
|
}
|
|
21742
21961
|
function appendMoodLog(workspace, state2, summary) {
|
|
21743
21962
|
try {
|
|
21744
|
-
const logPath =
|
|
21963
|
+
const logPath = path20.join(workspace, "mood-history.log");
|
|
21745
21964
|
const ts = formatBj(/* @__PURE__ */ new Date(), false);
|
|
21746
|
-
|
|
21965
|
+
fs19.appendFileSync(logPath, `${ts} mood=${state2.mood.toFixed(2)} trend=${state2.trend} ${summary}
|
|
21747
21966
|
`);
|
|
21748
21967
|
} catch (err) {
|
|
21749
21968
|
console.warn(`[emotional-state] mood log failed: ${err.message}`);
|
|
@@ -21751,32 +21970,32 @@ function appendMoodLog(workspace, state2, summary) {
|
|
|
21751
21970
|
}
|
|
21752
21971
|
function loadJson(file) {
|
|
21753
21972
|
try {
|
|
21754
|
-
return JSON.parse(
|
|
21973
|
+
return JSON.parse(fs19.readFileSync(file, "utf-8"));
|
|
21755
21974
|
} catch {
|
|
21756
21975
|
return null;
|
|
21757
21976
|
}
|
|
21758
21977
|
}
|
|
21759
21978
|
function saveJson(file, data) {
|
|
21760
21979
|
try {
|
|
21761
|
-
|
|
21762
|
-
|
|
21980
|
+
fs19.mkdirSync(path20.dirname(file), { recursive: true });
|
|
21981
|
+
fs19.writeFileSync(file, JSON.stringify(data, null, 2));
|
|
21763
21982
|
} catch (err) {
|
|
21764
21983
|
console.warn(`[emotional-state] save failed: ${err.message}`);
|
|
21765
21984
|
}
|
|
21766
21985
|
}
|
|
21767
21986
|
function readLastNLines(file, maxLines) {
|
|
21768
21987
|
try {
|
|
21769
|
-
const stat4 =
|
|
21988
|
+
const stat4 = fs19.statSync(file);
|
|
21770
21989
|
const tailBytes = Math.min(stat4.size, maxLines * 512);
|
|
21771
|
-
const fd =
|
|
21990
|
+
const fd = fs19.openSync(file, "r");
|
|
21772
21991
|
try {
|
|
21773
21992
|
const buf = Buffer.alloc(tailBytes);
|
|
21774
|
-
|
|
21993
|
+
fs19.readSync(fd, buf, 0, tailBytes, stat4.size - tailBytes);
|
|
21775
21994
|
const lines = buf.toString("utf-8").split("\n").filter(Boolean);
|
|
21776
21995
|
if (stat4.size > tailBytes && lines.length > 0) lines.shift();
|
|
21777
21996
|
return lines;
|
|
21778
21997
|
} finally {
|
|
21779
|
-
|
|
21998
|
+
fs19.closeSync(fd);
|
|
21780
21999
|
}
|
|
21781
22000
|
} catch {
|
|
21782
22001
|
return [];
|
|
@@ -21803,8 +22022,8 @@ function formatBj(d, withSec) {
|
|
|
21803
22022
|
}
|
|
21804
22023
|
|
|
21805
22024
|
// src/inner-voice/topics-scorer.ts
|
|
21806
|
-
import
|
|
21807
|
-
import
|
|
22025
|
+
import fs20 from "node:fs";
|
|
22026
|
+
import path21 from "node:path";
|
|
21808
22027
|
var HALF_LIFE_DAYS = 3;
|
|
21809
22028
|
var PROJECT_HALF_LIFE_DAYS = 1.5;
|
|
21810
22029
|
var COOLDOWN_HOURS = 6;
|
|
@@ -21812,8 +22031,8 @@ var MAX_CHARS = 8e3;
|
|
|
21812
22031
|
var SKIP_NAMES = /* @__PURE__ */ new Set(["MEMORY.md", "archive"]);
|
|
21813
22032
|
var SKIP_DIRS = /* @__PURE__ */ new Set(["archive"]);
|
|
21814
22033
|
function pickTopic(workspace, typeFilter, opts) {
|
|
21815
|
-
const topicsDir =
|
|
21816
|
-
const usageFile =
|
|
22034
|
+
const topicsDir = path21.join(workspace, "topics");
|
|
22035
|
+
const usageFile = path21.join(workspace, "inner-voice", "topics-usage.json");
|
|
21817
22036
|
const files = scanTopics(topicsDir, typeFilter);
|
|
21818
22037
|
if (files.length === 0) {
|
|
21819
22038
|
console.log(`[topics-scorer] no topics found (type=${typeFilter})`);
|
|
@@ -21830,7 +22049,7 @@ function pickTopic(workspace, typeFilter, opts) {
|
|
|
21830
22049
|
else type2 = "other";
|
|
21831
22050
|
let mtime;
|
|
21832
22051
|
try {
|
|
21833
|
-
mtime =
|
|
22052
|
+
mtime = fs20.statSync(fullpath).mtimeMs;
|
|
21834
22053
|
} catch {
|
|
21835
22054
|
continue;
|
|
21836
22055
|
}
|
|
@@ -21845,7 +22064,7 @@ function pickTopic(workspace, typeFilter, opts) {
|
|
|
21845
22064
|
recency: Math.round(recency * 1e3) / 1e3,
|
|
21846
22065
|
freq: Math.round(freq * 1e3) / 1e3,
|
|
21847
22066
|
type: type2,
|
|
21848
|
-
name: meta.name ||
|
|
22067
|
+
name: meta.name || path21.basename(relpath),
|
|
21849
22068
|
description: meta.description || "",
|
|
21850
22069
|
mtime
|
|
21851
22070
|
});
|
|
@@ -21865,7 +22084,7 @@ function pickTopic(workspace, typeFilter, opts) {
|
|
|
21865
22084
|
saveJson2(usageFile, usage);
|
|
21866
22085
|
let content = "";
|
|
21867
22086
|
try {
|
|
21868
|
-
const raw =
|
|
22087
|
+
const raw = fs20.readFileSync(chosen.fullpath, "utf-8");
|
|
21869
22088
|
content = raw.length > MAX_CHARS ? raw.slice(0, MAX_CHARS) + "\n... (truncated) ..." : raw;
|
|
21870
22089
|
} catch {
|
|
21871
22090
|
}
|
|
@@ -21899,18 +22118,18 @@ function frequencyWeight(relpath, usage, isProject, type2) {
|
|
|
21899
22118
|
return reconsolidation + countBonus;
|
|
21900
22119
|
}
|
|
21901
22120
|
function scanTopics(topicsDir, typeFilter) {
|
|
21902
|
-
if (!
|
|
22121
|
+
if (!fs20.existsSync(topicsDir)) return [];
|
|
21903
22122
|
const out = [];
|
|
21904
22123
|
const walk = (dir) => {
|
|
21905
|
-
for (const name of
|
|
21906
|
-
const full =
|
|
21907
|
-
const stat4 =
|
|
22124
|
+
for (const name of fs20.readdirSync(dir)) {
|
|
22125
|
+
const full = path21.join(dir, name);
|
|
22126
|
+
const stat4 = fs20.statSync(full);
|
|
21908
22127
|
if (stat4.isDirectory()) {
|
|
21909
22128
|
if (SKIP_DIRS.has(name)) continue;
|
|
21910
22129
|
walk(full);
|
|
21911
22130
|
} else {
|
|
21912
22131
|
if (!name.endsWith(".md") || SKIP_NAMES.has(name)) continue;
|
|
21913
|
-
const relpath =
|
|
22132
|
+
const relpath = path21.relative(topicsDir, full).replace(/\\/g, "/");
|
|
21914
22133
|
if (typeFilter && !relpath.startsWith(typeFilter + "/") && !relpath.startsWith(typeFilter + "_")) continue;
|
|
21915
22134
|
out.push({ relpath, fullpath: full });
|
|
21916
22135
|
}
|
|
@@ -21922,7 +22141,7 @@ function scanTopics(topicsDir, typeFilter) {
|
|
|
21922
22141
|
function readFrontmatter(file) {
|
|
21923
22142
|
let content = "";
|
|
21924
22143
|
try {
|
|
21925
|
-
content =
|
|
22144
|
+
content = fs20.readFileSync(file, "utf-8").slice(0, 2e3);
|
|
21926
22145
|
} catch {
|
|
21927
22146
|
return {};
|
|
21928
22147
|
}
|
|
@@ -21948,40 +22167,40 @@ function weightedRandom(items, weights) {
|
|
|
21948
22167
|
}
|
|
21949
22168
|
function loadJson2(file) {
|
|
21950
22169
|
try {
|
|
21951
|
-
return JSON.parse(
|
|
22170
|
+
return JSON.parse(fs20.readFileSync(file, "utf-8"));
|
|
21952
22171
|
} catch {
|
|
21953
22172
|
return null;
|
|
21954
22173
|
}
|
|
21955
22174
|
}
|
|
21956
22175
|
function saveJson2(file, data) {
|
|
21957
22176
|
try {
|
|
21958
|
-
|
|
21959
|
-
|
|
22177
|
+
fs20.mkdirSync(path21.dirname(file), { recursive: true });
|
|
22178
|
+
fs20.writeFileSync(file, JSON.stringify(data, null, 2));
|
|
21960
22179
|
} catch (err) {
|
|
21961
22180
|
console.warn(`[topics-scorer] usage save failed: ${err.message}`);
|
|
21962
22181
|
}
|
|
21963
22182
|
}
|
|
21964
22183
|
|
|
21965
22184
|
// src/inner-voice/memory-reader.ts
|
|
21966
|
-
import
|
|
21967
|
-
import
|
|
22185
|
+
import fs21 from "node:fs";
|
|
22186
|
+
import path22 from "node:path";
|
|
21968
22187
|
var US_HALF_LIFE_DAYS = 10;
|
|
21969
22188
|
var US_MAX_LINES = 60;
|
|
21970
22189
|
function readRecentMemory(workspace) {
|
|
21971
|
-
const dir =
|
|
22190
|
+
const dir = path22.join(workspace, "memory");
|
|
21972
22191
|
const now = new Date(Date.now() + 8 * 36e5);
|
|
21973
22192
|
const today = formatYmd(now);
|
|
21974
22193
|
const yesterday = formatYmd(new Date(now.getTime() - 864e5));
|
|
21975
22194
|
return {
|
|
21976
|
-
today: readIfExists(
|
|
21977
|
-
yesterday: readIfExists(
|
|
22195
|
+
today: readIfExists(path22.join(dir, `${today}.md`)),
|
|
22196
|
+
yesterday: readIfExists(path22.join(dir, `${yesterday}.md`))
|
|
21978
22197
|
};
|
|
21979
22198
|
}
|
|
21980
22199
|
function sampleUs(workspace) {
|
|
21981
|
-
const usFile =
|
|
22200
|
+
const usFile = path22.join(workspace, "memory", "us.md");
|
|
21982
22201
|
let content;
|
|
21983
22202
|
try {
|
|
21984
|
-
content =
|
|
22203
|
+
content = fs21.readFileSync(usFile, "utf-8");
|
|
21985
22204
|
} catch {
|
|
21986
22205
|
return null;
|
|
21987
22206
|
}
|
|
@@ -22027,7 +22246,7 @@ function recencyWeight(dateStr) {
|
|
|
22027
22246
|
}
|
|
22028
22247
|
function readIfExists(file) {
|
|
22029
22248
|
try {
|
|
22030
|
-
return
|
|
22249
|
+
return fs21.readFileSync(file, "utf-8");
|
|
22031
22250
|
} catch {
|
|
22032
22251
|
return "";
|
|
22033
22252
|
}
|
|
@@ -22318,9 +22537,9 @@ var InnerVoicePlugin = class {
|
|
|
22318
22537
|
}
|
|
22319
22538
|
/** 读 workspace/prompts/my-inner-voice.md,不存在用 DEFAULT_PROMPT */
|
|
22320
22539
|
loadPrompt(workspace) {
|
|
22321
|
-
const promptPath =
|
|
22540
|
+
const promptPath = path23.join(workspace, "prompts", "my-inner-voice.md");
|
|
22322
22541
|
try {
|
|
22323
|
-
const content =
|
|
22542
|
+
const content = fs22.readFileSync(promptPath, "utf-8").trim();
|
|
22324
22543
|
if (content) {
|
|
22325
22544
|
console.log(`[inner-voice] Loaded custom prompt from ${promptPath}`);
|
|
22326
22545
|
return content;
|
|
@@ -22392,7 +22611,7 @@ var InnerVoicePlugin = class {
|
|
|
22392
22611
|
console.warn(`[inner-voice] emotional-state failed: ${err.message}`);
|
|
22393
22612
|
}
|
|
22394
22613
|
try {
|
|
22395
|
-
const content =
|
|
22614
|
+
const content = fs22.readFileSync(path23.join(this.workspace, "SESSION-STATE.md"), "utf-8");
|
|
22396
22615
|
lines.push("\n--- SESSION-STATE\uFF08\u5C3E\u90E8\uFF09 ---");
|
|
22397
22616
|
lines.push(content.slice(-2e3));
|
|
22398
22617
|
} catch {
|
|
@@ -22506,10 +22725,10 @@ var InnerVoicePlugin = class {
|
|
|
22506
22725
|
if (Math.random() >= activity.hintProb) {
|
|
22507
22726
|
return { text: thought, hintTriggered: false, hintText: "" };
|
|
22508
22727
|
}
|
|
22509
|
-
const poolPath =
|
|
22728
|
+
const poolPath = path23.join(this.workspace, "inner-voice", "hints_pool.txt");
|
|
22510
22729
|
let hint = "\u60F3\u4ED6\u5C31\u53D1\u6D88\u606F\u5427";
|
|
22511
22730
|
try {
|
|
22512
|
-
const pool =
|
|
22731
|
+
const pool = fs22.readFileSync(poolPath, "utf-8").split("\n").map((s) => s.trim()).filter(Boolean);
|
|
22513
22732
|
if (pool.length) hint = pool[Math.floor(Math.random() * pool.length)];
|
|
22514
22733
|
} catch {
|
|
22515
22734
|
}
|
|
@@ -22534,7 +22753,7 @@ var InnerVoicePlugin = class {
|
|
|
22534
22753
|
try {
|
|
22535
22754
|
const writer = sessions.getWriter(mainSessionId);
|
|
22536
22755
|
const history = sessions.getHistory(mainSessionId);
|
|
22537
|
-
const fullPath =
|
|
22756
|
+
const fullPath = path23.resolve(this.workspace, emoTopic.file);
|
|
22538
22757
|
const memories = [{
|
|
22539
22758
|
path: fullPath,
|
|
22540
22759
|
content: emoTopic.content,
|
|
@@ -22562,12 +22781,12 @@ var InnerVoicePlugin = class {
|
|
|
22562
22781
|
/** 写 xiaoyi.log(格式对齐旧 memory_whisper.py,便于既有日志分析复用)。 */
|
|
22563
22782
|
writeLog(status, delivered, activity, hintTriggered, hintText) {
|
|
22564
22783
|
try {
|
|
22565
|
-
const logDir =
|
|
22566
|
-
|
|
22567
|
-
const logPath =
|
|
22784
|
+
const logDir = path23.join(this.workspace, "inner-voice");
|
|
22785
|
+
fs22.mkdirSync(logDir, { recursive: true });
|
|
22786
|
+
const logPath = path23.join(logDir, "xiaoyi.log");
|
|
22568
22787
|
const ts = formatBeijingTs(/* @__PURE__ */ new Date());
|
|
22569
22788
|
const hintStatus = hintTriggered ? `YES (${(hintText || "").trim()})` : "no";
|
|
22570
|
-
|
|
22789
|
+
fs22.appendFileSync(
|
|
22571
22790
|
logPath,
|
|
22572
22791
|
`[${ts}] ${status} hint=${hintStatus} prob=${Math.round(activity.hintProb * 100)}%
|
|
22573
22792
|
delivered: ${delivered}
|
|
@@ -23103,8 +23322,8 @@ var PluginManager = class {
|
|
|
23103
23322
|
// src/voice-chat/plugin.ts
|
|
23104
23323
|
import { spawn as spawn4, exec } from "node:child_process";
|
|
23105
23324
|
import net from "node:net";
|
|
23106
|
-
import
|
|
23107
|
-
import
|
|
23325
|
+
import path24 from "node:path";
|
|
23326
|
+
import fs23 from "node:fs";
|
|
23108
23327
|
|
|
23109
23328
|
// src/voice-chat/bridge.ts
|
|
23110
23329
|
function registerVoiceChatBridge(httpServer, dispatcher, deps, config2, sessions, voiceChatDeps) {
|
|
@@ -23473,20 +23692,20 @@ var VoiceChatPlugin = class _VoiceChatPlugin {
|
|
|
23473
23692
|
}
|
|
23474
23693
|
}
|
|
23475
23694
|
findPython() {
|
|
23476
|
-
if (this.config.pythonPath &&
|
|
23695
|
+
if (this.config.pythonPath && fs23.existsSync(this.config.pythonPath)) {
|
|
23477
23696
|
return this.config.pythonPath;
|
|
23478
23697
|
}
|
|
23479
23698
|
return "python";
|
|
23480
23699
|
}
|
|
23481
23700
|
getPythonDir() {
|
|
23482
23701
|
const dir = import.meta.dirname;
|
|
23483
|
-
const srcDir =
|
|
23484
|
-
const localDir =
|
|
23485
|
-
return
|
|
23702
|
+
const srcDir = path24.resolve(dir, "..", "src", "voice-chat", "python");
|
|
23703
|
+
const localDir = path24.join(dir, "python");
|
|
23704
|
+
return fs23.existsSync(srcDir) ? srcDir : localDir;
|
|
23486
23705
|
}
|
|
23487
23706
|
startPython() {
|
|
23488
23707
|
const pythonDir = this.getPythonDir();
|
|
23489
|
-
const serverPy =
|
|
23708
|
+
const serverPy = path24.join(pythonDir, "server.py");
|
|
23490
23709
|
const pythonBin = this.findPython();
|
|
23491
23710
|
const args2 = [serverPy];
|
|
23492
23711
|
if (this.config.pythonPort) args2.push("--port", String(this.config.pythonPort));
|
|
@@ -23515,7 +23734,7 @@ var VoiceChatPlugin = class _VoiceChatPlugin {
|
|
|
23515
23734
|
}
|
|
23516
23735
|
console.log(`[voice-chat] Starting Python: ${pythonBin} ${args2.join(" ")}`);
|
|
23517
23736
|
console.log(`[voice-chat] Python dir: ${pythonDir}`);
|
|
23518
|
-
if (!
|
|
23737
|
+
if (!fs23.existsSync(pythonDir)) {
|
|
23519
23738
|
console.error(`[voice-chat] FATAL: Python directory does not exist: ${pythonDir}`);
|
|
23520
23739
|
throw new Error(`voice-chat: python dir not found: ${pythonDir}`);
|
|
23521
23740
|
}
|
|
@@ -23538,7 +23757,7 @@ var VoiceChatPlugin = class _VoiceChatPlugin {
|
|
|
23538
23757
|
child.on("error", (err) => {
|
|
23539
23758
|
console.error(`[voice-chat] spawn error: ${err.message}`);
|
|
23540
23759
|
console.error(`[voice-chat] shell=${pythonBin} cwd=${pythonDir}`);
|
|
23541
|
-
console.error(`[voice-chat] cwd exists=${
|
|
23760
|
+
console.error(`[voice-chat] cwd exists=${fs23.existsSync(pythonDir)}`);
|
|
23542
23761
|
});
|
|
23543
23762
|
child.stdout?.on("data", (data) => {
|
|
23544
23763
|
const lines = data.toString().trim().split("\n");
|
|
@@ -23571,8 +23790,8 @@ var VoiceChatPlugin = class _VoiceChatPlugin {
|
|
|
23571
23790
|
init_BashTool();
|
|
23572
23791
|
import { spawn as spawn5, exec as exec2 } from "node:child_process";
|
|
23573
23792
|
import net2 from "node:net";
|
|
23574
|
-
import
|
|
23575
|
-
import
|
|
23793
|
+
import path25 from "node:path";
|
|
23794
|
+
import fs24 from "node:fs";
|
|
23576
23795
|
|
|
23577
23796
|
// src/memory/cognifold/config.ts
|
|
23578
23797
|
var DEFAULTS3 = {
|
|
@@ -23610,11 +23829,11 @@ var CogniFoldClient = class {
|
|
|
23610
23829
|
this.timeoutMs = timeoutMs;
|
|
23611
23830
|
this.modelName = modelName;
|
|
23612
23831
|
}
|
|
23613
|
-
async req(
|
|
23832
|
+
async req(path46, options = {}) {
|
|
23614
23833
|
const ctrl = new AbortController();
|
|
23615
23834
|
const timer = setTimeout(() => ctrl.abort(), this.timeoutMs);
|
|
23616
23835
|
try {
|
|
23617
|
-
const resp = await fetch(`${this.baseUrl}${
|
|
23836
|
+
const resp = await fetch(`${this.baseUrl}${path46}`, {
|
|
23618
23837
|
...options,
|
|
23619
23838
|
signal: ctrl.signal,
|
|
23620
23839
|
headers: {
|
|
@@ -23704,8 +23923,8 @@ var CogniFoldClient = class {
|
|
|
23704
23923
|
});
|
|
23705
23924
|
}
|
|
23706
23925
|
/** 兼容老版命名 */
|
|
23707
|
-
async recl(
|
|
23708
|
-
return this.req(
|
|
23926
|
+
async recl(path46, options = {}) {
|
|
23927
|
+
return this.req(path46, options);
|
|
23709
23928
|
}
|
|
23710
23929
|
};
|
|
23711
23930
|
|
|
@@ -23986,16 +24205,16 @@ var CogniFoldPlugin = class {
|
|
|
23986
24205
|
const dir = import.meta.dirname;
|
|
23987
24206
|
const candidates = [
|
|
23988
24207
|
// 从 dist/ 往回找 src
|
|
23989
|
-
|
|
23990
|
-
|
|
23991
|
-
|
|
24208
|
+
path25.resolve(dir, "..", "src", "memory", "cognifold", "python"),
|
|
24209
|
+
path25.resolve(dir, "..", "..", "src", "memory", "cognifold", "python"),
|
|
24210
|
+
path25.resolve(dir, "..", "..", "..", "src", "memory", "cognifold", "python"),
|
|
23992
24211
|
// 从 src/memory/cognifold/ 找本地
|
|
23993
|
-
|
|
24212
|
+
path25.join(dir, "python"),
|
|
23994
24213
|
// 从 dist/memory/cognifold/ 找本地
|
|
23995
|
-
|
|
24214
|
+
path25.resolve(dir, "python")
|
|
23996
24215
|
];
|
|
23997
24216
|
for (const candidate of candidates) {
|
|
23998
|
-
if (
|
|
24217
|
+
if (fs24.existsSync(path25.join(candidate, "cognifold"))) {
|
|
23999
24218
|
return candidate;
|
|
24000
24219
|
}
|
|
24001
24220
|
}
|
|
@@ -24021,7 +24240,7 @@ var CogniFoldPlugin = class {
|
|
|
24021
24240
|
const pythonBin = this.findPython();
|
|
24022
24241
|
console.log(`[cognifold] Starting Python: ${pythonBin} ${args2.join(" ")}`);
|
|
24023
24242
|
console.log(`[cognifold] Python dir: ${pythonDir}`);
|
|
24024
|
-
if (!
|
|
24243
|
+
if (!fs24.existsSync(path25.join(pythonDir, "cognifold"))) {
|
|
24025
24244
|
console.error(`[cognifold] FATAL: Python module not found at ${pythonDir}/cognifold`);
|
|
24026
24245
|
throw new Error(`cognifold: python module not found`);
|
|
24027
24246
|
}
|
|
@@ -24032,10 +24251,10 @@ var CogniFoldPlugin = class {
|
|
|
24032
24251
|
if (this.config.llm?.baseUrl) {
|
|
24033
24252
|
childEnv["OPENAI_BASE_URL"] = this.config.llm.baseUrl;
|
|
24034
24253
|
}
|
|
24035
|
-
const envFile =
|
|
24254
|
+
const envFile = path25.join(pythonDir, ".env");
|
|
24036
24255
|
try {
|
|
24037
|
-
if (
|
|
24038
|
-
const envContent =
|
|
24256
|
+
if (fs24.existsSync(envFile)) {
|
|
24257
|
+
const envContent = fs24.readFileSync(envFile, "utf-8");
|
|
24039
24258
|
for (const line of envContent.split("\n")) {
|
|
24040
24259
|
const trimmed = line.trim();
|
|
24041
24260
|
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
@@ -24101,11 +24320,10 @@ var CogniFoldPlugin = class {
|
|
|
24101
24320
|
};
|
|
24102
24321
|
|
|
24103
24322
|
// src/memory/everos/plugin.ts
|
|
24104
|
-
init_BashTool();
|
|
24105
24323
|
import { spawn as spawn6 } from "node:child_process";
|
|
24106
24324
|
import net3 from "node:net";
|
|
24107
|
-
import
|
|
24108
|
-
import
|
|
24325
|
+
import path26 from "node:path";
|
|
24326
|
+
import fs25 from "node:fs";
|
|
24109
24327
|
|
|
24110
24328
|
// src/memory/everos/config.ts
|
|
24111
24329
|
var DEFAULTS4 = {
|
|
@@ -24312,8 +24530,8 @@ var EverosPlugin = class {
|
|
|
24312
24530
|
}, 3e5);
|
|
24313
24531
|
}
|
|
24314
24532
|
async startEveros() {
|
|
24315
|
-
const pythonDir =
|
|
24316
|
-
const configPath2 =
|
|
24533
|
+
const pythonDir = path26.dirname(this.config.lancedbPath);
|
|
24534
|
+
const configPath2 = path26.join(pythonDir, "config.toml");
|
|
24317
24535
|
await this.ensureFcntlCompat();
|
|
24318
24536
|
const venvPython = this.findVenvPython();
|
|
24319
24537
|
const everosBin = venvPython.replace(/python\.exe$/, "everos.exe");
|
|
@@ -24322,16 +24540,15 @@ var EverosPlugin = class {
|
|
|
24322
24540
|
console.log(`[everos] Starting EverOS: ${cmd}`);
|
|
24323
24541
|
console.log(`[everos] LLM config: ${this.config.llm.model} @ ${this.config.llm.baseUrl}`);
|
|
24324
24542
|
if (process.platform === "win32") {
|
|
24325
|
-
|
|
24326
|
-
spawn6(shell, [...shellArgs, cmd], {
|
|
24543
|
+
spawn6(everosBin, args2, {
|
|
24327
24544
|
cwd: pythonDir,
|
|
24328
|
-
stdio:
|
|
24545
|
+
stdio: "ignore",
|
|
24329
24546
|
env: { ...process.env, PYTHONUNBUFFERED: "1", NO_PROXY: "127.0.0.1,localhost", no_proxy: "127.0.0.1,localhost" }
|
|
24330
24547
|
});
|
|
24331
24548
|
} else {
|
|
24332
24549
|
spawn6(venvPython, args2, {
|
|
24333
24550
|
cwd: pythonDir,
|
|
24334
|
-
stdio:
|
|
24551
|
+
stdio: "ignore",
|
|
24335
24552
|
env: { ...process.env, PYTHONUNBUFFERED: "1", NO_PROXY: "127.0.0.1,localhost", no_proxy: "127.0.0.1,localhost" }
|
|
24336
24553
|
});
|
|
24337
24554
|
}
|
|
@@ -24404,19 +24621,19 @@ var EverosPlugin = class {
|
|
|
24404
24621
|
return child;
|
|
24405
24622
|
}
|
|
24406
24623
|
findVenvPython() {
|
|
24407
|
-
const stateDir = (process.env.ENGINE7_STATE_DIR ?? process.env.OPENCLAW_STATE_DIR) ||
|
|
24624
|
+
const stateDir = (process.env.ENGINE7_STATE_DIR ?? process.env.OPENCLAW_STATE_DIR) || path26.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7");
|
|
24408
24625
|
if (process.platform === "win32") {
|
|
24409
|
-
return
|
|
24626
|
+
return path26.join(stateDir, "everos-venv", "Scripts", "python.exe");
|
|
24410
24627
|
}
|
|
24411
|
-
return
|
|
24628
|
+
return path26.join(stateDir, "everos-venv", "bin", "python");
|
|
24412
24629
|
}
|
|
24413
24630
|
/** 检测 venv 是否存在,不存在就自动创建 + 装 EverOS */
|
|
24414
24631
|
async ensureVenv() {
|
|
24415
24632
|
const venvPython = this.findVenvPython();
|
|
24416
|
-
if (
|
|
24417
|
-
const stateDir = (process.env.ENGINE7_STATE_DIR ?? process.env.OPENCLAW_STATE_DIR) ||
|
|
24418
|
-
const venvDir =
|
|
24419
|
-
const everosSrc =
|
|
24633
|
+
if (fs25.existsSync(venvPython)) return;
|
|
24634
|
+
const stateDir = (process.env.ENGINE7_STATE_DIR ?? process.env.OPENCLAW_STATE_DIR) || path26.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7");
|
|
24635
|
+
const venvDir = path26.join(stateDir, "everos-venv");
|
|
24636
|
+
const everosSrc = path26.join(stateDir, "workspace", "research", "EverOS");
|
|
24420
24637
|
console.log(`[everos] venv not found at ${venvDir}, auto-creating...`);
|
|
24421
24638
|
console.log(`[everos] \u23F3 This may take a few minutes on first run...`);
|
|
24422
24639
|
const pyCandidates = process.platform === "win32" ? ["python", "python3", "C:\\Python314\\python.exe", "C:\\Python313\\python.exe", "C:\\Python312\\python.exe"] : ["python3", "python"];
|
|
@@ -24438,9 +24655,9 @@ var EverosPlugin = class {
|
|
|
24438
24655
|
console.log(`[everos] Creating venv with ${sysPython}...`);
|
|
24439
24656
|
const { execSync: execSync3 } = await import("node:child_process");
|
|
24440
24657
|
execSync3(`"${sysPython}" -m venv "${venvDir}"`, { stdio: "pipe", shell: true });
|
|
24441
|
-
const pip = process.platform === "win32" ?
|
|
24442
|
-
const everosReq =
|
|
24443
|
-
if (
|
|
24658
|
+
const pip = process.platform === "win32" ? path26.join(venvDir, "Scripts", "pip.exe") : path26.join(venvDir, "bin", "pip");
|
|
24659
|
+
const everosReq = path26.join(this.getPythonDir(), "requirements.txt");
|
|
24660
|
+
if (fs25.existsSync(everosReq)) {
|
|
24444
24661
|
console.log(`[everos] Installing from requirements.txt...`);
|
|
24445
24662
|
execSync3(`"${pip}" install -r "${everosReq}" -q`, { stdio: "pipe", shell: true, timeout: 3e5 });
|
|
24446
24663
|
} else {
|
|
@@ -24456,12 +24673,12 @@ var EverosPlugin = class {
|
|
|
24456
24673
|
getPythonDir() {
|
|
24457
24674
|
const dir = import.meta.dirname;
|
|
24458
24675
|
const candidates = [
|
|
24459
|
-
|
|
24460
|
-
|
|
24461
|
-
|
|
24676
|
+
path26.join(dir, "python"),
|
|
24677
|
+
path26.resolve(dir, "..", "src", "memory", "everos", "python"),
|
|
24678
|
+
path26.resolve(dir, "..", "..", "..", "src", "memory", "everos", "python")
|
|
24462
24679
|
];
|
|
24463
24680
|
for (const candidate of candidates) {
|
|
24464
|
-
if (
|
|
24681
|
+
if (fs25.existsSync(path26.join(candidate, "agentic_server.py"))) {
|
|
24465
24682
|
return candidate;
|
|
24466
24683
|
}
|
|
24467
24684
|
}
|
|
@@ -24470,14 +24687,14 @@ var EverosPlugin = class {
|
|
|
24470
24687
|
async ensureFcntlCompat() {
|
|
24471
24688
|
if (process.platform !== "win32") return;
|
|
24472
24689
|
const venvPython = this.findVenvPython();
|
|
24473
|
-
const venvDir =
|
|
24474
|
-
const sitePackages =
|
|
24475
|
-
const target =
|
|
24476
|
-
if (
|
|
24477
|
-
const source =
|
|
24478
|
-
if (
|
|
24690
|
+
const venvDir = path26.dirname(path26.dirname(venvPython));
|
|
24691
|
+
const sitePackages = path26.join(venvDir, "Lib", "site-packages");
|
|
24692
|
+
const target = path26.join(sitePackages, "fcntl.py");
|
|
24693
|
+
if (fs25.existsSync(target)) return;
|
|
24694
|
+
const source = path26.join(this.getPythonDir(), "fcntl_compat.py");
|
|
24695
|
+
if (fs25.existsSync(source)) {
|
|
24479
24696
|
try {
|
|
24480
|
-
|
|
24697
|
+
fs25.copyFileSync(source, target);
|
|
24481
24698
|
console.log(`[everos] Installed fcntl compat shim to ${target}`);
|
|
24482
24699
|
} catch (err) {
|
|
24483
24700
|
console.warn(`[everos] Failed to install fcntl shim: ${err.message}`);
|
|
@@ -24524,21 +24741,21 @@ var EverosPlugin = class {
|
|
|
24524
24741
|
init_task_manager();
|
|
24525
24742
|
|
|
24526
24743
|
// src/skills/scanner.ts
|
|
24527
|
-
import * as
|
|
24528
|
-
import * as
|
|
24744
|
+
import * as path27 from "node:path";
|
|
24745
|
+
import * as fs26 from "node:fs";
|
|
24529
24746
|
function scanSkills(skillsDir) {
|
|
24530
|
-
if (!
|
|
24747
|
+
if (!fs26.existsSync(skillsDir)) {
|
|
24531
24748
|
console.log(`[skills] Directory not found: ${skillsDir}`);
|
|
24532
24749
|
return [];
|
|
24533
24750
|
}
|
|
24534
|
-
const entries =
|
|
24751
|
+
const entries = fs26.readdirSync(skillsDir, { withFileTypes: true });
|
|
24535
24752
|
const skills = [];
|
|
24536
24753
|
for (const entry of entries) {
|
|
24537
24754
|
if (!entry.isDirectory()) continue;
|
|
24538
|
-
const skillMdPath =
|
|
24539
|
-
if (!
|
|
24755
|
+
const skillMdPath = path27.join(skillsDir, entry.name, "SKILL.md");
|
|
24756
|
+
if (!fs26.existsSync(skillMdPath)) continue;
|
|
24540
24757
|
try {
|
|
24541
|
-
const content =
|
|
24758
|
+
const content = fs26.readFileSync(skillMdPath, "utf-8");
|
|
24542
24759
|
const frontmatter = parseFrontmatter2(content);
|
|
24543
24760
|
if (!frontmatter.name) {
|
|
24544
24761
|
console.warn(`[skills] Skipping ${entry.name}/SKILL.md: missing 'name' in frontmatter`);
|
|
@@ -24602,8 +24819,8 @@ function parseFrontmatter2(content) {
|
|
|
24602
24819
|
|
|
24603
24820
|
// src/tools/SkillTool/SkillTool.ts
|
|
24604
24821
|
init_registry();
|
|
24605
|
-
import * as
|
|
24606
|
-
import * as
|
|
24822
|
+
import * as fs27 from "node:fs";
|
|
24823
|
+
import * as path28 from "node:path";
|
|
24607
24824
|
|
|
24608
24825
|
// src/tools/SkillTool/constants.ts
|
|
24609
24826
|
var SKILL_TOOL_NAME2 = "Skill";
|
|
@@ -24680,12 +24897,12 @@ Important:
|
|
|
24680
24897
|
`;
|
|
24681
24898
|
}
|
|
24682
24899
|
function loadSkillContent(skillName) {
|
|
24683
|
-
const skillMdPath =
|
|
24684
|
-
if (!
|
|
24685
|
-
const content =
|
|
24900
|
+
const skillMdPath = path28.join(skillsDirPath, skillName, "SKILL.md");
|
|
24901
|
+
if (!fs27.existsSync(skillMdPath)) return null;
|
|
24902
|
+
const content = fs27.readFileSync(skillMdPath, "utf-8");
|
|
24686
24903
|
const bodyMatch = content.match(/^---\s*\n[\s\S]*?\n---\s*\n([\s\S]*)/);
|
|
24687
24904
|
const body = bodyMatch ? bodyMatch[1] : content;
|
|
24688
|
-
const skillDir =
|
|
24905
|
+
const skillDir = path28.dirname(skillMdPath);
|
|
24689
24906
|
const normalizedDir = process.platform === "win32" ? skillDir.replace(/\\/g, "/") : skillDir;
|
|
24690
24907
|
let finalContent = `Base directory for this skill: ${normalizedDir}
|
|
24691
24908
|
|
|
@@ -24959,12 +25176,12 @@ Examples:
|
|
|
24959
25176
|
// src/tools/msg-husband.ts
|
|
24960
25177
|
init_registry();
|
|
24961
25178
|
init_live();
|
|
24962
|
-
import
|
|
24963
|
-
import
|
|
25179
|
+
import fs28 from "node:fs";
|
|
25180
|
+
import path29 from "node:path";
|
|
24964
25181
|
function getHusbandFeishuId(workspace) {
|
|
24965
|
-
const contactsPath =
|
|
25182
|
+
const contactsPath = path29.join(workspace, "prompts", "contacts.md");
|
|
24966
25183
|
try {
|
|
24967
|
-
const text =
|
|
25184
|
+
const text = fs28.readFileSync(contactsPath, "utf-8");
|
|
24968
25185
|
const m = text.match(/\|\s*翀哥\s*\|\s*(ou_[a-f0-9]+)\s*\|/);
|
|
24969
25186
|
return m ? m[1] : null;
|
|
24970
25187
|
} catch {
|
|
@@ -25106,8 +25323,8 @@ Examples:
|
|
|
25106
25323
|
if (!to && !resolvedChannelId) {
|
|
25107
25324
|
return { content: "to \u548C channel_id \u4E0D\u80FD\u540C\u65F6\u4E3A\u7A7A\uFF0C\u4E14\u6CA1\u6709\u53EF\u7528\u7684\u6765\u6E90\u9891\u9053", isError: true };
|
|
25108
25325
|
}
|
|
25109
|
-
const
|
|
25110
|
-
if (!
|
|
25326
|
+
const fs43 = await import("node:fs");
|
|
25327
|
+
if (!fs43.existsSync(filePath)) {
|
|
25111
25328
|
return { content: `\u53D1\u9001\u5931\u8D25: \u6587\u4EF6\u4E0D\u5B58\u5728 ${filePath}`, isError: true };
|
|
25112
25329
|
}
|
|
25113
25330
|
const toIds = to ? to.split(",").map((s) => s.trim()).filter(Boolean) : [];
|
|
@@ -25135,7 +25352,7 @@ Examples:
|
|
|
25135
25352
|
md: "text/markdown"
|
|
25136
25353
|
};
|
|
25137
25354
|
const mimeType = mimeTypeMap[ext] || "application/octet-stream";
|
|
25138
|
-
const stat4 =
|
|
25355
|
+
const stat4 = fs43.statSync(filePath);
|
|
25139
25356
|
const sizeMB = stat4.size / 1024 / 1024;
|
|
25140
25357
|
if (sizeMB > 25) {
|
|
25141
25358
|
return { content: `\u53D1\u9001\u5931\u8D25: \u6587\u4EF6 ${sizeMB.toFixed(1)}MB \u8D85\u8FC7 Discord 25MB \u9650\u5236`, isError: true };
|
|
@@ -25164,8 +25381,8 @@ Examples:
|
|
|
25164
25381
|
// src/tools/my-eyes.ts
|
|
25165
25382
|
init_live();
|
|
25166
25383
|
init_registry();
|
|
25167
|
-
import * as
|
|
25168
|
-
import * as
|
|
25384
|
+
import * as fs29 from "node:fs";
|
|
25385
|
+
import * as path30 from "node:path";
|
|
25169
25386
|
var MIME_MAP = {
|
|
25170
25387
|
".jpg": "jpeg",
|
|
25171
25388
|
".jpeg": "jpeg",
|
|
@@ -25175,9 +25392,9 @@ var MIME_MAP = {
|
|
|
25175
25392
|
".bmp": "bmp"
|
|
25176
25393
|
};
|
|
25177
25394
|
function resolveLatestImage(specifiedPath, mediaDir) {
|
|
25178
|
-
if (specifiedPath &&
|
|
25179
|
-
if (!
|
|
25180
|
-
const files =
|
|
25395
|
+
if (specifiedPath && fs29.existsSync(specifiedPath)) return specifiedPath;
|
|
25396
|
+
if (!fs29.existsSync(mediaDir)) return null;
|
|
25397
|
+
const files = fs29.readdirSync(mediaDir).filter((f) => /\.(jpg|jpeg|png|webp|gif|bmp)$/i.test(f)).map((f) => ({ name: f, p: path30.join(mediaDir, f), mtime: fs29.statSync(path30.join(mediaDir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
|
|
25181
25398
|
return files[0]?.p || null;
|
|
25182
25399
|
}
|
|
25183
25400
|
registry.register({
|
|
@@ -25202,15 +25419,15 @@ registry.register({
|
|
|
25202
25419
|
if (!provider?.streamChat) {
|
|
25203
25420
|
return { content: "Error: provider \u4E0D\u53EF\u7528\u3002", isError: true };
|
|
25204
25421
|
}
|
|
25205
|
-
const mediaDir =
|
|
25422
|
+
const mediaDir = path30.join(ctx.stateDir, "media", "inbound");
|
|
25206
25423
|
const imagePath = resolveLatestImage(args2.image_path, mediaDir);
|
|
25207
25424
|
if (!imagePath) {
|
|
25208
25425
|
return { content: "Error: no image found. Provide image_path or ensure media/inbound has images.", isError: true };
|
|
25209
25426
|
}
|
|
25210
25427
|
const rawPrompt = args2.prompt?.trim() || "\u63CF\u8FF0\u8FD9\u5F20\u56FE\u7247\u7684\u5185\u5BB9";
|
|
25211
|
-
const ext =
|
|
25428
|
+
const ext = path30.extname(imagePath).toLowerCase();
|
|
25212
25429
|
const mime = MIME_MAP[ext] || "jpeg";
|
|
25213
|
-
const imgB64 =
|
|
25430
|
+
const imgB64 = fs29.readFileSync(imagePath).toString("base64");
|
|
25214
25431
|
const userMsg = {
|
|
25215
25432
|
role: "user",
|
|
25216
25433
|
content: [
|
|
@@ -25247,14 +25464,14 @@ init_live();
|
|
|
25247
25464
|
init_registry();
|
|
25248
25465
|
import { execFile } from "node:child_process";
|
|
25249
25466
|
import { promisify } from "node:util";
|
|
25250
|
-
import * as
|
|
25251
|
-
import * as
|
|
25467
|
+
import * as fs30 from "node:fs";
|
|
25468
|
+
import * as path31 from "node:path";
|
|
25252
25469
|
import * as os3 from "node:os";
|
|
25253
25470
|
var execFileAsync = promisify(execFile);
|
|
25254
|
-
var VOICE_DIR =
|
|
25471
|
+
var VOICE_DIR = path31.join(os3.tmpdir(), "engine-voice");
|
|
25255
25472
|
async function ttsCosyvoice(text, apiKey, model, voice, workspaceId, instruction) {
|
|
25256
|
-
|
|
25257
|
-
const output =
|
|
25473
|
+
fs30.mkdirSync(VOICE_DIR, { recursive: true });
|
|
25474
|
+
const output = path31.join(VOICE_DIR, `tts_${Date.now()}.wav`);
|
|
25258
25475
|
const script = `
|
|
25259
25476
|
import sys, json, wave, time, threading
|
|
25260
25477
|
import dashscope
|
|
@@ -25311,7 +25528,7 @@ print(f"OK: {len(pcm)} bytes")
|
|
|
25311
25528
|
`;
|
|
25312
25529
|
const configJson = JSON.stringify({ apiKey, model, voice, workspaceId, instruction });
|
|
25313
25530
|
await execFileAsync("python3", ["-c", script, configJson, text, output], { timeout: 3e4 });
|
|
25314
|
-
if (!
|
|
25531
|
+
if (!fs30.existsSync(output) || fs30.statSync(output).size < 100) {
|
|
25315
25532
|
throw new Error("CosyVoice produced empty output");
|
|
25316
25533
|
}
|
|
25317
25534
|
return output;
|
|
@@ -25321,8 +25538,8 @@ var GPTSOVITS_REF_WAV = "/home/chong/voice/ref/shanshan_ref_v2.wav";
|
|
|
25321
25538
|
var GPTSOVITS_REF_TEXT = "\u6625\u7720\u4E0D\u89C9\u6653\uFF0C\u5904\u5904\u95FB\u557C\u9E1F\uFF0C\u591C\u6765\u98CE\u96E8\u58F0\uFF0C\u82B1\u843D\u77E5\u591A\u5C11";
|
|
25322
25539
|
var GPTSOVITS_REF_LANG = "zh";
|
|
25323
25540
|
async function ttsGptsovits(text) {
|
|
25324
|
-
|
|
25325
|
-
const output =
|
|
25541
|
+
fs30.mkdirSync(VOICE_DIR, { recursive: true });
|
|
25542
|
+
const output = path31.join(VOICE_DIR, `tts_${Date.now()}.wav`);
|
|
25326
25543
|
const params = new URLSearchParams({
|
|
25327
25544
|
text,
|
|
25328
25545
|
text_language: "zh",
|
|
@@ -25333,13 +25550,13 @@ async function ttsGptsovits(text) {
|
|
|
25333
25550
|
const res = await fetch(`${GPTSOVITS_API}/?${params}`);
|
|
25334
25551
|
if (!res.ok) throw new Error(`GPT-SoVITS API ${res.status}`);
|
|
25335
25552
|
const buf = Buffer.from(await res.arrayBuffer());
|
|
25336
|
-
|
|
25553
|
+
fs30.writeFileSync(output, buf);
|
|
25337
25554
|
return output;
|
|
25338
25555
|
}
|
|
25339
25556
|
var EDGE_VOICE = "zh-CN-XiaoxiaoNeural";
|
|
25340
25557
|
async function ttsEdge(text) {
|
|
25341
|
-
|
|
25342
|
-
const output =
|
|
25558
|
+
fs30.mkdirSync(VOICE_DIR, { recursive: true });
|
|
25559
|
+
const output = path31.join(VOICE_DIR, `tts_${Date.now()}.mp3`);
|
|
25343
25560
|
const script = `
|
|
25344
25561
|
import asyncio, edge_tts, sys
|
|
25345
25562
|
async def main():
|
|
@@ -25365,7 +25582,7 @@ async function compressWav(wavPath) {
|
|
|
25365
25582
|
"+faststart",
|
|
25366
25583
|
m4aPath
|
|
25367
25584
|
], { timeout: 3e4 });
|
|
25368
|
-
|
|
25585
|
+
fs30.unlinkSync(wavPath);
|
|
25369
25586
|
return m4aPath;
|
|
25370
25587
|
} catch {
|
|
25371
25588
|
return wavPath;
|
|
@@ -25433,10 +25650,10 @@ registry.register({
|
|
|
25433
25650
|
} catch (e) {
|
|
25434
25651
|
return { content: `TTS failed: ${e.message}`, isError: true };
|
|
25435
25652
|
}
|
|
25436
|
-
const ext =
|
|
25653
|
+
const ext = path31.extname(audioPath).toLowerCase();
|
|
25437
25654
|
const mimeMap = { ".mp3": "audio/mpeg", ".wav": "audio/wav", ".m4a": "audio/mp4", ".ogg": "audio/ogg" };
|
|
25438
25655
|
const mimeType = mimeMap[ext] || "audio/mpeg";
|
|
25439
|
-
const sizeKB =
|
|
25656
|
+
const sizeKB = fs30.statSync(audioPath).size / 1024;
|
|
25440
25657
|
const resolvedChannel = args2.channel || ctx.channel || "feishu";
|
|
25441
25658
|
const target = ctx.channelTarget || ctx.from;
|
|
25442
25659
|
try {
|
|
@@ -25446,7 +25663,7 @@ registry.register({
|
|
|
25446
25663
|
filename: `voice_${Date.now()}${ext}`
|
|
25447
25664
|
});
|
|
25448
25665
|
try {
|
|
25449
|
-
|
|
25666
|
+
fs30.unlinkSync(audioPath);
|
|
25450
25667
|
} catch {
|
|
25451
25668
|
}
|
|
25452
25669
|
return { content: `Voice sent! (${actualEngine}, ${sizeKB.toFixed(0)}KB, ${resolvedChannel})` };
|
|
@@ -25463,8 +25680,8 @@ registry.register({
|
|
|
25463
25680
|
// src/tools/my-selfie.ts
|
|
25464
25681
|
init_live();
|
|
25465
25682
|
init_registry();
|
|
25466
|
-
import * as
|
|
25467
|
-
import * as
|
|
25683
|
+
import * as fs31 from "node:fs";
|
|
25684
|
+
import * as path32 from "node:path";
|
|
25468
25685
|
function getProxyDispatcher2() {
|
|
25469
25686
|
const cfg = liveConfig.all();
|
|
25470
25687
|
const proxy = cfg.providers?.xai?.proxy;
|
|
@@ -25521,16 +25738,48 @@ function detectMode(input) {
|
|
|
25521
25738
|
return "direct";
|
|
25522
25739
|
}
|
|
25523
25740
|
async function generateWithFal(imageB64, prompt, resolution) {
|
|
25741
|
+
let aspectRatio;
|
|
25742
|
+
try {
|
|
25743
|
+
const refBuf = Buffer.from(imageB64, "base64");
|
|
25744
|
+
let w = 0, h = 0;
|
|
25745
|
+
if (refBuf[0] === 137 && refBuf[1] === 80) {
|
|
25746
|
+
w = refBuf.readUInt32BE(16);
|
|
25747
|
+
h = refBuf.readUInt32BE(20);
|
|
25748
|
+
} else if (refBuf[0] === 255 && refBuf[1] === 216) {
|
|
25749
|
+
let pos = 2;
|
|
25750
|
+
while (pos < refBuf.length - 1) {
|
|
25751
|
+
if (refBuf[pos] !== 255) {
|
|
25752
|
+
pos++;
|
|
25753
|
+
continue;
|
|
25754
|
+
}
|
|
25755
|
+
const marker = refBuf[pos + 1];
|
|
25756
|
+
if (marker === 192 || marker === 194) {
|
|
25757
|
+
h = refBuf.readUInt16BE(pos + 5);
|
|
25758
|
+
w = refBuf.readUInt16BE(pos + 7);
|
|
25759
|
+
break;
|
|
25760
|
+
}
|
|
25761
|
+
pos += 2 + refBuf.readUInt16BE(pos + 2);
|
|
25762
|
+
}
|
|
25763
|
+
}
|
|
25764
|
+
if (w > 0 && h > 0) {
|
|
25765
|
+
aspectRatio = `${w}/${h}`;
|
|
25766
|
+
console.log(`[my-selfie] ref image ${w}x${h}, aspect_ratio=${aspectRatio}`);
|
|
25767
|
+
}
|
|
25768
|
+
} catch (e) {
|
|
25769
|
+
console.warn(`[my-selfie] Failed to read ref dimensions: ${e.message}`);
|
|
25770
|
+
}
|
|
25771
|
+
const body = {
|
|
25772
|
+
image_url: `data:image/png;base64,${imageB64}`,
|
|
25773
|
+
prompt,
|
|
25774
|
+
num_images: 1,
|
|
25775
|
+
output_format: "jpeg",
|
|
25776
|
+
resolution
|
|
25777
|
+
};
|
|
25778
|
+
if (aspectRatio) body.aspect_ratio = aspectRatio;
|
|
25524
25779
|
const res = await fetch(FAL_ENDPOINT, {
|
|
25525
25780
|
method: "POST",
|
|
25526
25781
|
headers: { "Authorization": `Key ${FAL_KEY}`, "Content-Type": "application/json" },
|
|
25527
|
-
body: JSON.stringify(
|
|
25528
|
-
image_url: `data:image/png;base64,${imageB64}`,
|
|
25529
|
-
prompt,
|
|
25530
|
-
num_images: 1,
|
|
25531
|
-
output_format: "jpeg",
|
|
25532
|
-
resolution
|
|
25533
|
-
})
|
|
25782
|
+
body: JSON.stringify(body)
|
|
25534
25783
|
});
|
|
25535
25784
|
if (!res.ok) {
|
|
25536
25785
|
const text = await res.text();
|
|
@@ -25739,12 +25988,12 @@ registry.register({
|
|
|
25739
25988
|
const REFERENCES = getReferences(ctx);
|
|
25740
25989
|
const refName = args2.reference || "default";
|
|
25741
25990
|
const refEntry = REFERENCES.find((r) => r.name === refName) || REFERENCES[0];
|
|
25742
|
-
const refPath =
|
|
25743
|
-
if (provider !== "autodl" && !
|
|
25991
|
+
const refPath = path32.join(ctx.workspace, refEntry.p);
|
|
25992
|
+
if (provider !== "autodl" && !fs31.existsSync(refPath)) {
|
|
25744
25993
|
return { content: `Error: reference image not found at ${refPath}`, isError: true };
|
|
25745
25994
|
}
|
|
25746
25995
|
const resolution = args2.resolution || DEFAULT_RESOLUTION;
|
|
25747
|
-
const refB64 =
|
|
25996
|
+
const refB64 = fs31.existsSync(refPath) ? fs31.readFileSync(refPath).toString("base64") : "";
|
|
25748
25997
|
let imageBuffer;
|
|
25749
25998
|
try {
|
|
25750
25999
|
if (provider === "autodl") {
|
|
@@ -25759,11 +26008,11 @@ registry.register({
|
|
|
25759
26008
|
} catch (err) {
|
|
25760
26009
|
return { content: `Selfie generation failed: ${err.message}`, isError: true };
|
|
25761
26010
|
}
|
|
25762
|
-
const imagesDir =
|
|
25763
|
-
if (!
|
|
26011
|
+
const imagesDir = path32.join(ctx.workspace, "images");
|
|
26012
|
+
if (!fs31.existsSync(imagesDir)) fs31.mkdirSync(imagesDir, { recursive: true });
|
|
25764
26013
|
const filename = `selfie_${Date.now()}.jpg`;
|
|
25765
|
-
const outputPath =
|
|
25766
|
-
|
|
26014
|
+
const outputPath = path32.join(imagesDir, filename);
|
|
26015
|
+
fs31.writeFileSync(outputPath, imageBuffer);
|
|
25767
26016
|
const mgr = ctx.channelManager;
|
|
25768
26017
|
if (mgr) {
|
|
25769
26018
|
const resolvedChannel = ctx.channel || "feishu";
|
|
@@ -25774,11 +26023,11 @@ registry.register({
|
|
|
25774
26023
|
mimeType: "image/jpeg"
|
|
25775
26024
|
});
|
|
25776
26025
|
} catch (err) {
|
|
25777
|
-
return { content: `Selfie generated but send failed: ${err.message}. Image: ${
|
|
26026
|
+
return { content: `Selfie generated but send failed: ${err.message}. Image: ${path32.resolve(outputPath)}`, isError: false };
|
|
25778
26027
|
}
|
|
25779
26028
|
return { content: `Selfie sent! Mode: ${mode}, Provider: ${provider}, Ref: ${refEntry.name}` };
|
|
25780
26029
|
}
|
|
25781
|
-
return { content: `Selfie generated! Mode: ${mode}, Ref: ${refEntry.name}. Image: ${
|
|
26030
|
+
return { content: `Selfie generated! Mode: ${mode}, Ref: ${refEntry.name}. Image: ${path32.resolve(outputPath)}` };
|
|
25782
26031
|
},
|
|
25783
26032
|
isConcurrencySafe: () => false,
|
|
25784
26033
|
interruptBehavior: () => "block",
|
|
@@ -26323,16 +26572,16 @@ var EXIT_PLAN_MODE_TOOL_NAME = "ExitPlanMode";
|
|
|
26323
26572
|
init_planModeState();
|
|
26324
26573
|
|
|
26325
26574
|
// src/utils/plans.ts
|
|
26326
|
-
import * as
|
|
26327
|
-
import * as
|
|
26575
|
+
import * as fs33 from "node:fs";
|
|
26576
|
+
import * as path34 from "node:path";
|
|
26328
26577
|
import * as crypto4 from "node:crypto";
|
|
26329
26578
|
var MAX_SLUG_RETRIES = 10;
|
|
26330
26579
|
function generateSlug() {
|
|
26331
26580
|
return crypto4.randomBytes(4).toString("hex");
|
|
26332
26581
|
}
|
|
26333
26582
|
function getPlansDirectory(stateDir) {
|
|
26334
|
-
const plansDir =
|
|
26335
|
-
|
|
26583
|
+
const plansDir = path34.join(stateDir, "plans");
|
|
26584
|
+
fs33.mkdirSync(plansDir, { recursive: true });
|
|
26336
26585
|
return plansDir;
|
|
26337
26586
|
}
|
|
26338
26587
|
var planSlugCache = /* @__PURE__ */ new Map();
|
|
@@ -26342,8 +26591,8 @@ function getPlanSlug(sessionId, stateDir) {
|
|
|
26342
26591
|
const plansDir = getPlansDirectory(stateDir);
|
|
26343
26592
|
for (let i = 0; i < MAX_SLUG_RETRIES; i++) {
|
|
26344
26593
|
slug = generateSlug();
|
|
26345
|
-
const filePath =
|
|
26346
|
-
if (!
|
|
26594
|
+
const filePath = path34.join(plansDir, `${slug}.md`);
|
|
26595
|
+
if (!fs33.existsSync(filePath)) {
|
|
26347
26596
|
break;
|
|
26348
26597
|
}
|
|
26349
26598
|
}
|
|
@@ -26354,21 +26603,21 @@ function getPlanSlug(sessionId, stateDir) {
|
|
|
26354
26603
|
function getPlanFilePath(sessionId, stateDir, agentId) {
|
|
26355
26604
|
const slug = getPlanSlug(sessionId, stateDir);
|
|
26356
26605
|
if (!agentId) {
|
|
26357
|
-
return
|
|
26606
|
+
return path34.join(getPlansDirectory(stateDir), `${slug}.md`);
|
|
26358
26607
|
}
|
|
26359
|
-
return
|
|
26608
|
+
return path34.join(getPlansDirectory(stateDir), `${slug}-agent-${agentId}.md`);
|
|
26360
26609
|
}
|
|
26361
26610
|
function getPlan(sessionId, stateDir, agentId) {
|
|
26362
26611
|
const filePath = getPlanFilePath(sessionId, stateDir, agentId);
|
|
26363
26612
|
try {
|
|
26364
|
-
return
|
|
26613
|
+
return fs33.readFileSync(filePath, "utf-8");
|
|
26365
26614
|
} catch {
|
|
26366
26615
|
return null;
|
|
26367
26616
|
}
|
|
26368
26617
|
}
|
|
26369
26618
|
function writePlan(sessionId, stateDir, content, agentId) {
|
|
26370
26619
|
const filePath = getPlanFilePath(sessionId, stateDir, agentId);
|
|
26371
|
-
|
|
26620
|
+
fs33.writeFileSync(filePath, content, "utf-8");
|
|
26372
26621
|
return filePath;
|
|
26373
26622
|
}
|
|
26374
26623
|
|
|
@@ -27005,7 +27254,7 @@ ${blocks.join("\n")}
|
|
|
27005
27254
|
// src/engine-startup.ts
|
|
27006
27255
|
init_registry();
|
|
27007
27256
|
init_deferred();
|
|
27008
|
-
|
|
27257
|
+
init_features2();
|
|
27009
27258
|
init_license();
|
|
27010
27259
|
|
|
27011
27260
|
// src/tools/memory-bridge.ts
|
|
@@ -27083,7 +27332,7 @@ ${formatted}` };
|
|
|
27083
27332
|
};
|
|
27084
27333
|
}
|
|
27085
27334
|
function createEverosGetTool() {
|
|
27086
|
-
const
|
|
27335
|
+
const fs43 = __require("node:fs/promises");
|
|
27087
27336
|
return {
|
|
27088
27337
|
name: "memory_get",
|
|
27089
27338
|
description: "Read a memory file by path.",
|
|
@@ -27099,7 +27348,7 @@ function createEverosGetTool() {
|
|
|
27099
27348
|
handler: async (args2) => {
|
|
27100
27349
|
try {
|
|
27101
27350
|
const filePath = args2.path;
|
|
27102
|
-
const content = await
|
|
27351
|
+
const content = await fs43.readFile(filePath, "utf-8");
|
|
27103
27352
|
const lines = content.split("\n");
|
|
27104
27353
|
const fromLine = args2.from ?? 1;
|
|
27105
27354
|
const numLines = args2.lines ?? lines.length;
|
|
@@ -27572,11 +27821,11 @@ async function startEngine(config2, opts) {
|
|
|
27572
27821
|
process.env.ENGINE7_WORKSPACE = config2.workspace;
|
|
27573
27822
|
process.env.OPENCLAW_WORKSPACE = config2.workspace;
|
|
27574
27823
|
process.env.ENGINE7_STATE_DIR = config2.stateDir;
|
|
27575
|
-
|
|
27576
|
-
|
|
27577
|
-
|
|
27578
|
-
|
|
27579
|
-
|
|
27824
|
+
fs42.mkdirSync(path45.join(config2.stateDir, "agents", "main", "memory"), { recursive: true });
|
|
27825
|
+
fs42.mkdirSync(path45.join(config2.stateDir, "agents", "main", "sessions"), { recursive: true });
|
|
27826
|
+
fs42.mkdirSync(path45.join(config2.stateDir, "logs"), { recursive: true });
|
|
27827
|
+
fs42.mkdirSync(config2.workspace, { recursive: true });
|
|
27828
|
+
fs42.mkdirSync(config2.mediaDir, { recursive: true });
|
|
27580
27829
|
try {
|
|
27581
27830
|
process.chdir(config2.workspace);
|
|
27582
27831
|
} catch (e) {
|
|
@@ -27631,7 +27880,7 @@ async function startEngine(config2, opts) {
|
|
|
27631
27880
|
const { initSessionMemory: initSessionMemory2 } = await Promise.resolve().then(() => (init_sessionMemory(), sessionMemory_exports));
|
|
27632
27881
|
initSessionMemory2({
|
|
27633
27882
|
workspace: config2.workspace,
|
|
27634
|
-
stateDir:
|
|
27883
|
+
stateDir: path45.join(config2.stateDir, "session-memory"),
|
|
27635
27884
|
provider,
|
|
27636
27885
|
model: config2.provider.modelId || config2.model || "deepseek-v4-flash",
|
|
27637
27886
|
features: config2.profile.features
|
|
@@ -27661,9 +27910,9 @@ async function startEngine(config2, opts) {
|
|
|
27661
27910
|
if (config2.hooks) {
|
|
27662
27911
|
loadHooksFromConfig({ hooks: config2.hooks });
|
|
27663
27912
|
}
|
|
27664
|
-
const hooksPath =
|
|
27913
|
+
const hooksPath = path45.join(config2.workspace, ".hooks.json");
|
|
27665
27914
|
loadHooksFromFile(hooksPath);
|
|
27666
|
-
const settingsHooksPath =
|
|
27915
|
+
const settingsHooksPath = path45.join(config2.stateDir, "settings.json");
|
|
27667
27916
|
loadHooksFromFile(settingsHooksPath);
|
|
27668
27917
|
console.log(`[hooks] Loaded hooks configuration`);
|
|
27669
27918
|
registerCallbackHook("PreCompact", {
|
|
@@ -27677,18 +27926,18 @@ async function startEngine(config2, opts) {
|
|
|
27677
27926
|
const bjTime = new Date(now.getTime() + (bjOffset + now.getTimezoneOffset()) * 6e4);
|
|
27678
27927
|
const dateStr = `${bjTime.getFullYear()}-${String(bjTime.getMonth() + 1).padStart(2, "0")}-${String(bjTime.getDate()).padStart(2, "0")}`;
|
|
27679
27928
|
const timeStr = `${String(bjTime.getHours()).padStart(2, "0")}:${String(bjTime.getMinutes()).padStart(2, "0")}`;
|
|
27680
|
-
const dailyDir =
|
|
27681
|
-
const dailyPath =
|
|
27929
|
+
const dailyDir = path45.join(workspace, "memory", "daily");
|
|
27930
|
+
const dailyPath = path45.join(dailyDir, `${dateStr}.md`);
|
|
27682
27931
|
try {
|
|
27683
|
-
const
|
|
27684
|
-
if (!
|
|
27685
|
-
|
|
27932
|
+
const fs43 = await import("node:fs");
|
|
27933
|
+
if (!fs43.existsSync(dailyDir)) {
|
|
27934
|
+
fs43.mkdirSync(dailyDir, { recursive: true });
|
|
27686
27935
|
}
|
|
27687
|
-
const sessionsDir =
|
|
27688
|
-
const sessionFile =
|
|
27936
|
+
const sessionsDir = path45.join(config2.stateDir, "agents", "main", "sessions");
|
|
27937
|
+
const sessionFile = path45.join(sessionsDir, `${sessionId}.jsonl`);
|
|
27689
27938
|
const recentLines = [];
|
|
27690
|
-
if (
|
|
27691
|
-
const content =
|
|
27939
|
+
if (fs43.existsSync(sessionFile)) {
|
|
27940
|
+
const content = fs43.readFileSync(sessionFile, "utf-8");
|
|
27692
27941
|
const lines = content.trim().split("\n").filter(Boolean);
|
|
27693
27942
|
const userLines = lines.filter((l) => {
|
|
27694
27943
|
try {
|
|
@@ -27718,10 +27967,10 @@ async function startEngine(config2, opts) {
|
|
|
27718
27967
|
const entry = `${header}
|
|
27719
27968
|
${body}
|
|
27720
27969
|
`;
|
|
27721
|
-
if (
|
|
27722
|
-
|
|
27970
|
+
if (fs43.existsSync(dailyPath)) {
|
|
27971
|
+
fs43.appendFileSync(dailyPath, entry);
|
|
27723
27972
|
} else {
|
|
27724
|
-
|
|
27973
|
+
fs43.writeFileSync(dailyPath, `# ${dateStr} \u65E5\u5FD7
|
|
27725
27974
|
${entry}`);
|
|
27726
27975
|
}
|
|
27727
27976
|
console.log(`[hooks] PreCompact: saved ${recentLines.length} lines to ${dailyPath}`);
|
|
@@ -27737,16 +27986,16 @@ ${entry}`);
|
|
|
27737
27986
|
const workspace = input.cwd || input.workspace || "";
|
|
27738
27987
|
if (!workspace) return { continue: true };
|
|
27739
27988
|
try {
|
|
27740
|
-
const
|
|
27741
|
-
const bufferPath =
|
|
27742
|
-
if (
|
|
27743
|
-
const stat4 =
|
|
27989
|
+
const fs43 = await import("node:fs");
|
|
27990
|
+
const bufferPath = path45.join(workspace, "memory", "working-buffer.md");
|
|
27991
|
+
if (fs43.existsSync(bufferPath)) {
|
|
27992
|
+
const stat4 = fs43.statSync(bufferPath);
|
|
27744
27993
|
const ageMs = Date.now() - stat4.mtimeMs;
|
|
27745
27994
|
const ageMin = Math.round(ageMs / 6e4);
|
|
27746
27995
|
if (ageMin > 10) {
|
|
27747
27996
|
console.warn(`[hooks] PostCompact: \u26A0\uFE0F working-buffer.md is ${ageMin}min old (last modified ${stat4.mtime.toISOString()}) \u2014 content may be stale!`);
|
|
27748
27997
|
}
|
|
27749
|
-
const content =
|
|
27998
|
+
const content = fs43.readFileSync(bufferPath, "utf-8");
|
|
27750
27999
|
if (content.trim()) {
|
|
27751
28000
|
console.log(`[hooks] PostCompact: injecting working-buffer (${content.length} chars, ${ageMin}min old)`);
|
|
27752
28001
|
return {
|
|
@@ -27791,7 +28040,7 @@ ${content}`
|
|
|
27791
28040
|
return `${hr}h ${remMin}m`;
|
|
27792
28041
|
}
|
|
27793
28042
|
if (config2.skills?.enabled !== false) {
|
|
27794
|
-
const skillsDir = config2.skills?.path ?
|
|
28043
|
+
const skillsDir = config2.skills?.path ? path45.isAbsolute(config2.skills.path) ? config2.skills.path : path45.resolve(config2.workspace, config2.skills.path) : path45.resolve(config2.workspace, "skills");
|
|
27795
28044
|
const modelDef2 = config2.provider.models.find((m) => m.id === config2.model);
|
|
27796
28045
|
const contextWindowTokens = modelDef2?.contextWindow;
|
|
27797
28046
|
const skills = scanSkills(skillsDir);
|
|
@@ -27810,8 +28059,8 @@ ${content}`
|
|
|
27810
28059
|
workspace: config2.workspace
|
|
27811
28060
|
});
|
|
27812
28061
|
const systemPrompt = [systemStable, systemDynamic].join("\n\n");
|
|
27813
|
-
const promptDumpPath =
|
|
27814
|
-
|
|
28062
|
+
const promptDumpPath = path45.join(config2.workspace, ".system-prompt.txt");
|
|
28063
|
+
fs42.writeFileSync(promptDumpPath, systemPrompt);
|
|
27815
28064
|
console.log(`System prompt: ${systemStable.length} chars stable + ${systemDynamic.length} chars dynamic \u2192 ${promptDumpPath}`);
|
|
27816
28065
|
const modelDef = config2.provider.models.find((m) => m.id === config2.model);
|
|
27817
28066
|
const modelContextWindow = modelDef?.contextWindow;
|
|
@@ -27936,13 +28185,11 @@ ${content}`
|
|
|
27936
28185
|
model: config2.model,
|
|
27937
28186
|
modelInputs: modelDef?.input || ["text"],
|
|
27938
28187
|
systemPrompt,
|
|
27939
|
-
features: config2.profile.features,
|
|
27940
28188
|
channels: config2.channels,
|
|
27941
28189
|
config: config2,
|
|
27942
28190
|
// tool 读自己配置用
|
|
27943
28191
|
recallProvider: memoryRecallProvider || void 0,
|
|
27944
28192
|
extractProvider: memoryExtractProvider || void 0,
|
|
27945
|
-
topics: config2.topics,
|
|
27946
28193
|
everosCfg: config2.everos,
|
|
27947
28194
|
mcpManager
|
|
27948
28195
|
};
|
|
@@ -27959,7 +28206,6 @@ ${content}`
|
|
|
27959
28206
|
model: visionConfig.modelId,
|
|
27960
28207
|
modelInputs: visionModelDef?.input || ["text", "image"],
|
|
27961
28208
|
systemPrompt,
|
|
27962
|
-
features: config2.profile.features,
|
|
27963
28209
|
channels: config2.channels,
|
|
27964
28210
|
config: config2,
|
|
27965
28211
|
// tool 读自己配置用
|
|
@@ -28010,7 +28256,6 @@ ${content}`
|
|
|
28010
28256
|
model: p.model,
|
|
28011
28257
|
modelInputs: p.modelInputs,
|
|
28012
28258
|
systemPrompt,
|
|
28013
|
-
features: config2.profile.features,
|
|
28014
28259
|
channels: config2.channels,
|
|
28015
28260
|
config: config2,
|
|
28016
28261
|
recallProvider: memoryRecallProvider || void 0,
|
|
@@ -28054,7 +28299,6 @@ ${content}`
|
|
|
28054
28299
|
model: modelId,
|
|
28055
28300
|
modelInputs: modelDef2.input || ["text"],
|
|
28056
28301
|
systemPrompt,
|
|
28057
|
-
features: config2.profile.features,
|
|
28058
28302
|
channels: config2.channels,
|
|
28059
28303
|
recallProvider: memoryRecallProvider || void 0,
|
|
28060
28304
|
extractProvider: memoryExtractProvider || void 0
|
|
@@ -28839,8 +29083,7 @@ ${result.changes.map((c) => `- ${c}`).join("\n")}` : `\u274C Reload failed: ${re
|
|
|
28839
29083
|
const featureKeys = ["topic-recall", "topic-extract", "session-memory"];
|
|
28840
29084
|
if (featureKeys.includes(ctx.command)) {
|
|
28841
29085
|
const key = ctx.command;
|
|
28842
|
-
const
|
|
28843
|
-
const cur = f[key] === false ? "off" : "on";
|
|
29086
|
+
const cur = getFeature(key) === false ? "off" : "on";
|
|
28844
29087
|
const rawState = (ctx.args.state || "").trim().toLowerCase();
|
|
28845
29088
|
if (rawState === "") {
|
|
28846
29089
|
await ctx.reply(`\u{1F4CA} ${key}: **${cur}**`);
|
|
@@ -28856,39 +29099,9 @@ ${result.changes.map((c) => `- ${c}`).join("\n")}` : `\u274C Reload failed: ${re
|
|
|
28856
29099
|
return;
|
|
28857
29100
|
}
|
|
28858
29101
|
const next = rawState === "on";
|
|
28859
|
-
|
|
28860
|
-
|
|
28861
|
-
|
|
28862
|
-
try {
|
|
28863
|
-
const fs42 = await import("fs");
|
|
28864
|
-
const pathMod = await import("path");
|
|
28865
|
-
let cfgPath = config2._configFilePath;
|
|
28866
|
-
if (!cfgPath || !fs42.existsSync(cfgPath)) {
|
|
28867
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
28868
|
-
const __dirname = pathMod.dirname(__filename);
|
|
28869
|
-
cfgPath = pathMod.resolve(__dirname, "../configs", pathMod.basename(cfgPath || "engine-config.json"));
|
|
28870
|
-
}
|
|
28871
|
-
const cfg = JSON.parse(fs42.readFileSync(cfgPath, "utf-8"));
|
|
28872
|
-
let featObj = null;
|
|
28873
|
-
if (cfg.agents?.defaults?.features) {
|
|
28874
|
-
featObj = cfg.agents.defaults.features;
|
|
28875
|
-
} else if (cfg.agents?.defaults) {
|
|
28876
|
-
cfg.agents.defaults.features = {};
|
|
28877
|
-
featObj = cfg.agents.defaults.features;
|
|
28878
|
-
}
|
|
28879
|
-
if (featObj) {
|
|
28880
|
-
featObj[key] = next;
|
|
28881
|
-
fs42.writeFileSync(cfgPath, JSON.stringify(cfg, null, 2) + "\n", "utf-8");
|
|
28882
|
-
console.log(`[${ctx.command}] ${key} ${cur} \u2192 ${rawState} (disk persisted)`);
|
|
28883
|
-
await ctx.reply(`\u2705 ${key}: **${cur}** \u2192 **${rawState}**`);
|
|
28884
|
-
} else {
|
|
28885
|
-
console.warn(`[${ctx.command}] could not locate features in config, in-memory only`);
|
|
28886
|
-
await ctx.reply(`\u2705 ${key}: **${cur}** \u2192 **${rawState}**\uFF08\u5185\u5B58\u751F\u6548\uFF0C\u78C1\u76D8\u672A\u627E\u5230 features \u8DEF\u5F84\uFF09`);
|
|
28887
|
-
}
|
|
28888
|
-
} catch (e) {
|
|
28889
|
-
console.warn(`[${ctx.command}] disk write failed: ${e.message}`);
|
|
28890
|
-
await ctx.reply(`\u2705 ${key}: **${cur}** \u2192 **${rawState}**\uFF08\u5185\u5B58\u751F\u6548\uFF0C\u78C1\u76D8\u5199\u5931\u8D25\uFF09`);
|
|
28891
|
-
}
|
|
29102
|
+
await liveConfig.set(`agents.defaults.features.${key}`, next);
|
|
29103
|
+
console.log(`[${ctx.command}] ${key} ${cur} \u2192 ${rawState} (live + persisted)`);
|
|
29104
|
+
await ctx.reply(`\u2705 ${key}: **${cur}** \u2192 **${rawState}**`);
|
|
28892
29105
|
return;
|
|
28893
29106
|
}
|
|
28894
29107
|
if (ctx.command === "model") {
|
|
@@ -29006,11 +29219,11 @@ Auto-routing disabled \u2014 all messages use this model.
|
|
|
29006
29219
|
const input = (ctx.args.model || "").trim();
|
|
29007
29220
|
const configPath2 = config2._configFilePath;
|
|
29008
29221
|
let writePath = configPath2;
|
|
29009
|
-
if (configPath2 && !
|
|
29222
|
+
if (configPath2 && !fs42.existsSync(configPath2)) {
|
|
29010
29223
|
const __pFile = fileURLToPath(import.meta.url);
|
|
29011
|
-
const __pDir =
|
|
29012
|
-
const altPath =
|
|
29013
|
-
if (
|
|
29224
|
+
const __pDir = path45.dirname(__pFile);
|
|
29225
|
+
const altPath = path45.join(path45.resolve(__pDir, "../configs"), path45.basename(configPath2));
|
|
29226
|
+
if (fs42.existsSync(altPath)) {
|
|
29014
29227
|
console.warn(`[primary] Config not found at ${configPath2}, falling back to ${altPath}`);
|
|
29015
29228
|
writePath = altPath;
|
|
29016
29229
|
}
|
|
@@ -29054,14 +29267,14 @@ Use full ref like \`/primary ${candidates[0].ref}\``);
|
|
|
29054
29267
|
return;
|
|
29055
29268
|
}
|
|
29056
29269
|
try {
|
|
29057
|
-
const raw = await
|
|
29270
|
+
const raw = await fs42.promises.readFile(writePath, "utf-8");
|
|
29058
29271
|
const cfg = JSON.parse(raw);
|
|
29059
29272
|
if (!cfg.agents?.defaults?.model) {
|
|
29060
29273
|
await ctx.reply(`\u26A0\uFE0F Config structure mismatch: agents.defaults.model not found`);
|
|
29061
29274
|
return;
|
|
29062
29275
|
}
|
|
29063
29276
|
cfg.agents.defaults.model.primary = target;
|
|
29064
|
-
await
|
|
29277
|
+
await fs42.promises.writeFile(writePath, JSON.stringify(cfg, null, 2), "utf-8");
|
|
29065
29278
|
console.log(`[primary] Persisted primary=${target} to ${writePath}`);
|
|
29066
29279
|
await ctx.reply(`\u2705 Primary model set to **${target}** (${candidates[0].name})
|
|
29067
29280
|
Written to config. **Restart required** to take effect.`);
|
|
@@ -29074,11 +29287,11 @@ Written to config. **Restart required** to take effect.`);
|
|
|
29074
29287
|
const input = (ctx.args.model || "").trim();
|
|
29075
29288
|
const configPath2 = config2._configFilePath;
|
|
29076
29289
|
let writePath = configPath2;
|
|
29077
|
-
if (configPath2 && !
|
|
29290
|
+
if (configPath2 && !fs42.existsSync(configPath2)) {
|
|
29078
29291
|
const __pFile = fileURLToPath(import.meta.url);
|
|
29079
|
-
const __pDir =
|
|
29080
|
-
const altPath =
|
|
29081
|
-
if (
|
|
29292
|
+
const __pDir = path45.dirname(__pFile);
|
|
29293
|
+
const altPath = path45.join(path45.resolve(__pDir, "../configs"), path45.basename(configPath2));
|
|
29294
|
+
if (fs42.existsSync(altPath)) {
|
|
29082
29295
|
console.warn(`[vision-primary] Config not found at ${configPath2}, falling back to ${altPath}`);
|
|
29083
29296
|
writePath = altPath;
|
|
29084
29297
|
}
|
|
@@ -29123,7 +29336,7 @@ Use full ref like \`/vision-primary ${candidates[0].ref}\``);
|
|
|
29123
29336
|
return;
|
|
29124
29337
|
}
|
|
29125
29338
|
try {
|
|
29126
|
-
const raw = await
|
|
29339
|
+
const raw = await fs42.promises.readFile(writePath, "utf-8");
|
|
29127
29340
|
const cfg = JSON.parse(raw);
|
|
29128
29341
|
if (!cfg.agents?.defaults?.model) {
|
|
29129
29342
|
await ctx.reply(`\u26A0\uFE0F Config structure mismatch: agents.defaults.model not found`);
|
|
@@ -29131,12 +29344,12 @@ Use full ref like \`/vision-primary ${candidates[0].ref}\``);
|
|
|
29131
29344
|
}
|
|
29132
29345
|
if (input === "auto" || input === "reset") {
|
|
29133
29346
|
delete cfg.agents.defaults.model.vision;
|
|
29134
|
-
await
|
|
29347
|
+
await fs42.promises.writeFile(writePath, JSON.stringify(cfg, null, 2), "utf-8");
|
|
29135
29348
|
console.log(`[vision-primary] Cleared vision primary in ${writePath}`);
|
|
29136
29349
|
await ctx.reply(`\u2705 Vision primary cleared (auto). Written to config. Hot-reload will apply.`);
|
|
29137
29350
|
} else {
|
|
29138
29351
|
cfg.agents.defaults.model.vision = target;
|
|
29139
|
-
await
|
|
29352
|
+
await fs42.promises.writeFile(writePath, JSON.stringify(cfg, null, 2), "utf-8");
|
|
29140
29353
|
console.log(`[vision-primary] Persisted vision=${target} to ${writePath}`);
|
|
29141
29354
|
await ctx.reply(`\u2705 Vision primary set to **${target}** (${candidates[0].name})
|
|
29142
29355
|
Written to config. Hot-reload will apply.`);
|
|
@@ -29359,7 +29572,7 @@ Use full ref like \`/vision-model ${candidates[0].ref}\``);
|
|
|
29359
29572
|
console.log(`[vision] Downloading image: ${att.filename}`);
|
|
29360
29573
|
let rawBuffer;
|
|
29361
29574
|
if (att.url.startsWith("file://")) {
|
|
29362
|
-
rawBuffer =
|
|
29575
|
+
rawBuffer = fs42.readFileSync(decodeURIComponent(att.url.slice(7)));
|
|
29363
29576
|
} else {
|
|
29364
29577
|
rawBuffer = await downloadImage2(att.url);
|
|
29365
29578
|
}
|
|
@@ -29367,8 +29580,8 @@ Use full ref like \`/vision-model ${candidates[0].ref}\``);
|
|
|
29367
29580
|
const ext = detected.split("/")[1] || "png";
|
|
29368
29581
|
const resized = await maybeResizeAndDownsampleImageBuffer2(rawBuffer, rawBuffer.length, ext);
|
|
29369
29582
|
const imageId = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
29370
|
-
const savedPath =
|
|
29371
|
-
|
|
29583
|
+
const savedPath = path45.join(config2.mediaDir, `${imageId}.${ext}`);
|
|
29584
|
+
fs42.writeFileSync(savedPath, resized.buffer);
|
|
29372
29585
|
savedPaths.push(savedPath);
|
|
29373
29586
|
console.log(`[vision] Saved: ${savedPath} (${resized.buffer.length}B)`);
|
|
29374
29587
|
imageBlocks.push({
|
|
@@ -29394,8 +29607,8 @@ ${pathStr}` }];
|
|
|
29394
29607
|
}
|
|
29395
29608
|
const nonImageAttachments = inbound.attachments?.filter((a) => !a.contentType.startsWith("image/"));
|
|
29396
29609
|
if (nonImageAttachments && nonImageAttachments.length > 0) {
|
|
29397
|
-
const outDir =
|
|
29398
|
-
|
|
29610
|
+
const outDir = path45.join(config2.mediaDir, sessionId);
|
|
29611
|
+
fs42.mkdirSync(outDir, { recursive: true });
|
|
29399
29612
|
const resolved = [];
|
|
29400
29613
|
for (const att of nonImageAttachments) {
|
|
29401
29614
|
console.log(`[file] Downloading: ${att.filename} (${att.contentType}, ${att.size}B)`);
|
|
@@ -29403,9 +29616,9 @@ ${pathStr}` }];
|
|
|
29403
29616
|
const resp = await fetch(att.url);
|
|
29404
29617
|
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
|
|
29405
29618
|
const buffer = Buffer.from(await resp.arrayBuffer());
|
|
29406
|
-
const safeName2 =
|
|
29407
|
-
const savedPath =
|
|
29408
|
-
|
|
29619
|
+
const safeName2 = path45.basename(att.filename).replace(/[<>:"/\\|?*\x00-\x1f]/g, "_") || "attachment";
|
|
29620
|
+
const savedPath = path45.join(outDir, safeName2);
|
|
29621
|
+
fs42.writeFileSync(savedPath, buffer);
|
|
29409
29622
|
resolved.push(savedPath);
|
|
29410
29623
|
console.log(`[file] Saved: ${savedPath} (${buffer.length}B)`);
|
|
29411
29624
|
} catch (err) {
|
|
@@ -29759,7 +29972,7 @@ ${pathStr}` }];
|
|
|
29759
29972
|
console.warn("[cognifold] watcher: config.workspace \u672A\u914D\u7F6E\uFF0C\u8DF3\u8FC7 proactive \u5199\u5165");
|
|
29760
29973
|
return;
|
|
29761
29974
|
}
|
|
29762
|
-
const pFile =
|
|
29975
|
+
const pFile = path45.join(wsDir, ".cognifold-proactive.json");
|
|
29763
29976
|
const cognifoldBaseUrl = config2.cognifold?.baseUrl || "http://127.0.0.1:9001";
|
|
29764
29977
|
const cognifoldSessionId = cfSessionId;
|
|
29765
29978
|
const rawSuggestions = data.suggestions || data.actions || (data.intent_id ? [data] : []);
|
|
@@ -29807,14 +30020,14 @@ ${pathStr}` }];
|
|
|
29807
30020
|
return s;
|
|
29808
30021
|
}));
|
|
29809
30022
|
try {
|
|
29810
|
-
|
|
30023
|
+
fs42.writeFileSync(pFile, JSON.stringify(enriched, null, 2));
|
|
29811
30024
|
console.log(`[cognifold] proactive suggestions saved (${enriched.length} total)`);
|
|
29812
30025
|
} catch (e) {
|
|
29813
30026
|
console.error(`[cognifold] failed to save proactive: ${e.message}`);
|
|
29814
30027
|
}
|
|
29815
30028
|
if (enriched.length > 0) {
|
|
29816
|
-
const promptFile =
|
|
29817
|
-
const promptText =
|
|
30029
|
+
const promptFile = path45.join(config2.workspace, "prompts", "cognifold-proactive.md");
|
|
30030
|
+
const promptText = fs42.existsSync(promptFile) ? fs42.readFileSync(promptFile, "utf-8") : "[CogniFold proactive] \u6709 " + enriched.length + " \u4E2A action \u5230\u671F\u4E86";
|
|
29818
30031
|
const actionsJson = JSON.stringify(enriched, null, 2);
|
|
29819
30032
|
const sessionId = cfSessionId;
|
|
29820
30033
|
const mainSessionId = sessions.getSessionId("scope:main");
|
|
@@ -29981,12 +30194,12 @@ async function doReloadConfig(config2, deps, provider) {
|
|
|
29981
30194
|
try {
|
|
29982
30195
|
const savedConfigPath = config2._configFilePath;
|
|
29983
30196
|
let reloadConfigPath = savedConfigPath;
|
|
29984
|
-
if (!
|
|
30197
|
+
if (!fs42.existsSync(reloadConfigPath)) {
|
|
29985
30198
|
const __filename = fileURLToPath(import.meta.url);
|
|
29986
|
-
const __dirname =
|
|
29987
|
-
const engineConfigsDir =
|
|
29988
|
-
const altPath =
|
|
29989
|
-
if (
|
|
30199
|
+
const __dirname = path45.dirname(__filename);
|
|
30200
|
+
const engineConfigsDir = path45.resolve(__dirname, "../configs");
|
|
30201
|
+
const altPath = path45.join(engineConfigsDir, path45.basename(savedConfigPath));
|
|
30202
|
+
if (fs42.existsSync(altPath)) {
|
|
29990
30203
|
console.warn(`[reload] Config not found at ${reloadConfigPath}, falling back to ${altPath} (dev mode)`);
|
|
29991
30204
|
reloadConfigPath = altPath;
|
|
29992
30205
|
}
|
|
@@ -30059,12 +30272,6 @@ async function doReloadConfig(config2, deps, provider) {
|
|
|
30059
30272
|
deps.extractProvider = newExtract;
|
|
30060
30273
|
changes.push(`extract \u2192 ${newConfig.topics?.extract?.provider}/${newConfig.topics?.extract?.model}`);
|
|
30061
30274
|
}
|
|
30062
|
-
if (newConfig.topics) {
|
|
30063
|
-
deps.topics = newConfig.topics;
|
|
30064
|
-
}
|
|
30065
|
-
if (newConfig.profile?.features) {
|
|
30066
|
-
deps.features = newConfig.profile.features;
|
|
30067
|
-
}
|
|
30068
30275
|
try {
|
|
30069
30276
|
const { setAutoDreamConfig: setAutoDreamConfig2 } = await Promise.resolve().then(() => (init_config2(), config_exports));
|
|
30070
30277
|
setAutoDreamConfig2(newConfig);
|
|
@@ -30110,7 +30317,7 @@ async function doReloadConfig(config2, deps, provider) {
|
|
|
30110
30317
|
} catch (err) {
|
|
30111
30318
|
console.error(`[reload] Failed: ${err.message}`);
|
|
30112
30319
|
try {
|
|
30113
|
-
|
|
30320
|
+
fs42.appendFileSync(path45.join(config2.stateDir, "logs", "engine-config-watch.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] RELOAD FAILED: ${err.message}
|
|
30114
30321
|
${err.stack}
|
|
30115
30322
|
`);
|
|
30116
30323
|
} catch {
|
|
@@ -30121,36 +30328,36 @@ ${err.stack}
|
|
|
30121
30328
|
function startConfigWatcher(config2, deps, provider) {
|
|
30122
30329
|
const raw = config2._configFilePath;
|
|
30123
30330
|
let configPath2 = raw;
|
|
30124
|
-
if (!
|
|
30125
|
-
configPath2 =
|
|
30331
|
+
if (!fs42.existsSync(configPath2)) {
|
|
30332
|
+
configPath2 = path45.resolve(raw);
|
|
30126
30333
|
}
|
|
30127
|
-
if (!
|
|
30334
|
+
if (!fs42.existsSync(configPath2)) {
|
|
30128
30335
|
const __filename2 = fileURLToPath(import.meta.url);
|
|
30129
|
-
const __dirname22 =
|
|
30130
|
-
configPath2 =
|
|
30336
|
+
const __dirname22 = path45.dirname(__filename2);
|
|
30337
|
+
configPath2 = path45.resolve(__dirname22, "..", raw);
|
|
30131
30338
|
}
|
|
30132
|
-
if (!
|
|
30339
|
+
if (!fs42.existsSync(configPath2)) {
|
|
30133
30340
|
console.warn(`[config-watch] config path invalid: ${configPath2}, watcher disabled`);
|
|
30134
30341
|
try {
|
|
30135
|
-
|
|
30342
|
+
fs42.appendFileSync(path45.join(config2.stateDir, "logs", "engine-config-watch.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] DISABLED: configPath=${configPath2}
|
|
30136
30343
|
`);
|
|
30137
30344
|
} catch {
|
|
30138
30345
|
}
|
|
30139
30346
|
return null;
|
|
30140
30347
|
}
|
|
30141
30348
|
let debounceTimer = null;
|
|
30142
|
-
const watcher =
|
|
30349
|
+
const watcher = fs42.watch(configPath2, { persistent: true }, (eventType) => {
|
|
30143
30350
|
if (debounceTimer) clearTimeout(debounceTimer);
|
|
30144
30351
|
debounceTimer = setTimeout(async () => {
|
|
30145
30352
|
console.log(`[config-watch] file changed (${eventType}), reloading...`);
|
|
30146
30353
|
try {
|
|
30147
|
-
|
|
30354
|
+
fs42.appendFileSync(path45.join(config2.stateDir, "logs", "engine-config-watch.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] CHANGE eventType=${eventType}, calling doReloadConfig
|
|
30148
30355
|
`);
|
|
30149
30356
|
} catch {
|
|
30150
30357
|
}
|
|
30151
30358
|
const result = await doReloadConfig(config2, deps, provider);
|
|
30152
30359
|
try {
|
|
30153
|
-
|
|
30360
|
+
fs42.appendFileSync(path45.join(config2.stateDir, "logs", "engine-config-watch.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] RELOAD DONE: ok=${result.ok} changes=${result.changes.join(",")}
|
|
30154
30361
|
`);
|
|
30155
30362
|
} catch {
|
|
30156
30363
|
}
|
|
@@ -30159,30 +30366,30 @@ function startConfigWatcher(config2, deps, provider) {
|
|
|
30159
30366
|
watcher.on("error", (err) => {
|
|
30160
30367
|
console.error(`[config-watch] error: ${err.message}`);
|
|
30161
30368
|
try {
|
|
30162
|
-
|
|
30369
|
+
fs42.appendFileSync(path45.join(config2.stateDir, "logs", "engine-config-watch.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] ERROR: ${err.message}
|
|
30163
30370
|
`);
|
|
30164
30371
|
} catch {
|
|
30165
30372
|
}
|
|
30166
30373
|
});
|
|
30167
30374
|
console.log(`[config-watch] watching ${configPath2}`);
|
|
30168
30375
|
try {
|
|
30169
|
-
|
|
30376
|
+
fs42.appendFileSync(path45.join(config2.stateDir, "logs", "engine-config-watch.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] STARTED watching=${configPath2}
|
|
30170
30377
|
`);
|
|
30171
30378
|
} catch {
|
|
30172
30379
|
}
|
|
30173
30380
|
return watcher;
|
|
30174
30381
|
}
|
|
30175
30382
|
function startSecretsWatcher(config2, deps, provider) {
|
|
30176
|
-
const secretsDir =
|
|
30177
|
-
const cfgBase =
|
|
30383
|
+
const secretsDir = path45.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7-secrets");
|
|
30384
|
+
const cfgBase = path45.basename(config2._configFilePath || "", ".json");
|
|
30178
30385
|
const secretCandidates = [
|
|
30179
|
-
|
|
30180
|
-
|
|
30181
|
-
|
|
30386
|
+
path45.join(secretsDir, `${cfgBase}.env`),
|
|
30387
|
+
path45.join(path45.dirname(config2._configFilePath || ""), `.env.${cfgBase}`),
|
|
30388
|
+
path45.join(path45.dirname(config2._configFilePath || ""), ".env")
|
|
30182
30389
|
];
|
|
30183
30390
|
let secretsPath = null;
|
|
30184
30391
|
for (const p of secretCandidates) {
|
|
30185
|
-
if (
|
|
30392
|
+
if (fs42.existsSync(p)) {
|
|
30186
30393
|
secretsPath = p;
|
|
30187
30394
|
break;
|
|
30188
30395
|
}
|
|
@@ -30195,9 +30402,9 @@ function startSecretsWatcher(config2, deps, provider) {
|
|
|
30195
30402
|
let activeWatcher = null;
|
|
30196
30403
|
const startWatch = () => {
|
|
30197
30404
|
if (activeWatcher) activeWatcher.close();
|
|
30198
|
-
activeWatcher =
|
|
30405
|
+
activeWatcher = fs42.watch(secretsPath, { persistent: true }, (eventType) => {
|
|
30199
30406
|
if (eventType === "rename") {
|
|
30200
|
-
if (
|
|
30407
|
+
if (fs42.existsSync(secretsPath)) {
|
|
30201
30408
|
console.log("[secrets-watch] rename detected, re-watching file...");
|
|
30202
30409
|
startWatch();
|
|
30203
30410
|
} else {
|
|
@@ -30209,7 +30416,7 @@ function startSecretsWatcher(config2, deps, provider) {
|
|
|
30209
30416
|
debounceTimer = setTimeout(async () => {
|
|
30210
30417
|
console.log(`[secrets-watch] file changed (${eventType}), reloading secrets...`);
|
|
30211
30418
|
try {
|
|
30212
|
-
const content =
|
|
30419
|
+
const content = fs42.readFileSync(secretsPath, "utf-8");
|
|
30213
30420
|
let updated = 0;
|
|
30214
30421
|
for (const line of content.split("\n")) {
|
|
30215
30422
|
const trimmed = line.trim();
|
|
@@ -30228,7 +30435,7 @@ function startSecretsWatcher(config2, deps, provider) {
|
|
|
30228
30435
|
const result = await doReloadConfig(config2, deps, provider);
|
|
30229
30436
|
console.log(`[secrets-watch] config reloaded: ok=${result.ok} changes=${result.changes.join(",")}`);
|
|
30230
30437
|
try {
|
|
30231
|
-
|
|
30438
|
+
fs42.appendFileSync(path45.join(config2.stateDir, "logs", "engine-config-watch.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] SECRETS RELOAD: ok=${result.ok} keys=${updated}
|
|
30232
30439
|
`);
|
|
30233
30440
|
} catch {
|
|
30234
30441
|
}
|
|
@@ -30289,7 +30496,7 @@ if (!configPath) {
|
|
|
30289
30496
|
}
|
|
30290
30497
|
if (args[0] === "features") {
|
|
30291
30498
|
const { getLicenseStatus: getLicenseStatus2 } = await Promise.resolve().then(() => (init_license(), license_exports));
|
|
30292
|
-
const { listFeatures: listFeatures2 } = await Promise.resolve().then(() => (
|
|
30499
|
+
const { listFeatures: listFeatures2 } = await Promise.resolve().then(() => (init_features2(), features_exports));
|
|
30293
30500
|
const stateDir = process.env.ENGINE_STATE_DIR || ".";
|
|
30294
30501
|
const status = getLicenseStatus2(stateDir);
|
|
30295
30502
|
const allFeatures = listFeatures2();
|