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.
package/dist/main.mjs CHANGED
@@ -8215,26 +8215,26 @@ async function writeToMailbox(recipientName, message, teamName) {
8215
8215
  await writeFile2(inboxPath, "[]", { encoding: "utf-8", flag: "wx" });
8216
8216
  } catch {
8217
8217
  }
8218
- const release2 = await acquireLock(inboxPath);
8218
+ const release3 = await acquireLock(inboxPath);
8219
8219
  try {
8220
8220
  const messages = await readMailbox(recipientName, teamName);
8221
8221
  messages.push({ ...message, read: false });
8222
8222
  await writeFile2(inboxPath, JSON.stringify(messages, null, 2), "utf-8");
8223
8223
  console.log(`[mailbox] Wrote message to ${recipientName} from ${message.from} (team=${teamName || "default"}, inbox=${inboxPath})`);
8224
8224
  } finally {
8225
- await release2();
8225
+ await release3();
8226
8226
  }
8227
8227
  }
8228
8228
  async function markMessagesAsRead(agentName, teamName) {
8229
8229
  const inboxPath = getInboxPath(agentName, teamName);
8230
- const release2 = await acquireLock(inboxPath);
8230
+ const release3 = await acquireLock(inboxPath);
8231
8231
  try {
8232
8232
  const messages = await readMailbox(agentName, teamName);
8233
8233
  if (messages.length === 0) return;
8234
8234
  for (const m of messages) m.read = true;
8235
8235
  await writeFile2(inboxPath, JSON.stringify(messages, null, 2), "utf-8");
8236
8236
  } finally {
8237
- await release2();
8237
+ await release3();
8238
8238
  }
8239
8239
  }
