engine7 7.1.94 → 7.1.96

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.
@@ -8077,26 +8077,26 @@ async function writeToMailbox(recipientName, message, teamName) {
8077
8077
  await writeFile2(inboxPath, "[]", { encoding: "utf-8", flag: "wx" });
8078
8078
  } catch {
8079
8079
  }
8080
- const release2 = await acquireLock(inboxPath);
8080
+ const release3 = await acquireLock(inboxPath);
8081
8081
  try {
8082
8082
  const messages = await readMailbox(recipientName, teamName);
8083
8083
  messages.push({ ...message, read: false });
8084
8084
  await writeFile2(inboxPath, JSON.stringify(messages, null, 2), "utf-8");
8085
8085
  console.log(`[mailbox] Wrote message to ${recipientName} from ${message.from} (team=${teamName || "default"}, inbox=${inboxPath})`);
8086
8086
  } finally {
8087
- await release2();
8087
+ await release3();
8088
8088
  }
8089
8089
  }
8090
8090
  async function markMessagesAsRead(agentName, teamName) {
8091
8091
  const inboxPath = getInboxPath(agentName, teamName);
8092
- const release2 = await acquireLock(inboxPath);
8092
+ const release3 = await acquireLock(inboxPath);
8093
8093
  try {
8094
8094
  const messages = await readMailbox(agentName, teamName);
8095
8095
  if (messages.length === 0) return;
8096
8096
  for (const m of messages) m.read = true;
8097
8097
  await writeFile2(inboxPath, JSON.stringify(messages, null, 2), "utf-8");
8098
8098
  } finally {
8099
- await release2();
8099
+ await release3();
8100
8100
  }
8101
8101
  }
