engine7 7.1.113 → 7.1.114

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2445,14 +2445,14 @@ var init_live = __esm({
2445
2445
  }
2446
2446
  /** 把改动写回 config 文件对应段(找不到文件路径则只内存生效) */
2447
2447
  async persistToFile(dotPath, val) {
2448
- const fs59 = await import("node:fs");
2448
+ const fs58 = await import("node:fs");
2449
2449
  const cfgPath = this.current?._configFilePath;
2450
- if (!cfgPath || !fs59.existsSync(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(fs59.readFileSync(cfgPath, "utf-8"));
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
- fs59.writeFileSync(cfgPath, JSON.stringify(raw, null, 2) + "\n", "utf-8");
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 candidates = result.trim().split(/\r?\n/).map((s) => s.trim()).filter(Boolean);
3087
- const nonWsl = candidates.find((p) => !isWslBash(p));
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 fs59 = await import("node:fs");
4041
+ const fs58 = await import("node:fs");
4042
4042
  try {
4043
- await fs59.promises.mkdir(memoryDir, { recursive: true });
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((fs59) => fs59.rm(lockPath2, { force: true }));
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((fs59) => fs59.rm(lockPath2, { force: true }));
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 candidates = fenced ? [fenced[1], text] : [text];
14194
- for (const c of candidates) {
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 candidates = actionable.filter((s) => {
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 (candidates.length === 0) return 0;
14870
+ if (candidates2.length === 0) return 0;
14871
14871
  let enqueued = 0;
14872
- for (const scored of candidates) {
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 path61 = lockPath(memoryDir);
16731
+ const path60 = lockPath(memoryDir);
16732
16732
  let mtimeMs;
16733
16733
  let holderPid;
16734
16734
  try {
16735
- const [s, raw] = await Promise.all([stat3(path61), readFile5(path61, "utf8")]);
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(path61, String(process.pid));
16748
+ await writeFile4(path60, String(process.pid));
16749
16749
  let verify2;
16750
16750
  try {
16751
- verify2 = await readFile5(path61, "utf8");
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 path61 = lockPath(memoryDir);
16759
+ const path60 = lockPath(memoryDir);
16760
16760
  try {
16761
16761
  if (priorMtime === 0) {
16762
- await unlink(path61);
16762
+ await unlink(path60);
16763
16763
  return;
16764
16764
  }
16765
- await writeFile4(path61, "");
16765
+ await writeFile4(path60, "");
16766
16766
  const t = priorMtime / 1e3;
16767
- await utimes(path61, t, t);
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 fs59 = await import("fs");
17370
- const path61 = await import("path");
17371
- if (!path61.isAbsolute(filePath)) {
17372
- filePath = path61.join(deps.sessions["config"].stateDir, 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 = fs59.readFileSync(filePath, "utf-8");
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 path61 = await import("path");
17413
- const fs59 = await import("fs");
17412
+ const path60 = await import("path");
17413
+ const fs58 = await import("fs");
17414
17414
  let scriptPath = task.postProcess;
17415
- if (!path61.isAbsolute(scriptPath)) {
17416
- scriptPath = path61.join(deps.sessions["config"].stateDir, scriptPath);
17415
+ if (!path60.isAbsolute(scriptPath)) {
17416
+ scriptPath = path60.join(deps.sessions["config"].stateDir, scriptPath);
17417
17417
  }
17418
- const resultsDirTmp = path61.join(getStorageDir(), "results");
17419
- fs59.mkdirSync(resultsDirTmp, { recursive: true });
17420
- const inputFile = path61.join(resultsDirTmp, `${task.id}.input.txt`);
17421
- fs59.writeFileSync(inputFile, result, "utf-8");
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 fs59 = await import("fs");
17449
- const path61 = await import("path");
17450
- const resultsDir = path61.join(getStorageDir(), "results");
17451
- fs59.mkdirSync(resultsDir, { recursive: true });
17452
- const resultFile = path61.join(resultsDir, `${task.id}.json`);
17453
- fs59.writeFileSync(resultFile, JSON.stringify({
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 fs59 = await import("fs");
17784
- const path61 = await import("path");
17785
- const resultsDir = path61.join(getStorageDir(), "results");
17786
- if (!fs59.existsSync(resultsDir)) {
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 = path61.join(resultsDir, `${args.task_id}.json`);
17791
- if (!fs59.existsSync(file2)) {
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(fs59.readFileSync(file2, "utf-8"));
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 = fs59.readdirSync(resultsDir).filter((f) => f.endsWith(".json"));
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(fs59.readFileSync(path61.join(resultsDir, f), "utf-8"));
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/startup/api-status.ts
18331
- var api_status_exports = {};
18332
- __export(api_status_exports, {
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 readEngineVersion() {
18340
- const here = path35.dirname(fileURLToPath6(import.meta.url));
18341
- for (const p of [path35.join(here, "..", "package.json"), path35.join(here, "..", "..", "package.json")]) {
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(fs35.readFileSync(p, "utf8")).version || "unknown";
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 path61 = join44(workspace, ".reply-blocklist.json");
18500
+ const path60 = join44(workspace, ".reply-blocklist.json");
18482
18501
  try {
18483
- if (existsSync22(path61)) {
18484
- const raw = readFileSync32(path61, "utf-8");
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 path61 = join44(workspace, ".reply-blocklist.json");
18519
+ const path60 = join44(workspace, ".reply-blocklist.json");
18501
18520
  try {
18502
- writeFileSync10(path61, JSON.stringify(state, null, 2), "utf-8");
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 path39 from "path";
18948
- import fs39 from "fs";
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 = path39.dirname(new URL(import.meta.url).pathname);
18994
- const candidates = [
18995
- path39.join(distDir, "..", "python", "tts_daemon.py"),
18996
- path39.join(process.cwd(), "engine/src/python/tts_daemon.py"),
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 candidates) {
19000
- if (fs39.existsSync(c)) return c;
19018
+ for (const c of candidates2) {
19019
+ if (fs38.existsSync(c)) return c;
19001
19020
  }
19002
- return candidates[0];
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 fs52 from "node:fs";
19073
- import * as path51 from "node:path";
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 = fs52.statSync(filePath);
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 = fs52.openSync(filePath, "r");
19113
+ const fd = fs51.openSync(filePath, "r");
19095
19114
  const bom = Buffer.alloc(2);
19096
- fs52.readSync(fd, bom, 0, 2, 0);
19097
- fs52.closeSync(fd);
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 = fs52.statSync(filePath);
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 = fs52.readFileSync(filePath, encoding);
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 (!fs52.existsSync(filePath)) {
19267
+ if (!fs51.existsSync(filePath)) {
19249
19268
  return { content: `\u6587\u4EF6\u4E0D\u5B58\u5728: ${filePath}`, isError: true };
19250
19269
  }
19251
- const stat4 = fs52.statSync(filePath);
19252
- const baseName = path51.basename(filePath).toUpperCase();
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 = fs52.readdirSync(filePath);
19279
+ const entries2 = fs51.readdirSync(filePath);
19261
19280
  const items = entries2.map((e) => {
19262
- const full = path51.join(filePath, e);
19281
+ const full = path50.join(filePath, e);
19263
19282
  try {
19264
- const s = fs52.statSync(full);
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 = path51.extname(filePath).toLowerCase();
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 fs53 from "node:fs";
19322
- import * as path52 from "node:path";
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
- fs53.writeFileSync(tmpPath, content, "utf-8");
19347
+ fs52.writeFileSync(tmpPath, content, "utf-8");
19329
19348
  try {
19330
- fs53.renameSync(tmpPath, filePath);
19349
+ fs52.renameSync(tmpPath, filePath);
19331
19350
  } catch (e) {
19332
19351
  try {
19333
- fs53.unlinkSync(tmpPath);
19352
+ fs52.unlinkSync(tmpPath);
19334
19353
  } catch {
19335
19354
  }
19336
- fs53.writeFileSync(filePath, content, "utf-8");
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 (fs53.existsSync(filePath) && fs53.statSync(filePath).isDirectory()) {
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 (fs53.existsSync(filePath)) {
19454
+ if (fs52.existsSync(filePath)) {
19436
19455
  isCreate = false;
19437
19456
  try {
19438
- oldContent = fs53.readFileSync(filePath, "utf-8").replaceAll("\r\n", "\n");
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 = fs53.statSync(filePath);
19473
+ const currentStat = fs52.statSync(filePath);
19455
19474
  const lastWriteTime = Math.floor(currentStat.mtimeMs);
19456
19475
  if (lastWriteTime > readState.timestamp) {
19457
- const currentContent = fs53.readFileSync(filePath, "utf-8").replaceAll("\r\n", "\n");
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 = path52.dirname(filePath);
19485
+ const dir = path51.dirname(filePath);
19467
19486
  try {
19468
- fs53.mkdirSync(dir, { recursive: true });
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: fs53.statSync(filePath).mtimeMs });
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 = fs53.statSync(filePath);
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 fs54 from "node:fs";
19502
- import * as path53 from "node:path";
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 = fs54.statSync(filePath);
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 = path53.dirname(filePath);
19666
- fs54.mkdirSync(dir, { recursive: true });
19667
- fs54.writeFileSync(filePath, newString, "utf-8");
19668
- readFileState.set(filePath, { timestamp: fs54.statSync(filePath).mtimeMs });
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 = fs54.readFileSync(filePath, "utf-8");
19694
+ const rawContent = fs53.readFileSync(filePath, "utf-8");
19676
19695
  fileContent = rawContent.replaceAll("\r\n", "\n");
19677
19696
  if (oldString === "" && fileContent.trim() === "") {
19678
- fs54.writeFileSync(filePath, newString, "utf-8");
19679
- readFileState.set(filePath, { timestamp: fs54.statSync(filePath).mtimeMs });
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 = fs54.statSync(filePath);
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 !== fs54.readFileSync(filePath, "utf-8").replaceAll("\r\n", "\n")) {
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
- fs54.writeFileSync(filePath, newContent, "utf-8");
19726
- readFileState.set(filePath, { timestamp: fs54.statSync(filePath).mtimeMs });
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 fs55 from "node:fs";
19745
- import * as path54 from "node:path";
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 = fs55.readdirSync(currentDir, { withFileTypes: true });
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 = path54.join(currentDir, entry.name);
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 = path54.relative(baseDir, fullPath).replace(/\\/g, "/");
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 = fs55.statSync(fullPath);
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 + path54.sep)) {
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 (!fs55.existsSync(searchPath)) {
19855
+ if (!fs54.existsSync(searchPath)) {
19837
19856
  return { content: `\u76EE\u5F55\u4E0D\u5B58\u5728: ${searchPath}`, isError: true };
19838
19857
  }
19839
- if (!fs55.statSync(searchPath).isDirectory()) {
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 path55 from "node:path";
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 + path55.sep)) {
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 randomUUID8 } from "crypto";
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_${randomUUID8().replace(/-/g, "").slice(0, 24)}`
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 randomBytes6 } from "node:crypto";
20590
+ import { randomBytes as randomBytes7 } from "node:crypto";
20572
20591
  function generateAgentId() {
20573
20592
  const prefix = "a";
20574
- const bytes = randomBytes6(8);
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 fs58 from "node:fs";
22419
- import * as path58 from "node:path";
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 = path58.join(process.env.ENGINE_STATE_DIR || ".engine", "mcp-blobs");
22461
- fs58.mkdirSync(dir, { recursive: true });
22462
- const filepath = path58.join(dir, `${persistId}.${ext}`);
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
- fs58.writeFileSync(filepath, buf);
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 path59 from "node:path";
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 || path59.join(process.env.ENGINE_STATE_DIR || ".engine", "media", "inbound");
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 path60 from "node:path";
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 fs59 = __require("node:fs/promises");
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 fs59.readFile(filePath, "utf-8");
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, candidates, topK, ollamaChatUrl, model) {
25651
- if (candidates.length <= topK) return candidates;
25652
- const manifest = candidates.map(
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 candidates.slice(0, topK);
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 <= candidates.length).map((n) => n - 1);
25694
- const result = indices.map((i) => candidates[i]);
25695
- console.log(`[memdir] rerank: ${model} selected ${result.length}/${candidates.length} candidates (indices: ${indices.map((i) => i + 1).join(",")})`);
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 candidates.slice(0, topK);
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 candidates.slice(0, topK);
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 candidates = scored.slice(0, CANDIDATE_POOL);
25773
+ const candidates2 = scored.slice(0, CANDIDATE_POOL);
25755
25774
  const vectorMs = Date.now() - t0;
25756
25775
  console.log(
25757
- `[memdir] vector recall: ${candidates.length} candidates in ${vectorMs}ms (embed=${embedMs}ms, scanned=${rows.length} files, minScore=${minScore})`
25776
+ `[memdir] vector recall: ${candidates2.length} candidates in ${vectorMs}ms (embed=${embedMs}ms, scanned=${rows.length} files, minScore=${minScore})`
25758
25777
  );
25759
- if (candidates.length > 0) {
25760
- console.log(`[memdir] vector top scores: ${candidates.slice(0, 5).map((r) => `${r.filename}=${r.score.toFixed(3)}`).join(", ")}${candidates.length > 5 ? "..." : ""}`);
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 (candidates.length === 0) return [];
25781
+ if (candidates2.length === 0) return [];
25763
25782
  const rerankT0 = Date.now();
25764
- const reranked = await llmRerank(query, candidates, topK, DEFAULT_OLLAMA_CHAT_URL, rerankModel);
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 path61 = join36(workspace, "prompts", "external-chan-rules.md");
26192
- if (externalChanRulesCache && externalChanRulesCache.path === path61) return externalChanRulesCache;
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(path61)) {
26213
+ if (existsSync19(path60)) {
26195
26214
  try {
26196
- content = readFileSync26(path61, "utf-8").trim();
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: path61, content };
26202
- console.log(`[external-chan-rules] Loaded ${content.length} chars from ${path61}`);
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 fs59 = await import("node:fs");
27090
- if (!fs59.existsSync(dailyDir)) {
27091
- fs59.mkdirSync(dailyDir, { recursive: true });
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 (fs59.existsSync(sessionFile)) {
27097
- const content = fs59.readFileSync(sessionFile, "utf-8");
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 (fs59.existsSync(dailyPath)) {
27128
- fs59.appendFileSync(dailyPath, entry);
27146
+ if (fs58.existsSync(dailyPath)) {
27147
+ fs58.appendFileSync(dailyPath, entry);
27129
27148
  } else {
27130
- fs59.writeFileSync(dailyPath, `# ${dateStr} \u65E5\u5FD7
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 fs59 = await import("node:fs");
27165
+ const fs58 = await import("node:fs");
27147
27166
  const bufferPath = path22.join(workspace, "memory", "working-buffer.md");
27148
- if (fs59.existsSync(bufferPath)) {
27149
- const stat4 = fs59.statSync(bufferPath);
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 = fs59.readFileSync(bufferPath, "utf-8");
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
- console.log(`[inbox-poller] #${pollCycleCount} teammates=[${statusSummary}] mainActive=${isMainActive} mainPending=${mainPending}`);
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: (text) => {
30657
- if (inboxPreview) {
30658
- inboxPreview.appendText(text);
30659
- } else {
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 (content) => {
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 path36 from "node:path";
31365
- import fs36 from "node:fs";
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 = path36.dirname(this.config.lancedbPath);
31600
- const configPath = path36.join(pythonDir, "config.toml");
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 || path36.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7");
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 path36.join(stateDir, "everos-venv", "Scripts", "python.exe");
31707
+ return path35.join(stateDir, "everos-venv", "Scripts", "python.exe");
31693
31708
  }
31694
- return path36.join(stateDir, "everos-venv", "bin", "python");
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 (fs36.existsSync(venvPython)) return;
31700
- const stateDir = process.env.ENGINE7_STATE_DIR || path36.join(process.env.HOME || process.env.USERPROFILE || ".", ".engine7");
31701
- const venvDir = path36.join(stateDir, "everos-venv");
31702
- const everosSrc = path36.join(stateDir, "workspace", "research", "EverOS");
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" ? path36.join(venvDir, "Scripts", "pip.exe") : path36.join(venvDir, "bin", "pip");
31725
- const everosReq = path36.join(this.getPythonDir(), "requirements.txt");
31726
- if (fs36.existsSync(everosReq)) {
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 candidates = [
31742
- path36.join(dir, "python"),
31743
- path36.resolve(dir, "..", "src", "memory", "everos", "python"),
31744
- path36.resolve(dir, "..", "..", "..", "src", "memory", "everos", "python")
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 candidates) {
31747
- if (fs36.existsSync(path36.join(candidate, "agentic_server.py"))) {
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 candidates[0];
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 = path36.dirname(path36.dirname(venvPython));
31757
- const sitePackages = path36.join(venvDir, "Lib", "site-packages");
31758
- const target = path36.join(sitePackages, "fcntl.py");
31759
- if (fs36.existsSync(target)) return;
31760
- const source = path36.join(this.getPythonDir(), "fcntl_compat.py");
31761
- if (fs36.existsSync(source)) {
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
- fs36.copyFileSync(source, target);
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 fs37 from "node:fs";
32373
- import * as path37 from "node:path";
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 = fs37.readFileSync(decodeURIComponent(att.url.slice(7)));
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 = path37.join(config.mediaDir, `${imageId}.${ext}`);
33273
- fs37.writeFileSync(savedPath, resized.buffer);
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 = path37.join(config.mediaDir, sessionId);
33304
- fs37.mkdirSync(outDir, { recursive: true });
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 = path37.basename(att.filename).replace(/[<>:"/\\|?*\x00-\x1f]/g, "_") || "attachment";
33313
- const savedPath = path37.join(outDir, safeName2);
33314
- fs37.writeFileSync(savedPath, buffer);
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 readInstallIdentity(stateDir) {
33572
- try {
33573
- const parsed = JSON.parse(readFileSync34(join46(stateDir, IDENTITY_FILE), "utf8"));
33574
- if (typeof parsed?.installId !== "string" || typeof parsed?.installSecret !== "string") return null;
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 maybeIdentity = readInstallIdentity(stateDir);
33760
- if (!maybeIdentity) {
33761
- log("[reporting] \u6CA1\u6709\u53EF\u7528\u7684\u88C5\u673A\u8EAB\u4EFD\uFF0C\u4E0A\u62A5\u5173\u95ED");
33762
- return { stop() {
33763
- }, async beatNow() {
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 fs59 = await import("node:fs");
33991
- const path61 = await import("node:path");
33992
- if (!fs59.existsSync(attachment.path)) {
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 || path61.basename(attachment.path);
33996
- const fileBuffer = fs59.readFileSync(attachment.path);
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 fs59 = await import("node:fs");
34446
- const path61 = await import("node:path");
34447
- if (!fs59.existsSync(attachment.path)) {
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 || path61.basename(attachment.path);
34451
- const fileBuffer = fs59.readFileSync(attachment.path);
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 fs38 from "fs";
35049
- import * as path38 from "path";
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 = path38.extname(filename).toLowerCase();
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 = path38.join(stateDir, "weixin", `${accountId}.context-tokens.json`);
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 (fs38.existsSync(this.filePath)) {
35348
- for (const [k, v] of Object.entries(JSON.parse(fs38.readFileSync(this.filePath, "utf-8"))))
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 = path38.dirname(this.filePath);
35357
- if (!fs38.existsSync(dir)) fs38.mkdirSync(dir, { recursive: true });
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
- fs38.writeFileSync(this.filePath, JSON.stringify(obj));
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 = path38.join(stateDir, "weixin", `${accountId}.sync.json`);
35381
- if (fs38.existsSync(fp)) return String(JSON.parse(fs38.readFileSync(fp, "utf-8")).sync_buf || "");
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 = path38.join(stateDir, "weixin", `${accountId}.sync.json`);
35389
- const dir = path38.dirname(fp);
35390
- if (!fs38.existsSync(dir)) fs38.mkdirSync(dir, { recursive: true });
35391
- fs38.writeFileSync(fp, JSON.stringify({ sync_buf: buf }));
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 || path38.join(os4.homedir?.() || "/tmp", ".engine7");
35434
- if (!fs38.existsSync(this.stateDir)) fs38.mkdirSync(this.stateDir, { recursive: true });
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 (!fs38.existsSync(filePath)) throw new Error(`File not found: ${filePath}`);
35488
- const plaintext = fs38.readFileSync(filePath);
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: path38.basename(filePath),
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 = path38.join(os4.tmpdir(), "weixin-media");
35780
- if (!fs38.existsSync(tmpDir)) fs38.mkdirSync(tmpDir, { recursive: true });
35781
- const tmpPath = path38.join(tmpDir, `${crypto5.randomUUID().replace(/-/g, "")}-${filename}`);
35782
- fs38.writeFileSync(tmpPath, data);
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 = path38.extname(filePath).toLowerCase();
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 fs40 from "node:fs";
35879
- import * as path40 from "node:path";
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 = path40.join(os5.tmpdir(), "engine-voice");
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 candidates = [
36007
+ const candidates2 = [
35933
36008
  "python3",
35934
36009
  "python",
35935
36010
  // LOCALAPPDATA 缺席(非 Windows / 精简环境)时**不加这两个候选**:
35936
36011
  // 拼出来会是相对路径 'Microsoft/WindowsApps/python.exe',那可能撞上 cwd 里的东西。
35937
36012
  ...localAppData ? [
35938
- path40.join(localAppData, "Microsoft", "WindowsApps", "python3.exe"),
35939
- path40.join(localAppData, "Microsoft", "WindowsApps", "python.exe")
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 candidates) {
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
- fs40.mkdirSync(VOICE_DIR, { recursive: true });
35960
- const output = path40.join(VOICE_DIR, `tts_${Date.now()}.wav`);
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
- fs40.writeFileSync(output, Buffer.concat([header, pcm]));
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
- fs40.mkdirSync(VOICE_DIR, { recursive: true });
36156
- const oggPath = path40.join(VOICE_DIR, `tts_${Date.now()}.ogg`);
36157
- fs40.writeFileSync(oggPath, ogg);
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
- fs40.mkdirSync(VOICE_DIR, { recursive: true });
36170
- const output = path40.join(VOICE_DIR, `tts_${Date.now()}.wav`);
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
- fs40.writeFileSync(output, buf);
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
- fs40.mkdirSync(VOICE_DIR, { recursive: true });
36187
- const output = path40.join(VOICE_DIR, `tts_${Date.now()}.mp3`);
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
- fs40.mkdirSync(VOICE_DIR, { recursive: true });
36233
- const wavPath = path40.join(VOICE_DIR, `tts_${Date.now()}.wav`);
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
- fs40.writeFileSync(wavPath, Buffer.concat([header, pcm]));
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 fs60 = __require("fs");
36274
- const path61 = __require("path");
36275
- const dir = path61.join(os7.homedir(), "xiaowen", "workspace", ".desktopBuddy");
36276
- fs60.mkdirSync(dir, { recursive: true });
36277
- this.historyFile = path61.join(dir, "history.json");
36278
- this._fs = fs60;
36279
- }
36280
- const fs59 = this._fs;
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(fs59.readFileSync(this.historyFile, "utf-8")) || [];
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
- fs59.writeFileSync(this.historyFile, JSON.stringify(arr, null, 1));
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 fs41 from "node:fs";
36570
- import path41 from "node:path";
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 path41.join(sd, "state", "cc-bridge", "outbox.jsonl");
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 = fs41.readFileSync(this.outboxFile(), "utf8");
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
- fs41.mkdirSync(path41.dirname(file2), { recursive: true });
36646
- fs41.writeFileSync(tmp, items.map((i) => JSON.stringify(i)).join("\n") + (items.length ? "\n" : ""), "utf8");
36647
- fs41.renameSync(tmp, file2);
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
- fs41.mkdirSync(path41.dirname(this.outboxFile()), { recursive: true });
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 = fs41.statSync(attachment.path);
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 || path41.basename(attachment.path),
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 path43 from "node:path";
37262
- import * as fs43 from "node:fs";
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 fs42 from "node:fs";
37268
- import * as path42 from "node:path";
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 = fs42.createReadStream(filePath, { encoding: "utf-8" });
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 = fs42.statSync(filePath);
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 = fs42.openSync(filePath, "r");
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 = fs42.readSync(fd, chunk, 0, Math.min(CHUNK_SIZE, fileSize - filePos), filePos);
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
- fs42.closeSync(fd);
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 = fs42.statSync(filePath);
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 = fs42.createReadStream(filePath, { encoding: "utf-8" });
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 (!fs42.existsSync(sessionsDir)) return [];
37689
- const files = fs42.readdirSync(sessionsDir).filter((f) => f.endsWith(".jsonl") || f.includes(".jsonl.")).map((f) => ({
37690
- file: path42.join(sessionsDir, f),
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(fs42.statSync(path42.join(sessionsDir, f)).mtimeMs)
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 = path43.join(config.stateDir, "agents", "main", "sessions");
37729
- this.indexPath = path43.join(this.sessionsDir, "session-index.json");
37730
- this.platformMapPath = path43.join(this.sessionsDir, "platform-map.json");
37731
- fs43.mkdirSync(this.sessionsDir, { recursive: true });
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 (fs43.existsSync(this.indexPath)) {
37737
- const raw = fs43.readFileSync(this.indexPath, "utf-8");
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 (fs43.existsSync(entry.file)) continue;
37743
- const basename10 = path43.basename(entry.file);
37744
- const localPath = path43.join(this.sessionsDir, basename10);
37745
- if (fs43.existsSync(localPath)) {
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
- fs43.writeFileSync(this.indexPath, JSON.stringify(obj, null, 2));
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 (fs43.existsSync(this.platformMapPath)) {
37773
- const raw = fs43.readFileSync(this.platformMapPath, "utf-8");
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
- fs43.writeFileSync(this.platformMapPath, JSON.stringify(obj, null, 2));
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 && fs43.existsSync(entry.file)) return entry.file;
37825
- const direct = path43.join(this.sessionsDir, `${sessionId}.jsonl`);
37826
- return fs43.existsSync(direct) ? direct : null;
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 && fs43.existsSync(existing.file)) {
37834
- const existingFileId = path43.basename(existing.file, ".jsonl");
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 ${path43.basename(writer.path)}`);
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 = fs43.statSync(writer.path);
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 = fs43.statSync(writer.path).size;
37949
+ const newSize = fs42.statSync(writer.path).size;
37875
37950
  const oldSizeMB = (stat4.size / 1024 / 1024).toFixed(1);
37876
- console.log(`[session] Archive complete: ${path43.basename(archivedPath)} (${oldSizeMB}MB) \u2192 new JSONL created (${newSize} bytes)`);
37877
- const fileId = path43.basename(writer.path).replace(/\.jsonl$/, "");
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 (!fs43.existsSync(dir)) return;
37894
- const allFiles = fs43.readdirSync(dir);
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: path43.join(dir, f),
37901
- mtime: fs43.statSync(path43.join(dir, f)).mtimeMs
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
- fs43.unlinkSync(f.path);
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 = path43.join(this.sessionsDir, `${sessionId}.jsonl`);
37961
- if (fs43.existsSync(mainFile)) {
38035
+ const mainFile = path42.join(this.sessionsDir, `${sessionId}.jsonl`);
38036
+ if (fs42.existsSync(mainFile)) {
37962
38037
  results.push(mainFile);
37963
38038
  }
37964
- if (fs43.existsSync(this.sessionsDir)) {
37965
- const compactionFiles = fs43.readdirSync(this.sessionsDir).filter((f) => f.startsWith(`${sessionId}.jsonl.compaction.`)).map((f) => ({
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: path43.join(this.sessionsDir, f),
37968
- mtime: fs43.statSync(path43.join(this.sessionsDir, f)).mtimeMs
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 = fs43.statSync(a).mtimeMs;
37976
- const tb = fs43.statSync(b).mtimeMs;
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 (!fs43.existsSync(this.sessionsDir)) {
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 && fs43.existsSync(indexedEntry.file)) {
37995
- const fileUuid = path43.basename(indexedEntry.file, ".jsonl");
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 = path43.basename(f);
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=${fs43.existsSync(indexed.file)})`);
38011
- if (fs43.existsSync(indexed.file)) {
38012
- return this.findAllSessionFiles(path43.basename(indexed.file, ".jsonl"));
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 = fs43.statSync(a).mtimeMs;
38042
- const tb = fs43.statSync(b).mtimeMs;
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 ${path43.basename(latestFile)}`);
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(path43.resolve(mem.path));
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 || !fs43.existsSync(entry.file)) return;
38122
- const oldFileId = path43.basename(entry.file, ".jsonl");
38123
- const stat4 = fs43.statSync(entry.file);
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
- fs43.renameSync(entry.file, archivedPath);
38202
+ fs42.renameSync(entry.file, archivedPath);
38128
38203
  const sizeMB = (stat4.size / 1024 / 1024).toFixed(1);
38129
- console.log(`[session] Archived: ${path43.basename(entry.file)} \u2192 ${path43.basename(archivedPath)} (${sizeMB}MB)`);
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 ${path43.basename(newPath)}`);
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 fs44 from "node:fs";
39031
- import path44 from "node:path";
39105
+ import fs43 from "node:fs";
39106
+ import path43 from "node:path";
39032
39107
  function getHusbandFeishuId(workspace) {
39033
- const contactsPath = path44.join(workspace, "prompts", "contacts.md");
39108
+ const contactsPath = path43.join(workspace, "prompts", "contacts.md");
39034
39109
  try {
39035
- const text = fs44.readFileSync(contactsPath, "utf-8");
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 fs59 = await import("node:fs");
39178
- if (!fs59.existsSync(filePath)) {
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 = fs59.statSync(filePath);
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 fs45 from "node:fs";
39237
- import * as path45 from "node:path";
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 && fs45.existsSync(specifiedPath)) return specifiedPath;
39250
- if (!fs45.existsSync(mediaDir)) return null;
39251
- const files = fs45.readdirSync(mediaDir).filter((f) => /\.(jpg|jpeg|png|webp|gif|bmp|mp4|mov)$/i.test(f)).map((f) => ({ name: f, p: path45.join(mediaDir, f), mtime: fs45.statSync(path45.join(mediaDir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
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 = path45.join(ctx.stateDir, "media", "inbound");
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 = path45.extname(imagePath).toLowerCase();
39363
+ const ext = path44.extname(imagePath).toLowerCase();
39289
39364
  if (VIDEO_EXT.test(imagePath)) {
39290
- const stat4 = fs45.statSync(imagePath);
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 = fs45.readFileSync(imagePath).toString("base64");
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 = fs45.readFileSync(imagePath).toString("base64");
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 fs46 from "node:fs";
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(fs46.readFileSync(wavPath));
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
- fs46.writeFileSync(oggPath, ogg.finish());
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 fs47 from "node:fs";
39661
+ import * as fs46 from "node:fs";
39587
39662
  import * as os6 from "node:os";
39588
- import * as path46 from "node:path";
39589
- var VOICE_DIR2 = path46.join(os6.tmpdir(), "engine-voice");
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
- fs47.mkdirSync(VOICE_DIR2, { recursive: true });
39609
- const out = path46.join(VOICE_DIR2, `tts_relay_${Date.now()}.mp3`);
39610
- fs47.writeFileSync(out, buf);
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 fs48 from "node:fs";
39730
- import * as path47 from "node:path";
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 (!fs48.existsSync(wavPath) || fs48.statSync(wavPath).size < 44) {
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
- fs48.unlinkSync(audioPath);
39827
+ fs47.unlinkSync(audioPath);
39753
39828
  } catch {
39754
39829
  }
39755
39830
  }
39756
- const durationSec = wavDurationSec(fs48.readFileSync(wavPath));
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
- fs48.unlinkSync(wavPath);
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 (!fs48.existsSync(oggPath) || fs48.statSync(oggPath).size < 20) {
39876
+ if (!fs47.existsSync(oggPath) || fs47.statSync(oggPath).size < 20) {
39802
39877
  throw new Error("ogg/opus encode produced empty output");
39803
39878
  }
39804
- fs48.unlinkSync(wavPath);
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 || !fs48.existsSync(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 = path47.extname(audioPath).toLowerCase();
39830
- const sizeKB = fs48.statSync(audioPath).size / 1024;
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 = path47.join(process.cwd(), voiceFile);
39907
+ const cwdCopy = path46.join(process.cwd(), voiceFile);
39833
39908
  try {
39834
- fs48.copyFileSync(audioPath, cwdCopy);
39909
+ fs47.copyFileSync(audioPath, cwdCopy);
39835
39910
  } catch (e) {
39836
39911
  try {
39837
- fs48.unlinkSync(audioPath);
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
- fs48.unlinkSync(audioPath);
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
- fs48.unlinkSync(cwdCopy);
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
- fs48.unlinkSync(cwdCopy);
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 = path47.extname(audioPath).toLowerCase();
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 = fs48.statSync(audioPath).size / 1024;
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
- fs48.unlinkSync(audioPath);
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 fs49 from "node:fs";
40026
- import * as path48 from "node:path";
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 = fs49.readFileSync(p);
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 path61 = cfg?.tools?.my_selfie ? "tools.my_selfie.references" : "my_selfie.references";
40164
- void liveConfig.set(path61, next);
40165
- console.log(`[my-selfie] \u5F62\u8C61\u5DF2\u767B\u8BB0\uFF1A${path61}[0] = ${relPath}`);
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 = path48.join(ctx.workspace, refEntry.p);
40521
+ let refPath = path47.join(ctx.workspace, refEntry.p);
40447
40522
  const adoptImg = args.referenceImage?.trim();
40448
40523
  if (adoptImg) {
40449
- if (!fs49.existsSync(adoptImg)) {
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 = path48.join(ctx.workspace, "images");
40461
- if (!fs49.existsSync(adir)) fs49.mkdirSync(adir, { recursive: true });
40462
- const aext = (path48.extname(adoptImg) || ".png").toLowerCase();
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
- fs49.copyFileSync(adoptImg, path48.join(adir, afname));
40539
+ fs48.copyFileSync(adoptImg, path47.join(adir, afname));
40465
40540
  registerPortrait(`images/${afname}`, refName);
40466
- refPath = path48.join(adir, afname);
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" && !fs49.existsSync(refPath)) {
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 = path48.join(ctx.workspace, "images");
40495
- if (!fs49.existsSync(pdir)) fs49.mkdirSync(pdir, { recursive: true });
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
- fs49.writeFileSync(path48.join(pdir, pfname), portraitBuf);
40572
+ fs48.writeFileSync(path47.join(pdir, pfname), portraitBuf);
40498
40573
  registerPortrait(`images/${pfname}`, refName);
40499
- refPath = path48.join(pdir, pfname);
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 = fs49.existsSync(refPath) ? fs49.readFileSync(refPath).toString("base64") : "";
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 = path48.extname(refPath).toLowerCase();
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 = path48.join(ctx.workspace, "images");
40529
- if (!fs49.existsSync(imagesDir)) fs49.mkdirSync(imagesDir, { recursive: true });
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 = path48.join(imagesDir, filename);
40532
- fs49.writeFileSync(outputPath, imageBuffer);
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: ${path48.resolve(outputPath)}`, isError: false };
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: ${path48.resolve(outputPath)}` };
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 fs50 from "node:fs";
41100
- import * as path49 from "node:path";
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 = path49.join(stateDir, "logs");
41110
- if (!fs50.existsSync(logDir)) fs50.mkdirSync(logDir, { recursive: true });
41111
- return path49.join(logDir, fileName);
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 fs51 from "node:fs";
41431
- import * as path50 from "node:path";
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 = path50.join(stateDir, "plans");
41439
- fs51.mkdirSync(plansDir, { recursive: true });
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 = path50.join(plansDir, `${slug}.md`);
41450
- if (!fs51.existsSync(filePath)) {
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 path50.join(getPlansDirectory(stateDir), `${slug}.md`);
41536
+ return path49.join(getPlansDirectory(stateDir), `${slug}.md`);
41462
41537
  }
41463
- return path50.join(getPlansDirectory(stateDir), `${slug}-agent-${agentId}.md`);
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 fs51.readFileSync(filePath, "utf-8");
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
- fs51.writeFileSync(filePath, content, "utf-8");
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 fs56 from "node:fs";
42294
- import * as path56 from "node:path";
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 = path56.join(deps.config.workspace, ".work-mode");
42382
+ const modeFile = path55.join(deps.config.workspace, ".work-mode");
42308
42383
  if (mode === "on" || mode === "off") {
42309
- fs56.writeFileSync(modeFile, mode, "utf8");
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
- fs56.unlinkSync(modeFile);
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 = fs56.readFileSync(modeFile, "utf8").trim() || "auto";
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 fs57 from "node:fs";
42791
- import * as path57 from "node:path";
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 && !fs57.existsSync(configPath)) {
42898
+ if (configPath && !fs56.existsSync(configPath)) {
42824
42899
  const __pFile = fileURLToPath8(import.meta.url);
42825
- const __pDir = path57.dirname(__pFile);
42826
- const altPath = path57.join(path57.resolve(__pDir, "../configs"), path57.basename(configPath));
42827
- if (fs57.existsSync(altPath)) {
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 candidates = matchModels(input, aliases, available);
42887
- if (candidates.length === 0) {
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 (candidates.length > 1) {
42892
- const lines = candidates.slice(0, 10).map((a) => `- \`${a.ref}\` \u2014 ${a.name}`);
42893
- const more = candidates.length > 10 ? `
42894
- ... and ${candidates.length - 10} more` : "";
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 ${candidates[0].ref}\``);
42973
+ Use full ref like \`/model ${candidates2[0].ref}\``);
42899
42974
  return;
42900
42975
  }
42901
- const target = candidates[0].ref;
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} (${candidates[0].name})`);
42940
- await ctx.reply(`Switched to **${target}** (${candidates[0].name})
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 candidates = matchModels(input, aliases, available);
42964
- if (candidates.length === 0) {
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 (candidates.length > 1) {
42969
- const lines = candidates.slice(0, 10).map((a) => `- \`${a.ref}\` \u2014 ${a.name}`);
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 ${candidates[0].ref}\``);
43048
+ Use full ref like \`/primary ${candidates2[0].ref}\``);
42974
43049
  return;
42975
43050
  }
42976
- const target = candidates[0].ref;
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 fs57.promises.readFile(writePath, "utf-8");
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 fs57.promises.writeFile(writePath, JSON.stringify(cfg, null, 2), "utf-8");
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}** (${candidates[0].name})
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 candidates = matchModels(input, aliases, available);
43018
- if (candidates.length === 0) {
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 (candidates.length > 1) {
43023
- const lines = candidates.slice(0, 10).map((a) => `- \`${a.ref}\` \u2014 ${a.name}`);
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 ${candidates[0].ref}\``);
43102
+ Use full ref like \`/vision-primary ${candidates2[0].ref}\``);
43028
43103
  return;
43029
43104
  }
43030
- const target = candidates[0].ref;
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 fs57.promises.readFile(writePath, "utf-8");
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 fs57.promises.writeFile(writePath, JSON.stringify(cfg, null, 2), "utf-8");
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 fs57.promises.writeFile(writePath, JSON.stringify(cfg, null, 2), "utf-8");
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}** (${candidates[0].name})
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 candidates = matchModels(input, aliases, available);
43084
- if (candidates.length === 0) {
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 (candidates.length > 1) {
43089
- const lines = candidates.slice(0, 10).map((a) => `- \`${a.ref}\` \u2014 ${a.name}`);
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 ${candidates[0].ref}\``);
43168
+ Use full ref like \`/vision-model ${candidates2[0].ref}\``);
43094
43169
  return;
43095
43170
  }
43096
- const target = candidates[0].ref;
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}** (${candidates[0].name}) (immediate)
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: path60.join(config.stateDir, "session-memory"),
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({