engine7 7.1.113 → 7.1.114
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.mjs +28 -9
- package/dist/engine-startup.mjs +602 -527
- package/dist/main.mjs +606 -535
- package/package.json +1 -1
package/dist/main.mjs
CHANGED
|
@@ -141,14 +141,14 @@ var init_live = __esm({
|
|
|
141
141
|
}
|
|
142
142
|
/** 把改动写回 config 文件对应段(找不到文件路径则只内存生效) */
|
|
143
143
|
async persistToFile(dotPath, val) {
|
|
144
|
-
const
|
|
144
|
+
const fs58 = await import("node:fs");
|
|
145
145
|
const cfgPath = this.current?._configFilePath;
|
|
146
|
-
if (!cfgPath || !
|
|
146
|
+
if (!cfgPath || !fs58.existsSync(cfgPath)) {
|
|
147
147
|
console.warn(`[liveConfig] set: no config file path, in-memory only (${dotPath})`);
|
|
148
148
|
return;
|
|
149
149
|
}
|
|
150
150
|
try {
|
|
151
|
-
const raw = JSON.parse(
|
|
151
|
+
const raw = JSON.parse(fs58.readFileSync(cfgPath, "utf-8"));
|
|
152
152
|
const keys = dotPath.split(".");
|
|
153
153
|
let o = raw;
|
|
154
154
|
for (let i = 0; i < keys.length - 1; i++) {
|
|
@@ -156,7 +156,7 @@ var init_live = __esm({
|
|
|
156
156
|
o = o[keys[i]];
|
|
157
157
|
}
|
|
158
158
|
o[keys[keys.length - 1]] = val;
|
|
159
|
-
|
|
159
|
+
fs58.writeFileSync(cfgPath, JSON.stringify(raw, null, 2) + "\n", "utf-8");
|
|
160
160
|
console.log(`[liveConfig] persisted ${dotPath} = ${JSON.stringify(val)} to ${cfgPath}`);
|
|
161
161
|
markSelfWrite();
|
|
162
162
|
} catch (e) {
|
|
@@ -3647,8 +3647,8 @@ function findShell() {
|
|
|
3647
3647
|
timeout: 5e3,
|
|
3648
3648
|
stdio: ["ignore", "pipe", "ignore"]
|
|
3649
3649
|
});
|
|
3650
|
-
const
|
|
3651
|
-
const nonWsl =
|
|
3650
|
+
const candidates2 = result.trim().split(/\r?\n/).map((s) => s.trim()).filter(Boolean);
|
|
3651
|
+
const nonWsl = candidates2.find((p) => !isWslBash(p));
|
|
3652
3652
|
if (nonWsl && fs6.existsSync(nonWsl)) {
|
|
3653
3653
|
cachedShell = { shell: nonWsl, args: ["-c"] };
|
|
3654
3654
|
return cachedShell;
|
|
@@ -4602,9 +4602,9 @@ function isAutoMemPath(absolutePath, workspace) {
|
|
|
4602
4602
|
return normalizedPath.startsWith(getAutoMemPath(workspace));
|
|
4603
4603
|
}
|
|
4604
4604
|
async function ensureMemoryDirExists(memoryDir) {
|
|
4605
|
-
const
|
|
4605
|
+
const fs58 = await import("node:fs");
|
|
4606
4606
|
try {
|
|
4607
|
-
await
|
|
4607
|
+
await fs58.promises.mkdir(memoryDir, { recursive: true });
|
|
4608
4608
|
} catch (e) {
|
|
4609
4609
|
const code = e?.code;
|
|
4610
4610
|
if (code !== "EEXIST") {
|
|
@@ -8496,7 +8496,7 @@ async function acquireLock(inboxPath) {
|
|
|
8496
8496
|
for (let i = 0; i < LOCK_RETRIES; i++) {
|
|
8497
8497
|
if (await isLockStale(lockPath2)) {
|
|
8498
8498
|
try {
|
|
8499
|
-
await import("node:fs/promises").then((
|
|
8499
|
+
await import("node:fs/promises").then((fs58) => fs58.rm(lockPath2, { force: true }));
|
|
8500
8500
|
} catch {
|
|
8501
8501
|
}
|
|
8502
8502
|
}
|
|
@@ -8504,7 +8504,7 @@ async function acquireLock(inboxPath) {
|
|
|
8504
8504
|
await writeFile2(lockPath2, `${process.pid}-${Date.now()}`, { encoding: "utf-8", flag: "wx" });
|
|
8505
8505
|
return async () => {
|
|
8506
8506
|
try {
|
|
8507
|
-
await import("node:fs/promises").then((
|
|
8507
|
+
await import("node:fs/promises").then((fs58) => fs58.rm(lockPath2, { force: true }));
|
|
8508
8508
|
} catch {
|
|
8509
8509
|
}
|
|
8510
8510
|
};
|
|
@@ -14324,8 +14324,8 @@ function mapOperation(raw) {
|
|
|
14324
14324
|
}
|
|
14325
14325
|
function extractJson2(text) {
|
|
14326
14326
|
const fenced = text.match(/```(?:json)?\s*([\s\S]*?)```/);
|
|
14327
|
-
const
|
|
14328
|
-
for (const c of
|
|
14327
|
+
const candidates2 = fenced ? [fenced[1], text] : [text];
|
|
14328
|
+
for (const c of candidates2) {
|
|
14329
14329
|
const start = c.indexOf("{");
|
|
14330
14330
|
const end = c.lastIndexOf("}");
|
|
14331
14331
|
if (start === -1 || end <= start) continue;
|
|
@@ -14996,14 +14996,14 @@ async function runProactiveCycle(deps, now) {
|
|
|
14996
14996
|
for (const act of persist.dueActions("9999-12-31T23:59:59Z", 1e3)) {
|
|
14997
14997
|
if (act.status === "queued") existingTitles.add(normalizeTitle(act.title));
|
|
14998
14998
|
}
|
|
14999
|
-
const
|
|
14999
|
+
const candidates2 = actionable.filter((s) => {
|
|
15000
15000
|
if (queuedIntentIds.has(s.node.id)) return false;
|
|
15001
15001
|
if (cooldownIntentIds.has(s.node.id)) return false;
|
|
15002
15002
|
return true;
|
|
15003
15003
|
});
|
|
15004
|
-
if (
|
|
15004
|
+
if (candidates2.length === 0) return 0;
|
|
15005
15005
|
let enqueued = 0;
|
|
15006
|
-
for (const scored of
|
|
15006
|
+
for (const scored of candidates2) {
|
|
15007
15007
|
const intent = scored.node;
|
|
15008
15008
|
if (intent.data.status === "resolved") continue;
|
|
15009
15009
|
store.updateNode(intent.id, { status: "action_scheduled" });
|
|
@@ -16862,11 +16862,11 @@ async function readLastConsolidatedAt(memoryDir) {
|
|
|
16862
16862
|
}
|
|
16863
16863
|
}
|
|
16864
16864
|
async function tryAcquireConsolidationLock(memoryDir) {
|
|
16865
|
-
const
|
|
16865
|
+
const path60 = lockPath(memoryDir);
|
|
16866
16866
|
let mtimeMs;
|
|
16867
16867
|
let holderPid;
|
|
16868
16868
|
try {
|
|
16869
|
-
const [s, raw] = await Promise.all([stat3(
|
|
16869
|
+
const [s, raw] = await Promise.all([stat3(path60), readFile5(path60, "utf8")]);
|
|
16870
16870
|
mtimeMs = s.mtimeMs;
|
|
16871
16871
|
const parsed = parseInt(raw.trim(), 10);
|
|
16872
16872
|
holderPid = Number.isFinite(parsed) ? parsed : void 0;
|
|
@@ -16879,10 +16879,10 @@ async function tryAcquireConsolidationLock(memoryDir) {
|
|
|
16879
16879
|
}
|
|
16880
16880
|
}
|
|
16881
16881
|
await mkdir3(memoryDir, { recursive: true });
|
|
16882
|
-
await writeFile4(
|
|
16882
|
+
await writeFile4(path60, String(process.pid));
|
|
16883
16883
|
let verify2;
|
|
16884
16884
|
try {
|
|
16885
|
-
verify2 = await readFile5(
|
|
16885
|
+
verify2 = await readFile5(path60, "utf8");
|
|
16886
16886
|
} catch {
|
|
16887
16887
|
return null;
|
|
16888
16888
|
}
|
|
@@ -16890,15 +16890,15 @@ async function tryAcquireConsolidationLock(memoryDir) {
|
|
|
16890
16890
|
return mtimeMs ?? 0;
|
|
16891
16891
|
}
|
|
16892
16892
|
async function rollbackConsolidationLock(memoryDir, priorMtime) {
|
|
16893
|
-
const
|
|
16893
|
+
const path60 = lockPath(memoryDir);
|
|
16894
16894
|
try {
|
|
16895
16895
|
if (priorMtime === 0) {
|
|
16896
|
-
await unlink(
|
|
16896
|
+
await unlink(path60);
|
|
16897
16897
|
return;
|
|
16898
16898
|
}
|
|
16899
|
-
await writeFile4(
|
|
16899
|
+
await writeFile4(path60, "");
|
|
16900
16900
|
const t = priorMtime / 1e3;
|
|
16901
|
-
await utimes(
|
|
16901
|
+
await utimes(path60, t, t);
|
|
16902
16902
|
} catch (e) {
|
|
16903
16903
|
console.log(`[autoDream] rollback failed: ${e.message} \u2014 next trigger delayed to minHours`);
|
|
16904
16904
|
}
|
|
@@ -17500,12 +17500,12 @@ async function executeAndDeliver(task, now, deps) {
|
|
|
17500
17500
|
if (promptText.startsWith("@")) {
|
|
17501
17501
|
let filePath = promptText.slice(1).trim();
|
|
17502
17502
|
try {
|
|
17503
|
-
const
|
|
17504
|
-
const
|
|
17505
|
-
if (!
|
|
17506
|
-
filePath =
|
|
17503
|
+
const fs58 = await import("fs");
|
|
17504
|
+
const path60 = await import("path");
|
|
17505
|
+
if (!path60.isAbsolute(filePath)) {
|
|
17506
|
+
filePath = path60.join(deps.sessions["config"].stateDir, filePath);
|
|
17507
17507
|
}
|
|
17508
|
-
promptText =
|
|
17508
|
+
promptText = fs58.readFileSync(filePath, "utf-8");
|
|
17509
17509
|
console.log(`[cron] Loaded prompt from ${filePath} (${promptText.length} chars)`);
|
|
17510
17510
|
} catch (err) {
|
|
17511
17511
|
throw new Error(`Prompt file not found: ${filePath}: ${err.message}`);
|
|
@@ -17543,16 +17543,16 @@ async function executeAndDeliver(task, now, deps) {
|
|
|
17543
17543
|
let finalResult = result;
|
|
17544
17544
|
if (task.postProcess) {
|
|
17545
17545
|
try {
|
|
17546
|
-
const
|
|
17547
|
-
const
|
|
17546
|
+
const path60 = await import("path");
|
|
17547
|
+
const fs58 = await import("fs");
|
|
17548
17548
|
let scriptPath = task.postProcess;
|
|
17549
|
-
if (!
|
|
17550
|
-
scriptPath =
|
|
17549
|
+
if (!path60.isAbsolute(scriptPath)) {
|
|
17550
|
+
scriptPath = path60.join(deps.sessions["config"].stateDir, scriptPath);
|
|
17551
17551
|
}
|
|
17552
|
-
const resultsDirTmp =
|
|
17553
|
-
|
|
17554
|
-
const inputFile =
|
|
17555
|
-
|
|
17552
|
+
const resultsDirTmp = path60.join(getStorageDir(), "results");
|
|
17553
|
+
fs58.mkdirSync(resultsDirTmp, { recursive: true });
|
|
17554
|
+
const inputFile = path60.join(resultsDirTmp, `${task.id}.input.txt`);
|
|
17555
|
+
fs58.writeFileSync(inputFile, result, "utf-8");
|
|
17556
17556
|
const { execFile: execFile5 } = await import("child_process");
|
|
17557
17557
|
await new Promise((resolve12) => {
|
|
17558
17558
|
execFile5("python", [scriptPath, "main", "--file", inputFile], {
|
|
@@ -17579,12 +17579,12 @@ async function executeAndDeliver(task, now, deps) {
|
|
|
17579
17579
|
}
|
|
17580
17580
|
}
|
|
17581
17581
|
try {
|
|
17582
|
-
const
|
|
17583
|
-
const
|
|
17584
|
-
const resultsDir =
|
|
17585
|
-
|
|
17586
|
-
const resultFile =
|
|
17587
|
-
|
|
17582
|
+
const fs58 = await import("fs");
|
|
17583
|
+
const path60 = await import("path");
|
|
17584
|
+
const resultsDir = path60.join(getStorageDir(), "results");
|
|
17585
|
+
fs58.mkdirSync(resultsDir, { recursive: true });
|
|
17586
|
+
const resultFile = path60.join(resultsDir, `${task.id}.json`);
|
|
17587
|
+
fs58.writeFileSync(resultFile, JSON.stringify({
|
|
17588
17588
|
taskId: task.id,
|
|
17589
17589
|
description: task.description,
|
|
17590
17590
|
executedAt: now.toISOString(),
|
|
@@ -17914,30 +17914,30 @@ function registerCronTools() {
|
|
|
17914
17914
|
}
|
|
17915
17915
|
},
|
|
17916
17916
|
handler: async (args2) => {
|
|
17917
|
-
const
|
|
17918
|
-
const
|
|
17919
|
-
const resultsDir =
|
|
17920
|
-
if (!
|
|
17917
|
+
const fs58 = await import("fs");
|
|
17918
|
+
const path60 = await import("path");
|
|
17919
|
+
const resultsDir = path60.join(getStorageDir(), "results");
|
|
17920
|
+
if (!fs58.existsSync(resultsDir)) {
|
|
17921
17921
|
return { content: "\u6682\u65E0cron\u6267\u884C\u7ED3\u679C" };
|
|
17922
17922
|
}
|
|
17923
17923
|
if (args2.task_id) {
|
|
17924
|
-
const file2 =
|
|
17925
|
-
if (!
|
|
17924
|
+
const file2 = path60.join(resultsDir, `${args2.task_id}.json`);
|
|
17925
|
+
if (!fs58.existsSync(file2)) {
|
|
17926
17926
|
return { content: `\u4EFB\u52A1 ${args2.task_id} \u6682\u65E0\u6267\u884C\u7ED3\u679C`, isError: true };
|
|
17927
17927
|
}
|
|
17928
|
-
const data = JSON.parse(
|
|
17928
|
+
const data = JSON.parse(fs58.readFileSync(file2, "utf-8"));
|
|
17929
17929
|
return { content: `## ${data.description}
|
|
17930
17930
|
\u6267\u884C\u65F6\u95F4: ${data.executedAt}
|
|
17931
17931
|
\u7B2C${data.runCount}\u6B21\u6267\u884C
|
|
17932
17932
|
|
|
17933
17933
|
${data.result}` };
|
|
17934
17934
|
}
|
|
17935
|
-
const files =
|
|
17935
|
+
const files = fs58.readdirSync(resultsDir).filter((f) => f.endsWith(".json"));
|
|
17936
17936
|
if (files.length === 0) {
|
|
17937
17937
|
return { content: "\u6682\u65E0cron\u6267\u884C\u7ED3\u679C" };
|
|
17938
17938
|
}
|
|
17939
17939
|
const results = files.map((f) => {
|
|
17940
|
-
const data = JSON.parse(
|
|
17940
|
+
const data = JSON.parse(fs58.readFileSync(path60.join(resultsDir, f), "utf-8"));
|
|
17941
17941
|
return `### ${data.description} (${data.taskId.slice(0, 8)})
|
|
17942
17942
|
\u6267\u884C: ${data.executedAt} | \u7B2C${data.runCount}\u6B21
|
|
17943
17943
|
${data.result.slice(0, 500)}${data.result.length > 500 ? "..." : ""}`;
|
|
@@ -18461,25 +18461,43 @@ var init_tasks2 = __esm({
|
|
|
18461
18461
|
}
|
|
18462
18462
|
});
|
|
18463
18463
|
|
|
18464
|
-
// src/
|
|
18465
|
-
|
|
18466
|
-
|
|
18467
|
-
buildEngineStatus: () => buildEngineStatus,
|
|
18468
|
-
readEngineVersion: () => readEngineVersion
|
|
18469
|
-
});
|
|
18470
|
-
import * as fs35 from "node:fs";
|
|
18471
|
-
import * as path35 from "node:path";
|
|
18464
|
+
// src/version.ts
|
|
18465
|
+
import { readFileSync as readFileSync32 } from "node:fs";
|
|
18466
|
+
import { dirname as dirname10, join as join43 } from "node:path";
|
|
18472
18467
|
import { fileURLToPath as fileURLToPath6 } from "node:url";
|
|
18473
|
-
function
|
|
18474
|
-
|
|
18475
|
-
|
|
18468
|
+
function candidates() {
|
|
18469
|
+
if (_pkgDirOverride !== null) return [join43(_pkgDirOverride, "package.json")];
|
|
18470
|
+
const here = dirname10(fileURLToPath6(import.meta.url));
|
|
18471
|
+
return [join43(here, "..", "package.json"), join43(here, "..", "..", "package.json")];
|
|
18472
|
+
}
|
|
18473
|
+
function readFromDisk() {
|
|
18474
|
+
for (const p of candidates()) {
|
|
18476
18475
|
try {
|
|
18477
|
-
return JSON.parse(
|
|
18476
|
+
return JSON.parse(readFileSync32(p, "utf-8")).version || "unknown";
|
|
18478
18477
|
} catch {
|
|
18479
18478
|
}
|
|
18480
18479
|
}
|
|
18481
18480
|
return "unknown";
|
|
18482
18481
|
}
|
|
18482
|
+
function readEngineVersion() {
|
|
18483
|
+
if (_loaded === null) _loaded = readFromDisk();
|
|
18484
|
+
return _loaded;
|
|
18485
|
+
}
|
|
18486
|
+
var _loaded, _pkgDirOverride;
|
|
18487
|
+
var init_version = __esm({
|
|
18488
|
+
"src/version.ts"() {
|
|
18489
|
+
"use strict";
|
|
18490
|
+
_loaded = null;
|
|
18491
|
+
_pkgDirOverride = null;
|
|
18492
|
+
}
|
|
18493
|
+
});
|
|
18494
|
+
|
|
18495
|
+
// src/startup/api-status.ts
|
|
18496
|
+
var api_status_exports = {};
|
|
18497
|
+
__export(api_status_exports, {
|
|
18498
|
+
buildEngineStatus: () => buildEngineStatus,
|
|
18499
|
+
readEngineVersion: () => readEngineVersion
|
|
18500
|
+
});
|
|
18483
18501
|
function hasUsable(v) {
|
|
18484
18502
|
return !!v && !isUnresolvedEnvRef(v);
|
|
18485
18503
|
}
|
|
@@ -18502,6 +18520,7 @@ var init_api_status = __esm({
|
|
|
18502
18520
|
"src/startup/api-status.ts"() {
|
|
18503
18521
|
"use strict";
|
|
18504
18522
|
init_loader();
|
|
18523
|
+
init_version();
|
|
18505
18524
|
}
|
|
18506
18525
|
});
|
|
18507
18526
|
|
|
@@ -18612,10 +18631,10 @@ function ensureLoaded(workspace, configIds) {
|
|
|
18612
18631
|
if (!state.blockedUserIds.includes(id)) state.blockedUserIds.push(id);
|
|
18613
18632
|
}
|
|
18614
18633
|
}
|
|
18615
|
-
const
|
|
18634
|
+
const path60 = join44(workspace, ".reply-blocklist.json");
|
|
18616
18635
|
try {
|
|
18617
|
-
if (existsSync23(
|
|
18618
|
-
const raw = readFileSync33(
|
|
18636
|
+
if (existsSync23(path60)) {
|
|
18637
|
+
const raw = readFileSync33(path60, "utf-8");
|
|
18619
18638
|
const parsed = JSON.parse(raw);
|
|
18620
18639
|
if (parsed.blockedUserIds) {
|
|
18621
18640
|
for (const id of parsed.blockedUserIds) {
|
|
@@ -18631,9 +18650,9 @@ function ensureLoaded(workspace, configIds) {
|
|
|
18631
18650
|
loaded = true;
|
|
18632
18651
|
}
|
|
18633
18652
|
function save(workspace) {
|
|
18634
|
-
const
|
|
18653
|
+
const path60 = join44(workspace, ".reply-blocklist.json");
|
|
18635
18654
|
try {
|
|
18636
|
-
writeFileSync11(
|
|
18655
|
+
writeFileSync11(path60, JSON.stringify(state, null, 2), "utf-8");
|
|
18637
18656
|
} catch (err) {
|
|
18638
18657
|
console.warn(`[reply-blocklist] Failed to save: ${err.message}`);
|
|
18639
18658
|
}
|
|
@@ -19078,8 +19097,8 @@ __export(voice_chat_tts_daemon_exports, {
|
|
|
19078
19097
|
});
|
|
19079
19098
|
import { spawn as spawn5 } from "child_process";
|
|
19080
19099
|
import net2 from "net";
|
|
19081
|
-
import
|
|
19082
|
-
import
|
|
19100
|
+
import path38 from "path";
|
|
19101
|
+
import fs38 from "fs";
|
|
19083
19102
|
function _log(msg2) {
|
|
19084
19103
|
console.log(`[tts-daemon] ${msg2}`);
|
|
19085
19104
|
}
|
|
@@ -19124,16 +19143,16 @@ async function startTtsDaemon(warmupCfg) {
|
|
|
19124
19143
|
return;
|
|
19125
19144
|
}
|
|
19126
19145
|
const script = (() => {
|
|
19127
|
-
const distDir =
|
|
19128
|
-
const
|
|
19129
|
-
|
|
19130
|
-
|
|
19146
|
+
const distDir = path38.dirname(new URL(import.meta.url).pathname);
|
|
19147
|
+
const candidates2 = [
|
|
19148
|
+
path38.join(distDir, "..", "python", "tts_daemon.py"),
|
|
19149
|
+
path38.join(process.cwd(), "engine/src/python/tts_daemon.py"),
|
|
19131
19150
|
"/Users/chongzhang/work/twinsun-hearth/engine/src/python/tts_daemon.py"
|
|
19132
19151
|
];
|
|
19133
|
-
for (const c of
|
|
19134
|
-
if (
|
|
19152
|
+
for (const c of candidates2) {
|
|
19153
|
+
if (fs38.existsSync(c)) return c;
|
|
19135
19154
|
}
|
|
19136
|
-
return
|
|
19155
|
+
return candidates2[0];
|
|
19137
19156
|
})();
|
|
19138
19157
|
_log(`spawning ${script}`);
|
|
19139
19158
|
const env = {
|
|
@@ -19203,15 +19222,15 @@ var read_exports = {};
|
|
|
19203
19222
|
__export(read_exports, {
|
|
19204
19223
|
readFileState: () => readFileState
|
|
19205
19224
|
});
|
|
19206
|
-
import * as
|
|
19207
|
-
import * as
|
|
19225
|
+
import * as fs51 from "node:fs";
|
|
19226
|
+
import * as path50 from "node:path";
|
|
19208
19227
|
function isBlockedDevicePath(filePath) {
|
|
19209
19228
|
if (BLOCKED_DEVICE_PATHS.has(filePath)) return true;
|
|
19210
19229
|
if (filePath.startsWith("/proc/") && (filePath.endsWith("/fd/0") || filePath.endsWith("/fd/1") || filePath.endsWith("/fd/2"))) return true;
|
|
19211
19230
|
return false;
|
|
19212
19231
|
}
|
|
19213
19232
|
function checkReadLoop(filePath, offset, limit) {
|
|
19214
|
-
const stat4 =
|
|
19233
|
+
const stat4 = fs51.statSync(filePath);
|
|
19215
19234
|
const mtimeMs = stat4.mtimeMs;
|
|
19216
19235
|
const prev = readHistory.get(filePath);
|
|
19217
19236
|
if (prev && prev.offset === offset && prev.limit === limit && prev.mtimeMs === mtimeMs) {
|
|
@@ -19225,19 +19244,19 @@ function checkReadLoop(filePath, offset, limit) {
|
|
|
19225
19244
|
return null;
|
|
19226
19245
|
}
|
|
19227
19246
|
function readFileContent(filePath) {
|
|
19228
|
-
const fd =
|
|
19247
|
+
const fd = fs51.openSync(filePath, "r");
|
|
19229
19248
|
const bom = Buffer.alloc(2);
|
|
19230
|
-
|
|
19231
|
-
|
|
19249
|
+
fs51.readSync(fd, bom, 0, 2, 0);
|
|
19250
|
+
fs51.closeSync(fd);
|
|
19232
19251
|
let encoding = "utf8";
|
|
19233
19252
|
if (bom[0] === 255 && bom[1] === 254) {
|
|
19234
19253
|
encoding = "utf16le";
|
|
19235
19254
|
}
|
|
19236
|
-
const stat4 =
|
|
19255
|
+
const stat4 = fs51.statSync(filePath);
|
|
19237
19256
|
if (stat4.size > MAX_FILE_SIZE) {
|
|
19238
19257
|
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`);
|
|
19239
19258
|
}
|
|
19240
|
-
const raw =
|
|
19259
|
+
const raw = fs51.readFileSync(filePath, encoding);
|
|
19241
19260
|
const content = raw.toString().replaceAll("\r\n", "\n");
|
|
19242
19261
|
return { content, encoding };
|
|
19243
19262
|
}
|
|
@@ -19379,11 +19398,11 @@ Usage:
|
|
|
19379
19398
|
} catch (e) {
|
|
19380
19399
|
return { content: e.message, isError: true };
|
|
19381
19400
|
}
|
|
19382
|
-
if (!
|
|
19401
|
+
if (!fs51.existsSync(filePath)) {
|
|
19383
19402
|
return { content: `\u6587\u4EF6\u4E0D\u5B58\u5728: ${filePath}`, isError: true };
|
|
19384
19403
|
}
|
|
19385
|
-
const stat4 =
|
|
19386
|
-
const baseName =
|
|
19404
|
+
const stat4 = fs51.statSync(filePath);
|
|
19405
|
+
const baseName = path50.basename(filePath).toUpperCase();
|
|
19387
19406
|
if (BLOCKED_BASENAMES.has(baseName)) {
|
|
19388
19407
|
return { content: `\u8BBE\u5907\u6587\u4EF6\u4E0D\u652F\u6301\u8BFB\u53D6: ${filePath}`, isError: true };
|
|
19389
19408
|
}
|
|
@@ -19391,11 +19410,11 @@ Usage:
|
|
|
19391
19410
|
return { content: `\u8BBE\u5907\u6587\u4EF6\u4F1A\u963B\u585E\u6216\u4EA7\u751F\u65E0\u9650\u8F93\u51FA: ${filePath}`, isError: true };
|
|
19392
19411
|
}
|
|
19393
19412
|
if (stat4.isDirectory()) {
|
|
19394
|
-
const entries2 =
|
|
19413
|
+
const entries2 = fs51.readdirSync(filePath);
|
|
19395
19414
|
const items = entries2.map((e) => {
|
|
19396
|
-
const full =
|
|
19415
|
+
const full = path50.join(filePath, e);
|
|
19397
19416
|
try {
|
|
19398
|
-
const s =
|
|
19417
|
+
const s = fs51.statSync(full);
|
|
19399
19418
|
return s.isDirectory() ? `${e}/` : e;
|
|
19400
19419
|
} catch {
|
|
19401
19420
|
return e;
|
|
@@ -19404,7 +19423,7 @@ Usage:
|
|
|
19404
19423
|
return { content: `\u76EE\u5F55 (${entries2.length} \u9879):
|
|
19405
19424
|
${items.join("\n")}` };
|
|
19406
19425
|
}
|
|
19407
|
-
const ext =
|
|
19426
|
+
const ext = path50.extname(filePath).toLowerCase();
|
|
19408
19427
|
if (BINARY_EXTENSIONS.has(ext)) {
|
|
19409
19428
|
return { content: `\u4E8C\u8FDB\u5236\u6587\u4EF6\u4E0D\u652F\u6301\u8BFB\u53D6 (${ext}): ${filePath}`, isError: true };
|
|
19410
19429
|
}
|
|
@@ -19452,22 +19471,22 @@ ${result}` : result };
|
|
|
19452
19471
|
|
|
19453
19472
|
// src/tools/write.ts
|
|
19454
19473
|
var write_exports = {};
|
|
19455
|
-
import * as
|
|
19456
|
-
import * as
|
|
19474
|
+
import * as fs52 from "node:fs";
|
|
19475
|
+
import * as path51 from "node:path";
|
|
19457
19476
|
function isBlockedPath(filePath) {
|
|
19458
19477
|
return BLOCKED_PATTERNS.some((p) => p.test(filePath));
|
|
19459
19478
|
}
|
|
19460
19479
|
function atomicWrite(filePath, content) {
|
|
19461
19480
|
const tmpPath = filePath + ".tmp." + Date.now() + ".write";
|
|
19462
|
-
|
|
19481
|
+
fs52.writeFileSync(tmpPath, content, "utf-8");
|
|
19463
19482
|
try {
|
|
19464
|
-
|
|
19483
|
+
fs52.renameSync(tmpPath, filePath);
|
|
19465
19484
|
} catch (e) {
|
|
19466
19485
|
try {
|
|
19467
|
-
|
|
19486
|
+
fs52.unlinkSync(tmpPath);
|
|
19468
19487
|
} catch {
|
|
19469
19488
|
}
|
|
19470
|
-
|
|
19489
|
+
fs52.writeFileSync(filePath, content, "utf-8");
|
|
19471
19490
|
}
|
|
19472
19491
|
}
|
|
19473
19492
|
function simpleDiff(oldContent, newContent) {
|
|
@@ -19561,15 +19580,15 @@ Usage:
|
|
|
19561
19580
|
}
|
|
19562
19581
|
const rawContent = args2.content;
|
|
19563
19582
|
const content = rawContent.replaceAll("\r\n", "\n");
|
|
19564
|
-
if (
|
|
19583
|
+
if (fs52.existsSync(filePath) && fs52.statSync(filePath).isDirectory()) {
|
|
19565
19584
|
return { content: `\u8DEF\u5F84\u662F\u76EE\u5F55\u4E0D\u662F\u6587\u4EF6: ${filePath}`, isError: true };
|
|
19566
19585
|
}
|
|
19567
19586
|
let oldContent = null;
|
|
19568
19587
|
let isCreate = true;
|
|
19569
|
-
if (
|
|
19588
|
+
if (fs52.existsSync(filePath)) {
|
|
19570
19589
|
isCreate = false;
|
|
19571
19590
|
try {
|
|
19572
|
-
oldContent =
|
|
19591
|
+
oldContent = fs52.readFileSync(filePath, "utf-8").replaceAll("\r\n", "\n");
|
|
19573
19592
|
} catch {
|
|
19574
19593
|
isCreate = true;
|
|
19575
19594
|
}
|
|
@@ -19585,10 +19604,10 @@ Usage:
|
|
|
19585
19604
|
isError: true
|
|
19586
19605
|
};
|
|
19587
19606
|
}
|
|
19588
|
-
const currentStat =
|
|
19607
|
+
const currentStat = fs52.statSync(filePath);
|
|
19589
19608
|
const lastWriteTime = Math.floor(currentStat.mtimeMs);
|
|
19590
19609
|
if (lastWriteTime > readState.timestamp) {
|
|
19591
|
-
const currentContent =
|
|
19610
|
+
const currentContent = fs52.readFileSync(filePath, "utf-8").replaceAll("\r\n", "\n");
|
|
19592
19611
|
if (currentContent !== oldContent) {
|
|
19593
19612
|
return {
|
|
19594
19613
|
content: `\u6587\u4EF6\u5728\u8BFB\u53D6\u540E\u88AB\u4FEE\u6539\u3002\u8BF7\u5148\u91CD\u65B0\u8BFB\u53D6\u6587\u4EF6\u518D\u5199\u5165: ${filePath}`,
|
|
@@ -19597,9 +19616,9 @@ Usage:
|
|
|
19597
19616
|
}
|
|
19598
19617
|
}
|
|
19599
19618
|
}
|
|
19600
|
-
const dir =
|
|
19619
|
+
const dir = path51.dirname(filePath);
|
|
19601
19620
|
try {
|
|
19602
|
-
|
|
19621
|
+
fs52.mkdirSync(dir, { recursive: true });
|
|
19603
19622
|
} catch (e) {
|
|
19604
19623
|
return { content: `\u65E0\u6CD5\u521B\u5EFA\u76EE\u5F55: ${dir} \u2014 ${e.message}`, isError: true };
|
|
19605
19624
|
}
|
|
@@ -19608,11 +19627,11 @@ Usage:
|
|
|
19608
19627
|
} catch (e) {
|
|
19609
19628
|
return { content: `\u5199\u5165\u5931\u8D25: ${e.message}`, isError: true };
|
|
19610
19629
|
}
|
|
19611
|
-
readFileState.set(filePath, { timestamp:
|
|
19630
|
+
readFileState.set(filePath, { timestamp: fs52.statSync(filePath).mtimeMs });
|
|
19612
19631
|
const action = isCreate ? "\u521B\u5EFA" : "\u66F4\u65B0";
|
|
19613
19632
|
const lines = content.split("\n").length;
|
|
19614
19633
|
const chars = content.length;
|
|
19615
|
-
const stat4 =
|
|
19634
|
+
const stat4 = fs52.statSync(filePath);
|
|
19616
19635
|
let diff = "";
|
|
19617
19636
|
if (!isCreate && oldContent !== null) {
|
|
19618
19637
|
diff = `
|
|
@@ -19632,8 +19651,8 @@ ${simpleDiff(oldContent, content)}`;
|
|
|
19632
19651
|
|
|
19633
19652
|
// src/tools/edit.ts
|
|
19634
19653
|
var edit_exports = {};
|
|
19635
|
-
import * as
|
|
19636
|
-
import * as
|
|
19654
|
+
import * as fs53 from "node:fs";
|
|
19655
|
+
import * as path52 from "node:path";
|
|
19637
19656
|
function normalizeQuotes(str) {
|
|
19638
19657
|
return str.replaceAll(LEFT_SINGLE_CURLY, "'").replaceAll(RIGHT_SINGLE_CURLY, "'").replaceAll(LEFT_DOUBLE_CURLY, '"').replaceAll(RIGHT_DOUBLE_CURLY, '"');
|
|
19639
19658
|
}
|
|
@@ -19786,7 +19805,7 @@ Usage:
|
|
|
19786
19805
|
}
|
|
19787
19806
|
let fileContent = null;
|
|
19788
19807
|
try {
|
|
19789
|
-
const stat4 =
|
|
19808
|
+
const stat4 = fs53.statSync(filePath);
|
|
19790
19809
|
if (stat4.isDirectory()) {
|
|
19791
19810
|
return { content: `\u8DEF\u5F84\u662F\u76EE\u5F55\u4E0D\u662F\u6587\u4EF6: ${filePath}`, isError: true };
|
|
19792
19811
|
}
|
|
@@ -19796,21 +19815,21 @@ Usage:
|
|
|
19796
19815
|
} catch (e) {
|
|
19797
19816
|
if (e.code === "ENOENT") {
|
|
19798
19817
|
if (oldString === "") {
|
|
19799
|
-
const dir =
|
|
19800
|
-
|
|
19801
|
-
|
|
19802
|
-
readFileState.set(filePath, { timestamp:
|
|
19818
|
+
const dir = path52.dirname(filePath);
|
|
19819
|
+
fs53.mkdirSync(dir, { recursive: true });
|
|
19820
|
+
fs53.writeFileSync(filePath, newString, "utf-8");
|
|
19821
|
+
readFileState.set(filePath, { timestamp: fs53.statSync(filePath).mtimeMs });
|
|
19803
19822
|
return { content: `\u521B\u5EFA\u6587\u4EF6: ${filePath} (${newString.split("\n").length} \u884C)` };
|
|
19804
19823
|
}
|
|
19805
19824
|
return { content: `\u6587\u4EF6\u4E0D\u5B58\u5728: ${filePath}`, isError: true };
|
|
19806
19825
|
}
|
|
19807
19826
|
throw e;
|
|
19808
19827
|
}
|
|
19809
|
-
const rawContent =
|
|
19828
|
+
const rawContent = fs53.readFileSync(filePath, "utf-8");
|
|
19810
19829
|
fileContent = rawContent.replaceAll("\r\n", "\n");
|
|
19811
19830
|
if (oldString === "" && fileContent.trim() === "") {
|
|
19812
|
-
|
|
19813
|
-
readFileState.set(filePath, { timestamp:
|
|
19831
|
+
fs53.writeFileSync(filePath, newString, "utf-8");
|
|
19832
|
+
readFileState.set(filePath, { timestamp: fs53.statSync(filePath).mtimeMs });
|
|
19814
19833
|
return { content: `\u5199\u5165\u7A7A\u6587\u4EF6: ${filePath} (${newString.split("\n").length} \u884C)` };
|
|
19815
19834
|
}
|
|
19816
19835
|
const readState = readFileState.get(filePath);
|
|
@@ -19820,11 +19839,11 @@ Usage:
|
|
|
19820
19839
|
isError: true
|
|
19821
19840
|
};
|
|
19822
19841
|
}
|
|
19823
|
-
const currentStat =
|
|
19842
|
+
const currentStat = fs53.statSync(filePath);
|
|
19824
19843
|
const lastWriteTime = Math.floor(currentStat.mtimeMs);
|
|
19825
19844
|
if (lastWriteTime > readState.timestamp) {
|
|
19826
19845
|
if (fileContent !== rawContent.replaceAll("\r\n", "\n")) {
|
|
19827
|
-
if (fileContent !==
|
|
19846
|
+
if (fileContent !== fs53.readFileSync(filePath, "utf-8").replaceAll("\r\n", "\n")) {
|
|
19828
19847
|
return {
|
|
19829
19848
|
content: `\u6587\u4EF6\u5728\u8BFB\u53D6\u540E\u88AB\u4FEE\u6539\u3002\u8BF7\u5148\u91CD\u65B0\u8BFB\u53D6\u6587\u4EF6\u518D\u7F16\u8F91: ${filePath}`,
|
|
19830
19849
|
isError: true
|
|
@@ -19856,8 +19875,8 @@ ${preview}
|
|
|
19856
19875
|
const actualNewString = preserveQuoteStyle(oldString, actualOldString, newString);
|
|
19857
19876
|
const diffView = generateEditDiff(fileContent, actualOldString, actualNewString);
|
|
19858
19877
|
const newContent = applyEditToFile(fileContent, actualOldString, actualNewString, replaceAll);
|
|
19859
|
-
|
|
19860
|
-
readFileState.set(filePath, { timestamp:
|
|
19878
|
+
fs53.writeFileSync(filePath, newContent, "utf-8");
|
|
19879
|
+
readFileState.set(filePath, { timestamp: fs53.statSync(filePath).mtimeMs });
|
|
19861
19880
|
const strategy = actualOldString === oldString ? "\u7CBE\u786E\u5339\u914D" : "\u5F15\u53F7\u89C4\u8303\u5316\u5339\u914D";
|
|
19862
19881
|
const count = replaceAll ? matchCount : 1;
|
|
19863
19882
|
const diff = `${oldString.length}\u2192${newString.length}\u5B57\u7B26`;
|
|
@@ -19875,8 +19894,8 @@ ${diffView}`
|
|
|
19875
19894
|
|
|
19876
19895
|
// src/tools/glob.ts
|
|
19877
19896
|
var glob_exports = {};
|
|
19878
|
-
import * as
|
|
19879
|
-
import * as
|
|
19897
|
+
import * as fs54 from "node:fs";
|
|
19898
|
+
import * as path53 from "node:path";
|
|
19880
19899
|
function globMatch(pattern, filename) {
|
|
19881
19900
|
const regexStr = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "{{GLOBSTAR}}").replace(/\*/g, "[^/]*").replace(/\?/g, "[^/]").replace(/\{\{GLOBSTAR\}\}/g, ".*");
|
|
19882
19901
|
try {
|
|
@@ -19896,18 +19915,18 @@ function findFiles(dir, pattern, limit, baseDir) {
|
|
|
19896
19915
|
}
|
|
19897
19916
|
let entries2;
|
|
19898
19917
|
try {
|
|
19899
|
-
entries2 =
|
|
19918
|
+
entries2 = fs54.readdirSync(currentDir, { withFileTypes: true });
|
|
19900
19919
|
} catch {
|
|
19901
19920
|
return;
|
|
19902
19921
|
}
|
|
19903
19922
|
for (const entry of entries2) {
|
|
19904
19923
|
if (truncated) return;
|
|
19905
|
-
const fullPath =
|
|
19924
|
+
const fullPath = path53.join(currentDir, entry.name);
|
|
19906
19925
|
if (entry.isDirectory()) {
|
|
19907
19926
|
if (VCS_DIRS.has(entry.name)) continue;
|
|
19908
19927
|
walk(fullPath);
|
|
19909
19928
|
} else if (entry.isFile()) {
|
|
19910
|
-
const relativePath =
|
|
19929
|
+
const relativePath = path53.relative(baseDir, fullPath).replace(/\\/g, "/");
|
|
19911
19930
|
const patternsToTry = [pattern];
|
|
19912
19931
|
if (pattern.startsWith("**/")) {
|
|
19913
19932
|
patternsToTry.push(pattern.slice(3));
|
|
@@ -19917,7 +19936,7 @@ function findFiles(dir, pattern, limit, baseDir) {
|
|
|
19917
19936
|
);
|
|
19918
19937
|
if (matched) {
|
|
19919
19938
|
try {
|
|
19920
|
-
const stat4 =
|
|
19939
|
+
const stat4 = fs54.statSync(fullPath);
|
|
19921
19940
|
results.push({ path: fullPath, mtimeMs: stat4.mtimeMs });
|
|
19922
19941
|
} catch {
|
|
19923
19942
|
}
|
|
@@ -19934,7 +19953,7 @@ function findFiles(dir, pattern, limit, baseDir) {
|
|
|
19934
19953
|
};
|
|
19935
19954
|
}
|
|
19936
19955
|
function toRelativePath(absolutePath, cwd) {
|
|
19937
|
-
if (absolutePath.startsWith(cwd +
|
|
19956
|
+
if (absolutePath.startsWith(cwd + path53.sep)) {
|
|
19938
19957
|
return absolutePath.slice(cwd.length + 1);
|
|
19939
19958
|
}
|
|
19940
19959
|
return absolutePath;
|
|
@@ -19967,10 +19986,10 @@ var init_glob = __esm({
|
|
|
19967
19986
|
const searchPath = args2.path ? resolvePath(args2.path, ctx.workspace) : ctx.workspace;
|
|
19968
19987
|
const pattern = args2.pattern;
|
|
19969
19988
|
const limit = args2.limit || DEFAULT_LIMIT;
|
|
19970
|
-
if (!
|
|
19989
|
+
if (!fs54.existsSync(searchPath)) {
|
|
19971
19990
|
return { content: `\u76EE\u5F55\u4E0D\u5B58\u5728: ${searchPath}`, isError: true };
|
|
19972
19991
|
}
|
|
19973
|
-
if (!
|
|
19992
|
+
if (!fs54.statSync(searchPath).isDirectory()) {
|
|
19974
19993
|
return { content: `\u8DEF\u5F84\u4E0D\u662F\u76EE\u5F55: ${searchPath}`, isError: true };
|
|
19975
19994
|
}
|
|
19976
19995
|
const start = Date.now();
|
|
@@ -19995,7 +20014,7 @@ ${filenames.join("\n")}${truncatedNote}`
|
|
|
19995
20014
|
// src/tools/grep.ts
|
|
19996
20015
|
var grep_exports = {};
|
|
19997
20016
|
import { execFile as execFile4 } from "node:child_process";
|
|
19998
|
-
import * as
|
|
20017
|
+
import * as path54 from "node:path";
|
|
19999
20018
|
function ripGrep(args2, searchPath, signal) {
|
|
20000
20019
|
return new Promise((resolve12) => {
|
|
20001
20020
|
const fullArgs = [...args2, searchPath];
|
|
@@ -20027,7 +20046,7 @@ function applyHeadLimit(items, limit, offset = 0) {
|
|
|
20027
20046
|
};
|
|
20028
20047
|
}
|
|
20029
20048
|
function toRelativePath2(absolutePath, cwd) {
|
|
20030
|
-
if (absolutePath.startsWith(cwd +
|
|
20049
|
+
if (absolutePath.startsWith(cwd + path54.sep)) {
|
|
20031
20050
|
return absolutePath.slice(cwd.length + 1);
|
|
20032
20051
|
}
|
|
20033
20052
|
if (absolutePath.startsWith(cwd)) {
|
|
@@ -20600,7 +20619,7 @@ var init_builtInAgents = __esm({
|
|
|
20600
20619
|
});
|
|
20601
20620
|
|
|
20602
20621
|
// src/tools/AgentTool/forkSubagent.ts
|
|
20603
|
-
import { randomUUID as
|
|
20622
|
+
import { randomUUID as randomUUID9 } from "crypto";
|
|
20604
20623
|
function isForkSubagentEnabled() {
|
|
20605
20624
|
return true;
|
|
20606
20625
|
}
|
|
@@ -20639,7 +20658,7 @@ function buildForkedMessages(directive, parentMessages) {
|
|
|
20639
20658
|
type: "tool_result",
|
|
20640
20659
|
tool_use_id: block.id,
|
|
20641
20660
|
content: FORK_PLACEHOLDER_RESULT,
|
|
20642
|
-
id: `toolr_${
|
|
20661
|
+
id: `toolr_${randomUUID9().replace(/-/g, "").slice(0, 24)}`
|
|
20643
20662
|
}));
|
|
20644
20663
|
const toolResultMessage = msg_user(
|
|
20645
20664
|
buildChildMessage(directive),
|
|
@@ -20702,10 +20721,10 @@ var init_forkSubagent = __esm({
|
|
|
20702
20721
|
});
|
|
20703
20722
|
|
|
20704
20723
|
// src/tools/AgentTool/runAgent.ts
|
|
20705
|
-
import { randomBytes as
|
|
20724
|
+
import { randomBytes as randomBytes7 } from "node:crypto";
|
|
20706
20725
|
function generateAgentId() {
|
|
20707
20726
|
const prefix = "a";
|
|
20708
|
-
const bytes =
|
|
20727
|
+
const bytes = randomBytes7(8);
|
|
20709
20728
|
let id = prefix;
|
|
20710
20729
|
for (let i = 0; i < 8; i++) {
|
|
20711
20730
|
id += TASK_ID_ALPHABET2[bytes[i] % TASK_ID_ALPHABET2.length];
|
|
@@ -22764,8 +22783,8 @@ __export(manager_exports, {
|
|
|
22764
22783
|
McpManager: () => McpManager,
|
|
22765
22784
|
convertInputSchema: () => convertInputSchema
|
|
22766
22785
|
});
|
|
22767
|
-
import * as
|
|
22768
|
-
import * as
|
|
22786
|
+
import * as fs57 from "node:fs";
|
|
22787
|
+
import * as path57 from "node:path";
|
|
22769
22788
|
import { Client as Client3 } from "@modelcontextprotocol/sdk/client/index.js";
|
|
22770
22789
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
22771
22790
|
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
@@ -22806,12 +22825,12 @@ function convertInputSchema(inputSchema) {
|
|
|
22806
22825
|
}
|
|
22807
22826
|
function persistBinary(base64Data, mimeType, persistId) {
|
|
22808
22827
|
const ext = mimeType?.split("/")[1] || "bin";
|
|
22809
|
-
const dir =
|
|
22810
|
-
|
|
22811
|
-
const filepath =
|
|
22828
|
+
const dir = path57.join(process.env.ENGINE_STATE_DIR || ".engine", "mcp-blobs");
|
|
22829
|
+
fs57.mkdirSync(dir, { recursive: true });
|
|
22830
|
+
const filepath = path57.join(dir, `${persistId}.${ext}`);
|
|
22812
22831
|
try {
|
|
22813
22832
|
const buf = Buffer.from(base64Data, "base64");
|
|
22814
|
-
|
|
22833
|
+
fs57.writeFileSync(filepath, buf);
|
|
22815
22834
|
return { filepath, size: buf.length };
|
|
22816
22835
|
} catch (err) {
|
|
22817
22836
|
return { error: err.message };
|
|
@@ -23145,7 +23164,7 @@ __export(resources_exports, {
|
|
|
23145
23164
|
registerMcpResourceTools: () => registerMcpResourceTools,
|
|
23146
23165
|
unregisterMcpResourceTools: () => unregisterMcpResourceTools
|
|
23147
23166
|
});
|
|
23148
|
-
import * as
|
|
23167
|
+
import * as path58 from "node:path";
|
|
23149
23168
|
function registerMcpResourceTools(manager) {
|
|
23150
23169
|
mcpManagerRef = manager;
|
|
23151
23170
|
registry.register(listResourcesTool);
|
|
@@ -23163,7 +23182,7 @@ var init_resources = __esm({
|
|
|
23163
23182
|
"use strict";
|
|
23164
23183
|
init_registry();
|
|
23165
23184
|
MAX_RESULT_CHARS2 = 1e5;
|
|
23166
|
-
MEDIA_DIR = process.env.ENGINE_MEDIA_DIR ||
|
|
23185
|
+
MEDIA_DIR = process.env.ENGINE_MEDIA_DIR || path58.join(process.env.ENGINE_STATE_DIR || ".engine", "media", "inbound");
|
|
23167
23186
|
MCP_LIST_RESOURCES_TOOL = "mcp__list_resources";
|
|
23168
23187
|
MCP_READ_RESOURCE_TOOL = "mcp__read_resource";
|
|
23169
23188
|
mcpManagerRef = null;
|
|
@@ -23311,7 +23330,7 @@ function loadSecretsEnvForConfig(configPath2) {
|
|
|
23311
23330
|
// src/engine-startup.ts
|
|
23312
23331
|
init_query();
|
|
23313
23332
|
init_live();
|
|
23314
|
-
import * as
|
|
23333
|
+
import * as path59 from "node:path";
|
|
23315
23334
|
|
|
23316
23335
|
// src/startup/providers.ts
|
|
23317
23336
|
init_provider_factory();
|
|
@@ -23840,8 +23859,8 @@ function startConfigWatcher(config2, deps, provider) {
|
|
|
23840
23859
|
}
|
|
23841
23860
|
if (!fs10.existsSync(configPath2)) {
|
|
23842
23861
|
const __filename2 = fileURLToPath(import.meta.url);
|
|
23843
|
-
const
|
|
23844
|
-
configPath2 = path10.resolve(
|
|
23862
|
+
const __dirname2 = path10.dirname(__filename2);
|
|
23863
|
+
configPath2 = path10.resolve(__dirname2, "..", raw);
|
|
23845
23864
|
}
|
|
23846
23865
|
if (!fs10.existsSync(configPath2)) {
|
|
23847
23866
|
console.warn(`[config-watch] config path invalid: ${configPath2}, watcher disabled`);
|
|
@@ -24664,7 +24683,7 @@ ${formatted}` };
|
|
|
24664
24683
|
};
|
|
24665
24684
|
}
|
|
24666
24685
|
function createEverosGetTool() {
|
|
24667
|
-
const
|
|
24686
|
+
const fs58 = __require("node:fs/promises");
|
|
24668
24687
|
return {
|
|
24669
24688
|
name: "memory_get",
|
|
24670
24689
|
description: "Read a memory file by path.",
|
|
@@ -24680,7 +24699,7 @@ function createEverosGetTool() {
|
|
|
24680
24699
|
handler: async (args2) => {
|
|
24681
24700
|
try {
|
|
24682
24701
|
const filePath = args2.path;
|
|
24683
|
-
const content = await
|
|
24702
|
+
const content = await fs58.readFile(filePath, "utf-8");
|
|
24684
24703
|
const lines = content.split("\n");
|
|
24685
24704
|
const fromLine = args2.from ?? 1;
|
|
24686
24705
|
const numLines = args2.lines ?? lines.length;
|
|
@@ -25932,9 +25951,9 @@ function readDbEmbeddings(dbPath) {
|
|
|
25932
25951
|
db2.close();
|
|
25933
25952
|
}
|
|
25934
25953
|
}
|
|
25935
|
-
async function llmRerank(query,
|
|
25936
|
-
if (
|
|
25937
|
-
const manifest =
|
|
25954
|
+
async function llmRerank(query, candidates2, topK, ollamaChatUrl, model) {
|
|
25955
|
+
if (candidates2.length <= topK) return candidates2;
|
|
25956
|
+
const manifest = candidates2.map(
|
|
25938
25957
|
(c, i) => `${i + 1}. ${c.filename}
|
|
25939
25958
|
${c.description || c.name}`
|
|
25940
25959
|
).join("\n");
|
|
@@ -25966,7 +25985,7 @@ Select up to ${topK} most relevant (return their 1-indexed numbers as JSON {"sel
|
|
|
25966
25985
|
});
|
|
25967
25986
|
if (!resp.ok) {
|
|
25968
25987
|
console.warn(`[memdir] rerank: ollama chat failed: ${resp.status}`);
|
|
25969
|
-
return
|
|
25988
|
+
return candidates2.slice(0, topK);
|
|
25970
25989
|
}
|
|
25971
25990
|
const data = await resp.json();
|
|
25972
25991
|
const text = data?.message?.content ?? "";
|
|
@@ -25975,19 +25994,19 @@ Select up to ${topK} most relevant (return their 1-indexed numbers as JSON {"sel
|
|
|
25975
25994
|
try {
|
|
25976
25995
|
const parsed = JSON.parse(jsonMatch[0]);
|
|
25977
25996
|
if (parsed.selected && Array.isArray(parsed.selected)) {
|
|
25978
|
-
const indices = parsed.selected.filter((n) => n >= 1 && n <=
|
|
25979
|
-
const result = indices.map((i) =>
|
|
25980
|
-
console.log(`[memdir] rerank: ${model} selected ${result.length}/${
|
|
25997
|
+
const indices = parsed.selected.filter((n) => n >= 1 && n <= candidates2.length).map((n) => n - 1);
|
|
25998
|
+
const result = indices.map((i) => candidates2[i]);
|
|
25999
|
+
console.log(`[memdir] rerank: ${model} selected ${result.length}/${candidates2.length} candidates (indices: ${indices.map((i) => i + 1).join(",")})`);
|
|
25981
26000
|
return result.slice(0, topK);
|
|
25982
26001
|
}
|
|
25983
26002
|
} catch {
|
|
25984
26003
|
}
|
|
25985
26004
|
}
|
|
25986
26005
|
console.warn(`[memdir] rerank: no valid JSON in response (${text.length} chars), falling back to vector order`);
|
|
25987
|
-
return
|
|
26006
|
+
return candidates2.slice(0, topK);
|
|
25988
26007
|
} catch (e) {
|
|
25989
26008
|
console.warn(`[memdir] rerank: error: ${e?.message ?? e}, falling back to vector order`);
|
|
25990
|
-
return
|
|
26009
|
+
return candidates2.slice(0, topK);
|
|
25991
26010
|
}
|
|
25992
26011
|
}
|
|
25993
26012
|
async function findRelevantMemoriesVector(query, memoryDir, alreadySurfaced = /* @__PURE__ */ new Set(), options) {
|
|
@@ -26036,17 +26055,17 @@ async function findRelevantMemoriesVector(query, memoryDir, alreadySurfaced = /*
|
|
|
26036
26055
|
}
|
|
26037
26056
|
}
|
|
26038
26057
|
scored.sort((a, b) => b.score - a.score);
|
|
26039
|
-
const
|
|
26058
|
+
const candidates2 = scored.slice(0, CANDIDATE_POOL);
|
|
26040
26059
|
const vectorMs = Date.now() - t0;
|
|
26041
26060
|
console.log(
|
|
26042
|
-
`[memdir] vector recall: ${
|
|
26061
|
+
`[memdir] vector recall: ${candidates2.length} candidates in ${vectorMs}ms (embed=${embedMs}ms, scanned=${rows.length} files, minScore=${minScore})`
|
|
26043
26062
|
);
|
|
26044
|
-
if (
|
|
26045
|
-
console.log(`[memdir] vector top scores: ${
|
|
26063
|
+
if (candidates2.length > 0) {
|
|
26064
|
+
console.log(`[memdir] vector top scores: ${candidates2.slice(0, 5).map((r) => `${r.filename}=${r.score.toFixed(3)}`).join(", ")}${candidates2.length > 5 ? "..." : ""}`);
|
|
26046
26065
|
}
|
|
26047
|
-
if (
|
|
26066
|
+
if (candidates2.length === 0) return [];
|
|
26048
26067
|
const rerankT0 = Date.now();
|
|
26049
|
-
const reranked = await llmRerank(query,
|
|
26068
|
+
const reranked = await llmRerank(query, candidates2, topK, DEFAULT_OLLAMA_CHAT_URL, rerankModel);
|
|
26050
26069
|
const rerankMs = Date.now() - rerankT0;
|
|
26051
26070
|
const totalMs = Date.now() - t0;
|
|
26052
26071
|
console.log(`[memdir] recall total: ${totalMs}ms (vector=${vectorMs}ms, rerank=${rerankMs}ms)`);
|
|
@@ -26473,18 +26492,18 @@ function resetSessionStartInjection(sessionId) {
|
|
|
26473
26492
|
}
|
|
26474
26493
|
var externalChanRulesCache = null;
|
|
26475
26494
|
function loadExternalChanRules(workspace) {
|
|
26476
|
-
const
|
|
26477
|
-
if (externalChanRulesCache && externalChanRulesCache.path ===
|
|
26495
|
+
const path60 = join36(workspace, "prompts", "external-chan-rules.md");
|
|
26496
|
+
if (externalChanRulesCache && externalChanRulesCache.path === path60) return externalChanRulesCache;
|
|
26478
26497
|
let content = "";
|
|
26479
|
-
if (existsSync20(
|
|
26498
|
+
if (existsSync20(path60)) {
|
|
26480
26499
|
try {
|
|
26481
|
-
content = readFileSync27(
|
|
26500
|
+
content = readFileSync27(path60, "utf-8").trim();
|
|
26482
26501
|
} catch (e) {
|
|
26483
26502
|
console.warn(`[external-chan-rules] Failed to load: ${e}`);
|
|
26484
26503
|
}
|
|
26485
26504
|
}
|
|
26486
|
-
externalChanRulesCache = { path:
|
|
26487
|
-
console.log(`[external-chan-rules] Loaded ${content.length} chars from ${
|
|
26505
|
+
externalChanRulesCache = { path: path60, content };
|
|
26506
|
+
console.log(`[external-chan-rules] Loaded ${content.length} chars from ${path60}`);
|
|
26488
26507
|
return externalChanRulesCache;
|
|
26489
26508
|
}
|
|
26490
26509
|
function getExternalChanRulesBlock(inboundMeta, workspace) {
|
|
@@ -27371,15 +27390,15 @@ function registerCompactHooks(config2) {
|
|
|
27371
27390
|
const dailyDir = path22.join(workspace, "memory", "daily");
|
|
27372
27391
|
const dailyPath = path22.join(dailyDir, `${dateStr}.md`);
|
|
27373
27392
|
try {
|
|
27374
|
-
const
|
|
27375
|
-
if (!
|
|
27376
|
-
|
|
27393
|
+
const fs58 = await import("node:fs");
|
|
27394
|
+
if (!fs58.existsSync(dailyDir)) {
|
|
27395
|
+
fs58.mkdirSync(dailyDir, { recursive: true });
|
|
27377
27396
|
}
|
|
27378
27397
|
const sessionsDir = path22.join(config2.stateDir, "agents", "main", "sessions");
|
|
27379
27398
|
const sessionFile = path22.join(sessionsDir, `${sessionId}.jsonl`);
|
|
27380
27399
|
const recentLines = [];
|
|
27381
|
-
if (
|
|
27382
|
-
const content =
|
|
27400
|
+
if (fs58.existsSync(sessionFile)) {
|
|
27401
|
+
const content = fs58.readFileSync(sessionFile, "utf-8");
|
|
27383
27402
|
const lines = content.trim().split("\n").filter(Boolean);
|
|
27384
27403
|
const userLines = lines.filter((l) => {
|
|
27385
27404
|
try {
|
|
@@ -27409,10 +27428,10 @@ function registerCompactHooks(config2) {
|
|
|
27409
27428
|
const entry = `${header}
|
|
27410
27429
|
${body}
|
|
27411
27430
|
`;
|
|
27412
|
-
if (
|
|
27413
|
-
|
|
27431
|
+
if (fs58.existsSync(dailyPath)) {
|
|
27432
|
+
fs58.appendFileSync(dailyPath, entry);
|
|
27414
27433
|
} else {
|
|
27415
|
-
|
|
27434
|
+
fs58.writeFileSync(dailyPath, `# ${dateStr} \u65E5\u5FD7
|
|
27416
27435
|
${entry}`);
|
|
27417
27436
|
}
|
|
27418
27437
|
console.log(`[hooks] PreCompact: saved ${recentLines.length} lines to ${dailyPath}`);
|
|
@@ -27428,16 +27447,16 @@ ${entry}`);
|
|
|
27428
27447
|
const workspace = input.cwd || input.workspace || "";
|
|
27429
27448
|
if (!workspace) return { continue: true };
|
|
27430
27449
|
try {
|
|
27431
|
-
const
|
|
27450
|
+
const fs58 = await import("node:fs");
|
|
27432
27451
|
const bufferPath = path22.join(workspace, "memory", "working-buffer.md");
|
|
27433
|
-
if (
|
|
27434
|
-
const stat4 =
|
|
27452
|
+
if (fs58.existsSync(bufferPath)) {
|
|
27453
|
+
const stat4 = fs58.statSync(bufferPath);
|
|
27435
27454
|
const ageMs = Date.now() - stat4.mtimeMs;
|
|
27436
27455
|
const ageMin = Math.round(ageMs / 6e4);
|
|
27437
27456
|
if (ageMin > 10) {
|
|
27438
27457
|
console.warn(`[hooks] PostCompact: \u26A0\uFE0F working-buffer.md is ${ageMin}min old (last modified ${stat4.mtime.toISOString()}) \u2014 content may be stale!`);
|
|
27439
27458
|
}
|
|
27440
|
-
const content =
|
|
27459
|
+
const content = fs58.readFileSync(bufferPath, "utf-8");
|
|
27441
27460
|
if (content.trim()) {
|
|
27442
27461
|
console.log(`[hooks] PostCompact: injecting working-buffer (${content.length} chars, ${ageMin}min old)`);
|
|
27443
27462
|
return {
|
|
@@ -30814,6 +30833,8 @@ function startInboxPoller(ctx) {
|
|
|
30814
30833
|
const INBOX_POLL_INTERVAL_MS = 2e3;
|
|
30815
30834
|
const INBOX_IDLE_INTERVAL_MS = 3e4;
|
|
30816
30835
|
let pollCycleCount = 0;
|
|
30836
|
+
let lastStatusLine = "";
|
|
30837
|
+
let warnedNoPreview = false;
|
|
30817
30838
|
let inboxPollerTimer = null;
|
|
30818
30839
|
let inboxPollerStandby = false;
|
|
30819
30840
|
function runInboxPollCycle() {
|
|
@@ -30850,7 +30871,11 @@ function startInboxPoller(ctx) {
|
|
|
30850
30871
|
).join(" ");
|
|
30851
30872
|
const isMainActive = dispatcher.isActive("main");
|
|
30852
30873
|
const mainPending = dispatcher.pendingCount("main");
|
|
30853
|
-
|
|
30874
|
+
const statusLine = `teammates=[${statusSummary}] mainActive=${isMainActive} mainPending=${mainPending}`;
|
|
30875
|
+
if (statusLine !== lastStatusLine || pollCycleCount % 15 === 0) {
|
|
30876
|
+
lastStatusLine = statusLine;
|
|
30877
|
+
console.log(`[inbox-poller] #${pollCycleCount} ${statusLine}`);
|
|
30878
|
+
}
|
|
30854
30879
|
const now = Date.now();
|
|
30855
30880
|
const allTeamNames = new Set(teammates.filter((t) => t.status !== "killed").map((t) => t.identity.teamName));
|
|
30856
30881
|
const teams = [...allTeamNames];
|
|
@@ -30928,7 +30953,6 @@ function startInboxPoller(ctx) {
|
|
|
30928
30953
|
${notifications}
|
|
30929
30954
|
[/teammate-status]${taskSummary}`;
|
|
30930
30955
|
const inboxTarget = "";
|
|
30931
|
-
const inboxPreview = null;
|
|
30932
30956
|
const submitted = dispatcher.submitMessage({
|
|
30933
30957
|
text: queryContent,
|
|
30934
30958
|
sessionId: "main",
|
|
@@ -30938,21 +30962,12 @@ ${notifications}
|
|
|
30938
30962
|
priority: "next",
|
|
30939
30963
|
// 对齐 CC: idle 时立即提交,不是 'later' 排队
|
|
30940
30964
|
callbacks: {
|
|
30941
|
-
onText: (
|
|
30942
|
-
if (
|
|
30943
|
-
|
|
30944
|
-
|
|
30945
|
-
console.warn(`[inbox-poller:onText] no preview target, Discord output dropped (${text.length} chars)`);
|
|
30946
|
-
}
|
|
30965
|
+
onText: (_text) => {
|
|
30966
|
+
if (warnedNoPreview) return;
|
|
30967
|
+
warnedNoPreview = true;
|
|
30968
|
+
console.warn("[inbox-poller] teammate-status \u7684\u8F93\u51FA\u4E0D\u6295\u9012\u5230\u5916\u90E8\u9891\u9053\uFF08\u8BBE\u8BA1\u5982\u6B64\uFF09\uFF0C\u4EC5\u5904\u7406\u526F\u4F5C\u7528");
|
|
30947
30969
|
},
|
|
30948
|
-
onResult: async (
|
|
30949
|
-
if (inboxPreview) {
|
|
30950
|
-
const delivered = await inboxPreview.finish(content.trim() || "(\u5904\u7406\u5B8C\u6210)");
|
|
30951
|
-
if (!delivered && inboxTarget) {
|
|
30952
|
-
channelManager.send("discord", inboxTarget, content.trim() || "(\u5904\u7406\u5B8C\u6210)").catch(() => {
|
|
30953
|
-
});
|
|
30954
|
-
}
|
|
30955
|
-
}
|
|
30970
|
+
onResult: async (_content) => {
|
|
30956
30971
|
}
|
|
30957
30972
|
},
|
|
30958
30973
|
deps
|
|
@@ -31646,8 +31661,8 @@ var VoiceChatPlugin = class {
|
|
|
31646
31661
|
// src/memory/everos/plugin.ts
|
|
31647
31662
|
import { spawn as spawn4 } from "node:child_process";
|
|
31648
31663
|
import net from "node:net";
|
|
31649
|
-
import
|
|
31650
|
-
import
|
|
31664
|
+
import path35 from "node:path";
|
|
31665
|
+
import fs35 from "node:fs";
|
|
31651
31666
|
|
|
31652
31667
|
// src/memory/everos/config.ts
|
|
31653
31668
|
var DEFAULTS4 = {
|
|
@@ -31881,8 +31896,8 @@ var EverosPlugin = class {
|
|
|
31881
31896
|
}, 3e5);
|
|
31882
31897
|
}
|
|
31883
31898
|
async startEveros() {
|
|
31884
|
-
const pythonDir =
|
|
31885
|
-
const configPath2 =
|
|
31899
|
+
const pythonDir = path35.dirname(this.config.lancedbPath);
|
|
31900
|
+
const configPath2 = path35.join(pythonDir, "config.toml");
|
|
31886
31901
|
await this.ensureFcntlCompat();
|
|
31887
31902
|
const venvPython = this.findVenvPython();
|
|
31888
31903
|
const everosBin = venvPython.replace(/python\.exe$/, "everos.exe");
|
|
@@ -31972,19 +31987,19 @@ var EverosPlugin = class {
|
|
|
31972
31987
|
return child;
|
|
31973
31988
|
}
|
|
31974
31989
|
findVenvPython() {
|
|
31975
|
-
const stateDir = process.env.ENGINE7_STATE_DIR ||
|
|
31990
|
+
const stateDir = process.env.ENGINE7_STATE_DIR || path35.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7");
|
|
31976
31991
|
if (process.platform === "win32") {
|
|
31977
|
-
return
|
|
31992
|
+
return path35.join(stateDir, "everos-venv", "Scripts", "python.exe");
|
|
31978
31993
|
}
|
|
31979
|
-
return
|
|
31994
|
+
return path35.join(stateDir, "everos-venv", "bin", "python");
|
|
31980
31995
|
}
|
|
31981
31996
|
/** 检测 venv 是否存在,不存在就自动创建 + 装 EverOS */
|
|
31982
31997
|
async ensureVenv() {
|
|
31983
31998
|
const venvPython = this.findVenvPython();
|
|
31984
|
-
if (
|
|
31985
|
-
const stateDir = process.env.ENGINE7_STATE_DIR ||
|
|
31986
|
-
const venvDir =
|
|
31987
|
-
const everosSrc =
|
|
31999
|
+
if (fs35.existsSync(venvPython)) return;
|
|
32000
|
+
const stateDir = process.env.ENGINE7_STATE_DIR || path35.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7");
|
|
32001
|
+
const venvDir = path35.join(stateDir, "everos-venv");
|
|
32002
|
+
const everosSrc = path35.join(stateDir, "workspace", "research", "EverOS");
|
|
31988
32003
|
console.log(`[everos] venv not found at ${venvDir}, auto-creating...`);
|
|
31989
32004
|
console.log(`[everos] \u23F3 This may take a few minutes on first run...`);
|
|
31990
32005
|
const pyCandidates = process.platform === "win32" ? ["python", "python3", "C:\\Python314\\python.exe", "C:\\Python313\\python.exe", "C:\\Python312\\python.exe"] : ["python3", "python"];
|
|
@@ -32006,9 +32021,9 @@ var EverosPlugin = class {
|
|
|
32006
32021
|
console.log(`[everos] Creating venv with ${sysPython}...`);
|
|
32007
32022
|
const { execSync: execSync3 } = await import("node:child_process");
|
|
32008
32023
|
execSync3(`"${sysPython}" -m venv "${venvDir}"`, { stdio: "pipe", shell: true });
|
|
32009
|
-
const pip = process.platform === "win32" ?
|
|
32010
|
-
const everosReq =
|
|
32011
|
-
if (
|
|
32024
|
+
const pip = process.platform === "win32" ? path35.join(venvDir, "Scripts", "pip.exe") : path35.join(venvDir, "bin", "pip");
|
|
32025
|
+
const everosReq = path35.join(this.getPythonDir(), "requirements.txt");
|
|
32026
|
+
if (fs35.existsSync(everosReq)) {
|
|
32012
32027
|
console.log(`[everos] Installing from requirements.txt...`);
|
|
32013
32028
|
execSync3(`"${pip}" install -r "${everosReq}" -q`, { stdio: "pipe", shell: true, timeout: 3e5 });
|
|
32014
32029
|
} else {
|
|
@@ -32023,29 +32038,29 @@ var EverosPlugin = class {
|
|
|
32023
32038
|
}
|
|
32024
32039
|
getPythonDir() {
|
|
32025
32040
|
const dir = import.meta.dirname;
|
|
32026
|
-
const
|
|
32027
|
-
|
|
32028
|
-
|
|
32029
|
-
|
|
32041
|
+
const candidates2 = [
|
|
32042
|
+
path35.join(dir, "python"),
|
|
32043
|
+
path35.resolve(dir, "..", "src", "memory", "everos", "python"),
|
|
32044
|
+
path35.resolve(dir, "..", "..", "..", "src", "memory", "everos", "python")
|
|
32030
32045
|
];
|
|
32031
|
-
for (const candidate of
|
|
32032
|
-
if (
|
|
32046
|
+
for (const candidate of candidates2) {
|
|
32047
|
+
if (fs35.existsSync(path35.join(candidate, "agentic_server.py"))) {
|
|
32033
32048
|
return candidate;
|
|
32034
32049
|
}
|
|
32035
32050
|
}
|
|
32036
|
-
return
|
|
32051
|
+
return candidates2[0];
|
|
32037
32052
|
}
|
|
32038
32053
|
async ensureFcntlCompat() {
|
|
32039
32054
|
if (process.platform !== "win32") return;
|
|
32040
32055
|
const venvPython = this.findVenvPython();
|
|
32041
|
-
const venvDir =
|
|
32042
|
-
const sitePackages =
|
|
32043
|
-
const target =
|
|
32044
|
-
if (
|
|
32045
|
-
const source =
|
|
32046
|
-
if (
|
|
32056
|
+
const venvDir = path35.dirname(path35.dirname(venvPython));
|
|
32057
|
+
const sitePackages = path35.join(venvDir, "Lib", "site-packages");
|
|
32058
|
+
const target = path35.join(sitePackages, "fcntl.py");
|
|
32059
|
+
if (fs35.existsSync(target)) return;
|
|
32060
|
+
const source = path35.join(this.getPythonDir(), "fcntl_compat.py");
|
|
32061
|
+
if (fs35.existsSync(source)) {
|
|
32047
32062
|
try {
|
|
32048
|
-
|
|
32063
|
+
fs35.copyFileSync(source, target);
|
|
32049
32064
|
console.log(`[everos] Installed fcntl compat shim to ${target}`);
|
|
32050
32065
|
} catch (err) {
|
|
32051
32066
|
console.warn(`[everos] Failed to install fcntl shim: ${err.message}`);
|
|
@@ -32654,8 +32669,8 @@ function createVisualBoot(ctx) {
|
|
|
32654
32669
|
}
|
|
32655
32670
|
|
|
32656
32671
|
// src/startup/message-pipeline.ts
|
|
32657
|
-
import * as
|
|
32658
|
-
import * as
|
|
32672
|
+
import * as fs36 from "node:fs";
|
|
32673
|
+
import * as path36 from "node:path";
|
|
32659
32674
|
|
|
32660
32675
|
// src/commands/registry.ts
|
|
32661
32676
|
var commands = /* @__PURE__ */ new Map();
|
|
@@ -33546,7 +33561,7 @@ function setupMessagePipeline(ctx) {
|
|
|
33546
33561
|
console.log(`[vision] Downloading image: ${att.filename}`);
|
|
33547
33562
|
let rawBuffer;
|
|
33548
33563
|
if (att.url.startsWith("file://")) {
|
|
33549
|
-
rawBuffer =
|
|
33564
|
+
rawBuffer = fs36.readFileSync(decodeURIComponent(att.url.slice(7)));
|
|
33550
33565
|
} else {
|
|
33551
33566
|
rawBuffer = await downloadImage2(att.url, attachDispatcher);
|
|
33552
33567
|
}
|
|
@@ -33554,8 +33569,8 @@ function setupMessagePipeline(ctx) {
|
|
|
33554
33569
|
const ext = detected.split("/")[1] || "png";
|
|
33555
33570
|
const resized = await maybeResizeAndDownsampleImageBuffer2(rawBuffer, rawBuffer.length, ext);
|
|
33556
33571
|
const imageId = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
33557
|
-
const savedPath =
|
|
33558
|
-
|
|
33572
|
+
const savedPath = path36.join(config2.mediaDir, `${imageId}.${ext}`);
|
|
33573
|
+
fs36.writeFileSync(savedPath, resized.buffer);
|
|
33559
33574
|
savedPaths.push(savedPath);
|
|
33560
33575
|
console.log(`[vision] Saved: ${savedPath} (${resized.buffer.length}B)`);
|
|
33561
33576
|
imageBlocks.push({
|
|
@@ -33585,8 +33600,8 @@ ${pathStr}` }];
|
|
|
33585
33600
|
}
|
|
33586
33601
|
const nonImageAttachments = inbound.attachments?.filter((a) => !a.contentType.startsWith("image/"));
|
|
33587
33602
|
if (nonImageAttachments && nonImageAttachments.length > 0) {
|
|
33588
|
-
const outDir =
|
|
33589
|
-
|
|
33603
|
+
const outDir = path36.join(config2.mediaDir, sessionId);
|
|
33604
|
+
fs36.mkdirSync(outDir, { recursive: true });
|
|
33590
33605
|
const resolved = [];
|
|
33591
33606
|
for (const att of nonImageAttachments) {
|
|
33592
33607
|
console.log(`[file] Downloading: ${att.filename} (${att.contentType}, ${att.size}B)`);
|
|
@@ -33594,9 +33609,9 @@ ${pathStr}` }];
|
|
|
33594
33609
|
const resp = attachDispatcher ? await fetch(att.url, { dispatcher: attachDispatcher, signal: AbortSignal.timeout(3e4) }) : await fetch(att.url, { signal: AbortSignal.timeout(3e4) });
|
|
33595
33610
|
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
|
|
33596
33611
|
const buffer = Buffer.from(await resp.arrayBuffer());
|
|
33597
|
-
const safeName2 =
|
|
33598
|
-
const savedPath =
|
|
33599
|
-
|
|
33612
|
+
const safeName2 = path36.basename(att.filename).replace(/[<>:"/\\|?*\x00-\x1f]/g, "_") || "attachment";
|
|
33613
|
+
const savedPath = path36.join(outDir, safeName2);
|
|
33614
|
+
fs36.writeFileSync(savedPath, buffer);
|
|
33600
33615
|
resolved.push(savedPath);
|
|
33601
33616
|
console.log(`[file] Saved: ${savedPath} (${buffer.length}B)`);
|
|
33602
33617
|
} catch (err) {
|
|
@@ -33845,6 +33860,7 @@ ${pathStr}` }];
|
|
|
33845
33860
|
init_live();
|
|
33846
33861
|
|
|
33847
33862
|
// src/provision-free.ts
|
|
33863
|
+
import { randomBytes as randomBytes4, randomUUID as randomUUID6 } from "node:crypto";
|
|
33848
33864
|
import { chmodSync as chmodSync2, existsSync as existsSync24, mkdirSync as mkdirSync16, readFileSync as readFileSync35, writeFileSync as writeFileSync13 } from "node:fs";
|
|
33849
33865
|
import { dirname as dirname11, join as join46 } from "node:path";
|
|
33850
33866
|
import { fileURLToPath as fileURLToPath7 } from "node:url";
|
|
@@ -33853,19 +33869,68 @@ var IDENTITY_FILE = "install-identity.json";
|
|
|
33853
33869
|
function readContactEmailOf(parsed) {
|
|
33854
33870
|
return typeof parsed?.contactEmail === "string" ? parsed.contactEmail.trim() : "";
|
|
33855
33871
|
}
|
|
33856
|
-
function
|
|
33857
|
-
|
|
33858
|
-
|
|
33859
|
-
|
|
33872
|
+
function loadOrCreateInstallIdentity(stateDir) {
|
|
33873
|
+
const file2 = join46(stateDir, IDENTITY_FILE);
|
|
33874
|
+
if (existsSync24(file2)) {
|
|
33875
|
+
let parsed;
|
|
33876
|
+
try {
|
|
33877
|
+
parsed = JSON.parse(readFileSync35(file2, "utf8"));
|
|
33878
|
+
} catch (e) {
|
|
33879
|
+
throw new Error(
|
|
33880
|
+
`${IDENTITY_FILE} \u5B58\u5728\u4F46\u4E0D\u662F\u5408\u6CD5 JSON\uFF08${e.message}\uFF09\u2014\u2014\u5220\u6389\u5B83\u91CD\u8DD1\u4F1A\u9886\u4E00\u628A\u65B0\u4EE4\u724C\uFF0C\u65E7\u7684\u90A3\u628A\u53D6\u4E0D\u56DE\u6765`
|
|
33881
|
+
);
|
|
33882
|
+
}
|
|
33883
|
+
if (typeof parsed?.installId !== "string" || typeof parsed?.installSecret !== "string") {
|
|
33884
|
+
throw new Error(`${IDENTITY_FILE} \u7F3A installId / installSecret \u5B57\u6BB5`);
|
|
33885
|
+
}
|
|
33860
33886
|
const email = readContactEmailOf(parsed);
|
|
33861
33887
|
return {
|
|
33862
33888
|
installId: parsed.installId,
|
|
33863
33889
|
installSecret: parsed.installSecret,
|
|
33864
33890
|
...email ? { contactEmail: email } : {}
|
|
33865
33891
|
};
|
|
33892
|
+
}
|
|
33893
|
+
const identity = {
|
|
33894
|
+
// 服务端校验 installId 长度为 8..36、只允许字母数字和连字符;uuid 正好符合
|
|
33895
|
+
installId: randomUUID6(),
|
|
33896
|
+
// 服务端校验 installSecret 为 32..64 位十六进制
|
|
33897
|
+
installSecret: randomBytes4(32).toString("hex")
|
|
33898
|
+
};
|
|
33899
|
+
mkdirSync16(stateDir, { recursive: true });
|
|
33900
|
+
writeFileSync13(file2, JSON.stringify(identity, null, 2) + "\n", { mode: 384 });
|
|
33901
|
+
try {
|
|
33902
|
+
chmodSync2(file2, 384);
|
|
33866
33903
|
} catch {
|
|
33867
|
-
return null;
|
|
33868
33904
|
}
|
|
33905
|
+
return identity;
|
|
33906
|
+
}
|
|
33907
|
+
function readInstallIdentityDetailed(stateDir) {
|
|
33908
|
+
const file2 = join46(stateDir, IDENTITY_FILE);
|
|
33909
|
+
if (!existsSync24(file2)) return { ok: false, reason: "missing" };
|
|
33910
|
+
let text;
|
|
33911
|
+
try {
|
|
33912
|
+
text = readFileSync35(file2, "utf8");
|
|
33913
|
+
} catch (e) {
|
|
33914
|
+
return { ok: false, reason: "corrupt", detail: `\u5B58\u5728\u4F46\u8BFB\u4E0D\u4E86\uFF08${e?.message ?? e}\uFF09` };
|
|
33915
|
+
}
|
|
33916
|
+
let parsed;
|
|
33917
|
+
try {
|
|
33918
|
+
parsed = JSON.parse(text);
|
|
33919
|
+
} catch (e) {
|
|
33920
|
+
return { ok: false, reason: "corrupt", detail: `\u4E0D\u662F\u5408\u6CD5 JSON\uFF08${e?.message ?? e}\uFF09` };
|
|
33921
|
+
}
|
|
33922
|
+
if (typeof parsed?.installId !== "string" || typeof parsed?.installSecret !== "string") {
|
|
33923
|
+
return { ok: false, reason: "corrupt", detail: "\u7F3A installId / installSecret \u5B57\u6BB5" };
|
|
33924
|
+
}
|
|
33925
|
+
const email = readContactEmailOf(parsed);
|
|
33926
|
+
return {
|
|
33927
|
+
ok: true,
|
|
33928
|
+
identity: {
|
|
33929
|
+
installId: parsed.installId,
|
|
33930
|
+
installSecret: parsed.installSecret,
|
|
33931
|
+
...email ? { contactEmail: email } : {}
|
|
33932
|
+
}
|
|
33933
|
+
};
|
|
33869
33934
|
}
|
|
33870
33935
|
|
|
33871
33936
|
// src/optional/reporting/state.ts
|
|
@@ -34041,13 +34106,23 @@ function startReporting(opts) {
|
|
|
34041
34106
|
const log = opts.log ?? (() => {
|
|
34042
34107
|
});
|
|
34043
34108
|
const startedAt = nowFn3();
|
|
34044
|
-
const
|
|
34045
|
-
|
|
34046
|
-
|
|
34047
|
-
|
|
34048
|
-
|
|
34049
|
-
|
|
34109
|
+
const identityRead = readInstallIdentityDetailed(stateDir);
|
|
34110
|
+
let maybeIdentity = null;
|
|
34111
|
+
if (identityRead.ok) {
|
|
34112
|
+
maybeIdentity = identityRead.identity;
|
|
34113
|
+
} else if (identityRead.reason === "missing") {
|
|
34114
|
+
try {
|
|
34115
|
+
maybeIdentity = loadOrCreateInstallIdentity(stateDir);
|
|
34116
|
+
log("[reporting] \u672C\u673A\u6CA1\u6709\u88C5\u673A\u8EAB\u4EFD\uFF080921 \u524D\u88C5\u7684 / \u4EE4\u724C\u662F\u4ECE\u522B\u5904\u62F7\u6765\u7684\uFF09\u2014\u2014 \u5DF2\u5C31\u5730\u8865\u5EFA\uFF0C\u6B64\u540E\u5F00\u59CB\u4E0A\u62A5");
|
|
34117
|
+
} catch (e) {
|
|
34118
|
+
log(`[reporting] \u8865\u5EFA\u88C5\u673A\u8EAB\u4EFD\u5931\u8D25\uFF1A${e?.message ?? e} \u2014\u2014 \u4E0A\u62A5\u5173\u95ED`);
|
|
34119
|
+
}
|
|
34120
|
+
} else {
|
|
34121
|
+
log(`[reporting] install-identity.json \u635F\u574F\uFF08${identityRead.detail}\uFF09\u2014\u2014 \u4E0A\u62A5\u5173\u95ED\u3002\u523B\u610F\u4E0D\u91CD\u5EFA\uFF1A\u91CD\u5EFA\u7B49\u4E8E\u6362\u4E00\u53F0\u673A\u5668\uFF0C\u65E7\u4EE4\u724C\u518D\u4E5F\u53D6\u4E0D\u56DE\u6765`);
|
|
34050
34122
|
}
|
|
34123
|
+
if (!maybeIdentity) return { stop() {
|
|
34124
|
+
}, async beatNow() {
|
|
34125
|
+
} };
|
|
34051
34126
|
const identity = maybeIdentity;
|
|
34052
34127
|
const bootState = readReportState(stateDir);
|
|
34053
34128
|
restoreCounters(bootState);
|
|
@@ -34272,13 +34347,13 @@ var DiscordAdapter = class _DiscordAdapter {
|
|
|
34272
34347
|
}
|
|
34273
34348
|
/** 发送媒体附件(图片/文件/音频)— discord.js channel.send({ files }) */
|
|
34274
34349
|
async sendFile(target, message, attachment) {
|
|
34275
|
-
const
|
|
34276
|
-
const
|
|
34277
|
-
if (!
|
|
34350
|
+
const fs58 = await import("node:fs");
|
|
34351
|
+
const path60 = await import("node:path");
|
|
34352
|
+
if (!fs58.existsSync(attachment.path)) {
|
|
34278
34353
|
throw new Error(`File not found: ${attachment.path}`);
|
|
34279
34354
|
}
|
|
34280
|
-
const filename = attachment.filename ||
|
|
34281
|
-
const fileBuffer =
|
|
34355
|
+
const filename = attachment.filename || path60.basename(attachment.path);
|
|
34356
|
+
const fileBuffer = fs58.readFileSync(attachment.path);
|
|
34282
34357
|
const filePayload = {
|
|
34283
34358
|
attachment: fileBuffer,
|
|
34284
34359
|
name: filename
|
|
@@ -34727,13 +34802,13 @@ var FeishuAdapter = class _FeishuAdapter {
|
|
|
34727
34802
|
}
|
|
34728
34803
|
/** 发送媒体附件(图片/文件) */
|
|
34729
34804
|
async sendFile(target, message, attachment) {
|
|
34730
|
-
const
|
|
34731
|
-
const
|
|
34732
|
-
if (!
|
|
34805
|
+
const fs58 = await import("node:fs");
|
|
34806
|
+
const path60 = await import("node:path");
|
|
34807
|
+
if (!fs58.existsSync(attachment.path)) {
|
|
34733
34808
|
throw new Error(`File not found: ${attachment.path}`);
|
|
34734
34809
|
}
|
|
34735
|
-
const filename = attachment.filename ||
|
|
34736
|
-
const fileBuffer =
|
|
34810
|
+
const filename = attachment.filename || path60.basename(attachment.path);
|
|
34811
|
+
const fileBuffer = fs58.readFileSync(attachment.path);
|
|
34737
34812
|
const safeTarget = target || this.config.defaultTarget || "";
|
|
34738
34813
|
if (!safeTarget) throw new Error("Feishu sendFile: no target (\u4E3B\u52A8\u53D1\u9001\u9700\u914D\u7F6E defaultTarget \u6216\u4F20\u5165 target)");
|
|
34739
34814
|
const receiveIdType = safeTarget.startsWith("ou_") ? "open_id" : "chat_id";
|
|
@@ -35330,8 +35405,8 @@ var FeishuAdapter = class _FeishuAdapter {
|
|
|
35330
35405
|
|
|
35331
35406
|
// src/channels/wechat.ts
|
|
35332
35407
|
import * as crypto5 from "crypto";
|
|
35333
|
-
import * as
|
|
35334
|
-
import * as
|
|
35408
|
+
import * as fs37 from "fs";
|
|
35409
|
+
import * as path37 from "path";
|
|
35335
35410
|
import * as os4 from "os";
|
|
35336
35411
|
import { promises as dns } from "dns";
|
|
35337
35412
|
function sleep3(ms) {
|
|
@@ -35555,7 +35630,7 @@ function guessChatType(msg2, accountId) {
|
|
|
35555
35630
|
return isGroup ? { type: "group", chatId: roomId || toId || String(msg2.from_user_id || "") } : { type: "dm", chatId: String(msg2.from_user_id || "") };
|
|
35556
35631
|
}
|
|
35557
35632
|
function mimeFromFilename(filename) {
|
|
35558
|
-
const ext =
|
|
35633
|
+
const ext = path37.extname(filename).toLowerCase();
|
|
35559
35634
|
const map = {
|
|
35560
35635
|
".jpg": "image/jpeg",
|
|
35561
35636
|
".jpeg": "image/jpeg",
|
|
@@ -35622,15 +35697,15 @@ var ContextTokenStore = class {
|
|
|
35622
35697
|
cache = /* @__PURE__ */ new Map();
|
|
35623
35698
|
filePath;
|
|
35624
35699
|
constructor(stateDir, accountId) {
|
|
35625
|
-
this.filePath =
|
|
35700
|
+
this.filePath = path37.join(stateDir, "weixin", `${accountId}.context-tokens.json`);
|
|
35626
35701
|
}
|
|
35627
35702
|
k(a, p) {
|
|
35628
35703
|
return `${a}:${p}`;
|
|
35629
35704
|
}
|
|
35630
35705
|
restore() {
|
|
35631
35706
|
try {
|
|
35632
|
-
if (
|
|
35633
|
-
for (const [k, v] of Object.entries(JSON.parse(
|
|
35707
|
+
if (fs37.existsSync(this.filePath)) {
|
|
35708
|
+
for (const [k, v] of Object.entries(JSON.parse(fs37.readFileSync(this.filePath, "utf-8"))))
|
|
35634
35709
|
this.cache.set(k, String(v));
|
|
35635
35710
|
}
|
|
35636
35711
|
} catch {
|
|
@@ -35638,11 +35713,11 @@ var ContextTokenStore = class {
|
|
|
35638
35713
|
}
|
|
35639
35714
|
save() {
|
|
35640
35715
|
try {
|
|
35641
|
-
const dir =
|
|
35642
|
-
if (!
|
|
35716
|
+
const dir = path37.dirname(this.filePath);
|
|
35717
|
+
if (!fs37.existsSync(dir)) fs37.mkdirSync(dir, { recursive: true });
|
|
35643
35718
|
const obj = {};
|
|
35644
35719
|
this.cache.forEach((v, k) => obj[k] = v);
|
|
35645
|
-
|
|
35720
|
+
fs37.writeFileSync(this.filePath, JSON.stringify(obj));
|
|
35646
35721
|
} catch {
|
|
35647
35722
|
}
|
|
35648
35723
|
}
|
|
@@ -35662,18 +35737,18 @@ var ContextTokenStore = class {
|
|
|
35662
35737
|
};
|
|
35663
35738
|
function loadSyncBuf(stateDir, accountId) {
|
|
35664
35739
|
try {
|
|
35665
|
-
const fp =
|
|
35666
|
-
if (
|
|
35740
|
+
const fp = path37.join(stateDir, "weixin", `${accountId}.sync.json`);
|
|
35741
|
+
if (fs37.existsSync(fp)) return String(JSON.parse(fs37.readFileSync(fp, "utf-8")).sync_buf || "");
|
|
35667
35742
|
} catch {
|
|
35668
35743
|
}
|
|
35669
35744
|
return "";
|
|
35670
35745
|
}
|
|
35671
35746
|
function saveSyncBuf(stateDir, accountId, buf) {
|
|
35672
35747
|
try {
|
|
35673
|
-
const fp =
|
|
35674
|
-
const dir =
|
|
35675
|
-
if (!
|
|
35676
|
-
|
|
35748
|
+
const fp = path37.join(stateDir, "weixin", `${accountId}.sync.json`);
|
|
35749
|
+
const dir = path37.dirname(fp);
|
|
35750
|
+
if (!fs37.existsSync(dir)) fs37.mkdirSync(dir, { recursive: true });
|
|
35751
|
+
fs37.writeFileSync(fp, JSON.stringify({ sync_buf: buf }));
|
|
35677
35752
|
} catch {
|
|
35678
35753
|
}
|
|
35679
35754
|
}
|
|
@@ -35715,8 +35790,8 @@ var WechatAdapter = class {
|
|
|
35715
35790
|
this.config = config2;
|
|
35716
35791
|
this.baseUrl = config2.baseUrl?.replace(/\/$/, "") || ILINK_BASE_URL;
|
|
35717
35792
|
this.cdnBaseUrl = config2.cdnBaseUrl?.replace(/\/$/, "") || WEIXIN_CDN_BASE_URL;
|
|
35718
|
-
this.stateDir = config2.stateDir ||
|
|
35719
|
-
if (!
|
|
35793
|
+
this.stateDir = config2.stateDir || path37.join(os4.homedir?.() || "/tmp", ".engine7");
|
|
35794
|
+
if (!fs37.existsSync(this.stateDir)) fs37.mkdirSync(this.stateDir, { recursive: true });
|
|
35720
35795
|
}
|
|
35721
35796
|
// --- ChannelAdapter interface ---
|
|
35722
35797
|
onMessage(handler2) {
|
|
@@ -35769,8 +35844,8 @@ var WechatAdapter = class {
|
|
|
35769
35844
|
}
|
|
35770
35845
|
async sendFile(target, message, attachment) {
|
|
35771
35846
|
const filePath = attachment.path;
|
|
35772
|
-
if (!
|
|
35773
|
-
const plaintext =
|
|
35847
|
+
if (!fs37.existsSync(filePath)) throw new Error(`File not found: ${filePath}`);
|
|
35848
|
+
const plaintext = fs37.readFileSync(filePath);
|
|
35774
35849
|
const mediaType = this.guessMediaType(filePath, attachment.mimeType);
|
|
35775
35850
|
const filekey = crypto5.randomBytes(16).toString("hex");
|
|
35776
35851
|
const aesKey = crypto5.randomBytes(16);
|
|
@@ -35802,7 +35877,7 @@ var WechatAdapter = class {
|
|
|
35802
35877
|
aesKeyForApi,
|
|
35803
35878
|
ciphertextSize: ciphertext.length,
|
|
35804
35879
|
plaintextSize: rawsize,
|
|
35805
|
-
filename:
|
|
35880
|
+
filename: path37.basename(filePath),
|
|
35806
35881
|
rawfilemd5,
|
|
35807
35882
|
voiceDurationSec: attachment.voiceDurationSec
|
|
35808
35883
|
});
|
|
@@ -36061,10 +36136,10 @@ var WechatAdapter = class {
|
|
|
36061
36136
|
mediaRef.full_url,
|
|
36062
36137
|
timeoutSec
|
|
36063
36138
|
);
|
|
36064
|
-
const tmpDir =
|
|
36065
|
-
if (!
|
|
36066
|
-
const tmpPath =
|
|
36067
|
-
|
|
36139
|
+
const tmpDir = path37.join(os4.tmpdir(), "weixin-media");
|
|
36140
|
+
if (!fs37.existsSync(tmpDir)) fs37.mkdirSync(tmpDir, { recursive: true });
|
|
36141
|
+
const tmpPath = path37.join(tmpDir, `${crypto5.randomUUID().replace(/-/g, "")}-${filename}`);
|
|
36142
|
+
fs37.writeFileSync(tmpPath, data);
|
|
36068
36143
|
return { url: `file://${tmpPath}`, filename, contentType, size: data.length };
|
|
36069
36144
|
}
|
|
36070
36145
|
// --- Internal: send helpers ---
|
|
@@ -36114,7 +36189,7 @@ var WechatAdapter = class {
|
|
|
36114
36189
|
throw lastError;
|
|
36115
36190
|
}
|
|
36116
36191
|
guessMediaType(filePath, mimeType) {
|
|
36117
|
-
const ext =
|
|
36192
|
+
const ext = path37.extname(filePath).toLowerCase();
|
|
36118
36193
|
const mime = mimeType || mimeFromFilename(filePath);
|
|
36119
36194
|
if (mime.startsWith("image/")) return MEDIA_IMAGE;
|
|
36120
36195
|
if (mime.startsWith("video/")) return MEDIA_VIDEO;
|
|
@@ -36160,12 +36235,12 @@ init_voice_chat_tts_daemon();
|
|
|
36160
36235
|
import { execFile as execFile2 } from "node:child_process";
|
|
36161
36236
|
import { createInterface as createInterface2 } from "node:readline";
|
|
36162
36237
|
import { promisify as promisify2 } from "node:util";
|
|
36163
|
-
import * as
|
|
36164
|
-
import * as
|
|
36238
|
+
import * as fs39 from "node:fs";
|
|
36239
|
+
import * as path39 from "node:path";
|
|
36165
36240
|
import * as os5 from "node:os";
|
|
36166
36241
|
import net3 from "net";
|
|
36167
36242
|
var execFileAsync2 = promisify2(execFile2);
|
|
36168
|
-
var VOICE_DIR =
|
|
36243
|
+
var VOICE_DIR = path39.join(os5.tmpdir(), "engine-voice");
|
|
36169
36244
|
function wavDurationSec(buf) {
|
|
36170
36245
|
if (buf.length < 12 || buf.toString("ascii", 0, 4) !== "RIFF" || buf.toString("ascii", 8, 12) !== "WAVE") {
|
|
36171
36246
|
throw new Error("wavDurationSec: not a RIFF/WAVE file");
|
|
@@ -36214,17 +36289,17 @@ function resolvePython(configuredPath) {
|
|
|
36214
36289
|
}
|
|
36215
36290
|
if (_pyCache) return _pyCache;
|
|
36216
36291
|
const localAppData = process.env.LOCALAPPDATA;
|
|
36217
|
-
const
|
|
36292
|
+
const candidates2 = [
|
|
36218
36293
|
"python3",
|
|
36219
36294
|
"python",
|
|
36220
36295
|
// LOCALAPPDATA 缺席(非 Windows / 精简环境)时**不加这两个候选**:
|
|
36221
36296
|
// 拼出来会是相对路径 'Microsoft/WindowsApps/python.exe',那可能撞上 cwd 里的东西。
|
|
36222
36297
|
...localAppData ? [
|
|
36223
|
-
|
|
36224
|
-
|
|
36298
|
+
path39.join(localAppData, "Microsoft", "WindowsApps", "python3.exe"),
|
|
36299
|
+
path39.join(localAppData, "Microsoft", "WindowsApps", "python.exe")
|
|
36225
36300
|
] : []
|
|
36226
36301
|
];
|
|
36227
|
-
for (const c of
|
|
36302
|
+
for (const c of candidates2) {
|
|
36228
36303
|
try {
|
|
36229
36304
|
__require("child_process").execFileSync(c, ["-c", "1"], { timeout: 5e3, stdio: "ignore" });
|
|
36230
36305
|
_pyCache = c;
|
|
@@ -36241,8 +36316,8 @@ async function ttsCosyvoice(text, apiKey, model, voice, workspaceId, instruction
|
|
|
36241
36316
|
}
|
|
36242
36317
|
async function ttsCosyvoiceStream(text, cfg, onChunk) {
|
|
36243
36318
|
const { apiKey, model, voice, workspaceId, instruction } = cfg;
|
|
36244
|
-
|
|
36245
|
-
const output =
|
|
36319
|
+
fs39.mkdirSync(VOICE_DIR, { recursive: true });
|
|
36320
|
+
const output = path39.join(VOICE_DIR, `tts_${Date.now()}.wav`);
|
|
36246
36321
|
const script = `
|
|
36247
36322
|
import sys, json, base64, threading
|
|
36248
36323
|
import dashscope
|
|
@@ -36327,7 +36402,7 @@ print('EOS')
|
|
|
36327
36402
|
header.writeUInt16LE(16, 34);
|
|
36328
36403
|
header.write("data", 36);
|
|
36329
36404
|
header.writeUInt32LE(pcm.length, 40);
|
|
36330
|
-
|
|
36405
|
+
fs39.writeFileSync(output, Buffer.concat([header, pcm]));
|
|
36331
36406
|
return output;
|
|
36332
36407
|
}
|
|
36333
36408
|
async function ttsCosyvoiceWorker(text, cfg, onChunk) {
|
|
@@ -36437,9 +36512,9 @@ async function ttsQwen3Opus(text, cfg) {
|
|
|
36437
36512
|
const ogg = Buffer.from(await res.arrayBuffer());
|
|
36438
36513
|
if (ogg.length < 20) throw new Error("qwen3-3060 opus: empty output");
|
|
36439
36514
|
const durationMs = parseInt(res.headers.get("x-duration-ms") || "0", 10);
|
|
36440
|
-
|
|
36441
|
-
const oggPath =
|
|
36442
|
-
|
|
36515
|
+
fs39.mkdirSync(VOICE_DIR, { recursive: true });
|
|
36516
|
+
const oggPath = path39.join(VOICE_DIR, `tts_${Date.now()}.ogg`);
|
|
36517
|
+
fs39.writeFileSync(oggPath, ogg);
|
|
36443
36518
|
return { oggPath, durationMs };
|
|
36444
36519
|
}
|
|
36445
36520
|
async function ttsGptsovits(text, c) {
|
|
@@ -36451,8 +36526,8 @@ async function ttsGptsovits(text, c) {
|
|
|
36451
36526
|
"gptsovits \u672A\u914D\u7F6E\uFF1A\u9700\u8981 tools.my_voice \u91CC\u7684 gptsovitsUrl / gptsovitsRefWav / gptsovitsRefText\u3002\u53C2\u8003\u97F3\u9891\u4E0E\u53C2\u8003\u6587\u672C**\u5FC5\u987B\u9010\u5B57\u5BF9\u5E94**\uFF0C\u5426\u5219\u5408\u6210\u51FA\u6765\u7684\u58F0\u97F3\u4F1A\u5E26\u6742\u97F3\uFF080925 \u8E29\u8FC7\u88C1\u574F ref.wav \u7684\u5751\uFF09\u3002"
|
|
36452
36527
|
);
|
|
36453
36528
|
}
|
|
36454
|
-
|
|
36455
|
-
const output =
|
|
36529
|
+
fs39.mkdirSync(VOICE_DIR, { recursive: true });
|
|
36530
|
+
const output = path39.join(VOICE_DIR, `tts_${Date.now()}.wav`);
|
|
36456
36531
|
const params = new URLSearchParams({
|
|
36457
36532
|
text,
|
|
36458
36533
|
text_language: "zh",
|
|
@@ -36463,13 +36538,13 @@ async function ttsGptsovits(text, c) {
|
|
|
36463
36538
|
const res = await fetch(`${url}/?${params}`);
|
|
36464
36539
|
if (!res.ok) throw new Error(`GPT-SoVITS API ${res.status}`);
|
|
36465
36540
|
const buf = Buffer.from(await res.arrayBuffer());
|
|
36466
|
-
|
|
36541
|
+
fs39.writeFileSync(output, buf);
|
|
36467
36542
|
return output;
|
|
36468
36543
|
}
|
|
36469
36544
|
var EDGE_VOICE = "zh-CN-XiaoxiaoNeural";
|
|
36470
36545
|
async function ttsEdge(text) {
|
|
36471
|
-
|
|
36472
|
-
const output =
|
|
36546
|
+
fs39.mkdirSync(VOICE_DIR, { recursive: true });
|
|
36547
|
+
const output = path39.join(VOICE_DIR, `tts_${Date.now()}.mp3`);
|
|
36473
36548
|
const script = `
|
|
36474
36549
|
import asyncio, edge_tts, sys
|
|
36475
36550
|
async def main():
|
|
@@ -36514,8 +36589,8 @@ async function synthQwen3(text, _sink) {
|
|
|
36514
36589
|
const pcmChunks = [];
|
|
36515
36590
|
await ttsQwen3Local(text, { url: c.url, voice: c.voice, lang: c.lang }, (pcm2) => pcmChunks.push(pcm2));
|
|
36516
36591
|
const pcm = Buffer.concat(pcmChunks);
|
|
36517
|
-
|
|
36518
|
-
const wavPath =
|
|
36592
|
+
fs39.mkdirSync(VOICE_DIR, { recursive: true });
|
|
36593
|
+
const wavPath = path39.join(VOICE_DIR, `tts_${Date.now()}.wav`);
|
|
36519
36594
|
const header = Buffer.alloc(44);
|
|
36520
36595
|
header.write("RIFF", 0);
|
|
36521
36596
|
header.writeUInt32LE(36 + pcm.length, 4);
|
|
@@ -36530,7 +36605,7 @@ async function synthQwen3(text, _sink) {
|
|
|
36530
36605
|
header.writeUInt16LE(16, 34);
|
|
36531
36606
|
header.write("data", 36);
|
|
36532
36607
|
header.writeUInt32LE(pcm.length, 40);
|
|
36533
|
-
|
|
36608
|
+
fs39.writeFileSync(wavPath, Buffer.concat([header, pcm]));
|
|
36534
36609
|
return { path: wavPath, format: "wav", unit: unit(text), voice: c.voice };
|
|
36535
36610
|
}
|
|
36536
36611
|
}
|
|
@@ -36555,22 +36630,22 @@ var DeskBuddyAdapter = class {
|
|
|
36555
36630
|
try {
|
|
36556
36631
|
if (!this.historyFile) {
|
|
36557
36632
|
const os7 = __require("os");
|
|
36558
|
-
const
|
|
36559
|
-
const
|
|
36560
|
-
const dir =
|
|
36561
|
-
|
|
36562
|
-
this.historyFile =
|
|
36563
|
-
this._fs =
|
|
36564
|
-
}
|
|
36565
|
-
const
|
|
36633
|
+
const fs59 = __require("fs");
|
|
36634
|
+
const path60 = __require("path");
|
|
36635
|
+
const dir = path60.join(os7.homedir(), "xiaowen", "workspace", ".desktopBuddy");
|
|
36636
|
+
fs59.mkdirSync(dir, { recursive: true });
|
|
36637
|
+
this.historyFile = path60.join(dir, "history.json");
|
|
36638
|
+
this._fs = fs59;
|
|
36639
|
+
}
|
|
36640
|
+
const fs58 = this._fs;
|
|
36566
36641
|
let arr = [];
|
|
36567
36642
|
try {
|
|
36568
|
-
arr = JSON.parse(
|
|
36643
|
+
arr = JSON.parse(fs58.readFileSync(this.historyFile, "utf-8")) || [];
|
|
36569
36644
|
} catch {
|
|
36570
36645
|
}
|
|
36571
36646
|
arr.push({ ...entry, ts: (/* @__PURE__ */ new Date()).toLocaleString("zh-CN", { hour12: false }) });
|
|
36572
36647
|
if (arr.length > 500) arr = arr.slice(-500);
|
|
36573
|
-
|
|
36648
|
+
fs58.writeFileSync(this.historyFile, JSON.stringify(arr, null, 1));
|
|
36574
36649
|
} catch (e) {
|
|
36575
36650
|
console.warn("[deskBuddy] history write fail", e);
|
|
36576
36651
|
}
|
|
@@ -36851,8 +36926,8 @@ var DeskBuddyAdapter = class {
|
|
|
36851
36926
|
|
|
36852
36927
|
// src/channels/cc-bridge.ts
|
|
36853
36928
|
init_live();
|
|
36854
|
-
import
|
|
36855
|
-
import
|
|
36929
|
+
import fs40 from "node:fs";
|
|
36930
|
+
import path40 from "node:path";
|
|
36856
36931
|
import { WebSocketServer as WebSocketServer2, WebSocket as WebSocket2 } from "ws";
|
|
36857
36932
|
var DEFAULT_PORT = 16996;
|
|
36858
36933
|
var CcBridgeAdapter = class {
|
|
@@ -36883,7 +36958,7 @@ var CcBridgeAdapter = class {
|
|
|
36883
36958
|
// 只会在热加载后变成指向旧目录的幽灵路径(配置访问铁律)。
|
|
36884
36959
|
outboxFile() {
|
|
36885
36960
|
const sd = liveConfig.get("stateDir") || process.cwd();
|
|
36886
|
-
return
|
|
36961
|
+
return path40.join(sd, "state", "cc-bridge", "outbox.jsonl");
|
|
36887
36962
|
}
|
|
36888
36963
|
/**
|
|
36889
36964
|
* 读队列。**只有 ENOENT 才等于"空队列"。**
|
|
@@ -36897,7 +36972,7 @@ var CcBridgeAdapter = class {
|
|
|
36897
36972
|
readOutbox() {
|
|
36898
36973
|
let raw;
|
|
36899
36974
|
try {
|
|
36900
|
-
raw =
|
|
36975
|
+
raw = fs40.readFileSync(this.outboxFile(), "utf8");
|
|
36901
36976
|
} catch (e) {
|
|
36902
36977
|
if (e?.code === "ENOENT") return [];
|
|
36903
36978
|
throw e;
|
|
@@ -36927,9 +37002,9 @@ var CcBridgeAdapter = class {
|
|
|
36927
37002
|
writeOutbox(items) {
|
|
36928
37003
|
const file2 = this.outboxFile();
|
|
36929
37004
|
const tmp = `${file2}.tmp`;
|
|
36930
|
-
|
|
36931
|
-
|
|
36932
|
-
|
|
37005
|
+
fs40.mkdirSync(path40.dirname(file2), { recursive: true });
|
|
37006
|
+
fs40.writeFileSync(tmp, items.map((i) => JSON.stringify(i)).join("\n") + (items.length ? "\n" : ""), "utf8");
|
|
37007
|
+
fs40.renameSync(tmp, file2);
|
|
36933
37008
|
}
|
|
36934
37009
|
/** 入队(dedupe 不做 —— id 是新的,重复投递由 ack 收敛)。读/写失败都往外抛,不吞。 */
|
|
36935
37010
|
enqueue(item) {
|
|
@@ -37007,7 +37082,7 @@ var CcBridgeAdapter = class {
|
|
|
37007
37082
|
async connect() {
|
|
37008
37083
|
const port = this.config.port ?? DEFAULT_PORT;
|
|
37009
37084
|
try {
|
|
37010
|
-
|
|
37085
|
+
fs40.mkdirSync(path40.dirname(this.outboxFile()), { recursive: true });
|
|
37011
37086
|
} catch {
|
|
37012
37087
|
}
|
|
37013
37088
|
this.wss = new WebSocketServer2({
|
|
@@ -37180,14 +37255,14 @@ var CcBridgeAdapter = class {
|
|
|
37180
37255
|
async sendFile(_target, message, attachment) {
|
|
37181
37256
|
let st;
|
|
37182
37257
|
try {
|
|
37183
|
-
st =
|
|
37258
|
+
st = fs40.statSync(attachment.path);
|
|
37184
37259
|
} catch (e) {
|
|
37185
37260
|
throw new Error(`\u9644\u4EF6\u4E0D\u5B58\u5728\uFF0C\u672A\u53D1\u9001\uFF1A${attachment.path}\uFF08${e?.code || e?.message}\uFF09`);
|
|
37186
37261
|
}
|
|
37187
37262
|
const file2 = {
|
|
37188
37263
|
mode: "path-ref",
|
|
37189
37264
|
path: attachment.path,
|
|
37190
|
-
filename: attachment.filename ||
|
|
37265
|
+
filename: attachment.filename || path40.basename(attachment.path),
|
|
37191
37266
|
mimeType: attachment.mimeType || "application/octet-stream",
|
|
37192
37267
|
size: st.size,
|
|
37193
37268
|
mtimeMs: Math.round(st.mtimeMs)
|
|
@@ -37543,20 +37618,20 @@ var ChannelManager = class {
|
|
|
37543
37618
|
// src/session/session-manager.ts
|
|
37544
37619
|
init_types();
|
|
37545
37620
|
init_types();
|
|
37546
|
-
import * as
|
|
37547
|
-
import * as
|
|
37621
|
+
import * as path42 from "node:path";
|
|
37622
|
+
import * as fs42 from "node:fs";
|
|
37548
37623
|
import * as crypto6 from "node:crypto";
|
|
37549
37624
|
|
|
37550
37625
|
// src/session/reader.ts
|
|
37551
37626
|
init_attachments();
|
|
37552
|
-
import * as
|
|
37553
|
-
import * as
|
|
37627
|
+
import * as fs41 from "node:fs";
|
|
37628
|
+
import * as path41 from "node:path";
|
|
37554
37629
|
import * as readline2 from "node:readline";
|
|
37555
37630
|
var SKIP_PRECOMPACT_THRESHOLD = 5 * 1024 * 1024;
|
|
37556
37631
|
var TRANSCRIPT_READ_CHUNK_SIZE = 1024 * 1024;
|
|
37557
37632
|
var MAX_TRANSCRIPT_READ_BYTES = 50 * 1024 * 1024;
|
|
37558
37633
|
async function readSessionHeader(filePath) {
|
|
37559
|
-
const stream =
|
|
37634
|
+
const stream = fs41.createReadStream(filePath, { encoding: "utf-8" });
|
|
37560
37635
|
const rl = readline2.createInterface({ input: stream });
|
|
37561
37636
|
return new Promise((resolve12) => {
|
|
37562
37637
|
let resolved = false;
|
|
@@ -37587,7 +37662,7 @@ async function readSessionHeader(filePath) {
|
|
|
37587
37662
|
});
|
|
37588
37663
|
}
|
|
37589
37664
|
async function readLargeFilePostBoundary(filePath) {
|
|
37590
|
-
const stat4 =
|
|
37665
|
+
const stat4 = fs41.statSync(filePath);
|
|
37591
37666
|
const fileSize = stat4.size;
|
|
37592
37667
|
const boundaryMarker = '"compact_boundary"';
|
|
37593
37668
|
const CHUNK_SIZE = TRANSCRIPT_READ_CHUNK_SIZE;
|
|
@@ -37595,13 +37670,13 @@ async function readLargeFilePostBoundary(filePath) {
|
|
|
37595
37670
|
let outLen = 0;
|
|
37596
37671
|
let boundaryStartOffset = 0;
|
|
37597
37672
|
const chunk = Buffer.allocUnsafe(CHUNK_SIZE);
|
|
37598
|
-
const fd =
|
|
37673
|
+
const fd = fs41.openSync(filePath, "r");
|
|
37599
37674
|
try {
|
|
37600
37675
|
let filePos = 0;
|
|
37601
37676
|
let carryBuf;
|
|
37602
37677
|
let carryLen = 0;
|
|
37603
37678
|
while (filePos < fileSize) {
|
|
37604
|
-
const bytesRead =
|
|
37679
|
+
const bytesRead = fs41.readSync(fd, chunk, 0, Math.min(CHUNK_SIZE, fileSize - filePos), filePos);
|
|
37605
37680
|
if (bytesRead === 0) break;
|
|
37606
37681
|
filePos += bytesRead;
|
|
37607
37682
|
let scanBuf;
|
|
@@ -37653,7 +37728,7 @@ async function readLargeFilePostBoundary(filePath) {
|
|
|
37653
37728
|
}
|
|
37654
37729
|
}
|
|
37655
37730
|
} finally {
|
|
37656
|
-
|
|
37731
|
+
fs41.closeSync(fd);
|
|
37657
37732
|
}
|
|
37658
37733
|
const postBoundaryText = outBuf.subarray(0, outLen).toString("utf-8");
|
|
37659
37734
|
return postBoundaryText.split("\n").filter((l) => l.trim().length > 0);
|
|
@@ -37777,7 +37852,7 @@ function recoverOrphanedParallelToolResults(allEntries, chain, byUuid, seen) {
|
|
|
37777
37852
|
return result;
|
|
37778
37853
|
}
|
|
37779
37854
|
async function readSessionHistory(filePath) {
|
|
37780
|
-
const stat4 =
|
|
37855
|
+
const stat4 = fs41.statSync(filePath);
|
|
37781
37856
|
const fileSize = stat4.size;
|
|
37782
37857
|
if (fileSize > MAX_TRANSCRIPT_READ_BYTES) {
|
|
37783
37858
|
console.warn(`[reader] Session file exceeds 50MB limit (${(fileSize / 1024 / 1024).toFixed(1)}MB), using chunked fd read with boundary skip`);
|
|
@@ -37816,7 +37891,7 @@ async function readSessionHistory(filePath) {
|
|
|
37816
37891
|
return [...sessionStarts, ...filtered, ...restAttachments];
|
|
37817
37892
|
}
|
|
37818
37893
|
async function readAllLines(filePath) {
|
|
37819
|
-
const stream =
|
|
37894
|
+
const stream = fs41.createReadStream(filePath, { encoding: "utf-8" });
|
|
37820
37895
|
const rl = readline2.createInterface({ input: stream });
|
|
37821
37896
|
const lines = [];
|
|
37822
37897
|
return new Promise((resolve12, reject) => {
|
|
@@ -37970,12 +38045,12 @@ function extractText4(content) {
|
|
|
37970
38045
|
return content.filter((b) => b.type === "text").map((b) => b.text || "").join("") || null;
|
|
37971
38046
|
}
|
|
37972
38047
|
function listSessions(sessionsDir) {
|
|
37973
|
-
if (!
|
|
37974
|
-
const files =
|
|
37975
|
-
file:
|
|
38048
|
+
if (!fs41.existsSync(sessionsDir)) return [];
|
|
38049
|
+
const files = fs41.readdirSync(sessionsDir).filter((f) => f.endsWith(".jsonl") || f.includes(".jsonl.")).map((f) => ({
|
|
38050
|
+
file: path41.join(sessionsDir, f),
|
|
37976
38051
|
id: f.replace(/\.jsonl.*$/, ""),
|
|
37977
38052
|
// strip .jsonl and everything after (archived suffix)
|
|
37978
|
-
modified: new Date(
|
|
38053
|
+
modified: new Date(fs41.statSync(path41.join(sessionsDir, f)).mtimeMs)
|
|
37979
38054
|
})).sort((a, b) => b.modified.getTime() - a.modified.getTime());
|
|
37980
38055
|
return files;
|
|
37981
38056
|
}
|
|
@@ -38010,24 +38085,24 @@ var SessionManager = class {
|
|
|
38010
38085
|
constructor(config2) {
|
|
38011
38086
|
this.config = config2;
|
|
38012
38087
|
this.scopeConfig = config2.scopeConfig;
|
|
38013
|
-
this.sessionsDir =
|
|
38014
|
-
this.indexPath =
|
|
38015
|
-
this.platformMapPath =
|
|
38016
|
-
|
|
38088
|
+
this.sessionsDir = path42.join(config2.stateDir, "agents", "main", "sessions");
|
|
38089
|
+
this.indexPath = path42.join(this.sessionsDir, "session-index.json");
|
|
38090
|
+
this.platformMapPath = path42.join(this.sessionsDir, "platform-map.json");
|
|
38091
|
+
fs42.mkdirSync(this.sessionsDir, { recursive: true });
|
|
38017
38092
|
}
|
|
38018
38093
|
// === 索引操作 ===
|
|
38019
38094
|
loadIndex() {
|
|
38020
38095
|
try {
|
|
38021
|
-
if (
|
|
38022
|
-
const raw =
|
|
38096
|
+
if (fs42.existsSync(this.indexPath)) {
|
|
38097
|
+
const raw = fs42.readFileSync(this.indexPath, "utf-8");
|
|
38023
38098
|
const obj = JSON.parse(raw);
|
|
38024
38099
|
this.index = new Map(Object.entries(obj));
|
|
38025
38100
|
let fixed = 0;
|
|
38026
38101
|
for (const [key, entry] of this.index) {
|
|
38027
|
-
if (
|
|
38028
|
-
const basename10 =
|
|
38029
|
-
const localPath =
|
|
38030
|
-
if (
|
|
38102
|
+
if (fs42.existsSync(entry.file)) continue;
|
|
38103
|
+
const basename10 = path42.basename(entry.file);
|
|
38104
|
+
const localPath = path42.join(this.sessionsDir, basename10);
|
|
38105
|
+
if (fs42.existsSync(localPath)) {
|
|
38031
38106
|
entry.file = localPath;
|
|
38032
38107
|
fixed++;
|
|
38033
38108
|
}
|
|
@@ -38046,7 +38121,7 @@ var SessionManager = class {
|
|
|
38046
38121
|
try {
|
|
38047
38122
|
const obj = {};
|
|
38048
38123
|
for (const [k, v] of this.index) obj[k] = v;
|
|
38049
|
-
|
|
38124
|
+
fs42.writeFileSync(this.indexPath, JSON.stringify(obj, null, 2));
|
|
38050
38125
|
} catch (err) {
|
|
38051
38126
|
console.error(`[session] Failed to save index: ${err.message}`);
|
|
38052
38127
|
}
|
|
@@ -38054,8 +38129,8 @@ var SessionManager = class {
|
|
|
38054
38129
|
// === 平台映射 ===
|
|
38055
38130
|
loadPlatformMap() {
|
|
38056
38131
|
try {
|
|
38057
|
-
if (
|
|
38058
|
-
const raw =
|
|
38132
|
+
if (fs42.existsSync(this.platformMapPath)) {
|
|
38133
|
+
const raw = fs42.readFileSync(this.platformMapPath, "utf-8");
|
|
38059
38134
|
const obj = JSON.parse(raw);
|
|
38060
38135
|
this.platformMap = new Map(Object.entries(obj));
|
|
38061
38136
|
console.log(`[session] Platform map loaded: ${this.platformMap.size} entries`);
|
|
@@ -38067,7 +38142,7 @@ var SessionManager = class {
|
|
|
38067
38142
|
try {
|
|
38068
38143
|
const obj = {};
|
|
38069
38144
|
for (const [k, v] of this.platformMap) obj[k] = v;
|
|
38070
|
-
|
|
38145
|
+
fs42.writeFileSync(this.platformMapPath, JSON.stringify(obj, null, 2));
|
|
38071
38146
|
} catch (err) {
|
|
38072
38147
|
console.error(`[session] Failed to save platform map: ${err.message}`);
|
|
38073
38148
|
}
|
|
@@ -38106,17 +38181,17 @@ var SessionManager = class {
|
|
|
38106
38181
|
*/
|
|
38107
38182
|
getSessionFilePath(sessionId) {
|
|
38108
38183
|
const entry = this.index.get(sessionId);
|
|
38109
|
-
if (entry &&
|
|
38110
|
-
const direct =
|
|
38111
|
-
return
|
|
38184
|
+
if (entry && fs42.existsSync(entry.file)) return entry.file;
|
|
38185
|
+
const direct = path42.join(this.sessionsDir, `${sessionId}.jsonl`);
|
|
38186
|
+
return fs42.existsSync(direct) ? direct : null;
|
|
38112
38187
|
}
|
|
38113
38188
|
// === Writer 管理 ===
|
|
38114
38189
|
getWriter(sessionId) {
|
|
38115
38190
|
let writer = this.writers.get(sessionId);
|
|
38116
38191
|
if (!writer) {
|
|
38117
38192
|
const existing = this.index.get(sessionId);
|
|
38118
|
-
if (existing &&
|
|
38119
|
-
const existingFileId =
|
|
38193
|
+
if (existing && fs42.existsSync(existing.file)) {
|
|
38194
|
+
const existingFileId = path42.basename(existing.file, ".jsonl");
|
|
38120
38195
|
writer = new SessionWriter(this.sessionsDir, existingFileId);
|
|
38121
38196
|
writer.open(this.config.workspace, sessionId);
|
|
38122
38197
|
} else {
|
|
@@ -38128,7 +38203,7 @@ var SessionManager = class {
|
|
|
38128
38203
|
this.saveIndex();
|
|
38129
38204
|
this.writers.set(sessionId, writer);
|
|
38130
38205
|
this.onWriterCreated?.(writer, sessionId);
|
|
38131
|
-
console.log(`[session] ${existing ? "Resumed" : "New"}: ${sessionId} \u2192 ${
|
|
38206
|
+
console.log(`[session] ${existing ? "Resumed" : "New"}: ${sessionId} \u2192 ${path42.basename(writer.path)}`);
|
|
38132
38207
|
}
|
|
38133
38208
|
return writer;
|
|
38134
38209
|
}
|
|
@@ -38147,7 +38222,7 @@ var SessionManager = class {
|
|
|
38147
38222
|
if (!writer) return null;
|
|
38148
38223
|
try {
|
|
38149
38224
|
this.lastArchiveCheck = Date.now();
|
|
38150
|
-
const stat4 =
|
|
38225
|
+
const stat4 = fs42.statSync(writer.path);
|
|
38151
38226
|
if (stat4.size < threshold) return null;
|
|
38152
38227
|
const sizeMB = (stat4.size / 1024 / 1024).toFixed(1);
|
|
38153
38228
|
const thresholdMB = (threshold / 1024 / 1024).toFixed(1);
|
|
@@ -38156,10 +38231,10 @@ var SessionManager = class {
|
|
|
38156
38231
|
if (archivedPath) {
|
|
38157
38232
|
this.index.set(sessionId, { file: writer.path, updatedAt: Date.now() });
|
|
38158
38233
|
this.saveIndex();
|
|
38159
|
-
const newSize =
|
|
38234
|
+
const newSize = fs42.statSync(writer.path).size;
|
|
38160
38235
|
const oldSizeMB = (stat4.size / 1024 / 1024).toFixed(1);
|
|
38161
|
-
console.log(`[session] Archive complete: ${
|
|
38162
|
-
const fileId =
|
|
38236
|
+
console.log(`[session] Archive complete: ${path42.basename(archivedPath)} (${oldSizeMB}MB) \u2192 new JSONL created (${newSize} bytes)`);
|
|
38237
|
+
const fileId = path42.basename(writer.path).replace(/\.jsonl$/, "");
|
|
38163
38238
|
this.purgeOldArchives(fileId, 3);
|
|
38164
38239
|
return archivedPath;
|
|
38165
38240
|
}
|
|
@@ -38175,15 +38250,15 @@ var SessionManager = class {
|
|
|
38175
38250
|
purgeOldArchives(sessionId, keepCount = 3) {
|
|
38176
38251
|
try {
|
|
38177
38252
|
const dir = this.sessionsDir;
|
|
38178
|
-
if (!
|
|
38179
|
-
const allFiles =
|
|
38253
|
+
if (!fs42.existsSync(dir)) return;
|
|
38254
|
+
const allFiles = fs42.readdirSync(dir);
|
|
38180
38255
|
const archiveFiles = allFiles.filter((f) => {
|
|
38181
38256
|
if (!f.startsWith(sessionId)) return false;
|
|
38182
38257
|
return f.includes(".archived.") || f.includes(".compaction.");
|
|
38183
38258
|
}).map((f) => ({
|
|
38184
38259
|
name: f,
|
|
38185
|
-
path:
|
|
38186
|
-
mtime:
|
|
38260
|
+
path: path42.join(dir, f),
|
|
38261
|
+
mtime: fs42.statSync(path42.join(dir, f)).mtimeMs
|
|
38187
38262
|
})).sort((a, b) => b.mtime - a.mtime);
|
|
38188
38263
|
console.log(`[session] purgeOldArchives: sessionId=${sessionId.substring(0, 8)}... found=${archiveFiles.length} keep=${keepCount}`);
|
|
38189
38264
|
if (archiveFiles.length <= keepCount) return;
|
|
@@ -38193,7 +38268,7 @@ var SessionManager = class {
|
|
|
38193
38268
|
console.log(`[session] Skipping archived (kept for history): ${f.name}`);
|
|
38194
38269
|
continue;
|
|
38195
38270
|
}
|
|
38196
|
-
|
|
38271
|
+
fs42.unlinkSync(f.path);
|
|
38197
38272
|
console.log(`[session] Purged old archive: ${f.name}`);
|
|
38198
38273
|
}
|
|
38199
38274
|
if (toDelete.length > 0) {
|
|
@@ -38242,29 +38317,29 @@ var SessionManager = class {
|
|
|
38242
38317
|
/** 列出 session 的所有文件(当前 + 归档),按修改时间排序 */
|
|
38243
38318
|
findAllSessionFiles(sessionId) {
|
|
38244
38319
|
const results = [];
|
|
38245
|
-
const mainFile =
|
|
38246
|
-
if (
|
|
38320
|
+
const mainFile = path42.join(this.sessionsDir, `${sessionId}.jsonl`);
|
|
38321
|
+
if (fs42.existsSync(mainFile)) {
|
|
38247
38322
|
results.push(mainFile);
|
|
38248
38323
|
}
|
|
38249
|
-
if (
|
|
38250
|
-
const compactionFiles =
|
|
38324
|
+
if (fs42.existsSync(this.sessionsDir)) {
|
|
38325
|
+
const compactionFiles = fs42.readdirSync(this.sessionsDir).filter((f) => f.startsWith(`${sessionId}.jsonl.compaction.`)).map((f) => ({
|
|
38251
38326
|
name: f,
|
|
38252
|
-
path:
|
|
38253
|
-
mtime:
|
|
38327
|
+
path: path42.join(this.sessionsDir, f),
|
|
38328
|
+
mtime: fs42.statSync(path42.join(this.sessionsDir, f)).mtimeMs
|
|
38254
38329
|
})).sort((a, b) => b.mtime - a.mtime);
|
|
38255
38330
|
if (compactionFiles.length > 0) {
|
|
38256
38331
|
results.push(compactionFiles[0].path);
|
|
38257
38332
|
}
|
|
38258
38333
|
}
|
|
38259
38334
|
results.sort((a, b) => {
|
|
38260
|
-
const ta =
|
|
38261
|
-
const tb =
|
|
38335
|
+
const ta = fs42.statSync(a).mtimeMs;
|
|
38336
|
+
const tb = fs42.statSync(b).mtimeMs;
|
|
38262
38337
|
return ta - tb;
|
|
38263
38338
|
});
|
|
38264
38339
|
return results;
|
|
38265
38340
|
}
|
|
38266
38341
|
async findSessionFiles(sessionId) {
|
|
38267
|
-
if (!
|
|
38342
|
+
if (!fs42.existsSync(this.sessionsDir)) {
|
|
38268
38343
|
console.log(`[session:find] SESSIONS_DIR not found: ${this.sessionsDir}`);
|
|
38269
38344
|
return [];
|
|
38270
38345
|
}
|
|
@@ -38276,15 +38351,15 @@ var SessionManager = class {
|
|
|
38276
38351
|
return mappedFiles;
|
|
38277
38352
|
}
|
|
38278
38353
|
const indexedEntry = this.index.get(mappedId);
|
|
38279
|
-
if (indexedEntry &&
|
|
38280
|
-
const fileUuid =
|
|
38354
|
+
if (indexedEntry && fs42.existsSync(indexedEntry.file)) {
|
|
38355
|
+
const fileUuid = path42.basename(indexedEntry.file, ".jsonl");
|
|
38281
38356
|
return this.findAllSessionFiles(fileUuid);
|
|
38282
38357
|
}
|
|
38283
38358
|
}
|
|
38284
38359
|
const allFiles = this.findAllSessionFiles(sessionId);
|
|
38285
38360
|
if (allFiles.length > 0) {
|
|
38286
38361
|
const labels = allFiles.map((f) => {
|
|
38287
|
-
const base =
|
|
38362
|
+
const base = path42.basename(f);
|
|
38288
38363
|
return base.endsWith(".jsonl") ? base : `${base} (archived)`;
|
|
38289
38364
|
});
|
|
38290
38365
|
console.log(`[session:find] Found ${allFiles.length} file(s) for ${sessionId}: ${labels.join(", ")}`);
|
|
@@ -38292,9 +38367,9 @@ var SessionManager = class {
|
|
|
38292
38367
|
}
|
|
38293
38368
|
const indexed = this.index.get(sessionId);
|
|
38294
38369
|
if (indexed) {
|
|
38295
|
-
console.log(`[session:find] Index hit: ${sessionId} \u2192 ${indexed.file} (exists=${
|
|
38296
|
-
if (
|
|
38297
|
-
return this.findAllSessionFiles(
|
|
38370
|
+
console.log(`[session:find] Index hit: ${sessionId} \u2192 ${indexed.file} (exists=${fs42.existsSync(indexed.file)})`);
|
|
38371
|
+
if (fs42.existsSync(indexed.file)) {
|
|
38372
|
+
return this.findAllSessionFiles(path42.basename(indexed.file, ".jsonl"));
|
|
38298
38373
|
}
|
|
38299
38374
|
} else {
|
|
38300
38375
|
console.log(`[session:find] Index miss: ${sessionId} (index has ${this.index.size} entries)`);
|
|
@@ -38323,8 +38398,8 @@ var SessionManager = class {
|
|
|
38323
38398
|
return [];
|
|
38324
38399
|
}
|
|
38325
38400
|
files.sort((a, b) => {
|
|
38326
|
-
const ta =
|
|
38327
|
-
const tb =
|
|
38401
|
+
const ta = fs42.statSync(a).mtimeMs;
|
|
38402
|
+
const tb = fs42.statSync(b).mtimeMs;
|
|
38328
38403
|
return ta - tb;
|
|
38329
38404
|
});
|
|
38330
38405
|
const latestFile = files[files.length - 1];
|
|
@@ -38332,7 +38407,7 @@ var SessionManager = class {
|
|
|
38332
38407
|
if (!currentEntry || currentEntry.file !== latestFile) {
|
|
38333
38408
|
this.index.set(sessionId, { file: latestFile, updatedAt: Date.now() });
|
|
38334
38409
|
this.saveIndex();
|
|
38335
|
-
console.log(`[session:restore] Synced index: ${sessionId} \u2192 ${
|
|
38410
|
+
console.log(`[session:restore] Synced index: ${sessionId} \u2192 ${path42.basename(latestFile)}`);
|
|
38336
38411
|
}
|
|
38337
38412
|
const allMessages = [];
|
|
38338
38413
|
for (const file2 of files) {
|
|
@@ -38371,7 +38446,7 @@ var SessionManager = class {
|
|
|
38371
38446
|
if (isAttachmentMessage(m) && m.attachment.type === "relevant_memories") {
|
|
38372
38447
|
for (const mem of m.attachment.memories) {
|
|
38373
38448
|
rawCount++;
|
|
38374
|
-
restoredPaths.add(
|
|
38449
|
+
restoredPaths.add(path42.resolve(mem.path));
|
|
38375
38450
|
}
|
|
38376
38451
|
}
|
|
38377
38452
|
}
|
|
@@ -38403,15 +38478,15 @@ var SessionManager = class {
|
|
|
38403
38478
|
*/
|
|
38404
38479
|
rotateMainSession() {
|
|
38405
38480
|
const entry = this.index.get("main");
|
|
38406
|
-
if (!entry || !
|
|
38407
|
-
const oldFileId =
|
|
38408
|
-
const stat4 =
|
|
38481
|
+
if (!entry || !fs42.existsSync(entry.file)) return;
|
|
38482
|
+
const oldFileId = path42.basename(entry.file, ".jsonl");
|
|
38483
|
+
const stat4 = fs42.statSync(entry.file);
|
|
38409
38484
|
if (stat4.size < 1024) return;
|
|
38410
38485
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/:/g, "-");
|
|
38411
38486
|
const archivedPath = `${entry.file}.archived.${ts}`;
|
|
38412
|
-
|
|
38487
|
+
fs42.renameSync(entry.file, archivedPath);
|
|
38413
38488
|
const sizeMB = (stat4.size / 1024 / 1024).toFixed(1);
|
|
38414
|
-
console.log(`[session] Archived: ${
|
|
38489
|
+
console.log(`[session] Archived: ${path42.basename(entry.file)} \u2192 ${path42.basename(archivedPath)} (${sizeMB}MB)`);
|
|
38415
38490
|
const newWriter = new SessionWriter(this.sessionsDir);
|
|
38416
38491
|
newWriter.open(this.config.workspace, "main");
|
|
38417
38492
|
newWriter.writeModelChange(this.config.providerId, this.config.model);
|
|
@@ -38420,7 +38495,7 @@ var SessionManager = class {
|
|
|
38420
38495
|
this.index.set("main", { file: newPath, updatedAt: Date.now() });
|
|
38421
38496
|
this.saveIndex();
|
|
38422
38497
|
this.purgeOldArchives(oldFileId, 3);
|
|
38423
|
-
console.log(`[session] Rotated main: ${oldFileId}.jsonl \u2192 ${
|
|
38498
|
+
console.log(`[session] Rotated main: ${oldFileId}.jsonl \u2192 ${path42.basename(newPath)}`);
|
|
38424
38499
|
}
|
|
38425
38500
|
// === 迁移 ===
|
|
38426
38501
|
/** 迁移旧索引:session-index.json 里有 "discord:xxx" 格式的 key 时,生成 UUID 替换 */
|
|
@@ -39312,12 +39387,12 @@ Examples:
|
|
|
39312
39387
|
// src/tools/msg-husband.ts
|
|
39313
39388
|
init_registry();
|
|
39314
39389
|
init_live();
|
|
39315
|
-
import
|
|
39316
|
-
import
|
|
39390
|
+
import fs43 from "node:fs";
|
|
39391
|
+
import path43 from "node:path";
|
|
39317
39392
|
function getHusbandFeishuId(workspace) {
|
|
39318
|
-
const contactsPath =
|
|
39393
|
+
const contactsPath = path43.join(workspace, "prompts", "contacts.md");
|
|
39319
39394
|
try {
|
|
39320
|
-
const text =
|
|
39395
|
+
const text = fs43.readFileSync(contactsPath, "utf-8");
|
|
39321
39396
|
const m = text.match(/\|\s*翀哥\s*\|\s*(ou_[a-f0-9]+)\s*\|/);
|
|
39322
39397
|
return m ? m[1] : null;
|
|
39323
39398
|
} catch {
|
|
@@ -39459,8 +39534,8 @@ Examples:
|
|
|
39459
39534
|
if (!to && !resolvedChannelId) {
|
|
39460
39535
|
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 };
|
|
39461
39536
|
}
|
|
39462
|
-
const
|
|
39463
|
-
if (!
|
|
39537
|
+
const fs58 = await import("node:fs");
|
|
39538
|
+
if (!fs58.existsSync(filePath)) {
|
|
39464
39539
|
return { content: `\u53D1\u9001\u5931\u8D25: \u6587\u4EF6\u4E0D\u5B58\u5728 ${filePath}`, isError: true };
|
|
39465
39540
|
}
|
|
39466
39541
|
const toIds = to ? to.split(",").map((s) => s.trim()).filter(Boolean) : [];
|
|
@@ -39488,7 +39563,7 @@ Examples:
|
|
|
39488
39563
|
md: "text/markdown"
|
|
39489
39564
|
};
|
|
39490
39565
|
const mimeType = mimeTypeMap[ext] || "application/octet-stream";
|
|
39491
|
-
const stat4 =
|
|
39566
|
+
const stat4 = fs58.statSync(filePath);
|
|
39492
39567
|
const sizeMB = stat4.size / 1024 / 1024;
|
|
39493
39568
|
if (sizeMB > 25) {
|
|
39494
39569
|
return { content: `\u53D1\u9001\u5931\u8D25: \u6587\u4EF6 ${sizeMB.toFixed(1)}MB \u8D85\u8FC7 Discord 25MB \u9650\u5236`, isError: true };
|
|
@@ -39518,8 +39593,8 @@ Examples:
|
|
|
39518
39593
|
init_live();
|
|
39519
39594
|
init_registry();
|
|
39520
39595
|
init_well_formed();
|
|
39521
|
-
import * as
|
|
39522
|
-
import * as
|
|
39596
|
+
import * as fs44 from "node:fs";
|
|
39597
|
+
import * as path44 from "node:path";
|
|
39523
39598
|
var MIME_MAP = {
|
|
39524
39599
|
".jpg": "jpeg",
|
|
39525
39600
|
".jpeg": "jpeg",
|
|
@@ -39531,9 +39606,9 @@ var MIME_MAP = {
|
|
|
39531
39606
|
var VIDEO_EXT = /\.(mp4|mov)$/i;
|
|
39532
39607
|
var VIDEO_MAX_BYTES = 40 * 1024 * 1024;
|
|
39533
39608
|
function resolveLatestImage(specifiedPath, mediaDir) {
|
|
39534
|
-
if (specifiedPath &&
|
|
39535
|
-
if (!
|
|
39536
|
-
const files =
|
|
39609
|
+
if (specifiedPath && fs44.existsSync(specifiedPath)) return specifiedPath;
|
|
39610
|
+
if (!fs44.existsSync(mediaDir)) return null;
|
|
39611
|
+
const files = fs44.readdirSync(mediaDir).filter((f) => /\.(jpg|jpeg|png|webp|gif|bmp|mp4|mov)$/i.test(f)).map((f) => ({ name: f, p: path44.join(mediaDir, f), mtime: fs44.statSync(path44.join(mediaDir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
|
|
39537
39612
|
return files[0]?.p || null;
|
|
39538
39613
|
}
|
|
39539
39614
|
registry.register({
|
|
@@ -39564,21 +39639,21 @@ registry.register({
|
|
|
39564
39639
|
if (!provider?.streamChat) {
|
|
39565
39640
|
return { content: "Error: provider \u4E0D\u53EF\u7528\u3002", isError: true };
|
|
39566
39641
|
}
|
|
39567
|
-
const mediaDir =
|
|
39642
|
+
const mediaDir = path44.join(ctx.stateDir, "media", "inbound");
|
|
39568
39643
|
const imagePath = resolveLatestImage(args2.image_path, mediaDir);
|
|
39569
39644
|
if (!imagePath) {
|
|
39570
39645
|
return { content: "Error: no image found. Provide image_path or ensure media/inbound has images.", isError: true };
|
|
39571
39646
|
}
|
|
39572
39647
|
const rawPrompt = args2.prompt?.trim() || "\u63CF\u8FF0\u8FD9\u5F20\u56FE\u7247\u7684\u5185\u5BB9";
|
|
39573
|
-
const ext =
|
|
39648
|
+
const ext = path44.extname(imagePath).toLowerCase();
|
|
39574
39649
|
if (VIDEO_EXT.test(imagePath)) {
|
|
39575
|
-
const stat4 =
|
|
39650
|
+
const stat4 = fs44.statSync(imagePath);
|
|
39576
39651
|
if (stat4.size > VIDEO_MAX_BYTES) {
|
|
39577
39652
|
return { content: `Error: video too large (${(stat4.size / 1e6).toFixed(1)}MB > 40MB). Compress or trim first.`, isError: true };
|
|
39578
39653
|
}
|
|
39579
39654
|
const explicit = liveConfig.get("tools.my_eyes.videoBaseUrl");
|
|
39580
39655
|
const baseUrl = explicit || providerCfg.baseUrl.replace(/\/anthropic\/?$/, "/v1").replace(/\/$/, "");
|
|
39581
|
-
const vidB64 =
|
|
39656
|
+
const vidB64 = fs44.readFileSync(imagePath).toString("base64");
|
|
39582
39657
|
try {
|
|
39583
39658
|
const res = await fetch(`${baseUrl}/chat/completions`, {
|
|
39584
39659
|
method: "POST",
|
|
@@ -39608,7 +39683,7 @@ registry.register({
|
|
|
39608
39683
|
}
|
|
39609
39684
|
}
|
|
39610
39685
|
const mime = MIME_MAP[ext] || "jpeg";
|
|
39611
|
-
const imgB64 =
|
|
39686
|
+
const imgB64 = fs44.readFileSync(imagePath).toString("base64");
|
|
39612
39687
|
const userMsg = {
|
|
39613
39688
|
role: "user",
|
|
39614
39689
|
content: [
|
|
@@ -39686,7 +39761,7 @@ var TTS_PROVIDERS = [
|
|
|
39686
39761
|
init_registry();
|
|
39687
39762
|
|
|
39688
39763
|
// src/tools/opus-encoder.ts
|
|
39689
|
-
import * as
|
|
39764
|
+
import * as fs45 from "node:fs";
|
|
39690
39765
|
var FRAME_MS = 20;
|
|
39691
39766
|
var PRESKIP_48K = 312;
|
|
39692
39767
|
var OPUS_RATE = 48e3;
|
|
@@ -39803,7 +39878,7 @@ async function wavToOggOpusNative(wavPath) {
|
|
|
39803
39878
|
const mod = await import("@discordjs/opus");
|
|
39804
39879
|
const OpusEncoder = mod.OpusEncoder ?? mod.default?.OpusEncoder;
|
|
39805
39880
|
if (!OpusEncoder) throw new Error("@discordjs/opus export shape unexpected");
|
|
39806
|
-
const wav = parseWav(
|
|
39881
|
+
const wav = parseWav(fs45.readFileSync(wavPath));
|
|
39807
39882
|
if (wav.channels !== 1) throw new Error(`unsupported ${wav.channels}ch (need mono)`);
|
|
39808
39883
|
if (!NATIVE_RATES.includes(wav.sampleRate)) throw new Error(`unsupported rate ${wav.sampleRate}`);
|
|
39809
39884
|
if (wav.pcm.length === 0) throw new Error("empty pcm data");
|
|
@@ -39839,7 +39914,7 @@ async function wavToOggOpusNative(wavPath) {
|
|
|
39839
39914
|
}
|
|
39840
39915
|
ogg.page(cur, pageGranule, false, true);
|
|
39841
39916
|
const oggPath = wavPath.replace(/\.wav$/, ".ogg");
|
|
39842
|
-
|
|
39917
|
+
fs45.writeFileSync(oggPath, ogg.finish());
|
|
39843
39918
|
return oggPath;
|
|
39844
39919
|
}
|
|
39845
39920
|
|
|
@@ -39868,10 +39943,10 @@ function fallbackChainOf(raw) {
|
|
|
39868
39943
|
init_live();
|
|
39869
39944
|
|
|
39870
39945
|
// src/tools/tts/relay.ts
|
|
39871
|
-
import * as
|
|
39946
|
+
import * as fs46 from "node:fs";
|
|
39872
39947
|
import * as os6 from "node:os";
|
|
39873
|
-
import * as
|
|
39874
|
-
var VOICE_DIR2 =
|
|
39948
|
+
import * as path45 from "node:path";
|
|
39949
|
+
var VOICE_DIR2 = path45.join(os6.tmpdir(), "engine-voice");
|
|
39875
39950
|
var fetchFn = fetch;
|
|
39876
39951
|
async function synthRelay(text, cfg) {
|
|
39877
39952
|
const res = await fetchFn(`${cfg.baseUrl}/audio/speech`, {
|
|
@@ -39890,9 +39965,9 @@ async function synthRelay(text, cfg) {
|
|
|
39890
39965
|
}
|
|
39891
39966
|
const buf = Buffer.from(await res.arrayBuffer());
|
|
39892
39967
|
if (buf.length < 20) throw new Error(`relay tts: \u54CD\u5E94\u4F53\u53EA\u6709 ${buf.length} \u5B57\u8282\uFF0C\u4E0D\u662F\u6709\u6548\u97F3\u9891`);
|
|
39893
|
-
|
|
39894
|
-
const out =
|
|
39895
|
-
|
|
39968
|
+
fs46.mkdirSync(VOICE_DIR2, { recursive: true });
|
|
39969
|
+
const out = path45.join(VOICE_DIR2, `tts_relay_${Date.now()}.mp3`);
|
|
39970
|
+
fs46.writeFileSync(out, buf);
|
|
39896
39971
|
return {
|
|
39897
39972
|
path: out,
|
|
39898
39973
|
format: "mp3",
|
|
@@ -40011,8 +40086,8 @@ function synthesize(id, text, sink) {
|
|
|
40011
40086
|
// src/tools/my-voice.ts
|
|
40012
40087
|
import { execFile as execFile3 } from "node:child_process";
|
|
40013
40088
|
import { promisify as promisify3 } from "node:util";
|
|
40014
|
-
import * as
|
|
40015
|
-
import * as
|
|
40089
|
+
import * as fs47 from "node:fs";
|
|
40090
|
+
import * as path46 from "node:path";
|
|
40016
40091
|
var execFileAsync3 = promisify3(execFile3);
|
|
40017
40092
|
async function toWav24kWithDuration(audioPath) {
|
|
40018
40093
|
let wavPath = audioPath;
|
|
@@ -40030,15 +40105,15 @@ async function toWav24kWithDuration(audioPath) {
|
|
|
40030
40105
|
"pcm_s16le",
|
|
40031
40106
|
wavPath
|
|
40032
40107
|
], { timeout: 3e4 });
|
|
40033
|
-
if (!
|
|
40108
|
+
if (!fs47.existsSync(wavPath) || fs47.statSync(wavPath).size < 44) {
|
|
40034
40109
|
throw new Error("toWav24k produced empty output");
|
|
40035
40110
|
}
|
|
40036
40111
|
try {
|
|
40037
|
-
|
|
40112
|
+
fs47.unlinkSync(audioPath);
|
|
40038
40113
|
} catch {
|
|
40039
40114
|
}
|
|
40040
40115
|
}
|
|
40041
|
-
const durationSec = wavDurationSec(
|
|
40116
|
+
const durationSec = wavDurationSec(fs47.readFileSync(wavPath));
|
|
40042
40117
|
return { wavPath, durationSec };
|
|
40043
40118
|
}
|
|
40044
40119
|
async function compressWav(wavPath) {
|
|
@@ -40056,7 +40131,7 @@ async function compressWav(wavPath) {
|
|
|
40056
40131
|
"+faststart",
|
|
40057
40132
|
m4aPath
|
|
40058
40133
|
], { timeout: 3e4 });
|
|
40059
|
-
|
|
40134
|
+
fs47.unlinkSync(wavPath);
|
|
40060
40135
|
return m4aPath;
|
|
40061
40136
|
} catch {
|
|
40062
40137
|
return wavPath;
|
|
@@ -40083,10 +40158,10 @@ async function wavToOggOpus(wavPath) {
|
|
|
40083
40158
|
oggPath
|
|
40084
40159
|
], { timeout: 3e4 });
|
|
40085
40160
|
}
|
|
40086
|
-
if (!
|
|
40161
|
+
if (!fs47.existsSync(oggPath) || fs47.statSync(oggPath).size < 20) {
|
|
40087
40162
|
throw new Error("ogg/opus encode produced empty output");
|
|
40088
40163
|
}
|
|
40089
|
-
|
|
40164
|
+
fs47.unlinkSync(wavPath);
|
|
40090
40165
|
return oggPath;
|
|
40091
40166
|
}
|
|
40092
40167
|
async function sendVoiceToMulticaIssue(text, issueId, opts) {
|
|
@@ -40101,7 +40176,7 @@ async function sendVoiceToMulticaIssue(text, issueId, opts) {
|
|
|
40101
40176
|
} catch (e) {
|
|
40102
40177
|
return { content: `\u8BED\u97F3\u751F\u6210\u5931\u8D25\uFF08headless\u2192multaca\uFF09\uFF1A${e.message}\u3002\u8BF7\u7528\u6587\u5B57\u56DE\u590D\u4EE3\u66FF\u3002`, isError: true };
|
|
40103
40178
|
}
|
|
40104
|
-
if (!audioPath || !
|
|
40179
|
+
if (!audioPath || !fs47.existsSync(audioPath)) {
|
|
40105
40180
|
return { content: "\u8BED\u97F3\u751F\u6210\u5931\u8D25\uFF08headless\u2192multaca\uFF09\uFF1ATTS \u672A\u4EA7\u51FA\u6587\u4EF6\u3002\u8BF7\u7528\u6587\u5B57\u56DE\u590D\u4EE3\u66FF\u3002", isError: true };
|
|
40106
40181
|
}
|
|
40107
40182
|
if (audioPath.endsWith(".wav")) {
|
|
@@ -40111,21 +40186,21 @@ async function sendVoiceToMulticaIssue(text, issueId, opts) {
|
|
|
40111
40186
|
console.warn(`[my-voice:multaca] opus encode failed (${e.message}), attaching wav`);
|
|
40112
40187
|
}
|
|
40113
40188
|
}
|
|
40114
|
-
const ext =
|
|
40115
|
-
const sizeKB =
|
|
40189
|
+
const ext = path46.extname(audioPath).toLowerCase();
|
|
40190
|
+
const sizeKB = fs47.statSync(audioPath).size / 1024;
|
|
40116
40191
|
const voiceFile = `voice_${Date.now()}${ext}`;
|
|
40117
|
-
const cwdCopy =
|
|
40192
|
+
const cwdCopy = path46.join(process.cwd(), voiceFile);
|
|
40118
40193
|
try {
|
|
40119
|
-
|
|
40194
|
+
fs47.copyFileSync(audioPath, cwdCopy);
|
|
40120
40195
|
} catch (e) {
|
|
40121
40196
|
try {
|
|
40122
|
-
|
|
40197
|
+
fs47.unlinkSync(audioPath);
|
|
40123
40198
|
} catch {
|
|
40124
40199
|
}
|
|
40125
40200
|
return { content: `\u8BED\u97F3\u6302\u8F7D\u5931\u8D25\uFF08\u62F7\u8D1D\u5230\u5DE5\u4F5C\u76EE\u5F55\uFF09\uFF1A${e.message}`, isError: true };
|
|
40126
40201
|
}
|
|
40127
40202
|
try {
|
|
40128
|
-
|
|
40203
|
+
fs47.unlinkSync(audioPath);
|
|
40129
40204
|
} catch {
|
|
40130
40205
|
}
|
|
40131
40206
|
const content = opts.caption || `\u{1F399}\uFE0F \u8BED\u97F3\u6D88\u606F\uFF08${text.length} \u5B57\uFF09`;
|
|
@@ -40154,13 +40229,13 @@ async function sendVoiceToMulticaIssue(text, issueId, opts) {
|
|
|
40154
40229
|
}
|
|
40155
40230
|
if (!ok) throw new Error(`unexpected CLI output: ${String(stdout).slice(0, 200)}`);
|
|
40156
40231
|
try {
|
|
40157
|
-
|
|
40232
|
+
fs47.unlinkSync(cwdCopy);
|
|
40158
40233
|
} catch {
|
|
40159
40234
|
}
|
|
40160
40235
|
return { content: `Voice sent to multaca issue ${issueId}! (${actualEngine}, ${sizeKB.toFixed(0)}KB, \u9644\u4EF6\u5DF2\u6302\u5230\u8BC4\u8BBA\u2014\u2014\u5728 multaca \u5BA2\u6237\u7AEF\u64AD\u653E)` };
|
|
40161
40236
|
} catch (e) {
|
|
40162
40237
|
try {
|
|
40163
|
-
|
|
40238
|
+
fs47.unlinkSync(cwdCopy);
|
|
40164
40239
|
} catch {
|
|
40165
40240
|
}
|
|
40166
40241
|
return { content: `\u8BED\u97F3\u6302\u5230 multaca issue \u5931\u8D25\uFF1A${e.message}\u3002\u8BF7\u7528\u6587\u5B57\u56DE\u590D\u4EE3\u66FF\u3002`, isError: true };
|
|
@@ -40277,10 +40352,10 @@ registry.register({
|
|
|
40277
40352
|
audioPath = await compressWav(audioPath);
|
|
40278
40353
|
}
|
|
40279
40354
|
}
|
|
40280
|
-
const ext =
|
|
40355
|
+
const ext = path46.extname(audioPath).toLowerCase();
|
|
40281
40356
|
const mimeMap = { ".mp3": "audio/mpeg", ".wav": "audio/wav", ".m4a": "audio/mp4", ".ogg": "audio/ogg", ".silk": "audio/silk" };
|
|
40282
40357
|
const mimeType = mimeMap[ext] || "audio/mpeg";
|
|
40283
|
-
const sizeKB =
|
|
40358
|
+
const sizeKB = fs47.statSync(audioPath).size / 1024;
|
|
40284
40359
|
try {
|
|
40285
40360
|
await mgr.sendFile(resolvedChannel, target, caption, {
|
|
40286
40361
|
path: audioPath,
|
|
@@ -40289,7 +40364,7 @@ registry.register({
|
|
|
40289
40364
|
...voiceDurationSec !== void 0 ? { voiceDurationSec } : {}
|
|
40290
40365
|
});
|
|
40291
40366
|
try {
|
|
40292
|
-
|
|
40367
|
+
fs47.unlinkSync(audioPath);
|
|
40293
40368
|
} catch {
|
|
40294
40369
|
}
|
|
40295
40370
|
return { content: `Voice sent! (${actualEngine}, ${sizeKB.toFixed(0)}KB, ${resolvedChannel})` };
|
|
@@ -40307,8 +40382,8 @@ registry.register({
|
|
|
40307
40382
|
init_live();
|
|
40308
40383
|
init_registry();
|
|
40309
40384
|
init_well_formed();
|
|
40310
|
-
import * as
|
|
40311
|
-
import * as
|
|
40385
|
+
import * as fs48 from "node:fs";
|
|
40386
|
+
import * as path47 from "node:path";
|
|
40312
40387
|
function getProxyDispatcher2() {
|
|
40313
40388
|
const cfg = liveConfig.all();
|
|
40314
40389
|
const proxy = cfg.providers?.xai?.proxy;
|
|
@@ -40322,7 +40397,7 @@ function getProxyDispatcher2() {
|
|
|
40322
40397
|
}
|
|
40323
40398
|
function dimsOf(p) {
|
|
40324
40399
|
try {
|
|
40325
|
-
const b =
|
|
40400
|
+
const b = fs48.readFileSync(p);
|
|
40326
40401
|
let w = 0, h = 0;
|
|
40327
40402
|
if (b.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]))) {
|
|
40328
40403
|
w = b.readUInt32BE(16);
|
|
@@ -40445,9 +40520,9 @@ function registerPortrait(relPath, name) {
|
|
|
40445
40520
|
const cur = cfg?.tools?.my_selfie?.references || cfg?.my_selfie?.references || [];
|
|
40446
40521
|
const next = Array.isArray(cur) ? cur.filter((r) => r?.name !== name) : [];
|
|
40447
40522
|
next.unshift({ name, path: relPath });
|
|
40448
|
-
const
|
|
40449
|
-
void liveConfig.set(
|
|
40450
|
-
console.log(`[my-selfie] \u5F62\u8C61\u5DF2\u767B\u8BB0\uFF1A${
|
|
40523
|
+
const path60 = cfg?.tools?.my_selfie ? "tools.my_selfie.references" : "my_selfie.references";
|
|
40524
|
+
void liveConfig.set(path60, next);
|
|
40525
|
+
console.log(`[my-selfie] \u5F62\u8C61\u5DF2\u767B\u8BB0\uFF1A${path60}[0] = ${relPath}`);
|
|
40451
40526
|
} catch (e) {
|
|
40452
40527
|
console.warn(`[my-selfie] \u5199\u5165 references \u5931\u8D25\uFF08\u4E0D\u5F71\u54CD\u672C\u6B21\u51FA\u56FE\uFF09: ${e.message}`);
|
|
40453
40528
|
}
|
|
@@ -40728,10 +40803,10 @@ registry.register({
|
|
|
40728
40803
|
const REFERENCES = getReferences(ctx);
|
|
40729
40804
|
const refName = args2.reference || "default";
|
|
40730
40805
|
const refEntry = REFERENCES.find((r) => r.name === refName) || REFERENCES[0];
|
|
40731
|
-
let refPath =
|
|
40806
|
+
let refPath = path47.join(ctx.workspace, refEntry.p);
|
|
40732
40807
|
const adoptImg = args2.referenceImage?.trim();
|
|
40733
40808
|
if (adoptImg) {
|
|
40734
|
-
if (!
|
|
40809
|
+
if (!fs48.existsSync(adoptImg)) {
|
|
40735
40810
|
return { content: `\u627E\u4E0D\u5230\u90A3\u5F20\u56FE\uFF1A${adoptImg}`, isError: true };
|
|
40736
40811
|
}
|
|
40737
40812
|
const acheck = dimsOf(adoptImg);
|
|
@@ -40742,16 +40817,16 @@ registry.register({
|
|
|
40742
40817
|
isError: true
|
|
40743
40818
|
};
|
|
40744
40819
|
}
|
|
40745
|
-
const adir =
|
|
40746
|
-
if (!
|
|
40747
|
-
const aext = (
|
|
40820
|
+
const adir = path47.join(ctx.workspace, "images");
|
|
40821
|
+
if (!fs48.existsSync(adir)) fs48.mkdirSync(adir, { recursive: true });
|
|
40822
|
+
const aext = (path47.extname(adoptImg) || ".png").toLowerCase();
|
|
40748
40823
|
const afname = `portrait_${Date.now()}${aext}`;
|
|
40749
|
-
|
|
40824
|
+
fs48.copyFileSync(adoptImg, path47.join(adir, afname));
|
|
40750
40825
|
registerPortrait(`images/${afname}`, refName);
|
|
40751
|
-
refPath =
|
|
40826
|
+
refPath = path47.join(adir, afname);
|
|
40752
40827
|
console.log(`[my-selfie] \u91C7\u7EB3\u73B0\u6210\u56FE\u5F53\u5F62\u8C61\uFF1Aimages/${afname}${acheck ? ` (${acheck})` : ""}`);
|
|
40753
40828
|
}
|
|
40754
|
-
if (provider !== "autodl" && !
|
|
40829
|
+
if (provider !== "autodl" && !fs48.existsSync(refPath)) {
|
|
40755
40830
|
const cfgAll = liveConfig.all();
|
|
40756
40831
|
const portraitDesc = resolvePortraitDesc(
|
|
40757
40832
|
args2.portrait,
|
|
@@ -40776,16 +40851,16 @@ registry.register({
|
|
|
40776
40851
|
} catch (e) {
|
|
40777
40852
|
return { content: `\u5851\u9020\u5F62\u8C61\u5931\u8D25\uFF1A${e.message}`, isError: true };
|
|
40778
40853
|
}
|
|
40779
|
-
const pdir =
|
|
40780
|
-
if (!
|
|
40854
|
+
const pdir = path47.join(ctx.workspace, "images");
|
|
40855
|
+
if (!fs48.existsSync(pdir)) fs48.mkdirSync(pdir, { recursive: true });
|
|
40781
40856
|
const pfname = `portrait_${Date.now()}.png`;
|
|
40782
|
-
|
|
40857
|
+
fs48.writeFileSync(path47.join(pdir, pfname), portraitBuf);
|
|
40783
40858
|
registerPortrait(`images/${pfname}`, refName);
|
|
40784
|
-
refPath =
|
|
40859
|
+
refPath = path47.join(pdir, pfname);
|
|
40785
40860
|
console.log(`[my-selfie] \u5F62\u8C61\u5DF2\u5B58 images/${pfname}\uFF0C\u7EE7\u7EED\u8FD9\u6B21\u81EA\u62CD`);
|
|
40786
40861
|
}
|
|
40787
40862
|
const resolution = args2.resolution || DEFAULT_RESOLUTION;
|
|
40788
|
-
const refB64 =
|
|
40863
|
+
const refB64 = fs48.existsSync(refPath) ? fs48.readFileSync(refPath).toString("base64") : "";
|
|
40789
40864
|
let imageBuffer;
|
|
40790
40865
|
try {
|
|
40791
40866
|
if (provider === "autodl") {
|
|
@@ -40801,7 +40876,7 @@ registry.register({
|
|
|
40801
40876
|
return { content: `Error: relay provider \u672A\u914D\u7F6E\u3002config \u91CC\u8981\u6709 models.providers.${cfgAll?.my_selfie?.relayProviderId || "7yi"} \u7684 baseUrl \u548C apiKey\u3002`, isError: true };
|
|
40802
40877
|
}
|
|
40803
40878
|
const model = cfgAll?.my_selfie?.relayModel || cfgAll?.tools?.my_selfie?.relayModel || "engine7-img-free";
|
|
40804
|
-
const ext =
|
|
40879
|
+
const ext = path47.extname(refPath).toLowerCase();
|
|
40805
40880
|
const mime = ext === ".png" ? "image/png" : ext === ".webp" ? "image/webp" : "image/jpeg";
|
|
40806
40881
|
imageBuffer = await generateWithRelay(refB64, fullPrompt, mime, relay.baseUrl, relay.apiKey, model);
|
|
40807
40882
|
} else {
|
|
@@ -40810,11 +40885,11 @@ registry.register({
|
|
|
40810
40885
|
} catch (err) {
|
|
40811
40886
|
return { content: `Selfie generation failed: ${err.message}`, isError: true };
|
|
40812
40887
|
}
|
|
40813
|
-
const imagesDir =
|
|
40814
|
-
if (!
|
|
40888
|
+
const imagesDir = path47.join(ctx.workspace, "images");
|
|
40889
|
+
if (!fs48.existsSync(imagesDir)) fs48.mkdirSync(imagesDir, { recursive: true });
|
|
40815
40890
|
const filename = `selfie_${Date.now()}.jpg`;
|
|
40816
|
-
const outputPath =
|
|
40817
|
-
|
|
40891
|
+
const outputPath = path47.join(imagesDir, filename);
|
|
40892
|
+
fs48.writeFileSync(outputPath, imageBuffer);
|
|
40818
40893
|
const mgr = ctx.channelManager;
|
|
40819
40894
|
if (mgr) {
|
|
40820
40895
|
const resolvedChannel = ctx.channel || "feishu";
|
|
@@ -40825,11 +40900,11 @@ registry.register({
|
|
|
40825
40900
|
mimeType: "image/jpeg"
|
|
40826
40901
|
});
|
|
40827
40902
|
} catch (err) {
|
|
40828
|
-
return { content: `Selfie generated but send failed: ${err.message}. Image: ${
|
|
40903
|
+
return { content: `Selfie generated but send failed: ${err.message}. Image: ${path47.resolve(outputPath)}`, isError: false };
|
|
40829
40904
|
}
|
|
40830
40905
|
return { content: `Selfie sent! Mode: ${mode}, Provider: ${provider}, Ref: ${refEntry.name}` };
|
|
40831
40906
|
}
|
|
40832
|
-
return { content: `Selfie generated! Mode: ${mode}, Ref: ${refEntry.name}. Image: ${
|
|
40907
|
+
return { content: `Selfie generated! Mode: ${mode}, Ref: ${refEntry.name}. Image: ${path47.resolve(outputPath)}` };
|
|
40833
40908
|
},
|
|
40834
40909
|
isConcurrencySafe: () => false,
|
|
40835
40910
|
interruptBehavior: () => "block",
|
|
@@ -41381,8 +41456,8 @@ ${lines.join("\n")}` };
|
|
|
41381
41456
|
init_registry();
|
|
41382
41457
|
init_live();
|
|
41383
41458
|
init_clock();
|
|
41384
|
-
import * as
|
|
41385
|
-
import * as
|
|
41459
|
+
import * as fs49 from "node:fs";
|
|
41460
|
+
import * as path48 from "node:path";
|
|
41386
41461
|
import { exec as exec2, spawn as spawn6 } from "node:child_process";
|
|
41387
41462
|
import { promisify as promisify4 } from "node:util";
|
|
41388
41463
|
var execAsync = promisify4(exec2);
|
|
@@ -41391,9 +41466,9 @@ function getServices() {
|
|
|
41391
41466
|
}
|
|
41392
41467
|
function serviceLogPath(fileName) {
|
|
41393
41468
|
const stateDir = String(liveConfig.get("stateDir") ?? "");
|
|
41394
|
-
const logDir =
|
|
41395
|
-
if (!
|
|
41396
|
-
return
|
|
41469
|
+
const logDir = path48.join(stateDir, "logs");
|
|
41470
|
+
if (!fs49.existsSync(logDir)) fs49.mkdirSync(logDir, { recursive: true });
|
|
41471
|
+
return path48.join(logDir, fileName);
|
|
41397
41472
|
}
|
|
41398
41473
|
async function runCmd(cmd, timeoutMs = 15e3) {
|
|
41399
41474
|
try {
|
|
@@ -41712,16 +41787,16 @@ var EXIT_PLAN_MODE_TOOL_NAME = "ExitPlanMode";
|
|
|
41712
41787
|
init_planModeState();
|
|
41713
41788
|
|
|
41714
41789
|
// src/utils/plans.ts
|
|
41715
|
-
import * as
|
|
41716
|
-
import * as
|
|
41790
|
+
import * as fs50 from "node:fs";
|
|
41791
|
+
import * as path49 from "node:path";
|
|
41717
41792
|
import * as crypto7 from "node:crypto";
|
|
41718
41793
|
var MAX_SLUG_RETRIES = 10;
|
|
41719
41794
|
function generateSlug() {
|
|
41720
41795
|
return crypto7.randomBytes(4).toString("hex");
|
|
41721
41796
|
}
|
|
41722
41797
|
function getPlansDirectory(stateDir) {
|
|
41723
|
-
const plansDir =
|
|
41724
|
-
|
|
41798
|
+
const plansDir = path49.join(stateDir, "plans");
|
|
41799
|
+
fs50.mkdirSync(plansDir, { recursive: true });
|
|
41725
41800
|
return plansDir;
|
|
41726
41801
|
}
|
|
41727
41802
|
var planSlugCache = /* @__PURE__ */ new Map();
|
|
@@ -41731,8 +41806,8 @@ function getPlanSlug(sessionId, stateDir) {
|
|
|
41731
41806
|
const plansDir = getPlansDirectory(stateDir);
|
|
41732
41807
|
for (let i = 0; i < MAX_SLUG_RETRIES; i++) {
|
|
41733
41808
|
slug = generateSlug();
|
|
41734
|
-
const filePath =
|
|
41735
|
-
if (!
|
|
41809
|
+
const filePath = path49.join(plansDir, `${slug}.md`);
|
|
41810
|
+
if (!fs50.existsSync(filePath)) {
|
|
41736
41811
|
break;
|
|
41737
41812
|
}
|
|
41738
41813
|
}
|
|
@@ -41743,21 +41818,21 @@ function getPlanSlug(sessionId, stateDir) {
|
|
|
41743
41818
|
function getPlanFilePath(sessionId, stateDir, agentId) {
|
|
41744
41819
|
const slug = getPlanSlug(sessionId, stateDir);
|
|
41745
41820
|
if (!agentId) {
|
|
41746
|
-
return
|
|
41821
|
+
return path49.join(getPlansDirectory(stateDir), `${slug}.md`);
|
|
41747
41822
|
}
|
|
41748
|
-
return
|
|
41823
|
+
return path49.join(getPlansDirectory(stateDir), `${slug}-agent-${agentId}.md`);
|
|
41749
41824
|
}
|
|
41750
41825
|
function getPlan(sessionId, stateDir, agentId) {
|
|
41751
41826
|
const filePath = getPlanFilePath(sessionId, stateDir, agentId);
|
|
41752
41827
|
try {
|
|
41753
|
-
return
|
|
41828
|
+
return fs50.readFileSync(filePath, "utf-8");
|
|
41754
41829
|
} catch {
|
|
41755
41830
|
return null;
|
|
41756
41831
|
}
|
|
41757
41832
|
}
|
|
41758
41833
|
function writePlan(sessionId, stateDir, content, agentId) {
|
|
41759
41834
|
const filePath = getPlanFilePath(sessionId, stateDir, agentId);
|
|
41760
|
-
|
|
41835
|
+
fs50.writeFileSync(filePath, content, "utf-8");
|
|
41761
41836
|
return filePath;
|
|
41762
41837
|
}
|
|
41763
41838
|
|
|
@@ -42398,8 +42473,8 @@ init_features2();
|
|
|
42398
42473
|
init_agent_registry();
|
|
42399
42474
|
|
|
42400
42475
|
// src/commands/work.ts
|
|
42401
|
-
import * as
|
|
42402
|
-
import * as
|
|
42476
|
+
import * as fs55 from "node:fs";
|
|
42477
|
+
import * as path55 from "node:path";
|
|
42403
42478
|
registerCommand({
|
|
42404
42479
|
name: "work",
|
|
42405
42480
|
description: "\u5DE5\u4F5C\u6A21\u5F0F\uFF1A\u65E0\u53C2\u770B\u72B6\u6001\uFF0Con=\u5F3A\u5236work\uFF0Coff=\u5F3A\u5236emotion\uFF0Cauto=\u81EA\u52A8\u5224\u5B9A",
|
|
@@ -42412,20 +42487,20 @@ registerCommand({
|
|
|
42412
42487
|
],
|
|
42413
42488
|
handler: async (ctx, deps) => {
|
|
42414
42489
|
const mode = (ctx.args.mode || "").trim().toLowerCase();
|
|
42415
|
-
const modeFile =
|
|
42490
|
+
const modeFile = path55.join(deps.config.workspace, ".work-mode");
|
|
42416
42491
|
if (mode === "on" || mode === "off") {
|
|
42417
|
-
|
|
42492
|
+
fs55.writeFileSync(modeFile, mode, "utf8");
|
|
42418
42493
|
await ctx.reply(mode === "on" ? "\u5DE5\u4F5C\u6A21\u5F0F\u5DF2\u5F3A\u5236 **work**\uFF08\u6240\u6709\u6D88\u606F\u5168\u91CF\u4E0A\u4E0B\u6587\uFF0C\u4E0B\u4E00\u6761\u751F\u6548\uFF09" : "\u5DE5\u4F5C\u6A21\u5F0F\u5DF2\u5F3A\u5236 **emotion**\uFF08\u6240\u6709\u6D88\u606F\u8F7B\u91CF\u95F2\u804A\uFF0C\u4E0B\u4E00\u6761\u751F\u6548\uFF09");
|
|
42419
42494
|
} else if (mode === "auto") {
|
|
42420
42495
|
try {
|
|
42421
|
-
|
|
42496
|
+
fs55.unlinkSync(modeFile);
|
|
42422
42497
|
} catch {
|
|
42423
42498
|
}
|
|
42424
42499
|
await ctx.reply("\u5DE5\u4F5C\u6A21\u5F0F\u5DF2\u6062\u590D **auto**\uFF08emotion_state_machine \u9010\u6761\u81EA\u52A8\u5224\u5B9A\uFF09");
|
|
42425
42500
|
} else {
|
|
42426
42501
|
let cur = "auto";
|
|
42427
42502
|
try {
|
|
42428
|
-
cur =
|
|
42503
|
+
cur = fs55.readFileSync(modeFile, "utf8").trim() || "auto";
|
|
42429
42504
|
} catch {
|
|
42430
42505
|
}
|
|
42431
42506
|
const hint = cur === "on" ? "\uFF08\u5F3A\u5236 work\uFF1A\u5168\u91CF\u4E0A\u4E0B\u6587\uFF09" : cur === "off" ? "\uFF08\u5F3A\u5236 emotion\uFF1A\u8F7B\u91CF\u4E0A\u4E0B\u6587\uFF09" : "\uFF08\u6BCF\u6761\u6D88\u606F\u7531 emotion_state_machine \u81EA\u52A8\u5224\u5B9A\uFF09";
|
|
@@ -42895,8 +42970,8 @@ ${err.stack}`);
|
|
|
42895
42970
|
});
|
|
42896
42971
|
|
|
42897
42972
|
// src/commands/model.ts
|
|
42898
|
-
import * as
|
|
42899
|
-
import * as
|
|
42973
|
+
import * as fs56 from "node:fs";
|
|
42974
|
+
import * as path56 from "node:path";
|
|
42900
42975
|
import { fileURLToPath as fileURLToPath8 } from "node:url";
|
|
42901
42976
|
function collectModels(config2) {
|
|
42902
42977
|
const aliases = config2.modelAliases || {};
|
|
@@ -42928,11 +43003,11 @@ function resolveConfigWritePath(config2, label) {
|
|
|
42928
43003
|
const configPath2 = config2._configFilePath;
|
|
42929
43004
|
if (!configPath2) return void 0;
|
|
42930
43005
|
let writePath = configPath2;
|
|
42931
|
-
if (configPath2 && !
|
|
43006
|
+
if (configPath2 && !fs56.existsSync(configPath2)) {
|
|
42932
43007
|
const __pFile = fileURLToPath8(import.meta.url);
|
|
42933
|
-
const __pDir =
|
|
42934
|
-
const altPath =
|
|
42935
|
-
if (
|
|
43008
|
+
const __pDir = path56.dirname(__pFile);
|
|
43009
|
+
const altPath = path56.join(path56.resolve(__pDir, "../configs"), path56.basename(configPath2));
|
|
43010
|
+
if (fs56.existsSync(altPath)) {
|
|
42936
43011
|
console.warn(`[${label}] Config not found at ${configPath2}, falling back to ${altPath}`);
|
|
42937
43012
|
writePath = altPath;
|
|
42938
43013
|
}
|
|
@@ -42991,22 +43066,22 @@ ${lines.join("\n")}`);
|
|
|
42991
43066
|
await ctx.reply(wasOverride ? `Reset to default: **${defaultRef}** (auto-routing restored, fallback cooldowns cleared)` : `Already using default: **${defaultRef}**`);
|
|
42992
43067
|
return;
|
|
42993
43068
|
}
|
|
42994
|
-
const
|
|
42995
|
-
if (
|
|
43069
|
+
const candidates2 = matchModels(input, aliases, available);
|
|
43070
|
+
if (candidates2.length === 0) {
|
|
42996
43071
|
await ctx.reply(`No model matching "${input}". Use \`/model\` to see list.`);
|
|
42997
43072
|
return;
|
|
42998
43073
|
}
|
|
42999
|
-
if (
|
|
43000
|
-
const lines =
|
|
43001
|
-
const more =
|
|
43002
|
-
... and ${
|
|
43074
|
+
if (candidates2.length > 1) {
|
|
43075
|
+
const lines = candidates2.slice(0, 10).map((a) => `- \`${a.ref}\` \u2014 ${a.name}`);
|
|
43076
|
+
const more = candidates2.length > 10 ? `
|
|
43077
|
+
... and ${candidates2.length - 10} more` : "";
|
|
43003
43078
|
await ctx.reply(`Multiple matches for "${input}":
|
|
43004
43079
|
${lines.join("\n")}${more}
|
|
43005
43080
|
|
|
43006
|
-
Use full ref like \`/model ${
|
|
43081
|
+
Use full ref like \`/model ${candidates2[0].ref}\``);
|
|
43007
43082
|
return;
|
|
43008
43083
|
}
|
|
43009
|
-
const target =
|
|
43084
|
+
const target = candidates2[0].ref;
|
|
43010
43085
|
let targetDeps = deps.modelDepsCache.get(target);
|
|
43011
43086
|
if (!targetDeps) {
|
|
43012
43087
|
targetDeps = deps.createModelDeps(target);
|
|
@@ -43044,8 +43119,8 @@ Use full ref like \`/model ${candidates[0].ref}\``);
|
|
|
43044
43119
|
const writer = deps.sessions.getWriter(sid);
|
|
43045
43120
|
writer.writeModelChange(pid, mid);
|
|
43046
43121
|
}
|
|
43047
|
-
console.log(`[model] Switched to ${target} (${
|
|
43048
|
-
await ctx.reply(`Switched to **${target}** (${
|
|
43122
|
+
console.log(`[model] Switched to ${target} (${candidates2[0].name})`);
|
|
43123
|
+
await ctx.reply(`Switched to **${target}** (${candidates2[0].name})
|
|
43049
43124
|
Auto-routing disabled \u2014 all messages use this model.
|
|
43050
43125
|
\`/model auto\` to restore default.`);
|
|
43051
43126
|
}
|
|
@@ -43068,35 +43143,35 @@ Usage: \`/primary provider/model\` to persist (restart required)`);
|
|
|
43068
43143
|
return;
|
|
43069
43144
|
}
|
|
43070
43145
|
const { aliases, available } = collectModels(deps.config);
|
|
43071
|
-
const
|
|
43072
|
-
if (
|
|
43146
|
+
const candidates2 = matchModels(input, aliases, available);
|
|
43147
|
+
if (candidates2.length === 0) {
|
|
43073
43148
|
await ctx.reply(`No model matching "${input}".`);
|
|
43074
43149
|
return;
|
|
43075
43150
|
}
|
|
43076
|
-
if (
|
|
43077
|
-
const lines =
|
|
43151
|
+
if (candidates2.length > 1) {
|
|
43152
|
+
const lines = candidates2.slice(0, 10).map((a) => `- \`${a.ref}\` \u2014 ${a.name}`);
|
|
43078
43153
|
await ctx.reply(`Multiple matches:
|
|
43079
43154
|
${lines.join("\n")}
|
|
43080
43155
|
|
|
43081
|
-
Use full ref like \`/primary ${
|
|
43156
|
+
Use full ref like \`/primary ${candidates2[0].ref}\``);
|
|
43082
43157
|
return;
|
|
43083
43158
|
}
|
|
43084
|
-
const target =
|
|
43159
|
+
const target = candidates2[0].ref;
|
|
43085
43160
|
if (!configPath2 || !writePath) {
|
|
43086
43161
|
await ctx.reply(`\u26A0\uFE0F Config file path not available, cannot persist. Set manually in config.`);
|
|
43087
43162
|
return;
|
|
43088
43163
|
}
|
|
43089
43164
|
try {
|
|
43090
|
-
const raw = await
|
|
43165
|
+
const raw = await fs56.promises.readFile(writePath, "utf-8");
|
|
43091
43166
|
const cfg = JSON.parse(raw);
|
|
43092
43167
|
if (!cfg.agents?.defaults?.model) {
|
|
43093
43168
|
await ctx.reply(`\u26A0\uFE0F Config structure mismatch: agents.defaults.model not found`);
|
|
43094
43169
|
return;
|
|
43095
43170
|
}
|
|
43096
43171
|
cfg.agents.defaults.model.primary = target;
|
|
43097
|
-
await
|
|
43172
|
+
await fs56.promises.writeFile(writePath, JSON.stringify(cfg, null, 2), "utf-8");
|
|
43098
43173
|
console.log(`[primary] Persisted primary=${target} to ${writePath}`);
|
|
43099
|
-
await ctx.reply(`\u2705 Primary model set to **${target}** (${
|
|
43174
|
+
await ctx.reply(`\u2705 Primary model set to **${target}** (${candidates2[0].name})
|
|
43100
43175
|
Written to config, hot-reloading provider chain now.`);
|
|
43101
43176
|
} catch (err) {
|
|
43102
43177
|
await ctx.reply(`\u26A0\uFE0F Failed to write config: ${err.message}`);
|
|
@@ -43122,26 +43197,26 @@ Usage: \`/vision-primary provider/model\` to persist (hot-reload)
|
|
|
43122
43197
|
return;
|
|
43123
43198
|
}
|
|
43124
43199
|
const { aliases, available } = collectModels(deps.config);
|
|
43125
|
-
const
|
|
43126
|
-
if (
|
|
43200
|
+
const candidates2 = matchModels(input, aliases, available);
|
|
43201
|
+
if (candidates2.length === 0) {
|
|
43127
43202
|
await ctx.reply(`No model matching "${input}".`);
|
|
43128
43203
|
return;
|
|
43129
43204
|
}
|
|
43130
|
-
if (
|
|
43131
|
-
const lines =
|
|
43205
|
+
if (candidates2.length > 1) {
|
|
43206
|
+
const lines = candidates2.slice(0, 10).map((a) => `- \`${a.ref}\` \u2014 ${a.name}`);
|
|
43132
43207
|
await ctx.reply(`Multiple matches:
|
|
43133
43208
|
${lines.join("\n")}
|
|
43134
43209
|
|
|
43135
|
-
Use full ref like \`/vision-primary ${
|
|
43210
|
+
Use full ref like \`/vision-primary ${candidates2[0].ref}\``);
|
|
43136
43211
|
return;
|
|
43137
43212
|
}
|
|
43138
|
-
const target =
|
|
43213
|
+
const target = candidates2[0].ref;
|
|
43139
43214
|
if (!configPath2 || !writePath) {
|
|
43140
43215
|
await ctx.reply(`\u26A0\uFE0F Config file path not available, cannot persist. Set manually in config.`);
|
|
43141
43216
|
return;
|
|
43142
43217
|
}
|
|
43143
43218
|
try {
|
|
43144
|
-
const raw = await
|
|
43219
|
+
const raw = await fs56.promises.readFile(writePath, "utf-8");
|
|
43145
43220
|
const cfg = JSON.parse(raw);
|
|
43146
43221
|
if (!cfg.agents?.defaults?.model) {
|
|
43147
43222
|
await ctx.reply(`\u26A0\uFE0F Config structure mismatch: agents.defaults.model not found`);
|
|
@@ -43149,14 +43224,14 @@ Use full ref like \`/vision-primary ${candidates[0].ref}\``);
|
|
|
43149
43224
|
}
|
|
43150
43225
|
if (input === "auto" || input === "reset") {
|
|
43151
43226
|
delete cfg.agents.defaults.model.vision;
|
|
43152
|
-
await
|
|
43227
|
+
await fs56.promises.writeFile(writePath, JSON.stringify(cfg, null, 2), "utf-8");
|
|
43153
43228
|
console.log(`[vision-primary] Cleared vision primary in ${writePath}`);
|
|
43154
43229
|
await ctx.reply(`\u2705 Vision primary cleared (auto). Written to config. Hot-reload will apply.`);
|
|
43155
43230
|
} else {
|
|
43156
43231
|
cfg.agents.defaults.model.vision = target;
|
|
43157
|
-
await
|
|
43232
|
+
await fs56.promises.writeFile(writePath, JSON.stringify(cfg, null, 2), "utf-8");
|
|
43158
43233
|
console.log(`[vision-primary] Persisted vision=${target} to ${writePath}`);
|
|
43159
|
-
await ctx.reply(`\u2705 Vision primary set to **${target}** (${
|
|
43234
|
+
await ctx.reply(`\u2705 Vision primary set to **${target}** (${candidates2[0].name})
|
|
43160
43235
|
Written to config. Hot-reload will apply.`);
|
|
43161
43236
|
}
|
|
43162
43237
|
} catch (err) {
|
|
@@ -43188,20 +43263,20 @@ Available models: use \`/model\` to see full list
|
|
|
43188
43263
|
return;
|
|
43189
43264
|
}
|
|
43190
43265
|
const { aliases, available } = collectModels(deps.config);
|
|
43191
|
-
const
|
|
43192
|
-
if (
|
|
43266
|
+
const candidates2 = matchModels(input, aliases, available);
|
|
43267
|
+
if (candidates2.length === 0) {
|
|
43193
43268
|
await ctx.reply(`No model matching "${input}".`);
|
|
43194
43269
|
return;
|
|
43195
43270
|
}
|
|
43196
|
-
if (
|
|
43197
|
-
const lines =
|
|
43271
|
+
if (candidates2.length > 1) {
|
|
43272
|
+
const lines = candidates2.slice(0, 10).map((a) => `- \`${a.ref}\` \u2014 ${a.name}`);
|
|
43198
43273
|
await ctx.reply(`Multiple matches:
|
|
43199
43274
|
${lines.join("\n")}
|
|
43200
43275
|
|
|
43201
|
-
Use full ref like \`/vision-model ${
|
|
43276
|
+
Use full ref like \`/vision-model ${candidates2[0].ref}\``);
|
|
43202
43277
|
return;
|
|
43203
43278
|
}
|
|
43204
|
-
const target =
|
|
43279
|
+
const target = candidates2[0].ref;
|
|
43205
43280
|
let targetDeps = deps.modelDepsCache.get(`vision:${target}`);
|
|
43206
43281
|
if (!targetDeps) {
|
|
43207
43282
|
targetDeps = deps.createModelDeps(target);
|
|
@@ -43214,7 +43289,7 @@ Use full ref like \`/vision-model ${candidates[0].ref}\``);
|
|
|
43214
43289
|
deps.setVisionOverride(target);
|
|
43215
43290
|
deps.setVisionDeps(targetDeps);
|
|
43216
43291
|
console.log(`[vision-model] Override: ${target}`);
|
|
43217
|
-
await ctx.reply(`Vision switched to **${target}** (${
|
|
43292
|
+
await ctx.reply(`Vision switched to **${target}** (${candidates2[0].name}) (immediate)
|
|
43218
43293
|
\`/vision-model auto\` to restore default.`);
|
|
43219
43294
|
}
|
|
43220
43295
|
});
|
|
@@ -43562,7 +43637,7 @@ async function startEngine(config2, opts) {
|
|
|
43562
43637
|
const { initSessionMemory: initSessionMemory2 } = await Promise.resolve().then(() => (init_sessionMemory(), sessionMemory_exports));
|
|
43563
43638
|
initSessionMemory2({
|
|
43564
43639
|
workspace: config2.workspace,
|
|
43565
|
-
stateDir:
|
|
43640
|
+
stateDir: path59.join(config2.stateDir, "session-memory"),
|
|
43566
43641
|
provider,
|
|
43567
43642
|
model: config2.provider.modelId || config2.model || "deepseek-v4-flash",
|
|
43568
43643
|
features: config2.profile.features
|
|
@@ -44033,7 +44108,7 @@ async function startEngine(config2, opts) {
|
|
|
44033
44108
|
};
|
|
44034
44109
|
const startReportingNow = () => {
|
|
44035
44110
|
stopReporting();
|
|
44036
|
-
reportingHandle = startReporting({ stateDir: config2.stateDir });
|
|
44111
|
+
reportingHandle = startReporting({ stateDir: config2.stateDir, log: (m) => console.log(m) });
|
|
44037
44112
|
};
|
|
44038
44113
|
const reportingEnabled = () => liveConfig.get("reporting.enabled") !== false;
|
|
44039
44114
|
reloadOrchestrator.register({
|
|
@@ -44091,11 +44166,7 @@ async function startEngine(config2, opts) {
|
|
|
44091
44166
|
}
|
|
44092
44167
|
|
|
44093
44168
|
// src/main.ts
|
|
44094
|
-
|
|
44095
|
-
import { fileURLToPath as fileURLToPath9 } from "node:url";
|
|
44096
|
-
import { dirname as dirname16, join as join66 } from "node:path";
|
|
44097
|
-
var __dirname2 = dirname16(fileURLToPath9(import.meta.url));
|
|
44098
|
-
var pkg = JSON.parse(readFileSync48(join66(__dirname2, "..", "package.json"), "utf-8"));
|
|
44169
|
+
init_version();
|
|
44099
44170
|
var epipeSeen = false;
|
|
44100
44171
|
process.on("uncaughtException", (err) => {
|
|
44101
44172
|
const code = err?.code ?? "";
|
|
@@ -44168,7 +44239,7 @@ if (args[0] === "features") {
|
|
|
44168
44239
|
var secretsPath = configPath ? loadSecretsEnvForConfig(configPath) : null;
|
|
44169
44240
|
console.log(secretsPath ? `[secrets] Loaded API keys from ${secretsPath}` : "[secrets] \u672A\u627E\u5230 .env \u2014\u2014 \u82E5 config \u7528\u7684\u662F env:XXX_API_KEY \u5360\u4F4D\u7B26\uFF0C\u5C06\u89E3\u6790\u5931\u8D25\uFF08401\uFF09");
|
|
44170
44241
|
var config = loadConfig(configPath);
|
|
44171
|
-
console.log(`=== Engine 7 v${
|
|
44242
|
+
console.log(`=== Engine 7 v${readEngineVersion()} ===`);
|
|
44172
44243
|
console.log(`PID: ${process.pid}`);
|
|
44173
44244
|
console.log(configSummary(config));
|
|
44174
44245
|
startEngine(config, { cliMode: true }).catch((err) => {
|