8102
8102
  async function clearMailbox(agentName, teamName) {
@@ -9927,7 +9927,7 @@ CREATE TABLE IF NOT EXISTS watermarks (
9927
9927
  }
9928
9928
  // ── md 读(proactive 消费):开窗预测(全 owner 扫描,end>=今天)──
9929
9929
  getOpenPredictions(now, limit = 50) {
9930
- const today = todayKey(now);
9930
+ const today2 = todayKey(now);
9931
9931
  const out = [];
9932
9932
  const usersDir = join22(this.root, "users");
9933
9933
  if (!existsSync12(usersDir)) return out;
@@ -9950,7 +9950,7 @@ CREATE TABLE IF NOT EXISTS watermarks (
9950
9950
  const text = ((block.match(/### Foresight\s*\n+([\s\S]*?)(?:\n### Evidence|$)/) ?? [])[1] ?? "").trim();
9951
9951
  const evidence = ((block.match(/### Evidence\s*\n+([\s\S]*?)$/) ?? [])[1] ?? "").trim();
9952
9952
  if (!end || !start || !text) continue;
9953
- if (end < today) continue;
9953
+ if (end < today2) continue;
9954
9954
  out.push({ ownerId: owner.name, startDate: start, endDate: end, content: text.replace(/\n+/g, " ").slice(0, 200), evidence: evidence.replace(/\n+/g, " ").slice(0, 120) });
9955
9955
  if (out.length >= limit) return out;
9956
9956
  }
@@ -13491,7 +13491,7 @@ function loadForesightEntries(everosRoot, now, userId, ownerFilter) {
13491
13491
  return entries2.slice();
13492
13492
  }
13493
13493
  function parseForesightEntries(everosRoot, now, userId) {
13494
- const today = todayKey(now);
13494
+ const today2 = todayKey(now);
13495
13495
  let files;
13496
13496
  if (userId) {
13497
13497
  const ownDir = join29(everosRoot, userId, "default_project", "users", userId, ".foresights");
@@ -13516,7 +13516,7 @@ function parseForesightEntries(everosRoot, now, userId) {
13516
13516
  const end = (block.match(/\*\*end_time\*\*:\s*(\d{4}-\d{2}-\d{2})/) ?? [])[1];
13517
13517
  const text = ((block.match(/### Foresight\s*\n+([\s\S]*?)(?:\n### Evidence|$)/) ?? [])[1] ?? "").trim();
13518
13518
  if (!start || !end || !text) continue;
13519
- if (end < today) continue;
13519
+ if (end < today2) continue;
13520
13520
  const evidence = ((block.match(/### Evidence\s*\n+([\s\S]*?)$/) ?? [])[1] ?? "").trim();
13521
13521
  const blockOwner = (block.match(/\*\*owner_id\*\*:\s*(\S+)/) ?? [])[1] ?? fileOwner;
13522
13522
  const key = text.replace(/\s+/g, "");
@@ -21454,7 +21454,7 @@ function isPermittedRedirect(original, redirect) {
21454
21454
  async function fetchWithRedirects(url, signal, depth = 0) {
21455
21455
  if (depth > MAX_REDIRECTS) throw new Error(`\u91CD\u5B9A\u5411\u6B21\u6570\u8FC7\u591A (>${MAX_REDIRECTS})`);
21456
21456
  const controller = new AbortController();
21457
- const timeoutId = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
21457
+ const timeoutId = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS2);
21458
21458
  const onSignalAbort = () => controller.abort();
21459
21459
  signal.addEventListener("abort", onSignalAbort, { once: true });
21460
21460
  try {
@@ -21497,14 +21497,14 @@ function getTurndown() {
21497
21497
  }
21498
21498
  return td;
21499
21499
  }
21500
- var MAX_URL_LENGTH, MAX_CONTENT_LENGTH, FETCH_TIMEOUT_MS, MAX_REDIRECTS, td;
21500
+ var MAX_URL_LENGTH, MAX_CONTENT_LENGTH, FETCH_TIMEOUT_MS2, MAX_REDIRECTS, td;
21501
21501
  var init_web_fetch = __esm({
21502
21502
  "src/tools/web-fetch.ts"() {
21503
21503
  "use strict";
21504
21504
  init_registry();
21505
21505
  MAX_URL_LENGTH = 2e3;
21506
21506
  MAX_CONTENT_LENGTH = 10 * 1024 * 1024;
21507
- FETCH_TIMEOUT_MS = 6e4;
21507
+ FETCH_TIMEOUT_MS2 = 6e4;
21508
21508
  MAX_REDIRECTS = 10;
21509
21509
  registry.register({
21510
21510
  name: "web_fetch",
@@ -21575,7 +21575,7 @@ var init_web_fetch = __esm({
21575
21575
 
21576
21576
  // src/tools/wechat/wx-query.ts
21577
21577
  var wx_query_exports = {};
21578
- import { join as join54 } from "node:path";
21578
+ import { join as join56 } from "node:path";
21579
21579
  function getDescription() {
21580
21580
  return `\u67E5\u8BE2\u7FC0\u54E5\u7684\u5FAE\u4FE1\u6D88\u606F\uFF08\u7F13\u5B58\u89E3\u5BC6\u540E\u7684\u672C\u5730\u6570\u636E\u5E93\uFF09\u3002
21581
21581
 
@@ -21610,8 +21610,8 @@ var init_wx_query = __esm({
21610
21610
  "use strict";
21611
21611
  init_registry();
21612
21612
  init_live();
21613
- STATE_DIR = process.env.ENGINE7_STATE_DIR || join54(process.env.HOME || process.env.USERPROFILE || ".", ".engine7");
21614
- SCRIPT = join54("/Users/chongzhang/work/twinsun-hearth/engine", "src", "tools", "wechat", "wx_query.py");
21613
+ STATE_DIR = process.env.ENGINE7_STATE_DIR || join56(process.env.HOME || process.env.USERPROFILE || ".", ".engine7");
21614
+ SCRIPT = join56("/Users/chongzhang/work/twinsun-hearth/engine", "src", "tools", "wechat", "wx_query.py");
21615
21615
  PYTHON = "python3";
21616
21616
  registry.register({
21617
21617
  name: "wx_query",
@@ -22532,8 +22532,8 @@ async function doReloadConfigInner(config, deps, provider, force = false) {
22532
22532
  const savedConfigPath = config._configFilePath;
22533
22533
  let reloadConfigPath = savedConfigPath;
22534
22534
  if (!fs10.existsSync(reloadConfigPath)) {
22535
- const __filename = fileURLToPath(import.meta.url);
22536
- const __dirname = path10.dirname(__filename);
22535
+ const __filename2 = fileURLToPath(import.meta.url);
22536
+ const __dirname = path10.dirname(__filename2);
22537
22537
  const engineConfigsDir = path10.resolve(__dirname, "../configs");
22538
22538
  const altPath = path10.join(engineConfigsDir, path10.basename(savedConfigPath));
22539
22539
  if (fs10.existsSync(altPath)) {
@@ -22847,20 +22847,20 @@ function acquireEngineLock(stateDir) {
22847
22847
  } catch (err) {
22848
22848
  console.warn(`[pid-lock] write lock failed: ${err.message}`);
22849
22849
  }
22850
- const release2 = () => {
22850
+ const release3 = () => {
22851
22851
  try {
22852
22852
  const cur = fs11.existsSync(lockFile) ? fs11.readFileSync(lockFile, "utf-8").trim() : "";
22853
22853
  if (cur === String(myPid)) fs11.unlinkSync(lockFile);
22854
22854
  } catch {
22855
22855
  }
22856
22856
  };
22857
- process.on("exit", release2);
22857
+ process.on("exit", release3);
22858
22858
  process.on("SIGINT", () => {
22859
- release2();
22859
+ release3();
22860
22860
  process.exit(0);
22861
22861
  });
22862
22862
  process.on("SIGTERM", () => {
22863
- release2();
22863
+ release3();
22864
22864
  process.exit(0);
22865
22865
  });
22866
22866
  }
@@ -24614,7 +24614,8 @@ function buildLightHistory(history, opts) {
24614
24614
  function buildLightStablePrompt(workspace, mode, opts) {
24615
24615
  const lp = liveConfig.get(`channels.${mode}.liveSystemPrompt`);
24616
24616
  const parts = [];
24617
- for (const f of lp?.files ?? ["SOUL.md"]) {
24617
+ const files = lp?.files ?? (mode === "emotion" ? ["SOUL.md", "EMOTION.md"] : ["SOUL.md"]);
24618
+ for (const f of files) {
24618
24619
  try {
24619
24620
  parts.push(readFileSync11(join18(workspace, f), "utf-8").trim());
24620
24621
  } catch {
@@ -24637,7 +24638,7 @@ function buildLightStablePrompt(workspace, mode, opts) {
24637
24638
  ].join("\n"));
24638
24639
  }
24639
24640
  const built = parts.join("\n\n");
24640
- console.log(`[light-stable] mode=${mode} files=[${(lp?.files ?? ["SOUL.md"]).join(",")}] ~${Math.round(built.length / 3)} tokens`);
24641
+ console.log(`[light-stable] mode=${mode} files=[${files.join(",")}] ~${Math.round(built.length / 3)} tokens`);
24641
24642
  return built;
24642
24643
  }
24643
24644
 
@@ -28389,10 +28390,10 @@ var US_HALF_LIFE_DAYS = 10;
28389
28390
  var US_MAX_LINES = 60;
28390
28391
  function readRecentMemory(workspace) {
28391
28392
  const dir = path30.join(workspace, "memory");
28392
- const today = dailyFileKeyFor();
28393
+ const today2 = dailyFileKeyFor();
28393
28394
  const yesterday = dailyFileKeyFor(Date.now() - 864e5);
28394
28395
  return {
28395
- today: readIfExists(path30.join(dir, `${today}.md`)),
28396
+ today: readIfExists(path30.join(dir, `${today2}.md`)),
28396
28397
  yesterday: readIfExists(path30.join(dir, `${yesterday}.md`))
28397
28398
  };
28398
28399
  }
@@ -32329,6 +32330,200 @@ ${pathStr}` }];
32329
32330
  channelManager.startAll();
32330
32331
  }
32331
32332
 
32333
+ // src/optional/reporting/reporter.ts
32334
+ init_live();
32335
+
32336
+ // src/provision-free.ts
32337
+ import { chmodSync, existsSync as existsSync21, mkdirSync as mkdirSync13, readFileSync as readFileSync33, writeFileSync as writeFileSync11 } from "node:fs";
32338
+ import { dirname as dirname9, join as join44 } from "node:path";
32339
+ import { fileURLToPath as fileURLToPath7 } from "node:url";
32340
+ var __filename = fileURLToPath7(import.meta.url);
32341
+ var IDENTITY_FILE = "install-identity.json";
32342
+ function readContactEmailOf(parsed) {
32343
+ return typeof parsed?.contactEmail === "string" ? parsed.contactEmail.trim() : "";
32344
+ }
32345
+ function readInstallIdentity(stateDir) {
32346
+ try {
32347
+ const parsed = JSON.parse(readFileSync33(join44(stateDir, IDENTITY_FILE), "utf8"));
32348
+ if (typeof parsed?.installId !== "string" || typeof parsed?.installSecret !== "string") return null;
32349
+ const email = readContactEmailOf(parsed);
32350
+ return {
32351
+ installId: parsed.installId,
32352
+ installSecret: parsed.installSecret,
32353
+ ...email ? { contactEmail: email } : {}
32354
+ };
32355
+ } catch {
32356
+ return null;
32357
+ }
32358
+ }
32359
+
32360
+ // src/optional/reporting/state.ts
32361
+ import { existsSync as existsSync22, mkdirSync as mkdirSync14, readFileSync as readFileSync34, writeFileSync as writeFileSync12 } from "node:fs";
32362
+ import { join as join45 } from "node:path";
32363
+ var STATE_FILE2 = "report-state.json";
32364
+ function readReportState(stateDir) {
32365
+ try {
32366
+ const p = join45(stateDir, STATE_FILE2);
32367
+ if (!existsSync22(p)) return {};
32368
+ const parsed = JSON.parse(readFileSync34(p, "utf8"));
32369
+ if (!parsed || typeof parsed !== "object") return {};
32370
+ return parsed;
32371
+ } catch {
32372
+ return {};
32373
+ }
32374
+ }
32375
+ function writeReportState(stateDir, s) {
32376
+ try {
32377
+ mkdirSync14(stateDir, { recursive: true });
32378
+ writeFileSync12(join45(stateDir, STATE_FILE2), JSON.stringify(s, null, 2) + "\n");
32379
+ } catch {
32380
+ }
32381
+ }
32382
+
32383
+ // src/optional/reporting/payload.ts
32384
+ import { createHash as createHash2 } from "node:crypto";
32385
+ import * as os3 from "node:os";
32386
+ function installKeyOf(installId, installSecret) {
32387
+ return createHash2("sha256").update(installId + installSecret).digest("hex").slice(0, 32);
32388
+ }
32389
+ function buildReportPayload(opts) {
32390
+ const p = {
32391
+ installId: opts.identity.installId,
32392
+ installKey: installKeyOf(opts.identity.installId, opts.identity.installSecret),
32393
+ engineVersion: opts.engineVersion,
32394
+ platform: process.platform,
32395
+ osVersion: typeof os3.release === "function" ? os3.release() : "",
32396
+ arch: process.arch,
32397
+ stateDir: opts.stateDir,
32398
+ startedAt: opts.startedAt,
32399
+ // 时钟回拨时别报个负数上去
32400
+ uptimeSec: Math.max(0, Math.floor((opts.now - opts.startedAt) / 1e3)),
32401
+ msgsToday: opts.counters.msgsToday,
32402
+ msgsTotal: opts.counters.msgsTotal
32403
+ };
32404
+ if (opts.identity.contactEmail) p.contactEmail = opts.identity.contactEmail;
32405
+ return p;
32406
+ }
32407
+
32408
+ // src/core/activity-counter.ts
32409
+ init_clock();
32410
+ var USER_SOURCES = /* @__PURE__ */ new Set(["user", "inbox"]);
32411
+ var nowFn = () => /* @__PURE__ */ new Date();
32412
+ var today = "";
32413
+ var msgsToday = 0;
32414
+ var msgsTotal = 0;
32415
+ function rolloverIfNeeded(now) {
32416
+ const d = todayKey(now);
32417
+ if (d !== today) {
32418
+ today = d;
32419
+ msgsToday = 0;
32420
+ }
32421
+ }
32422
+ function noteUserMessage(source) {
32423
+ if (!source || !USER_SOURCES.has(source)) return;
32424
+ const now = nowFn();
32425
+ rolloverIfNeeded(now);
32426
+ msgsToday++;
32427
+ msgsTotal++;
32428
+ }
32429
+ function snapshotCounters() {
32430
+ rolloverIfNeeded(nowFn());
32431
+ return { day: today, msgsToday, msgsTotal };
32432
+ }
32433
+ function restoreCounters(s) {
32434
+ today = todayKey(nowFn());
32435
+ msgsToday = s.day === today && typeof s.msgsToday === "number" && s.msgsToday > 0 ? s.msgsToday : 0;
32436
+ msgsTotal = typeof s.msgsTotal === "number" && s.msgsTotal > 0 ? s.msgsTotal : 0;
32437
+ }
32438
+
32439
+ // src/optional/reporting/reporter.ts
32440
+ init_api_status();
32441
+ var DEFAULT_REPORT_URL = "https://www.twinsun.top:8866/api/engine7/report";
32442
+ var DEFAULT_INTERVAL_MS2 = 5 * 60 * 1e3;
32443
+ var DEFAULT_INITIAL_DELAY_MS = 10 * 1e3;
32444
+ var FETCH_TIMEOUT_MS = 10 * 1e3;
32445
+ function acceptReportUrl(v) {
32446
+ if (typeof v !== "string") return null;
32447
+ const t = v.trim();
32448
+ return t.startsWith("https://") ? t : null;
32449
+ }
32450
+ function startReporting(opts) {
32451
+ const { stateDir } = opts;
32452
+ const doFetch = opts.fetchImpl ?? fetch;
32453
+ const nowFn2 = opts.now ?? (() => Date.now());
32454
+ const intervalMs = opts.intervalMs ?? DEFAULT_INTERVAL_MS2;
32455
+ const initialDelayMs = opts.initialDelayMs ?? DEFAULT_INITIAL_DELAY_MS;
32456
+ const log = opts.log ?? (() => {
32457
+ });
32458
+ const startedAt = nowFn2();
32459
+ const maybeIdentity = readInstallIdentity(stateDir);
32460
+ if (!maybeIdentity) {
32461
+ log("[reporting] \u6CA1\u6709\u53EF\u7528\u7684\u88C5\u673A\u8EAB\u4EFD\uFF0C\u4E0A\u62A5\u5173\u95ED");
32462
+ return { stop() {
32463
+ }, async beatNow() {
32464
+ } };
32465
+ }
32466
+ const identity = maybeIdentity;
32467
+ restoreCounters(readReportState(stateDir));
32468
+ const engineVersion = readEngineVersion();
32469
+ let timer = null;
32470
+ let stopped = false;
32471
+ async function beatOnce() {
32472
+ const state2 = readReportState(stateDir);
32473
+ const enabled = liveConfig.get("reporting.enabled") !== false;
32474
+ const counters = snapshotCounters();
32475
+ if (!enabled) {
32476
+ writeReportState(stateDir, { ...counters, reportUrl: state2.reportUrl });
32477
+ return;
32478
+ }
32479
+ const fromServer = acceptReportUrl(state2.reportUrl);
32480
+ const fromConfig = (liveConfig.get("reporting.url") || "").trim();
32481
+ const url = fromServer ?? (fromConfig || DEFAULT_REPORT_URL);
32482
+ const payload = buildReportPayload({
32483
+ identity,
32484
+ stateDir,
32485
+ engineVersion,
32486
+ startedAt,
32487
+ now: nowFn2(),
32488
+ counters
32489
+ });
32490
+ let nextUrl = state2.reportUrl;
32491
+ try {
32492
+ const res = await doFetch(url, {
32493
+ method: "POST",
32494
+ headers: { "Content-Type": "application/json" },
32495
+ body: JSON.stringify(payload),
32496
+ signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
32497
+ });
32498
+ const body = JSON.parse(await res.text());
32499
+ const adopted = acceptReportUrl(body?.reportUrl);
32500
+ if (adopted) nextUrl = adopted;
32501
+ } catch {
32502
+ }
32503
+ writeReportState(stateDir, { ...counters, reportUrl: nextUrl });
32504
+ }
32505
+ function schedule(delay) {
32506
+ if (stopped) return;
32507
+ timer = setTimeout(() => {
32508
+ void beatOnce().finally(() => schedule(intervalMs));
32509
+ }, delay);
32510
+ if (typeof timer.unref === "function") timer.unref();
32511
+ }
32512
+ schedule(initialDelayMs);
32513
+ return {
32514
+ stop() {
32515
+ stopped = true;
32516
+ if (timer) {
32517
+ clearTimeout(timer);
32518
+ timer = null;
32519
+ }
32520
+ },
32521
+ async beatNow() {
32522
+ await beatOnce();
32523
+ }
32524
+ };
32525
+ }
32526
+
32332
32527
  // src/engine-startup.ts
32333
32528
  init_provider_factory();
32334
32529
 
@@ -33499,7 +33694,7 @@ var FeishuAdapter = class _FeishuAdapter {
33499
33694
  import * as crypto4 from "crypto";
33500
33695
  import * as fs38 from "fs";
33501
33696
  import * as path38 from "path";
33502
- import * as os3 from "os";
33697
+ import * as os4 from "os";
33503
33698
  import { promises as dns } from "dns";
33504
33699
  function sleep3(ms) {
33505
33700
  return new Promise((r) => setTimeout(r, ms));
@@ -33882,7 +34077,7 @@ var WechatAdapter = class {
33882
34077
  this.config = config;
33883
34078
  this.baseUrl = config.baseUrl?.replace(/\/$/, "") || ILINK_BASE_URL;
33884
34079
  this.cdnBaseUrl = config.cdnBaseUrl?.replace(/\/$/, "") || WEIXIN_CDN_BASE_URL;
33885
- this.stateDir = config.stateDir || path38.join(os3.homedir?.() || "/tmp", ".engine7");
34080
+ this.stateDir = config.stateDir || path38.join(os4.homedir?.() || "/tmp", ".engine7");
33886
34081
  if (!fs38.existsSync(this.stateDir)) fs38.mkdirSync(this.stateDir, { recursive: true });
33887
34082
  }
33888
34083
  // --- ChannelAdapter interface ---
@@ -34228,7 +34423,7 @@ var WechatAdapter = class {
34228
34423
  mediaRef.full_url,
34229
34424
  timeoutSec
34230
34425
  );
34231
- const tmpDir = path38.join(os3.tmpdir(), "weixin-media");
34426
+ const tmpDir = path38.join(os4.tmpdir(), "weixin-media");
34232
34427
  if (!fs38.existsSync(tmpDir)) fs38.mkdirSync(tmpDir, { recursive: true });
34233
34428
  const tmpPath = path38.join(tmpDir, `${crypto4.randomUUID().replace(/-/g, "")}-${filename}`);
34234
34429
  fs38.writeFileSync(tmpPath, data);
@@ -34490,10 +34685,10 @@ import { createInterface as createInterface2 } from "node:readline";
34490
34685
  import { promisify as promisify2 } from "node:util";
34491
34686
  import * as fs41 from "node:fs";
34492
34687
  import * as path40 from "node:path";
34493
- import * as os4 from "node:os";
34688
+ import * as os5 from "node:os";
34494
34689
  import net4 from "net";
34495
34690
  var execFileAsync2 = promisify2(execFile2);
34496
- var VOICE_DIR = path40.join(os4.tmpdir(), "engine-voice");
34691
+ var VOICE_DIR = path40.join(os5.tmpdir(), "engine-voice");
34497
34692
  var _pyCache = null;
34498
34693
  function resolvePython(configuredPath) {
34499
34694
  if (configuredPath) {
@@ -35137,10 +35332,10 @@ var DeskBuddyAdapter = class {
35137
35332
  appendHistory(entry) {
35138
35333
  try {
35139
35334
  if (!this.historyFile) {
35140
- const os5 = __require("os");
35335
+ const os6 = __require("os");
35141
35336
  const fs57 = __require("fs");
35142
35337
  const path58 = __require("path");
35143
- const dir = path58.join(os5.homedir(), "xiaowen", "workspace", ".desktopBuddy");
35338
+ const dir = path58.join(os6.homedir(), "xiaowen", "workspace", ".desktopBuddy");
35144
35339
  fs57.mkdirSync(dir, { recursive: true });
35145
35340
  this.historyFile = path58.join(dir, "history.json");
35146
35341
  this._fs = fs57;
@@ -37466,6 +37661,7 @@ var MessageDispatcher = class {
37466
37661
  displayText = imgCount > 0 ? `${txt} [\u56FE\u7247\xD7${imgCount}]`.trim() : txt;
37467
37662
  }
37468
37663
  console.log(`[dispatcher] Executing (session=${msg2.sessionId}, source=${msg2.source}, gen=${generation}): ${displayText.slice(0, 200).replace(/\n/g, " ")}`);
37664
+ noteUserMessage(msg2.source);
37469
37665
  try {
37470
37666
  await handleQuery(
37471
37667
  msg2.text,
@@ -40919,7 +41115,7 @@ ${err.stack}`);
40919
41115
  // src/commands/model.ts
40920
41116
  import * as fs54 from "node:fs";
40921
41117
  import * as path54 from "node:path";
40922
- import { fileURLToPath as fileURLToPath7 } from "node:url";
41118
+ import { fileURLToPath as fileURLToPath8 } from "node:url";
40923
41119
  function collectModels(config) {
40924
41120
  const aliases = config.modelAliases || {};
40925
41121
  const aliasByRef = /* @__PURE__ */ new Map();
@@ -40951,7 +41147,7 @@ function resolveConfigWritePath(config, label) {
40951
41147
  if (!configPath) return void 0;
40952
41148
  let writePath = configPath;
40953
41149
  if (configPath && !fs54.existsSync(configPath)) {
40954
- const __pFile = fileURLToPath7(import.meta.url);
41150
+ const __pFile = fileURLToPath8(import.meta.url);
40955
41151
  const __pDir = path54.dirname(__pFile);
40956
41152
  const altPath = path54.join(path54.resolve(__pDir, "../configs"), path54.basename(configPath));
40957
41153
  if (fs54.existsSync(altPath)) {
@@ -42044,6 +42240,33 @@ async function startEngine(config, opts) {
42044
42240
  // 常开 entry,stop 不触发
42045
42241
  });
42046
42242
  }
42243
+ {
42244
+ let reportingHandle;
42245
+ const stopReporting = () => {
42246
+ try {
42247
+ reportingHandle?.stop();
42248
+ } catch {
42249
+ }
42250
+ reportingHandle = void 0;
42251
+ };
42252
+ const startReportingNow = () => {
42253
+ stopReporting();
42254
+ reportingHandle = startReporting({ stateDir: config.stateDir });
42255
+ };
42256
+ const reportingEnabled = () => liveConfig.get("reporting.enabled") !== false;
42257
+ reloadOrchestrator.register({
42258
+ name: "reporting",
42259
+ // url 也进 key:运维手改地址要能热生效,不用重启
42260
+ select: (cfg) => ({ enabled: cfg.reporting?.enabled !== false, url: cfg.reporting?.url ?? "" }),
42261
+ start: async () => {
42262
+ startReportingNow();
42263
+ },
42264
+ stop: async () => {
42265
+ stopReporting();
42266
+ }
42267
+ }, reportingEnabled());
42268
+ if (reportingEnabled()) startReportingNow();
42269
+ }
42047
42270
  const shutdownPromise = new Promise((resolve12) => {
42048
42271
  const shutdown = (signal) => {
42049
42272
  console.log(`[engine] ${signal} received, shutting down...`);