engine7 7.1.113 → 7.1.115
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/engine-startup.mjs
CHANGED
|
@@ -2445,14 +2445,14 @@ var init_live = __esm({
|
|
|
2445
2445
|
}
|
|
2446
2446
|
/** 把改动写回 config 文件对应段(找不到文件路径则只内存生效) */
|
|
2447
2447
|
async persistToFile(dotPath, val) {
|
|
2448
|
-
const
|
|
2448
|
+
const fs58 = await import("node:fs");
|
|
2449
2449
|
const cfgPath = this.current?._configFilePath;
|
|
2450
|
-
if (!cfgPath || !
|
|
2450
|
+
if (!cfgPath || !fs58.existsSync(cfgPath)) {
|
|
2451
2451
|
console.warn(`[liveConfig] set: no config file path, in-memory only (${dotPath})`);
|
|
2452
2452
|
return;
|
|
2453
2453
|
}
|
|
2454
2454
|
try {
|
|
2455
|
-
const raw = JSON.parse(
|
|
2455
|
+
const raw = JSON.parse(fs58.readFileSync(cfgPath, "utf-8"));
|
|
2456
2456
|
const keys = dotPath.split(".");
|
|
2457
2457
|
let o = raw;
|
|
2458
2458
|
for (let i = 0; i < keys.length - 1; i++) {
|
|
@@ -2460,7 +2460,7 @@ var init_live = __esm({
|
|
|
2460
2460
|
o = o[keys[i]];
|
|
2461
2461
|
}
|
|
2462
2462
|
o[keys[keys.length - 1]] = val;
|
|
2463
|
-
|
|
2463
|
+
fs58.writeFileSync(cfgPath, JSON.stringify(raw, null, 2) + "\n", "utf-8");
|
|
2464
2464
|
console.log(`[liveConfig] persisted ${dotPath} = ${JSON.stringify(val)} to ${cfgPath}`);
|
|
2465
2465
|
markSelfWrite();
|
|
2466
2466
|
} catch (e) {
|
|
@@ -3083,8 +3083,8 @@ function findShell() {
|
|
|
3083
3083
|
timeout: 5e3,
|
|
3084
3084
|
stdio: ["ignore", "pipe", "ignore"]
|
|
3085
3085
|
});
|
|
3086
|
-
const
|
|
3087
|
-
const nonWsl =
|
|
3086
|
+
const candidates2 = result.trim().split(/\r?\n/).map((s) => s.trim()).filter(Boolean);
|
|
3087
|
+
const nonWsl = candidates2.find((p) => !isWslBash(p));
|
|
3088
3088
|
if (nonWsl && fs5.existsSync(nonWsl)) {
|
|
3089
3089
|
cachedShell = { shell: nonWsl, args: ["-c"] };
|
|
3090
3090
|
return cachedShell;
|
|
@@ -4038,9 +4038,9 @@ function isAutoMemPath(absolutePath, workspace) {
|
|
|
4038
4038
|
return normalizedPath.startsWith(getAutoMemPath(workspace));
|
|
4039
4039
|
}
|
|
4040
4040
|
async function ensureMemoryDirExists(memoryDir) {
|
|
4041
|
-
const
|
|
4041
|
+
const fs58 = await import("node:fs");
|
|
4042
4042
|
try {
|
|
4043
|
-
await
|
|
4043
|
+
await fs58.promises.mkdir(memoryDir, { recursive: true });
|
|
4044
4044
|
} catch (e) {
|
|
4045
4045
|
const code = e?.code;
|
|
4046
4046
|
if (code !== "EEXIST") {
|
|
@@ -8362,7 +8362,7 @@ async function acquireLock(inboxPath) {
|
|
|
8362
8362
|
for (let i = 0; i < LOCK_RETRIES; i++) {
|
|
8363
8363
|
if (await isLockStale(lockPath2)) {
|
|
8364
8364
|
try {
|
|
8365
|
-
await import("node:fs/promises").then((
|
|
8365
|
+
await import("node:fs/promises").then((fs58) => fs58.rm(lockPath2, { force: true }));
|
|
8366
8366
|
} catch {
|
|
8367
8367
|
}
|
|
8368
8368
|
}
|
|
@@ -8370,7 +8370,7 @@ async function acquireLock(inboxPath) {
|
|
|
8370
8370
|
await writeFile2(lockPath2, `${process.pid}-${Date.now()}`, { encoding: "utf-8", flag: "wx" });
|
|
8371
8371
|
return async () => {
|
|
8372
8372
|
try {
|
|
8373
|
-
await import("node:fs/promises").then((
|
|
8373
|
+
await import("node:fs/promises").then((fs58) => fs58.rm(lockPath2, { force: true }));
|
|
8374
8374
|
} catch {
|
|
8375
8375
|
}
|
|
8376
8376
|
};
|
|
@@ -14190,8 +14190,8 @@ function mapOperation(raw) {
|
|
|
14190
14190
|
}
|
|
14191
14191
|
function extractJson2(text) {
|
|
14192
14192
|
const fenced = text.match(/```(?:json)?\s*([\s\S]*?)```/);
|
|
14193
|
-
const
|
|
14194
|
-
for (const c of
|
|
14193
|
+
const candidates2 = fenced ? [fenced[1], text] : [text];
|
|
14194
|
+
for (const c of candidates2) {
|
|
14195
14195
|
const start = c.indexOf("{");
|
|
14196
14196
|
const end = c.lastIndexOf("}");
|
|
14197
14197
|
if (start === -1 || end <= start) continue;
|
|
@@ -14862,14 +14862,14 @@ async function runProactiveCycle(deps, now) {
|
|
|
14862
14862
|
for (const act of persist.dueActions("9999-12-31T23:59:59Z", 1e3)) {
|
|
14863
14863
|
if (act.status === "queued") existingTitles.add(normalizeTitle(act.title));
|
|
14864
14864
|
}
|
|
14865
|
-
const
|
|
14865
|
+
const candidates2 = actionable.filter((s) => {
|
|
14866
14866
|
if (queuedIntentIds.has(s.node.id)) return false;
|
|
14867
14867
|
if (cooldownIntentIds.has(s.node.id)) return false;
|
|
14868
14868
|
return true;
|
|
14869
14869
|
});
|
|
14870
|
-
if (
|
|
14870
|
+
if (candidates2.length === 0) return 0;
|
|
14871
14871
|
let enqueued = 0;
|
|
14872
|
-
for (const scored of
|
|
14872
|
+
for (const scored of candidates2) {
|
|
14873
14873
|
const intent = scored.node;
|
|
14874
14874
|
if (intent.data.status === "resolved") continue;
|
|
14875
14875
|
store.updateNode(intent.id, { status: "action_scheduled" });
|
|
@@ -16728,11 +16728,11 @@ async function readLastConsolidatedAt(memoryDir) {
|
|
|
16728
16728
|
}
|
|
16729
16729
|
}
|
|
16730
16730
|
async function tryAcquireConsolidationLock(memoryDir) {
|
|
16731
|
-
const
|
|
16731
|
+
const path60 = lockPath(memoryDir);
|
|
16732
16732
|
let mtimeMs;
|
|
16733
16733
|
let holderPid;
|
|
16734
16734
|
try {
|
|
16735
|
-
const [s, raw] = await Promise.all([stat3(
|
|
16735
|
+
const [s, raw] = await Promise.all([stat3(path60), readFile5(path60, "utf8")]);
|
|
16736
16736
|
mtimeMs = s.mtimeMs;
|
|
16737
16737
|
const parsed = parseInt(raw.trim(), 10);
|
|
16738
16738
|
holderPid = Number.isFinite(parsed) ? parsed : void 0;
|
|
@@ -16745,10 +16745,10 @@ async function tryAcquireConsolidationLock(memoryDir) {
|
|
|
16745
16745
|
}
|
|
16746
16746
|
}
|
|
16747
16747
|
await mkdir3(memoryDir, { recursive: true });
|
|
16748
|
-
await writeFile4(
|
|
16748
|
+
await writeFile4(path60, String(process.pid));
|
|
16749
16749
|
let verify2;
|
|
16750
16750
|
try {
|
|
16751
|
-
verify2 = await readFile5(
|
|
16751
|
+
verify2 = await readFile5(path60, "utf8");
|
|
16752
16752
|
} catch {
|
|
16753
16753
|
return null;
|
|
16754
16754
|
}
|
|
@@ -16756,15 +16756,15 @@ async function tryAcquireConsolidationLock(memoryDir) {
|
|
|
16756
16756
|
return mtimeMs ?? 0;
|
|
16757
16757
|
}
|
|
16758
16758
|
async function rollbackConsolidationLock(memoryDir, priorMtime) {
|
|
16759
|
-
const
|
|
16759
|
+
const path60 = lockPath(memoryDir);
|
|
16760
16760
|
try {
|
|
16761
16761
|
if (priorMtime === 0) {
|
|
16762
|
-
await unlink(
|
|
16762
|
+
await unlink(path60);
|
|
16763
16763
|
return;
|
|
16764
16764
|
}
|
|
16765
|
-
await writeFile4(
|
|
16765
|
+
await writeFile4(path60, "");
|
|
16766
16766
|
const t = priorMtime / 1e3;
|
|
16767
|
-
await utimes(
|
|
16767
|
+
await utimes(path60, t, t);
|
|
16768
16768
|
} catch (e) {
|
|
16769
16769
|
console.log(`[autoDream] rollback failed: ${e.message} \u2014 next trigger delayed to minHours`);
|
|
16770
16770
|
}
|
|
@@ -17366,12 +17366,12 @@ async function executeAndDeliver(task, now, deps) {
|
|
|
17366
17366
|
if (promptText.startsWith("@")) {
|
|
17367
17367
|
let filePath = promptText.slice(1).trim();
|
|
17368
17368
|
try {
|
|
17369
|
-
const
|
|
17370
|
-
const
|
|
17371
|
-
if (!
|
|
17372
|
-
filePath =
|
|
17369
|
+
const fs58 = await import("fs");
|
|
17370
|
+
const path60 = await import("path");
|
|
17371
|
+
if (!path60.isAbsolute(filePath)) {
|
|
17372
|
+
filePath = path60.join(deps.sessions["config"].stateDir, filePath);
|
|
17373
17373
|
}
|
|
17374
|
-
promptText =
|
|
17374
|
+
promptText = fs58.readFileSync(filePath, "utf-8");
|
|
17375
17375
|
console.log(`[cron] Loaded prompt from ${filePath} (${promptText.length} chars)`);
|
|
17376
17376
|
} catch (err) {
|
|
17377
17377
|
throw new Error(`Prompt file not found: ${filePath}: ${err.message}`);
|
|
@@ -17409,16 +17409,16 @@ async function executeAndDeliver(task, now, deps) {
|
|
|
17409
17409
|
let finalResult = result;
|
|
17410
17410
|
if (task.postProcess) {
|
|
17411
17411
|
try {
|
|
17412
|
-
const
|
|
17413
|
-
const
|
|
17412
|
+
const path60 = await import("path");
|
|
17413
|
+
const fs58 = await import("fs");
|
|
17414
17414
|
let scriptPath = task.postProcess;
|
|
17415
|
-
if (!
|
|
17416
|
-
scriptPath =
|
|
17415
|
+
if (!path60.isAbsolute(scriptPath)) {
|
|
17416
|
+
scriptPath = path60.join(deps.sessions["config"].stateDir, scriptPath);
|
|
17417
17417
|
}
|
|
17418
|
-
const resultsDirTmp =
|
|
17419
|
-
|
|
17420
|
-
const inputFile =
|
|
17421
|
-
|
|
17418
|
+
const resultsDirTmp = path60.join(getStorageDir(), "results");
|
|
17419
|
+
fs58.mkdirSync(resultsDirTmp, { recursive: true });
|
|
17420
|
+
const inputFile = path60.join(resultsDirTmp, `${task.id}.input.txt`);
|
|
17421
|
+
fs58.writeFileSync(inputFile, result, "utf-8");
|
|
17422
17422
|
const { execFile: execFile5 } = await import("child_process");
|
|
17423
17423
|
await new Promise((resolve12) => {
|
|
17424
17424
|
execFile5("python", [scriptPath, "main", "--file", inputFile], {
|
|
@@ -17445,12 +17445,12 @@ async function executeAndDeliver(task, now, deps) {
|
|
|
17445
17445
|
}
|
|
17446
17446
|
}
|
|
17447
17447
|
try {
|
|
17448
|
-
const
|
|
17449
|
-
const
|
|
17450
|
-
const resultsDir =
|
|
17451
|
-
|
|
17452
|
-
const resultFile =
|
|
17453
|
-
|
|
17448
|
+
const fs58 = await import("fs");
|
|
17449
|
+
const path60 = await import("path");
|
|
17450
|
+
const resultsDir = path60.join(getStorageDir(), "results");
|
|
17451
|
+
fs58.mkdirSync(resultsDir, { recursive: true });
|
|
17452
|
+
const resultFile = path60.join(resultsDir, `${task.id}.json`);
|
|
17453
|
+
fs58.writeFileSync(resultFile, JSON.stringify({
|
|
17454
17454
|
taskId: task.id,
|
|
17455
17455
|
description: task.description,
|
|
17456
17456
|
executedAt: now.toISOString(),
|
|
@@ -17780,30 +17780,30 @@ function registerCronTools() {
|
|
|
17780
17780
|
}
|
|
17781
17781
|
},
|
|
17782
17782
|
handler: async (args) => {
|
|
17783
|
-
const
|
|
17784
|
-
const
|
|
17785
|
-
const resultsDir =
|
|
17786
|
-
if (!
|
|
17783
|
+
const fs58 = await import("fs");
|
|
17784
|
+
const path60 = await import("path");
|
|
17785
|
+
const resultsDir = path60.join(getStorageDir(), "results");
|
|
17786
|
+
if (!fs58.existsSync(resultsDir)) {
|
|
17787
17787
|
return { content: "\u6682\u65E0cron\u6267\u884C\u7ED3\u679C" };
|
|
17788
17788
|
}
|
|
17789
17789
|
if (args.task_id) {
|
|
17790
|
-
const file2 =
|
|
17791
|
-
if (!
|
|
17790
|
+
const file2 = path60.join(resultsDir, `${args.task_id}.json`);
|
|
17791
|
+
if (!fs58.existsSync(file2)) {
|
|
17792
17792
|
return { content: `\u4EFB\u52A1 ${args.task_id} \u6682\u65E0\u6267\u884C\u7ED3\u679C`, isError: true };
|
|
17793
17793
|
}
|
|
17794
|
-
const data = JSON.parse(
|
|
17794
|
+
const data = JSON.parse(fs58.readFileSync(file2, "utf-8"));
|
|
17795
17795
|
return { content: `## ${data.description}
|
|
17796
17796
|
\u6267\u884C\u65F6\u95F4: ${data.executedAt}
|
|
17797
17797
|
\u7B2C${data.runCount}\u6B21\u6267\u884C
|
|
17798
17798
|
|
|
17799
17799
|
${data.result}` };
|
|
17800
17800
|
}
|
|
17801
|
-
const files =
|
|
17801
|
+
const files = fs58.readdirSync(resultsDir).filter((f) => f.endsWith(".json"));
|
|
17802
17802
|
if (files.length === 0) {
|
|
17803
17803
|
return { content: "\u6682\u65E0cron\u6267\u884C\u7ED3\u679C" };
|
|
17804
17804
|
}
|
|
17805
17805
|
const results = files.map((f) => {
|
|
17806
|
-
const data = JSON.parse(
|
|
17806
|
+
const data = JSON.parse(fs58.readFileSync(path60.join(resultsDir, f), "utf-8"));
|
|
17807
17807
|
return `### ${data.description} (${data.taskId.slice(0, 8)})
|
|
17808
17808
|
\u6267\u884C: ${data.executedAt} | \u7B2C${data.runCount}\u6B21
|
|
17809
17809
|
${data.result.slice(0, 500)}${data.result.length > 500 ? "..." : ""}`;
|
|
@@ -18327,25 +18327,43 @@ var init_tasks2 = __esm({
|
|
|
18327
18327
|
}
|
|
18328
18328
|
});
|
|
18329
18329
|
|
|
18330
|
-
// src/
|
|
18331
|
-
|
|
18332
|
-
|
|
18333
|
-
buildEngineStatus: () => buildEngineStatus,
|
|
18334
|
-
readEngineVersion: () => readEngineVersion
|
|
18335
|
-
});
|
|
18336
|
-
import * as fs35 from "node:fs";
|
|
18337
|
-
import * as path35 from "node:path";
|
|
18330
|
+
// src/version.ts
|
|
18331
|
+
import { readFileSync as readFileSync31 } from "node:fs";
|
|
18332
|
+
import { dirname as dirname10, join as join43 } from "node:path";
|
|
18338
18333
|
import { fileURLToPath as fileURLToPath6 } from "node:url";
|
|
18339
|
-
function
|
|
18340
|
-
|
|
18341
|
-
|
|
18334
|
+
function candidates() {
|
|
18335
|
+
if (_pkgDirOverride !== null) return [join43(_pkgDirOverride, "package.json")];
|
|
18336
|
+
const here = dirname10(fileURLToPath6(import.meta.url));
|
|
18337
|
+
return [join43(here, "..", "package.json"), join43(here, "..", "..", "package.json")];
|
|
18338
|
+
}
|
|
18339
|
+
function readFromDisk() {
|
|
18340
|
+
for (const p of candidates()) {
|
|
18342
18341
|
try {
|
|
18343
|
-
return JSON.parse(
|
|
18342
|
+
return JSON.parse(readFileSync31(p, "utf-8")).version || "unknown";
|
|
18344
18343
|
} catch {
|
|
18345
18344
|
}
|
|
18346
18345
|
}
|
|
18347
18346
|
return "unknown";
|
|
18348
18347
|
}
|
|
18348
|
+
function readEngineVersion() {
|
|
18349
|
+
if (_loaded === null) _loaded = readFromDisk();
|
|
18350
|
+
return _loaded;
|
|
18351
|
+
}
|
|
18352
|
+
var _loaded, _pkgDirOverride;
|
|
18353
|
+
var init_version = __esm({
|
|
18354
|
+
"src/version.ts"() {
|
|
18355
|
+
"use strict";
|
|
18356
|
+
_loaded = null;
|
|
18357
|
+
_pkgDirOverride = null;
|
|
18358
|
+
}
|
|
18359
|
+
});
|
|
18360
|
+
|
|
18361
|
+
// src/startup/api-status.ts
|
|
18362
|
+
var api_status_exports = {};
|
|
18363
|
+
__export(api_status_exports, {
|
|
18364
|
+
buildEngineStatus: () => buildEngineStatus,
|
|
18365
|
+
readEngineVersion: () => readEngineVersion
|
|
18366
|
+
});
|
|
18349
18367
|
function hasUsable(v) {
|
|
18350
18368
|
return !!v && !isUnresolvedEnvRef(v);
|
|
18351
18369
|
}
|
|
@@ -18368,6 +18386,7 @@ var init_api_status = __esm({
|
|
|
18368
18386
|
"src/startup/api-status.ts"() {
|
|
18369
18387
|
"use strict";
|
|
18370
18388
|
init_loader();
|
|
18389
|
+
init_version();
|
|
18371
18390
|
}
|
|
18372
18391
|
});
|
|
18373
18392
|
|
|
@@ -18478,10 +18497,10 @@ function ensureLoaded(workspace, configIds) {
|
|
|
18478
18497
|
if (!state.blockedUserIds.includes(id)) state.blockedUserIds.push(id);
|
|
18479
18498
|
}
|
|
18480
18499
|
}
|
|
18481
|
-
const
|
|
18500
|
+
const path60 = join44(workspace, ".reply-blocklist.json");
|
|
18482
18501
|
try {
|
|
18483
|
-
if (existsSync22(
|
|
18484
|
-
const raw = readFileSync32(
|
|
18502
|
+
if (existsSync22(path60)) {
|
|
18503
|
+
const raw = readFileSync32(path60, "utf-8");
|
|
18485
18504
|
const parsed = JSON.parse(raw);
|
|
18486
18505
|
if (parsed.blockedUserIds) {
|
|
18487
18506
|
for (const id of parsed.blockedUserIds) {
|
|
@@ -18497,9 +18516,9 @@ function ensureLoaded(workspace, configIds) {
|
|
|
18497
18516
|
loaded = true;
|
|
18498
18517
|
}
|
|
18499
18518
|
function save(workspace) {
|
|
18500
|
-
const
|
|
18519
|
+
const path60 = join44(workspace, ".reply-blocklist.json");
|
|
18501
18520
|
try {
|
|
18502
|
-
writeFileSync10(
|
|
18521
|
+
writeFileSync10(path60, JSON.stringify(state, null, 2), "utf-8");
|
|
18503
18522
|
} catch (err) {
|
|
18504
18523
|
console.warn(`[reply-blocklist] Failed to save: ${err.message}`);
|
|
18505
18524
|
}
|
|
@@ -18944,8 +18963,8 @@ __export(voice_chat_tts_daemon_exports, {
|
|
|
18944
18963
|
});
|
|
18945
18964
|
import { spawn as spawn5 } from "child_process";
|
|
18946
18965
|
import net2 from "net";
|
|
18947
|
-
import
|
|
18948
|
-
import
|
|
18966
|
+
import path38 from "path";
|
|
18967
|
+
import fs38 from "fs";
|
|
18949
18968
|
function _log(msg2) {
|
|
18950
18969
|
console.log(`[tts-daemon] ${msg2}`);
|
|
18951
18970
|
}
|
|
@@ -18990,16 +19009,16 @@ async function startTtsDaemon(warmupCfg) {
|
|
|
18990
19009
|
return;
|
|
18991
19010
|
}
|
|
18992
19011
|
const script = (() => {
|
|
18993
|
-
const distDir =
|
|
18994
|
-
const
|
|
18995
|
-
|
|
18996
|
-
|
|
19012
|
+
const distDir = path38.dirname(new URL(import.meta.url).pathname);
|
|
19013
|
+
const candidates2 = [
|
|
19014
|
+
path38.join(distDir, "..", "python", "tts_daemon.py"),
|
|
19015
|
+
path38.join(process.cwd(), "engine/src/python/tts_daemon.py"),
|
|
18997
19016
|
"/Users/chongzhang/work/twinsun-hearth/engine/src/python/tts_daemon.py"
|
|
18998
19017
|
];
|
|
18999
|
-
for (const c of
|
|
19000
|
-
if (
|
|
19018
|
+
for (const c of candidates2) {
|
|
19019
|
+
if (fs38.existsSync(c)) return c;
|
|
19001
19020
|
}
|
|
19002
|
-
return
|
|
19021
|
+
return candidates2[0];
|
|
19003
19022
|
})();
|
|
19004
19023
|
_log(`spawning ${script}`);
|
|
19005
19024
|
const env = {
|
|
@@ -19069,15 +19088,15 @@ var read_exports = {};
|
|
|
19069
19088
|
__export(read_exports, {
|
|
19070
19089
|
readFileState: () => readFileState
|
|
19071
19090
|
});
|
|
19072
|
-
import * as
|
|
19073
|
-
import * as
|
|
19091
|
+
import * as fs51 from "node:fs";
|
|
19092
|
+
import * as path50 from "node:path";
|
|
19074
19093
|
function isBlockedDevicePath(filePath) {
|
|
19075
19094
|
if (BLOCKED_DEVICE_PATHS.has(filePath)) return true;
|
|
19076
19095
|
if (filePath.startsWith("/proc/") && (filePath.endsWith("/fd/0") || filePath.endsWith("/fd/1") || filePath.endsWith("/fd/2"))) return true;
|
|
19077
19096
|
return false;
|
|
19078
19097
|
}
|
|
19079
19098
|
function checkReadLoop(filePath, offset, limit) {
|
|
19080
|
-
const stat4 =
|
|
19099
|
+
const stat4 = fs51.statSync(filePath);
|
|
19081
19100
|
const mtimeMs = stat4.mtimeMs;
|
|
19082
19101
|
const prev = readHistory.get(filePath);
|
|
19083
19102
|
if (prev && prev.offset === offset && prev.limit === limit && prev.mtimeMs === mtimeMs) {
|
|
@@ -19091,19 +19110,19 @@ function checkReadLoop(filePath, offset, limit) {
|
|
|
19091
19110
|
return null;
|
|
19092
19111
|
}
|
|
19093
19112
|
function readFileContent(filePath) {
|
|
19094
|
-
const fd =
|
|
19113
|
+
const fd = fs51.openSync(filePath, "r");
|
|
19095
19114
|
const bom = Buffer.alloc(2);
|
|
19096
|
-
|
|
19097
|
-
|
|
19115
|
+
fs51.readSync(fd, bom, 0, 2, 0);
|
|
19116
|
+
fs51.closeSync(fd);
|
|
19098
19117
|
let encoding = "utf8";
|
|
19099
19118
|
if (bom[0] === 255 && bom[1] === 254) {
|
|
19100
19119
|
encoding = "utf16le";
|
|
19101
19120
|
}
|
|
19102
|
-
const stat4 =
|
|
19121
|
+
const stat4 = fs51.statSync(filePath);
|
|
19103
19122
|
if (stat4.size > MAX_FILE_SIZE) {
|
|
19104
19123
|
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`);
|
|
19105
19124
|
}
|
|
19106
|
-
const raw =
|
|
19125
|
+
const raw = fs51.readFileSync(filePath, encoding);
|
|
19107
19126
|
const content = raw.toString().replaceAll("\r\n", "\n");
|
|
19108
19127
|
return { content, encoding };
|
|
19109
19128
|
}
|
|
@@ -19245,11 +19264,11 @@ Usage:
|
|
|
19245
19264
|
} catch (e) {
|
|
19246
19265
|
return { content: e.message, isError: true };
|
|
19247
19266
|
}
|
|
19248
|
-
if (!
|
|
19267
|
+
if (!fs51.existsSync(filePath)) {
|
|
19249
19268
|
return { content: `\u6587\u4EF6\u4E0D\u5B58\u5728: ${filePath}`, isError: true };
|
|
19250
19269
|
}
|
|
19251
|
-
const stat4 =
|
|
19252
|
-
const baseName =
|
|
19270
|
+
const stat4 = fs51.statSync(filePath);
|
|
19271
|
+
const baseName = path50.basename(filePath).toUpperCase();
|
|
19253
19272
|
if (BLOCKED_BASENAMES.has(baseName)) {
|
|
19254
19273
|
return { content: `\u8BBE\u5907\u6587\u4EF6\u4E0D\u652F\u6301\u8BFB\u53D6: ${filePath}`, isError: true };
|
|
19255
19274
|
}
|
|
@@ -19257,11 +19276,11 @@ Usage:
|
|
|
19257
19276
|
return { content: `\u8BBE\u5907\u6587\u4EF6\u4F1A\u963B\u585E\u6216\u4EA7\u751F\u65E0\u9650\u8F93\u51FA: ${filePath}`, isError: true };
|
|
19258
19277
|
}
|
|
19259
19278
|
if (stat4.isDirectory()) {
|
|
19260
|
-
const entries2 =
|
|
19279
|
+
const entries2 = fs51.readdirSync(filePath);
|
|
19261
19280
|
const items = entries2.map((e) => {
|
|
19262
|
-
const full =
|
|
19281
|
+
const full = path50.join(filePath, e);
|
|
19263
19282
|
try {
|
|
19264
|
-
const s =
|
|
19283
|
+
const s = fs51.statSync(full);
|
|
19265
19284
|
return s.isDirectory() ? `${e}/` : e;
|
|
19266
19285
|
} catch {
|
|
19267
19286
|
return e;
|
|
@@ -19270,7 +19289,7 @@ Usage:
|
|
|
19270
19289
|
return { content: `\u76EE\u5F55 (${entries2.length} \u9879):
|
|
19271
19290
|
${items.join("\n")}` };
|
|
19272
19291
|
}
|
|
19273
|
-
const ext =
|
|
19292
|
+
const ext = path50.extname(filePath).toLowerCase();
|
|
19274
19293
|
if (BINARY_EXTENSIONS.has(ext)) {
|
|
19275
19294
|
return { content: `\u4E8C\u8FDB\u5236\u6587\u4EF6\u4E0D\u652F\u6301\u8BFB\u53D6 (${ext}): ${filePath}`, isError: true };
|
|
19276
19295
|
}
|
|
@@ -19318,22 +19337,22 @@ ${result}` : result };
|
|
|
19318
19337
|
|
|
19319
19338
|
// src/tools/write.ts
|
|
19320
19339
|
var write_exports = {};
|
|
19321
|
-
import * as
|
|
19322
|
-
import * as
|
|
19340
|
+
import * as fs52 from "node:fs";
|
|
19341
|
+
import * as path51 from "node:path";
|
|
19323
19342
|
function isBlockedPath(filePath) {
|
|
19324
19343
|
return BLOCKED_PATTERNS.some((p) => p.test(filePath));
|
|
19325
19344
|
}
|
|
19326
19345
|
function atomicWrite(filePath, content) {
|
|
19327
19346
|
const tmpPath = filePath + ".tmp." + Date.now() + ".write";
|
|
19328
|
-
|
|
19347
|
+
fs52.writeFileSync(tmpPath, content, "utf-8");
|
|
19329
19348
|
try {
|
|
19330
|
-
|
|
19349
|
+
fs52.renameSync(tmpPath, filePath);
|
|
19331
19350
|
} catch (e) {
|
|
19332
19351
|
try {
|
|
19333
|
-
|
|
19352
|
+
fs52.unlinkSync(tmpPath);
|
|
19334
19353
|
} catch {
|
|
19335
19354
|
}
|
|
19336
|
-
|
|
19355
|
+
fs52.writeFileSync(filePath, content, "utf-8");
|
|
19337
19356
|
}
|
|
19338
19357
|
}
|
|
19339
19358
|
function simpleDiff(oldContent, newContent) {
|
|
@@ -19427,15 +19446,15 @@ Usage:
|
|
|
19427
19446
|
}
|
|
19428
19447
|
const rawContent = args.content;
|
|
19429
19448
|
const content = rawContent.replaceAll("\r\n", "\n");
|
|
19430
|
-
if (
|
|
19449
|
+
if (fs52.existsSync(filePath) && fs52.statSync(filePath).isDirectory()) {
|
|
19431
19450
|
return { content: `\u8DEF\u5F84\u662F\u76EE\u5F55\u4E0D\u662F\u6587\u4EF6: ${filePath}`, isError: true };
|
|
19432
19451
|
}
|
|
19433
19452
|
let oldContent = null;
|
|
19434
19453
|
let isCreate = true;
|
|
19435
|
-
if (
|
|
19454
|
+
if (fs52.existsSync(filePath)) {
|
|
19436
19455
|
isCreate = false;
|
|
19437
19456
|
try {
|
|
19438
|
-
oldContent =
|
|
19457
|
+
oldContent = fs52.readFileSync(filePath, "utf-8").replaceAll("\r\n", "\n");
|
|
19439
19458
|
} catch {
|
|
19440
19459
|
isCreate = true;
|
|
19441
19460
|
}
|
|
@@ -19451,10 +19470,10 @@ Usage:
|
|
|
19451
19470
|
isError: true
|
|
19452
19471
|
};
|
|
19453
19472
|
}
|
|
19454
|
-
const currentStat =
|
|
19473
|
+
const currentStat = fs52.statSync(filePath);
|
|
19455
19474
|
const lastWriteTime = Math.floor(currentStat.mtimeMs);
|
|
19456
19475
|
if (lastWriteTime > readState.timestamp) {
|
|
19457
|
-
const currentContent =
|
|
19476
|
+
const currentContent = fs52.readFileSync(filePath, "utf-8").replaceAll("\r\n", "\n");
|
|
19458
19477
|
if (currentContent !== oldContent) {
|
|
19459
19478
|
return {
|
|
19460
19479
|
content: `\u6587\u4EF6\u5728\u8BFB\u53D6\u540E\u88AB\u4FEE\u6539\u3002\u8BF7\u5148\u91CD\u65B0\u8BFB\u53D6\u6587\u4EF6\u518D\u5199\u5165: ${filePath}`,
|
|
@@ -19463,9 +19482,9 @@ Usage:
|
|
|
19463
19482
|
}
|
|
19464
19483
|
}
|
|
19465
19484
|
}
|
|
19466
|
-
const dir =
|
|
19485
|
+
const dir = path51.dirname(filePath);
|
|
19467
19486
|
try {
|
|
19468
|
-
|
|
19487
|
+
fs52.mkdirSync(dir, { recursive: true });
|
|
19469
19488
|
} catch (e) {
|
|
19470
19489
|
return { content: `\u65E0\u6CD5\u521B\u5EFA\u76EE\u5F55: ${dir} \u2014 ${e.message}`, isError: true };
|
|
19471
19490
|
}
|
|
@@ -19474,11 +19493,11 @@ Usage:
|
|
|
19474
19493
|
} catch (e) {
|
|
19475
19494
|
return { content: `\u5199\u5165\u5931\u8D25: ${e.message}`, isError: true };
|
|
19476
19495
|
}
|
|
19477
|
-
readFileState.set(filePath, { timestamp:
|
|
19496
|
+
readFileState.set(filePath, { timestamp: fs52.statSync(filePath).mtimeMs });
|
|
19478
19497
|
const action = isCreate ? "\u521B\u5EFA" : "\u66F4\u65B0";
|
|
19479
19498
|
const lines = content.split("\n").length;
|
|
19480
19499
|
const chars = content.length;
|
|
19481
|
-
const stat4 =
|
|
19500
|
+
const stat4 = fs52.statSync(filePath);
|
|
19482
19501
|
let diff = "";
|
|
19483
19502
|
if (!isCreate && oldContent !== null) {
|
|
19484
19503
|
diff = `
|
|
@@ -19498,8 +19517,8 @@ ${simpleDiff(oldContent, content)}`;
|
|
|
19498
19517
|
|
|
19499
19518
|
// src/tools/edit.ts
|
|
19500
19519
|
var edit_exports = {};
|
|
19501
|
-
import * as
|
|
19502
|
-
import * as
|
|
19520
|
+
import * as fs53 from "node:fs";
|
|
19521
|
+
import * as path52 from "node:path";
|
|
19503
19522
|
function normalizeQuotes(str) {
|
|
19504
19523
|
return str.replaceAll(LEFT_SINGLE_CURLY, "'").replaceAll(RIGHT_SINGLE_CURLY, "'").replaceAll(LEFT_DOUBLE_CURLY, '"').replaceAll(RIGHT_DOUBLE_CURLY, '"');
|
|
19505
19524
|
}
|
|
@@ -19652,7 +19671,7 @@ Usage:
|
|
|
19652
19671
|
}
|
|
19653
19672
|
let fileContent = null;
|
|
19654
19673
|
try {
|
|
19655
|
-
const stat4 =
|
|
19674
|
+
const stat4 = fs53.statSync(filePath);
|
|
19656
19675
|
if (stat4.isDirectory()) {
|
|
19657
19676
|
return { content: `\u8DEF\u5F84\u662F\u76EE\u5F55\u4E0D\u662F\u6587\u4EF6: ${filePath}`, isError: true };
|
|
19658
19677
|
}
|
|
@@ -19662,21 +19681,21 @@ Usage:
|
|
|
19662
19681
|
} catch (e) {
|
|
19663
19682
|
if (e.code === "ENOENT") {
|
|
19664
19683
|
if (oldString === "") {
|
|
19665
|
-
const dir =
|
|
19666
|
-
|
|
19667
|
-
|
|
19668
|
-
readFileState.set(filePath, { timestamp:
|
|
19684
|
+
const dir = path52.dirname(filePath);
|
|
19685
|
+
fs53.mkdirSync(dir, { recursive: true });
|
|
19686
|
+
fs53.writeFileSync(filePath, newString, "utf-8");
|
|
19687
|
+
readFileState.set(filePath, { timestamp: fs53.statSync(filePath).mtimeMs });
|
|
19669
19688
|
return { content: `\u521B\u5EFA\u6587\u4EF6: ${filePath} (${newString.split("\n").length} \u884C)` };
|
|
19670
19689
|
}
|
|
19671
19690
|
return { content: `\u6587\u4EF6\u4E0D\u5B58\u5728: ${filePath}`, isError: true };
|
|
19672
19691
|
}
|
|
19673
19692
|
throw e;
|
|
19674
19693
|
}
|
|
19675
|
-
const rawContent =
|
|
19694
|
+
const rawContent = fs53.readFileSync(filePath, "utf-8");
|
|
19676
19695
|
fileContent = rawContent.replaceAll("\r\n", "\n");
|
|
19677
19696
|
if (oldString === "" && fileContent.trim() === "") {
|
|
19678
|
-
|
|
19679
|
-
readFileState.set(filePath, { timestamp:
|
|
19697
|
+
fs53.writeFileSync(filePath, newString, "utf-8");
|
|
19698
|
+
readFileState.set(filePath, { timestamp: fs53.statSync(filePath).mtimeMs });
|
|
19680
19699
|
return { content: `\u5199\u5165\u7A7A\u6587\u4EF6: ${filePath} (${newString.split("\n").length} \u884C)` };
|
|
19681
19700
|
}
|
|
19682
19701
|
const readState = readFileState.get(filePath);
|
|
@@ -19686,11 +19705,11 @@ Usage:
|
|
|
19686
19705
|
isError: true
|
|
19687
19706
|
};
|
|
19688
19707
|
}
|
|
19689
|
-
const currentStat =
|
|
19708
|
+
const currentStat = fs53.statSync(filePath);
|
|
19690
19709
|
const lastWriteTime = Math.floor(currentStat.mtimeMs);
|
|
19691
19710
|
if (lastWriteTime > readState.timestamp) {
|
|
19692
19711
|
if (fileContent !== rawContent.replaceAll("\r\n", "\n")) {
|
|
19693
|
-
if (fileContent !==
|
|
19712
|
+
if (fileContent !== fs53.readFileSync(filePath, "utf-8").replaceAll("\r\n", "\n")) {
|
|
19694
19713
|
return {
|
|
19695
19714
|
content: `\u6587\u4EF6\u5728\u8BFB\u53D6\u540E\u88AB\u4FEE\u6539\u3002\u8BF7\u5148\u91CD\u65B0\u8BFB\u53D6\u6587\u4EF6\u518D\u7F16\u8F91: ${filePath}`,
|
|
19696
19715
|
isError: true
|
|
@@ -19722,8 +19741,8 @@ ${preview}
|
|
|
19722
19741
|
const actualNewString = preserveQuoteStyle(oldString, actualOldString, newString);
|
|
19723
19742
|
const diffView = generateEditDiff(fileContent, actualOldString, actualNewString);
|
|
19724
19743
|
const newContent = applyEditToFile(fileContent, actualOldString, actualNewString, replaceAll);
|
|
19725
|
-
|
|
19726
|
-
readFileState.set(filePath, { timestamp:
|
|
19744
|
+
fs53.writeFileSync(filePath, newContent, "utf-8");
|
|
19745
|
+
readFileState.set(filePath, { timestamp: fs53.statSync(filePath).mtimeMs });
|
|
19727
19746
|
const strategy = actualOldString === oldString ? "\u7CBE\u786E\u5339\u914D" : "\u5F15\u53F7\u89C4\u8303\u5316\u5339\u914D";
|
|
19728
19747
|
const count = replaceAll ? matchCount : 1;
|
|
19729
19748
|
const diff = `${oldString.length}\u2192${newString.length}\u5B57\u7B26`;
|
|
@@ -19741,8 +19760,8 @@ ${diffView}`
|
|
|
19741
19760
|
|
|
19742
19761
|
// src/tools/glob.ts
|
|
19743
19762
|
var glob_exports = {};
|
|
19744
|
-
import * as
|
|
19745
|
-
import * as
|
|
19763
|
+
import * as fs54 from "node:fs";
|
|
19764
|
+
import * as path53 from "node:path";
|
|
19746
19765
|
function globMatch(pattern, filename) {
|
|
19747
19766
|
const regexStr = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "{{GLOBSTAR}}").replace(/\*/g, "[^/]*").replace(/\?/g, "[^/]").replace(/\{\{GLOBSTAR\}\}/g, ".*");
|
|
19748
19767
|
try {
|
|
@@ -19762,18 +19781,18 @@ function findFiles(dir, pattern, limit, baseDir) {
|
|
|
19762
19781
|
}
|
|
19763
19782
|
let entries2;
|
|
19764
19783
|
try {
|
|
19765
|
-
entries2 =
|
|
19784
|
+
entries2 = fs54.readdirSync(currentDir, { withFileTypes: true });
|
|
19766
19785
|
} catch {
|
|
19767
19786
|
return;
|
|
19768
19787
|
}
|
|
19769
19788
|
for (const entry of entries2) {
|
|
19770
19789
|
if (truncated) return;
|
|
19771
|
-
const fullPath =
|
|
19790
|
+
const fullPath = path53.join(currentDir, entry.name);
|
|
19772
19791
|
if (entry.isDirectory()) {
|
|
19773
19792
|
if (VCS_DIRS.has(entry.name)) continue;
|
|
19774
19793
|
walk(fullPath);
|
|
19775
19794
|
} else if (entry.isFile()) {
|
|
19776
|
-
const relativePath =
|
|
19795
|
+
const relativePath = path53.relative(baseDir, fullPath).replace(/\\/g, "/");
|
|
19777
19796
|
const patternsToTry = [pattern];
|
|
19778
19797
|
if (pattern.startsWith("**/")) {
|
|
19779
19798
|
patternsToTry.push(pattern.slice(3));
|
|
@@ -19783,7 +19802,7 @@ function findFiles(dir, pattern, limit, baseDir) {
|
|
|
19783
19802
|
);
|
|
19784
19803
|
if (matched) {
|
|
19785
19804
|
try {
|
|
19786
|
-
const stat4 =
|
|
19805
|
+
const stat4 = fs54.statSync(fullPath);
|
|
19787
19806
|
results.push({ path: fullPath, mtimeMs: stat4.mtimeMs });
|
|
19788
19807
|
} catch {
|
|
19789
19808
|
}
|
|
@@ -19800,7 +19819,7 @@ function findFiles(dir, pattern, limit, baseDir) {
|
|
|
19800
19819
|
};
|
|
19801
19820
|
}
|
|
19802
19821
|
function toRelativePath(absolutePath, cwd) {
|
|
19803
|
-
if (absolutePath.startsWith(cwd +
|
|
19822
|
+
if (absolutePath.startsWith(cwd + path53.sep)) {
|
|
19804
19823
|
return absolutePath.slice(cwd.length + 1);
|
|
19805
19824
|
}
|
|
19806
19825
|
return absolutePath;
|
|
@@ -19833,10 +19852,10 @@ var init_glob = __esm({
|
|
|
19833
19852
|
const searchPath = args.path ? resolvePath(args.path, ctx.workspace) : ctx.workspace;
|
|
19834
19853
|
const pattern = args.pattern;
|
|
19835
19854
|
const limit = args.limit || DEFAULT_LIMIT;
|
|
19836
|
-
if (!
|
|
19855
|
+
if (!fs54.existsSync(searchPath)) {
|
|
19837
19856
|
return { content: `\u76EE\u5F55\u4E0D\u5B58\u5728: ${searchPath}`, isError: true };
|
|
19838
19857
|
}
|
|
19839
|
-
if (!
|
|
19858
|
+
if (!fs54.statSync(searchPath).isDirectory()) {
|
|
19840
19859
|
return { content: `\u8DEF\u5F84\u4E0D\u662F\u76EE\u5F55: ${searchPath}`, isError: true };
|
|
19841
19860
|
}
|
|
19842
19861
|
const start = Date.now();
|
|
@@ -19861,7 +19880,7 @@ ${filenames.join("\n")}${truncatedNote}`
|
|
|
19861
19880
|
// src/tools/grep.ts
|
|
19862
19881
|
var grep_exports = {};
|
|
19863
19882
|
import { execFile as execFile4 } from "node:child_process";
|
|
19864
|
-
import * as
|
|
19883
|
+
import * as path54 from "node:path";
|
|
19865
19884
|
function ripGrep(args, searchPath, signal) {
|
|
19866
19885
|
return new Promise((resolve12) => {
|
|
19867
19886
|
const fullArgs = [...args, searchPath];
|
|
@@ -19893,7 +19912,7 @@ function applyHeadLimit(items, limit, offset = 0) {
|
|
|
19893
19912
|
};
|
|
19894
19913
|
}
|
|
19895
19914
|
function toRelativePath2(absolutePath, cwd) {
|
|
19896
|
-
if (absolutePath.startsWith(cwd +
|
|
19915
|
+
if (absolutePath.startsWith(cwd + path54.sep)) {
|
|
19897
19916
|
return absolutePath.slice(cwd.length + 1);
|
|
19898
19917
|
}
|
|
19899
19918
|
if (absolutePath.startsWith(cwd)) {
|
|
@@ -20466,7 +20485,7 @@ var init_builtInAgents = __esm({
|
|
|
20466
20485
|
});
|
|
20467
20486
|
|
|
20468
20487
|
// src/tools/AgentTool/forkSubagent.ts
|
|
20469
|
-
import { randomUUID as
|
|
20488
|
+
import { randomUUID as randomUUID9 } from "crypto";
|
|
20470
20489
|
function isForkSubagentEnabled() {
|
|
20471
20490
|
return true;
|
|
20472
20491
|
}
|
|
@@ -20505,7 +20524,7 @@ function buildForkedMessages(directive, parentMessages) {
|
|
|
20505
20524
|
type: "tool_result",
|
|
20506
20525
|
tool_use_id: block.id,
|
|
20507
20526
|
content: FORK_PLACEHOLDER_RESULT,
|
|
20508
|
-
id: `toolr_${
|
|
20527
|
+
id: `toolr_${randomUUID9().replace(/-/g, "").slice(0, 24)}`
|
|
20509
20528
|
}));
|
|
20510
20529
|
const toolResultMessage = msg_user(
|
|
20511
20530
|
buildChildMessage(directive),
|
|
@@ -20568,10 +20587,10 @@ var init_forkSubagent = __esm({
|
|
|
20568
20587
|
});
|
|
20569
20588
|
|
|
20570
20589
|
// src/tools/AgentTool/runAgent.ts
|
|
20571
|
-
import { randomBytes as
|
|
20590
|
+
import { randomBytes as randomBytes7 } from "node:crypto";
|
|
20572
20591
|
function generateAgentId() {
|
|
20573
20592
|
const prefix = "a";
|
|
20574
|
-
const bytes =
|
|
20593
|
+
const bytes = randomBytes7(8);
|
|
20575
20594
|
let id = prefix;
|
|
20576
20595
|
for (let i = 0; i < 8; i++) {
|
|
20577
20596
|
id += TASK_ID_ALPHABET2[bytes[i] % TASK_ID_ALPHABET2.length];
|
|
@@ -22415,8 +22434,8 @@ __export(manager_exports, {
|
|
|
22415
22434
|
McpManager: () => McpManager,
|
|
22416
22435
|
convertInputSchema: () => convertInputSchema
|
|
22417
22436
|
});
|
|
22418
|
-
import * as
|
|
22419
|
-
import * as
|
|
22437
|
+
import * as fs57 from "node:fs";
|
|
22438
|
+
import * as path57 from "node:path";
|
|
22420
22439
|
import { Client as Client3 } from "@modelcontextprotocol/sdk/client/index.js";
|
|
22421
22440
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
22422
22441
|
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
@@ -22457,12 +22476,12 @@ function convertInputSchema(inputSchema) {
|
|
|
22457
22476
|
}
|
|
22458
22477
|
function persistBinary(base64Data, mimeType, persistId) {
|
|
22459
22478
|
const ext = mimeType?.split("/")[1] || "bin";
|
|
22460
|
-
const dir =
|
|
22461
|
-
|
|
22462
|
-
const filepath =
|
|
22479
|
+
const dir = path57.join(process.env.ENGINE_STATE_DIR || ".engine", "mcp-blobs");
|
|
22480
|
+
fs57.mkdirSync(dir, { recursive: true });
|
|
22481
|
+
const filepath = path57.join(dir, `${persistId}.${ext}`);
|
|
22463
22482
|
try {
|
|
22464
22483
|
const buf = Buffer.from(base64Data, "base64");
|
|
22465
|
-
|
|
22484
|
+
fs57.writeFileSync(filepath, buf);
|
|
22466
22485
|
return { filepath, size: buf.length };
|
|
22467
22486
|
} catch (err) {
|
|
22468
22487
|
return { error: err.message };
|
|
@@ -22796,7 +22815,7 @@ __export(resources_exports, {
|
|
|
22796
22815
|
registerMcpResourceTools: () => registerMcpResourceTools,
|
|
22797
22816
|
unregisterMcpResourceTools: () => unregisterMcpResourceTools
|
|
22798
22817
|
});
|
|
22799
|
-
import * as
|
|
22818
|
+
import * as path58 from "node:path";
|
|
22800
22819
|
function registerMcpResourceTools(manager) {
|
|
22801
22820
|
mcpManagerRef = manager;
|
|
22802
22821
|
registry.register(listResourcesTool);
|
|
@@ -22814,7 +22833,7 @@ var init_resources = __esm({
|
|
|
22814
22833
|
"use strict";
|
|
22815
22834
|
init_registry();
|
|
22816
22835
|
MAX_RESULT_CHARS2 = 1e5;
|
|
22817
|
-
MEDIA_DIR = process.env.ENGINE_MEDIA_DIR ||
|
|
22836
|
+
MEDIA_DIR = process.env.ENGINE_MEDIA_DIR || path58.join(process.env.ENGINE_STATE_DIR || ".engine", "media", "inbound");
|
|
22818
22837
|
MCP_LIST_RESOURCES_TOOL = "mcp__list_resources";
|
|
22819
22838
|
MCP_READ_RESOURCE_TOOL = "mcp__read_resource";
|
|
22820
22839
|
mcpManagerRef = null;
|
|
@@ -22902,7 +22921,7 @@ ${lines.join("\n\n")}`;
|
|
|
22902
22921
|
// src/engine-startup.ts
|
|
22903
22922
|
init_query();
|
|
22904
22923
|
init_live();
|
|
22905
|
-
import * as
|
|
22924
|
+
import * as path59 from "node:path";
|
|
22906
22925
|
|
|
22907
22926
|
// src/startup/providers.ts
|
|
22908
22927
|
init_provider_factory();
|
|
@@ -24284,7 +24303,7 @@ ${formatted}` };
|
|
|
24284
24303
|
};
|
|
24285
24304
|
}
|
|
24286
24305
|
function createEverosGetTool() {
|
|
24287
|
-
const
|
|
24306
|
+
const fs58 = __require("node:fs/promises");
|
|
24288
24307
|
return {
|
|
24289
24308
|
name: "memory_get",
|
|
24290
24309
|
description: "Read a memory file by path.",
|
|
@@ -24300,7 +24319,7 @@ function createEverosGetTool() {
|
|
|
24300
24319
|
handler: async (args) => {
|
|
24301
24320
|
try {
|
|
24302
24321
|
const filePath = args.path;
|
|
24303
|
-
const content = await
|
|
24322
|
+
const content = await fs58.readFile(filePath, "utf-8");
|
|
24304
24323
|
const lines = content.split("\n");
|
|
24305
24324
|
const fromLine = args.from ?? 1;
|
|
24306
24325
|
const numLines = args.lines ?? lines.length;
|
|
@@ -25647,9 +25666,9 @@ function readDbEmbeddings(dbPath) {
|
|
|
25647
25666
|
db2.close();
|
|
25648
25667
|
}
|
|
25649
25668
|
}
|
|
25650
|
-
async function llmRerank(query,
|
|
25651
|
-
if (
|
|
25652
|
-
const manifest =
|
|
25669
|
+
async function llmRerank(query, candidates2, topK, ollamaChatUrl, model) {
|
|
25670
|
+
if (candidates2.length <= topK) return candidates2;
|
|
25671
|
+
const manifest = candidates2.map(
|
|
25653
25672
|
(c, i) => `${i + 1}. ${c.filename}
|
|
25654
25673
|
${c.description || c.name}`
|
|
25655
25674
|
).join("\n");
|
|
@@ -25681,7 +25700,7 @@ Select up to ${topK} most relevant (return their 1-indexed numbers as JSON {"sel
|
|
|
25681
25700
|
});
|
|
25682
25701
|
if (!resp.ok) {
|
|
25683
25702
|
console.warn(`[memdir] rerank: ollama chat failed: ${resp.status}`);
|
|
25684
|
-
return
|
|
25703
|
+
return candidates2.slice(0, topK);
|
|
25685
25704
|
}
|
|
25686
25705
|
const data = await resp.json();
|
|
25687
25706
|
const text = data?.message?.content ?? "";
|
|
@@ -25690,19 +25709,19 @@ Select up to ${topK} most relevant (return their 1-indexed numbers as JSON {"sel
|
|
|
25690
25709
|
try {
|
|
25691
25710
|
const parsed = JSON.parse(jsonMatch[0]);
|
|
25692
25711
|
if (parsed.selected && Array.isArray(parsed.selected)) {
|
|
25693
|
-
const indices = parsed.selected.filter((n) => n >= 1 && n <=
|
|
25694
|
-
const result = indices.map((i) =>
|
|
25695
|
-
console.log(`[memdir] rerank: ${model} selected ${result.length}/${
|
|
25712
|
+
const indices = parsed.selected.filter((n) => n >= 1 && n <= candidates2.length).map((n) => n - 1);
|
|
25713
|
+
const result = indices.map((i) => candidates2[i]);
|
|
25714
|
+
console.log(`[memdir] rerank: ${model} selected ${result.length}/${candidates2.length} candidates (indices: ${indices.map((i) => i + 1).join(",")})`);
|
|
25696
25715
|
return result.slice(0, topK);
|
|
25697
25716
|
}
|
|
25698
25717
|
} catch {
|
|
25699
25718
|
}
|
|
25700
25719
|
}
|
|
25701
25720
|
console.warn(`[memdir] rerank: no valid JSON in response (${text.length} chars), falling back to vector order`);
|
|
25702
|
-
return
|
|
25721
|
+
return candidates2.slice(0, topK);
|
|
25703
25722
|
} catch (e) {
|
|
25704
25723
|
console.warn(`[memdir] rerank: error: ${e?.message ?? e}, falling back to vector order`);
|
|
25705
|
-
return
|
|
25724
|
+
return candidates2.slice(0, topK);
|
|
25706
25725
|
}
|
|
25707
25726
|
}
|
|
25708
25727
|
async function findRelevantMemoriesVector(query, memoryDir, alreadySurfaced = /* @__PURE__ */ new Set(), options) {
|
|
@@ -25751,17 +25770,17 @@ async function findRelevantMemoriesVector(query, memoryDir, alreadySurfaced = /*
|
|
|
25751
25770
|
}
|
|
25752
25771
|
}
|
|
25753
25772
|
scored.sort((a, b) => b.score - a.score);
|
|
25754
|
-
const
|
|
25773
|
+
const candidates2 = scored.slice(0, CANDIDATE_POOL);
|
|
25755
25774
|
const vectorMs = Date.now() - t0;
|
|
25756
25775
|
console.log(
|
|
25757
|
-
`[memdir] vector recall: ${
|
|
25776
|
+
`[memdir] vector recall: ${candidates2.length} candidates in ${vectorMs}ms (embed=${embedMs}ms, scanned=${rows.length} files, minScore=${minScore})`
|
|
25758
25777
|
);
|
|
25759
|
-
if (
|
|
25760
|
-
console.log(`[memdir] vector top scores: ${
|
|
25778
|
+
if (candidates2.length > 0) {
|
|
25779
|
+
console.log(`[memdir] vector top scores: ${candidates2.slice(0, 5).map((r) => `${r.filename}=${r.score.toFixed(3)}`).join(", ")}${candidates2.length > 5 ? "..." : ""}`);
|
|
25761
25780
|
}
|
|
25762
|
-
if (
|
|
25781
|
+
if (candidates2.length === 0) return [];
|
|
25763
25782
|
const rerankT0 = Date.now();
|
|
25764
|
-
const reranked = await llmRerank(query,
|
|
25783
|
+
const reranked = await llmRerank(query, candidates2, topK, DEFAULT_OLLAMA_CHAT_URL, rerankModel);
|
|
25765
25784
|
const rerankMs = Date.now() - rerankT0;
|
|
25766
25785
|
const totalMs = Date.now() - t0;
|
|
25767
25786
|
console.log(`[memdir] recall total: ${totalMs}ms (vector=${vectorMs}ms, rerank=${rerankMs}ms)`);
|
|
@@ -26188,18 +26207,18 @@ function resetSessionStartInjection(sessionId) {
|
|
|
26188
26207
|
}
|
|
26189
26208
|
var externalChanRulesCache = null;
|
|
26190
26209
|
function loadExternalChanRules(workspace) {
|
|
26191
|
-
const
|
|
26192
|
-
if (externalChanRulesCache && externalChanRulesCache.path ===
|
|
26210
|
+
const path60 = join36(workspace, "prompts", "external-chan-rules.md");
|
|
26211
|
+
if (externalChanRulesCache && externalChanRulesCache.path === path60) return externalChanRulesCache;
|
|
26193
26212
|
let content = "";
|
|
26194
|
-
if (existsSync19(
|
|
26213
|
+
if (existsSync19(path60)) {
|
|
26195
26214
|
try {
|
|
26196
|
-
content = readFileSync26(
|
|
26215
|
+
content = readFileSync26(path60, "utf-8").trim();
|
|
26197
26216
|
} catch (e) {
|
|
26198
26217
|
console.warn(`[external-chan-rules] Failed to load: ${e}`);
|
|
26199
26218
|
}
|
|
26200
26219
|
}
|
|
26201
|
-
externalChanRulesCache = { path:
|
|
26202
|
-
console.log(`[external-chan-rules] Loaded ${content.length} chars from ${
|
|
26220
|
+
externalChanRulesCache = { path: path60, content };
|
|
26221
|
+
console.log(`[external-chan-rules] Loaded ${content.length} chars from ${path60}`);
|
|
26203
26222
|
return externalChanRulesCache;
|
|
26204
26223
|
}
|
|
26205
26224
|
function getExternalChanRulesBlock(inboundMeta, workspace) {
|
|
@@ -27086,15 +27105,15 @@ function registerCompactHooks(config) {
|
|
|
27086
27105
|
const dailyDir = path22.join(workspace, "memory", "daily");
|
|
27087
27106
|
const dailyPath = path22.join(dailyDir, `${dateStr}.md`);
|
|
27088
27107
|
try {
|
|
27089
|
-
const
|
|
27090
|
-
if (!
|
|
27091
|
-
|
|
27108
|
+
const fs58 = await import("node:fs");
|
|
27109
|
+
if (!fs58.existsSync(dailyDir)) {
|
|
27110
|
+
fs58.mkdirSync(dailyDir, { recursive: true });
|
|
27092
27111
|
}
|
|
27093
27112
|
const sessionsDir = path22.join(config.stateDir, "agents", "main", "sessions");
|
|
27094
27113
|
const sessionFile = path22.join(sessionsDir, `${sessionId}.jsonl`);
|
|
27095
27114
|
const recentLines = [];
|
|
27096
|
-
if (
|
|
27097
|
-
const content =
|
|
27115
|
+
if (fs58.existsSync(sessionFile)) {
|
|
27116
|
+
const content = fs58.readFileSync(sessionFile, "utf-8");
|
|
27098
27117
|
const lines = content.trim().split("\n").filter(Boolean);
|
|
27099
27118
|
const userLines = lines.filter((l) => {
|
|
27100
27119
|
try {
|
|
@@ -27124,10 +27143,10 @@ function registerCompactHooks(config) {
|
|
|
27124
27143
|
const entry = `${header}
|
|
27125
27144
|
${body}
|
|
27126
27145
|
`;
|
|
27127
|
-
if (
|
|
27128
|
-
|
|
27146
|
+
if (fs58.existsSync(dailyPath)) {
|
|
27147
|
+
fs58.appendFileSync(dailyPath, entry);
|
|
27129
27148
|
} else {
|
|
27130
|
-
|
|
27149
|
+
fs58.writeFileSync(dailyPath, `# ${dateStr} \u65E5\u5FD7
|
|
27131
27150
|
${entry}`);
|
|
27132
27151
|
}
|
|
27133
27152
|
console.log(`[hooks] PreCompact: saved ${recentLines.length} lines to ${dailyPath}`);
|
|
@@ -27143,16 +27162,16 @@ ${entry}`);
|
|
|
27143
27162
|
const workspace = input.cwd || input.workspace || "";
|
|
27144
27163
|
if (!workspace) return { continue: true };
|
|
27145
27164
|
try {
|
|
27146
|
-
const
|
|
27165
|
+
const fs58 = await import("node:fs");
|
|
27147
27166
|
const bufferPath = path22.join(workspace, "memory", "working-buffer.md");
|
|
27148
|
-
if (
|
|
27149
|
-
const stat4 =
|
|
27167
|
+
if (fs58.existsSync(bufferPath)) {
|
|
27168
|
+
const stat4 = fs58.statSync(bufferPath);
|
|
27150
27169
|
const ageMs = Date.now() - stat4.mtimeMs;
|
|
27151
27170
|
const ageMin = Math.round(ageMs / 6e4);
|
|
27152
27171
|
if (ageMin > 10) {
|
|
27153
27172
|
console.warn(`[hooks] PostCompact: \u26A0\uFE0F working-buffer.md is ${ageMin}min old (last modified ${stat4.mtime.toISOString()}) \u2014 content may be stale!`);
|
|
27154
27173
|
}
|
|
27155
|
-
const content =
|
|
27174
|
+
const content = fs58.readFileSync(bufferPath, "utf-8");
|
|
27156
27175
|
if (content.trim()) {
|
|
27157
27176
|
console.log(`[hooks] PostCompact: injecting working-buffer (${content.length} chars, ${ageMin}min old)`);
|
|
27158
27177
|
return {
|
|
@@ -30529,6 +30548,8 @@ function startInboxPoller(ctx) {
|
|
|
30529
30548
|
const INBOX_POLL_INTERVAL_MS = 2e3;
|
|
30530
30549
|
const INBOX_IDLE_INTERVAL_MS = 3e4;
|
|
30531
30550
|
let pollCycleCount = 0;
|
|
30551
|
+
let lastStatusLine = "";
|
|
30552
|
+
let warnedNoPreview = false;
|
|
30532
30553
|
let inboxPollerTimer = null;
|
|
30533
30554
|
let inboxPollerStandby = false;
|
|
30534
30555
|
function runInboxPollCycle() {
|
|
@@ -30565,7 +30586,11 @@ function startInboxPoller(ctx) {
|
|
|
30565
30586
|
).join(" ");
|
|
30566
30587
|
const isMainActive = dispatcher.isActive("main");
|
|
30567
30588
|
const mainPending = dispatcher.pendingCount("main");
|
|
30568
|
-
|
|
30589
|
+
const statusLine = `teammates=[${statusSummary}] mainActive=${isMainActive} mainPending=${mainPending}`;
|
|
30590
|
+
if (statusLine !== lastStatusLine || pollCycleCount % 15 === 0) {
|
|
30591
|
+
lastStatusLine = statusLine;
|
|
30592
|
+
console.log(`[inbox-poller] #${pollCycleCount} ${statusLine}`);
|
|
30593
|
+
}
|
|
30569
30594
|
const now = Date.now();
|
|
30570
30595
|
const allTeamNames = new Set(teammates.filter((t) => t.status !== "killed").map((t) => t.identity.teamName));
|
|
30571
30596
|
const teams = [...allTeamNames];
|
|
@@ -30643,7 +30668,6 @@ function startInboxPoller(ctx) {
|
|
|
30643
30668
|
${notifications}
|
|
30644
30669
|
[/teammate-status]${taskSummary}`;
|
|
30645
30670
|
const inboxTarget = "";
|
|
30646
|
-
const inboxPreview = null;
|
|
30647
30671
|
const submitted = dispatcher.submitMessage({
|
|
30648
30672
|
text: queryContent,
|
|
30649
30673
|
sessionId: "main",
|
|
@@ -30653,21 +30677,12 @@ ${notifications}
|
|
|
30653
30677
|
priority: "next",
|
|
30654
30678
|
// 对齐 CC: idle 时立即提交,不是 'later' 排队
|
|
30655
30679
|
callbacks: {
|
|
30656
|
-
onText: (
|
|
30657
|
-
if (
|
|
30658
|
-
|
|
30659
|
-
|
|
30660
|
-
console.warn(`[inbox-poller:onText] no preview target, Discord output dropped (${text.length} chars)`);
|
|
30661
|
-
}
|
|
30680
|
+
onText: (_text) => {
|
|
30681
|
+
if (warnedNoPreview) return;
|
|
30682
|
+
warnedNoPreview = true;
|
|
30683
|
+
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");
|
|
30662
30684
|
},
|
|
30663
|
-
onResult: async (
|
|
30664
|
-
if (inboxPreview) {
|
|
30665
|
-
const delivered = await inboxPreview.finish(content.trim() || "(\u5904\u7406\u5B8C\u6210)");
|
|
30666
|
-
if (!delivered && inboxTarget) {
|
|
30667
|
-
channelManager.send("discord", inboxTarget, content.trim() || "(\u5904\u7406\u5B8C\u6210)").catch(() => {
|
|
30668
|
-
});
|
|
30669
|
-
}
|
|
30670
|
-
}
|
|
30685
|
+
onResult: async (_content) => {
|
|
30671
30686
|
}
|
|
30672
30687
|
},
|
|
30673
30688
|
deps
|
|
@@ -31361,8 +31376,8 @@ var VoiceChatPlugin = class {
|
|
|
31361
31376
|
// src/memory/everos/plugin.ts
|
|
31362
31377
|
import { spawn as spawn4 } from "node:child_process";
|
|
31363
31378
|
import net from "node:net";
|
|
31364
|
-
import
|
|
31365
|
-
import
|
|
31379
|
+
import path35 from "node:path";
|
|
31380
|
+
import fs35 from "node:fs";
|
|
31366
31381
|
|
|
31367
31382
|
// src/memory/everos/config.ts
|
|
31368
31383
|
var DEFAULTS4 = {
|
|
@@ -31596,8 +31611,8 @@ var EverosPlugin = class {
|
|
|
31596
31611
|
}, 3e5);
|
|
31597
31612
|
}
|
|
31598
31613
|
async startEveros() {
|
|
31599
|
-
const pythonDir =
|
|
31600
|
-
const configPath =
|
|
31614
|
+
const pythonDir = path35.dirname(this.config.lancedbPath);
|
|
31615
|
+
const configPath = path35.join(pythonDir, "config.toml");
|
|
31601
31616
|
await this.ensureFcntlCompat();
|
|
31602
31617
|
const venvPython = this.findVenvPython();
|
|
31603
31618
|
const everosBin = venvPython.replace(/python\.exe$/, "everos.exe");
|
|
@@ -31687,19 +31702,19 @@ var EverosPlugin = class {
|
|
|
31687
31702
|
return child;
|
|
31688
31703
|
}
|
|
31689
31704
|
findVenvPython() {
|
|
31690
|
-
const stateDir = process.env.ENGINE7_STATE_DIR ||
|
|
31705
|
+
const stateDir = process.env.ENGINE7_STATE_DIR || path35.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7");
|
|
31691
31706
|
if (process.platform === "win32") {
|
|
31692
|
-
return
|
|
31707
|
+
return path35.join(stateDir, "everos-venv", "Scripts", "python.exe");
|
|
31693
31708
|
}
|
|
31694
|
-
return
|
|
31709
|
+
return path35.join(stateDir, "everos-venv", "bin", "python");
|
|
31695
31710
|
}
|
|
31696
31711
|
/** 检测 venv 是否存在,不存在就自动创建 + 装 EverOS */
|
|
31697
31712
|
async ensureVenv() {
|
|
31698
31713
|
const venvPython = this.findVenvPython();
|
|
31699
|
-
if (
|
|
31700
|
-
const stateDir = process.env.ENGINE7_STATE_DIR ||
|
|
31701
|
-
const venvDir =
|
|
31702
|
-
const everosSrc =
|
|
31714
|
+
if (fs35.existsSync(venvPython)) return;
|
|
31715
|
+
const stateDir = process.env.ENGINE7_STATE_DIR || path35.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7");
|
|
31716
|
+
const venvDir = path35.join(stateDir, "everos-venv");
|
|
31717
|
+
const everosSrc = path35.join(stateDir, "workspace", "research", "EverOS");
|
|
31703
31718
|
console.log(`[everos] venv not found at ${venvDir}, auto-creating...`);
|
|
31704
31719
|
console.log(`[everos] \u23F3 This may take a few minutes on first run...`);
|
|
31705
31720
|
const pyCandidates = process.platform === "win32" ? ["python", "python3", "C:\\Python314\\python.exe", "C:\\Python313\\python.exe", "C:\\Python312\\python.exe"] : ["python3", "python"];
|
|
@@ -31721,9 +31736,9 @@ var EverosPlugin = class {
|
|
|
31721
31736
|
console.log(`[everos] Creating venv with ${sysPython}...`);
|
|
31722
31737
|
const { execSync: execSync3 } = await import("node:child_process");
|
|
31723
31738
|
execSync3(`"${sysPython}" -m venv "${venvDir}"`, { stdio: "pipe", shell: true });
|
|
31724
|
-
const pip = process.platform === "win32" ?
|
|
31725
|
-
const everosReq =
|
|
31726
|
-
if (
|
|
31739
|
+
const pip = process.platform === "win32" ? path35.join(venvDir, "Scripts", "pip.exe") : path35.join(venvDir, "bin", "pip");
|
|
31740
|
+
const everosReq = path35.join(this.getPythonDir(), "requirements.txt");
|
|
31741
|
+
if (fs35.existsSync(everosReq)) {
|
|
31727
31742
|
console.log(`[everos] Installing from requirements.txt...`);
|
|
31728
31743
|
execSync3(`"${pip}" install -r "${everosReq}" -q`, { stdio: "pipe", shell: true, timeout: 3e5 });
|
|
31729
31744
|
} else {
|
|
@@ -31738,29 +31753,29 @@ var EverosPlugin = class {
|
|
|
31738
31753
|
}
|
|
31739
31754
|
getPythonDir() {
|
|
31740
31755
|
const dir = import.meta.dirname;
|
|
31741
|
-
const
|
|
31742
|
-
|
|
31743
|
-
|
|
31744
|
-
|
|
31756
|
+
const candidates2 = [
|
|
31757
|
+
path35.join(dir, "python"),
|
|
31758
|
+
path35.resolve(dir, "..", "src", "memory", "everos", "python"),
|
|
31759
|
+
path35.resolve(dir, "..", "..", "..", "src", "memory", "everos", "python")
|
|
31745
31760
|
];
|
|
31746
|
-
for (const candidate of
|
|
31747
|
-
if (
|
|
31761
|
+
for (const candidate of candidates2) {
|
|
31762
|
+
if (fs35.existsSync(path35.join(candidate, "agentic_server.py"))) {
|
|
31748
31763
|
return candidate;
|
|
31749
31764
|
}
|
|
31750
31765
|
}
|
|
31751
|
-
return
|
|
31766
|
+
return candidates2[0];
|
|
31752
31767
|
}
|
|
31753
31768
|
async ensureFcntlCompat() {
|
|
31754
31769
|
if (process.platform !== "win32") return;
|
|
31755
31770
|
const venvPython = this.findVenvPython();
|
|
31756
|
-
const venvDir =
|
|
31757
|
-
const sitePackages =
|
|
31758
|
-
const target =
|
|
31759
|
-
if (
|
|
31760
|
-
const source =
|
|
31761
|
-
if (
|
|
31771
|
+
const venvDir = path35.dirname(path35.dirname(venvPython));
|
|
31772
|
+
const sitePackages = path35.join(venvDir, "Lib", "site-packages");
|
|
31773
|
+
const target = path35.join(sitePackages, "fcntl.py");
|
|
31774
|
+
if (fs35.existsSync(target)) return;
|
|
31775
|
+
const source = path35.join(this.getPythonDir(), "fcntl_compat.py");
|
|
31776
|
+
if (fs35.existsSync(source)) {
|
|
31762
31777
|
try {
|
|
31763
|
-
|
|
31778
|
+
fs35.copyFileSync(source, target);
|
|
31764
31779
|
console.log(`[everos] Installed fcntl compat shim to ${target}`);
|
|
31765
31780
|
} catch (err) {
|
|
31766
31781
|
console.warn(`[everos] Failed to install fcntl shim: ${err.message}`);
|
|
@@ -32369,8 +32384,8 @@ function createVisualBoot(ctx) {
|
|
|
32369
32384
|
}
|
|
32370
32385
|
|
|
32371
32386
|
// src/startup/message-pipeline.ts
|
|
32372
|
-
import * as
|
|
32373
|
-
import * as
|
|
32387
|
+
import * as fs36 from "node:fs";
|
|
32388
|
+
import * as path36 from "node:path";
|
|
32374
32389
|
|
|
32375
32390
|
// src/commands/registry.ts
|
|
32376
32391
|
var commands = /* @__PURE__ */ new Map();
|
|
@@ -33261,7 +33276,7 @@ function setupMessagePipeline(ctx) {
|
|
|
33261
33276
|
console.log(`[vision] Downloading image: ${att.filename}`);
|
|
33262
33277
|
let rawBuffer;
|
|
33263
33278
|
if (att.url.startsWith("file://")) {
|
|
33264
|
-
rawBuffer =
|
|
33279
|
+
rawBuffer = fs36.readFileSync(decodeURIComponent(att.url.slice(7)));
|
|
33265
33280
|
} else {
|
|
33266
33281
|
rawBuffer = await downloadImage2(att.url, attachDispatcher);
|
|
33267
33282
|
}
|
|
@@ -33269,8 +33284,8 @@ function setupMessagePipeline(ctx) {
|
|
|
33269
33284
|
const ext = detected.split("/")[1] || "png";
|
|
33270
33285
|
const resized = await maybeResizeAndDownsampleImageBuffer2(rawBuffer, rawBuffer.length, ext);
|
|
33271
33286
|
const imageId = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
33272
|
-
const savedPath =
|
|
33273
|
-
|
|
33287
|
+
const savedPath = path36.join(config.mediaDir, `${imageId}.${ext}`);
|
|
33288
|
+
fs36.writeFileSync(savedPath, resized.buffer);
|
|
33274
33289
|
savedPaths.push(savedPath);
|
|
33275
33290
|
console.log(`[vision] Saved: ${savedPath} (${resized.buffer.length}B)`);
|
|
33276
33291
|
imageBlocks.push({
|
|
@@ -33300,8 +33315,8 @@ ${pathStr}` }];
|
|
|
33300
33315
|
}
|
|
33301
33316
|
const nonImageAttachments = inbound.attachments?.filter((a) => !a.contentType.startsWith("image/"));
|
|
33302
33317
|
if (nonImageAttachments && nonImageAttachments.length > 0) {
|
|
33303
|
-
const outDir =
|
|
33304
|
-
|
|
33318
|
+
const outDir = path36.join(config.mediaDir, sessionId);
|
|
33319
|
+
fs36.mkdirSync(outDir, { recursive: true });
|
|
33305
33320
|
const resolved = [];
|
|
33306
33321
|
for (const att of nonImageAttachments) {
|
|
33307
33322
|
console.log(`[file] Downloading: ${att.filename} (${att.contentType}, ${att.size}B)`);
|
|
@@ -33309,9 +33324,9 @@ ${pathStr}` }];
|
|
|
33309
33324
|
const resp = attachDispatcher ? await fetch(att.url, { dispatcher: attachDispatcher, signal: AbortSignal.timeout(3e4) }) : await fetch(att.url, { signal: AbortSignal.timeout(3e4) });
|
|
33310
33325
|
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
|
|
33311
33326
|
const buffer = Buffer.from(await resp.arrayBuffer());
|
|
33312
|
-
const safeName2 =
|
|
33313
|
-
const savedPath =
|
|
33314
|
-
|
|
33327
|
+
const safeName2 = path36.basename(att.filename).replace(/[<>:"/\\|?*\x00-\x1f]/g, "_") || "attachment";
|
|
33328
|
+
const savedPath = path36.join(outDir, safeName2);
|
|
33329
|
+
fs36.writeFileSync(savedPath, buffer);
|
|
33315
33330
|
resolved.push(savedPath);
|
|
33316
33331
|
console.log(`[file] Saved: ${savedPath} (${buffer.length}B)`);
|
|
33317
33332
|
} catch (err) {
|
|
@@ -33560,6 +33575,7 @@ ${pathStr}` }];
|
|
|
33560
33575
|
init_live();
|
|
33561
33576
|
|
|
33562
33577
|
// src/provision-free.ts
|
|
33578
|
+
import { randomBytes as randomBytes4, randomUUID as randomUUID6 } from "node:crypto";
|
|
33563
33579
|
import { chmodSync, existsSync as existsSync23, mkdirSync as mkdirSync15, readFileSync as readFileSync34, writeFileSync as writeFileSync12 } from "node:fs";
|
|
33564
33580
|
import { dirname as dirname11, join as join46 } from "node:path";
|
|
33565
33581
|
import { fileURLToPath as fileURLToPath7 } from "node:url";
|
|
@@ -33568,19 +33584,68 @@ var IDENTITY_FILE = "install-identity.json";
|
|
|
33568
33584
|
function readContactEmailOf(parsed) {
|
|
33569
33585
|
return typeof parsed?.contactEmail === "string" ? parsed.contactEmail.trim() : "";
|
|
33570
33586
|
}
|
|
33571
|
-
function
|
|
33572
|
-
|
|
33573
|
-
|
|
33574
|
-
|
|
33587
|
+
function loadOrCreateInstallIdentity(stateDir) {
|
|
33588
|
+
const file2 = join46(stateDir, IDENTITY_FILE);
|
|
33589
|
+
if (existsSync23(file2)) {
|
|
33590
|
+
let parsed;
|
|
33591
|
+
try {
|
|
33592
|
+
parsed = JSON.parse(readFileSync34(file2, "utf8"));
|
|
33593
|
+
} catch (e) {
|
|
33594
|
+
throw new Error(
|
|
33595
|
+
`${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`
|
|
33596
|
+
);
|
|
33597
|
+
}
|
|
33598
|
+
if (typeof parsed?.installId !== "string" || typeof parsed?.installSecret !== "string") {
|
|
33599
|
+
throw new Error(`${IDENTITY_FILE} \u7F3A installId / installSecret \u5B57\u6BB5`);
|
|
33600
|
+
}
|
|
33575
33601
|
const email = readContactEmailOf(parsed);
|
|
33576
33602
|
return {
|
|
33577
33603
|
installId: parsed.installId,
|
|
33578
33604
|
installSecret: parsed.installSecret,
|
|
33579
33605
|
...email ? { contactEmail: email } : {}
|
|
33580
33606
|
};
|
|
33607
|
+
}
|
|
33608
|
+
const identity = {
|
|
33609
|
+
// 服务端校验 installId 长度为 8..36、只允许字母数字和连字符;uuid 正好符合
|
|
33610
|
+
installId: randomUUID6(),
|
|
33611
|
+
// 服务端校验 installSecret 为 32..64 位十六进制
|
|
33612
|
+
installSecret: randomBytes4(32).toString("hex")
|
|
33613
|
+
};
|
|
33614
|
+
mkdirSync15(stateDir, { recursive: true });
|
|
33615
|
+
writeFileSync12(file2, JSON.stringify(identity, null, 2) + "\n", { mode: 384 });
|
|
33616
|
+
try {
|
|
33617
|
+
chmodSync(file2, 384);
|
|
33581
33618
|
} catch {
|
|
33582
|
-
return null;
|
|
33583
33619
|
}
|
|
33620
|
+
return identity;
|
|
33621
|
+
}
|
|
33622
|
+
function readInstallIdentityDetailed(stateDir) {
|
|
33623
|
+
const file2 = join46(stateDir, IDENTITY_FILE);
|
|
33624
|
+
if (!existsSync23(file2)) return { ok: false, reason: "missing" };
|
|
33625
|
+
let text;
|
|
33626
|
+
try {
|
|
33627
|
+
text = readFileSync34(file2, "utf8");
|
|
33628
|
+
} catch (e) {
|
|
33629
|
+
return { ok: false, reason: "corrupt", detail: `\u5B58\u5728\u4F46\u8BFB\u4E0D\u4E86\uFF08${e?.message ?? e}\uFF09` };
|
|
33630
|
+
}
|
|
33631
|
+
let parsed;
|
|
33632
|
+
try {
|
|
33633
|
+
parsed = JSON.parse(text);
|
|
33634
|
+
} catch (e) {
|
|
33635
|
+
return { ok: false, reason: "corrupt", detail: `\u4E0D\u662F\u5408\u6CD5 JSON\uFF08${e?.message ?? e}\uFF09` };
|
|
33636
|
+
}
|
|
33637
|
+
if (typeof parsed?.installId !== "string" || typeof parsed?.installSecret !== "string") {
|
|
33638
|
+
return { ok: false, reason: "corrupt", detail: "\u7F3A installId / installSecret \u5B57\u6BB5" };
|
|
33639
|
+
}
|
|
33640
|
+
const email = readContactEmailOf(parsed);
|
|
33641
|
+
return {
|
|
33642
|
+
ok: true,
|
|
33643
|
+
identity: {
|
|
33644
|
+
installId: parsed.installId,
|
|
33645
|
+
installSecret: parsed.installSecret,
|
|
33646
|
+
...email ? { contactEmail: email } : {}
|
|
33647
|
+
}
|
|
33648
|
+
};
|
|
33584
33649
|
}
|
|
33585
33650
|
|
|
33586
33651
|
// src/optional/reporting/state.ts
|
|
@@ -33756,13 +33821,23 @@ function startReporting(opts) {
|
|
|
33756
33821
|
const log = opts.log ?? (() => {
|
|
33757
33822
|
});
|
|
33758
33823
|
const startedAt = nowFn3();
|
|
33759
|
-
const
|
|
33760
|
-
|
|
33761
|
-
|
|
33762
|
-
|
|
33763
|
-
|
|
33764
|
-
|
|
33824
|
+
const identityRead = readInstallIdentityDetailed(stateDir);
|
|
33825
|
+
let maybeIdentity = null;
|
|
33826
|
+
if (identityRead.ok) {
|
|
33827
|
+
maybeIdentity = identityRead.identity;
|
|
33828
|
+
} else if (identityRead.reason === "missing") {
|
|
33829
|
+
try {
|
|
33830
|
+
maybeIdentity = loadOrCreateInstallIdentity(stateDir);
|
|
33831
|
+
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");
|
|
33832
|
+
} catch (e) {
|
|
33833
|
+
log(`[reporting] \u8865\u5EFA\u88C5\u673A\u8EAB\u4EFD\u5931\u8D25\uFF1A${e?.message ?? e} \u2014\u2014 \u4E0A\u62A5\u5173\u95ED`);
|
|
33834
|
+
}
|
|
33835
|
+
} else {
|
|
33836
|
+
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`);
|
|
33765
33837
|
}
|
|
33838
|
+
if (!maybeIdentity) return { stop() {
|
|
33839
|
+
}, async beatNow() {
|
|
33840
|
+
} };
|
|
33766
33841
|
const identity = maybeIdentity;
|
|
33767
33842
|
const bootState = readReportState(stateDir);
|
|
33768
33843
|
restoreCounters(bootState);
|
|
@@ -33987,13 +34062,13 @@ var DiscordAdapter = class _DiscordAdapter {
|
|
|
33987
34062
|
}
|
|
33988
34063
|
/** 发送媒体附件(图片/文件/音频)— discord.js channel.send({ files }) */
|
|
33989
34064
|
async sendFile(target, message, attachment) {
|
|
33990
|
-
const
|
|
33991
|
-
const
|
|
33992
|
-
if (!
|
|
34065
|
+
const fs58 = await import("node:fs");
|
|
34066
|
+
const path60 = await import("node:path");
|
|
34067
|
+
if (!fs58.existsSync(attachment.path)) {
|
|
33993
34068
|
throw new Error(`File not found: ${attachment.path}`);
|
|
33994
34069
|
}
|
|
33995
|
-
const filename = attachment.filename ||
|
|
33996
|
-
const fileBuffer =
|
|
34070
|
+
const filename = attachment.filename || path60.basename(attachment.path);
|
|
34071
|
+
const fileBuffer = fs58.readFileSync(attachment.path);
|
|
33997
34072
|
const filePayload = {
|
|
33998
34073
|
attachment: fileBuffer,
|
|
33999
34074
|
name: filename
|
|
@@ -34442,13 +34517,13 @@ var FeishuAdapter = class _FeishuAdapter {
|
|
|
34442
34517
|
}
|
|
34443
34518
|
/** 发送媒体附件(图片/文件) */
|
|
34444
34519
|
async sendFile(target, message, attachment) {
|
|
34445
|
-
const
|
|
34446
|
-
const
|
|
34447
|
-
if (!
|
|
34520
|
+
const fs58 = await import("node:fs");
|
|
34521
|
+
const path60 = await import("node:path");
|
|
34522
|
+
if (!fs58.existsSync(attachment.path)) {
|
|
34448
34523
|
throw new Error(`File not found: ${attachment.path}`);
|
|
34449
34524
|
}
|
|
34450
|
-
const filename = attachment.filename ||
|
|
34451
|
-
const fileBuffer =
|
|
34525
|
+
const filename = attachment.filename || path60.basename(attachment.path);
|
|
34526
|
+
const fileBuffer = fs58.readFileSync(attachment.path);
|
|
34452
34527
|
const safeTarget = target || this.config.defaultTarget || "";
|
|
34453
34528
|
if (!safeTarget) throw new Error("Feishu sendFile: no target (\u4E3B\u52A8\u53D1\u9001\u9700\u914D\u7F6E defaultTarget \u6216\u4F20\u5165 target)");
|
|
34454
34529
|
const receiveIdType = safeTarget.startsWith("ou_") ? "open_id" : "chat_id";
|
|
@@ -35045,8 +35120,8 @@ var FeishuAdapter = class _FeishuAdapter {
|
|
|
35045
35120
|
|
|
35046
35121
|
// src/channels/wechat.ts
|
|
35047
35122
|
import * as crypto5 from "crypto";
|
|
35048
|
-
import * as
|
|
35049
|
-
import * as
|
|
35123
|
+
import * as fs37 from "fs";
|
|
35124
|
+
import * as path37 from "path";
|
|
35050
35125
|
import * as os4 from "os";
|
|
35051
35126
|
import { promises as dns } from "dns";
|
|
35052
35127
|
function sleep3(ms) {
|
|
@@ -35270,7 +35345,7 @@ function guessChatType(msg2, accountId) {
|
|
|
35270
35345
|
return isGroup ? { type: "group", chatId: roomId || toId || String(msg2.from_user_id || "") } : { type: "dm", chatId: String(msg2.from_user_id || "") };
|
|
35271
35346
|
}
|
|
35272
35347
|
function mimeFromFilename(filename) {
|
|
35273
|
-
const ext =
|
|
35348
|
+
const ext = path37.extname(filename).toLowerCase();
|
|
35274
35349
|
const map = {
|
|
35275
35350
|
".jpg": "image/jpeg",
|
|
35276
35351
|
".jpeg": "image/jpeg",
|
|
@@ -35337,15 +35412,15 @@ var ContextTokenStore = class {
|
|
|
35337
35412
|
cache = /* @__PURE__ */ new Map();
|
|
35338
35413
|
filePath;
|
|
35339
35414
|
constructor(stateDir, accountId) {
|
|
35340
|
-
this.filePath =
|
|
35415
|
+
this.filePath = path37.join(stateDir, "weixin", `${accountId}.context-tokens.json`);
|
|
35341
35416
|
}
|
|
35342
35417
|
k(a, p) {
|
|
35343
35418
|
return `${a}:${p}`;
|
|
35344
35419
|
}
|
|
35345
35420
|
restore() {
|
|
35346
35421
|
try {
|
|
35347
|
-
if (
|
|
35348
|
-
for (const [k, v] of Object.entries(JSON.parse(
|
|
35422
|
+
if (fs37.existsSync(this.filePath)) {
|
|
35423
|
+
for (const [k, v] of Object.entries(JSON.parse(fs37.readFileSync(this.filePath, "utf-8"))))
|
|
35349
35424
|
this.cache.set(k, String(v));
|
|
35350
35425
|
}
|
|
35351
35426
|
} catch {
|
|
@@ -35353,11 +35428,11 @@ var ContextTokenStore = class {
|
|
|
35353
35428
|
}
|
|
35354
35429
|
save() {
|
|
35355
35430
|
try {
|
|
35356
|
-
const dir =
|
|
35357
|
-
if (!
|
|
35431
|
+
const dir = path37.dirname(this.filePath);
|
|
35432
|
+
if (!fs37.existsSync(dir)) fs37.mkdirSync(dir, { recursive: true });
|
|
35358
35433
|
const obj = {};
|
|
35359
35434
|
this.cache.forEach((v, k) => obj[k] = v);
|
|
35360
|
-
|
|
35435
|
+
fs37.writeFileSync(this.filePath, JSON.stringify(obj));
|
|
35361
35436
|
} catch {
|
|
35362
35437
|
}
|
|
35363
35438
|
}
|
|
@@ -35377,18 +35452,18 @@ var ContextTokenStore = class {
|
|
|
35377
35452
|
};
|
|
35378
35453
|
function loadSyncBuf(stateDir, accountId) {
|
|
35379
35454
|
try {
|
|
35380
|
-
const fp =
|
|
35381
|
-
if (
|
|
35455
|
+
const fp = path37.join(stateDir, "weixin", `${accountId}.sync.json`);
|
|
35456
|
+
if (fs37.existsSync(fp)) return String(JSON.parse(fs37.readFileSync(fp, "utf-8")).sync_buf || "");
|
|
35382
35457
|
} catch {
|
|
35383
35458
|
}
|
|
35384
35459
|
return "";
|
|
35385
35460
|
}
|
|
35386
35461
|
function saveSyncBuf(stateDir, accountId, buf) {
|
|
35387
35462
|
try {
|
|
35388
|
-
const fp =
|
|
35389
|
-
const dir =
|
|
35390
|
-
if (!
|
|
35391
|
-
|
|
35463
|
+
const fp = path37.join(stateDir, "weixin", `${accountId}.sync.json`);
|
|
35464
|
+
const dir = path37.dirname(fp);
|
|
35465
|
+
if (!fs37.existsSync(dir)) fs37.mkdirSync(dir, { recursive: true });
|
|
35466
|
+
fs37.writeFileSync(fp, JSON.stringify({ sync_buf: buf }));
|
|
35392
35467
|
} catch {
|
|
35393
35468
|
}
|
|
35394
35469
|
}
|
|
@@ -35430,8 +35505,8 @@ var WechatAdapter = class {
|
|
|
35430
35505
|
this.config = config;
|
|
35431
35506
|
this.baseUrl = config.baseUrl?.replace(/\/$/, "") || ILINK_BASE_URL;
|
|
35432
35507
|
this.cdnBaseUrl = config.cdnBaseUrl?.replace(/\/$/, "") || WEIXIN_CDN_BASE_URL;
|
|
35433
|
-
this.stateDir = config.stateDir ||
|
|
35434
|
-
if (!
|
|
35508
|
+
this.stateDir = config.stateDir || path37.join(os4.homedir?.() || "/tmp", ".engine7");
|
|
35509
|
+
if (!fs37.existsSync(this.stateDir)) fs37.mkdirSync(this.stateDir, { recursive: true });
|
|
35435
35510
|
}
|
|
35436
35511
|
// --- ChannelAdapter interface ---
|
|
35437
35512
|
onMessage(handler2) {
|
|
@@ -35484,8 +35559,8 @@ var WechatAdapter = class {
|
|
|
35484
35559
|
}
|
|
35485
35560
|
async sendFile(target, message, attachment) {
|
|
35486
35561
|
const filePath = attachment.path;
|
|
35487
|
-
if (!
|
|
35488
|
-
const plaintext =
|
|
35562
|
+
if (!fs37.existsSync(filePath)) throw new Error(`File not found: ${filePath}`);
|
|
35563
|
+
const plaintext = fs37.readFileSync(filePath);
|
|
35489
35564
|
const mediaType = this.guessMediaType(filePath, attachment.mimeType);
|
|
35490
35565
|
const filekey = crypto5.randomBytes(16).toString("hex");
|
|
35491
35566
|
const aesKey = crypto5.randomBytes(16);
|
|
@@ -35517,7 +35592,7 @@ var WechatAdapter = class {
|
|
|
35517
35592
|
aesKeyForApi,
|
|
35518
35593
|
ciphertextSize: ciphertext.length,
|
|
35519
35594
|
plaintextSize: rawsize,
|
|
35520
|
-
filename:
|
|
35595
|
+
filename: path37.basename(filePath),
|
|
35521
35596
|
rawfilemd5,
|
|
35522
35597
|
voiceDurationSec: attachment.voiceDurationSec
|
|
35523
35598
|
});
|
|
@@ -35776,10 +35851,10 @@ var WechatAdapter = class {
|
|
|
35776
35851
|
mediaRef.full_url,
|
|
35777
35852
|
timeoutSec
|
|
35778
35853
|
);
|
|
35779
|
-
const tmpDir =
|
|
35780
|
-
if (!
|
|
35781
|
-
const tmpPath =
|
|
35782
|
-
|
|
35854
|
+
const tmpDir = path37.join(os4.tmpdir(), "weixin-media");
|
|
35855
|
+
if (!fs37.existsSync(tmpDir)) fs37.mkdirSync(tmpDir, { recursive: true });
|
|
35856
|
+
const tmpPath = path37.join(tmpDir, `${crypto5.randomUUID().replace(/-/g, "")}-${filename}`);
|
|
35857
|
+
fs37.writeFileSync(tmpPath, data);
|
|
35783
35858
|
return { url: `file://${tmpPath}`, filename, contentType, size: data.length };
|
|
35784
35859
|
}
|
|
35785
35860
|
// --- Internal: send helpers ---
|
|
@@ -35829,7 +35904,7 @@ var WechatAdapter = class {
|
|
|
35829
35904
|
throw lastError;
|
|
35830
35905
|
}
|
|
35831
35906
|
guessMediaType(filePath, mimeType) {
|
|
35832
|
-
const ext =
|
|
35907
|
+
const ext = path37.extname(filePath).toLowerCase();
|
|
35833
35908
|
const mime = mimeType || mimeFromFilename(filePath);
|
|
35834
35909
|
if (mime.startsWith("image/")) return MEDIA_IMAGE;
|
|
35835
35910
|
if (mime.startsWith("video/")) return MEDIA_VIDEO;
|
|
@@ -35875,12 +35950,12 @@ init_voice_chat_tts_daemon();
|
|
|
35875
35950
|
import { execFile as execFile2 } from "node:child_process";
|
|
35876
35951
|
import { createInterface as createInterface2 } from "node:readline";
|
|
35877
35952
|
import { promisify as promisify2 } from "node:util";
|
|
35878
|
-
import * as
|
|
35879
|
-
import * as
|
|
35953
|
+
import * as fs39 from "node:fs";
|
|
35954
|
+
import * as path39 from "node:path";
|
|
35880
35955
|
import * as os5 from "node:os";
|
|
35881
35956
|
import net3 from "net";
|
|
35882
35957
|
var execFileAsync2 = promisify2(execFile2);
|
|
35883
|
-
var VOICE_DIR =
|
|
35958
|
+
var VOICE_DIR = path39.join(os5.tmpdir(), "engine-voice");
|
|
35884
35959
|
function wavDurationSec(buf) {
|
|
35885
35960
|
if (buf.length < 12 || buf.toString("ascii", 0, 4) !== "RIFF" || buf.toString("ascii", 8, 12) !== "WAVE") {
|
|
35886
35961
|
throw new Error("wavDurationSec: not a RIFF/WAVE file");
|
|
@@ -35929,17 +36004,17 @@ function resolvePython(configuredPath) {
|
|
|
35929
36004
|
}
|
|
35930
36005
|
if (_pyCache) return _pyCache;
|
|
35931
36006
|
const localAppData = process.env.LOCALAPPDATA;
|
|
35932
|
-
const
|
|
36007
|
+
const candidates2 = [
|
|
35933
36008
|
"python3",
|
|
35934
36009
|
"python",
|
|
35935
36010
|
// LOCALAPPDATA 缺席(非 Windows / 精简环境)时**不加这两个候选**:
|
|
35936
36011
|
// 拼出来会是相对路径 'Microsoft/WindowsApps/python.exe',那可能撞上 cwd 里的东西。
|
|
35937
36012
|
...localAppData ? [
|
|
35938
|
-
|
|
35939
|
-
|
|
36013
|
+
path39.join(localAppData, "Microsoft", "WindowsApps", "python3.exe"),
|
|
36014
|
+
path39.join(localAppData, "Microsoft", "WindowsApps", "python.exe")
|
|
35940
36015
|
] : []
|
|
35941
36016
|
];
|
|
35942
|
-
for (const c of
|
|
36017
|
+
for (const c of candidates2) {
|
|
35943
36018
|
try {
|
|
35944
36019
|
__require("child_process").execFileSync(c, ["-c", "1"], { timeout: 5e3, stdio: "ignore" });
|
|
35945
36020
|
_pyCache = c;
|
|
@@ -35956,8 +36031,8 @@ async function ttsCosyvoice(text, apiKey, model, voice, workspaceId, instruction
|
|
|
35956
36031
|
}
|
|
35957
36032
|
async function ttsCosyvoiceStream(text, cfg, onChunk) {
|
|
35958
36033
|
const { apiKey, model, voice, workspaceId, instruction } = cfg;
|
|
35959
|
-
|
|
35960
|
-
const output =
|
|
36034
|
+
fs39.mkdirSync(VOICE_DIR, { recursive: true });
|
|
36035
|
+
const output = path39.join(VOICE_DIR, `tts_${Date.now()}.wav`);
|
|
35961
36036
|
const script = `
|
|
35962
36037
|
import sys, json, base64, threading
|
|
35963
36038
|
import dashscope
|
|
@@ -36042,7 +36117,7 @@ print('EOS')
|
|
|
36042
36117
|
header.writeUInt16LE(16, 34);
|
|
36043
36118
|
header.write("data", 36);
|
|
36044
36119
|
header.writeUInt32LE(pcm.length, 40);
|
|
36045
|
-
|
|
36120
|
+
fs39.writeFileSync(output, Buffer.concat([header, pcm]));
|
|
36046
36121
|
return output;
|
|
36047
36122
|
}
|
|
36048
36123
|
async function ttsCosyvoiceWorker(text, cfg, onChunk) {
|
|
@@ -36152,9 +36227,9 @@ async function ttsQwen3Opus(text, cfg) {
|
|
|
36152
36227
|
const ogg = Buffer.from(await res.arrayBuffer());
|
|
36153
36228
|
if (ogg.length < 20) throw new Error("qwen3-3060 opus: empty output");
|
|
36154
36229
|
const durationMs = parseInt(res.headers.get("x-duration-ms") || "0", 10);
|
|
36155
|
-
|
|
36156
|
-
const oggPath =
|
|
36157
|
-
|
|
36230
|
+
fs39.mkdirSync(VOICE_DIR, { recursive: true });
|
|
36231
|
+
const oggPath = path39.join(VOICE_DIR, `tts_${Date.now()}.ogg`);
|
|
36232
|
+
fs39.writeFileSync(oggPath, ogg);
|
|
36158
36233
|
return { oggPath, durationMs };
|
|
36159
36234
|
}
|
|
36160
36235
|
async function ttsGptsovits(text, c) {
|
|
@@ -36166,8 +36241,8 @@ async function ttsGptsovits(text, c) {
|
|
|
36166
36241
|
"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"
|
|
36167
36242
|
);
|
|
36168
36243
|
}
|
|
36169
|
-
|
|
36170
|
-
const output =
|
|
36244
|
+
fs39.mkdirSync(VOICE_DIR, { recursive: true });
|
|
36245
|
+
const output = path39.join(VOICE_DIR, `tts_${Date.now()}.wav`);
|
|
36171
36246
|
const params = new URLSearchParams({
|
|
36172
36247
|
text,
|
|
36173
36248
|
text_language: "zh",
|
|
@@ -36178,13 +36253,13 @@ async function ttsGptsovits(text, c) {
|
|
|
36178
36253
|
const res = await fetch(`${url}/?${params}`);
|
|
36179
36254
|
if (!res.ok) throw new Error(`GPT-SoVITS API ${res.status}`);
|
|
36180
36255
|
const buf = Buffer.from(await res.arrayBuffer());
|
|
36181
|
-
|
|
36256
|
+
fs39.writeFileSync(output, buf);
|
|
36182
36257
|
return output;
|
|
36183
36258
|
}
|
|
36184
36259
|
var EDGE_VOICE = "zh-CN-XiaoxiaoNeural";
|
|
36185
36260
|
async function ttsEdge(text) {
|
|
36186
|
-
|
|
36187
|
-
const output =
|
|
36261
|
+
fs39.mkdirSync(VOICE_DIR, { recursive: true });
|
|
36262
|
+
const output = path39.join(VOICE_DIR, `tts_${Date.now()}.mp3`);
|
|
36188
36263
|
const script = `
|
|
36189
36264
|
import asyncio, edge_tts, sys
|
|
36190
36265
|
async def main():
|
|
@@ -36229,8 +36304,8 @@ async function synthQwen3(text, _sink) {
|
|
|
36229
36304
|
const pcmChunks = [];
|
|
36230
36305
|
await ttsQwen3Local(text, { url: c.url, voice: c.voice, lang: c.lang }, (pcm2) => pcmChunks.push(pcm2));
|
|
36231
36306
|
const pcm = Buffer.concat(pcmChunks);
|
|
36232
|
-
|
|
36233
|
-
const wavPath =
|
|
36307
|
+
fs39.mkdirSync(VOICE_DIR, { recursive: true });
|
|
36308
|
+
const wavPath = path39.join(VOICE_DIR, `tts_${Date.now()}.wav`);
|
|
36234
36309
|
const header = Buffer.alloc(44);
|
|
36235
36310
|
header.write("RIFF", 0);
|
|
36236
36311
|
header.writeUInt32LE(36 + pcm.length, 4);
|
|
@@ -36245,7 +36320,7 @@ async function synthQwen3(text, _sink) {
|
|
|
36245
36320
|
header.writeUInt16LE(16, 34);
|
|
36246
36321
|
header.write("data", 36);
|
|
36247
36322
|
header.writeUInt32LE(pcm.length, 40);
|
|
36248
|
-
|
|
36323
|
+
fs39.writeFileSync(wavPath, Buffer.concat([header, pcm]));
|
|
36249
36324
|
return { path: wavPath, format: "wav", unit: unit(text), voice: c.voice };
|
|
36250
36325
|
}
|
|
36251
36326
|
}
|
|
@@ -36270,22 +36345,22 @@ var DeskBuddyAdapter = class {
|
|
|
36270
36345
|
try {
|
|
36271
36346
|
if (!this.historyFile) {
|
|
36272
36347
|
const os7 = __require("os");
|
|
36273
|
-
const
|
|
36274
|
-
const
|
|
36275
|
-
const dir =
|
|
36276
|
-
|
|
36277
|
-
this.historyFile =
|
|
36278
|
-
this._fs =
|
|
36279
|
-
}
|
|
36280
|
-
const
|
|
36348
|
+
const fs59 = __require("fs");
|
|
36349
|
+
const path60 = __require("path");
|
|
36350
|
+
const dir = path60.join(os7.homedir(), "xiaowen", "workspace", ".desktopBuddy");
|
|
36351
|
+
fs59.mkdirSync(dir, { recursive: true });
|
|
36352
|
+
this.historyFile = path60.join(dir, "history.json");
|
|
36353
|
+
this._fs = fs59;
|
|
36354
|
+
}
|
|
36355
|
+
const fs58 = this._fs;
|
|
36281
36356
|
let arr = [];
|
|
36282
36357
|
try {
|
|
36283
|
-
arr = JSON.parse(
|
|
36358
|
+
arr = JSON.parse(fs58.readFileSync(this.historyFile, "utf-8")) || [];
|
|
36284
36359
|
} catch {
|
|
36285
36360
|
}
|
|
36286
36361
|
arr.push({ ...entry, ts: (/* @__PURE__ */ new Date()).toLocaleString("zh-CN", { hour12: false }) });
|
|
36287
36362
|
if (arr.length > 500) arr = arr.slice(-500);
|
|
36288
|
-
|
|
36363
|
+
fs58.writeFileSync(this.historyFile, JSON.stringify(arr, null, 1));
|
|
36289
36364
|
} catch (e) {
|
|
36290
36365
|
console.warn("[deskBuddy] history write fail", e);
|
|
36291
36366
|
}
|
|
@@ -36566,8 +36641,8 @@ var DeskBuddyAdapter = class {
|
|
|
36566
36641
|
|
|
36567
36642
|
// src/channels/cc-bridge.ts
|
|
36568
36643
|
init_live();
|
|
36569
|
-
import
|
|
36570
|
-
import
|
|
36644
|
+
import fs40 from "node:fs";
|
|
36645
|
+
import path40 from "node:path";
|
|
36571
36646
|
import { WebSocketServer as WebSocketServer2, WebSocket as WebSocket2 } from "ws";
|
|
36572
36647
|
var DEFAULT_PORT = 16996;
|
|
36573
36648
|
var CcBridgeAdapter = class {
|
|
@@ -36598,7 +36673,7 @@ var CcBridgeAdapter = class {
|
|
|
36598
36673
|
// 只会在热加载后变成指向旧目录的幽灵路径(配置访问铁律)。
|
|
36599
36674
|
outboxFile() {
|
|
36600
36675
|
const sd = liveConfig.get("stateDir") || process.cwd();
|
|
36601
|
-
return
|
|
36676
|
+
return path40.join(sd, "state", "cc-bridge", "outbox.jsonl");
|
|
36602
36677
|
}
|
|
36603
36678
|
/**
|
|
36604
36679
|
* 读队列。**只有 ENOENT 才等于"空队列"。**
|
|
@@ -36612,7 +36687,7 @@ var CcBridgeAdapter = class {
|
|
|
36612
36687
|
readOutbox() {
|
|
36613
36688
|
let raw;
|
|
36614
36689
|
try {
|
|
36615
|
-
raw =
|
|
36690
|
+
raw = fs40.readFileSync(this.outboxFile(), "utf8");
|
|
36616
36691
|
} catch (e) {
|
|
36617
36692
|
if (e?.code === "ENOENT") return [];
|
|
36618
36693
|
throw e;
|
|
@@ -36642,9 +36717,9 @@ var CcBridgeAdapter = class {
|
|
|
36642
36717
|
writeOutbox(items) {
|
|
36643
36718
|
const file2 = this.outboxFile();
|
|
36644
36719
|
const tmp = `${file2}.tmp`;
|
|
36645
|
-
|
|
36646
|
-
|
|
36647
|
-
|
|
36720
|
+
fs40.mkdirSync(path40.dirname(file2), { recursive: true });
|
|
36721
|
+
fs40.writeFileSync(tmp, items.map((i) => JSON.stringify(i)).join("\n") + (items.length ? "\n" : ""), "utf8");
|
|
36722
|
+
fs40.renameSync(tmp, file2);
|
|
36648
36723
|
}
|
|
36649
36724
|
/** 入队(dedupe 不做 —— id 是新的,重复投递由 ack 收敛)。读/写失败都往外抛,不吞。 */
|
|
36650
36725
|
enqueue(item) {
|
|
@@ -36722,7 +36797,7 @@ var CcBridgeAdapter = class {
|
|
|
36722
36797
|
async connect() {
|
|
36723
36798
|
const port = this.config.port ?? DEFAULT_PORT;
|
|
36724
36799
|
try {
|
|
36725
|
-
|
|
36800
|
+
fs40.mkdirSync(path40.dirname(this.outboxFile()), { recursive: true });
|
|
36726
36801
|
} catch {
|
|
36727
36802
|
}
|
|
36728
36803
|
this.wss = new WebSocketServer2({
|
|
@@ -36895,14 +36970,14 @@ var CcBridgeAdapter = class {
|
|
|
36895
36970
|
async sendFile(_target, message, attachment) {
|
|
36896
36971
|
let st;
|
|
36897
36972
|
try {
|
|
36898
|
-
st =
|
|
36973
|
+
st = fs40.statSync(attachment.path);
|
|
36899
36974
|
} catch (e) {
|
|
36900
36975
|
throw new Error(`\u9644\u4EF6\u4E0D\u5B58\u5728\uFF0C\u672A\u53D1\u9001\uFF1A${attachment.path}\uFF08${e?.code || e?.message}\uFF09`);
|
|
36901
36976
|
}
|
|
36902
36977
|
const file2 = {
|
|
36903
36978
|
mode: "path-ref",
|
|
36904
36979
|
path: attachment.path,
|
|
36905
|
-
filename: attachment.filename ||
|
|
36980
|
+
filename: attachment.filename || path40.basename(attachment.path),
|
|
36906
36981
|
mimeType: attachment.mimeType || "application/octet-stream",
|
|
36907
36982
|
size: st.size,
|
|
36908
36983
|
mtimeMs: Math.round(st.mtimeMs)
|
|
@@ -37258,20 +37333,20 @@ var ChannelManager = class {
|
|
|
37258
37333
|
// src/session/session-manager.ts
|
|
37259
37334
|
init_types();
|
|
37260
37335
|
init_types();
|
|
37261
|
-
import * as
|
|
37262
|
-
import * as
|
|
37336
|
+
import * as path42 from "node:path";
|
|
37337
|
+
import * as fs42 from "node:fs";
|
|
37263
37338
|
import * as crypto6 from "node:crypto";
|
|
37264
37339
|
|
|
37265
37340
|
// src/session/reader.ts
|
|
37266
37341
|
init_attachments();
|
|
37267
|
-
import * as
|
|
37268
|
-
import * as
|
|
37342
|
+
import * as fs41 from "node:fs";
|
|
37343
|
+
import * as path41 from "node:path";
|
|
37269
37344
|
import * as readline2 from "node:readline";
|
|
37270
37345
|
var SKIP_PRECOMPACT_THRESHOLD = 5 * 1024 * 1024;
|
|
37271
37346
|
var TRANSCRIPT_READ_CHUNK_SIZE = 1024 * 1024;
|
|
37272
37347
|
var MAX_TRANSCRIPT_READ_BYTES = 50 * 1024 * 1024;
|
|
37273
37348
|
async function readSessionHeader(filePath) {
|
|
37274
|
-
const stream =
|
|
37349
|
+
const stream = fs41.createReadStream(filePath, { encoding: "utf-8" });
|
|
37275
37350
|
const rl = readline2.createInterface({ input: stream });
|
|
37276
37351
|
return new Promise((resolve12) => {
|
|
37277
37352
|
let resolved = false;
|
|
@@ -37302,7 +37377,7 @@ async function readSessionHeader(filePath) {
|
|
|
37302
37377
|
});
|
|
37303
37378
|
}
|
|
37304
37379
|
async function readLargeFilePostBoundary(filePath) {
|
|
37305
|
-
const stat4 =
|
|
37380
|
+
const stat4 = fs41.statSync(filePath);
|
|
37306
37381
|
const fileSize = stat4.size;
|
|
37307
37382
|
const boundaryMarker = '"compact_boundary"';
|
|
37308
37383
|
const CHUNK_SIZE = TRANSCRIPT_READ_CHUNK_SIZE;
|
|
@@ -37310,13 +37385,13 @@ async function readLargeFilePostBoundary(filePath) {
|
|
|
37310
37385
|
let outLen = 0;
|
|
37311
37386
|
let boundaryStartOffset = 0;
|
|
37312
37387
|
const chunk = Buffer.allocUnsafe(CHUNK_SIZE);
|
|
37313
|
-
const fd =
|
|
37388
|
+
const fd = fs41.openSync(filePath, "r");
|
|
37314
37389
|
try {
|
|
37315
37390
|
let filePos = 0;
|
|
37316
37391
|
let carryBuf;
|
|
37317
37392
|
let carryLen = 0;
|
|
37318
37393
|
while (filePos < fileSize) {
|
|
37319
|
-
const bytesRead =
|
|
37394
|
+
const bytesRead = fs41.readSync(fd, chunk, 0, Math.min(CHUNK_SIZE, fileSize - filePos), filePos);
|
|
37320
37395
|
if (bytesRead === 0) break;
|
|
37321
37396
|
filePos += bytesRead;
|
|
37322
37397
|
let scanBuf;
|
|
@@ -37368,7 +37443,7 @@ async function readLargeFilePostBoundary(filePath) {
|
|
|
37368
37443
|
}
|
|
37369
37444
|
}
|
|
37370
37445
|
} finally {
|
|
37371
|
-
|
|
37446
|
+
fs41.closeSync(fd);
|
|
37372
37447
|
}
|
|
37373
37448
|
const postBoundaryText = outBuf.subarray(0, outLen).toString("utf-8");
|
|
37374
37449
|
return postBoundaryText.split("\n").filter((l) => l.trim().length > 0);
|
|
@@ -37492,7 +37567,7 @@ function recoverOrphanedParallelToolResults(allEntries, chain, byUuid, seen) {
|
|
|
37492
37567
|
return result;
|
|
37493
37568
|
}
|
|
37494
37569
|
async function readSessionHistory(filePath) {
|
|
37495
|
-
const stat4 =
|
|
37570
|
+
const stat4 = fs41.statSync(filePath);
|
|
37496
37571
|
const fileSize = stat4.size;
|
|
37497
37572
|
if (fileSize > MAX_TRANSCRIPT_READ_BYTES) {
|
|
37498
37573
|
console.warn(`[reader] Session file exceeds 50MB limit (${(fileSize / 1024 / 1024).toFixed(1)}MB), using chunked fd read with boundary skip`);
|
|
@@ -37531,7 +37606,7 @@ async function readSessionHistory(filePath) {
|
|
|
37531
37606
|
return [...sessionStarts, ...filtered, ...restAttachments];
|
|
37532
37607
|
}
|
|
37533
37608
|
async function readAllLines(filePath) {
|
|
37534
|
-
const stream =
|
|
37609
|
+
const stream = fs41.createReadStream(filePath, { encoding: "utf-8" });
|
|
37535
37610
|
const rl = readline2.createInterface({ input: stream });
|
|
37536
37611
|
const lines = [];
|
|
37537
37612
|
return new Promise((resolve12, reject) => {
|
|
@@ -37685,12 +37760,12 @@ function extractText4(content) {
|
|
|
37685
37760
|
return content.filter((b) => b.type === "text").map((b) => b.text || "").join("") || null;
|
|
37686
37761
|
}
|
|
37687
37762
|
function listSessions(sessionsDir) {
|
|
37688
|
-
if (!
|
|
37689
|
-
const files =
|
|
37690
|
-
file:
|
|
37763
|
+
if (!fs41.existsSync(sessionsDir)) return [];
|
|
37764
|
+
const files = fs41.readdirSync(sessionsDir).filter((f) => f.endsWith(".jsonl") || f.includes(".jsonl.")).map((f) => ({
|
|
37765
|
+
file: path41.join(sessionsDir, f),
|
|
37691
37766
|
id: f.replace(/\.jsonl.*$/, ""),
|
|
37692
37767
|
// strip .jsonl and everything after (archived suffix)
|
|
37693
|
-
modified: new Date(
|
|
37768
|
+
modified: new Date(fs41.statSync(path41.join(sessionsDir, f)).mtimeMs)
|
|
37694
37769
|
})).sort((a, b) => b.modified.getTime() - a.modified.getTime());
|
|
37695
37770
|
return files;
|
|
37696
37771
|
}
|
|
@@ -37725,24 +37800,24 @@ var SessionManager = class {
|
|
|
37725
37800
|
constructor(config) {
|
|
37726
37801
|
this.config = config;
|
|
37727
37802
|
this.scopeConfig = config.scopeConfig;
|
|
37728
|
-
this.sessionsDir =
|
|
37729
|
-
this.indexPath =
|
|
37730
|
-
this.platformMapPath =
|
|
37731
|
-
|
|
37803
|
+
this.sessionsDir = path42.join(config.stateDir, "agents", "main", "sessions");
|
|
37804
|
+
this.indexPath = path42.join(this.sessionsDir, "session-index.json");
|
|
37805
|
+
this.platformMapPath = path42.join(this.sessionsDir, "platform-map.json");
|
|
37806
|
+
fs42.mkdirSync(this.sessionsDir, { recursive: true });
|
|
37732
37807
|
}
|
|
37733
37808
|
// === 索引操作 ===
|
|
37734
37809
|
loadIndex() {
|
|
37735
37810
|
try {
|
|
37736
|
-
if (
|
|
37737
|
-
const raw =
|
|
37811
|
+
if (fs42.existsSync(this.indexPath)) {
|
|
37812
|
+
const raw = fs42.readFileSync(this.indexPath, "utf-8");
|
|
37738
37813
|
const obj = JSON.parse(raw);
|
|
37739
37814
|
this.index = new Map(Object.entries(obj));
|
|
37740
37815
|
let fixed = 0;
|
|
37741
37816
|
for (const [key, entry] of this.index) {
|
|
37742
|
-
if (
|
|
37743
|
-
const basename10 =
|
|
37744
|
-
const localPath =
|
|
37745
|
-
if (
|
|
37817
|
+
if (fs42.existsSync(entry.file)) continue;
|
|
37818
|
+
const basename10 = path42.basename(entry.file);
|
|
37819
|
+
const localPath = path42.join(this.sessionsDir, basename10);
|
|
37820
|
+
if (fs42.existsSync(localPath)) {
|
|
37746
37821
|
entry.file = localPath;
|
|
37747
37822
|
fixed++;
|
|
37748
37823
|
}
|
|
@@ -37761,7 +37836,7 @@ var SessionManager = class {
|
|
|
37761
37836
|
try {
|
|
37762
37837
|
const obj = {};
|
|
37763
37838
|
for (const [k, v] of this.index) obj[k] = v;
|
|
37764
|
-
|
|
37839
|
+
fs42.writeFileSync(this.indexPath, JSON.stringify(obj, null, 2));
|
|
37765
37840
|
} catch (err) {
|
|
37766
37841
|
console.error(`[session] Failed to save index: ${err.message}`);
|
|
37767
37842
|
}
|
|
@@ -37769,8 +37844,8 @@ var SessionManager = class {
|
|
|
37769
37844
|
// === 平台映射 ===
|
|
37770
37845
|
loadPlatformMap() {
|
|
37771
37846
|
try {
|
|
37772
|
-
if (
|
|
37773
|
-
const raw =
|
|
37847
|
+
if (fs42.existsSync(this.platformMapPath)) {
|
|
37848
|
+
const raw = fs42.readFileSync(this.platformMapPath, "utf-8");
|
|
37774
37849
|
const obj = JSON.parse(raw);
|
|
37775
37850
|
this.platformMap = new Map(Object.entries(obj));
|
|
37776
37851
|
console.log(`[session] Platform map loaded: ${this.platformMap.size} entries`);
|
|
@@ -37782,7 +37857,7 @@ var SessionManager = class {
|
|
|
37782
37857
|
try {
|
|
37783
37858
|
const obj = {};
|
|
37784
37859
|
for (const [k, v] of this.platformMap) obj[k] = v;
|
|
37785
|
-
|
|
37860
|
+
fs42.writeFileSync(this.platformMapPath, JSON.stringify(obj, null, 2));
|
|
37786
37861
|
} catch (err) {
|
|
37787
37862
|
console.error(`[session] Failed to save platform map: ${err.message}`);
|
|
37788
37863
|
}
|
|
@@ -37821,17 +37896,17 @@ var SessionManager = class {
|
|
|
37821
37896
|
*/
|
|
37822
37897
|
getSessionFilePath(sessionId) {
|
|
37823
37898
|
const entry = this.index.get(sessionId);
|
|
37824
|
-
if (entry &&
|
|
37825
|
-
const direct =
|
|
37826
|
-
return
|
|
37899
|
+
if (entry && fs42.existsSync(entry.file)) return entry.file;
|
|
37900
|
+
const direct = path42.join(this.sessionsDir, `${sessionId}.jsonl`);
|
|
37901
|
+
return fs42.existsSync(direct) ? direct : null;
|
|
37827
37902
|
}
|
|
37828
37903
|
// === Writer 管理 ===
|
|
37829
37904
|
getWriter(sessionId) {
|
|
37830
37905
|
let writer = this.writers.get(sessionId);
|
|
37831
37906
|
if (!writer) {
|
|
37832
37907
|
const existing = this.index.get(sessionId);
|
|
37833
|
-
if (existing &&
|
|
37834
|
-
const existingFileId =
|
|
37908
|
+
if (existing && fs42.existsSync(existing.file)) {
|
|
37909
|
+
const existingFileId = path42.basename(existing.file, ".jsonl");
|
|
37835
37910
|
writer = new SessionWriter(this.sessionsDir, existingFileId);
|
|
37836
37911
|
writer.open(this.config.workspace, sessionId);
|
|
37837
37912
|
} else {
|
|
@@ -37843,7 +37918,7 @@ var SessionManager = class {
|
|
|
37843
37918
|
this.saveIndex();
|
|
37844
37919
|
this.writers.set(sessionId, writer);
|
|
37845
37920
|
this.onWriterCreated?.(writer, sessionId);
|
|
37846
|
-
console.log(`[session] ${existing ? "Resumed" : "New"}: ${sessionId} \u2192 ${
|
|
37921
|
+
console.log(`[session] ${existing ? "Resumed" : "New"}: ${sessionId} \u2192 ${path42.basename(writer.path)}`);
|
|
37847
37922
|
}
|
|
37848
37923
|
return writer;
|
|
37849
37924
|
}
|
|
@@ -37862,7 +37937,7 @@ var SessionManager = class {
|
|
|
37862
37937
|
if (!writer) return null;
|
|
37863
37938
|
try {
|
|
37864
37939
|
this.lastArchiveCheck = Date.now();
|
|
37865
|
-
const stat4 =
|
|
37940
|
+
const stat4 = fs42.statSync(writer.path);
|
|
37866
37941
|
if (stat4.size < threshold) return null;
|
|
37867
37942
|
const sizeMB = (stat4.size / 1024 / 1024).toFixed(1);
|
|
37868
37943
|
const thresholdMB = (threshold / 1024 / 1024).toFixed(1);
|
|
@@ -37871,10 +37946,10 @@ var SessionManager = class {
|
|
|
37871
37946
|
if (archivedPath) {
|
|
37872
37947
|
this.index.set(sessionId, { file: writer.path, updatedAt: Date.now() });
|
|
37873
37948
|
this.saveIndex();
|
|
37874
|
-
const newSize =
|
|
37949
|
+
const newSize = fs42.statSync(writer.path).size;
|
|
37875
37950
|
const oldSizeMB = (stat4.size / 1024 / 1024).toFixed(1);
|
|
37876
|
-
console.log(`[session] Archive complete: ${
|
|
37877
|
-
const fileId =
|
|
37951
|
+
console.log(`[session] Archive complete: ${path42.basename(archivedPath)} (${oldSizeMB}MB) \u2192 new JSONL created (${newSize} bytes)`);
|
|
37952
|
+
const fileId = path42.basename(writer.path).replace(/\.jsonl$/, "");
|
|
37878
37953
|
this.purgeOldArchives(fileId, 3);
|
|
37879
37954
|
return archivedPath;
|
|
37880
37955
|
}
|
|
@@ -37890,15 +37965,15 @@ var SessionManager = class {
|
|
|
37890
37965
|
purgeOldArchives(sessionId, keepCount = 3) {
|
|
37891
37966
|
try {
|
|
37892
37967
|
const dir = this.sessionsDir;
|
|
37893
|
-
if (!
|
|
37894
|
-
const allFiles =
|
|
37968
|
+
if (!fs42.existsSync(dir)) return;
|
|
37969
|
+
const allFiles = fs42.readdirSync(dir);
|
|
37895
37970
|
const archiveFiles = allFiles.filter((f) => {
|
|
37896
37971
|
if (!f.startsWith(sessionId)) return false;
|
|
37897
37972
|
return f.includes(".archived.") || f.includes(".compaction.");
|
|
37898
37973
|
}).map((f) => ({
|
|
37899
37974
|
name: f,
|
|
37900
|
-
path:
|
|
37901
|
-
mtime:
|
|
37975
|
+
path: path42.join(dir, f),
|
|
37976
|
+
mtime: fs42.statSync(path42.join(dir, f)).mtimeMs
|
|
37902
37977
|
})).sort((a, b) => b.mtime - a.mtime);
|
|
37903
37978
|
console.log(`[session] purgeOldArchives: sessionId=${sessionId.substring(0, 8)}... found=${archiveFiles.length} keep=${keepCount}`);
|
|
37904
37979
|
if (archiveFiles.length <= keepCount) return;
|
|
@@ -37908,7 +37983,7 @@ var SessionManager = class {
|
|
|
37908
37983
|
console.log(`[session] Skipping archived (kept for history): ${f.name}`);
|
|
37909
37984
|
continue;
|
|
37910
37985
|
}
|
|
37911
|
-
|
|
37986
|
+
fs42.unlinkSync(f.path);
|
|
37912
37987
|
console.log(`[session] Purged old archive: ${f.name}`);
|
|
37913
37988
|
}
|
|
37914
37989
|
if (toDelete.length > 0) {
|
|
@@ -37957,29 +38032,29 @@ var SessionManager = class {
|
|
|
37957
38032
|
/** 列出 session 的所有文件(当前 + 归档),按修改时间排序 */
|
|
37958
38033
|
findAllSessionFiles(sessionId) {
|
|
37959
38034
|
const results = [];
|
|
37960
|
-
const mainFile =
|
|
37961
|
-
if (
|
|
38035
|
+
const mainFile = path42.join(this.sessionsDir, `${sessionId}.jsonl`);
|
|
38036
|
+
if (fs42.existsSync(mainFile)) {
|
|
37962
38037
|
results.push(mainFile);
|
|
37963
38038
|
}
|
|
37964
|
-
if (
|
|
37965
|
-
const compactionFiles =
|
|
38039
|
+
if (fs42.existsSync(this.sessionsDir)) {
|
|
38040
|
+
const compactionFiles = fs42.readdirSync(this.sessionsDir).filter((f) => f.startsWith(`${sessionId}.jsonl.compaction.`)).map((f) => ({
|
|
37966
38041
|
name: f,
|
|
37967
|
-
path:
|
|
37968
|
-
mtime:
|
|
38042
|
+
path: path42.join(this.sessionsDir, f),
|
|
38043
|
+
mtime: fs42.statSync(path42.join(this.sessionsDir, f)).mtimeMs
|
|
37969
38044
|
})).sort((a, b) => b.mtime - a.mtime);
|
|
37970
38045
|
if (compactionFiles.length > 0) {
|
|
37971
38046
|
results.push(compactionFiles[0].path);
|
|
37972
38047
|
}
|
|
37973
38048
|
}
|
|
37974
38049
|
results.sort((a, b) => {
|
|
37975
|
-
const ta =
|
|
37976
|
-
const tb =
|
|
38050
|
+
const ta = fs42.statSync(a).mtimeMs;
|
|
38051
|
+
const tb = fs42.statSync(b).mtimeMs;
|
|
37977
38052
|
return ta - tb;
|
|
37978
38053
|
});
|
|
37979
38054
|
return results;
|
|
37980
38055
|
}
|
|
37981
38056
|
async findSessionFiles(sessionId) {
|
|
37982
|
-
if (!
|
|
38057
|
+
if (!fs42.existsSync(this.sessionsDir)) {
|
|
37983
38058
|
console.log(`[session:find] SESSIONS_DIR not found: ${this.sessionsDir}`);
|
|
37984
38059
|
return [];
|
|
37985
38060
|
}
|
|
@@ -37991,15 +38066,15 @@ var SessionManager = class {
|
|
|
37991
38066
|
return mappedFiles;
|
|
37992
38067
|
}
|
|
37993
38068
|
const indexedEntry = this.index.get(mappedId);
|
|
37994
|
-
if (indexedEntry &&
|
|
37995
|
-
const fileUuid =
|
|
38069
|
+
if (indexedEntry && fs42.existsSync(indexedEntry.file)) {
|
|
38070
|
+
const fileUuid = path42.basename(indexedEntry.file, ".jsonl");
|
|
37996
38071
|
return this.findAllSessionFiles(fileUuid);
|
|
37997
38072
|
}
|
|
37998
38073
|
}
|
|
37999
38074
|
const allFiles = this.findAllSessionFiles(sessionId);
|
|
38000
38075
|
if (allFiles.length > 0) {
|
|
38001
38076
|
const labels = allFiles.map((f) => {
|
|
38002
|
-
const base =
|
|
38077
|
+
const base = path42.basename(f);
|
|
38003
38078
|
return base.endsWith(".jsonl") ? base : `${base} (archived)`;
|
|
38004
38079
|
});
|
|
38005
38080
|
console.log(`[session:find] Found ${allFiles.length} file(s) for ${sessionId}: ${labels.join(", ")}`);
|
|
@@ -38007,9 +38082,9 @@ var SessionManager = class {
|
|
|
38007
38082
|
}
|
|
38008
38083
|
const indexed = this.index.get(sessionId);
|
|
38009
38084
|
if (indexed) {
|
|
38010
|
-
console.log(`[session:find] Index hit: ${sessionId} \u2192 ${indexed.file} (exists=${
|
|
38011
|
-
if (
|
|
38012
|
-
return this.findAllSessionFiles(
|
|
38085
|
+
console.log(`[session:find] Index hit: ${sessionId} \u2192 ${indexed.file} (exists=${fs42.existsSync(indexed.file)})`);
|
|
38086
|
+
if (fs42.existsSync(indexed.file)) {
|
|
38087
|
+
return this.findAllSessionFiles(path42.basename(indexed.file, ".jsonl"));
|
|
38013
38088
|
}
|
|
38014
38089
|
} else {
|
|
38015
38090
|
console.log(`[session:find] Index miss: ${sessionId} (index has ${this.index.size} entries)`);
|
|
@@ -38038,8 +38113,8 @@ var SessionManager = class {
|
|
|
38038
38113
|
return [];
|
|
38039
38114
|
}
|
|
38040
38115
|
files.sort((a, b) => {
|
|
38041
|
-
const ta =
|
|
38042
|
-
const tb =
|
|
38116
|
+
const ta = fs42.statSync(a).mtimeMs;
|
|
38117
|
+
const tb = fs42.statSync(b).mtimeMs;
|
|
38043
38118
|
return ta - tb;
|
|
38044
38119
|
});
|
|
38045
38120
|
const latestFile = files[files.length - 1];
|
|
@@ -38047,7 +38122,7 @@ var SessionManager = class {
|
|
|
38047
38122
|
if (!currentEntry || currentEntry.file !== latestFile) {
|
|
38048
38123
|
this.index.set(sessionId, { file: latestFile, updatedAt: Date.now() });
|
|
38049
38124
|
this.saveIndex();
|
|
38050
|
-
console.log(`[session:restore] Synced index: ${sessionId} \u2192 ${
|
|
38125
|
+
console.log(`[session:restore] Synced index: ${sessionId} \u2192 ${path42.basename(latestFile)}`);
|
|
38051
38126
|
}
|
|
38052
38127
|
const allMessages = [];
|
|
38053
38128
|
for (const file2 of files) {
|
|
@@ -38086,7 +38161,7 @@ var SessionManager = class {
|
|
|
38086
38161
|
if (isAttachmentMessage(m) && m.attachment.type === "relevant_memories") {
|
|
38087
38162
|
for (const mem of m.attachment.memories) {
|
|
38088
38163
|
rawCount++;
|
|
38089
|
-
restoredPaths.add(
|
|
38164
|
+
restoredPaths.add(path42.resolve(mem.path));
|
|
38090
38165
|
}
|
|
38091
38166
|
}
|
|
38092
38167
|
}
|
|
@@ -38118,15 +38193,15 @@ var SessionManager = class {
|
|
|
38118
38193
|
*/
|
|
38119
38194
|
rotateMainSession() {
|
|
38120
38195
|
const entry = this.index.get("main");
|
|
38121
|
-
if (!entry || !
|
|
38122
|
-
const oldFileId =
|
|
38123
|
-
const stat4 =
|
|
38196
|
+
if (!entry || !fs42.existsSync(entry.file)) return;
|
|
38197
|
+
const oldFileId = path42.basename(entry.file, ".jsonl");
|
|
38198
|
+
const stat4 = fs42.statSync(entry.file);
|
|
38124
38199
|
if (stat4.size < 1024) return;
|
|
38125
38200
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/:/g, "-");
|
|
38126
38201
|
const archivedPath = `${entry.file}.archived.${ts}`;
|
|
38127
|
-
|
|
38202
|
+
fs42.renameSync(entry.file, archivedPath);
|
|
38128
38203
|
const sizeMB = (stat4.size / 1024 / 1024).toFixed(1);
|
|
38129
|
-
console.log(`[session] Archived: ${
|
|
38204
|
+
console.log(`[session] Archived: ${path42.basename(entry.file)} \u2192 ${path42.basename(archivedPath)} (${sizeMB}MB)`);
|
|
38130
38205
|
const newWriter = new SessionWriter(this.sessionsDir);
|
|
38131
38206
|
newWriter.open(this.config.workspace, "main");
|
|
38132
38207
|
newWriter.writeModelChange(this.config.providerId, this.config.model);
|
|
@@ -38135,7 +38210,7 @@ var SessionManager = class {
|
|
|
38135
38210
|
this.index.set("main", { file: newPath, updatedAt: Date.now() });
|
|
38136
38211
|
this.saveIndex();
|
|
38137
38212
|
this.purgeOldArchives(oldFileId, 3);
|
|
38138
|
-
console.log(`[session] Rotated main: ${oldFileId}.jsonl \u2192 ${
|
|
38213
|
+
console.log(`[session] Rotated main: ${oldFileId}.jsonl \u2192 ${path42.basename(newPath)}`);
|
|
38139
38214
|
}
|
|
38140
38215
|
// === 迁移 ===
|
|
38141
38216
|
/** 迁移旧索引:session-index.json 里有 "discord:xxx" 格式的 key 时,生成 UUID 替换 */
|
|
@@ -39027,12 +39102,12 @@ Examples:
|
|
|
39027
39102
|
// src/tools/msg-husband.ts
|
|
39028
39103
|
init_registry();
|
|
39029
39104
|
init_live();
|
|
39030
|
-
import
|
|
39031
|
-
import
|
|
39105
|
+
import fs43 from "node:fs";
|
|
39106
|
+
import path43 from "node:path";
|
|
39032
39107
|
function getHusbandFeishuId(workspace) {
|
|
39033
|
-
const contactsPath =
|
|
39108
|
+
const contactsPath = path43.join(workspace, "prompts", "contacts.md");
|
|
39034
39109
|
try {
|
|
39035
|
-
const text =
|
|
39110
|
+
const text = fs43.readFileSync(contactsPath, "utf-8");
|
|
39036
39111
|
const m = text.match(/\|\s*翀哥\s*\|\s*(ou_[a-f0-9]+)\s*\|/);
|
|
39037
39112
|
return m ? m[1] : null;
|
|
39038
39113
|
} catch {
|
|
@@ -39174,8 +39249,8 @@ Examples:
|
|
|
39174
39249
|
if (!to && !resolvedChannelId) {
|
|
39175
39250
|
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 };
|
|
39176
39251
|
}
|
|
39177
|
-
const
|
|
39178
|
-
if (!
|
|
39252
|
+
const fs58 = await import("node:fs");
|
|
39253
|
+
if (!fs58.existsSync(filePath)) {
|
|
39179
39254
|
return { content: `\u53D1\u9001\u5931\u8D25: \u6587\u4EF6\u4E0D\u5B58\u5728 ${filePath}`, isError: true };
|
|
39180
39255
|
}
|
|
39181
39256
|
const toIds = to ? to.split(",").map((s) => s.trim()).filter(Boolean) : [];
|
|
@@ -39203,7 +39278,7 @@ Examples:
|
|
|
39203
39278
|
md: "text/markdown"
|
|
39204
39279
|
};
|
|
39205
39280
|
const mimeType = mimeTypeMap[ext] || "application/octet-stream";
|
|
39206
|
-
const stat4 =
|
|
39281
|
+
const stat4 = fs58.statSync(filePath);
|
|
39207
39282
|
const sizeMB = stat4.size / 1024 / 1024;
|
|
39208
39283
|
if (sizeMB > 25) {
|
|
39209
39284
|
return { content: `\u53D1\u9001\u5931\u8D25: \u6587\u4EF6 ${sizeMB.toFixed(1)}MB \u8D85\u8FC7 Discord 25MB \u9650\u5236`, isError: true };
|
|
@@ -39233,8 +39308,8 @@ Examples:
|
|
|
39233
39308
|
init_live();
|
|
39234
39309
|
init_registry();
|
|
39235
39310
|
init_well_formed();
|
|
39236
|
-
import * as
|
|
39237
|
-
import * as
|
|
39311
|
+
import * as fs44 from "node:fs";
|
|
39312
|
+
import * as path44 from "node:path";
|
|
39238
39313
|
var MIME_MAP = {
|
|
39239
39314
|
".jpg": "jpeg",
|
|
39240
39315
|
".jpeg": "jpeg",
|
|
@@ -39246,9 +39321,9 @@ var MIME_MAP = {
|
|
|
39246
39321
|
var VIDEO_EXT = /\.(mp4|mov)$/i;
|
|
39247
39322
|
var VIDEO_MAX_BYTES = 40 * 1024 * 1024;
|
|
39248
39323
|
function resolveLatestImage(specifiedPath, mediaDir) {
|
|
39249
|
-
if (specifiedPath &&
|
|
39250
|
-
if (!
|
|
39251
|
-
const files =
|
|
39324
|
+
if (specifiedPath && fs44.existsSync(specifiedPath)) return specifiedPath;
|
|
39325
|
+
if (!fs44.existsSync(mediaDir)) return null;
|
|
39326
|
+
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);
|
|
39252
39327
|
return files[0]?.p || null;
|
|
39253
39328
|
}
|
|
39254
39329
|
registry.register({
|
|
@@ -39279,21 +39354,21 @@ registry.register({
|
|
|
39279
39354
|
if (!provider?.streamChat) {
|
|
39280
39355
|
return { content: "Error: provider \u4E0D\u53EF\u7528\u3002", isError: true };
|
|
39281
39356
|
}
|
|
39282
|
-
const mediaDir =
|
|
39357
|
+
const mediaDir = path44.join(ctx.stateDir, "media", "inbound");
|
|
39283
39358
|
const imagePath = resolveLatestImage(args.image_path, mediaDir);
|
|
39284
39359
|
if (!imagePath) {
|
|
39285
39360
|
return { content: "Error: no image found. Provide image_path or ensure media/inbound has images.", isError: true };
|
|
39286
39361
|
}
|
|
39287
39362
|
const rawPrompt = args.prompt?.trim() || "\u63CF\u8FF0\u8FD9\u5F20\u56FE\u7247\u7684\u5185\u5BB9";
|
|
39288
|
-
const ext =
|
|
39363
|
+
const ext = path44.extname(imagePath).toLowerCase();
|
|
39289
39364
|
if (VIDEO_EXT.test(imagePath)) {
|
|
39290
|
-
const stat4 =
|
|
39365
|
+
const stat4 = fs44.statSync(imagePath);
|
|
39291
39366
|
if (stat4.size > VIDEO_MAX_BYTES) {
|
|
39292
39367
|
return { content: `Error: video too large (${(stat4.size / 1e6).toFixed(1)}MB > 40MB). Compress or trim first.`, isError: true };
|
|
39293
39368
|
}
|
|
39294
39369
|
const explicit = liveConfig.get("tools.my_eyes.videoBaseUrl");
|
|
39295
39370
|
const baseUrl = explicit || providerCfg.baseUrl.replace(/\/anthropic\/?$/, "/v1").replace(/\/$/, "");
|
|
39296
|
-
const vidB64 =
|
|
39371
|
+
const vidB64 = fs44.readFileSync(imagePath).toString("base64");
|
|
39297
39372
|
try {
|
|
39298
39373
|
const res = await fetch(`${baseUrl}/chat/completions`, {
|
|
39299
39374
|
method: "POST",
|
|
@@ -39323,7 +39398,7 @@ registry.register({
|
|
|
39323
39398
|
}
|
|
39324
39399
|
}
|
|
39325
39400
|
const mime = MIME_MAP[ext] || "jpeg";
|
|
39326
|
-
const imgB64 =
|
|
39401
|
+
const imgB64 = fs44.readFileSync(imagePath).toString("base64");
|
|
39327
39402
|
const userMsg = {
|
|
39328
39403
|
role: "user",
|
|
39329
39404
|
content: [
|
|
@@ -39401,7 +39476,7 @@ var TTS_PROVIDERS = [
|
|
|
39401
39476
|
init_registry();
|
|
39402
39477
|
|
|
39403
39478
|
// src/tools/opus-encoder.ts
|
|
39404
|
-
import * as
|
|
39479
|
+
import * as fs45 from "node:fs";
|
|
39405
39480
|
var FRAME_MS = 20;
|
|
39406
39481
|
var PRESKIP_48K = 312;
|
|
39407
39482
|
var OPUS_RATE = 48e3;
|
|
@@ -39518,7 +39593,7 @@ async function wavToOggOpusNative(wavPath) {
|
|
|
39518
39593
|
const mod = await import("@discordjs/opus");
|
|
39519
39594
|
const OpusEncoder = mod.OpusEncoder ?? mod.default?.OpusEncoder;
|
|
39520
39595
|
if (!OpusEncoder) throw new Error("@discordjs/opus export shape unexpected");
|
|
39521
|
-
const wav = parseWav(
|
|
39596
|
+
const wav = parseWav(fs45.readFileSync(wavPath));
|
|
39522
39597
|
if (wav.channels !== 1) throw new Error(`unsupported ${wav.channels}ch (need mono)`);
|
|
39523
39598
|
if (!NATIVE_RATES.includes(wav.sampleRate)) throw new Error(`unsupported rate ${wav.sampleRate}`);
|
|
39524
39599
|
if (wav.pcm.length === 0) throw new Error("empty pcm data");
|
|
@@ -39554,7 +39629,7 @@ async function wavToOggOpusNative(wavPath) {
|
|
|
39554
39629
|
}
|
|
39555
39630
|
ogg.page(cur, pageGranule, false, true);
|
|
39556
39631
|
const oggPath = wavPath.replace(/\.wav$/, ".ogg");
|
|
39557
|
-
|
|
39632
|
+
fs45.writeFileSync(oggPath, ogg.finish());
|
|
39558
39633
|
return oggPath;
|
|
39559
39634
|
}
|
|
39560
39635
|
|
|
@@ -39583,10 +39658,10 @@ function fallbackChainOf(raw) {
|
|
|
39583
39658
|
init_live();
|
|
39584
39659
|
|
|
39585
39660
|
// src/tools/tts/relay.ts
|
|
39586
|
-
import * as
|
|
39661
|
+
import * as fs46 from "node:fs";
|
|
39587
39662
|
import * as os6 from "node:os";
|
|
39588
|
-
import * as
|
|
39589
|
-
var VOICE_DIR2 =
|
|
39663
|
+
import * as path45 from "node:path";
|
|
39664
|
+
var VOICE_DIR2 = path45.join(os6.tmpdir(), "engine-voice");
|
|
39590
39665
|
var fetchFn = fetch;
|
|
39591
39666
|
async function synthRelay(text, cfg) {
|
|
39592
39667
|
const res = await fetchFn(`${cfg.baseUrl}/audio/speech`, {
|
|
@@ -39605,9 +39680,9 @@ async function synthRelay(text, cfg) {
|
|
|
39605
39680
|
}
|
|
39606
39681
|
const buf = Buffer.from(await res.arrayBuffer());
|
|
39607
39682
|
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`);
|
|
39608
|
-
|
|
39609
|
-
const out =
|
|
39610
|
-
|
|
39683
|
+
fs46.mkdirSync(VOICE_DIR2, { recursive: true });
|
|
39684
|
+
const out = path45.join(VOICE_DIR2, `tts_relay_${Date.now()}.mp3`);
|
|
39685
|
+
fs46.writeFileSync(out, buf);
|
|
39611
39686
|
return {
|
|
39612
39687
|
path: out,
|
|
39613
39688
|
format: "mp3",
|
|
@@ -39726,8 +39801,8 @@ function synthesize(id, text, sink) {
|
|
|
39726
39801
|
// src/tools/my-voice.ts
|
|
39727
39802
|
import { execFile as execFile3 } from "node:child_process";
|
|
39728
39803
|
import { promisify as promisify3 } from "node:util";
|
|
39729
|
-
import * as
|
|
39730
|
-
import * as
|
|
39804
|
+
import * as fs47 from "node:fs";
|
|
39805
|
+
import * as path46 from "node:path";
|
|
39731
39806
|
var execFileAsync3 = promisify3(execFile3);
|
|
39732
39807
|
async function toWav24kWithDuration(audioPath) {
|
|
39733
39808
|
let wavPath = audioPath;
|
|
@@ -39745,15 +39820,15 @@ async function toWav24kWithDuration(audioPath) {
|
|
|
39745
39820
|
"pcm_s16le",
|
|
39746
39821
|
wavPath
|
|
39747
39822
|
], { timeout: 3e4 });
|
|
39748
|
-
if (!
|
|
39823
|
+
if (!fs47.existsSync(wavPath) || fs47.statSync(wavPath).size < 44) {
|
|
39749
39824
|
throw new Error("toWav24k produced empty output");
|
|
39750
39825
|
}
|
|
39751
39826
|
try {
|
|
39752
|
-
|
|
39827
|
+
fs47.unlinkSync(audioPath);
|
|
39753
39828
|
} catch {
|
|
39754
39829
|
}
|
|
39755
39830
|
}
|
|
39756
|
-
const durationSec = wavDurationSec(
|
|
39831
|
+
const durationSec = wavDurationSec(fs47.readFileSync(wavPath));
|
|
39757
39832
|
return { wavPath, durationSec };
|
|
39758
39833
|
}
|
|
39759
39834
|
async function compressWav(wavPath) {
|
|
@@ -39771,7 +39846,7 @@ async function compressWav(wavPath) {
|
|
|
39771
39846
|
"+faststart",
|
|
39772
39847
|
m4aPath
|
|
39773
39848
|
], { timeout: 3e4 });
|
|
39774
|
-
|
|
39849
|
+
fs47.unlinkSync(wavPath);
|
|
39775
39850
|
return m4aPath;
|
|
39776
39851
|
} catch {
|
|
39777
39852
|
return wavPath;
|
|
@@ -39798,10 +39873,10 @@ async function wavToOggOpus(wavPath) {
|
|
|
39798
39873
|
oggPath
|
|
39799
39874
|
], { timeout: 3e4 });
|
|
39800
39875
|
}
|
|
39801
|
-
if (!
|
|
39876
|
+
if (!fs47.existsSync(oggPath) || fs47.statSync(oggPath).size < 20) {
|
|
39802
39877
|
throw new Error("ogg/opus encode produced empty output");
|
|
39803
39878
|
}
|
|
39804
|
-
|
|
39879
|
+
fs47.unlinkSync(wavPath);
|
|
39805
39880
|
return oggPath;
|
|
39806
39881
|
}
|
|
39807
39882
|
async function sendVoiceToMulticaIssue(text, issueId, opts) {
|
|
@@ -39816,7 +39891,7 @@ async function sendVoiceToMulticaIssue(text, issueId, opts) {
|
|
|
39816
39891
|
} catch (e) {
|
|
39817
39892
|
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 };
|
|
39818
39893
|
}
|
|
39819
|
-
if (!audioPath || !
|
|
39894
|
+
if (!audioPath || !fs47.existsSync(audioPath)) {
|
|
39820
39895
|
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 };
|
|
39821
39896
|
}
|
|
39822
39897
|
if (audioPath.endsWith(".wav")) {
|
|
@@ -39826,21 +39901,21 @@ async function sendVoiceToMulticaIssue(text, issueId, opts) {
|
|
|
39826
39901
|
console.warn(`[my-voice:multaca] opus encode failed (${e.message}), attaching wav`);
|
|
39827
39902
|
}
|
|
39828
39903
|
}
|
|
39829
|
-
const ext =
|
|
39830
|
-
const sizeKB =
|
|
39904
|
+
const ext = path46.extname(audioPath).toLowerCase();
|
|
39905
|
+
const sizeKB = fs47.statSync(audioPath).size / 1024;
|
|
39831
39906
|
const voiceFile = `voice_${Date.now()}${ext}`;
|
|
39832
|
-
const cwdCopy =
|
|
39907
|
+
const cwdCopy = path46.join(process.cwd(), voiceFile);
|
|
39833
39908
|
try {
|
|
39834
|
-
|
|
39909
|
+
fs47.copyFileSync(audioPath, cwdCopy);
|
|
39835
39910
|
} catch (e) {
|
|
39836
39911
|
try {
|
|
39837
|
-
|
|
39912
|
+
fs47.unlinkSync(audioPath);
|
|
39838
39913
|
} catch {
|
|
39839
39914
|
}
|
|
39840
39915
|
return { content: `\u8BED\u97F3\u6302\u8F7D\u5931\u8D25\uFF08\u62F7\u8D1D\u5230\u5DE5\u4F5C\u76EE\u5F55\uFF09\uFF1A${e.message}`, isError: true };
|
|
39841
39916
|
}
|
|
39842
39917
|
try {
|
|
39843
|
-
|
|
39918
|
+
fs47.unlinkSync(audioPath);
|
|
39844
39919
|
} catch {
|
|
39845
39920
|
}
|
|
39846
39921
|
const content = opts.caption || `\u{1F399}\uFE0F \u8BED\u97F3\u6D88\u606F\uFF08${text.length} \u5B57\uFF09`;
|
|
@@ -39869,13 +39944,13 @@ async function sendVoiceToMulticaIssue(text, issueId, opts) {
|
|
|
39869
39944
|
}
|
|
39870
39945
|
if (!ok) throw new Error(`unexpected CLI output: ${String(stdout).slice(0, 200)}`);
|
|
39871
39946
|
try {
|
|
39872
|
-
|
|
39947
|
+
fs47.unlinkSync(cwdCopy);
|
|
39873
39948
|
} catch {
|
|
39874
39949
|
}
|
|
39875
39950
|
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)` };
|
|
39876
39951
|
} catch (e) {
|
|
39877
39952
|
try {
|
|
39878
|
-
|
|
39953
|
+
fs47.unlinkSync(cwdCopy);
|
|
39879
39954
|
} catch {
|
|
39880
39955
|
}
|
|
39881
39956
|
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 };
|
|
@@ -39992,10 +40067,10 @@ registry.register({
|
|
|
39992
40067
|
audioPath = await compressWav(audioPath);
|
|
39993
40068
|
}
|
|
39994
40069
|
}
|
|
39995
|
-
const ext =
|
|
40070
|
+
const ext = path46.extname(audioPath).toLowerCase();
|
|
39996
40071
|
const mimeMap = { ".mp3": "audio/mpeg", ".wav": "audio/wav", ".m4a": "audio/mp4", ".ogg": "audio/ogg", ".silk": "audio/silk" };
|
|
39997
40072
|
const mimeType = mimeMap[ext] || "audio/mpeg";
|
|
39998
|
-
const sizeKB =
|
|
40073
|
+
const sizeKB = fs47.statSync(audioPath).size / 1024;
|
|
39999
40074
|
try {
|
|
40000
40075
|
await mgr.sendFile(resolvedChannel, target, caption, {
|
|
40001
40076
|
path: audioPath,
|
|
@@ -40004,7 +40079,7 @@ registry.register({
|
|
|
40004
40079
|
...voiceDurationSec !== void 0 ? { voiceDurationSec } : {}
|
|
40005
40080
|
});
|
|
40006
40081
|
try {
|
|
40007
|
-
|
|
40082
|
+
fs47.unlinkSync(audioPath);
|
|
40008
40083
|
} catch {
|
|
40009
40084
|
}
|
|
40010
40085
|
return { content: `Voice sent! (${actualEngine}, ${sizeKB.toFixed(0)}KB, ${resolvedChannel})` };
|
|
@@ -40022,8 +40097,8 @@ registry.register({
|
|
|
40022
40097
|
init_live();
|
|
40023
40098
|
init_registry();
|
|
40024
40099
|
init_well_formed();
|
|
40025
|
-
import * as
|
|
40026
|
-
import * as
|
|
40100
|
+
import * as fs48 from "node:fs";
|
|
40101
|
+
import * as path47 from "node:path";
|
|
40027
40102
|
function getProxyDispatcher2() {
|
|
40028
40103
|
const cfg = liveConfig.all();
|
|
40029
40104
|
const proxy = cfg.providers?.xai?.proxy;
|
|
@@ -40037,7 +40112,7 @@ function getProxyDispatcher2() {
|
|
|
40037
40112
|
}
|
|
40038
40113
|
function dimsOf(p) {
|
|
40039
40114
|
try {
|
|
40040
|
-
const b =
|
|
40115
|
+
const b = fs48.readFileSync(p);
|
|
40041
40116
|
let w = 0, h = 0;
|
|
40042
40117
|
if (b.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]))) {
|
|
40043
40118
|
w = b.readUInt32BE(16);
|
|
@@ -40160,9 +40235,9 @@ function registerPortrait(relPath, name) {
|
|
|
40160
40235
|
const cur = cfg?.tools?.my_selfie?.references || cfg?.my_selfie?.references || [];
|
|
40161
40236
|
const next = Array.isArray(cur) ? cur.filter((r) => r?.name !== name) : [];
|
|
40162
40237
|
next.unshift({ name, path: relPath });
|
|
40163
|
-
const
|
|
40164
|
-
void liveConfig.set(
|
|
40165
|
-
console.log(`[my-selfie] \u5F62\u8C61\u5DF2\u767B\u8BB0\uFF1A${
|
|
40238
|
+
const path60 = cfg?.tools?.my_selfie ? "tools.my_selfie.references" : "my_selfie.references";
|
|
40239
|
+
void liveConfig.set(path60, next);
|
|
40240
|
+
console.log(`[my-selfie] \u5F62\u8C61\u5DF2\u767B\u8BB0\uFF1A${path60}[0] = ${relPath}`);
|
|
40166
40241
|
} catch (e) {
|
|
40167
40242
|
console.warn(`[my-selfie] \u5199\u5165 references \u5931\u8D25\uFF08\u4E0D\u5F71\u54CD\u672C\u6B21\u51FA\u56FE\uFF09: ${e.message}`);
|
|
40168
40243
|
}
|
|
@@ -40443,10 +40518,10 @@ registry.register({
|
|
|
40443
40518
|
const REFERENCES = getReferences(ctx);
|
|
40444
40519
|
const refName = args.reference || "default";
|
|
40445
40520
|
const refEntry = REFERENCES.find((r) => r.name === refName) || REFERENCES[0];
|
|
40446
|
-
let refPath =
|
|
40521
|
+
let refPath = path47.join(ctx.workspace, refEntry.p);
|
|
40447
40522
|
const adoptImg = args.referenceImage?.trim();
|
|
40448
40523
|
if (adoptImg) {
|
|
40449
|
-
if (!
|
|
40524
|
+
if (!fs48.existsSync(adoptImg)) {
|
|
40450
40525
|
return { content: `\u627E\u4E0D\u5230\u90A3\u5F20\u56FE\uFF1A${adoptImg}`, isError: true };
|
|
40451
40526
|
}
|
|
40452
40527
|
const acheck = dimsOf(adoptImg);
|
|
@@ -40457,16 +40532,16 @@ registry.register({
|
|
|
40457
40532
|
isError: true
|
|
40458
40533
|
};
|
|
40459
40534
|
}
|
|
40460
|
-
const adir =
|
|
40461
|
-
if (!
|
|
40462
|
-
const aext = (
|
|
40535
|
+
const adir = path47.join(ctx.workspace, "images");
|
|
40536
|
+
if (!fs48.existsSync(adir)) fs48.mkdirSync(adir, { recursive: true });
|
|
40537
|
+
const aext = (path47.extname(adoptImg) || ".png").toLowerCase();
|
|
40463
40538
|
const afname = `portrait_${Date.now()}${aext}`;
|
|
40464
|
-
|
|
40539
|
+
fs48.copyFileSync(adoptImg, path47.join(adir, afname));
|
|
40465
40540
|
registerPortrait(`images/${afname}`, refName);
|
|
40466
|
-
refPath =
|
|
40541
|
+
refPath = path47.join(adir, afname);
|
|
40467
40542
|
console.log(`[my-selfie] \u91C7\u7EB3\u73B0\u6210\u56FE\u5F53\u5F62\u8C61\uFF1Aimages/${afname}${acheck ? ` (${acheck})` : ""}`);
|
|
40468
40543
|
}
|
|
40469
|
-
if (provider !== "autodl" && !
|
|
40544
|
+
if (provider !== "autodl" && !fs48.existsSync(refPath)) {
|
|
40470
40545
|
const cfgAll = liveConfig.all();
|
|
40471
40546
|
const portraitDesc = resolvePortraitDesc(
|
|
40472
40547
|
args.portrait,
|
|
@@ -40491,16 +40566,16 @@ registry.register({
|
|
|
40491
40566
|
} catch (e) {
|
|
40492
40567
|
return { content: `\u5851\u9020\u5F62\u8C61\u5931\u8D25\uFF1A${e.message}`, isError: true };
|
|
40493
40568
|
}
|
|
40494
|
-
const pdir =
|
|
40495
|
-
if (!
|
|
40569
|
+
const pdir = path47.join(ctx.workspace, "images");
|
|
40570
|
+
if (!fs48.existsSync(pdir)) fs48.mkdirSync(pdir, { recursive: true });
|
|
40496
40571
|
const pfname = `portrait_${Date.now()}.png`;
|
|
40497
|
-
|
|
40572
|
+
fs48.writeFileSync(path47.join(pdir, pfname), portraitBuf);
|
|
40498
40573
|
registerPortrait(`images/${pfname}`, refName);
|
|
40499
|
-
refPath =
|
|
40574
|
+
refPath = path47.join(pdir, pfname);
|
|
40500
40575
|
console.log(`[my-selfie] \u5F62\u8C61\u5DF2\u5B58 images/${pfname}\uFF0C\u7EE7\u7EED\u8FD9\u6B21\u81EA\u62CD`);
|
|
40501
40576
|
}
|
|
40502
40577
|
const resolution = args.resolution || DEFAULT_RESOLUTION;
|
|
40503
|
-
const refB64 =
|
|
40578
|
+
const refB64 = fs48.existsSync(refPath) ? fs48.readFileSync(refPath).toString("base64") : "";
|
|
40504
40579
|
let imageBuffer;
|
|
40505
40580
|
try {
|
|
40506
40581
|
if (provider === "autodl") {
|
|
@@ -40516,7 +40591,7 @@ registry.register({
|
|
|
40516
40591
|
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 };
|
|
40517
40592
|
}
|
|
40518
40593
|
const model = cfgAll?.my_selfie?.relayModel || cfgAll?.tools?.my_selfie?.relayModel || "engine7-img-free";
|
|
40519
|
-
const ext =
|
|
40594
|
+
const ext = path47.extname(refPath).toLowerCase();
|
|
40520
40595
|
const mime = ext === ".png" ? "image/png" : ext === ".webp" ? "image/webp" : "image/jpeg";
|
|
40521
40596
|
imageBuffer = await generateWithRelay(refB64, fullPrompt, mime, relay.baseUrl, relay.apiKey, model);
|
|
40522
40597
|
} else {
|
|
@@ -40525,11 +40600,11 @@ registry.register({
|
|
|
40525
40600
|
} catch (err) {
|
|
40526
40601
|
return { content: `Selfie generation failed: ${err.message}`, isError: true };
|
|
40527
40602
|
}
|
|
40528
|
-
const imagesDir =
|
|
40529
|
-
if (!
|
|
40603
|
+
const imagesDir = path47.join(ctx.workspace, "images");
|
|
40604
|
+
if (!fs48.existsSync(imagesDir)) fs48.mkdirSync(imagesDir, { recursive: true });
|
|
40530
40605
|
const filename = `selfie_${Date.now()}.jpg`;
|
|
40531
|
-
const outputPath =
|
|
40532
|
-
|
|
40606
|
+
const outputPath = path47.join(imagesDir, filename);
|
|
40607
|
+
fs48.writeFileSync(outputPath, imageBuffer);
|
|
40533
40608
|
const mgr = ctx.channelManager;
|
|
40534
40609
|
if (mgr) {
|
|
40535
40610
|
const resolvedChannel = ctx.channel || "feishu";
|
|
@@ -40540,11 +40615,11 @@ registry.register({
|
|
|
40540
40615
|
mimeType: "image/jpeg"
|
|
40541
40616
|
});
|
|
40542
40617
|
} catch (err) {
|
|
40543
|
-
return { content: `Selfie generated but send failed: ${err.message}. Image: ${
|
|
40618
|
+
return { content: `Selfie generated but send failed: ${err.message}. Image: ${path47.resolve(outputPath)}`, isError: false };
|
|
40544
40619
|
}
|
|
40545
40620
|
return { content: `Selfie sent! Mode: ${mode}, Provider: ${provider}, Ref: ${refEntry.name}` };
|
|
40546
40621
|
}
|
|
40547
|
-
return { content: `Selfie generated! Mode: ${mode}, Ref: ${refEntry.name}. Image: ${
|
|
40622
|
+
return { content: `Selfie generated! Mode: ${mode}, Ref: ${refEntry.name}. Image: ${path47.resolve(outputPath)}` };
|
|
40548
40623
|
},
|
|
40549
40624
|
isConcurrencySafe: () => false,
|
|
40550
40625
|
interruptBehavior: () => "block",
|
|
@@ -41096,8 +41171,8 @@ ${lines.join("\n")}` };
|
|
|
41096
41171
|
init_registry();
|
|
41097
41172
|
init_live();
|
|
41098
41173
|
init_clock();
|
|
41099
|
-
import * as
|
|
41100
|
-
import * as
|
|
41174
|
+
import * as fs49 from "node:fs";
|
|
41175
|
+
import * as path48 from "node:path";
|
|
41101
41176
|
import { exec as exec2, spawn as spawn6 } from "node:child_process";
|
|
41102
41177
|
import { promisify as promisify4 } from "node:util";
|
|
41103
41178
|
var execAsync = promisify4(exec2);
|
|
@@ -41106,9 +41181,9 @@ function getServices() {
|
|
|
41106
41181
|
}
|
|
41107
41182
|
function serviceLogPath(fileName) {
|
|
41108
41183
|
const stateDir = String(liveConfig.get("stateDir") ?? "");
|
|
41109
|
-
const logDir =
|
|
41110
|
-
if (!
|
|
41111
|
-
return
|
|
41184
|
+
const logDir = path48.join(stateDir, "logs");
|
|
41185
|
+
if (!fs49.existsSync(logDir)) fs49.mkdirSync(logDir, { recursive: true });
|
|
41186
|
+
return path48.join(logDir, fileName);
|
|
41112
41187
|
}
|
|
41113
41188
|
async function runCmd(cmd, timeoutMs = 15e3) {
|
|
41114
41189
|
try {
|
|
@@ -41427,16 +41502,16 @@ var EXIT_PLAN_MODE_TOOL_NAME = "ExitPlanMode";
|
|
|
41427
41502
|
init_planModeState();
|
|
41428
41503
|
|
|
41429
41504
|
// src/utils/plans.ts
|
|
41430
|
-
import * as
|
|
41431
|
-
import * as
|
|
41505
|
+
import * as fs50 from "node:fs";
|
|
41506
|
+
import * as path49 from "node:path";
|
|
41432
41507
|
import * as crypto7 from "node:crypto";
|
|
41433
41508
|
var MAX_SLUG_RETRIES = 10;
|
|
41434
41509
|
function generateSlug() {
|
|
41435
41510
|
return crypto7.randomBytes(4).toString("hex");
|
|
41436
41511
|
}
|
|
41437
41512
|
function getPlansDirectory(stateDir) {
|
|
41438
|
-
const plansDir =
|
|
41439
|
-
|
|
41513
|
+
const plansDir = path49.join(stateDir, "plans");
|
|
41514
|
+
fs50.mkdirSync(plansDir, { recursive: true });
|
|
41440
41515
|
return plansDir;
|
|
41441
41516
|
}
|
|
41442
41517
|
var planSlugCache = /* @__PURE__ */ new Map();
|
|
@@ -41446,8 +41521,8 @@ function getPlanSlug(sessionId, stateDir) {
|
|
|
41446
41521
|
const plansDir = getPlansDirectory(stateDir);
|
|
41447
41522
|
for (let i = 0; i < MAX_SLUG_RETRIES; i++) {
|
|
41448
41523
|
slug = generateSlug();
|
|
41449
|
-
const filePath =
|
|
41450
|
-
if (!
|
|
41524
|
+
const filePath = path49.join(plansDir, `${slug}.md`);
|
|
41525
|
+
if (!fs50.existsSync(filePath)) {
|
|
41451
41526
|
break;
|
|
41452
41527
|
}
|
|
41453
41528
|
}
|
|
@@ -41458,21 +41533,21 @@ function getPlanSlug(sessionId, stateDir) {
|
|
|
41458
41533
|
function getPlanFilePath(sessionId, stateDir, agentId) {
|
|
41459
41534
|
const slug = getPlanSlug(sessionId, stateDir);
|
|
41460
41535
|
if (!agentId) {
|
|
41461
|
-
return
|
|
41536
|
+
return path49.join(getPlansDirectory(stateDir), `${slug}.md`);
|
|
41462
41537
|
}
|
|
41463
|
-
return
|
|
41538
|
+
return path49.join(getPlansDirectory(stateDir), `${slug}-agent-${agentId}.md`);
|
|
41464
41539
|
}
|
|
41465
41540
|
function getPlan(sessionId, stateDir, agentId) {
|
|
41466
41541
|
const filePath = getPlanFilePath(sessionId, stateDir, agentId);
|
|
41467
41542
|
try {
|
|
41468
|
-
return
|
|
41543
|
+
return fs50.readFileSync(filePath, "utf-8");
|
|
41469
41544
|
} catch {
|
|
41470
41545
|
return null;
|
|
41471
41546
|
}
|
|
41472
41547
|
}
|
|
41473
41548
|
function writePlan(sessionId, stateDir, content, agentId) {
|
|
41474
41549
|
const filePath = getPlanFilePath(sessionId, stateDir, agentId);
|
|
41475
|
-
|
|
41550
|
+
fs50.writeFileSync(filePath, content, "utf-8");
|
|
41476
41551
|
return filePath;
|
|
41477
41552
|
}
|
|
41478
41553
|
|
|
@@ -42290,8 +42365,8 @@ async function setupFeatures(features, licensedFeatures) {
|
|
|
42290
42365
|
init_agent_registry();
|
|
42291
42366
|
|
|
42292
42367
|
// src/commands/work.ts
|
|
42293
|
-
import * as
|
|
42294
|
-
import * as
|
|
42368
|
+
import * as fs55 from "node:fs";
|
|
42369
|
+
import * as path55 from "node:path";
|
|
42295
42370
|
registerCommand({
|
|
42296
42371
|
name: "work",
|
|
42297
42372
|
description: "\u5DE5\u4F5C\u6A21\u5F0F\uFF1A\u65E0\u53C2\u770B\u72B6\u6001\uFF0Con=\u5F3A\u5236work\uFF0Coff=\u5F3A\u5236emotion\uFF0Cauto=\u81EA\u52A8\u5224\u5B9A",
|
|
@@ -42304,20 +42379,20 @@ registerCommand({
|
|
|
42304
42379
|
],
|
|
42305
42380
|
handler: async (ctx, deps) => {
|
|
42306
42381
|
const mode = (ctx.args.mode || "").trim().toLowerCase();
|
|
42307
|
-
const modeFile =
|
|
42382
|
+
const modeFile = path55.join(deps.config.workspace, ".work-mode");
|
|
42308
42383
|
if (mode === "on" || mode === "off") {
|
|
42309
|
-
|
|
42384
|
+
fs55.writeFileSync(modeFile, mode, "utf8");
|
|
42310
42385
|
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");
|
|
42311
42386
|
} else if (mode === "auto") {
|
|
42312
42387
|
try {
|
|
42313
|
-
|
|
42388
|
+
fs55.unlinkSync(modeFile);
|
|
42314
42389
|
} catch {
|
|
42315
42390
|
}
|
|
42316
42391
|
await ctx.reply("\u5DE5\u4F5C\u6A21\u5F0F\u5DF2\u6062\u590D **auto**\uFF08emotion_state_machine \u9010\u6761\u81EA\u52A8\u5224\u5B9A\uFF09");
|
|
42317
42392
|
} else {
|
|
42318
42393
|
let cur = "auto";
|
|
42319
42394
|
try {
|
|
42320
|
-
cur =
|
|
42395
|
+
cur = fs55.readFileSync(modeFile, "utf8").trim() || "auto";
|
|
42321
42396
|
} catch {
|
|
42322
42397
|
}
|
|
42323
42398
|
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";
|
|
@@ -42787,8 +42862,8 @@ ${err.stack}`);
|
|
|
42787
42862
|
});
|
|
42788
42863
|
|
|
42789
42864
|
// src/commands/model.ts
|
|
42790
|
-
import * as
|
|
42791
|
-
import * as
|
|
42865
|
+
import * as fs56 from "node:fs";
|
|
42866
|
+
import * as path56 from "node:path";
|
|
42792
42867
|
import { fileURLToPath as fileURLToPath8 } from "node:url";
|
|
42793
42868
|
function collectModels(config) {
|
|
42794
42869
|
const aliases = config.modelAliases || {};
|
|
@@ -42820,11 +42895,11 @@ function resolveConfigWritePath(config, label) {
|
|
|
42820
42895
|
const configPath = config._configFilePath;
|
|
42821
42896
|
if (!configPath) return void 0;
|
|
42822
42897
|
let writePath = configPath;
|
|
42823
|
-
if (configPath && !
|
|
42898
|
+
if (configPath && !fs56.existsSync(configPath)) {
|
|
42824
42899
|
const __pFile = fileURLToPath8(import.meta.url);
|
|
42825
|
-
const __pDir =
|
|
42826
|
-
const altPath =
|
|
42827
|
-
if (
|
|
42900
|
+
const __pDir = path56.dirname(__pFile);
|
|
42901
|
+
const altPath = path56.join(path56.resolve(__pDir, "../configs"), path56.basename(configPath));
|
|
42902
|
+
if (fs56.existsSync(altPath)) {
|
|
42828
42903
|
console.warn(`[${label}] Config not found at ${configPath}, falling back to ${altPath}`);
|
|
42829
42904
|
writePath = altPath;
|
|
42830
42905
|
}
|
|
@@ -42883,22 +42958,22 @@ ${lines.join("\n")}`);
|
|
|
42883
42958
|
await ctx.reply(wasOverride ? `Reset to default: **${defaultRef}** (auto-routing restored, fallback cooldowns cleared)` : `Already using default: **${defaultRef}**`);
|
|
42884
42959
|
return;
|
|
42885
42960
|
}
|
|
42886
|
-
const
|
|
42887
|
-
if (
|
|
42961
|
+
const candidates2 = matchModels(input, aliases, available);
|
|
42962
|
+
if (candidates2.length === 0) {
|
|
42888
42963
|
await ctx.reply(`No model matching "${input}". Use \`/model\` to see list.`);
|
|
42889
42964
|
return;
|
|
42890
42965
|
}
|
|
42891
|
-
if (
|
|
42892
|
-
const lines =
|
|
42893
|
-
const more =
|
|
42894
|
-
... and ${
|
|
42966
|
+
if (candidates2.length > 1) {
|
|
42967
|
+
const lines = candidates2.slice(0, 10).map((a) => `- \`${a.ref}\` \u2014 ${a.name}`);
|
|
42968
|
+
const more = candidates2.length > 10 ? `
|
|
42969
|
+
... and ${candidates2.length - 10} more` : "";
|
|
42895
42970
|
await ctx.reply(`Multiple matches for "${input}":
|
|
42896
42971
|
${lines.join("\n")}${more}
|
|
42897
42972
|
|
|
42898
|
-
Use full ref like \`/model ${
|
|
42973
|
+
Use full ref like \`/model ${candidates2[0].ref}\``);
|
|
42899
42974
|
return;
|
|
42900
42975
|
}
|
|
42901
|
-
const target =
|
|
42976
|
+
const target = candidates2[0].ref;
|
|
42902
42977
|
let targetDeps = deps.modelDepsCache.get(target);
|
|
42903
42978
|
if (!targetDeps) {
|
|
42904
42979
|
targetDeps = deps.createModelDeps(target);
|
|
@@ -42936,8 +43011,8 @@ Use full ref like \`/model ${candidates[0].ref}\``);
|
|
|
42936
43011
|
const writer = deps.sessions.getWriter(sid);
|
|
42937
43012
|
writer.writeModelChange(pid, mid);
|
|
42938
43013
|
}
|
|
42939
|
-
console.log(`[model] Switched to ${target} (${
|
|
42940
|
-
await ctx.reply(`Switched to **${target}** (${
|
|
43014
|
+
console.log(`[model] Switched to ${target} (${candidates2[0].name})`);
|
|
43015
|
+
await ctx.reply(`Switched to **${target}** (${candidates2[0].name})
|
|
42941
43016
|
Auto-routing disabled \u2014 all messages use this model.
|
|
42942
43017
|
\`/model auto\` to restore default.`);
|
|
42943
43018
|
}
|
|
@@ -42960,35 +43035,35 @@ Usage: \`/primary provider/model\` to persist (restart required)`);
|
|
|
42960
43035
|
return;
|
|
42961
43036
|
}
|
|
42962
43037
|
const { aliases, available } = collectModels(deps.config);
|
|
42963
|
-
const
|
|
42964
|
-
if (
|
|
43038
|
+
const candidates2 = matchModels(input, aliases, available);
|
|
43039
|
+
if (candidates2.length === 0) {
|
|
42965
43040
|
await ctx.reply(`No model matching "${input}".`);
|
|
42966
43041
|
return;
|
|
42967
43042
|
}
|
|
42968
|
-
if (
|
|
42969
|
-
const lines =
|
|
43043
|
+
if (candidates2.length > 1) {
|
|
43044
|
+
const lines = candidates2.slice(0, 10).map((a) => `- \`${a.ref}\` \u2014 ${a.name}`);
|
|
42970
43045
|
await ctx.reply(`Multiple matches:
|
|
42971
43046
|
${lines.join("\n")}
|
|
42972
43047
|
|
|
42973
|
-
Use full ref like \`/primary ${
|
|
43048
|
+
Use full ref like \`/primary ${candidates2[0].ref}\``);
|
|
42974
43049
|
return;
|
|
42975
43050
|
}
|
|
42976
|
-
const target =
|
|
43051
|
+
const target = candidates2[0].ref;
|
|
42977
43052
|
if (!configPath || !writePath) {
|
|
42978
43053
|
await ctx.reply(`\u26A0\uFE0F Config file path not available, cannot persist. Set manually in config.`);
|
|
42979
43054
|
return;
|
|
42980
43055
|
}
|
|
42981
43056
|
try {
|
|
42982
|
-
const raw = await
|
|
43057
|
+
const raw = await fs56.promises.readFile(writePath, "utf-8");
|
|
42983
43058
|
const cfg = JSON.parse(raw);
|
|
42984
43059
|
if (!cfg.agents?.defaults?.model) {
|
|
42985
43060
|
await ctx.reply(`\u26A0\uFE0F Config structure mismatch: agents.defaults.model not found`);
|
|
42986
43061
|
return;
|
|
42987
43062
|
}
|
|
42988
43063
|
cfg.agents.defaults.model.primary = target;
|
|
42989
|
-
await
|
|
43064
|
+
await fs56.promises.writeFile(writePath, JSON.stringify(cfg, null, 2), "utf-8");
|
|
42990
43065
|
console.log(`[primary] Persisted primary=${target} to ${writePath}`);
|
|
42991
|
-
await ctx.reply(`\u2705 Primary model set to **${target}** (${
|
|
43066
|
+
await ctx.reply(`\u2705 Primary model set to **${target}** (${candidates2[0].name})
|
|
42992
43067
|
Written to config, hot-reloading provider chain now.`);
|
|
42993
43068
|
} catch (err) {
|
|
42994
43069
|
await ctx.reply(`\u26A0\uFE0F Failed to write config: ${err.message}`);
|
|
@@ -43014,26 +43089,26 @@ Usage: \`/vision-primary provider/model\` to persist (hot-reload)
|
|
|
43014
43089
|
return;
|
|
43015
43090
|
}
|
|
43016
43091
|
const { aliases, available } = collectModels(deps.config);
|
|
43017
|
-
const
|
|
43018
|
-
if (
|
|
43092
|
+
const candidates2 = matchModels(input, aliases, available);
|
|
43093
|
+
if (candidates2.length === 0) {
|
|
43019
43094
|
await ctx.reply(`No model matching "${input}".`);
|
|
43020
43095
|
return;
|
|
43021
43096
|
}
|
|
43022
|
-
if (
|
|
43023
|
-
const lines =
|
|
43097
|
+
if (candidates2.length > 1) {
|
|
43098
|
+
const lines = candidates2.slice(0, 10).map((a) => `- \`${a.ref}\` \u2014 ${a.name}`);
|
|
43024
43099
|
await ctx.reply(`Multiple matches:
|
|
43025
43100
|
${lines.join("\n")}
|
|
43026
43101
|
|
|
43027
|
-
Use full ref like \`/vision-primary ${
|
|
43102
|
+
Use full ref like \`/vision-primary ${candidates2[0].ref}\``);
|
|
43028
43103
|
return;
|
|
43029
43104
|
}
|
|
43030
|
-
const target =
|
|
43105
|
+
const target = candidates2[0].ref;
|
|
43031
43106
|
if (!configPath || !writePath) {
|
|
43032
43107
|
await ctx.reply(`\u26A0\uFE0F Config file path not available, cannot persist. Set manually in config.`);
|
|
43033
43108
|
return;
|
|
43034
43109
|
}
|
|
43035
43110
|
try {
|
|
43036
|
-
const raw = await
|
|
43111
|
+
const raw = await fs56.promises.readFile(writePath, "utf-8");
|
|
43037
43112
|
const cfg = JSON.parse(raw);
|
|
43038
43113
|
if (!cfg.agents?.defaults?.model) {
|
|
43039
43114
|
await ctx.reply(`\u26A0\uFE0F Config structure mismatch: agents.defaults.model not found`);
|
|
@@ -43041,14 +43116,14 @@ Use full ref like \`/vision-primary ${candidates[0].ref}\``);
|
|
|
43041
43116
|
}
|
|
43042
43117
|
if (input === "auto" || input === "reset") {
|
|
43043
43118
|
delete cfg.agents.defaults.model.vision;
|
|
43044
|
-
await
|
|
43119
|
+
await fs56.promises.writeFile(writePath, JSON.stringify(cfg, null, 2), "utf-8");
|
|
43045
43120
|
console.log(`[vision-primary] Cleared vision primary in ${writePath}`);
|
|
43046
43121
|
await ctx.reply(`\u2705 Vision primary cleared (auto). Written to config. Hot-reload will apply.`);
|
|
43047
43122
|
} else {
|
|
43048
43123
|
cfg.agents.defaults.model.vision = target;
|
|
43049
|
-
await
|
|
43124
|
+
await fs56.promises.writeFile(writePath, JSON.stringify(cfg, null, 2), "utf-8");
|
|
43050
43125
|
console.log(`[vision-primary] Persisted vision=${target} to ${writePath}`);
|
|
43051
|
-
await ctx.reply(`\u2705 Vision primary set to **${target}** (${
|
|
43126
|
+
await ctx.reply(`\u2705 Vision primary set to **${target}** (${candidates2[0].name})
|
|
43052
43127
|
Written to config. Hot-reload will apply.`);
|
|
43053
43128
|
}
|
|
43054
43129
|
} catch (err) {
|
|
@@ -43080,20 +43155,20 @@ Available models: use \`/model\` to see full list
|
|
|
43080
43155
|
return;
|
|
43081
43156
|
}
|
|
43082
43157
|
const { aliases, available } = collectModels(deps.config);
|
|
43083
|
-
const
|
|
43084
|
-
if (
|
|
43158
|
+
const candidates2 = matchModels(input, aliases, available);
|
|
43159
|
+
if (candidates2.length === 0) {
|
|
43085
43160
|
await ctx.reply(`No model matching "${input}".`);
|
|
43086
43161
|
return;
|
|
43087
43162
|
}
|
|
43088
|
-
if (
|
|
43089
|
-
const lines =
|
|
43163
|
+
if (candidates2.length > 1) {
|
|
43164
|
+
const lines = candidates2.slice(0, 10).map((a) => `- \`${a.ref}\` \u2014 ${a.name}`);
|
|
43090
43165
|
await ctx.reply(`Multiple matches:
|
|
43091
43166
|
${lines.join("\n")}
|
|
43092
43167
|
|
|
43093
|
-
Use full ref like \`/vision-model ${
|
|
43168
|
+
Use full ref like \`/vision-model ${candidates2[0].ref}\``);
|
|
43094
43169
|
return;
|
|
43095
43170
|
}
|
|
43096
|
-
const target =
|
|
43171
|
+
const target = candidates2[0].ref;
|
|
43097
43172
|
let targetDeps = deps.modelDepsCache.get(`vision:${target}`);
|
|
43098
43173
|
if (!targetDeps) {
|
|
43099
43174
|
targetDeps = deps.createModelDeps(target);
|
|
@@ -43106,7 +43181,7 @@ Use full ref like \`/vision-model ${candidates[0].ref}\``);
|
|
|
43106
43181
|
deps.setVisionOverride(target);
|
|
43107
43182
|
deps.setVisionDeps(targetDeps);
|
|
43108
43183
|
console.log(`[vision-model] Override: ${target}`);
|
|
43109
|
-
await ctx.reply(`Vision switched to **${target}** (${
|
|
43184
|
+
await ctx.reply(`Vision switched to **${target}** (${candidates2[0].name}) (immediate)
|
|
43110
43185
|
\`/vision-model auto\` to restore default.`);
|
|
43111
43186
|
}
|
|
43112
43187
|
});
|
|
@@ -43454,7 +43529,7 @@ async function startEngine(config, opts) {
|
|
|
43454
43529
|
const { initSessionMemory: initSessionMemory2 } = await Promise.resolve().then(() => (init_sessionMemory(), sessionMemory_exports));
|
|
43455
43530
|
initSessionMemory2({
|
|
43456
43531
|
workspace: config.workspace,
|
|
43457
|
-
stateDir:
|
|
43532
|
+
stateDir: path59.join(config.stateDir, "session-memory"),
|
|
43458
43533
|
provider,
|
|
43459
43534
|
model: config.provider.modelId || config.model || "deepseek-v4-flash",
|
|
43460
43535
|
features: config.profile.features
|
|
@@ -43925,7 +44000,7 @@ async function startEngine(config, opts) {
|
|
|
43925
44000
|
};
|
|
43926
44001
|
const startReportingNow = () => {
|
|
43927
44002
|
stopReporting();
|
|
43928
|
-
reportingHandle = startReporting({ stateDir: config.stateDir });
|
|
44003
|
+
reportingHandle = startReporting({ stateDir: config.stateDir, log: (m) => console.log(m) });
|
|
43929
44004
|
};
|
|
43930
44005
|
const reportingEnabled = () => liveConfig.get("reporting.enabled") !== false;
|
|
43931
44006
|
reloadOrchestrator.register({
|