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/engine-startup.mjs
CHANGED
|
@@ -174,17 +174,19 @@ var init_types = __esm({
|
|
|
174
174
|
"src/messages/types.ts"() {
|
|
175
175
|
"use strict";
|
|
176
176
|
msg = {
|
|
177
|
-
system: (content) => ({ role: "system", content }),
|
|
178
|
-
user: (content) => ({ role: "user", content }),
|
|
177
|
+
system: (content) => ({ role: "system", content, timestamp: (/* @__PURE__ */ new Date()).toISOString() }),
|
|
178
|
+
user: (content) => ({ role: "user", content, timestamp: (/* @__PURE__ */ new Date()).toISOString() }),
|
|
179
179
|
assistant: (content, tool_calls) => ({
|
|
180
180
|
role: "assistant",
|
|
181
181
|
content,
|
|
182
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
182
183
|
...tool_calls ? { tool_calls } : {}
|
|
183
184
|
}),
|
|
184
185
|
tool: (tool_call_id, content, isError) => ({
|
|
185
186
|
role: "tool",
|
|
186
187
|
tool_call_id,
|
|
187
188
|
content,
|
|
189
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
188
190
|
...isError ? { is_error: true } : {}
|
|
189
191
|
})
|
|
190
192
|
};
|
|
@@ -2139,9 +2141,9 @@ function isAutoMemPath(absolutePath, workspace) {
|
|
|
2139
2141
|
return normalizedPath.startsWith(getAutoMemPath(workspace));
|
|
2140
2142
|
}
|
|
2141
2143
|
async function ensureMemoryDirExists(memoryDir) {
|
|
2142
|
-
const
|
|
2144
|
+
const fs43 = await import("node:fs");
|
|
2143
2145
|
try {
|
|
2144
|
-
await
|
|
2146
|
+
await fs43.promises.mkdir(memoryDir, { recursive: true });
|
|
2145
2147
|
} catch (e) {
|
|
2146
2148
|
const code = e?.code;
|
|
2147
2149
|
if (code !== "EEXIST") {
|
|
@@ -3343,6 +3345,41 @@ var init_live = __esm({
|
|
|
3343
3345
|
}
|
|
3344
3346
|
Object.assign(this.current, newConfig);
|
|
3345
3347
|
}
|
|
3348
|
+
/** 改活树上的值;文件承载路径同步持久化(read-modify-write 回 config 文件) */
|
|
3349
|
+
async set(dotPath, val) {
|
|
3350
|
+
if (!this.current) throw new Error("[liveConfig] not initialized \u2014 call liveConfig.init() first");
|
|
3351
|
+
const keys = dotPath.split(".");
|
|
3352
|
+
let obj = this.current;
|
|
3353
|
+
for (let i = 0; i < keys.length - 1; i++) {
|
|
3354
|
+
if (obj[keys[i]] == null) obj[keys[i]] = {};
|
|
3355
|
+
obj = obj[keys[i]];
|
|
3356
|
+
}
|
|
3357
|
+
obj[keys[keys.length - 1]] = val;
|
|
3358
|
+
await this.persistToFile(dotPath, val);
|
|
3359
|
+
}
|
|
3360
|
+
/** 把改动写回 config 文件对应段(找不到文件路径则只内存生效) */
|
|
3361
|
+
async persistToFile(dotPath, val) {
|
|
3362
|
+
const fs43 = await import("node:fs");
|
|
3363
|
+
const cfgPath = this.current?._configFilePath;
|
|
3364
|
+
if (!cfgPath || !fs43.existsSync(cfgPath)) {
|
|
3365
|
+
console.warn(`[liveConfig] set: no config file path, in-memory only (${dotPath})`);
|
|
3366
|
+
return;
|
|
3367
|
+
}
|
|
3368
|
+
try {
|
|
3369
|
+
const raw = JSON.parse(fs43.readFileSync(cfgPath, "utf-8"));
|
|
3370
|
+
const keys = dotPath.split(".");
|
|
3371
|
+
let o = raw;
|
|
3372
|
+
for (let i = 0; i < keys.length - 1; i++) {
|
|
3373
|
+
if (o[keys[i]] == null) o[keys[i]] = {};
|
|
3374
|
+
o = o[keys[i]];
|
|
3375
|
+
}
|
|
3376
|
+
o[keys[keys.length - 1]] = val;
|
|
3377
|
+
fs43.writeFileSync(cfgPath, JSON.stringify(raw, null, 2) + "\n", "utf-8");
|
|
3378
|
+
console.log(`[liveConfig] persisted ${dotPath} = ${JSON.stringify(val)} to ${cfgPath}`);
|
|
3379
|
+
} catch (e) {
|
|
3380
|
+
console.warn(`[liveConfig] persist failed (${dotPath}): ${e.message}`);
|
|
3381
|
+
}
|
|
3382
|
+
}
|
|
3346
3383
|
/** 是否已初始化 */
|
|
3347
3384
|
isReady() {
|
|
3348
3385
|
return this.current !== null;
|
|
@@ -3352,6 +3389,40 @@ var init_live = __esm({
|
|
|
3352
3389
|
}
|
|
3353
3390
|
});
|
|
3354
3391
|
|
|
3392
|
+
// src/config/features.ts
|
|
3393
|
+
function getFeature(key) {
|
|
3394
|
+
const v = liveConfig.get(`agents.defaults.features.${key}`);
|
|
3395
|
+
return v === void 0 ? FEATURE_DEFAULTS[key] : v;
|
|
3396
|
+
}
|
|
3397
|
+
var FEATURE_DEFAULTS;
|
|
3398
|
+
var init_features = __esm({
|
|
3399
|
+
"src/config/features.ts"() {
|
|
3400
|
+
"use strict";
|
|
3401
|
+
init_live();
|
|
3402
|
+
FEATURE_DEFAULTS = {
|
|
3403
|
+
filesystem: true,
|
|
3404
|
+
shell: true,
|
|
3405
|
+
memory: true,
|
|
3406
|
+
"topic-extract": true,
|
|
3407
|
+
"topic-recall": true,
|
|
3408
|
+
"session-memory": true,
|
|
3409
|
+
todo: true,
|
|
3410
|
+
cron: false,
|
|
3411
|
+
voice: false,
|
|
3412
|
+
selfie: false,
|
|
3413
|
+
eyes: false,
|
|
3414
|
+
calendar: false,
|
|
3415
|
+
webSearch: true,
|
|
3416
|
+
webFetch: true,
|
|
3417
|
+
agentTeams: true,
|
|
3418
|
+
autoDream: true,
|
|
3419
|
+
processOutput: "verbose",
|
|
3420
|
+
interrupt: "command",
|
|
3421
|
+
debounceMs: 5e3
|
|
3422
|
+
};
|
|
3423
|
+
}
|
|
3424
|
+
});
|
|
3425
|
+
|
|
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(config) {
|
|
5558
5749
|
_config = config;
|
|
5559
|
-
const c = config;
|
|
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 = args.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 = args.path ? resolvePath(args.path, ctx.workspace) : ctx.workspace;
|
|
7075
7258
|
const pattern = args.pattern;
|
|
7076
7259
|
const limit = args.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(args, searchPath, signal) {
|
|
7107
7290
|
return new Promise((resolve10) => {
|
|
7108
7291
|
const fullArgs = [...args, 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(config) {
|
|
|
8200
8383
|
_config2 = config;
|
|
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 (args) => {
|
|
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 (args.task_id) {
|
|
10450
|
-
const file =
|
|
10451
|
-
if (!
|
|
10634
|
+
const file = path46.join(resultsDir, `${args.task_id}.json`);
|
|
10635
|
+
if (!fs43.existsSync(file)) {
|
|
10452
10636
|
return { content: `\u4EFB\u52A1 ${args.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 ? "..." : ""}`;
|
|
@@ -10626,8 +10810,8 @@ var manager_exports = {};
|
|
|
10626
10810
|
__export(manager_exports, {
|
|
10627
10811
|
McpManager: () => McpManager
|
|
10628
10812
|
});
|
|
10629
|
-
import * as
|
|
10630
|
-
import * as
|
|
10813
|
+
import * as fs41 from "node:fs";
|
|
10814
|
+
import * as path43 from "node:path";
|
|
10631
10815
|
import { Client as Client3 } from "@modelcontextprotocol/sdk/client/index.js";
|
|
10632
10816
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
10633
10817
|
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
@@ -10660,12 +10844,12 @@ function convertInputSchema(inputSchema) {
|
|
|
10660
10844
|
}
|
|
10661
10845
|
function persistBinary(base64Data, mimeType, persistId) {
|
|
10662
10846
|
const ext = mimeType?.split("/")[1] || "bin";
|
|
10663
|
-
const dir =
|
|
10664
|
-
|
|
10665
|
-
const filepath =
|
|
10847
|
+
const dir = path43.join(process.env.ENGINE_STATE_DIR || ".engine", "mcp-blobs");
|
|
10848
|
+
fs41.mkdirSync(dir, { recursive: true });
|
|
10849
|
+
const filepath = path43.join(dir, `${persistId}.${ext}`);
|
|
10666
10850
|
try {
|
|
10667
10851
|
const buf = Buffer.from(base64Data, "base64");
|
|
10668
|
-
|
|
10852
|
+
fs41.writeFileSync(filepath, buf);
|
|
10669
10853
|
return { filepath, size: buf.length };
|
|
10670
10854
|
} catch (err) {
|
|
10671
10855
|
return { error: err.message };
|
|
@@ -10999,7 +11183,7 @@ __export(resources_exports, {
|
|
|
10999
11183
|
registerMcpResourceTools: () => registerMcpResourceTools,
|
|
11000
11184
|
unregisterMcpResourceTools: () => unregisterMcpResourceTools
|
|
11001
11185
|
});
|
|
11002
|
-
import * as
|
|
11186
|
+
import * as path44 from "node:path";
|
|
11003
11187
|
function registerMcpResourceTools(manager) {
|
|
11004
11188
|
mcpManagerRef = manager;
|
|
11005
11189
|
registry.register(listResourcesTool);
|
|
@@ -11017,7 +11201,7 @@ var init_resources = __esm({
|
|
|
11017
11201
|
"use strict";
|
|
11018
11202
|
init_registry();
|
|
11019
11203
|
MAX_RESULT_CHARS2 = 1e5;
|
|
11020
|
-
MEDIA_DIR = process.env.ENGINE_MEDIA_DIR ||
|
|
11204
|
+
MEDIA_DIR = process.env.ENGINE_MEDIA_DIR || path44.join(process.env.ENGINE_STATE_DIR || ".engine", "media", "inbound");
|
|
11021
11205
|
MCP_LIST_RESOURCES_TOOL = "mcp__list_resources";
|
|
11022
11206
|
MCP_READ_RESOURCE_TOOL = "mcp__read_resource";
|
|
11023
11207
|
mcpManagerRef = null;
|
|
@@ -11186,10 +11370,10 @@ function ensureLoaded(workspace, configIds) {
|
|
|
11186
11370
|
if (!state.blockedUserIds.includes(id)) state.blockedUserIds.push(id);
|
|
11187
11371
|
}
|
|
11188
11372
|
}
|
|
11189
|
-
const
|
|
11373
|
+
const path46 = join38(workspace, ".reply-blocklist.json");
|
|
11190
11374
|
try {
|
|
11191
|
-
if (existsSync24(
|
|
11192
|
-
const raw = readFileSync26(
|
|
11375
|
+
if (existsSync24(path46)) {
|
|
11376
|
+
const raw = readFileSync26(path46, "utf-8");
|
|
11193
11377
|
const parsed = JSON.parse(raw);
|
|
11194
11378
|
if (parsed.blockedUserIds) {
|
|
11195
11379
|
for (const id of parsed.blockedUserIds) {
|
|
@@ -11205,9 +11389,9 @@ function ensureLoaded(workspace, configIds) {
|
|
|
11205
11389
|
loaded = true;
|
|
11206
11390
|
}
|
|
11207
11391
|
function save(workspace) {
|
|
11208
|
-
const
|
|
11392
|
+
const path46 = join38(workspace, ".reply-blocklist.json");
|
|
11209
11393
|
try {
|
|
11210
|
-
writeFileSync16(
|
|
11394
|
+
writeFileSync16(path46, JSON.stringify(state, null, 2), "utf-8");
|
|
11211
11395
|
} catch (err) {
|
|
11212
11396
|
console.warn(`[reply-blocklist] Failed to save: ${err.message}`);
|
|
11213
11397
|
}
|
|
@@ -11804,8 +11988,8 @@ var init_cognifold_intent_watcher = __esm({
|
|
|
11804
11988
|
});
|
|
11805
11989
|
|
|
11806
11990
|
// src/engine-startup.ts
|
|
11807
|
-
import * as
|
|
11808
|
-
import * as
|
|
11991
|
+
import * as path45 from "node:path";
|
|
11992
|
+
import * as fs42 from "node:fs";
|
|
11809
11993
|
import { fileURLToPath } from "node:url";
|
|
11810
11994
|
|
|
11811
11995
|
// src/pid-lock.ts
|
|
@@ -11961,6 +12145,7 @@ function loadDisplayConfig(raw) {
|
|
|
11961
12145
|
}
|
|
11962
12146
|
|
|
11963
12147
|
// src/config/loader.ts
|
|
12148
|
+
init_features();
|
|
11964
12149
|
function parseModelRef(ref) {
|
|
11965
12150
|
const idx = ref.indexOf("/");
|
|
11966
12151
|
if (idx <= 0 || idx === ref.length - 1) {
|
|
@@ -12054,6 +12239,13 @@ function loadConfig(configPath) {
|
|
|
12054
12239
|
const stateDir = raw.stateDir || process.env.ENGINE_STATE_DIR || path3.resolve(".engine");
|
|
12055
12240
|
const workspace = process.env.ENGINE_WORKSPACE || agentDefaults.workspace || path3.join(stateDir, "workspace");
|
|
12056
12241
|
const mediaDir = raw.mediaDir || path3.join(stateDir, "media", "inbound");
|
|
12242
|
+
if (!agentDefaults.features) agentDefaults.features = {};
|
|
12243
|
+
for (const [k, v] of Object.entries(FEATURE_DEFAULTS)) {
|
|
12244
|
+
if (agentDefaults.features[k] === void 0) {
|
|
12245
|
+
;
|
|
12246
|
+
agentDefaults.features[k] = v;
|
|
12247
|
+
}
|
|
12248
|
+
}
|
|
12057
12249
|
const profile = {
|
|
12058
12250
|
id: process.env.ENGINE_AGENT || "default",
|
|
12059
12251
|
name: agentDefaults.name || "AI Assistant",
|
|
@@ -12061,27 +12253,8 @@ function loadConfig(configPath) {
|
|
|
12061
12253
|
workspace,
|
|
12062
12254
|
soul: agentDefaults.soul,
|
|
12063
12255
|
agents: agentDefaults.agents,
|
|
12064
|
-
features:
|
|
12065
|
-
|
|
12066
|
-
shell: true,
|
|
12067
|
-
memory: true,
|
|
12068
|
-
"topic-extract": true,
|
|
12069
|
-
"topic-recall": true,
|
|
12070
|
-
"session-memory": true,
|
|
12071
|
-
todo: true,
|
|
12072
|
-
cron: false,
|
|
12073
|
-
voice: false,
|
|
12074
|
-
selfie: false,
|
|
12075
|
-
eyes: false,
|
|
12076
|
-
calendar: false,
|
|
12077
|
-
webSearch: true,
|
|
12078
|
-
webFetch: true,
|
|
12079
|
-
agentTeams: true,
|
|
12080
|
-
processOutput: "verbose",
|
|
12081
|
-
interrupt: "command",
|
|
12082
|
-
debounceMs: 5e3,
|
|
12083
|
-
...agentDefaults.features || {}
|
|
12084
|
-
},
|
|
12256
|
+
features: agentDefaults.features,
|
|
12257
|
+
// canonical:profile.features 即 agents.defaults.features(同一对象,过渡兼容)
|
|
12085
12258
|
channels: agentDefaults.channels || [],
|
|
12086
12259
|
extensions: agentDefaults.extensions,
|
|
12087
12260
|
maxTurns: agentDefaults.maxTurns,
|
|
@@ -12170,6 +12343,7 @@ function loadConfig(configPath) {
|
|
|
12170
12343
|
|
|
12171
12344
|
// src/engine-startup.ts
|
|
12172
12345
|
init_live();
|
|
12346
|
+
init_features();
|
|
12173
12347
|
|
|
12174
12348
|
// src/services/withRetry.ts
|
|
12175
12349
|
import { ProxyAgent } from "undici";
|
|
@@ -13430,13 +13604,13 @@ var DiscordAdapter = class _DiscordAdapter {
|
|
|
13430
13604
|
}
|
|
13431
13605
|
/** 发送媒体附件(图片/文件/音频)— discord.js channel.send({ files }) */
|
|
13432
13606
|
async sendFile(target, message, attachment) {
|
|
13433
|
-
const
|
|
13434
|
-
const
|
|
13435
|
-
if (!
|
|
13607
|
+
const fs43 = await import("node:fs");
|
|
13608
|
+
const path46 = await import("node:path");
|
|
13609
|
+
if (!fs43.existsSync(attachment.path)) {
|
|
13436
13610
|
throw new Error(`File not found: ${attachment.path}`);
|
|
13437
13611
|
}
|
|
13438
|
-
const filename = attachment.filename ||
|
|
13439
|
-
const fileBuffer =
|
|
13612
|
+
const filename = attachment.filename || path46.basename(attachment.path);
|
|
13613
|
+
const fileBuffer = fs43.readFileSync(attachment.path);
|
|
13440
13614
|
const filePayload = {
|
|
13441
13615
|
attachment: fileBuffer,
|
|
13442
13616
|
name: filename
|
|
@@ -13876,13 +14050,13 @@ var FeishuAdapter = class _FeishuAdapter {
|
|
|
13876
14050
|
}
|
|
13877
14051
|
/** 发送媒体附件(图片/文件) */
|
|
13878
14052
|
async sendFile(target, message, attachment) {
|
|
13879
|
-
const
|
|
13880
|
-
const
|
|
13881
|
-
if (!
|
|
14053
|
+
const fs43 = await import("node:fs");
|
|
14054
|
+
const path46 = await import("node:path");
|
|
14055
|
+
if (!fs43.existsSync(attachment.path)) {
|
|
13882
14056
|
throw new Error(`File not found: ${attachment.path}`);
|
|
13883
14057
|
}
|
|
13884
|
-
const filename = attachment.filename ||
|
|
13885
|
-
const fileBuffer =
|
|
14058
|
+
const filename = attachment.filename || path46.basename(attachment.path);
|
|
14059
|
+
const fileBuffer = fs43.readFileSync(attachment.path);
|
|
13886
14060
|
const receiveIdType = target.startsWith("ou_") ? "open_id" : "chat_id";
|
|
13887
14061
|
const mimeType = attachment.mimeType || "application/octet-stream";
|
|
13888
14062
|
if (mimeType.startsWith("image/")) {
|
|
@@ -14159,6 +14333,7 @@ var FeishuAdapter = class _FeishuAdapter {
|
|
|
14159
14333
|
const message = data?.message;
|
|
14160
14334
|
if (!sender || !message) return;
|
|
14161
14335
|
const messageId = message.message_id || "";
|
|
14336
|
+
console.log(`[feishu] recv msg_type=${message.message_type} chat=${message.chat_type} from=${sender.sender_id?.open_id?.slice(0, 10)}`);
|
|
14162
14337
|
if (this.recentMessageIds.has(messageId)) return;
|
|
14163
14338
|
this.recentMessageIds.add(messageId);
|
|
14164
14339
|
if (this.recentMessageIds.size > 500) {
|
|
@@ -14273,6 +14448,13 @@ var FeishuAdapter = class _FeishuAdapter {
|
|
|
14273
14448
|
if (msgType === "file") {
|
|
14274
14449
|
return { text: `[\u6587\u4EF6: ${parsed.file_name || "\u672A\u77E5\u6587\u4EF6"}]`, imageKeys, fileKey: parsed.file_key, fileName: parsed.file_name };
|
|
14275
14450
|
}
|
|
14451
|
+
if (msgType === "share_location" || msgType === "location") {
|
|
14452
|
+
const name = parsed.name || "";
|
|
14453
|
+
const lat = parsed.latitude || "";
|
|
14454
|
+
const lng = parsed.longitude || "";
|
|
14455
|
+
const text = `[\u4F4D\u7F6E: ${name}${lat && lng ? ` (${lat}, ${lng})` : ""}]`;
|
|
14456
|
+
return { text, imageKeys };
|
|
14457
|
+
}
|
|
14276
14458
|
if (msgType === "post") {
|
|
14277
14459
|
const lines = [];
|
|
14278
14460
|
if (Array.isArray(parsed.content)) {
|
|
@@ -16630,7 +16812,7 @@ function entryToSessionMessage(entry) {
|
|
|
16630
16812
|
if (role === "user") {
|
|
16631
16813
|
const text = extractText2(m.content);
|
|
16632
16814
|
if (text !== null) {
|
|
16633
|
-
return { role: "user", content: text, _raw: entry.raw };
|
|
16815
|
+
return { role: "user", content: text, timestamp: entry.timestamp, _raw: entry.raw };
|
|
16634
16816
|
}
|
|
16635
16817
|
return null;
|
|
16636
16818
|
} else if (role === "assistant") {
|
|
@@ -16653,6 +16835,7 @@ function entryToSessionMessage(entry) {
|
|
|
16653
16835
|
const result = {
|
|
16654
16836
|
role: "assistant",
|
|
16655
16837
|
content: textContent,
|
|
16838
|
+
timestamp: entry.timestamp,
|
|
16656
16839
|
_raw: entry.raw
|
|
16657
16840
|
};
|
|
16658
16841
|
if (toolCalls.length > 0) {
|
|
@@ -16664,6 +16847,7 @@ function entryToSessionMessage(entry) {
|
|
|
16664
16847
|
return {
|
|
16665
16848
|
role: "tool",
|
|
16666
16849
|
content: text || "",
|
|
16850
|
+
timestamp: entry.timestamp,
|
|
16667
16851
|
tool_call_id: m.toolCallId,
|
|
16668
16852
|
_raw: entry.raw
|
|
16669
16853
|
};
|
|
@@ -17077,16 +17261,22 @@ var SessionManager = class {
|
|
|
17077
17261
|
continue;
|
|
17078
17262
|
}
|
|
17079
17263
|
if (m.role === "user") {
|
|
17080
|
-
|
|
17264
|
+
const u = msg.user(m.content);
|
|
17265
|
+
if (m.timestamp) u.timestamp = m.timestamp;
|
|
17266
|
+
allMessages.push(u);
|
|
17081
17267
|
} else if (m.role === "assistant") {
|
|
17082
17268
|
const toolCalls = m.tool_calls?.map((tc) => ({
|
|
17083
17269
|
id: tc.id,
|
|
17084
17270
|
type: "function",
|
|
17085
17271
|
function: { name: tc.function.name, arguments: tc.function.arguments }
|
|
17086
17272
|
}));
|
|
17087
|
-
|
|
17273
|
+
const a = msg.assistant(m.content, toolCalls);
|
|
17274
|
+
if (m.timestamp) a.timestamp = m.timestamp;
|
|
17275
|
+
allMessages.push(a);
|
|
17088
17276
|
} else if (m.role === "tool") {
|
|
17089
|
-
|
|
17277
|
+
const t = msg.tool(m.tool_call_id || "", m.content);
|
|
17278
|
+
if (m.timestamp) t.timestamp = m.timestamp;
|
|
17279
|
+
allMessages.push(t);
|
|
17090
17280
|
}
|
|
17091
17281
|
}
|
|
17092
17282
|
}
|
|
@@ -17811,6 +18001,8 @@ var MessageQueue = class {
|
|
|
17811
18001
|
// src/handle-query.ts
|
|
17812
18002
|
init_types();
|
|
17813
18003
|
init_attachments();
|
|
18004
|
+
init_live();
|
|
18005
|
+
init_features();
|
|
17814
18006
|
init_task_manager();
|
|
17815
18007
|
|
|
17816
18008
|
// src/prompt.ts
|
|
@@ -18591,7 +18783,7 @@ ${ep.episode || ep.summary}`,
|
|
|
18591
18783
|
init_paths();
|
|
18592
18784
|
import { readFileSync as readFileSync15, existsSync as existsSync12 } from "node:fs";
|
|
18593
18785
|
import { join as join20, resolve as resolve6 } from "node:path";
|
|
18594
|
-
import * as
|
|
18786
|
+
import * as path14 from "node:path";
|
|
18595
18787
|
var contactMap = null;
|
|
18596
18788
|
var externalChanWhitelist = null;
|
|
18597
18789
|
function loadContactMap(workspace) {
|
|
@@ -18659,18 +18851,18 @@ function truncate(s, maxLen) {
|
|
|
18659
18851
|
}
|
|
18660
18852
|
var externalChanRulesCache = null;
|
|
18661
18853
|
function loadExternalChanRules(workspace) {
|
|
18662
|
-
const
|
|
18663
|
-
if (externalChanRulesCache && externalChanRulesCache.path ===
|
|
18854
|
+
const path46 = join20(workspace, "prompts", "external-chan-rules.md");
|
|
18855
|
+
if (externalChanRulesCache && externalChanRulesCache.path === path46) return externalChanRulesCache;
|
|
18664
18856
|
let content = "";
|
|
18665
|
-
if (existsSync12(
|
|
18857
|
+
if (existsSync12(path46)) {
|
|
18666
18858
|
try {
|
|
18667
|
-
content = readFileSync15(
|
|
18859
|
+
content = readFileSync15(path46, "utf-8").trim();
|
|
18668
18860
|
} catch (e) {
|
|
18669
18861
|
console.warn(`[external-chan-rules] Failed to load: ${e}`);
|
|
18670
18862
|
}
|
|
18671
18863
|
}
|
|
18672
|
-
externalChanRulesCache = { path:
|
|
18673
|
-
console.log(`[external-chan-rules] Loaded ${content.length} chars from ${
|
|
18864
|
+
externalChanRulesCache = { path: path46, content };
|
|
18865
|
+
console.log(`[external-chan-rules] Loaded ${content.length} chars from ${path46}`);
|
|
18674
18866
|
return externalChanRulesCache;
|
|
18675
18867
|
}
|
|
18676
18868
|
function getExternalChanRulesBlock(inboundMeta, workspace) {
|
|
@@ -18698,7 +18890,7 @@ async function handleQuery(text, sessionId, channelName, cb, deps, channelTarget
|
|
|
18698
18890
|
}
|
|
18699
18891
|
async function handleQueryInner(text, sessionId, channelName, cb, deps, channelTarget, inboundMeta, skipRecall, source) {
|
|
18700
18892
|
const { engine, sessions, channelManager, workspace, providerId, providerApi, model } = deps;
|
|
18701
|
-
const
|
|
18893
|
+
const topics = liveConfig.get("topics") || {};
|
|
18702
18894
|
const preQueryAbort = new AbortController();
|
|
18703
18895
|
engine.setPreQueryAbort(preQueryAbort);
|
|
18704
18896
|
let history = sessions.getHistory(sessionId);
|
|
@@ -18707,7 +18899,7 @@ async function handleQueryInner(text, sessionId, channelName, cb, deps, channelT
|
|
|
18707
18899
|
if (restored.length > 0) {
|
|
18708
18900
|
history = restored;
|
|
18709
18901
|
sessions.setHistory(sessionId, history);
|
|
18710
|
-
if (
|
|
18902
|
+
if (topics?.restoreRecall === false) {
|
|
18711
18903
|
let stripped = 0;
|
|
18712
18904
|
for (let i = history.length - 1; i >= 0; i--) {
|
|
18713
18905
|
const m = history[i];
|
|
@@ -18897,7 +19089,7 @@ ${text}` : text });
|
|
|
18897
19089
|
// 对齐 CC: fork subagent 继承父对话历史
|
|
18898
19090
|
parentSystemPrompt: deps.systemPrompt,
|
|
18899
19091
|
// 对齐 CC: fork 共享 prompt cache
|
|
18900
|
-
features:
|
|
19092
|
+
features: liveConfig.get("agents.defaults.features"),
|
|
18901
19093
|
// engine config features(AgentTool 读 agentTool.showProgress)
|
|
18902
19094
|
channelTarget: channelTarget ?? "",
|
|
18903
19095
|
// 回复目标(Discord channel ID / user ID)
|
|
@@ -19013,13 +19205,13 @@ ${text}` : text });
|
|
|
19013
19205
|
engine.setExternalAbort(queryAbortController);
|
|
19014
19206
|
setActiveQueryEngine(sessionId, engine);
|
|
19015
19207
|
const shouldSkipRecall = skipRecall ?? channelName === "cron";
|
|
19016
|
-
if (
|
|
19208
|
+
if (getFeature("topic-recall") !== false && !shouldSkipRecall) {
|
|
19017
19209
|
try {
|
|
19018
19210
|
const memoryDir = getAutoMemPath(workspace);
|
|
19019
19211
|
const provider = deps.engine.getProvider();
|
|
19020
19212
|
const surfacedHistory = collectSurfacedMemories(history);
|
|
19021
19213
|
const cumulativePaths = sessions.getRestoredRecallPaths(sessionId);
|
|
19022
|
-
const doRestore =
|
|
19214
|
+
const doRestore = topics?.restoreRecall === true;
|
|
19023
19215
|
const surfaced = doRestore ? { paths: /* @__PURE__ */ new Set([...surfacedHistory.paths, ...cumulativePaths]) } : surfacedHistory;
|
|
19024
19216
|
console.log(`[handle-query] surfaced: history=${surfacedHistory.paths.size} cumulative=${cumulativePaths.size} merged=${surfaced.paths.size} restoreRecall=${doRestore}`);
|
|
19025
19217
|
if (doRestore) {
|
|
@@ -19058,7 +19250,7 @@ ${text}` : text });
|
|
|
19058
19250
|
console.log(`[handle-query] Memory recall starting: dir=${memoryDir} query="${(typeof text === "string" ? text : "[content blocks]").slice(0, 50)}..." alreadySurfaced=${surfaced.paths.size}`);
|
|
19059
19251
|
const textForMemory = typeof text === "string" ? text : text.filter((b) => b.type === "text").map((b) => b.text).join(" ");
|
|
19060
19252
|
const recallP = deps.recallProvider;
|
|
19061
|
-
const recallMode =
|
|
19253
|
+
const recallMode = topics?.recall?.mode || "llm";
|
|
19062
19254
|
let relevantMemories;
|
|
19063
19255
|
if (recallMode === "everos") {
|
|
19064
19256
|
const everosCfg = deps?.everosCfg;
|
|
@@ -19073,7 +19265,7 @@ ${text}` : text });
|
|
|
19073
19265
|
rerankApiKey: everosCfg.rerank?.apiKey,
|
|
19074
19266
|
rerankModel: everosCfg.rerank?.model,
|
|
19075
19267
|
rerankProvider: everosCfg.rerank?.provider,
|
|
19076
|
-
minScore:
|
|
19268
|
+
minScore: topics?.recall?.minScore
|
|
19077
19269
|
} : void 0
|
|
19078
19270
|
);
|
|
19079
19271
|
} else if (recallMode === "vector") {
|
|
@@ -19091,7 +19283,7 @@ ${text}` : text });
|
|
|
19091
19283
|
queryAbortController.signal,
|
|
19092
19284
|
surfaced.paths,
|
|
19093
19285
|
recallP?.disableThinking,
|
|
19094
|
-
|
|
19286
|
+
topics?.maxScanFiles
|
|
19095
19287
|
);
|
|
19096
19288
|
}
|
|
19097
19289
|
console.log(`[handle-query] Memory recall result: ${relevantMemories.length} memories found: ${relevantMemories.map((m) => m.path.split(/[/\\]/).pop()).join(", ")}`);
|
|
@@ -19275,7 +19467,7 @@ ${text}` : text });
|
|
|
19275
19467
|
}
|
|
19276
19468
|
}
|
|
19277
19469
|
sessions.setHistory(sessionId, history);
|
|
19278
|
-
if (
|
|
19470
|
+
if (getFeature("topic-extract") === true && sessionId === deps.sessions.getSessionId("scope:main")) {
|
|
19279
19471
|
try {
|
|
19280
19472
|
const { createMemoryExtractor: createMemoryExtractor2 } = await Promise.resolve().then(() => (init_extractMemories(), extractMemories_exports));
|
|
19281
19473
|
const extractor = createMemoryExtractor2(workspace, true);
|
|
@@ -19290,6 +19482,15 @@ ${text}` : text });
|
|
|
19290
19482
|
console.warn(`[handle-query] Memory extraction init failed: ${err.message}`);
|
|
19291
19483
|
}
|
|
19292
19484
|
}
|
|
19485
|
+
if (liveConfig.get("everos.enabled") === true && sessionId === deps.sessions.getSessionId("scope:main")) {
|
|
19486
|
+
try {
|
|
19487
|
+
const { pushConversation: pushConversation2 } = await Promise.resolve().then(() => (init_ingest(), ingest_exports));
|
|
19488
|
+
pushConversation2(messages, sessionId, workspace).catch(() => {
|
|
19489
|
+
});
|
|
19490
|
+
} catch (e) {
|
|
19491
|
+
console.warn(`[handle-query] everos push init failed: ${e?.message ?? e}`);
|
|
19492
|
+
}
|
|
19493
|
+
}
|
|
19293
19494
|
try {
|
|
19294
19495
|
const { isSessionMemoryEnabled: isSessionMemoryEnabled2, shouldExtractMemory: shouldExtractMemory2, extractSessionMemory: extractSessionMemory2 } = await Promise.resolve().then(() => (init_sessionMemory(), sessionMemory_exports));
|
|
19295
19496
|
if (isSessionMemoryEnabled2()) {
|
|
@@ -19336,7 +19537,7 @@ stack: ${err.stack ?? "(none)"}`);
|
|
|
19336
19537
|
}
|
|
19337
19538
|
} catch (err) {
|
|
19338
19539
|
try {
|
|
19339
|
-
(await import("node:fs")).appendFileSync(join20(process.env.ENGINE7_STATE_DIR || process.env.OPENCLAW_STATE_DIR ||
|
|
19540
|
+
(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}
|
|
19340
19541
|
stack: ${err.stack ?? "(none)"}
|
|
19341
19542
|
`);
|
|
19342
19543
|
} catch {
|
|
@@ -19535,17 +19736,17 @@ var MessageDispatcher = class {
|
|
|
19535
19736
|
};
|
|
19536
19737
|
|
|
19537
19738
|
// src/cli-startup.ts
|
|
19538
|
-
import * as
|
|
19539
|
-
import * as
|
|
19739
|
+
import * as path15 from "node:path";
|
|
19740
|
+
import * as fs14 from "node:fs";
|
|
19540
19741
|
import * as readline2 from "node:readline";
|
|
19541
19742
|
function getDailyLogPath(stateDir) {
|
|
19542
19743
|
const dateStr = (/* @__PURE__ */ new Date()).toLocaleDateString("sv-SE", { timeZone: "Asia/Shanghai" });
|
|
19543
|
-
return
|
|
19744
|
+
return path15.join(stateDir, "logs", `engine-${dateStr}.log`);
|
|
19544
19745
|
}
|
|
19545
19746
|
function setupFileLogging(stateDir) {
|
|
19546
19747
|
const LOG_PATH = getDailyLogPath(stateDir);
|
|
19547
|
-
|
|
19548
|
-
const logStream =
|
|
19748
|
+
fs14.mkdirSync(path15.join(stateDir, "logs"), { recursive: true });
|
|
19749
|
+
const logStream = fs14.createWriteStream(LOG_PATH, { flags: "a" });
|
|
19549
19750
|
logStream.on("error", (err) => console.error(`[log] Write error: ${err.message}`));
|
|
19550
19751
|
function ts() {
|
|
19551
19752
|
return (/* @__PURE__ */ new Date()).toLocaleString("sv-SE", { timeZone: "Asia/Shanghai", hour12: false }) + "." + String(Date.now() % 1e3).padStart(3, "0");
|
|
@@ -19635,8 +19836,8 @@ function startCliLoop(deps, cliConfig, channelManager, dispatcher) {
|
|
|
19635
19836
|
}
|
|
19636
19837
|
|
|
19637
19838
|
// src/session/session-history.ts
|
|
19638
|
-
import
|
|
19639
|
-
import
|
|
19839
|
+
import fs15 from "node:fs";
|
|
19840
|
+
import path16 from "node:path";
|
|
19640
19841
|
var BEIJING_OFFSET_MS = 8 * 36e5;
|
|
19641
19842
|
var INJECTED_CONTENT_PATTERNS = [
|
|
19642
19843
|
/【定时心跳】/,
|
|
@@ -19690,10 +19891,10 @@ function scopeMainJsonlPaths(sessions) {
|
|
|
19690
19891
|
let latestArchive = null;
|
|
19691
19892
|
if (current) {
|
|
19692
19893
|
try {
|
|
19693
|
-
const dir =
|
|
19694
|
-
const base =
|
|
19695
|
-
const archives =
|
|
19696
|
-
if (archives.length > 0) latestArchive =
|
|
19894
|
+
const dir = path16.dirname(current);
|
|
19895
|
+
const base = path16.basename(current);
|
|
19896
|
+
const archives = fs15.readdirSync(dir).filter((f) => f.startsWith(base + ".archived.")).sort();
|
|
19897
|
+
if (archives.length > 0) latestArchive = path16.join(dir, archives[archives.length - 1]);
|
|
19697
19898
|
} catch {
|
|
19698
19899
|
}
|
|
19699
19900
|
}
|
|
@@ -19711,7 +19912,7 @@ function extractText3(content) {
|
|
|
19711
19912
|
function findLastRealUserMsg(jsonlPath) {
|
|
19712
19913
|
let lines;
|
|
19713
19914
|
try {
|
|
19714
|
-
lines =
|
|
19915
|
+
lines = fs15.readFileSync(jsonlPath, "utf-8").split("\n");
|
|
19715
19916
|
} catch {
|
|
19716
19917
|
return null;
|
|
19717
19918
|
}
|
|
@@ -19755,7 +19956,7 @@ function lastUserMsg(sessions) {
|
|
|
19755
19956
|
function recentMessages(sessions, hours = 12, limit = 60) {
|
|
19756
19957
|
const jsonlPath = resolveScopeMainJsonl(sessions);
|
|
19757
19958
|
if (!jsonlPath) return [];
|
|
19758
|
-
const lines =
|
|
19959
|
+
const lines = fs15.readFileSync(jsonlPath, "utf-8").split("\n");
|
|
19759
19960
|
const entries = parseJsonlEntries(lines);
|
|
19760
19961
|
const nowMs = Date.now();
|
|
19761
19962
|
const cutoffMs = nowMs - hours * 36e5;
|
|
@@ -19951,8 +20152,8 @@ ${basePrompt}`;
|
|
|
19951
20152
|
};
|
|
19952
20153
|
|
|
19953
20154
|
// src/nudge/plugin.ts
|
|
19954
|
-
import
|
|
19955
|
-
import
|
|
20155
|
+
import fs18 from "node:fs";
|
|
20156
|
+
import path19 from "node:path";
|
|
19956
20157
|
|
|
19957
20158
|
// src/nudge/judge.ts
|
|
19958
20159
|
function shouldNudge(task, taskState, cfg) {
|
|
@@ -20120,14 +20321,14 @@ function formatDuration2(ms) {
|
|
|
20120
20321
|
}
|
|
20121
20322
|
|
|
20122
20323
|
// src/nudge/session-state-reader.ts
|
|
20123
|
-
import
|
|
20124
|
-
import
|
|
20324
|
+
import fs16 from "node:fs";
|
|
20325
|
+
import path17 from "node:path";
|
|
20125
20326
|
function parseSessionStateFull(workspace, sessionStateFile) {
|
|
20126
20327
|
const stateFile = sessionStateFile || "SESSION-STATE.md";
|
|
20127
|
-
const statePath =
|
|
20328
|
+
const statePath = path17.isAbsolute(stateFile) ? stateFile : path17.join(workspace, stateFile);
|
|
20128
20329
|
let content;
|
|
20129
20330
|
try {
|
|
20130
|
-
content =
|
|
20331
|
+
content = fs16.readFileSync(statePath, "utf-8");
|
|
20131
20332
|
} catch {
|
|
20132
20333
|
console.warn(`[nudge] SESSION-STATE not found at ${statePath}`);
|
|
20133
20334
|
return { activeTasks: [], orphanPendings: [] };
|
|
@@ -20179,13 +20380,13 @@ function taskIdFromTitle(title) {
|
|
|
20179
20380
|
|
|
20180
20381
|
// src/calendar/db.ts
|
|
20181
20382
|
import { DatabaseSync } from "node:sqlite";
|
|
20182
|
-
import * as
|
|
20183
|
-
import * as
|
|
20383
|
+
import * as path18 from "node:path";
|
|
20384
|
+
import * as fs17 from "node:fs";
|
|
20184
20385
|
var TZ_OFFSET_MS = 8 * 60 * 60 * 1e3;
|
|
20185
20386
|
function openDb(workspace) {
|
|
20186
|
-
const dir =
|
|
20187
|
-
|
|
20188
|
-
const dbPath =
|
|
20387
|
+
const dir = path18.join(workspace, ".calendar");
|
|
20388
|
+
fs17.mkdirSync(dir, { recursive: true });
|
|
20389
|
+
const dbPath = path18.join(dir, "calendar.db");
|
|
20189
20390
|
const db = new DatabaseSync(dbPath);
|
|
20190
20391
|
db.exec("PRAGMA journal_mode=WAL");
|
|
20191
20392
|
db.exec(`CREATE TABLE IF NOT EXISTS events (
|
|
@@ -20274,9 +20475,9 @@ var NudgePlugin = class {
|
|
|
20274
20475
|
provider;
|
|
20275
20476
|
model;
|
|
20276
20477
|
loadPrompt(workspace, promptFile) {
|
|
20277
|
-
const promptPath = promptFile ?
|
|
20478
|
+
const promptPath = promptFile ? path19.isAbsolute(promptFile) ? promptFile : path19.join(workspace, promptFile) : path19.join(workspace, "prompts", "nudge-prompt.md");
|
|
20278
20479
|
try {
|
|
20279
|
-
const content =
|
|
20480
|
+
const content = fs18.readFileSync(promptPath, "utf-8").trim();
|
|
20280
20481
|
if (content) {
|
|
20281
20482
|
console.log(`[nudge] Loaded custom prompt from ${promptPath}`);
|
|
20282
20483
|
return content;
|
|
@@ -20307,6 +20508,18 @@ var NudgePlugin = class {
|
|
|
20307
20508
|
registerCallbackHook("Stop", {
|
|
20308
20509
|
type: "callback",
|
|
20309
20510
|
callback: async (input, _toolUseID, _signal) => {
|
|
20511
|
+
const mode = this.cfg.stopHookMode || "sync";
|
|
20512
|
+
if (mode === "async") {
|
|
20513
|
+
console.log("[stop-hook] async mode \u2014 firing judge in background, not blocking");
|
|
20514
|
+
this.runStopHookJudge(input, sessions).catch((err) => {
|
|
20515
|
+
if (/judge \d+ms timeout/i.test(err?.message || "")) {
|
|
20516
|
+
console.warn(`[stop-hook] async judge timed out (abandoned)`);
|
|
20517
|
+
} else {
|
|
20518
|
+
console.warn(`[stop-hook] async judge error: ${err.message}`);
|
|
20519
|
+
}
|
|
20520
|
+
});
|
|
20521
|
+
return { outcome: { outcome: "success" } };
|
|
20522
|
+
}
|
|
20310
20523
|
const timeoutMs = this.cfg.timeoutMs ?? 15e3;
|
|
20311
20524
|
let judgeTimer;
|
|
20312
20525
|
const judgeTimeout = new Promise((_, reject) => {
|
|
@@ -20329,7 +20542,7 @@ var NudgePlugin = class {
|
|
|
20329
20542
|
return { outcome: { outcome: "success" } };
|
|
20330
20543
|
}
|
|
20331
20544
|
});
|
|
20332
|
-
console.log(
|
|
20545
|
+
console.log(`[stop-hook] Registered Stop callback hook (mode=${this.cfg.stopHookMode || "sync"}, LLM semantic judge + 5min wake-up)`);
|
|
20333
20546
|
}
|
|
20334
20547
|
/** Judge 完整逻辑(被 callback 用 Promise.race 调用,可被 timeout 截断) */
|
|
20335
20548
|
async runStopHookJudge(input, sessions) {
|
|
@@ -20364,6 +20577,12 @@ var NudgePlugin = class {
|
|
|
20364
20577
|
if (!lastMsg) {
|
|
20365
20578
|
return;
|
|
20366
20579
|
}
|
|
20580
|
+
const currentHour = (/* @__PURE__ */ new Date()).getHours();
|
|
20581
|
+
const isNightTime = currentHour >= 22 || currentHour < 8;
|
|
20582
|
+
if (isNightTime) {
|
|
20583
|
+
console.log(`[stop-hook] night time (${currentHour}:xx), skipping needLanding/waiting judge`);
|
|
20584
|
+
return;
|
|
20585
|
+
}
|
|
20367
20586
|
let contextStr = "";
|
|
20368
20587
|
try {
|
|
20369
20588
|
const recent = recentMessages(sessions, 0.5, 6);
|
|
@@ -20486,18 +20705,18 @@ var NudgePlugin = class {
|
|
|
20486
20705
|
if (!isWaiting) {
|
|
20487
20706
|
return;
|
|
20488
20707
|
}
|
|
20489
|
-
const nudgeDir =
|
|
20490
|
-
const notifPath =
|
|
20708
|
+
const nudgeDir = path19.join(this.workspace, ".nudge");
|
|
20709
|
+
const notifPath = path19.join(nudgeDir, "stop-hook-notifications.json");
|
|
20491
20710
|
try {
|
|
20492
|
-
if (!
|
|
20711
|
+
if (!fs18.existsSync(nudgeDir)) fs18.mkdirSync(nudgeDir, { recursive: true });
|
|
20493
20712
|
let notifs = [];
|
|
20494
|
-
if (
|
|
20495
|
-
notifs = JSON.parse(
|
|
20713
|
+
if (fs18.existsSync(notifPath)) {
|
|
20714
|
+
notifs = JSON.parse(fs18.readFileSync(notifPath, "utf-8"));
|
|
20496
20715
|
const now = Date.now();
|
|
20497
20716
|
const dup = notifs.find((n) => !n.notified && n.description === (waitDesc || lastMsg.slice(0, 200)));
|
|
20498
20717
|
if (dup) {
|
|
20499
20718
|
dup.wakeAt = new Date(now + 5 * 6e4).toISOString();
|
|
20500
|
-
|
|
20719
|
+
fs18.writeFileSync(notifPath, JSON.stringify(notifs, null, 2));
|
|
20501
20720
|
console.log(`[stop-hook] Duplicate wait (same desc, not fired yet), refreshed wakeAt: ${dup.id}`);
|
|
20502
20721
|
return;
|
|
20503
20722
|
}
|
|
@@ -20515,7 +20734,7 @@ var NudgePlugin = class {
|
|
|
20515
20734
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
20516
20735
|
wakeAt
|
|
20517
20736
|
});
|
|
20518
|
-
|
|
20737
|
+
fs18.writeFileSync(notifPath, JSON.stringify(notifs, null, 2));
|
|
20519
20738
|
console.log(`[stop-hook] Registered wake-up ${notifId} at ${wakeAt} (sessionId=${sessionId}): ${waitDesc}`);
|
|
20520
20739
|
} catch (e) {
|
|
20521
20740
|
console.warn(`[stop-hook] Failed to register: ${e.message}`);
|
|
@@ -20552,10 +20771,10 @@ var NudgePlugin = class {
|
|
|
20552
20771
|
* 已 notified 的不会再触发,等 agent 回复 "<id> 过期了" 由 cleanup 删。
|
|
20553
20772
|
*/
|
|
20554
20773
|
collectDueStopHookNotifications() {
|
|
20555
|
-
const notifPath =
|
|
20774
|
+
const notifPath = path19.join(this.workspace, ".nudge", "stop-hook-notifications.json");
|
|
20556
20775
|
try {
|
|
20557
|
-
if (!
|
|
20558
|
-
const notifs = JSON.parse(
|
|
20776
|
+
if (!fs18.existsSync(notifPath)) return null;
|
|
20777
|
+
const notifs = JSON.parse(fs18.readFileSync(notifPath, "utf-8"));
|
|
20559
20778
|
if (notifs.length === 0) return null;
|
|
20560
20779
|
const now = Date.now();
|
|
20561
20780
|
const due = notifs.filter((n) => new Date(n.wakeAt).getTime() <= now && !n.notified);
|
|
@@ -20591,18 +20810,18 @@ ${items}
|
|
|
20591
20810
|
}
|
|
20592
20811
|
/** 按 id 删除条目(stop-hook 实时清理用;正常删除路径,agent 回复即删) */
|
|
20593
20812
|
removeNotificationsById(ids) {
|
|
20594
|
-
const notifPath =
|
|
20813
|
+
const notifPath = path19.join(this.workspace, ".nudge", "stop-hook-notifications.json");
|
|
20595
20814
|
try {
|
|
20596
|
-
if (!
|
|
20597
|
-
const notifs = JSON.parse(
|
|
20815
|
+
if (!fs18.existsSync(notifPath)) return;
|
|
20816
|
+
const notifs = JSON.parse(fs18.readFileSync(notifPath, "utf-8"));
|
|
20598
20817
|
const idSet = new Set(ids);
|
|
20599
20818
|
const remaining = notifs.filter((n) => !idSet.has(n.id));
|
|
20600
20819
|
const removed = notifs.length - remaining.length;
|
|
20601
20820
|
if (removed === 0) return;
|
|
20602
20821
|
if (remaining.length > 0) {
|
|
20603
|
-
|
|
20822
|
+
fs18.writeFileSync(notifPath, JSON.stringify(remaining, null, 2));
|
|
20604
20823
|
} else {
|
|
20605
|
-
|
|
20824
|
+
fs18.unlinkSync(notifPath);
|
|
20606
20825
|
}
|
|
20607
20826
|
console.log(`[stop-hook] Cleaned ${removed} notification(s) from reply: ${ids.join(", ")}`);
|
|
20608
20827
|
} catch (e) {
|
|
@@ -20611,13 +20830,13 @@ ${items}
|
|
|
20611
20830
|
}
|
|
20612
20831
|
/** 投递成功后标记 notified(防重复触发);不删除——删除只走 agent 回复 "<id> 过期了" */
|
|
20613
20832
|
markNotified(ids) {
|
|
20614
|
-
const notifPath =
|
|
20833
|
+
const notifPath = path19.join(this.workspace, ".nudge", "stop-hook-notifications.json");
|
|
20615
20834
|
try {
|
|
20616
|
-
if (!
|
|
20617
|
-
const notifs = JSON.parse(
|
|
20835
|
+
if (!fs18.existsSync(notifPath)) return;
|
|
20836
|
+
const notifs = JSON.parse(fs18.readFileSync(notifPath, "utf-8"));
|
|
20618
20837
|
const idSet = new Set(ids);
|
|
20619
20838
|
const updated = notifs.map((n) => idSet.has(n.id) ? { ...n, notified: true } : n);
|
|
20620
|
-
|
|
20839
|
+
fs18.writeFileSync(notifPath, JSON.stringify(updated, null, 2));
|
|
20621
20840
|
} catch (e) {
|
|
20622
20841
|
console.warn(`[nudge] markNotified error: ${e.message}`);
|
|
20623
20842
|
}
|
|
@@ -20634,9 +20853,9 @@ ${items}
|
|
|
20634
20853
|
*/
|
|
20635
20854
|
cleanupStaleNotificationsFromMessages(sessions) {
|
|
20636
20855
|
try {
|
|
20637
|
-
const notifPath =
|
|
20638
|
-
if (!
|
|
20639
|
-
const notifs = JSON.parse(
|
|
20856
|
+
const notifPath = path19.join(this.workspace, ".nudge", "stop-hook-notifications.json");
|
|
20857
|
+
if (!fs18.existsSync(notifPath)) return;
|
|
20858
|
+
const notifs = JSON.parse(fs18.readFileSync(notifPath, "utf-8"));
|
|
20640
20859
|
if (notifs.length === 0) return;
|
|
20641
20860
|
const expiredIds = this.findExpiredReplyIds(sessions, notifs);
|
|
20642
20861
|
const ttlMs = (this.cfg.cleanupTtlHours || 24) * 36e5;
|
|
@@ -20648,9 +20867,9 @@ ${items}
|
|
|
20648
20867
|
if (removeIds.size === 0) return;
|
|
20649
20868
|
const remaining = notifs.filter((n) => !removeIds.has(n.id));
|
|
20650
20869
|
if (remaining.length > 0) {
|
|
20651
|
-
|
|
20870
|
+
fs18.writeFileSync(notifPath, JSON.stringify(remaining, null, 2));
|
|
20652
20871
|
} else {
|
|
20653
|
-
|
|
20872
|
+
fs18.unlinkSync(notifPath);
|
|
20654
20873
|
}
|
|
20655
20874
|
if (expiredIds.size > 0) {
|
|
20656
20875
|
console.log(`[nudge] Cleaned ${expiredIds.size} notification(s) by reply: ${[...expiredIds].join(", ")}`);
|
|
@@ -20675,10 +20894,10 @@ ${items}
|
|
|
20675
20894
|
const oldestMs = Math.min(...notifs.map((n) => new Date(n.wakeAt).getTime()));
|
|
20676
20895
|
const { current, latestArchive } = scopeMainJsonlPaths(sessions);
|
|
20677
20896
|
for (const file of [current, latestArchive]) {
|
|
20678
|
-
if (!file || !
|
|
20897
|
+
if (!file || !fs18.existsSync(file)) continue;
|
|
20679
20898
|
let lines;
|
|
20680
20899
|
try {
|
|
20681
|
-
lines =
|
|
20900
|
+
lines = fs18.readFileSync(file, "utf-8").split("\n");
|
|
20682
20901
|
} catch (e) {
|
|
20683
20902
|
console.warn(`[nudge] findExpiredReplyIds read error on ${file}: ${e.message}`);
|
|
20684
20903
|
continue;
|
|
@@ -20935,9 +21154,9 @@ ${items}
|
|
|
20935
21154
|
// === state 持久化 ===
|
|
20936
21155
|
loadState() {
|
|
20937
21156
|
const stateFile = this.cfg.stateFile || "nudge-state.json";
|
|
20938
|
-
const statePath =
|
|
21157
|
+
const statePath = path19.isAbsolute(stateFile) ? stateFile : path19.join(this.workspace, stateFile);
|
|
20939
21158
|
try {
|
|
20940
|
-
const content =
|
|
21159
|
+
const content = fs18.readFileSync(statePath, "utf-8");
|
|
20941
21160
|
return JSON.parse(content);
|
|
20942
21161
|
} catch {
|
|
20943
21162
|
return { tasks: {} };
|
|
@@ -20945,8 +21164,8 @@ ${items}
|
|
|
20945
21164
|
}
|
|
20946
21165
|
saveState(state2) {
|
|
20947
21166
|
const stateFile = this.cfg.stateFile || "nudge-state.json";
|
|
20948
|
-
const statePath =
|
|
20949
|
-
|
|
21167
|
+
const statePath = path19.isAbsolute(stateFile) ? stateFile : path19.join(this.workspace, stateFile);
|
|
21168
|
+
fs18.writeFileSync(statePath, JSON.stringify(state2, null, 2), "utf-8");
|
|
20950
21169
|
}
|
|
20951
21170
|
newTaskState() {
|
|
20952
21171
|
return {
|
|
@@ -21124,8 +21343,8 @@ ${items}
|
|
|
21124
21343
|
};
|
|
21125
21344
|
|
|
21126
21345
|
// src/inner-voice/plugin.ts
|
|
21127
|
-
import
|
|
21128
|
-
import
|
|
21346
|
+
import fs22 from "node:fs";
|
|
21347
|
+
import path23 from "node:path";
|
|
21129
21348
|
|
|
21130
21349
|
// src/inner-voice/activity.ts
|
|
21131
21350
|
function checkActivity(sessions, activeThresholdMs) {
|
|
@@ -21164,8 +21383,8 @@ function calcHintProb(min) {
|
|
|
21164
21383
|
}
|
|
21165
21384
|
|
|
21166
21385
|
// src/inner-voice/emotional-state.ts
|
|
21167
|
-
import
|
|
21168
|
-
import
|
|
21386
|
+
import fs19 from "node:fs";
|
|
21387
|
+
import path20 from "node:path";
|
|
21169
21388
|
var NEUTRAL = 0.5;
|
|
21170
21389
|
var DECAY_RATE = 0.17;
|
|
21171
21390
|
var MAX_EVENTS = 20;
|
|
@@ -21216,7 +21435,7 @@ function initialState() {
|
|
|
21216
21435
|
return { version: 1, mood: NEUTRAL, trend: "stable", updatedAt: nowIsoBj(), events: [] };
|
|
21217
21436
|
}
|
|
21218
21437
|
async function updateEmotionalState(workspace, sessions) {
|
|
21219
|
-
const stateFile =
|
|
21438
|
+
const stateFile = path20.join(workspace, "inner-voice", "emotional-state.json");
|
|
21220
21439
|
const messages = readRecentMessages(sessions, RECENT_N);
|
|
21221
21440
|
if (messages.length === 0) {
|
|
21222
21441
|
console.log("[emotional-state] no messages");
|
|
@@ -21249,8 +21468,8 @@ async function updateEmotionalState(workspace, sessions) {
|
|
|
21249
21468
|
function readRecentMessages(sessions, n) {
|
|
21250
21469
|
const mainId = sessions.getSessionId("scope:main");
|
|
21251
21470
|
if (!mainId) return [];
|
|
21252
|
-
const file =
|
|
21253
|
-
if (!
|
|
21471
|
+
const file = path20.join(sessions.sessionsDir, `${mainId}.jsonl`);
|
|
21472
|
+
if (!fs19.existsSync(file)) return [];
|
|
21254
21473
|
const lines = readLastNLines(file, n * 4 + 20);
|
|
21255
21474
|
const entries = [];
|
|
21256
21475
|
for (const line of lines) {
|
|
@@ -21367,9 +21586,9 @@ function refreshHoursAgo(events) {
|
|
|
21367
21586
|
}
|
|
21368
21587
|
function appendMoodLog(workspace, state2, summary) {
|
|
21369
21588
|
try {
|
|
21370
|
-
const logPath =
|
|
21589
|
+
const logPath = path20.join(workspace, "mood-history.log");
|
|
21371
21590
|
const ts = formatBj(/* @__PURE__ */ new Date(), false);
|
|
21372
|
-
|
|
21591
|
+
fs19.appendFileSync(logPath, `${ts} mood=${state2.mood.toFixed(2)} trend=${state2.trend} ${summary}
|
|
21373
21592
|
`);
|
|
21374
21593
|
} catch (err) {
|
|
21375
21594
|
console.warn(`[emotional-state] mood log failed: ${err.message}`);
|
|
@@ -21377,32 +21596,32 @@ function appendMoodLog(workspace, state2, summary) {
|
|
|
21377
21596
|
}
|
|
21378
21597
|
function loadJson(file) {
|
|
21379
21598
|
try {
|
|
21380
|
-
return JSON.parse(
|
|
21599
|
+
return JSON.parse(fs19.readFileSync(file, "utf-8"));
|
|
21381
21600
|
} catch {
|
|
21382
21601
|
return null;
|
|
21383
21602
|
}
|
|
21384
21603
|
}
|
|
21385
21604
|
function saveJson(file, data) {
|
|
21386
21605
|
try {
|
|
21387
|
-
|
|
21388
|
-
|
|
21606
|
+
fs19.mkdirSync(path20.dirname(file), { recursive: true });
|
|
21607
|
+
fs19.writeFileSync(file, JSON.stringify(data, null, 2));
|
|
21389
21608
|
} catch (err) {
|
|
21390
21609
|
console.warn(`[emotional-state] save failed: ${err.message}`);
|
|
21391
21610
|
}
|
|
21392
21611
|
}
|
|
21393
21612
|
function readLastNLines(file, maxLines) {
|
|
21394
21613
|
try {
|
|
21395
|
-
const stat4 =
|
|
21614
|
+
const stat4 = fs19.statSync(file);
|
|
21396
21615
|
const tailBytes = Math.min(stat4.size, maxLines * 512);
|
|
21397
|
-
const fd =
|
|
21616
|
+
const fd = fs19.openSync(file, "r");
|
|
21398
21617
|
try {
|
|
21399
21618
|
const buf = Buffer.alloc(tailBytes);
|
|
21400
|
-
|
|
21619
|
+
fs19.readSync(fd, buf, 0, tailBytes, stat4.size - tailBytes);
|
|
21401
21620
|
const lines = buf.toString("utf-8").split("\n").filter(Boolean);
|
|
21402
21621
|
if (stat4.size > tailBytes && lines.length > 0) lines.shift();
|
|
21403
21622
|
return lines;
|
|
21404
21623
|
} finally {
|
|
21405
|
-
|
|
21624
|
+
fs19.closeSync(fd);
|
|
21406
21625
|
}
|
|
21407
21626
|
} catch {
|
|
21408
21627
|
return [];
|
|
@@ -21429,8 +21648,8 @@ function formatBj(d, withSec) {
|
|
|
21429
21648
|
}
|
|
21430
21649
|
|
|
21431
21650
|
// src/inner-voice/topics-scorer.ts
|
|
21432
|
-
import
|
|
21433
|
-
import
|
|
21651
|
+
import fs20 from "node:fs";
|
|
21652
|
+
import path21 from "node:path";
|
|
21434
21653
|
var HALF_LIFE_DAYS = 3;
|
|
21435
21654
|
var PROJECT_HALF_LIFE_DAYS = 1.5;
|
|
21436
21655
|
var COOLDOWN_HOURS = 6;
|
|
@@ -21438,8 +21657,8 @@ var MAX_CHARS = 8e3;
|
|
|
21438
21657
|
var SKIP_NAMES = /* @__PURE__ */ new Set(["MEMORY.md", "archive"]);
|
|
21439
21658
|
var SKIP_DIRS = /* @__PURE__ */ new Set(["archive"]);
|
|
21440
21659
|
function pickTopic(workspace, typeFilter, opts) {
|
|
21441
|
-
const topicsDir =
|
|
21442
|
-
const usageFile =
|
|
21660
|
+
const topicsDir = path21.join(workspace, "topics");
|
|
21661
|
+
const usageFile = path21.join(workspace, "inner-voice", "topics-usage.json");
|
|
21443
21662
|
const files = scanTopics(topicsDir, typeFilter);
|
|
21444
21663
|
if (files.length === 0) {
|
|
21445
21664
|
console.log(`[topics-scorer] no topics found (type=${typeFilter})`);
|
|
@@ -21456,7 +21675,7 @@ function pickTopic(workspace, typeFilter, opts) {
|
|
|
21456
21675
|
else type2 = "other";
|
|
21457
21676
|
let mtime;
|
|
21458
21677
|
try {
|
|
21459
|
-
mtime =
|
|
21678
|
+
mtime = fs20.statSync(fullpath).mtimeMs;
|
|
21460
21679
|
} catch {
|
|
21461
21680
|
continue;
|
|
21462
21681
|
}
|
|
@@ -21471,7 +21690,7 @@ function pickTopic(workspace, typeFilter, opts) {
|
|
|
21471
21690
|
recency: Math.round(recency * 1e3) / 1e3,
|
|
21472
21691
|
freq: Math.round(freq * 1e3) / 1e3,
|
|
21473
21692
|
type: type2,
|
|
21474
|
-
name: meta.name ||
|
|
21693
|
+
name: meta.name || path21.basename(relpath),
|
|
21475
21694
|
description: meta.description || "",
|
|
21476
21695
|
mtime
|
|
21477
21696
|
});
|
|
@@ -21491,7 +21710,7 @@ function pickTopic(workspace, typeFilter, opts) {
|
|
|
21491
21710
|
saveJson2(usageFile, usage);
|
|
21492
21711
|
let content = "";
|
|
21493
21712
|
try {
|
|
21494
|
-
const raw =
|
|
21713
|
+
const raw = fs20.readFileSync(chosen.fullpath, "utf-8");
|
|
21495
21714
|
content = raw.length > MAX_CHARS ? raw.slice(0, MAX_CHARS) + "\n... (truncated) ..." : raw;
|
|
21496
21715
|
} catch {
|
|
21497
21716
|
}
|
|
@@ -21525,18 +21744,18 @@ function frequencyWeight(relpath, usage, isProject, type2) {
|
|
|
21525
21744
|
return reconsolidation + countBonus;
|
|
21526
21745
|
}
|
|
21527
21746
|
function scanTopics(topicsDir, typeFilter) {
|
|
21528
|
-
if (!
|
|
21747
|
+
if (!fs20.existsSync(topicsDir)) return [];
|
|
21529
21748
|
const out = [];
|
|
21530
21749
|
const walk = (dir) => {
|
|
21531
|
-
for (const name of
|
|
21532
|
-
const full =
|
|
21533
|
-
const stat4 =
|
|
21750
|
+
for (const name of fs20.readdirSync(dir)) {
|
|
21751
|
+
const full = path21.join(dir, name);
|
|
21752
|
+
const stat4 = fs20.statSync(full);
|
|
21534
21753
|
if (stat4.isDirectory()) {
|
|
21535
21754
|
if (SKIP_DIRS.has(name)) continue;
|
|
21536
21755
|
walk(full);
|
|
21537
21756
|
} else {
|
|
21538
21757
|
if (!name.endsWith(".md") || SKIP_NAMES.has(name)) continue;
|
|
21539
|
-
const relpath =
|
|
21758
|
+
const relpath = path21.relative(topicsDir, full).replace(/\\/g, "/");
|
|
21540
21759
|
if (typeFilter && !relpath.startsWith(typeFilter + "/") && !relpath.startsWith(typeFilter + "_")) continue;
|
|
21541
21760
|
out.push({ relpath, fullpath: full });
|
|
21542
21761
|
}
|
|
@@ -21548,7 +21767,7 @@ function scanTopics(topicsDir, typeFilter) {
|
|
|
21548
21767
|
function readFrontmatter(file) {
|
|
21549
21768
|
let content = "";
|
|
21550
21769
|
try {
|
|
21551
|
-
content =
|
|
21770
|
+
content = fs20.readFileSync(file, "utf-8").slice(0, 2e3);
|
|
21552
21771
|
} catch {
|
|
21553
21772
|
return {};
|
|
21554
21773
|
}
|
|
@@ -21574,40 +21793,40 @@ function weightedRandom(items, weights) {
|
|
|
21574
21793
|
}
|
|
21575
21794
|
function loadJson2(file) {
|
|
21576
21795
|
try {
|
|
21577
|
-
return JSON.parse(
|
|
21796
|
+
return JSON.parse(fs20.readFileSync(file, "utf-8"));
|
|
21578
21797
|
} catch {
|
|
21579
21798
|
return null;
|
|
21580
21799
|
}
|
|
21581
21800
|
}
|
|
21582
21801
|
function saveJson2(file, data) {
|
|
21583
21802
|
try {
|
|
21584
|
-
|
|
21585
|
-
|
|
21803
|
+
fs20.mkdirSync(path21.dirname(file), { recursive: true });
|
|
21804
|
+
fs20.writeFileSync(file, JSON.stringify(data, null, 2));
|
|
21586
21805
|
} catch (err) {
|
|
21587
21806
|
console.warn(`[topics-scorer] usage save failed: ${err.message}`);
|
|
21588
21807
|
}
|
|
21589
21808
|
}
|
|
21590
21809
|
|
|
21591
21810
|
// src/inner-voice/memory-reader.ts
|
|
21592
|
-
import
|
|
21593
|
-
import
|
|
21811
|
+
import fs21 from "node:fs";
|
|
21812
|
+
import path22 from "node:path";
|
|
21594
21813
|
var US_HALF_LIFE_DAYS = 10;
|
|
21595
21814
|
var US_MAX_LINES = 60;
|
|
21596
21815
|
function readRecentMemory(workspace) {
|
|
21597
|
-
const dir =
|
|
21816
|
+
const dir = path22.join(workspace, "memory");
|
|
21598
21817
|
const now = new Date(Date.now() + 8 * 36e5);
|
|
21599
21818
|
const today = formatYmd(now);
|
|
21600
21819
|
const yesterday = formatYmd(new Date(now.getTime() - 864e5));
|
|
21601
21820
|
return {
|
|
21602
|
-
today: readIfExists(
|
|
21603
|
-
yesterday: readIfExists(
|
|
21821
|
+
today: readIfExists(path22.join(dir, `${today}.md`)),
|
|
21822
|
+
yesterday: readIfExists(path22.join(dir, `${yesterday}.md`))
|
|
21604
21823
|
};
|
|
21605
21824
|
}
|
|
21606
21825
|
function sampleUs(workspace) {
|
|
21607
|
-
const usFile =
|
|
21826
|
+
const usFile = path22.join(workspace, "memory", "us.md");
|
|
21608
21827
|
let content;
|
|
21609
21828
|
try {
|
|
21610
|
-
content =
|
|
21829
|
+
content = fs21.readFileSync(usFile, "utf-8");
|
|
21611
21830
|
} catch {
|
|
21612
21831
|
return null;
|
|
21613
21832
|
}
|
|
@@ -21653,7 +21872,7 @@ function recencyWeight(dateStr) {
|
|
|
21653
21872
|
}
|
|
21654
21873
|
function readIfExists(file) {
|
|
21655
21874
|
try {
|
|
21656
|
-
return
|
|
21875
|
+
return fs21.readFileSync(file, "utf-8");
|
|
21657
21876
|
} catch {
|
|
21658
21877
|
return "";
|
|
21659
21878
|
}
|
|
@@ -21944,9 +22163,9 @@ var InnerVoicePlugin = class {
|
|
|
21944
22163
|
}
|
|
21945
22164
|
/** 读 workspace/prompts/my-inner-voice.md,不存在用 DEFAULT_PROMPT */
|
|
21946
22165
|
loadPrompt(workspace) {
|
|
21947
|
-
const promptPath =
|
|
22166
|
+
const promptPath = path23.join(workspace, "prompts", "my-inner-voice.md");
|
|
21948
22167
|
try {
|
|
21949
|
-
const content =
|
|
22168
|
+
const content = fs22.readFileSync(promptPath, "utf-8").trim();
|
|
21950
22169
|
if (content) {
|
|
21951
22170
|
console.log(`[inner-voice] Loaded custom prompt from ${promptPath}`);
|
|
21952
22171
|
return content;
|
|
@@ -22018,7 +22237,7 @@ var InnerVoicePlugin = class {
|
|
|
22018
22237
|
console.warn(`[inner-voice] emotional-state failed: ${err.message}`);
|
|
22019
22238
|
}
|
|
22020
22239
|
try {
|
|
22021
|
-
const content =
|
|
22240
|
+
const content = fs22.readFileSync(path23.join(this.workspace, "SESSION-STATE.md"), "utf-8");
|
|
22022
22241
|
lines.push("\n--- SESSION-STATE\uFF08\u5C3E\u90E8\uFF09 ---");
|
|
22023
22242
|
lines.push(content.slice(-2e3));
|
|
22024
22243
|
} catch {
|
|
@@ -22132,10 +22351,10 @@ var InnerVoicePlugin = class {
|
|
|
22132
22351
|
if (Math.random() >= activity.hintProb) {
|
|
22133
22352
|
return { text: thought, hintTriggered: false, hintText: "" };
|
|
22134
22353
|
}
|
|
22135
|
-
const poolPath =
|
|
22354
|
+
const poolPath = path23.join(this.workspace, "inner-voice", "hints_pool.txt");
|
|
22136
22355
|
let hint = "\u60F3\u4ED6\u5C31\u53D1\u6D88\u606F\u5427";
|
|
22137
22356
|
try {
|
|
22138
|
-
const pool =
|
|
22357
|
+
const pool = fs22.readFileSync(poolPath, "utf-8").split("\n").map((s) => s.trim()).filter(Boolean);
|
|
22139
22358
|
if (pool.length) hint = pool[Math.floor(Math.random() * pool.length)];
|
|
22140
22359
|
} catch {
|
|
22141
22360
|
}
|
|
@@ -22160,7 +22379,7 @@ var InnerVoicePlugin = class {
|
|
|
22160
22379
|
try {
|
|
22161
22380
|
const writer = sessions.getWriter(mainSessionId);
|
|
22162
22381
|
const history = sessions.getHistory(mainSessionId);
|
|
22163
|
-
const fullPath =
|
|
22382
|
+
const fullPath = path23.resolve(this.workspace, emoTopic.file);
|
|
22164
22383
|
const memories = [{
|
|
22165
22384
|
path: fullPath,
|
|
22166
22385
|
content: emoTopic.content,
|
|
@@ -22188,12 +22407,12 @@ var InnerVoicePlugin = class {
|
|
|
22188
22407
|
/** 写 xiaoyi.log(格式对齐旧 memory_whisper.py,便于既有日志分析复用)。 */
|
|
22189
22408
|
writeLog(status, delivered, activity, hintTriggered, hintText) {
|
|
22190
22409
|
try {
|
|
22191
|
-
const logDir =
|
|
22192
|
-
|
|
22193
|
-
const logPath =
|
|
22410
|
+
const logDir = path23.join(this.workspace, "inner-voice");
|
|
22411
|
+
fs22.mkdirSync(logDir, { recursive: true });
|
|
22412
|
+
const logPath = path23.join(logDir, "xiaoyi.log");
|
|
22194
22413
|
const ts = formatBeijingTs(/* @__PURE__ */ new Date());
|
|
22195
22414
|
const hintStatus = hintTriggered ? `YES (${(hintText || "").trim()})` : "no";
|
|
22196
|
-
|
|
22415
|
+
fs22.appendFileSync(
|
|
22197
22416
|
logPath,
|
|
22198
22417
|
`[${ts}] ${status} hint=${hintStatus} prob=${Math.round(activity.hintProb * 100)}%
|
|
22199
22418
|
delivered: ${delivered}
|
|
@@ -22729,8 +22948,8 @@ var PluginManager = class {
|
|
|
22729
22948
|
// src/voice-chat/plugin.ts
|
|
22730
22949
|
import { spawn as spawn4, exec } from "node:child_process";
|
|
22731
22950
|
import net from "node:net";
|
|
22732
|
-
import
|
|
22733
|
-
import
|
|
22951
|
+
import path24 from "node:path";
|
|
22952
|
+
import fs23 from "node:fs";
|
|
22734
22953
|
|
|
22735
22954
|
// src/voice-chat/bridge.ts
|
|
22736
22955
|
function registerVoiceChatBridge(httpServer, dispatcher, deps, config, sessions, voiceChatDeps) {
|
|
@@ -23099,20 +23318,20 @@ var VoiceChatPlugin = class _VoiceChatPlugin {
|
|
|
23099
23318
|
}
|
|
23100
23319
|
}
|
|
23101
23320
|
findPython() {
|
|
23102
|
-
if (this.config.pythonPath &&
|
|
23321
|
+
if (this.config.pythonPath && fs23.existsSync(this.config.pythonPath)) {
|
|
23103
23322
|
return this.config.pythonPath;
|
|
23104
23323
|
}
|
|
23105
23324
|
return "python";
|
|
23106
23325
|
}
|
|
23107
23326
|
getPythonDir() {
|
|
23108
23327
|
const dir = import.meta.dirname;
|
|
23109
|
-
const srcDir =
|
|
23110
|
-
const localDir =
|
|
23111
|
-
return
|
|
23328
|
+
const srcDir = path24.resolve(dir, "..", "src", "voice-chat", "python");
|
|
23329
|
+
const localDir = path24.join(dir, "python");
|
|
23330
|
+
return fs23.existsSync(srcDir) ? srcDir : localDir;
|
|
23112
23331
|
}
|
|
23113
23332
|
startPython() {
|
|
23114
23333
|
const pythonDir = this.getPythonDir();
|
|
23115
|
-
const serverPy =
|
|
23334
|
+
const serverPy = path24.join(pythonDir, "server.py");
|
|
23116
23335
|
const pythonBin = this.findPython();
|
|
23117
23336
|
const args = [serverPy];
|
|
23118
23337
|
if (this.config.pythonPort) args.push("--port", String(this.config.pythonPort));
|
|
@@ -23141,7 +23360,7 @@ var VoiceChatPlugin = class _VoiceChatPlugin {
|
|
|
23141
23360
|
}
|
|
23142
23361
|
console.log(`[voice-chat] Starting Python: ${pythonBin} ${args.join(" ")}`);
|
|
23143
23362
|
console.log(`[voice-chat] Python dir: ${pythonDir}`);
|
|
23144
|
-
if (!
|
|
23363
|
+
if (!fs23.existsSync(pythonDir)) {
|
|
23145
23364
|
console.error(`[voice-chat] FATAL: Python directory does not exist: ${pythonDir}`);
|
|
23146
23365
|
throw new Error(`voice-chat: python dir not found: ${pythonDir}`);
|
|
23147
23366
|
}
|
|
@@ -23164,7 +23383,7 @@ var VoiceChatPlugin = class _VoiceChatPlugin {
|
|
|
23164
23383
|
child.on("error", (err) => {
|
|
23165
23384
|
console.error(`[voice-chat] spawn error: ${err.message}`);
|
|
23166
23385
|
console.error(`[voice-chat] shell=${pythonBin} cwd=${pythonDir}`);
|
|
23167
|
-
console.error(`[voice-chat] cwd exists=${
|
|
23386
|
+
console.error(`[voice-chat] cwd exists=${fs23.existsSync(pythonDir)}`);
|
|
23168
23387
|
});
|
|
23169
23388
|
child.stdout?.on("data", (data) => {
|
|
23170
23389
|
const lines = data.toString().trim().split("\n");
|
|
@@ -23197,8 +23416,8 @@ var VoiceChatPlugin = class _VoiceChatPlugin {
|
|
|
23197
23416
|
init_BashTool();
|
|
23198
23417
|
import { spawn as spawn5, exec as exec2 } from "node:child_process";
|
|
23199
23418
|
import net2 from "node:net";
|
|
23200
|
-
import
|
|
23201
|
-
import
|
|
23419
|
+
import path25 from "node:path";
|
|
23420
|
+
import fs24 from "node:fs";
|
|
23202
23421
|
|
|
23203
23422
|
// src/memory/cognifold/config.ts
|
|
23204
23423
|
var DEFAULTS3 = {
|
|
@@ -23236,11 +23455,11 @@ var CogniFoldClient = class {
|
|
|
23236
23455
|
this.timeoutMs = timeoutMs;
|
|
23237
23456
|
this.modelName = modelName;
|
|
23238
23457
|
}
|
|
23239
|
-
async req(
|
|
23458
|
+
async req(path46, options = {}) {
|
|
23240
23459
|
const ctrl = new AbortController();
|
|
23241
23460
|
const timer = setTimeout(() => ctrl.abort(), this.timeoutMs);
|
|
23242
23461
|
try {
|
|
23243
|
-
const resp = await fetch(`${this.baseUrl}${
|
|
23462
|
+
const resp = await fetch(`${this.baseUrl}${path46}`, {
|
|
23244
23463
|
...options,
|
|
23245
23464
|
signal: ctrl.signal,
|
|
23246
23465
|
headers: {
|
|
@@ -23330,8 +23549,8 @@ var CogniFoldClient = class {
|
|
|
23330
23549
|
});
|
|
23331
23550
|
}
|
|
23332
23551
|
/** 兼容老版命名 */
|
|
23333
|
-
async recl(
|
|
23334
|
-
return this.req(
|
|
23552
|
+
async recl(path46, options = {}) {
|
|
23553
|
+
return this.req(path46, options);
|
|
23335
23554
|
}
|
|
23336
23555
|
};
|
|
23337
23556
|
|
|
@@ -23612,16 +23831,16 @@ var CogniFoldPlugin = class {
|
|
|
23612
23831
|
const dir = import.meta.dirname;
|
|
23613
23832
|
const candidates = [
|
|
23614
23833
|
// 从 dist/ 往回找 src
|
|
23615
|
-
|
|
23616
|
-
|
|
23617
|
-
|
|
23834
|
+
path25.resolve(dir, "..", "src", "memory", "cognifold", "python"),
|
|
23835
|
+
path25.resolve(dir, "..", "..", "src", "memory", "cognifold", "python"),
|
|
23836
|
+
path25.resolve(dir, "..", "..", "..", "src", "memory", "cognifold", "python"),
|
|
23618
23837
|
// 从 src/memory/cognifold/ 找本地
|
|
23619
|
-
|
|
23838
|
+
path25.join(dir, "python"),
|
|
23620
23839
|
// 从 dist/memory/cognifold/ 找本地
|
|
23621
|
-
|
|
23840
|
+
path25.resolve(dir, "python")
|
|
23622
23841
|
];
|
|
23623
23842
|
for (const candidate of candidates) {
|
|
23624
|
-
if (
|
|
23843
|
+
if (fs24.existsSync(path25.join(candidate, "cognifold"))) {
|
|
23625
23844
|
return candidate;
|
|
23626
23845
|
}
|
|
23627
23846
|
}
|
|
@@ -23647,7 +23866,7 @@ var CogniFoldPlugin = class {
|
|
|
23647
23866
|
const pythonBin = this.findPython();
|
|
23648
23867
|
console.log(`[cognifold] Starting Python: ${pythonBin} ${args.join(" ")}`);
|
|
23649
23868
|
console.log(`[cognifold] Python dir: ${pythonDir}`);
|
|
23650
|
-
if (!
|
|
23869
|
+
if (!fs24.existsSync(path25.join(pythonDir, "cognifold"))) {
|
|
23651
23870
|
console.error(`[cognifold] FATAL: Python module not found at ${pythonDir}/cognifold`);
|
|
23652
23871
|
throw new Error(`cognifold: python module not found`);
|
|
23653
23872
|
}
|
|
@@ -23658,10 +23877,10 @@ var CogniFoldPlugin = class {
|
|
|
23658
23877
|
if (this.config.llm?.baseUrl) {
|
|
23659
23878
|
childEnv["OPENAI_BASE_URL"] = this.config.llm.baseUrl;
|
|
23660
23879
|
}
|
|
23661
|
-
const envFile =
|
|
23880
|
+
const envFile = path25.join(pythonDir, ".env");
|
|
23662
23881
|
try {
|
|
23663
|
-
if (
|
|
23664
|
-
const envContent =
|
|
23882
|
+
if (fs24.existsSync(envFile)) {
|
|
23883
|
+
const envContent = fs24.readFileSync(envFile, "utf-8");
|
|
23665
23884
|
for (const line of envContent.split("\n")) {
|
|
23666
23885
|
const trimmed = line.trim();
|
|
23667
23886
|
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
@@ -23727,11 +23946,10 @@ var CogniFoldPlugin = class {
|
|
|
23727
23946
|
};
|
|
23728
23947
|
|
|
23729
23948
|
// src/memory/everos/plugin.ts
|
|
23730
|
-
init_BashTool();
|
|
23731
23949
|
import { spawn as spawn6 } from "node:child_process";
|
|
23732
23950
|
import net3 from "node:net";
|
|
23733
|
-
import
|
|
23734
|
-
import
|
|
23951
|
+
import path26 from "node:path";
|
|
23952
|
+
import fs25 from "node:fs";
|
|
23735
23953
|
|
|
23736
23954
|
// src/memory/everos/config.ts
|
|
23737
23955
|
var DEFAULTS4 = {
|
|
@@ -23938,8 +24156,8 @@ var EverosPlugin = class {
|
|
|
23938
24156
|
}, 3e5);
|
|
23939
24157
|
}
|
|
23940
24158
|
async startEveros() {
|
|
23941
|
-
const pythonDir =
|
|
23942
|
-
const configPath =
|
|
24159
|
+
const pythonDir = path26.dirname(this.config.lancedbPath);
|
|
24160
|
+
const configPath = path26.join(pythonDir, "config.toml");
|
|
23943
24161
|
await this.ensureFcntlCompat();
|
|
23944
24162
|
const venvPython = this.findVenvPython();
|
|
23945
24163
|
const everosBin = venvPython.replace(/python\.exe$/, "everos.exe");
|
|
@@ -23948,16 +24166,15 @@ var EverosPlugin = class {
|
|
|
23948
24166
|
console.log(`[everos] Starting EverOS: ${cmd}`);
|
|
23949
24167
|
console.log(`[everos] LLM config: ${this.config.llm.model} @ ${this.config.llm.baseUrl}`);
|
|
23950
24168
|
if (process.platform === "win32") {
|
|
23951
|
-
|
|
23952
|
-
spawn6(shell, [...shellArgs, cmd], {
|
|
24169
|
+
spawn6(everosBin, args, {
|
|
23953
24170
|
cwd: pythonDir,
|
|
23954
|
-
stdio:
|
|
24171
|
+
stdio: "ignore",
|
|
23955
24172
|
env: { ...process.env, PYTHONUNBUFFERED: "1", NO_PROXY: "127.0.0.1,localhost", no_proxy: "127.0.0.1,localhost" }
|
|
23956
24173
|
});
|
|
23957
24174
|
} else {
|
|
23958
24175
|
spawn6(venvPython, args, {
|
|
23959
24176
|
cwd: pythonDir,
|
|
23960
|
-
stdio:
|
|
24177
|
+
stdio: "ignore",
|
|
23961
24178
|
env: { ...process.env, PYTHONUNBUFFERED: "1", NO_PROXY: "127.0.0.1,localhost", no_proxy: "127.0.0.1,localhost" }
|
|
23962
24179
|
});
|
|
23963
24180
|
}
|
|
@@ -24030,19 +24247,19 @@ var EverosPlugin = class {
|
|
|
24030
24247
|
return child;
|
|
24031
24248
|
}
|
|
24032
24249
|
findVenvPython() {
|
|
24033
|
-
const stateDir = (process.env.ENGINE7_STATE_DIR ?? process.env.OPENCLAW_STATE_DIR) ||
|
|
24250
|
+
const stateDir = (process.env.ENGINE7_STATE_DIR ?? process.env.OPENCLAW_STATE_DIR) || path26.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7");
|
|
24034
24251
|
if (process.platform === "win32") {
|
|
24035
|
-
return
|
|
24252
|
+
return path26.join(stateDir, "everos-venv", "Scripts", "python.exe");
|
|
24036
24253
|
}
|
|
24037
|
-
return
|
|
24254
|
+
return path26.join(stateDir, "everos-venv", "bin", "python");
|
|
24038
24255
|
}
|
|
24039
24256
|
/** 检测 venv 是否存在,不存在就自动创建 + 装 EverOS */
|
|
24040
24257
|
async ensureVenv() {
|
|
24041
24258
|
const venvPython = this.findVenvPython();
|
|
24042
|
-
if (
|
|
24043
|
-
const stateDir = (process.env.ENGINE7_STATE_DIR ?? process.env.OPENCLAW_STATE_DIR) ||
|
|
24044
|
-
const venvDir =
|
|
24045
|
-
const everosSrc =
|
|
24259
|
+
if (fs25.existsSync(venvPython)) return;
|
|
24260
|
+
const stateDir = (process.env.ENGINE7_STATE_DIR ?? process.env.OPENCLAW_STATE_DIR) || path26.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7");
|
|
24261
|
+
const venvDir = path26.join(stateDir, "everos-venv");
|
|
24262
|
+
const everosSrc = path26.join(stateDir, "workspace", "research", "EverOS");
|
|
24046
24263
|
console.log(`[everos] venv not found at ${venvDir}, auto-creating...`);
|
|
24047
24264
|
console.log(`[everos] \u23F3 This may take a few minutes on first run...`);
|
|
24048
24265
|
const pyCandidates = process.platform === "win32" ? ["python", "python3", "C:\\Python314\\python.exe", "C:\\Python313\\python.exe", "C:\\Python312\\python.exe"] : ["python3", "python"];
|
|
@@ -24064,9 +24281,9 @@ var EverosPlugin = class {
|
|
|
24064
24281
|
console.log(`[everos] Creating venv with ${sysPython}...`);
|
|
24065
24282
|
const { execSync: execSync3 } = await import("node:child_process");
|
|
24066
24283
|
execSync3(`"${sysPython}" -m venv "${venvDir}"`, { stdio: "pipe", shell: true });
|
|
24067
|
-
const pip = process.platform === "win32" ?
|
|
24068
|
-
const everosReq =
|
|
24069
|
-
if (
|
|
24284
|
+
const pip = process.platform === "win32" ? path26.join(venvDir, "Scripts", "pip.exe") : path26.join(venvDir, "bin", "pip");
|
|
24285
|
+
const everosReq = path26.join(this.getPythonDir(), "requirements.txt");
|
|
24286
|
+
if (fs25.existsSync(everosReq)) {
|
|
24070
24287
|
console.log(`[everos] Installing from requirements.txt...`);
|
|
24071
24288
|
execSync3(`"${pip}" install -r "${everosReq}" -q`, { stdio: "pipe", shell: true, timeout: 3e5 });
|
|
24072
24289
|
} else {
|
|
@@ -24082,12 +24299,12 @@ var EverosPlugin = class {
|
|
|
24082
24299
|
getPythonDir() {
|
|
24083
24300
|
const dir = import.meta.dirname;
|
|
24084
24301
|
const candidates = [
|
|
24085
|
-
|
|
24086
|
-
|
|
24087
|
-
|
|
24302
|
+
path26.join(dir, "python"),
|
|
24303
|
+
path26.resolve(dir, "..", "src", "memory", "everos", "python"),
|
|
24304
|
+
path26.resolve(dir, "..", "..", "..", "src", "memory", "everos", "python")
|
|
24088
24305
|
];
|
|
24089
24306
|
for (const candidate of candidates) {
|
|
24090
|
-
if (
|
|
24307
|
+
if (fs25.existsSync(path26.join(candidate, "agentic_server.py"))) {
|
|
24091
24308
|
return candidate;
|
|
24092
24309
|
}
|
|
24093
24310
|
}
|
|
@@ -24096,14 +24313,14 @@ var EverosPlugin = class {
|
|
|
24096
24313
|
async ensureFcntlCompat() {
|
|
24097
24314
|
if (process.platform !== "win32") return;
|
|
24098
24315
|
const venvPython = this.findVenvPython();
|
|
24099
|
-
const venvDir =
|
|
24100
|
-
const sitePackages =
|
|
24101
|
-
const target =
|
|
24102
|
-
if (
|
|
24103
|
-
const source =
|
|
24104
|
-
if (
|
|
24316
|
+
const venvDir = path26.dirname(path26.dirname(venvPython));
|
|
24317
|
+
const sitePackages = path26.join(venvDir, "Lib", "site-packages");
|
|
24318
|
+
const target = path26.join(sitePackages, "fcntl.py");
|
|
24319
|
+
if (fs25.existsSync(target)) return;
|
|
24320
|
+
const source = path26.join(this.getPythonDir(), "fcntl_compat.py");
|
|
24321
|
+
if (fs25.existsSync(source)) {
|
|
24105
24322
|
try {
|
|
24106
|
-
|
|
24323
|
+
fs25.copyFileSync(source, target);
|
|
24107
24324
|
console.log(`[everos] Installed fcntl compat shim to ${target}`);
|
|
24108
24325
|
} catch (err) {
|
|
24109
24326
|
console.warn(`[everos] Failed to install fcntl shim: ${err.message}`);
|
|
@@ -24150,21 +24367,21 @@ var EverosPlugin = class {
|
|
|
24150
24367
|
init_task_manager();
|
|
24151
24368
|
|
|
24152
24369
|
// src/skills/scanner.ts
|
|
24153
|
-
import * as
|
|
24154
|
-
import * as
|
|
24370
|
+
import * as path27 from "node:path";
|
|
24371
|
+
import * as fs26 from "node:fs";
|
|
24155
24372
|
function scanSkills(skillsDir) {
|
|
24156
|
-
if (!
|
|
24373
|
+
if (!fs26.existsSync(skillsDir)) {
|
|
24157
24374
|
console.log(`[skills] Directory not found: ${skillsDir}`);
|
|
24158
24375
|
return [];
|
|
24159
24376
|
}
|
|
24160
|
-
const entries =
|
|
24377
|
+
const entries = fs26.readdirSync(skillsDir, { withFileTypes: true });
|
|
24161
24378
|
const skills = [];
|
|
24162
24379
|
for (const entry of entries) {
|
|
24163
24380
|
if (!entry.isDirectory()) continue;
|
|
24164
|
-
const skillMdPath =
|
|
24165
|
-
if (!
|
|
24381
|
+
const skillMdPath = path27.join(skillsDir, entry.name, "SKILL.md");
|
|
24382
|
+
if (!fs26.existsSync(skillMdPath)) continue;
|
|
24166
24383
|
try {
|
|
24167
|
-
const content =
|
|
24384
|
+
const content = fs26.readFileSync(skillMdPath, "utf-8");
|
|
24168
24385
|
const frontmatter = parseFrontmatter2(content);
|
|
24169
24386
|
if (!frontmatter.name) {
|
|
24170
24387
|
console.warn(`[skills] Skipping ${entry.name}/SKILL.md: missing 'name' in frontmatter`);
|
|
@@ -24228,8 +24445,8 @@ function parseFrontmatter2(content) {
|
|
|
24228
24445
|
|
|
24229
24446
|
// src/tools/SkillTool/SkillTool.ts
|
|
24230
24447
|
init_registry();
|
|
24231
|
-
import * as
|
|
24232
|
-
import * as
|
|
24448
|
+
import * as fs27 from "node:fs";
|
|
24449
|
+
import * as path28 from "node:path";
|
|
24233
24450
|
|
|
24234
24451
|
// src/tools/SkillTool/constants.ts
|
|
24235
24452
|
var SKILL_TOOL_NAME2 = "Skill";
|
|
@@ -24306,12 +24523,12 @@ Important:
|
|
|
24306
24523
|
`;
|
|
24307
24524
|
}
|
|
24308
24525
|
function loadSkillContent(skillName) {
|
|
24309
|
-
const skillMdPath =
|
|
24310
|
-
if (!
|
|
24311
|
-
const content =
|
|
24526
|
+
const skillMdPath = path28.join(skillsDirPath, skillName, "SKILL.md");
|
|
24527
|
+
if (!fs27.existsSync(skillMdPath)) return null;
|
|
24528
|
+
const content = fs27.readFileSync(skillMdPath, "utf-8");
|
|
24312
24529
|
const bodyMatch = content.match(/^---\s*\n[\s\S]*?\n---\s*\n([\s\S]*)/);
|
|
24313
24530
|
const body = bodyMatch ? bodyMatch[1] : content;
|
|
24314
|
-
const skillDir =
|
|
24531
|
+
const skillDir = path28.dirname(skillMdPath);
|
|
24315
24532
|
const normalizedDir = process.platform === "win32" ? skillDir.replace(/\\/g, "/") : skillDir;
|
|
24316
24533
|
let finalContent = `Base directory for this skill: ${normalizedDir}
|
|
24317
24534
|
|
|
@@ -24585,12 +24802,12 @@ Examples:
|
|
|
24585
24802
|
// src/tools/msg-husband.ts
|
|
24586
24803
|
init_registry();
|
|
24587
24804
|
init_live();
|
|
24588
|
-
import
|
|
24589
|
-
import
|
|
24805
|
+
import fs28 from "node:fs";
|
|
24806
|
+
import path29 from "node:path";
|
|
24590
24807
|
function getHusbandFeishuId(workspace) {
|
|
24591
|
-
const contactsPath =
|
|
24808
|
+
const contactsPath = path29.join(workspace, "prompts", "contacts.md");
|
|
24592
24809
|
try {
|
|
24593
|
-
const text =
|
|
24810
|
+
const text = fs28.readFileSync(contactsPath, "utf-8");
|
|
24594
24811
|
const m = text.match(/\|\s*翀哥\s*\|\s*(ou_[a-f0-9]+)\s*\|/);
|
|
24595
24812
|
return m ? m[1] : null;
|
|
24596
24813
|
} catch {
|
|
@@ -24732,8 +24949,8 @@ Examples:
|
|
|
24732
24949
|
if (!to && !resolvedChannelId) {
|
|
24733
24950
|
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 };
|
|
24734
24951
|
}
|
|
24735
|
-
const
|
|
24736
|
-
if (!
|
|
24952
|
+
const fs43 = await import("node:fs");
|
|
24953
|
+
if (!fs43.existsSync(filePath)) {
|
|
24737
24954
|
return { content: `\u53D1\u9001\u5931\u8D25: \u6587\u4EF6\u4E0D\u5B58\u5728 ${filePath}`, isError: true };
|
|
24738
24955
|
}
|
|
24739
24956
|
const toIds = to ? to.split(",").map((s) => s.trim()).filter(Boolean) : [];
|
|
@@ -24761,7 +24978,7 @@ Examples:
|
|
|
24761
24978
|
md: "text/markdown"
|
|
24762
24979
|
};
|
|
24763
24980
|
const mimeType = mimeTypeMap[ext] || "application/octet-stream";
|
|
24764
|
-
const stat4 =
|
|
24981
|
+
const stat4 = fs43.statSync(filePath);
|
|
24765
24982
|
const sizeMB = stat4.size / 1024 / 1024;
|
|
24766
24983
|
if (sizeMB > 25) {
|
|
24767
24984
|
return { content: `\u53D1\u9001\u5931\u8D25: \u6587\u4EF6 ${sizeMB.toFixed(1)}MB \u8D85\u8FC7 Discord 25MB \u9650\u5236`, isError: true };
|
|
@@ -24790,8 +25007,8 @@ Examples:
|
|
|
24790
25007
|
// src/tools/my-eyes.ts
|
|
24791
25008
|
init_live();
|
|
24792
25009
|
init_registry();
|
|
24793
|
-
import * as
|
|
24794
|
-
import * as
|
|
25010
|
+
import * as fs29 from "node:fs";
|
|
25011
|
+
import * as path30 from "node:path";
|
|
24795
25012
|
var MIME_MAP = {
|
|
24796
25013
|
".jpg": "jpeg",
|
|
24797
25014
|
".jpeg": "jpeg",
|
|
@@ -24801,9 +25018,9 @@ var MIME_MAP = {
|
|
|
24801
25018
|
".bmp": "bmp"
|
|
24802
25019
|
};
|
|
24803
25020
|
function resolveLatestImage(specifiedPath, mediaDir) {
|
|
24804
|
-
if (specifiedPath &&
|
|
24805
|
-
if (!
|
|
24806
|
-
const files =
|
|
25021
|
+
if (specifiedPath && fs29.existsSync(specifiedPath)) return specifiedPath;
|
|
25022
|
+
if (!fs29.existsSync(mediaDir)) return null;
|
|
25023
|
+
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);
|
|
24807
25024
|
return files[0]?.p || null;
|
|
24808
25025
|
}
|
|
24809
25026
|
registry.register({
|
|
@@ -24828,15 +25045,15 @@ registry.register({
|
|
|
24828
25045
|
if (!provider?.streamChat) {
|
|
24829
25046
|
return { content: "Error: provider \u4E0D\u53EF\u7528\u3002", isError: true };
|
|
24830
25047
|
}
|
|
24831
|
-
const mediaDir =
|
|
25048
|
+
const mediaDir = path30.join(ctx.stateDir, "media", "inbound");
|
|
24832
25049
|
const imagePath = resolveLatestImage(args.image_path, mediaDir);
|
|
24833
25050
|
if (!imagePath) {
|
|
24834
25051
|
return { content: "Error: no image found. Provide image_path or ensure media/inbound has images.", isError: true };
|
|
24835
25052
|
}
|
|
24836
25053
|
const rawPrompt = args.prompt?.trim() || "\u63CF\u8FF0\u8FD9\u5F20\u56FE\u7247\u7684\u5185\u5BB9";
|
|
24837
|
-
const ext =
|
|
25054
|
+
const ext = path30.extname(imagePath).toLowerCase();
|
|
24838
25055
|
const mime = MIME_MAP[ext] || "jpeg";
|
|
24839
|
-
const imgB64 =
|
|
25056
|
+
const imgB64 = fs29.readFileSync(imagePath).toString("base64");
|
|
24840
25057
|
const userMsg = {
|
|
24841
25058
|
role: "user",
|
|
24842
25059
|
content: [
|
|
@@ -24873,14 +25090,14 @@ init_live();
|
|
|
24873
25090
|
init_registry();
|
|
24874
25091
|
import { execFile } from "node:child_process";
|
|
24875
25092
|
import { promisify } from "node:util";
|
|
24876
|
-
import * as
|
|
24877
|
-
import * as
|
|
25093
|
+
import * as fs30 from "node:fs";
|
|
25094
|
+
import * as path31 from "node:path";
|
|
24878
25095
|
import * as os3 from "node:os";
|
|
24879
25096
|
var execFileAsync = promisify(execFile);
|
|
24880
|
-
var VOICE_DIR =
|
|
25097
|
+
var VOICE_DIR = path31.join(os3.tmpdir(), "engine-voice");
|
|
24881
25098
|
async function ttsCosyvoice(text, apiKey, model, voice, workspaceId, instruction) {
|
|
24882
|
-
|
|
24883
|
-
const output =
|
|
25099
|
+
fs30.mkdirSync(VOICE_DIR, { recursive: true });
|
|
25100
|
+
const output = path31.join(VOICE_DIR, `tts_${Date.now()}.wav`);
|
|
24884
25101
|
const script = `
|
|
24885
25102
|
import sys, json, wave, time, threading
|
|
24886
25103
|
import dashscope
|
|
@@ -24937,7 +25154,7 @@ print(f"OK: {len(pcm)} bytes")
|
|
|
24937
25154
|
`;
|
|
24938
25155
|
const configJson = JSON.stringify({ apiKey, model, voice, workspaceId, instruction });
|
|
24939
25156
|
await execFileAsync("python3", ["-c", script, configJson, text, output], { timeout: 3e4 });
|
|
24940
|
-
if (!
|
|
25157
|
+
if (!fs30.existsSync(output) || fs30.statSync(output).size < 100) {
|
|
24941
25158
|
throw new Error("CosyVoice produced empty output");
|
|
24942
25159
|
}
|
|
24943
25160
|
return output;
|
|
@@ -24947,8 +25164,8 @@ var GPTSOVITS_REF_WAV = "/home/chong/voice/ref/shanshan_ref_v2.wav";
|
|
|
24947
25164
|
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";
|
|
24948
25165
|
var GPTSOVITS_REF_LANG = "zh";
|
|
24949
25166
|
async function ttsGptsovits(text) {
|
|
24950
|
-
|
|
24951
|
-
const output =
|
|
25167
|
+
fs30.mkdirSync(VOICE_DIR, { recursive: true });
|
|
25168
|
+
const output = path31.join(VOICE_DIR, `tts_${Date.now()}.wav`);
|
|
24952
25169
|
const params = new URLSearchParams({
|
|
24953
25170
|
text,
|
|
24954
25171
|
text_language: "zh",
|
|
@@ -24959,13 +25176,13 @@ async function ttsGptsovits(text) {
|
|
|
24959
25176
|
const res = await fetch(`${GPTSOVITS_API}/?${params}`);
|
|
24960
25177
|
if (!res.ok) throw new Error(`GPT-SoVITS API ${res.status}`);
|
|
24961
25178
|
const buf = Buffer.from(await res.arrayBuffer());
|
|
24962
|
-
|
|
25179
|
+
fs30.writeFileSync(output, buf);
|
|
24963
25180
|
return output;
|
|
24964
25181
|
}
|
|
24965
25182
|
var EDGE_VOICE = "zh-CN-XiaoxiaoNeural";
|
|
24966
25183
|
async function ttsEdge(text) {
|
|
24967
|
-
|
|
24968
|
-
const output =
|
|
25184
|
+
fs30.mkdirSync(VOICE_DIR, { recursive: true });
|
|
25185
|
+
const output = path31.join(VOICE_DIR, `tts_${Date.now()}.mp3`);
|
|
24969
25186
|
const script = `
|
|
24970
25187
|
import asyncio, edge_tts, sys
|
|
24971
25188
|
async def main():
|
|
@@ -24991,7 +25208,7 @@ async function compressWav(wavPath) {
|
|
|
24991
25208
|
"+faststart",
|
|
24992
25209
|
m4aPath
|
|
24993
25210
|
], { timeout: 3e4 });
|
|
24994
|
-
|
|
25211
|
+
fs30.unlinkSync(wavPath);
|
|
24995
25212
|
return m4aPath;
|
|
24996
25213
|
} catch {
|
|
24997
25214
|
return wavPath;
|
|
@@ -25059,10 +25276,10 @@ registry.register({
|
|
|
25059
25276
|
} catch (e) {
|
|
25060
25277
|
return { content: `TTS failed: ${e.message}`, isError: true };
|
|
25061
25278
|
}
|
|
25062
|
-
const ext =
|
|
25279
|
+
const ext = path31.extname(audioPath).toLowerCase();
|
|
25063
25280
|
const mimeMap = { ".mp3": "audio/mpeg", ".wav": "audio/wav", ".m4a": "audio/mp4", ".ogg": "audio/ogg" };
|
|
25064
25281
|
const mimeType = mimeMap[ext] || "audio/mpeg";
|
|
25065
|
-
const sizeKB =
|
|
25282
|
+
const sizeKB = fs30.statSync(audioPath).size / 1024;
|
|
25066
25283
|
const resolvedChannel = args.channel || ctx.channel || "feishu";
|
|
25067
25284
|
const target = ctx.channelTarget || ctx.from;
|
|
25068
25285
|
try {
|
|
@@ -25072,7 +25289,7 @@ registry.register({
|
|
|
25072
25289
|
filename: `voice_${Date.now()}${ext}`
|
|
25073
25290
|
});
|
|
25074
25291
|
try {
|
|
25075
|
-
|
|
25292
|
+
fs30.unlinkSync(audioPath);
|
|
25076
25293
|
} catch {
|
|
25077
25294
|
}
|
|
25078
25295
|
return { content: `Voice sent! (${actualEngine}, ${sizeKB.toFixed(0)}KB, ${resolvedChannel})` };
|
|
@@ -25089,8 +25306,8 @@ registry.register({
|
|
|
25089
25306
|
// src/tools/my-selfie.ts
|
|
25090
25307
|
init_live();
|
|
25091
25308
|
init_registry();
|
|
25092
|
-
import * as
|
|
25093
|
-
import * as
|
|
25309
|
+
import * as fs31 from "node:fs";
|
|
25310
|
+
import * as path32 from "node:path";
|
|
25094
25311
|
function getProxyDispatcher2() {
|
|
25095
25312
|
const cfg = liveConfig.all();
|
|
25096
25313
|
const proxy = cfg.providers?.xai?.proxy;
|
|
@@ -25147,16 +25364,48 @@ function detectMode(input) {
|
|
|
25147
25364
|
return "direct";
|
|
25148
25365
|
}
|
|
25149
25366
|
async function generateWithFal(imageB64, prompt, resolution) {
|
|
25367
|
+
let aspectRatio;
|
|
25368
|
+
try {
|
|
25369
|
+
const refBuf = Buffer.from(imageB64, "base64");
|
|
25370
|
+
let w = 0, h = 0;
|
|
25371
|
+
if (refBuf[0] === 137 && refBuf[1] === 80) {
|
|
25372
|
+
w = refBuf.readUInt32BE(16);
|
|
25373
|
+
h = refBuf.readUInt32BE(20);
|
|
25374
|
+
} else if (refBuf[0] === 255 && refBuf[1] === 216) {
|
|
25375
|
+
let pos = 2;
|
|
25376
|
+
while (pos < refBuf.length - 1) {
|
|
25377
|
+
if (refBuf[pos] !== 255) {
|
|
25378
|
+
pos++;
|
|
25379
|
+
continue;
|
|
25380
|
+
}
|
|
25381
|
+
const marker = refBuf[pos + 1];
|
|
25382
|
+
if (marker === 192 || marker === 194) {
|
|
25383
|
+
h = refBuf.readUInt16BE(pos + 5);
|
|
25384
|
+
w = refBuf.readUInt16BE(pos + 7);
|
|
25385
|
+
break;
|
|
25386
|
+
}
|
|
25387
|
+
pos += 2 + refBuf.readUInt16BE(pos + 2);
|
|
25388
|
+
}
|
|
25389
|
+
}
|
|
25390
|
+
if (w > 0 && h > 0) {
|
|
25391
|
+
aspectRatio = `${w}/${h}`;
|
|
25392
|
+
console.log(`[my-selfie] ref image ${w}x${h}, aspect_ratio=${aspectRatio}`);
|
|
25393
|
+
}
|
|
25394
|
+
} catch (e) {
|
|
25395
|
+
console.warn(`[my-selfie] Failed to read ref dimensions: ${e.message}`);
|
|
25396
|
+
}
|
|
25397
|
+
const body = {
|
|
25398
|
+
image_url: `data:image/png;base64,${imageB64}`,
|
|
25399
|
+
prompt,
|
|
25400
|
+
num_images: 1,
|
|
25401
|
+
output_format: "jpeg",
|
|
25402
|
+
resolution
|
|
25403
|
+
};
|
|
25404
|
+
if (aspectRatio) body.aspect_ratio = aspectRatio;
|
|
25150
25405
|
const res = await fetch(FAL_ENDPOINT, {
|
|
25151
25406
|
method: "POST",
|
|
25152
25407
|
headers: { "Authorization": `Key ${FAL_KEY}`, "Content-Type": "application/json" },
|
|
25153
|
-
body: JSON.stringify(
|
|
25154
|
-
image_url: `data:image/png;base64,${imageB64}`,
|
|
25155
|
-
prompt,
|
|
25156
|
-
num_images: 1,
|
|
25157
|
-
output_format: "jpeg",
|
|
25158
|
-
resolution
|
|
25159
|
-
})
|
|
25408
|
+
body: JSON.stringify(body)
|
|
25160
25409
|
});
|
|
25161
25410
|
if (!res.ok) {
|
|
25162
25411
|
const text = await res.text();
|
|
@@ -25365,12 +25614,12 @@ registry.register({
|
|
|
25365
25614
|
const REFERENCES = getReferences(ctx);
|
|
25366
25615
|
const refName = args.reference || "default";
|
|
25367
25616
|
const refEntry = REFERENCES.find((r) => r.name === refName) || REFERENCES[0];
|
|
25368
|
-
const refPath =
|
|
25369
|
-
if (provider !== "autodl" && !
|
|
25617
|
+
const refPath = path32.join(ctx.workspace, refEntry.p);
|
|
25618
|
+
if (provider !== "autodl" && !fs31.existsSync(refPath)) {
|
|
25370
25619
|
return { content: `Error: reference image not found at ${refPath}`, isError: true };
|
|
25371
25620
|
}
|
|
25372
25621
|
const resolution = args.resolution || DEFAULT_RESOLUTION;
|
|
25373
|
-
const refB64 =
|
|
25622
|
+
const refB64 = fs31.existsSync(refPath) ? fs31.readFileSync(refPath).toString("base64") : "";
|
|
25374
25623
|
let imageBuffer;
|
|
25375
25624
|
try {
|
|
25376
25625
|
if (provider === "autodl") {
|
|
@@ -25385,11 +25634,11 @@ registry.register({
|
|
|
25385
25634
|
} catch (err) {
|
|
25386
25635
|
return { content: `Selfie generation failed: ${err.message}`, isError: true };
|
|
25387
25636
|
}
|
|
25388
|
-
const imagesDir =
|
|
25389
|
-
if (!
|
|
25637
|
+
const imagesDir = path32.join(ctx.workspace, "images");
|
|
25638
|
+
if (!fs31.existsSync(imagesDir)) fs31.mkdirSync(imagesDir, { recursive: true });
|
|
25390
25639
|
const filename = `selfie_${Date.now()}.jpg`;
|
|
25391
|
-
const outputPath =
|
|
25392
|
-
|
|
25640
|
+
const outputPath = path32.join(imagesDir, filename);
|
|
25641
|
+
fs31.writeFileSync(outputPath, imageBuffer);
|
|
25393
25642
|
const mgr = ctx.channelManager;
|
|
25394
25643
|
if (mgr) {
|
|
25395
25644
|
const resolvedChannel = ctx.channel || "feishu";
|
|
@@ -25400,11 +25649,11 @@ registry.register({
|
|
|
25400
25649
|
mimeType: "image/jpeg"
|
|
25401
25650
|
});
|
|
25402
25651
|
} catch (err) {
|
|
25403
|
-
return { content: `Selfie generated but send failed: ${err.message}. Image: ${
|
|
25652
|
+
return { content: `Selfie generated but send failed: ${err.message}. Image: ${path32.resolve(outputPath)}`, isError: false };
|
|
25404
25653
|
}
|
|
25405
25654
|
return { content: `Selfie sent! Mode: ${mode}, Provider: ${provider}, Ref: ${refEntry.name}` };
|
|
25406
25655
|
}
|
|
25407
|
-
return { content: `Selfie generated! Mode: ${mode}, Ref: ${refEntry.name}. Image: ${
|
|
25656
|
+
return { content: `Selfie generated! Mode: ${mode}, Ref: ${refEntry.name}. Image: ${path32.resolve(outputPath)}` };
|
|
25408
25657
|
},
|
|
25409
25658
|
isConcurrencySafe: () => false,
|
|
25410
25659
|
interruptBehavior: () => "block",
|
|
@@ -25949,16 +26198,16 @@ var EXIT_PLAN_MODE_TOOL_NAME = "ExitPlanMode";
|
|
|
25949
26198
|
init_planModeState();
|
|
25950
26199
|
|
|
25951
26200
|
// src/utils/plans.ts
|
|
25952
|
-
import * as
|
|
25953
|
-
import * as
|
|
26201
|
+
import * as fs33 from "node:fs";
|
|
26202
|
+
import * as path34 from "node:path";
|
|
25954
26203
|
import * as crypto4 from "node:crypto";
|
|
25955
26204
|
var MAX_SLUG_RETRIES = 10;
|
|
25956
26205
|
function generateSlug() {
|
|
25957
26206
|
return crypto4.randomBytes(4).toString("hex");
|
|
25958
26207
|
}
|
|
25959
26208
|
function getPlansDirectory(stateDir) {
|
|
25960
|
-
const plansDir =
|
|
25961
|
-
|
|
26209
|
+
const plansDir = path34.join(stateDir, "plans");
|
|
26210
|
+
fs33.mkdirSync(plansDir, { recursive: true });
|
|
25962
26211
|
return plansDir;
|
|
25963
26212
|
}
|
|
25964
26213
|
var planSlugCache = /* @__PURE__ */ new Map();
|
|
@@ -25968,8 +26217,8 @@ function getPlanSlug(sessionId, stateDir) {
|
|
|
25968
26217
|
const plansDir = getPlansDirectory(stateDir);
|
|
25969
26218
|
for (let i = 0; i < MAX_SLUG_RETRIES; i++) {
|
|
25970
26219
|
slug = generateSlug();
|
|
25971
|
-
const filePath =
|
|
25972
|
-
if (!
|
|
26220
|
+
const filePath = path34.join(plansDir, `${slug}.md`);
|
|
26221
|
+
if (!fs33.existsSync(filePath)) {
|
|
25973
26222
|
break;
|
|
25974
26223
|
}
|
|
25975
26224
|
}
|
|
@@ -25980,21 +26229,21 @@ function getPlanSlug(sessionId, stateDir) {
|
|
|
25980
26229
|
function getPlanFilePath(sessionId, stateDir, agentId) {
|
|
25981
26230
|
const slug = getPlanSlug(sessionId, stateDir);
|
|
25982
26231
|
if (!agentId) {
|
|
25983
|
-
return
|
|
26232
|
+
return path34.join(getPlansDirectory(stateDir), `${slug}.md`);
|
|
25984
26233
|
}
|
|
25985
|
-
return
|
|
26234
|
+
return path34.join(getPlansDirectory(stateDir), `${slug}-agent-${agentId}.md`);
|
|
25986
26235
|
}
|
|
25987
26236
|
function getPlan(sessionId, stateDir, agentId) {
|
|
25988
26237
|
const filePath = getPlanFilePath(sessionId, stateDir, agentId);
|
|
25989
26238
|
try {
|
|
25990
|
-
return
|
|
26239
|
+
return fs33.readFileSync(filePath, "utf-8");
|
|
25991
26240
|
} catch {
|
|
25992
26241
|
return null;
|
|
25993
26242
|
}
|
|
25994
26243
|
}
|
|
25995
26244
|
function writePlan(sessionId, stateDir, content, agentId) {
|
|
25996
26245
|
const filePath = getPlanFilePath(sessionId, stateDir, agentId);
|
|
25997
|
-
|
|
26246
|
+
fs33.writeFileSync(filePath, content, "utf-8");
|
|
25998
26247
|
return filePath;
|
|
25999
26248
|
}
|
|
26000
26249
|
|
|
@@ -26830,8 +27079,8 @@ async function setupFeatures(features, licensedFeatures) {
|
|
|
26830
27079
|
|
|
26831
27080
|
// src/license/license.ts
|
|
26832
27081
|
import * as crypto6 from "node:crypto";
|
|
26833
|
-
import * as
|
|
26834
|
-
import * as
|
|
27082
|
+
import * as fs40 from "node:fs";
|
|
27083
|
+
import * as path42 from "node:path";
|
|
26835
27084
|
var EMBEDDED_PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----
|
|
26836
27085
|
MCowBQYDK2VwAyEAaKBEX+e8+D59qwtidazsu7WYDglApyvsVI3APwFoakA=
|
|
26837
27086
|
-----END PUBLIC KEY-----`;
|
|
@@ -26862,13 +27111,13 @@ function loadLicense(stateDir, devMode) {
|
|
|
26862
27111
|
_cachedLicense = allActive;
|
|
26863
27112
|
return allActive;
|
|
26864
27113
|
}
|
|
26865
|
-
const licensePath =
|
|
26866
|
-
if (!
|
|
27114
|
+
const licensePath = path42.join(stateDir, "license.json");
|
|
27115
|
+
if (!fs40.existsSync(licensePath)) {
|
|
26867
27116
|
console.log("[license] No license.json found, running basic engine only");
|
|
26868
27117
|
return null;
|
|
26869
27118
|
}
|
|
26870
27119
|
try {
|
|
26871
|
-
const raw =
|
|
27120
|
+
const raw = fs40.readFileSync(licensePath, "utf-8");
|
|
26872
27121
|
const license = JSON.parse(raw);
|
|
26873
27122
|
const { signature, ...payload } = license;
|
|
26874
27123
|
if (!signature) {
|
|
@@ -26999,7 +27248,7 @@ ${formatted}` };
|
|
|
26999
27248
|
};
|
|
27000
27249
|
}
|
|
27001
27250
|
function createEverosGetTool() {
|
|
27002
|
-
const
|
|
27251
|
+
const fs43 = __require("node:fs/promises");
|
|
27003
27252
|
return {
|
|
27004
27253
|
name: "memory_get",
|
|
27005
27254
|
description: "Read a memory file by path.",
|
|
@@ -27015,7 +27264,7 @@ function createEverosGetTool() {
|
|
|
27015
27264
|
handler: async (args) => {
|
|
27016
27265
|
try {
|
|
27017
27266
|
const filePath = args.path;
|
|
27018
|
-
const content = await
|
|
27267
|
+
const content = await fs43.readFile(filePath, "utf-8");
|
|
27019
27268
|
const lines = content.split("\n");
|
|
27020
27269
|
const fromLine = args.from ?? 1;
|
|
27021
27270
|
const numLines = args.lines ?? lines.length;
|
|
@@ -27488,11 +27737,11 @@ async function startEngine(config, opts) {
|
|
|
27488
27737
|
process.env.ENGINE7_WORKSPACE = config.workspace;
|
|
27489
27738
|
process.env.OPENCLAW_WORKSPACE = config.workspace;
|
|
27490
27739
|
process.env.ENGINE7_STATE_DIR = config.stateDir;
|
|
27491
|
-
|
|
27492
|
-
|
|
27493
|
-
|
|
27494
|
-
|
|
27495
|
-
|
|
27740
|
+
fs42.mkdirSync(path45.join(config.stateDir, "agents", "main", "memory"), { recursive: true });
|
|
27741
|
+
fs42.mkdirSync(path45.join(config.stateDir, "agents", "main", "sessions"), { recursive: true });
|
|
27742
|
+
fs42.mkdirSync(path45.join(config.stateDir, "logs"), { recursive: true });
|
|
27743
|
+
fs42.mkdirSync(config.workspace, { recursive: true });
|
|
27744
|
+
fs42.mkdirSync(config.mediaDir, { recursive: true });
|
|
27496
27745
|
try {
|
|
27497
27746
|
process.chdir(config.workspace);
|
|
27498
27747
|
} catch (e) {
|
|
@@ -27547,7 +27796,7 @@ async function startEngine(config, opts) {
|
|
|
27547
27796
|
const { initSessionMemory: initSessionMemory2 } = await Promise.resolve().then(() => (init_sessionMemory(), sessionMemory_exports));
|
|
27548
27797
|
initSessionMemory2({
|
|
27549
27798
|
workspace: config.workspace,
|
|
27550
|
-
stateDir:
|
|
27799
|
+
stateDir: path45.join(config.stateDir, "session-memory"),
|
|
27551
27800
|
provider,
|
|
27552
27801
|
model: config.provider.modelId || config.model || "deepseek-v4-flash",
|
|
27553
27802
|
features: config.profile.features
|
|
@@ -27577,9 +27826,9 @@ async function startEngine(config, opts) {
|
|
|
27577
27826
|
if (config.hooks) {
|
|
27578
27827
|
loadHooksFromConfig({ hooks: config.hooks });
|
|
27579
27828
|
}
|
|
27580
|
-
const hooksPath =
|
|
27829
|
+
const hooksPath = path45.join(config.workspace, ".hooks.json");
|
|
27581
27830
|
loadHooksFromFile(hooksPath);
|
|
27582
|
-
const settingsHooksPath =
|
|
27831
|
+
const settingsHooksPath = path45.join(config.stateDir, "settings.json");
|
|
27583
27832
|
loadHooksFromFile(settingsHooksPath);
|
|
27584
27833
|
console.log(`[hooks] Loaded hooks configuration`);
|
|
27585
27834
|
registerCallbackHook("PreCompact", {
|
|
@@ -27593,18 +27842,18 @@ async function startEngine(config, opts) {
|
|
|
27593
27842
|
const bjTime = new Date(now.getTime() + (bjOffset + now.getTimezoneOffset()) * 6e4);
|
|
27594
27843
|
const dateStr = `${bjTime.getFullYear()}-${String(bjTime.getMonth() + 1).padStart(2, "0")}-${String(bjTime.getDate()).padStart(2, "0")}`;
|
|
27595
27844
|
const timeStr = `${String(bjTime.getHours()).padStart(2, "0")}:${String(bjTime.getMinutes()).padStart(2, "0")}`;
|
|
27596
|
-
const dailyDir =
|
|
27597
|
-
const dailyPath =
|
|
27845
|
+
const dailyDir = path45.join(workspace, "memory", "daily");
|
|
27846
|
+
const dailyPath = path45.join(dailyDir, `${dateStr}.md`);
|
|
27598
27847
|
try {
|
|
27599
|
-
const
|
|
27600
|
-
if (!
|
|
27601
|
-
|
|
27848
|
+
const fs43 = await import("node:fs");
|
|
27849
|
+
if (!fs43.existsSync(dailyDir)) {
|
|
27850
|
+
fs43.mkdirSync(dailyDir, { recursive: true });
|
|
27602
27851
|
}
|
|
27603
|
-
const sessionsDir =
|
|
27604
|
-
const sessionFile =
|
|
27852
|
+
const sessionsDir = path45.join(config.stateDir, "agents", "main", "sessions");
|
|
27853
|
+
const sessionFile = path45.join(sessionsDir, `${sessionId}.jsonl`);
|
|
27605
27854
|
const recentLines = [];
|
|
27606
|
-
if (
|
|
27607
|
-
const content =
|
|
27855
|
+
if (fs43.existsSync(sessionFile)) {
|
|
27856
|
+
const content = fs43.readFileSync(sessionFile, "utf-8");
|
|
27608
27857
|
const lines = content.trim().split("\n").filter(Boolean);
|
|
27609
27858
|
const userLines = lines.filter((l) => {
|
|
27610
27859
|
try {
|
|
@@ -27634,10 +27883,10 @@ async function startEngine(config, opts) {
|
|
|
27634
27883
|
const entry = `${header}
|
|
27635
27884
|
${body}
|
|
27636
27885
|
`;
|
|
27637
|
-
if (
|
|
27638
|
-
|
|
27886
|
+
if (fs43.existsSync(dailyPath)) {
|
|
27887
|
+
fs43.appendFileSync(dailyPath, entry);
|
|
27639
27888
|
} else {
|
|
27640
|
-
|
|
27889
|
+
fs43.writeFileSync(dailyPath, `# ${dateStr} \u65E5\u5FD7
|
|
27641
27890
|
${entry}`);
|
|
27642
27891
|
}
|
|
27643
27892
|
console.log(`[hooks] PreCompact: saved ${recentLines.length} lines to ${dailyPath}`);
|
|
@@ -27653,16 +27902,16 @@ ${entry}`);
|
|
|
27653
27902
|
const workspace = input.cwd || input.workspace || "";
|
|
27654
27903
|
if (!workspace) return { continue: true };
|
|
27655
27904
|
try {
|
|
27656
|
-
const
|
|
27657
|
-
const bufferPath =
|
|
27658
|
-
if (
|
|
27659
|
-
const stat4 =
|
|
27905
|
+
const fs43 = await import("node:fs");
|
|
27906
|
+
const bufferPath = path45.join(workspace, "memory", "working-buffer.md");
|
|
27907
|
+
if (fs43.existsSync(bufferPath)) {
|
|
27908
|
+
const stat4 = fs43.statSync(bufferPath);
|
|
27660
27909
|
const ageMs = Date.now() - stat4.mtimeMs;
|
|
27661
27910
|
const ageMin = Math.round(ageMs / 6e4);
|
|
27662
27911
|
if (ageMin > 10) {
|
|
27663
27912
|
console.warn(`[hooks] PostCompact: \u26A0\uFE0F working-buffer.md is ${ageMin}min old (last modified ${stat4.mtime.toISOString()}) \u2014 content may be stale!`);
|
|
27664
27913
|
}
|
|
27665
|
-
const content =
|
|
27914
|
+
const content = fs43.readFileSync(bufferPath, "utf-8");
|
|
27666
27915
|
if (content.trim()) {
|
|
27667
27916
|
console.log(`[hooks] PostCompact: injecting working-buffer (${content.length} chars, ${ageMin}min old)`);
|
|
27668
27917
|
return {
|
|
@@ -27707,7 +27956,7 @@ ${content}`
|
|
|
27707
27956
|
return `${hr}h ${remMin}m`;
|
|
27708
27957
|
}
|
|
27709
27958
|
if (config.skills?.enabled !== false) {
|
|
27710
|
-
const skillsDir = config.skills?.path ?
|
|
27959
|
+
const skillsDir = config.skills?.path ? path45.isAbsolute(config.skills.path) ? config.skills.path : path45.resolve(config.workspace, config.skills.path) : path45.resolve(config.workspace, "skills");
|
|
27711
27960
|
const modelDef2 = config.provider.models.find((m) => m.id === config.model);
|
|
27712
27961
|
const contextWindowTokens = modelDef2?.contextWindow;
|
|
27713
27962
|
const skills = scanSkills(skillsDir);
|
|
@@ -27726,8 +27975,8 @@ ${content}`
|
|
|
27726
27975
|
workspace: config.workspace
|
|
27727
27976
|
});
|
|
27728
27977
|
const systemPrompt = [systemStable, systemDynamic].join("\n\n");
|
|
27729
|
-
const promptDumpPath =
|
|
27730
|
-
|
|
27978
|
+
const promptDumpPath = path45.join(config.workspace, ".system-prompt.txt");
|
|
27979
|
+
fs42.writeFileSync(promptDumpPath, systemPrompt);
|
|
27731
27980
|
console.log(`System prompt: ${systemStable.length} chars stable + ${systemDynamic.length} chars dynamic \u2192 ${promptDumpPath}`);
|
|
27732
27981
|
const modelDef = config.provider.models.find((m) => m.id === config.model);
|
|
27733
27982
|
const modelContextWindow = modelDef?.contextWindow;
|
|
@@ -27852,13 +28101,11 @@ ${content}`
|
|
|
27852
28101
|
model: config.model,
|
|
27853
28102
|
modelInputs: modelDef?.input || ["text"],
|
|
27854
28103
|
systemPrompt,
|
|
27855
|
-
features: config.profile.features,
|
|
27856
28104
|
channels: config.channels,
|
|
27857
28105
|
config,
|
|
27858
28106
|
// tool 读自己配置用
|
|
27859
28107
|
recallProvider: memoryRecallProvider || void 0,
|
|
27860
28108
|
extractProvider: memoryExtractProvider || void 0,
|
|
27861
|
-
topics: config.topics,
|
|
27862
28109
|
everosCfg: config.everos,
|
|
27863
28110
|
mcpManager
|
|
27864
28111
|
};
|
|
@@ -27875,7 +28122,6 @@ ${content}`
|
|
|
27875
28122
|
model: visionConfig.modelId,
|
|
27876
28123
|
modelInputs: visionModelDef?.input || ["text", "image"],
|
|
27877
28124
|
systemPrompt,
|
|
27878
|
-
features: config.profile.features,
|
|
27879
28125
|
channels: config.channels,
|
|
27880
28126
|
config,
|
|
27881
28127
|
// tool 读自己配置用
|
|
@@ -27926,7 +28172,6 @@ ${content}`
|
|
|
27926
28172
|
model: p.model,
|
|
27927
28173
|
modelInputs: p.modelInputs,
|
|
27928
28174
|
systemPrompt,
|
|
27929
|
-
features: config.profile.features,
|
|
27930
28175
|
channels: config.channels,
|
|
27931
28176
|
config,
|
|
27932
28177
|
recallProvider: memoryRecallProvider || void 0,
|
|
@@ -27970,7 +28215,6 @@ ${content}`
|
|
|
27970
28215
|
model: modelId,
|
|
27971
28216
|
modelInputs: modelDef2.input || ["text"],
|
|
27972
28217
|
systemPrompt,
|
|
27973
|
-
features: config.profile.features,
|
|
27974
28218
|
channels: config.channels,
|
|
27975
28219
|
recallProvider: memoryRecallProvider || void 0,
|
|
27976
28220
|
extractProvider: memoryExtractProvider || void 0
|
|
@@ -28755,8 +28999,7 @@ ${result.changes.map((c) => `- ${c}`).join("\n")}` : `\u274C Reload failed: ${re
|
|
|
28755
28999
|
const featureKeys = ["topic-recall", "topic-extract", "session-memory"];
|
|
28756
29000
|
if (featureKeys.includes(ctx.command)) {
|
|
28757
29001
|
const key = ctx.command;
|
|
28758
|
-
const
|
|
28759
|
-
const cur = f[key] === false ? "off" : "on";
|
|
29002
|
+
const cur = getFeature(key) === false ? "off" : "on";
|
|
28760
29003
|
const rawState = (ctx.args.state || "").trim().toLowerCase();
|
|
28761
29004
|
if (rawState === "") {
|
|
28762
29005
|
await ctx.reply(`\u{1F4CA} ${key}: **${cur}**`);
|
|
@@ -28772,39 +29015,9 @@ ${result.changes.map((c) => `- ${c}`).join("\n")}` : `\u274C Reload failed: ${re
|
|
|
28772
29015
|
return;
|
|
28773
29016
|
}
|
|
28774
29017
|
const next = rawState === "on";
|
|
28775
|
-
|
|
28776
|
-
|
|
28777
|
-
|
|
28778
|
-
try {
|
|
28779
|
-
const fs42 = await import("fs");
|
|
28780
|
-
const pathMod = await import("path");
|
|
28781
|
-
let cfgPath = config._configFilePath;
|
|
28782
|
-
if (!cfgPath || !fs42.existsSync(cfgPath)) {
|
|
28783
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
28784
|
-
const __dirname = pathMod.dirname(__filename);
|
|
28785
|
-
cfgPath = pathMod.resolve(__dirname, "../configs", pathMod.basename(cfgPath || "engine-config.json"));
|
|
28786
|
-
}
|
|
28787
|
-
const cfg = JSON.parse(fs42.readFileSync(cfgPath, "utf-8"));
|
|
28788
|
-
let featObj = null;
|
|
28789
|
-
if (cfg.agents?.defaults?.features) {
|
|
28790
|
-
featObj = cfg.agents.defaults.features;
|
|
28791
|
-
} else if (cfg.agents?.defaults) {
|
|
28792
|
-
cfg.agents.defaults.features = {};
|
|
28793
|
-
featObj = cfg.agents.defaults.features;
|
|
28794
|
-
}
|
|
28795
|
-
if (featObj) {
|
|
28796
|
-
featObj[key] = next;
|
|
28797
|
-
fs42.writeFileSync(cfgPath, JSON.stringify(cfg, null, 2) + "\n", "utf-8");
|
|
28798
|
-
console.log(`[${ctx.command}] ${key} ${cur} \u2192 ${rawState} (disk persisted)`);
|
|
28799
|
-
await ctx.reply(`\u2705 ${key}: **${cur}** \u2192 **${rawState}**`);
|
|
28800
|
-
} else {
|
|
28801
|
-
console.warn(`[${ctx.command}] could not locate features in config, in-memory only`);
|
|
28802
|
-
await ctx.reply(`\u2705 ${key}: **${cur}** \u2192 **${rawState}**\uFF08\u5185\u5B58\u751F\u6548\uFF0C\u78C1\u76D8\u672A\u627E\u5230 features \u8DEF\u5F84\uFF09`);
|
|
28803
|
-
}
|
|
28804
|
-
} catch (e) {
|
|
28805
|
-
console.warn(`[${ctx.command}] disk write failed: ${e.message}`);
|
|
28806
|
-
await ctx.reply(`\u2705 ${key}: **${cur}** \u2192 **${rawState}**\uFF08\u5185\u5B58\u751F\u6548\uFF0C\u78C1\u76D8\u5199\u5931\u8D25\uFF09`);
|
|
28807
|
-
}
|
|
29018
|
+
await liveConfig.set(`agents.defaults.features.${key}`, next);
|
|
29019
|
+
console.log(`[${ctx.command}] ${key} ${cur} \u2192 ${rawState} (live + persisted)`);
|
|
29020
|
+
await ctx.reply(`\u2705 ${key}: **${cur}** \u2192 **${rawState}**`);
|
|
28808
29021
|
return;
|
|
28809
29022
|
}
|
|
28810
29023
|
if (ctx.command === "model") {
|
|
@@ -28922,11 +29135,11 @@ Auto-routing disabled \u2014 all messages use this model.
|
|
|
28922
29135
|
const input = (ctx.args.model || "").trim();
|
|
28923
29136
|
const configPath = config._configFilePath;
|
|
28924
29137
|
let writePath = configPath;
|
|
28925
|
-
if (configPath && !
|
|
29138
|
+
if (configPath && !fs42.existsSync(configPath)) {
|
|
28926
29139
|
const __pFile = fileURLToPath(import.meta.url);
|
|
28927
|
-
const __pDir =
|
|
28928
|
-
const altPath =
|
|
28929
|
-
if (
|
|
29140
|
+
const __pDir = path45.dirname(__pFile);
|
|
29141
|
+
const altPath = path45.join(path45.resolve(__pDir, "../configs"), path45.basename(configPath));
|
|
29142
|
+
if (fs42.existsSync(altPath)) {
|
|
28930
29143
|
console.warn(`[primary] Config not found at ${configPath}, falling back to ${altPath}`);
|
|
28931
29144
|
writePath = altPath;
|
|
28932
29145
|
}
|
|
@@ -28970,14 +29183,14 @@ Use full ref like \`/primary ${candidates[0].ref}\``);
|
|
|
28970
29183
|
return;
|
|
28971
29184
|
}
|
|
28972
29185
|
try {
|
|
28973
|
-
const raw = await
|
|
29186
|
+
const raw = await fs42.promises.readFile(writePath, "utf-8");
|
|
28974
29187
|
const cfg = JSON.parse(raw);
|
|
28975
29188
|
if (!cfg.agents?.defaults?.model) {
|
|
28976
29189
|
await ctx.reply(`\u26A0\uFE0F Config structure mismatch: agents.defaults.model not found`);
|
|
28977
29190
|
return;
|
|
28978
29191
|
}
|
|
28979
29192
|
cfg.agents.defaults.model.primary = target;
|
|
28980
|
-
await
|
|
29193
|
+
await fs42.promises.writeFile(writePath, JSON.stringify(cfg, null, 2), "utf-8");
|
|
28981
29194
|
console.log(`[primary] Persisted primary=${target} to ${writePath}`);
|
|
28982
29195
|
await ctx.reply(`\u2705 Primary model set to **${target}** (${candidates[0].name})
|
|
28983
29196
|
Written to config. **Restart required** to take effect.`);
|
|
@@ -28990,11 +29203,11 @@ Written to config. **Restart required** to take effect.`);
|
|
|
28990
29203
|
const input = (ctx.args.model || "").trim();
|
|
28991
29204
|
const configPath = config._configFilePath;
|
|
28992
29205
|
let writePath = configPath;
|
|
28993
|
-
if (configPath && !
|
|
29206
|
+
if (configPath && !fs42.existsSync(configPath)) {
|
|
28994
29207
|
const __pFile = fileURLToPath(import.meta.url);
|
|
28995
|
-
const __pDir =
|
|
28996
|
-
const altPath =
|
|
28997
|
-
if (
|
|
29208
|
+
const __pDir = path45.dirname(__pFile);
|
|
29209
|
+
const altPath = path45.join(path45.resolve(__pDir, "../configs"), path45.basename(configPath));
|
|
29210
|
+
if (fs42.existsSync(altPath)) {
|
|
28998
29211
|
console.warn(`[vision-primary] Config not found at ${configPath}, falling back to ${altPath}`);
|
|
28999
29212
|
writePath = altPath;
|
|
29000
29213
|
}
|
|
@@ -29039,7 +29252,7 @@ Use full ref like \`/vision-primary ${candidates[0].ref}\``);
|
|
|
29039
29252
|
return;
|
|
29040
29253
|
}
|
|
29041
29254
|
try {
|
|
29042
|
-
const raw = await
|
|
29255
|
+
const raw = await fs42.promises.readFile(writePath, "utf-8");
|
|
29043
29256
|
const cfg = JSON.parse(raw);
|
|
29044
29257
|
if (!cfg.agents?.defaults?.model) {
|
|
29045
29258
|
await ctx.reply(`\u26A0\uFE0F Config structure mismatch: agents.defaults.model not found`);
|
|
@@ -29047,12 +29260,12 @@ Use full ref like \`/vision-primary ${candidates[0].ref}\``);
|
|
|
29047
29260
|
}
|
|
29048
29261
|
if (input === "auto" || input === "reset") {
|
|
29049
29262
|
delete cfg.agents.defaults.model.vision;
|
|
29050
|
-
await
|
|
29263
|
+
await fs42.promises.writeFile(writePath, JSON.stringify(cfg, null, 2), "utf-8");
|
|
29051
29264
|
console.log(`[vision-primary] Cleared vision primary in ${writePath}`);
|
|
29052
29265
|
await ctx.reply(`\u2705 Vision primary cleared (auto). Written to config. Hot-reload will apply.`);
|
|
29053
29266
|
} else {
|
|
29054
29267
|
cfg.agents.defaults.model.vision = target;
|
|
29055
|
-
await
|
|
29268
|
+
await fs42.promises.writeFile(writePath, JSON.stringify(cfg, null, 2), "utf-8");
|
|
29056
29269
|
console.log(`[vision-primary] Persisted vision=${target} to ${writePath}`);
|
|
29057
29270
|
await ctx.reply(`\u2705 Vision primary set to **${target}** (${candidates[0].name})
|
|
29058
29271
|
Written to config. Hot-reload will apply.`);
|
|
@@ -29275,7 +29488,7 @@ Use full ref like \`/vision-model ${candidates[0].ref}\``);
|
|
|
29275
29488
|
console.log(`[vision] Downloading image: ${att.filename}`);
|
|
29276
29489
|
let rawBuffer;
|
|
29277
29490
|
if (att.url.startsWith("file://")) {
|
|
29278
|
-
rawBuffer =
|
|
29491
|
+
rawBuffer = fs42.readFileSync(decodeURIComponent(att.url.slice(7)));
|
|
29279
29492
|
} else {
|
|
29280
29493
|
rawBuffer = await downloadImage2(att.url);
|
|
29281
29494
|
}
|
|
@@ -29283,8 +29496,8 @@ Use full ref like \`/vision-model ${candidates[0].ref}\``);
|
|
|
29283
29496
|
const ext = detected.split("/")[1] || "png";
|
|
29284
29497
|
const resized = await maybeResizeAndDownsampleImageBuffer2(rawBuffer, rawBuffer.length, ext);
|
|
29285
29498
|
const imageId = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
29286
|
-
const savedPath =
|
|
29287
|
-
|
|
29499
|
+
const savedPath = path45.join(config.mediaDir, `${imageId}.${ext}`);
|
|
29500
|
+
fs42.writeFileSync(savedPath, resized.buffer);
|
|
29288
29501
|
savedPaths.push(savedPath);
|
|
29289
29502
|
console.log(`[vision] Saved: ${savedPath} (${resized.buffer.length}B)`);
|
|
29290
29503
|
imageBlocks.push({
|
|
@@ -29310,8 +29523,8 @@ ${pathStr}` }];
|
|
|
29310
29523
|
}
|
|
29311
29524
|
const nonImageAttachments = inbound.attachments?.filter((a) => !a.contentType.startsWith("image/"));
|
|
29312
29525
|
if (nonImageAttachments && nonImageAttachments.length > 0) {
|
|
29313
|
-
const outDir =
|
|
29314
|
-
|
|
29526
|
+
const outDir = path45.join(config.mediaDir, sessionId);
|
|
29527
|
+
fs42.mkdirSync(outDir, { recursive: true });
|
|
29315
29528
|
const resolved = [];
|
|
29316
29529
|
for (const att of nonImageAttachments) {
|
|
29317
29530
|
console.log(`[file] Downloading: ${att.filename} (${att.contentType}, ${att.size}B)`);
|
|
@@ -29319,9 +29532,9 @@ ${pathStr}` }];
|
|
|
29319
29532
|
const resp = await fetch(att.url);
|
|
29320
29533
|
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
|
|
29321
29534
|
const buffer = Buffer.from(await resp.arrayBuffer());
|
|
29322
|
-
const safeName2 =
|
|
29323
|
-
const savedPath =
|
|
29324
|
-
|
|
29535
|
+
const safeName2 = path45.basename(att.filename).replace(/[<>:"/\\|?*\x00-\x1f]/g, "_") || "attachment";
|
|
29536
|
+
const savedPath = path45.join(outDir, safeName2);
|
|
29537
|
+
fs42.writeFileSync(savedPath, buffer);
|
|
29325
29538
|
resolved.push(savedPath);
|
|
29326
29539
|
console.log(`[file] Saved: ${savedPath} (${buffer.length}B)`);
|
|
29327
29540
|
} catch (err) {
|
|
@@ -29675,7 +29888,7 @@ ${pathStr}` }];
|
|
|
29675
29888
|
console.warn("[cognifold] watcher: config.workspace \u672A\u914D\u7F6E\uFF0C\u8DF3\u8FC7 proactive \u5199\u5165");
|
|
29676
29889
|
return;
|
|
29677
29890
|
}
|
|
29678
|
-
const pFile =
|
|
29891
|
+
const pFile = path45.join(wsDir, ".cognifold-proactive.json");
|
|
29679
29892
|
const cognifoldBaseUrl = config.cognifold?.baseUrl || "http://127.0.0.1:9001";
|
|
29680
29893
|
const cognifoldSessionId = cfSessionId;
|
|
29681
29894
|
const rawSuggestions = data.suggestions || data.actions || (data.intent_id ? [data] : []);
|
|
@@ -29723,14 +29936,14 @@ ${pathStr}` }];
|
|
|
29723
29936
|
return s;
|
|
29724
29937
|
}));
|
|
29725
29938
|
try {
|
|
29726
|
-
|
|
29939
|
+
fs42.writeFileSync(pFile, JSON.stringify(enriched, null, 2));
|
|
29727
29940
|
console.log(`[cognifold] proactive suggestions saved (${enriched.length} total)`);
|
|
29728
29941
|
} catch (e) {
|
|
29729
29942
|
console.error(`[cognifold] failed to save proactive: ${e.message}`);
|
|
29730
29943
|
}
|
|
29731
29944
|
if (enriched.length > 0) {
|
|
29732
|
-
const promptFile =
|
|
29733
|
-
const promptText =
|
|
29945
|
+
const promptFile = path45.join(config.workspace, "prompts", "cognifold-proactive.md");
|
|
29946
|
+
const promptText = fs42.existsSync(promptFile) ? fs42.readFileSync(promptFile, "utf-8") : "[CogniFold proactive] \u6709 " + enriched.length + " \u4E2A action \u5230\u671F\u4E86";
|
|
29734
29947
|
const actionsJson = JSON.stringify(enriched, null, 2);
|
|
29735
29948
|
const sessionId = cfSessionId;
|
|
29736
29949
|
const mainSessionId = sessions.getSessionId("scope:main");
|
|
@@ -29897,12 +30110,12 @@ async function doReloadConfig(config, deps, provider) {
|
|
|
29897
30110
|
try {
|
|
29898
30111
|
const savedConfigPath = config._configFilePath;
|
|
29899
30112
|
let reloadConfigPath = savedConfigPath;
|
|
29900
|
-
if (!
|
|
30113
|
+
if (!fs42.existsSync(reloadConfigPath)) {
|
|
29901
30114
|
const __filename = fileURLToPath(import.meta.url);
|
|
29902
|
-
const __dirname =
|
|
29903
|
-
const engineConfigsDir =
|
|
29904
|
-
const altPath =
|
|
29905
|
-
if (
|
|
30115
|
+
const __dirname = path45.dirname(__filename);
|
|
30116
|
+
const engineConfigsDir = path45.resolve(__dirname, "../configs");
|
|
30117
|
+
const altPath = path45.join(engineConfigsDir, path45.basename(savedConfigPath));
|
|
30118
|
+
if (fs42.existsSync(altPath)) {
|
|
29906
30119
|
console.warn(`[reload] Config not found at ${reloadConfigPath}, falling back to ${altPath} (dev mode)`);
|
|
29907
30120
|
reloadConfigPath = altPath;
|
|
29908
30121
|
}
|
|
@@ -29975,12 +30188,6 @@ async function doReloadConfig(config, deps, provider) {
|
|
|
29975
30188
|
deps.extractProvider = newExtract;
|
|
29976
30189
|
changes.push(`extract \u2192 ${newConfig.topics?.extract?.provider}/${newConfig.topics?.extract?.model}`);
|
|
29977
30190
|
}
|
|
29978
|
-
if (newConfig.topics) {
|
|
29979
|
-
deps.topics = newConfig.topics;
|
|
29980
|
-
}
|
|
29981
|
-
if (newConfig.profile?.features) {
|
|
29982
|
-
deps.features = newConfig.profile.features;
|
|
29983
|
-
}
|
|
29984
30191
|
try {
|
|
29985
30192
|
const { setAutoDreamConfig: setAutoDreamConfig2 } = await Promise.resolve().then(() => (init_config2(), config_exports));
|
|
29986
30193
|
setAutoDreamConfig2(newConfig);
|
|
@@ -30026,7 +30233,7 @@ async function doReloadConfig(config, deps, provider) {
|
|
|
30026
30233
|
} catch (err) {
|
|
30027
30234
|
console.error(`[reload] Failed: ${err.message}`);
|
|
30028
30235
|
try {
|
|
30029
|
-
|
|
30236
|
+
fs42.appendFileSync(path45.join(config.stateDir, "logs", "engine-config-watch.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] RELOAD FAILED: ${err.message}
|
|
30030
30237
|
${err.stack}
|
|
30031
30238
|
`);
|
|
30032
30239
|
} catch {
|
|
@@ -30037,36 +30244,36 @@ ${err.stack}
|
|
|
30037
30244
|
function startConfigWatcher(config, deps, provider) {
|
|
30038
30245
|
const raw = config._configFilePath;
|
|
30039
30246
|
let configPath = raw;
|
|
30040
|
-
if (!
|
|
30041
|
-
configPath =
|
|
30247
|
+
if (!fs42.existsSync(configPath)) {
|
|
30248
|
+
configPath = path45.resolve(raw);
|
|
30042
30249
|
}
|
|
30043
|
-
if (!
|
|
30250
|
+
if (!fs42.existsSync(configPath)) {
|
|
30044
30251
|
const __filename2 = fileURLToPath(import.meta.url);
|
|
30045
|
-
const __dirname2 =
|
|
30046
|
-
configPath =
|
|
30252
|
+
const __dirname2 = path45.dirname(__filename2);
|
|
30253
|
+
configPath = path45.resolve(__dirname2, "..", raw);
|
|
30047
30254
|
}
|
|
30048
|
-
if (!
|
|
30255
|
+
if (!fs42.existsSync(configPath)) {
|
|
30049
30256
|
console.warn(`[config-watch] config path invalid: ${configPath}, watcher disabled`);
|
|
30050
30257
|
try {
|
|
30051
|
-
|
|
30258
|
+
fs42.appendFileSync(path45.join(config.stateDir, "logs", "engine-config-watch.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] DISABLED: configPath=${configPath}
|
|
30052
30259
|
`);
|
|
30053
30260
|
} catch {
|
|
30054
30261
|
}
|
|
30055
30262
|
return null;
|
|
30056
30263
|
}
|
|
30057
30264
|
let debounceTimer = null;
|
|
30058
|
-
const watcher =
|
|
30265
|
+
const watcher = fs42.watch(configPath, { persistent: true }, (eventType) => {
|
|
30059
30266
|
if (debounceTimer) clearTimeout(debounceTimer);
|
|
30060
30267
|
debounceTimer = setTimeout(async () => {
|
|
30061
30268
|
console.log(`[config-watch] file changed (${eventType}), reloading...`);
|
|
30062
30269
|
try {
|
|
30063
|
-
|
|
30270
|
+
fs42.appendFileSync(path45.join(config.stateDir, "logs", "engine-config-watch.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] CHANGE eventType=${eventType}, calling doReloadConfig
|
|
30064
30271
|
`);
|
|
30065
30272
|
} catch {
|
|
30066
30273
|
}
|
|
30067
30274
|
const result = await doReloadConfig(config, deps, provider);
|
|
30068
30275
|
try {
|
|
30069
|
-
|
|
30276
|
+
fs42.appendFileSync(path45.join(config.stateDir, "logs", "engine-config-watch.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] RELOAD DONE: ok=${result.ok} changes=${result.changes.join(",")}
|
|
30070
30277
|
`);
|
|
30071
30278
|
} catch {
|
|
30072
30279
|
}
|
|
@@ -30075,30 +30282,30 @@ function startConfigWatcher(config, deps, provider) {
|
|
|
30075
30282
|
watcher.on("error", (err) => {
|
|
30076
30283
|
console.error(`[config-watch] error: ${err.message}`);
|
|
30077
30284
|
try {
|
|
30078
|
-
|
|
30285
|
+
fs42.appendFileSync(path45.join(config.stateDir, "logs", "engine-config-watch.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] ERROR: ${err.message}
|
|
30079
30286
|
`);
|
|
30080
30287
|
} catch {
|
|
30081
30288
|
}
|
|
30082
30289
|
});
|
|
30083
30290
|
console.log(`[config-watch] watching ${configPath}`);
|
|
30084
30291
|
try {
|
|
30085
|
-
|
|
30292
|
+
fs42.appendFileSync(path45.join(config.stateDir, "logs", "engine-config-watch.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] STARTED watching=${configPath}
|
|
30086
30293
|
`);
|
|
30087
30294
|
} catch {
|
|
30088
30295
|
}
|
|
30089
30296
|
return watcher;
|
|
30090
30297
|
}
|
|
30091
30298
|
function startSecretsWatcher(config, deps, provider) {
|
|
30092
|
-
const secretsDir =
|
|
30093
|
-
const cfgBase =
|
|
30299
|
+
const secretsDir = path45.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7-secrets");
|
|
30300
|
+
const cfgBase = path45.basename(config._configFilePath || "", ".json");
|
|
30094
30301
|
const secretCandidates = [
|
|
30095
|
-
|
|
30096
|
-
|
|
30097
|
-
|
|
30302
|
+
path45.join(secretsDir, `${cfgBase}.env`),
|
|
30303
|
+
path45.join(path45.dirname(config._configFilePath || ""), `.env.${cfgBase}`),
|
|
30304
|
+
path45.join(path45.dirname(config._configFilePath || ""), ".env")
|
|
30098
30305
|
];
|
|
30099
30306
|
let secretsPath = null;
|
|
30100
30307
|
for (const p of secretCandidates) {
|
|
30101
|
-
if (
|
|
30308
|
+
if (fs42.existsSync(p)) {
|
|
30102
30309
|
secretsPath = p;
|
|
30103
30310
|
break;
|
|
30104
30311
|
}
|
|
@@ -30111,9 +30318,9 @@ function startSecretsWatcher(config, deps, provider) {
|
|
|
30111
30318
|
let activeWatcher = null;
|
|
30112
30319
|
const startWatch = () => {
|
|
30113
30320
|
if (activeWatcher) activeWatcher.close();
|
|
30114
|
-
activeWatcher =
|
|
30321
|
+
activeWatcher = fs42.watch(secretsPath, { persistent: true }, (eventType) => {
|
|
30115
30322
|
if (eventType === "rename") {
|
|
30116
|
-
if (
|
|
30323
|
+
if (fs42.existsSync(secretsPath)) {
|
|
30117
30324
|
console.log("[secrets-watch] rename detected, re-watching file...");
|
|
30118
30325
|
startWatch();
|
|
30119
30326
|
} else {
|
|
@@ -30125,7 +30332,7 @@ function startSecretsWatcher(config, deps, provider) {
|
|
|
30125
30332
|
debounceTimer = setTimeout(async () => {
|
|
30126
30333
|
console.log(`[secrets-watch] file changed (${eventType}), reloading secrets...`);
|
|
30127
30334
|
try {
|
|
30128
|
-
const content =
|
|
30335
|
+
const content = fs42.readFileSync(secretsPath, "utf-8");
|
|
30129
30336
|
let updated = 0;
|
|
30130
30337
|
for (const line of content.split("\n")) {
|
|
30131
30338
|
const trimmed = line.trim();
|
|
@@ -30144,7 +30351,7 @@ function startSecretsWatcher(config, deps, provider) {
|
|
|
30144
30351
|
const result = await doReloadConfig(config, deps, provider);
|
|
30145
30352
|
console.log(`[secrets-watch] config reloaded: ok=${result.ok} changes=${result.changes.join(",")}`);
|
|
30146
30353
|
try {
|
|
30147
|
-
|
|
30354
|
+
fs42.appendFileSync(path45.join(config.stateDir, "logs", "engine-config-watch.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] SECRETS RELOAD: ok=${result.ok} keys=${updated}
|
|
30148
30355
|
`);
|
|
30149
30356
|
} catch {
|
|
30150
30357
|
}
|