8240
8240
  async function clearMailbox(agentName, teamName) {
@@ -10065,7 +10065,7 @@ CREATE TABLE IF NOT EXISTS watermarks (
10065
10065
  }
10066
10066
  // ── md 读(proactive 消费):开窗预测(全 owner 扫描,end>=今天)──
10067
10067
  getOpenPredictions(now, limit = 50) {
10068
- const today = todayKey(now);
10068
+ const today2 = todayKey(now);
10069
10069
  const out = [];
10070
10070
  const usersDir = join23(this.root, "users");
10071
10071
  if (!existsSync13(usersDir)) return out;
@@ -10088,7 +10088,7 @@ CREATE TABLE IF NOT EXISTS watermarks (
10088
10088
  const text = ((block.match(/### Foresight\s*\n+([\s\S]*?)(?:\n### Evidence|$)/) ?? [])[1] ?? "").trim();
10089
10089
  const evidence = ((block.match(/### Evidence\s*\n+([\s\S]*?)$/) ?? [])[1] ?? "").trim();
10090
10090
  if (!end || !start || !text) continue;
10091
- if (end < today) continue;
10091
+ if (end < today2) continue;
10092
10092
  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) });
10093
10093
  if (out.length >= limit) return out;
10094
10094
  }
@@ -13629,7 +13629,7 @@ function loadForesightEntries(everosRoot, now, userId, ownerFilter) {
13629
13629
  return entries2.slice();
13630
13630
  }
13631
13631
  function parseForesightEntries(everosRoot, now, userId) {
13632
- const today = todayKey(now);
13632
+ const today2 = todayKey(now);
13633
13633
  let files;
13634
13634
  if (userId) {
13635
13635
  const ownDir = join30(everosRoot, userId, "default_project", "users", userId, ".foresights");
@@ -13654,7 +13654,7 @@ function parseForesightEntries(everosRoot, now, userId) {
13654
13654
  const end = (block.match(/\*\*end_time\*\*:\s*(\d{4}-\d{2}-\d{2})/) ?? [])[1];
13655
13655
  const text = ((block.match(/### Foresight\s*\n+([\s\S]*?)(?:\n### Evidence|$)/) ?? [])[1] ?? "").trim();
13656
13656
  if (!start || !end || !text) continue;
13657
- if (end < today) continue;
13657
+ if (end < today2) continue;
13658
13658
  const evidence = ((block.match(/### Evidence\s*\n+([\s\S]*?)$/) ?? [])[1] ?? "").trim();
13659
13659
  const blockOwner = (block.match(/\*\*owner_id\*\*:\s*(\S+)/) ?? [])[1] ?? fileOwner;
13660
13660
  const key = text.replace(/\s+/g, "");
@@ -21592,7 +21592,7 @@ function isPermittedRedirect(original, redirect) {
21592
21592
  async function fetchWithRedirects(url, signal, depth = 0) {
21593
21593
  if (depth > MAX_REDIRECTS) throw new Error(`\u91CD\u5B9A\u5411\u6B21\u6570\u8FC7\u591A (>${MAX_REDIRECTS})`);
21594
21594
  const controller = new AbortController();
21595
- const timeoutId = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
21595
+ const timeoutId = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS2);
21596
21596
  const onSignalAbort = () => controller.abort();
21597
21597
  signal.addEventListener("abort", onSignalAbort, { once: true });
21598
21598
  try {
@@ -21635,14 +21635,14 @@ function getTurndown() {
21635
21635
  }
21636
21636
  return td;
21637
21637
  }
21638
- var MAX_URL_LENGTH, MAX_CONTENT_LENGTH, FETCH_TIMEOUT_MS, MAX_REDIRECTS, td;
21638
+ var MAX_URL_LENGTH, MAX_CONTENT_LENGTH, FETCH_TIMEOUT_MS2, MAX_REDIRECTS, td;
21639
21639
  var init_web_fetch = __esm({
21640
21640
  "src/tools/web-fetch.ts"() {
21641
21641
  "use strict";
21642
21642
  init_registry();
21643
21643
  MAX_URL_LENGTH = 2e3;
21644
21644
  MAX_CONTENT_LENGTH = 10 * 1024 * 1024;
21645
- FETCH_TIMEOUT_MS = 6e4;
21645
+ FETCH_TIMEOUT_MS2 = 6e4;
21646
21646
  MAX_REDIRECTS = 10;
21647
21647
  registry.register({
21648
21648
  name: "web_fetch",
@@ -21713,7 +21713,7 @@ var init_web_fetch = __esm({
21713
21713
 
21714
21714
  // src/tools/wechat/wx-query.ts
21715
21715
  var wx_query_exports = {};
21716
- import { join as join55 } from "node:path";
21716
+ import { join as join57 } from "node:path";
21717
21717
  function getDescription() {
21718
21718
  return `\u67E5\u8BE2\u7FC0\u54E5\u7684\u5FAE\u4FE1\u6D88\u606F\uFF08\u7F13\u5B58\u89E3\u5BC6\u540E\u7684\u672C\u5730\u6570\u636E\u5E93\uFF09\u3002
21719
21719
 
@@ -21748,8 +21748,8 @@ var init_wx_query = __esm({
21748
21748
  "use strict";
21749
21749
  init_registry();
21750
21750
  init_live();
21751
- STATE_DIR = process.env.ENGINE7_STATE_DIR || join55(process.env.HOME || process.env.USERPROFILE || ".", ".engine7");
21752
- SCRIPT = join55("/Users/chongzhang/work/twinsun-hearth/engine", "src", "tools", "wechat", "wx_query.py");
21751
+ STATE_DIR = process.env.ENGINE7_STATE_DIR || join57(process.env.HOME || process.env.USERPROFILE || ".", ".engine7");
21752
+ SCRIPT = join57("/Users/chongzhang/work/twinsun-hearth/engine", "src", "tools", "wechat", "wx_query.py");
21753
21753
  PYTHON = "python3";
21754
21754
  registry.register({
21755
21755
  name: "wx_query",
@@ -22924,8 +22924,8 @@ async function doReloadConfigInner(config2, deps, provider, force = false) {
22924
22924
  const savedConfigPath = config2._configFilePath;
22925
22925
  let reloadConfigPath = savedConfigPath;
22926
22926
  if (!fs10.existsSync(reloadConfigPath)) {
22927
- const __filename = fileURLToPath(import.meta.url);
22928
- const __dirname = path10.dirname(__filename);
22927
+ const __filename2 = fileURLToPath(import.meta.url);
22928
+ const __dirname = path10.dirname(__filename2);
22929
22929
  const engineConfigsDir = path10.resolve(__dirname, "../configs");
22930
22930
  const altPath = path10.join(engineConfigsDir, path10.basename(savedConfigPath));
22931
22931
  if (fs10.existsSync(altPath)) {
@@ -23239,20 +23239,20 @@ function acquireEngineLock(stateDir) {
23239
23239
  } catch (err) {
23240
23240
  console.warn(`[pid-lock] write lock failed: ${err.message}`);
23241
23241
  }
23242
- const release2 = () => {
23242
+ const release3 = () => {
23243
23243
  try {
23244
23244
  const cur = fs11.existsSync(lockFile) ? fs11.readFileSync(lockFile, "utf-8").trim() : "";
23245
23245
  if (cur === String(myPid)) fs11.unlinkSync(lockFile);
23246
23246
  } catch {
23247
23247
  }
23248
23248
  };
23249
- process.on("exit", release2);
23249
+ process.on("exit", release3);
23250
23250
  process.on("SIGINT", () => {
23251
- release2();
23251
+ release3();
23252
23252
  process.exit(0);
23253
23253
  });
23254
23254
  process.on("SIGTERM", () => {
23255
- release2();
23255
+ release3();
23256
23256
  process.exit(0);
23257
23257
  });
23258
23258
  }
@@ -24911,7 +24911,8 @@ function buildLightHistory(history, opts) {
24911
24911
  function buildLightStablePrompt(workspace, mode, opts) {
24912
24912
  const lp = liveConfig.get(`channels.${mode}.liveSystemPrompt`);
24913
24913
  const parts = [];
24914
- for (const f of lp?.files ?? ["SOUL.md"]) {
24914
+ const files = lp?.files ?? (mode === "emotion" ? ["SOUL.md", "EMOTION.md"] : ["SOUL.md"]);
24915
+ for (const f of files) {
24915
24916
  try {
24916
24917
  parts.push(readFileSync12(join19(workspace, f), "utf-8").trim());
24917
24918
  } catch {
@@ -24934,7 +24935,7 @@ function buildLightStablePrompt(workspace, mode, opts) {
24934
24935
  ].join("\n"));
24935
24936
  }
24936
24937
  const built = parts.join("\n\n");
24937
- console.log(`[light-stable] mode=${mode} files=[${(lp?.files ?? ["SOUL.md"]).join(",")}] ~${Math.round(built.length / 3)} tokens`);
24938
+ console.log(`[light-stable] mode=${mode} files=[${files.join(",")}] ~${Math.round(built.length / 3)} tokens`);
24938
24939
  return built;
24939
24940
  }
24940
24941
 
@@ -28686,10 +28687,10 @@ var US_HALF_LIFE_DAYS = 10;
28686
28687
  var US_MAX_LINES = 60;
28687
28688
  function readRecentMemory(workspace) {
28688
28689
  const dir = path30.join(workspace, "memory");
28689
- const today = dailyFileKeyFor();
28690
+ const today2 = dailyFileKeyFor();
28690
28691
  const yesterday = dailyFileKeyFor(Date.now() - 864e5);
28691
28692
  return {
28692
- today: readIfExists(path30.join(dir, `${today}.md`)),
28693
+ today: readIfExists(path30.join(dir, `${today2}.md`)),
28693
28694
  yesterday: readIfExists(path30.join(dir, `${yesterday}.md`))
28694
28695
  };
28695
28696
  }
@@ -32626,6 +32627,200 @@ ${pathStr}` }];
32626
32627
  channelManager.startAll();
32627
32628
  }
32628
32629
 
32630
+ // src/optional/reporting/reporter.ts
32631
+ init_live();
32632
+
32633
+ // src/provision-free.ts
32634
+ import { chmodSync as chmodSync2, existsSync as existsSync22, mkdirSync as mkdirSync14, readFileSync as readFileSync34, writeFileSync as writeFileSync12 } from "node:fs";
32635
+ import { dirname as dirname10, join as join45 } from "node:path";
32636
+ import { fileURLToPath as fileURLToPath7 } from "node:url";
32637
+ var __filename = fileURLToPath7(import.meta.url);
32638
+ var IDENTITY_FILE = "install-identity.json";
32639
+ function readContactEmailOf(parsed) {
32640
+ return typeof parsed?.contactEmail === "string" ? parsed.contactEmail.trim() : "";
32641
+ }
32642
+ function readInstallIdentity(stateDir) {
32643
+ try {
32644
+ const parsed = JSON.parse(readFileSync34(join45(stateDir, IDENTITY_FILE), "utf8"));
32645
+ if (typeof parsed?.installId !== "string" || typeof parsed?.installSecret !== "string") return null;
32646
+ const email = readContactEmailOf(parsed);
32647
+ return {
32648
+ installId: parsed.installId,
32649
+ installSecret: parsed.installSecret,
32650
+ ...email ? { contactEmail: email } : {}
32651
+ };
32652
+ } catch {
32653
+ return null;
32654
+ }
32655
+ }
32656
+
32657
+ // src/optional/reporting/state.ts
32658
+ import { existsSync as existsSync23, mkdirSync as mkdirSync15, readFileSync as readFileSync35, writeFileSync as writeFileSync13 } from "node:fs";
32659
+ import { join as join46 } from "node:path";
32660
+ var STATE_FILE2 = "report-state.json";
32661
+ function readReportState(stateDir) {
32662
+ try {
32663
+ const p = join46(stateDir, STATE_FILE2);
32664
+ if (!existsSync23(p)) return {};
32665
+ const parsed = JSON.parse(readFileSync35(p, "utf8"));
32666
+ if (!parsed || typeof parsed !== "object") return {};
32667
+ return parsed;
32668
+ } catch {
32669
+ return {};
32670
+ }
32671
+ }
32672
+ function writeReportState(stateDir, s) {
32673
+ try {
32674
+ mkdirSync15(stateDir, { recursive: true });
32675
+ writeFileSync13(join46(stateDir, STATE_FILE2), JSON.stringify(s, null, 2) + "\n");
32676
+ } catch {
32677
+ }
32678
+ }
32679
+
32680
+ // src/optional/reporting/payload.ts
32681
+ import { createHash as createHash2 } from "node:crypto";
32682
+ import * as os3 from "node:os";
32683
+ function installKeyOf(installId, installSecret) {
32684
+ return createHash2("sha256").update(installId + installSecret).digest("hex").slice(0, 32);
32685
+ }
32686
+ function buildReportPayload(opts) {
32687
+ const p = {
32688
+ installId: opts.identity.installId,
32689
+ installKey: installKeyOf(opts.identity.installId, opts.identity.installSecret),
32690
+ engineVersion: opts.engineVersion,
32691
+ platform: process.platform,
32692
+ osVersion: typeof os3.release === "function" ? os3.release() : "",
32693
+ arch: process.arch,
32694
+ stateDir: opts.stateDir,
32695
+ startedAt: opts.startedAt,
32696
+ // 时钟回拨时别报个负数上去
32697
+ uptimeSec: Math.max(0, Math.floor((opts.now - opts.startedAt) / 1e3)),
32698
+ msgsToday: opts.counters.msgsToday,
32699
+ msgsTotal: opts.counters.msgsTotal
32700
+ };
32701
+ if (opts.identity.contactEmail) p.contactEmail = opts.identity.contactEmail;
32702
+ return p;
32703
+ }
32704
+
32705
+ // src/core/activity-counter.ts
32706
+ init_clock();
32707
+ var USER_SOURCES = /* @__PURE__ */ new Set(["user", "inbox"]);
32708
+ var nowFn = () => /* @__PURE__ */ new Date();
32709
+ var today = "";
32710
+ var msgsToday = 0;
32711
+ var msgsTotal = 0;
32712
+ function rolloverIfNeeded(now) {
32713
+ const d = todayKey(now);
32714
+ if (d !== today) {
32715
+ today = d;
32716
+ msgsToday = 0;
32717
+ }
32718
+ }
32719
+ function noteUserMessage(source) {
32720
+ if (!source || !USER_SOURCES.has(source)) return;
32721
+ const now = nowFn();
32722
+ rolloverIfNeeded(now);
32723
+ msgsToday++;
32724
+ msgsTotal++;
32725
+ }
32726
+ function snapshotCounters() {
32727
+ rolloverIfNeeded(nowFn());
32728
+ return { day: today, msgsToday, msgsTotal };
32729
+ }
32730
+ function restoreCounters(s) {
32731
+ today = todayKey(nowFn());
32732
+ msgsToday = s.day === today && typeof s.msgsToday === "number" && s.msgsToday > 0 ? s.msgsToday : 0;
32733
+ msgsTotal = typeof s.msgsTotal === "number" && s.msgsTotal > 0 ? s.msgsTotal : 0;
32734
+ }
32735
+
32736
+ // src/optional/reporting/reporter.ts
32737
+ init_api_status();
32738
+ var DEFAULT_REPORT_URL = "https://www.twinsun.top:8866/api/engine7/report";
32739
+ var DEFAULT_INTERVAL_MS2 = 5 * 60 * 1e3;
32740
+ var DEFAULT_INITIAL_DELAY_MS = 10 * 1e3;
32741
+ var FETCH_TIMEOUT_MS = 10 * 1e3;
32742
+ function acceptReportUrl(v) {
32743
+ if (typeof v !== "string") return null;
32744
+ const t = v.trim();
32745
+ return t.startsWith("https://") ? t : null;
32746
+ }
32747
+ function startReporting(opts) {
32748
+ const { stateDir } = opts;
32749
+ const doFetch = opts.fetchImpl ?? fetch;
32750
+ const nowFn2 = opts.now ?? (() => Date.now());
32751
+ const intervalMs = opts.intervalMs ?? DEFAULT_INTERVAL_MS2;
32752
+ const initialDelayMs = opts.initialDelayMs ?? DEFAULT_INITIAL_DELAY_MS;
32753
+ const log = opts.log ?? (() => {
32754
+ });
32755
+ const startedAt = nowFn2();
32756
+ const maybeIdentity = readInstallIdentity(stateDir);
32757
+ if (!maybeIdentity) {
32758
+ log("[reporting] \u6CA1\u6709\u53EF\u7528\u7684\u88C5\u673A\u8EAB\u4EFD\uFF0C\u4E0A\u62A5\u5173\u95ED");
32759
+ return { stop() {
32760
+ }, async beatNow() {
32761
+ } };
32762
+ }
32763
+ const identity = maybeIdentity;
32764
+ restoreCounters(readReportState(stateDir));
32765
+ const engineVersion = readEngineVersion();
32766
+ let timer = null;
32767
+ let stopped = false;
32768
+ async function beatOnce() {
32769
+ const state2 = readReportState(stateDir);
32770
+ const enabled = liveConfig.get("reporting.enabled") !== false;
32771
+ const counters = snapshotCounters();
32772
+ if (!enabled) {
32773
+ writeReportState(stateDir, { ...counters, reportUrl: state2.reportUrl });
32774
+ return;
32775
+ }
32776
+ const fromServer = acceptReportUrl(state2.reportUrl);
32777
+ const fromConfig = (liveConfig.get("reporting.url") || "").trim();
32778
+ const url = fromServer ?? (fromConfig || DEFAULT_REPORT_URL);
32779
+ const payload = buildReportPayload({
32780
+ identity,
32781
+ stateDir,
32782
+ engineVersion,
32783
+ startedAt,
32784
+ now: nowFn2(),
32785
+ counters
32786
+ });
32787
+ let nextUrl = state2.reportUrl;
32788
+ try {
32789
+ const res = await doFetch(url, {
32790
+ method: "POST",
32791
+ headers: { "Content-Type": "application/json" },
32792
+ body: JSON.stringify(payload),
32793
+ signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
32794
+ });
32795
+ const body = JSON.parse(await res.text());
32796
+ const adopted = acceptReportUrl(body?.reportUrl);
32797
+ if (adopted) nextUrl = adopted;
32798
+ } catch {
32799
+ }
32800
+ writeReportState(stateDir, { ...counters, reportUrl: nextUrl });
32801
+ }
32802
+ function schedule(delay) {
32803
+ if (stopped) return;
32804
+ timer = setTimeout(() => {
32805
+ void beatOnce().finally(() => schedule(intervalMs));
32806
+ }, delay);
32807
+ if (typeof timer.unref === "function") timer.unref();
32808
+ }
32809
+ schedule(initialDelayMs);
32810
+ return {
32811
+ stop() {
32812
+ stopped = true;
32813
+ if (timer) {
32814
+ clearTimeout(timer);
32815
+ timer = null;
32816
+ }
32817
+ },
32818
+ async beatNow() {
32819
+ await beatOnce();
32820
+ }
32821
+ };
32822
+ }
32823
+
32629
32824
  // src/engine-startup.ts
32630
32825
  init_provider_factory();
32631
32826
 
@@ -33796,7 +33991,7 @@ var FeishuAdapter = class _FeishuAdapter {
33796
33991
  import * as crypto4 from "crypto";
33797
33992
  import * as fs38 from "fs";
33798
33993
  import * as path38 from "path";
33799
- import * as os3 from "os";
33994
+ import * as os4 from "os";
33800
33995
  import { promises as dns } from "dns";
33801
33996
  function sleep3(ms) {
33802
33997
  return new Promise((r) => setTimeout(r, ms));
@@ -34179,7 +34374,7 @@ var WechatAdapter = class {
34179
34374
  this.config = config2;
34180
34375
  this.baseUrl = config2.baseUrl?.replace(/\/$/, "") || ILINK_BASE_URL;
34181
34376
  this.cdnBaseUrl = config2.cdnBaseUrl?.replace(/\/$/, "") || WEIXIN_CDN_BASE_URL;
34182
- this.stateDir = config2.stateDir || path38.join(os3.homedir?.() || "/tmp", ".engine7");
34377
+ this.stateDir = config2.stateDir || path38.join(os4.homedir?.() || "/tmp", ".engine7");
34183
34378
  if (!fs38.existsSync(this.stateDir)) fs38.mkdirSync(this.stateDir, { recursive: true });
34184
34379
  }
34185
34380
  // --- ChannelAdapter interface ---
@@ -34525,7 +34720,7 @@ var WechatAdapter = class {
34525
34720
  mediaRef.full_url,
34526
34721
  timeoutSec
34527
34722
  );
34528
- const tmpDir = path38.join(os3.tmpdir(), "weixin-media");
34723
+ const tmpDir = path38.join(os4.tmpdir(), "weixin-media");
34529
34724
  if (!fs38.existsSync(tmpDir)) fs38.mkdirSync(tmpDir, { recursive: true });
34530
34725
  const tmpPath = path38.join(tmpDir, `${crypto4.randomUUID().replace(/-/g, "")}-${filename}`);
34531
34726
  fs38.writeFileSync(tmpPath, data);
@@ -34787,10 +34982,10 @@ import { createInterface as createInterface2 } from "node:readline";
34787
34982
  import { promisify as promisify2 } from "node:util";
34788
34983
  import * as fs41 from "node:fs";
34789
34984
  import * as path40 from "node:path";
34790
- import * as os4 from "node:os";
34985
+ import * as os5 from "node:os";
34791
34986
  import net4 from "net";
34792
34987
  var execFileAsync2 = promisify2(execFile2);
34793
- var VOICE_DIR = path40.join(os4.tmpdir(), "engine-voice");
34988
+ var VOICE_DIR = path40.join(os5.tmpdir(), "engine-voice");
34794
34989
  var _pyCache = null;
34795
34990
  function resolvePython(configuredPath) {
34796
34991
  if (configuredPath) {
@@ -35434,10 +35629,10 @@ var DeskBuddyAdapter = class {
35434
35629
  appendHistory(entry) {
35435
35630
  try {
35436
35631
  if (!this.historyFile) {
35437
- const os5 = __require("os");
35632
+ const os6 = __require("os");
35438
35633
  const fs57 = __require("fs");
35439
35634
  const path58 = __require("path");
35440
- const dir = path58.join(os5.homedir(), "xiaowen", "workspace", ".desktopBuddy");
35635
+ const dir = path58.join(os6.homedir(), "xiaowen", "workspace", ".desktopBuddy");
35441
35636
  fs57.mkdirSync(dir, { recursive: true });
35442
35637
  this.historyFile = path58.join(dir, "history.json");
35443
35638
  this._fs = fs57;
@@ -37763,6 +37958,7 @@ var MessageDispatcher = class {
37763
37958
  displayText = imgCount > 0 ? `${txt} [\u56FE\u7247\xD7${imgCount}]`.trim() : txt;
37764
37959
  }
37765
37960
  console.log(`[dispatcher] Executing (session=${msg2.sessionId}, source=${msg2.source}, gen=${generation}): ${displayText.slice(0, 200).replace(/\n/g, " ")}`);
37961
+ noteUserMessage(msg2.source);
37766
37962
  try {
37767
37963
  await handleQuery(
37768
37964
  msg2.text,
@@ -41039,7 +41235,7 @@ ${err.stack}`);
41039
41235
  // src/commands/model.ts
41040
41236
  import * as fs54 from "node:fs";
41041
41237
  import * as path54 from "node:path";
41042
- import { fileURLToPath as fileURLToPath7 } from "node:url";
41238
+ import { fileURLToPath as fileURLToPath8 } from "node:url";
41043
41239
  function collectModels(config2) {
41044
41240
  const aliases = config2.modelAliases || {};
41045
41241
  const aliasByRef = /* @__PURE__ */ new Map();
@@ -41071,7 +41267,7 @@ function resolveConfigWritePath(config2, label) {
41071
41267
  if (!configPath2) return void 0;
41072
41268
  let writePath = configPath2;
41073
41269
  if (configPath2 && !fs54.existsSync(configPath2)) {
41074
- const __pFile = fileURLToPath7(import.meta.url);
41270
+ const __pFile = fileURLToPath8(import.meta.url);
41075
41271
  const __pDir = path54.dirname(__pFile);
41076
41272
  const altPath = path54.join(path54.resolve(__pDir, "../configs"), path54.basename(configPath2));
41077
41273
  if (fs54.existsSync(altPath)) {
@@ -42164,6 +42360,33 @@ async function startEngine(config2, opts) {
42164
42360
  // 常开 entry,stop 不触发
42165
42361
  });
42166
42362
  }
42363
+ {
42364
+ let reportingHandle;
42365
+ const stopReporting = () => {
42366
+ try {
42367
+ reportingHandle?.stop();
42368
+ } catch {
42369
+ }
42370
+ reportingHandle = void 0;
42371
+ };
42372
+ const startReportingNow = () => {
42373
+ stopReporting();
42374
+ reportingHandle = startReporting({ stateDir: config2.stateDir });
42375
+ };
42376
+ const reportingEnabled = () => liveConfig.get("reporting.enabled") !== false;
42377
+ reloadOrchestrator.register({
42378
+ name: "reporting",
42379
+ // url 也进 key:运维手改地址要能热生效,不用重启
42380
+ select: (cfg) => ({ enabled: cfg.reporting?.enabled !== false, url: cfg.reporting?.url ?? "" }),
42381
+ start: async () => {
42382
+ startReportingNow();
42383
+ },
42384
+ stop: async () => {
42385
+ stopReporting();
42386
+ }
42387
+ }, reportingEnabled());
42388
+ if (reportingEnabled()) startReportingNow();
42389
+ }
42167
42390
  const shutdownPromise = new Promise((resolve12) => {
42168
42391
  const shutdown = (signal) => {
42169
42392
  console.log(`[engine] ${signal} received, shutting down...`);
@@ -42206,11 +42429,11 @@ async function startEngine(config2, opts) {
42206
42429
  }
42207
42430
 
42208
42431
  // src/main.ts
42209
- import { readFileSync as readFileSync45 } from "node:fs";
42210
- import { fileURLToPath as fileURLToPath8 } from "node:url";
42211
- import { dirname as dirname15, join as join61 } from "node:path";
42212
- var __dirname2 = dirname15(fileURLToPath8(import.meta.url));
42213
- var pkg = JSON.parse(readFileSync45(join61(__dirname2, "..", "package.json"), "utf-8"));
42432
+ import { readFileSync as readFileSync47 } from "node:fs";
42433
+ import { fileURLToPath as fileURLToPath9 } from "node:url";
42434
+ import { dirname as dirname16, join as join63 } from "node:path";
42435
+ var __dirname2 = dirname16(fileURLToPath9(import.meta.url));
42436
+ var pkg = JSON.parse(readFileSync47(join63(__dirname2, "..", "package.json"), "utf-8"));
42214
42437
  var epipeSeen = false;
42215
42438
  process.on("uncaughtException", (err) => {
42216
42439
  const code = err?.code ?? "";