engine7 7.1.113 → 7.1.114

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